@sap/cds-dk 4.5.0 → 4.6.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 (42) hide show
  1. package/CHANGELOG.md +65 -9
  2. package/bin/bind.js +124 -8
  3. package/bin/cds-ts.js +1 -1
  4. package/bin/cds.js +1 -0
  5. package/bin/deploy/index.js +2 -1
  6. package/bin/env.js +50 -9
  7. package/bin/help.js +2 -1
  8. package/bin/import.js +126 -24
  9. package/bin/watch.js +45 -9
  10. package/lib/bind/bindingResolver.js +138 -0
  11. package/lib/bind/cfKeyProvider.js +353 -0
  12. package/lib/bind/userCdsrcJsonStorageProvider.js +144 -0
  13. package/lib/client/auth_manager.js +4 -4
  14. package/lib/client/settings_manager.js +1 -1
  15. package/lib/import/common.js +33 -1
  16. package/lib/import/importapi.js +4 -3
  17. package/lib/import/index.js +49 -23
  18. package/lib/import/message.js +11 -6
  19. package/lib/import/utils/MetadataConverter.js +25 -4
  20. package/lib/import/utils/MetadataConverterFactory.js +1 -2
  21. package/lib/import/utils/MultiMap.js +26 -0
  22. package/lib/import/v2parser.js +142 -24
  23. package/lib/import/v4parser.js +222 -149
  24. package/lib/init/constants.js +1 -1
  25. package/lib/init/index.js +2 -0
  26. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +36 -52
  27. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +15 -0
  28. package/lib/init/template/lint/index.js +14 -6
  29. package/lib/init/template/mta/files/mta.yaml.hbs +0 -7
  30. package/lib/init/template/mtx/files/xs-security.json.hbs +3 -1
  31. package/lib/init/template/mtx/package/dependencies.package.json +1 -1
  32. package/lib/init/template/nodejs/files/.gitignore.hbs +3 -0
  33. package/lib/init/util/commandUtil.js +5 -0
  34. package/lib/lint/Linter.js +31 -20
  35. package/lib/lint/checks.js +5 -1
  36. package/lib/lint/generators.js +1 -1
  37. package/lib/lint/io.js +59 -35
  38. package/lib/util/term.js +2 -0
  39. package/lib/watch/node-watch.js +38 -19
  40. package/npm-shrinkwrap.json +1276 -1102
  41. package/package.json +4 -3
  42. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/test.js +0 -10
@@ -1,56 +1,40 @@
1
- const cdsLint = require("@sap/eslint-plugin-cds/lib/api");
2
-
3
- module.exports = cdsLint.createRule(
4
- // Rule meta data
5
- {
1
+ module.exports = require("@sap/eslint-plugin-cds/lib/api").createRule({
2
+ meta: {
6
3
  docs: {
7
- description: `Demonstrates how to implement a model validation check. This check does not allow any entities named 'Moo'.
8
-
9
- ________________________
10
- < No entity Moo allowed! >
11
- ------------------------
12
- \ ^__^
13
- \ (oo)\_______
14
- (__)\ )\/\
15
- ||----w |
16
- || ||`,
17
- category: "Model Validation",
4
+ description: `Demonstrates how to implement a model validation check.
5
+
6
+ __________________-_______
7
+ < Entity 'Moo' not allowed! >
8
+ --------------------------
9
+ \ ^__^
10
+ \ (oo)\_______
11
+ (__)\ )\/\
12
+ ||----w |
13
+ || ||`,
14
+ version: "1.0.0",
18
15
  },
19
16
  fixable: "code",
20
- type: "problem",
21
- version: "1.0.0",
22
17
  },
23
-
24
- // Rule (cds) logic
25
- (cds, context) => {
26
- let report = [];
27
-
28
- const filepath = context.getFilename();
29
- if (filepath.endsWith(".cds")) {
30
- // Always get model CSN from 'cds.model'
31
- const m = cds.reflect(cds.model);
32
-
33
- // Browse all entities of reflected model
34
- m.forall("entity", (d) => {
35
- // strip namespace from entity, assuming its name doesn't contain dots
36
- const entityName = d.name.split('.').pop()
37
-
38
- // If entity name is "Moo"
39
- if (entityName === "Moo") {
40
-
41
- // Get ESLint properties $loc
42
- const loc = cds.getLocation(entityName, d);
43
- const sourcecode = context.getSourceCode();
44
-
45
- // Apply fix by changing "Moo" to "Moon"
46
- const fix = (fixer) => {
47
- const rangeEnd = sourcecode.getIndexFromLoc({line: loc.end.line, column: loc.end.column});
48
- return fixer.insertTextAfterRange([0, rangeEnd], "n");
49
- };
50
- report.push({ message: "Entity 'Moo' not allowed!", loc, fix, file: d.$location.file });
51
- }
52
- });
53
- return report;
54
- }
55
- }
56
- );
18
+ create: function (context) {
19
+ const m = context.cds.model;
20
+ m.forall("entity", (d) => {
21
+ const entityName = d.name.split(".").pop();
22
+ if (entityName === "Moo") {
23
+ const loc = context.cds.getLocation(entityName, d);
24
+ const fix = (fixer) => {
25
+ const rangeEnd = context.sourcecode.getIndexFromLoc({
26
+ line: loc.end.line,
27
+ column: loc.end.column,
28
+ });
29
+ return fixer.insertTextAfterRange([0, rangeEnd], "n");
30
+ };
31
+ context.report({
32
+ message: "Entity 'Moo' not allowed!",
33
+ loc,
34
+ fix,
35
+ file: d.$location.file,
36
+ });
37
+ }
38
+ });
39
+ },
40
+ })
@@ -0,0 +1,15 @@
1
+ const { runRuleTester } = require("@sap/eslint-plugin-cds/lib/api");
2
+
3
+ runRuleTester({
4
+ root: __dirname,
5
+ filename: "schema.cds",
6
+ errors: [
7
+ {
8
+ message: "Entity 'Moo' not allowed!",
9
+ line: 2,
10
+ column: 8,
11
+ endLine: 2,
12
+ endColumn: 11,
13
+ },
14
+ ],
15
+ });
@@ -24,6 +24,7 @@ module.exports = class LintTemplate extends TemplateBase {
24
24
  this.lintType = "local";
25
25
  this.customRuleExample = false;
26
26
  this.missingNpmDependencies = { names: [], msgs: [] };
27
+ this.isTest = false;
27
28
  }
28
29
 
29
30
  async checkEnabled() {
@@ -45,13 +46,15 @@ module.exports = class LintTemplate extends TemplateBase {
45
46
  const globalPath = path.join(cdsdkPath, "../..");
46
47
 
47
48
  // Require ESLint v>=7.0.0
48
- this._checkEslint(globalPath);
49
+ if (!this.isTest) {
50
+ this._checkEslint(globalPath);
51
+ }
49
52
 
50
53
  // To enable custom lint rules ('lint' or 'lint:dev')
51
54
  if (this.lintType === "local") {
52
55
  // Require local ESLint plugin installation and corresponding config
53
56
  this._checkEslintPlugin();
54
- this._addEslintPluginConfig();
57
+ await this._addEslintPluginConfig();
55
58
  // Include custom lint sample rule and test ('lint:dev')
56
59
  if (this.customRuleExample) {
57
60
  // Generate custom lint rules dirs
@@ -101,15 +104,19 @@ module.exports = class LintTemplate extends TemplateBase {
101
104
  this.logger.log("\n");
102
105
  }
103
106
  });
104
-
105
107
  this._promptInstallDependencies(task);
106
108
  }
107
109
  }
108
110
  }
111
+
109
112
  }
110
113
 
111
114
  _checkEslint(globalPath) {
112
- const eslintCmd = checks.resolveEslint(this.projectPath, globalPath);
115
+ const eslintInfo = checks.resolveEslint(this.projectPath, globalPath);
116
+ let eslintCmd;
117
+ if (eslintInfo) {
118
+ eslintCmd = eslintInfo.cmd;
119
+ }
113
120
  if (!eslintCmd) {
114
121
  this.missingNpmDependencies["names"].push("eslint");
115
122
  this.missingNpmDependencies["msgs"].push("ESLint v>=7.0.0");
@@ -144,9 +151,10 @@ module.exports = class LintTemplate extends TemplateBase {
144
151
 
145
152
  async _addEslintPluginConfig() {
146
153
  let configPath = getConfigPath(this.projectPath, this.logger);
147
- if (configPath) {
148
- await io.sanitizeEslintConfig(configPath, this.customRuleExample);
154
+ if (!configPath) {
155
+ configPath = path.join(this.projectPath, ".eslintrc");
149
156
  }
157
+ await io.sanitizeEslintConfig(configPath, this.customRuleExample, this.logger);
150
158
  return;
151
159
  }
152
160
 
@@ -38,7 +38,6 @@ modules:
38
38
  {{#cap.isJava}}
39
39
  {{#cap.isMultitenant}}
40
40
  properties:
41
- SAP_JWT_TRUST_ACL: [{"clientid":"*","identityzone":"sap-provisioning"}] # Trust between server and SaaS Manager
42
41
  SPRING_PROFILES_ACTIVE: cloud
43
42
  {{/cap.isMultitenant}}
44
43
  {{^cap.isMultitenant}}
@@ -50,12 +49,6 @@ modules:
50
49
  commands: [ mvn clean package ]
51
50
  build-result: "target/*-exec.[wj]ar"
52
51
  {{/cap.isJava}}
53
- {{#cap.isNodejs}}
54
- {{#cap.isMultitenant}}
55
- properties:
56
- SAP_JWT_TRUST_ACL: [{"clientid":"*","identityzone":"sap-provisioning"}] # Trust between server and SaaS Manager
57
- {{/cap.isMultitenant}}
58
- {{/cap.isNodejs}}
59
52
  {{#cap.hasRequires}}
60
53
  requires:
61
54
  {{#cap.isJava}}
@@ -11,7 +11,9 @@
11
11
  ]}
12
12
  ],
13
13
  "authorities": [
14
- "$XSAPPNAME.MtxDiagnose"
14
+ "$XSAPPNAME.MtxDiagnose",
15
+ "$XSAPPNAME.mtdeployment",
16
+ "$XSAPPNAME.mtcallback"
15
17
  ],
16
18
  "role-templates": [
17
19
  {
@@ -3,7 +3,7 @@
3
3
  "@sap/cds-mtx": "^2",
4
4
  "@sap/hana-client": "^2",
5
5
  "@sap/hdi-deploy": "^4",
6
- "@sap/instance-manager": "^2",
6
+ "@sap/instance-manager": "^3",
7
7
  "@sap/xssec": "^3",
8
8
  "passport": "^0"
9
9
  }
@@ -3,6 +3,7 @@ _out
3
3
  *.db
4
4
  connection.properties
5
5
  default-*.json
6
+ .cdsrc-private.json
6
7
  gen/
7
8
  node_modules/
8
9
  target/
@@ -27,3 +28,5 @@ mta_archives/
27
28
  # IDEs
28
29
  # .vscode
29
30
  # .idea
31
+
32
+ .cdsrc-private.json
@@ -50,12 +50,17 @@ class CommandUtil {
50
50
  resolve(stdLogBuffer.getResult());
51
51
  } else {
52
52
  const errorLog = errLogBuffer.getResult();
53
+
53
54
  const error = new Error(`${cmd} ${args.join(' ')} failed with code ${code}, ${errorLog}`)
54
55
  // add code ENOENT on Win if command not found
55
56
  if (IS_WIN && errorLog.includes(cmd) && /not recognized/i.exec(errorLog)) {
56
57
  error.code = 'ENOENT';
57
58
  error.path = cmd;
58
59
  }
60
+
61
+ error.errLog = errorLog;
62
+ error.stdLog = stdLogBuffer.getResult();
63
+
59
64
  reject(error);
60
65
  }
61
66
  });
@@ -21,6 +21,7 @@ class Linter {
21
21
  this.eslintCmdOpts = {};
22
22
  this.eslintCmdOptsIndex = 0;
23
23
  this.eslintCmdFileExpr = "";
24
+ this.formatter = false;
24
25
  this.isFile = false;
25
26
  this.help = "";
26
27
  this.debug = "";
@@ -44,7 +45,11 @@ class Linter {
44
45
  * @returns object continaing help, options, flags and shortcuts
45
46
  */
46
47
  init(help = "", options = [], flags = [], shortcuts = []) {
47
- this.eslintCmd = checks.resolveEslint(this.cdsdkPath, this.globalPath);
48
+ const eslintInfo = checks.resolveEslint(this.cdsdkPath, this.globalPath);
49
+ if (eslintInfo) {
50
+ this.eslintCmd = eslintInfo.cmd;
51
+ }
52
+ this.addFormatter = eslintInfo.addFormatter;
48
53
  if (this.eslintCmd) {
49
54
  help = generators.genEslintHelp(this.eslintCmd);
50
55
  flags = generators.genEslintFlags(help);
@@ -75,7 +80,7 @@ class Linter {
75
80
  this._printHelp();
76
81
  } else {
77
82
  // Determine if case "local" or "global" and resolve plugin accordingly
78
- this._getConfigFileAndSetProjectPath(args);
83
+ await this._getConfigFileAndSetProjectPath(args);
79
84
 
80
85
  if (this.lintType === "local") {
81
86
  await this._addRulePaths();
@@ -88,12 +93,12 @@ class Linter {
88
93
  "rules"
89
94
  );
90
95
  if (overwriteRules) {
91
- this._overwriteRuleSeverities();
96
+ await this._overwriteRuleSeverities();
92
97
  }
93
98
  }
94
99
 
95
100
  // Limit to CDS file extensions
96
- this._addExtensions();
101
+ this._addExtensions(this.addFormatter);
97
102
  // Run ESLint with collected options
98
103
  try {
99
104
  await this._runEslint();
@@ -136,23 +141,25 @@ class Linter {
136
141
  return;
137
142
  }
138
143
 
139
- _addExtensions() {
144
+ _addExtensions(addFormatter) {
140
145
  // Add CDS file extensions to lint
141
146
  this.eslintCmdOpts = io.mergeWithUserOpts(
142
147
  this.eslintCmdOpts,
143
148
  "ext",
144
149
  ".cds,.csn"
145
150
  );
146
- // Add custom CDS formatter
147
- const formatterPath = this.pluginPath.replace(
148
- "index.js",
149
- "../api/formatter.js"
150
- );
151
- this.eslintCmdOpts = io.mergeWithUserOpts(
152
- this.eslintCmdOpts,
153
- "format",
154
- path.relative(".", formatterPath)
155
- );
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
+ }
156
163
  // Enable colored output
157
164
  if (process.stdout.isTTY) {
158
165
  this.eslintCmdOpts = io.mergeWithUserOpts(this.eslintCmdOpts, "color");
@@ -217,10 +224,14 @@ class Linter {
217
224
  eslintCmdOpts.unshift(eslintCmdSplit[1]);
218
225
  eslintCmdOpts.push(input);
219
226
  // Run ESLint with given cmd line options
227
+ // - Show 'eslint' instead of 'node ...eslint.js' cmd
228
+ // - Remove debug flag for printed cmd
220
229
  if (this.eslintCmdOpts.debug) {
230
+ eslintCmdOpts.splice(eslintCmdOpts.indexOf('--debug'), 1);
221
231
  console.log(
222
- `Linting:\n ${term.info(`${this.eslintCmd} ${eslintCmdOpts.join(' ')}`)}`
232
+ `Linting:\n ${term.info(`eslint ${eslintCmdOpts.slice(1).join(' ')}`)}\n`
223
233
  );
234
+ eslintCmdOpts.push('--debug');
224
235
  }
225
236
  if (!dryRun) {
226
237
  return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts, {
@@ -245,7 +256,7 @@ class Linter {
245
256
  return;
246
257
  }
247
258
 
248
- _getConfigFileAndSetProjectPath(args) {
259
+ async _getConfigFileAndSetProjectPath(args) {
249
260
  let input;
250
261
  // Only resolve the first input argument
251
262
  //
@@ -269,7 +280,7 @@ class Linter {
269
280
  this.configPath = this.configGlobalPath;
270
281
  this.lintType === "global";
271
282
  } else {
272
- this.configContents = io.readEslintConfig(this.configPath);
283
+ this.configContents = await io.readEslintConfig(this.configPath);
273
284
  if (this.configContents) {
274
285
  if ("extends" in this.configContents) {
275
286
  this.extendsPlugin = checks.hasEslintConfigContent(
@@ -295,8 +306,8 @@ class Linter {
295
306
  return;
296
307
  }
297
308
 
298
- _overwriteRuleSeverities() {
299
- let configContents = io.readEslintConfig(this.configPath) || {};
309
+ async _overwriteRuleSeverities() {
310
+ let configContents = (await io.readEslintConfig(this.configPath)) || {};
300
311
  let rules = configContents.rules;
301
312
  // Allow recommended plugin rules in cds-dk to be overwritten
302
313
  // by user by adding rule to cmd line (because of precedence)
@@ -21,6 +21,7 @@ module.exports = {
21
21
  let cmd;
22
22
  let version;
23
23
  let errMessage;
24
+ let addFormatter = false;
24
25
  try {
25
26
  const eslintPath = require.resolve("eslint/package.json", {
26
27
  paths: [inputPath, globalPath],
@@ -28,6 +29,9 @@ module.exports = {
28
29
  const packageJson = require(eslintPath);
29
30
  if (packageJson.version > "7") {
30
31
  version = packageJson.version;
32
+ if (version < "8") {
33
+ addFormatter = true;
34
+ }
31
35
  } else {
32
36
  errMessage =
33
37
  `ESLint v>=6.0.0 required!\n\n` +
@@ -51,7 +55,7 @@ module.exports = {
51
55
  )}\n`;
52
56
  }
53
57
  if (cmd && version) {
54
- return cmd;
58
+ return { cmd, addFormatter };
55
59
  }
56
60
  if (logger) {
57
61
  logger.error(errMessage);
@@ -36,7 +36,7 @@ module.exports = {
36
36
  eslintOpts[0] = `
37
37
  # SYNOPSIS
38
38
 
39
- ${cdslintCmd}
39
+ ${cdslintCmd} [beta]
40
40
 
41
41
  Runs environment checks and/or checks the specified models
42
42
  based on the ESLint framework
package/lib/lint/io.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const os = require("os");
2
- const fs = require("fs");
2
+ const fsp = require("fs").promises;
3
3
  const path = require("path");
4
4
  const yaml = require("@sap/cds-foss")("yaml");
5
+ const term = require("../util/term");
5
6
  const FsUtil = require("../init/util/fsUtil");
6
7
  const fsUtil = new FsUtil();
7
8
 
@@ -13,23 +14,28 @@ module.exports = {
13
14
  * @param {*} configPath config file path to read from
14
15
  * @returns config file contents
15
16
  */
16
- readEslintConfig(configPath) {
17
+ async readEslintConfig(configPath) {
17
18
  let config;
18
19
  let configFile = path.basename(configPath);
20
+ let configString = await fsp.readFile(configPath, "utf8");
19
21
  switch (configFile) {
20
22
  case ".eslintrc.js":
21
23
  case ".eslintrc.cjs":
22
- config = require(configPath);
24
+ try {
25
+ config = JSON.parse(configString.replace(/^module\.exports =/, ""));
26
+ } catch (err) {
27
+ config = {};
28
+ }
23
29
  break;
24
30
  case ".eslintrc.yaml":
25
31
  case ".eslintrc.yml":
26
- config = yaml.parse(fs.readFileSync(configPath, "utf8"));
32
+ config = yaml.parse(await fsp.readFile(configPath, "utf8"));
27
33
  break;
28
34
  case ".eslintrc.json":
29
35
  case ".eslintrc":
30
36
  case "package.json":
31
37
  try {
32
- config = JSON.parse(fs.readFileSync(configPath, "utf8"));
38
+ config = JSON.parse(await fsp.readFile(configPath, "utf8"));
33
39
  if (configFile === "package.json" && "eslintConfig" in config) {
34
40
  config = config["eslintConfig"];
35
41
  }
@@ -52,8 +58,11 @@ module.exports = {
52
58
  * @param {*} configPath ESLint config file
53
59
  * @returns {void}
54
60
  */
55
- async sanitizeEslintConfig(configPath, customRuleExample=false) {
56
- let configContents = this.readEslintConfig(configPath) || {};
61
+ async sanitizeEslintConfig(configPath, customRuleExample = false, logger = console) {
62
+ let configContents = {};
63
+ if (await fsUtil.pathExists(configPath)) {
64
+ configContents = (await this.readEslintConfig(configPath)) || {};
65
+ }
57
66
  const configType = "recommended";
58
67
  const extendsValue = `plugin:@sap/cds/${configType}`;
59
68
  if ("extends" in configContents) {
@@ -79,7 +88,7 @@ module.exports = {
79
88
  configContents["rules"] = { [ruleName]: ruleValue };
80
89
  }
81
90
  }
82
- await this.writeEslintConfig(configContents, configPath);
91
+ await this.writeEslintConfig(configPath, configContents, logger);
83
92
  return;
84
93
  },
85
94
 
@@ -89,16 +98,37 @@ module.exports = {
89
98
  * @param {*} configPath config file path to write to
90
99
  * @returns {void}
91
100
  */
92
- async writeEslintConfig(configContents, configPath) {
101
+ async writeEslintConfig(configPath, configContents, logger=console) {
102
+ const configType = "recommended";
103
+ const extendsValue = `plugin:@sap/cds/${configType}`;
93
104
  let contents = {};
94
105
  let configFile = path.basename(configPath);
106
+ let configToAdd = {};
95
107
  switch (configFile) {
96
108
  case ".eslintrc.js":
97
109
  case ".eslintrc.cjs":
98
- await fsUtil.writeFile(
99
- configPath,
100
- `module.exports = ${JSON.stringify(configContents, null, 2)}`
101
- );
110
+ try {
111
+ configContents = await this.readEslintConfig(configPath);
112
+ } catch (err) {
113
+ configContents = {};
114
+ }
115
+ if (configContents && configContents["extends"]) {
116
+ if (
117
+ !configContents["extends"] === extendsValue ||
118
+ !configContents["extends"].includes(extendsValue)
119
+ ) {
120
+ configToAdd["extends"] = extendsValue;
121
+ }
122
+ } else {
123
+ configToAdd["extends"] = extendsValue;
124
+ }
125
+ if (configToAdd["extends"]) {
126
+ logger.log(
127
+ `${term.warn(
128
+ `\n\nPlease add the following to your "${configFile}":\n\nmodule.exports = ${JSON.stringify(configToAdd, null, 2)}`
129
+ )}\n`
130
+ );
131
+ }
102
132
  break;
103
133
  case ".eslintrc.yaml":
104
134
  case ".eslintrc.yml":
@@ -108,25 +138,19 @@ module.exports = {
108
138
  case ".eslintrc":
109
139
  case "package.json":
110
140
  if (configFile === "package.json") {
111
- if (fs.existsSync(configPath)) {
112
- contents = JSON.parse(fs.readFileSync(configPath, "utf8"));
141
+ if (await fsp.access(configPath)) {
142
+ contents = JSON.parse(await fsp.readFile(configPath, "utf8"));
113
143
  } else {
114
144
  contents = {};
115
145
  }
116
146
  if (!("eslintConfig" in configContents)) {
117
147
  contents["eslintConfig"] = configContents;
118
148
  } else {
119
- contents["eslintConfig"] = [
120
- ...configContents,
121
- ...contents["eslintConfig"],
122
- ];
149
+ contents["eslintConfig"] = [...configContents, ...contents["eslintConfig"]];
123
150
  }
124
151
  configContents = contents;
125
152
  }
126
- await fsUtil.writeFile(
127
- configPath,
128
- `${JSON.stringify(configContents, null, 2)}`
129
- );
153
+ await fsUtil.writeFile(configPath, `${JSON.stringify(configContents, null, 2)}`);
130
154
  break;
131
155
  default:
132
156
  break;
@@ -141,8 +165,12 @@ module.exports = {
141
165
  */
142
166
  async readVscodeSettings(settingsPath) {
143
167
  let settings;
144
- if (fs.existsSync(settingsPath)) {
145
- settings = await fsUtil.readJSONC(settingsPath);
168
+ if (fsUtil.pathExists(settingsPath)) {
169
+ try {
170
+ settings = await fsUtil.readJSONC(settingsPath);
171
+ } catch (err) {
172
+ settings = {};
173
+ }
146
174
  }
147
175
  return settings;
148
176
  },
@@ -186,10 +214,7 @@ module.exports = {
186
214
  }
187
215
 
188
216
  if (settings["eslint.validate"]) {
189
- settings["eslint.validate"] = this.mergeArrays(
190
- settings["eslint.validate"],
191
- lintFileTypes
192
- );
217
+ settings["eslint.validate"] = this.mergeArrays(settings["eslint.validate"], lintFileTypes);
193
218
  } else {
194
219
  settings["eslint.validate"] = lintFileTypes;
195
220
  }
@@ -208,7 +233,7 @@ module.exports = {
208
233
  }
209
234
  }
210
235
 
211
- await this.writeVscodeSettings(settings, settingsPath);
236
+ await this.writeVscodeSettings(settingsPath, settings);
212
237
  },
213
238
 
214
239
  /**
@@ -217,7 +242,7 @@ module.exports = {
217
242
  * @param {*} settingsPath settings file path to write to
218
243
  * @returns {void}
219
244
  */
220
- async writeVscodeSettings(settings, settingsPath) {
245
+ async writeVscodeSettings(settingsPath, settings) {
221
246
  if (!settings) {
222
247
  await fsUtil.mkdirp(path.dirname(settingsPath));
223
248
  }
@@ -236,10 +261,9 @@ module.exports = {
236
261
  if (propsToAdd) {
237
262
  if (Object.keys(userOpts).includes(propKey)) {
238
263
  if (!["config", "format"].includes(propKey)) {
239
- propsToAdd = this.mergeArrays(
240
- userOpts[propKey].split(","),
241
- propsToAdd.split(",")
242
- ).join(",");
264
+ propsToAdd = this.mergeArrays(userOpts[propKey].split(","), propsToAdd.split(",")).join(
265
+ ","
266
+ );
243
267
  }
244
268
  }
245
269
  userOpts[propKey] = propsToAdd;
package/lib/util/term.js CHANGED
@@ -8,6 +8,7 @@ const t = module.exports.codes = {
8
8
  link: '\x1b[4m', // underline
9
9
  red: '\x1b[91m', // Bright Foreground Red
10
10
  green: '\x1b[32m', // Foreground Green
11
+ blue: '\x1b[34m', // Foreground Blue
11
12
  orange: '\x1b[38;2;255;140;0m' // darker orange, works with bright and dark background
12
13
  }
13
14
 
@@ -24,6 +25,7 @@ module.exports.warn = o => as(t.orange, o)
24
25
  module.exports.info = o => as(t.green, o)
25
26
  module.exports.link = o => as(t.link, o)
26
27
  module.exports.bold = o => as(t.bold, o)
28
+ module.exports.highlight = o => as(t.blue,as(t.bold, o))
27
29
 
28
30
  const format = module.exports.format = (o, severity='Error', asInternalError=false, withStack=false) => {
29
31
  switch (severity) {