@sap/cds-dk 4.6.0 → 4.7.1
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 +70 -0
- package/bin/add.js +2 -1
- package/bin/bind.js +121 -48
- package/bin/cds.js +8 -0
- package/bin/compile/index.js +2 -1
- package/bin/env.js +0 -2
- package/bin/repl.js +11 -4
- package/bin/watch.js +25 -13
- package/lib/bind/bindingResolver.js +26 -14
- package/lib/bind/bindingUtil.js +144 -0
- package/lib/bind/cfKeyProvider.js +2 -80
- package/lib/bind/kubernetesCredentialsProvider.js +157 -0
- package/lib/bind/userCdsrcJsonStorageProvider.js +7 -7
- package/lib/client/activate.js +9 -17
- package/lib/client/auth_manager.js +1 -1
- package/lib/client/extend.js +4 -9
- package/lib/client/settings_manager.js +5 -4
- package/lib/import/index.js +3 -2
- package/lib/import/internalDoc/edm2cdsTypeMapping.md +38 -0
- package/lib/import/utils/MultiMap.js +1 -0
- package/lib/import/v2parser.js +102 -37
- package/lib/import/v4parser.js +59 -20
- package/lib/index.js +6 -5
- package/lib/init/constants.js +2 -2
- package/lib/init/index.js +1 -0
- package/lib/init/template/data/index.js +29 -7
- package/lib/init/template/hana/files/common/undeploy.json +5 -0
- package/lib/init/template/hana/files/java/package.json +3 -0
- package/lib/init/template/hana/index.js +19 -23
- package/lib/init/template/lint/index.js +28 -18
- package/lib/init/template/mta/files/mta.yaml.hbs +12 -5
- package/lib/init/template/mta/projectReader.js +1 -3
- package/lib/init/template/nodejs/files/.gitignore.hbs +0 -2
- package/lib/init/template/samples/index.js +1 -1
- package/lib/init/template/templateBase.js +10 -41
- package/lib/init/util/fsUtil.js +1 -1
- package/lib/lint/Linter.js +13 -33
- package/lib/lint/checks.js +1 -5
- package/lib/lint/generators.js +5 -4
- package/lib/lint/io.js +23 -31
- package/lib/watch/node-watch.js +46 -20
- package/npm-shrinkwrap.json +11524 -5622
- package/package.json +3 -3
|
@@ -11,16 +11,12 @@ module.exports = class DataTemplate extends TemplateBase {
|
|
|
11
11
|
async run() {
|
|
12
12
|
const env = await this.getEnv();
|
|
13
13
|
|
|
14
|
-
const prefix = (typeof this.options.for === 'string') // --for <prefix>
|
|
15
|
-
? this.options.for
|
|
16
|
-
: '';
|
|
17
|
-
const prefixedWith = (definition) => definition.name === prefix || definition.name.startsWith(prefix);
|
|
18
|
-
|
|
19
14
|
let dest = (typeof this.options.out === 'string') // target folder
|
|
20
15
|
? this.options.out
|
|
21
16
|
: getDefaultTargetFolder(env, this.projectPath);
|
|
22
17
|
dest = resolve(this.projectPath, dest);
|
|
23
18
|
|
|
19
|
+
const nameFilter = asRegex(this.options.for)
|
|
24
20
|
const force = this.options.force;
|
|
25
21
|
const logger = this.logger;
|
|
26
22
|
|
|
@@ -29,18 +25,44 @@ module.exports = class DataTemplate extends TemplateBase {
|
|
|
29
25
|
|
|
30
26
|
// Also include 'external' entities w/ cds.persistence.skip (similar to 'mocked' option of serve).
|
|
31
27
|
// Could be too much sometimes, but don't want to bother users w/ a separate option for this.
|
|
32
|
-
|
|
28
|
+
includeExternalEntities(csn, logger)
|
|
33
29
|
|
|
34
30
|
csn = cds.compile.for.sql(csn, { names:env.sql.names, messages:[] }) // CSN w/ persistence information
|
|
35
31
|
csn = cds.reflect(csn); // reflected model (adds additional helper functions)
|
|
36
32
|
|
|
37
33
|
csn.all('entity')
|
|
38
|
-
.filter(
|
|
34
|
+
.filter (e => e.name.match(nameFilter)) // --for prefix|regex
|
|
39
35
|
.filter (e => !e.query) // exclude entities with queries (projection on, select from ...)
|
|
40
36
|
.filter (e => e.name !== 'DRAFT.DraftAdministrativeData' && !e.name.endsWith('.drafts')) // exclude draft stuff
|
|
41
37
|
.forEach(e => processEntity(e, dest, this.projectPath, csn, force, logger));
|
|
42
38
|
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function includeExternalEntities(model, logger) {
|
|
42
|
+
for (let each in model.definitions) {
|
|
43
|
+
const def = model.definitions[each]
|
|
44
|
+
if (def['@cds.persistence.skip'] === true) {
|
|
45
|
+
logger.debug ('Including skipped entity '+each)
|
|
46
|
+
delete def['@cds.persistence.skip']
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return model
|
|
50
|
+
}
|
|
43
51
|
|
|
52
|
+
function asRegex(spec) {
|
|
53
|
+
if (typeof spec === 'string') {
|
|
54
|
+
try {
|
|
55
|
+
if (spec.match(/[\^$|*]/))
|
|
56
|
+
return new RegExp(spec)
|
|
57
|
+
else { // no meta chars -> prefix semantics
|
|
58
|
+
spec = spec.replace(/\./g, '\\.') // escape dot
|
|
59
|
+
return new RegExp('^'+spec+'.*')
|
|
60
|
+
}
|
|
61
|
+
} catch (err) {
|
|
62
|
+
throw new Error (err.message) // user error, so cut off stack trace
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return /.*/
|
|
44
66
|
}
|
|
45
67
|
|
|
46
68
|
function processEntity (entity, dest, projectPath, csn, force, logger) {
|
|
@@ -13,8 +13,6 @@ const { nullLogger } = require('../../util/logger');
|
|
|
13
13
|
module.exports = class HanaTemplate extends TemplateBase {
|
|
14
14
|
constructor(projectPath, generator) {
|
|
15
15
|
super(projectPath, generator, __dirname);
|
|
16
|
-
|
|
17
|
-
this.env = null;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
async checkEnabled() {
|
|
@@ -22,34 +20,32 @@ module.exports = class HanaTemplate extends TemplateBase {
|
|
|
22
20
|
return true;
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
const env = await this.getEnv();
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
25
|
+
await Promise.all(['src/.hdiconfig', 'undeploy.json'].map(async(filePath) => {
|
|
26
|
+
if (await this.fsUtil.pathExists(path.join(this.projectPath, env.folders.db, filePath))) {
|
|
27
|
+
throw new Error(`File ${path.join(env.folders.db, filePath)} already exists. Use --force to overwrite.`);
|
|
28
|
+
}
|
|
29
|
+
}))
|
|
32
30
|
|
|
33
31
|
return true;
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
// read env from project
|
|
37
|
-
async getEnv(
|
|
35
|
+
async getEnv() {
|
|
38
36
|
const cdsEnvVar = process.env.CDS_ENV;
|
|
39
37
|
process.env.CDS_ENV = 'production'
|
|
40
|
-
let env
|
|
41
38
|
try {
|
|
42
|
-
|
|
39
|
+
return await super.getEnv();
|
|
43
40
|
} finally {
|
|
44
41
|
cdsEnvVar ? process.env.CDS_ENV = cdsEnvVar : delete process.env.CDS_ENV
|
|
45
42
|
}
|
|
46
|
-
return env
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
async run() {
|
|
50
|
-
|
|
46
|
+
const env = await this.getEnv();
|
|
51
47
|
|
|
52
|
-
await this.templateUtil.copyFiles('common', path.join(this.projectPath,
|
|
48
|
+
await this.templateUtil.copyFiles('common', path.join(this.projectPath, env.folders.db), {
|
|
53
49
|
projectName: this.projectName
|
|
54
50
|
}, this.options.force);
|
|
55
51
|
|
|
@@ -57,13 +53,13 @@ module.exports = class HanaTemplate extends TemplateBase {
|
|
|
57
53
|
const projectType = await this.getProjectType();
|
|
58
54
|
switch (projectType) {
|
|
59
55
|
case PROJECT_TYPE.java:
|
|
60
|
-
await this.templateUtil.copyFiles('java', path.join(this.projectPath,
|
|
56
|
+
await this.templateUtil.copyFiles('java', path.join(this.projectPath, env.folders.db), {}, this.options.force);
|
|
61
57
|
await this._updatePomXml();
|
|
62
|
-
await this._updateCdsrcJson(cdsrcJsonPath,
|
|
58
|
+
await this._updateCdsrcJson(cdsrcJsonPath, env.folders.db, env);
|
|
63
59
|
break;
|
|
64
60
|
|
|
65
61
|
case PROJECT_TYPE.nodejs:
|
|
66
|
-
await this._updatePackageJson(path.join(this.projectPath, 'package.json'),
|
|
62
|
+
await this._updatePackageJson(path.join(this.projectPath, 'package.json'), env.folders.db, env);
|
|
67
63
|
break;
|
|
68
64
|
|
|
69
65
|
default: break;
|
|
@@ -87,7 +83,7 @@ module.exports = class HanaTemplate extends TemplateBase {
|
|
|
87
83
|
}
|
|
88
84
|
}
|
|
89
85
|
|
|
90
|
-
async _updatePackageJson(packageJsonPath, modelName) { //NOSONAR
|
|
86
|
+
async _updatePackageJson(packageJsonPath, modelName, env) { //NOSONAR
|
|
91
87
|
modelName = path.basename(modelName);
|
|
92
88
|
|
|
93
89
|
if (!await this.fsUtil.pathExists(packageJsonPath)) {
|
|
@@ -109,7 +105,7 @@ module.exports = class HanaTemplate extends TemplateBase {
|
|
|
109
105
|
changed = true
|
|
110
106
|
}
|
|
111
107
|
|
|
112
|
-
if (!this._isUsingHana(modelName)) {
|
|
108
|
+
if (!this._isUsingHana(modelName, env)) {
|
|
113
109
|
packageJson.cds = packageJson.cds || {};
|
|
114
110
|
packageJson.cds.requires = packageJson.cds.requires || {};
|
|
115
111
|
packageJson.cds.requires[modelName] = packageJson.cds.requires[modelName] || {};
|
|
@@ -130,7 +126,7 @@ module.exports = class HanaTemplate extends TemplateBase {
|
|
|
130
126
|
}
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
async _updateCdsrcJson(cdsrcJsonPath, modelName) {
|
|
129
|
+
async _updateCdsrcJson(cdsrcJsonPath, modelName, env) {
|
|
134
130
|
modelName = path.basename(modelName);
|
|
135
131
|
|
|
136
132
|
let changed;
|
|
@@ -143,7 +139,7 @@ module.exports = class HanaTemplate extends TemplateBase {
|
|
|
143
139
|
|
|
144
140
|
this.logger.isDebug && this.logger.debug(`_updateCdsrcJson before: ${JSON.stringify(cdsrcJson, null, 2)}`);
|
|
145
141
|
|
|
146
|
-
if (!this._isUsingHana(modelName)) {
|
|
142
|
+
if (!this._isUsingHana(modelName, env)) {
|
|
147
143
|
cdsrcJson.requires = cdsrcJson.requires || {};
|
|
148
144
|
cdsrcJson.requires[modelName] = cdsrcJson.requires[modelName] || {};
|
|
149
145
|
cdsrcJson.requires[modelName].kind = KIND_SQL;
|
|
@@ -161,7 +157,7 @@ module.exports = class HanaTemplate extends TemplateBase {
|
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
159
|
|
|
164
|
-
_isUsingHana(db) {
|
|
165
|
-
return
|
|
160
|
+
_isUsingHana(db, env) {
|
|
161
|
+
return env.get(`requires.${db}.kind`) === KIND_HANA || env.get(`requires.${db}.dialect`) === KIND_HANA || env.get(`requires.${db}.use`) === KIND_HANA;
|
|
166
162
|
}
|
|
167
163
|
}
|
|
@@ -9,10 +9,15 @@ const readline = require("readline");
|
|
|
9
9
|
|
|
10
10
|
const { OPTION_LINT_DEV, OPTION_LINT_GLOBAL } = require("../../constants");
|
|
11
11
|
const { mkdirp, fs } = require("@sap/cds/lib/utils");
|
|
12
|
-
const { getConfigPath } = require("@sap/eslint-plugin-cds/lib/api");
|
|
12
|
+
const { getConfigPath, getFileExtensions } = require("@sap/eslint-plugin-cds/lib/api");
|
|
13
13
|
const generators = require("../../../lint/generators");
|
|
14
14
|
|
|
15
15
|
const IS_WIN = os.platform() === "win32";
|
|
16
|
+
const ALLOWED_FILE_EXTENSIONS = getFileExtensions();
|
|
17
|
+
const VSCODE_FILE_ASSOCIATIONS = {
|
|
18
|
+
"csv": [ "csv", "csv (semicolon)", "tsv", "tab" ]
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
module.exports = class LintTemplate extends TemplateBase {
|
|
17
22
|
constructor(projectPath, generator) {
|
|
18
23
|
super(projectPath, generator, __dirname);
|
|
@@ -42,12 +47,9 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
async run() {
|
|
45
|
-
const cdsdkPath = path.join(__dirname, "../../../..");
|
|
46
|
-
const globalPath = path.join(cdsdkPath, "../..");
|
|
47
|
-
|
|
48
50
|
// Require ESLint v>=7.0.0
|
|
49
51
|
if (!this.isTest) {
|
|
50
|
-
this._checkEslint(
|
|
52
|
+
this._checkEslint();
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
// To enable custom lint rules ('lint' or 'lint:dev')
|
|
@@ -69,15 +71,27 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
69
71
|
// Generate custom lint rules docs
|
|
70
72
|
await generators.genDocs(this.projectPath);
|
|
71
73
|
}
|
|
74
|
+
|
|
75
|
+
// Generate VS Code extension settings
|
|
76
|
+
const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => {
|
|
77
|
+
return path.extname(ext).replace('.', '');
|
|
78
|
+
})
|
|
79
|
+
extensions.forEach((ext) => {
|
|
80
|
+
if (ext in VSCODE_FILE_ASSOCIATIONS) {
|
|
81
|
+
VSCODE_FILE_ASSOCIATIONS[ext].forEach((assoc) => {
|
|
82
|
+
extensions.push(assoc)
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
await io.sanitizeVscodeSettings(
|
|
87
|
+
this.projectPath,
|
|
88
|
+
path.join(this.projectPath, ".vscode/settings.json"),
|
|
89
|
+
this.lintType,
|
|
90
|
+
extensions,
|
|
91
|
+
this.customRuleExample
|
|
92
|
+
);
|
|
72
93
|
}
|
|
73
94
|
|
|
74
|
-
// Generate VS Code extension settings
|
|
75
|
-
await io.sanitizeVscodeSettings(
|
|
76
|
-
this.projectPath,
|
|
77
|
-
path.join(this.projectPath, ".vscode/settings.json"),
|
|
78
|
-
this.lintType,
|
|
79
|
-
this.customRuleExample
|
|
80
|
-
);
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
async finalize() {
|
|
@@ -111,12 +125,8 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
111
125
|
|
|
112
126
|
}
|
|
113
127
|
|
|
114
|
-
_checkEslint(
|
|
115
|
-
const
|
|
116
|
-
let eslintCmd;
|
|
117
|
-
if (eslintInfo) {
|
|
118
|
-
eslintCmd = eslintInfo.cmd;
|
|
119
|
-
}
|
|
128
|
+
_checkEslint() {
|
|
129
|
+
const eslintCmd = checks.resolveEslint(this.projectPath, '');
|
|
120
130
|
if (!eslintCmd) {
|
|
121
131
|
this.missingNpmDependencies["names"].push("eslint");
|
|
122
132
|
this.missingNpmDependencies["msgs"].push("ESLint v>=7.0.0");
|
|
@@ -13,7 +13,12 @@ build-parameters:
|
|
|
13
13
|
before-all:
|
|
14
14
|
- builder: custom
|
|
15
15
|
commands:
|
|
16
|
+
{{#cap.isNodejs}}
|
|
17
|
+
- npm ci
|
|
18
|
+
{{/cap.isNodejs}}
|
|
19
|
+
{{#cap.isJava}}
|
|
16
20
|
- npm install --production
|
|
21
|
+
{{/cap.isJava}}
|
|
17
22
|
- npx -p @sap/cds-dk cds build --production
|
|
18
23
|
|
|
19
24
|
{{! This template creates one or two deployable modules:
|
|
@@ -30,6 +35,8 @@ modules:
|
|
|
30
35
|
{{#cap.isNodejs}}
|
|
31
36
|
parameters:
|
|
32
37
|
buildpack: nodejs_buildpack
|
|
38
|
+
build-parameters:
|
|
39
|
+
builder: npm-ci
|
|
33
40
|
{{/cap.isNodejs}}
|
|
34
41
|
{{#cap.isJava}}
|
|
35
42
|
parameters:
|
|
@@ -207,11 +214,11 @@ resources:
|
|
|
207
214
|
type: org.cloudfoundry.managed-service
|
|
208
215
|
requires:
|
|
209
216
|
- name: {{cap.appName}}-uaa-mt
|
|
210
|
-
- name: mtx-api
|
|
211
|
-
properties:
|
|
212
|
-
prop: ~{mtx-url}
|
|
213
|
-
parameters:
|
|
214
|
-
param: ~{mtx-url}
|
|
217
|
+
- name: mtx-api
|
|
218
|
+
properties:
|
|
219
|
+
prop: ~{mtx-url}
|
|
220
|
+
parameters:
|
|
221
|
+
param: ~{mtx-url}
|
|
215
222
|
parameters:
|
|
216
223
|
service: saas-registry
|
|
217
224
|
service-plan: application
|
|
@@ -22,13 +22,11 @@ module.exports = class ProjectReader {
|
|
|
22
22
|
async getEnv(profile = 'production') {
|
|
23
23
|
const cdsEnvVar = process.env.CDS_ENV
|
|
24
24
|
process.env.CDS_ENV = profile
|
|
25
|
-
let env
|
|
26
25
|
try {
|
|
27
|
-
|
|
26
|
+
return await this.template.getEnv();
|
|
28
27
|
} finally {
|
|
29
28
|
cdsEnvVar ? process.env.CDS_ENV = cdsEnvVar : delete process.env.CDS_ENV
|
|
30
29
|
}
|
|
31
|
-
return env
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
get fsUtil() {
|
|
@@ -58,7 +58,7 @@ module.exports = class SamplesTemplate extends TemplateBase {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
async _addNodejsSamples() {
|
|
61
|
-
const folders = (await this.getEnv(
|
|
61
|
+
const folders = (await this.getEnv()).folders;
|
|
62
62
|
const dbFolder = path.join(this.projectPath, folders.db);
|
|
63
63
|
await this.templateUtil.copyFiles('nodejs/db', dbFolder, {}, this.options.force);
|
|
64
64
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
-
const
|
|
2
|
+
const Config = require('@sap/cds/lib/env');
|
|
3
3
|
|
|
4
4
|
const TemplateUtil = require('../util/templateUtil');
|
|
5
|
-
const commandUtil = require('../util/commandUtil');
|
|
6
|
-
const { nullLogger } = require('../util/logger');
|
|
7
5
|
|
|
8
|
-
const {
|
|
6
|
+
const { PROJECT_TYPE } = require('../constants');
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
module.exports = class TemplateBase {
|
|
@@ -43,49 +41,20 @@ module.exports = class TemplateBase {
|
|
|
43
41
|
return true;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
getCdsModulePath() {
|
|
47
|
-
return path.join(__dirname, '../../../bin/cds.js');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
44
|
/**
|
|
51
45
|
* calls cds env and caches result
|
|
52
46
|
* @param {boolean} force, ignore cached value
|
|
53
47
|
* @returns {object} the current cds env
|
|
54
48
|
*/
|
|
55
|
-
async getEnv(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
projectPath = this.cwd;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const logger = (this.logger.isDebug ? this.logger : nullLogger);
|
|
65
|
-
|
|
66
|
-
let modPath = this.getCdsModulePath();
|
|
67
|
-
if (IS_WIN) {
|
|
68
|
-
modPath = `"${modPath}"`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let envJsonOutput = await commandUtil.spawnCommand('node', [modPath, 'env', 'json'], {
|
|
72
|
-
cwd: projectPath,
|
|
73
|
-
env: process.env
|
|
74
|
-
}, logger, true);
|
|
75
|
-
|
|
76
|
-
if (envJsonOutput) {
|
|
77
|
-
// cheap check to see if json is valid
|
|
78
|
-
if (envJsonOutput.indexOf('":') < 0) {
|
|
79
|
-
// eslint-disable-next-line no-control-regex
|
|
80
|
-
envJsonOutput = envJsonOutput.replace(/'/g, '"').replace(/\s(\w+):\s/g, ' "$1": ').replace(/\x1b\[\w+m/g, '');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
this.env = JSON.parse(envJsonOutput);
|
|
84
|
-
// env has additional getters and setters
|
|
85
|
-
Object.setPrototypeOf(this.env, cds.env.__proto__);
|
|
86
|
-
}
|
|
49
|
+
async getEnv() {
|
|
50
|
+
let projectPath;
|
|
51
|
+
if (await this.fsUtil.pathExists(this.projectPath)) {
|
|
52
|
+
projectPath = this.projectPath;
|
|
53
|
+
} else {
|
|
54
|
+
projectPath = this.cwd;
|
|
87
55
|
}
|
|
88
|
-
|
|
56
|
+
|
|
57
|
+
return Config.for('cds', projectPath);
|
|
89
58
|
}
|
|
90
59
|
|
|
91
60
|
/**
|
package/lib/init/util/fsUtil.js
CHANGED
|
@@ -18,7 +18,7 @@ module.exports = class FsUtil {
|
|
|
18
18
|
await fse.outputFile(filepath, content, UTF_8);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
async writeJSON(filepath, object, options = { spaces:
|
|
21
|
+
async writeJSON(filepath, object, options = { spaces: 2 }, skipFileLog = false) {
|
|
22
22
|
if (!skipFileLog) {
|
|
23
23
|
this._addTouchedFile(filepath);
|
|
24
24
|
}
|
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 = "";
|
|
@@ -45,11 +47,7 @@ class Linter {
|
|
|
45
47
|
* @returns object continaing help, options, flags and shortcuts
|
|
46
48
|
*/
|
|
47
49
|
init(help = "", options = [], flags = [], shortcuts = []) {
|
|
48
|
-
|
|
49
|
-
if (eslintInfo) {
|
|
50
|
-
this.eslintCmd = eslintInfo.cmd;
|
|
51
|
-
}
|
|
52
|
-
this.addFormatter = eslintInfo.addFormatter;
|
|
50
|
+
this.eslintCmd = checks.resolveEslint(this.cdsdkPath, this.globalPath);
|
|
53
51
|
if (this.eslintCmd) {
|
|
54
52
|
help = generators.genEslintHelp(this.eslintCmd);
|
|
55
53
|
flags = generators.genEslintFlags(help);
|
|
@@ -98,7 +96,7 @@ class Linter {
|
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
// Limit to CDS file extensions
|
|
101
|
-
this._addExtensions(
|
|
99
|
+
this._addExtensions();
|
|
102
100
|
// Run ESLint with collected options
|
|
103
101
|
try {
|
|
104
102
|
await this._runEslint();
|
|
@@ -141,29 +139,16 @@ class Linter {
|
|
|
141
139
|
return;
|
|
142
140
|
}
|
|
143
141
|
|
|
144
|
-
_addExtensions(
|
|
142
|
+
_addExtensions() {
|
|
145
143
|
// Add CDS file extensions to lint
|
|
144
|
+
const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => path.extname(ext));
|
|
146
145
|
this.eslintCmdOpts = io.mergeWithUserOpts(
|
|
147
146
|
this.eslintCmdOpts,
|
|
148
147
|
"ext",
|
|
149
|
-
|
|
148
|
+
extensions.join(',')
|
|
150
149
|
);
|
|
151
|
-
// Add custom CDS formatter (for ESLint v<8)
|
|
152
|
-
if (addFormatter) {
|
|
153
|
-
const formatterPath = this.pluginPath.replace(
|
|
154
|
-
"index.js",
|
|
155
|
-
"../api/formatter.js"
|
|
156
|
-
);
|
|
157
|
-
this.eslintCmdOpts = io.mergeWithUserOpts(
|
|
158
|
-
this.eslintCmdOpts,
|
|
159
|
-
"format",
|
|
160
|
-
path.relative(".", formatterPath)
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
150
|
// Enable colored output
|
|
164
|
-
|
|
165
|
-
this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
|
|
166
|
-
}
|
|
151
|
+
this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
|
|
167
152
|
return;
|
|
168
153
|
}
|
|
169
154
|
|
|
@@ -193,7 +178,6 @@ class Linter {
|
|
|
193
178
|
}
|
|
194
179
|
}
|
|
195
180
|
// Only lint file extensions prescribed by plugin
|
|
196
|
-
const fileExtensions = getFileExtensions();
|
|
197
181
|
eslintCmdOpts.push("--ignore-pattern");
|
|
198
182
|
let ignorePattern = "*.*";
|
|
199
183
|
if (IS_WIN) {
|
|
@@ -202,7 +186,7 @@ class Linter {
|
|
|
202
186
|
ignorePattern = `'${ignorePattern}'`;
|
|
203
187
|
}
|
|
204
188
|
eslintCmdOpts.push(ignorePattern);
|
|
205
|
-
|
|
189
|
+
ALLOWED_FILE_EXTENSIONS.forEach((ext) => {
|
|
206
190
|
eslintCmdOpts.push("--ignore-pattern");
|
|
207
191
|
ignorePattern = `!${ext}`;
|
|
208
192
|
if (IS_WIN) {
|
|
@@ -219,22 +203,18 @@ class Linter {
|
|
|
219
203
|
} else {
|
|
220
204
|
input = `'${this.eslintCmdFileExpr.join("' '")}'`;
|
|
221
205
|
}
|
|
222
|
-
const eslintCmdSplit = this.eslintCmd.split(" ");
|
|
223
|
-
this.eslintCmd = eslintCmdSplit[0];
|
|
224
|
-
eslintCmdOpts.unshift(eslintCmdSplit[1]);
|
|
225
|
-
eslintCmdOpts.push(input);
|
|
226
206
|
// Run ESLint with given cmd line options
|
|
227
|
-
// - Show 'eslint' instead of 'node
|
|
228
|
-
// - Remove debug flag for printed cmd
|
|
207
|
+
// - Show 'eslint' instead of actual eslint cmd ('node .../.eslint.js')
|
|
208
|
+
// - Remove debug flag for printed cmd line
|
|
229
209
|
if (this.eslintCmdOpts.debug) {
|
|
230
210
|
eslintCmdOpts.splice(eslintCmdOpts.indexOf('--debug'), 1);
|
|
231
211
|
console.log(
|
|
232
|
-
`Linting:\n ${term.info(`eslint ${eslintCmdOpts.
|
|
212
|
+
`Linting:\n ${term.info(`eslint ${eslintCmdOpts.concat(input).join(' ')}`)}\n`
|
|
233
213
|
);
|
|
234
214
|
eslintCmdOpts.push('--debug');
|
|
235
215
|
}
|
|
236
216
|
if (!dryRun) {
|
|
237
|
-
return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts, {
|
|
217
|
+
return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts.concat(input), {
|
|
238
218
|
cwd: process.cwd(),
|
|
239
219
|
shell: true,
|
|
240
220
|
stdio: process.env.NODE_ENV === 'test' ? 'pipe' : 'inherit',
|
package/lib/lint/checks.js
CHANGED
|
@@ -21,7 +21,6 @@ module.exports = {
|
|
|
21
21
|
let cmd;
|
|
22
22
|
let version;
|
|
23
23
|
let errMessage;
|
|
24
|
-
let addFormatter = false;
|
|
25
24
|
try {
|
|
26
25
|
const eslintPath = require.resolve("eslint/package.json", {
|
|
27
26
|
paths: [inputPath, globalPath],
|
|
@@ -29,9 +28,6 @@ module.exports = {
|
|
|
29
28
|
const packageJson = require(eslintPath);
|
|
30
29
|
if (packageJson.version > "7") {
|
|
31
30
|
version = packageJson.version;
|
|
32
|
-
if (version < "8") {
|
|
33
|
-
addFormatter = true;
|
|
34
|
-
}
|
|
35
31
|
} else {
|
|
36
32
|
errMessage =
|
|
37
33
|
`ESLint v>=6.0.0 required!\n\n` +
|
|
@@ -55,7 +51,7 @@ module.exports = {
|
|
|
55
51
|
)}\n`;
|
|
56
52
|
}
|
|
57
53
|
if (cmd && version) {
|
|
58
|
-
return
|
|
54
|
+
return cmd;
|
|
59
55
|
}
|
|
60
56
|
if (logger) {
|
|
61
57
|
logger.error(errMessage);
|
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
|
*/
|