@sap/cds-dk 4.5.3 → 4.6.3

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 (48) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/bin/bind.js +124 -8
  3. package/bin/cds-ts.js +1 -1
  4. package/bin/cds.js +1 -0
  5. package/bin/compile/index.js +2 -1
  6. package/bin/env.js +50 -9
  7. package/bin/help.js +1 -0
  8. package/bin/import.js +34 -14
  9. package/bin/repl.js +6 -2
  10. package/bin/watch.js +59 -14
  11. package/lib/bind/bindingResolver.js +138 -0
  12. package/lib/bind/cfKeyProvider.js +353 -0
  13. package/lib/bind/userCdsrcJsonStorageProvider.js +144 -0
  14. package/lib/client/activate.js +3 -9
  15. package/lib/client/auth_manager.js +4 -4
  16. package/lib/client/extend.js +4 -9
  17. package/lib/client/settings_manager.js +6 -5
  18. package/lib/import/common.js +10 -1
  19. package/lib/import/importapi.js +4 -3
  20. package/lib/import/index.js +34 -5
  21. package/lib/import/message.js +1 -0
  22. package/lib/import/utils/MetadataConverter.js +25 -4
  23. package/lib/import/utils/MetadataConverterFactory.js +1 -2
  24. package/lib/import/utils/MultiMap.js +26 -0
  25. package/lib/import/v2parser.js +137 -16
  26. package/lib/import/v4parser.js +212 -172
  27. package/lib/init/constants.js +1 -1
  28. package/lib/init/template/data/index.js +11 -1
  29. package/lib/init/template/hana/index.js +16 -20
  30. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +36 -52
  31. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +15 -0
  32. package/lib/init/template/lint/index.js +19 -17
  33. package/lib/init/template/mta/files/mta.yaml.hbs +0 -7
  34. package/lib/init/template/mta/projectReader.js +1 -3
  35. package/lib/init/template/mtx/files/xs-security.json.hbs +3 -1
  36. package/lib/init/template/mtx/package/dependencies.package.json +1 -1
  37. package/lib/init/template/nodejs/files/.gitignore.hbs +1 -0
  38. package/lib/init/template/samples/index.js +1 -1
  39. package/lib/init/template/templateBase.js +10 -41
  40. package/lib/init/util/commandUtil.js +5 -0
  41. package/lib/lint/Linter.js +19 -28
  42. package/lib/lint/generators.js +5 -4
  43. package/lib/lint/io.js +76 -51
  44. package/lib/util/term.js +2 -0
  45. package/lib/watch/node-watch.js +38 -19
  46. package/npm-shrinkwrap.json +1435 -1946
  47. package/package.json +3 -3
  48. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/test.js +0 -10
@@ -26,12 +26,12 @@ function getTokenUrl(params) {
26
26
  tokenUrl.search = `subdomain=${params.get('subdomain')}`;
27
27
 
28
28
  if (params.has('refreshToken')) {
29
- tokenUrl.search += `&refresh_token=${params.get('refreshToken')}`;
29
+ tokenUrl.search += `&refresh_token=${encodeURIComponent(params.get('refreshToken'))}`;
30
30
  } else if (params.has('passcode')) {
31
- tokenUrl.search += `&passcode=${params.get('passcode')}`;
31
+ tokenUrl.search += `&passcode=${encodeURIComponent(params.get('passcode'))}`;
32
32
  }
33
33
  if (params.has('clientid')) {
34
- tokenUrl.search += `&clientid=${params.get('clientid')}&clientsecret=${params.get('clientsecret')}`;
34
+ tokenUrl.search += `&clientid=${encodeURIComponent(params.get('clientid'))}&clientsecret=${encodeURIComponent(params.get('clientsecret'))}`;
35
35
  }
36
36
  return tokenUrl.toString();
37
37
  }
@@ -58,7 +58,7 @@ async function retrieveTokenOrPasscodeUrl(params) {
58
58
 
59
59
  let response;
60
60
  try {
61
- response = await axios(tokenUrl.toString(), { method: 'GET' });
61
+ response = await axios.get(tokenUrl);
62
62
  } catch (error) {
63
63
  throw new Error(`Failed to get authentication token: ${error}.\nResponse body: ${util.inspect(response && response.data)}`);
64
64
  }
@@ -104,15 +104,12 @@ module.exports = class Extend extends BaseCommand {
104
104
  }
105
105
 
106
106
  static async runExtend(params) {
107
- const extendUrl = Extend.getMtxApiUrl(params.get('appUrl'), COMMAND_URL_SUFFIX);
108
- const requestOptions = Object.assign({
109
- method: 'GET',
110
- retry: 0
111
- }, params.get('reqAuth'));
107
+ const contentUrl = Extend.getMtxApiUrl(params.get('appUrl'), COMMAND_URL_SUFFIX);
108
+ const requestOptions = Object.assign({ retry: 0 }, params.get('reqAuth'));
112
109
 
113
110
  Logger.log('Retrieving files...');
114
111
 
115
- const [ response ] = (await axios(extendUrl, requestOptions)).data;
112
+ const [ response ] = (await axios.get(contentUrl, requestOptions)).data;
116
113
 
117
114
  Logger.log('\nWriting files to: ' + params.get('projectFolder'));
118
115
 
@@ -142,11 +139,9 @@ module.exports = class Extend extends BaseCommand {
142
139
  }
143
140
 
144
141
  if (params.get('wsdl')) {
145
-
146
142
  Logger.log('Writing custom files');
147
-
148
143
  const customFileUrl = Extend.getMtxApiUrl(params.get('appUrl'), Extend.CUSTOM_FILE_URL_SUFFIX);
149
- const customFiles = (await axios(customFileUrl, params)).data;
144
+ const customFiles = (await axios.get(customFileUrl, requestOptions)).data;
150
145
  await Extend.storeCustomFiles(params.get('projectFolder'), customFiles);
151
146
  }
152
147
  }
@@ -55,7 +55,7 @@ function other(tokenStorage) {
55
55
 
56
56
  function getProjectFolder(params) {
57
57
  const relativePath = params.get('projectFolder') || params.get('directory') || (
58
- params.has('subdomain') && fse.existsSync(path.resolve(params.get('subdomain')))
58
+ params.has('subdomain') && fse.existsSync(params.get('subdomain'))
59
59
  ? params.get('subdomain')
60
60
  : '.'
61
61
  );
@@ -138,7 +138,7 @@ class SettingsManager {
138
138
  if (params.get('clearOtherTokenStorage')) {
139
139
  // Delete token from the other storage.
140
140
  params.delete('clearOtherTokenStorage');
141
- await this.deleteToken(params, other(params.get('tokenStorage')));
141
+ await this.deleteToken(params, true);
142
142
  }
143
143
 
144
144
  if (params.get('tokenStorage') === 'plain') {
@@ -303,15 +303,16 @@ class SettingsManager {
303
303
  }
304
304
  }
305
305
 
306
- static async deleteToken(params, fromStorage) {
306
+ static async deleteToken(params, fromOtherStorage = false) {
307
307
  const allParams = params.clone();
308
308
  await this.loadAndMergeSettings(allParams, true);
309
309
 
310
310
  const target = `URL ${allParams.get('appUrl')}, subdomain '${allParams.get('subdomain')}'`;
311
- Logger.debug(`Deleting authentication data for ${target}`);
312
-
311
+ let fromStorage = fromOtherStorage && other(params.get('tokenStorage'))
313
312
  const deleteBoth = !fromStorage && allParams.get('tokenStorage') && allParams.get('clearOtherTokenStorage');
314
313
 
314
+ Logger.debug(`Deleting authentication data${fromOtherStorage ? ' from other storage' : ''} for ${target}`);
315
+
315
316
  fromStorage = fromStorage || allParams.get('tokenStorage');
316
317
  if (!fromStorage) {
317
318
  Logger.log(`No authentication data found for ${target}`);
@@ -30,6 +30,14 @@ function checkForEmptyKeys(element, oDataVersion) {
30
30
  }
31
31
  }
32
32
 
33
+ //to replace the alias value with original schema namespace value
34
+ function replaceAliasValue(schemaContent, schemaNamespaceValue, aliasValue){
35
+ const re = RegExp(`([("/])${aliasValue}([/").])`, 'g');
36
+ const val = `$1${schemaNamespaceValue}$2`;
37
+ schemaContent = schemaContent.replace(re, val);
38
+ return JSON.parse(schemaContent);
39
+ }
40
+
33
41
  async function _getODataVersion(edmx) {
34
42
  let oDataVersion;
35
43
  let jsonObj;
@@ -115,5 +123,6 @@ module.exports = {
115
123
  getVersion,
116
124
  getSuffix,
117
125
  supportedFormats,
118
- checkForEmptyKeys
126
+ checkForEmptyKeys,
127
+ replaceAliasValue
119
128
  };
@@ -1,5 +1,7 @@
1
1
  const edm2csn = require('.');
2
-
2
+ let context={};
3
+ context.oDataInfo = {};
4
+ context.namespaces = [];
3
5
  /**
4
6
  * This is the import API function to generate CSN from XML/EDMX files.
5
7
  * @param {string} filepath
@@ -10,11 +12,10 @@ const edm2csn = require('.');
10
12
  * - other import options not supported
11
13
  * @returns {object} CSN
12
14
  */
13
- const oDataInfo={};
14
15
  module.exports = async function cds_import(filepath, options = {keepNamespace : false}) //namespace will be taken as false in case it is not mentioned
15
16
  {
16
17
  filepath = await edm2csn.isValidInputFile(filepath);
17
18
  let edmx= await edm2csn.getMetadataFromFile(filepath);
18
- let csn = await edm2csn.edmx2csn(edmx, !options.keepNamespace && filepath, false, oDataInfo);
19
+ let csn = await edm2csn.edmx2csn(edmx, !options.keepNamespace && filepath, context);
19
20
  return csn;
20
21
  }
@@ -116,7 +116,15 @@ function _convertEDMXWithMultipleSchemas(edmx, multipleSchemas, namespace) {
116
116
  </Schema>
117
117
  </edmx:DataServices>
118
118
  */
119
- edmx = edmx.replace(multipleSchemas, '').replace(/<Schema Namespace="[^"]+"/, `<Schema Namespace="${namespace}"`);
119
+
120
+ // Remove the ending and beginning of the first and second schema tag
121
+ edmx = edmx.replace(multipleSchemas, '');
122
+ // Now capture the schema tag details
123
+ let schemaDetails = edmx.match(/(<Schema [^>]*>)/);
124
+ // Replace the Namespace value with the correct one
125
+ schemaDetails = schemaDetails[0].replace(/Namespace="[^"]+"/, `Namespace="${namespace}"`);
126
+ // Place the above computed schema details in the edmx content
127
+ edmx = edmx.replace(/(<Schema [^>]*>)/, `${schemaDetails}`);
120
128
 
121
129
  return edmx;
122
130
  }
@@ -132,7 +140,7 @@ async function edmx2csn(edmx, filename, context) {
132
140
  if (multipleSchemas.test(edmx)) {
133
141
  edmx = _convertEDMXWithMultipleSchemas(edmx, multipleSchemas, namespace);
134
142
  }
135
- let csn = await generateCSN(edmx, true, context);
143
+ let csn = await generateCSN(edmx, false, true, context);
136
144
  if (filename) {
137
145
  // Replace namespace by given filename in the csn file instead of edmx file
138
146
  const re = RegExp(`([("/])${namespace}([/").])`, 'g');
@@ -151,20 +159,33 @@ async function _generateEDMX2JSON(edmx) {
151
159
  return JSON.parse(cjson);
152
160
  }
153
161
 
154
- async function generateCSN(edmx, mockServerUc, context) {
162
+ async function generateCSN(edmx, ignorePersistenceSkip, mockServerUc, context) {
155
163
  let csn;
156
164
  let odataVersion;
157
165
  let edmx2jsonModel;
166
+ let defaultNamespaces;
167
+ let namespaces = [];
168
+ if(context.namespaces) namespaces.push(...(context.namespaces));
158
169
  odataVersion = await common.getVersion(edmx);
159
170
  if (odataVersion === "V2") {
160
171
  if(context){
161
172
  context.oDataVersion = "V2";
162
173
  }
174
+ //default namespaces to be present
175
+ if(!context.include_all_namespaces)
176
+ {
177
+ defaultNamespaces = ['edmx','sap','m'];
178
+ namespaces = namespaces.concat(defaultNamespaces);
179
+ namespaces = namespaces.filter((item,pos) => namespaces.indexOf(item) === pos); //removing duplicate values
180
+ }
181
+ context.namespaces = namespaces;
163
182
  edmx2jsonModel = await _generateEDMX2JSON(edmx);
164
183
  return new Promise(function getCsn(resolve, reject) {
165
184
  csn = edmxv2CSN.getEdmxv2CSN(
166
185
  edmx2jsonModel,
167
- mockServerUc
186
+ ignorePersistenceSkip,
187
+ mockServerUc,
188
+ context
168
189
  );
169
190
  if (csn) {
170
191
  resolve(csn);
@@ -177,7 +198,15 @@ async function generateCSN(edmx, mockServerUc, context) {
177
198
  if(context){
178
199
  context.oDataVersion = "V4";
179
200
  }
180
- return edmxv4CSN.getEdmxv4CSN(edmx, mockServerUc);
201
+ //default namespaces to be present
202
+ if(!context.include_all_namespaces)
203
+ {
204
+ defaultNamespaces = ['edmx'];
205
+ namespaces = namespaces.concat(defaultNamespaces);
206
+ namespaces = namespaces.filter((item,pos) => namespaces.indexOf(item) === pos); //removing duplicate values
207
+ }
208
+ context.namespaces = namespaces;
209
+ return edmxv4CSN.getEdmxv4CSN(edmx, ignorePersistenceSkip, mockServerUc, context);
181
210
  }
182
211
  return new Promise(function invalidFile(resolve, reject) {
183
212
  reject(new Error(messages.INVALID_EDMX_METADATA));
@@ -13,6 +13,7 @@ const messages = {
13
13
  OUTPUT_FILE_MISMATCH: 'Specify the file extension that --as option supports.',
14
14
  INVALID_AS_OPTION: 'For --as option, please specify one of these output file format [cds, csn, json].',
15
15
  INCORRECT_EXTENSION: 'If --as option is not provided, then please provide either .json or .csn output file extension.',
16
+ INCORRECT_INPUT_NAMESPACES: 'Invalid value for --include-namespaces option. Specify namespaces as comma-separated list or "*"'
16
17
  };
17
18
 
18
19
  function getMessages() {
@@ -396,7 +396,7 @@ class Expression {
396
396
  const target = this.getTarget();
397
397
  const element = this.getElement();
398
398
  const attribs = element.attributes;
399
-
399
+ let custom_namespace = MetadataConverter.custom_namespace;
400
400
  if (attribs == null) return;
401
401
  let realType = attribs.Type || attribs.EntityType || attribs.UnderlyingType;
402
402
  const propertyName = attribs.UnderlyingType == null ? '$Type' : '$UnderlyingType';
@@ -574,9 +574,29 @@ class Expression {
574
574
  !(target.$Kind === 'NavigationProperty' && target.$Collection === true)) {
575
575
  target.$Nullable = true;
576
576
  }
577
+ const nonStdAttributes = this.getNonStdAttributes(element.attributes);
578
+ for (let i = 0; i < nonStdAttributes.length; i++) {
579
+ let attr = nonStdAttributes[i];
580
+ let [prefix, attrName] = attr.split(':');
581
+ if(attrName)
582
+ attrName = attrName.replace(/-/g,'.');
583
+ let attribute;
584
+ if ((custom_namespace.includes(prefix) && attrName !== undefined) || custom_namespace.includes(true))
585
+ attribute = "@" + prefix + "." + attrName;
586
+ else if (attrName === undefined)
587
+ attribute = "$" + prefix;
588
+ if (attribute !== undefined)
589
+ target[attribute] = element.attributes[attr];
590
+ }
591
+ }
592
+ getNonStdAttributes(attributes) {
593
+ const attributeList = [];
594
+ const standardArrtibutes = ['MaxLength', 'Precision', 'Scale', 'Nullable', 'DefaultValue',
595
+ 'Name', 'Type', 'HasStream', 'IsFlags', 'Alias', 'Namespace', 'BaseType', 'Partner',
596
+ 'IsComposable', 'ContainsTarget', 'IsBound', 'EntitySet', 'EntitySetPath', 'EntityType'];
597
+ attributeList.push(...Object.keys(attributes).filter(attribute => standardArrtibutes.indexOf(attribute) === -1));
598
+ return attributeList;
577
599
  }
578
-
579
-
580
600
  }
581
601
 
582
602
  class EdmPrimitiveType {
@@ -2361,7 +2381,8 @@ class OnDeleteExpression extends Expression {
2361
2381
  }
2362
2382
 
2363
2383
 
2364
- MetadataConverter.createOdataV4MetadataXmlToOdataV4CsdlStrategy = () => {
2384
+ MetadataConverter.createOdataV4MetadataXmlToOdataV4CsdlStrategy = (name_space) => {
2385
+ MetadataConverter.custom_namespace = name_space;
2365
2386
  return new MetadataConverter.DefaultXmlStrategy()
2366
2387
  .use('http://docs.oasis-open.org/odata/ns/edmx:Edmx', (element, parentExpression, context) => {
2367
2388
  return new EdmxRootExpression(element, null, context);
@@ -1,5 +1,4 @@
1
1
  'use strict';
2
-
3
2
  const xmljs = require('xml-js');
4
3
  const MetadataConverterV4 = require('../utils/MetadataConverter');
5
4
 
@@ -61,7 +60,7 @@ class MetadataConverterFactory {
61
60
  *
62
61
  */
63
62
  static createEdmxV40XmlToV40Json(options = {}) {
64
- const defaultStrategy = MetadataConverterV4.createOdataV4MetadataXmlToOdataV4CsdlStrategy();
63
+ const defaultStrategy = MetadataConverterV4.createOdataV4MetadataXmlToOdataV4CsdlStrategy(options);
65
64
 
66
65
  if (options.astFactory) {
67
66
  defaultStrategy.setASTFactory(options.astFactory);
@@ -67,6 +67,32 @@ var Multimap = (function () {
67
67
  return this;
68
68
  };
69
69
 
70
+ /**
71
+ * @return {Array} all the keys in the map
72
+ */
73
+ Multimap.prototype.keys = function () {
74
+ if (this._map)
75
+ return makeIterator(this._.keys());
76
+
77
+ return makeIterator(Object.keys(this._));
78
+ };
79
+
80
+ function makeIterator(iterator) {
81
+ if (Array.isArray(iterator)) {
82
+ var nextIndex = 0;
83
+
84
+ return {
85
+ next: function () {
86
+ return nextIndex < iterator.length ?
87
+ { value: iterator[nextIndex++], done: false } :
88
+ { done: true };
89
+ }
90
+ };
91
+ }
92
+
93
+ return iterator;
94
+ }
95
+
70
96
  return Multimap;
71
97
  })();
72
98