@sap/cds-dk 4.3.3 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +62 -1
  2. package/bin/activate.js +1 -2
  3. package/bin/deploy/index.js +1 -1
  4. package/bin/deploy/to-sqlite.js +2 -2
  5. package/bin/extend.js +2 -4
  6. package/bin/help.js +1 -1
  7. package/bin/login.js +7 -8
  8. package/bin/logout.js +1 -2
  9. package/bin/repl.js +1 -1
  10. package/bin/watch.js +12 -8
  11. package/lib/client/activate.js +243 -0
  12. package/lib/client/auth_manager.js +115 -0
  13. package/lib/client/base_command.js +55 -0
  14. package/lib/client/extend.js +179 -0
  15. package/lib/client/helper/cf_helper.js +186 -0
  16. package/lib/client/helper/dependency_helper.js +26 -0
  17. package/lib/client/helper/env_helper.js +4 -0
  18. package/lib/client/helper/fs_helper.js +83 -0
  19. package/lib/client/helper/logging.js +37 -0
  20. package/lib/client/helper/question.js +50 -0
  21. package/lib/client/helper/string_helper.js +53 -0
  22. package/lib/client/helper/url_helper.js +17 -0
  23. package/lib/client/index.js +14 -0
  24. package/lib/client/params.js +435 -0
  25. package/lib/client/settings_manager.js +526 -0
  26. package/lib/import/index.js +17 -38
  27. package/lib/import/message.js +6 -7
  28. package/lib/import/v2parser.js +340 -64
  29. package/lib/import/v4parser.js +346 -59
  30. package/lib/init/constants.js +1 -1
  31. package/lib/init/index.js +13 -10
  32. package/lib/init/template/data/index.js +38 -46
  33. package/lib/init/template/hana/index.js +2 -2
  34. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/fixed/schema.cds +4 -0
  35. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/invalid/schema.cds +4 -0
  36. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/test.js +10 -0
  37. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/valid/schema.cds +6 -0
  38. package/lib/init/template/lint/index.js +8 -6
  39. package/lib/init/template/mta/projectReader.js +8 -5
  40. package/lib/init/template/nodejs/files/.vscode/extensions.json +1 -1
  41. package/lib/init/template/nodejs/index.js +1 -8
  42. package/lib/init/util/logger.js +1 -1
  43. package/lib/lint/Linter.js +82 -65
  44. package/lib/lint/io.js +9 -33
  45. package/npm-shrinkwrap.json +6327 -11301
  46. package/package.json +6 -7
  47. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo.test.js +0 -34
@@ -25,14 +25,20 @@ module.exports = class DataTemplate extends TemplateBase {
25
25
  const logger = this.logger;
26
26
 
27
27
  cds.root = this.projectPath;
28
- let csn = await cds.compile.to.csn(['*']); // normal CSN
29
- csn = cds.compile.for.sql(csn, { names:env.sql.names }); // CSN w/ persistence information
28
+ let csn = await cds.compile.to.csn(cds.env.roots); // normal CSN
29
+
30
+ // Also include 'external' entities w/ cds.persistence.skip (similar to 'mocked' option of serve).
31
+ // Could be too much sometimes, but don't want to bother users w/ a separate option for this.
32
+ cds.deploy.include_external_entities_in(csn)
33
+
34
+ csn = cds.compile.for.sql(csn, { names:env.sql.names, messages:[] }) // CSN w/ persistence information
30
35
  csn = cds.reflect(csn); // reflected model (adds additional helper functions)
31
36
 
32
37
  csn.all('entity')
33
38
  .filter(prefixedWith)
34
- .filter (entity => !entity.query) // exclude entities with queries (projection on, select from ...)
35
- .forEach(entity => processEntity(entity, dest, this.projectPath, csn, force, logger));
39
+ .filter (e => !e.query) // exclude entities with queries (projection on, select from ...)
40
+ .filter (e => e.name !== 'DRAFT.DraftAdministrativeData' && !e.name.endsWith('.drafts')) // exclude draft stuff
41
+ .forEach(e => processEntity(e, dest, this.projectPath, csn, force, logger));
36
42
  }
37
43
 
38
44
  }
@@ -44,15 +50,15 @@ function processEntity (entity, dest, projectPath, csn, force, logger) {
44
50
  dataFileName = `${entity.name}.csv`;
45
51
  }
46
52
  else {
47
- const entityName = entity.name.replace(namespace + ".", "");
53
+ const entityName = entity.name.replace(namespace + '.', '');
48
54
  dataFileName = `${namespace}-${entityName}.csv`;
49
55
  }
50
56
 
51
- if (entity.name.endsWith(".texts")) {
57
+ if (entity.name.endsWith('.texts')) {
52
58
  // handle '.texts' entities (for localized elements) differently:
53
59
  // if there is already file exist with '_texts' (old cds versions) - overwrite this one (when --force is used)
54
60
  // otherwise use the new '.texts' format
55
- const dataFileNameOldFormat = dataFileName.replace(".texts.csv","_texts.csv");
61
+ const dataFileNameOldFormat = dataFileName.replace('.texts.csv','_texts.csv');
56
62
  const dataFilePathOldFormat = join(dest, dataFileNameOldFormat);
57
63
  if (fs.existsSync(dataFilePathOldFormat)) {
58
64
  createDataFile(true, dataFilePathOldFormat, dest, projectPath, force, entity, logger);
@@ -68,62 +74,48 @@ function getDefaultTargetFolder (env, projectPath) {
68
74
  const dbFolder = env.folders.db;
69
75
  // csv files should be located in the 'db/data' folder unless a 'db/csv' folder already exists
70
76
  let mockDataFolder;
71
- if (fs.existsSync(join(projectPath, dbFolder, "csv"))) {
72
- mockDataFolder = "csv";
77
+ if (fs.existsSync(join(projectPath, dbFolder, 'csv'))) {
78
+ mockDataFolder = 'csv';
73
79
  } else {
74
- mockDataFolder = "data";
80
+ mockDataFolder = 'data';
75
81
  }
76
82
  return join(dbFolder, mockDataFolder);
77
83
  }
78
84
 
79
85
 
80
86
  function createDataFile (isFileExists, dataFilePath, dest, projectPath, force, entity, logger) {
87
+ let relFilePath = dataFilePath;
88
+ if (dataFilePath.indexOf(projectPath) == 0) {
89
+ // use relative path in log (for readability), only when data files are added within the project
90
+ // (potentially can be located anywhere using the --out parameter)
91
+ relFilePath = relative(projectPath, dataFilePath);
92
+ }
81
93
  if (isFileExists && !force) {
82
- let loggedDataFilePath = dataFilePath;
83
- if (dataFilePath.indexOf(projectPath) == 0) {
84
- // use relative path in log (for readability), only when data files are added within the project
85
- // (potentially can be located anywhere using the --out parameter)
86
- loggedDataFilePath = relative(projectPath, dataFilePath);
87
- }
88
- logger.log(`file ${loggedDataFilePath} already exists with no '--force' option - skip add data for entity ${entity.name}`);
94
+ logger.log(`Skipping ${relFilePath}`);
89
95
  }
90
96
  else {
91
- // continue only if file not already exists, or "--force" option provided
97
+ // continue only if file not already exists, or '--force' option provided
92
98
  const dataFileContent = prepareDataFileContent(entity);
93
- if (!fs.existsSync(dest)) {
94
- fs.mkdirSync(dest, {recursive: true});
99
+ if (dataFileContent && dataFileContent.length) {
100
+ if (!fs.existsSync(dest)) fs.mkdirSync(dest, {recursive: true})
101
+ fs.writeFileSync(dataFilePath, dataFileContent);
102
+ isFileExists ? logger.log(`Overwriting `+relFilePath) : logger.log(`Creating `+relFilePath)
95
103
  }
96
- fs.writeFileSync(dataFilePath, dataFileContent);
97
104
  }
98
105
  }
99
106
 
100
107
  function prepareDataFileContent (entity) {
101
- const persistenceKeyNames = Object.values(entity.keys)
102
- .map(element => element['@cds.persistence.name']);
103
-
104
- const persistenceNames = Object.values(entity.elements)
108
+ const persistenceKeyNames = Object.values(entity.keys||[]).map(element => element['@cds.persistence.name']);
109
+ return Object.values(entity.elements)
105
110
  .filter(element => !(element instanceof cds.Association)) // exclude associations+compositions
106
- .map(element => element['@cds.persistence.name'])
107
- .filter(elementName => persistenceKeyNames.indexOf(elementName) === -1); // filter out key elements
108
-
109
- let content = "";
110
- let isFirst = true;
111
- // create keys first (assuming keys cannot be empty)
112
- persistenceKeyNames.forEach(name => {
113
- if (isFirst) {
114
- content += `${name}`;
115
- isFirst = false;
116
- }
117
- else {
118
- content += `;${name}`;
119
- }
120
- });
121
-
122
- persistenceNames.forEach(name => {
123
- content += `;${name}`;
124
- });
125
-
126
- return content;
111
+ .filter(element => !!element['@cds.persistence.name']) // exclude no-persistence elements, e.g. virtual ones
112
+ .map (element => element['@cds.persistence.name'])
113
+ .sort((e1, e2) => { // sort with keys first
114
+ if (persistenceKeyNames.includes(e1) && !persistenceKeyNames.includes(e2)) return -1
115
+ if (!persistenceKeyNames.includes(e1) && persistenceKeyNames.includes(e2)) return 1
116
+ return 0 // preserve original order otherwise
117
+ })
118
+ .join(';')
127
119
  }
128
120
 
129
121
  // Logic is taken from cds-compile
@@ -161,7 +161,7 @@ module.exports = class HanaTemplate extends TemplateBase {
161
161
  }
162
162
  }
163
163
 
164
- _isUsingHana(modelName) {
165
- return this.env.get(`requires.${modelName}.kind`) === KIND_HANA || this.env.get(`requires.${modelName}.use`) === KIND_HANA;
164
+ _isUsingHana(db) {
165
+ return this.env.get(`requires.${db}.kind`) === KIND_HANA || this.env.get(`requires.${db}.dialect`) === KIND_HANA || this.env.get(`requires.${db}.use`) === KIND_HANA;
166
166
  }
167
167
  }
@@ -0,0 +1,4 @@
1
+ namespace my.bookshop;
2
+ entity Moon {
3
+ key ID : Integer;
4
+ }
@@ -0,0 +1,4 @@
1
+ namespace my.bookshop;
2
+ entity Moo {
3
+ key ID : Integer;
4
+ }
@@ -0,0 +1,10 @@
1
+ const path = require("path");
2
+ const rule = require("../../rules/no-entity-moo");
3
+ const { runRuleTester } = require("@sap/eslint-plugin-cds/lib/api");
4
+
5
+ runRuleTester({
6
+ root: path.resolve(__dirname),
7
+ rule,
8
+ filename: 'schema.cds',
9
+ errors: [{ message: "Entity 'Moo' not allowed!" }],
10
+ });
@@ -0,0 +1,6 @@
1
+ namespace my.bookshop;
2
+ entity Books {
3
+ key ID : Integer;
4
+ title : String;
5
+ stock : Integer;
6
+ }
@@ -52,26 +52,28 @@ module.exports = class LintTemplate extends TemplateBase {
52
52
  // Require local ESLint plugin installation and corresponding config
53
53
  this._checkEslintPlugin();
54
54
  this._addEslintPluginConfig();
55
- // Generate custom lint rules dirs
56
- await this._generateEslintDirs();
57
55
  // Include custom lint sample rule and test ('lint:dev')
58
56
  if (this.customRuleExample) {
57
+ // Generate custom lint rules dirs
58
+ await this._generateEslintDirs();
59
+
59
60
  if (!fs.existsSync(".eslint/rules/no-entity-moo.js")) {
60
61
  await this._copyFromTemplate(".eslint/rules", this.rulesPath);
61
62
  }
62
63
  if (!fs.existsSync(".eslint/tests/no-entity-moo.test.js")) {
63
64
  await this._copyFromTemplate(".eslint/tests", this.testsPath);
64
65
  }
66
+ // Generate custom lint rules docs
67
+ await generators.genDocs(this.projectPath);
65
68
  }
66
- // Generate custom lint rules docs
67
- await generators.genDocs(this.projectPath);
68
69
  }
69
70
 
70
71
  // Generate VS Code extension settings
71
72
  await io.sanitizeVscodeSettings(
72
73
  this.projectPath,
73
74
  path.join(this.projectPath, ".vscode/settings.json"),
74
- this.lintType
75
+ this.lintType,
76
+ this.customRuleExample
75
77
  );
76
78
  }
77
79
 
@@ -96,7 +98,7 @@ module.exports = class LintTemplate extends TemplateBase {
96
98
  this.missingNpmDependencies["msgs"].forEach((msg, i) => {
97
99
  this.logger.log(`(${i + 1}) ${msg}`);
98
100
  if (i === this.missingNpmDependencies["msgs"].length - 1) {
99
- this.logger.log('\n');
101
+ this.logger.log("\n");
100
102
  }
101
103
  });
102
104
 
@@ -331,7 +331,10 @@ module.exports = class ProjectReader {
331
331
 
332
332
  _hasHanaServiceBinding(env) {
333
333
  const kind = ProjectReader._getProperty(env, 'requires.db.kind')
334
- return kind === 'hana' || (kind === 'sql' && ProjectReader._getProperty(env, 'requires.db.use') === 'hana')
334
+ return kind === 'hana' || kind === 'sql' && (
335
+ ProjectReader._getProperty(env, 'requires.db.dialect') === 'hana' ||
336
+ ProjectReader._getProperty(env, 'requires.db.use') === 'hana'
337
+ )
335
338
  }
336
339
 
337
340
  _getReqResource(key, reqEntry, capDescriptor) {
@@ -359,7 +362,7 @@ module.exports = class ProjectReader {
359
362
  switch (reqEntry.kind) {
360
363
  case 'sql':
361
364
  case 'hana':
362
- if (reqEntry.kind === 'sql' && reqEntry.use !== 'hana') {
365
+ if (reqEntry.kind === 'sql' && reqEntry.dialect !== 'hana' && reqEntry.use !== 'hana') {
363
366
  break
364
367
  }
365
368
  // use different service name to avoid conflicts when switching from single tenant to multitenant
@@ -394,12 +397,12 @@ module.exports = class ProjectReader {
394
397
  }
395
398
 
396
399
  /**
397
- * Parse a given string containing xml
400
+ * Parse a given string containing xml
398
401
  * used to remove the _text object from converted json i.e. from xml-js.
399
402
  * example : converted json has "groupId":[{"_text":["customer"]}]
400
403
  * and after removing textAttributes (using this function): "groupId":["customer"]
401
404
  * @param xml string to parse
402
- * @returns parsed json object
405
+ * @returns parsed json object
403
406
  */
404
407
  async _parseXml(pomXmlPath) {
405
408
  const xmljs = require('xml-js');
@@ -426,7 +429,7 @@ module.exports = class ProjectReader {
426
429
  }
427
430
  }
428
431
 
429
- /*
432
+ /*
430
433
  Remove the _text attributes and convert value it into array
431
434
  input : "groupId":[{"_text":["customer"]}]
432
435
  output: "groupId":["customer"]
@@ -4,7 +4,7 @@
4
4
 
5
5
  // List of extensions which should be recommended for users of this workspace.
6
6
  "recommendations": [
7
- // >>>>>>>> Add CDS Editor here as soon it is available of vscode marketplace!,
7
+ "SAPSE.vscode-cds",
8
8
  "dbaeumer.vscode-eslint",
9
9
  "esbenp.prettier-vscode",
10
10
  "mechatroner.rainbow-csv",
@@ -1,7 +1,7 @@
1
1
  const path = require('path');
2
2
 
3
3
  const TemplateBase = require('../templateBase');
4
- const { COMMAND_ADD, OPTION_JAVA, OPTION_JAVA_MVN, OPTION_JAVA_PACKAGE, OPTION_NODEJS, URLS } = require('../../constants');
4
+ const { COMMAND_ADD, OPTION_JAVA, OPTION_NODEJS, URLS } = require('../../constants');
5
5
 
6
6
 
7
7
  module.exports = class NodeJSTemplate extends TemplateBase {
@@ -18,13 +18,6 @@ module.exports = class NodeJSTemplate extends TemplateBase {
18
18
  throw new Error(`Only one runtime per project is supported. Specify either ${OPTION_JAVA} or ${OPTION_NODEJS}.`);
19
19
  }
20
20
 
21
- if (this.options[OPTION_JAVA_PACKAGE]) {
22
- this.logger.warn(`Specified Java package will be ignored since project type is not Java. Use --add java to create project type Java.`);
23
- }
24
- if (this.options[OPTION_JAVA_MVN]) {
25
- this.logger.warn(`Specified Maven parameters will be ignored since project type is not Java. Use --add java to create project type Java.`);
26
- }
27
-
28
21
  return true;
29
22
  }
30
23
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const term = require('../../util/term');
4
4
  const cds = require('@sap/cds/lib');
5
- const LOG = cds.log('init');
5
+ const LOG = cds.log ? cds.log('init') : console;
6
6
 
7
7
  const defaultLogger = {
8
8
  isDebug: LOG._debug,
@@ -1,8 +1,6 @@
1
1
  const os = require("os");
2
2
  const fs = require("fs");
3
- const cp = require("child_process");
4
- const util = require("util");
5
- const execAsync = util.promisify(cp.exec);
3
+ const commandUtil = require("../init/util/commandUtil");
6
4
  const path = require("path");
7
5
  const glob = require("glob");
8
6
  const term = require("../util/term");
@@ -23,6 +21,7 @@ class Linter {
23
21
  this.eslintCmdOpts = {};
24
22
  this.eslintCmdOptsIndex = 0;
25
23
  this.eslintCmdFileExpr = "";
24
+ this.isFile = false;
26
25
  this.help = "";
27
26
  this.debug = "";
28
27
  this.flags = [];
@@ -71,7 +70,7 @@ class Linter {
71
70
  */
72
71
  async lint(args, options) {
73
72
  this.eslintCmdOpts = this._sanitizeUserOpts(options);
74
- this.eslintCmdFileExpr = args;
73
+ this.eslintCmdFileExpr = args.length ? args : ['.']
75
74
  if (this.eslintCmdOpts.help) {
76
75
  this._printHelp();
77
76
  } else {
@@ -96,16 +95,10 @@ class Linter {
96
95
  // Limit to CDS file extensions
97
96
  this._addExtensions();
98
97
  // Run ESLint with collected options
99
- let result = "";
100
98
  try {
101
- result = await this._runEslint();
99
+ await this._runEslint();
102
100
  } catch (err) {
103
- if (err.stdout) {
104
- console.log(err.stdout);
105
- }
106
- }
107
- if (result.stdout) {
108
- console.log(result.stdout);
101
+ term.error(err);
109
102
  }
110
103
  }
111
104
  }
@@ -150,10 +143,6 @@ class Linter {
150
143
  "ext",
151
144
  ".cds,.csn"
152
145
  );
153
- // Enable colored output
154
- if (process.stdout.isTTY) {
155
- this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
156
- }
157
146
  // Add custom CDS formatter
158
147
  const formatterPath = this.pluginPath.replace(
159
148
  "index.js",
@@ -164,72 +153,86 @@ class Linter {
164
153
  "format",
165
154
  path.relative(".", formatterPath)
166
155
  );
156
+ // Enable colored output
157
+ if (process.stdout.isTTY) {
158
+ this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
159
+ }
167
160
  return;
168
161
  }
169
162
 
170
163
  async _runEslint(dryRun = false) {
171
164
  const eslintCmdOpts = [];
172
165
  // Collect cmd line options
173
- for (let key in this.eslintCmdOpts) {
174
- let value = this.eslintCmdOpts[key];
175
- if (this.flags.includes(`--${key}`)) {
176
- eslintCmdOpts.push(`--${key}`);
177
- } else {
178
- if (value) {
166
+ try {
167
+ for (let key in this.eslintCmdOpts) {
168
+ let value = this.eslintCmdOpts[key];
169
+ if (this.flags.includes(`--${key}`)) {
179
170
  eslintCmdOpts.push(`--${key}`);
180
- // Always quote args which are not paths
181
- if (!fs.existsSync(value)) {
182
- eslintCmdOpts.push(`"${value}"`);
183
- // Paths are quoted according on os
184
- } else {
185
- if (IS_WIN) {
171
+ } else {
172
+ if (value) {
173
+ eslintCmdOpts.push(`--${key}`);
174
+ // Always quote args which are not paths
175
+ if (!fs.existsSync(value)) {
186
176
  eslintCmdOpts.push(`"${value}"`);
177
+ // Paths are quoted according on os
187
178
  } else {
188
- eslintCmdOpts.push(value);
179
+ if (IS_WIN) {
180
+ eslintCmdOpts.push(`"${value}"`);
181
+ } else {
182
+ eslintCmdOpts.push(value);
183
+ }
189
184
  }
190
185
  }
191
186
  }
192
187
  }
193
- }
194
- // Only lint file extensions prescribed by plugin
195
- const fileExtensions = getFileExtensions();
196
- eslintCmdOpts.push("--ignore-pattern");
197
- let ignorePattern = "*.*";
198
- if (IS_WIN) {
199
- ignorePattern = `"${ignorePattern}"`;
200
- }
201
- eslintCmdOpts.push(ignorePattern);
202
- fileExtensions.forEach((ext) => {
188
+ // Only lint file extensions prescribed by plugin
189
+ const fileExtensions = getFileExtensions();
203
190
  eslintCmdOpts.push("--ignore-pattern");
204
- ignorePattern = `!${ext}`;
191
+ let ignorePattern = "*.*";
205
192
  if (IS_WIN) {
206
193
  ignorePattern = `"${ignorePattern}"`;
194
+ } else {
195
+ ignorePattern = `'${ignorePattern}'`;
207
196
  }
208
197
  eslintCmdOpts.push(ignorePattern);
209
- });
210
- let input = '';
211
- if (IS_WIN) {
212
- input = `"${this.eslintCmdFileExpr.join('" "')}"`;
213
- }
214
- // Run ESLint with given cmd line options
215
- if (this.eslintCmdOpts.debug) {
216
- console.log(
217
- `Linting:\n ${term.info(
218
- `${this.eslintCmdShort} ${eslintCmdOpts.join(" ")} ${input}`
219
- )}`
220
- );
221
- }
222
- if (!dryRun) {
223
- return execAsync(
224
- `${this.eslintCmd} ${eslintCmdOpts.join(" ")} ${input}`,
225
- {
226
- cwd: process.cwd(),
227
- shell: IS_WIN,
228
- stdio: "inherit",
198
+ fileExtensions.forEach((ext) => {
199
+ eslintCmdOpts.push("--ignore-pattern");
200
+ ignorePattern = `!${ext}`;
201
+ if (IS_WIN) {
202
+ ignorePattern = `"${ignorePattern}"`;
203
+ } else {
204
+ ignorePattern = `'${ignorePattern}'`;
229
205
  }
230
- );
231
- } else {
232
- return Promise.resolve("");
206
+ eslintCmdOpts.push(ignorePattern);
207
+ });
208
+ let input = "";
209
+ if (IS_WIN) {
210
+ // Braucht es diese unterscheidung wirklich? Unterstützt Windows nicht auch single quotes?
211
+ input = `"${this.eslintCmdFileExpr.join('" "')}"`;
212
+ } else {
213
+ input = `'${this.eslintCmdFileExpr.join("' '")}'`;
214
+ }
215
+ const eslintCmdSplit = this.eslintCmd.split(" ");
216
+ this.eslintCmd = eslintCmdSplit[0];
217
+ eslintCmdOpts.unshift(eslintCmdSplit[1]);
218
+ eslintCmdOpts.push(input);
219
+ // Run ESLint with given cmd line options
220
+ if (this.eslintCmdOpts.debug) {
221
+ console.log(
222
+ `Linting:\n ${term.info(`${this.eslintCmd} ${eslintCmdOpts.join(' ')}`)}`
223
+ );
224
+ }
225
+ if (!dryRun) {
226
+ return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts, {
227
+ cwd: process.cwd(),
228
+ shell: true,
229
+ stdio: process.env.NODE_ENV === 'test' ? 'pipe' : 'inherit',
230
+ });
231
+ } else {
232
+ return Promise.resolve("");
233
+ }
234
+ } catch (err) {
235
+ return Promise.resolve(err);
233
236
  }
234
237
  }
235
238
 
@@ -244,8 +247,22 @@ class Linter {
244
247
 
245
248
  _getConfigFileAndSetProjectPath(args) {
246
249
  let input;
250
+ // Only resolve the first input argument
251
+ //
247
252
  if (args.length > 0) {
248
- input = glob.sync(args[0])[0]
253
+ let stats;
254
+ try {
255
+ stats = fs.statSync(args[0]);
256
+ } catch (err) {
257
+ // Do nothing
258
+ }
259
+ if (
260
+ args[0] === "." ||
261
+ (stats && (stats.isFile() || stats.isDirectory()))
262
+ ) {
263
+ this.isFile = true;
264
+ }
265
+ input = glob.sync(args[0])[0];
249
266
  }
250
267
  this.configPath = getConfigPath(input);
251
268
  if (!this.configPath) {
@@ -290,7 +307,7 @@ class Linter {
290
307
  this.esllintCmdOpts = io.mergeWithUserOpts(
291
308
  this.eslintCmdOpts,
292
309
  "rule",
293
- `${rule}: ${rules[rule]}`
310
+ `${rule}:${rules[rule]}`
294
311
  );
295
312
  }
296
313
  });
package/lib/lint/io.js CHANGED
@@ -172,10 +172,10 @@ module.exports = {
172
172
  * (3) "Global" case adds configFile and removes rulePaths
173
173
  * @param {*} settingsPath VS Code settings file
174
174
  */
175
- async sanitizeVscodeSettings(projectPath, settingsPath, lintType) {
175
+ async sanitizeVscodeSettings(projectPath, settingsPath, lintType, customRuleExample = false) {
176
176
  let settings = (await this.readVscodeSettings(settingsPath)) || {};
177
177
  const lintFileTypes = ["cds", "csn"];
178
- const rulePaths = [path.join(projectPath, ".eslint", "rules")];
178
+ const rulePaths = [path.join(".eslint/rules")];
179
179
  const configFile = path.join(__dirname, ".eslintrc.js");
180
180
 
181
181
  function _addArrayOrString(array) {
@@ -194,42 +194,18 @@ module.exports = {
194
194
  settings["eslint.validate"] = lintFileTypes;
195
195
  }
196
196
 
197
- switch (lintType) {
198
- case "local":
199
- if (settings["eslint.runtime"]) {
200
- delete settings["eslint.runtime"];
201
- }
202
- if (settings["eslint.nodePath"]) {
203
- delete settings["eslint.nodePath"];
204
- }
205
- if (settings["eslint.options"]) {
206
- if (settings["eslint.options"]["configFile"]) {
207
- delete settings["eslint.options"]["configFile"];
208
- }
197
+ if (lintType === "local") {
198
+ if (settings["eslint.options"]) {
199
+ if (customRuleExample) {
209
200
  settings["eslint.options"]["rulePaths"] = rulePaths;
210
- } else {
211
- settings["eslint.options"] = {
212
- rulePaths: rulePaths,
213
- };
214
201
  }
215
- break;
216
- case "global":
217
- settings["eslint.runtime"] = "node";
218
- settings["eslint.nodePath"] = path.join(__dirname, "../../node_modules");
219
- if (settings["eslint.options"]) {
220
- if (settings["eslint.options"]["rulePaths"]) {
221
- delete settings["eslint.options"]["rulePaths"];
222
- }
223
- settings["eslint.options"]["configFile"] =
224
- _addArrayOrString(configFile);
225
- } else {
202
+ } else {
203
+ if (customRuleExample) {
226
204
  settings["eslint.options"] = {
227
- configFile: _addArrayOrString(configFile),
205
+ rulePaths: rulePaths,
228
206
  };
229
207
  }
230
- break;
231
- default:
232
- break;
208
+ }
233
209
  }
234
210
 
235
211
  await this.writeVscodeSettings(settings, settingsPath);