@sap/cds-dk 7.1.1 → 7.3.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 (84) hide show
  1. package/bin/activate.js +2 -2
  2. package/bin/build.js +5 -2
  3. package/bin/compile/index.js +13 -5
  4. package/bin/env.js +0 -3
  5. package/bin/extend.js +25 -3
  6. package/bin/gen.js +27 -0
  7. package/bin/help.js +2 -1
  8. package/bin/import.js +7 -3
  9. package/bin/push.js +10 -6
  10. package/bin/watch.js +3 -4
  11. package/bin/watched.js +2 -3
  12. package/lib/bind/bindingUtil.js +1 -0
  13. package/lib/build/{buildTaskHandler.js → buildPlugin.js} +25 -30
  14. package/lib/build/buildTaskEngine.js +84 -89
  15. package/lib/build/buildTaskFactory.js +23 -44
  16. package/lib/build/buildTaskProvider.js +24 -19
  17. package/lib/build/buildTaskProviderFactory.js +176 -66
  18. package/lib/build/constants.js +6 -5
  19. package/lib/build/index.js +4 -3
  20. package/lib/build/provider/{buildTaskHandlerEdmx.js → edmxBuildPlugin.js} +6 -6
  21. package/lib/build/provider/{buildTaskHandlerFeatureToggles.js → featureToggleBuildPlugin.js} +3 -3
  22. package/lib/build/provider/fiori/index.js +5 -6
  23. package/lib/build/provider/hana/index.js +67 -36
  24. package/lib/build/provider/{buildTaskHandlerInternal.js → internalBuildPlugin.js} +11 -11
  25. package/lib/build/provider/{buildTaskProviderInternal.js → internalBuildTaskProvider.js} +42 -53
  26. package/lib/build/provider/java/index.js +24 -24
  27. package/lib/build/provider/mtx/index.js +4 -4
  28. package/lib/build/provider/mtx/resourcesTarBuilder.js +8 -8
  29. package/lib/build/provider/mtx-extension/index.js +17 -9
  30. package/lib/build/provider/mtx-sidecar/index.js +17 -11
  31. package/lib/build/provider/nodejs/index.js +63 -29
  32. package/lib/build/util.js +11 -19
  33. package/lib/client/auth_manager.js +6 -12
  34. package/lib/client/base_command.js +1 -1
  35. package/lib/client/download_legacy.js +48 -0
  36. package/lib/client/params.js +5 -0
  37. package/lib/client/push.js +41 -1
  38. package/lib/client/settings_manager.js +12 -3
  39. package/lib/compile/openapi/csdl2openapi.js +30 -21
  40. package/lib/compile/openapi/index.js +7 -3
  41. package/lib/env/schema.js +36 -0
  42. package/lib/env/schemas/cds-rc.json +101 -0
  43. package/lib/import/common.js +24 -11
  44. package/lib/import/importapi.js +2 -2
  45. package/lib/import/message.js +3 -1
  46. package/lib/import/odata/v4parser.js +23 -7
  47. package/lib/index.js +5 -0
  48. package/lib/init/constants.js +9 -12
  49. package/lib/init/index.js +86 -74
  50. package/lib/init/template/_merging/registry-mta.js +21 -12
  51. package/lib/init/template/approuter/files/mta.yaml.hbs +1 -1
  52. package/lib/init/template/approuter/index.js +3 -2
  53. package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +0 -5
  54. package/lib/init/template/cf-manifest/index.js +2 -2
  55. package/lib/init/template/connectivity/index.js +5 -4
  56. package/lib/init/template/destination/index.js +2 -5
  57. package/lib/init/template/h2/index.js +16 -0
  58. package/lib/init/template/hana/index.js +2 -3
  59. package/lib/init/template/helm/chart/values.root.schema.json +0 -5
  60. package/lib/init/template/helm/chart/values.schema.json +0 -4
  61. package/lib/init/template/helm/index.js +1 -1
  62. package/lib/init/template/html5-repo/index.js +27 -3
  63. package/lib/init/template/lint/index.js +3 -7
  64. package/lib/init/template/mta/index.js +9 -3
  65. package/lib/init/template/multitenancy/files/package.json.hbs +0 -3
  66. package/lib/init/template/multitenancy/index.js +2 -0
  67. package/lib/init/template/nodejs/index.js +3 -3
  68. package/lib/init/template/pipeline/index.js +2 -4
  69. package/lib/init/template/postgres/files/mta.yaml.hbs +27 -0
  70. package/lib/init/template/postgres/files/package.json.hbs +5 -0
  71. package/lib/init/template/postgres/index.js +52 -0
  72. package/lib/init/template/sample/index.js +5 -7
  73. package/lib/init/template/sqlite/index.js +8 -3
  74. package/lib/init/template/tiny-sample/index.js +16 -30
  75. package/lib/init/util/mvn.js +25 -1
  76. package/lib/init/util/projectReader.js +2 -7
  77. package/lib/init/util/template.js +7 -6
  78. package/lib/util/pruneAxiosErrors.js +22 -8
  79. package/lib/watch/node-watch.js +6 -1
  80. package/npm-shrinkwrap.json +2207 -384
  81. package/package.json +3 -3
  82. package/lib/init/template/auditlog/files/mta.yaml.hbs +0 -14
  83. package/lib/init/template/auditlog/files/package.json.hbs +0 -27
  84. package/lib/init/template/auditlog/index.js +0 -74
@@ -52,6 +52,7 @@ module.exports.csdl2openapi = function (
52
52
  {
53
53
  url: serviceRoot,
54
54
  servers: serversObject,
55
+ odataVersion: odataVersion,
55
56
  scheme: scheme = 'https',
56
57
  host: host = 'localhost',
57
58
  basePath: basePath = '/service-root',
@@ -61,6 +62,7 @@ module.exports.csdl2openapi = function (
61
62
  ) {
62
63
  // as preProcess below mutates the csdl, copy it before, to avoid side-effects on the caller side
63
64
  csdl = JSON.parse(JSON.stringify(csdl))
65
+ csdl.$Version = odataVersion ? odataVersion : '4.01'
64
66
  serviceRoot = serviceRoot || (scheme + '://' + host + basePath);
65
67
  const queryOptionPrefix = csdl.$Version <= '4.0' ? '$' : '';
66
68
  const typesToInline = {}; // filled in schema() and used in inlineTypes()
@@ -82,7 +84,7 @@ module.exports.csdl2openapi = function (
82
84
  openapi: '3.0.2',
83
85
  info: getInfo(csdl, entityContainer),
84
86
  'x-sap-api-type': 'ODATAV4',
85
- 'x-odata-version': '4.0',
87
+ 'x-odata-version': csdl.$Version,
86
88
  'x-sap-shortText': getShortText(csdl, entityContainer),
87
89
  servers: getServers(serviceRoot, serversObject),
88
90
  tags: entityContainer ? getTags(entityContainer) : {},
@@ -638,12 +640,12 @@ module.exports.csdl2openapi = function (
638
640
  */
639
641
  function operationCreate(pathItem, element, name, sourceName, targetName, target, level, restrictions) {
640
642
  const insertRestrictions = restrictions.InsertRestrictions || target && target[voc.Capabilities.InsertRestrictions] || {};
641
-
643
+ let countRestrictions = target && (target[voc.Capabilities.CountRestrictions]?.Countable === false); // count property will be added if CountRestrictions is false
642
644
  if (insertRestrictions.Insertable !== false) {
643
645
  const lname = pluralize.singular(splitName(name));
644
646
  const type = modelElement(element.$Type);
645
647
  pathItem.post = {
646
- summary: insertRestrictions.Description || operationSummary('Create', name, sourceName, level, true, true),
648
+ summary: insertRestrictions.Description || operationSummary('Creates', name, sourceName, level, true, true),
647
649
  tags: [sourceName],
648
650
  requestBody: {
649
651
  description: type && type[voc.Core.Description] || 'New ' + lname,
@@ -653,8 +655,8 @@ module.exports.csdl2openapi = function (
653
655
  schema: ref(element.$Type, SUFFIX.create),
654
656
  }
655
657
  }
656
- },
657
- responses: response(201, 'Created ' + lname, { $Type: element.$Type }, insertRestrictions.ErrorResponses),
658
+ },
659
+ responses: response(201, 'Created ' + lname, { $Type: element.$Type }, insertRestrictions.ErrorResponses, !countRestrictions),
658
660
  };
659
661
  if (insertRestrictions.LongDescription) pathItem.post.description = insertRestrictions.LongDescription;
660
662
  if (targetName && sourceName != targetName) pathItem.post.tags.push(targetName);
@@ -711,6 +713,7 @@ module.exports.csdl2openapi = function (
711
713
  const readRestrictions = restrictions.ReadRestrictions || targetRestrictions || {};
712
714
  const readByKeyRestrictions = readRestrictions.ReadByKeyRestrictions;
713
715
  let readable = true;
716
+ let countRestrictions = target && (target[voc.Capabilities.CountRestrictions]?.Countable === false);
714
717
  if (byKey && readByKeyRestrictions && readByKeyRestrictions.Readable !== undefined)
715
718
  readable = readByKeyRestrictions.Readable;
716
719
  else if (readRestrictions.Readable !== undefined)
@@ -722,11 +725,11 @@ module.exports.csdl2openapi = function (
722
725
  const lname = splitName(name);
723
726
  const collection = !byKey && element.$Collection;
724
727
  const operation = {
725
- summary: descriptions.Description || operationSummary('Retrieve', name, sourceName, level, element.$Collection, byKey),
728
+ summary: descriptions.Description || operationSummary('Retrieves', name, sourceName, level, element.$Collection, byKey),
726
729
  tags: [sourceName],
727
730
  parameters: [],
728
731
  responses: response(200, 'Retrieved ' + (byKey ? pluralize.singular(lname) : lname), { $Type: element.$Type, $Collection: collection },
729
- byKey ? readByKeyRestrictions?.ErrorResponses : readRestrictions?.ErrorResponses)
732
+ byKey ? readByKeyRestrictions?.ErrorResponses : readRestrictions?.ErrorResponses, !countRestrictions)
730
733
  };
731
734
  const deltaSupported = element[voc.Capabilities.ChangeTracking] && element[voc.Capabilities.ChangeTracking].Supported;
732
735
  if (!byKey && deltaSupported) {
@@ -1165,11 +1168,11 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1165
1168
  */
1166
1169
  function operationUpdate(pathItem, element, name, sourceName, target, level, restrictions, byKey) {
1167
1170
  const updateRestrictions = restrictions.UpdateRestrictions || target && target[voc.Capabilities.UpdateRestrictions] || {};
1168
-
1171
+ let countRestrictions = target && (target[voc.Capabilities.CountRestrictions]?.Countable === false);
1169
1172
  if (updateRestrictions.Updatable !== false) {
1170
1173
  const type = modelElement(element.$Type);
1171
1174
  const operation = {
1172
- summary: updateRestrictions.Description || operationSummary('Change', name, sourceName, level, element.$Collection, byKey),
1175
+ summary: updateRestrictions.Description || operationSummary('Changes', name, sourceName, level, element.$Collection, byKey),
1173
1176
  tags: [sourceName],
1174
1177
  requestBody: {
1175
1178
  description: type && type[voc.Core.Description] || 'New property values',
@@ -1180,7 +1183,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1180
1183
  }
1181
1184
  }
1182
1185
  },
1183
- responses: response(204, "Success", undefined, updateRestrictions.ErrorResponses),
1186
+ responses: response(204, "Success", undefined, updateRestrictions.ErrorResponses, !countRestrictions),
1184
1187
  };
1185
1188
  if (updateRestrictions.LongDescription) operation.description = updateRestrictions.LongDescription;
1186
1189
  customParameters(operation, updateRestrictions);
@@ -1202,12 +1205,12 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1202
1205
  */
1203
1206
  function operationDelete(pathItem, element, name, sourceName, target, level, restrictions, byKey) {
1204
1207
  const deleteRestrictions = restrictions.DeleteRestrictions || target && target[voc.Capabilities.DeleteRestrictions] || {};
1205
-
1208
+ let countRestrictions = target && (target[voc.Capabilities.CountRestrictions]?.Countable === false);
1206
1209
  if (deleteRestrictions.Deletable !== false) {
1207
1210
  pathItem.delete = {
1208
- summary: deleteRestrictions.Description || operationSummary('Delete', name, sourceName, level, element.$Collection, byKey),
1211
+ summary: deleteRestrictions.Description || operationSummary('Deletes', name, sourceName, level, element.$Collection, byKey),
1209
1212
  tags: [sourceName],
1210
- responses: response(204, "Success", undefined, deleteRestrictions.ErrorResponses),
1213
+ responses: response(204, "Success", undefined, deleteRestrictions.ErrorResponses, !countRestrictions),
1211
1214
  };
1212
1215
  if (deleteRestrictions.LongDescription) pathItem.delete.description = deleteRestrictions.LongDescription;
1213
1216
  customParameters(pathItem.delete, deleteRestrictions);
@@ -1423,7 +1426,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1423
1426
  const name = actionName.indexOf('.') === -1 ? actionName : nameParts(actionName).name;
1424
1427
  const pathItem = {
1425
1428
  post: {
1426
- summary: actionImport[voc.Core.Description] || overload[voc.Core.Description] || 'Invoke action ' + name,
1429
+ summary: actionImport[voc.Core.Description] || overload[voc.Core.Description] || 'Invokes action ' + name,
1427
1430
  tags: [overload[voc.Common.Label] || sourceName || 'Service Operations'],
1428
1431
  responses: overload.$ReturnType ? response(200, "Success", overload.$ReturnType, overload[voc.Capabilities.OperationRestrictions]?.ErrorResponses)
1429
1432
  : response(204, "Success", undefined, overload[voc.Capabilities.OperationRestrictions]?.ErrorResponses),
@@ -1479,7 +1482,6 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1479
1482
  const name = functionName.indexOf('.') === -1 ? functionName : nameParts(functionName).name;
1480
1483
  let parameters = overload.$Parameter || [];
1481
1484
  if (overload.$IsBound) parameters = parameters.slice(1);
1482
-
1483
1485
  const pathSegments = [];
1484
1486
  const params = [];
1485
1487
 
@@ -1534,7 +1536,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1534
1536
  const pathParameters = implicitAliases ? '' : '(' + pathSegments.join(',') + ')';
1535
1537
  const pathItem = {
1536
1538
  get: {
1537
- summary: functionImport[voc.Core.Description] || overload[voc.Core.Description] || 'Invoke function ' + name,
1539
+ summary: functionImport[voc.Core.Description] || overload[voc.Core.Description] || 'Invokes function ' + name,
1538
1540
  tags: [overload[voc.Common.Label] || sourceName || 'Service Operations'],
1539
1541
  parameters: prefixParameters.concat(params),
1540
1542
  responses: response(200, "Success", overload.$ReturnType, overload[voc.Capabilities.OperationRestrictions]?.ErrorResponses),
@@ -1558,7 +1560,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1558
1560
  const firstEntitySet = Object.keys(container).filter(child => isIdentifier(child) && container[child].$Collection)[0];
1559
1561
  paths['/$batch'] = {
1560
1562
  post: {
1561
- summary: batchSupport[voc.Core.Description] || 'Send a group of requests',
1563
+ summary: batchSupport[voc.Core.Description] || 'Sends a group of requests',
1562
1564
  description: (batchSupport[voc.Core.LongDescription] || 'Group multiple requests into a single request payload, see '
1563
1565
  + '[Batch Requests](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_BatchRequests).')
1564
1566
  + '\n\n*Please note that "Try it out" is not supported for this request.*',
@@ -1613,11 +1615,12 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1613
1615
  * @param {object} type Response type object
1614
1616
  * @param {array} errors Array of operation-specific status codes with descriptions
1615
1617
  */
1616
- function response(code, description, type, errors) {
1618
+ function response(code, description, type, errors, isCount = true) {
1617
1619
  const r = {};
1618
1620
  r[code] = {
1619
1621
  description: description
1620
1622
  };
1623
+ let CountPropertyObj = {[csdl.$Version > '4.0' ? '@count' : '@odata.count'] : ref('count')} ;
1621
1624
  if (code != 204) {
1622
1625
  const s = getSchema(type);
1623
1626
  r[code].content = {
@@ -1627,7 +1630,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1627
1630
  type: 'object',
1628
1631
  title: 'Collection of ' + nameParts(type.$Type || 'Edm.String').name,
1629
1632
  properties: {
1630
- [csdl.$Version > '4.0' ? '@count' : '@odata.count']: ref('count'),
1633
+ ...(isCount && CountPropertyObj),
1631
1634
  value: s
1632
1635
  }
1633
1636
  }
@@ -1806,14 +1809,20 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
1806
1809
  const isKey = keyMap(type);
1807
1810
  const required = Object.keys(isKey);
1808
1811
  const schemaProperties = {};
1809
-
1812
+ let isCount = true;
1813
+ if (csdl[qualifier]?.$Annotations) {
1814
+ const annotations = csdl[qualifier].$Annotations[`${qualifier}.EntityContainer/${name}`];
1815
+ if (annotations && annotations[voc.Capabilities.CountRestrictions] && annotations[voc.Capabilities.CountRestrictions]?.Countable === false) {
1816
+ isCount = false;
1817
+ }
1818
+ }
1810
1819
  const properties = propertiesOfStructuredType(type);
1811
1820
  Object.keys(properties).forEach(iName => {
1812
1821
  const property = properties[iName];
1813
1822
  if (suffix === SUFFIX.read) schemaProperties[iName] = getSchema(property);
1814
1823
  if ((Object.prototype.hasOwnProperty.call(property, '@Common.FieldControl')) && property['@Common.FieldControl'] === 'Mandatory') { required.push(iName) }
1815
1824
  if (property.$Kind == 'NavigationProperty') {
1816
- if (property.$Collection && suffix === "") {
1825
+ if (property.$Collection && suffix === "" && isCount === true) {
1817
1826
  schemaProperties[`${iName}@${csdl.$Version === '4.0' ? 'odata.' : ''}count`] = ref('count');
1818
1827
  }
1819
1828
  if (property[voc.Core.Permissions] != "Read" && !property[voc.Core.Computed] && property.$ContainsTarget) {
@@ -34,11 +34,15 @@ function _getOpenApi(csdl, options) {
34
34
  return openapi;
35
35
  }
36
36
 
37
- function toOpenApiOptions(csdl, csn, options={}) {
37
+ function toOpenApiOptions(csdl, csn, options = {}) {
38
38
  const result = {}
39
39
  for (const key in options) {
40
- if (/^openapi:(.*)/.test(key) && RegExp.$1)
41
- result[RegExp.$1] = options[key]
40
+ if (/^openapi:(.*)/.test(key) && RegExp.$1) {
41
+ result[RegExp.$1] = options[key];
42
+ }
43
+ else if (key === 'odata-version') {
44
+ result['odataVersion'] = options[key];
45
+ }
42
46
  }
43
47
  if (result.url) {
44
48
  result.url = result.url.replace(/\/*\$\{service-path\}/g, servicePath(csdl, csn))
@@ -0,0 +1,36 @@
1
+ const { join } = require('path')
2
+ const { mergeJSON } = require('../init/util/merge')
3
+ const { readJSON } = require('../util/fs')
4
+
5
+ module.exports = async function overlay4(schemaName, cwd = process.cwd()) {
6
+
7
+ // need to load @sap/cds from current cwd which might
8
+ // differ from initial cwd to get project specific cds version
9
+ const cds = require(require.resolve('@sap/cds', {
10
+ paths: [cwd, __dirname]
11
+ }))
12
+
13
+ // force cds.root to be project root
14
+ cds.root = cwd
15
+
16
+ // load defaults, throw err if schema not found
17
+ let result;
18
+ if (typeof cds.schema?.default4 === 'function') {
19
+ result = await cds.schema.default4(schemaName)
20
+ } else if (cds.env?.schemas?.[schemaName]) {
21
+ // backwards compatibility
22
+ result = await readJSON(cds.env.schemas[schemaName])
23
+ } else {
24
+ throw new Error(`cds ${cds.version} in ${cwd} does not support schema retrieval.`)
25
+ }
26
+
27
+ // optional, don't throw if file not found
28
+ try {
29
+ await mergeJSON(result, join(__dirname, 'schemas', schemaName))
30
+ result.description = result.description + ' - overlaid'
31
+ } catch (err) {
32
+ if (err.code !== 'ENOENT') throw err
33
+ }
34
+
35
+ return result
36
+ }
@@ -0,0 +1,101 @@
1
+ {
2
+ "title": "JSON schema for CDS-DK configuration",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "description": "This is a JSON schema representation for CDS project configuration",
5
+ "type": "object",
6
+ "additionalProperties": true,
7
+ "properties": {
8
+ "build": {
9
+ "type": "object",
10
+ "description": "Customize CDS build settings.",
11
+ "additionalProperties": true,
12
+ "properties": {
13
+ "target": {
14
+ "type": "string",
15
+ "description": "Specify the folder which contains generated build results. Defaults to './gen'.",
16
+ "format": "uri-reference"
17
+ },
18
+ "tasks": {
19
+ "type": "array",
20
+ "description": "Control which tasks 'cds build' will execute on your project modules. This is a typical task configuration: '\"tasks\": [{ \"for\": \"hana\"}];",
21
+ "uniqueItems": true,
22
+ "default": [
23
+ {}
24
+ ],
25
+ "items": {
26
+ "type": "object",
27
+ "additionalProperties": true,
28
+ "properties": {
29
+ "dest": {
30
+ "type": "string",
31
+ "description": "Optional: Define the destination folder for this build task, relative to build target folder. \nFor example: Destination defined as 'custom' results in an output written to 'gen/custom'.",
32
+ "format": "uri-reference"
33
+ },
34
+ "src": {
35
+ "type": "string",
36
+ "description": "Optional: Prefer defining 'cds.folders'. Use 'src' if you want it only to be valid for this specific build task, which excludes, for example, 'cds watch'.",
37
+ "format": "uri-reference"
38
+ },
39
+ "for": {
40
+ "type": "string",
41
+ "description": "Define the target technology for this build task.",
42
+ "minLength": 1,
43
+ "enum": [
44
+ "nodejs",
45
+ "java",
46
+ "hana",
47
+ "mtx-sidecar",
48
+ "mtx-extension",
49
+ "mtx",
50
+ "fiori",
51
+ "node-cf",
52
+ "java-cf"
53
+ ]
54
+ },
55
+ "options": {
56
+ "type": "object",
57
+ "description": "Optional: Set target technology specific options for this build task.",
58
+ "additionalProperties": true,
59
+ "properties": {
60
+ "model": {
61
+ "$ref": "#/$defs/foldersStringArray"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ },
70
+ "deploy": {
71
+ "type": "object",
72
+ "description": "Customize 'cds deploy' settings.",
73
+ "additionalProperties": true,
74
+ "properties": {
75
+ "no_save": {
76
+ "type": "boolean",
77
+ "description": "Do / don't update configuration in package.json.",
78
+ "default": true
79
+ }
80
+ }
81
+ }
82
+ },
83
+ "$defs": {
84
+ "foldersStringArray": {
85
+ "oneOf": [
86
+ {
87
+ "type": "string",
88
+ "format": "uri-reference"
89
+ },
90
+ {
91
+ "type": "array",
92
+ "uniqueItems": true,
93
+ "items": {
94
+ "type": "string",
95
+ "format": "uri-reference"
96
+ }
97
+ }
98
+ ]
99
+ }
100
+ }
101
+ }
@@ -7,7 +7,7 @@ const messages = require("./message").getMessages();
7
7
  const cds = require('../cds');
8
8
  const { fs, path, write, mkdirp, exists, read } = cds.utils;
9
9
  const cdsCompiler = require('..').compile.to;
10
- const md5 = require('md5');
10
+ const md5 = data => require('crypto').createHash('md5').update(data).digest('hex');
11
11
 
12
12
  let optionsMapping = {
13
13
  'keep-namespace': 'keepNamespace',
@@ -17,7 +17,7 @@ let optionsMapping = {
17
17
  };
18
18
 
19
19
  let apiOptions = ['includeNamespaces', 'keepNamespace'];
20
- let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force'];
20
+ let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force', 'config'];
21
21
 
22
22
  async function generateEDMX2JSON(edmx) {
23
23
  let cjson = convert.xml2json(edmx, {
@@ -148,6 +148,18 @@ async function _copyToSrvExternal(file, dst, cwd) {
148
148
  return file;
149
149
  }
150
150
 
151
+ async function isValidJsonObject(options){
152
+ let config;
153
+ try {
154
+ if (options.config) {
155
+ config = JSON.parse(options.config);
156
+ return config;
157
+ }
158
+ } catch (error) {
159
+ throw new Error(messages.SPECIFY_CONFIG);
160
+ }
161
+ }
162
+
151
163
  async function preProcess(file, options, cwd) {
152
164
  let srcFilePath = await isValidInputFile(path.resolve(cwd, file));
153
165
  if (options.as && !_supportedAsFormats().includes(options.as))
@@ -266,12 +278,12 @@ async function _generateChecksumValidate(dest, output, force) {
266
278
  return "/* checksum : " + currentChecksum + " */\n" + output;
267
279
  }
268
280
 
269
- async function _getResult(output, as, dest, force, version) {
281
+ async function _getResult(output, as, dest, force, kind) {
270
282
  let extension = dest.substring(dest.lastIndexOf(".") + 1);
271
283
  as = (as === "cds") ? "cdl" : as;
272
284
 
273
285
  // output filepath should simply contain .csn as extension
274
- if (version === 'rest' && ['swagger', 'openapi3'].includes(extension)) {
286
+ if (kind === 'rest' && ['swagger', 'openapi3'].includes(extension)) {
275
287
  dest = dest.replace('.' + extension, '');
276
288
  }
277
289
 
@@ -325,19 +337,19 @@ ${using}
325
337
  console.log(message);
326
338
  }
327
339
 
328
- async function _updatePackageJson(dest, services, version, cwd) {
340
+ async function _updatePackageJson(dest, services, kind, cwd, config) {
329
341
  const package_json = path.resolve(cwd, 'package.json');
330
342
  const conf = await exists(package_json) ? require(package_json) : {};
331
343
  const requires = ['cds', 'requires'].reduce((p, n) => p[n] || (p[n] = {}), conf);
332
- if (version !== 'rest') {
333
- version = (version === "V2") ? 'odata-v2' : 'odata';
344
+ if (kind !== 'rest') {
345
+ kind = (kind === "V2") ? 'odata-v2' : 'odata';
334
346
  }
335
347
  let package_json_updated = false;
336
348
  for (let service of services) {
337
349
  if (!requires[service]) {
338
350
  const initial_model = path.relative(cwd, dest);
339
351
  const model = isLinux() ? initial_model.replace(/\\/g, '/') : initial_model;
340
- cds.env.requires[service] = requires[service] = { kind: version, model };
352
+ cds.env.requires[service] = requires[service] = { kind: kind, model, ...config };
341
353
  await write(package_json, JSON.stringify(conf, null, ' '));
342
354
  package_json_updated = true;
343
355
  }
@@ -349,11 +361,12 @@ async function _updatePackageJson(dest, services, version, cwd) {
349
361
 
350
362
  async function postProcess(filePath, options, csn, cwd) {
351
363
  const services = _getServiceNames(csn);
364
+ let config = await isValidJsonObject(options);
352
365
  if (options.out) options.out = _validateAndComputeOutputFilePath(options.out, options.as, filePath);
353
- const version = options.inputFileVersion;
354
- const result = await _getResult(csn, options.as, options.out || filePath.replace(/\.[^.]+$/, ''), options.force, version);
366
+ const kind = options.inputFileKind;
367
+ const result = await _getResult(csn, options.as, options.out || filePath.replace(/\.[^.]+$/, ''), options.force, kind);
355
368
  const written = options.dry || await _write(result, services, cwd);
356
- const registered = options.dry || options.no_save || await _updatePackageJson(result[1].replace(/\.[^.]+$/, ''), services, version, cwd);
369
+ const registered = options.dry || options.no_save || await _updatePackageJson(result[1].replace(/\.[^.]+$/, ''), services, kind, cwd, config);
357
370
  if (options.dry) return console.log(result[0]);
358
371
  return Promise.all([written, registered]);
359
372
  }
@@ -91,7 +91,7 @@ async function cds_import_from_openapi(filepath, options = {}) {
91
91
  filepath = await common.isValidInputFile(path.resolve(process.cwd(), filepath));
92
92
  const src = await common.getContentFromFile(filepath);
93
93
  let csn = openapi.openAPI2csn(src);
94
- options.inputFileVersion = 'rest';
94
+ options.inputFileKind = 'rest';
95
95
  return csn;
96
96
  }
97
97
 
@@ -106,6 +106,6 @@ async function cds_import_from_asyncapi(filepath, options = {}) {
106
106
  filepath = await common.isValidInputFile(path.resolve(process.cwd(), filepath));
107
107
  const src = await common.getContentFromFile(filepath);
108
108
  let csn = asyncapi.asyncapi2csn(src);
109
- options.inputFileVersion = 'odata';
109
+ options.inputFileKind = 'odata';
110
110
  return csn;
111
111
  }
@@ -34,7 +34,9 @@ const messages = {
34
34
  BINARY_MAXLENGTH: 'WARNING: MaxLength for type Edm.Binary should not exceed 5000.',
35
35
  SCALE_GT_PRECISION: 'WARNING: Scale value should not be greater than Precision value.',
36
36
  FIXED_PRECISION_VARIABLE_SCALE: 'WARNING: Fixed Precision with Variable or Floating Scale is not supported in CDS.',
37
- NULLABLE_KEY: 'WARNING: Key element cannot be Nullable.'
37
+ NULLABLE_KEY: 'WARNING: Key element cannot be Nullable.',
38
+ COLLISION_DETECTED: `INFO: Element name collision detected. Adding suffix to affected type category.`,
39
+ SPECIFY_CONFIG: 'For --config option, please specify correct JSON Object.',
38
40
  };
39
41
 
40
42
  function getMessages() {
@@ -9,7 +9,7 @@ let common = require("../common");
9
9
  let versionInfo = require("../../../package.json").version;
10
10
  let Multimap = require("./util/MultiMap");
11
11
  const ignoreObjects = ["$Reference"]; // add all the objects that needs to be ignored for parsing.
12
- const { warn } = require("../../util/term");
12
+ const { warn, info } = require("../../util/term");
13
13
  const MetadataConverterFactory = require("./metadataconverter/MetadataConverterFactory");
14
14
 
15
15
  const edmPrimitiveTypes = [
@@ -1216,6 +1216,12 @@ function _parseAnnotations(schemaAnnotations, csnDefs, parserContext) {
1216
1216
  });
1217
1217
  }
1218
1218
 
1219
+ function _addSuffixForCollisionTypes(fqName, suffix) {
1220
+ console.log(info(`INFO: Due to collision in ${fqName} suffix "${suffix}" is added.`));
1221
+ const suffixedFqElementName = (fqName + suffix);
1222
+ return suffixedFqElementName;
1223
+ }
1224
+
1219
1225
  function _parseEntityContainer(csnDefs, entityContainerElements, parserContext) {
1220
1226
  const entityContainerElementNames = Object.keys(entityContainerElements);
1221
1227
  const redundantElementNames = [];
@@ -1241,16 +1247,26 @@ function _parseEntityContainer(csnDefs, entityContainerElements, parserContext)
1241
1247
  let fqDefRefName = _resolveAliasedElementName(definitionRefName, parserContext);
1242
1248
  let fqElementName = parserContext.primarySchema + "." + ecElement;
1243
1249
 
1244
- /**
1245
- * For now we don't support the collision between entitycontainer element name
1246
- * and any of the schema elemetents like entitytype, complextype, etc.
1247
- * TODO: In future we might have to support it.
1248
- */
1249
1250
  if (csnDefs[fqElementName] && csnDefs[fqElementName].kind !== kind) {
1250
- throw new Error(messages.ELEMENT_NAME_COLLISION + ecElement);
1251
+ console.log(info(messages.COLLISION_DETECTED));
1252
+ let suffixedFqElementName;
1253
+ // Check the type category that experienced the collision
1254
+ if (parserContext.complexTypes.includes(fqElementName)) {
1255
+ suffixedFqElementName = _addSuffixForCollisionTypes(fqElementName, "_ComplexType");
1256
+ } else if (parserContext.enumTypes.includes(fqElementName)) {
1257
+ suffixedFqElementName = _addSuffixForCollisionTypes(fqElementName, "_EnumType");
1258
+ } else if (parserContext.typeDefinitions.includes(fqElementName)) {
1259
+ suffixedFqElementName = _addSuffixForCollisionTypes(fqElementName, "_TypeDefinition");
1260
+ }
1261
+ // copy the definition with new suffixed name and delete the old definition from csnDefs
1262
+ csnDefs[suffixedFqElementName] = csnDefs[fqElementName];
1263
+ delete csnDefs[fqElementName];
1251
1264
  }
1252
1265
 
1253
1266
  if (fqElementName !== fqDefRefName) {
1267
+ if (csnDefs[fqElementName] && !parserContext.entityToEntitySetMap.get(fqElementName)) {
1268
+ fqElementName = _addSuffixForCollisionTypes(fqElementName, "_EntityType");
1269
+ }
1254
1270
  csnDefs[fqElementName] = Object.assign({}, csnDefs[fqDefRefName]);
1255
1271
  /**
1256
1272
  * Capture all the defintion reference element name which are no
package/lib/index.js CHANGED
@@ -18,3 +18,8 @@ cds.extend (cds.compile.to.constructor) .with (class {
18
18
  if (cds.compile.to.constructor.name === 'Object') { // not a class as in cds 7
19
19
  cds.compile.to.xsuaa = require('./compile/to-xsuaa')
20
20
  }
21
+
22
+ cds.schema = cds.schema || {} // backward compatibility
23
+ cds.extend (cds.schema) .with ( {
24
+ overlay4: require('./env/schema')
25
+ })
@@ -1,14 +1,10 @@
1
- const os = require('os');
2
-
3
- const MAVEN_ARCHETYPE_VERSION = '2.1.0';
4
-
5
- const constants = {
6
- IS_WIN: (os.platform() === 'win32'),
1
+ module.exports = {
2
+ IS_WIN: require('os').platform() === 'win32',
7
3
 
8
4
  COMMAND_INIT: 'init',
9
5
  COMMAND_ADD: 'add',
10
6
 
11
- MAVEN_ARCHETYPE_VERSION,
7
+ MAVEN_ARCHETYPE_VERSION: '2.3.0',
12
8
 
13
9
  OPTIONS: Object.freeze({
14
10
  JAVA: 'java',
@@ -28,8 +24,9 @@ const constants = {
28
24
  EXTENSIBILITY: 'extensibility',
29
25
  XSUAA: 'xsuaa',
30
26
  HANA: 'hana',
27
+ POSTGRES: 'postgres',
31
28
  SQLITE: 'sqlite',
32
- AUDITLOG: 'auditlog',
29
+ H2: 'h2',
33
30
  ENTERPRISE_MESSAGING: 'enterprise-messaging',
34
31
  ENTERPRISE_MESSAGING_SHARED: 'enterprise-messaging-shared',
35
32
  FILE_BASED_MESSAGING: 'file-based-messaging',
@@ -42,12 +39,15 @@ const constants = {
42
39
  LINT_GLOBAL: 'lint:global',
43
40
  LINT_DEV: 'lint:dev',
44
41
  HELM: 'helm',
45
- TYPER: 'typer'
42
+ TYPER: 'typer',
43
+ HTML5_REPO: 'html5-repo'
46
44
  }),
47
45
 
48
46
  PROJECT_TYPE: Object.freeze({ nodejs: 1, java: 2, unknown: 3 }),
49
47
 
50
48
  REGEX_JAVA_PACKAGE: /^[a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)*$/g,
49
+ // copied from mbt error message
50
+ REGEX_JAVA_VERSION: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/,
51
51
  REGEX_PROJECT_NAME: /[^0-9a-zA-Z_-]/g,
52
52
 
53
53
  URLS: Object.freeze({
@@ -57,11 +57,8 @@ const constants = {
57
57
  MAVEN_ARCHETYPE_HELP: `https://cap.cloud.sap/docs/java/development/#the-maven-archetype`,
58
58
  MAVEN_INSTALL_HELP: `https://maven.apache.org/install.html`,
59
59
  VSCODE: 'https://code.visualstudio.com/',
60
- VSCODE_NBVIEWER: 'https://marketplace.visualstudio.com/items?itemName=ms-python.python',
61
60
  VSCODE_ESLINT: 'https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint'
62
61
  }),
63
62
 
64
63
  PROJECT_FILES: ['package.json', 'pom.xml', '.cdsrc.json']
65
64
  }
66
-
67
- module.exports = constants;