@sap/cds-dk 4.8.2 → 4.9.2

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 (83) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/bin/activate.js +8 -7
  3. package/bin/bind.js +12 -12
  4. package/bin/build/all.js +3 -5
  5. package/bin/build/index.js +1 -1
  6. package/bin/cds.js +1 -1
  7. package/bin/deploy/index.js +7 -1
  8. package/bin/deploy/to-hana.js +5 -4
  9. package/bin/deploy/to-sqlite.js +2 -1
  10. package/bin/extend.js +5 -5
  11. package/bin/help.js +1 -0
  12. package/bin/import.js +45 -31
  13. package/bin/login.js +5 -6
  14. package/bin/logout.js +2 -2
  15. package/bin/parse.js +19 -0
  16. package/lib/bind/bindingUtil.js +41 -49
  17. package/lib/bind/cfKeyProvider.js +9 -17
  18. package/lib/bind/userCdsrcJsonStorageProvider.js +1 -0
  19. package/lib/client/activate.js +3 -2
  20. package/lib/client/extend.js +5 -6
  21. package/lib/client/helper/fs_helper.js +8 -8
  22. package/lib/client/settings_manager.js +12 -9
  23. package/lib/compile/openapi/csdl2openapi.js +213 -165
  24. package/lib/compile/openapi/index.js +1 -2
  25. package/lib/compile/to-xsuaa.js +1 -1
  26. package/lib/import/index.js +22 -15
  27. package/lib/import/message.js +3 -1
  28. package/lib/import/utils/MetadataConverter.js +1 -1
  29. package/lib/import/v2parser.js +112 -56
  30. package/lib/import/v4parser.js +149 -98
  31. package/lib/init/constants.js +6 -2
  32. package/lib/init/index.js +3 -2
  33. package/lib/init/template/_merging/existences.js +80 -4
  34. package/lib/init/template/approuter/files/cds.cdsrc.json +7 -0
  35. package/lib/init/template/approuter/files/cds.cdsrc.json.hbs +9 -0
  36. package/lib/init/template/approuter/files/cds.package.json +9 -0
  37. package/lib/init/template/approuter/files/cds.package.json.hbs +11 -0
  38. package/lib/init/template/approuter/files/index.html +1 -0
  39. package/lib/init/template/approuter/files/mta.yaml.hbs +35 -21
  40. package/lib/init/template/approuter/files/package.json +3 -0
  41. package/lib/init/template/approuter/files/xs-app.json.hbs +19 -0
  42. package/lib/init/template/approuter/index.js +47 -18
  43. package/lib/init/template/auditlog/index.js +5 -5
  44. package/lib/init/template/hana/files/java/cdsrc.json.hbs +7 -0
  45. package/lib/init/template/hana/files/java/{package.json → db/package.json} +0 -0
  46. package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +12 -0
  47. package/lib/init/template/hana/files/mta.yaml.hbs +10 -17
  48. package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +9 -0
  49. package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +14 -0
  50. package/lib/init/template/hana/files/nodejs/dependencies.package.json +1 -1
  51. package/lib/init/template/hana/index.js +60 -86
  52. package/lib/init/template/java/index.js +5 -2
  53. package/lib/init/template/kibana-logging/files/cds.package.json +7 -0
  54. package/lib/init/template/kibana-logging/files/cds.profile.package.json.hbs +9 -0
  55. package/lib/init/template/kibana-logging/files/mta.yaml.hbs +13 -0
  56. package/lib/init/template/kibana-logging/index.js +64 -0
  57. package/lib/init/template/mta/files/mta.yaml.hbs +3 -8
  58. package/lib/init/template/mta/index.js +8 -2
  59. package/lib/init/template/mtx/files/cds.package.json +0 -12
  60. package/lib/init/template/mtx/files/cds.package.json.hbs +14 -0
  61. package/lib/init/template/mtx/files/java/.cdsrc.json +17 -0
  62. package/lib/init/template/mtx/files/java/package.json +43 -0
  63. package/lib/init/template/mtx/files/java/server.js +30 -0
  64. package/lib/init/template/mtx/files/mta.yaml.hbs +6 -6
  65. package/lib/init/template/mtx/index.js +41 -22
  66. package/lib/init/template/templateBase.js +4 -1
  67. package/lib/init/template/xsuaa/files/cds.cdsrc.json +7 -0
  68. package/lib/init/template/xsuaa/files/cds.cdsrc.json.hbs +9 -0
  69. package/lib/init/template/xsuaa/files/cds.package.json +1 -1
  70. package/lib/init/template/xsuaa/files/cds.package.json.hbs +11 -0
  71. package/lib/init/template/xsuaa/files/mta.yaml.hbs +2 -2
  72. package/lib/init/template/xsuaa/index.js +43 -27
  73. package/lib/init/types.d.ts +43 -19
  74. package/lib/init/util/fsUtil.js +15 -4
  75. package/lib/init/util/projectReader.js +21 -18
  76. package/lib/init/util/templateUtil.js +78 -28
  77. package/lib/util/exec.js +2 -2
  78. package/lib/watch/livereload-server.js +3 -0
  79. package/lib/watch/node-watch.js +8 -1
  80. package/npm-shrinkwrap.json +170 -148
  81. package/package.json +3 -3
  82. package/lib/init/template/approuter/files/xs-app.json +0 -8
  83. 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} pCsdl CSDL document
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
- pCsdl,
32
+ csdl,
33
33
  {
34
- url: gServiceRoot,
35
- scheme: pScheme = 'https',
36
- host: pHost = 'localhost',
37
- basePath: pBasePath = '/service-root',
38
- diagram: pDiagram = false,
39
- maxLevels: pMaxLevels = 5
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
- gServiceRoot = gServiceRoot || (pScheme + '://' + pHost + pBasePath);
43
- const gQueryOptionPrefix = pCsdl.$Version <= '4.0' ? '$' : '';
44
- const gTypesToInline = {}; // filled in schema() and used in inlineTypes()
45
- const gBoundOverloads = {};
46
- const gDerivedTypes = {};
47
- const gAlias = {};
48
- const gNamespace = { 'Edm': 'Edm' };
49
- const gNamespaceUrl = {};
50
- const gVoc = {};
51
- preProcess(pCsdl, gBoundOverloads, gDerivedTypes, gAlias, gNamespace, gNamespaceUrl, gVoc);
52
-
53
- const gEntityContainer = pCsdl.$EntityContainer ? modelElement(pCsdl.$EntityContainer) : {};
54
- const gKeyAsSegment = gEntityContainer[gVoc.Capabilities.KeyAsSegmentSupported];
55
- const gDeepUpdate = gEntityContainer[gVoc.Capabilities.DeepUpdateSupport] && gEntityContainer[gVoc.Capabilities.DeepUpdateSupport].Supported;
56
-
57
- const gOpenapi = {
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(pCsdl, gEntityContainer),
60
- servers: getServers(gServiceRoot),
61
- tags: getTags(gEntityContainer),
62
- paths: getPaths(gEntityContainer),
63
- components: getComponents(pCsdl, gEntityContainer)
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 (!pCsdl.$EntityContainer) {
66
- delete gOpenapi.servers;
67
- delete gOpenapi.tags;
65
+ if (!csdl.$EntityContainer) {
66
+ delete openapi.servers;
67
+ delete openapi.tags;
68
68
  }
69
69
 
70
- security(gOpenapi, gEntityContainer);
70
+ security(openapi, entityContainer);
71
71
 
72
- return gOpenapi;
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} pEntityContainer Entity Container object
207
+ * @param {object} entityContainer Entity Container object
204
208
  * @return {object} Info Object
205
209
  */
206
- function getInfo(csdl, pEntityContainer) {
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
- pEntityContainer[gVoc.Core.LongDescription]
211
- || containerSchema[gVoc.Core.LongDescription]
212
- || 'This service is located at [' + gServiceRoot + '/]('
213
- + gServiceRoot.replace(/\(/g, '%28').replace(/\)/g, '%29') + '/)'
214
- ) + (pDiagram ? getResourceDiagram(csdl, pEntityContainer) : '');
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: pEntityContainer[gVoc.Core.Description]
217
- || containerSchema[gVoc.Core.Description]
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[gVoc.Core.SchemaVersion] || ''
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
- if (overload.$ReturnType) {
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
- const iOverload = unbound[0];
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 = pCsdl[q.qualifier] || pCsdl[gNamespace[q.qualifier]];
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 tag = { name: child };
358
- const type = modelElement(container[child].$Type);
359
- const description = container[child][gVoc.Core.Description]
360
- || type && type[gVoc.Core.Description];
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, name, name, child, 0, '');
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 < pMaxLevels)
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[gVoc.Capabilities.NavigationRestrictions] || {};
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[gVoc.Capabilities.ExpandRestrictions] || {};
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[gVoc.Capabilities.IndexableByKey] != false;
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[gVoc.Capabilities.InsertRestrictions] || {};
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[gVoc.Core.Description] || 'New ' + lname,
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[gVoc.Capabilities.ReadRestrictions];
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[gVoc.Capabilities.ChangeTracking] && element[gVoc.Capabilities.ChangeTracking].Supported;
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: pBasePath + '/' + name + '?$deltatoken=opaque server-generated token for fetching the delta'
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 (pCsdl.$Version >= '4.0') optionSearch(operation.parameters, target, restrictions);
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[gVoc.Capabilities.CountRestrictions];
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[gVoc.Capabilities.ExpandRestrictions];
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: gQueryOptionPrefix + 'expand',
666
- description: (targetRestrictions && targetRestrictions[gVoc.Core.Description])
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 < pMaxLevels) {
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[gVoc.Capabilities.FilterRestrictions] || {};
728
+ const filterRestrictions = restrictions.FilterRestrictions || target && target[voc.Capabilities.FilterRestrictions] || {};
712
729
 
713
730
  if (filterRestrictions.Filterable !== false) {
714
731
  const filter = {
715
- name: gQueryOptionPrefix + 'filter',
716
- description: filterRestrictions[gVoc.Core.Description]
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[gVoc.Capabilities.SortRestrictions] || {};
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: gQueryOptionPrefix + 'orderby',
758
- description: sortRestrictions[gVoc.Core.Description]
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[gVoc.Capabilities.SearchRestrictions] || {};
914
+ const searchRestrictions = restrictions.SearchRestrictions || target && target[voc.Capabilities.SearchRestrictions] || {};
898
915
 
899
916
  if (searchRestrictions.Searchable !== false) {
900
- if (searchRestrictions[gVoc.Core.Description]) {
917
+ if (searchRestrictions[voc.Core.Description]) {
901
918
  parameters.push({
902
- name: gQueryOptionPrefix + 'search',
903
- description: searchRestrictions[gVoc.Core.Description],
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[gVoc.Capabilities.SelectSupport] || {};
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: gQueryOptionPrefix + 'select',
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[gVoc.Capabilities.SkipSupported] !== false;
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[gVoc.Capabilities.TopSupported] !== false;
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[gVoc.Capabilities.UpdateRestrictions] || {};
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[gVoc.Core.Description] || 'New property values',
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[gVoc.Capabilities.DeleteRestrictions] || {};
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[gVoc.Capabilities.NavigationRestrictions] || {};
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 < pMaxLevels) {
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 = gEntityContainer[targetSetName];
1071
- pathItems(paths, prefix + '/' + name, prefixParameters, properties[name], root, sourceName, targetSetName, target, level + 1, navigationPath);
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 < pMaxLevels) {
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 gProperties = propertiesOfStructuredType(entityType);
1159
+ const properties = propertiesOfStructuredType(entityType);
1141
1160
 
1142
1161
  keys.forEach((key, index) => {
1143
1162
  const suffix = level > 0 ? '_' + level : '';
1144
- if (gKeyAsSegment)
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 = gProperties[key];
1173
+ property = properties[key];
1155
1174
  } else {
1156
1175
  parameter = Object.keys(key)[0];
1157
1176
  const segments = key[parameter].split('/');
1158
- property = gProperties[segments[0]];
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[gVoc.Core.Description], property[gVoc.Core.LongDescription]].filter(t => t).join(' \n')
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: (gKeyAsSegment ? '' : '(') + segment + (gKeyAsSegment ? '' : ')'), parameters: params };
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 (gKeyAsSegment) return '';
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 (gKeyAsSegment) return '';
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 = gBoundOverloads[element.$Type + (!byKey && element.$Collection ? '-c' : '')] || [];
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[gVoc.Core.Description] || overload[gVoc.Core.Description] || 'Invoke action ' + name,
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[gVoc.Core.LongDescription] || overload[gVoc.Core.LongDescription];
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 = pCsdl.$Version > '4.0' || parameters.some(p => p[gVoc.Core.OptionalParameter]);
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[gVoc.Core.OptionalParameter] : true
1333
+ required: implicitAliases ? !p[voc.Core.OptionalParameter] : true
1315
1334
  };
1316
- const description = [p[gVoc.Core.Description], p[gVoc.Core.LongDescription]].filter(t => t).join(' \n');
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 + '=' + pathValuePrefix(p.$Type) + '{' + p.$Name + '}' + pathValueSuffix(p.$Type));
1363
+ pathSegments.push(p.$Name + "={" + p.$Name + "}");
1345
1364
  param.in = 'path';
1346
1365
  }
1347
1366
  param.name = p.$Name;
1348
- param.schema = getSchema(p, '', true);
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[gVoc.Core.Description] || overload[gVoc.Core.Description] || 'Invoke function ' + name,
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[gVoc.Core.LongDescription] || overload[gVoc.Core.LongDescription];
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[gVoc.Capabilities.BatchSupport] || {};
1374
- const supported = container[gVoc.Capabilities.BatchSupported] !== false && batchSupport.Supported !== false;
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[gVoc.Core.Description] || 'Send a group of requests',
1380
- description: (batchSupport[gVoc.Core.LongDescription] || 'Group multiple requests into a single request payload, see '
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[pCsdl.$Version < '4.0' ? 202 : 200] = {
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
- [pCsdl.$Version > '4.0' ? '@count' : '@odata.count']: ref('count'),
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 (gTypesToInline.geoPoint) {
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[gVoc.Core.Description];
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[gVoc.Core.Description];
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}@${pCsdl.$Version === '4.0' ? 'odata.' : ''}count`] = ref('count');
1643
+ allProperties[`${iName}@${csdl.$Version === '4.0' ? 'odata.' : ''}count`] = ref('count');
1620
1644
  }
1621
1645
  creProperties[iName] = getSchema(property, '-create');
1622
- if (gDeepUpdate)
1646
+ if (deepUpdate)
1623
1647
  updProperties[iName] = getSchema(property, '-create');
1624
1648
  } else {
1625
- if (property[gVoc.Core.Permissions] == 'Read' || property[gVoc.Core.Computed]) {
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[gVoc.Core.Immutable])
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[gVoc.Core.Description];
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 (gDerivedTypes[allName]) {
1688
+ if (derivedTypes[allName]) {
1665
1689
  schemas[allName].anyOf = [];
1666
1690
  schemas[creName].anyOf = [];
1667
1691
  schemas[updName].anyOf = [];
1668
- gDerivedTypes[allName].forEach(derivedType => {
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: gQueryOptionPrefix + 'top',
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: gQueryOptionPrefix + 'skip',
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: gQueryOptionPrefix + 'count',
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 (pCsdl.$Version >= '4.0') param.search = {
1732
- name: gQueryOptionPrefix + 'search',
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 (pCsdl.$Version < '4.0') {
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
- gTypesToInline.geoPoint = true;
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[gVoc.JSON.Schema];
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[gVoc.Core.Example]) {
2019
+ if (element[voc.Core.Example]) {
1996
2020
  if (s.$ref) s = { allOf: [s] };
1997
- s.example = element[gVoc.Core.Example].Value;
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[gVoc.Validation.Maximum] != undefined) {
2048
+ if (element[voc.Validation.Maximum] != undefined) {
2001
2049
  if (s.$ref) s = { allOf: [s] };
2002
- s.maximum = element[gVoc.Validation.Maximum];
2003
- if (element[gVoc.Validation.Maximum + gVoc.Validation.Exclusive]) s.exclusiveMaximum = true;
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[gVoc.Validation.Minimum] != undefined) {
2054
+ if (element[voc.Validation.Minimum] != undefined) {
2007
2055
  if (s.$ref) s = { allOf: [s] };
2008
- s.minimum = element[gVoc.Validation.Minimum];
2009
- if (element[gVoc.Validation.Minimum + gVoc.Validation.Exclusive]) s.exclusiveMinimum = true;
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[gVoc.Core.Description]) {
2067
+ if (!forParameter && element[voc.Core.Description]) {
2020
2068
  if (s.$ref) s = { allOf: [s] };
2021
- s.description = element[gVoc.Core.Description];
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[gVoc.Validation.AllowedValues];
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[gVoc.Validation.Pattern];
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 = gNamespace[parts.qualifier];
2107
+ nsp = namespace[parts.qualifier];
2060
2108
  name = nsp + '.' + parts.name;
2061
- url = gNamespaceUrl[nsp] || '';
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[gVoc.Authorization.Authorizations] || [];
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[gVoc.Authorization.SecuritySchemes] || [];
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 gNamespace[np.qualifier] + '.' + np.name;
2216
+ return namespace[np.qualifier] + '.' + np.name;
2169
2217
  }
2170
2218
 
2171
2219
  /**