@sap/cds-dk 4.6.0 → 4.6.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,27 @@ 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.2 - 2021-11-09
10
+
11
+ ### Fixed
12
+
13
+ - `cds add lint` now correctly detects missing local `eslint`
14
+ - `cds add lint` no longer removes parts of `package.json`
15
+ - `cds add lint` no longer creates duplicate configuration entries
16
+
17
+ ## Version 4.6.1 - 2021-11-08
18
+
19
+ ### Changed
20
+
21
+ - `cds init` uses latest `Maven Java archetype` version `1.20.0` for creating Java projects.
22
+ - `cds watch` now resolves local node modules like `hdb` even though `@sap/cds` is not installed locally. This is useful during development where `@sap/cds` shall only be installed in a 'central' location, while extra modules shall still be found in the app's dir.
23
+
24
+ ### Fixed
25
+
26
+ - `cds repl` now finds modules like `hdb` that are installed locally in the app folder
27
+ - `cds repl` now enables the `await` statement also on Windows
28
+ - `cds lint` now limits all file extensions to those allowed by the @sap/eslint-plugin-cds ESLint configuration
29
+
9
30
  ## Version 4.6.0 - 2021-11-02
10
31
  ### Added
11
32
 
@@ -38,6 +38,7 @@ module.exports = Object.assign ( compile, {
38
38
  - json, yml
39
39
  - edm, edmx, edmx-v2, edmx-v4, edmx-w4, edmx-x4
40
40
  - sql, hdbcds, hdbtable
41
+ - cdl [beta]
41
42
  - xsuaa
42
43
  - openapi
43
44
 
@@ -261,7 +262,7 @@ function compile (models, options={}) {
261
262
 
262
263
  function suffix4 (x) { return x && ({
263
264
  edmx: '.xml',
264
- "edmx-v2": '.xml',
265
+ "edmx-v2": '.xml',
265
266
  "edmx-v4": '.xml',
266
267
  openapi: '.openapi3.json', //'.yml',
267
268
  cdl: '.cds',
package/bin/repl.js CHANGED
@@ -14,8 +14,12 @@ module.exports = Object.assign (repl, { options: [], help: `
14
14
 
15
15
  function repl (_, options={}) {
16
16
 
17
- if (module.parent && module.parent.filename.endsWith('/bin/cds.js')) {
18
- return require('child_process').spawn('node',['--experimental-repl-await', __filename ],{stdio:'inherit'})
17
+ // enable `await` statement for Node.js < 16
18
+ if (!process.env['CDS_REPL_SPAWNED'] && process.version.split('.')[0].slice(1) < '16') {
19
+ process.env['CDS_REPL_SPAWNED'] = true
20
+ return require('child_process').spawn('node',['--experimental-repl-await',
21
+ ...process.argv.slice(1) ], {stdio:'inherit'}
22
+ )
19
23
  }
20
24
 
21
25
  const cds = require('@sap/cds/lib')
package/bin/watch.js CHANGED
@@ -43,7 +43,7 @@ module.exports = Object.assign ( watch, {
43
43
  `})
44
44
 
45
45
  const DEBUG = /\bwatch\b/.test(process.env.DEBUG) && console.debug
46
- const path = require ('path')
46
+ const {delimiter,dirname,relative,resolve,sep} = require ('path')
47
47
  const fs = require ('fs')
48
48
  const t = module.exports.codes = {
49
49
  reset: '\x1b[0m', // Default
@@ -71,8 +71,11 @@ async function watch ([cwd], {
71
71
  _args: JSON.stringify(args),
72
72
  _options: JSON.stringify(options)
73
73
  })
74
+
75
+ // allow running w/o or partial local node_modules, also add cds-dk for its sqlite
76
+ env.NODE_PATH = [...paths(cwd||process.cwd()), ...paths(__dirname)].join(delimiter)
77
+
74
78
  if (typeof ext !== 'string') ext = extDefaults
75
- env.NODE_PATH = path.resolve (__dirname,'../node_modules') // allow global sqlite to be resolved
76
79
 
77
80
  let liveReload //= ...
78
81
  let firstTime = true
@@ -83,7 +86,7 @@ async function watch ([cwd], {
83
86
  env.CDS_LIVERELOAD_URL = await liveReload.start (options['livereload'])
84
87
  .catch(err => { console.log(`Error starting live reload: ${err.message}`); liveReload = null })
85
88
  } else {
86
- ignore = RegExp(`app${path.sep}.*\\.(js|ts)|`+ignore.source) // exclude more frontend stuff
89
+ ignore = RegExp(`app${sep}.*\\.(js|ts)|`+ignore.source) // exclude more frontend stuff
87
90
  }
88
91
 
89
92
  const log = (first,...more) => console.log (t.yellow + (first||''), ...more, t.reset)
@@ -91,8 +94,8 @@ async function watch ([cwd], {
91
94
  const ocwd = process.env._original_cwd = process.cwd()
92
95
  if (fs.existsSync(cwd)) log (`cd ${cwd}`)
93
96
  else try {
94
- const resolved = path.dirname (require.resolve(cwd+'/package.json', {paths:[ocwd]}))
95
- log (`cd ${path.relative(ocwd,cwd = resolved)}`)
97
+ const resolved = dirname (require.resolve(cwd+'/package.json', {paths:[ocwd]}))
98
+ log (`cd ${relative(ocwd,cwd = resolved)}`)
96
99
  } catch(_){ throw new Error(`No such folder or package: '${ocwd}' -> '${cwd}'`) }
97
100
  }
98
101
  log ()
@@ -172,6 +175,12 @@ function removeArgsIn (toRemove) {
172
175
  }
173
176
  }
174
177
 
178
+ // builds paths from dir + its parent node_modules
179
+ function paths (dir) {
180
+ const parts = resolve(dir).split(sep), n = parts.length, nm = sep+'node_modules'
181
+ return parts.map ((_,i,a)=> a.slice(0,n-i).join(sep)+nm).filter(p => fs.existsSync(p))
182
+ }
183
+
175
184
  //
176
185
  // Child process impl launched by watch
177
186
  //
@@ -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}`);
@@ -1,6 +1,6 @@
1
1
  const os = require('os');
2
2
 
3
- const MAVEN_ARCHETYPE_VERSION = '1.19.0';
3
+ const MAVEN_ARCHETYPE_VERSION = '1.20.0';
4
4
 
5
5
  const constants = {
6
6
  IS_WIN: (os.platform() === 'win32'),
@@ -42,12 +42,9 @@ module.exports = class LintTemplate extends TemplateBase {
42
42
  }
43
43
 
44
44
  async run() {
45
- const cdsdkPath = path.join(__dirname, "../../../..");
46
- const globalPath = path.join(cdsdkPath, "../..");
47
-
48
45
  // Require ESLint v>=7.0.0
49
46
  if (!this.isTest) {
50
- this._checkEslint(globalPath);
47
+ this._checkEslint();
51
48
  }
52
49
 
53
50
  // To enable custom lint rules ('lint' or 'lint:dev')
@@ -69,15 +66,16 @@ module.exports = class LintTemplate extends TemplateBase {
69
66
  // Generate custom lint rules docs
70
67
  await generators.genDocs(this.projectPath);
71
68
  }
69
+
70
+ // Generate VS Code extension settings
71
+ await io.sanitizeVscodeSettings(
72
+ this.projectPath,
73
+ path.join(this.projectPath, ".vscode/settings.json"),
74
+ this.lintType,
75
+ this.customRuleExample
76
+ );
72
77
  }
73
78
 
74
- // Generate VS Code extension settings
75
- await io.sanitizeVscodeSettings(
76
- this.projectPath,
77
- path.join(this.projectPath, ".vscode/settings.json"),
78
- this.lintType,
79
- this.customRuleExample
80
- );
81
79
  }
82
80
 
83
81
  async finalize() {
@@ -111,12 +109,8 @@ module.exports = class LintTemplate extends TemplateBase {
111
109
 
112
110
  }
113
111
 
114
- _checkEslint(globalPath) {
115
- const eslintInfo = checks.resolveEslint(this.projectPath, globalPath);
116
- let eslintCmd;
117
- if (eslintInfo) {
118
- eslintCmd = eslintInfo.cmd;
119
- }
112
+ _checkEslint() {
113
+ const eslintCmd = checks.resolveEslint(this.projectPath, '');
120
114
  if (!eslintCmd) {
121
115
  this.missingNpmDependencies["names"].push("eslint");
122
116
  this.missingNpmDependencies["msgs"].push("ESLint v>=7.0.0");
@@ -28,5 +28,3 @@ mta_archives/
28
28
  # IDEs
29
29
  # .vscode
30
30
  # .idea
31
-
32
- .cdsrc-private.json
@@ -14,6 +14,8 @@ const {
14
14
  } = require("@sap/eslint-plugin-cds/lib/api");
15
15
 
16
16
  const IS_WIN = os.platform() === "win32";
17
+ const ALLOWED_FILE_EXTENSIONS = getFileExtensions();
18
+
17
19
  class Linter {
18
20
  constructor() {
19
21
  this.eslintCmd = "";
@@ -45,11 +47,7 @@ class Linter {
45
47
  * @returns object continaing help, options, flags and shortcuts
46
48
  */
47
49
  init(help = "", options = [], flags = [], shortcuts = []) {
48
- const eslintInfo = checks.resolveEslint(this.cdsdkPath, this.globalPath);
49
- if (eslintInfo) {
50
- this.eslintCmd = eslintInfo.cmd;
51
- }
52
- this.addFormatter = eslintInfo.addFormatter;
50
+ this.eslintCmd = checks.resolveEslint(this.cdsdkPath, this.globalPath);
53
51
  if (this.eslintCmd) {
54
52
  help = generators.genEslintHelp(this.eslintCmd);
55
53
  flags = generators.genEslintFlags(help);
@@ -98,7 +96,7 @@ class Linter {
98
96
  }
99
97
 
100
98
  // Limit to CDS file extensions
101
- this._addExtensions(this.addFormatter);
99
+ this._addExtensions();
102
100
  // Run ESLint with collected options
103
101
  try {
104
102
  await this._runEslint();
@@ -141,25 +139,14 @@ class Linter {
141
139
  return;
142
140
  }
143
141
 
144
- _addExtensions(addFormatter) {
142
+ _addExtensions() {
145
143
  // Add CDS file extensions to lint
144
+ const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => ext.replace('*.', '.'));
146
145
  this.eslintCmdOpts = io.mergeWithUserOpts(
147
146
  this.eslintCmdOpts,
148
147
  "ext",
149
- ".cds,.csn"
148
+ extensions.join(',')
150
149
  );
151
- // Add custom CDS formatter (for ESLint v<8)
152
- if (addFormatter) {
153
- const formatterPath = this.pluginPath.replace(
154
- "index.js",
155
- "../api/formatter.js"
156
- );
157
- this.eslintCmdOpts = io.mergeWithUserOpts(
158
- this.eslintCmdOpts,
159
- "format",
160
- path.relative(".", formatterPath)
161
- );
162
- }
163
150
  // Enable colored output
164
151
  if (process.stdout.isTTY) {
165
152
  this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
@@ -193,7 +180,6 @@ class Linter {
193
180
  }
194
181
  }
195
182
  // Only lint file extensions prescribed by plugin
196
- const fileExtensions = getFileExtensions();
197
183
  eslintCmdOpts.push("--ignore-pattern");
198
184
  let ignorePattern = "*.*";
199
185
  if (IS_WIN) {
@@ -202,7 +188,7 @@ class Linter {
202
188
  ignorePattern = `'${ignorePattern}'`;
203
189
  }
204
190
  eslintCmdOpts.push(ignorePattern);
205
- fileExtensions.forEach((ext) => {
191
+ ALLOWED_FILE_EXTENSIONS.forEach((ext) => {
206
192
  eslintCmdOpts.push("--ignore-pattern");
207
193
  ignorePattern = `!${ext}`;
208
194
  if (IS_WIN) {
@@ -21,7 +21,6 @@ module.exports = {
21
21
  let cmd;
22
22
  let version;
23
23
  let errMessage;
24
- let addFormatter = false;
25
24
  try {
26
25
  const eslintPath = require.resolve("eslint/package.json", {
27
26
  paths: [inputPath, globalPath],
@@ -29,9 +28,6 @@ module.exports = {
29
28
  const packageJson = require(eslintPath);
30
29
  if (packageJson.version > "7") {
31
30
  version = packageJson.version;
32
- if (version < "8") {
33
- addFormatter = true;
34
- }
35
31
  } else {
36
32
  errMessage =
37
33
  `ESLint v>=6.0.0 required!\n\n` +
@@ -55,7 +51,7 @@ module.exports = {
55
51
  )}\n`;
56
52
  }
57
53
  if (cmd && version) {
58
- return { cmd, addFormatter };
54
+ return cmd;
59
55
  }
60
56
  if (logger) {
61
57
  logger.error(errMessage);
@@ -3,6 +3,7 @@ const os = require("os");
3
3
  const cp = require("child_process");
4
4
  const path = require("path");
5
5
  const { mkdirp } = require("@sap/cds/lib/utils");
6
+ const term = require("../util/term");
6
7
 
7
8
  const IS_WIN = os.platform() === "win32";
8
9
 
@@ -35,12 +36,12 @@ module.exports = {
35
36
  let cdslintCmd = eslintOpts[0].replace("eslint", "*cds lint*");
36
37
  eslintOpts[0] = `
37
38
  # SYNOPSIS
38
-
39
+
39
40
  ${cdslintCmd} [beta]
40
-
41
+
41
42
  Runs environment checks and/or checks the specified models
42
43
  based on the ESLint framework
43
-
44
+
44
45
  # OPTIONS`;
45
46
  return `${eslintOpts.join("\n ")}\n`;
46
47
  },
@@ -97,7 +98,7 @@ module.exports = {
97
98
  },
98
99
 
99
100
  /**
100
- * Generates custom rules documentation for user
101
+ * Generates custom rules documentation for user
101
102
  * according to contents of rules files
102
103
  * @param {*} projectPath
103
104
  */
package/lib/lint/io.js CHANGED
@@ -71,7 +71,9 @@ module.exports = {
71
71
  configContents["extends"].push(extendsValue);
72
72
  }
73
73
  } else {
74
- configContents["extends"] = [configContents["extends"], extendsValue];
74
+ if (configContents["extends"] !== extendsValue) {
75
+ configContents["extends"] = [configContents["extends"], extendsValue];
76
+ }
75
77
  }
76
78
  } else {
77
79
  configContents["extends"] = extendsValue;
@@ -138,7 +140,7 @@ module.exports = {
138
140
  case ".eslintrc":
139
141
  case "package.json":
140
142
  if (configFile === "package.json") {
141
- if (await fsp.access(configPath)) {
143
+ if (await fsUtil.pathExists(configPath)) {
142
144
  contents = JSON.parse(await fsp.readFile(configPath, "utf8"));
143
145
  } else {
144
146
  contents = {};