@sap/eslint-plugin-cds 2.3.2 → 2.3.3

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 (43) hide show
  1. package/CHANGELOG.md +11 -50
  2. package/lib/api/index.js +11 -13
  3. package/lib/api/lint.d.ts +48 -0
  4. package/lib/constants.js +54 -0
  5. package/lib/index.js +44 -0
  6. package/lib/{impl/parser.js → parser.js} +2 -13
  7. package/lib/processor.js +47 -0
  8. package/lib/{impl/rules → rules}/assoc2many-ambiguous-key.js +50 -53
  9. package/lib/rules/latest-cds-version.js +42 -0
  10. package/lib/rules/min-node-version.js +47 -0
  11. package/lib/rules/no-db-keywords.js +46 -0
  12. package/lib/rules/no-dollar-prefixed-names.js +47 -0
  13. package/lib/{impl/rules → rules}/no-join-on-draft-enabled-entities.js +14 -11
  14. package/lib/rules/require-2many-oncond.js +27 -0
  15. package/lib/rules/sql-cast-suggestion.js +52 -0
  16. package/lib/rules/start-elements-lowercase.js +61 -0
  17. package/lib/rules/start-entities-uppercase.js +55 -0
  18. package/lib/{impl/rules → rules}/valid-csv-header.js +17 -9
  19. package/lib/{impl/utils → utils}/fuzzySearch.js +0 -0
  20. package/lib/utils/helpers.js +55 -0
  21. package/lib/{impl/utils → utils}/jsonc.js +0 -0
  22. package/lib/{impl/utils → utils}/model.js +107 -221
  23. package/lib/utils/ruleHelpers.js +56 -0
  24. package/lib/utils/ruleTester.js +79 -0
  25. package/lib/utils/rules.js +1033 -0
  26. package/lib/{impl/utils → utils}/validate.js +2 -18
  27. package/package.json +2 -2
  28. package/lib/impl/constants.js +0 -30
  29. package/lib/impl/index.js +0 -63
  30. package/lib/impl/processor.js +0 -23
  31. package/lib/impl/ruleFactory.js +0 -360
  32. package/lib/impl/rules/cds-compile-error.js +0 -34
  33. package/lib/impl/rules/latest-cds-version.js +0 -51
  34. package/lib/impl/rules/min-node-version.js +0 -44
  35. package/lib/impl/rules/no-db-keywords.js +0 -38
  36. package/lib/impl/rules/require-2many-oncond.js +0 -31
  37. package/lib/impl/rules/rule.hbs +0 -20
  38. package/lib/impl/rules/sql-cast-suggestion.js +0 -52
  39. package/lib/impl/rules/start-elements-lowercase.js +0 -75
  40. package/lib/impl/rules/start-entities-uppercase.js +0 -65
  41. package/lib/impl/types.d.ts +0 -48
  42. package/lib/impl/utils/helpers.js +0 -68
  43. package/lib/impl/utils/rules.js +0 -697
@@ -12,7 +12,7 @@ module.exports = {
12
12
  * @returns
13
13
  */
14
14
  isValidRule: function (context, rules) {
15
- if (rules.includes(context.ruleID.replace("@sap/cds/", ""))) {
15
+ if (rules.includes(context.id.replace("@sap/cds/", ""))) {
16
16
  return true;
17
17
  }
18
18
  return false;
@@ -32,21 +32,5 @@ module.exports = {
32
32
  return true; // allow no model
33
33
  }
34
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
- },
35
+ }
52
36
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/eslint-plugin-cds",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
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": [
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "author": "SAP SE (https://www.sap.com)",
14
14
  "license": "See LICENSE file",
15
- "main": "lib/impl/index.js",
15
+ "main": "lib/index.js",
16
16
  "files": [
17
17
  "lib/",
18
18
  "CHANGELOG.md",
@@ -1,30 +0,0 @@
1
- /**
2
- * This file contains all constants for:
3
- * - categories: The category labels we use to for model and environment rules
4
- * - customRulesDir: The custom rules directory name in the user's project home
5
- * which contains the subdirs 'docs', 'rules' and 'tests'
6
- * - globals: The globals which should be exposed to ESLint by this plugin
7
- * - files: Any additional file extensions which ESLint should lint
8
- */
9
-
10
- module.exports = {
11
- categories: {
12
- env: "Environment",
13
- model: "Model Validation",
14
- },
15
- customRulesDir: ".eslint",
16
- globals: {
17
- SELECT: true,
18
- INSERT: true,
19
- UPDATE: true,
20
- DELETE: true,
21
- CREATE: true,
22
- DROP: true,
23
- CDL: true,
24
- CQL: true,
25
- CXL: true,
26
- cds: true,
27
- },
28
- files: ["*.cds", "*.csn", "*.csv"],
29
- modelFiles: ["*.cds", "*.csn"],
30
- };
package/lib/impl/index.js DELETED
@@ -1,63 +0,0 @@
1
- /**
2
- * Custom ESLint plugin:
3
- * https://eslint.org/docs/developer-guide/working-with-plugins
4
- * This file exposes our plugins ESLint configuration, which must:
5
- * - Expose any 'configs' for prescribed rule configuration bundles
6
- * (i.e. "recommended"). See shareable configs:
7
- * https://eslint.org/docs/developer-guide/shareable-configs
8
- * - Expose any 'globals' for use in ESLint
9
- * - Expose any 'processors' for use in ESLint
10
- * - Expose any 'rules' for use in ESLint
11
- * We also initiate and cache the objects 'rulesInfo' and 'cds' for later use.
12
- */
13
-
14
- const path = require("path");
15
- const processor = require("./processor");
16
- const plugin = require("../../package.json").name;
17
-
18
- const { getRules } = require("../impl/utils/rules");
19
- const {
20
- Cache,
21
- getCDSProxy,
22
- getLocation,
23
- getRange,
24
- } = require("../impl/utils/model");
25
- const { files, globals } = require("./constants");
26
-
27
- const cds = require("@sap/cds");
28
- cds.getLocation = getLocation;
29
- cds.getRange = getRange;
30
- Cache.set("cds", getCDSProxy(cds));
31
-
32
- let rulesInfo;
33
- if (!Cache.has("rulesInfo")) {
34
- rulesInfo = getRules(path.join(__dirname, "rules"));
35
- Cache.set("rulesInfo", rulesInfo);
36
- } else {
37
- rulesInfo = Cache.get("rulesInfo");
38
- }
39
- const recommended = Object.assign({},
40
- ...Object.entries(rulesInfo.rules)
41
- .filter(([k,v]) => (v.meta.docs.recommended))
42
- .map(([k,v]) => ({ [`@sap/cds/${k}`]:v.meta.severity }))
43
- );
44
-
45
- module.exports = {
46
- configs: {
47
- recommended: {
48
- globals,
49
- plugins: [plugin],
50
- overrides: [
51
- {
52
- files: files,
53
- processor: "@sap/cds/cds",
54
- },
55
- ],
56
- rules: recommended,
57
- },
58
- },
59
- processors: {
60
- cds: processor,
61
- },
62
- rules: rulesInfo.rules,
63
- };
@@ -1,23 +0,0 @@
1
- /**
2
- * ESLint custom processor:
3
- * https://eslint.org/docs/developer-guide/working-with-plugins#processors-in-plugins
4
- * This processor is used to avoid parsing errors when this plugin is extended
5
- * in ESLint alongside other plugins, such as prettier which then also try to
6
- * read the new file types exposed via globs.
7
- * Note, that because we cache the file contents and return empty files, the
8
- * plugin's parser is not actually used and we must retrieve the file contents
9
- * later on (ruleFactory).
10
- */
11
-
12
- const { Cache } = require("./utils/model");
13
- const { isValidFile } = require("./utils/helpers");
14
-
15
- module.exports = {
16
- preprocess: function (text, filename) {
17
- if (isValidFile(filename)) {
18
- Cache.set(`file:${filename}`, text);
19
- }
20
- return [{ text: "", filename }];
21
- },
22
- supportsAutofix: true,
23
- };
@@ -1,360 +0,0 @@
1
- /**
2
- * Rule report object (as prescribed by ESLint):
3
- * https://eslint.org/docs/developer-guide/working-with-rules
4
- *
5
- * Each ESLint rule module must be composed of a 'meta', 'create' object:
6
- * - 'meta': meta data for rule (docs, fixable, etc.)
7
- * - 'create': ingests rule context and returns object with nodes to visit
8
- * while traversing the AST
9
- *
10
- * Since we want to lint cds models without an AST, we adapted the context
11
- * object to explicitly pass some additional information:
12
- * - 'category' : Rule category
13
- * - 'cds' : Proxy for cds object which also caches results
14
- * - 'code' : Code object based on ESLint getFromSourceCode()
15
- * - 'ruleID' : Rule ID ("@sap/cds/...")
16
- * - 'filePath' : ESLint's 'physical' filename
17
- * - 'options' : CDS Environment parameters
18
- * - 'report' : Proxy for ESLint's context.report() for lint filtering
19
- * - 'ruleID' : ESLint's rule ID
20
- * - 'sourcecode': ESLint's SourceCode object
21
- *
22
- * @typedef { import('eslint').Rule.RuleModule } RuleModule
23
- * @typedef { import('eslint').Rule.RuleContext } RuleContext
24
- * @typedef { import('eslint').Rule.Node } RuleNode
25
- * @typedef { import("./types").CDSRuleSpec } CDSRuleSpec
26
- * @typedef { import("./types").CDSRuleMetaData } CDSRuleMetaData
27
- * @typedef { import("./types").CDSRuleContext } CDSRuleContext
28
- * @typedef { import("./types").CDSRuleTestOpts } CDSRuleTestOpts
29
- */
30
-
31
- const fs = require("fs");
32
- const path = require("path");
33
- const { RuleTester, SourceCode } = require("eslint");
34
- const { isEditor, isValidFile } = require("./utils/helpers");
35
- const { isValidEnv, isValidModel } = require("./utils/validate");
36
- const {
37
- Cache,
38
- populateModelAndEnv,
39
- hasCompilationError,
40
- getAST,
41
- initModelRuleTester,
42
- loadConfigPath,
43
- } = require("./utils/model");
44
- const { isRuleDisabled, getRules, populateRules } = require("./utils/rules");
45
- const { customRulesDir, categories } = require("./constants");
46
-
47
- /**
48
- * Wrapper for ESLint's Rule creator:
49
- * https://eslint.org/docs/developer-guide/working-with-rules
50
- * - Must follow the ESLint prescribed convention for all rule exports
51
- * - ESLint uses 'create' function to traverse its AST nodes
52
- * - Since we do not work with an AST for cds models, a dummy 'Programm'
53
- * node is used as an entry point
54
- * - For all ESLint rules, we have two entry points for additional checks:
55
- * 1. Before ESLint's rule creation via create()
56
- * (see below)
57
- * 2. Before ESLint's report via context.report()
58
- * (see getProxyReport())
59
- * @param {CDSRuleSpec} spec
60
- * @returns {RuleModule}
61
- */
62
- function createRule(spec) {
63
- const { meta, create } = spec;
64
- return {
65
- meta,
66
- create: function (context) {
67
- return {
68
- Program: function (node) {
69
- // --- Checks before create() ---
70
- let cdscontext = createCDSContext(context, node, meta);
71
- // 1. Is file exension allowed?
72
- // (i.e. when using globs + other plugins)
73
- if (
74
- isValidFile(cdscontext.filePath) ||
75
- meta.docs.category === categories["env"]
76
- ) {
77
- // Update model/env contents and rules (at runtime)
78
- populateModelAndEnv(cdscontext);
79
- populateRules(cdscontext, customRulesDir);
80
- // 2. Is rule allowed and model/env valid?
81
- if (isValidEnv(cdscontext) || isValidModel(cdscontext)) {
82
- try {
83
- create(cdscontext);
84
- } catch (err) {
85
- if (isEditor()) { // Do not throw to avoid ESLint VSCode editor pop-ups
86
- console.error(`An error occurred while linting. Rule: ${cdscontext.ruleID}\n`, err);
87
- } else {
88
- throw err;
89
- }
90
- }
91
- // Show compilation error only on console
92
- } else if (hasCompilationError(cdscontext) && !isEditor()) {
93
- create(cdscontext);
94
- }
95
- }
96
- },
97
- };
98
- },
99
- };
100
- }
101
-
102
- /**
103
- * Experimental wrapper for 'createRule' to yield:
104
- * - More eslint-like API
105
- * - More convenience re error reports
106
- * @param {CDSRuleSpec} spec
107
- * @returns {RuleModule}
108
- */
109
- function defineRule(spec) {
110
- const { meta, create } = spec;
111
- if (!meta.type) meta.type = "problem";
112
- if (meta.docs && !meta.docs.category) meta.docs.category = "Model Validation";
113
- return createRule({
114
- meta,
115
- create: (context) => {
116
- const { cds, report } = context;
117
- const handlers = create({
118
- cds,
119
- model: cds.model,
120
- report: (r) => report(r),
121
- });
122
- if (cds.model) {
123
- cds.model.forall((d) => {
124
- for (let each in handlers)
125
- if (d.is(each)) {
126
- let r = handlers[each](d);
127
- if (r) {
128
- if (typeof r === "string") r = { message: r };
129
- if (!r.loc) r.loc = cds.getLocation(d.name, d);
130
- if (!r.file)
131
- r.file = (d.$location && d.$location.file) || "unknown.cds";
132
- context.report(r);
133
- }
134
- }
135
- });
136
- }
137
- },
138
- });
139
- }
140
-
141
- /**
142
- * Generates proxy for ESLint's context object which adds caching
143
- * @param obj ESLint's context object
144
- * @returns Proxy for cds
145
- */
146
- function getProxyReport(obj) {
147
- const handler = {
148
- get(target, prop, receiver) {
149
- const value = Reflect.get(target, prop, receiver);
150
- if (typeof value !== "object") {
151
- return value;
152
- }
153
- /* eslint no-extra-boolean-cast: "off" */
154
- if (!!value) {
155
- return new Proxy(value, handler);
156
- }
157
- return {
158
- err: `Property ${prop} prop does not exist on object ${obj}!`,
159
- };
160
- },
161
- apply(target, thisArg, argumentsList) {
162
- let report = false;
163
- if (argumentsList.length > 0) {
164
- argumentsList.forEach((lint) => {
165
- if (lint) {
166
- // --- Checks before context.report() ---
167
- // 1. Is lint (loc) not disabled by ESLint disable comments?
168
- if (!isRuleDisabled(lint, thisArg)) {
169
- const fileRel = lint.file;
170
- let fileAbs = lint.file || "";
171
- if (!path.isAbsolute(fileAbs)) {
172
- fileAbs = fileRel
173
- ? path.join(Cache.get("configpath"), fileRel)
174
- : "";
175
- }
176
- // Only show 'env' lints on console
177
- if (thisArg.category === "env" && !isEditor()) {
178
- lint["loc"] = {
179
- start: { line: 0, column: -1 },
180
- end: { line: 0, column: -1 },
181
- };
182
- if (!seenReport(lint, thisArg.ruleID)) {
183
- report = true;
184
- }
185
- // Only show 'model' lints at corrsponding file
186
- } else if (
187
- fileAbs === thisArg.filePath ||
188
- fileRel === "<stdin>.cds"
189
- ) {
190
- report = true;
191
- }
192
- if (report) {
193
- return thisArg._context.report(lint);
194
- }
195
- }
196
- }
197
- });
198
- }
199
- },
200
- };
201
- return new Proxy(obj, handler);
202
- }
203
-
204
- function seenReport(msg, ruleID) {
205
- let seenReports = [];
206
- if (Cache.has("reports")) {
207
- seenReports = Cache.get("reports");
208
- }
209
- const lintString = `configpath:${Cache.get('configpath')}|rule:${ruleID}|` +
210
- `message:${msg.message}|` +
211
- `loc:${msg.loc.start.line},${msg.loc.start.column}-${msg.loc.end.line},${msg.loc.end.column}`;
212
- if (!seenReports.includes(lintString)) {
213
- seenReports.push(lintString);
214
- Cache.set("reports", seenReports);
215
- return false;
216
- } else {
217
- return true;
218
- }
219
- }
220
-
221
- /**
222
- * Expands CDS context object with some CDS properties
223
- * We also retrieve the file contents cached by the preprocessor
224
- * @param {RuleContext} context
225
- * @param {RuleNode} node
226
- * @returns cdscontext
227
- */
228
- function createCDSContext(context, node, meta) {
229
- const filePath = context.getPhysicalFilename();
230
- let configPath;
231
- if (!Cache.has("pluginpath")) {
232
- configPath = loadConfigPath(filePath);
233
- } else {
234
- configPath = Cache.get("configpath")
235
- }
236
- let category = "model";
237
- if (meta.docs.category === categories["env"]) {
238
- category = "env";
239
- }
240
- let sourcecode = context.getSourceCode();
241
- let code = sourcecode.getText(node);
242
- if (!code) {
243
- code = Cache.get(`file:${context.getPhysicalFilename()}`);
244
- }
245
- if (code) {
246
- sourcecode = new SourceCode(code, getAST(code));
247
- }
248
- return {
249
- _context: context,
250
- ...context,
251
- category,
252
- cds: context.parserServices.cdsProxy || Cache.get("cds"),
253
- configPath,
254
- code,
255
- filePath,
256
- options: context.options,
257
- report: getProxyReport(context.report),
258
- ruleID: context.id,
259
- sourcecode
260
- };
261
- }
262
-
263
- function getProxyRun(obj) {
264
- const handler = {
265
- get(target, prop, receiver) {
266
- const value = Reflect.get(target, prop, receiver);
267
- if (typeof value !== "object") {
268
- return value;
269
- }
270
- /* eslint no-extra-boolean-cast: "off" */
271
- if (!!value) {
272
- return new Proxy(value, handler);
273
- }
274
- return {
275
- err: `Property ${prop} prop does not exist on object ${obj}!`,
276
- };
277
- },
278
- apply(target, thisArg, argumentsList) {
279
- return thisArg.run();
280
- },
281
- };
282
- return new Proxy(obj, handler);
283
- }
284
-
285
- /**
286
- * ESLint RuleTester (used by custom rule creator api)
287
- * Calls ESLint's RuleTester with custom cds parser and input for
288
- * valid/invalid checks:
289
- * Model checks require input 'code' entries
290
- * Env checks require input 'options' with selected parameters
291
- * @param {CDSRuleTestOpts} options RuleTester input options
292
- * @returns RuleTester results
293
- */
294
- function runRuleTester(options, dryRun=false) {
295
- let parser;
296
- let rule = {};
297
- process.env.LINT_FLAVOR = "inferred";
298
- const rulename = path.basename(options.root);
299
- const plugin = "eslint-plugin-cds";
300
- if (options.root.includes(plugin)) {
301
- // For plugin's internal tests, resolve parser from here
302
- parser = require.resolve("./parser");
303
- rule = require(`./rules/${path.basename(options.root)}`);
304
- const pluginPath = path.join(path.dirname(options.root), "../..");
305
- Cache.set(
306
- "rulesInfo",
307
- getRules(path.join(path.dirname(options.root), "../../lib/impl/rules"))
308
- );
309
- Cache.set("pluginpath", pluginPath);
310
- } else {
311
- // Otherwise from project root
312
- const resolvedPlugin = require.resolve("@sap/eslint-plugin-cds", {
313
- paths: [options.root],
314
- });
315
- parser = path.join(path.dirname(resolvedPlugin), "parser");
316
- rule = require(path.join(
317
- options.root,
318
- `../../rules/${path.basename(options.root)}`
319
- ));
320
- const pluginPath = path.join(path.dirname(options.root), "../../../..");
321
- Cache.set("rulesInfo", getRules(path.join(options.root, "../../rules")));
322
- Cache.set("pluginpath", pluginPath);
323
- }
324
- let category = categories["model"];
325
- if (rule.meta) {
326
- category = rule.meta.docs.category;
327
- }
328
- let tester = new RuleTester({});
329
- if (parser) {
330
- tester = new RuleTester({ parser });
331
- }
332
- const testerCases = {};
333
- ["valid", "invalid"].forEach((type) => {
334
- const filePath = path.join(options.root, `${type}/${options.filename}`);
335
- testerCases[type] = [
336
- {
337
- filename: filePath,
338
- },
339
- ];
340
- if (category === categories["env"]) {
341
- testerCases[type][0].code = "";
342
- testerCases[type][0].options = [
343
- { environment: JSON.parse(fs.readFileSync(filePath, "utf8")) },
344
- ];
345
- } else if (!category || category === categories.model) {
346
- testerCases[type][0].code = fs.readFileSync(filePath, "utf8");
347
- initModelRuleTester(filePath);
348
- }
349
- if (type === "invalid") {
350
- testerCases[type][0].errors = options.errors;
351
- const fileFixed = path.join(options.root, `fixed/${options.filename}`);
352
- if (fs.existsSync(fileFixed) && rule.meta.type !== "suggestion") {
353
- testerCases[type][0].output = fs.readFileSync(fileFixed, "utf8");
354
- }
355
- }
356
- });
357
- return tester.run(rulename, rule, testerCases);
358
- }
359
-
360
- module.exports = { createRule, defineRule, runRuleTester };
@@ -1,34 +0,0 @@
1
- module.exports = require("../../api").createRule({
2
- meta: {
3
- docs: {
4
- description: `Checks whether the CDS model file can be compiled by the @sap/cds wihtout errors.`,
5
- category: "Model Validation",
6
- version: "1.0.0",
7
- },
8
- severity: "error",
9
- type: "problem",
10
- },
11
- create: function (context) {
12
- const m = context.cds.model;
13
- if (m && m.err) {
14
- // If any csn compile errors occur
15
- m.err.messages.forEach((err) => {
16
- const msg = err.message;
17
- let file = "";
18
- const loc = {
19
- start: { line: 0, column: 0 },
20
- end: { line: 1, column: 0 },
21
- };
22
- // Get its location if it exists
23
- if (err.$location) {
24
- loc.start.column = err.$location.col;
25
- loc.start.line = err.$location.line;
26
- loc.end.column = err.$location.endCol;
27
- loc.end.line = err.$location.endLine;
28
- file = err.$location.file;
29
- }
30
- context.report({ message: `${msg}`, loc, file });
31
- });
32
- }
33
- }
34
- });
@@ -1,51 +0,0 @@
1
- const os = require("os");
2
- const cp = require("child_process");
3
- const semver = require("semver");
4
-
5
- const IS_WIN = os.platform() === "win32";
6
-
7
- module.exports = require("../../api").createRule({
8
- meta: {
9
- docs: {
10
- description: "Checks whether the latest `@sap/cds` version is being used.",
11
- category: "Environment",
12
- version: "1.0.4",
13
- },
14
- type: "suggestion",
15
- hasSuggestions: true,
16
- messages: {
17
- latestCDSVersion: `A newer CDS version is available!`,
18
- },
19
- },
20
- create: function (context) {
21
- let result;
22
- let cdsVersions;
23
- const e = context.cds.environment;
24
- if (!e) {
25
- try {
26
- result = cp
27
- .execSync(`npm outdated @sap/cds --json`, {
28
- cwd: process.cwd(),
29
- shell: IS_WIN,
30
- stdio: "pipe",
31
- })
32
- .toString();
33
- cdsVersions = JSON.parse(result)["@sap/cds"];
34
- } catch (err) {
35
- // Do not throw
36
- }
37
- } else {
38
- cdsVersions = context.cds.environment["@sap/cds"];
39
- }
40
- // If current cds version is not the latest
41
- if (
42
- Object.keys(cdsVersions).length !== 0 &&
43
- !semver.satisfies(cdsVersions.latest, cdsVersions.current)
44
- ) {
45
- // Add to ESLint report
46
- context.report({
47
- messageId: "latestCDSVersion",
48
- });
49
- }
50
- },
51
- });
@@ -1,44 +0,0 @@
1
- const path = require("path");
2
- const semver = require("semver");
3
-
4
- module.exports = require("../../api").createRule({
5
- meta: {
6
- docs: {
7
- description: `Checks whether the minimum Node.js version required by \`@sap/cds\` is achieved.`,
8
- category: "Environment",
9
- recommended: true,
10
- version: "1.0.0",
11
- },
12
- severity: "error",
13
- type: "problem",
14
- },
15
- create: function (context) {
16
- const e = context.cds.environment;
17
- let nodeVersion, nodeVersionCDS;
18
- if (!e) {
19
- // Get current and required node versions
20
- try {
21
- const CDSPath = require.resolve("@sap/cds/package.json", {
22
- paths: [path.dirname(context.filePath)],
23
- });
24
- const jsonCDS = require(CDSPath);
25
- nodeVersion = process.version;
26
- nodeVersionCDS = jsonCDS.engines.node;
27
- } catch (err) {
28
- // Do not throw
29
- }
30
- } else {
31
- nodeVersion = context.cds.environment.nodeVersion;
32
- nodeVersionCDS = context.cds.environment.nodeVersionCDS;
33
- }
34
- if (
35
- nodeVersion &&
36
- nodeVersionCDS &&
37
- !semver.satisfies(nodeVersion, nodeVersionCDS, { loose: true })
38
- ) {
39
- context.report({
40
- message: `CDS minimum node version of ${nodeVersionCDS} required, found ${nodeVersion}!`,
41
- });
42
- }
43
- },
44
- });
@@ -1,38 +0,0 @@
1
- module.exports = require("../../api").defineRule({
2
- meta: {
3
- docs: {
4
- description: `Avoid using reserved SQL keywords.`,
5
- category: "Model Validation",
6
- recommended: true,
7
- version: "2.1.0",
8
- },
9
- severity: "error"
10
- },
11
- create(context) {
12
- const { db = { kind: "sql" } } = context.cds.env.requires;
13
- function _check(d) {
14
- if (d.name in RESERVED) {
15
- // Do not blame in case of external services
16
- let srv = d._service || (d.parent && d.parent._service);
17
- if (srv && srv["@cds.external"]) return;
18
-
19
- // Do blame
20
- return `'${d.name}' is a reserved keyword in ${db.kind.toUpperCase()}`;
21
- }
22
- }
23
- return { entity: _check, element: _check };
24
- },
25
- });
26
-
27
- // REVISIT: Replace by compiler-provided check
28
- const RESERVED = {
29
- ORDER: 1,
30
- Order: 1,
31
- order: 1,
32
- GROUP: 1,
33
- Group: 1,
34
- group: 1,
35
- LIMIT: 1,
36
- Limit: 1,
37
- limit: 1,
38
- };