@sap/cds-dk 6.0.4 → 6.1.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 (104) hide show
  1. package/CHANGELOG.md +60 -1
  2. package/bin/add.js +29 -16
  3. package/bin/compile/index.js +7 -2
  4. package/bin/fix-redirects.js +4 -2
  5. package/bin/init.js +5 -0
  6. package/bin/login.js +20 -4
  7. package/bin/pull.js +58 -0
  8. package/bin/push.js +52 -0
  9. package/bin/subscribe.js +45 -0
  10. package/lib/bind/bindingUtil.js +1 -2
  11. package/lib/cds.js +2 -3
  12. package/lib/client/activate.js +17 -16
  13. package/lib/client/auth_manager.js +10 -5
  14. package/lib/client/base_command.js +4 -6
  15. package/lib/client/extend.js +3 -2
  16. package/lib/client/helper/cf_helper.js +1 -0
  17. package/lib/client/helper/errors.js +11 -0
  18. package/lib/client/helper/logging.js +3 -10
  19. package/lib/client/helper/url_helper.js +7 -3
  20. package/lib/client/index.js +1 -1
  21. package/lib/client/params.js +9 -6
  22. package/lib/client/pull.js +48 -0
  23. package/lib/client/push.js +45 -0
  24. package/lib/client/settings_manager.js +81 -27
  25. package/lib/compile/openapi/csdl2openapi.js +135 -163
  26. package/lib/compile/openapi/index.js +0 -1
  27. package/lib/import/common.js +9 -1
  28. package/lib/import/odata/metadataconverter/MetadataConverter.js +17 -4
  29. package/lib/import/odata/v2parser.js +50 -26
  30. package/lib/import/odata/v4parser.js +110 -29
  31. package/lib/import/openapi/importOpenAPI.js +3 -3
  32. package/lib/init/constants.js +9 -3
  33. package/lib/init/template/_merging/registry-mta.js +284 -0
  34. package/lib/init/template/approuter/files/xs-app.json.hbs +7 -7
  35. package/lib/init/template/approuter/index.js +22 -32
  36. package/lib/init/template/auditlog/index.js +7 -9
  37. package/lib/init/template/data/index.js +2 -4
  38. package/lib/init/template/extensibility/files/cds.package.json +7 -0
  39. package/lib/init/template/extensibility/files/cds.package.json.hbs +9 -0
  40. package/lib/init/template/extensibility/files/xs-security.json.hbs +26 -0
  41. package/lib/init/template/extensibility/index.js +48 -0
  42. package/lib/init/template/hana/files/java/cdsrc.json.hbs +1 -1
  43. package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +2 -2
  44. package/lib/init/template/hana/files/mta.yaml.hbs +10 -0
  45. package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +1 -1
  46. package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +2 -2
  47. package/lib/init/template/hana/index.js +74 -61
  48. package/lib/init/template/kibana-logging/index.js +31 -37
  49. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +14 -14
  50. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  51. package/lib/init/template/mta/index.js +13 -7
  52. package/lib/init/template/mtx/index.js +2 -142
  53. package/lib/init/template/multitenancy/files/cds.package.json +7 -0
  54. package/lib/init/template/multitenancy/files/cds.package.json.hbs +9 -0
  55. package/lib/init/template/{mtx → multitenancy}/files/dependencies.package.json +1 -1
  56. package/lib/init/template/multitenancy/files/java/.cdsrc.json +19 -0
  57. package/lib/init/template/multitenancy/files/java/package.json +31 -0
  58. package/lib/init/template/{mtx → multitenancy}/files/mta.yaml.hbs +13 -6
  59. package/lib/init/template/multitenancy/files/xs-security.json.hbs +18 -0
  60. package/lib/init/template/multitenancy/index.js +109 -0
  61. package/lib/init/template/nodejs/files/package.json.hbs +4 -1
  62. package/lib/init/template/templateBase.js +2 -1
  63. package/lib/init/template/toggles/files/cds.package.json +7 -0
  64. package/lib/init/template/toggles/files/cds.package.json.hbs +9 -0
  65. package/lib/init/template/toggles/index.js +24 -0
  66. package/lib/init/template/xsuaa/files/mta.yaml.hbs +10 -0
  67. package/lib/init/template/xsuaa/index.js +44 -33
  68. package/lib/init/util/projectReader.js +12 -7
  69. package/lib/init/util/templateUtil.js +113 -111
  70. package/lib/k8s/ChartAdder.js +13 -3
  71. package/lib/k8s/ChartBuilder.js +6 -0
  72. package/lib/k8s/buildModel.js +1 -3
  73. package/lib/k8s/connectivity/index.js +5 -5
  74. package/lib/k8s/deployment/index.js +2 -4
  75. package/lib/k8s/deployment/subchart/Chart.yaml +1 -1
  76. package/lib/k8s/deployment/subchart/templates/_helpers.tpl +22 -11
  77. package/lib/k8s/deployment/subchart/templates/deployment.yaml +12 -5
  78. package/lib/k8s/deployment/subchart/templates/network-policy.yaml +3 -1
  79. package/lib/k8s/deployment/subchart/templates/pod-disruption-budget.yaml +1 -1
  80. package/lib/k8s/deployment/subchart/values.md +812 -0
  81. package/lib/k8s/deployment/subchart/values.schema.json +125 -30
  82. package/lib/k8s/deployment/subchart/values.yaml +7 -3
  83. package/lib/k8s/hana-deployer/index.js +10 -0
  84. package/lib/k8s/hana-deployer/templates/hana-deployer-job.yaml +8 -0
  85. package/lib/k8s/html5-apps-deployer/index.js +10 -0
  86. package/lib/k8s/html5-apps-deployer/templates/html5-apps-deployer-job.yaml +8 -0
  87. package/lib/k8s/index.js +2 -2
  88. package/lib/k8s/resources/helm/chart/schemas/values.root.schema.json +11 -0
  89. package/lib/k8s/resources/helm/chart/schemas/values.schema.json +479 -0
  90. package/lib/k8s/resources/helm/chart/templates/_deployment_helpers.tpl +1 -159
  91. package/lib/k8s/resources/helm/chart/templates/_helpers.tpl +0 -33
  92. package/lib/k8s/resources/helm/chart/templates/_sapcp_helpers.tpl +1 -1
  93. package/lib/lint/Linter.js +155 -158
  94. package/lib/lint/io.js +12 -5
  95. package/npm-shrinkwrap.json +214 -74
  96. package/package.json +5 -4
  97. package/lib/init/template/_merging/existences.js +0 -297
  98. package/lib/init/template/mtx/files/cds.package.json +0 -12
  99. package/lib/init/template/mtx/files/cds.package.json.hbs +0 -14
  100. package/lib/init/template/mtx/files/java/.cdsrc.json +0 -17
  101. package/lib/init/template/mtx/files/java/package.json +0 -43
  102. package/lib/init/template/mtx/files/java/server.js +0 -30
  103. package/lib/init/template/mtx/files/xs-security.json.hbs +0 -48
  104. package/lib/lint/.eslintrc.js +0 -3
@@ -45,14 +45,6 @@ app.kubernetes.io/instance: {{ .Release.Name }}
45
45
  {{/*
46
46
  Image
47
47
  */}}
48
- {{- define "cap.image.srv" -}}
49
- {{- if .Values.srv.image.tag -}}
50
- {{ .Values.srv.image.repository }}:{{ .Values.srv.image.tag }}
51
- {{- else -}}
52
- {{ .Values.srv.image.repository }}
53
- {{- end -}}
54
- {{- end -}}
55
-
56
48
  {{- define "cap.image" -}}
57
49
  {{- if .image.tag -}}
58
50
  {{ .image.repository }}:{{ .image.tag }}
@@ -64,14 +56,6 @@ Image
64
56
  {{/*
65
57
  Image Pull Policy
66
58
  */}}
67
- {{- define "cap.imagePullPolicy.srv" -}}
68
- {{- if and (.Values.srv.image.tag) (ne .Values.srv.image.tag "latest") -}}
69
- IfNotPresent
70
- {{- else -}}
71
- Always
72
- {{- end -}}
73
- {{- end -}}
74
-
75
59
  {{- define "cap.imagePullPolicy" -}}
76
60
  {{- if and (.image.tag) (ne .image.tag "latest") -}}
77
61
  IfNotPresent
@@ -90,23 +74,6 @@ imagePullSecrets:
90
74
  {{- end -}}
91
75
  {{- end -}}
92
76
 
93
-
94
- {{/*
95
- Binding
96
- */}}
97
- {{- define "cap.binding" -}}
98
- apiVersion: services.cloud.sap.com/v1alpha1
99
- kind: ServiceBinding
100
- metadata:
101
- name: {{ include "cap.bindingSecretName" $ | quote }}
102
- namespace: {{ $.Release.Namespace }}
103
- labels: {{- include "cap.labels" $ | nindent 4 }}
104
- spec:
105
- serviceInstanceName: {{ $.Release.Name }}-{{ $.binding.service }}
106
- externalName: {{ include "cap.bindingSecretName" $ | quote }}
107
- secretName: {{ include "cap.bindingSecretName" $ | quote }}
108
- {{- end -}}
109
-
110
77
  {{/*
111
78
  Service Instance NEW
112
79
  ternary dict ($.Files.Get $.service.config | fromJson)
@@ -6,7 +6,7 @@ SAPCP Service Bindings: volume mounts
6
6
  {{- $ := . -}}
7
7
  {{- range $key, $binding := .bindings }}
8
8
  - name: {{ $key | replace "_" "-" }}-secret
9
- mountPath: /etc/secrets/sapcp/{{ $key | replace "_" "-" }}/{{ $key }}
9
+ mountPath: /bindings/{{ $key }}
10
10
  readOnly: true
11
11
  {{- end }}
12
12
  {{- end }}
@@ -1,41 +1,37 @@
1
- const os = require("os");
2
- const fs = require("fs");
3
- const commandUtil = require("../init/util/commandUtil");
4
- const path = require("path");
5
- const glob = require("glob");
6
1
  const term = require("../util/term");
7
2
 
8
3
  const io = require("./io");
9
4
  const checks = require("./checks");
10
5
  const generators = require("./generators");
11
- const {
12
- getConfigPath,
13
- getFileExtensions,
14
- } = require("@sap/eslint-plugin-cds/lib/api");
15
6
 
16
- const IS_WIN = os.platform() === "win32";
17
- const ALLOWED_FILE_EXTENSIONS = getFileExtensions();
7
+ const cds = require("../../lib/cds");
8
+ const { path, exists, isdir, isfile, readdir } = cds.utils
9
+ const { exit } = require("process");
10
+ const LOG = cds.debug("lint");
11
+ const LOG_CONFIG = cds.debug("lint:config");
18
12
 
19
13
  class Linter {
20
14
  constructor() {
21
15
  this.eslintCmd = "";
22
16
  this.eslintCmdShort = "eslint";
23
- this.eslintCmdOpts = {};
24
- this.eslintCmdOptsIndex = 0;
25
17
  this.eslintCmdFileExpr = "";
26
18
  this.isFile = false;
27
19
  this.help = "";
28
20
  this.debug = "";
29
21
  this.flags = [];
30
22
  this.configPath = "";
31
- this.configGlobalPath = path.join(__dirname, ".eslintrc.js");
32
23
  this.configContents = {};
33
24
  this.projectPath = "";
34
25
  this.cdsdkPath = path.join(__dirname, "../..");
35
26
  this.globalPath = path.join(this.cdsdkPath, "../..");
36
27
  this.extendsPlugin = false;
28
+ this.fileExtensions = [];
37
29
  this.pluginPath = "";
30
+ this.pluginApi = {};
38
31
  this.lintType = "global";
32
+ this.ruleOpts = {};
33
+ this.customRulesOpts = [];
34
+ this.pluginRules = [];
39
35
  this.init = this.init.bind(this);
40
36
  this.lint = this.lint.bind(this);
41
37
  }
@@ -50,16 +46,11 @@ class Linter {
50
46
  if (this.eslintCmd) {
51
47
  help = generators.genEslintHelp(this.eslintCmd);
52
48
  flags = generators.genEslintFlags(help);
53
- [help, options, shortcuts, flags] = generators.genEslintShortcutsAndOpts(
54
- help,
55
- flags
56
- );
49
+ [help, options, shortcuts, flags] = generators.genEslintShortcutsAndOpts(help, flags);
57
50
  this.help = help;
58
51
  this.flags = flags;
59
52
  } else {
60
- console.log(
61
- `${term.error("Cannot call 'eslint -h', install and try again.")}\n`
62
- );
53
+ console.log(`${term.error("Cannot call 'eslint -h', install and try again.")}\n`);
63
54
  }
64
55
  return { help, options, flags, shortcuts };
65
56
  }
@@ -72,30 +63,24 @@ class Linter {
72
63
  */
73
64
  async lint(args, options) {
74
65
  this.eslintCmdOpts = this._sanitizeUserOpts(options);
75
- this.eslintCmdFileExpr = args.length ? args : ['.']
66
+ this.eslintCmdFileExpr = args.length ? args : ["."];
76
67
  if (this.eslintCmdOpts.help) {
77
68
  this._printHelp();
78
69
  } else {
79
70
  // Determine if case "local" or "global" and resolve plugin accordingly
80
71
  await this._getConfigFileAndSetProjectPath(args);
81
72
 
82
- if (this.lintType === "local") {
83
- await this._addRulePaths();
84
- }
73
+ // Add custom rules
74
+ await this._addRulePaths();
85
75
 
86
- if (this.lintType === "global") {
87
- this._addConfig();
88
- const overwriteRules = checks.hasEslintConfigContent(
89
- this.configContents,
90
- "rules"
91
- );
92
- if (overwriteRules) {
93
- await this._overwriteRuleSeverities();
94
- }
76
+ const overwriteRules = checks.hasEslintConfigContent(this.configContents, "rules");
77
+ if (overwriteRules) {
78
+ await this._overwriteRuleSeverities();
95
79
  }
96
80
 
97
81
  // Limit to CDS file extensions
98
82
  this._addExtensions();
83
+
99
84
  // Run ESLint with collected options
100
85
  try {
101
86
  await this._runEslint();
@@ -106,12 +91,7 @@ class Linter {
106
91
  }
107
92
 
108
93
  _printHelp() {
109
- console.log(
110
- this.help.replace(
111
- / \*([^*]+)\*/g,
112
- ` ${term.codes.bold}$1${term.codes.reset}`
113
- )
114
- );
94
+ console.log(this.help.replace(/ \*([^*]+)\*/g, ` ${term.codes.bold}$1${term.codes.reset}`));
115
95
  return;
116
96
  }
117
97
 
@@ -127,139 +107,146 @@ class Linter {
127
107
 
128
108
  async _addRulePaths() {
129
109
  const rulesPath = path.relative(".", ".eslint/rules");
130
- if (fs.existsSync(rulesPath) && fs.statSync(rulesPath).isDirectory()) {
131
- this.esllintCmdOpts = io.mergeWithUserOpts(
132
- this.eslintCmdOpts,
133
- "rulesdir",
134
- path.relative(".", rulesPath)
135
- );
110
+ if (await exists(rulesPath) && await isdir(rulesPath)) {
111
+ const opts = io.mergeWithUserOpts(this.eslintCmdOpts, "rulesdir", path.relative(".", rulesPath));
112
+ this.customRulesOpts = opts.rulesdir;
136
113
  await generators.genDocs(this.projectPath.replace(rulesPath, ""));
137
114
  }
138
115
  return;
139
116
  }
140
117
 
118
+ /**
119
+ * Searches for ESLint config file types (in order or precedence)
120
+ * and returns corresponding directory (usually project's root dir)
121
+ * https://eslint.org/docs/user-guide/configuring#configuration-file-formats
122
+ * @param {string} currentDir start here and search until root dir
123
+ * @returns {string} dir containing ESLint config file (empty if not exists)
124
+ */
125
+ async _getConfigPath(currentDir = ".") {
126
+ const configFiles = [
127
+ ".eslintrc.js",
128
+ ".eslintrc.cjs",
129
+ ".eslintrc.yaml",
130
+ ".eslintrc.yml",
131
+ ".eslintrc.json",
132
+ ".eslintrc",
133
+ "package.json",
134
+ ];
135
+ let configDir = path.resolve(currentDir);
136
+ while (configDir !== path.resolve(configDir, "..")) {
137
+ for (let i = 0; i < configFiles.length; i++) {
138
+ const configPath = path.join(configDir, configFiles[i]);
139
+ if (await exists(configPath) && await isfile(configPath)) {
140
+ return configPath;
141
+ }
142
+ }
143
+ configDir = path.join(configDir, "..");
144
+ }
145
+ return "";
146
+ }
147
+
141
148
  _addExtensions() {
142
149
  // Add CDS file extensions to lint
143
- const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => path.extname(ext));
144
- this.eslintCmdOpts = io.mergeWithUserOpts(
145
- this.eslintCmdOpts,
146
- "ext",
147
- extensions.join(',')
148
- );
149
- // Enable colored output
150
- this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
150
+ this.fileExtensions = this.pluginApi.getFileExtensions().map((ext) => path.extname(ext));
151
+ // Only lint file extensions prescribed by plugin
152
+ this.ignorePatterns = [];
153
+ this.fileExtensions.forEach((ext) => {
154
+ this.ignorePatterns.push(`!${ext}`);
155
+ });
151
156
  return;
152
157
  }
153
158
 
154
- async _runEslint(dryRun = false) {
155
- const eslintCmdOpts = [];
156
- // Collect cmd line options
159
+ async _runEslint() {
157
160
  try {
158
- for (let key in this.eslintCmdOpts) {
159
- let value = this.eslintCmdOpts[key];
160
- if (this.flags.includes(`--${key}`)) {
161
- eslintCmdOpts.push(`--${key}`);
162
- } else {
163
- if (value) {
164
- eslintCmdOpts.push(`--${key}`);
165
- // Always quote args which are not paths
166
- if (!fs.existsSync(value)) {
167
- eslintCmdOpts.push(`"${value}"`);
168
- // Paths are quoted according on os
169
- } else {
170
- if (IS_WIN) {
171
- eslintCmdOpts.push(`"${value}"`);
172
- } else {
173
- eslintCmdOpts.push(value);
174
- }
175
- }
176
- }
177
- }
178
- }
179
- // Only lint file extensions prescribed by plugin
180
- eslintCmdOpts.push("--ignore-pattern");
181
- let ignorePattern = "*.*";
182
- if (IS_WIN) {
183
- ignorePattern = `"${ignorePattern}"`;
184
- } else {
185
- ignorePattern = `'${ignorePattern}'`;
161
+ const currentDir = process.cwd();
162
+
163
+ const { ESLint } = require("eslint");
164
+
165
+ let eslintOpts = {
166
+ cwd: currentDir,
167
+ extensions: this.fileExtensions,
168
+ overrideConfig: {
169
+ ...this.configContents,
170
+ },
171
+ useEslintrc: false,
172
+ };
173
+
174
+ if (this.lintType === "global") {
175
+ eslintOpts = {
176
+ cwd: process.cwd(),
177
+ extensions: this.fileExtensions,
178
+ overrideConfig: {
179
+ plugins: ["@sap/eslint-plugin-cds"],
180
+ extends: "plugin:@sap/cds/recommended"
181
+ },
182
+ useEslintrc: false,
183
+ resolvePluginsRelativeTo: this.cdsdkPath
184
+ };
186
185
  }
187
- eslintCmdOpts.push(ignorePattern);
188
- ALLOWED_FILE_EXTENSIONS.forEach((ext) => {
189
- eslintCmdOpts.push("--ignore-pattern");
190
- ignorePattern = `!${ext}`;
191
- if (IS_WIN) {
192
- ignorePattern = `"${ignorePattern}"`;
193
- } else {
194
- ignorePattern = `'${ignorePattern}'`;
195
- }
196
- eslintCmdOpts.push(ignorePattern);
197
- });
198
- let input = "";
199
- if (IS_WIN) {
200
- // Braucht es diese unterscheidung wirklich? Unterstützt Windows nicht auch single quotes?
201
- input = `"${this.eslintCmdFileExpr.join('" "')}"`;
202
- } else {
203
- input = `'${this.eslintCmdFileExpr.join("' '")}'`;
186
+
187
+ if (this.customRulesOpts && this.customRulesOpts.length > 0) {
188
+ eslintOpts.rulePaths = [this.customRulesOpts]
204
189
  }
205
- // Run ESLint with given cmd line options
206
- // - Show 'eslint' instead of actual eslint cmd ('node .../.eslint.js')
207
- // - Remove debug flag for printed cmd line
208
- if (this.eslintCmdOpts.debug) {
209
- eslintCmdOpts.splice(eslintCmdOpts.indexOf('--debug'), 1);
210
- console.log(
211
- `Linting:\n ${term.info(`eslint ${eslintCmdOpts.concat(input).join(' ')}`)}\n`
212
- );
213
- eslintCmdOpts.push('--debug');
190
+
191
+ LOG_CONFIG && LOG_CONFIG(eslintOpts);
192
+
193
+ let lintString = `eslint`;
194
+ if (this.fileExtensions) { lintString += ` --ext "${this.fileExtensions.join(",")}"`};
195
+ for (const ruleOpt of Object.entries(this.ruleOpts)) {
196
+ lintString += ` --rule ${ruleOpt[0]}:${ruleOpt[1]}`;
214
197
  }
215
- if (!dryRun) {
216
- return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts.concat(input), {
217
- cwd: process.cwd(),
218
- shell: true,
219
- stdio: process.env.NODE_ENV === 'test' ? 'pipe' : 'inherit',
220
- });
221
- } else {
222
- return Promise.resolve("");
198
+ if (this.customRulesOpts && this.customRulesOpts.length > 0) {
199
+ lintString += ` --rulesdir "${this.customRulesOpts}"`
200
+ };
201
+
202
+ LOG && LOG(lintString);
203
+
204
+ if (!process.env.isTest) {
205
+ const eslint = new ESLint(eslintOpts);
206
+ const formatter = await eslint.loadFormatter("stylish");
207
+
208
+ let results = (await eslint.lintText("")).map((result) => {
209
+ result.filePath = path.resolve(currentDir);
210
+ return result;
211
+ }).filter(result => result.messages.length > 0);
212
+
213
+ const files = await readdir(currentDir);
214
+ const hasFiles = files.some(file => isfile(file));
215
+ if (hasFiles) {
216
+ const resultsModel = await eslint.lintFiles(this.eslintCmdFileExpr);
217
+ results = results.concat(resultsModel);
218
+ }
219
+
220
+ if (results && results.length > 0) {
221
+ console.log(formatter.format(results));
222
+ }
223
223
  }
224
224
  } catch (err) {
225
- return Promise.resolve(err);
225
+ console.log(err);
226
+ exit(1)
226
227
  }
227
228
  }
228
229
 
229
- _addConfig() {
230
- this.esllintCmdOpts = io.mergeWithUserOpts(
231
- this.eslintCmdOpts,
232
- "config",
233
- path.relative(".", this.configGlobalPath)
234
- );
235
- return;
236
- }
237
-
238
230
  async _getConfigFileAndSetProjectPath(args) {
239
231
  let input;
240
- // Only resolve the first input argument
241
- //
232
+ // Get config path
242
233
  if (args.length > 0) {
243
- let stats;
244
- try {
245
- stats = fs.statSync(args[0]);
246
- } catch (err) {
247
- // Do nothing
248
- }
249
- if (
250
- args[0] === "." ||
251
- (stats && (stats.isFile() || stats.isDirectory()))
252
- ) {
234
+ const firstArg = args[0];
235
+ if (firstArg === "." || (isfile(firstArg) || isdir(firstArg))) {
253
236
  this.isFile = true;
254
237
  }
255
- input = glob.sync(args[0])[0];
238
+ input = args.join(" ");
239
+ if (!input) {
240
+ input = ".";
241
+ }
256
242
  }
257
- this.configPath = getConfigPath(input);
243
+ this.configPath = await this._getConfigPath(process.cwd());
258
244
  if (!this.configPath) {
259
- this.configPath = this.configGlobalPath;
260
245
  this.lintType === "global";
246
+ this.configContents = await io.sanitizeEslintConfig({}, false, LOG);
261
247
  } else {
262
- this.configContents = await io.readEslintConfig(this.configPath);
248
+ const configContents = await io.readEslintConfig(this.configPath);
249
+ this.configContents = await io.sanitizeEslintConfig(configContents, false, LOG);
263
250
  if (this.configContents) {
264
251
  if ("extends" in this.configContents) {
265
252
  this.extendsPlugin = checks.hasEslintConfigContent(
@@ -268,9 +255,14 @@ class Linter {
268
255
  );
269
256
  if (this.extendsPlugin) {
270
257
  this.lintType = "local";
271
- this.pluginPath = require.resolve("@sap/eslint-plugin-cds", {
272
- paths: [path.dirname(this.configPath)],
273
- });
258
+ try {
259
+ this.pluginPath = require.resolve("@sap/eslint-plugin-cds", {
260
+ paths: [path.dirname(this.configPath)],
261
+ });
262
+ } catch (err) {
263
+ // Do nothing
264
+ }
265
+ this.pluginApi = require(this.pluginPath.replace("index.js", "api"));
274
266
  }
275
267
  }
276
268
  }
@@ -279,6 +271,7 @@ class Linter {
279
271
  this.pluginPath = require.resolve("@sap/eslint-plugin-cds", {
280
272
  paths: [this.cdsdkPath],
281
273
  });
274
+ this.pluginApi = require(this.pluginPath.replace("index.js", "api"));
282
275
  }
283
276
  // Project path is directory of ESLint config file
284
277
  this.projectPath = path.dirname(this.configPath);
@@ -286,21 +279,25 @@ class Linter {
286
279
  }
287
280
 
288
281
  async _overwriteRuleSeverities() {
289
- let configContents = (await io.readEslintConfig(this.configPath)) || {};
282
+ let configContents = {};
283
+ if (this.configPath) {
284
+ configContents = await io.readEslintConfig(this.configPath);
285
+ } else {
286
+ configContents = await io.readEslintConfig(await this._getConfigPath(this.cdsdkPath));
287
+ }
290
288
  let rules = configContents.rules;
291
289
  // Allow recommended plugin rules in cds-dk to be overwritten
292
290
  // by user by adding rule to cmd line (because of precedence)
293
- const pluginRules = require(this.pluginPath).rules;
291
+ const pluginRules = require(this.pluginPath).configs.recommended.rules;
294
292
  if (rules && pluginRules) {
295
- Object.keys(rules).forEach((rule) => {
296
- if (Object.keys(pluginRules).includes(rule.replace("@sap/cds/", ""))) {
297
- this.esllintCmdOpts = io.mergeWithUserOpts(
298
- this.eslintCmdOpts,
299
- "rule",
300
- `${rule}:${rules[rule]}`
301
- );
293
+ for (const rule of Object.keys(rules)) {
294
+ if (typeof rules[rule] !== "undefined" && rules[rule] != pluginRules[rule] ||
295
+ isfile(path.relative(".", ".eslint", "rules", rule))) {
296
+ pluginRules[rule] = rules[rule];
297
+ this.ruleOpts[rule] = rules[rule];
298
+ this.pluginRules = pluginRules;
302
299
  }
303
- });
300
+ }
304
301
  }
305
302
  return;
306
303
  }
package/lib/lint/io.js CHANGED
@@ -58,10 +58,15 @@ module.exports = {
58
58
  * @param {*} configPath ESLint config file
59
59
  * @returns {void}
60
60
  */
61
- async sanitizeEslintConfig(configPath, customRuleExample = false, logger = console) {
61
+ async sanitizeEslintConfig(configIn, customRuleExample = false, logger = console) {
62
62
  let configContents = {};
63
- if (await fsUtil.pathExists(configPath)) {
64
- configContents = (await this.readEslintConfig(configPath)) || {};
63
+ const isFilePath = typeof configIn === "string";
64
+ if (isFilePath) {
65
+ if (await fsUtil.pathExists(configIn)) {
66
+ configContents = (await this.readEslintConfig(configIn)) || {};
67
+ }
68
+ } else {
69
+ configContents = { ...configIn };
65
70
  }
66
71
  const configType = "recommended";
67
72
  const extendsValue = `plugin:@sap/cds/${configType}`;
@@ -90,8 +95,10 @@ module.exports = {
90
95
  configContents["rules"] = { [ruleName]: ruleValue };
91
96
  }
92
97
  }
93
- await this.writeEslintConfig(configPath, configContents, logger);
94
- return;
98
+ if (isFilePath) {
99
+ await this.writeEslintConfig(configIn, configContents, logger);
100
+ }
101
+ return configContents;
95
102
  },
96
103
 
97
104
  /**