@sap/cds-dk 7.0.3 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/bin/bind.js +5 -6
  2. package/bin/build.js +2 -7
  3. package/bin/cds.js +0 -4
  4. package/bin/subscribe.js +4 -4
  5. package/bin/unsubscribe.js +4 -4
  6. package/bin/upgrade.js +4 -4
  7. package/lib/bind/cfKeyProvider.js +9 -10
  8. package/lib/bind/index.js +1 -3
  9. package/lib/build/buildTaskEngine.js +9 -22
  10. package/lib/build/buildTaskFactory.js +18 -27
  11. package/lib/build/index.js +12 -3
  12. package/lib/build/provider/buildTaskProviderInternal.js +23 -15
  13. package/lib/build/provider/mtx/index.js +8 -2
  14. package/lib/build/util.js +13 -0
  15. package/lib/client/activate.js +7 -7
  16. package/lib/client/auth_manager.js +5 -5
  17. package/lib/client/base_command.js +5 -5
  18. package/lib/client/extend.js +2 -2
  19. package/lib/client/helper/logging.js +7 -2
  20. package/lib/client/params.js +2 -3
  21. package/lib/client/pull.js +3 -3
  22. package/lib/client/push.js +3 -3
  23. package/lib/client/settings_manager.js +7 -8
  24. package/lib/client/tenant_action.js +3 -3
  25. package/lib/deploy/to-hana/hana.js +1 -2
  26. package/lib/import/common.js +3 -0
  27. package/lib/import/message.js +2 -1
  28. package/lib/import/odata/v4parser.js +85 -95
  29. package/lib/init/index.js +24 -11
  30. package/lib/init/template/cf-manifest/files/manifest.yml.hbs +1 -1
  31. package/lib/init/template/data/index.js +2 -3
  32. package/lib/init/template/lint/index.js +5 -6
  33. package/lib/init/template/nodejs/index.js +2 -3
  34. package/lib/init/template/pipeline/index.js +1 -2
  35. package/lib/init/util/indent.js +1 -1
  36. package/lib/init/util/merge.js +3 -3
  37. package/lib/init/util/mvn.js +17 -22
  38. package/lib/util/cfUtil.js +1 -2
  39. package/npm-shrinkwrap.json +353 -300
  40. package/package.json +1 -1
  41. package/lib/client/helper/errors.js +0 -26
  42. package/lib/util/version.js +0 -27
@@ -4,7 +4,7 @@ const cds = require('../cds');
4
4
  const DEBUG = cds.debug('cli');
5
5
  const { SettingsManager } = require('./settings_manager');
6
6
  const { ParamCollection } = require('./params');
7
- const { CliError } = require('./helper/errors');
7
+ const { getMessage } = require('./helper/logging');
8
8
 
9
9
  function addTokenInfo(params, authData) {
10
10
  params.set('token', authData.access_token);
@@ -79,14 +79,14 @@ async function retrieveTokenOrPasscodeUrl(params) {
79
79
  if (error.response?.status === 404) { // may represent 405 in case of wrong method
80
80
  continue;
81
81
  }
82
- throw new CliError('Failed to get authentication token', { error });
82
+ throw getMessage('Failed to get authentication token', { error });
83
83
  }
84
84
  if (response) {
85
85
  break;
86
86
  }
87
87
  }
88
88
  if (!response) {
89
- throw new CliError('Failed to get authentication token');
89
+ throw 'Failed to get authentication token';
90
90
  }
91
91
  authData = response.data;
92
92
 
@@ -115,9 +115,9 @@ module.exports = class AuthManager {
115
115
  if (params.get('saveData')) {
116
116
  await SettingsManager.saveSettings(params);
117
117
  }
118
- throw new CliError(`Failed to login: no valid token or passcode provided. Get a passcode${
118
+ throw `Failed to login: no valid token or passcode provided. Get a passcode${
119
119
  params.get('passcodeUrl') ? ' from ' + params.get('passcodeUrl') : ''
120
- } and supply the code when re-running the command`);
120
+ } and supply the code when re-running the command`;
121
121
  }
122
122
  params.set('reqAuth', { headers: { Authorization: 'Bearer ' + params.get('token') } });
123
123
  }
@@ -3,7 +3,7 @@ const fs = require('fs').promises;
3
3
 
4
4
  require('../util/pruneAxiosErrors');
5
5
 
6
- const { CliError } = require('./helper/errors');
6
+ const { getMessage } = require('./helper/logging');
7
7
 
8
8
  const MTX_URL_PATH_PREFIX = 'mtx/v1/model/';
9
9
  const CUSTOM_FILE_URL_SUFFIX = 'customTenantContent';
@@ -22,16 +22,16 @@ module.exports = class BaseCommand {
22
22
  const prefix = `Request to ${url} failed`;
23
23
  switch (error.response?.status) {
24
24
  case 401:
25
- throw new CliError(`${prefix}: invalid authentication.\nRetry with valid passcode${
25
+ throw getMessage(`${prefix}: invalid authentication.\nRetry with valid passcode${
26
26
  params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''
27
27
  } or username/password (required if SaaS app is configured with mocked-auth).`, { error, command });
28
28
  case 403:
29
- throw new CliError(prefix + ': insufficient authorization. Ensure client has all necessary roles.', { error, command });
29
+ throw getMessage(prefix + ': insufficient authorization. Ensure client has all necessary roles.', { error, command });
30
30
  case 404:
31
- throw new CliError(prefix + ': resource not found.', { error, command });
31
+ throw getMessage(prefix + ': resource not found.', { error, command });
32
32
  case 422:
33
33
  // Compilation or native-extension error.
34
- throw new CliError(prefix + '.', { error, command });
34
+ throw getMessage(prefix + '.', { error, command });
35
35
  default:
36
36
  // Unexpected error should be transparent to user.
37
37
  throw error;
@@ -6,7 +6,7 @@ const AuthManager = require('./auth_manager');
6
6
  const BaseCommand = require('./base_command');
7
7
  const { normalizePath, isParent } = require('./helper/fs_helper');
8
8
  const Question = require('./helper/question');
9
- const { CliError } = require('./helper/errors');
9
+ const { getMessage } = require('./helper/logging');
10
10
 
11
11
  const COMMAND_URL_SUFFIX = 'content';
12
12
  const CUSTOM_FILE_FOLDERS = ['wsdl'];
@@ -87,7 +87,7 @@ module.exports = class Extend extends BaseCommand {
87
87
 
88
88
  const runOnExistingProject = await Extend.checkProject(params.get('projectFolder'));
89
89
  if (runOnExistingProject && !(params.get('force') || params.get('templates'))) {
90
- throw new CliError(folderExists(params.get('projectFolder')), { command: 'extend' });
90
+ throw getMessage(folderExists(params.get('projectFolder')), { command: 'extend' });
91
91
  }
92
92
 
93
93
  try {
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-console */
2
2
 
3
- function getMessage(errorText, { error, help } = {}) {
3
+ function getMessage(errorText, { error, command, help = command && getCommandHelp(command) } = {}) {
4
4
  let message = errorText ? errorText : '';
5
5
  if (error) {
6
6
  message += '\n' + (
@@ -8,7 +8,7 @@ function getMessage(errorText, { error, help } = {}) {
8
8
  || error.response?.data?.error?.message // response body == { error }
9
9
  || error.message // no response attached
10
10
  );
11
- if (process.env.DEBUG && error.stack) {
11
+ if (error.stack && require('../../cds').debug('cli')) {
12
12
  message += '\n' + error.stack;
13
13
  }
14
14
  }
@@ -18,6 +18,11 @@ function getMessage(errorText, { error, help } = {}) {
18
18
  return message;
19
19
  }
20
20
 
21
+ function getCommandHelp(command) {
22
+ const cli = require('../../../bin/cds');
23
+ return cli?.load(command, () => ({ help: '' }))?.help ?? '';
24
+ }
25
+
21
26
  module.exports = {
22
27
  getMessage
23
28
  };
@@ -1,7 +1,6 @@
1
1
  const cds = require('../cds');
2
2
  const DEBUG = cds.debug('cli');
3
3
  const { escapeRegex } = require('./helper/string_helper');
4
- const { CliError } = require('./helper/errors');
5
4
 
6
5
 
7
6
  // PARAM BASE TYPES
@@ -106,10 +105,10 @@ class Param {
106
105
  expectedType = typeof this.allowedValues[0];
107
106
  }
108
107
  if (typeof val !== expectedType) {
109
- throw new CliError(`Failed to set '${(this.name)}' = ${JSON.stringify(val)}: expected value of type ${expectedType}`);
108
+ throw `Failed to set '${(this.name)}' = ${JSON.stringify(val)}: expected value of type ${expectedType}`;
110
109
  }
111
110
  if (this.allowedValues && !(this.allowedValues).includes(val)) {
112
- throw new CliError(`Failed to set '${(this.name)}' = ${JSON.stringify(val)}: expected one of ${JSON.stringify(this.allowedValues)}`);
111
+ throw `Failed to set '${(this.name)}' = ${JSON.stringify(val)}: expected one of ${JSON.stringify(this.allowedValues)}`;
113
112
  }
114
113
  }
115
114
 
@@ -7,13 +7,13 @@ const axios = require('axios');
7
7
 
8
8
  const { login } = require('./auth_manager');
9
9
  const BaseCommand = require('./base_command');
10
- const { CliError } = require('./helper/errors');
10
+ const { getMessage } = require('./helper/logging');
11
11
 
12
12
  module.exports = class Pull extends BaseCommand {
13
13
 
14
14
  static async run(paramValues) {
15
15
  if (!tar) {
16
- throw new CliError(`cds pull requires @sap/cds version >= 6.2. Current version is ${cds.version}\n`);
16
+ throw `cds pull requires @sap/cds version >= 6.2. Current version is ${cds.version}\n`;
17
17
  }
18
18
 
19
19
  const params = await login(paramValues);
@@ -59,7 +59,7 @@ module.exports = class Pull extends BaseCommand {
59
59
  try {
60
60
  packageContents = JSON.parse(fs.readFileSync(packageJson, { encoding: 'utf-8' }));
61
61
  } catch (error) {
62
- throw new CliError('package.json missing or unreadable', { error });
62
+ throw getMessage('package.json missing or unreadable', { error });
63
63
  }
64
64
  fs.writeFileSync(packageJson, JSON.stringify({
65
65
  ...packageContents,
@@ -5,7 +5,7 @@ const axios = require('axios');
5
5
 
6
6
  const { login } = require('./auth_manager');
7
7
  const BaseCommand = require('./base_command');
8
- const { CliError } = require('./helper/errors');
8
+ const { getMessage } = require('./helper/logging');
9
9
  const { schemaRegex } = require('./helper/url_helper');
10
10
  const buildSystem = require('../build')
11
11
 
@@ -39,7 +39,7 @@ module.exports = class Push extends BaseCommand {
39
39
  src = local(src);
40
40
  } else {
41
41
  if (!schemaRegex.test(src)) {
42
- throw new CliError(`Nonexistent path: ${src}`, { command: 'push' });
42
+ throw getMessage(`Nonexistent path: ${src}`, { command: 'push' });
43
43
  }
44
44
  try {
45
45
  content = (await axios.get(src, { responseEncoding: 'base64' })).data;
@@ -54,7 +54,7 @@ module.exports = class Push extends BaseCommand {
54
54
  try {
55
55
  return require(join(projectFolder, 'package.json')).name;
56
56
  } catch (error) {
57
- throw new CliError(`Extension project at ${projectFolder} is missing package.json file`, { error, command: 'push' });
57
+ throw getMessage(`Extension project at ${projectFolder} is missing package.json file`, { error, command: 'push' });
58
58
  }
59
59
  }
60
60
 
@@ -9,7 +9,6 @@ const { requireGlobal } = require('./helper/dependency_helper');
9
9
  const { getAppFromSuggestions, getSubdomain } = require('./helper/cf_helper');
10
10
  const isBas = require('./helper/env_helper');
11
11
  const Question = require('./helper/question');
12
- const { CliError } = require('./helper/errors');
13
12
  const { httpSchema, httpsSchema, schemaRegex, localhostRegex } = require('./helper/url_helper');
14
13
  const { capitalize } = require('./helper/string_helper');
15
14
 
@@ -95,7 +94,7 @@ async function getTokenBaseUrl(params, renewUrl) {
95
94
  return params.get('tokenUrl');
96
95
  }
97
96
  if (!params.has('appUrl')) {
98
- throw new CliError('Failed to determine token URL: app URL not given');
97
+ throw 'Failed to determine token URL: app URL not given';
99
98
  }
100
99
  const baseUrl = new URL(params.get('appUrl'));
101
100
  const cleanPathname = pathname => baseUrl.pathname.replace(/\/?$/, pathname);
@@ -237,7 +236,7 @@ class SettingsManager {
237
236
 
238
237
  // Check required param: appUrl
239
238
  if (!params.has('appUrl')) {
240
- throw new CliError('App URL not given. Please specify it or log in to Cloud Foundry and repeat this command.');
239
+ throw 'App URL not given. Please specify it or log in to Cloud Foundry and repeat this command.';
241
240
  }
242
241
  }
243
242
  async function renewTokenUrl() {
@@ -273,8 +272,8 @@ class SettingsManager {
273
272
 
274
273
  if (params.get('tokenStorage') === 'keyring' && params.get('saveData')) {
275
274
  // Explicit login w/o plain-text storage enabled
276
- throw new CliError(capitalize(TOKEN_STORAGE_DESC.keyring) + ' requested but keytar not installed. ' +
277
- 'Run `npm install -g keytar` or switch to ' + TOKEN_STORAGE_DESC.plain + ' by adding `--plain` (discouraged).');
275
+ throw capitalize(TOKEN_STORAGE_DESC.keyring) + ' requested but keytar not installed. ' +
276
+ 'Run `npm install -g keytar` or switch to ' + TOKEN_STORAGE_DESC.plain + ' by adding `--plain` (discouraged).';
278
277
  }
279
278
 
280
279
  const doLog = params.get('saveData') || logout
@@ -296,14 +295,14 @@ class SettingsManager {
296
295
  params.set('clientsecret', await Question.askQuestion('clientsecret: ', undefined, true));
297
296
  console.log();
298
297
  if (params.get('clientsecret') === '') {
299
- throw new CliError('Clientsecret cannot be empty');
298
+ throw 'Clientsecret cannot be empty';
300
299
  }
301
300
  }
302
301
  async function addKey() {
303
302
  params.set('key', await Question.askQuestion('key: ', undefined, true));
304
303
  console.log();
305
304
  if (params.get('key') === '') {
306
- throw new CliError('Key cannot be empty');
305
+ throw 'Key cannot be empty';
307
306
  }
308
307
  }
309
308
  async function addPasscode() {
@@ -311,7 +310,7 @@ class SettingsManager {
311
310
  params.set('passcode', (await Question.askQuestion(prompt, undefined, true)).trim());
312
311
  console.log();
313
312
  if (params.get('passcode') === '') {
314
- throw new CliError('Passcode cannot be empty');
313
+ throw 'Passcode cannot be empty';
315
314
  }
316
315
  }
317
316
  function setRelevantAuth(auth) {
@@ -2,7 +2,7 @@ const cds = require('../cds');
2
2
  const DEBUG = cds.debug('cli');
3
3
 
4
4
  const BaseCommand = require('./base_command');
5
- const { CliError } = require('./helper/errors');
5
+ const { getMessage } = require('./helper/logging');
6
6
  const { ParamCollection } = require('./params');
7
7
  const AuthManager = require('./auth_manager');
8
8
  const { capitalize } = require('./helper/string_helper');
@@ -65,13 +65,13 @@ module.exports = class TenantAction extends BaseCommand {
65
65
  libPath = require.resolve(libId);
66
66
  DEBUG?.(`Using cds-mtxs from ${libPath}`);
67
67
  } catch (error) {
68
- throw new CliError('@sap/cds-mtxs not found or outdated. Have you changed into the directory of your SaaS app? If so, please upgrade to @sap/cds-mtxs@>=1.7.0', { error, command: this.command });
68
+ throw getMessage('@sap/cds-mtxs not found or outdated. Have you changed into the directory of your SaaS app? If so, please upgrade to @sap/cds-mtxs@>=1.7.0', { error, command: this.command });
69
69
  }
70
70
  }
71
71
 
72
72
  const { cds_mtx } = require(libPath);
73
73
  if (!cds_mtx) {
74
- throw new CliError('@sap/cds-mtxs outdated. Please upgrade to @sap/cds-mtxs@>=1.7.0 and re-run this command.');
74
+ throw '@sap/cds-mtxs outdated. Please upgrade to @sap/cds-mtxs@>=1.7.0 and re-run this command.';
75
75
  }
76
76
  return cds_mtx(this.command, tenant);
77
77
  }
@@ -15,7 +15,6 @@ const gitUtil = require('../../util/gitUtil');
15
15
  const mtaUtil = require('./mtaUtil');
16
16
 
17
17
  const { bold, info } = require('../../util/term');
18
- const { CliError } = require('../../client/helper/errors');
19
18
 
20
19
  const { bind } = require('../../bind');
21
20
 
@@ -49,7 +48,7 @@ class HanaDeployer {
49
48
  let { model, serviceName, tunnelAddress, vcapFile, undeployWhitelist, hdiOptions } = options;
50
49
 
51
50
  if (model) {
52
- throw new CliError('Specifying a model for hana deployment is not supported.');
51
+ throw 'Specifying a model for hana deployment is not supported.';
53
52
  }
54
53
 
55
54
  console.log(`${bold('Starting deploy to SAP HANA ...')}`);
@@ -66,6 +66,9 @@ async function getVersion(fileInputStream){
66
66
  } else if (version === '4.0' || version === "4.01") {
67
67
  oDataVersion = 'V4';
68
68
  }
69
+ else {
70
+ throw new Error(messages.INVALID_EDMX_METADATA_VERSION);
71
+ }
69
72
 
70
73
  return oDataVersion;
71
74
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  const messages = {
4
4
  INVALID_EDMX_METADATA: 'The OData model is not valid. Specify the correct OData model.',
5
+ INVALID_EDMX_METADATA_VERSION: 'The OData version is not valid. Specify the correct OData version.',
5
6
  INVALID_OUTPUT_FILE: 'Please provide an output file with one of these [cds, csn, json] file extension.',
6
7
  SPECIFY_INPUT_FILE: 'Specify an input file that exists.',
7
8
  SPECIFY_OUTPUT_FILE: 'Specify an output file or correct the output file path provided.',
@@ -26,7 +27,7 @@ const messages = {
26
27
  BOUNDED_ACTION_COLLISION: 'For Bounded Action, combination of action name and binding parameter type should be unique.',
27
28
  STREAM_NO_COLLECTION: `'Edm.Stream' cannot be of Collection type.`,
28
29
  UNSUPPORTED_PROPERTY_TYPE: 'Property cannot be of EntityType. Check the type: ',
29
- UNRESOLVED_SCHEMA_NAMESPACE: `Could not resolve the schema `,
30
+ UNRESOLVED_SCHEMA_NAMESPACE: `Could not resolve the schema `,
30
31
  INVALID_DATATYPE: `Invalid Data Type `,
31
32
  ELEMENT_NAME_COLLISION: 'Collision between EntityContainer Element Name and Schema Element Name is currenlty not supported. Please check the element name: '
32
33
  };