@sap/eslint-plugin-cds 2.0.5 → 2.2.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.
package/lib/impl/index.js CHANGED
@@ -1,35 +1,58 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
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, recommended } = 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
+
40
+ module.exports = {
41
+ configs: {
42
+ recommended: {
43
+ globals,
44
+ plugins: [plugin],
45
+ overrides: [
46
+ {
47
+ files: files,
48
+ processor: "@sap/cds/cds",
49
+ },
50
+ ],
51
+ rules: recommended,
52
+ },
53
+ },
54
+ processors: {
55
+ cds: processor,
56
+ },
57
+ rules: rulesInfo.rules,
4
58
  };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.configs = exports.globals = exports.rules = void 0;
7
- const constants_1 = require("./constants");
8
- const csn_compile_error_1 = __importDefault(require("./rules/csn-compile-error"));
9
- const assocs_card_flaw_1 = __importDefault(require("./rules/assocs-card-flaw"));
10
- const latest_cds_version_1 = __importDefault(require("./rules/latest-cds-version"));
11
- const lower_camelcase_elements_1 = __importDefault(require("./rules/lower-camelcase-elements"));
12
- const min_node_version_1 = __importDefault(require("./rules/min-node-version"));
13
- const sql_cast_suggestion_1 = __importDefault(require("./rules/sql-cast-suggestion"));
14
- const upper_camelcase_entities_1 = __importDefault(require("./rules/upper-camelcase-entities"));
15
- const rules = {
16
- "csn-compile-error": csn_compile_error_1.default,
17
- "assocs-card-flaw": assocs_card_flaw_1.default,
18
- "latest-cds-version": latest_cds_version_1.default,
19
- "lower-camelcase-elements": lower_camelcase_elements_1.default,
20
- "min-node-version": min_node_version_1.default,
21
- "sql-cast-suggestion": sql_cast_suggestion_1.default,
22
- "upper-camelcase-entities": upper_camelcase_entities_1.default
23
- };
24
- exports.rules = rules;
25
- const configs = {
26
- "recommended": {
27
- "plugins": ["@sap/eslint-plugin-cds"],
28
- "overrides": constants_1.Constants.overrides,
29
- "rules": constants_1.Constants.recRules
30
- }
31
- };
32
- exports.configs = configs;
33
- const globals = constants_1.Constants.globals;
34
- exports.globals = globals;
35
- //# sourceMappingURL=index.js.map
@@ -1,27 +1,39 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.parseForESLint = exports.parse = void 0;
7
- const utils_1 = require("./utils");
8
- const cds_1 = __importDefault(require("@sap/cds"));
9
- function parse(code, options) {
10
- return parseForESLint(code, options).ast;
11
- }
12
- exports.parse = parse;
13
- function parseForESLint(code, options) {
14
- cds_1.default.getLocation = utils_1.getLocation;
15
- cds_1.default.getRange = utils_1.getRange;
1
+ /**
2
+ * Custom ESLint parser:
3
+ * https://eslint.org/docs/developer-guide/working-with-custom-parsers
4
+ * This file must:
5
+ * - Expose 'parseForESLint' method on the parser which should return the AST,
6
+ * optional properties services, a scopeManager, and visitorKeys
7
+ * - Expose default method 'parse' which should return the AST
8
+ * Both methods should take in the source code and an optional configuration
9
+ * (parserOptions). Note, that because we use a 'empty' preprocessor, the
10
+ * parser is only used by ESLint's ruleTester.
11
+ */
12
+
13
+ const {
14
+ getAST,
15
+ getCDSProxy,
16
+ getLocation,
17
+ getRange,
18
+ } = require("../impl/utils/model");
19
+ const cds = require("@sap/cds");
20
+
21
+ module.exports = {
22
+ parse: function (code, options) {
23
+ return module.exports.parseForESLint(code, options).ast;
24
+ },
25
+
26
+ parseForESLint: function (code) {
27
+ cds.getLocation = getLocation;
28
+ cds.getRange = getRange;
16
29
  return {
17
- ast: utils_1.getAST(code),
18
- services: {
19
- cdsProxy: utils_1.getProxy(cds_1.default)
20
- },
21
- scopeManager: null,
22
- tokensAndComments: [],
23
- visitorKeys: null
30
+ ast: getAST(code),
31
+ services: {
32
+ cdsProxy: getCDSProxy(cds),
33
+ },
34
+ scopeManager: null,
35
+ tokensAndComments: [],
36
+ visitorKeys: null,
24
37
  };
25
- }
26
- exports.parseForESLint = parseForESLint;
27
- //# sourceMappingURL=parser.js.map
38
+ },
39
+ };
@@ -0,0 +1,23 @@
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,159 +1,311 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runRuleTester = exports.createRule = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const eslint_1 = require("eslint");
10
- const utils_1 = require("./utils");
11
- const constants_1 = require("./constants");
12
- function createRule(defineMeta, defineReport) {
13
- return {
14
- meta: Object.assign({}, defineMeta),
15
- create(context) {
16
- {
17
- return cbRuleFunctions(context, defineReport);
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, styleText } = require("./utils/helpers");
35
+ const { isValidEnv, isValidModel } = require("./utils/validate");
36
+ const {
37
+ Cache,
38
+ populateModelAndEnv,
39
+ hasCompilationError,
40
+ getAST,
41
+ loadConfigPath,
42
+ } = require("./utils/model");
43
+ const { isRuleDisabled, getRules, populateRules } = require("./utils/rules");
44
+ const { customRulesDir, categories } = require("./constants");
45
+
46
+ /**
47
+ * Wrapper for ESLint's Rule creator:
48
+ * https://eslint.org/docs/developer-guide/working-with-rules
49
+ * - Must follow the ESLint prescribed convention for all rule exports
50
+ * - ESLint uses 'create' function to traverse its AST nodes
51
+ * - Since we do not work with an AST for cds models, a dummy 'Programm'
52
+ * node is used as an entry point
53
+ * - For all ESLint rules, we have two entry points for additional checks:
54
+ * 1. Before ESLint's rule creation via create()
55
+ * (see below)
56
+ * 2. Before ESLint's report via context.report()
57
+ * (see getProxyReport())
58
+ * @param {CDSRuleSpec} spec
59
+ * @returns {RuleModule}
60
+ */
61
+ function createRule(spec) {
62
+ const { meta, create } = spec;
63
+ if (!meta.type) meta.type = "problem";
64
+ if (meta.docs && !meta.docs.category)
65
+ meta.docs.category = categories["model"];
66
+ return {
67
+ meta,
68
+ create: function (context) {
69
+ return {
70
+ Program: function (node) {
71
+ // --- Checks before create() ---
72
+ let cdscontext = createCDSContext(context, node, meta);
73
+ // 1. Is file exension allowed?
74
+ // (i.e. when using globs + other plugins)
75
+ if (
76
+ isValidFile(cdscontext.filePath) ||
77
+ meta.docs.category === categories["env"]
78
+ ) {
79
+ // Update model/env contents and rules (at runtime)
80
+ populateModelAndEnv(cdscontext);
81
+ populateRules(cdscontext, customRulesDir);
82
+ // 2. Is rule allowed and model/env valid?
83
+ if (isValidEnv(cdscontext) || isValidModel(cdscontext)) {
84
+ try {
85
+ create(cdscontext);
86
+ } catch (err) {
87
+ // Do not throw to avoid ESLint VSCode editor pop-ups
88
+ styleText(
89
+ `Rule ${cdscontext.ruleID} has failed unexpectedly - please report this error!\n`,
90
+ ["bold", "red"]
91
+ );
92
+ }
93
+ // Show compilation error only on console
94
+ } else if (hasCompilationError(cdscontext) && !isEditor()) {
95
+ create(cdscontext);
18
96
  }
19
- }
20
- };
97
+ }
98
+ },
99
+ };
100
+ },
101
+ };
21
102
  }
22
- exports.createRule = createRule;
23
- function cbRuleFunctions(context, defineReport) {
24
- return {
25
- Program(node) {
26
- var _a;
27
- let report = [];
28
- const ruleID = context.id;
29
- const cds = context.parserServices.cdsProxy;
30
- const sourcecode = context.getSourceCode();
31
- const code = sourcecode.getText(node);
32
- const filePath = context.getFilename();
33
- let configPath = path_1.default.dirname(utils_1.getConfigPath(filePath));
34
- utils_1.Cache.set('configpath', configPath);
35
- utils_1.loadModel(code, configPath, filePath);
36
- utils_1.updateConfigPath(code, configPath, filePath);
37
- configPath = utils_1.Cache.get('configpath');
38
- if (utils_1.Cache.has(`file:${filePath}`) && code !== utils_1.Cache.get(`file:${filePath}`)) {
39
- utils_1.Cache.set(`file:${filePath}`, code);
40
- utils_1.updateModel(code, configPath, filePath);
103
+
104
+ /**
105
+ * Experimental wrapper for 'createRule' to yield:
106
+ * - More eslint-like API
107
+ * - More convenience re error reports
108
+ * @param {CDSRuleSpec} spec
109
+ * @returns {RuleModule}
110
+ */
111
+ function defineRule(spec) {
112
+ const { meta, create } = spec;
113
+ if (!meta.type) meta.type = "problem";
114
+ if (meta.docs && !meta.docs.category) meta.docs.category = "Model Validation";
115
+ return createRule({
116
+ meta,
117
+ create: (context) => {
118
+ const { cds, report } = context;
119
+ const handlers = create({
120
+ cds,
121
+ model: cds.model,
122
+ report: (r) => report(r),
123
+ });
124
+ if (cds.model) {
125
+ cds.model.forall((d) => {
126
+ for (let each in handlers)
127
+ if (d.is(each)) {
128
+ let r = handlers[each](d);
129
+ if (r) {
130
+ if (typeof r === "string") r = { message: r };
131
+ if (!r.loc) r.loc = cds.getLocation(d.name, d);
132
+ if (!r.file)
133
+ r.file = (d.$location && d.$location.file) || "unknown.cds";
134
+ context.report(r);
135
+ }
41
136
  }
42
- if ((_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.environment) {
43
- utils_1.Cache.set(`environment`, context.options[0].environment);
44
- }
45
- const properties = { filePath, configPath, ruleID, code, sourcecode };
46
- if (isValidModel(cds, ruleID)) {
47
- if ((cds === null || cds === void 0 ? void 0 : cds.model) || (cds === null || cds === void 0 ? void 0 : cds.environment)) {
48
- report = defineReport(cds, context, node);
49
- }
50
- if (report.length > 0) {
51
- reportErrors(report, context, properties);
52
- }
53
- }
54
- else {
55
- if (hasCompilationError(cds, ruleID) && !isEditor()) {
56
- report = defineReport(cds, context, node);
57
- if (report.length > 0) {
58
- reportErrors(report, context, properties);
59
- }
60
- }
61
- }
62
- }
63
- };
64
- }
65
- function isValidModel(cds, ruleID) {
66
- var _a;
67
- if (((cds === null || cds === void 0 ? void 0 : cds.model) && !((_a = cds === null || cds === void 0 ? void 0 : cds.model) === null || _a === void 0 ? void 0 : _a.err)) ||
68
- (cds === null || cds === void 0 ? void 0 : cds.environment) &&
69
- !(ruleID === '@sap/cds/csn-compile-error' || ruleID === 'csn-compile-error')) {
70
- return true;
71
- }
72
- return false;
73
- }
74
- function hasCompilationError(cds, ruleID) {
75
- var _a, _b, _c, _d;
76
- if (((_a = cds === null || cds === void 0 ? void 0 : cds.model) === null || _a === void 0 ? void 0 : _a.err) && ((_d = (_c = (_b = cds === null || cds === void 0 ? void 0 : cds.model) === null || _b === void 0 ? void 0 : _b.err) === null || _c === void 0 ? void 0 : _c.message) === null || _d === void 0 ? void 0 : _d.startsWith('CDS compilation failed'))) {
77
- if (ruleID === '@sap/cds/csn-compile-error' || ruleID === 'csn-compile-error') {
78
- return true;
79
- }
80
- }
81
- return false;
82
- }
83
- function isEditor() {
84
- return process.argv.join(' ').includes('dbaeumer.vscode-eslint');
137
+ });
138
+ }
139
+ },
140
+ });
85
141
  }
86
- function reportErrors(report, context, properties) {
87
- report.forEach((entry, i) => {
88
- var _a, _b;
89
- if (entry) {
90
- const ruleID = properties.ruleID;
91
- const configPath = properties.configPath;
92
- const fileRel = entry.file;
93
- let fileAbs = entry.file || '';
94
- if (!path_1.default.isAbsolute(fileAbs)) {
95
- fileAbs = (fileRel) ? path_1.default.join(utils_1.Cache.get('configpath'), fileRel) : '';
142
+
143
+ /**
144
+ * Generates proxy for ESLint's context object which adds caching
145
+ * @param obj ESLint's context object
146
+ * @returns Proxy for cds
147
+ */
148
+ function getProxyReport(obj) {
149
+ const handler = {
150
+ get(target, prop, receiver) {
151
+ const value = Reflect.get(target, prop, receiver);
152
+ if (typeof value !== "object") {
153
+ return value;
154
+ }
155
+ /* eslint no-extra-boolean-cast: "off" */
156
+ if (!!value) {
157
+ return new Proxy(value, handler);
158
+ }
159
+ return {
160
+ err: `Property ${prop} prop does not exist on object ${obj}!`,
161
+ };
162
+ },
163
+ apply(target, thisArg, argumentsList) {
164
+ let report = false;
165
+ if (argumentsList.length > 0) {
166
+ argumentsList.forEach((lint) => {
167
+ if (lint) {
168
+ // --- Checks before context.report() ---
169
+ // 1. Is lint (loc) not disabled by ESLint disable comments?
170
+ if (!isRuleDisabled(lint, thisArg)) {
171
+ const fileRel = lint.file;
172
+ let fileAbs = lint.file || "";
173
+ if (!path.isAbsolute(fileAbs)) {
174
+ fileAbs = fileRel
175
+ ? path.join(Cache.get("configpath"), fileRel)
176
+ : "";
177
+ }
178
+ // Only show 'env' lints on console
179
+ if (thisArg.category === "env" && !isEditor()) {
180
+ lint["loc"] = {
181
+ start: { line: 0, column: -1 },
182
+ end: { line: 0, column: -1 },
183
+ };
184
+ report = true;
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
+ }
96
195
  }
97
- const line = (_b = (_a = entry === null || entry === void 0 ? void 0 : entry.loc) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.line;
98
- const rulesDisabled = utils_1.getDisabledFromComments(properties.code, properties.sourcecode, line);
99
- let isDisabled = false;
100
- if (line && ruleID in rulesDisabled && rulesDisabled[ruleID] === "off") {
101
- isDisabled = true;
102
- }
103
- if (!isDisabled) {
104
- if (constants_1.Constants.envRules.includes(ruleID) || constants_1.Constants.envRules.includes(ruleID.replace('@sap/cds/', ''))) {
105
- if (!isEditor()) {
106
- if (!utils_1.Cache.has(`envChecks:${configPath}`)) {
107
- context.report(entry);
108
- utils_1.Cache.set(`envChecks:${configPath}`, [entry.message]);
109
- }
110
- else if (utils_1.Cache.has(`envChecks:${configPath}`) && !utils_1.Cache.get(`envChecks:${configPath}`).includes(entry.message)) {
111
- context.report(entry);
112
- utils_1.Cache.set(`envChecks:${configPath}`, [entry.message]);
113
- }
114
- }
115
- }
116
- else if ((fileRel && ((fileAbs === properties.filePath) || fileRel === '<stdin>.cds'))) {
117
- context.report(entry);
118
- }
119
- }
120
- }
121
- });
196
+ }
197
+ });
198
+ }
199
+ },
200
+ };
201
+ return new Proxy(obj, handler);
202
+ }
203
+
204
+ /**
205
+ * Expands CDS context object with some CDS properties
206
+ * We also retrieve the file contents cached by the preprocessor
207
+ * @param {RuleContext} context
208
+ * @param {RuleNode} node
209
+ * @returns cdscontext
210
+ */
211
+ function createCDSContext(context, node, meta) {
212
+ const filePath = context.getPhysicalFilename();
213
+ const configPath = loadConfigPath(filePath);
214
+ let category = "model";
215
+ if (meta.docs.category === categories["env"]) {
216
+ category = "env";
217
+ }
218
+ let sourcecode = context.getSourceCode();
219
+ let code = sourcecode.getText(node);
220
+ if (!code) {
221
+ code = Cache.get(`file:${context.getPhysicalFilename()}`);
222
+ }
223
+ if (code) {
224
+ sourcecode = new SourceCode(code, getAST(code));
225
+ }
226
+ return {
227
+ _context: context,
228
+ ...context,
229
+ category,
230
+ cds: context.parserServices.cdsProxy || Cache.get("cds"),
231
+ configPath,
232
+ code,
233
+ filePath,
234
+ options: context.options,
235
+ report: getProxyReport(context.report),
236
+ ruleID: context.id,
237
+ sourcecode,
238
+ };
122
239
  }
240
+
241
+ /**
242
+ * ESLint RuleTester (used by custom rule creator api)
243
+ * Calls ESLint's RuleTester with custom cds parser and input for
244
+ * valid/invalid checks:
245
+ * Model checks require input 'code' entries
246
+ * Env checks require input 'options' with selected parameters
247
+ * @param {CDSRuleTestOpts} options RuleTester input options
248
+ * @returns RuleTester results
249
+ */
123
250
  function runRuleTester(options) {
124
- let parser;
125
- if (options.root.includes('eslint-plugin-cds')) {
126
- parser = path_1.default.join(path_1.default.resolve('.'), 'src/impl/parser');
251
+ process.env['RULE_TESTER'] = true;
252
+ let parser;
253
+ let rule = {};
254
+ const rulename = path.basename(options.root);
255
+ const plugin = "eslint-plugin-cds";
256
+ if (options.root.includes(plugin)) {
257
+ // For plugin's internal tests, resolve parser from here
258
+ parser = require.resolve("./parser");
259
+ rule = require(`./rules/${path.basename(options.root)}`);
260
+ Cache.set(
261
+ "rulesInfo",
262
+ getRules(path.join(path.dirname(options.root), "../../lib/impl/rules"))
263
+ );
264
+ } else {
265
+ // Otherwise from project root
266
+ const resolvedPlugin = require.resolve("@sap/eslint-plugin-cds", {
267
+ paths: [options.root],
268
+ });
269
+ parser = path.join(path.dirname(resolvedPlugin), "parser");
270
+ rule = require(path.join(
271
+ options.root,
272
+ `../../rules/${path.basename(options.root)}`
273
+ ));
274
+ Cache.set("rulesInfo", getRules(path.join(options.root, "../../rules")));
275
+ }
276
+ let category = categories["model"];
277
+ if (rule.meta) {
278
+ category = rule.meta.docs.category;
279
+ }
280
+ let tester = new RuleTester({});
281
+ if (parser) {
282
+ tester = new RuleTester({ parser });
283
+ }
284
+ const testerCases = {};
285
+ ["valid", "invalid"].forEach((type) => {
286
+ const filePath = path.join(options.root, `${type}/${options.filename}`);
287
+ testerCases[type] = [
288
+ {
289
+ filename: filePath,
290
+ },
291
+ ];
292
+ if (category === categories["env"]) {
293
+ testerCases[type][0].code = "";
294
+ testerCases[type][0].options = [
295
+ { environment: JSON.parse(fs.readFileSync(filePath, "utf8")) },
296
+ ];
297
+ } else if (!category || category === categories.model) {
298
+ testerCases[type][0].code = fs.readFileSync(filePath, "utf8");
127
299
  }
128
- else {
129
- const resolvedPlugin = require.resolve('@sap/eslint-plugin-cds', { paths: [options.root] });
130
- parser = path_1.default.join(path_1.default.dirname(resolvedPlugin), 'parser');
300
+ if (type === "invalid") {
301
+ testerCases[type][0].errors = options.errors;
302
+ const fileFixed = path.join(options.root, `fixed/${options.filename}`);
303
+ if (fs.existsSync(fileFixed)) {
304
+ testerCases[type][0].output = fs.readFileSync(fileFixed, "utf8");
305
+ }
131
306
  }
132
- const category = options.rule['meta']['docs']['category'];
133
- const rulename = path_1.default.basename(options.root);
134
- const tester = new eslint_1.RuleTester({ parser });
135
- const testerCases = {};
136
- ['valid', 'invalid'].forEach((type) => {
137
- const filePath = path_1.default.join(options.root, `${type}/${options.filename}`);
138
- testerCases[type] = [{
139
- filename: filePath
140
- }];
141
- if (category === 'Environment') {
142
- testerCases[type][0].code = '';
143
- testerCases[type][0].options = [{ "environment": JSON.parse(fs_1.default.readFileSync(filePath, 'utf8')) }];
144
- }
145
- else if (category === 'Model Validation') {
146
- testerCases[type][0].code = fs_1.default.readFileSync(filePath, 'utf8');
147
- }
148
- if (type === 'invalid') {
149
- testerCases[type][0].errors = options.errors;
150
- const fileFixed = path_1.default.join(options.root, `fixed/${options.filename}`);
151
- if (fs_1.default.existsSync(fileFixed)) {
152
- testerCases[type][0].output = fs_1.default.readFileSync(fileFixed, 'utf8');
153
- }
154
- }
155
- });
156
- return tester.run(rulename, options.rule, testerCases);
307
+ });
308
+ return tester.run(rulename, rule, testerCases);
157
309
  }
158
- exports.runRuleTester = runRuleTester;
159
- //# sourceMappingURL=ruleFactory.js.map
310
+
311
+ module.exports = { createRule, defineRule, runRuleTester };