@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.
Files changed (171) hide show
  1. package/CHANGELOG.md +1093 -0
  2. package/configs/.gitkeep +1 -0
  3. package/configs/admin.js +203 -0
  4. package/configs/api-client.js +46 -0
  5. package/configs/backend.js +895 -0
  6. package/configs/domains.js +123 -0
  7. package/configs/frontend.js +30 -0
  8. package/configs/image-server.js +26 -0
  9. package/configs/ionos-proxy.js +372 -0
  10. package/configs/nestjs.js +156 -0
  11. package/configs/node.js +92 -0
  12. package/configs/react.js +111 -0
  13. package/configs/wiki.js +42 -0
  14. package/index.js +39 -0
  15. package/package.json +85 -0
  16. package/rules/.gitkeep +1 -0
  17. package/rules/__tests__/analyze-relation-usage.test.js.disabled +300 -0
  18. package/rules/__tests__/complexity.test.js.disabled +300 -0
  19. package/rules/__tests__/enforce-dto-factory-in-services.integration.test.js +226 -0
  20. package/rules/__tests__/enforce-dto-factory-in-services.test.js +177 -0
  21. package/rules/__tests__/enforce-entity-dto-create-no-id.integration.test.js +18 -0
  22. package/rules/__tests__/enforce-function-argument-count.test.js.disabled +300 -0
  23. package/rules/__tests__/enforce-repository-token-handling.test.js +58 -0
  24. package/rules/__tests__/english-only-code-strings.test.js.disabled +300 -0
  25. package/rules/__tests__/eslint-rules.integration.test.ts +350 -0
  26. package/rules/__tests__/integration-test-controller-response-dto.js +261 -0
  27. package/rules/__tests__/integration-test-dto-factory-in-services.js +260 -0
  28. package/rules/__tests__/integration-test-no-entity-type-casting.js +161 -0
  29. package/rules/__tests__/integration-test-typeorm-naming-conventions.js +501 -0
  30. package/rules/__tests__/test-config.js +33 -0
  31. package/rules/admin-controller-security.js +180 -0
  32. package/rules/analyze-relation-usage.js +687 -0
  33. package/rules/api-response-dto.js +174 -0
  34. package/rules/auth-guard-required.js +142 -0
  35. package/rules/backend-specific.js +36 -0
  36. package/rules/best-practices.js +421 -0
  37. package/rules/complexity.js +20 -0
  38. package/rules/controller-architecture.js +340 -0
  39. package/rules/controller-naming-conventions.js +190 -0
  40. package/rules/controller-readonly-restriction.js +148 -0
  41. package/rules/controller-swagger-complete.js +312 -0
  42. package/rules/controller-swagger-docs.js +119 -0
  43. package/rules/controller-swagger-english.js +320 -0
  44. package/rules/coordinate-naming.js +132 -0
  45. package/rules/custom-mui-button.js +135 -0
  46. package/rules/dead-code-detection-backend.js +50 -0
  47. package/rules/dead-code-detection-frontend.js +48 -0
  48. package/rules/dead-code-detection.js +71 -0
  49. package/rules/debug-controller-response-dto.js +79 -0
  50. package/rules/deprecate.js +8 -0
  51. package/rules/dto-annotation-property-consistency.js +111 -0
  52. package/rules/dto-entity-mapping-completeness.js +688 -0
  53. package/rules/dto-entity-swagger-separation.js +265 -0
  54. package/rules/dto-entity-type-consistency.js +352 -0
  55. package/rules/dto-entity-type-matching.js +519 -0
  56. package/rules/dto-naming-convention.js +98 -0
  57. package/rules/dto-visibility-modifiers.js +159 -0
  58. package/rules/enforce-api-versioning.js +122 -0
  59. package/rules/enforce-app-module-registration.js +179 -0
  60. package/rules/enforce-basecontroller.js +152 -0
  61. package/rules/enforce-body-request-dto.js +141 -0
  62. package/rules/enforce-controller-response-dto.js +349 -0
  63. package/rules/enforce-custom-error-classes.js +242 -0
  64. package/rules/enforce-database-transaction-safety.js +179 -0
  65. package/rules/enforce-dto-constructor.js +95 -0
  66. package/rules/enforce-dto-create-parameter-types.js +170 -0
  67. package/rules/enforce-dto-create-pattern.js +274 -0
  68. package/rules/enforce-dto-entity-creation.js +164 -0
  69. package/rules/enforce-dto-factory-in-services.js +188 -0
  70. package/rules/enforce-dto-from-entity-method.js +47 -0
  71. package/rules/enforce-dto-from-entity.js +314 -0
  72. package/rules/enforce-dto-naming-conventions.js +212 -0
  73. package/rules/enforce-dto-naming.js +176 -0
  74. package/rules/enforce-dto-usage-simple.js +114 -0
  75. package/rules/enforce-dto-usage.js +407 -0
  76. package/rules/enforce-eager-translation-loading.js +178 -0
  77. package/rules/enforce-entity-creation-pattern.js +137 -0
  78. package/rules/enforce-entity-dto-convert-method.js +157 -0
  79. package/rules/enforce-entity-dto-create-no-id.js +117 -0
  80. package/rules/enforce-entity-dto-extends-base.js +141 -0
  81. package/rules/enforce-entity-dto-from-request-dto-structure.js +113 -0
  82. package/rules/enforce-entity-dto-fromentity-complex.js +69 -0
  83. package/rules/enforce-entity-dto-fromentity-simple.js +69 -0
  84. package/rules/enforce-entity-dto-fromrequestdto-structure.js +262 -0
  85. package/rules/enforce-entity-dto-methods-restriction.js +159 -0
  86. package/rules/enforce-entity-dto-no-request-dto.js +102 -0
  87. package/rules/enforce-entity-dto-optional-auto-fields.js +101 -0
  88. package/rules/enforce-entity-dto-required-methods.js +248 -0
  89. package/rules/enforce-entity-factory-pattern.js +180 -0
  90. package/rules/enforce-entity-instantiation-in-toentity.js +125 -0
  91. package/rules/enforce-enum-for-playable-entities.js +95 -0
  92. package/rules/enforce-error-handling.js +257 -0
  93. package/rules/enforce-explicit-dto-types.js +118 -0
  94. package/rules/enforce-from-request-dto-usage.js +62 -0
  95. package/rules/enforce-generic-entity-dto.js +71 -0
  96. package/rules/enforce-inject-decorator.js +133 -0
  97. package/rules/enforce-lazy-type-loading.js +170 -0
  98. package/rules/enforce-module-existence.js +157 -0
  99. package/rules/enforce-nonentity-dto-create.js +107 -0
  100. package/rules/enforce-playable-entity-naming.js +108 -0
  101. package/rules/enforce-repository-token-handling.js +92 -0
  102. package/rules/enforce-request-dto-no-entity-dto.js +201 -0
  103. package/rules/enforce-request-dto-required-fields.js +217 -0
  104. package/rules/enforce-result-pattern.js +45 -0
  105. package/rules/enforce-service-relation-loading.js +116 -0
  106. package/rules/enforce-test-coverage.js +96 -0
  107. package/rules/enforce-toentity-conditional-assignment.js +132 -0
  108. package/rules/enforce-translations-required.js +203 -0
  109. package/rules/enforce-typeorm-naming-conventions.js +366 -0
  110. package/rules/enforce-vite-health-metrics.js +240 -0
  111. package/rules/entity-required-properties.js +321 -0
  112. package/rules/entity-to-dto-test.js +73 -0
  113. package/rules/enum-database-validation.js +149 -0
  114. package/rules/errors.js +190 -0
  115. package/rules/es6.js +204 -0
  116. package/rules/eslint-plugin-no-comments.js +44 -0
  117. package/rules/filename-class-name-match.js +62 -0
  118. package/rules/forbid-fromentity-outside-entity-folder.js +237 -0
  119. package/rules/function-params-newline.js +111 -0
  120. package/rules/imports.js +264 -0
  121. package/rules/jest.js +13 -0
  122. package/rules/jsx.js +16 -0
  123. package/rules/max-classes-per-file.js +49 -0
  124. package/rules/multiline-formatting.js +146 -0
  125. package/rules/no-blank-lines-between-decorators-and-properties.js +95 -0
  126. package/rules/no-comments.js +62 -0
  127. package/rules/no-dto-constructors.js +126 -0
  128. package/rules/no-dto-default-values.js +220 -0
  129. package/rules/no-dto-duplicates.js +127 -0
  130. package/rules/no-dto-in-entity.js +99 -0
  131. package/rules/no-dynamic-import-in-types.js +71 -0
  132. package/rules/no-dynamic-imports-in-controllers.js +95 -0
  133. package/rules/no-entity-imports-in-controllers.js +101 -0
  134. package/rules/no-entity-in-swagger-docs.js +139 -0
  135. package/rules/no-entity-type-casting.js +104 -0
  136. package/rules/no-fetch.js +77 -0
  137. package/rules/no-import-meta-env.js +151 -0
  138. package/rules/no-inline-styles.js +5 -0
  139. package/rules/no-magic-values.js +85 -0
  140. package/rules/no-partial-type.js +168 -0
  141. package/rules/no-relative-imports.js +31 -0
  142. package/rules/no-tsyringe.js +181 -0
  143. package/rules/no-type-assertion.js +175 -0
  144. package/rules/no-undefined-entity-properties.js +121 -0
  145. package/rules/node.js +44 -0
  146. package/rules/perfectionist.js +50 -0
  147. package/rules/performance-minimal.js +155 -0
  148. package/rules/performance.js +44 -0
  149. package/rules/pino-logger-format.js +200 -0
  150. package/rules/prefer-dto-classes.js +112 -0
  151. package/rules/prefer-dto-create-method.js +225 -0
  152. package/rules/promises.js +17 -0
  153. package/rules/react-hooks.js +15 -0
  154. package/rules/react.js +28 -0
  155. package/rules/regexp.js +70 -0
  156. package/rules/require-dto-response.js +81 -0
  157. package/rules/require-valid-relations.js +388 -0
  158. package/rules/result-pattern.js +162 -0
  159. package/rules/security.js +37 -0
  160. package/rules/service-architecture.js +148 -0
  161. package/rules/sonarjs.js +26 -0
  162. package/rules/strict.js +7 -0
  163. package/rules/style.js +611 -0
  164. package/rules/stylistic.js +93 -0
  165. package/rules/typeorm-column-type-validation.js +224 -0
  166. package/rules/typescript-advanced.js +113 -0
  167. package/rules/typescript-core.js +111 -0
  168. package/rules/typescript.js +146 -0
  169. package/rules/unicorn.js +168 -0
  170. package/rules/variables.js +51 -0
  171. package/rules/websocket-architecture.js +115 -0
@@ -0,0 +1,320 @@
1
+ /**
2
+ * @fileoverview Ensure all controller Swagger documentation is written in English
3
+ */
4
+
5
+ "use strict";
6
+
7
+ import { franc } from "franc";
8
+
9
+ export default {
10
+ meta: {
11
+ type: "problem",
12
+ docs: {
13
+ description: "enforce that all Swagger documentation in controllers is written in English",
14
+ category: "Best Practices",
15
+ recommended: true,
16
+ },
17
+ fixable: null,
18
+ schema: [],
19
+ messages: {
20
+ germanDocumentation: "Swagger documentation should be in English. Found German text: '{{text}}'",
21
+ nonEnglishDocumentation: "Swagger documentation should be in English. Detected language: '{{language}}' in text: '{{text}}'",
22
+ missingApiOperation: "Controller method '{{methodName}}' is missing @ApiOperation decorator",
23
+ emptyApiOperation: "Controller method '{{methodName}}' has empty @ApiOperation summary or description",
24
+ },
25
+ },
26
+
27
+ create(context) {
28
+ // Common German words that shouldn't appear in API documentation (fallback)
29
+ const germanWords = [
30
+ // Articles
31
+ "der", "die", "das", "ein", "eine", "einen", "einem", "einer", "eines",
32
+ // Common verbs
33
+ "ist", "sind", "wird", "werden", "hat", "haben", "kann", "können",
34
+ "gibt", "geben", "ruft", "abrufen", "erstellt", "erstellen", "aktualisiert",
35
+ "aktualisieren", "löscht", "löschen", "zurück", "erfolgreich",
36
+ // Common nouns
37
+ "daten", "fehler", "serverfehler", "liste", "details",
38
+ "gesundheit", "position", "koordinate", "karten",
39
+ // Adjectives/Adverbs
40
+ "alle", "aller", "neues", "neue", "bestimmten", "ungültige", "ungültiger",
41
+ // Prepositions
42
+ "mit", "von", "für", "beim", "nach", "oder", "und",
43
+ // Other common words
44
+ "nicht", "gefunden", "wo", "wenn", "dass", "welche", "welcher",
45
+ // Status messages
46
+ "erfolgreich", "fehlgeschlagen", "abgerufen", "gelöscht"
47
+ ];
48
+
49
+ // Language code mappings for better error messages
50
+ const languageNames = {
51
+ "deu": "German",
52
+ "fra": "French",
53
+ "spa": "Spanish",
54
+ "ita": "Italian",
55
+ "por": "Portuguese",
56
+ "rus": "Russian",
57
+ "jpn": "Japanese",
58
+ "kor": "Korean",
59
+ "chi": "Chinese",
60
+ "ara": "Arabic",
61
+ "hin": "Hindi",
62
+ "ben": "Bengali",
63
+ "urd": "Urdu",
64
+ "tur": "Turkish",
65
+ "pol": "Polish",
66
+ "nld": "Dutch",
67
+ "swe": "Swedish",
68
+ "dan": "Danish",
69
+ "nor": "Norwegian",
70
+ "fin": "Finnish",
71
+ };
72
+
73
+ function isControllerClass(node) {
74
+ if (node.type !== "ClassDeclaration") return false;
75
+
76
+ return node.decorators && node.decorators.some(decorator => {
77
+ return decorator.expression &&
78
+ ((decorator.expression.type === "Identifier" && decorator.expression.name === "Controller") ||
79
+ (decorator.expression.type === "CallExpression" &&
80
+ decorator.expression.callee.name === "Controller"));
81
+ });
82
+ }
83
+
84
+ function containsGermanWords(text) {
85
+ if (!text || typeof text !== "string") return null;
86
+
87
+ const lowerText = text.toLowerCase();
88
+
89
+ for (const word of germanWords) {
90
+ // Use word boundaries to avoid false positives
91
+ const regex = new RegExp(`\\b${word}\\b`, "i");
92
+ if (regex.test(lowerText)) {
93
+ return word;
94
+ }
95
+ }
96
+
97
+ return null;
98
+ }
99
+
100
+ function detectLanguageWithFranc(text) {
101
+ if (!text || typeof text !== "string" || text.trim().length < 20) {
102
+ // For very short texts, franc is unreliable, skip detection
103
+ return null;
104
+ }
105
+
106
+ try {
107
+ const detectedLanguage = franc(text);
108
+
109
+ // franc returns 'und' for undetermined language
110
+ if (detectedLanguage === "und" || detectedLanguage === "eng") {
111
+ return null; // Assume English or undetermined is OK
112
+ }
113
+
114
+ // Only report if confidence is high and text is long enough
115
+ if (text.length < 30) {
116
+ return null; // Skip detection for short technical texts
117
+ }
118
+
119
+ return detectedLanguage;
120
+ } catch (error) {
121
+ // If franc fails, fall back to word detection
122
+ return null;
123
+ }
124
+ }
125
+
126
+ function checkStringForLanguage(stringNode, context) {
127
+ if (stringNode && stringNode.type === "Literal" && typeof stringNode.value === "string") {
128
+ const text = stringNode.value.trim();
129
+
130
+ // Skip very short texts (likely single words or technical terms)
131
+ if (text.length < 10) {
132
+ return;
133
+ }
134
+
135
+ // Skip common API terms that might be misdetected
136
+ const commonApiTerms = [
137
+ "retrieved", "retrieves", "monster", "monsters", "error", "server",
138
+ "fetching", "filter", "list", "found", "not found", "successfully",
139
+ "user", "details", "available", "aura", "definitions", "specific",
140
+ "statistic", "formula", "returns", "get", "cat"
141
+ ];
142
+
143
+ const lowerText = text.toLowerCase();
144
+ const hasCommonApiTerms = commonApiTerms.some(term => lowerText.includes(term));
145
+
146
+ if (hasCommonApiTerms && text.length < 100) {
147
+ // Skip short texts with common API terms
148
+ return;
149
+ }
150
+
151
+ // Primary check: Use franc for language detection
152
+ const detectedLanguage = detectLanguageWithFranc(text);
153
+ if (detectedLanguage) {
154
+ const languageName = languageNames[detectedLanguage] || detectedLanguage;
155
+ context.report({
156
+ node: stringNode,
157
+ messageId: "nonEnglishDocumentation",
158
+ data: {
159
+ language: languageName,
160
+ text: text.substring(0, 50) + (text.length > 50 ? "..." : "")
161
+ }
162
+ });
163
+ return;
164
+ }
165
+
166
+ // Fallback check: Use German word detection for more specific cases
167
+ const germanWord = containsGermanWords(text);
168
+ if (germanWord) {
169
+ context.report({
170
+ node: stringNode,
171
+ messageId: "germanDocumentation",
172
+ data: {
173
+ text: text.substring(0, 50) + (text.length > 50 ? "..." : "")
174
+ }
175
+ });
176
+ }
177
+ }
178
+ }
179
+
180
+ function hasApiOperationDecorator(decorators) {
181
+ if (!decorators) return false;
182
+
183
+ return decorators.some(decorator => {
184
+ return decorator.expression &&
185
+ decorator.expression.type === "CallExpression" &&
186
+ decorator.expression.callee.name === "ApiOperation";
187
+ });
188
+ }
189
+
190
+ function getApiOperationContent(decorators) {
191
+ if (!decorators) return null;
192
+
193
+ for (const decorator of decorators) {
194
+ if (decorator.expression &&
195
+ decorator.expression.type === "CallExpression" &&
196
+ decorator.expression.callee.name === "ApiOperation") {
197
+
198
+ const args = decorator.expression.arguments;
199
+ if (args.length > 0 && args[0].type === "ObjectExpression") {
200
+ return args[0];
201
+ }
202
+ }
203
+ }
204
+ return null;
205
+ }
206
+
207
+ function validateApiOperation(member) {
208
+ const methodName = member.key.name;
209
+
210
+ if (!hasApiOperationDecorator(member.decorators)) {
211
+ context.report({
212
+ node: member,
213
+ messageId: "missingApiOperation",
214
+ data: { methodName }
215
+ });
216
+ return;
217
+ }
218
+
219
+ const apiOpContent = getApiOperationContent(member.decorators);
220
+ if (!apiOpContent) return;
221
+
222
+ let hasSummary = false;
223
+ let hasDescription = false;
224
+
225
+ // Check each property in ApiOperation
226
+ apiOpContent.properties.forEach(prop => {
227
+ if (prop.key && prop.key.name === "summary") {
228
+ hasSummary = true;
229
+ checkStringForLanguage(prop.value, context);
230
+ } else if (prop.key && prop.key.name === "description") {
231
+ hasDescription = true;
232
+ checkStringForLanguage(prop.value, context);
233
+ }
234
+ });
235
+
236
+ if (!hasSummary || !hasDescription) {
237
+ context.report({
238
+ node: member,
239
+ messageId: "emptyApiOperation",
240
+ data: { methodName }
241
+ });
242
+ }
243
+ }
244
+
245
+ function validateApiResponseDecorators(member) {
246
+ if (!member.decorators) return;
247
+
248
+ member.decorators.forEach(decorator => {
249
+ if (decorator.expression &&
250
+ decorator.expression.type === "CallExpression" &&
251
+ decorator.expression.callee.name === "ApiResponseDecorator") {
252
+
253
+ const args = decorator.expression.arguments;
254
+ if (args.length > 0 && args[0].type === "ObjectExpression") {
255
+ args[0].properties.forEach(prop => {
256
+ if (prop.key && prop.key.name === "description") {
257
+ checkStringForLanguage(prop.value, context);
258
+ }
259
+ });
260
+ }
261
+ }
262
+ });
263
+ }
264
+
265
+ function validateApiParamDecorators(member) {
266
+ if (!member.decorators) return;
267
+
268
+ member.decorators.forEach(decorator => {
269
+ if (decorator.expression &&
270
+ decorator.expression.type === "CallExpression" &&
271
+ (decorator.expression.callee.name === "ApiParam" ||
272
+ decorator.expression.callee.name === "ApiQuery" ||
273
+ decorator.expression.callee.name === "ApiBody")) {
274
+
275
+ const args = decorator.expression.arguments;
276
+ if (args.length > 0 && args[0].type === "ObjectExpression") {
277
+ args[0].properties.forEach(prop => {
278
+ if (prop.key && prop.key.name === "description") {
279
+ checkStringForLanguage(prop.value, context);
280
+ }
281
+ });
282
+ }
283
+ }
284
+ });
285
+ }
286
+
287
+ function getHttpMethodType(decorators) {
288
+ if (!decorators) return null;
289
+
290
+ const httpMethods = ["Get", "Post", "Put", "Delete", "Patch"];
291
+ for (const decorator of decorators) {
292
+ const decoratorName = decorator.expression?.name || decorator.expression?.callee?.name;
293
+ if (httpMethods.includes(decoratorName)) {
294
+ return decoratorName.toLowerCase();
295
+ }
296
+ }
297
+ return null;
298
+ }
299
+
300
+ return {
301
+ ClassDeclaration(node) {
302
+ if (!isControllerClass(node)) return;
303
+
304
+ node.body.body.forEach(member => {
305
+ if (member.type === "MethodDefinition" &&
306
+ member.kind === "method" &&
307
+ member.accessibility === "public") {
308
+
309
+ const httpMethod = getHttpMethodType(member.decorators);
310
+ if (httpMethod) {
311
+ validateApiOperation(member);
312
+ validateApiResponseDecorators(member);
313
+ validateApiParamDecorators(member);
314
+ }
315
+ }
316
+ });
317
+ },
318
+ };
319
+ },
320
+ };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * ESLint-Regel: coordinate-naming
3
+ *
4
+ * Erweitert die standard id-length Regel um spezifische Vorschläge
5
+ * für Koordinaten-Variablen x und y.
6
+ */
7
+
8
+ export default {
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ description: "Enforce minimum identifier length with coordinate naming suggestions",
13
+ category: "Stylistic Issues",
14
+ recommended: false,
15
+ },
16
+ fixable: "code",
17
+ schema: [
18
+ {
19
+ type: "object",
20
+ properties: {
21
+ min: {
22
+ type: "integer",
23
+ minimum: 0,
24
+ default: 2,
25
+ },
26
+ max: {
27
+ type: "integer",
28
+ },
29
+ exceptions: {
30
+ type: "array",
31
+ uniqueItems: true,
32
+ items: {
33
+ type: "string",
34
+ },
35
+ },
36
+ },
37
+ additionalProperties: false,
38
+ },
39
+ ],
40
+ },
41
+
42
+ create (context) {
43
+ const options = context.options[0] || {};
44
+ const min = typeof options.min === "number" ? options.min : 2;
45
+ const max = typeof options.max === "number" ? options.max : Infinity;
46
+ const exceptions = new Set(options.exceptions || []);
47
+
48
+ const coordinateMapping = {
49
+ x: "positionX",
50
+ y: "positionY",
51
+ };
52
+
53
+ /**
54
+ * Checks if an identifier is a coordinate variable that needs better naming
55
+ */
56
+ function checkIdentifier (node, name) {
57
+ if (exceptions.has(name)) {
58
+ return;
59
+ }
60
+
61
+ // Only check for coordinate variables x and y
62
+ if (coordinateMapping[name]) {
63
+ context.report({
64
+ node,
65
+ message: `Identifier name '${name}' is too short (< ${min}). For coordinates, consider using '${coordinateMapping[name]}' instead.`,
66
+ fix (fixer) {
67
+ // Only fix if it's a variable declaration or parameter
68
+ const parent = node.parent;
69
+
70
+ // Check if this is a safe context to rename
71
+ if (
72
+ parent.type === "VariableDeclarator" ||
73
+ parent.type === "Property" ||
74
+ parent.type === "FunctionExpression" ||
75
+ parent.type === "ArrowFunctionExpression" ||
76
+ parent.type === "AssignmentPattern"
77
+ ) {
78
+ return fixer.replaceText(node, coordinateMapping[name]);
79
+ }
80
+
81
+ // Don't autofix in complex contexts to avoid breaking code
82
+ return null;
83
+ },
84
+ });
85
+ }
86
+ }
87
+
88
+ return {
89
+ Identifier (node) {
90
+ const name = node.name;
91
+ const parent = node.parent;
92
+
93
+ /*
94
+ * Don't check properties that don't have their name computed:
95
+ * - foo.bar
96
+ * - foo["bar"] (computed property names are checked)
97
+ * Don't check destructured identifiers (parameters):
98
+ * - function foo({ prop }) {}
99
+ * - function foo([item1, item2]) {}
100
+ * Don't check property shorthand (ES6 features):
101
+ * - const { x } = {}; (destructuring shorthand)
102
+ * - const { x: x } = {}; (destructuring alias)
103
+ */
104
+ if (parent.type === "MemberExpression") {
105
+ if (parent.property === node && !parent.computed) {
106
+ return;
107
+ }
108
+ } else if (parent.type === "Property") {
109
+ if (parent.method || parent.shorthand || parent.key === node) {
110
+ return;
111
+ }
112
+ } else if (parent.type === "ImportDefaultSpecifier") {
113
+ return;
114
+ } else if (parent.type === "RestElement") {
115
+ return;
116
+ } else if (parent.type === "ExportSpecifier") {
117
+ return;
118
+ } else if (parent.type === "FunctionExpression" || parent.type === "ArrowFunctionExpression") {
119
+ // Don't check function names
120
+ if (parent.id === node) {
121
+ return;
122
+ }
123
+ }
124
+
125
+ // Only check coordinate variables (x, y)
126
+ if (coordinateMapping[name]) {
127
+ checkIdentifier(node, name);
128
+ }
129
+ },
130
+ };
131
+ },
132
+ };
@@ -0,0 +1,135 @@
1
+ /**
2
+ * ESLint-Regel, die die Verwendung von MUI-Button statt unserer eigenen Button-Komponente prüft
3
+ */
4
+ const noMuiButtonRule = {
5
+ meta: {
6
+ type: "suggestion",
7
+ docs: {
8
+ description: "Verbietet die direkte Verwendung von MUI-Button",
9
+ category: "Best Practices",
10
+ recommended: true,
11
+ },
12
+ fixable: "code",
13
+ messages: {
14
+ noMuiButton: "Bitte verwende die eigene Button-Komponente aus '@/components/UI/Button' statt der MUI-Button-Komponente.",
15
+ noMuiButtonImport: "Bitte verwende die eigene Button-Komponente aus '@/components/UI/Button' statt der MUI-Button-Komponente.",
16
+ },
17
+ },
18
+ create(context) {
19
+ // Speichert Material-UI Button Importe
20
+ const muiButtonImports = new Set();
21
+
22
+ return {
23
+ // Prüft alle Import-Deklarationen
24
+ ImportDeclaration(node) {
25
+ // Überprüft, ob aus @mui/material importiert wird
26
+ if (node.source.value === "@mui/material" || node.source.value === "@material-ui/core") {
27
+ // Überprüft alle Importe aus diesem Modul
28
+ node.specifiers.forEach((specifier) => {
29
+ // Wenn Button importiert wird
30
+ if (
31
+ (specifier.type === "ImportSpecifier" && specifier.imported && specifier.imported.name === "Button") ||
32
+ (specifier.type === "ImportDefaultSpecifier" && specifier.local.name === "Button")
33
+ ) {
34
+ // Speichert den lokalen Namen des importierten Buttons
35
+ muiButtonImports.add(specifier.local.name);
36
+
37
+ context.report({
38
+ node,
39
+ messageId: "noMuiButtonImport",
40
+ fix(fixer) {
41
+ // Entfernt Button aus dem Import
42
+ // Behandelt verschiedene Fälle, je nachdem wie der Import aussieht
43
+
44
+ // Fall 1: Einziger Import aus @mui/material
45
+ if (node.specifiers.length === 1) {
46
+ return fixer.remove(node);
47
+ }
48
+
49
+ // Fall 2: Benannter Import in geschweiften Klammern
50
+ if (specifier.type === "ImportSpecifier") {
51
+ const importText = context.getSourceCode().getText(node);
52
+ const buttonPattern = specifier.local.name === "Button"
53
+ ? "Button" // Direkter Import: import { Button } from "@mui/material"
54
+ : `Button as ${specifier.local.name}`; // Alias Import: import { Button as MuiButton } from "@mui/material"
55
+
56
+ // Entfernt nur Button aus der Import-Liste
57
+ if (importText.includes(`, ${buttonPattern}`)) {
58
+ return fixer.replaceText(node, importText.replace(`, ${buttonPattern}`, ""));
59
+ } else if (importText.includes(`${buttonPattern}, `)) {
60
+ return fixer.replaceText(node, importText.replace(`${buttonPattern}, `, ""));
61
+ } else if (importText.includes(`{ ${buttonPattern} }`)) {
62
+ return fixer.remove(node);
63
+ }
64
+ }
65
+
66
+ return null;
67
+ }
68
+ });
69
+ }
70
+ });
71
+ }
72
+ },
73
+
74
+ // Prüft alle JSX-Elemente
75
+ JSXOpeningElement(node) {
76
+ // Wenn ein Element mit dem Namen "Button" gefunden wird
77
+ if (node.name.type === "JSXIdentifier" && node.name.name === "Button") {
78
+ // Prüfe anhand des Scopes, ob dieser Button aus @mui/material stammt
79
+ const scope = context.getScope();
80
+ let currentScope = scope;
81
+
82
+ // Durchsuche alle Scopes nach dem Button-Variablennamen
83
+ while (currentScope) {
84
+ const buttonVar = currentScope.variables.find(v => v.name === "Button");
85
+
86
+ if (buttonVar) {
87
+ // Prüfe jede Definition der Button-Variable
88
+ for (const def of buttonVar.defs) {
89
+ // Wenn es sich um einen Import handelt
90
+ if (def.type === "ImportBinding" && def.parent && def.parent.source) {
91
+ const importSource = def.parent.source.value;
92
+
93
+ // Wenn der Import von @mui/material oder @material-ui/core stammt
94
+ if (importSource === "@mui/material" || importSource === "@material-ui/core") {
95
+ context.report({
96
+ node,
97
+ messageId: "noMuiButton",
98
+ });
99
+ return;
100
+ }
101
+ }
102
+ }
103
+
104
+ // Wenn wir eine Definition gefunden haben, aber sie ist nicht von MUI,
105
+ // dann brechen wir die Suche ab (überschreibende Variable gefunden)
106
+ break;
107
+ }
108
+
109
+ // Zum übergeordneten Scope wechseln
110
+ currentScope = currentScope.upper;
111
+ }
112
+
113
+ // Außerdem prüfen wir anhand unserer Liste von MUI-Button-Importen
114
+ if (muiButtonImports.has("Button")) {
115
+ context.report({
116
+ node,
117
+ messageId: "noMuiButton",
118
+ });
119
+ }
120
+ }
121
+ },
122
+
123
+ // Am Ende der Datei werden die gesammelten Informationen zurückgesetzt
124
+ "Program:exit": function() {
125
+ muiButtonImports.clear();
126
+ }
127
+ };
128
+ }
129
+ };
130
+
131
+ export default {
132
+ rules: {
133
+ "no-mui-button": noMuiButtonRule
134
+ }
135
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Dead Code Detection Rules für Backend
3
+ *
4
+ * Diese Regeln erkennen und verhindern toten Code in Backend-Anwendungen
5
+ * Ohne Frontend-spezifische Regeln (React, JSX)
6
+ */
7
+ export default {
8
+ rules: {
9
+ // Ungenutzte Variablen und Funktionen
10
+ "@typescript-eslint/no-unused-vars": ["error", {
11
+ "vars": "all",
12
+ "args": "after-used",
13
+ "ignoreRestSiblings": true,
14
+ "argsIgnorePattern": "^_",
15
+ "varsIgnorePattern": "^_"
16
+ }],
17
+
18
+ // Ungenutzte private Klassen-Member
19
+ "no-unused-private-class-members": "error",
20
+
21
+ // Unreachable Code Detection
22
+ "no-unreachable": "error",
23
+ "no-unreachable-loop": "error",
24
+
25
+ // Unused Expressions
26
+ "@typescript-eslint/no-unused-expressions": ["error", {
27
+ "allowShortCircuit": true,
28
+ "allowTernary": true,
29
+ "allowTaggedTemplates": true
30
+ }],
31
+
32
+ // Dead Code durch logische Operatoren
33
+ "no-constant-condition": ["error", {
34
+ "checkLoops": false
35
+ }],
36
+
37
+ // Ungenutzte Labels
38
+ "no-unused-labels": "error",
39
+
40
+ // Ungenutzte Escape-Sequenzen in RegExp
41
+ "no-useless-escape": "error",
42
+
43
+ // Ungenutzte Return-Werte
44
+ "no-useless-return": "error",
45
+
46
+ // Redundante Konstruktor-Calls
47
+ "no-useless-constructor": "off", // Deaktiviert wegen TypeScript
48
+ "@typescript-eslint/no-useless-constructor": "error",
49
+ }
50
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Dead Code Detection Rules für Frontend/Admin
3
+ *
4
+ * Diese Regeln erkennen und verhindern toten Code in Frontend-Anwendungen
5
+ */
6
+ export default {
7
+ rules: {
8
+ // Import/Export Dead Code Detection - deaktiviert wegen Flat Config Kompatibilität
9
+ // "import/no-unused-modules": ["error", {
10
+ // "missingExports": true,
11
+ // "unusedExports": true,
12
+ // "ignoreExports": [
13
+ // "src/main.tsx",
14
+ // "src/App.tsx",
15
+ // "src/AppRouter.tsx",
16
+ // "src/vite-env.d.ts",
17
+ // "**/*.d.ts",
18
+ // "**/test/**",
19
+ // "**/tests/**",
20
+ // "**/*.test.*",
21
+ // "**/*.spec.*"
22
+ // ]
23
+ // }],
24
+
25
+ // Ungenutzte Variablen und Funktionen
26
+ "@typescript-eslint/no-unused-vars": ["error", {
27
+ "vars": "all",
28
+ "args": "after-used",
29
+ "ignoreRestSiblings": true,
30
+ "argsIgnorePattern": "^_",
31
+ "varsIgnorePattern": "^_"
32
+ }],
33
+
34
+ // Ungenutzte private Klassen-Member
35
+ "no-unused-private-class-members": "error",
36
+
37
+ // Unreachable Code Detection
38
+ "no-unreachable": "error",
39
+ "no-unreachable-loop": "error",
40
+
41
+ // Unused Expressions
42
+ "@typescript-eslint/no-unused-expressions": ["error", {
43
+ "allowShortCircuit": true,
44
+ "allowTernary": true,
45
+ "allowTaggedTemplates": true
46
+ }],
47
+ }
48
+ };