@sap/cds-dk 4.5.0 → 4.6.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/CHANGELOG.md +65 -9
  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/deploy/index.js +2 -1
  6. package/bin/env.js +50 -9
  7. package/bin/help.js +2 -1
  8. package/bin/import.js +126 -24
  9. package/bin/watch.js +45 -9
  10. package/lib/bind/bindingResolver.js +138 -0
  11. package/lib/bind/cfKeyProvider.js +353 -0
  12. package/lib/bind/userCdsrcJsonStorageProvider.js +144 -0
  13. package/lib/client/auth_manager.js +4 -4
  14. package/lib/client/settings_manager.js +1 -1
  15. package/lib/import/common.js +33 -1
  16. package/lib/import/importapi.js +4 -3
  17. package/lib/import/index.js +49 -23
  18. package/lib/import/message.js +11 -6
  19. package/lib/import/utils/MetadataConverter.js +25 -4
  20. package/lib/import/utils/MetadataConverterFactory.js +1 -2
  21. package/lib/import/utils/MultiMap.js +26 -0
  22. package/lib/import/v2parser.js +142 -24
  23. package/lib/import/v4parser.js +222 -149
  24. package/lib/init/constants.js +1 -1
  25. package/lib/init/index.js +2 -0
  26. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +36 -52
  27. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +15 -0
  28. package/lib/init/template/lint/index.js +14 -6
  29. package/lib/init/template/mta/files/mta.yaml.hbs +0 -7
  30. package/lib/init/template/mtx/files/xs-security.json.hbs +3 -1
  31. package/lib/init/template/mtx/package/dependencies.package.json +1 -1
  32. package/lib/init/template/nodejs/files/.gitignore.hbs +3 -0
  33. package/lib/init/util/commandUtil.js +5 -0
  34. package/lib/lint/Linter.js +31 -20
  35. package/lib/lint/checks.js +5 -1
  36. package/lib/lint/generators.js +1 -1
  37. package/lib/lint/io.js +59 -35
  38. package/lib/util/term.js +2 -0
  39. package/lib/watch/node-watch.js +38 -19
  40. package/npm-shrinkwrap.json +1276 -1102
  41. package/package.json +4 -3
  42. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/test.js +0 -10
package/CHANGELOG.md CHANGED
@@ -6,11 +6,65 @@ This project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
7
  The format is based on [Keep a Changelog](http://keepachangelog.com/).
8
8
 
9
+ ## Version 4.6.0 - 2021-11-02
10
+ ### Added
11
+
12
+ - `cds bind` binds the given service to a hana instance by storing the credentials in `.cdsrc.json` in your user home directory [beta].
13
+ - `cds import` introduced option `--include-namespaces` which imports the custom defined namespaces.
14
+ - `cds import` preserve documentation in CSN file for actions and functions from OData V4 EDMX file.
15
+ - `cds import` now supports reading values of the `as` option from cds.env
16
+
17
+ ### Fixed
18
+
19
+ - `cds import` fix for reflecting only supported datatypes in csn for actions and functions for OData V4.
20
+ - `cds import` fix for TypeError issue (#9868) during OData V4 EDMX conversion to CSN.
21
+ - `cds watch` no longer omits starting some services every other time it is restarting the process
22
+ - `cds-ts watch` now honors a local `tsconfig.json` file
23
+ - `cds import` fix for TypeError issue (#9950) during OData V2 EDMX conversion to CSN.
24
+ - `cds import` fix to generate the csn (#9950) during OData V2 EDMX conversion to CSN.
25
+ - `cds import` fix to replace the aliases with original schema namespace value.
26
+ - `cds import` adds `@cds.persistence.skip` back to imported models. Its accidental removal in 4.5.0 caused wrong DB deployments of imported entities.
27
+
28
+ ## Version 4.5.4 - 2021-10-07
29
+
30
+ ### Fixed
31
+
32
+ - `cds watch` no longer fails if started with `--ext`, `--livereload`, or `--open` arguments
33
+
34
+ ## Version 4.5.3 - 2021-10-05
35
+
36
+ ### Fixed
37
+
38
+ - `cds import` fix for `--dry` shortcut `-`
39
+ - `cds import` fix for missing type properties in csn for unbounded action and function in OData V4.
40
+ - A bug with `cds init` when called in BAS project wizard
41
+
42
+ ## Version 4.5.2 - 2021-09-30
43
+
44
+ ### Changed
45
+
46
+ - `cds init` uses latest `Maven Java archetype` version `1.19.0` for creating Java projects.
47
+
48
+ ### Fixed
49
+
50
+ - `cds deploy --to sqlite` now writes `credentials.database` again to `package.json`
51
+
52
+ ## Version 4.5.1 - 2021-09-29
53
+
54
+ ### Added
55
+
56
+ - `cds import` introduced option `--as` which converts EDMX file to different file formats such as cds, csn and json.
57
+ - `cds import` introduced flag `--f` which forcefully overwrite the content of existing cds file when specified with `--as` option.
58
+
59
+ ### Changed
60
+
61
+ - Marked `cds lint` as beta again to further investigate issues from 'extends' via prettier plugin.
62
+
9
63
  ## Version 4.5.0 - 2021-09-23
10
64
 
11
65
  ### Added
12
66
 
13
- - `cds import` supports import of functions, action, functionimport and actionimport from both OData v2 and v4 edmx files.
67
+ - `cds import` supports import of functions, action, functionimport and actionimport from both OData V2 and V4 EDMX files.
14
68
 
15
69
  ### Changed
16
70
 
@@ -18,16 +72,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
18
72
 
19
73
  ### Fixed
20
74
 
21
- - `cds watch` additional CLI args were not passed to launched process, e.g. `--odata x4`.
22
- - `cds import` fix for TypeError issue during OData v4 edmx conversion to csn.
23
- - `cds import` fix for multi-line documentation text in OData v2 edmx file.
24
- - `cds import` fix for v4 csn generation when non standard OData vocabularies are referred.
75
+ - `cds watch` additional CLI args were not passed to launched process, for example, `--odata x4`.
76
+ - `cds import` fix for TypeError issue during OData V4 EDMX conversion to CSN.
77
+ - `cds import` fix for multi-line documentation text in OData V2 EDMX file.
78
+ - `cds import` fix for V4 CSN generation when non standard OData vocabularies are referred.
25
79
  - `cds add data`
26
- - no longer fails for entities without keys
27
- - no longer creates csv files for synthetic draft entities
28
- - no longer creates entries for virtual fields
29
- - no longer skips over entities marked with `@cds.persistence.skip`, which is true for 'external' entities created by `cds import`.
80
+ + no longer fails for entities without keys
81
+ + no longer creates csv files for synthetic draft entities
82
+ + no longer creates entries for virtual fields
83
+ + no longer skips over entities marked with `@cds.persistence.skip`, which is true for 'external' entities created by `cds import`.
30
84
  - `cds init --add` handles comma list correctly.
85
+ - `cds import` fix for multi-line documentation text in OData V4 EDMX file.
86
+ - `cds import` fix preserves the missing entities in csn for OData V2 EDMX file.
31
87
 
32
88
 
33
89
  ## Version 4.4.2 - 2021-09-03
package/bin/bind.js CHANGED
@@ -1,17 +1,133 @@
1
- module.exports = Object.assign (
2
- cds_bind, {help: `
1
+
2
+
3
+ module.exports = Object.assign(cds_bind, {
4
+ options: ['--to', '--profile', '--kind', '--output-file'],
5
+ flags: [],
6
+ shortcuts: ['-2', '-p', '-k', '-o'],
7
+ help: `
3
8
  # SYNOPSIS
4
9
 
5
- *cds bind* <service> [<options>]
10
+ *cds bind* <service> [<options>] -- beta feature
6
11
 
7
- Binds the given service to
12
+ Binds the given service to a service instance by storing connection information in *.cdsrc-private.json*
13
+ in your project directory. Credentials are not stored in the file but rather retrieved dynamically during *cds watch*.
14
+ Use option *--output-file* to specify a different path or file.
15
+
16
+ Currently *cds bind* only supports Node.js projects.
8
17
 
9
18
  # OPTIONS
10
19
 
11
- *-2|--to* <credentials>
20
+ *-2 | --to* <instance>[:<key>]
21
+ bind to a given instance
22
+
23
+ *-p | --profile* <profile>
24
+ add the given profile, defaults to *hybrid*
25
+
26
+ *-k | --kind* <kind>
27
+ the kind of service
28
+
29
+ *-o | --output-file <path>*
30
+ save bindings to the given *.cdsrc.json* or *package.json* file. Default is *.cdsrc-private.json*.
31
+ If *path* is a directory, then it will save it to the *.cdsrc.json* file in that directory.
32
+
33
+ # EXAMPLE
34
+
35
+ cds bind --to my-hdi-container
36
+ cds bind --to my-hdi-container,my-xsuaa
37
+ cds bind uaa --to my-xsuaa:my-xsuaa-key --kind xsuaa --profile myprofile
38
+
39
+ cds bind --to my-hdi-container --output-file ~
40
+ cds bind --to my-hdi-container --output-file package.json
41
+
42
+ `});
43
+
44
+ const { constants, promises: fsp } = require('fs');
45
+ const path = require('path');
46
+
47
+ const cds = require('@sap/cds/lib');
48
+ const LOG = cds.log('bind');
49
+ // required for spinner
50
+ LOG.isDebug = LOG._debug;
51
+ LOG.isTTY = process.stdout.isTTY;
52
+
53
+ const { bold, info } = require('../lib/util/term');
54
+
55
+ const Spinner = require('../lib/init/util/spinner');
56
+
12
57
 
13
- `})
58
+ async function cds_bind(args, options) { // eslint-disable-line
59
+
60
+ options.profile = options.profile || 'hybrid';
61
+
62
+ if (await isJavaProject('.')) {
63
+ throw new Error(`Found a 'pom.xml' file in your project root folder indicating a Java project. Currently, 'cds bind' only supports Node.js projects.`);
64
+ }
65
+
66
+ if (!options.to) {
67
+ throw new Error(`use option --to or -2 to specify the target instance, e.g. cds bind --to myInstance:myService`);
68
+ }
69
+
70
+ if (args.length > 1) {
71
+ throw new Error(`Too many arguments: Please specify only one or no service.`);
72
+ }
73
+
74
+ let serviceArg = args[0]
75
+ const targets = options.to.split(/,/g);
76
+
77
+ if (targets.length >= 2 && serviceArg) {
78
+ throw new Error(`Service argument cannot be specified together with multiple targets ('--to') services. Use one service per call or omit the service argument.`);
79
+ }
80
+
81
+ if (targets.length >= 2 && options.kind) {
82
+ throw new Error(`The option '--kind' cannot be specified together with multiple targets ('--to') services. Use one service per call or omit the '--kind' option.`);
83
+ }
84
+
85
+ // prepare for different providers
86
+ const keyProvider = require('../lib/bind/cfKeyProvider');
87
+ keyProvider.setLogger(LOG);
88
+ const spinner = new Spinner(LOG);
89
+ const resolvedServices = await spinner.run(`Retrieving data from Cloud Foundry...`, async () => { // NOSONAR
90
+ const resolvedServices = [];
91
+ await Promise.all( targets.map( async target => {
92
+ const [instance, key] = target.split(/:/);
93
+ const resolvedService = await keyProvider.resolve(undefined, { instance, key });
94
+ // if (!options["save-credentials"]) {
95
+ delete resolvedService.credentials;
96
+ resolvedService.binding.resolved = false;
97
+ // }
98
+ resolvedServices.push(resolvedService);
99
+ }));
100
+ return resolvedServices;
101
+ });
102
+
103
+ if (!options.kind) {
104
+ keyProvider.determineKinds(resolvedServices);
105
+ }
106
+
107
+ for (const resolvedService of resolvedServices) {
108
+ resolvedService.kind = options.kind || resolvedService.kind;
109
+ resolvedService.name = serviceArg || keyProvider.getRequiresNameFromKind(resolvedService.binding.instance, resolvedService.kind);
110
+ }
111
+
112
+ // prepare for different providers
113
+ const userCdsrcJsonStorageProvider = require('../lib/bind/userCdsrcJsonStorageProvider');
114
+
115
+ await userCdsrcJsonStorageProvider.storeServices(resolvedServices, {
116
+ ...options,
117
+ logger: LOG
118
+ });
119
+
120
+ LOG.log();
121
+ LOG.log(`${info("TIP:")} Run with cloud bindings: ${bold(`cds watch --profile ${options.profile}`)}`);
122
+ // LOG.log();
123
+ }
14
124
 
15
- function cds_bind (projects, options) { // eslint-disable-line
16
- console.log (`cds bind is not yet released`)
125
+ async function isJavaProject(projectPath) {
126
+ const pomXmlPath = path.join(projectPath, 'pom.xml');
127
+ try {
128
+ await fsp.access(pomXmlPath, constants.F_OK);
129
+ return true;
130
+ } catch (err) {
131
+ return false;
132
+ }
17
133
  }
package/bin/cds-ts.js CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env ts-node
1
+ #!/usr/bin/env ts-node-cwd
2
2
  require('./cds').apply(process.argv)
package/bin/cds.js CHANGED
@@ -5,6 +5,7 @@ const cli = { //NOSONAR
5
5
  Shortcuts: {
6
6
  i: 'init',
7
7
  a: 'add',
8
+ y: 'bind',
8
9
  m: 'import',
9
10
  c: 'compile',
10
11
  s: 'serve',
@@ -94,7 +94,7 @@ async function deploy (_model, options) { // NOSONAR
94
94
  }
95
95
 
96
96
 
97
- async function updata_package_json (kind, model='*', database) {
97
+ async function updata_package_json (kind, model, database) {
98
98
  const { fs, path, isfile } = cds.utils
99
99
  const { readFile, writeFile } = fs.promises
100
100
  const package_json = path.resolve ('package.json'), exists = isfile (package_json)
@@ -102,6 +102,7 @@ async function updata_package_json (kind, model='*', database) {
102
102
  const requires = ['cds','requires'] .reduce ((p,n)=>p[n] || (p[n]={}), conf)
103
103
  requires.db = cds.env.requires.db = { kind, model }
104
104
  if (database) requires.db.credentials = { database }
105
+ else if (kind === 'sqlite') requires.db.credentials = { database:'sqlite.db' }
105
106
  await writeFile (package_json, JSON.stringify(conf,null,' '))
106
107
  console.log (`/> ${ exists ? 'updated' : 'created' } ./package.json`)
107
108
  }
package/bin/env.js CHANGED
@@ -1,5 +1,5 @@
1
1
  module.exports = Object.assign (env, {
2
- options: ['--for', '--mocked'], flags: [], shortcuts: ['-4'],
2
+ options: ['--for', '--mocked'], flags: ['--process-env', '--resolve-bindings'], shortcuts: ['-4', undefined, '-P', '-b'],
3
3
  help: `
4
4
  # SYNOPSIS
5
5
 
@@ -11,13 +11,29 @@ module.exports = Object.assign (env, {
11
11
 
12
12
  # EXPLANATION
13
13
 
14
- Without any arguments, this will display the effective configuration in
15
- the current environment in JavaScript object format. <ls | list> displays
16
- it in _.properties_ format.
14
+ Lists the effective configuration of the current environment in
15
+ _.properties_ format if no command, *ls*, or *list* is given.
17
16
 
18
- The other variants either get or set a single option or display the sources
19
- from which the effective configuration has been loaded.
17
+ The other commands either get or set a single property or display
18
+ the sources from which the effective configuration has been loaded.
20
19
 
20
+ # OPTIONS
21
+
22
+ *-4* | *--for* <path>
23
+
24
+ Load configuration from path instead of the current working directory.
25
+
26
+ *--profile* <profile,...>
27
+
28
+ Load configuration for the specified profile(s).
29
+
30
+ *-P* | *--process-env*
31
+
32
+ Show properties from Node.js _process.env_.
33
+
34
+ *-b* | *--resolve-bindings*
35
+
36
+ Resolve _cds bind_ bindings.
21
37
  `})
22
38
 
23
39
  const path = require('path')
@@ -29,15 +45,20 @@ const info = (s) => process.stdout.isTTY ? term.info (s) : s
29
45
  async function env ([cmd, key, value], options={}) {
30
46
 
31
47
  const cds = require('@sap/cds/lib')
32
- const fn = commands[cmd] || (()=>{
48
+ const fn = (options["process-env"] ? processEnvCommands[cmd] : commands[cmd]) || (()=>{
33
49
  this.help ('env')
34
50
  throw new Error (`Don't understand '${cmd}' here...`)
35
51
  })
36
52
 
53
+ if (options.profile) process.env.CDS_ENV = options.profile
54
+
37
55
  const env = options.for ? cds.env.for (options.for) : cds.env
38
56
  env['_home_cds-dk'] = path.resolve(__dirname, '..') // to help tools find the DK
39
57
 
58
+ if (options["resolve-bindings"]) await require('../lib/bind/bindingResolver').applyTo({env, output: "debug"})
59
+
40
60
  if (!options.for && options.mocked) await cds.service.bindings
61
+
41
62
  fn (env, key, value)
42
63
  }
43
64
 
@@ -69,19 +90,39 @@ const commands = {
69
90
  if (!process.stdout.isTTY) return commands.json (conf, key, val)
70
91
  // tty: display formatted object
71
92
  const obj = (key ? conf.get(key) : conf)
72
- console.log (inspect (obj, {depth:22,colors:true}))
93
+ console.log (inspect (obj, {depth:22,colors:true}).replace(/\s+use:.*\[Getter\].*/g,''))
73
94
  },
74
95
 
75
96
  // eslint-disable-next-line no-unused-vars
76
97
  json (conf, key, val) {
77
98
  const obj = (key ? conf.get(key) : conf)
78
- return console.log (JSON.stringify(obj, null, 2))
99
+ const str = JSON.stringify(obj, null, 2)
100
+ return console.log (str ? str.replace(/\s+use:.*\[Getter\].*/g,'') : str)
79
101
  },
80
102
 
81
103
  set () {
82
104
  throw new Error ('cds config set is not yet implemented, sorry')
105
+ }
106
+ }
107
+
108
+ const processEnvCommands = {
109
+ get [undefined]() { return processEnvCommands.list },
110
+ get ''() { return processEnvCommands.list },
111
+ get ls() { return process.list },
112
+
113
+ list (_, key) {
114
+ if (key) {
115
+ processEnvCommands.get(undefined, key)
116
+ } else {
117
+ for (const name in process.env) {
118
+ console.log(`${name}=${process.env[name]}`)
119
+ }
120
+ }
83
121
  },
84
122
 
123
+ get (_, key) {
124
+ console.log (process.env[key] || "")
125
+ }
85
126
  }
86
127
 
87
128
  /* eslint no-console:0 */
package/bin/help.js CHANGED
@@ -10,6 +10,7 @@ module.exports = exports = Object.assign (help, {help:`
10
10
 
11
11
  *i* | *init* jump-start cds-based projects
12
12
  *a* | *add* add a feature to an existing project
13
+ *y* | *bind* [beta] bind a service to a hana instance
13
14
  *m* | *import* add models from external sources
14
15
  *c* | *compile* compile cds models to different outputs
15
16
  *s* | *serve* run your services in local server
@@ -20,7 +21,7 @@ module.exports = exports = Object.assign (help, {help:`
20
21
  *d* | *deploy* deploy to databases or cloud
21
22
  *l* | *login* login to extendable SaaS application
22
23
  *x* | *extend* create extension project from SaaS application
23
- *t* | *lint* run linter for env or model checks
24
+ *t* | *lint* [beta] run linter for env or model checks
24
25
  *v* | *version* get detailed version information
25
26
  *?* | *help* get detailed usage information
26
27
 
package/bin/import.js CHANGED
@@ -1,9 +1,9 @@
1
1
 
2
2
  module.exports = Object.assign(_import, {
3
3
  _name: 'import',
4
- options: ['--out', '--into'],
5
- flags: ['--dry', '--no-copy', '--no-save', '--keep-namespace'],
6
- shortcuts: ['-o', '-in', '-'],
4
+ options: ['--out', '--into', '--as', '--include-namespaces'],
5
+ flags: ['--dry', '--force', '--no-copy', '--no-save', '--keep-namespace'],
6
+ shortcuts: ['-o', '-in', '-as', '-ns', '-', '-f'],
7
7
  help: `
8
8
  # SYNOPSIS
9
9
 
@@ -38,23 +38,51 @@ module.exports = Object.assign(_import, {
38
38
  *- | --dry*
39
39
  Writes the converted csn to stdout only.
40
40
 
41
+ *-as | --as <output_file_format>*
42
+ Converts the input edmx or xml file into one of these supported formats "cds", "csn", "json"
43
+
44
+ *-f | --force*
45
+ Forcefully overwrites the contents in the CDS file and updates the checksum
46
+
47
+ *-ns | --include-namespaces <string_of_namespaces> or* *
48
+ Imports only entities matching to the given list of namespaces.
49
+
50
+
51
+
41
52
 
42
53
  # EXAMPLES
43
54
 
44
55
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx
45
56
  cds import - ~/Downloads/API_BUSINESS_PARTNER.edmx
57
+ cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --as cds
58
+ cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "sap,c4c"
59
+ cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "*"
46
60
 
47
61
  `})
48
62
  const cds = require('@sap/cds/lib')
49
- const { fs, path, write, mkdirp, exists } = cds.utils
63
+ const { fs, path, write, mkdirp, exists, read} = cds.utils
50
64
  const edm2csn = require('../lib/import')
65
+ const messages = require('../lib/import/message').getMessages();
66
+ const common = require('../lib/import/common');
67
+ const cdsCompiler = require('../lib/compile').compile.to;
68
+ const md5 = require('md5');
51
69
  let cwd;
52
- async function _import(file, { out, dry, into,
70
+ async function _import(file, { out, dry, into, as,
71
+ 'include-namespaces': include_namespaces,
53
72
  'no-save': no_save,
54
73
  'no-copy': no_copy,
55
- 'keep-namespace': keep_namespace
74
+ 'keep-namespace': keep_namespace,
75
+ force
56
76
  } = {}) {
77
+ if (!as) {
78
+ if (cds.env.import) as = cds.env.import.as;
79
+ }
80
+ if (!include_namespaces) {
81
+ if(cds.env.import) include_namespaces = cds.env.import.include_namespaces;
82
+ }
57
83
  cwd = into || process.cwd();
84
+ if (as && !common.supportedFormats().includes(as))
85
+ throw new Error(messages.INVALID_AS_OPTION);
58
86
  if (Array.isArray(file)) file = file[0]
59
87
  if (!file) return this.help('import')
60
88
  file = await edm2csn.isValidInputFile(path.resolve(cwd, file))
@@ -62,25 +90,102 @@ async function _import(file, { out, dry, into,
62
90
  const dst = path.join(external, path.basename(file))
63
91
  if (!dry && !no_copy) file = await _copy_to_srv_external(file, dst)
64
92
  const src = await edm2csn.getMetadataFromFile(file)
65
- const csn = await edm2csn.edmx2csn(src, !keep_namespace && file, this)
66
- if (out) out = edm2csn.validateAndComputeOutputFilePath(out);
67
- const written = dry || await _write(csn, out = out || dst.replace(/\.[^.]+$/, '.csn'))
68
- const registered = dry || no_save || await _update_package_json(out, csn, this.oDataVersion)
69
- if (dry) return console.log(JSON.stringify(csn, 0, ' '))
93
+ this.include_all_namespaces = false;
94
+ let namespaces = [];
95
+ if(include_namespaces) {
96
+ if(include_namespaces === "*") this.include_all_namespaces = true;
97
+ else if(typeof include_namespaces === 'string' && !include_namespaces.startsWith('-')) namespaces = include_namespaces.replace(/ /g, "").split(',');
98
+ else throw new Error(messages.INCORRECT_INPUT_NAMESPACES);
99
+ }
100
+ this.namespaces = namespaces;
101
+ let csn = await edm2csn.edmx2csn(src, !keep_namespace && file, this)
102
+ const service = _service_name_from(csn);
103
+ if (out) out = edm2csn.validateAndComputeOutputFilePath(out, as);
104
+ const result = await _getResult(csn, service, as, out || dst.replace(/\.[^.]+$/, ''), force);
105
+ const written = dry || await _write(result[0], result[1], result[2]);
106
+ const registered = dry || no_save || await _update_package_json(result[1].replace(/\.[^.]+$/, ''), service, this.oDataVersion);
107
+ if (dry) return console.log(result[0]);
70
108
  return Promise.all([written, registered])
71
109
  }
72
110
 
73
- async function _write(csn, dest) {
74
- await edm2csn.saveCSNModel(JSON.stringify(csn, null, ' '), dest);
75
- const service = _service_name_from(csn)
76
- let using = `using { ${service} as external } from './${path.relative('srv', dest).replace(/\\/g, '/')}';`
77
- using = require('../lib/util/term').info(using)
78
- console.log(
79
- `[cds] - imported API to ${path.relative(cwd, dest)}
111
+ async function _generateChecksumValidate(dest, output, force) {
112
+ let fileResolved = await exists(dest);
113
+ if (fileResolved === false) {
114
+ let checksum = md5(output);
115
+ output = "/* checksum : " + checksum + " */\n" + output;
116
+ return output;
117
+ }
118
+ else {
119
+ let existingFileContent = await read(dest, "utf-8");
120
+ existingFileContent = String(existingFileContent);
121
+ if (existingFileContent.indexOf("checksum") === -1){
122
+ let checksum = md5(existingFileContent);
123
+ output = "/* checksum : " + checksum + " */\n" + output;
124
+ return output;
125
+ }
126
+ let fileChecksum = existingFileContent.substring(existingFileContent.indexOf("checksum") + 11, existingFileContent.indexOf(" */"));
127
+ existingFileContent = existingFileContent.substring(existingFileContent.indexOf('*/') + 3);
128
+ let checksum = md5(existingFileContent);
129
+ if (fileChecksum === checksum) {
130
+ output = "/* checksum : " + checksum + " */\n" + existingFileContent;
131
+ return output;
132
+ }
133
+ else {
134
+ if (force) {
135
+ output = "/* checksum : " + md5(output) + " */\n" + output;
136
+ return output;
137
+ }
138
+ else {
139
+ throw new Error(messages.FILE_MODIFIED);
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
+ async function _getResult(output, service, as, dest, force) {
146
+ let using, message, extension;
147
+ as = (as === "cds") ? "cdl" : as;
148
+
149
+ if (!common.supportedFormats().includes(extension = dest.substring(dest.lastIndexOf(".") + 1))) {
150
+ // dest doesn't have any file extension, so get it
151
+ extension = common.getSuffix(as);
152
+ }
153
+
154
+ dest = dest.replace('.' + extension, '');
155
+ using = `using { ${service} as external } from './${path.relative('srv', dest).replace(/\\/g, '/')}'`;
156
+ using = require('../lib/util/term').info(using);
157
+ message = `[cds] - imported API to ${path.relative(cwd, dest)}
80
158
  > use it in your CDS models through the like of:
81
159
 
82
160
  ${using}
83
- `) // Please keep the newline above! -> it's intentional
161
+ `;
162
+
163
+ dest += '.' + extension;
164
+
165
+ if (as && as != "csn" && as != "json") {
166
+ // cdsCompiler[as] will convert the csn output into various output formats
167
+ output = cdsCompiler[as](output);
168
+ }
169
+
170
+ switch(as) {
171
+ case "cdl":
172
+ output = await _generateChecksumValidate(dest, output, force);
173
+ break;
174
+ case undefined:
175
+ case "csn":
176
+ case "json":
177
+ output = JSON.stringify(output, null, ' ');
178
+ break;
179
+ default:
180
+ break;
181
+ }
182
+
183
+ return [output, dest, message];
184
+ }
185
+
186
+ async function _write(output, dest, message) {
187
+ await edm2csn.saveCSNModel(output, dest);
188
+ console.log(message);
84
189
  }
85
190
 
86
191
  async function _copy_to_srv_external(file, dst) {
@@ -100,17 +205,14 @@ function _service_name_from(csn) {
100
205
  }
101
206
  }
102
207
 
103
- async function _update_package_json(dest, csn, version) {
208
+ async function _update_package_json(dest, service, version) {
104
209
  const package_json = path.resolve(cwd, 'package.json')
105
210
  const conf = await exists(package_json) ? require(package_json) : {}
106
- const service = _service_name_from(csn)
107
211
  const requires = ['cds', 'requires'].reduce((p, n) => p[n] || (p[n] = {}), conf)
108
212
  if (!requires[service]) {
109
- if (dest.endsWith(".json")) dest = dest.replace(/\.json$/, '').replace(/\\/g, '/');
110
- else dest = dest.replace(/\.csn$/, '').replace(/\\/g, '/');
111
213
  const model = path.relative(cwd, dest)
112
214
  cds.env.requires[service] = requires[service] = { kind: (version === "V2") ? 'odata-v2' : 'odata', model }
113
215
  await write(package_json, JSON.stringify(conf, null, ' '))
114
216
  console.log(`[cds] - updated ./package.json`)
115
217
  }
116
- }
218
+ }