@sap/cds-dk 4.8.2 → 4.9.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.
- package/CHANGELOG.md +37 -0
- package/bin/activate.js +8 -7
- package/bin/bind.js +12 -12
- package/bin/build/all.js +3 -5
- package/bin/build/index.js +1 -1
- package/bin/cds.js +1 -1
- package/bin/deploy/index.js +7 -1
- package/bin/deploy/to-hana.js +5 -4
- package/bin/deploy/to-sqlite.js +2 -1
- package/bin/extend.js +5 -5
- package/bin/help.js +1 -0
- package/bin/import.js +45 -31
- package/bin/login.js +5 -6
- package/bin/logout.js +2 -2
- package/bin/parse.js +19 -0
- package/lib/bind/bindingUtil.js +41 -49
- package/lib/bind/cfKeyProvider.js +9 -17
- package/lib/bind/userCdsrcJsonStorageProvider.js +1 -0
- package/lib/client/activate.js +3 -2
- package/lib/client/auth_manager.js +1 -0
- package/lib/client/extend.js +6 -6
- package/lib/client/helper/fs_helper.js +8 -8
- package/lib/client/settings_manager.js +12 -9
- package/lib/compile/openapi/csdl2openapi.js +213 -165
- package/lib/compile/openapi/index.js +1 -2
- package/lib/compile/to-xsuaa.js +1 -1
- package/lib/import/index.js +22 -15
- package/lib/import/message.js +3 -1
- package/lib/import/utils/MetadataConverter.js +1 -1
- package/lib/import/v2parser.js +112 -56
- package/lib/import/v4parser.js +149 -98
- package/lib/init/constants.js +6 -2
- package/lib/init/index.js +3 -2
- package/lib/init/template/_merging/existences.js +80 -4
- package/lib/init/template/approuter/files/cds.cdsrc.json +7 -0
- package/lib/init/template/approuter/files/cds.cdsrc.json.hbs +9 -0
- package/lib/init/template/approuter/files/cds.package.json +9 -0
- package/lib/init/template/approuter/files/cds.package.json.hbs +11 -0
- package/lib/init/template/approuter/files/index.html +1 -0
- package/lib/init/template/approuter/files/mta.yaml.hbs +35 -21
- package/lib/init/template/approuter/files/package.json +3 -0
- package/lib/init/template/approuter/files/xs-app.json.hbs +19 -0
- package/lib/init/template/approuter/index.js +47 -18
- package/lib/init/template/auditlog/index.js +5 -5
- package/lib/init/template/hana/files/java/cdsrc.json.hbs +7 -0
- package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +12 -0
- package/lib/init/template/hana/files/mta.yaml.hbs +10 -17
- package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +9 -0
- package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +14 -0
- package/lib/init/template/hana/files/nodejs/dependencies.package.json +1 -1
- package/lib/init/template/hana/index.js +59 -85
- package/lib/init/template/java/index.js +5 -2
- package/lib/init/template/kibana-logging/files/cds.package.json +7 -0
- package/lib/init/template/kibana-logging/files/cds.profile.package.json.hbs +9 -0
- package/lib/init/template/kibana-logging/files/mta.yaml.hbs +13 -0
- package/lib/init/template/kibana-logging/index.js +64 -0
- package/lib/init/template/mta/files/mta.yaml.hbs +3 -8
- package/lib/init/template/mta/index.js +8 -2
- package/lib/init/template/mtx/files/cds.package.json +0 -12
- package/lib/init/template/mtx/files/cds.package.json.hbs +14 -0
- package/lib/init/template/mtx/files/java/.cdsrc.json +17 -0
- package/lib/init/template/mtx/files/java/package.json +43 -0
- package/lib/init/template/mtx/files/java/server.js +30 -0
- package/lib/init/template/mtx/files/mta.yaml.hbs +6 -6
- package/lib/init/template/mtx/index.js +41 -22
- package/lib/init/template/templateBase.js +4 -1
- package/lib/init/template/xsuaa/files/cds.cdsrc.json +7 -0
- package/lib/init/template/xsuaa/files/cds.cdsrc.json.hbs +9 -0
- package/lib/init/template/xsuaa/files/cds.package.json +1 -1
- package/lib/init/template/xsuaa/files/cds.package.json.hbs +11 -0
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +2 -2
- package/lib/init/template/xsuaa/index.js +43 -27
- package/lib/init/types.d.ts +43 -19
- package/lib/init/util/fsUtil.js +15 -4
- package/lib/init/util/projectReader.js +21 -18
- package/lib/init/util/templateUtil.js +78 -28
- package/lib/util/exec.js +2 -2
- package/lib/watch/livereload-server.js +3 -0
- package/lib/watch/node-watch.js +8 -1
- package/npm-shrinkwrap.json +88 -82
- package/package.json +3 -3
- package/lib/init/template/approuter/files/xs-app.json +0 -8
- package/lib/init/template/nodejs/files/.vscode/settings.json +0 -7
|
@@ -24,52 +24,52 @@ var pluralize = require('pluralize')
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Construct an OpenAPI description from a CSDL document
|
|
27
|
-
* @param {object}
|
|
27
|
+
* @param {object} csdl CSDL document
|
|
28
28
|
* @param {object} options Optional parameters
|
|
29
29
|
* @return {object} OpenAPI description
|
|
30
30
|
*/
|
|
31
31
|
module.exports.csdl2openapi = function (
|
|
32
|
-
|
|
32
|
+
csdl,
|
|
33
33
|
{
|
|
34
|
-
url:
|
|
35
|
-
scheme:
|
|
36
|
-
host:
|
|
37
|
-
basePath:
|
|
38
|
-
diagram:
|
|
39
|
-
maxLevels:
|
|
34
|
+
url: serviceRoot,
|
|
35
|
+
scheme: scheme = 'https',
|
|
36
|
+
host: host = 'localhost',
|
|
37
|
+
basePath: basePath = '/service-root',
|
|
38
|
+
diagram: diagram = false,
|
|
39
|
+
maxLevels: maxLevels = 5
|
|
40
40
|
} = {}
|
|
41
41
|
) {
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
preProcess(
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
const
|
|
42
|
+
serviceRoot = serviceRoot || (scheme + '://' + host + basePath);
|
|
43
|
+
const queryOptionPrefix = csdl.$Version <= '4.0' ? '$' : '';
|
|
44
|
+
const typesToInline = {}; // filled in schema() and used in inlineTypes()
|
|
45
|
+
const boundOverloads = {};
|
|
46
|
+
const derivedTypes = {};
|
|
47
|
+
const alias = {};
|
|
48
|
+
const namespace = { 'Edm': 'Edm' };
|
|
49
|
+
const namespaceUrl = {};
|
|
50
|
+
const voc = {};
|
|
51
|
+
preProcess(csdl, boundOverloads, derivedTypes, alias, namespace, namespaceUrl, voc);
|
|
52
|
+
|
|
53
|
+
const entityContainer = csdl.$EntityContainer ? modelElement(csdl.$EntityContainer) : {};
|
|
54
|
+
const keyAsSegment = entityContainer[voc.Capabilities.KeyAsSegmentSupported];
|
|
55
|
+
const deepUpdate = entityContainer[voc.Capabilities.DeepUpdateSupport] && entityContainer[voc.Capabilities.DeepUpdateSupport].Supported;
|
|
56
|
+
|
|
57
|
+
const openapi = {
|
|
58
58
|
openapi: '3.0.2',
|
|
59
|
-
info: getInfo(
|
|
60
|
-
servers: getServers(
|
|
61
|
-
tags: getTags(
|
|
62
|
-
paths: getPaths(
|
|
63
|
-
components: getComponents(
|
|
59
|
+
info: getInfo(csdl, entityContainer),
|
|
60
|
+
servers: getServers(serviceRoot),
|
|
61
|
+
tags: getTags(entityContainer),
|
|
62
|
+
paths: getPaths(entityContainer),
|
|
63
|
+
components: getComponents(csdl, entityContainer)
|
|
64
64
|
};
|
|
65
|
-
if (!
|
|
66
|
-
delete
|
|
67
|
-
delete
|
|
65
|
+
if (!csdl.$EntityContainer) {
|
|
66
|
+
delete openapi.servers;
|
|
67
|
+
delete openapi.tags;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
security(
|
|
70
|
+
security(openapi, entityContainer);
|
|
71
71
|
|
|
72
|
-
return
|
|
72
|
+
return openapi;
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -134,7 +134,7 @@ module.exports.csdl2openapi = function (
|
|
|
134
134
|
element = element.find(overload =>
|
|
135
135
|
overload.$Kind == 'Action' && overload.$IsBound != true && args == ''
|
|
136
136
|
|| overload.$Kind == 'Action' && args == (overload.$Parameter[0].$Type || '')
|
|
137
|
-
|| (overload.$Parameter || []).map(p => p.$Type || 'Edm.String').join(',') == args);
|
|
137
|
+
|| (overload.$Parameter || []).map(p => { const type = p.$Type || 'Edm.String'; return p.$Collection ? `Collection(${type})` : type }).join(',') == args);
|
|
138
138
|
}
|
|
139
139
|
if (!element) {
|
|
140
140
|
// console.warn(`Invalid annotation target '${target}'`)
|
|
@@ -195,29 +195,33 @@ module.exports.csdl2openapi = function (
|
|
|
195
195
|
voc[vocab][term] = '@' + alias['Org.OData.' + vocab + '.V1'] + '.' + term;
|
|
196
196
|
});
|
|
197
197
|
});
|
|
198
|
+
|
|
199
|
+
voc.Common = {
|
|
200
|
+
Label: `@${alias['com.sap.vocabularies.Common.v1']}.Label`
|
|
201
|
+
}
|
|
198
202
|
}
|
|
199
203
|
|
|
200
204
|
/**
|
|
201
205
|
* Construct the Info Object
|
|
202
206
|
* @param {object} csdl CSDL document
|
|
203
|
-
* @param {object}
|
|
207
|
+
* @param {object} entityContainer Entity Container object
|
|
204
208
|
* @return {object} Info Object
|
|
205
209
|
*/
|
|
206
|
-
function getInfo(csdl,
|
|
210
|
+
function getInfo(csdl, entityContainer) {
|
|
207
211
|
const namespace = csdl.$EntityContainer ? nameParts(csdl.$EntityContainer).qualifier : null;
|
|
208
212
|
const containerSchema = csdl.$EntityContainer ? csdl[namespace] : {};
|
|
209
213
|
const description = (
|
|
210
|
-
|
|
211
|
-
|| containerSchema[
|
|
212
|
-
|| 'This service is located at [' +
|
|
213
|
-
+
|
|
214
|
-
) + (
|
|
214
|
+
entityContainer[voc.Core.LongDescription]
|
|
215
|
+
|| containerSchema[voc.Core.LongDescription]
|
|
216
|
+
|| 'This service is located at [' + serviceRoot + '/]('
|
|
217
|
+
+ serviceRoot.replace(/\(/g, '%28').replace(/\)/g, '%29') + '/)'
|
|
218
|
+
) + (diagram ? getResourceDiagram(csdl, entityContainer) : '');
|
|
215
219
|
return {
|
|
216
|
-
title:
|
|
217
|
-
|| containerSchema[
|
|
220
|
+
title: entityContainer[voc.Core.Description]
|
|
221
|
+
|| containerSchema[voc.Core.Description]
|
|
218
222
|
|| (csdl.$EntityContainer ? 'Service for namespace ' + namespace : 'OData CSDL document'),
|
|
219
223
|
description: csdl.$EntityContainer ? description : '',
|
|
220
|
-
version: containerSchema[
|
|
224
|
+
version: containerSchema[voc.Core.SchemaVersion] || ''
|
|
221
225
|
};
|
|
222
226
|
}
|
|
223
227
|
|
|
@@ -277,14 +281,7 @@ module.exports.csdl2openapi = function (
|
|
|
277
281
|
diagram += comma
|
|
278
282
|
+ '[' + name + color.resource + ']';
|
|
279
283
|
const overload = modelElement(resource.$Action).find(pOverload => !pOverload.$IsBound);
|
|
280
|
-
|
|
281
|
-
const type = modelElement(overload.$ReturnType.$Type || 'Edm.String');
|
|
282
|
-
if (type) {
|
|
283
|
-
diagram += '-'
|
|
284
|
-
+ cardinality(overload.$ReturnType)
|
|
285
|
-
+ '>[' + nameParts(overload.$ReturnType.$Type).name + ']';
|
|
286
|
-
}
|
|
287
|
-
}
|
|
284
|
+
diagram += overloadDiagram(name, overload);
|
|
288
285
|
} else if (resource.$Function) {
|
|
289
286
|
diagram += comma
|
|
290
287
|
+ '[' + name + color.resource + ']';
|
|
@@ -292,13 +289,7 @@ module.exports.csdl2openapi = function (
|
|
|
292
289
|
if (overloads) {
|
|
293
290
|
const unbound = overloads.filter(overload => !overload.$IsBound);
|
|
294
291
|
// TODO: loop over all overloads, add new source box after first arrow
|
|
295
|
-
|
|
296
|
-
const type = modelElement(iOverload.$ReturnType.$Type || 'Edm.String');
|
|
297
|
-
if (type) {
|
|
298
|
-
diagram += '-'
|
|
299
|
-
+ cardinality(iOverload.$ReturnType)
|
|
300
|
-
+ '>[' + nameParts(iOverload.$ReturnType.$Type).name + ']';
|
|
301
|
-
}
|
|
292
|
+
diagram += overloadDiagram(name, unbound[0]);
|
|
302
293
|
}
|
|
303
294
|
}
|
|
304
295
|
}
|
|
@@ -322,6 +313,29 @@ module.exports.csdl2openapi = function (
|
|
|
322
313
|
function cardinality(typedElement) {
|
|
323
314
|
return typedElement.$Collection ? '*' : (typedElement.$Nullable ? '0..1' : '');
|
|
324
315
|
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Diagram representation of action or function overload
|
|
319
|
+
* @param {string} name Name of action or function import
|
|
320
|
+
* @param {object} overload Action or function overload
|
|
321
|
+
* @return {string} diagram part
|
|
322
|
+
*/
|
|
323
|
+
function overloadDiagram(name, overload) {
|
|
324
|
+
let diag = "";
|
|
325
|
+
if (overload.$ReturnType) {
|
|
326
|
+
const type = modelElement(overload.$ReturnType.$Type || "Edm.String");
|
|
327
|
+
if (type) {
|
|
328
|
+
diag += "-" + cardinality(overload.$ReturnType) + ">[" + nameParts(overload.$ReturnType.$Type).name + "]";
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
for (const param of overload.$Parameter || []) {
|
|
332
|
+
const type = modelElement(param.$Type || "Edm.String");
|
|
333
|
+
if (type) {
|
|
334
|
+
diag += comma + "[" + name + color.resource + "]in-" + cardinality(param.$Type) + ">[" + nameParts(param.$Type).name + "]";
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return diag;
|
|
338
|
+
}
|
|
325
339
|
}
|
|
326
340
|
|
|
327
341
|
/**
|
|
@@ -331,7 +345,7 @@ module.exports.csdl2openapi = function (
|
|
|
331
345
|
*/
|
|
332
346
|
function modelElement(qname) {
|
|
333
347
|
const q = nameParts(qname);
|
|
334
|
-
const schema =
|
|
348
|
+
const schema = csdl[q.qualifier] || csdl[namespace[q.qualifier]];
|
|
335
349
|
return schema ? schema[q.name] : null;
|
|
336
350
|
}
|
|
337
351
|
|
|
@@ -354,10 +368,11 @@ module.exports.csdl2openapi = function (
|
|
|
354
368
|
const tags = [];
|
|
355
369
|
// all entity sets and singletons
|
|
356
370
|
Object.keys(container).filter(name => isIdentifier(name) && container[name].$Type).forEach(child => {
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
371
|
+
const type = modelElement(container[child].$Type) || {};
|
|
372
|
+
const tag = {
|
|
373
|
+
name: type[voc.Common.Label] || child
|
|
374
|
+
};
|
|
375
|
+
const description = container[child][voc.Core.Description] || type[voc.Core.Description];
|
|
361
376
|
if (description) tag.description = description;
|
|
362
377
|
tags.push(tag);
|
|
363
378
|
})
|
|
@@ -375,9 +390,11 @@ module.exports.csdl2openapi = function (
|
|
|
375
390
|
resources.forEach(name => {
|
|
376
391
|
let child = container[name];
|
|
377
392
|
if (child.$Type) {
|
|
393
|
+
const type = modelElement(child.$Type);
|
|
394
|
+
const sourceName = (type && type[voc.Common.Label]) || name;
|
|
378
395
|
// entity sets and singletons are almost containment navigation properties
|
|
379
396
|
child.$ContainsTarget = true;
|
|
380
|
-
pathItems(paths, '/' + name, [], child, child,
|
|
397
|
+
pathItems(paths, '/' + name, [], child, child, sourceName, sourceName, child, 0, '');
|
|
381
398
|
} else if (child.$Action) {
|
|
382
399
|
pathItemActionImport(paths, name, child);
|
|
383
400
|
} else if (child.$Function) {
|
|
@@ -421,7 +438,7 @@ module.exports.csdl2openapi = function (
|
|
|
421
438
|
|
|
422
439
|
if (element.$ContainsTarget) {
|
|
423
440
|
if (element.$Collection) {
|
|
424
|
-
if (level <
|
|
441
|
+
if (level < maxLevels)
|
|
425
442
|
pathItemsWithKey(paths, prefix, prefixParameters, element, root, sourceName, targetName, target, level, navigationPath, restrictions, nonExpandable);
|
|
426
443
|
} else {
|
|
427
444
|
operationUpdate(pathItem, element, name, sourceName, target, level, restrictions);
|
|
@@ -441,7 +458,7 @@ module.exports.csdl2openapi = function (
|
|
|
441
458
|
* @return Navigation property restrictions of navigation segment
|
|
442
459
|
*/
|
|
443
460
|
function navigationPropertyRestrictions(root, navigationPath) {
|
|
444
|
-
const navigationRestrictions = root[
|
|
461
|
+
const navigationRestrictions = root[voc.Capabilities.NavigationRestrictions] || {};
|
|
445
462
|
return (navigationRestrictions.RestrictedProperties || []).find(item => navigationPropertyPath(item.NavigationProperty) == navigationPath)
|
|
446
463
|
|| {};
|
|
447
464
|
}
|
|
@@ -453,7 +470,7 @@ module.exports.csdl2openapi = function (
|
|
|
453
470
|
* @return Navigation property restrictions of navigation segment
|
|
454
471
|
*/
|
|
455
472
|
function nonExpandableProperties(root, navigationPath) {
|
|
456
|
-
const expandRestrictions = root[
|
|
473
|
+
const expandRestrictions = root[voc.Capabilities.ExpandRestrictions] || {};
|
|
457
474
|
const prefix = navigationPath.length === 0 ? '' : navigationPath + '/'
|
|
458
475
|
const from = prefix.length
|
|
459
476
|
const nonExpandable = []
|
|
@@ -481,7 +498,7 @@ module.exports.csdl2openapi = function (
|
|
|
481
498
|
* @param {array} nonExpandable Non-expandable navigation properties
|
|
482
499
|
*/
|
|
483
500
|
function pathItemsWithKey(paths, prefix, prefixParameters, element, root, sourceName, targetName, target, level, navigationPath, restrictions, nonExpandable) {
|
|
484
|
-
const targetIndexable = target == null || target[
|
|
501
|
+
const targetIndexable = target == null || target[voc.Capabilities.IndexableByKey] != false;
|
|
485
502
|
if (restrictions.IndexableByKey == true || restrictions.IndexableByKey != false && targetIndexable) {
|
|
486
503
|
const name = prefix.substring(prefix.lastIndexOf('/') + 1);
|
|
487
504
|
const type = modelElement(element.$Type);
|
|
@@ -514,7 +531,7 @@ module.exports.csdl2openapi = function (
|
|
|
514
531
|
* @param {object} restrictions Navigation property restrictions of navigation segment
|
|
515
532
|
*/
|
|
516
533
|
function operationCreate(pathItem, element, name, sourceName, targetName, target, level, restrictions) {
|
|
517
|
-
const insertRestrictions = restrictions.InsertRestrictions || target && target[
|
|
534
|
+
const insertRestrictions = restrictions.InsertRestrictions || target && target[voc.Capabilities.InsertRestrictions] || {};
|
|
518
535
|
|
|
519
536
|
if (insertRestrictions.Insertable !== false) {
|
|
520
537
|
const lname = pluralize.singular(splitName(name));
|
|
@@ -523,7 +540,7 @@ module.exports.csdl2openapi = function (
|
|
|
523
540
|
summary: insertRestrictions.Description || operationSummary('Create', name, sourceName, level, true, true),
|
|
524
541
|
tags: [sourceName],
|
|
525
542
|
requestBody: {
|
|
526
|
-
description: type && type[
|
|
543
|
+
description: type && type[voc.Core.Description] || 'New ' + lname,
|
|
527
544
|
required: true,
|
|
528
545
|
content: {
|
|
529
546
|
'application/json': {
|
|
@@ -583,7 +600,7 @@ module.exports.csdl2openapi = function (
|
|
|
583
600
|
* @param {array} nonExpandable Non-expandable navigation properties
|
|
584
601
|
*/
|
|
585
602
|
function operationRead(pathItem, element, name, sourceName, targetName, target, level, restrictions, byKey, nonExpandable) {
|
|
586
|
-
const targetRestrictions = target && target[
|
|
603
|
+
const targetRestrictions = target && target[voc.Capabilities.ReadRestrictions];
|
|
587
604
|
const readRestrictions = restrictions.ReadRestrictions || targetRestrictions || {};
|
|
588
605
|
const readByKeyRestrictions = readRestrictions.ReadByKeyRestrictions;
|
|
589
606
|
let readable = true;
|
|
@@ -603,11 +620,11 @@ module.exports.csdl2openapi = function (
|
|
|
603
620
|
parameters: [],
|
|
604
621
|
responses: response(200, 'Retrieved ' + (byKey ? pluralize.singular(lname) : lname), { $Type: element.$Type, $Collection: collection })
|
|
605
622
|
};
|
|
606
|
-
const deltaSupported = element[
|
|
623
|
+
const deltaSupported = element[voc.Capabilities.ChangeTracking] && element[voc.Capabilities.ChangeTracking].Supported;
|
|
607
624
|
if (!byKey && deltaSupported) {
|
|
608
625
|
operation.responses[200].content['application/json'].schema.properties['@odata.deltaLink'] = {
|
|
609
626
|
type: 'string',
|
|
610
|
-
example:
|
|
627
|
+
example: basePath + '/' + name + '?$deltatoken=opaque server-generated token for fetching the delta'
|
|
611
628
|
}
|
|
612
629
|
}
|
|
613
630
|
if (descriptions.LongDescription) operation.description = descriptions.LongDescription;
|
|
@@ -616,7 +633,7 @@ module.exports.csdl2openapi = function (
|
|
|
616
633
|
if (collection) {
|
|
617
634
|
optionTop(operation.parameters, target, restrictions);
|
|
618
635
|
optionSkip(operation.parameters, target, restrictions);
|
|
619
|
-
if (
|
|
636
|
+
if (csdl.$Version >= '4.0') optionSearch(operation.parameters, target, restrictions);
|
|
620
637
|
optionFilter(operation.parameters, target, restrictions);
|
|
621
638
|
optionCount(operation.parameters, target);
|
|
622
639
|
optionOrderBy(operation.parameters, element, target, restrictions);
|
|
@@ -635,7 +652,7 @@ module.exports.csdl2openapi = function (
|
|
|
635
652
|
* @param {string} target Target container child of path
|
|
636
653
|
*/
|
|
637
654
|
function optionCount(parameters, target) {
|
|
638
|
-
const targetRestrictions = target && target[
|
|
655
|
+
const targetRestrictions = target && target[voc.Capabilities.CountRestrictions];
|
|
639
656
|
const targetCountable = target == null
|
|
640
657
|
|| targetRestrictions == null
|
|
641
658
|
|| targetRestrictions.Countable !== false;
|
|
@@ -656,14 +673,14 @@ module.exports.csdl2openapi = function (
|
|
|
656
673
|
* @param {array} nonExpandable Non-expandable navigation properties
|
|
657
674
|
*/
|
|
658
675
|
function optionExpand(parameters, element, target, nonExpandable) {
|
|
659
|
-
const targetRestrictions = target && target[
|
|
676
|
+
const targetRestrictions = target && target[voc.Capabilities.ExpandRestrictions];
|
|
660
677
|
const supported = targetRestrictions == null || targetRestrictions.Expandable != false;
|
|
661
678
|
if (supported) {
|
|
662
679
|
const expandItems = ['*'].concat(navigationPaths(element).filter(path => !nonExpandable.includes(path)));
|
|
663
680
|
if (expandItems.length > 1) {
|
|
664
681
|
parameters.push({
|
|
665
|
-
name:
|
|
666
|
-
description: (targetRestrictions && targetRestrictions[
|
|
682
|
+
name: queryOptionPrefix + 'expand',
|
|
683
|
+
description: (targetRestrictions && targetRestrictions[voc.Core.Description])
|
|
667
684
|
|| 'Expand related entities, see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionexpand)',
|
|
668
685
|
in: 'query',
|
|
669
686
|
explode: false,
|
|
@@ -694,7 +711,7 @@ module.exports.csdl2openapi = function (
|
|
|
694
711
|
Object.keys(properties).forEach(key => {
|
|
695
712
|
if (properties[key].$Kind == 'NavigationProperty') {
|
|
696
713
|
paths.push(prefix + key)
|
|
697
|
-
} else if (properties[key].$Type && level <
|
|
714
|
+
} else if (properties[key].$Type && level < maxLevels) {
|
|
698
715
|
paths.push(...navigationPaths(properties[key], prefix + key + '/', level + 1));
|
|
699
716
|
}
|
|
700
717
|
})
|
|
@@ -708,12 +725,12 @@ module.exports.csdl2openapi = function (
|
|
|
708
725
|
* @param {object} restrictions Navigation property restrictions of navigation segment
|
|
709
726
|
*/
|
|
710
727
|
function optionFilter(parameters, target, restrictions) {
|
|
711
|
-
const filterRestrictions = restrictions.FilterRestrictions || target && target[
|
|
728
|
+
const filterRestrictions = restrictions.FilterRestrictions || target && target[voc.Capabilities.FilterRestrictions] || {};
|
|
712
729
|
|
|
713
730
|
if (filterRestrictions.Filterable !== false) {
|
|
714
731
|
const filter = {
|
|
715
|
-
name:
|
|
716
|
-
description: filterRestrictions[
|
|
732
|
+
name: queryOptionPrefix + 'filter',
|
|
733
|
+
description: filterRestrictions[voc.Core.Description]
|
|
717
734
|
|| 'Filter items by property values, see [Filtering](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionfilter)',
|
|
718
735
|
in: 'query',
|
|
719
736
|
schema: {
|
|
@@ -740,7 +757,7 @@ module.exports.csdl2openapi = function (
|
|
|
740
757
|
* @param {object} restrictions Navigation property restrictions of navigation segment
|
|
741
758
|
*/
|
|
742
759
|
function optionOrderBy(parameters, element, target, restrictions) {
|
|
743
|
-
const sortRestrictions = restrictions.SortRestrictions || target && target[
|
|
760
|
+
const sortRestrictions = restrictions.SortRestrictions || target && target[voc.Capabilities.SortRestrictions] || {};
|
|
744
761
|
|
|
745
762
|
if (sortRestrictions.Sortable !== false) {
|
|
746
763
|
const nonSortable = {};
|
|
@@ -754,8 +771,8 @@ module.exports.csdl2openapi = function (
|
|
|
754
771
|
});
|
|
755
772
|
if (orderbyItems.length > 0) {
|
|
756
773
|
parameters.push({
|
|
757
|
-
name:
|
|
758
|
-
description: sortRestrictions[
|
|
774
|
+
name: queryOptionPrefix + 'orderby',
|
|
775
|
+
description: sortRestrictions[voc.Core.Description]
|
|
759
776
|
|| 'Order items by property values, see [Sorting](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionorderby)',
|
|
760
777
|
in: 'query',
|
|
761
778
|
explode: false,
|
|
@@ -894,13 +911,13 @@ module.exports.csdl2openapi = function (
|
|
|
894
911
|
* @param {object} restrictions Navigation property restrictions of navigation segment
|
|
895
912
|
*/
|
|
896
913
|
function optionSearch(parameters, target, restrictions) {
|
|
897
|
-
const searchRestrictions = restrictions.SearchRestrictions || target && target[
|
|
914
|
+
const searchRestrictions = restrictions.SearchRestrictions || target && target[voc.Capabilities.SearchRestrictions] || {};
|
|
898
915
|
|
|
899
916
|
if (searchRestrictions.Searchable !== false) {
|
|
900
|
-
if (searchRestrictions[
|
|
917
|
+
if (searchRestrictions[voc.Core.Description]) {
|
|
901
918
|
parameters.push({
|
|
902
|
-
name:
|
|
903
|
-
description: searchRestrictions[
|
|
919
|
+
name: queryOptionPrefix + 'search',
|
|
920
|
+
description: searchRestrictions[voc.Core.Description],
|
|
904
921
|
in: 'query',
|
|
905
922
|
schema: { type: 'string' }
|
|
906
923
|
});
|
|
@@ -918,7 +935,7 @@ module.exports.csdl2openapi = function (
|
|
|
918
935
|
* @param {object} restrictions Navigation property restrictions of navigation segment
|
|
919
936
|
*/
|
|
920
937
|
function optionSelect(parameters, element, target, restrictions) {
|
|
921
|
-
const selectSupport = restrictions.SelectSupport || target && target[
|
|
938
|
+
const selectSupport = restrictions.SelectSupport || target && target[voc.Capabilities.SelectSupport] || {};
|
|
922
939
|
|
|
923
940
|
if (selectSupport.Supported !== false) {
|
|
924
941
|
const type = modelElement(element.$Type) || {};
|
|
@@ -929,7 +946,7 @@ module.exports.csdl2openapi = function (
|
|
|
929
946
|
)
|
|
930
947
|
if (selectItems.length > 0) {
|
|
931
948
|
parameters.push({
|
|
932
|
-
name:
|
|
949
|
+
name: queryOptionPrefix + 'select',
|
|
933
950
|
description: 'Select properties to be returned, see [Select](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionselect)',
|
|
934
951
|
in: 'query',
|
|
935
952
|
explode: false,
|
|
@@ -955,7 +972,7 @@ module.exports.csdl2openapi = function (
|
|
|
955
972
|
function optionSkip(parameters, target, restrictions) {
|
|
956
973
|
const supported = restrictions.SkipSupported !== undefined
|
|
957
974
|
? restrictions.SkipSupported
|
|
958
|
-
: target == null || target[
|
|
975
|
+
: target == null || target[voc.Capabilities.SkipSupported] !== false;
|
|
959
976
|
|
|
960
977
|
if (supported) {
|
|
961
978
|
parameters.push({
|
|
@@ -973,7 +990,7 @@ module.exports.csdl2openapi = function (
|
|
|
973
990
|
function optionTop(parameters, target, restrictions) {
|
|
974
991
|
const supported = restrictions.TopSupported !== undefined
|
|
975
992
|
? restrictions.TopSupported
|
|
976
|
-
: target == null || target[
|
|
993
|
+
: target == null || target[voc.Capabilities.TopSupported] !== false;
|
|
977
994
|
|
|
978
995
|
if (supported) {
|
|
979
996
|
parameters.push({
|
|
@@ -994,7 +1011,7 @@ module.exports.csdl2openapi = function (
|
|
|
994
1011
|
* @param {boolean} byKey Update by key
|
|
995
1012
|
*/
|
|
996
1013
|
function operationUpdate(pathItem, element, name, sourceName, target, level, restrictions, byKey) {
|
|
997
|
-
const updateRestrictions = restrictions.UpdateRestrictions || target && target[
|
|
1014
|
+
const updateRestrictions = restrictions.UpdateRestrictions || target && target[voc.Capabilities.UpdateRestrictions] || {};
|
|
998
1015
|
|
|
999
1016
|
if (updateRestrictions.Updatable !== false) {
|
|
1000
1017
|
const type = modelElement(element.$Type);
|
|
@@ -1002,7 +1019,7 @@ module.exports.csdl2openapi = function (
|
|
|
1002
1019
|
summary: updateRestrictions.Description || operationSummary('Change', name, sourceName, level, element.$Collection, byKey),
|
|
1003
1020
|
tags: [sourceName],
|
|
1004
1021
|
requestBody: {
|
|
1005
|
-
description: type && type[
|
|
1022
|
+
description: type && type[voc.Core.Description] || 'New property values',
|
|
1006
1023
|
required: true,
|
|
1007
1024
|
content: {
|
|
1008
1025
|
'application/json': {
|
|
@@ -1028,7 +1045,7 @@ module.exports.csdl2openapi = function (
|
|
|
1028
1045
|
* @param {boolean} byKey Delete by key
|
|
1029
1046
|
*/
|
|
1030
1047
|
function operationDelete(pathItem, element, name, sourceName, target, level, restrictions, byKey) {
|
|
1031
|
-
const deleteRestrictions = restrictions.DeleteRestrictions || target && target[
|
|
1048
|
+
const deleteRestrictions = restrictions.DeleteRestrictions || target && target[voc.Capabilities.DeleteRestrictions] || {};
|
|
1032
1049
|
|
|
1033
1050
|
if (deleteRestrictions.Deletable !== false) {
|
|
1034
1051
|
pathItem.delete = {
|
|
@@ -1051,12 +1068,12 @@ module.exports.csdl2openapi = function (
|
|
|
1051
1068
|
* @param {string} navigationPrefix Path for finding navigation restrictions
|
|
1052
1069
|
*/
|
|
1053
1070
|
function pathItemsWithNavigation(paths, prefix, prefixParameters, type, root, sourceName, level, navigationPrefix) {
|
|
1054
|
-
const navigationRestrictions = root[
|
|
1071
|
+
const navigationRestrictions = root[voc.Capabilities.NavigationRestrictions] || {};
|
|
1055
1072
|
const rootNavigable = level == 0 && enumMember(navigationRestrictions.Navigability) != 'None'
|
|
1056
1073
|
|| level == 1 && enumMember(navigationRestrictions.Navigability) != 'Single'
|
|
1057
1074
|
|| level > 1;
|
|
1058
1075
|
|
|
1059
|
-
if (type && level <
|
|
1076
|
+
if (type && level < maxLevels) {
|
|
1060
1077
|
const properties = navigationPathMap(type);
|
|
1061
1078
|
Object.keys(properties).forEach(name => {
|
|
1062
1079
|
const parentRestrictions = navigationPropertyRestrictions(root, navigationPrefix);
|
|
@@ -1067,8 +1084,10 @@ module.exports.csdl2openapi = function (
|
|
|
1067
1084
|
if (['Recursive', 'Single'].includes(enumMember(restrictions.Navigability))
|
|
1068
1085
|
|| restrictions.Navigability == null && rootNavigable) {
|
|
1069
1086
|
const targetSetName = root.$NavigationPropertyBinding && root.$NavigationPropertyBinding[navigationPath];
|
|
1070
|
-
const target =
|
|
1071
|
-
|
|
1087
|
+
const target = entityContainer[targetSetName];
|
|
1088
|
+
const targetType = target && modelElement(target.$Type);
|
|
1089
|
+
const targetName = (targetType && targetType[voc.Common.Label]) || targetSetName;
|
|
1090
|
+
pathItems(paths, prefix + '/' + name, prefixParameters, properties[name], root, sourceName, targetName, target, level + 1, navigationPath);
|
|
1072
1091
|
}
|
|
1073
1092
|
});
|
|
1074
1093
|
}
|
|
@@ -1087,7 +1106,7 @@ module.exports.csdl2openapi = function (
|
|
|
1087
1106
|
Object.keys(properties).forEach(key => {
|
|
1088
1107
|
if (properties[key].$Kind == 'NavigationProperty') {
|
|
1089
1108
|
map[prefix + key] = properties[key];
|
|
1090
|
-
} else if (properties[key].$Type && !properties[key].$Collection && level <
|
|
1109
|
+
} else if (properties[key].$Type && !properties[key].$Collection && level < maxLevels) {
|
|
1091
1110
|
navigationPathMap(modelElement(properties[key].$Type), map, prefix + key + '/', level + 1);
|
|
1092
1111
|
}
|
|
1093
1112
|
})
|
|
@@ -1137,11 +1156,11 @@ module.exports.csdl2openapi = function (
|
|
|
1137
1156
|
let segment = '';
|
|
1138
1157
|
const params = [];
|
|
1139
1158
|
const keys = getKey(entityType) || [];
|
|
1140
|
-
const
|
|
1159
|
+
const properties = propertiesOfStructuredType(entityType);
|
|
1141
1160
|
|
|
1142
1161
|
keys.forEach((key, index) => {
|
|
1143
1162
|
const suffix = level > 0 ? '_' + level : '';
|
|
1144
|
-
if (
|
|
1163
|
+
if (keyAsSegment)
|
|
1145
1164
|
segment += '/';
|
|
1146
1165
|
else {
|
|
1147
1166
|
if (index > 0) segment += ',';
|
|
@@ -1151,11 +1170,11 @@ module.exports.csdl2openapi = function (
|
|
|
1151
1170
|
let property = {};
|
|
1152
1171
|
if (typeof key == 'string') {
|
|
1153
1172
|
parameter = key;
|
|
1154
|
-
property =
|
|
1173
|
+
property = properties[key];
|
|
1155
1174
|
} else {
|
|
1156
1175
|
parameter = Object.keys(key)[0];
|
|
1157
1176
|
const segments = key[parameter].split('/');
|
|
1158
|
-
property =
|
|
1177
|
+
property = properties[segments[0]];
|
|
1159
1178
|
for (let i = 1; i < segments.length; i++) {
|
|
1160
1179
|
const complexType = modelElement(property.$Type);
|
|
1161
1180
|
const properties = propertiesOfStructuredType(complexType);
|
|
@@ -1165,7 +1184,7 @@ module.exports.csdl2openapi = function (
|
|
|
1165
1184
|
const propertyType = property.$Type;
|
|
1166
1185
|
segment += pathValuePrefix(propertyType) + '{' + parameter + suffix + '}' + pathValueSuffix(propertyType);
|
|
1167
1186
|
const param = {
|
|
1168
|
-
description: [property[
|
|
1187
|
+
description: [property[voc.Core.Description], property[voc.Core.LongDescription]].filter(t => t).join(' \n')
|
|
1169
1188
|
|| 'key: ' + parameter,
|
|
1170
1189
|
in: 'path',
|
|
1171
1190
|
name: parameter + suffix,
|
|
@@ -1174,7 +1193,7 @@ module.exports.csdl2openapi = function (
|
|
|
1174
1193
|
};
|
|
1175
1194
|
params.push(param);
|
|
1176
1195
|
})
|
|
1177
|
-
return { segment: (
|
|
1196
|
+
return { segment: (keyAsSegment ? '' : '(') + segment + (keyAsSegment ? '' : ')'), parameters: params };
|
|
1178
1197
|
}
|
|
1179
1198
|
|
|
1180
1199
|
/**
|
|
@@ -1186,7 +1205,7 @@ module.exports.csdl2openapi = function (
|
|
|
1186
1205
|
//TODO: handle other Edm types, enumeration types, and type definitions
|
|
1187
1206
|
if (['Edm.Int64', 'Edm.Int32', 'Edm.Int16', 'Edm.SByte', 'Edm.Byte',
|
|
1188
1207
|
'Edm.Double', 'Edm.Single', 'Edm.Date', 'Edm.DateTimeOffset', 'Edm.Guid'].includes(typename)) return '';
|
|
1189
|
-
if (
|
|
1208
|
+
if (keyAsSegment) return '';
|
|
1190
1209
|
return `'`;
|
|
1191
1210
|
}
|
|
1192
1211
|
|
|
@@ -1199,7 +1218,7 @@ module.exports.csdl2openapi = function (
|
|
|
1199
1218
|
//TODO: handle other Edm types, enumeration types, and type definitions
|
|
1200
1219
|
if (['Edm.Int64', 'Edm.Int32', 'Edm.Int16', 'Edm.SByte', 'Edm.Byte',
|
|
1201
1220
|
'Edm.Double', 'Edm.Single', 'Edm.Date', 'Edm.DateTimeOffset', 'Edm.Guid'].includes(typename)) return '';
|
|
1202
|
-
if (
|
|
1221
|
+
if (keyAsSegment) return '';
|
|
1203
1222
|
return `'`;
|
|
1204
1223
|
}
|
|
1205
1224
|
|
|
@@ -1213,7 +1232,7 @@ module.exports.csdl2openapi = function (
|
|
|
1213
1232
|
* @param {boolean} byKey read by key
|
|
1214
1233
|
*/
|
|
1215
1234
|
function pathItemsForBoundOperations(paths, prefix, prefixParameters, element, sourceName, byKey = false) {
|
|
1216
|
-
const overloads =
|
|
1235
|
+
const overloads = boundOverloads[element.$Type + (!byKey && element.$Collection ? '-c' : '')] || [];
|
|
1217
1236
|
overloads.forEach(item => {
|
|
1218
1237
|
if (item.overload.$Kind == 'Action')
|
|
1219
1238
|
pathItemAction(paths, prefix + '/' + item.name, prefixParameters, item.name, item.overload, sourceName);
|
|
@@ -1247,14 +1266,14 @@ module.exports.csdl2openapi = function (
|
|
|
1247
1266
|
const name = actionName.indexOf('.') === -1 ? actionName : nameParts(actionName).name;
|
|
1248
1267
|
const pathItem = {
|
|
1249
1268
|
post: {
|
|
1250
|
-
summary: actionImport[
|
|
1251
|
-
tags: [sourceName || 'Service Operations'],
|
|
1269
|
+
summary: actionImport[voc.Core.Description] || overload[voc.Core.Description] || 'Invoke action ' + name,
|
|
1270
|
+
tags: [overload[voc.Common.Label] || sourceName || 'Service Operations'],
|
|
1252
1271
|
responses: overload.$ReturnType
|
|
1253
1272
|
? response(200, 'Success', overload.$ReturnType)
|
|
1254
1273
|
: response(204, 'Success')
|
|
1255
1274
|
}
|
|
1256
1275
|
};
|
|
1257
|
-
const description = actionImport[
|
|
1276
|
+
const description = actionImport[voc.Core.LongDescription] || overload[voc.Core.LongDescription];
|
|
1258
1277
|
if (description) pathItem.post.description = description;
|
|
1259
1278
|
if (prefixParameters.length > 0) pathItem.post.parameters = prefixParameters;
|
|
1260
1279
|
let parameters = overload.$Parameter || [];
|
|
@@ -1307,13 +1326,13 @@ module.exports.csdl2openapi = function (
|
|
|
1307
1326
|
const pathSegments = [];
|
|
1308
1327
|
const params = [];
|
|
1309
1328
|
|
|
1310
|
-
const implicitAliases =
|
|
1329
|
+
const implicitAliases = csdl.$Version > '4.0' || parameters.some(p => p[voc.Core.OptionalParameter]);
|
|
1311
1330
|
|
|
1312
1331
|
parameters.forEach(p => {
|
|
1313
1332
|
const param = {
|
|
1314
|
-
required: implicitAliases ? !p[
|
|
1333
|
+
required: implicitAliases ? !p[voc.Core.OptionalParameter] : true
|
|
1315
1334
|
};
|
|
1316
|
-
const description = [p[
|
|
1335
|
+
const description = [p[voc.Core.Description], p[voc.Core.LongDescription]].filter(t => t).join(' \n');
|
|
1317
1336
|
if (description) param.description = description;
|
|
1318
1337
|
const type = modelElement(p.$Type || 'Edm.String');
|
|
1319
1338
|
// TODO: check whether parameter or type definition of Edm.Stream is annotated with JSON.Schema
|
|
@@ -1341,11 +1360,16 @@ module.exports.csdl2openapi = function (
|
|
|
1341
1360
|
if (implicitAliases) {
|
|
1342
1361
|
param.in = 'query';
|
|
1343
1362
|
} else {
|
|
1344
|
-
pathSegments.push(p.$Name +
|
|
1363
|
+
pathSegments.push(p.$Name + "={" + p.$Name + "}");
|
|
1345
1364
|
param.in = 'path';
|
|
1346
1365
|
}
|
|
1347
1366
|
param.name = p.$Name;
|
|
1348
|
-
|
|
1367
|
+
if (!p.$Type || p.$Type === "Edm.String" || (type && (!type.$Type || type.$Type === "Edm.String"))) {
|
|
1368
|
+
if (description) param.description += " \n";
|
|
1369
|
+
else param.description = "";
|
|
1370
|
+
param.description += "String value needs to be enclosed in single quotes";
|
|
1371
|
+
}
|
|
1372
|
+
param.schema = getSchema(p, '', true, true);
|
|
1349
1373
|
}
|
|
1350
1374
|
params.push(param);
|
|
1351
1375
|
});
|
|
@@ -1353,13 +1377,13 @@ module.exports.csdl2openapi = function (
|
|
|
1353
1377
|
const pathParameters = implicitAliases ? '' : '(' + pathSegments.join(',') + ')';
|
|
1354
1378
|
const pathItem = {
|
|
1355
1379
|
get: {
|
|
1356
|
-
summary: functionImport[
|
|
1357
|
-
tags: [sourceName || 'Service Operations'],
|
|
1380
|
+
summary: functionImport[voc.Core.Description] || overload[voc.Core.Description] || 'Invoke function ' + name,
|
|
1381
|
+
tags: [overload[voc.Common.Label] || sourceName || 'Service Operations'],
|
|
1358
1382
|
parameters: prefixParameters.concat(params),
|
|
1359
1383
|
responses: response(200, 'Success', overload.$ReturnType)
|
|
1360
1384
|
}
|
|
1361
1385
|
};
|
|
1362
|
-
const iDescription = functionImport[
|
|
1386
|
+
const iDescription = functionImport[voc.Core.LongDescription] || overload[voc.Core.LongDescription];
|
|
1363
1387
|
if (iDescription) pathItem.get.description = iDescription;
|
|
1364
1388
|
paths[prefix + pathParameters] = pathItem;
|
|
1365
1389
|
}
|
|
@@ -1370,14 +1394,14 @@ module.exports.csdl2openapi = function (
|
|
|
1370
1394
|
* @param {object} container Entity container
|
|
1371
1395
|
*/
|
|
1372
1396
|
function pathItemBatch(paths, container) {
|
|
1373
|
-
const batchSupport = container[
|
|
1374
|
-
const supported = container[
|
|
1397
|
+
const batchSupport = container[voc.Capabilities.BatchSupport] || {};
|
|
1398
|
+
const supported = container[voc.Capabilities.BatchSupported] !== false && batchSupport.Supported !== false;
|
|
1375
1399
|
if (supported) {
|
|
1376
1400
|
const firstEntitySet = Object.keys(container).filter(child => isIdentifier(child) && container[child].$Collection)[0];
|
|
1377
1401
|
paths['/$batch'] = {
|
|
1378
1402
|
post: {
|
|
1379
|
-
summary: batchSupport[
|
|
1380
|
-
description: (batchSupport[
|
|
1403
|
+
summary: batchSupport[voc.Core.Description] || 'Send a group of requests',
|
|
1404
|
+
description: (batchSupport[voc.Core.LongDescription] || 'Group multiple requests into a single request payload, see '
|
|
1381
1405
|
+ '[Batch Requests](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_BatchRequests).')
|
|
1382
1406
|
+ '\n\n*Please note that "Try it out" is not supported for this request.*',
|
|
1383
1407
|
tags: ['Batch Requests'],
|
|
@@ -1405,7 +1429,7 @@ module.exports.csdl2openapi = function (
|
|
|
1405
1429
|
}
|
|
1406
1430
|
}
|
|
1407
1431
|
};
|
|
1408
|
-
paths['/$batch'].post.responses[
|
|
1432
|
+
paths['/$batch'].post.responses[csdl.$Version < '4.0' ? 202 : 200] = {
|
|
1409
1433
|
description: 'Batch response',
|
|
1410
1434
|
content: {
|
|
1411
1435
|
'multipart/mixed': {
|
|
@@ -1444,7 +1468,7 @@ module.exports.csdl2openapi = function (
|
|
|
1444
1468
|
type: 'object',
|
|
1445
1469
|
title: 'Collection of ' + nameParts(type.$Type || 'Edm.String').name,
|
|
1446
1470
|
properties: {
|
|
1447
|
-
[
|
|
1471
|
+
[csdl.$Version > '4.0' ? '@count' : '@odata.count']: ref('count'),
|
|
1448
1472
|
value: s
|
|
1449
1473
|
}
|
|
1450
1474
|
}
|
|
@@ -1529,7 +1553,7 @@ module.exports.csdl2openapi = function (
|
|
|
1529
1553
|
* @param {object} schemas Map of Schema Objects to augment
|
|
1530
1554
|
*/
|
|
1531
1555
|
function inlineTypes(schemas) {
|
|
1532
|
-
if (
|
|
1556
|
+
if (typesToInline.geoPoint) {
|
|
1533
1557
|
schemas.geoPoint = {
|
|
1534
1558
|
type: 'object',
|
|
1535
1559
|
properties: {
|
|
@@ -1571,7 +1595,7 @@ module.exports.csdl2openapi = function (
|
|
|
1571
1595
|
title: name,
|
|
1572
1596
|
enum: members
|
|
1573
1597
|
};
|
|
1574
|
-
const description = type[
|
|
1598
|
+
const description = type[voc.Core.Description];
|
|
1575
1599
|
if (description) s.description = description;
|
|
1576
1600
|
schemas[qualifier + '.' + name] = s;
|
|
1577
1601
|
}
|
|
@@ -1587,7 +1611,7 @@ module.exports.csdl2openapi = function (
|
|
|
1587
1611
|
function schemaForTypeDefinition(schemas, qualifier, name, type) {
|
|
1588
1612
|
const s = getSchema(Object.assign({ $Type: type.$UnderlyingType }, type));
|
|
1589
1613
|
s.title = name;
|
|
1590
|
-
const description = type[
|
|
1614
|
+
const description = type[voc.Core.Description];
|
|
1591
1615
|
if (description) s.description = description;
|
|
1592
1616
|
schemas[qualifier + '.' + name] = s;
|
|
1593
1617
|
}
|
|
@@ -1616,18 +1640,18 @@ module.exports.csdl2openapi = function (
|
|
|
1616
1640
|
allProperties[iName] = getSchema(property);
|
|
1617
1641
|
if (property.$Kind == 'NavigationProperty') {
|
|
1618
1642
|
if (property.$Collection) {
|
|
1619
|
-
allProperties[`${iName}@${
|
|
1643
|
+
allProperties[`${iName}@${csdl.$Version === '4.0' ? 'odata.' : ''}count`] = ref('count');
|
|
1620
1644
|
}
|
|
1621
1645
|
creProperties[iName] = getSchema(property, '-create');
|
|
1622
|
-
if (
|
|
1646
|
+
if (deepUpdate)
|
|
1623
1647
|
updProperties[iName] = getSchema(property, '-create');
|
|
1624
1648
|
} else {
|
|
1625
|
-
if (property[
|
|
1649
|
+
if (property[voc.Core.Permissions] == 'Read' || property[voc.Core.Computed]) {
|
|
1626
1650
|
let index = required.indexOf(iName);
|
|
1627
1651
|
if (index != -1) required.splice(index, 1);
|
|
1628
1652
|
} else {
|
|
1629
1653
|
creProperties[iName] = getSchema(property, '-create');
|
|
1630
|
-
if (!isKey[iName] && !property[
|
|
1654
|
+
if (!isKey[iName] && !property[voc.Core.Immutable])
|
|
1631
1655
|
updProperties[iName] = getSchema(property, '-update');
|
|
1632
1656
|
}
|
|
1633
1657
|
}
|
|
@@ -1654,18 +1678,18 @@ module.exports.csdl2openapi = function (
|
|
|
1654
1678
|
};
|
|
1655
1679
|
if (Object.keys(updProperties).length > 0) schemas[updName].properties = updProperties;
|
|
1656
1680
|
|
|
1657
|
-
const description = type[
|
|
1681
|
+
const description = type[voc.Core.Description];
|
|
1658
1682
|
if (description) {
|
|
1659
1683
|
schemas[allName].description = description;
|
|
1660
1684
|
schemas[creName].description = description;
|
|
1661
1685
|
schemas[updName].description = description;
|
|
1662
1686
|
}
|
|
1663
1687
|
|
|
1664
|
-
if (
|
|
1688
|
+
if (derivedTypes[allName]) {
|
|
1665
1689
|
schemas[allName].anyOf = [];
|
|
1666
1690
|
schemas[creName].anyOf = [];
|
|
1667
1691
|
schemas[updName].anyOf = [];
|
|
1668
|
-
|
|
1692
|
+
derivedTypes[allName].forEach(derivedType => {
|
|
1669
1693
|
schemas[allName].anyOf.push(ref(derivedType));
|
|
1670
1694
|
schemas[creName].anyOf.push(ref(derivedType, '-create'));
|
|
1671
1695
|
schemas[updName].anyOf.push(ref(derivedType, '-update'));
|
|
@@ -1700,7 +1724,7 @@ module.exports.csdl2openapi = function (
|
|
|
1700
1724
|
function getParameters() {
|
|
1701
1725
|
const param = {
|
|
1702
1726
|
top: {
|
|
1703
|
-
name:
|
|
1727
|
+
name: queryOptionPrefix + 'top',
|
|
1704
1728
|
in: 'query',
|
|
1705
1729
|
description: 'Show only the first n items, see [Paging - Top](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptiontop)',
|
|
1706
1730
|
schema: {
|
|
@@ -1710,7 +1734,7 @@ module.exports.csdl2openapi = function (
|
|
|
1710
1734
|
example: 50
|
|
1711
1735
|
},
|
|
1712
1736
|
skip: {
|
|
1713
|
-
name:
|
|
1737
|
+
name: queryOptionPrefix + 'skip',
|
|
1714
1738
|
in: 'query',
|
|
1715
1739
|
description: 'Skip the first n items, see [Paging - Skip](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionskip)',
|
|
1716
1740
|
schema: {
|
|
@@ -1719,7 +1743,7 @@ module.exports.csdl2openapi = function (
|
|
|
1719
1743
|
}
|
|
1720
1744
|
},
|
|
1721
1745
|
count: {
|
|
1722
|
-
name:
|
|
1746
|
+
name: queryOptionPrefix + 'count',
|
|
1723
1747
|
in: 'query',
|
|
1724
1748
|
description: 'Include count of items, see [Count](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptioncount)',
|
|
1725
1749
|
schema: {
|
|
@@ -1728,8 +1752,8 @@ module.exports.csdl2openapi = function (
|
|
|
1728
1752
|
}
|
|
1729
1753
|
};
|
|
1730
1754
|
|
|
1731
|
-
if (
|
|
1732
|
-
name:
|
|
1755
|
+
if (csdl.$Version >= '4.0') param.search = {
|
|
1756
|
+
name: queryOptionPrefix + 'search',
|
|
1733
1757
|
in: 'query',
|
|
1734
1758
|
description: 'Search items by search phrases, see [Searching](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionsearch)',
|
|
1735
1759
|
schema: {
|
|
@@ -1777,7 +1801,7 @@ module.exports.csdl2openapi = function (
|
|
|
1777
1801
|
}
|
|
1778
1802
|
};
|
|
1779
1803
|
|
|
1780
|
-
if (
|
|
1804
|
+
if (csdl.$Version < '4.0') {
|
|
1781
1805
|
err.properties.error.properties.message = {
|
|
1782
1806
|
type: 'object',
|
|
1783
1807
|
properties: {
|
|
@@ -1812,7 +1836,7 @@ module.exports.csdl2openapi = function (
|
|
|
1812
1836
|
* @param {object} modelElement referencing a type
|
|
1813
1837
|
* @return {object} Schema Object
|
|
1814
1838
|
*/
|
|
1815
|
-
function getSchema(element, suffix = '', forParameter = false) {
|
|
1839
|
+
function getSchema(element, suffix = '', forParameter = false, forFunction = false) {
|
|
1816
1840
|
let s = {};
|
|
1817
1841
|
switch (element.$Type) {
|
|
1818
1842
|
case 'Edm.AnnotationPath':
|
|
@@ -1891,7 +1915,7 @@ module.exports.csdl2openapi = function (
|
|
|
1891
1915
|
case 'Edm.GeographyPoint':
|
|
1892
1916
|
case 'Edm.GeometryPoint':
|
|
1893
1917
|
s = ref('geoPoint');
|
|
1894
|
-
|
|
1918
|
+
typesToInline.geoPoint = true;
|
|
1895
1919
|
break;
|
|
1896
1920
|
case 'Edm.Guid':
|
|
1897
1921
|
s = {
|
|
@@ -1939,7 +1963,7 @@ module.exports.csdl2openapi = function (
|
|
|
1939
1963
|
break;
|
|
1940
1964
|
case 'Edm.Stream':
|
|
1941
1965
|
// eslint-disable-next-line no-case-declarations
|
|
1942
|
-
let jsonSchema = element[
|
|
1966
|
+
let jsonSchema = element[voc.JSON.Schema];
|
|
1943
1967
|
if (jsonSchema) {
|
|
1944
1968
|
if (typeof jsonSchema == 'string')
|
|
1945
1969
|
s = JSON.parse(jsonSchema);
|
|
@@ -1992,21 +2016,45 @@ module.exports.csdl2openapi = function (
|
|
|
1992
2016
|
s.default = element.$DefaultValue;
|
|
1993
2017
|
}
|
|
1994
2018
|
|
|
1995
|
-
if (element[
|
|
2019
|
+
if (element[voc.Core.Example]) {
|
|
1996
2020
|
if (s.$ref) s = { allOf: [s] };
|
|
1997
|
-
s.example = element[
|
|
2021
|
+
s.example = element[voc.Core.Example].Value;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
if (forFunction) {
|
|
2025
|
+
if (s.example && typeof s.example === "string") {
|
|
2026
|
+
s.example = `${pathValuePrefix(element.$Type)}${s.example
|
|
2027
|
+
}${pathValueSuffix(element.$Type)}`;
|
|
2028
|
+
}
|
|
2029
|
+
if (s.pattern) {
|
|
2030
|
+
const pre = pathValuePrefix(element.$Type);
|
|
2031
|
+
const suf = pathValueSuffix(element.$Type);
|
|
2032
|
+
s.pattern = s.pattern.replace(/^\^/, `^${pre}(`);
|
|
2033
|
+
s.pattern = s.pattern.replace(/\$$/, `)${suf}$`);
|
|
2034
|
+
} else if (!element.$Type || element.$Type === "Edm.String") {
|
|
2035
|
+
s.pattern = "^'([^']|'')*'$";
|
|
2036
|
+
}
|
|
2037
|
+
if (element.$Nullable) {
|
|
2038
|
+
if (!s.anyOf && !s.allOf) s.type = "string";
|
|
2039
|
+
if (s.format) s.format += ",null";
|
|
2040
|
+
s.default = "null";
|
|
2041
|
+
if (s.pattern) {
|
|
2042
|
+
s.pattern = s.pattern.replace(/^\^/, "^(null|");
|
|
2043
|
+
s.pattern = s.pattern.replace(/\$$/, ")$");
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
1998
2046
|
}
|
|
1999
2047
|
|
|
2000
|
-
if (element[
|
|
2048
|
+
if (element[voc.Validation.Maximum] != undefined) {
|
|
2001
2049
|
if (s.$ref) s = { allOf: [s] };
|
|
2002
|
-
s.maximum = element[
|
|
2003
|
-
if (element[
|
|
2050
|
+
s.maximum = element[voc.Validation.Maximum];
|
|
2051
|
+
if (element[voc.Validation.Maximum + voc.Validation.Exclusive]) s.exclusiveMaximum = true;
|
|
2004
2052
|
}
|
|
2005
2053
|
|
|
2006
|
-
if (element[
|
|
2054
|
+
if (element[voc.Validation.Minimum] != undefined) {
|
|
2007
2055
|
if (s.$ref) s = { allOf: [s] };
|
|
2008
|
-
s.minimum = element[
|
|
2009
|
-
if (element[
|
|
2056
|
+
s.minimum = element[voc.Validation.Minimum];
|
|
2057
|
+
if (element[voc.Validation.Minimum + voc.Validation.Exclusive]) s.exclusiveMinimum = true;
|
|
2010
2058
|
}
|
|
2011
2059
|
|
|
2012
2060
|
if (element.$Collection) {
|
|
@@ -2016,9 +2064,9 @@ module.exports.csdl2openapi = function (
|
|
|
2016
2064
|
};
|
|
2017
2065
|
}
|
|
2018
2066
|
|
|
2019
|
-
if (!forParameter && element[
|
|
2067
|
+
if (!forParameter && element[voc.Core.Description]) {
|
|
2020
2068
|
if (s.$ref) s = { allOf: [s] };
|
|
2021
|
-
s.description = element[
|
|
2069
|
+
s.description = element[voc.Core.Description];
|
|
2022
2070
|
}
|
|
2023
2071
|
|
|
2024
2072
|
return s;
|
|
@@ -2030,7 +2078,7 @@ module.exports.csdl2openapi = function (
|
|
|
2030
2078
|
* @param {object} element Model element
|
|
2031
2079
|
*/
|
|
2032
2080
|
function allowedValues(schema, element) {
|
|
2033
|
-
const values = element[
|
|
2081
|
+
const values = element[voc.Validation.AllowedValues];
|
|
2034
2082
|
if (values) schema.enum = values.map(record => record.Value);
|
|
2035
2083
|
}
|
|
2036
2084
|
|
|
@@ -2040,7 +2088,7 @@ module.exports.csdl2openapi = function (
|
|
|
2040
2088
|
* @param {object} element Model element
|
|
2041
2089
|
*/
|
|
2042
2090
|
function getPattern(schema, element) {
|
|
2043
|
-
const pattern = element[
|
|
2091
|
+
const pattern = element[voc.Validation.Pattern];
|
|
2044
2092
|
if (pattern) schema.pattern = pattern;
|
|
2045
2093
|
}
|
|
2046
2094
|
|
|
@@ -2056,9 +2104,9 @@ module.exports.csdl2openapi = function (
|
|
|
2056
2104
|
let url = '';
|
|
2057
2105
|
if (typename.indexOf('.') != -1) {
|
|
2058
2106
|
let parts = nameParts(typename);
|
|
2059
|
-
nsp =
|
|
2107
|
+
nsp = namespace[parts.qualifier];
|
|
2060
2108
|
name = nsp + '.' + parts.name;
|
|
2061
|
-
url =
|
|
2109
|
+
url = namespaceUrl[nsp] || '';
|
|
2062
2110
|
//TODO: introduce better way than guessing
|
|
2063
2111
|
if (url.endsWith('.xml')) url = url.substr(0, url.length - 3) + 'openapi3.json';
|
|
2064
2112
|
}
|
|
@@ -2073,7 +2121,7 @@ module.exports.csdl2openapi = function (
|
|
|
2073
2121
|
* @param {object} entityContainer Entity Container object
|
|
2074
2122
|
*/
|
|
2075
2123
|
function getSecuritySchemes(components, entityContainer) {
|
|
2076
|
-
const authorizations = entityContainer[
|
|
2124
|
+
const authorizations = entityContainer[voc.Authorization.Authorizations] || [];
|
|
2077
2125
|
const schemes = {};
|
|
2078
2126
|
const location = { Header: 'header', QueryOption: 'query', Cookie: 'cookie' };
|
|
2079
2127
|
authorizations.forEach(auth => {
|
|
@@ -2149,7 +2197,7 @@ module.exports.csdl2openapi = function (
|
|
|
2149
2197
|
* @param {object} entityContainer Entity Container object
|
|
2150
2198
|
*/
|
|
2151
2199
|
function security(openapi, entityContainer) {
|
|
2152
|
-
const securitySchemes = entityContainer[
|
|
2200
|
+
const securitySchemes = entityContainer[voc.Authorization.SecuritySchemes] || [];
|
|
2153
2201
|
if (securitySchemes.length > 0) openapi.security = [];
|
|
2154
2202
|
securitySchemes.forEach(scheme => {
|
|
2155
2203
|
const s = {};
|
|
@@ -2165,7 +2213,7 @@ module.exports.csdl2openapi = function (
|
|
|
2165
2213
|
*/
|
|
2166
2214
|
function namespaceQualifiedName(qualifiedName) {
|
|
2167
2215
|
let np = nameParts(qualifiedName);
|
|
2168
|
-
return
|
|
2216
|
+
return namespace[np.qualifier] + '.' + np.name;
|
|
2169
2217
|
}
|
|
2170
2218
|
|
|
2171
2219
|
/**
|