@sap/eslint-plugin-cds 2.1.1 → 2.3.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.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @typedef { import("eslint").Rule.RuleContext.options } ContextOptions
3
+ */
4
+
5
+ module.exports = {
6
+ /**
7
+ * Checks whether the rule name is valid (i.e. is contained within
8
+ * the plugin's or user's *custom* rules).
9
+ * @param context
10
+ * @param pluginRules
11
+ * @param customRules
12
+ * @returns
13
+ */
14
+ isValidRule: function (context, rules) {
15
+ if (rules.includes(context.ruleID.replace("@sap/cds/", ""))) {
16
+ return true;
17
+ }
18
+ return false;
19
+ },
20
+
21
+ /**
22
+ * Checks whether a cds model is error-free
23
+ * @param context cds context object
24
+ * @returns
25
+ */
26
+ isValidModel: function (context) {
27
+ const cds = context.cds;
28
+ if (cds) {
29
+ if (cds.model) {
30
+ return !cds.model.err;
31
+ }
32
+ return true; // allow no model
33
+ }
34
+ return false;
35
+ },
36
+
37
+ /**
38
+ * Checks whether a well-defined cds environment exists
39
+ * @param context cds context object
40
+ * @returns
41
+ */
42
+ isValidEnv: function (context) {
43
+ if (
44
+ context.options &&
45
+ context.options[0] &&
46
+ context.options[0].environment
47
+ ) {
48
+ return true;
49
+ }
50
+ return false;
51
+ },
52
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/eslint-plugin-cds",
3
- "version": "2.1.1",
3
+ "version": "2.3.2",
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": [
@@ -20,7 +20,7 @@
20
20
  "README.md"
21
21
  ],
22
22
  "dependencies": {
23
- "@sap/cds": "^5.0.0",
23
+ "@sap/cds": "^5.6.0",
24
24
  "semver": "^7.3.4"
25
25
  },
26
26
  "peerDependencies": {
@@ -1,205 +0,0 @@
1
- /**
2
- * Custom ESLint formatter:
3
- * https://eslint.org/docs/developer-guide/working-with-custom-formatters
4
- * Here, we take the ESLint.LintResult[] and format it into ESLint's standard (stylish) error report.
5
- * Then, we adapt it to report environment errors:
6
- * - Separately from model errors
7
- * - Report them within a project scope but independent of a specific file within that scope
8
- */
9
- const fs = require("fs");
10
- const path = require("path");
11
- const { CLIEngine } = require("eslint")
12
- // Note: CliEngine depracted, but new Node API requires
13
- // async Linter framework
14
- const formatter = CLIEngine.getFormatter("stylish");
15
- const { Cache } = require("../impl/utils/model");
16
- const { styleText, isEditor, isTest } = require("../impl/utils/helpers");
17
-
18
- const CONSTANTS = require("../impl/constants");
19
-
20
- // eslint-disable-next-line no-control-regex
21
- const REGEX_STRIP_ANSI = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
22
- const REGEX_NEWLINE = /\r?\n/g;
23
-
24
- let projects = Cache.getModels();
25
-
26
- // Types: results: ESLint.LintResult[], data: any
27
- module.exports = function (results, data) {
28
- let output = "";
29
- // Get plugin ruleIDs
30
- const rules = getPluginRules(data);
31
- // Get ruleIDs from custom rules
32
- const customRules = [];
33
- projects.forEach((project) => {
34
- const customRulesPath = path.resolve(project, CONSTANTS.customRulesDir, 'rules');
35
- if (fs.existsSync(customRulesPath)) {
36
- fs.readdirSync(customRulesPath).forEach((customRule) => {
37
- const ruleID = path.basename(customRule, '.js');
38
- if (!customRules.includes(ruleID)) {
39
- customRules.push(ruleID)
40
- }
41
- })
42
- }
43
- })
44
- if (!Cache.has("err")) {
45
- // Filter out error messages not from plugin or custom rules
46
- if (!isEditor() && !isTest()) {
47
- results.forEach((result) => {
48
- result.messages = result.messages.filter (msg => (
49
- rules.model.includes(msg.ruleId) ||
50
- rules.environment.includes(msg.ruleId) ||
51
- customRules.includes(msg.ruleId)
52
- ))
53
- // result.messages.forEach((msg) => {
54
- // if (!rules.model.includes(msg.ruleId) &&
55
- // !rules.environment.includes(msg.ruleId) &&
56
- // !customRules.includes(msg.ruleId)) {
57
- // if (!resultsToRemove.includes(i)) {
58
- // resultsToRemove.push(i);
59
- // }
60
- // }
61
- // })
62
- })
63
- // results.forEach((result, index) => {
64
- // if (resultsToRemove.includes(index)) {
65
- // results.splice(index, 1);
66
- // }
67
- // })
68
- }
69
- // Get standard ESLint 'stylish' output
70
- const outputStylish = formatter(results);
71
-
72
- // Split according to category
73
- const msgs = splitOutput(outputStylish, rules);
74
-
75
- // Format new CDSLint output
76
- output = formatOutput(output, msgs);
77
- }
78
- return output;
79
- };
80
-
81
- /**
82
- * Splits rules by config and category
83
- * @param data Rules meta data
84
- * @returns rules object based on category
85
- */
86
- function getPluginRules (data) {
87
- const rules = { environment: [], model: [], recommended: [] };
88
- Object.keys(data.rulesMeta).forEach((rule) => {
89
- if (data.rulesMeta[rule]) {
90
- const category = data.rulesMeta[rule].docs.category;
91
- if (category === CONSTANTS.categories.model) {
92
- rules.model.push(rule);
93
- rules.recommended.push(rule);
94
- } else if (category === CONSTANTS.categories.env) {
95
- rules.environment.push(rule);
96
- rules.recommended.push(rule);
97
- }
98
- }
99
- });
100
- return rules;
101
- }
102
-
103
- /**
104
- * Obtains ESLint's standard (*stylish*) output, then splits and reccollects error messages
105
- * based on rule category and content type (msg vs. error count/report)
106
- * @param outputStylish ESLint's standard output
107
- * @param rules Plugin rules based on category
108
- * @returns Collected msgs
109
- */
110
- function splitOutput (outputStylish, rules) {
111
- const msgs = { environment: {}, model: {}, report: [] };
112
- let projects = Cache.getModels();
113
- let file = "";
114
- outputStylish.split(REGEX_NEWLINE).forEach((line) => {
115
- const lineStripped = line.replace(REGEX_STRIP_ANSI, "");
116
- // Collect model file (default)
117
- const lineStrippedSplit = lineStripped.split(" ");
118
- const rule = lineStrippedSplit[lineStrippedSplit.length - 1];
119
- if (
120
- !lineStripped.startsWith(" ") &&
121
- !rules.recommended.includes(rule) &&
122
- !lineStripped.startsWith("✖")
123
- ) {
124
- file = line;
125
- if (
126
- process.argv[1].includes("jest") ||
127
- process.argv[1].includes("mocha")
128
- ) {
129
- projects = [path.dirname(lineStripped)];
130
- }
131
- } else if (rules.environment.includes(rule)) {
132
- // Collect error/warning messages from @sap/cds/ rules
133
- const delimiter = line.split(/ +/, 2)[1];
134
- const lineWithoutLocation = line.split(delimiter)[1];
135
- let project = "";
136
- for (let i = 0; i < projects.length; i++) {
137
- project = projects[i];
138
- if (file.includes(project)) {
139
- project = styleText(project, ["link"]);
140
- break;
141
- }
142
- }
143
- if (project) {
144
- if (!Object.keys(msgs.environment).includes(project)) {
145
- msgs.environment[project] = [lineWithoutLocation];
146
- } else if (
147
- !msgs.environment[project].includes(lineWithoutLocation)
148
- ) {
149
- msgs.environment[project].push(lineWithoutLocation);
150
- }
151
- }
152
- } else if (
153
- lineStripped &&
154
- !rules.environment.includes(rule) &&
155
- !lineStripped.includes("potentially fixable") &&
156
- !lineStripped.startsWith("✖")
157
- ) {
158
- if (lineStripped) {
159
- if (!msgs.model[file]) {
160
- msgs.model[file] = [line];
161
- } else {
162
- msgs.model[file].push(line);
163
- }
164
- }
165
- } else if (
166
- lineStripped.startsWith("✖") ||
167
- lineStripped.includes("potentially fixable")
168
- ) {
169
- msgs.report.push(line);
170
- }
171
- });
172
- return msgs;
173
- }
174
-
175
- /**
176
- * Takes the collected error messages and collects them
177
- * in a final string for ESLint to output
178
- * @param output final string to output
179
- * @param msgs error messages based on category
180
- * @returns
181
- */
182
- function formatOutput (output, msgs) {
183
- // First, output model msgs per file (from ESLint 'stylish' output)
184
- for (const fileModel in msgs.model) {
185
- if (msgs.model[fileModel].length > 0) {
186
- output += `${fileModel}\n`;
187
- output += `${msgs.model[fileModel].join("\n")}\n\n`;
188
- }
189
- }
190
- // Next, output env msgs (file-independent but associated to project)
191
- for (const fileModel in msgs.environment) {
192
- if (msgs.environment[fileModel].length > 0) {
193
- output += `${fileModel}\n`;
194
- output += `${msgs.environment[fileModel].join("\n")}\n\n`;
195
- }
196
- }
197
- // Finally output error/warning report count
198
- if (output && msgs.report) {
199
- output += `${msgs.report.join("\n")}`;
200
- }
201
- if (output) {
202
- output = `\n${output}`;
203
- }
204
- return output;
205
- }
@@ -1,5 +0,0 @@
1
- const { getRules } = require("../utils/rules");
2
-
3
- const rules = getRules(__dirname);
4
-
5
- module.exports = { rules };
@@ -1,10 +0,0 @@
1
- const path = require("path");
2
- const { runRuleTester } = require("../../../lib/api");
3
-
4
- runRuleTester({
5
- root: path.resolve(__dirname),
6
- rule: require(`../../../lib/rules/${path.basename(__dirname)}`),
7
- filename: "{{filename}}",
8
- parser: path.resolve(path.join(__dirname, '../../../lib/impl/parser')),
9
- errors: "{{errors}}",
10
- });