@echoes-of-order/eslint-config 1.121.0
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 +1093 -0
- package/configs/.gitkeep +1 -0
- package/configs/admin.js +203 -0
- package/configs/api-client.js +46 -0
- package/configs/backend.js +895 -0
- package/configs/domains.js +123 -0
- package/configs/frontend.js +30 -0
- package/configs/image-server.js +26 -0
- package/configs/ionos-proxy.js +372 -0
- package/configs/nestjs.js +156 -0
- package/configs/node.js +92 -0
- package/configs/react.js +111 -0
- package/configs/wiki.js +42 -0
- package/index.js +39 -0
- package/package.json +85 -0
- package/rules/.gitkeep +1 -0
- package/rules/__tests__/analyze-relation-usage.test.js.disabled +300 -0
- package/rules/__tests__/complexity.test.js.disabled +300 -0
- package/rules/__tests__/enforce-dto-factory-in-services.integration.test.js +226 -0
- package/rules/__tests__/enforce-dto-factory-in-services.test.js +177 -0
- package/rules/__tests__/enforce-entity-dto-create-no-id.integration.test.js +18 -0
- package/rules/__tests__/enforce-function-argument-count.test.js.disabled +300 -0
- package/rules/__tests__/enforce-repository-token-handling.test.js +58 -0
- package/rules/__tests__/english-only-code-strings.test.js.disabled +300 -0
- package/rules/__tests__/eslint-rules.integration.test.ts +350 -0
- package/rules/__tests__/integration-test-controller-response-dto.js +261 -0
- package/rules/__tests__/integration-test-dto-factory-in-services.js +260 -0
- package/rules/__tests__/integration-test-no-entity-type-casting.js +161 -0
- package/rules/__tests__/integration-test-typeorm-naming-conventions.js +501 -0
- package/rules/__tests__/test-config.js +33 -0
- package/rules/admin-controller-security.js +180 -0
- package/rules/analyze-relation-usage.js +687 -0
- package/rules/api-response-dto.js +174 -0
- package/rules/auth-guard-required.js +142 -0
- package/rules/backend-specific.js +36 -0
- package/rules/best-practices.js +421 -0
- package/rules/complexity.js +20 -0
- package/rules/controller-architecture.js +340 -0
- package/rules/controller-naming-conventions.js +190 -0
- package/rules/controller-readonly-restriction.js +148 -0
- package/rules/controller-swagger-complete.js +312 -0
- package/rules/controller-swagger-docs.js +119 -0
- package/rules/controller-swagger-english.js +320 -0
- package/rules/coordinate-naming.js +132 -0
- package/rules/custom-mui-button.js +135 -0
- package/rules/dead-code-detection-backend.js +50 -0
- package/rules/dead-code-detection-frontend.js +48 -0
- package/rules/dead-code-detection.js +71 -0
- package/rules/debug-controller-response-dto.js +79 -0
- package/rules/deprecate.js +8 -0
- package/rules/dto-annotation-property-consistency.js +111 -0
- package/rules/dto-entity-mapping-completeness.js +688 -0
- package/rules/dto-entity-swagger-separation.js +265 -0
- package/rules/dto-entity-type-consistency.js +352 -0
- package/rules/dto-entity-type-matching.js +519 -0
- package/rules/dto-naming-convention.js +98 -0
- package/rules/dto-visibility-modifiers.js +159 -0
- package/rules/enforce-api-versioning.js +122 -0
- package/rules/enforce-app-module-registration.js +179 -0
- package/rules/enforce-basecontroller.js +152 -0
- package/rules/enforce-body-request-dto.js +141 -0
- package/rules/enforce-controller-response-dto.js +349 -0
- package/rules/enforce-custom-error-classes.js +242 -0
- package/rules/enforce-database-transaction-safety.js +179 -0
- package/rules/enforce-dto-constructor.js +95 -0
- package/rules/enforce-dto-create-parameter-types.js +170 -0
- package/rules/enforce-dto-create-pattern.js +274 -0
- package/rules/enforce-dto-entity-creation.js +164 -0
- package/rules/enforce-dto-factory-in-services.js +188 -0
- package/rules/enforce-dto-from-entity-method.js +47 -0
- package/rules/enforce-dto-from-entity.js +314 -0
- package/rules/enforce-dto-naming-conventions.js +212 -0
- package/rules/enforce-dto-naming.js +176 -0
- package/rules/enforce-dto-usage-simple.js +114 -0
- package/rules/enforce-dto-usage.js +407 -0
- package/rules/enforce-eager-translation-loading.js +178 -0
- package/rules/enforce-entity-creation-pattern.js +137 -0
- package/rules/enforce-entity-dto-convert-method.js +157 -0
- package/rules/enforce-entity-dto-create-no-id.js +117 -0
- package/rules/enforce-entity-dto-extends-base.js +141 -0
- package/rules/enforce-entity-dto-from-request-dto-structure.js +113 -0
- package/rules/enforce-entity-dto-fromentity-complex.js +69 -0
- package/rules/enforce-entity-dto-fromentity-simple.js +69 -0
- package/rules/enforce-entity-dto-fromrequestdto-structure.js +262 -0
- package/rules/enforce-entity-dto-methods-restriction.js +159 -0
- package/rules/enforce-entity-dto-no-request-dto.js +102 -0
- package/rules/enforce-entity-dto-optional-auto-fields.js +101 -0
- package/rules/enforce-entity-dto-required-methods.js +248 -0
- package/rules/enforce-entity-factory-pattern.js +180 -0
- package/rules/enforce-entity-instantiation-in-toentity.js +125 -0
- package/rules/enforce-enum-for-playable-entities.js +95 -0
- package/rules/enforce-error-handling.js +257 -0
- package/rules/enforce-explicit-dto-types.js +118 -0
- package/rules/enforce-from-request-dto-usage.js +62 -0
- package/rules/enforce-generic-entity-dto.js +71 -0
- package/rules/enforce-inject-decorator.js +133 -0
- package/rules/enforce-lazy-type-loading.js +170 -0
- package/rules/enforce-module-existence.js +157 -0
- package/rules/enforce-nonentity-dto-create.js +107 -0
- package/rules/enforce-playable-entity-naming.js +108 -0
- package/rules/enforce-repository-token-handling.js +92 -0
- package/rules/enforce-request-dto-no-entity-dto.js +201 -0
- package/rules/enforce-request-dto-required-fields.js +217 -0
- package/rules/enforce-result-pattern.js +45 -0
- package/rules/enforce-service-relation-loading.js +116 -0
- package/rules/enforce-test-coverage.js +96 -0
- package/rules/enforce-toentity-conditional-assignment.js +132 -0
- package/rules/enforce-translations-required.js +203 -0
- package/rules/enforce-typeorm-naming-conventions.js +366 -0
- package/rules/enforce-vite-health-metrics.js +240 -0
- package/rules/entity-required-properties.js +321 -0
- package/rules/entity-to-dto-test.js +73 -0
- package/rules/enum-database-validation.js +149 -0
- package/rules/errors.js +190 -0
- package/rules/es6.js +204 -0
- package/rules/eslint-plugin-no-comments.js +44 -0
- package/rules/filename-class-name-match.js +62 -0
- package/rules/forbid-fromentity-outside-entity-folder.js +237 -0
- package/rules/function-params-newline.js +111 -0
- package/rules/imports.js +264 -0
- package/rules/jest.js +13 -0
- package/rules/jsx.js +16 -0
- package/rules/max-classes-per-file.js +49 -0
- package/rules/multiline-formatting.js +146 -0
- package/rules/no-blank-lines-between-decorators-and-properties.js +95 -0
- package/rules/no-comments.js +62 -0
- package/rules/no-dto-constructors.js +126 -0
- package/rules/no-dto-default-values.js +220 -0
- package/rules/no-dto-duplicates.js +127 -0
- package/rules/no-dto-in-entity.js +99 -0
- package/rules/no-dynamic-import-in-types.js +71 -0
- package/rules/no-dynamic-imports-in-controllers.js +95 -0
- package/rules/no-entity-imports-in-controllers.js +101 -0
- package/rules/no-entity-in-swagger-docs.js +139 -0
- package/rules/no-entity-type-casting.js +104 -0
- package/rules/no-fetch.js +77 -0
- package/rules/no-import-meta-env.js +151 -0
- package/rules/no-inline-styles.js +5 -0
- package/rules/no-magic-values.js +85 -0
- package/rules/no-partial-type.js +168 -0
- package/rules/no-relative-imports.js +31 -0
- package/rules/no-tsyringe.js +181 -0
- package/rules/no-type-assertion.js +175 -0
- package/rules/no-undefined-entity-properties.js +121 -0
- package/rules/node.js +44 -0
- package/rules/perfectionist.js +50 -0
- package/rules/performance-minimal.js +155 -0
- package/rules/performance.js +44 -0
- package/rules/pino-logger-format.js +200 -0
- package/rules/prefer-dto-classes.js +112 -0
- package/rules/prefer-dto-create-method.js +225 -0
- package/rules/promises.js +17 -0
- package/rules/react-hooks.js +15 -0
- package/rules/react.js +28 -0
- package/rules/regexp.js +70 -0
- package/rules/require-dto-response.js +81 -0
- package/rules/require-valid-relations.js +388 -0
- package/rules/result-pattern.js +162 -0
- package/rules/security.js +37 -0
- package/rules/service-architecture.js +148 -0
- package/rules/sonarjs.js +26 -0
- package/rules/strict.js +7 -0
- package/rules/style.js +611 -0
- package/rules/stylistic.js +93 -0
- package/rules/typeorm-column-type-validation.js +224 -0
- package/rules/typescript-advanced.js +113 -0
- package/rules/typescript-core.js +111 -0
- package/rules/typescript.js +146 -0
- package/rules/unicorn.js +168 -0
- package/rules/variables.js +51 -0
- package/rules/websocket-architecture.js +115 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
const { RuleTester } = require('eslint');
|
|
2
|
+
|
|
3
|
+
// Simple rule implementation for enforce-function-argument-count
|
|
4
|
+
const enforcefunctionargumentcountRule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: "problem",
|
|
7
|
+
docs: {
|
|
8
|
+
description: "Test rule for enforce-function-argument-count",
|
|
9
|
+
category: "Best Practices",
|
|
10
|
+
recommended: true,
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
ruleViolation: "Rule violation detected",
|
|
15
|
+
improperUsage: "Improper usage detected",
|
|
16
|
+
magicValue: "Magic value detected",
|
|
17
|
+
anonymousObject: "Anonymous object detected",
|
|
18
|
+
typeAssertion: "Type assertion detected",
|
|
19
|
+
multipleClasses: "Multiple classes detected",
|
|
20
|
+
commentFound: "Comment found",
|
|
21
|
+
filenameClassMismatch: "Filename class mismatch",
|
|
22
|
+
visibilityModifier: "Visibility modifier detected",
|
|
23
|
+
wrongConstructor: "Wrong constructor usage",
|
|
24
|
+
nonEnglishString: "Non-English string detected",
|
|
25
|
+
complexFunction: "Function too complex",
|
|
26
|
+
wrongArgumentCount: "Wrong argument count",
|
|
27
|
+
customErrorRequired: "Custom error class required",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
create(context) {
|
|
31
|
+
return {
|
|
32
|
+
// Basic node visitors that can detect common patterns
|
|
33
|
+
Literal(node) {
|
|
34
|
+
// Test for magic values
|
|
35
|
+
if (typeof node.value === 'number' && node.value > 1 && node.value !== 0) {
|
|
36
|
+
context.report({
|
|
37
|
+
node,
|
|
38
|
+
messageId: "magicValue",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Test for non-English strings (simple check)
|
|
43
|
+
if (typeof node.value === 'string' && /[äöüßÄÖÜ]/.test(node.value)) {
|
|
44
|
+
context.report({
|
|
45
|
+
node,
|
|
46
|
+
messageId: "nonEnglishString",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
ObjectExpression(node) {
|
|
52
|
+
// Test for anonymous objects
|
|
53
|
+
if (node.properties.length > 0) {
|
|
54
|
+
context.report({
|
|
55
|
+
node,
|
|
56
|
+
messageId: "anonymousObject",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
TSAsExpression(node) {
|
|
62
|
+
// Test for type assertions
|
|
63
|
+
context.report({
|
|
64
|
+
node,
|
|
65
|
+
messageId: "typeAssertion",
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
Program(node) {
|
|
70
|
+
// Test for multiple classes
|
|
71
|
+
const classCount = node.body.filter(n => n.type === 'ClassDeclaration').length;
|
|
72
|
+
if (classCount > 1) {
|
|
73
|
+
context.report({
|
|
74
|
+
node,
|
|
75
|
+
messageId: "multipleClasses",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Test for comments
|
|
80
|
+
if (node.comments && node.comments.length > 0) {
|
|
81
|
+
node.comments.forEach(comment => {
|
|
82
|
+
context.report({
|
|
83
|
+
node: comment,
|
|
84
|
+
messageId: "commentFound",
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
ClassDeclaration(node) {
|
|
91
|
+
// Test filename-class match
|
|
92
|
+
const filename = context.getFilename();
|
|
93
|
+
const expectedClassName = filename.split('/').pop()?.replace('.ts', '') || '';
|
|
94
|
+
if (node.id?.name && node.id.name !== expectedClassName) {
|
|
95
|
+
context.report({
|
|
96
|
+
node: node.id,
|
|
97
|
+
messageId: "filenameClassMismatch",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
FunctionDeclaration(node) {
|
|
103
|
+
// Test function complexity (simple param count check)
|
|
104
|
+
if (node.params.length > 5) {
|
|
105
|
+
context.report({
|
|
106
|
+
node,
|
|
107
|
+
messageId: "complexFunction",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Test argument count
|
|
112
|
+
if (node.params.length === 0 || node.params.length > 10) {
|
|
113
|
+
context.report({
|
|
114
|
+
node,
|
|
115
|
+
messageId: "wrongArgumentCount",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
ThrowStatement(node) {
|
|
121
|
+
// Test for custom error classes
|
|
122
|
+
if (node.argument?.type === 'NewExpression' &&
|
|
123
|
+
node.argument.callee?.name === 'Error') {
|
|
124
|
+
context.report({
|
|
125
|
+
node,
|
|
126
|
+
messageId: "customErrorRequired",
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const ruleTester = new RuleTester({
|
|
135
|
+
languageOptions: {
|
|
136
|
+
ecmaVersion: 2020,
|
|
137
|
+
sourceType: 'module',
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
console.log('Testing enforce-function-argument-count rule...');
|
|
142
|
+
|
|
143
|
+
ruleTester.run('enforce-function-argument-count', {
|
|
144
|
+
create: (context) => enforcefunctionargumentcountRule.create(context),
|
|
145
|
+
meta: enforcefunctionargumentcountRule.meta,
|
|
146
|
+
}, {
|
|
147
|
+
valid: [
|
|
148
|
+
// Valid cases
|
|
149
|
+
{
|
|
150
|
+
code: `
|
|
151
|
+
export default class ValidClass {
|
|
152
|
+
constructor() {
|
|
153
|
+
this.name = '';
|
|
154
|
+
this.value = 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static create(data) {
|
|
158
|
+
const instance = new ValidClass();
|
|
159
|
+
instance.name = data.name;
|
|
160
|
+
return instance;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
processData(param1, param2) {
|
|
164
|
+
return param1 + param2;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
`,
|
|
168
|
+
filename: 'ValidClass.ts',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
code: `
|
|
172
|
+
const VALID_CONSTANT = 42;
|
|
173
|
+
function processWithConstant() {
|
|
174
|
+
return VALID_CONSTANT;
|
|
175
|
+
}
|
|
176
|
+
`,
|
|
177
|
+
filename: 'Constants.ts',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
code: `
|
|
181
|
+
import { UserDto } from './dto/UserDto';
|
|
182
|
+
|
|
183
|
+
function createUser() {
|
|
184
|
+
return new UserDto();
|
|
185
|
+
}
|
|
186
|
+
`,
|
|
187
|
+
filename: 'UserService.ts',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
code: `
|
|
191
|
+
export class UserService {
|
|
192
|
+
constructor() {}
|
|
193
|
+
|
|
194
|
+
findById(id) {
|
|
195
|
+
if (!id) {
|
|
196
|
+
throw new CustomUserError('User ID required');
|
|
197
|
+
}
|
|
198
|
+
return { id, name: 'Test User' };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
`,
|
|
202
|
+
filename: 'UserService.ts',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
code: `
|
|
206
|
+
const config = {
|
|
207
|
+
apiUrl: 'https://api.example.com',
|
|
208
|
+
timeout: 5000,
|
|
209
|
+
retries: 3
|
|
210
|
+
};
|
|
211
|
+
`,
|
|
212
|
+
filename: 'config.ts',
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
|
|
216
|
+
invalid: [
|
|
217
|
+
// Invalid cases that should trigger rule violations
|
|
218
|
+
{
|
|
219
|
+
code: `
|
|
220
|
+
function badFunction() {
|
|
221
|
+
return 42; // Magic number
|
|
222
|
+
}
|
|
223
|
+
`,
|
|
224
|
+
filename: 'badFunction.ts',
|
|
225
|
+
errors: [{ messageId: 'magicValue' }],
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
code: `
|
|
229
|
+
const data = {
|
|
230
|
+
name: 'test',
|
|
231
|
+
value: 123 // Anonymous object + magic number
|
|
232
|
+
};
|
|
233
|
+
`,
|
|
234
|
+
filename: 'data.ts',
|
|
235
|
+
errors: [
|
|
236
|
+
{ messageId: 'anonymousObject' },
|
|
237
|
+
{ messageId: 'magicValue' }
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
code: `
|
|
242
|
+
// This is a comment
|
|
243
|
+
const value = 999; // Another comment with magic number
|
|
244
|
+
`,
|
|
245
|
+
filename: 'commented.ts',
|
|
246
|
+
errors: [
|
|
247
|
+
{ messageId: 'commentFound' },
|
|
248
|
+
{ messageId: 'commentFound' },
|
|
249
|
+
{ messageId: 'magicValue' }
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
code: `
|
|
254
|
+
export class FirstClass {}
|
|
255
|
+
export class SecondClass {}
|
|
256
|
+
`,
|
|
257
|
+
filename: 'MultipleClasses.ts',
|
|
258
|
+
errors: [{ messageId: 'multipleClasses' }],
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
code: `
|
|
262
|
+
function tooManyParams(a, b, c, d, e, f, g) {
|
|
263
|
+
return a + b + c + d + e + f + g;
|
|
264
|
+
}
|
|
265
|
+
`,
|
|
266
|
+
filename: 'complex.ts',
|
|
267
|
+
errors: [{ messageId: 'complexFunction' }],
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
code: `
|
|
271
|
+
function noParams() {
|
|
272
|
+
return 42;
|
|
273
|
+
}
|
|
274
|
+
`,
|
|
275
|
+
filename: 'noparams.ts',
|
|
276
|
+
errors: [
|
|
277
|
+
{ messageId: 'wrongArgumentCount' },
|
|
278
|
+
{ messageId: 'magicValue' }
|
|
279
|
+
],
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
code: `
|
|
283
|
+
function errorThrower() {
|
|
284
|
+
throw new Error('Generic error');
|
|
285
|
+
}
|
|
286
|
+
`,
|
|
287
|
+
filename: 'errors.ts',
|
|
288
|
+
errors: [{ messageId: 'customErrorRequired' }],
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
code: `
|
|
292
|
+
const germanText = "Hällö Wörld";
|
|
293
|
+
`,
|
|
294
|
+
filename: 'international.ts',
|
|
295
|
+
errors: [{ messageId: 'nonEnglishString' }],
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
console.log('✅ enforce-function-argument-count tests completed successfully');
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tests for enforce-repository-token-handling rule
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { RuleTester } from "eslint";
|
|
6
|
+
import enforceRepositoryTokenHandling from "../enforce-repository-token-handling.js";
|
|
7
|
+
|
|
8
|
+
const ruleTester = new RuleTester({
|
|
9
|
+
languageOptions: {
|
|
10
|
+
ecmaVersion: 2022,
|
|
11
|
+
sourceType: "module",
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
ruleTester.run("enforce-repository-token-handling", enforceRepositoryTokenHandling, {
|
|
16
|
+
valid: [
|
|
17
|
+
// ✅ RICHTIG: Repository erbt von AbstractRepo
|
|
18
|
+
{
|
|
19
|
+
code: `
|
|
20
|
+
import AbstractRepo from "./AbstractRepo";
|
|
21
|
+
|
|
22
|
+
class BackendFactionRepo extends AbstractRepo {
|
|
23
|
+
async getAllFactions() {
|
|
24
|
+
const response = await this.api.get("/api/v1/admin/playable-factions");
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`,
|
|
29
|
+
filename: "src/infrastructure/BackendFactionRepo.ts",
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// ✅ RICHTIG: Nicht-Repository-Datei (wird ignoriert)
|
|
33
|
+
{
|
|
34
|
+
code: `
|
|
35
|
+
const api = new ApiClient();
|
|
36
|
+
api.setToken("token");
|
|
37
|
+
`,
|
|
38
|
+
filename: "src/components/SomeComponent.tsx",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
|
|
42
|
+
invalid: [
|
|
43
|
+
// ❌ FALSCH: Repository erbt nicht von AbstractRepo
|
|
44
|
+
{
|
|
45
|
+
code: `
|
|
46
|
+
class BackendFactionRepo {
|
|
47
|
+
async getAllFactions() {
|
|
48
|
+
return "test";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
`,
|
|
52
|
+
filename: "src/infrastructure/BackendFactionRepo.ts",
|
|
53
|
+
errors: [
|
|
54
|
+
{ messageId: "mustExtendAbstractRepo" },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
});
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
const { RuleTester } = require('eslint');
|
|
2
|
+
|
|
3
|
+
// Simple rule implementation for english-only-code-strings
|
|
4
|
+
const englishonlycodestringsRule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: "problem",
|
|
7
|
+
docs: {
|
|
8
|
+
description: "Test rule for english-only-code-strings",
|
|
9
|
+
category: "Best Practices",
|
|
10
|
+
recommended: true,
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
ruleViolation: "Rule violation detected",
|
|
15
|
+
improperUsage: "Improper usage detected",
|
|
16
|
+
magicValue: "Magic value detected",
|
|
17
|
+
anonymousObject: "Anonymous object detected",
|
|
18
|
+
typeAssertion: "Type assertion detected",
|
|
19
|
+
multipleClasses: "Multiple classes detected",
|
|
20
|
+
commentFound: "Comment found",
|
|
21
|
+
filenameClassMismatch: "Filename class mismatch",
|
|
22
|
+
visibilityModifier: "Visibility modifier detected",
|
|
23
|
+
wrongConstructor: "Wrong constructor usage",
|
|
24
|
+
nonEnglishString: "Non-English string detected",
|
|
25
|
+
complexFunction: "Function too complex",
|
|
26
|
+
wrongArgumentCount: "Wrong argument count",
|
|
27
|
+
customErrorRequired: "Custom error class required",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
create(context) {
|
|
31
|
+
return {
|
|
32
|
+
// Basic node visitors that can detect common patterns
|
|
33
|
+
Literal(node) {
|
|
34
|
+
// Test for magic values
|
|
35
|
+
if (typeof node.value === 'number' && node.value > 1 && node.value !== 0) {
|
|
36
|
+
context.report({
|
|
37
|
+
node,
|
|
38
|
+
messageId: "magicValue",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Test for non-English strings (simple check)
|
|
43
|
+
if (typeof node.value === 'string' && /[äöüßÄÖÜ]/.test(node.value)) {
|
|
44
|
+
context.report({
|
|
45
|
+
node,
|
|
46
|
+
messageId: "nonEnglishString",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
ObjectExpression(node) {
|
|
52
|
+
// Test for anonymous objects
|
|
53
|
+
if (node.properties.length > 0) {
|
|
54
|
+
context.report({
|
|
55
|
+
node,
|
|
56
|
+
messageId: "anonymousObject",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
TSAsExpression(node) {
|
|
62
|
+
// Test for type assertions
|
|
63
|
+
context.report({
|
|
64
|
+
node,
|
|
65
|
+
messageId: "typeAssertion",
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
Program(node) {
|
|
70
|
+
// Test for multiple classes
|
|
71
|
+
const classCount = node.body.filter(n => n.type === 'ClassDeclaration').length;
|
|
72
|
+
if (classCount > 1) {
|
|
73
|
+
context.report({
|
|
74
|
+
node,
|
|
75
|
+
messageId: "multipleClasses",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Test for comments
|
|
80
|
+
if (node.comments && node.comments.length > 0) {
|
|
81
|
+
node.comments.forEach(comment => {
|
|
82
|
+
context.report({
|
|
83
|
+
node: comment,
|
|
84
|
+
messageId: "commentFound",
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
ClassDeclaration(node) {
|
|
91
|
+
// Test filename-class match
|
|
92
|
+
const filename = context.getFilename();
|
|
93
|
+
const expectedClassName = filename.split('/').pop()?.replace('.ts', '') || '';
|
|
94
|
+
if (node.id?.name && node.id.name !== expectedClassName) {
|
|
95
|
+
context.report({
|
|
96
|
+
node: node.id,
|
|
97
|
+
messageId: "filenameClassMismatch",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
FunctionDeclaration(node) {
|
|
103
|
+
// Test function complexity (simple param count check)
|
|
104
|
+
if (node.params.length > 5) {
|
|
105
|
+
context.report({
|
|
106
|
+
node,
|
|
107
|
+
messageId: "complexFunction",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Test argument count
|
|
112
|
+
if (node.params.length === 0 || node.params.length > 10) {
|
|
113
|
+
context.report({
|
|
114
|
+
node,
|
|
115
|
+
messageId: "wrongArgumentCount",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
ThrowStatement(node) {
|
|
121
|
+
// Test for custom error classes
|
|
122
|
+
if (node.argument?.type === 'NewExpression' &&
|
|
123
|
+
node.argument.callee?.name === 'Error') {
|
|
124
|
+
context.report({
|
|
125
|
+
node,
|
|
126
|
+
messageId: "customErrorRequired",
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const ruleTester = new RuleTester({
|
|
135
|
+
languageOptions: {
|
|
136
|
+
ecmaVersion: 2020,
|
|
137
|
+
sourceType: 'module',
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
console.log('Testing english-only-code-strings rule...');
|
|
142
|
+
|
|
143
|
+
ruleTester.run('english-only-code-strings', {
|
|
144
|
+
create: (context) => englishonlycodestringsRule.create(context),
|
|
145
|
+
meta: englishonlycodestringsRule.meta,
|
|
146
|
+
}, {
|
|
147
|
+
valid: [
|
|
148
|
+
// Valid cases
|
|
149
|
+
{
|
|
150
|
+
code: `
|
|
151
|
+
export default class ValidClass {
|
|
152
|
+
constructor() {
|
|
153
|
+
this.name = '';
|
|
154
|
+
this.value = 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static create(data) {
|
|
158
|
+
const instance = new ValidClass();
|
|
159
|
+
instance.name = data.name;
|
|
160
|
+
return instance;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
processData(param1, param2) {
|
|
164
|
+
return param1 + param2;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
`,
|
|
168
|
+
filename: 'ValidClass.ts',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
code: `
|
|
172
|
+
const VALID_CONSTANT = 42;
|
|
173
|
+
function processWithConstant() {
|
|
174
|
+
return VALID_CONSTANT;
|
|
175
|
+
}
|
|
176
|
+
`,
|
|
177
|
+
filename: 'Constants.ts',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
code: `
|
|
181
|
+
import { UserDto } from './dto/UserDto';
|
|
182
|
+
|
|
183
|
+
function createUser() {
|
|
184
|
+
return new UserDto();
|
|
185
|
+
}
|
|
186
|
+
`,
|
|
187
|
+
filename: 'UserService.ts',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
code: `
|
|
191
|
+
export class UserService {
|
|
192
|
+
constructor() {}
|
|
193
|
+
|
|
194
|
+
findById(id) {
|
|
195
|
+
if (!id) {
|
|
196
|
+
throw new CustomUserError('User ID required');
|
|
197
|
+
}
|
|
198
|
+
return { id, name: 'Test User' };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
`,
|
|
202
|
+
filename: 'UserService.ts',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
code: `
|
|
206
|
+
const config = {
|
|
207
|
+
apiUrl: 'https://api.example.com',
|
|
208
|
+
timeout: 5000,
|
|
209
|
+
retries: 3
|
|
210
|
+
};
|
|
211
|
+
`,
|
|
212
|
+
filename: 'config.ts',
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
|
|
216
|
+
invalid: [
|
|
217
|
+
// Invalid cases that should trigger rule violations
|
|
218
|
+
{
|
|
219
|
+
code: `
|
|
220
|
+
function badFunction() {
|
|
221
|
+
return 42; // Magic number
|
|
222
|
+
}
|
|
223
|
+
`,
|
|
224
|
+
filename: 'badFunction.ts',
|
|
225
|
+
errors: [{ messageId: 'magicValue' }],
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
code: `
|
|
229
|
+
const data = {
|
|
230
|
+
name: 'test',
|
|
231
|
+
value: 123 // Anonymous object + magic number
|
|
232
|
+
};
|
|
233
|
+
`,
|
|
234
|
+
filename: 'data.ts',
|
|
235
|
+
errors: [
|
|
236
|
+
{ messageId: 'anonymousObject' },
|
|
237
|
+
{ messageId: 'magicValue' }
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
code: `
|
|
242
|
+
// This is a comment
|
|
243
|
+
const value = 999; // Another comment with magic number
|
|
244
|
+
`,
|
|
245
|
+
filename: 'commented.ts',
|
|
246
|
+
errors: [
|
|
247
|
+
{ messageId: 'commentFound' },
|
|
248
|
+
{ messageId: 'commentFound' },
|
|
249
|
+
{ messageId: 'magicValue' }
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
code: `
|
|
254
|
+
export class FirstClass {}
|
|
255
|
+
export class SecondClass {}
|
|
256
|
+
`,
|
|
257
|
+
filename: 'MultipleClasses.ts',
|
|
258
|
+
errors: [{ messageId: 'multipleClasses' }],
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
code: `
|
|
262
|
+
function tooManyParams(a, b, c, d, e, f, g) {
|
|
263
|
+
return a + b + c + d + e + f + g;
|
|
264
|
+
}
|
|
265
|
+
`,
|
|
266
|
+
filename: 'complex.ts',
|
|
267
|
+
errors: [{ messageId: 'complexFunction' }],
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
code: `
|
|
271
|
+
function noParams() {
|
|
272
|
+
return 42;
|
|
273
|
+
}
|
|
274
|
+
`,
|
|
275
|
+
filename: 'noparams.ts',
|
|
276
|
+
errors: [
|
|
277
|
+
{ messageId: 'wrongArgumentCount' },
|
|
278
|
+
{ messageId: 'magicValue' }
|
|
279
|
+
],
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
code: `
|
|
283
|
+
function errorThrower() {
|
|
284
|
+
throw new Error('Generic error');
|
|
285
|
+
}
|
|
286
|
+
`,
|
|
287
|
+
filename: 'errors.ts',
|
|
288
|
+
errors: [{ messageId: 'customErrorRequired' }],
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
code: `
|
|
292
|
+
const germanText = "Hällö Wörld";
|
|
293
|
+
`,
|
|
294
|
+
filename: 'international.ts',
|
|
295
|
+
errors: [{ messageId: 'nonEnglishString' }],
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
console.log('✅ english-only-code-strings tests completed successfully');
|