@sap/cds-dk 4.6.2 → 4.7.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 +59 -0
- package/bin/add.js +2 -1
- package/bin/bind.js +121 -48
- package/bin/cds.js +8 -0
- package/bin/env.js +0 -2
- package/bin/repl.js +5 -2
- package/bin/watch.js +11 -8
- 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/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 +17 -1
- package/lib/init/template/mta/files/mta.yaml.hbs +12 -5
- package/lib/init/template/mta/projectReader.js +1 -3
- 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/init/util/mvnArchetypeUtil.js +3 -1
- package/lib/lint/Linter.js +6 -13
- package/lib/lint/io.js +21 -31
- package/lib/watch/node-watch.js +46 -20
- package/npm-shrinkwrap.json +10648 -5083
- 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);
|
|
@@ -68,10 +73,21 @@ module.exports = class LintTemplate extends TemplateBase {
|
|
|
68
73
|
}
|
|
69
74
|
|
|
70
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
|
+
});
|
|
71
86
|
await io.sanitizeVscodeSettings(
|
|
72
87
|
this.projectPath,
|
|
73
88
|
path.join(this.projectPath, ".vscode/settings.json"),
|
|
74
89
|
this.lintType,
|
|
90
|
+
extensions,
|
|
75
91
|
this.customRuleExample
|
|
76
92
|
);
|
|
77
93
|
}
|
|
@@ -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
|
@@ -23,7 +23,6 @@ class Linter {
|
|
|
23
23
|
this.eslintCmdOpts = {};
|
|
24
24
|
this.eslintCmdOptsIndex = 0;
|
|
25
25
|
this.eslintCmdFileExpr = "";
|
|
26
|
-
this.formatter = false;
|
|
27
26
|
this.isFile = false;
|
|
28
27
|
this.help = "";
|
|
29
28
|
this.debug = "";
|
|
@@ -141,16 +140,14 @@ class Linter {
|
|
|
141
140
|
|
|
142
141
|
_addExtensions() {
|
|
143
142
|
// Add CDS file extensions to lint
|
|
144
|
-
const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) =>
|
|
143
|
+
const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => path.extname(ext));
|
|
145
144
|
this.eslintCmdOpts = io.mergeWithUserOpts(
|
|
146
145
|
this.eslintCmdOpts,
|
|
147
146
|
"ext",
|
|
148
147
|
extensions.join(',')
|
|
149
148
|
);
|
|
150
149
|
// Enable colored output
|
|
151
|
-
|
|
152
|
-
this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
|
|
153
|
-
}
|
|
150
|
+
this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
|
|
154
151
|
return;
|
|
155
152
|
}
|
|
156
153
|
|
|
@@ -205,22 +202,18 @@ class Linter {
|
|
|
205
202
|
} else {
|
|
206
203
|
input = `'${this.eslintCmdFileExpr.join("' '")}'`;
|
|
207
204
|
}
|
|
208
|
-
const eslintCmdSplit = this.eslintCmd.split(" ");
|
|
209
|
-
this.eslintCmd = eslintCmdSplit[0];
|
|
210
|
-
eslintCmdOpts.unshift(eslintCmdSplit[1]);
|
|
211
|
-
eslintCmdOpts.push(input);
|
|
212
205
|
// Run ESLint with given cmd line options
|
|
213
|
-
// - Show 'eslint' instead of 'node
|
|
214
|
-
// - Remove debug flag for printed cmd
|
|
206
|
+
// - Show 'eslint' instead of actual eslint cmd ('node .../.eslint.js')
|
|
207
|
+
// - Remove debug flag for printed cmd line
|
|
215
208
|
if (this.eslintCmdOpts.debug) {
|
|
216
209
|
eslintCmdOpts.splice(eslintCmdOpts.indexOf('--debug'), 1);
|
|
217
210
|
console.log(
|
|
218
|
-
`Linting:\n ${term.info(`eslint ${eslintCmdOpts.
|
|
211
|
+
`Linting:\n ${term.info(`eslint ${eslintCmdOpts.concat(input).join(' ')}`)}\n`
|
|
219
212
|
);
|
|
220
213
|
eslintCmdOpts.push('--debug');
|
|
221
214
|
}
|
|
222
215
|
if (!dryRun) {
|
|
223
|
-
return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts, {
|
|
216
|
+
return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts.concat(input), {
|
|
224
217
|
cwd: process.cwd(),
|
|
225
218
|
shell: true,
|
|
226
219
|
stdio: process.env.NODE_ENV === 'test' ? 'pipe' : 'inherit',
|
package/lib/lint/io.js
CHANGED
|
@@ -22,7 +22,7 @@ module.exports = {
|
|
|
22
22
|
case ".eslintrc.js":
|
|
23
23
|
case ".eslintrc.cjs":
|
|
24
24
|
try {
|
|
25
|
-
config =
|
|
25
|
+
config = JSONC.parse((configString.replace(/^module\.exports =/, "")));
|
|
26
26
|
} catch (err) {
|
|
27
27
|
config = {};
|
|
28
28
|
}
|
|
@@ -33,14 +33,14 @@ module.exports = {
|
|
|
33
33
|
break;
|
|
34
34
|
case ".eslintrc.json":
|
|
35
35
|
case ".eslintrc":
|
|
36
|
+
config = await fsUtil.readJSONC(configPath);
|
|
37
|
+
break;
|
|
36
38
|
case "package.json":
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
} catch (err) {
|
|
43
|
-
// Do nothing
|
|
39
|
+
config = JSON.parse(await fsp.readFile(configPath, "utf8"));
|
|
40
|
+
if ("eslintConfig" in config) {
|
|
41
|
+
config = config["eslintConfig"];
|
|
42
|
+
} else {
|
|
43
|
+
config = {}
|
|
44
44
|
}
|
|
45
45
|
break;
|
|
46
46
|
default:
|
|
@@ -138,21 +138,20 @@ module.exports = {
|
|
|
138
138
|
break;
|
|
139
139
|
case ".eslintrc.json":
|
|
140
140
|
case ".eslintrc":
|
|
141
|
+
await fsUtil.writeFile(configPath, `${JSON.stringify(configContents, null, 2)}`);
|
|
142
|
+
break;
|
|
141
143
|
case "package.json":
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
contents = {};
|
|
147
|
-
}
|
|
148
|
-
if (!("eslintConfig" in configContents)) {
|
|
149
|
-
contents["eslintConfig"] = configContents;
|
|
150
|
-
} else {
|
|
151
|
-
contents["eslintConfig"] = [...configContents, ...contents["eslintConfig"]];
|
|
152
|
-
}
|
|
153
|
-
configContents = contents;
|
|
144
|
+
if (await fsUtil.pathExists(configPath)) {
|
|
145
|
+
contents = JSON.parse(await fsp.readFile(configPath, "utf8"));
|
|
146
|
+
} else {
|
|
147
|
+
contents = {};
|
|
154
148
|
}
|
|
155
|
-
|
|
149
|
+
if (!("eslintConfig" in configContents)) {
|
|
150
|
+
contents["eslintConfig"] = configContents;
|
|
151
|
+
} else {
|
|
152
|
+
contents["eslintConfig"] = [...configContents, ...contents["eslintConfig"]];
|
|
153
|
+
}
|
|
154
|
+
await fsUtil.writeFile(configPath, `${JSON.stringify(contents, null, 2)}`);
|
|
156
155
|
break;
|
|
157
156
|
default:
|
|
158
157
|
break;
|
|
@@ -202,18 +201,9 @@ module.exports = {
|
|
|
202
201
|
* (3) "Global" case adds configFile and removes rulePaths
|
|
203
202
|
* @param {*} settingsPath VS Code settings file
|
|
204
203
|
*/
|
|
205
|
-
async sanitizeVscodeSettings(projectPath, settingsPath, lintType, customRuleExample = false) {
|
|
204
|
+
async sanitizeVscodeSettings(projectPath, settingsPath, lintType, lintFileTypes, customRuleExample = false) {
|
|
206
205
|
let settings = (await this.readVscodeSettings(settingsPath)) || {};
|
|
207
|
-
const lintFileTypes = ["cds", "csn"];
|
|
208
206
|
const rulePaths = [path.join(".eslint/rules")];
|
|
209
|
-
const configFile = path.join(__dirname, ".eslintrc.js");
|
|
210
|
-
|
|
211
|
-
function _addArrayOrString(array) {
|
|
212
|
-
if (array.length === 1) {
|
|
213
|
-
return array[0];
|
|
214
|
-
}
|
|
215
|
-
return array;
|
|
216
|
-
}
|
|
217
207
|
|
|
218
208
|
if (settings["eslint.validate"]) {
|
|
219
209
|
settings["eslint.validate"] = this.mergeArrays(settings["eslint.validate"], lintFileTypes);
|
package/lib/watch/node-watch.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const DEBUG = /\bwatch\b/.test(process.env.DEBUG) && console.debug
|
|
2
|
+
|
|
1
3
|
module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, options={} })=>{
|
|
2
4
|
|
|
3
5
|
let child
|
|
@@ -5,19 +7,23 @@ module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, option
|
|
|
5
7
|
// Phoning home...
|
|
6
8
|
const EventEmitter = require('events')
|
|
7
9
|
const emitter = new EventEmitter
|
|
8
|
-
process.on('exit', () => {
|
|
10
|
+
process.on('exit', () => { _kill (child); emitter.emit('quit') })
|
|
9
11
|
|
|
10
12
|
// Re-starting child process...
|
|
11
13
|
const { fork } = require('child_process')
|
|
12
|
-
const restart = (
|
|
13
|
-
|
|
14
|
+
const restart = _coalesceEvents(delay, (events) => {
|
|
15
|
+
DEBUG && DEBUG('>> Events:', events)
|
|
16
|
+
_kill (child, () => {
|
|
14
17
|
const execArgv = [...process.execArgv]
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
events.forEach(evt => {
|
|
19
|
+
if (evt.type && evt.type.startsWith('--')) execArgv.push(evt.type)
|
|
20
|
+
if (evt.name && evt.name.startsWith('--')) execArgv.push(evt.name)
|
|
21
|
+
})
|
|
17
22
|
if (options.debug) execArgv.push('--inspect')
|
|
18
23
|
if (options['debug-brk']) execArgv.push('--inspect-brk')
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
|
|
25
|
+
const updated = events.filter(evt => evt.type && evt.type === 'update').map(evt => evt.name)
|
|
26
|
+
emitter.emit ('restart', updated)
|
|
21
27
|
child = fork (script, { cwd, env, stdio:'inherit', execArgv }, (err)=>{
|
|
22
28
|
if (err) console.error (err)
|
|
23
29
|
})
|
|
@@ -26,14 +32,16 @@ module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, option
|
|
|
26
32
|
emitter.emit('message', msg)
|
|
27
33
|
})
|
|
28
34
|
})
|
|
29
|
-
|
|
35
|
+
|
|
36
|
+
})
|
|
37
|
+
|
|
30
38
|
restart()
|
|
31
39
|
|
|
32
40
|
// Watching for touched files...
|
|
33
41
|
const watch = require('node-watch')
|
|
34
42
|
const include = RegExp(`\\.(${ext.replace(/,/g,'|')})$`)
|
|
35
43
|
const filter = f => !ignore.test(f) && include.test(f)
|
|
36
|
-
watch (process.cwd(),{ recursive:true, filter, delay }, restart)
|
|
44
|
+
watch (process.cwd(),{ recursive:true, filter, delay:0 }, restart)
|
|
37
45
|
|
|
38
46
|
// Live commands...
|
|
39
47
|
const readline = require('readline')
|
|
@@ -44,12 +52,12 @@ module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, option
|
|
|
44
52
|
else if (input === 'break' || input === 'brk') restart('--inspect-brk')
|
|
45
53
|
else if (input === 'debug-brk') restart('--inspect-brk')
|
|
46
54
|
else if (input === 'ps') ps(child,env)
|
|
47
|
-
else if (input === 'bye' || input.match(/^n$/i)) {
|
|
55
|
+
else if (input === 'bye' || input.match(/^n$/i)) { _kill (child, () => process.exit()) }
|
|
48
56
|
else console.log ('?\n')
|
|
49
57
|
})
|
|
50
58
|
|
|
51
59
|
emitter.restart = restart
|
|
52
|
-
emitter.stop = () => {
|
|
60
|
+
emitter.stop = () => { _kill(child, () => false); child = undefined; }
|
|
53
61
|
emitter.setEnv = (name, value) => {
|
|
54
62
|
if (typeof value === "undefined") {
|
|
55
63
|
delete env[name]
|
|
@@ -67,14 +75,32 @@ const ps = (child,env) => console.log (`\x1b[32m
|
|
|
67
75
|
\x1b[0m`
|
|
68
76
|
)
|
|
69
77
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
// reduces mutiple node-watch events in a time frame into a bulk
|
|
79
|
+
function _coalesceEvents(delay, fn) {
|
|
80
|
+
let timer, cache = []
|
|
81
|
+
function handle() {
|
|
82
|
+
fn(cache)
|
|
83
|
+
timer = null
|
|
84
|
+
cache = []
|
|
85
|
+
}
|
|
86
|
+
return function(type, name) { // node-watch callback signature
|
|
87
|
+
cache.push({type, name})
|
|
88
|
+
if (!timer) {
|
|
89
|
+
timer = setTimeout(handle, delay);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _kill (proc, fn=()=>{}) {
|
|
95
|
+
if (!proc) return fn()
|
|
96
|
+
|
|
97
|
+
// On Windows, child_process.kill() abruptly kills the process (https://nodejs.org/api/child_process.html#subprocesskillsignal)
|
|
98
|
+
// Server has cleanup code to run, so send a custom message and give it a bit time.
|
|
99
|
+
if (process.platform === 'win32') {
|
|
100
|
+
proc.send({ exit: true }, () => {})
|
|
101
|
+
const waitTime = parseInt(process.env.CDS_WATCH_KILL_DELAY) || 500
|
|
102
|
+
setTimeout(()=> { proc.kill(); fn() }, waitTime)
|
|
103
|
+
} else {
|
|
104
|
+
proc.kill(); fn()
|
|
78
105
|
}
|
|
79
|
-
else fn()
|
|
80
106
|
}
|