@sap/cds-dk 4.5.2 → 4.6.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +55 -0
  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/compile/index.js +2 -1
  6. package/bin/env.js +50 -9
  7. package/bin/help.js +1 -0
  8. package/bin/import.js +38 -18
  9. package/bin/repl.js +6 -2
  10. package/bin/watch.js +58 -13
  11. package/lib/bind/bindingResolver.js +138 -0
  12. package/lib/bind/cfKeyProvider.js +353 -0
  13. package/lib/bind/userCdsrcJsonStorageProvider.js +144 -0
  14. package/lib/client/auth_manager.js +4 -4
  15. package/lib/client/settings_manager.js +6 -5
  16. package/lib/import/common.js +10 -1
  17. package/lib/import/importapi.js +4 -3
  18. package/lib/import/index.js +34 -5
  19. package/lib/import/message.js +2 -1
  20. package/lib/import/utils/MetadataConverter.js +25 -4
  21. package/lib/import/utils/MetadataConverterFactory.js +1 -2
  22. package/lib/import/utils/MultiMap.js +26 -0
  23. package/lib/import/v2parser.js +131 -12
  24. package/lib/import/v4parser.js +214 -168
  25. package/lib/init/constants.js +1 -1
  26. package/lib/init/index.js +2 -0
  27. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +36 -52
  28. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +15 -0
  29. package/lib/init/template/lint/index.js +19 -17
  30. package/lib/init/template/mta/files/mta.yaml.hbs +0 -7
  31. package/lib/init/template/mtx/files/xs-security.json.hbs +3 -1
  32. package/lib/init/template/mtx/package/dependencies.package.json +1 -1
  33. package/lib/init/template/nodejs/files/.gitignore.hbs +1 -0
  34. package/lib/init/util/commandUtil.js +5 -0
  35. package/lib/lint/Linter.js +17 -20
  36. package/lib/lint/generators.js +5 -4
  37. package/lib/lint/io.js +62 -36
  38. package/lib/util/term.js +2 -0
  39. package/lib/watch/node-watch.js +38 -19
  40. package/npm-shrinkwrap.json +1485 -1959
  41. package/package.json +3 -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() {
@@ -41,17 +42,16 @@ module.exports = class LintTemplate extends TemplateBase {
41
42
  }
42
43
 
43
44
  async run() {
44
- const cdsdkPath = path.join(__dirname, "../../../..");
45
- const globalPath = path.join(cdsdkPath, "../..");
46
-
47
45
  // Require ESLint v>=7.0.0
48
- this._checkEslint(globalPath);
46
+ if (!this.isTest) {
47
+ this._checkEslint();
48
+ }
49
49
 
50
50
  // To enable custom lint rules ('lint' or 'lint:dev')
51
51
  if (this.lintType === "local") {
52
52
  // Require local ESLint plugin installation and corresponding config
53
53
  this._checkEslintPlugin();
54
- this._addEslintPluginConfig();
54
+ await this._addEslintPluginConfig();
55
55
  // Include custom lint sample rule and test ('lint:dev')
56
56
  if (this.customRuleExample) {
57
57
  // Generate custom lint rules dirs
@@ -66,15 +66,16 @@ module.exports = class LintTemplate extends TemplateBase {
66
66
  // Generate custom lint rules docs
67
67
  await generators.genDocs(this.projectPath);
68
68
  }
69
+
70
+ // Generate VS Code extension settings
71
+ await io.sanitizeVscodeSettings(
72
+ this.projectPath,
73
+ path.join(this.projectPath, ".vscode/settings.json"),
74
+ this.lintType,
75
+ this.customRuleExample
76
+ );
69
77
  }
70
78
 
71
- // Generate VS Code extension settings
72
- await io.sanitizeVscodeSettings(
73
- this.projectPath,
74
- path.join(this.projectPath, ".vscode/settings.json"),
75
- this.lintType,
76
- this.customRuleExample
77
- );
78
79
  }
79
80
 
80
81
  async finalize() {
@@ -101,15 +102,15 @@ module.exports = class LintTemplate extends TemplateBase {
101
102
  this.logger.log("\n");
102
103
  }
103
104
  });
104
-
105
105
  this._promptInstallDependencies(task);
106
106
  }
107
107
  }
108
108
  }
109
+
109
110
  }
110
111
 
111
- _checkEslint(globalPath) {
112
- const eslintCmd = checks.resolveEslint(this.projectPath, globalPath);
112
+ _checkEslint() {
113
+ const eslintCmd = checks.resolveEslint(this.projectPath, '');
113
114
  if (!eslintCmd) {
114
115
  this.missingNpmDependencies["names"].push("eslint");
115
116
  this.missingNpmDependencies["msgs"].push("ESLint v>=7.0.0");
@@ -144,9 +145,10 @@ module.exports = class LintTemplate extends TemplateBase {
144
145
 
145
146
  async _addEslintPluginConfig() {
146
147
  let configPath = getConfigPath(this.projectPath, this.logger);
147
- if (configPath) {
148
- await io.sanitizeEslintConfig(configPath, this.customRuleExample);
148
+ if (!configPath) {
149
+ configPath = path.join(this.projectPath, ".eslintrc");
149
150
  }
151
+ await io.sanitizeEslintConfig(configPath, this.customRuleExample, this.logger);
150
152
  return;
151
153
  }
152
154
 
@@ -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/
@@ -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
  });
@@ -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 = "";
@@ -21,6 +23,7 @@ class Linter {
21
23
  this.eslintCmdOpts = {};
22
24
  this.eslintCmdOptsIndex = 0;
23
25
  this.eslintCmdFileExpr = "";
26
+ this.formatter = false;
24
27
  this.isFile = false;
25
28
  this.help = "";
26
29
  this.debug = "";
@@ -75,7 +78,7 @@ class Linter {
75
78
  this._printHelp();
76
79
  } else {
77
80
  // Determine if case "local" or "global" and resolve plugin accordingly
78
- this._getConfigFileAndSetProjectPath(args);
81
+ await this._getConfigFileAndSetProjectPath(args);
79
82
 
80
83
  if (this.lintType === "local") {
81
84
  await this._addRulePaths();
@@ -88,7 +91,7 @@ class Linter {
88
91
  "rules"
89
92
  );
90
93
  if (overwriteRules) {
91
- this._overwriteRuleSeverities();
94
+ await this._overwriteRuleSeverities();
92
95
  }
93
96
  }
94
97
 
@@ -138,20 +141,11 @@ class Linter {
138
141
 
139
142
  _addExtensions() {
140
143
  // Add CDS file extensions to lint
144
+ const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => ext.replace('*.', '.'));
141
145
  this.eslintCmdOpts = io.mergeWithUserOpts(
142
146
  this.eslintCmdOpts,
143
147
  "ext",
144
- ".cds,.csn"
145
- );
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)
148
+ extensions.join(',')
155
149
  );
156
150
  // Enable colored output
157
151
  if (process.stdout.isTTY) {
@@ -186,7 +180,6 @@ class Linter {
186
180
  }
187
181
  }
188
182
  // Only lint file extensions prescribed by plugin
189
- const fileExtensions = getFileExtensions();
190
183
  eslintCmdOpts.push("--ignore-pattern");
191
184
  let ignorePattern = "*.*";
192
185
  if (IS_WIN) {
@@ -195,7 +188,7 @@ class Linter {
195
188
  ignorePattern = `'${ignorePattern}'`;
196
189
  }
197
190
  eslintCmdOpts.push(ignorePattern);
198
- fileExtensions.forEach((ext) => {
191
+ ALLOWED_FILE_EXTENSIONS.forEach((ext) => {
199
192
  eslintCmdOpts.push("--ignore-pattern");
200
193
  ignorePattern = `!${ext}`;
201
194
  if (IS_WIN) {
@@ -217,10 +210,14 @@ class Linter {
217
210
  eslintCmdOpts.unshift(eslintCmdSplit[1]);
218
211
  eslintCmdOpts.push(input);
219
212
  // Run ESLint with given cmd line options
213
+ // - Show 'eslint' instead of 'node ...eslint.js' cmd
214
+ // - Remove debug flag for printed cmd
220
215
  if (this.eslintCmdOpts.debug) {
216
+ eslintCmdOpts.splice(eslintCmdOpts.indexOf('--debug'), 1);
221
217
  console.log(
222
- `Linting:\n ${term.info(`${this.eslintCmd} ${eslintCmdOpts.join(' ')}`)}`
218
+ `Linting:\n ${term.info(`eslint ${eslintCmdOpts.slice(1).join(' ')}`)}\n`
223
219
  );
220
+ eslintCmdOpts.push('--debug');
224
221
  }
225
222
  if (!dryRun) {
226
223
  return commandUtil.spawnCommand(this.eslintCmd, eslintCmdOpts, {
@@ -245,7 +242,7 @@ class Linter {
245
242
  return;
246
243
  }
247
244
 
248
- _getConfigFileAndSetProjectPath(args) {
245
+ async _getConfigFileAndSetProjectPath(args) {
249
246
  let input;
250
247
  // Only resolve the first input argument
251
248
  //
@@ -269,7 +266,7 @@ class Linter {
269
266
  this.configPath = this.configGlobalPath;
270
267
  this.lintType === "global";
271
268
  } else {
272
- this.configContents = io.readEslintConfig(this.configPath);
269
+ this.configContents = await io.readEslintConfig(this.configPath);
273
270
  if (this.configContents) {
274
271
  if ("extends" in this.configContents) {
275
272
  this.extendsPlugin = checks.hasEslintConfigContent(
@@ -295,8 +292,8 @@ class Linter {
295
292
  return;
296
293
  }
297
294
 
298
- _overwriteRuleSeverities() {
299
- let configContents = io.readEslintConfig(this.configPath) || {};
295
+ async _overwriteRuleSeverities() {
296
+ let configContents = (await io.readEslintConfig(this.configPath)) || {};
300
297
  let rules = configContents.rules;
301
298
  // Allow recommended plugin rules in cds-dk to be overwritten
302
299
  // by user by adding rule to cmd line (because of precedence)
@@ -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
  */
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) {
@@ -62,7 +71,9 @@ module.exports = {
62
71
  configContents["extends"].push(extendsValue);
63
72
  }
64
73
  } else {
65
- configContents["extends"] = [configContents["extends"], extendsValue];
74
+ if (configContents["extends"] !== extendsValue) {
75
+ configContents["extends"] = [configContents["extends"], extendsValue];
76
+ }
66
77
  }
67
78
  } else {
68
79
  configContents["extends"] = extendsValue;
@@ -79,7 +90,7 @@ module.exports = {
79
90
  configContents["rules"] = { [ruleName]: ruleValue };
80
91
  }
81
92
  }
82
- await this.writeEslintConfig(configContents, configPath);
93
+ await this.writeEslintConfig(configPath, configContents, logger);
83
94
  return;
84
95
  },
85
96
 
@@ -89,16 +100,37 @@ module.exports = {
89
100
  * @param {*} configPath config file path to write to
90
101
  * @returns {void}
91
102
  */
92
- async writeEslintConfig(configContents, configPath) {
103
+ async writeEslintConfig(configPath, configContents, logger=console) {
104
+ const configType = "recommended";
105
+ const extendsValue = `plugin:@sap/cds/${configType}`;
93
106
  let contents = {};
94
107
  let configFile = path.basename(configPath);
108
+ let configToAdd = {};
95
109
  switch (configFile) {
96
110
  case ".eslintrc.js":
97
111
  case ".eslintrc.cjs":
98
- await fsUtil.writeFile(
99
- configPath,
100
- `module.exports = ${JSON.stringify(configContents, null, 2)}`
101
- );
112
+ try {
113
+ configContents = await this.readEslintConfig(configPath);
114
+ } catch (err) {
115
+ configContents = {};
116
+ }
117
+ if (configContents && configContents["extends"]) {
118
+ if (
119
+ !configContents["extends"] === extendsValue ||
120
+ !configContents["extends"].includes(extendsValue)
121
+ ) {
122
+ configToAdd["extends"] = extendsValue;
123
+ }
124
+ } else {
125
+ configToAdd["extends"] = extendsValue;
126
+ }
127
+ if (configToAdd["extends"]) {
128
+ logger.log(
129
+ `${term.warn(
130
+ `\n\nPlease add the following to your "${configFile}":\n\nmodule.exports = ${JSON.stringify(configToAdd, null, 2)}`
131
+ )}\n`
132
+ );
133
+ }
102
134
  break;
103
135
  case ".eslintrc.yaml":
104
136
  case ".eslintrc.yml":
@@ -108,25 +140,19 @@ module.exports = {
108
140
  case ".eslintrc":
109
141
  case "package.json":
110
142
  if (configFile === "package.json") {
111
- if (fs.existsSync(configPath)) {
112
- contents = JSON.parse(fs.readFileSync(configPath, "utf8"));
143
+ if (await fsUtil.pathExists(configPath)) {
144
+ contents = JSON.parse(await fsp.readFile(configPath, "utf8"));
113
145
  } else {
114
146
  contents = {};
115
147
  }
116
148
  if (!("eslintConfig" in configContents)) {
117
149
  contents["eslintConfig"] = configContents;
118
150
  } else {
119
- contents["eslintConfig"] = [
120
- ...configContents,
121
- ...contents["eslintConfig"],
122
- ];
151
+ contents["eslintConfig"] = [...configContents, ...contents["eslintConfig"]];
123
152
  }
124
153
  configContents = contents;
125
154
  }
126
- await fsUtil.writeFile(
127
- configPath,
128
- `${JSON.stringify(configContents, null, 2)}`
129
- );
155
+ await fsUtil.writeFile(configPath, `${JSON.stringify(configContents, null, 2)}`);
130
156
  break;
131
157
  default:
132
158
  break;
@@ -141,8 +167,12 @@ module.exports = {
141
167
  */
142
168
  async readVscodeSettings(settingsPath) {
143
169
  let settings;
144
- if (fs.existsSync(settingsPath)) {
145
- settings = await fsUtil.readJSONC(settingsPath);
170
+ if (fsUtil.pathExists(settingsPath)) {
171
+ try {
172
+ settings = await fsUtil.readJSONC(settingsPath);
173
+ } catch (err) {
174
+ settings = {};
175
+ }
146
176
  }
147
177
  return settings;
148
178
  },
@@ -186,10 +216,7 @@ module.exports = {
186
216
  }
187
217
 
188
218
  if (settings["eslint.validate"]) {
189
- settings["eslint.validate"] = this.mergeArrays(
190
- settings["eslint.validate"],
191
- lintFileTypes
192
- );
219
+ settings["eslint.validate"] = this.mergeArrays(settings["eslint.validate"], lintFileTypes);
193
220
  } else {
194
221
  settings["eslint.validate"] = lintFileTypes;
195
222
  }
@@ -208,7 +235,7 @@ module.exports = {
208
235
  }
209
236
  }
210
237
 
211
- await this.writeVscodeSettings(settings, settingsPath);
238
+ await this.writeVscodeSettings(settingsPath, settings);
212
239
  },
213
240
 
214
241
  /**
@@ -217,7 +244,7 @@ module.exports = {
217
244
  * @param {*} settingsPath settings file path to write to
218
245
  * @returns {void}
219
246
  */
220
- async writeVscodeSettings(settings, settingsPath) {
247
+ async writeVscodeSettings(settingsPath, settings) {
221
248
  if (!settings) {
222
249
  await fsUtil.mkdirp(path.dirname(settingsPath));
223
250
  }
@@ -236,10 +263,9 @@ module.exports = {
236
263
  if (propsToAdd) {
237
264
  if (Object.keys(userOpts).includes(propKey)) {
238
265
  if (!["config", "format"].includes(propKey)) {
239
- propsToAdd = this.mergeArrays(
240
- userOpts[propKey].split(","),
241
- propsToAdd.split(",")
242
- ).join(",");
266
+ propsToAdd = this.mergeArrays(userOpts[propKey].split(","), propsToAdd.split(",")).join(
267
+ ","
268
+ );
243
269
  }
244
270
  }
245
271
  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) {