@sap/eslint-plugin-cds 2.0.4 → 2.2.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 +82 -1
- package/README.md +2 -3
- package/lib/api/formatter.js +170 -119
- package/lib/api/index.js +22 -9
- package/lib/impl/constants.js +42 -48
- package/lib/impl/index.js +56 -49
- package/lib/impl/parser.js +37 -25
- package/lib/impl/processor.js +23 -0
- package/lib/impl/ruleFactory.js +319 -117
- package/lib/impl/rules/assoc2many-ambiguous-key.js +153 -0
- package/lib/impl/rules/cds-compile-error.js +35 -0
- package/lib/impl/rules/latest-cds-version.js +41 -34
- package/lib/impl/rules/min-node-version.js +37 -34
- package/lib/impl/rules/no-db-keywords.js +25 -0
- package/lib/impl/rules/require-2many-oncond.js +29 -0
- package/lib/impl/rules/rule.hbs +13 -0
- package/lib/impl/rules/sql-cast-suggestion.js +43 -39
- package/lib/impl/rules/start-elements-lowercase.js +66 -0
- package/lib/impl/rules/start-entities-uppercase.js +56 -0
- package/lib/impl/types.d.ts +48 -0
- package/lib/impl/utils/helpers.js +89 -0
- package/lib/impl/utils/jsonc.js +1 -0
- package/lib/impl/utils/model.js +485 -0
- package/lib/impl/utils/rules.js +541 -0
- package/lib/impl/utils/validate.js +56 -0
- package/package.json +3 -3
- package/lib/impl/rules/assocs-card-flaw.js +0 -215
- package/lib/impl/rules/csn-compile-error.js +0 -37
- package/lib/impl/rules/lower-camelcase-elements.js +0 -42
- package/lib/impl/rules/upper-camelcase-entities.js +0 -50
- package/lib/impl/utils.js +0 -370
package/lib/impl/utils.js
DELETED
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
-
}) : function(o, v) {
|
|
12
|
-
o["default"] = v;
|
|
13
|
-
});
|
|
14
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
-
if (mod && mod.__esModule) return mod;
|
|
16
|
-
var result = {};
|
|
17
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
-
__setModuleDefault(result, mod);
|
|
19
|
-
return result;
|
|
20
|
-
};
|
|
21
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.getDisabledFromComments = exports.getLocation = exports.getLastLine = exports.getRange = exports.styleText = exports.updateModel = exports.loadModel = exports.getConfigPath = exports.getProxy = exports.getAST = exports.getFileExtensions = exports.getRules = exports.Cache = void 0;
|
|
23
|
-
const fs = __importStar(require("fs"));
|
|
24
|
-
const path = __importStar(require("path"));
|
|
25
|
-
const eslint_1 = require("eslint");
|
|
26
|
-
const constants_1 = require("./constants");
|
|
27
|
-
const REGEX_COMMENT_START = "(/\\*|(.+)?//)\\s+eslint-";
|
|
28
|
-
const REGEX_COMMENTS = `${REGEX_COMMENT_START}(enable|disable)(-next)?(-line)?(.+)?`;
|
|
29
|
-
const cache = new Map();
|
|
30
|
-
exports.Cache = {
|
|
31
|
-
has(key) {
|
|
32
|
-
return cache.has(key);
|
|
33
|
-
},
|
|
34
|
-
set(key, value) {
|
|
35
|
-
return cache.set(key, [value, Date.now()]);
|
|
36
|
-
},
|
|
37
|
-
get(key) {
|
|
38
|
-
if (cache.get(key)) {
|
|
39
|
-
return cache.get(key)[0];
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
dump() {
|
|
46
|
-
const dump = {};
|
|
47
|
-
for (const [key, value] of cache.entries()) {
|
|
48
|
-
const timestamp = new Date(value[1]);
|
|
49
|
-
dump[key] = { key, value: JSON.stringify(value[0]), timestamp };
|
|
50
|
-
}
|
|
51
|
-
return dump;
|
|
52
|
-
},
|
|
53
|
-
getModels() {
|
|
54
|
-
const models = [];
|
|
55
|
-
for (const [key, value] of cache.entries()) {
|
|
56
|
-
if (key.startsWith('model:')) {
|
|
57
|
-
models.push(key.replace('model:', ''));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return models;
|
|
61
|
-
},
|
|
62
|
-
remove(key) {
|
|
63
|
-
if (cache.has(key)) {
|
|
64
|
-
cache.delete(key);
|
|
65
|
-
}
|
|
66
|
-
return;
|
|
67
|
-
},
|
|
68
|
-
clear() {
|
|
69
|
-
cache.clear();
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
function getRules(ruleList, ruleSeverities) {
|
|
74
|
-
const ruleConfig = {};
|
|
75
|
-
ruleList.forEach((rule) => {
|
|
76
|
-
ruleConfig[`@sap/cds/${rule}`] = ruleSeverities[rule];
|
|
77
|
-
});
|
|
78
|
-
return ruleConfig;
|
|
79
|
-
}
|
|
80
|
-
exports.getRules = getRules;
|
|
81
|
-
function getFileExtensions() {
|
|
82
|
-
return constants_1.Constants.overrides[0].files;
|
|
83
|
-
}
|
|
84
|
-
exports.getFileExtensions = getFileExtensions;
|
|
85
|
-
function getAST(code) {
|
|
86
|
-
return {
|
|
87
|
-
type: 'Program',
|
|
88
|
-
body: [],
|
|
89
|
-
sourceType: 'module',
|
|
90
|
-
tokens: [],
|
|
91
|
-
comments: [],
|
|
92
|
-
range: [0, code.length],
|
|
93
|
-
loc: {
|
|
94
|
-
start: {
|
|
95
|
-
line: 1,
|
|
96
|
-
column: 0
|
|
97
|
-
},
|
|
98
|
-
end: {
|
|
99
|
-
line: 1,
|
|
100
|
-
column: 0
|
|
101
|
-
},
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
exports.getAST = getAST;
|
|
106
|
-
function getProxy(obj) {
|
|
107
|
-
const handler = {
|
|
108
|
-
get(target, prop, receiver) {
|
|
109
|
-
const value = Reflect.get(target, prop, receiver);
|
|
110
|
-
if (['model', 'environment'].includes(prop)) {
|
|
111
|
-
if (prop === 'model') {
|
|
112
|
-
prop = `model:${exports.Cache.get('configpath')}`;
|
|
113
|
-
}
|
|
114
|
-
return exports.Cache.get(prop);
|
|
115
|
-
}
|
|
116
|
-
if (typeof value !== 'object') {
|
|
117
|
-
return value;
|
|
118
|
-
}
|
|
119
|
-
if (!!value) {
|
|
120
|
-
return new Proxy(value, handler);
|
|
121
|
-
}
|
|
122
|
-
return { err: `Property ${prop} prop does not exist on object ${obj}!` };
|
|
123
|
-
},
|
|
124
|
-
apply(target, thisArg, argumentsList) {
|
|
125
|
-
const result = Reflect.apply(target, this, argumentsList);
|
|
126
|
-
return result;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
return new Proxy(obj, handler);
|
|
130
|
-
}
|
|
131
|
-
exports.getProxy = getProxy;
|
|
132
|
-
function getConfigPath(currentDir = ".") {
|
|
133
|
-
const configFiles = [
|
|
134
|
-
".eslintrc.js",
|
|
135
|
-
".eslintrc.cjs",
|
|
136
|
-
".eslintrc.yaml",
|
|
137
|
-
".eslintrc.yml",
|
|
138
|
-
".eslintrc.json",
|
|
139
|
-
".eslintrc",
|
|
140
|
-
"package.json",
|
|
141
|
-
];
|
|
142
|
-
let configDir = path.resolve(currentDir);
|
|
143
|
-
while (configDir !== path.resolve(configDir, "..")) {
|
|
144
|
-
for (let i = 0; i < configFiles.length; i++) {
|
|
145
|
-
const configPath = path.join(configDir, configFiles[i]);
|
|
146
|
-
if (fs.existsSync(configPath) && fs.statSync(configPath).isFile()) {
|
|
147
|
-
return configPath;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
configDir = path.join(configDir, "..");
|
|
151
|
-
}
|
|
152
|
-
throw new Error('Failed to find an ESLint configuration file!');
|
|
153
|
-
}
|
|
154
|
-
exports.getConfigPath = getConfigPath;
|
|
155
|
-
function loadModel(code = '', configPath, filePath) {
|
|
156
|
-
let cdsObject;
|
|
157
|
-
if (process.argv[1].includes('jest') || process.argv[1].includes('mocha')) {
|
|
158
|
-
if (code) {
|
|
159
|
-
try {
|
|
160
|
-
cdsObject = cds.compile.to.csn(code);
|
|
161
|
-
}
|
|
162
|
-
catch (errSingleFile) {
|
|
163
|
-
cdsObject = { err: errSingleFile };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
try {
|
|
169
|
-
const roots = cds.env.roots.map((root) => {
|
|
170
|
-
return `${path.join(configPath, root)}`;
|
|
171
|
-
});
|
|
172
|
-
let files = [];
|
|
173
|
-
if (roots) {
|
|
174
|
-
cdsObject = cds.load(roots, { cwd: configPath, sync: true, locations: true });
|
|
175
|
-
files = cdsObject.$sources;
|
|
176
|
-
if (files && files.length > 0) {
|
|
177
|
-
exports.Cache.set(`modelfiles:${configPath}`, files);
|
|
178
|
-
files.forEach((file) => {
|
|
179
|
-
exports.Cache.set(`file:${file}`, fs.readFileSync(file, 'utf8'));
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
if (!files || !files.includes(filePath)) {
|
|
184
|
-
try {
|
|
185
|
-
cdsObject = cds.compile.to.csn(code);
|
|
186
|
-
}
|
|
187
|
-
catch (errSingleFile) {
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
catch (err) {
|
|
192
|
-
cdsObject = { err: err };
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
exports.Cache.set(`model:${configPath}`, cdsObject);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
exports.loadModel = loadModel;
|
|
199
|
-
function updateModel(code, configPath, filePath) {
|
|
200
|
-
let cdsObject;
|
|
201
|
-
let files = [];
|
|
202
|
-
const dictFiles = {};
|
|
203
|
-
if (exports.Cache.has(`modelfiles:${configPath}`)) {
|
|
204
|
-
files = exports.Cache.get(`modelfiles:${configPath}`);
|
|
205
|
-
files.forEach((file) => {
|
|
206
|
-
if (exports.Cache.has(`file:${file}`)) {
|
|
207
|
-
dictFiles[file] = exports.Cache.get(`file:${file}`);
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
dictFiles[file] = fs.readFileSync(file, 'utf8');
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
try {
|
|
214
|
-
cdsObject = cds.compile.to.csn(dictFiles, { sync: true, locations: true });
|
|
215
|
-
}
|
|
216
|
-
catch (err) {
|
|
217
|
-
cdsObject = { err: err.message };
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
if (!files || !files.includes(filePath)) {
|
|
221
|
-
try {
|
|
222
|
-
cdsObject = cds.compile.to.csn(code);
|
|
223
|
-
}
|
|
224
|
-
catch (errSingleFile) {
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
exports.Cache.set(`model:${configPath}`, cdsObject);
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
exports.updateModel = updateModel;
|
|
231
|
-
function styleText(msg, styles) {
|
|
232
|
-
const types = {
|
|
233
|
-
reset: '\x1b[0m',
|
|
234
|
-
bold: '\x1b[1m',
|
|
235
|
-
link: '\x1b[4m',
|
|
236
|
-
red: '\x1b[31m',
|
|
237
|
-
green: '\x1b[32m',
|
|
238
|
-
yellow: '\x1b[33m',
|
|
239
|
-
};
|
|
240
|
-
let msgStyle = '';
|
|
241
|
-
styles.forEach((style) => {
|
|
242
|
-
msgStyle += types[style];
|
|
243
|
-
});
|
|
244
|
-
return `${msgStyle}${msg}${types['reset']}`;
|
|
245
|
-
}
|
|
246
|
-
exports.styleText = styleText;
|
|
247
|
-
function getRange(code, line, column) {
|
|
248
|
-
let lines;
|
|
249
|
-
if (typeof code === 'string') {
|
|
250
|
-
lines = eslint_1.SourceCode.splitLines(code);
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
lines = code;
|
|
254
|
-
}
|
|
255
|
-
const ranges = [0];
|
|
256
|
-
lines.forEach((line, i) => {
|
|
257
|
-
if (i === 0) {
|
|
258
|
-
ranges[i + 1] = line.length + 1;
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
ranges[i + 1] = ranges[i] + line.length + 1;
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
if (line > 1) {
|
|
265
|
-
return ranges[line - 1] + column;
|
|
266
|
-
}
|
|
267
|
-
else {
|
|
268
|
-
return column;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
exports.getRange = getRange;
|
|
272
|
-
function getLastLine(code) {
|
|
273
|
-
let lines;
|
|
274
|
-
if (typeof code === 'string') {
|
|
275
|
-
lines = eslint_1.SourceCode.splitLines(code);
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
lines = code;
|
|
279
|
-
}
|
|
280
|
-
return lines.length - 1;
|
|
281
|
-
}
|
|
282
|
-
exports.getLastLine = getLastLine;
|
|
283
|
-
function getLocation(name, obj) {
|
|
284
|
-
const loc = {
|
|
285
|
-
start: { line: 0, column: 0 },
|
|
286
|
-
end: { line: 1, column: 0 }
|
|
287
|
-
};
|
|
288
|
-
if (obj.$location) {
|
|
289
|
-
const nameloc = obj.$location;
|
|
290
|
-
if (nameloc.col === 0) {
|
|
291
|
-
nameloc.col = 1;
|
|
292
|
-
}
|
|
293
|
-
loc.start.column = nameloc.col - 1;
|
|
294
|
-
loc.start.line = nameloc.line;
|
|
295
|
-
loc.end.column = nameloc.col - 1 + name.length;
|
|
296
|
-
loc.end.line = nameloc.line;
|
|
297
|
-
}
|
|
298
|
-
return loc;
|
|
299
|
-
}
|
|
300
|
-
exports.getLocation = getLocation;
|
|
301
|
-
function getDisabledFromComments(code, sourcecode, line) {
|
|
302
|
-
const listDisabled = [];
|
|
303
|
-
const matches = [...code.matchAll(REGEX_COMMENTS)];
|
|
304
|
-
matches === null || matches === void 0 ? void 0 : matches.forEach((match) => {
|
|
305
|
-
const index = match.index;
|
|
306
|
-
match = match[0];
|
|
307
|
-
if (match.includes('*/')) {
|
|
308
|
-
match = match.split('*/')[0].replace('/*', '');
|
|
309
|
-
}
|
|
310
|
-
else if (match.includes('//')) {
|
|
311
|
-
match = match.split('//')[1];
|
|
312
|
-
}
|
|
313
|
-
if (match)
|
|
314
|
-
match = match.trim();
|
|
315
|
-
['disable', 'enable'].forEach((keyword) => {
|
|
316
|
-
const loc = sourcecode === null || sourcecode === void 0 ? void 0 : sourcecode.getLocFromIndex(index);
|
|
317
|
-
const disableType = match.split(' ')[0];
|
|
318
|
-
let disableRules = match.split(`${disableType} `)[1];
|
|
319
|
-
if (disableRules) {
|
|
320
|
-
disableRules = disableRules.split(',').map((rule) => rule.trim());
|
|
321
|
-
}
|
|
322
|
-
else {
|
|
323
|
-
disableRules = constants_1.Constants.envRules.concat(constants_1.Constants.modelRules).map((rule) => `@sap/cds/${rule}`);
|
|
324
|
-
}
|
|
325
|
-
let comment = {};
|
|
326
|
-
if ([
|
|
327
|
-
`eslint-${keyword}`,
|
|
328
|
-
`eslint-${keyword}-line`,
|
|
329
|
-
`eslint-${keyword}-next-line`
|
|
330
|
-
].includes(disableType)) {
|
|
331
|
-
if (disableType.includes('-next-line')) {
|
|
332
|
-
comment = { lineComment: loc.line, lineDisabled: (loc.line + 1), rules: disableRules, type: keyword };
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
comment = { lineComment: loc.line, lineDisabled: loc.line, rules: disableRules, type: keyword };
|
|
336
|
-
}
|
|
337
|
-
if (!disableType.includes('-line')) {
|
|
338
|
-
comment.lineDisabled = 'EOF';
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
listDisabled.push(comment);
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
const rules = constants_1.Constants.envRules.concat(constants_1.Constants.modelRules).map((rule) => `@sap/cds/${rule}`);
|
|
345
|
-
const rulesDisabled = rules.reduce((o, key) => (Object.assign(Object.assign({}, o), { [key]: "on" })), {});
|
|
346
|
-
for (let i = 0; i <= listDisabled.length - 1; i++) {
|
|
347
|
-
if (listDisabled[i].lineComment > line) {
|
|
348
|
-
break;
|
|
349
|
-
}
|
|
350
|
-
if (listDisabled[i].lineDisabled === 'EOF' ||
|
|
351
|
-
(listDisabled[i].lineDisabled === line)) {
|
|
352
|
-
if (listDisabled[i].lineDisabled === 'EOF') {
|
|
353
|
-
listDisabled[i].lineDisabled = getLastLine(code);
|
|
354
|
-
}
|
|
355
|
-
if (listDisabled[i].rules) {
|
|
356
|
-
listDisabled[i].rules.forEach((rule) => {
|
|
357
|
-
if (listDisabled[i].type === 'disable') {
|
|
358
|
-
rulesDisabled[rule] = "off";
|
|
359
|
-
}
|
|
360
|
-
else if (listDisabled[i].type === 'enable') {
|
|
361
|
-
rulesDisabled[rule] = "on";
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return rulesDisabled;
|
|
368
|
-
}
|
|
369
|
-
exports.getDisabledFromComments = getDisabledFromComments;
|
|
370
|
-
//# sourceMappingURL=utils.js.map
|