@sap/cds-dk 6.5.2 → 6.6.1

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 (124) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/bin/activate.js +7 -0
  3. package/bin/add.js +1 -2
  4. package/bin/build/all.js +14 -9
  5. package/bin/cds.js +11 -8
  6. package/bin/compile/index.js +13 -3
  7. package/bin/env.js +16 -25
  8. package/bin/extend.js +8 -0
  9. package/bin/init.js +0 -3
  10. package/bin/login.js +3 -7
  11. package/bin/logout.js +2 -7
  12. package/bin/watch.js +4 -5
  13. package/lib/client/activate.js +1 -1
  14. package/lib/client/helper/errors.js +4 -1
  15. package/lib/client/params.js +4 -3
  16. package/lib/client/pull.js +31 -5
  17. package/lib/client/push.js +3 -3
  18. package/lib/client/settings_manager.js +6 -6
  19. package/lib/client/subscription.js +1 -1
  20. package/lib/compile/asyncapi/channels.js +22 -0
  21. package/lib/compile/asyncapi/components/messageTraits/index.js +89 -0
  22. package/lib/compile/asyncapi/components/messages/index.js +150 -0
  23. package/lib/compile/asyncapi/components/schemas/annotations.js +13 -0
  24. package/lib/compile/asyncapi/components/schemas/array.js +8 -0
  25. package/lib/compile/asyncapi/components/schemas/cache.js +14 -0
  26. package/lib/compile/asyncapi/components/schemas/definition.js +187 -0
  27. package/lib/compile/asyncapi/components/schemas/enum.js +16 -0
  28. package/lib/compile/asyncapi/components/schemas/examples.js +10 -0
  29. package/lib/compile/asyncapi/components/schemas/index.js +14 -0
  30. package/lib/compile/asyncapi/components/schemas/localized.js +29 -0
  31. package/lib/compile/asyncapi/components/schemas/primitiveElement.js +41 -0
  32. package/lib/compile/asyncapi/components/schemas/ref.js +45 -0
  33. package/lib/compile/asyncapi/components/schemas/utils.js +108 -0
  34. package/lib/compile/asyncapi/index.js +226 -0
  35. package/lib/compile/asyncapi/message.js +13 -0
  36. package/lib/compile/asyncapi/utils.js +27 -0
  37. package/lib/compile/index.js +1 -0
  38. package/lib/compile/openapi/csdl2openapi.js +42 -18
  39. package/lib/import/message.js +4 -1
  40. package/lib/import/odata/metadataconverter/MetadataConverter.js +8 -3
  41. package/lib/import/odata/v2parser.js +131 -50
  42. package/lib/import/odata/v4parser.js +292 -112
  43. package/lib/import/openapi/importOpenAPI.js +14 -14
  44. package/lib/init/constants.js +1 -1
  45. package/lib/init/index.js +11 -21
  46. package/lib/init/template/_merging/registry-mta.js +15 -26
  47. package/lib/init/template/approuter/files/package.json +2 -2
  48. package/lib/init/template/approuter/index.js +6 -12
  49. package/lib/init/template/auditlog/files/auditlog.yaml +4 -1
  50. package/lib/init/template/auditlog/index.js +23 -8
  51. package/lib/init/template/cf-manifest/index.js +4 -14
  52. package/lib/init/template/connectivity/files/connectivity-proxy-info.yaml +2 -6
  53. package/lib/init/template/connectivity/files/values.yaml.hbs +5 -8
  54. package/lib/init/template/connectivity/index.js +2 -9
  55. package/lib/init/template/data/index.js +0 -4
  56. package/lib/init/template/destinations/files/destination.yaml +4 -1
  57. package/lib/init/template/destinations/index.js +25 -10
  58. package/lib/init/template/enterprise-messaging/files/event-mesh.yaml +4 -1
  59. package/lib/init/template/enterprise-messaging/files/values.yaml +1 -2
  60. package/lib/init/template/enterprise-messaging/index.js +28 -20
  61. package/lib/init/template/extensibility/index.js +23 -31
  62. package/lib/init/template/hana/files/hana.yaml +4 -1
  63. package/lib/init/template/hana/index.js +44 -24
  64. package/lib/init/template/helm/chart/templates/_helpers.tpl +12 -0
  65. package/lib/init/template/helm/chart/values.root.schema.json +40 -0
  66. package/lib/init/template/helm/chart/values.schema.json +32 -69
  67. package/lib/init/template/helm/index.js +26 -16
  68. package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +13 -26
  69. package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +3 -3
  70. package/lib/init/template/helm/subcharts/content-deployment/templates/service-account.yaml +2 -0
  71. package/lib/init/template/helm/subcharts/content-deployment/templates/service-binding.yaml +3 -3
  72. package/lib/init/template/helm/subcharts/content-deployment/templating.md +37 -0
  73. package/lib/init/template/helm/subcharts/content-deployment/values.md +182 -185
  74. package/lib/init/template/helm/subcharts/content-deployment/values.schema.json +18 -22
  75. package/lib/init/template/helm/subcharts/content-deployment/values.yaml +2 -0
  76. package/lib/init/template/helm/subcharts/service-instance/Chart.yaml +5 -0
  77. package/lib/init/template/helm/subcharts/service-instance/templates/_helpers.tpl +65 -0
  78. package/lib/init/template/helm/subcharts/service-instance/templates/serviceinstance.yaml +23 -0
  79. package/lib/init/template/helm/subcharts/service-instance/templating.md +18 -0
  80. package/lib/init/template/helm/subcharts/service-instance/values-lint.yaml +2 -0
  81. package/lib/init/template/helm/subcharts/service-instance/values.md +186 -0
  82. package/lib/init/template/helm/subcharts/service-instance/values.schema.json +102 -0
  83. package/lib/init/template/helm/subcharts/service-instance/values.yaml +15 -0
  84. package/lib/init/template/html5-repo/files/html5-apps-deployer-configmap.yaml +2 -2
  85. package/lib/init/template/html5-repo/files/html5-apps-repo-host.yaml +4 -1
  86. package/lib/init/template/html5-repo/index.js +30 -21
  87. package/lib/init/template/java/index.js +3 -6
  88. package/lib/init/template/kibana-logging/index.js +7 -10
  89. package/lib/init/template/lint/index.js +2 -3
  90. package/lib/init/template/mta/files/mta.yaml.hbs +4 -2
  91. package/lib/init/template/mta/index.js +7 -11
  92. package/lib/init/template/mtx/index.js +0 -5
  93. package/lib/init/template/multitenancy/files/java/package.json +16 -7
  94. package/lib/init/template/multitenancy/files/mta.yaml.hbs +11 -3
  95. package/lib/init/template/multitenancy/files/saas-registry-secret.yaml +9 -0
  96. package/lib/init/template/multitenancy/files/saas-registry.yaml +4 -17
  97. package/lib/init/template/multitenancy/files/service-manager.yaml +4 -1
  98. package/lib/init/template/multitenancy/files/values.yaml.hbs +15 -3
  99. package/lib/init/template/multitenancy/index.js +56 -31
  100. package/lib/init/template/nodejs/index.js +4 -7
  101. package/lib/init/template/notebook/index.js +1 -3
  102. package/lib/init/template/pipeline/index.js +2 -5
  103. package/lib/init/template/samples/index.js +6 -11
  104. package/lib/init/template/templateBase.js +10 -17
  105. package/lib/init/template/toggles/index.js +2 -6
  106. package/lib/init/template/xsuaa/files/values.yaml.hbs +0 -1
  107. package/lib/init/template/xsuaa/files/xsuaa.yaml +4 -1
  108. package/lib/init/template/xsuaa/index.js +27 -23
  109. package/lib/init/types.d.ts +0 -81
  110. package/lib/init/util/merge.js +23 -25
  111. package/lib/init/util/mvnArchetypeUtil.js +34 -2
  112. package/lib/init/util/projectReader.js +27 -24
  113. package/lib/lint/Linter.js +31 -13
  114. package/lib/watch/livereload-server.js +29 -17
  115. package/lib/watch/node-watch.js +51 -49
  116. package/npm-shrinkwrap.json +548 -467
  117. package/package.json +4 -4
  118. package/readme.md +5 -0
  119. package/lib/init/template/connectivity/files/connectivity-binding.yaml +0 -9
  120. package/lib/init/template/connectivity/files/connectivity.yaml +0 -1
  121. package/lib/init/template/multitenancy/files/xsuaa.yaml +0 -1
  122. /package/lib/init/template/hana/files/{chart.yaml → hana-deployer.yaml} +0 -0
  123. /package/lib/init/template/html5-repo/files/{chart.yaml → html5-apps-deployer.yaml} +0 -0
  124. /package/lib/init/template/multitenancy/files/{chart.yaml → sidecar.yaml} +0 -0
@@ -0,0 +1,22 @@
1
+ const { getEventName } = require('./utils');
2
+
3
+ function getChannel(eventName) {
4
+ return {
5
+ subscribe: {
6
+ message: {
7
+ $ref: "#/components/messages/" + eventName
8
+ }
9
+ }
10
+ }
11
+ }
12
+
13
+ module.exports = function getChannels(definitions, events) {
14
+ let channels = {};
15
+
16
+ events.forEach(event => {
17
+ let eventName = getEventName(event, definitions[event]);
18
+ channels[eventName] = getChannel(eventName);
19
+ });
20
+
21
+ return channels;
22
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Get a map of message traits.
3
+ */
4
+ module.exports = function getMessageTraits() {
5
+
6
+ return {
7
+ "CloudEventsContext.v1": {
8
+ "headers": {
9
+ "type": "object",
10
+ "properties": {
11
+ "id": {
12
+ "description": "Identifies the event.",
13
+ "type": "string",
14
+ "examples": [
15
+ "6925d08e-bc19-4ad7-902e-bd29721cc69b"
16
+ ]
17
+ },
18
+ "specversion": {
19
+ "description": "The version of the CloudEvents specification which the event uses.",
20
+ "type": "string",
21
+ "const": "1.0"
22
+ },
23
+ "source": {
24
+ "description": "Identifies the instance the event originated in.",
25
+ "type": "string",
26
+ "format": "uri-reference",
27
+ "examples": [
28
+ "/default/sap.s4.beh/ER9CLNT001",
29
+ "/eu/sap.billing.sb/91dec60d-9757-4e2c-b9e5-21da10016fe9"
30
+ ]
31
+ },
32
+ "type": {
33
+ "description": "Describes the type of the event related to the source the event originated in.",
34
+ "type": "string",
35
+ "examples": [
36
+ "sap.dsc.FreightOrder.Arrived.v1",
37
+ "sap.billing.sb.Subscription.Canceled.v1"
38
+ ]
39
+ },
40
+ "subject": {
41
+ "description": "Describes the subject of the event in the context of the source the event originated in (e.g., the id of the business object the event is about).",
42
+ "type": "string",
43
+ "examples": [
44
+ "ce307052-75a0-4a8f-a961-ebf21669bb80",
45
+ "urn:epc:tag:sgtin-96:1.7332402.026591.1234567890"
46
+ ]
47
+ },
48
+ "datacontenttype": {
49
+ "description": "Content type of the event data.",
50
+ "type": "string",
51
+ "const": "application/json"
52
+ },
53
+ "dataschema": {
54
+ "description": "Identifies the schema that the event data adheres to.",
55
+ "type": "string",
56
+ "format": "uri",
57
+ "examples": [
58
+ "http://example.com/event/sap.billing.sb.Subscription.Canceled/v1.2.0"
59
+ ]
60
+ },
61
+ "time": {
62
+ "description": "Timestamp of when the occurrence happened.",
63
+ "format": "date-time",
64
+ "type": "string",
65
+ "examples": [
66
+ "2018-04-05T17:31:00Z"
67
+ ]
68
+ }
69
+ },
70
+ "required": [
71
+ "id",
72
+ "source",
73
+ "specversion",
74
+ "type"
75
+ ],
76
+ "patternProperties": {
77
+ "^xsap[a-z0-9]+$": {
78
+ "description": "Application defined custom extension context attributes.",
79
+ "type": [
80
+ "boolean",
81
+ "integer",
82
+ "string"
83
+ ]
84
+ }
85
+ }
86
+ }
87
+ }
88
+ };
89
+ }
@@ -0,0 +1,150 @@
1
+ const { getEventName } = require('../../utils');
2
+
3
+ const annotationMapping = {
4
+ 'EventSpecVersion': 'x-sap-event-spec-version',
5
+ 'EventSource': 'x-sap-event-source',
6
+ 'EventSourceParams': 'x-sap-event-source-parameters',
7
+ 'EventCharacteristics': 'x-sap-event-characteristics',
8
+ 'EventStateInfo': 'x-sap-stateInfo',
9
+ 'EventSchemaVersion': 'x-sap-event-version'
10
+ };
11
+
12
+ /**
13
+ * Get header properties from definition.
14
+ */
15
+ function getHeaderProperties(name) {
16
+ return { type: { const: name } };
17
+ }
18
+
19
+ function readAnnotations(definition, presets) {
20
+ let resObj = {};
21
+
22
+ for (const [key, value] of Object.entries(definition)) {
23
+ if (key.startsWith('@AsyncAPI')) {
24
+ // get annotation value after @AsyncAPI
25
+ const annotationProperties = key.split('@AsyncAPI.')[1];
26
+ const keys = annotationProperties.split('.');
27
+
28
+ // convert annotation property (ex: EventSource) to asyncapi property (ex: x-sap-event-source)
29
+ // if annotation property isn't present in map then ignore the property
30
+ if (annotationMapping[keys[0]] === undefined) continue;
31
+
32
+ const asyncapiProperty = annotationMapping[keys[0]];
33
+
34
+ // if there's no nesting then just set the value
35
+ if (keys.length === 1) {
36
+ resObj[asyncapiProperty] = value;
37
+ } else {
38
+ if (resObj[asyncapiProperty] === undefined) {
39
+ resObj[asyncapiProperty] = {};
40
+ }
41
+
42
+ let node = resObj[asyncapiProperty];
43
+
44
+ // traverse the annotation property and define the objects if they're not defined
45
+ for (let nestedIndex = 1; nestedIndex < keys.length-1; nestedIndex++) {
46
+ const nestedElement = keys[nestedIndex];
47
+ if (node[nestedElement] === undefined) {
48
+ node[nestedElement] = {};
49
+ }
50
+ node = node[nestedElement];
51
+ }
52
+
53
+ // set value annotation property
54
+ node[keys[keys.length-1]] = value;
55
+ }
56
+ }
57
+ }
58
+
59
+ for (const [key, value] of Object.entries(presets)) {
60
+ if (resObj[key] === undefined) {
61
+ resObj[key] = value;
62
+ }
63
+ }
64
+
65
+ addDefaults(resObj);
66
+ return resObj;
67
+ }
68
+
69
+ function addDefaults(obj) {
70
+ const defaults = {
71
+ 'x-sap-event-source': '/{region}/{applicationNamespace}/{instanceId}',
72
+ 'x-sap-event-source-parameters': {
73
+ "region": {
74
+ "description": "The regional context of the application.",
75
+ "schema": {
76
+ "type": "string"
77
+ }
78
+ },
79
+ "applicationNamespace": {
80
+ "description": "The registered namespace of the application.",
81
+ "schema": {
82
+ "type": "string"
83
+ }
84
+ },
85
+ "instanceId": {
86
+ "description": "The instance id (tenant, installation, ...) of the application.",
87
+ "schema": {
88
+ "type": "string"
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ for (const [key, value] of Object.entries(defaults)) {
95
+ if (!obj[key]) {
96
+ obj[key] = value;
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Get message for the event definition.
103
+ */
104
+ function eventToMessage(definition, name, presets) {
105
+ let obj = readAnnotations(definition, presets);
106
+
107
+ let messageObj = {
108
+ name,
109
+ headers: {
110
+ type: 'object',
111
+ properties: getHeaderProperties(name)
112
+ },
113
+ payload: {
114
+ $ref: `#/components/schemas/${name}`
115
+ },
116
+ traits: [
117
+ {
118
+ $ref: '#/components/messageTraits/CloudEventsContext.v1'
119
+ }
120
+ ]
121
+ }
122
+
123
+ const message = { ...obj, ...messageObj};
124
+
125
+ return message;
126
+ }
127
+
128
+ /**
129
+ * Event definitions of one CSN to messages.
130
+ */
131
+ function entriesToMessages(definitions, events, presets) {
132
+ const messages = {};
133
+
134
+ events.forEach(event => {
135
+ let name = getEventName(event, definitions[event]);
136
+ messages[name] = eventToMessage(definitions[event], name, presets);
137
+ });
138
+
139
+ return messages;
140
+ }
141
+
142
+ /**
143
+ * Combining the definition objects from CSN into one schema
144
+ */
145
+ module.exports = function definitionsToMessages(definitions, events, presets) {
146
+ const messages = {};
147
+
148
+ Object.assign(messages, entriesToMessages(definitions, events, presets));
149
+ return messages;
150
+ }
@@ -0,0 +1,13 @@
1
+ module.exports = function addAnnotations(definition, object) {
2
+ if (typeof (definition['@title']) === 'string') {
3
+ object.title = definition['@title'];
4
+ }
5
+
6
+ if (typeof (definition['@description']) === 'string') {
7
+ object.description = definition['@description'];
8
+ } else if (typeof definition.doc === 'string') {
9
+ object.description = definition.doc.replace(/\n/g, ' ');
10
+ }
11
+
12
+ return object;
13
+ }
@@ -0,0 +1,8 @@
1
+ const { getBaseTypeStructure } = require('./utils');
2
+
3
+ module.exports = function getArrayOfType(type) {
4
+ const array = getBaseTypeStructure('array');
5
+ array.items = type;
6
+
7
+ return array;
8
+ }
@@ -0,0 +1,14 @@
1
+ function cacheAndReturn(schemaCache, type, schema) {
2
+ schemaCache[type] = schema;
3
+
4
+ return schema;
5
+ }
6
+
7
+ function getCache(schemaCache, type) {
8
+ return schemaCache[type];
9
+ }
10
+
11
+ module.exports = {
12
+ cacheAndReturn,
13
+ getCache
14
+ }
@@ -0,0 +1,187 @@
1
+ const { addEnum } = require('./enum');
2
+ const schemaUtils = require('./utils');
3
+ const { cacheAndReturn, getCache } = require('./cache');
4
+ const { getOwnValue } = require('../../utils');
5
+ const { toLocalizedArray } = require('./localized');
6
+ const addAnnotations = require('./annotations');
7
+ const primitiveElementToSchema = require('./primitiveElement');
8
+ const getArrayOfType= require('./array');
9
+ const { followRefRecursive } = require('./ref');
10
+
11
+ function definitionToSchema(eventDefinition, definitions, schemaCache) {
12
+ const definition = definitions[eventDefinition];
13
+
14
+ if (schemaUtils.isStructured(definition)) {
15
+ return addAnnotations(definition, elementsToSchema(schemaCache, definitions, definition));
16
+ }
17
+
18
+ return addAnnotations(definition, elementToSchema(schemaCache, definitions, definition));
19
+ }
20
+
21
+ function elementsToSchema(schemaCache, definitions, entry, nullable) {
22
+ if (!schemaUtils.isStructured(entry)) {
23
+ return elementToSchema(schemaCache, definitions, entry, nullable);
24
+ }
25
+
26
+ const required = [];
27
+ const object = schemaUtils.getBaseTypeStructure("object");
28
+ for (const [name, element] of Object.entries(entry.elements)) {
29
+ if (getOwnValue(element, "key")
30
+ || getOwnValue(element, "@mandatory")
31
+ || (getOwnValue(element, "@Common.FieldControl") && getOwnValue(element["@Common.FieldControl"], "#") === 'Mandatory')
32
+ ) {
33
+ required.push(name);
34
+ }
35
+
36
+ if (!schemaUtils.elementIsRelevant(name, element)) {
37
+ continue;
38
+ }
39
+
40
+ if (!object.properties) {
41
+ object.properties = {};
42
+ }
43
+
44
+ object.properties[name] = addAnnotations(element, elementToSchema(schemaCache, definitions, element));
45
+ }
46
+
47
+ if (required.length) {
48
+ object.required = required;
49
+ }
50
+
51
+ return object;
52
+ }
53
+
54
+ function elementToSchema(schemaCache, definitions, entry) {
55
+ /*
56
+ * Process reuse types as first step.
57
+ * A structured type will be preprocessed and 'elements' will exists as inherited prototype.
58
+ * If type is processed first, the reuse will be cached.
59
+ * If the inherited elements would be processed instead, each reuse would process them again.
60
+ */
61
+ if (typeof entry.type === "string" && definitions[entry.type]) {
62
+ // has been processed before
63
+ if (schemaCache[entry.type]) {
64
+ return getCache(schemaCache, entry.type);
65
+ }
66
+
67
+ return cacheAndReturn(schemaCache, entry.type,
68
+ elementToSchema(schemaCache, definitions, definitions[entry.type])
69
+ );
70
+ }
71
+
72
+ // Process anonymous attribute object structures like "deep: {deeper: {attr: String;};};"
73
+ if (schemaUtils.isStructured(entry)) {
74
+ return elementsToSchema(schemaCache, definitions, entry);
75
+ }
76
+
77
+ // Arrayed primitives and structured objects without keyed property
78
+ if (schemaUtils.isManyEntry(entry)) {
79
+ return manyToSchema(schemaCache, definitions, entry);
80
+ }
81
+
82
+ // Definition > element references
83
+ if (schemaUtils.isRefEntry(entry)) {
84
+ return refToSchema(schemaCache, definitions, entry);
85
+ }
86
+
87
+ // Associations to (root) entities and code lists
88
+ if (schemaUtils.isAssociation(entry)) {
89
+ return associationToSchema(schemaCache, definitions, entry);
90
+ }
91
+
92
+ // Compositions of aspect or entity
93
+ if (schemaUtils.isComposition(entry)) {
94
+ return compositionToSchema(schemaCache, definitions, entry);
95
+ }
96
+
97
+ //A localized element is a primitive at CSN and an array of objects at JSON schema (all translations)
98
+ if (entry.localized === true) {
99
+ return toLocalizedArray(entry);
100
+ }
101
+
102
+ const schema = addAnnotations(entry, primitiveElementToSchema(entry));
103
+
104
+ if (schemaUtils.isDefault(entry)) {
105
+ schemaUtils.addDefaultValue(entry, schema);
106
+ }
107
+
108
+ if (schemaUtils.isEnum(entry)) {
109
+ addEnum(entry, schema);
110
+ }
111
+
112
+ return schema;
113
+ }
114
+
115
+ function associationToSchema(schemaCache, definitions, entry) {
116
+ let associationTargetDefinition = JSON.parse(JSON.stringify(definitions[entry.target]));
117
+ Object.keys(associationTargetDefinition.elements).forEach(element => {
118
+ if (associationTargetDefinition.elements[element].key === undefined) {
119
+ delete associationTargetDefinition.elements[element];
120
+ }
121
+ });
122
+
123
+ if (schemaUtils.isToManyAssociation(entry)) {
124
+ return getArrayOfType(elementsToSchema(schemaCache, definitions, associationTargetDefinition));
125
+ } else {
126
+ return elementsToSchema(schemaCache, definitions, associationTargetDefinition);
127
+ }
128
+ }
129
+
130
+ function manyToSchema(schemaCache, definitions, entry) {
131
+ return getArrayOfType(
132
+ schemaUtils.isStructured(entry.items)
133
+ ? elementsToSchema(schemaCache, definitions, entry.items)
134
+ : elementToSchema(schemaCache, definitions,
135
+ // if entry.items.type can be found at definitions, it is a reuse type
136
+ definitions[entry.items.type] ? definitions[entry.items.type] : (entry.items)
137
+ )
138
+ );
139
+ }
140
+
141
+ function compositionToSchema(schemaCache, definitions, entry) {
142
+ if (schemaUtils.isStructured(entry.targetAspect)) {
143
+ const objectType = elementsToSchema(schemaCache, definitions, entry.targetAspect);
144
+ return schemaUtils.isToMany(entry) ? getArrayOfType(objectType) : objectType;
145
+ }
146
+ // Composition of aspects might have a target towards a generated entity
147
+ const target = entry.targetAspect || entry.target;
148
+ // An aspect is a reuse element, which might be used at more than one place with different cardinality
149
+ const cacheKey = `${target}${schemaUtils.isToMany(entry) ? 'Many' : 'One'}`;
150
+
151
+ /*
152
+ * Check if the target entity has been processed as association target before.
153
+ */
154
+ if (schemaCache[cacheKey]) {
155
+ return getCache(schemaCache, cacheKey);
156
+ }
157
+
158
+ let objectType;
159
+ if (schemaUtils.isStructured(definitions[target])) {
160
+ objectType = elementsToSchema(schemaCache, definitions, definitions[target]);
161
+ } else {
162
+ objectType = elementToSchema(schemaCache, definitions, target);
163
+ }
164
+
165
+ return cacheAndReturn(schemaCache, cacheKey,
166
+ schemaUtils.isToMany(entry) ? getArrayOfType(objectType) : objectType
167
+ );
168
+ }
169
+
170
+ function refToSchema(schemaCache, definitions, entry) {
171
+ const refKey = entry.type.ref.join('.');
172
+
173
+ if (schemaCache[refKey]) {
174
+ return getCache(schemaCache, refKey);
175
+ }
176
+
177
+ return cacheAndReturn(
178
+ schemaCache,
179
+ refKey,
180
+ elementToSchema(schemaCache, definitions, followRefRecursive(definitions, entry.type))
181
+ );
182
+ }
183
+
184
+ module.exports = {
185
+ definitionToSchema,
186
+ elementToSchema
187
+ }
@@ -0,0 +1,16 @@
1
+ const schemaUtils = require('./utils');
2
+
3
+ function addEnum(entry, schema) {
4
+ if (entry.kind === 'type') {
5
+ // eslint-disable-next-line no-unused-vars
6
+ schema.enum = Object.entries(entry.enum).map(([key, value]) => {
7
+ return (schemaUtils.isVal(entry) ? entry.val : key)
8
+ });
9
+ } else {
10
+ schema.enum = Object.keys(entry.enum);
11
+ }
12
+ }
13
+
14
+ module.exports = {
15
+ addEnum
16
+ }
@@ -0,0 +1,10 @@
1
+ const Examples = {
2
+ UUID_EXAMPLE: 'e78f1eb8-ada8-49b0-8c8f-a5d316e82952',
3
+ PARTIAL_TIME_EXAMPLE:'20:54:21',
4
+ DATE_EXAMPLE: '2017-02-14',
5
+ DATE_TIME_EXAMPLE: '2017-02-14T20:54:21+00:00',
6
+ INT_64_EXAMPLE: '3155378975999999999',
7
+ DECIMAL_EXAMPLE: '3.141592653589793238462643383279',
8
+ }
9
+
10
+ module.exports = Examples
@@ -0,0 +1,14 @@
1
+ const { definitionToSchema } = require('./definition');
2
+ const { getEventName } = require('../../utils');
3
+
4
+ module.exports = function csnToJSONSchema(definitions, events) {
5
+ let schemaCache = {};
6
+ let schema = {};
7
+
8
+ events.forEach(event => {
9
+ const eventName = getEventName(event, definitions[event]);
10
+ schema[eventName] = definitionToSchema(event, definitions, schemaCache);
11
+ });
12
+
13
+ return schema;
14
+ }
@@ -0,0 +1,29 @@
1
+ const primitiveElementToSchema = require('./primitiveElement');
2
+ const { getBaseTypeStructure } = require('./utils');
3
+
4
+ function getPatternStructure(pattern, example) {
5
+ var schema = getBaseTypeStructure('string');
6
+ schema.pattern = pattern;
7
+ if (example) {
8
+ schema.examples = [example];
9
+ }
10
+ return schema;
11
+ }
12
+
13
+ function toLocalizedArray(localizedElement) {
14
+ return {
15
+ type: "array",
16
+ items: {
17
+ type: "object",
18
+ properties: {
19
+ lang: getPatternStructure('^[a-z]{2}(?:-[A-z]{2})?$'),
20
+ content: primitiveElementToSchema(localizedElement)
21
+ },
22
+ required: ['lang', 'content']
23
+ }
24
+ }
25
+ }
26
+
27
+ module.exports = {
28
+ toLocalizedArray
29
+ }
@@ -0,0 +1,41 @@
1
+ const Examples = require('./examples');
2
+ const { getBaseTypeStructure, getFormatStructure, toString } = require('./utils');
3
+
4
+ module.exports = function primitiveElementToSchema(entry) {
5
+ switch(entry.type) {
6
+ case 'cds.Boolean':
7
+ return getBaseTypeStructure("boolean");
8
+ case 'cds.Integer':
9
+ return getBaseTypeStructure("integer");
10
+ case 'cds.Double':
11
+ return getBaseTypeStructure("number");
12
+ case 'cds.UUID':
13
+ return getFormatStructure("uuid", Examples.UUID_EXAMPLE);
14
+ case 'cds.Integer64':
15
+ return getFormatStructure("int64", Examples.INT_64_EXAMPLE);
16
+ case 'cds.Decimal': {
17
+ let schema = getFormatStructure("decimal", Examples.DECIMAL_EXAMPLE);
18
+ if (entry.precision) {
19
+ schema['x-sap-precision'] = entry.precision;
20
+ }
21
+ if (entry.scale) {
22
+ schema['x-sap-scale'] = entry.scale;
23
+ }
24
+ return schema;
25
+ }
26
+ case 'cds.Date':
27
+ return getFormatStructure("date", Examples.DATE_EXAMPLE);
28
+ case 'cds.Time':
29
+ return getFormatStructure("partial-time", Examples.PARTIAL_TIME_EXAMPLE);
30
+ case 'cds.DateTime':
31
+ case 'cds.Timestamp':
32
+ return getFormatStructure("date-time", Examples.DATE_TIME_EXAMPLE);
33
+ case 'cds.String':
34
+ case 'cds.LargeString':
35
+ case 'cds.Binary':
36
+ case 'cds.LargeBinary':
37
+ return toString(entry);
38
+ default:
39
+ throw new Error(`Unsupported type ${entry.type}`);
40
+ }
41
+ }
@@ -0,0 +1,45 @@
1
+ const { isElements, isRefEntry } = require('./utils');
2
+
3
+ function followRefRecursive(definitions, ref) {
4
+ const element = followRef(definitions, ref);
5
+
6
+ if (isRefEntry(element)) {
7
+ return followRefRecursive(definitions, element.type);
8
+ }
9
+
10
+ return element;
11
+ }
12
+
13
+ function followRef(definitions, { ref }) {
14
+ const definition = definitions[ref[0]];
15
+
16
+ if (!definition) {
17
+ throw new Error(`Cannot find definition '${ref[0]}'`);
18
+ }
19
+
20
+ if (!isElements(definition.elements)) {
21
+ throw new Error(`'${ref[0]}' is not a structured type`);
22
+ }
23
+
24
+ let pointer = definition.elements;
25
+ let element;
26
+
27
+ // Navigate down to the last elements section
28
+ for (let elementIndex = 1; elementIndex < ref.length; elementIndex++) {
29
+ element = pointer[ref[elementIndex]];
30
+
31
+ if (element && isElements(element.elements)) {
32
+ pointer = element.elements;
33
+ }
34
+ }
35
+
36
+ if (!element) {
37
+ throw new Error(`Cannot resolve reference '${ref.join(':')}'`);
38
+ }
39
+
40
+ return element;
41
+ }
42
+
43
+ module.exports = {
44
+ followRefRecursive
45
+ }