@sap/cds-compiler 3.4.4 → 3.5.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 (129) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +1 -0
  3. package/bin/cds_update_identifiers.js +5 -5
  4. package/bin/cdsc.js +12 -12
  5. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  6. package/doc/CHANGELOG_BETA.md +9 -1
  7. package/doc/CHANGELOG_DEPRECATED.md +2 -0
  8. package/lib/api/main.js +58 -59
  9. package/lib/api/options.js +4 -2
  10. package/lib/api/validate.js +2 -2
  11. package/lib/base/cleanSymbols.js +2 -3
  12. package/lib/base/dictionaries.js +6 -6
  13. package/lib/base/error.js +2 -2
  14. package/lib/base/keywords.js +6 -6
  15. package/lib/base/location.js +11 -12
  16. package/lib/base/message-registry.js +124 -28
  17. package/lib/base/messages.js +247 -179
  18. package/lib/base/model.js +14 -11
  19. package/lib/base/node-helpers.js +9 -10
  20. package/lib/base/optionProcessorHelper.js +138 -129
  21. package/lib/checks/actionsFunctions.js +5 -5
  22. package/lib/checks/annotationsOData.js +4 -4
  23. package/lib/checks/arrayOfs.js +1 -1
  24. package/lib/checks/cdsPersistence.js +1 -1
  25. package/lib/checks/checkForTypes.js +3 -3
  26. package/lib/checks/defaultValues.js +3 -3
  27. package/lib/checks/elements.js +7 -7
  28. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  29. package/lib/checks/foreignKeys.js +1 -1
  30. package/lib/checks/invalidTarget.js +4 -4
  31. package/lib/checks/managedInType.js +1 -1
  32. package/lib/checks/managedWithoutKeys.js +1 -1
  33. package/lib/checks/nonexpandableStructured.js +5 -3
  34. package/lib/checks/nullableKeys.js +1 -1
  35. package/lib/checks/onConditions.js +5 -6
  36. package/lib/checks/parameters.js +1 -1
  37. package/lib/checks/queryNoDbArtifacts.js +2 -2
  38. package/lib/checks/selectItems.js +4 -4
  39. package/lib/checks/sql-snippets.js +4 -4
  40. package/lib/checks/types.js +7 -7
  41. package/lib/checks/utils.js +4 -4
  42. package/lib/checks/validator.js +16 -13
  43. package/lib/compiler/.eslintrc.json +1 -1
  44. package/lib/compiler/assert-consistency.js +0 -1
  45. package/lib/compiler/builtins.js +1 -1
  46. package/lib/compiler/checks.js +73 -15
  47. package/lib/compiler/define.js +3 -7
  48. package/lib/compiler/extend.js +212 -32
  49. package/lib/compiler/finalize-parse-cdl.js +7 -2
  50. package/lib/compiler/index.js +17 -14
  51. package/lib/compiler/populate.js +2 -5
  52. package/lib/compiler/propagator.js +2 -0
  53. package/lib/compiler/shared.js +23 -12
  54. package/lib/compiler/tweak-assocs.js +5 -6
  55. package/lib/compiler/utils.js +6 -0
  56. package/lib/edm/annotations/genericTranslation.js +553 -319
  57. package/lib/edm/annotations/preprocessAnnotations.js +39 -35
  58. package/lib/edm/csn2edm.js +88 -75
  59. package/lib/edm/edm.js +17 -3
  60. package/lib/edm/edmAnnoPreprocessor.js +5 -5
  61. package/lib/edm/edmPreprocessor.js +106 -76
  62. package/lib/edm/edmUtils.js +41 -2
  63. package/lib/gen/Dictionary.json +34 -0
  64. package/lib/gen/language.checksum +1 -1
  65. package/lib/gen/language.interp +66 -63
  66. package/lib/gen/language.tokens +81 -81
  67. package/lib/gen/languageLexer.interp +4 -10
  68. package/lib/gen/languageLexer.js +854 -869
  69. package/lib/gen/languageLexer.tokens +79 -81
  70. package/lib/gen/languageParser.js +14360 -14146
  71. package/lib/inspect/inspectModelStatistics.js +2 -2
  72. package/lib/inspect/inspectPropagation.js +6 -6
  73. package/lib/inspect/inspectUtils.js +2 -2
  74. package/lib/json/from-csn.js +82 -40
  75. package/lib/json/to-csn.js +82 -157
  76. package/lib/language/.eslintrc.json +1 -4
  77. package/lib/language/genericAntlrParser.js +59 -38
  78. package/lib/language/language.g4 +1508 -1490
  79. package/lib/language/multiLineStringParser.js +1 -1
  80. package/lib/main.js +3 -3
  81. package/lib/model/csnUtils.js +130 -122
  82. package/lib/model/revealInternalProperties.js +1 -1
  83. package/lib/model/sortViews.js +4 -6
  84. package/lib/modelCompare/utils/filter.js +4 -3
  85. package/lib/optionProcessor.js +5 -0
  86. package/lib/render/DuplicateChecker.js +1 -1
  87. package/lib/render/manageConstraints.js +12 -12
  88. package/lib/render/toCdl.js +225 -159
  89. package/lib/render/toHdbcds.js +63 -63
  90. package/lib/render/toRename.js +5 -5
  91. package/lib/render/toSql.js +55 -65
  92. package/lib/render/utils/common.js +20 -37
  93. package/lib/render/utils/delta.js +3 -3
  94. package/lib/render/utils/sql.js +22 -6
  95. package/lib/render/utils/stringEscapes.js +3 -3
  96. package/lib/transform/db/applyTransformations.js +3 -3
  97. package/lib/transform/db/assertUnique.js +13 -12
  98. package/lib/transform/db/associations.js +5 -5
  99. package/lib/transform/db/cdsPersistence.js +10 -8
  100. package/lib/transform/db/constraints.js +14 -14
  101. package/lib/transform/db/expansion.js +20 -22
  102. package/lib/transform/db/flattening.js +24 -42
  103. package/lib/transform/db/groupByOrderBy.js +3 -3
  104. package/lib/transform/db/temporal.js +6 -6
  105. package/lib/transform/db/transformExists.js +23 -23
  106. package/lib/transform/db/views.js +16 -16
  107. package/lib/transform/draft/db.js +10 -10
  108. package/lib/transform/draft/odata.js +2 -2
  109. package/lib/transform/forOdataNew.js +12 -40
  110. package/lib/transform/forRelationalDB.js +17 -7
  111. package/lib/transform/localized.js +2 -2
  112. package/lib/transform/odata/toFinalBaseType.js +41 -27
  113. package/lib/transform/odata/typesExposure.js +106 -62
  114. package/lib/transform/parseExpr.js +209 -106
  115. package/lib/transform/transformUtilsNew.js +2 -2
  116. package/lib/transform/translateAssocsToJoins.js +24 -19
  117. package/lib/transform/universalCsn/coreComputed.js +10 -10
  118. package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
  119. package/lib/transform/universalCsn/utils.js +3 -3
  120. package/lib/utils/file.js +5 -5
  121. package/lib/utils/moduleResolve.js +13 -13
  122. package/lib/utils/objectUtils.js +6 -6
  123. package/lib/utils/term.js +5 -2
  124. package/lib/utils/timetrace.js +51 -24
  125. package/package.json +5 -7
  126. package/share/messages/check-proper-type-of.md +1 -1
  127. package/share/messages/message-explanations.json +1 -1
  128. package/share/messages/redirected-to-complex.md +4 -4
  129. package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
@@ -18,7 +18,7 @@ const NavResAnno = '@Capabilities.NavigationRestrictions.RestrictedProperties';
18
18
  const capabilities = Object.keys(require('../gen/Dictionary.json').
19
19
  types['Capabilities.NavigationPropertyRestriction'].Properties).
20
20
  filter(c => !['NavigationProperty', 'Navigability'].includes(c)).
21
- map(c => `@Capabilities.`+c);
21
+ map(c => '@Capabilities.'+c);
22
22
 
23
23
  /**
24
24
  * edmPreprocessor warms up the model so that it can be converted into an EDM document and
@@ -128,6 +128,10 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
128
128
  },
129
129
  linkAssociationTarget
130
130
  ]);
131
+ forEachGeneric(csn, 'vocabularies', (term, termName) => {
132
+ const mySchemaName = whatsMySchemaName(termName);
133
+ mySchemaName && setProp(term, '$mySchemaName', mySchemaName);
134
+ });
131
135
  // initialize requested services
132
136
  const skip = { skipArtifact: (_def, defName) => !isMyServiceRequested(defName) };
133
137
  forEachDefinition({ definitions: serviceRoots }, initService, skip);
@@ -161,7 +165,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
161
165
  if(options.isV4())
162
166
  forEachDefinition(reqDefs, [
163
167
  initEdmNavPropBindingTargets,
164
- rewriteContainmentAnnotations,
168
+ pullupCapabilitiesAnnotations,
165
169
  annotateOptionalActFuncParams
166
170
  ]);
167
171
 
@@ -172,7 +176,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
172
176
  forEachDefinition(reqDefs, [
173
177
  initEdmKeyRefPaths,
174
178
  initEdmNavPropBindingPaths,
175
- initEdmTypesAndDescription
179
+ finalize
176
180
  ]);
177
181
  }
178
182
  return [
@@ -275,36 +279,42 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
275
279
  }
276
280
  });
277
281
  // rename type refs to new type names
278
- forEachDefinition(csn, def => {
279
- forEachMemberRecursively(def, member => {
280
- member = member.items || member;
281
- if(member.type && dotTypeNameMap[member.type]) {
282
- member.type = dotTypeNameMap[member.type];
282
+ const rewrite = (def) => {
283
+ const applyOnNode = (node) => {
284
+ node = node.items || node;
285
+ if(node.type && dotTypeNameMap[node.type]) {
286
+ node.type = dotTypeNameMap[node.type];
283
287
  }
284
- if(member.target && dotEntityNameMap[member.target]) {
285
- member.target = dotEntityNameMap[member.target];
288
+ if(node.target && dotEntityNameMap[node.target]) {
289
+ node.target = dotEntityNameMap[node.target];
286
290
  }
287
- if(member.$path && dotEntityNameMap[member.$path[1]]) {
288
- member.$path[1] = dotEntityNameMap[member.$path[1]]
291
+ if(node.$path && dotEntityNameMap[node.$path[1]]) {
292
+ node.$path[1] = dotEntityNameMap[node.$path[1]]
289
293
  }
290
- _rewriteReferencesInActions(member);
291
- });
292
- // handle unbound action/function and params in views
293
- _rewriteReferencesInActions(def);
294
- });
294
+ rewriteReferencesInActions(node);
295
+ }
295
296
 
296
- function _rewriteReferencesInActions(act) {
297
- act.params && Object.values(act.params).forEach(param => {
298
- param = param.items || param;
299
- if(param.type && (dotEntityNameMap[param.type] || dotTypeNameMap[param.type]))
300
- param.type = dotEntityNameMap[param.type] || dotTypeNameMap[param.type];
301
- });
302
- if(act.returns){
303
- const returnsObj = act.returns.items || act.returns;
304
- if (returnsObj.type && dotEntityNameMap[returnsObj.type] || dotTypeNameMap[returnsObj.type])
305
- returnsObj.type = dotEntityNameMap[returnsObj.type] || dotTypeNameMap[returnsObj.type];
297
+ const rewriteReferencesInActions = (act) => {
298
+ act.params && Object.values(act.params).forEach(param => {
299
+ param = param.items || param;
300
+ if(param.type && (dotEntityNameMap[param.type] || dotTypeNameMap[param.type]))
301
+ param.type = dotEntityNameMap[param.type] || dotTypeNameMap[param.type];
302
+ });
303
+ if(act.returns){
304
+ const returnsObj = act.returns.items || act.returns;
305
+ if (returnsObj.type && dotEntityNameMap[returnsObj.type] || dotTypeNameMap[returnsObj.type])
306
+ returnsObj.type = dotEntityNameMap[returnsObj.type] || dotTypeNameMap[returnsObj.type];
307
+ }
306
308
  }
307
- }
309
+
310
+ forEachMemberRecursively(def, applyOnNode);
311
+ applyOnNode(def);
312
+ // handle unbound action/function and params in views
313
+ rewriteReferencesInActions(def);
314
+ };
315
+
316
+ forEachDefinition(csn, rewrite);
317
+ forEachGeneric(csn, 'vocabularies', rewrite);
308
318
  }
309
319
 
310
320
  /*
@@ -366,7 +376,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
366
376
  }
367
377
  }
368
378
  else {
369
- error(null, subpath, { target: element.target }, "Target $(TARGET) can't be found in the model");
379
+ error(null, subpath, { target: element.target }, 'Target $(TARGET) can\'t be found in the model');
370
380
  }
371
381
  }
372
382
  // in V4 tag all compositions to be containments
@@ -892,14 +902,14 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
892
902
  if(serviceRootNames.includes(targetSchemaName)) {
893
903
  // remove all definitions starting with < fqSchemaName >. and add a schema reference
894
904
  Object.keys(csn.definitions).forEach(dn => {
895
- if(dn.startsWith(fqSchemaName)) {// this includes the fqSchemaName context
905
+ if(dn.startsWith(fqSchemaName)) {
896
906
  delete csn.definitions[dn];
897
907
  delete reqDefs.definitions[dn];
898
908
  }
899
909
  });
900
910
  if(!schemas[fqSchemaName])
901
911
  schemaNames.push(fqSchemaName);
902
- schemas[fqSchemaName] = createSchemaRef(targetSchemaName);
912
+ schemas[fqSchemaName] = edmUtils.createSchemaRef(serviceRoots, targetSchemaName);
903
913
  }
904
914
  }
905
915
  });
@@ -1036,7 +1046,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1036
1046
  function createSchemaRefFor(targetSchemaName) {
1037
1047
  let ref = csn.definitions[globalSchemaPrefix + '.' + targetSchemaName];
1038
1048
  if(!ref) {
1039
- ref = createSchemaRef(targetSchemaName);
1049
+ ref = edmUtils.createSchemaRef(serviceRoots, targetSchemaName);
1040
1050
  }
1041
1051
 
1042
1052
  return ref;
@@ -1794,27 +1804,33 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1794
1804
  }
1795
1805
  }
1796
1806
 
1797
- function initEdmTypesAndDescription(def) {
1807
+ function finalize(def, defName) {
1798
1808
  // 1. let all doc props become @Core.Descriptions
1799
1809
  // 2. mark a member that will become a collection
1800
1810
  // 3. assign the edm primitive type to elements, to be used in the rendering later
1811
+ // 4. assign @Validation.AllowedValues to enums
1812
+ const path = ['definitions', defName];
1801
1813
  edmUtils.assignAnnotation(def, '@Core.Description', def.doc);
1802
1814
  markCollection(def);
1803
1815
  mapCdsToEdmProp(def);
1816
+ annotateAllowedValues(def, path);
1804
1817
  if (def.returns) {
1805
1818
  markCollection(def.returns);
1806
1819
  mapCdsToEdmProp(def.returns);
1820
+ annotateAllowedValues(def.returns, [...path, 'returns']);
1807
1821
  }
1808
- forEachMemberRecursively(def,member => {
1822
+ forEachMemberRecursively(def, (member, _memberName, _prop, path) => {
1809
1823
  edmUtils.assignAnnotation(member, '@Core.Description', member.doc);
1810
1824
  markCollection(member);
1811
1825
  mapCdsToEdmProp(member);
1826
+ annotateAllowedValues(member, path);
1812
1827
  ComputedDefaultValue(member);
1813
1828
  if (member.returns) {
1814
1829
  markCollection(member.returns);
1815
1830
  mapCdsToEdmProp(member.returns);
1831
+ annotateAllowedValues(member.returns, [...path, 'returns']);
1816
1832
  }
1817
- });
1833
+ }, path);
1818
1834
  // mark members that need to be rendered as collections
1819
1835
  function markCollection(obj) {
1820
1836
  const items = obj.items || csn.definitions[obj.type] && csn.definitions[obj.type].items;
@@ -1823,6 +1839,56 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1823
1839
  edmUtils.assignProp(obj, '_isCollection', true);
1824
1840
  }
1825
1841
  }
1842
+
1843
+ /*
1844
+ Add @Validation.AllowedValues annotation for all enum types
1845
+ A 'Value' is added if the enum symbol:
1846
+ - has a valid value other than 'null'
1847
+ - has no value but the base type is cds.String, use the
1848
+ symbol as value
1849
+ */
1850
+ function annotateAllowedValues(node, path) {
1851
+ let typeDef = node;
1852
+ if(!node.enum && node.type && !isBuiltinType(node.type))
1853
+ typeDef = csn.definitions[node.type];
1854
+ if(typeDef?.enum) {
1855
+ const enumValue = [];
1856
+ for(const enumSymbol in typeDef.enum) {
1857
+ let enumSymbolDef = typeDef.enum[enumSymbol];
1858
+ const result = { '@Core.SymbolicName': enumSymbol };
1859
+ if(enumSymbolDef['#'])
1860
+ enumSymbolDef = typeDef.enum[enumSymbolDef['#']];
1861
+ if(enumSymbolDef.val === undefined) {
1862
+ if(typeDef.type === 'cds.String') {
1863
+ // the symbol is used as value for type 'cds.String'
1864
+ result.Value = enumSymbol;
1865
+ enumValue.push(result);
1866
+ }
1867
+ else if(node.kind !== 'annotation')
1868
+ // omit the entry and warn
1869
+ warning('odata-enum-missing-value', path,
1870
+ { name: enumSymbol, anno: '@Valiation.AllowedValues', type: typeDef.type },
1871
+ 'Expected enum element $(NAME) of type $(TYPE) to have a value, not added to $(ANNO)');
1872
+ }
1873
+ else {
1874
+ // 'null' value is represented spec conform as empty record in AllowedValues collection
1875
+ //if(enumSymbolDef.val !== null)
1876
+ result.Value = enumSymbolDef.val;
1877
+ enumValue.push(result);
1878
+ }
1879
+
1880
+ // Can't rely that @description has already been renamed to @Core.Description
1881
+ // Eval description according to precedence (doc comment must be considered already in Odata transformer
1882
+ // as in contrast to the other doc commments as it is used to annotate the @Validation.AllowedValues)
1883
+ const desc = enumSymbolDef['@Core.Description'] || enumSymbolDef['@description'] || enumSymbolDef.doc;
1884
+ if (desc)
1885
+ result['@Core.Description'] = desc;
1886
+ }
1887
+ if(enumValue.length > 0)
1888
+ edmUtils.assignAnnotation(node, '@Validation.AllowedValues', enumValue);
1889
+ }
1890
+ }
1891
+
1826
1892
  }
1827
1893
 
1828
1894
  // If containment in V4 is active, annotations that would be assigned to the containees
@@ -1830,8 +1896,10 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1830
1896
  // the containment navigation property.
1831
1897
  // Today only Capabilities.*Restrictions are known to be remapped as there exists a CDS
1832
1898
  // short cut annotation @readonly that gets expanded and can be safely remapped.
1833
- function rewriteContainmentAnnotations(rootContainer) {
1899
+ function pullupCapabilitiesAnnotations(rootContainer) {
1834
1900
 
1901
+ if(!options.odataCapabilitiesPullup)
1902
+ return;
1835
1903
  // meaningless for non-entities and proxies
1836
1904
  if(rootContainer.kind !== 'entity' || rootContainer.$proxy)
1837
1905
  return;
@@ -1867,7 +1935,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1867
1935
  npe.NavigationProperty['='] &&
1868
1936
  typeof npe.NavigationProperty['='] === 'string') {
1869
1937
  applyTransformations({ definitions: { npe }}, {
1870
- "=": (parent, prop, value) => {
1938
+ '=': (parent, prop, value) => {
1871
1939
  parent[prop] = prefix.concat(value).join('.');
1872
1940
  }
1873
1941
  });
@@ -1975,45 +2043,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1975
2043
  // Helper section starts here
1976
2044
  //
1977
2045
 
1978
- //
1979
- // create Cross Schema Reference object
1980
- //
1981
- function createSchemaRef(targetSchemaName) {
1982
- // prepend as many path ups '..' as there are path steps in the service ref
1983
- let serviceRef = path4(serviceRoots[targetSchemaName]).split('/').filter(c=>c.length);
1984
- serviceRef.splice(0, 0, ...Array(serviceRef.length).fill('..'));
1985
- // uncomment this to make $metadata absolute
1986
- // if(serviceRef.length===0)
1987
- // serviceRef.push('');
1988
- if(serviceRef[serviceRef.length-1] !== '$metadata')
1989
- serviceRef.push('$metadata');
1990
- let sc = { kind: 'reference',
1991
- name: targetSchemaName,
1992
- ref: { Uri: serviceRef.join('/') },
1993
- inc: { Namespace: targetSchemaName }
1994
- };
1995
- setProp(sc, '$mySchemaName', targetSchemaName);
1996
- return sc;
1997
-
1998
- /**
1999
- * Resolve a service endpoint path to mount it to as follows...
2000
- * Use _path or def[@path] if given (and remove leading '/')
2001
- * Otherwise, use the service definition name with stripped 'Service'
2002
- */
2003
- function path4 (def, _path = def['@path']) {
2004
- if (_path)
2005
- return _path.replace(/^\//, "");
2006
- else
2007
- return ( // generate one from the service's name
2008
- /[^.]+$/.exec(def.name)[0] //> my.very.CatalogService --> CatalogService
2009
- .replace(/Service$/,'') //> CatalogService --> Catalog
2010
- .replace(/([a-z0-9])([A-Z])/g, (_,c,C) => c+'-'+C.toLowerCase()) //> ODataFooBarX9 --> odata-foo-bar-x9
2011
- .replace(/_/g,'-') //> foo_bar_baz --> foo-bar-baz
2012
- .toLowerCase() //> FOO --> foo
2013
- )
2014
- }
2015
- }
2016
-
2046
+
2017
2047
  function mapCdsToEdmProp(obj) {
2018
2048
  if (obj.type && isBuiltinType(obj.type) && !obj.target && !obj.targetAspect) {
2019
2049
  let edmType = edmUtils.mapCdsToEdmType(obj, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  const { setProp } = require('../base/model');
3
3
  const { isBuiltinType, isEdmPropertyRendered, applyTransformations, cloneAnnotationValue } = require('../model/csnUtils');
4
- const { escapeString, hasControlCharacters, hasUnpairedUnicodeSurrogate } = require("../render/utils/stringEscapes");
4
+ const { escapeString, hasControlCharacters, hasUnpairedUnicodeSurrogate } = require('../render/utils/stringEscapes');
5
5
 
6
6
  /* eslint max-statements-per-line:off */
7
7
  function validateOptions(_options)
@@ -769,7 +769,7 @@ function mergeIntoNavPropEntry(annoPrefix, navPropEntry, prefix, props) {
769
769
 
770
770
  // BEFORE merging found capabilities, prefix the paths
771
771
  applyTransformations({ definitions: { o }}, {
772
- "=": (parent, prop, value) => {
772
+ '=': (parent, prop, value) => {
773
773
  parent[prop] = prefix.concat(value).join('.');
774
774
  }
775
775
  });
@@ -830,11 +830,50 @@ function assignProp(obj, prop, value) {
830
830
  }
831
831
  }
832
832
 
833
+ //
834
+ // create Cross Schema Reference object
835
+ //
836
+ function createSchemaRef(serviceRoots, targetSchemaName) {
837
+ // prepend as many path ups '..' as there are path steps in the service ref
838
+ let serviceRef = path4(serviceRoots[targetSchemaName]).split('/').filter(c=>c.length);
839
+ serviceRef.splice(0, 0, ...Array(serviceRef.length).fill('..'));
840
+ // uncomment this to make $metadata absolute
841
+ // if(serviceRef.length===0)
842
+ // serviceRef.push('');
843
+ if(serviceRef[serviceRef.length-1] !== '$metadata')
844
+ serviceRef.push('$metadata');
845
+ let sc = { kind: 'reference',
846
+ name: targetSchemaName,
847
+ ref: { Uri: serviceRef.join('/') },
848
+ inc: { Namespace: targetSchemaName }
849
+ };
850
+ setProp(sc, '$mySchemaName', targetSchemaName);
851
+ return sc;
852
+
853
+ /**
854
+ * Resolve a service endpoint path to mount it to as follows...
855
+ * Use _path or def[@path] if given (and remove leading '/')
856
+ * Otherwise, use the service definition name with stripped 'Service'
857
+ */
858
+ function path4 (def, _path = def['@path']) {
859
+ if (_path)
860
+ return _path.replace(/^\//, '');
861
+ else
862
+ return ( // generate one from the service's name
863
+ /[^.]+$/.exec(def.name)[0] //> my.very.CatalogService --> CatalogService
864
+ .replace(/Service$/,'') //> CatalogService --> Catalog
865
+ .replace(/([a-z0-9])([A-Z])/g, (_,c,C) => c+'-'+C.toLowerCase()) //> ODataFooBarX9 --> odata-foo-bar-x9
866
+ .replace(/_/g,'-') //> foo_bar_baz --> foo-bar-baz
867
+ .toLowerCase() //> FOO --> foo
868
+ )
869
+ }
870
+ }
833
871
 
834
872
 
835
873
  module.exports = {
836
874
  assignAnnotation,
837
875
  assignProp,
876
+ createSchemaRef,
838
877
  validateOptions,
839
878
  intersect,
840
879
  foreach,
@@ -1499,6 +1499,23 @@
1499
1499
  ],
1500
1500
  "$experimental": true
1501
1501
  },
1502
+ "Offline.ClientOnly": {
1503
+ "Type": "Core.Tag",
1504
+ "AppliesTo": [
1505
+ "EntityType",
1506
+ "EntitySet",
1507
+ "EnumType",
1508
+ "ComplexType",
1509
+ "TypeDefinition"
1510
+ ],
1511
+ "$experimental": true
1512
+ },
1513
+ "PDF.Features": {
1514
+ "Type": "PDF.FeaturesType",
1515
+ "AppliesTo": [
1516
+ "EntityContainer"
1517
+ ]
1518
+ },
1502
1519
  "PersonalData.EntitySemantics": {
1503
1520
  "Type": "PersonalData.EntitySemanticsType",
1504
1521
  "AppliesTo": [
@@ -3357,6 +3374,23 @@
3357
3374
  "Symbols": {}
3358
3375
  }
3359
3376
  },
3377
+ "PDF.FeaturesType": {
3378
+ "$kind": "ComplexType",
3379
+ "Properties": {
3380
+ "DocumentDescriptionReference": "Edm.String",
3381
+ "DocumentDescriptionCollection": "Edm.String",
3382
+ "ArchiveFormat": "Edm.Boolean",
3383
+ "Signature": "Edm.Boolean",
3384
+ "CoverPage": "Edm.Boolean",
3385
+ "FontName": "Edm.Boolean",
3386
+ "FontSize": "Edm.Boolean",
3387
+ "Margin": "Edm.Boolean",
3388
+ "Border": "Edm.Boolean",
3389
+ "FitToPage": "Edm.Boolean",
3390
+ "ResultSizeDefault": "Edm.Int32",
3391
+ "ResultSizeMaximum": "Edm.Int32"
3392
+ }
3393
+ },
3360
3394
  "PersonalData.EntitySemanticsType": {
3361
3395
  "$kind": "TypeDefinition",
3362
3396
  "UnderlyingType": "Edm.String",
@@ -1 +1 @@
1
- 1afc5561b6e2c0af3e294a6781ba278c
1
+ bdbb2e738b68d13dc2f0f03c0caf5fc0