@sap/cds-dk 7.8.2 → 7.9.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 (78) hide show
  1. package/bin/add.js +28 -7
  2. package/bin/bind.js +64 -21
  3. package/bin/build.js +35 -3
  4. package/bin/cds.js +31 -13
  5. package/bin/compile/index.js +44 -3
  6. package/bin/completion/completionFs.js +61 -0
  7. package/bin/completion/index.js +212 -0
  8. package/bin/completion/scripts/cds-bash.sh +17 -0
  9. package/bin/completion/scripts/cds-ps.ps1 +18 -0
  10. package/bin/completion/scripts/cds-zsh.sh +12 -0
  11. package/bin/help.js +8 -2
  12. package/bin/init.js +34 -4
  13. package/bin/subscribe.js +5 -1
  14. package/bin/watch.js +4 -2
  15. package/lib/bind/KubernetesApiAccessor.js +3 -2
  16. package/lib/bind/bindingResolver.js +8 -4
  17. package/lib/bind/bindingUtil.js +10 -8
  18. package/lib/bind/cfKeyProvider.js +58 -153
  19. package/lib/bind/index.js +49 -36
  20. package/lib/bind/kubernetesCredentialsProvider.js +6 -5
  21. package/lib/bind/userCdsrcJsonStorageProvider.js +25 -3
  22. package/lib/build/buildTaskEngine.js +1 -1
  23. package/lib/build/provider/hana/index.js +1 -1
  24. package/lib/build/provider/hana/template/undeploy.json +3 -1
  25. package/lib/build/provider/nodejs/index.js +1 -1
  26. package/lib/compile/openapi/index.js +5 -0
  27. package/lib/deploy/to-hana/hana.js +25 -7
  28. package/lib/env/schemas/cds-rc.js +29 -2
  29. package/lib/import/odata/v4parser.js +78 -25
  30. package/lib/init/constants.js +2 -1
  31. package/lib/init/index.js +18 -13
  32. package/lib/init/merge.js +1 -0
  33. package/lib/init/mvn.js +8 -47
  34. package/lib/init/plugin.js +0 -4
  35. package/lib/init/projectReader.js +17 -10
  36. package/lib/init/template/approuter/files/values.yaml.hbs +0 -12
  37. package/lib/init/template/completion/completionSetup.js +184 -0
  38. package/lib/init/template/completion/index.js +22 -0
  39. package/lib/init/template/data/as-csv.js +25 -17
  40. package/lib/init/template/data/as-json.js +148 -44
  41. package/lib/init/template/data/index.js +28 -15
  42. package/lib/init/template/hana/files/undeploy.json +2 -1
  43. package/lib/init/template/helm/files/chart/values.schema.json +1 -1
  44. package/lib/init/template/helm/files/content-deployment/Chart.yaml +0 -2
  45. package/lib/init/template/helm/files/content-deployment/values.schema.json +0 -1
  46. package/lib/init/template/helm/files/service-instance/Chart.yaml +0 -2
  47. package/lib/init/template/helm/files/service-instance/values.schema.json +0 -1
  48. package/lib/init/template/helm/files/web-application/Chart.yaml +0 -2
  49. package/lib/init/template/helm/files/web-application/values.schema.json +0 -1
  50. package/lib/init/template/helm-unified-runtime/files/values.schema.json +1 -1
  51. package/lib/init/template/http/index.js +150 -104
  52. package/lib/init/template/kafka/index.js +6 -0
  53. package/lib/init/template/lint/index.js +12 -13
  54. package/lib/init/template/mta/files/mta.yaml.hbs +2 -2
  55. package/lib/init/template/multitenancy/files/values.yaml.hbs +0 -5
  56. package/lib/init/template/multitenancy/index.js +13 -5
  57. package/lib/init/template/nodejs/files/.vscode/settings.json +11 -0
  58. package/lib/init/template/nodejs/files/eslint.config.js +13 -0
  59. package/lib/init/template/nodejs/files/package.json.hbs +3 -1
  60. package/lib/init/template/sample/index.js +18 -20
  61. package/lib/init/template/tiny-sample/index.js +1 -2
  62. package/lib/init/template/typer/index.js +2 -2
  63. package/lib/lint/Linter.js +133 -55
  64. package/lib/lint/checks.js +5 -6
  65. package/lib/lint/io.js +119 -10
  66. package/lib/mtx/auth_manager.js +5 -5
  67. package/lib/mtx/params.js +4 -2
  68. package/lib/mtx/settings_manager.js +1 -1
  69. package/lib/mtx/tenant_action.js +12 -2
  70. package/lib/mtx/util/logging.js +10 -4
  71. package/lib/util/axios.js +2 -1
  72. package/lib/util/cf.js +32 -37
  73. package/lib/util/git.js +1 -1
  74. package/lib/util/term.js +1 -1
  75. package/{bin → lib/watch}/watched.js +2 -2
  76. package/npm-shrinkwrap.json +35 -52
  77. package/package.json +2 -2
  78. package/lib/init/template/nodejs/files/.eslintrc +0 -26
@@ -78,7 +78,14 @@ module.exports = class MultitenancyTemplate extends require('../../plugin') {
78
78
  }
79
79
 
80
80
  if (hasHelm || hasHelmUnifiedRuntime) {
81
- await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project })
81
+ const overwrites = hasXsuaa ? [{
82
+ item: [{
83
+ in: 'xsuaa',
84
+ where: { serviceOfferingName: 'xsuaa' }
85
+ }, 'parameters.tenant-mode'], withValue: 'shared'
86
+ }] : []
87
+
88
+ await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project, overwrites })
82
89
 
83
90
  const envFromObject = {
84
91
  envFrom: [{
@@ -100,11 +107,12 @@ module.exports = class MultitenancyTemplate extends require('../../plugin') {
100
107
  }
101
108
  }
102
109
  ]
103
- }}).into('chart/values.yaml', { with: project })
110
+ }
111
+ }).into('chart/values.yaml', { with: project })
104
112
 
105
- await removeFromYAML(join('chart', 'values.yaml'), ['srv.expose', 'srv.networkSecurity'])
106
- await copy(join(__dirname, 'files', `mtxs-configmap-${isJava ? 'java' : 'nodejs'}${hasApprouter ? '-approuter' : ''}.yaml`)).to('chart', 'templates', 'mtxs-configmap.yaml') // REVISIT: Move to build task
107
- await copy(join(__dirname, 'files', 'saas-registry-secret.yaml')).to('chart', 'templates', 'saas-registry-secret.yaml') // REVISIT: Move to build task
113
+ await removeFromYAML(join('chart', 'values.yaml'), ['srv.expose', 'srv.networkSecurity'])
114
+ await copy(join(__dirname, 'files', `mtxs-configmap-${isJava ? 'java' : 'nodejs'}${hasApprouter ? '-approuter' : ''}.yaml`)).to('chart', 'templates', 'mtxs-configmap.yaml') // REVISIT: Move to build task
115
+ await copy(join(__dirname, 'files', 'saas-registry-secret.yaml')).to('chart', 'templates', 'saas-registry-secret.yaml') // REVISIT: Move to build task
108
116
  }
109
117
 
110
118
  if (hasXsuaa) {
@@ -0,0 +1,11 @@
1
+ {
2
+ // uncomment entries once all libraries have been installed via 'npm install'
3
+ "eslint.validate": [
4
+ // "cds",
5
+ // "csn",
6
+ // "csv",
7
+ // "csv (semicolon)",
8
+ // "tab",
9
+ // "tsv"
10
+ ]
11
+ }
@@ -0,0 +1,13 @@
1
+ const cds = require('@sap/eslint-plugin-cds')
2
+
3
+ module.exports = [
4
+ cds.configs.recommended,
5
+ {
6
+ plugins: {
7
+ '@sap/cds': cds
8
+ },
9
+ rules: {
10
+ ...cds.configs.recommended.rules
11
+ }
12
+ }
13
+ ]
@@ -10,7 +10,9 @@
10
10
  "express": "^4"
11
11
  },
12
12
  "devDependencies": {
13
- "@cap-js/sqlite": "^1"
13
+ "@cap-js/sqlite": "^1",
14
+ "@sap/eslint-plugin-cds": "^3",
15
+ "eslint": "^9"
14
16
  },
15
17
  "scripts": {
16
18
  "start": "cds-serve"
@@ -1,33 +1,31 @@
1
1
  const { join } = require('path')
2
2
  const cds = require('../../../cds'), { exists, read, write, copy } = cds.utils
3
3
  const { env4, readProject } = require('../../projectReader')
4
+ const mvn = require('../../mvn')
4
5
 
5
6
  module.exports = class SampleTemplate extends require('../../plugin') {
6
7
 
7
- async canRun() {
8
- const { isJava } = readProject()
9
- if (isJava) throw `'cds add sample' is not available for Java yet`
10
- return true
11
- }
12
-
13
8
  async run() {
14
9
  const { db, srv, app } = env4('production').folders
15
10
  const language = exists('pom.xml') ? 'java' : 'nodejs'
16
11
 
17
- await Promise.all([
18
- copy(join(__dirname, 'files', 'db')).to(db),
19
- copy(join(__dirname, 'files', 'srv')).to(srv),
20
- copy(join(__dirname, 'files', language)).to(srv)
21
- ])
22
-
23
- await copy(join(__dirname, 'files', 'app')).to(app)
24
- const { appName, appPath, appUIPaths } = readProject()
12
+ if (language === 'nodejs') {
13
+ await Promise.all([
14
+ copy(join(__dirname, 'files/db')).to(db),
15
+ copy(join(__dirname, 'files/srv')).to(srv)
16
+ ])
17
+ await copy(join(__dirname, 'files', language)).to(srv)
18
+ await copy(join(__dirname, 'files', 'app')).to(app)
19
+ const { appName, appPath, appUIPaths } = readProject()
25
20
 
26
- // manifest.json must be unique
27
- await Promise.all(appUIPaths.map(async p => {
28
- const manifest = await read(join(appPath, p, 'webapp/manifest.json'))
29
- manifest['sap.app'].id = appName + '.' + p
30
- await write(join(appPath, p, 'webapp/manifest.json'), manifest, { spaces: 2 })
31
- }))
21
+ // manifest.json must be unique // REVISIT: Check if relevant for `cds add sample` in Java scenario
22
+ await Promise.all(appUIPaths.map(async p => {
23
+ const manifest = await read(join(appPath, p, 'webapp/manifest.json'))
24
+ manifest['sap.app'].id = appName + '.' + p
25
+ await write(join(appPath, p, 'webapp/manifest.json'), manifest, { spaces: 2 })
26
+ }))
27
+ } else if (language === 'java') {
28
+ await mvn.add('sample')
29
+ }
32
30
  }
33
31
  }
@@ -11,8 +11,7 @@ module.exports = class TinySampleTemplate extends require('../../plugin') {
11
11
  const { isJava } = readProject()
12
12
  if (isJava) {
13
13
  if (!cds.cli.options.add.has(JAVA)) {
14
- await mvn.execMvn(mvn.getAddSamplesCmdArgs())
15
- await mvn.execMvn(mvn.getAddTestsCmdArgs())
14
+ await mvn.add('tiny_sample')
16
15
  }
17
16
  } else {
18
17
  const { db, srv } = env4('production').folders
@@ -1,7 +1,7 @@
1
1
  const { join } = require('path')
2
2
  const { readProject } = require('../../projectReader')
3
3
  const { merge, mergeGitignore } = require('../../merge')
4
- const { warn, secondary } = require('../../../util/term')
4
+ const { warn, dim } = require('../../../util/term')
5
5
  const { TYPER } = require('../../constants').OPTIONS
6
6
  const { exists, read } = require('../../../cds').utils
7
7
 
@@ -25,7 +25,7 @@ module.exports = class TyperTemplate extends require('../../plugin') {
25
25
  }
26
26
  await merge(template('package.json')).into('package.json')
27
27
  await mergeGitignore('.gitignore', template('gitignore'))
28
- console.log(secondary(` > Adding '@cds-models' to .gitignore to ignore generated types`)) // REVISIT: other facets are silent wrt. what they change
28
+ console.log(dim(` Adding '@cds-models' to .gitignore to ignore generated types`)) // REVISIT: other facets are silent wrt. what they change
29
29
  try {
30
30
  await merge(source).into(target)
31
31
  } catch (e) {
@@ -10,6 +10,8 @@ const { exit } = require("process");
10
10
  const LOG = cds.debug("lint");
11
11
  const LOG_CONFIG = cds.debug("lint:config");
12
12
 
13
+ const GENERAL_ERROR = 1;
14
+
13
15
  class Linter {
14
16
  constructor() {
15
17
  this.eslintCmd = "";
@@ -61,6 +63,11 @@ class Linter {
61
63
  * @param {*} options options/flag passed by user
62
64
  */
63
65
  async lint(args, options) {
66
+ // Check for ESLint (legacy)
67
+ const currentDir = process.cwd();
68
+ const DefaultESLint = await this._loadEslint(currentDir);
69
+ this.isESLintLegacy = DefaultESLint.configType === "eslintrc";
70
+
64
71
  this.eslintCmdOpts = this._sanitizeUserOpts(options);
65
72
  this.eslintCmdFileExpr = args.length ? args : ["."];
66
73
  if (this.eslintCmdOpts.help) {
@@ -82,7 +89,7 @@ class Linter {
82
89
 
83
90
  // Run ESLint with collected options
84
91
  try {
85
- await this._runEslint();
92
+ await this._runEslint(currentDir, DefaultESLint);
86
93
  } catch (err) {
87
94
  term.error(err);
88
95
  }
@@ -91,7 +98,6 @@ class Linter {
91
98
 
92
99
  _printHelp() {
93
100
  console.log(this.help.replace(/ \*([^*]+)\*/g, ` ${term.codes.bold}$1${term.codes.reset}`));
94
- return;
95
101
  }
96
102
 
97
103
  _sanitizeUserOpts(options) {
@@ -111,7 +117,7 @@ class Linter {
111
117
  * @param {string} currentDir start here and search until root dir
112
118
  * @returns {string} dir containing ESLint config file (empty if not exists)
113
119
  */
114
- async _getConfigPath(currentDir = ".") {
120
+ async _getConfigPathLegacy(currentDir = ".") {
115
121
  const configFiles = [
116
122
  ".eslintrc.js",
117
123
  ".eslintrc.cjs",
@@ -122,18 +128,48 @@ class Linter {
122
128
  "package.json",
123
129
  ];
124
130
  let configDir = path.resolve(currentDir);
125
- while (configDir !== path.resolve(configDir, "..")) {
131
+ while (configDir && configDir !== path.dirname(configDir)) {
126
132
  for (let i = 0; i < configFiles.length; i++) {
127
133
  const configPath = path.join(configDir, configFiles[i]);
128
- if (configFiles[i] !== "package.json" || (
129
- configFiles[i] === "package.json" && require(configPath).eslintConfig
130
- )) {
134
+ const config = this.safeRequire(configPath)
135
+
136
+ if (configFiles[i] !== "package.json" || config?.eslintConfig) {
131
137
  if (exists(configPath) && await isfile(configPath)) {
132
138
  return configPath;
133
139
  }
134
140
  }
135
141
  }
136
- configDir = path.join(configDir, "..");
142
+
143
+ configDir = path.dirname(configDir);
144
+ }
145
+ return "";
146
+ }
147
+
148
+ /**
149
+ * Searches for ESLint config file types (in order or precedence)
150
+ * and returns corresponding directory (usually project's root dir)
151
+ * https://eslint.org/docs/user-guide/configuring#configuration-file-formats
152
+ * @param {string} currentDir start here and search until root dir
153
+ * @returns {string} dir containing ESLint config file (empty if not exists)
154
+ */
155
+ async _getConfigPath(currentDir = ".") {
156
+ const configFiles = [
157
+ "eslint.config.js",
158
+ "eslint.config.cjs",
159
+ "eslint.config.mjs"
160
+ ];
161
+ let configDir = path.resolve(currentDir);
162
+ while (configDir && configDir !== path.dirname(configDir)) {
163
+ for (let i = 0; i < configFiles.length; i++) {
164
+ const configPath = path.join(configDir, configFiles[i]);
165
+ const config = this.safeRequire(configPath)
166
+ if (configFiles[i] !== "package.json" || config?.eslintConfig) {
167
+ if (exists(configPath) && await isfile(configPath)) { // TODO exists neccessary ?
168
+ return configPath;
169
+ }
170
+ }
171
+ }
172
+ configDir = path.dirname(configDir);
137
173
  }
138
174
  return "";
139
175
  }
@@ -146,45 +182,51 @@ class Linter {
146
182
  this.fileExtensions.forEach((ext) => {
147
183
  this.ignorePatterns.push(`!${ext}`);
148
184
  });
149
- return;
150
185
  }
151
186
 
152
- async _runEslint() {
187
+ async _runEslint(currentDir, DefaultESLint) {
153
188
  try {
154
- const currentDir = process.cwd();
155
-
156
- const { ESLint } = require("eslint");
157
189
 
158
190
  let eslintOpts = {
159
191
  cwd: currentDir,
160
- extensions: this.fileExtensions,
161
192
  overrideConfig: {
162
193
  ...this.configContents,
163
194
  },
164
- useEslintrc: false,
165
195
  };
166
196
 
167
197
  if (this.lintType === "global") {
168
198
  eslintOpts = {
169
199
  cwd: process.cwd(),
170
- extensions: this.fileExtensions,
171
- overrideConfig: {
172
- plugins: ["@sap/eslint-plugin-cds"],
173
- extends: "plugin:@sap/cds/recommended"
174
- },
175
- useEslintrc: false,
176
- resolvePluginsRelativeTo: this.cdsdkPath
200
+ overrideConfig: {},
177
201
  };
178
202
  }
179
203
 
204
+ if (this.isESLintLegacy) {
205
+ LOG?.("Using legacy ESLint configuration");
206
+ eslintOpts.extensions = this.fileExtensions;
207
+ eslintOpts.overrideConfig.extends = "plugin:@sap/cds/recommended-legacy"
208
+ eslintOpts.overrideConfig.plugins = ["@sap/eslint-plugin-cds"]
209
+ eslintOpts.useEslintrc = false
210
+ if (this.lintType === "global") {
211
+ eslintOpts.resolvePluginsRelativeTo = this.cdsdkPath
212
+ }
213
+ } else {
214
+ LOG?.("Using flat ESLint configuration");
215
+ const cdsPlugin = require(this.pluginPath)
216
+ // Exvlude our own apis from plugin to avoid wrapper errors
217
+ delete cdsPlugin.configs.recommended?.plugins?.['@sap/cds']
218
+ eslintOpts.overrideConfig = [cdsPlugin.configs.recommended]
219
+ }
220
+
180
221
  if (this.customRulesOpts && this.customRulesOpts.length > 0) {
181
222
  eslintOpts.rulePaths = [this.customRulesOpts]
182
223
  }
183
224
 
184
- LOG_CONFIG && LOG_CONFIG(eslintOpts);
225
+ LOG_CONFIG?.(eslintOpts);
185
226
 
186
227
  let lintString = `eslint`;
187
- if (this.fileExtensions) { lintString += ` --ext "${this.fileExtensions.join(",")}"`}
228
+ if (this.fileExtensions) { lintString += ` --ext "${this.fileExtensions.join(",")}"` }
229
+
188
230
  for (const ruleOpt of Object.entries(this.ruleOpts)) {
189
231
  lintString += ` --rule ${ruleOpt[0]}:${ruleOpt[1]}`;
190
232
  }
@@ -192,10 +234,10 @@ class Linter {
192
234
  lintString += ` --rulesdir "${this.customRulesOpts}"`
193
235
  }
194
236
 
195
- LOG && LOG(lintString);
237
+ LOG?.(lintString);
196
238
 
197
239
  if (!process.env.isTest) {
198
- const eslint = new ESLint(eslintOpts);
240
+ const eslint = new DefaultESLint(eslintOpts);
199
241
  const formatter = await eslint.loadFormatter("stylish");
200
242
 
201
243
  let results = (await eslint.lintText("")).map((result) => {
@@ -221,13 +263,12 @@ class Linter {
221
263
  const eslintBase = `${require.resolve('eslint').split('eslint')[0]}/eslint`;
222
264
  const template = require(path.join(eslintBase, `messages/${err.messageTemplate}.js`));
223
265
  console.log(template(err.messageData || {}));
224
- exit(1)
225
266
  } catch {
226
- // Ignore template error then fallback to use `error.stack`.
267
+ // Ignore template error then fallback to use `error.stack`.
268
+ console.log(err.stack);
227
269
  }
228
- console.log(err.stack);
229
- }
230
- exit(1)
270
+ }
271
+ exit(GENERAL_ERROR); // TODO use error constant
231
272
  }
232
273
  }
233
274
 
@@ -244,31 +285,50 @@ class Linter {
244
285
  input = ".";
245
286
  }
246
287
  }
247
- this.configPath = await this._getConfigPath(process.cwd());
288
+ this.configPath = this.isESLintLegacy
289
+ ? await this._getConfigPathLegacy(process.cwd())
290
+ : await this._getConfigPath(process.cwd());
248
291
  if (!this.configPath) {
249
292
  this.lintType === "global";
250
- this.configContents = await io.sanitizeEslintConfig({}, false, LOG);
293
+ this.configContents = this.isESLintLegacy
294
+ ? await io.sanitizeEslintConfigLegacy({}, false, LOG)
295
+ : await io.sanitizeEslintConfig({}, false, LOG);
251
296
  } else {
252
- const configContents = await io.readEslintConfig(this.configPath);
253
- this.configContents = await io.sanitizeEslintConfig(configContents, false, LOG);
254
- if (this.configContents) {
255
- if ("extends" in this.configContents) {
256
- this.extendsPlugin = checks.hasEslintConfigContent(
257
- this.configContents,
258
- "extends"
259
- );
260
- if (this.extendsPlugin) {
261
- this.lintType = "local";
262
- try {
263
- this.pluginPath = require.resolve("@sap/eslint-plugin-cds", {
264
- paths: [path.dirname(this.configPath)],
265
- });
266
- this.pluginApi = require(this.pluginPath.replace("index.js", "api"));
267
- } catch (err) {
268
- // CLI will report (no locally installed plugin)
297
+ const configContents = this.isESLintLegacy
298
+ ? await io.readEslintConfigLegacy(this.configPath)
299
+ : await io.readEslintConfig(this.configPath);
300
+ this.configContents = configContents;
301
+ if (this.isESLintLegacy) {
302
+ this.configContents = await io.sanitizeEslintConfig(configContents, false, LOG);
303
+ if (this.configContents) {
304
+ if ("extends" in this.configContents) {
305
+ this.extendsPlugin = checks.hasEslintConfigContent(
306
+ this.configContents,
307
+ "extends"
308
+ );
309
+ if (this.extendsPlugin) {
310
+ this.lintType = "local";
311
+ try {
312
+ this.pluginPath = require.resolve("@sap/eslint-plugin-cds", {
313
+ paths: [path.dirname(this.configPath)],
314
+ });
315
+ this.pluginApi = require(this.pluginPath.replace("index.js", "api"));
316
+ } catch (err) {
317
+ // CLI will report (no locally installed plugin)
318
+ }
269
319
  }
270
320
  }
271
321
  }
322
+ } else {
323
+ const cdsConfig = configContents?.filter(c => c.files?.includes("*.cds"))[0] ?? {}
324
+ this.configContents = cdsConfig.files
325
+ ? {
326
+ ...cdsConfig.plugins.configs?.recommended,
327
+ languageOptions: cdsConfig.languageOptions,
328
+ files: cdsConfig.files,
329
+ rules: cdsConfig.rules,
330
+ }
331
+ : {};
272
332
  }
273
333
  }
274
334
  if (!this.pluginPath) {
@@ -281,17 +341,20 @@ class Linter {
281
341
  // CLI will report (no globally installed plugin)
282
342
  }
283
343
  }
284
- return;
344
+ LOG?.(`Lint type: ${this.lintType}`);
345
+ LOG?.(`ESLint CDS plugin resolved: ${this.pluginPath}`);
285
346
  }
286
347
 
287
348
  async _overwriteRuleSeverities() {
288
349
  let configContents = {};
289
350
  if (this.configPath) {
290
- configContents = await io.readEslintConfig(this.configPath);
351
+ configContents = await io.readEslintConfigLegacy(this.configPath);
291
352
  } else {
292
- configContents = await io.readEslintConfig(await this._getConfigPath(this.cdsdkPath));
353
+ configContents = this.isESLintLegacy
354
+ ? await io.readEslintConfigLegacy(await this._getConfigPath(this.cdsdkPath))
355
+ : await io.readEslintConfig(await this._getConfigPath(this.cdsdkPath));
293
356
  }
294
- let rules = configContents.rules;
357
+ let rules = configContents?.rules || {};
295
358
  // Allow recommended plugin rules in cds-dk to be overwritten
296
359
  // by user by adding rule to cmd line (because of precedence)
297
360
  const pluginRules = require(this.pluginPath).configs.recommended.rules;
@@ -305,7 +368,22 @@ class Linter {
305
368
  }
306
369
  }
307
370
  }
308
- return;
371
+ }
372
+
373
+ async _loadEslint(currentDir) {
374
+ const { loadESLint, ESLint } = require("eslint");
375
+ const DefaultESLint = loadESLint
376
+ ? await loadESLint({ cwd: currentDir }) // ESLint 9
377
+ : new ESLint({ cwd: currentDir }) // ESLint 8
378
+ return DefaultESLint;
379
+ }
380
+
381
+ safeRequire(module) {
382
+ try {
383
+ return require(module)
384
+ } catch (e) {
385
+ return {}
386
+ }
309
387
  }
310
388
  }
311
389
 
@@ -7,7 +7,7 @@ const IS_WIN = os.platform() === "win32";
7
7
 
8
8
  module.exports = {
9
9
  /**
10
- * Checks whether ESLint v>=7 is installed by trying to resolve
10
+ * Checks whether ESLint v>=8 is installed by trying to resolve
11
11
  * 'eslint' module from (1) <inputPath> or (2) global npm path
12
12
  * @param {*} inputPath where to resolve 'eslint' module from
13
13
  * @param {*} globalPath resolves 'eslint' module from cds-dk
@@ -23,14 +23,14 @@ module.exports = {
23
23
  paths: [inputPath, globalPath],
24
24
  });
25
25
  const packageJson = require(eslintPath);
26
- if (packageJson.version > "7") {
26
+ if (packageJson.version >= "8") {
27
27
  version = packageJson.version;
28
28
  } else {
29
29
  errMessage =
30
- `ESLint v>=6.0.0 required!\n\n` +
30
+ `ESLint v>=8.0.0 required!\n\n` +
31
31
  ` Make sure to update and check for any breaking changes:\n` +
32
32
  ` ${term.warn(
33
- "https://eslint.org/docs/user-guide/migrating-to-6.0.0"
33
+ "https://eslint.org/docs/user-guide/migrating-to-8.0.0"
34
34
  )}\n`;
35
35
  }
36
36
  const bin = packageJson.bin.eslint;
@@ -53,7 +53,6 @@ module.exports = {
53
53
  if (logger) {
54
54
  logger.error(errMessage);
55
55
  }
56
- return;
57
56
  },
58
57
 
59
58
  /**
@@ -132,5 +131,5 @@ module.exports = {
132
131
  // Do nothing
133
132
  }
134
133
  return false;
135
- },
134
+ }
136
135
  };