@sap/eslint-plugin-cds 2.3.5 → 2.4.1
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 +19 -0
- package/lib/processor.js +4 -1
- package/lib/rules/auth-no-empty-restrictions.js +45 -0
- package/lib/rules/auth-use-requires.js +38 -0
- package/lib/rules/auth-valid-restrict-grant.js +68 -0
- package/lib/rules/auth-valid-restrict-keys.js +37 -0
- package/lib/rules/auth-valid-restrict-to.js +86 -0
- package/lib/rules/auth-valid-restrict-where.js +80 -0
- package/lib/rules/no-db-keywords.js +0 -2
- package/lib/rules/no-dollar-prefixed-names.js +1 -29
- package/lib/rules/start-elements-lowercase.js +2 -2
- package/lib/rules/start-entities-uppercase.js +2 -2
- package/lib/utils/fuzzySearch.js +9 -2
- package/lib/utils/helpers.js +47 -0
- package/lib/utils/model.js +1 -2
- package/lib/utils/ruleHelpers.js +145 -2
- package/lib/utils/ruleTester.js +1 -2
- package/lib/utils/rules.js +1038 -975
- package/package.json +5 -2
package/lib/utils/ruleHelpers.js
CHANGED
|
@@ -36,7 +36,49 @@ module.exports = {
|
|
|
36
36
|
return { prefix, entity: entityName, suffix };
|
|
37
37
|
},
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param {*} reports
|
|
42
|
+
* @param {*} context
|
|
43
|
+
* @param {*} items
|
|
44
|
+
* @param {*} validItems
|
|
45
|
+
* @param {*} severity
|
|
46
|
+
*/
|
|
47
|
+
suggestItems: function (reports, context, items, validItems, severity, keepCase) {
|
|
48
|
+
const { code, sourcecode, filePath } = context;
|
|
49
|
+
let invalidItems = items.filter(
|
|
50
|
+
(e) => !validItems.includes(e) && !validItems.includes(e.toUpperCase() && !validItems.includes(e.toLowerCase()))
|
|
51
|
+
);
|
|
52
|
+
invalidItems.forEach((invalid) => {
|
|
53
|
+
const index = module.exports._findInCode(invalid, code);
|
|
54
|
+
// Safetey check that string exists in source code
|
|
55
|
+
if (index > 0) {
|
|
56
|
+
const loc = sourcecode.getLocFromIndex(index);
|
|
57
|
+
const candidates = findFuzzy(invalid, validItems.sort(), keepCase);
|
|
58
|
+
const suggest = candidates.map((cand) => {
|
|
59
|
+
return {
|
|
60
|
+
messageId: "ReplaceItemWith",
|
|
61
|
+
data: { invalid, candidates: cand },
|
|
62
|
+
fix: (fixer) => fixer.replaceTextRange([index, index + invalid.length], cand),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
reports.push({
|
|
66
|
+
messageId: "InvalidItem",
|
|
67
|
+
data: { invalid, candidates },
|
|
68
|
+
loc: {
|
|
69
|
+
start: loc,
|
|
70
|
+
end: { line: loc.line, column: loc.column + invalid.length },
|
|
71
|
+
},
|
|
72
|
+
file: filePath,
|
|
73
|
+
suggest,
|
|
74
|
+
severity,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
if (!invalidItems) {
|
|
79
|
+
reports.push(`Missing values!`);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
40
82
|
|
|
41
83
|
_findInCode: function (miss, code) {
|
|
42
84
|
// middle
|
|
@@ -52,5 +94,106 @@ module.exports = {
|
|
|
52
94
|
return code.indexOf(miss);
|
|
53
95
|
},
|
|
54
96
|
|
|
97
|
+
validateString: function (reports, context, e, text, value, allowedValues, fuzzySearch = true, keepCase = true) {
|
|
98
|
+
const { key, name } = text;
|
|
99
|
+
if (typeof value !== "string") {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!value) {
|
|
103
|
+
reports.push(`Missing ${name} on ${e.name} for @restrict \`${key}\`.`);
|
|
104
|
+
} else if (fuzzySearch) {
|
|
105
|
+
module.exports.suggestItems(reports, context, [value], allowedValues, keepCase);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
validateObject: function (reports, context, e, text, values, allowedValues, fuzzySearch = true) {
|
|
110
|
+
const { key, name } = text;
|
|
111
|
+
if (typeof values !== "object") {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (values.length === 0) {
|
|
115
|
+
reports.push(`Missing ${name} on ${e.name} for @restrict \`${key}\`.`);
|
|
116
|
+
} else if (fuzzySearch) {
|
|
117
|
+
switch (key) {
|
|
118
|
+
case "to": {
|
|
119
|
+
if (values.includes("any")) {
|
|
120
|
+
module.exports.suggestRedundantItems(reports, context, "any", e);
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case "grant": {
|
|
125
|
+
let valuesForWrite = allowedValues.filter(function (item) {
|
|
126
|
+
return item !== "READ" && item !== "WRITE" && item !== "*";
|
|
127
|
+
});
|
|
128
|
+
let allValuesIncluded = (arr, target) => target.every((v) => arr.includes(v));
|
|
129
|
+
if (allValuesIncluded(values, valuesForWrite)) {
|
|
130
|
+
module.exports.suggestRedundantItems(reports, context, "WRITE", e);
|
|
131
|
+
}
|
|
132
|
+
if (values.includes("*")) {
|
|
133
|
+
module.exports.suggestRedundantItems(reports, context, "*", e);
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
module.exports.suggestItems(reports, context, values, allowedValues);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
suggestRedundantItems: function (reports, context, value, e) {
|
|
143
|
+
let invalid;
|
|
144
|
+
const loc = e.$location;
|
|
145
|
+
const lineToReplace = context.sourcecode.lines[loc.line];
|
|
146
|
+
var regExp = /\[([^)]+)\]/;
|
|
147
|
+
var matches = regExp.exec(lineToReplace);
|
|
148
|
+
if (matches && matches[0]) {
|
|
149
|
+
invalid = matches[0];
|
|
150
|
+
}
|
|
151
|
+
const startIndex = lineToReplace.indexOf(invalid);
|
|
152
|
+
const candidates = `['${value}']`;
|
|
153
|
+
const suggest = {
|
|
154
|
+
messageId: "ReplaceItemWith",
|
|
155
|
+
data: { invalid, candidates },
|
|
156
|
+
fix: (fixer) => fixer.replaceTextRange([startIndex, startIndex + invalid.length] + 1, candidates),
|
|
157
|
+
};
|
|
158
|
+
reports.push({
|
|
159
|
+
messageId: "InvalidItem",
|
|
160
|
+
data: { invalid, candidates },
|
|
161
|
+
loc: {
|
|
162
|
+
start: { line: loc.line + 1, column: startIndex },
|
|
163
|
+
end: { line: loc.line + 1, column: startIndex + invalid.length },
|
|
164
|
+
},
|
|
165
|
+
file: context.filePath,
|
|
166
|
+
suggest,
|
|
167
|
+
severity: "warn",
|
|
168
|
+
});
|
|
169
|
+
},
|
|
55
170
|
|
|
56
|
-
|
|
171
|
+
suggestReplacementsItems: function (reports, context, value, e) {
|
|
172
|
+
let invalid;
|
|
173
|
+
const loc = e.$location;
|
|
174
|
+
const lineToReplace = context.sourcecode.lines[loc.line];
|
|
175
|
+
var regExp = /\[([^)]+)\]/;
|
|
176
|
+
var matches = regExp.exec(lineToReplace);
|
|
177
|
+
if (matches && matches[0]) {
|
|
178
|
+
invalid = matches[0];
|
|
179
|
+
}
|
|
180
|
+
const startIndex = lineToReplace.indexOf(invalid);
|
|
181
|
+
const candidates = `['${value}']`;
|
|
182
|
+
const suggest = {
|
|
183
|
+
messageId: "ReplaceItemWith",
|
|
184
|
+
data: { invalid, candidates },
|
|
185
|
+
fix: (fixer) => fixer.replaceTextRange([startIndex, startIndex + invalid.length] + 1, candidates),
|
|
186
|
+
};
|
|
187
|
+
reports.push({
|
|
188
|
+
messageId: "InvalidItem",
|
|
189
|
+
data: { invalid, candidates },
|
|
190
|
+
loc: {
|
|
191
|
+
start: { line: loc.line + 1, column: startIndex },
|
|
192
|
+
end: { line: loc.line + 1, column: startIndex + invalid.length },
|
|
193
|
+
},
|
|
194
|
+
file: context.filePath,
|
|
195
|
+
suggest,
|
|
196
|
+
severity: "warn",
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
};
|
package/lib/utils/ruleTester.js
CHANGED
|
@@ -20,8 +20,7 @@ runRuleTester: function(options) {
|
|
|
20
20
|
let parser;
|
|
21
21
|
let rule = {};
|
|
22
22
|
const rulename = path.basename(options.root);
|
|
23
|
-
|
|
24
|
-
if (options.root.includes(plugin)) {
|
|
23
|
+
if (options.root.startsWith(path.resolve(__dirname,'../..'))) {
|
|
25
24
|
// For plugin's internal tests, resolve parser from here
|
|
26
25
|
parser = require.resolve("../parser");
|
|
27
26
|
const pluginPath = path.join(path.dirname(options.root), "../..");
|