@sap/cds-dk 4.5.2 → 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 +55 -0
- package/bin/bind.js +124 -8
- package/bin/cds-ts.js +1 -1
- package/bin/cds.js +1 -0
- package/bin/compile/index.js +2 -1
- package/bin/env.js +50 -9
- package/bin/help.js +1 -0
- package/bin/import.js +38 -18
- package/bin/repl.js +6 -2
- package/bin/watch.js +58 -13
- package/lib/bind/bindingResolver.js +138 -0
- package/lib/bind/cfKeyProvider.js +353 -0
- package/lib/bind/userCdsrcJsonStorageProvider.js +144 -0
- package/lib/client/auth_manager.js +4 -4
- package/lib/client/settings_manager.js +6 -5
- package/lib/import/common.js +10 -1
- package/lib/import/importapi.js +4 -3
- package/lib/import/index.js +34 -5
- package/lib/import/message.js +2 -1
- package/lib/import/utils/MetadataConverter.js +25 -4
- package/lib/import/utils/MetadataConverterFactory.js +1 -2
- package/lib/import/utils/MultiMap.js +26 -0
- package/lib/import/v2parser.js +131 -12
- package/lib/import/v4parser.js +214 -168
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +2 -0
- package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +36 -52
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +15 -0
- package/lib/init/template/lint/index.js +19 -17
- package/lib/init/template/mta/files/mta.yaml.hbs +0 -7
- package/lib/init/template/mtx/files/xs-security.json.hbs +3 -1
- package/lib/init/template/mtx/package/dependencies.package.json +1 -1
- package/lib/init/template/nodejs/files/.gitignore.hbs +1 -0
- package/lib/init/util/commandUtil.js +5 -0
- package/lib/lint/Linter.js +17 -20
- package/lib/lint/generators.js +5 -4
- package/lib/lint/io.js +62 -36
- package/lib/util/term.js +2 -0
- package/lib/watch/node-watch.js +38 -19
- package/npm-shrinkwrap.json +1485 -1959
- package/package.json +3 -3
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/test.js +0 -10
|
@@ -1,56 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
module.exports = cdsLint.createRule(
|
|
4
|
-
// Rule meta data
|
|
5
|
-
{
|
|
1
|
+
module.exports = require("@sap/eslint-plugin-cds/lib/api").createRule({
|
|
2
|
+
meta: {
|
|
6
3
|
docs: {
|
|
7
|
-
description: `Demonstrates how to implement a model validation check.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
description: `Demonstrates how to implement a model validation check.
|
|
5
|
+
|
|
6
|
+
__________________-_______
|
|
7
|
+
< Entity 'Moo' not allowed! >
|
|
8
|
+
--------------------------
|
|
9
|
+
\ ^__^
|
|
10
|
+
\ (oo)\_______
|
|
11
|
+
(__)\ )\/\
|
|
12
|
+
||----w |
|
|
13
|
+
|| ||`,
|
|
14
|
+
version: "1.0.0",
|
|
18
15
|
},
|
|
19
16
|
fixable: "code",
|
|
20
|
-
type: "problem",
|
|
21
|
-
version: "1.0.0",
|
|
22
17
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const fix = (fixer) => {
|
|
47
|
-
const rangeEnd = sourcecode.getIndexFromLoc({line: loc.end.line, column: loc.end.column});
|
|
48
|
-
return fixer.insertTextAfterRange([0, rangeEnd], "n");
|
|
49
|
-
};
|
|
50
|
-
report.push({ message: "Entity 'Moo' not allowed!", loc, fix, file: d.$location.file });
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
return report;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
);
|
|
18
|
+
create: function (context) {
|
|
19
|
+
const m = context.cds.model;
|
|
20
|
+
m.forall("entity", (d) => {
|
|
21
|
+
const entityName = d.name.split(".").pop();
|
|
22
|
+
if (entityName === "Moo") {
|
|
23
|
+
const loc = context.cds.getLocation(entityName, d);
|
|
24
|
+
const fix = (fixer) => {
|
|
25
|
+
const rangeEnd = context.sourcecode.getIndexFromLoc({
|
|
26
|
+
line: loc.end.line,
|
|
27
|
+
column: loc.end.column,
|
|
28
|
+
});
|
|
29
|
+
return fixer.insertTextAfterRange([0, rangeEnd], "n");
|
|
30
|
+
};
|
|
31
|
+
context.report({
|
|
32
|
+
message: "Entity 'Moo' not allowed!",
|
|
33
|
+
loc,
|
|
34
|
+
fix,
|
|
35
|
+
file: d.$location.file,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { runRuleTester } = require("@sap/eslint-plugin-cds/lib/api");
|
|
2
|
+
|
|
3
|
+
runRuleTester({
|
|
4
|
+
root: __dirname,
|
|
5
|
+
filename: "schema.cds",
|
|
6
|
+
errors: [
|
|
7
|
+
{
|
|
8
|
+
message: "Entity 'Moo' not allowed!",
|
|
9
|
+
line: 2,
|
|
10
|
+
column: 8,
|
|
11
|
+
endLine: 2,
|
|
12
|
+
endColumn: 11,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
});
|
|
@@ -24,6 +24,7 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
24
24
|
this.lintType = "local";
|
|
25
25
|
this.customRuleExample = false;
|
|
26
26
|
this.missingNpmDependencies = { names: [], msgs: [] };
|
|
27
|
+
this.isTest = false;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
async checkEnabled() {
|
|
@@ -41,17 +42,16 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
async run() {
|
|
44
|
-
const cdsdkPath = path.join(__dirname, "../../../..");
|
|
45
|
-
const globalPath = path.join(cdsdkPath, "../..");
|
|
46
|
-
|
|
47
45
|
// Require ESLint v>=7.0.0
|
|
48
|
-
this.
|
|
46
|
+
if (!this.isTest) {
|
|
47
|
+
this._checkEslint();
|
|
48
|
+
}
|
|
49
49
|
|
|
50
50
|
// To enable custom lint rules ('lint' or 'lint:dev')
|
|
51
51
|
if (this.lintType === "local") {
|
|
52
52
|
// Require local ESLint plugin installation and corresponding config
|
|
53
53
|
this._checkEslintPlugin();
|
|
54
|
-
this._addEslintPluginConfig();
|
|
54
|
+
await this._addEslintPluginConfig();
|
|
55
55
|
// Include custom lint sample rule and test ('lint:dev')
|
|
56
56
|
if (this.customRuleExample) {
|
|
57
57
|
// Generate custom lint rules dirs
|
|
@@ -66,15 +66,16 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
66
66
|
// Generate custom lint rules docs
|
|
67
67
|
await generators.genDocs(this.projectPath);
|
|
68
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
|
+
);
|
|
69
77
|
}
|
|
70
78
|
|
|
71
|
-
// Generate VS Code extension settings
|
|
72
|
-
await io.sanitizeVscodeSettings(
|
|
73
|
-
this.projectPath,
|
|
74
|
-
path.join(this.projectPath, ".vscode/settings.json"),
|
|
75
|
-
this.lintType,
|
|
76
|
-
this.customRuleExample
|
|
77
|
-
);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
async finalize() {
|
|
@@ -101,15 +102,15 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
101
102
|
this.logger.log("\n");
|
|
102
103
|
}
|
|
103
104
|
});
|
|
104
|
-
|
|
105
105
|
this._promptInstallDependencies(task);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
+
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
_checkEslint(
|
|
112
|
-
const eslintCmd = checks.resolveEslint(this.projectPath,
|
|
112
|
+
_checkEslint() {
|
|
113
|
+
const eslintCmd = checks.resolveEslint(this.projectPath, '');
|
|
113
114
|
if (!eslintCmd) {
|
|
114
115
|
this.missingNpmDependencies["names"].push("eslint");
|
|
115
116
|
this.missingNpmDependencies["msgs"].push("ESLint v>=7.0.0");
|
|
@@ -144,9 +145,10 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
144
145
|
|
|
145
146
|
async _addEslintPluginConfig() {
|
|
146
147
|
let configPath = getConfigPath(this.projectPath, this.logger);
|
|
147
|
-
if (configPath) {
|
|
148
|
-
|
|
148
|
+
if (!configPath) {
|
|
149
|
+
configPath = path.join(this.projectPath, ".eslintrc");
|
|
149
150
|
}
|
|
151
|
+
await io.sanitizeEslintConfig(configPath, this.customRuleExample, this.logger);
|
|
150
152
|
return;
|
|
151
153
|
}
|
|
152
154
|
|
|
@@ -38,7 +38,6 @@ modules:
|
|
|
38
38
|
{{#cap.isJava}}
|
|
39
39
|
{{#cap.isMultitenant}}
|
|
40
40
|
properties:
|
|
41
|
-
SAP_JWT_TRUST_ACL: [{"clientid":"*","identityzone":"sap-provisioning"}] # Trust between server and SaaS Manager
|
|
42
41
|
SPRING_PROFILES_ACTIVE: cloud
|
|
43
42
|
{{/cap.isMultitenant}}
|
|
44
43
|
{{^cap.isMultitenant}}
|
|
@@ -50,12 +49,6 @@ modules:
|
|
|
50
49
|
commands: [ mvn clean package ]
|
|
51
50
|
build-result: "target/*-exec.[wj]ar"
|
|
52
51
|
{{/cap.isJava}}
|
|
53
|
-
{{#cap.isNodejs}}
|
|
54
|
-
{{#cap.isMultitenant}}
|
|
55
|
-
properties:
|
|
56
|
-
SAP_JWT_TRUST_ACL: [{"clientid":"*","identityzone":"sap-provisioning"}] # Trust between server and SaaS Manager
|
|
57
|
-
{{/cap.isMultitenant}}
|
|
58
|
-
{{/cap.isNodejs}}
|
|
59
52
|
{{#cap.hasRequires}}
|
|
60
53
|
requires:
|
|
61
54
|
{{#cap.isJava}}
|
|
@@ -50,12 +50,17 @@ class CommandUtil {
|
|
|
50
50
|
resolve(stdLogBuffer.getResult());
|
|
51
51
|
} else {
|
|
52
52
|
const errorLog = errLogBuffer.getResult();
|
|
53
|
+
|
|
53
54
|
const error = new Error(`${cmd} ${args.join(' ')} failed with code ${code}, ${errorLog}`)
|
|
54
55
|
// add code ENOENT on Win if command not found
|
|
55
56
|
if (IS_WIN && errorLog.includes(cmd) && /not recognized/i.exec(errorLog)) {
|
|
56
57
|
error.code = 'ENOENT';
|
|
57
58
|
error.path = cmd;
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
error.errLog = errorLog;
|
|
62
|
+
error.stdLog = stdLogBuffer.getResult();
|
|
63
|
+
|
|
59
64
|
reject(error);
|
|
60
65
|
}
|
|
61
66
|
});
|
package/lib/lint/Linter.js
CHANGED
|
@@ -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 = "";
|
|
@@ -21,6 +23,7 @@ class Linter {
|
|
|
21
23
|
this.eslintCmdOpts = {};
|
|
22
24
|
this.eslintCmdOptsIndex = 0;
|
|
23
25
|
this.eslintCmdFileExpr = "";
|
|
26
|
+
this.formatter = false;
|
|
24
27
|
this.isFile = false;
|
|
25
28
|
this.help = "";
|
|
26
29
|
this.debug = "";
|
|
@@ -75,7 +78,7 @@ class Linter {
|
|
|
75
78
|
this._printHelp();
|
|
76
79
|
} else {
|
|
77
80
|
// Determine if case "local" or "global" and resolve plugin accordingly
|
|
78
|
-
this._getConfigFileAndSetProjectPath(args);
|
|
81
|
+
await this._getConfigFileAndSetProjectPath(args);
|
|
79
82
|
|
|
80
83
|
if (this.lintType === "local") {
|
|
81
84
|
await this._addRulePaths();
|
|
@@ -88,7 +91,7 @@ class Linter {
|
|
|
88
91
|
"rules"
|
|
89
92
|
);
|
|
90
93
|
if (overwriteRules) {
|
|
91
|
-
this._overwriteRuleSeverities();
|
|
94
|
+
await this._overwriteRuleSeverities();
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
|
|
@@ -138,20 +141,11 @@ class Linter {
|
|
|
138
141
|
|
|
139
142
|
_addExtensions() {
|
|
140
143
|
// Add CDS file extensions to lint
|
|
144
|
+
const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => ext.replace('*.', '.'));
|
|
141
145
|
this.eslintCmdOpts = io.mergeWithUserOpts(
|
|
142
146
|
this.eslintCmdOpts,
|
|
143
147
|
"ext",
|
|
144
|
-
|
|
145
|
-
);
|
|
146
|
-
// Add custom CDS formatter
|
|
147
|
-
const formatterPath = this.pluginPath.replace(
|
|
148
|
-
"index.js",
|
|
149
|
-
"../api/formatter.js"
|
|
150
|
-
);
|
|
151
|
-
this.eslintCmdOpts = io.mergeWithUserOpts(
|
|
152
|
-
this.eslintCmdOpts,
|
|
153
|
-
"format",
|
|
154
|
-
path.relative(".", formatterPath)
|
|
148
|
+
extensions.join(',')
|
|
155
149
|
);
|
|
156
150
|
// Enable colored output
|
|
157
151
|
if (process.stdout.isTTY) {
|
|
@@ -186,7 +180,6 @@ class Linter {
|
|
|
186
180
|
}
|
|
187
181
|
}
|
|
188
182
|
// Only lint file extensions prescribed by plugin
|
|
189
|
-
const fileExtensions = getFileExtensions();
|
|
190
183
|
eslintCmdOpts.push("--ignore-pattern");
|
|
191
184
|
let ignorePattern = "*.*";
|
|
192
185
|
if (IS_WIN) {
|
|
@@ -195,7 +188,7 @@ class Linter {
|
|
|
195
188
|
ignorePattern = `'${ignorePattern}'`;
|
|
196
189
|
}
|
|
197
190
|
eslintCmdOpts.push(ignorePattern);
|
|
198
|
-
|
|
191
|
+
ALLOWED_FILE_EXTENSIONS.forEach((ext) => {
|
|
199
192
|
eslintCmdOpts.push("--ignore-pattern");
|
|
200
193
|
ignorePattern = `!${ext}`;
|
|
201
194
|
if (IS_WIN) {
|
|
@@ -217,10 +210,14 @@ class Linter {
|
|
|
217
210
|
eslintCmdOpts.unshift(eslintCmdSplit[1]);
|
|
218
211
|
eslintCmdOpts.push(input);
|
|
219
212
|
// Run ESLint with given cmd line options
|
|
213
|
+
// - Show 'eslint' instead of 'node ...eslint.js' cmd
|
|
214
|
+
// - Remove debug flag for printed cmd
|
|
220
215
|
if (this.eslintCmdOpts.debug) {
|
|
216
|
+
eslintCmdOpts.splice(eslintCmdOpts.indexOf('--debug'), 1);
|
|
221
217
|
console.log(
|
|
222
|
-
`Linting:\n ${term.info(
|
|
218
|
+
`Linting:\n ${term.info(`eslint ${eslintCmdOpts.slice(1).join(' ')}`)}\n`
|
|
223
219
|
);
|
|
220
|
+
eslintCmdOpts.push('--debug');
|
|
224
221
|
}
|
|
225
222
|
if (!dryRun) {
|
|
226
223
|
return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts, {
|
|
@@ -245,7 +242,7 @@ class Linter {
|
|
|
245
242
|
return;
|
|
246
243
|
}
|
|
247
244
|
|
|
248
|
-
_getConfigFileAndSetProjectPath(args) {
|
|
245
|
+
async _getConfigFileAndSetProjectPath(args) {
|
|
249
246
|
let input;
|
|
250
247
|
// Only resolve the first input argument
|
|
251
248
|
//
|
|
@@ -269,7 +266,7 @@ class Linter {
|
|
|
269
266
|
this.configPath = this.configGlobalPath;
|
|
270
267
|
this.lintType === "global";
|
|
271
268
|
} else {
|
|
272
|
-
this.configContents = io.readEslintConfig(this.configPath);
|
|
269
|
+
this.configContents = await io.readEslintConfig(this.configPath);
|
|
273
270
|
if (this.configContents) {
|
|
274
271
|
if ("extends" in this.configContents) {
|
|
275
272
|
this.extendsPlugin = checks.hasEslintConfigContent(
|
|
@@ -295,8 +292,8 @@ class Linter {
|
|
|
295
292
|
return;
|
|
296
293
|
}
|
|
297
294
|
|
|
298
|
-
_overwriteRuleSeverities() {
|
|
299
|
-
let configContents = io.readEslintConfig(this.configPath) || {};
|
|
295
|
+
async _overwriteRuleSeverities() {
|
|
296
|
+
let configContents = (await io.readEslintConfig(this.configPath)) || {};
|
|
300
297
|
let rules = configContents.rules;
|
|
301
298
|
// Allow recommended plugin rules in cds-dk to be overwritten
|
|
302
299
|
// by user by adding rule to cmd line (because of precedence)
|
package/lib/lint/generators.js
CHANGED
|
@@ -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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const os = require("os");
|
|
2
|
-
const
|
|
2
|
+
const fsp = require("fs").promises;
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const yaml = require("@sap/cds-foss")("yaml");
|
|
5
|
+
const term = require("../util/term");
|
|
5
6
|
const FsUtil = require("../init/util/fsUtil");
|
|
6
7
|
const fsUtil = new FsUtil();
|
|
7
8
|
|
|
@@ -13,23 +14,28 @@ module.exports = {
|
|
|
13
14
|
* @param {*} configPath config file path to read from
|
|
14
15
|
* @returns config file contents
|
|
15
16
|
*/
|
|
16
|
-
readEslintConfig(configPath) {
|
|
17
|
+
async readEslintConfig(configPath) {
|
|
17
18
|
let config;
|
|
18
19
|
let configFile = path.basename(configPath);
|
|
20
|
+
let configString = await fsp.readFile(configPath, "utf8");
|
|
19
21
|
switch (configFile) {
|
|
20
22
|
case ".eslintrc.js":
|
|
21
23
|
case ".eslintrc.cjs":
|
|
22
|
-
|
|
24
|
+
try {
|
|
25
|
+
config = JSON.parse(configString.replace(/^module\.exports =/, ""));
|
|
26
|
+
} catch (err) {
|
|
27
|
+
config = {};
|
|
28
|
+
}
|
|
23
29
|
break;
|
|
24
30
|
case ".eslintrc.yaml":
|
|
25
31
|
case ".eslintrc.yml":
|
|
26
|
-
config = yaml.parse(
|
|
32
|
+
config = yaml.parse(await fsp.readFile(configPath, "utf8"));
|
|
27
33
|
break;
|
|
28
34
|
case ".eslintrc.json":
|
|
29
35
|
case ".eslintrc":
|
|
30
36
|
case "package.json":
|
|
31
37
|
try {
|
|
32
|
-
config = JSON.parse(
|
|
38
|
+
config = JSON.parse(await fsp.readFile(configPath, "utf8"));
|
|
33
39
|
if (configFile === "package.json" && "eslintConfig" in config) {
|
|
34
40
|
config = config["eslintConfig"];
|
|
35
41
|
}
|
|
@@ -52,8 +58,11 @@ module.exports = {
|
|
|
52
58
|
* @param {*} configPath ESLint config file
|
|
53
59
|
* @returns {void}
|
|
54
60
|
*/
|
|
55
|
-
async sanitizeEslintConfig(configPath, customRuleExample=false) {
|
|
56
|
-
let configContents =
|
|
61
|
+
async sanitizeEslintConfig(configPath, customRuleExample = false, logger = console) {
|
|
62
|
+
let configContents = {};
|
|
63
|
+
if (await fsUtil.pathExists(configPath)) {
|
|
64
|
+
configContents = (await this.readEslintConfig(configPath)) || {};
|
|
65
|
+
}
|
|
57
66
|
const configType = "recommended";
|
|
58
67
|
const extendsValue = `plugin:@sap/cds/${configType}`;
|
|
59
68
|
if ("extends" in configContents) {
|
|
@@ -62,7 +71,9 @@ module.exports = {
|
|
|
62
71
|
configContents["extends"].push(extendsValue);
|
|
63
72
|
}
|
|
64
73
|
} else {
|
|
65
|
-
configContents["extends"]
|
|
74
|
+
if (configContents["extends"] !== extendsValue) {
|
|
75
|
+
configContents["extends"] = [configContents["extends"], extendsValue];
|
|
76
|
+
}
|
|
66
77
|
}
|
|
67
78
|
} else {
|
|
68
79
|
configContents["extends"] = extendsValue;
|
|
@@ -79,7 +90,7 @@ module.exports = {
|
|
|
79
90
|
configContents["rules"] = { [ruleName]: ruleValue };
|
|
80
91
|
}
|
|
81
92
|
}
|
|
82
|
-
await this.writeEslintConfig(configContents,
|
|
93
|
+
await this.writeEslintConfig(configPath, configContents, logger);
|
|
83
94
|
return;
|
|
84
95
|
},
|
|
85
96
|
|
|
@@ -89,16 +100,37 @@ module.exports = {
|
|
|
89
100
|
* @param {*} configPath config file path to write to
|
|
90
101
|
* @returns {void}
|
|
91
102
|
*/
|
|
92
|
-
async writeEslintConfig(configContents,
|
|
103
|
+
async writeEslintConfig(configPath, configContents, logger=console) {
|
|
104
|
+
const configType = "recommended";
|
|
105
|
+
const extendsValue = `plugin:@sap/cds/${configType}`;
|
|
93
106
|
let contents = {};
|
|
94
107
|
let configFile = path.basename(configPath);
|
|
108
|
+
let configToAdd = {};
|
|
95
109
|
switch (configFile) {
|
|
96
110
|
case ".eslintrc.js":
|
|
97
111
|
case ".eslintrc.cjs":
|
|
98
|
-
|
|
99
|
-
configPath
|
|
100
|
-
|
|
101
|
-
|
|
112
|
+
try {
|
|
113
|
+
configContents = await this.readEslintConfig(configPath);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
configContents = {};
|
|
116
|
+
}
|
|
117
|
+
if (configContents && configContents["extends"]) {
|
|
118
|
+
if (
|
|
119
|
+
!configContents["extends"] === extendsValue ||
|
|
120
|
+
!configContents["extends"].includes(extendsValue)
|
|
121
|
+
) {
|
|
122
|
+
configToAdd["extends"] = extendsValue;
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
configToAdd["extends"] = extendsValue;
|
|
126
|
+
}
|
|
127
|
+
if (configToAdd["extends"]) {
|
|
128
|
+
logger.log(
|
|
129
|
+
`${term.warn(
|
|
130
|
+
`\n\nPlease add the following to your "${configFile}":\n\nmodule.exports = ${JSON.stringify(configToAdd, null, 2)}`
|
|
131
|
+
)}\n`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
102
134
|
break;
|
|
103
135
|
case ".eslintrc.yaml":
|
|
104
136
|
case ".eslintrc.yml":
|
|
@@ -108,25 +140,19 @@ module.exports = {
|
|
|
108
140
|
case ".eslintrc":
|
|
109
141
|
case "package.json":
|
|
110
142
|
if (configFile === "package.json") {
|
|
111
|
-
if (
|
|
112
|
-
contents = JSON.parse(
|
|
143
|
+
if (await fsUtil.pathExists(configPath)) {
|
|
144
|
+
contents = JSON.parse(await fsp.readFile(configPath, "utf8"));
|
|
113
145
|
} else {
|
|
114
146
|
contents = {};
|
|
115
147
|
}
|
|
116
148
|
if (!("eslintConfig" in configContents)) {
|
|
117
149
|
contents["eslintConfig"] = configContents;
|
|
118
150
|
} else {
|
|
119
|
-
contents["eslintConfig"] = [
|
|
120
|
-
...configContents,
|
|
121
|
-
...contents["eslintConfig"],
|
|
122
|
-
];
|
|
151
|
+
contents["eslintConfig"] = [...configContents, ...contents["eslintConfig"]];
|
|
123
152
|
}
|
|
124
153
|
configContents = contents;
|
|
125
154
|
}
|
|
126
|
-
await fsUtil.writeFile(
|
|
127
|
-
configPath,
|
|
128
|
-
`${JSON.stringify(configContents, null, 2)}`
|
|
129
|
-
);
|
|
155
|
+
await fsUtil.writeFile(configPath, `${JSON.stringify(configContents, null, 2)}`);
|
|
130
156
|
break;
|
|
131
157
|
default:
|
|
132
158
|
break;
|
|
@@ -141,8 +167,12 @@ module.exports = {
|
|
|
141
167
|
*/
|
|
142
168
|
async readVscodeSettings(settingsPath) {
|
|
143
169
|
let settings;
|
|
144
|
-
if (
|
|
145
|
-
|
|
170
|
+
if (fsUtil.pathExists(settingsPath)) {
|
|
171
|
+
try {
|
|
172
|
+
settings = await fsUtil.readJSONC(settingsPath);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
settings = {};
|
|
175
|
+
}
|
|
146
176
|
}
|
|
147
177
|
return settings;
|
|
148
178
|
},
|
|
@@ -186,10 +216,7 @@ module.exports = {
|
|
|
186
216
|
}
|
|
187
217
|
|
|
188
218
|
if (settings["eslint.validate"]) {
|
|
189
|
-
settings["eslint.validate"] = this.mergeArrays(
|
|
190
|
-
settings["eslint.validate"],
|
|
191
|
-
lintFileTypes
|
|
192
|
-
);
|
|
219
|
+
settings["eslint.validate"] = this.mergeArrays(settings["eslint.validate"], lintFileTypes);
|
|
193
220
|
} else {
|
|
194
221
|
settings["eslint.validate"] = lintFileTypes;
|
|
195
222
|
}
|
|
@@ -208,7 +235,7 @@ module.exports = {
|
|
|
208
235
|
}
|
|
209
236
|
}
|
|
210
237
|
|
|
211
|
-
await this.writeVscodeSettings(
|
|
238
|
+
await this.writeVscodeSettings(settingsPath, settings);
|
|
212
239
|
},
|
|
213
240
|
|
|
214
241
|
/**
|
|
@@ -217,7 +244,7 @@ module.exports = {
|
|
|
217
244
|
* @param {*} settingsPath settings file path to write to
|
|
218
245
|
* @returns {void}
|
|
219
246
|
*/
|
|
220
|
-
async writeVscodeSettings(
|
|
247
|
+
async writeVscodeSettings(settingsPath, settings) {
|
|
221
248
|
if (!settings) {
|
|
222
249
|
await fsUtil.mkdirp(path.dirname(settingsPath));
|
|
223
250
|
}
|
|
@@ -236,10 +263,9 @@ module.exports = {
|
|
|
236
263
|
if (propsToAdd) {
|
|
237
264
|
if (Object.keys(userOpts).includes(propKey)) {
|
|
238
265
|
if (!["config", "format"].includes(propKey)) {
|
|
239
|
-
propsToAdd = this.mergeArrays(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
).join(",");
|
|
266
|
+
propsToAdd = this.mergeArrays(userOpts[propKey].split(","), propsToAdd.split(",")).join(
|
|
267
|
+
","
|
|
268
|
+
);
|
|
243
269
|
}
|
|
244
270
|
}
|
|
245
271
|
userOpts[propKey] = propsToAdd;
|
package/lib/util/term.js
CHANGED
|
@@ -8,6 +8,7 @@ const t = module.exports.codes = {
|
|
|
8
8
|
link: '\x1b[4m', // underline
|
|
9
9
|
red: '\x1b[91m', // Bright Foreground Red
|
|
10
10
|
green: '\x1b[32m', // Foreground Green
|
|
11
|
+
blue: '\x1b[34m', // Foreground Blue
|
|
11
12
|
orange: '\x1b[38;2;255;140;0m' // darker orange, works with bright and dark background
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -24,6 +25,7 @@ module.exports.warn = o => as(t.orange, o)
|
|
|
24
25
|
module.exports.info = o => as(t.green, o)
|
|
25
26
|
module.exports.link = o => as(t.link, o)
|
|
26
27
|
module.exports.bold = o => as(t.bold, o)
|
|
28
|
+
module.exports.highlight = o => as(t.blue,as(t.bold, o))
|
|
27
29
|
|
|
28
30
|
const format = module.exports.format = (o, severity='Error', asInternalError=false, withStack=false) => {
|
|
29
31
|
switch (severity) {
|