@sap/cds-dk 8.9.4 → 9.0.4
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 +89 -2012
- package/LICENSE +15 -21
- package/bin/bind.js +1 -1
- package/bin/build.js +35 -37
- package/bin/cds.js +12 -29
- package/bin/compile/index.js +2 -2
- package/bin/debug.js +27 -7
- package/bin/deploy/index.js +6 -23
- package/bin/deploy/to-hana.js +4 -2
- package/bin/help.js +3 -1
- package/bin/init.js +1 -1
- package/bin/up.js +45 -12
- package/bin/watch.js +45 -63
- package/lib/bind/cf.js +2 -1
- package/lib/bind/k8s.js +2 -2
- package/lib/bind/plugin.js +1 -1
- package/lib/bind/shared.js +16 -25
- package/lib/build/buildTaskEngine.js +26 -10
- package/lib/build/buildTaskFactory.js +3 -2
- package/lib/build/buildTaskProvider.js +18 -7
- package/lib/build/buildTaskProviderFactory.js +35 -13
- package/lib/build/constants.js +4 -0
- package/lib/build/index.js +1 -1
- package/lib/build/plugin.js +89 -54
- package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +3 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/_helpers.tpl +4 -2
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/api-rule.yaml +4 -2
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/deployment.yaml +18 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/service-binding.yaml +0 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +34 -2
- package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +9 -2
- package/lib/build/plugins/helm/index.js +2 -1
- package/lib/build/plugins.js +24 -10
- package/lib/build/provider/edmxBuildPlugin.js +1 -11
- package/lib/build/provider/hana/index.js +12 -5
- package/lib/build/provider/hana/template/package.json +1 -1
- package/lib/build/provider/internalBuildPlugin.js +1 -1
- package/lib/build/provider/internalBuildTaskProvider.js +3 -24
- package/lib/build/provider/java/index.js +1 -1
- package/lib/build/provider/mtx-extension/index.js +3 -8
- package/lib/build/provider/nodejs/index.js +28 -6
- package/lib/build/util.js +186 -125
- package/lib/deploy/index.js +5 -0
- package/lib/deploy/to-hana/hana.js +27 -33
- package/lib/deploy/to-hana/hdiDeployUtil.js +2 -2
- package/lib/import/odata/v2parser.js +34 -3
- package/lib/import/openapi/importOpenAPI.js +4 -0
- package/lib/index.js +2 -11
- package/lib/init/constants.js +0 -1
- package/lib/init/merge.js +101 -77
- package/lib/init/mvn.js +3 -3
- package/lib/init/projectReader.js +1 -1
- package/lib/init/template/ams/files/mta.yaml.hbs +6 -1
- package/lib/init/template/ams/files/package.json.hbs +1 -1
- package/lib/init/template/approuter/files/mta.yaml.hbs +5 -0
- package/lib/init/template/cf-manifest/files/manifest.yml.hbs +1 -1
- package/lib/init/template/cloud-logging/files/package.json.hbs +3 -3
- package/lib/init/template/dynatrace/files/mta.yaml.hbs +1 -1
- package/lib/init/template/dynatrace/files/package.json.hbs +2 -2
- package/lib/init/template/dynatrace/index.js +2 -1
- package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +6 -0
- package/lib/init/template/enterprise-messaging/index.js +5 -1
- package/lib/init/template/extensibility/files/package.json.hbs +1 -1
- package/lib/init/template/hana/files/db/package.json +1 -1
- package/lib/init/template/hana/files/package.json.hbs +2 -4
- package/lib/init/template/helm/index.js +13 -22
- package/lib/init/template/helm-unified-runtime/index.js +2 -1
- package/lib/init/template/html5-repo/files/values.yaml.hbs +12 -1
- package/lib/init/template/html5-repo/index.js +10 -5
- package/lib/init/template/http/index.js +1 -1
- package/lib/init/template/ias/files/mta.yaml.hbs +1 -1
- package/lib/init/template/ias/files/sidecar.package.json.hbs +0 -7
- package/lib/init/template/ias/index.js +5 -4
- package/lib/init/template/lint/files/package.json +6 -0
- package/lib/init/template/lint/index.js +61 -204
- package/lib/init/template/mta/files/package.json +1 -1
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +2 -2
- package/lib/init/template/multitenancy/files/package.json.hbs +1 -1
- package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +7 -4
- package/lib/init/template/multitenancy/index.js +3 -0
- package/lib/init/template/nodejs/files/package.json.hbs +5 -2
- package/lib/init/template/redis/files/package.json.hbs +1 -1
- package/lib/init/template/sqlite/files/package.json +1 -1
- package/lib/init/template/toggles/files/package.json.hbs +1 -1
- package/lib/init/template/typescript/files/package.json +1 -3
- package/lib/init/template/workzone-standard/index.js +2 -0
- package/lib/init/template/xsuaa/index.js +2 -6
- package/lib/lint/Linter.js +203 -331
- package/lib/lint/generators.js +52 -46
- package/lib/lint/io.js +77 -289
- package/lib/util/fs.js +2 -1
- package/lib/util/git.js +1 -1
- package/lib/util/glob.js +77 -0
- package/lib/watch/livereload-server.js +3 -4
- package/lib/watch/node-watch.js +3 -4
- package/lib/watch/watched.js +1 -1
- package/npm-shrinkwrap.json +59 -1232
- package/package.json +6 -8
- package/readme.md +1 -1
- package/lib/lint/checks.js +0 -135
package/lib/lint/generators.js
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
const os = require(
|
|
2
|
-
const cp = require(
|
|
3
|
-
const term = require(
|
|
1
|
+
const os = require('node:os')
|
|
2
|
+
const cp = require('node:child_process')
|
|
3
|
+
const term = require('../util/term')
|
|
4
4
|
|
|
5
|
-
const IS_WIN = os.platform() ===
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const REGEX_SHORTCUT_MAPPINGS = /\s-[a-zA-Z]+, --[a-zA-Z-]+/gm;
|
|
5
|
+
const IS_WIN = os.platform() === 'win32'
|
|
6
|
+
const REGEX_FLAGS = /--[a-z,a-z-]+[,\s+]\s+/gm
|
|
7
|
+
const REGEX_OPTIONS = /--[a-z,a-z-]+\s[^\s]/gm
|
|
8
|
+
const REGEX_SHORTCUT_MAPPINGS = /\s-[a-zA-Z]+, --[a-zA-Z-]+/gm
|
|
10
9
|
|
|
11
10
|
module.exports = {
|
|
12
11
|
/**
|
|
13
12
|
* Generates `cds lint` help string to print when calling `cds lint [-h, --help]`
|
|
14
13
|
* by getting available options/shortcuts from installed version of ESLint
|
|
15
|
-
* @
|
|
14
|
+
* @param {string} eslintCmd - ESLint command to call
|
|
15
|
+
* @returns {string} `cds lint` help string
|
|
16
16
|
*/
|
|
17
17
|
genEslintHelp: function (eslintCmd) {
|
|
18
|
-
let eslintHelp
|
|
18
|
+
let eslintHelp
|
|
19
19
|
try {
|
|
20
20
|
eslintHelp = cp
|
|
21
21
|
.execSync(`${eslintCmd} -h`, {
|
|
22
22
|
cwd: process.cwd(),
|
|
23
23
|
shell: IS_WIN,
|
|
24
|
-
stdio:
|
|
24
|
+
stdio: 'pipe',
|
|
25
25
|
})
|
|
26
|
-
.toString()
|
|
27
|
-
} catch
|
|
26
|
+
.toString()
|
|
27
|
+
} catch {
|
|
28
28
|
console.log(
|
|
29
|
-
`${term.error(
|
|
30
|
-
)
|
|
29
|
+
`${term.error('Cannot call "eslint -h", install and try again.')}\n`
|
|
30
|
+
)
|
|
31
31
|
}
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const eslintOpts = eslintHelp.split('\n')
|
|
33
|
+
const cdslintCmd = eslintOpts[0].replace('eslint', '*cds lint*')
|
|
34
34
|
eslintOpts[0] = `
|
|
35
35
|
# SYNOPSIS
|
|
36
36
|
|
|
@@ -39,8 +39,8 @@ module.exports = {
|
|
|
39
39
|
Runs environment checks and/or checks the specified models
|
|
40
40
|
based on the ESLint framework
|
|
41
41
|
|
|
42
|
-
# OPTIONS
|
|
43
|
-
return `${eslintOpts.join(
|
|
42
|
+
# OPTIONS`
|
|
43
|
+
return `${eslintOpts.join('\n ')}\n`
|
|
44
44
|
},
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -49,38 +49,45 @@ module.exports = {
|
|
|
49
49
|
* Shortcut order must match order of [options, flags]
|
|
50
50
|
* Any options without an shortcut must act as filler (undefined)
|
|
51
51
|
* until the shortcuts for the flags start
|
|
52
|
-
* @param help help string and shortcuts array for `cds lint`
|
|
53
|
-
* @param flags help string and shortcuts array for `cds lint`
|
|
54
|
-
* @returns
|
|
52
|
+
* @param {string} help - help string and shortcuts array for `cds lint`
|
|
53
|
+
* @param {string[]} flags help string and shortcuts array for `cds lint`
|
|
54
|
+
* @returns {{
|
|
55
|
+
* help: string,
|
|
56
|
+
* options: string[],
|
|
57
|
+
* shortcuts: string[],
|
|
58
|
+
* flags: string[]
|
|
59
|
+
* }} `cds lint` allowed options
|
|
55
60
|
*/
|
|
56
61
|
genEslintShortcutsAndOpts: function (help, flags) {
|
|
57
62
|
const allOptions = help
|
|
58
63
|
.match(REGEX_OPTIONS)
|
|
59
|
-
.map((str) => str.split(' ')[0].trim().replace(
|
|
64
|
+
.map((str) => str.split(' ')[0].trim().replace(',', ''))
|
|
60
65
|
const shortcutMappings = help
|
|
61
66
|
.match(REGEX_SHORTCUT_MAPPINGS)
|
|
62
|
-
.map((str) => str.trim().split(/,\s?/))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
.map((str) => str.trim().split(/,\s?/))
|
|
68
|
+
const optionsWithShortcuts = []
|
|
69
|
+
/** @type {string[]} */
|
|
70
|
+
let shortcuts = []
|
|
71
|
+
const shortcutsForFlags = []
|
|
72
|
+
shortcutMappings.forEach(([short, long]) => {
|
|
73
|
+
if (!flags.includes(long)) {
|
|
74
|
+
optionsWithShortcuts.push(long)
|
|
75
|
+
shortcuts.push(short)
|
|
70
76
|
} else {
|
|
71
|
-
const index = flags.indexOf(
|
|
72
|
-
flags.splice(index, 1)
|
|
73
|
-
flags.unshift(
|
|
74
|
-
shortcutsForFlags.unshift(
|
|
77
|
+
const index = flags.indexOf(long)
|
|
78
|
+
flags.splice(index, 1)
|
|
79
|
+
flags.unshift(long)
|
|
80
|
+
shortcutsForFlags.unshift(short)
|
|
75
81
|
}
|
|
76
|
-
})
|
|
77
|
-
const optionsWithoutShortcuts = allOptions.filter((o) => !optionsWithShortcuts.includes(o))
|
|
82
|
+
})
|
|
83
|
+
const optionsWithoutShortcuts = allOptions.filter((o) => !optionsWithShortcuts.includes(o))
|
|
78
84
|
optionsWithoutShortcuts.forEach(() => {
|
|
79
85
|
shortcuts.push(undefined)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
})
|
|
87
|
+
/** @type {string[]} */
|
|
88
|
+
const options = optionsWithShortcuts.concat(optionsWithoutShortcuts)
|
|
89
|
+
shortcuts = shortcuts.concat(shortcutsForFlags)
|
|
90
|
+
return [help, options, shortcuts, flags]
|
|
84
91
|
},
|
|
85
92
|
|
|
86
93
|
/**
|
|
@@ -90,8 +97,7 @@ module.exports = {
|
|
|
90
97
|
* @param help string from `cds lint [-h, --help]`
|
|
91
98
|
* @returns ESLint flags
|
|
92
99
|
*/
|
|
93
|
-
genEslintFlags:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
};
|
|
100
|
+
genEslintFlags: help => help
|
|
101
|
+
.match(REGEX_FLAGS)
|
|
102
|
+
.map(str => str.trim().replace(',', ''))
|
|
103
|
+
}
|
package/lib/lint/io.js
CHANGED
|
@@ -1,271 +1,93 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const cds = require(
|
|
1
|
+
const { write, exists } = require('../cds').utils
|
|
2
|
+
const cds = require('../cds')
|
|
3
3
|
|
|
4
|
-
const { readJSONC } = require(
|
|
5
|
-
const path = require(
|
|
6
|
-
const term = require(
|
|
7
|
-
const JSONC = require('../util/jsonc');
|
|
4
|
+
const { readJSONC } = require('../util/fs')
|
|
5
|
+
const path = require('node:path')
|
|
6
|
+
const term = require('../util/term')
|
|
8
7
|
|
|
9
|
-
const {
|
|
8
|
+
const { pathToFileURL } = require('node:url')
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Reads ESLint config contents from file
|
|
14
|
-
* @param {*} configPath config file path to read from
|
|
15
|
-
* @returns {object[] | object} config file contents
|
|
16
|
-
*/
|
|
17
|
-
async readEslintConfigLegacy(configPath) {
|
|
18
|
-
let config;
|
|
19
|
-
const configFile = path.basename(configPath);
|
|
20
|
-
const configString = await read(configPath, "utf8");
|
|
21
|
-
switch (configFile) {
|
|
22
|
-
case ".eslintrc.js":
|
|
23
|
-
case ".eslintrc.cjs":
|
|
24
|
-
try {
|
|
25
|
-
config = JSONC.parse((configString.replace(/^module\.exports =/, "")));
|
|
26
|
-
} catch {
|
|
27
|
-
config = {};
|
|
28
|
-
}
|
|
29
|
-
break;
|
|
30
|
-
case ".eslintrc.yaml":
|
|
31
|
-
case ".eslintrc.yml":
|
|
32
|
-
config = yaml.parse(await read(configPath, "utf8"));
|
|
33
|
-
break;
|
|
34
|
-
case ".eslintrc.json":
|
|
35
|
-
case ".eslintrc":
|
|
36
|
-
config = await readJSONC(configPath);
|
|
37
|
-
break;
|
|
38
|
-
case "package.json":
|
|
39
|
-
config = await read(configPath, "json");
|
|
40
|
-
if ("eslintConfig" in config) {
|
|
41
|
-
config = config["eslintConfig"];
|
|
42
|
-
} else {
|
|
43
|
-
config = {}
|
|
44
|
-
}
|
|
45
|
-
break;
|
|
46
|
-
default:
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
return config;
|
|
50
|
-
},
|
|
10
|
+
const { COMMAND_INIT } = require('../init/constants')
|
|
51
11
|
|
|
52
|
-
|
|
12
|
+
const installationHint = (logger, configFile, importStatement) => logger.log(
|
|
13
|
+
`${term.warn(
|
|
14
|
+
`\n\nPlease add the following to your '${configFile}':` +
|
|
15
|
+
'\n\n 1. At the top of your file, import the following:')}` +
|
|
16
|
+
`\n\n ${term.bold(importStatement)}` +
|
|
17
|
+
`${term.warn(
|
|
18
|
+
'\n\n 2. In your export, add the following to the front of the array:')}` +
|
|
19
|
+
`\n\n ${term.bold('cdsPlugin.configs.recommended')}`
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
/**
|
|
53
24
|
* Reads ESLint config contents from file
|
|
54
|
-
* @param {
|
|
55
|
-
* @returns config file contents
|
|
25
|
+
* @param {import('fs').PathLike} configPath config file path to read from
|
|
26
|
+
* @returns {Promise<object>} config file contents
|
|
56
27
|
*/
|
|
57
28
|
async readEslintConfig(configPath) {
|
|
58
|
-
let config
|
|
29
|
+
let config
|
|
59
30
|
switch (path.basename(configPath)) {
|
|
60
|
-
case
|
|
61
|
-
|
|
31
|
+
case 'eslint.config.mjs':
|
|
32
|
+
// pathToFileURL is used to convert the path to a file URL on Windows
|
|
33
|
+
try { config = (await import (pathToFileURL(configPath))).default } catch(e) { config = null }
|
|
62
34
|
break
|
|
63
|
-
case
|
|
64
|
-
case
|
|
35
|
+
case 'eslint.config.js':
|
|
36
|
+
case 'eslint.config.cjs':
|
|
65
37
|
try { config = require (configPath) } catch { config = null }
|
|
66
38
|
}
|
|
67
|
-
return config
|
|
39
|
+
return config
|
|
68
40
|
},
|
|
69
41
|
|
|
70
42
|
/**
|
|
71
43
|
* Checks ESLint config file contents for locally installed
|
|
72
44
|
* plugin with:
|
|
73
|
-
* (1) All CDS recommended rules
|
|
45
|
+
* (1) All CDS recommended rules 'on'
|
|
74
46
|
* (2) Add's custom rule example 'no-entity-moo' if requested
|
|
75
|
-
* @param {
|
|
76
|
-
* @
|
|
47
|
+
* @param {object | string} configPath - ESLint config file or path
|
|
48
|
+
* @param {import('console').Console} logger - logger to use
|
|
49
|
+
* @returns {object}
|
|
77
50
|
*/
|
|
78
|
-
async sanitizeEslintConfig(configIn,
|
|
79
|
-
let configContents
|
|
80
|
-
const isFilePath = typeof configIn ===
|
|
51
|
+
async sanitizeEslintConfig(configIn, logger = console) {
|
|
52
|
+
let configContents
|
|
53
|
+
const isFilePath = typeof configIn === 'string'
|
|
81
54
|
if (isFilePath) {
|
|
82
55
|
configContents = await this.readEslintConfig(configIn)
|
|
83
56
|
}
|
|
84
57
|
|
|
85
|
-
configContents ??= { ...configIn }
|
|
86
|
-
|
|
87
|
-
if (customRuleExample) {
|
|
88
|
-
const ruleName = "no-entity-moo";
|
|
89
|
-
const ruleValue = 2;
|
|
90
|
-
if ("rules" in configContents) {
|
|
91
|
-
configContents["rules"][ruleName] = ruleValue;
|
|
92
|
-
} else {
|
|
93
|
-
configContents["rules"] = { [ruleName]: ruleValue };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
58
|
+
configContents ??= { ...configIn }
|
|
96
59
|
if (isFilePath) {
|
|
97
|
-
await this.writeEslintConfig(configIn, cds.cli?.command === COMMAND_INIT, logger)
|
|
98
|
-
}
|
|
99
|
-
return configContents;
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Checks ESLint config file contents for locally installed
|
|
104
|
-
* plugin with:
|
|
105
|
-
* (1) All CDS recommended rules "on"
|
|
106
|
-
* (2) Option "root": false to stop further config merging
|
|
107
|
-
* (3) Add's custom rule example 'no-entity-moo' if requested
|
|
108
|
-
* @param {*} configPath ESLint config file
|
|
109
|
-
*/
|
|
110
|
-
async sanitizeEslintConfigLegacy(configIn, customRuleExample = false, logger = console) {
|
|
111
|
-
let configContents = {};
|
|
112
|
-
const isFilePath = typeof configIn === "string";
|
|
113
|
-
if (isFilePath) {
|
|
114
|
-
if (exists(configIn)) {
|
|
115
|
-
configContents = (await this.readEslintConfig(configIn)) || {};
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
configContents = { ...configIn };
|
|
119
|
-
}
|
|
120
|
-
const configType = "recommended";
|
|
121
|
-
const extendsValue = `plugin:@sap/cds/${configType}`;
|
|
122
|
-
if ("extends" in configContents) {
|
|
123
|
-
if (Array.isArray(configContents["extends"])) {
|
|
124
|
-
if (!configContents["extends"].includes(extendsValue)) {
|
|
125
|
-
configContents["extends"].push(extendsValue);
|
|
126
|
-
}
|
|
127
|
-
} else if (configContents["extends"] !== extendsValue) {
|
|
128
|
-
configContents["extends"] = [configContents["extends"], extendsValue];
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
configContents["extends"] = extendsValue;
|
|
132
|
-
}
|
|
133
|
-
if ("root" in configContents) {
|
|
134
|
-
configContents["root"] = false;
|
|
135
|
-
}
|
|
136
|
-
if (customRuleExample) {
|
|
137
|
-
const ruleName = "no-entity-moo";
|
|
138
|
-
const ruleValue = 2;
|
|
139
|
-
if ("rules" in configContents) {
|
|
140
|
-
configContents["rules"][ruleName] = ruleValue;
|
|
141
|
-
} else {
|
|
142
|
-
configContents["rules"] = { [ruleName]: ruleValue };
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (isFilePath) {
|
|
146
|
-
await this.writeEslintConfigLegacy(configIn, configContents, logger);
|
|
147
|
-
}
|
|
148
|
-
return configContents;
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Writes ESLint config contents to file
|
|
154
|
-
* @param {*} configContents config file contents
|
|
155
|
-
* @param {*} configPath config file path to write to
|
|
156
|
-
* @returns {Promise<void>}
|
|
157
|
-
*/
|
|
158
|
-
async writeEslintConfigLegacy(configPath, configContents, logger = console) {
|
|
159
|
-
const configType = "recommended-legacy";
|
|
160
|
-
const extendsValue = `plugin:@sap/cds/${configType}`;
|
|
161
|
-
let contents = {};
|
|
162
|
-
let configFile = path.basename(configPath);
|
|
163
|
-
let configToAdd = {};
|
|
164
|
-
switch (configFile) {
|
|
165
|
-
case ".eslintrc.js":
|
|
166
|
-
case ".eslintrc.cjs":
|
|
167
|
-
try {
|
|
168
|
-
configContents = await this.readEslintConfigLegacy(configPath);
|
|
169
|
-
} catch (err) {
|
|
170
|
-
configContents = {};
|
|
171
|
-
}
|
|
172
|
-
if (configContents && configContents["extends"]) {
|
|
173
|
-
if (
|
|
174
|
-
!configContents["extends"] === extendsValue ||
|
|
175
|
-
!configContents["extends"].includes(extendsValue)
|
|
176
|
-
) {
|
|
177
|
-
configToAdd["extends"] = extendsValue;
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
configToAdd["extends"] = extendsValue;
|
|
181
|
-
}
|
|
182
|
-
if (configToAdd["extends"]) {
|
|
183
|
-
logger.log(
|
|
184
|
-
`${term.warn(
|
|
185
|
-
`\n\nPlease add the following to your "${configFile}":\n\nmodule.exports = ${JSON.stringify(configToAdd, null, 2)}`
|
|
186
|
-
)}\n`
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
break;
|
|
190
|
-
case ".eslintrc.yaml":
|
|
191
|
-
case ".eslintrc.yml":
|
|
192
|
-
await write(configPath, yaml.stringify(configContents));
|
|
193
|
-
break;
|
|
194
|
-
case ".eslintrc.json":
|
|
195
|
-
case ".eslintrc":
|
|
196
|
-
await write(configPath, configContents, { spaces: 2 });
|
|
197
|
-
break;
|
|
198
|
-
case "package.json":
|
|
199
|
-
if (exists(configPath)) {
|
|
200
|
-
contents = await read(configPath, "json");
|
|
201
|
-
} else {
|
|
202
|
-
contents = {};
|
|
203
|
-
}
|
|
204
|
-
if (!("eslintConfig" in configContents)) {
|
|
205
|
-
contents["eslintConfig"] = configContents;
|
|
206
|
-
} else {
|
|
207
|
-
contents["eslintConfig"] = [...configContents, ...contents["eslintConfig"]];
|
|
208
|
-
}
|
|
209
|
-
await write(configPath, contents, { spaces: 2 });
|
|
210
|
-
break;
|
|
211
|
-
default:
|
|
212
|
-
break;
|
|
60
|
+
await this.writeEslintConfig(configIn, cds.cli?.command === COMMAND_INIT, logger)
|
|
213
61
|
}
|
|
62
|
+
return configContents
|
|
214
63
|
},
|
|
215
64
|
|
|
216
65
|
/**
|
|
217
66
|
* Suggest ESLint config contents to file
|
|
218
67
|
* @param {*} configContents config file contents
|
|
219
|
-
* @param {
|
|
68
|
+
* @param {import('node:fs').PathLike} configPath config file path to write to
|
|
220
69
|
* @returns {Promise<void>}
|
|
221
70
|
*/
|
|
222
71
|
async writeEslintConfig(configPath, force = false, logger = console) {
|
|
223
|
-
let configFile = path.basename(configPath)
|
|
72
|
+
let configFile = path.basename(configPath)
|
|
224
73
|
switch (configFile) {
|
|
225
|
-
case
|
|
226
|
-
case
|
|
74
|
+
case 'eslint.config.js':
|
|
75
|
+
case 'eslint.config.cjs':
|
|
227
76
|
if (!force && exists(configPath)) {
|
|
228
|
-
logger
|
|
229
|
-
`${term.warn(
|
|
230
|
-
`\n\nPlease add the following to your "${configFile}":` +
|
|
231
|
-
'\n\n 1. At the top of your file, import the following:')}` +
|
|
232
|
-
`\n\n ${term.bold('const cds = require(\'@sap/eslint-plugin-cds\')')}` +
|
|
233
|
-
`${term.warn(
|
|
234
|
-
'\n\n 2. In your export, add the following to the top of the array:')}` +
|
|
235
|
-
`\n\n ${term.bold('cds.configs.recommended')}`
|
|
236
|
-
);
|
|
77
|
+
installationHint(logger, configFile, 'const cdsPlugin = require(\'@sap/eslint-plugin-cds\')')
|
|
237
78
|
} else {
|
|
238
79
|
await write(configPath, `
|
|
239
80
|
const cds = require('@sap/eslint-plugin-cds')
|
|
240
81
|
|
|
241
|
-
module.exports = [
|
|
242
|
-
cds.configs.recommended,
|
|
243
|
-
{
|
|
244
|
-
plugins: {
|
|
245
|
-
'@sap/cds': cds
|
|
246
|
-
},
|
|
247
|
-
files: [
|
|
248
|
-
...cds.configs.recommended.files
|
|
249
|
-
],
|
|
250
|
-
rules: {
|
|
251
|
-
...cds.configs.recommended.rules
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
]
|
|
82
|
+
module.exports = [...cds.recommended, cdsPlugin.configs.recommended]
|
|
255
83
|
`)
|
|
256
84
|
}
|
|
257
|
-
|
|
258
|
-
|
|
85
|
+
logger.log(term.warn('\nMake sure to also run npm i to install the newly added dependencies.'))
|
|
86
|
+
break
|
|
87
|
+
|
|
88
|
+
case 'eslint.config.mjs':
|
|
259
89
|
if (!force && exists(configPath)) {
|
|
260
|
-
logger
|
|
261
|
-
`${term.warn(
|
|
262
|
-
`\n\nPlease add the following to your "${configFile}":` +
|
|
263
|
-
'\n\n 1. At the top of your file, import the following:')}` +
|
|
264
|
-
`\n\n ${term.bold('import cdsPlugin from \'@sap/eslint-plugin-cds\'')}` +
|
|
265
|
-
`${term.warn(
|
|
266
|
-
'\n\n 2. In your export, add the following to the front of the array:')}` +
|
|
267
|
-
`\n\n ${term.bold('cdsPlugin.configs.recommended')}`
|
|
268
|
-
);
|
|
90
|
+
installationHint(logger, configFile, 'import cdsPlugin from \'@sap/eslint-plugin-cds\'')
|
|
269
91
|
} else {
|
|
270
92
|
await write(configPath, `
|
|
271
93
|
import cds from '@sap/cds/eslint.config.mjs'
|
|
@@ -274,9 +96,8 @@ import cdsPlugin from '@sap/eslint-plugin-cds'
|
|
|
274
96
|
export default [...cds.recommended, cdsPlugin.configs.recommended]
|
|
275
97
|
`)
|
|
276
98
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
break;
|
|
99
|
+
logger.log(term.warn('\nMake sure to also run npm i to install the newly added dependencies.'))
|
|
100
|
+
break
|
|
280
101
|
}
|
|
281
102
|
},
|
|
282
103
|
|
|
@@ -286,15 +107,15 @@ export default [...cds.recommended, cdsPlugin.configs.recommended]
|
|
|
286
107
|
* @returns settings file contents
|
|
287
108
|
*/
|
|
288
109
|
async readVscodeSettings(settingsPath) {
|
|
289
|
-
let settings
|
|
110
|
+
let settings
|
|
290
111
|
if (exists(settingsPath)) {
|
|
291
112
|
try {
|
|
292
|
-
settings = await readJSONC(settingsPath)
|
|
293
|
-
} catch
|
|
294
|
-
settings = {}
|
|
113
|
+
settings = await readJSONC(settingsPath)
|
|
114
|
+
} catch {
|
|
115
|
+
settings = {}
|
|
295
116
|
}
|
|
296
117
|
}
|
|
297
|
-
return settings
|
|
118
|
+
return settings
|
|
298
119
|
},
|
|
299
120
|
|
|
300
121
|
/**
|
|
@@ -304,71 +125,38 @@ export default [...cds.recommended, cdsPlugin.configs.recommended]
|
|
|
304
125
|
* @returns merged array (without duplicates)
|
|
305
126
|
*/
|
|
306
127
|
mergeArrays(array, arrayToMerge) {
|
|
307
|
-
let arrayMerged = array.concat(arrayToMerge)
|
|
308
|
-
if (typeof array ===
|
|
309
|
-
array = [array]
|
|
128
|
+
let arrayMerged = array.concat(arrayToMerge)
|
|
129
|
+
if (typeof array === 'string') {
|
|
130
|
+
array = [array]
|
|
310
131
|
}
|
|
311
|
-
if (typeof arrayToMerge ===
|
|
312
|
-
arrayToMerge = [arrayToMerge]
|
|
132
|
+
if (typeof arrayToMerge === 'string') {
|
|
133
|
+
arrayToMerge = [arrayToMerge]
|
|
313
134
|
}
|
|
314
|
-
arrayMerged = [...new Set([...array, ...arrayToMerge])]
|
|
315
|
-
return arrayMerged
|
|
135
|
+
arrayMerged = [...new Set([...array, ...arrayToMerge])]
|
|
136
|
+
return arrayMerged
|
|
316
137
|
},
|
|
317
138
|
|
|
318
139
|
/**
|
|
319
140
|
* Add VS Code ESLint extension settings required for CDS linting:
|
|
320
141
|
* (1) Extension file types: [cds, csn]
|
|
321
|
-
* (2)
|
|
322
|
-
* (3)
|
|
142
|
+
* (2) 'Custom' case adds rulePaths and removes configFile
|
|
143
|
+
* (3) 'Global' case adds configFile and removes rulePaths
|
|
323
144
|
* @param {*} settingsPath VS Code settings file
|
|
324
145
|
*/
|
|
325
|
-
async sanitizeVscodeSettings(settingsPath,
|
|
326
|
-
|
|
327
|
-
const rulePaths = [path.join(
|
|
146
|
+
async sanitizeVscodeSettings(settingsPath, lintFileTypes, customRuleExample = false) {
|
|
147
|
+
const settings = (await this.readVscodeSettings(settingsPath)) ?? {}
|
|
148
|
+
const rulePaths = [path.join('.eslint/rules')]
|
|
328
149
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
settings["eslint.validate"] = lintFileTypes;
|
|
333
|
-
}
|
|
150
|
+
settings['eslint.validate'] = settings['eslint.validate']
|
|
151
|
+
? this.mergeArrays(settings['eslint.validate'], lintFileTypes)
|
|
152
|
+
: lintFileTypes
|
|
334
153
|
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
} else {
|
|
341
|
-
if (customRuleExample) {
|
|
342
|
-
settings["eslint.options"] = {
|
|
343
|
-
rulePaths: rulePaths,
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
}
|
|
154
|
+
if (settings['eslint.options'] && customRuleExample) {
|
|
155
|
+
settings['eslint.options'].rulePaths = rulePaths
|
|
156
|
+
} else if (customRuleExample) {
|
|
157
|
+
settings['eslint.options'] = { rulePaths: rulePaths }
|
|
347
158
|
}
|
|
348
159
|
|
|
349
|
-
await write(settingsPath, settings, { spaces: 2 })
|
|
350
|
-
},
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Joins or creates prescribed options with that of user
|
|
354
|
-
* - Value for 'config' key will be overwritten if assigned by `cds lint`
|
|
355
|
-
* @param {*} propKey option key property
|
|
356
|
-
* @param {*} propsToAdd option values to add for key property
|
|
357
|
-
* @returns {void}
|
|
358
|
-
*/
|
|
359
|
-
mergeWithUserOpts(userOpts, propKey = "", propsToAdd = "") {
|
|
360
|
-
if (propsToAdd) {
|
|
361
|
-
if (Object.keys(userOpts).includes(propKey)) {
|
|
362
|
-
if (!["config", "format"].includes(propKey)) {
|
|
363
|
-
propsToAdd = this.mergeArrays(userOpts[propKey].split(","), propsToAdd.split(",")).join(
|
|
364
|
-
","
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
userOpts[propKey] = propsToAdd;
|
|
369
|
-
} else {
|
|
370
|
-
userOpts[propKey] = true;
|
|
371
|
-
}
|
|
372
|
-
return userOpts;
|
|
160
|
+
await write(settingsPath, settings, { spaces: 2 })
|
|
373
161
|
},
|
|
374
|
-
}
|
|
162
|
+
}
|
package/lib/util/fs.js
CHANGED
package/lib/util/git.js
CHANGED
|
@@ -5,7 +5,7 @@ const util = require('util');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
|
|
7
7
|
const cds = require('../cds');
|
|
8
|
-
const DEBUG =
|
|
8
|
+
const DEBUG = /\b(y|all|cli)\b/.test (process.env.DEBUG) ? ((..._) => console.debug ('[cli] -', ..._)) : undefined
|
|
9
9
|
|
|
10
10
|
const GIT_IGNORE_FILE = '.gitignore';
|
|
11
11
|
|