@sap/eslint-plugin-cds 2.3.3 → 2.3.4

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 CHANGED
@@ -6,6 +6,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
7
  The format is based on [Keep a Changelog](http://keepachangelog.com/).
8
8
 
9
+ ## [2.3.4] - 2022-03-31
10
+
11
+ ### Changed
12
+
13
+ - Only deduplicate model error messages when working within VS Code Editor
14
+ - Hide `no-dollar-prefixed-names` compiler warning message in VS Code Editor (already passed by lsp)
15
+
9
16
  ## [2.3.3] - 2022-03-24
10
17
 
11
18
  ### Added
@@ -1,3 +1,5 @@
1
+ const { isVSCodeEditor } = require("../utils/helpers");
2
+
1
3
  module.exports = {
2
4
  meta: {
3
5
  docs: {
@@ -20,7 +22,7 @@ module.exports = {
20
22
  const results = [];
21
23
  for (const m in context.cds.model.messages) {
22
24
  const msg = context.cds.model.messages[m];
23
- if (msg.messageId === "syntax-dollar-ident") {
25
+ if (msg.messageId === "syntax-dollar-ident" && !isVSCodeEditor()) {
24
26
  results.push({
25
27
  message: msg.message,
26
28
  loc: {
@@ -7,15 +7,7 @@ module.exports = {
7
7
  * @returns boolean
8
8
  */
9
9
  isValidFile: function (filePath, fileType) {
10
- function genRegex(key) {
11
- return new RegExp(
12
- `${key
13
- .map((file) => {
14
- return file.replace("*", "");
15
- })
16
- .join("$|")}$`
17
- );
18
- }
10
+ const genRegex = (key) => new RegExp(`${key.map((file) => file.replace("*", "")).join("$|")}$`);
19
11
  let isValid = false;
20
12
  switch(fileType) {
21
13
  case 'MODEL_FILES':
@@ -23,11 +23,7 @@ module.exports = {
23
23
  return cache.set(key, [value, Date.now()]);
24
24
  },
25
25
  get(key) {
26
- if (cache.get(key)) {
27
- return cache.get(key)[0];
28
- } else {
29
- return;
30
- }
26
+ return cache.get(key) ? cache.get(key)[0] : undefined
31
27
  },
32
28
  dump() {
33
29
  const dump = {};
@@ -41,11 +37,9 @@ module.exports = {
41
37
  if (cache.has(key)) {
42
38
  cache.delete(key);
43
39
  }
44
- return;
45
40
  },
46
41
  clear() {
47
42
  cache.clear();
48
- return;
49
43
  },
50
44
  },
51
45
 
@@ -56,11 +50,8 @@ module.exports = {
56
50
  * @returns boolean
57
51
  */
58
52
  isNewConfigPath: function (configPath) {
59
- if (!module.exports.Cache.has("configpath") &&
60
- (configPath !== module.exports.Cache.get("configpath"))) {
61
- return true;
62
- }
63
- return false;
53
+ return !module.exports.Cache.has("configpath")
54
+ && (configPath !== module.exports.Cache.get("configpath"))
64
55
  },
65
56
 
66
57
  /**
@@ -115,25 +106,12 @@ module.exports = {
115
106
  * @returns ESLint range
116
107
  */
117
108
  getRange: function (code, line, column) {
118
- let lines;
119
- if (typeof code === "string") {
120
- lines = SourceCode.splitLines(code);
121
- } else {
122
- lines = code;
123
- }
109
+ const lines = typeof code === "string" ? SourceCode.splitLines(code) : code
124
110
  const ranges = [0];
125
111
  lines.forEach((line, i) => {
126
- if (i === 0) {
127
- ranges[i + 1] = line.length + 1;
128
- } else {
129
- ranges[i + 1] = ranges[i] + line.length + 1;
130
- }
112
+ ranges[i + 1] = i === 0 ? line.length + 1 : ranges[i] + line.length + 1
131
113
  });
132
- if (line > 1) {
133
- return ranges[line - 1] + column;
134
- } else {
135
- return column;
136
- }
114
+ return line > 1 ? ranges[line - 1] + column : column
137
115
  },
138
116
 
139
117
  /**
@@ -145,12 +123,7 @@ module.exports = {
145
123
  * @returns Last line index
146
124
  */
147
125
  getLastLine: function (code) {
148
- let lines;
149
- if (typeof code === "string") {
150
- lines = SourceCode.splitLines(code);
151
- } else {
152
- lines = code;
153
- }
126
+ const lines = typeof code === "string" ? SourceCode.splitLines(code) : code
154
127
  return lines.length - 1;
155
128
  },
156
129
 
@@ -181,10 +154,8 @@ module.exports = {
181
154
  loc.start.line = nameloc.line;
182
155
  loc.end.column = nameloc.col - 1 + name.length;
183
156
  loc.end.line = nameloc.line;
184
- } else {
185
- if (obj.parent) {
157
+ } else if (obj.parent) {
186
158
  this.getLocation(name, obj.parent, model);
187
- }
188
159
  }
189
160
  }
190
161
  // Empty locations default to line 0, column 0
@@ -332,13 +303,8 @@ module.exports = {
332
303
  const configPath = path.dirname(filePath);
333
304
  module.exports.Cache.set('configpath', configPath);
334
305
  let files = fs.readdirSync(configPath);
335
- const modelfiles = [];
336
- files.forEach((file) => {
337
- const filePath = path.join(configPath, file);
338
- if (isValidFile(filePath, 'MODEL_FILES')) {
339
- modelfiles.push(filePath);
340
- }
341
- });
306
+ const modelfiles = files.map(f => path.join(configPath, f))
307
+ .filter(fp => isValidFile(fp, 'MODEL_FILES'))
342
308
  module.exports.Cache.set(`modelfiles:${configPath}`, modelfiles);
343
309
  const dictFiles = module.exports.getDictFiles(configPath, modelfiles);
344
310
  module.exports.Cache.set(`dictfiles:${configPath}`, dictFiles);
@@ -359,11 +325,9 @@ module.exports = {
359
325
  dictFiles = module.exports.Cache.get(`dictfiles:${input}`);
360
326
  } else {
361
327
  files.forEach((file) => {
362
- if (module.exports.Cache.has(`file:${file}`)) {
363
- dictFiles[file] = module.exports.Cache.get(`file:${file}`);
364
- } else {
365
- dictFiles[file] = fs.readFileSync(file, "utf8");
366
- }
328
+ dictFiles[file] = module.exports.Cache.has(`file:${file}`)
329
+ ? module.exports.Cache.get(`file:${file}`)
330
+ : fs.readFileSync(file, "utf8")
367
331
  });
368
332
  }
369
333
  return dictFiles;
@@ -375,6 +339,7 @@ module.exports = {
375
339
  * @returns boolean
376
340
  */
377
341
  hasFileChanged: function (code, filePath, configPath) {
342
+ let result = false
378
343
  const files = module.exports.Cache.get(`modelfiles:${configPath}`);
379
344
  const dictFiles = module.exports.getDictFiles(configPath, files);
380
345
  const isFileInModel = module.exports.isFileInModel(filePath, configPath);
@@ -384,14 +349,12 @@ module.exports = {
384
349
  if (dictFiles[filePath] !== code) {
385
350
  dictFiles[filePath] = code;
386
351
  module.exports.Cache.set(`dictfiles:${configPath}`, dictFiles);
387
- return true;
388
- }
389
- } else {
390
- if (dictFiles[filePath] !== code) {
391
- return true;
352
+ result = true
392
353
  }
354
+ } else if (dictFiles[filePath] !== code) {
355
+ result = true
393
356
  }
394
- return false;
357
+ return result;
395
358
  },
396
359
 
397
360
  /**
@@ -401,14 +364,8 @@ module.exports = {
401
364
  * @returns boolean
402
365
  */
403
366
  isFileInModel(filePath, configPath) {
404
- let files = module.exports.Cache.get(`modelfiles:${configPath}`);
405
- if (!files) {
406
- files = [];
407
- }
408
- if (files && files.length > 0 && files.includes(filePath)) {
409
- return true;
410
- }
411
- return false;
367
+ let files = module.exports.Cache.get(`modelfiles:${configPath}`) || [];
368
+ return files && files.length > 0 && files.includes(filePath)
412
369
  },
413
370
 
414
371
  /**
@@ -419,10 +376,6 @@ module.exports = {
419
376
  */
420
377
  updateModel: function (code, filePath, configPath) {
421
378
  let reflectedModel;
422
- let files = module.exports.Cache.get(`modelfiles:${configPath}`);
423
- if (!files) {
424
- files = [];
425
- }
426
379
  const dictFiles = module.exports.Cache.get(`dictfiles:${configPath}`);
427
380
  dictFiles[filePath] = code;
428
381
  module.exports.Cache.set(`dictfiles:${configPath}`, dictFiles);
@@ -39,31 +39,29 @@ const REGEX_COMMENT_START = "(/\\*|(.+)?//)(\\s?)+eslint-";
39
39
  const REGEX_COMMENTS = `${REGEX_COMMENT_START}(enable|disable)(-next)?(-line)?(.+)?`;
40
40
 
41
41
  function doReport(cdscontext, reportDescriptor, d) {
42
+ const retouchLocations = (descriptor) => {
43
+ if (d) {
44
+ descriptor.loc = descriptor.loc || cdscontext.cds.getLocation(d.name, d);
45
+ descriptor.file = descriptor.file || (d.$location ? d.$location.file : "unknown.cds");
46
+ }
47
+ };
48
+
42
49
  switch (typeof reportDescriptor) {
43
50
  case "string":
44
51
  reportDescriptor = { message: reportDescriptor };
45
- if (d) {
46
- if (!reportDescriptor.loc) reportDescriptor.loc = cdscontext.cds.getLocation(d.name, d);
47
- if (!reportDescriptor.file) reportDescriptor.file = (d.$location && d.$location.file) || "unknown.cds";
48
- }
52
+ retouchLocations(reportDescriptor);
49
53
  cdscontext.report(reportDescriptor);
50
54
  break;
51
55
  case "object":
52
56
  if (!Array.isArray(reportDescriptor)) {
53
- if (d) {
54
- if (!reportDescriptor.loc) reportDescriptor.loc = getLocation(d.name, d);
55
- if (!reportDescriptor.file) reportDescriptor.file = (d.$location && d.$location.file) || "unknown.cds";
56
- }
57
+ retouchLocations(reportDescriptor);
57
58
  cdscontext.report(reportDescriptor);
58
59
  } else {
59
60
  reportDescriptor.forEach((x) => {
60
61
  if (typeof x === "string") {
61
62
  x = { message: x };
62
63
  }
63
- if (d) {
64
- if (!x.loc) x.loc = getLocation(d.name, d);
65
- if (!x.file) x.file = (d.$location && d.$location.file) || "unknown.cds";
66
- }
64
+ retouchLocations(x);
67
65
  cdscontext.report(x);
68
66
  });
69
67
  }
@@ -116,10 +114,7 @@ function addCDSContext(context, node) {
116
114
  const filePath = (context.filePath = context.getPhysicalFilename());
117
115
  const configPath = !Cache.has("test") ? loadConfigPath(filePath) : path.dirname(filePath);
118
116
  let sourcecode = context.getSourceCode();
119
- let code = sourcecode.getText(node);
120
- if (!code) {
121
- code = Cache.get(`file:${filePath}`);
122
- }
117
+ const code = sourcecode.getText(node) || Cache.get(`file:${filePath}`);
123
118
  if (code) {
124
119
  sourcecode = new SourceCode(code, getAST(code));
125
120
  }
@@ -162,167 +157,151 @@ function createRule(spec) {
162
157
 
163
158
  return {
164
159
  meta,
165
- create: function (context) {
166
- return {
167
- Program: function (node) {
168
- const cdscontext = addCDSContext(context, node, meta);
169
-
170
- try {
171
- const { report, ...ruleDescriptors } = cdscontext;
172
- const handlers = create({ ...ruleDescriptors, report: (r) => report(r) });
173
-
174
- // Report descriptors with fake visitor 'all'
175
- // Used for environment rules and rules which require another compiled model
176
- // (i.e. sql or odata)
177
- if (handlers.all) {
178
- let reportDescriptor = handlers.all();
179
- doReport(cdscontext, reportDescriptor);
180
- } else {
181
- // Report descriptors with visitors using using `any.is()`
182
- // https://pages.github.tools.sap/cap/docs/node.js/cds-reflect
183
- if (cdscontext.cds.model) {
184
- cdscontext.cds.model.forall((d) => {
185
- for (let each in handlers) {
186
- if (d.is(each)) {
187
- let reportDescriptor = handlers[each](d);
188
- doReport(cdscontext, reportDescriptor, d);
189
- }
190
- }
191
- });
192
- }
193
- }
194
- } catch (err) {
195
- // Report errors in ESLint style
196
- if (err.messages) {
197
- // Always show model compile errors
198
- reportCompilationErr(meta, node, cdscontext, err);
199
- } else {
200
- // Thrown errors are only shown on console with --debug
201
- reportErr(meta, node, cdscontext, err);
160
+ create: (context) => ({
161
+ Program: function (node) {
162
+ const cdscontext = addCDSContext(context, node, meta);
163
+
164
+ try {
165
+ const { report, ...ruleDescriptors } = cdscontext;
166
+ const handlers = create({ ...ruleDescriptors, report: (r) => report(r) });
167
+
168
+ // Report descriptors with fake visitor 'all'
169
+ // Used for environment rules and rules which require another compiled model
170
+ // (i.e. sql or odata)
171
+ if (handlers.all) {
172
+ let reportDescriptor = handlers.all();
173
+ doReport(cdscontext, reportDescriptor);
174
+ } else {
175
+ // TODO: Use external address
176
+ // Report descriptors with visitors using using `any.is()`
177
+ // https://pages.github.tools.sap/cap/docs/node.js/cds-reflect
178
+ if (cdscontext.cds.model) {
179
+ cdscontext.cds.model.forall((d) =>
180
+ Object.entries(handlers)
181
+ .filter(([type, lazy]) => d.is(type))
182
+ .forEach(([lazy, handler]) => doReport(cdscontext, handler(d), d))
183
+ );
202
184
  }
203
185
  }
204
- },
205
- };
206
- },
186
+ } catch (err) {
187
+ // Report errors in ESLint style
188
+ if (err.messages) {
189
+ // Always show model compile errors
190
+ reportCompilationErr(meta, node, cdscontext, err);
191
+ } else {
192
+ // Thrown errors are only shown on console with --debug
193
+ reportErr(meta, node, cdscontext, err);
194
+ }
195
+ }
196
+ },
197
+ }),
207
198
  };
208
199
  }
209
200
 
210
- /**
211
- * Checks whether a lint rule has been disabled by eslint-disable
212
- * comments at a given location
213
- * @param entry lint report
214
- * @param cdscontext cds context object
215
- * @param rules all availabe rules
216
- * @returns boolean
217
- */
201
+ /**
202
+ * Checks whether a lint rule has been disabled by eslint-disable
203
+ * comments at a given location
204
+ * @param entry lint report
205
+ * @param cdscontext cds context object
206
+ * @param rules all availabe rules
207
+ * @returns boolean
208
+ */
218
209
 
219
- function isRuleDisabled(entry, cdscontext) {
220
- let isDisabled = false;
221
- if (entry.loc && entry.loc.start) {
222
- const line = entry.loc.start.line;
223
- if (cdscontext) {
224
- const rulesDisabled = _getDisabled(cdscontext.code, cdscontext.sourcecode, line);
225
- let id = cdscontext.id;
226
- if (line && id in rulesDisabled && rulesDisabled[id] === "off") {
227
- isDisabled = true;
228
- }
229
- }
210
+ function isRuleDisabled(entry, cdscontext) {
211
+ let isDisabled = false;
212
+ if (entry.loc && entry.loc.start) {
213
+ const line = entry.loc.start.line;
214
+ if (cdscontext) {
215
+ const rulesDisabled = _getDisabled(cdscontext.code, cdscontext.sourcecode, line);
216
+ const id = cdscontext.id;
217
+ isDisabled = line && id in rulesDisabled && rulesDisabled[id] === "off";
230
218
  }
231
- return isDisabled;
232
219
  }
220
+ return isDisabled;
221
+ }
233
222
 
234
-
235
- /**
236
- * Turns rules "on" or "off" for given line according to eslint-disable
237
- * comments:
238
- * 1. Reads code string and extracts a list of comments (in order)
239
- * 2. Initiates rulesDisabled array with all rules "on" by default
240
- * 3. Switches rules "off" (or "on" again) based on disable comment
241
- * @param code current code
242
- * @param sourcecode source code object to get index from
243
- * @param line current code line to analyze
244
- * @returns rules dictionary with rules being either 'on' and 'off'
245
- */
246
- function _getDisabled(code, sourcecode, line) {
247
- const listDisabled = [];
248
- let { listEnvRules, listModelRules, listRules } = Cache.get("rulesInfo");
249
- const rulesDisabled = listRules.reduce((o, key) => ({ ...o, [key]: "on" }), {});
250
- let matches = [];
251
- if (code) {
252
- matches = [...code.matchAll(REGEX_COMMENTS)];
253
- if (matches.length > 0) {
254
- matches.forEach((match) => {
255
- if (match) {
256
- const index = match.index;
257
- match = match[0];
258
- if (match.includes("*/")) {
259
- match = match.split("*/")[0].replace("/*", "");
260
- } else if (match.includes("//")) {
261
- match = match.split("//")[1];
262
- }
263
- if (match) {
264
- match = match.trim();
265
- }
266
- ["disable", "enable"].forEach((keyword) => {
267
- const loc = sourcecode.getLocFromIndex(index);
268
- const disableType = match.split(" ")[0];
269
- let disableRules = match.split(`${disableType} `)[1];
270
- if (disableRules) {
271
- disableRules = disableRules.split(",").map((rule) => rule.trim());
272
- } else {
273
- disableRules = listEnvRules.concat(listModelRules).map((rule) => `@sap/cds/${rule}`);
274
- }
275
- let comment = {};
276
- if (
277
- [`eslint-${keyword}`, `eslint-${keyword}-line`, `eslint-${keyword}-next-line`].includes(disableType)
278
- ) {
279
- if (disableType.includes("-next-line")) {
280
- comment = {
281
- lineComment: loc.line,
282
- lineDisabled: loc.line + 1,
283
- rules: disableRules,
284
- type: keyword,
285
- };
286
- } else {
287
- comment = {
288
- lineComment: loc.line,
289
- lineDisabled: loc.line,
290
- rules: disableRules,
291
- type: keyword,
292
- };
293
- }
294
- if (!disableType.includes("-line")) {
295
- comment.lineDisabled = "EOF";
223
+ /**
224
+ * Turns rules "on" or "off" for given line according to eslint-disable
225
+ * comments:
226
+ * 1. Reads code string and extracts a list of comments (in order)
227
+ * 2. Initiates rulesDisabled array with all rules "on" by default
228
+ * 3. Switches rules "off" (or "on" again) based on disable comment
229
+ * @param code current code
230
+ * @param sourcecode source code object to get index from
231
+ * @param line current code line to analyze
232
+ * @returns rules dictionary with rules being either 'on' and 'off'
233
+ */
234
+ function _getDisabled(code, sourcecode, line) {
235
+ const listDisabled = [];
236
+ let { listEnvRules, listModelRules, listRules } = Cache.get("rulesInfo");
237
+ const rulesDisabled = listRules.reduce((o, key) => ({ ...o, [key]: "on" }), {});
238
+ let matches = [];
239
+ if (code) {
240
+ matches = [...code.matchAll(REGEX_COMMENTS)];
241
+ if (matches.length > 0) {
242
+ matches.forEach((match) => {
243
+ if (match) {
244
+ const index = match.index;
245
+ match = match[0];
246
+ if (match.includes("*/")) {
247
+ match = match.split("*/")[0].replace("/*", "");
248
+ } else if (match.includes("//")) {
249
+ match = match.split("//")[1];
250
+ }
251
+ if (match) {
252
+ match = match.trim();
253
+ }
254
+ ["disable", "enable"].forEach((keyword) => {
255
+ const loc = sourcecode.getLocFromIndex(index);
256
+ const disableType = match.split(" ")[0];
257
+ let disableRules = match.split(`${disableType} `)[1];
258
+ disableRules = disableRules
259
+ ? disableRules.split(",").map((rule) => rule.trim())
260
+ : listEnvRules.concat(listModelRules).map((rule) => `@sap/cds/${rule}`);
261
+ let comment = {};
262
+ if ([`eslint-${keyword}`, `eslint-${keyword}-line`, `eslint-${keyword}-next-line`].includes(disableType)) {
263
+ comment = disableType.includes("-next-line")
264
+ ? {
265
+ lineComment: loc.line,
266
+ lineDisabled: loc.line + 1,
267
+ rules: disableRules,
268
+ type: keyword,
296
269
  }
297
- }
298
- listDisabled.push(comment);
299
- });
270
+ : {
271
+ lineComment: loc.line,
272
+ lineDisabled: loc.line,
273
+ rules: disableRules,
274
+ type: keyword,
275
+ };
276
+ if (!disableType.includes("-line")) {
277
+ comment.lineDisabled = "EOF";
278
+ }
300
279
  }
280
+ listDisabled.push(comment);
301
281
  });
302
- for (let i = 0; i <= listDisabled.length - 1; i++) {
303
- if (listDisabled[i].lineComment > line) {
304
- break;
305
- }
306
- if (listDisabled[i].lineDisabled === "EOF" || listDisabled[i].lineDisabled === line) {
307
- if (listDisabled[i].lineDisabled === "EOF") {
308
- listDisabled[i].lineDisabled = getLastLine(code);
309
- }
310
- if (listDisabled[i].rules) {
311
- listDisabled[i].rules.forEach((rule) => {
312
- if (listDisabled[i].type === "disable") {
313
- rulesDisabled[rule] = "off";
314
- } else if (listDisabled[i].type === "enable") {
315
- rulesDisabled[rule] = "on";
316
- }
317
- });
318
- }
282
+ }
283
+ });
284
+ for (const el of listDisabled.filter(
285
+ (d) => d.lineComment > line && (d.lineDisabled === "EOF" || d.lineDisabled === line)
286
+ )) {
287
+ if (el.lineDisabled === "EOF") {
288
+ el.lineDisabled = getLastLine(code);
289
+ }
290
+ if (el.rules) {
291
+ el.rules.forEach((rule) => {
292
+ if (el.type === "disable") {
293
+ rulesDisabled[rule] = "off";
294
+ } else if (el.type === "enable") {
295
+ rulesDisabled[rule] = "on";
319
296
  }
320
- }
297
+ });
321
298
  }
322
299
  }
323
- return rulesDisabled;
324
300
  }
325
-
301
+ }
302
+ return rulesDisabled;
303
+ }
304
+
326
305
  module.exports = {
327
306
  /**
328
307
  * Gets value for a given key in allowed keys of ESLint's meta data
@@ -452,11 +431,9 @@ module.exports = {
452
431
  /* eslint-disable-next-line no-unused-vars */
453
432
  Object.entries(ruleDict).forEach(([, rules]) => {
454
433
  rules.forEach(function (rule) {
455
- if (release) {
456
- mdRules += `| ${rule.recommended} | ${rule.fixable} | ${rule.hasSuggestions} | | &nbsp; | [${rule.name}](Rules-released.md#${rule.name}) | ${rule.details}|\n`;
457
- } else {
458
- mdRules += `| ${rule.recommended} | ${rule.fixable} | ${rule.hasSuggestions} | ${rule.construction} | &nbsp; | [${rule.name}](Rules.md#${rule.name}) | ${rule.details}|\n`;
459
- }
434
+ mdRules += release
435
+ ? `| ${rule.recommended} | ${rule.fixable} | ${rule.hasSuggestions} | | &nbsp; | [${rule.name}](Rules-released.md#${rule.name}) | ${rule.details}|\n`
436
+ : `| ${rule.recommended} | ${rule.fixable} | ${rule.hasSuggestions} | ${rule.construction} | &nbsp; | [${rule.name}](Rules.md#${rule.name}) | ${rule.details}|\n`;
460
437
  });
461
438
  });
462
439
  mdRules += "\n";
@@ -493,7 +470,7 @@ module.exports = {
493
470
  const mdRuleListCur = fs.readFileSync(ruleListDocsPath, "utf8");
494
471
 
495
472
  // Get rules table
496
- let mdRuleList = module.exports.genMdRules(ruleDict, release, true);
473
+ const mdRuleList = module.exports.genMdRules(ruleDict, release, true);
497
474
 
498
475
  // Get rule details
499
476
  let mdRules = module.exports.genMdRules(ruleDict, release, false);
@@ -525,30 +502,21 @@ module.exports = {
525
502
  docsPath = path.join(__dirname, "../../docs");
526
503
  rulePath = path.join(__dirname, "../rules");
527
504
  testPath = path.join(__dirname, "../../test/rules");
528
- release = JSON.parse(fs.readFileSync(path.join(__dirname, "../../../package.json"))).version;
505
+ release = JSON.parse(fs.readFileSync(path.join(__dirname, "../../package.json"))).version;
529
506
  } else {
530
507
  docsPath = path.join(projectPath, `${customRulesDir}/docs`);
531
508
  rulePath = path.join(projectPath, `${customRulesDir}/rules`);
532
509
  testPath = path.join(projectPath, `${customRulesDir}/tests`);
533
- if (!fs.existsSync(docsPath)) {
534
- await mkdirp(docsPath);
535
- }
536
- if (!fs.existsSync(rulePath)) {
537
- await mkdirp(rulePath);
538
- }
539
- if (!fs.existsSync(testPath)) {
540
- await mkdirp(testPath);
541
- }
510
+ await Promise.all(
511
+ [docsPath, rulePath, testPath].filter((path) => !fs.existsSync(path)).map((path) => mkdirp(path))
512
+ );
542
513
  }
543
514
 
544
515
  if (registry) {
545
516
  // Get rules (internal on artifactory)
546
- let versionInternal;
547
- if (!prepareRelease) {
548
- versionInternal = module.exports.getPackageVersion(registry);
549
- } else {
550
- versionInternal = JSON.parse(fs.readFileSync(path.join(__dirname, "../../../package.json"))).version;
551
- }
517
+ const versionInternal = prepareRelease
518
+ ? JSON.parse(fs.readFileSync(path.join(__dirname, "../../package.json"))).version
519
+ : module.exports.getPackageVersion(registry);
552
520
  if (versionInternal) {
553
521
  console.log(`Updating internal rules from v>=${versionInternal}:\n${registry}\n`);
554
522
  const ruleDictInternal = module.exports.getRuleDict(docsPath, rulePath, testPath, versionInternal);
@@ -556,12 +524,9 @@ module.exports = {
556
524
  }
557
525
  // Get rules released (external on npm)
558
526
  const npmRegistry = "https://registry.npmjs.org";
559
- let versionExternal;
560
- if (!prepareRelease) {
561
- versionExternal = module.exports.getPackageVersion(npmRegistry);
562
- } else {
563
- versionExternal = JSON.parse(fs.readFileSync(path.join(__dirname, "../../../package.json"))).version;
564
- }
527
+ const versionExternal = prepareRelease
528
+ ? JSON.parse(fs.readFileSync(path.join(__dirname, "../../package.json"))).version
529
+ : module.exports.getPackageVersion(npmRegistry);
565
530
  if (versionExternal) {
566
531
  console.log(`Updating external rules from v>=${versionExternal}:\n${npmRegistry}\n`);
567
532
  const ruleDictExternal = module.exports.getRuleDict(docsPath, rulePath, testPath, versionExternal, release);
@@ -577,8 +542,8 @@ module.exports = {
577
542
 
578
543
  getRuleDict: function (docsPath, rulePath, testPath, versionRequired = "0.0.0", release = false) {
579
544
  let mdRule, mdRuleSources, mdRuleContents;
580
- let ruleDict = {};
581
- fs.readdirSync(rulePath).filter(function (file) {
545
+ const ruleDict = {};
546
+ fs.readdirSync(rulePath).filter((file) => {
582
547
  if (path.extname(file).toLowerCase() === ".js" && file !== "index.js") {
583
548
  const rule = path.basename(file).replace(path.extname(file), "");
584
549
  const ruleTestPath = path.join(testPath, rule, "rule.test.js");
@@ -596,25 +561,14 @@ module.exports = {
596
561
  const suggestions = ruleMeta.hasSuggestions;
597
562
 
598
563
  let underConstruction = "";
599
- if (!release && semver.satisfies(version, `>${versionRequired}`)) {
564
+ if (!release && (version === "TBD" || semver.satisfies(version, `>${versionRequired}`))) {
600
565
  underConstruction = "🚧";
601
566
  console.log(` > 🚧 Rule '${rule}' still under construction.\n`);
602
567
  }
603
568
 
604
- let isFixable = "";
605
- if (["code", "whitespace"].includes(fixable)) {
606
- isFixable = "🔧";
607
- }
608
-
609
- let isRecommended = "";
610
- if (recommended === true) {
611
- isRecommended = "✔️";
612
- }
613
-
614
- let hasSuggestions = "";
615
- if (suggestions === true) {
616
- hasSuggestions = "💡";
617
- }
569
+ const isFixable = ["code", "whitespace"].includes(fixable) ? "🔧" : "";
570
+ const isRecommended = recommended === true ? "✔️" : "";
571
+ const hasSuggestions = suggestions === true ? "💡" : "";
618
572
 
619
573
  const ruleDictEntry = {
620
574
  name: rule,
@@ -628,11 +582,12 @@ module.exports = {
628
582
  };
629
583
  mdRule = module.exports.getRuleExamples(ruleTestPath, testPath, ruleDictEntry);
630
584
  mdRuleContents = "";
631
- if (!release && underConstruction) {
632
- mdRuleContents += `## ${rule}\n<span class='shifted'>${underConstruction}&nbsp;&nbsp;<span class='label'>${category}</span></span>\n\n`;
633
- } else {
634
- mdRuleContents += `## ${rule}\n<span class='shifted label'>${category}</span>\n\n`;
635
- }
585
+
586
+ mdRuleContents +=
587
+ !release && underConstruction
588
+ ? `## ${rule}\n<span class='shifted'>${underConstruction}&nbsp;&nbsp;<span class='label'>${category}</span></span>\n\n`
589
+ : `## ${rule}\n<span class='shifted label'>${category}</span>\n\n`;
590
+
636
591
  mdRuleContents += `### Rule Details\n${details}\n\n`;
637
592
  if (mdRule) {
638
593
  mdRuleContents += `### Examples\n${mdRule}\n\n`;
@@ -890,27 +845,27 @@ module.exports = {
890
845
  // Do not consider disabled content
891
846
  if (!isRuleDisabled(lint, thisArg)) {
892
847
  const isModelLint = lint.file && isValidFile(lint.file, "MODEL_FILES") && !lint.err;
893
- if (isModelLint) {
894
- if (module.exports.isDedicatedFile(lint, thisArg) && module.exports.isReportUnique(lint, "modelReports")) {
848
+ if (isModelLint && module.exports.isDedicatedFile(lint, thisArg)) {
849
+ if (isVSCodeEditor()) {
895
850
  report = true;
851
+ } else {
852
+ if (module.exports.isReportUnique(lint, "modelReports")) {
853
+ report = true;
854
+ }
896
855
  }
897
856
  }
898
857
  if (!lint.loc) {
899
858
  lint.loc = module.exports.addDefaultLoc();
900
859
  }
901
- if (!isModelLint && !lint.err) {
902
- if (module.exports.isReportUnique(lint, "envReports", thisArg.configPath)) {
903
- report = true;
904
- }
860
+ if (
861
+ !isModelLint &&
862
+ !lint.err &&
863
+ module.exports.isReportUnique(lint, "envReports", thisArg.configPath)
864
+ ) {
865
+ report = true;
905
866
  }
906
- if (lint.err) {
907
- if (lint.file) {
908
- report = true;
909
- } else {
910
- if (module.exports.isReportUnique(lint, "errReports", thisArg.configPath)) {
911
- report = true;
912
- }
913
- }
867
+ if (lint.err && (lint.file || module.exports.isReportUnique(lint, "errReports", thisArg.configPath))) {
868
+ report = true;
914
869
  }
915
870
  if (report) {
916
871
  return thisArg._context.report(lint);
@@ -924,20 +879,10 @@ module.exports = {
924
879
  return new Proxy(ruleReport, handler);
925
880
  },
926
881
 
927
- resolveFilePath: function (file) {
928
- let fileAbs;
929
- if (!path.isAbsolute(file)) {
930
- fileAbs = path.join(Cache.get("configpath"), file);
931
- } else {
932
- fileAbs = file;
933
- }
934
- return fileAbs;
935
- },
882
+ resolveFilePath: (file) => (path.isAbsolute(file) ? file : path.join(Cache.get("configpath"), file)),
936
883
 
937
- isDedicatedFile: function (lint, thisArg) {
938
- let fileAbs = module.exports.resolveFilePath(lint.file);
939
- return fileAbs === thisArg.filePath || lint.file === "<stdin>.cds";
940
- },
884
+ isDedicatedFile: (lint, thisArg) =>
885
+ module.exports.resolveFilePath(lint.file) === thisArg.filePath || lint.file === "<stdin>.cds",
941
886
 
942
887
  isReportUnique: function (lint, name, uniqueness) {
943
888
  let report = false;
@@ -962,12 +907,10 @@ module.exports = {
962
907
  return report;
963
908
  },
964
909
 
965
- addDefaultLoc: function () {
966
- return {
967
- start: { line: 0, column: -1 },
968
- end: { line: 0, column: -1 },
969
- };
970
- },
910
+ addDefaultLoc: () => ({
911
+ start: { line: 0, column: -1 },
912
+ end: { line: 0, column: -1 },
913
+ }),
971
914
 
972
915
  getModel: function (code, filePath, configPath) {
973
916
  let model;
@@ -1013,11 +956,8 @@ module.exports = {
1013
956
  }
1014
957
  },
1015
958
 
1016
- isParkedModelFile: function (filePath, configPath) {
1017
- const isValidModelFile = isValidFile(filePath, "MODEL_FILES");
1018
- const isInModel = isFileInModel(filePath, configPath);
1019
- return isValidModelFile && !isInModel;
1020
- },
959
+ isParkedModelFile: (filePath, configPath) =>
960
+ isValidFile(filePath, "MODEL_FILES") && !isFileInModel(filePath, configPath),
1021
961
 
1022
962
  getEnvironment: function (options) {
1023
963
  let environment;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/eslint-plugin-cds",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "description": "ESLint plugin including recommended SAP Cloud Application Programming model and environment rules",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [