@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,176 @@
1
+ export default {
2
+ rules: {
3
+ "enforce-dto-naming": {
4
+ meta: {
5
+ type: "problem",
6
+ docs: {
7
+ description: "Enforce correct DTO naming conventions and filename matching",
8
+ category: "Best Practices",
9
+ recommended: true,
10
+ },
11
+ fixable: null,
12
+ schema: [],
13
+ messages: {
14
+ invalidDtoSuffix: "Invalid DTO suffix pattern. Avoid double suffixes like 'DtoEntityDto', 'EntityDtoEntityDto', or 'EntityEntityDto'. Use only one suffix: 'EntityDto' for entity DTOs or 'Dto' for other DTOs.",
15
+ filenameMismatch: "Filename '{{filename}}' does not match class name '{{className}}'. Rename the file to '{{expectedFilename}}'.",
16
+ suggestCorrectName: "Consider renaming the class to '{{suggestedName}}' to match the filename.",
17
+ suggestCorrectFilename: "Consider renaming the file to '{{suggestedFilename}}' to match the class name.",
18
+ },
19
+ },
20
+
21
+ create(context) {
22
+ function hasInvalidDtoSuffix(className) {
23
+ // Verbotene Muster:
24
+ // - DtoEntityDto (doppeltes Dto)
25
+ // - EntityDtoEntityDto (doppeltes EntityDto)
26
+ // - EntityEntityDto (doppeltes Entity)
27
+ // - DtoDto (doppeltes Dto)
28
+
29
+ const invalidPatterns = [
30
+ /DtoEntityDto$/, // DtoEntityDto
31
+ /EntityDtoEntityDto$/, // EntityDtoEntityDto
32
+ /EntityEntityDto$/, // EntityEntityDto
33
+ /DtoDto$/, // DtoDto
34
+ /EntityEntity$/, // EntityEntity
35
+ /DtoEntityEntity$/, // DtoEntityEntity
36
+ /EntityDtoEntity$/, // EntityDtoEntity
37
+ ];
38
+
39
+ return invalidPatterns.some(pattern => pattern.test(className));
40
+ }
41
+
42
+ function getValidDtoSuffix(className) {
43
+ // Entferne alle bekannten Suffixe
44
+ let cleanName = className
45
+ .replace(/EntityDto$/, '')
46
+ .replace(/Dto$/, '')
47
+ .replace(/Entity$/, '');
48
+
49
+ // Füge den korrekten Suffix hinzu
50
+ if (className.endsWith('EntityDto')) {
51
+ return `${cleanName}EntityDto`;
52
+ } else if (className.endsWith('Dto')) {
53
+ return `${cleanName}Dto`;
54
+ } else if (className.endsWith('Entity')) {
55
+ return `${cleanName}Entity`;
56
+ }
57
+
58
+ // Standardfall: Dto hinzufügen
59
+ return `${cleanName}Dto`;
60
+ }
61
+
62
+ function getExpectedFilename(className) {
63
+ return `${className}.ts`;
64
+ }
65
+
66
+ function getCurrentFilename(context) {
67
+ const filename = context.getFilename();
68
+ // Extrahiere den Dateinamen ohne Pfad und Erweiterung
69
+ const pathParts = filename.split('/');
70
+ const filenameWithExt = pathParts[pathParts.length - 1];
71
+ return filenameWithExt.replace(/\.ts$/, '');
72
+ }
73
+
74
+ function isDtoFile(filename) {
75
+ // Prüfe, ob es sich um eine DTO-Datei handelt
76
+ return filename.includes('Dto') || filename.includes('Entity');
77
+ }
78
+
79
+ function isTestFile(filename) {
80
+ return filename.includes('.test.') ||
81
+ filename.includes('.spec.') ||
82
+ filename.includes('__tests__');
83
+ }
84
+
85
+ return {
86
+ ClassDeclaration(node) {
87
+ if (!node.id) return;
88
+
89
+ const className = node.id.name;
90
+ const currentFilename = getCurrentFilename(context);
91
+
92
+ // Überspringe Test-Dateien
93
+ if (isTestFile(currentFilename)) return;
94
+
95
+ // Prüfe nur DTO-Dateien
96
+ if (!isDtoFile(currentFilename)) return;
97
+
98
+ // Regel 1: Prüfe auf ungültige DTO-Suffixe
99
+ if (hasInvalidDtoSuffix(className)) {
100
+ const validName = getValidDtoSuffix(className);
101
+
102
+ context.report({
103
+ node: node.id,
104
+ messageId: "invalidDtoSuffix",
105
+ data: {
106
+ className,
107
+ suggestedName: validName,
108
+ },
109
+ });
110
+ }
111
+
112
+ // Regel 2: Prüfe auf Dateiname-Klassenname-Übereinstimmung
113
+ if (currentFilename !== className) {
114
+ const expectedFilename = getExpectedFilename(className);
115
+
116
+ context.report({
117
+ node: node.id,
118
+ messageId: "filenameMismatch",
119
+ data: {
120
+ filename: currentFilename,
121
+ className,
122
+ expectedFilename,
123
+ suggestedFilename: expectedFilename,
124
+ },
125
+ });
126
+ }
127
+ },
128
+
129
+ ExportDefaultDeclaration(node) {
130
+ if (node.declaration.type !== 'ClassDeclaration') return;
131
+ if (!node.declaration.id) return;
132
+
133
+ const className = node.declaration.id.name;
134
+ const currentFilename = getCurrentFilename(context);
135
+
136
+ // Überspringe Test-Dateien
137
+ if (isTestFile(currentFilename)) return;
138
+
139
+ // Prüfe nur DTO-Dateien
140
+ if (!isDtoFile(currentFilename)) return;
141
+
142
+ // Regel 1: Prüfe auf ungültige DTO-Suffixe
143
+ if (hasInvalidDtoSuffix(className)) {
144
+ const validName = getValidDtoSuffix(className);
145
+
146
+ context.report({
147
+ node: node.declaration.id,
148
+ messageId: "invalidDtoSuffix",
149
+ data: {
150
+ className,
151
+ suggestedName: validName,
152
+ },
153
+ });
154
+ }
155
+
156
+ // Regel 2: Prüfe auf Dateiname-Klassenname-Übereinstimmung
157
+ if (currentFilename !== className) {
158
+ const expectedFilename = getExpectedFilename(className);
159
+
160
+ context.report({
161
+ node: node.declaration.id,
162
+ messageId: "filenameMismatch",
163
+ data: {
164
+ filename: currentFilename,
165
+ className,
166
+ expectedFilename,
167
+ suggestedFilename: expectedFilename,
168
+ },
169
+ });
170
+ }
171
+ },
172
+ };
173
+ },
174
+ },
175
+ },
176
+ };
@@ -0,0 +1,114 @@
1
+ export default {
2
+ meta: {
3
+ type: "problem",
4
+ docs: {
5
+ description: "Enforce usage of DTOs instead of anonymous objects",
6
+ category: "Best Practices",
7
+ recommended: true,
8
+ },
9
+ fixable: null,
10
+ schema: [],
11
+ messages: {
12
+ anonymousObjectForbidden: "Anonymous objects are not allowed. Use a DTO class instead.",
13
+ anonymousObjectInReturn: "Returning anonymous objects is not allowed. Create a DTO class for the return type.",
14
+ anonymousObjectInAssignment: "Assigning anonymous objects is not allowed. Use a DTO class instead.",
15
+ anonymousObjectInFunctionCall: "Passing anonymous objects to functions is not allowed. Use a DTO class instead.",
16
+ },
17
+ },
18
+
19
+ create(context) {
20
+ function isTestFile() {
21
+ const filename = context.getFilename();
22
+ return filename.includes('.test.') || filename.includes('.spec.') || filename.includes('__tests__');
23
+ }
24
+
25
+ function isExemptFunction(node) {
26
+ if (!node || !node.callee) return false;
27
+
28
+ // Check for method calls like logger.error
29
+ if (node.callee.type === "MemberExpression") {
30
+ const objectName = node.callee.object.name;
31
+ const propertyName = node.callee.property.name;
32
+ const fullName = `${objectName}.${propertyName}`;
33
+
34
+ // Allow logger methods
35
+ if (fullName.startsWith('logger.')) {
36
+ return true;
37
+ }
38
+
39
+ // Allow console methods
40
+ if (fullName.startsWith('console.')) {
41
+ return true;
42
+ }
43
+
44
+ // Allow DTO factory methods
45
+ if (propertyName === "create" && objectName && objectName.endsWith("Dto")) {
46
+ return true;
47
+ }
48
+ }
49
+
50
+ // Check for direct function calls
51
+ if (node.callee.type === "Identifier") {
52
+ const exemptFunctions = [
53
+ "Object.assign", "JSON.stringify", "JSON.parse", "collectDefaultMetrics"
54
+ ];
55
+ return exemptFunctions.includes(node.callee.name);
56
+ }
57
+
58
+ return false;
59
+ }
60
+
61
+ function isInsideExemptFunction(node) {
62
+ let parent = node.parent;
63
+ while (parent) {
64
+ if (parent.type === "CallExpression" && isExemptFunction(parent)) {
65
+ return true;
66
+ }
67
+ parent = parent.parent;
68
+ }
69
+ return false;
70
+ }
71
+
72
+ function checkObjectExpression(node) {
73
+ // Skip if it's a test file
74
+ if (isTestFile()) return;
75
+
76
+ // Skip if it's inside an exempt function
77
+ if (isInsideExemptFunction(node)) return;
78
+
79
+ // Skip if it's a simple object with only basic properties
80
+ if (node.properties && node.properties.length <= 2) {
81
+ const propertyNames = node.properties
82
+ .filter(prop => prop.type === "Property" && prop.key.type === "Identifier")
83
+ .map(prop => prop.key.name);
84
+
85
+ // Allow simple objects with basic properties
86
+ if (propertyNames.every(name => ["id", "isActive", "name", "type", "value"].includes(name))) {
87
+ return;
88
+ }
89
+ }
90
+
91
+ // Report the anonymous object
92
+ let messageId = "anonymousObjectForbidden";
93
+
94
+ if (node.parent) {
95
+ if (node.parent.type === "ReturnStatement") {
96
+ messageId = "anonymousObjectInReturn";
97
+ } else if (node.parent.type === "VariableDeclarator") {
98
+ messageId = "anonymousObjectInAssignment";
99
+ } else if (node.parent.type === "CallExpression") {
100
+ messageId = "anonymousObjectInFunctionCall";
101
+ }
102
+ }
103
+
104
+ context.report({
105
+ node,
106
+ messageId,
107
+ });
108
+ }
109
+
110
+ return {
111
+ ObjectExpression: checkObjectExpression,
112
+ };
113
+ },
114
+ };
@@ -0,0 +1,407 @@
1
+ export default {
2
+ rules: {
3
+ "enforce-dto-usage": {
4
+ meta: {
5
+ type: "problem",
6
+ docs: {
7
+ description: "Enforce usage of DTOs instead of anonymous objects",
8
+ category: "Best Practices",
9
+ recommended: true,
10
+ },
11
+ messages: {
12
+ anonymousObjectForbidden: "Anonymous objects are not allowed. Use DTO classes instead.",
13
+ anonymousObjectInReturn: "Returning anonymous objects is not allowed. Use a DTO class instead.",
14
+ anonymousObjectInAssignment: "Assigning anonymous objects is not allowed. Use a DTO class instead.",
15
+ anonymousObjectInFunctionCall: "Passing anonymous objects to functions is not allowed. Use a DTO class instead.",
16
+ },
17
+ },
18
+
19
+ create(context) {
20
+ function isTestFile() {
21
+ const filename = context.getFilename();
22
+ return filename.includes('.test.') || filename.includes('.spec.') || filename.includes('__tests__');
23
+ }
24
+
25
+ function isDtoFile() {
26
+ const filename = context.getFilename();
27
+ return filename.includes('/dto/') || filename.includes('\\dto\\');
28
+ }
29
+
30
+ function isExternalLibraryCall(node) {
31
+ if (!node || !node.callee) return false;
32
+
33
+ // Check for method calls like repository.findOne, repository.save, etc.
34
+ if (node.callee.type === "MemberExpression") {
35
+ const objectName = node.callee.object.name;
36
+ const propertyName = node.callee.property.name;
37
+
38
+ // TypeORM repository methods - check if object name suggests it's a repository
39
+ if (objectName && (
40
+ objectName.includes("Repository") ||
41
+ objectName === "repository" ||
42
+ objectName === "manager" ||
43
+ objectName === "transactionalEntityManager" ||
44
+ objectName === "entityManager" ||
45
+ objectName === "dataSource"
46
+ )) {
47
+ return true;
48
+ }
49
+
50
+ // TypeORM DataSource methods
51
+ if (objectName === "dataSource") {
52
+ return true;
53
+ }
54
+
55
+ // Check if the call is to a method that's likely from an external library
56
+ // by checking if the object is imported from node_modules
57
+ const sourceCode = context.getSourceCode();
58
+ const nodeText = sourceCode.getText(node.callee.object);
59
+
60
+ // If the object is a property access chain that starts with a variable
61
+ // that's likely from an external library, consider it external
62
+ if (node.callee.object.type === "MemberExpression") {
63
+ const rootObject = node.callee.object.object;
64
+ if (rootObject && rootObject.type === "Identifier") {
65
+ const rootObjectName = rootObject.name;
66
+ // Common external library objects
67
+ const externalObjects = [
68
+ "dataSource", "repository", "manager", "entityManager",
69
+ "transactionalEntityManager", "queryRunner", "connection"
70
+ ];
71
+ if (externalObjects.includes(rootObjectName)) {
72
+ return true;
73
+ }
74
+ }
75
+ }
76
+
77
+ // Check for specific TypeORM method names
78
+ const typeOrmMethods = [
79
+ "findOne", "find", "save", "create", "update", "delete", "remove",
80
+ "findOneBy", "findBy", "findAndCount", "findAndCountBy",
81
+ "count", "countBy", "exists", "existsBy",
82
+ "query", "transaction", "getRepository", "createQueryBuilder",
83
+ "insert", "upsert", "softDelete", "restore", "recover",
84
+ "increment", "decrement", "clear"
85
+ ];
86
+
87
+ if (typeOrmMethods.includes(propertyName)) {
88
+ return true;
89
+ }
90
+ }
91
+
92
+ return false;
93
+ }
94
+
95
+ function isExemptFunction(node) {
96
+ if (!node || !node.callee) return false;
97
+
98
+ // Check if it's an external library call first
99
+ if (isExternalLibraryCall(node)) {
100
+ return true;
101
+ }
102
+
103
+ // Check for method calls like logger.error
104
+ if (node.callee.type === "MemberExpression") {
105
+ const objectName = node.callee.object.name;
106
+ const propertyName = node.callee.property.name;
107
+ const fullName = `${objectName}.${propertyName}`;
108
+
109
+ // Allow logger methods
110
+ if (fullName.startsWith('logger.')) {
111
+ return true;
112
+ }
113
+
114
+ // Allow console methods
115
+ if (fullName.startsWith('console.')) {
116
+ return true;
117
+ }
118
+
119
+ // Allow DTO factory methods (create, fromEntity, fromEntityArray, etc.)
120
+ if ((propertyName === "create" ||
121
+ propertyName === "fromEntity" ||
122
+ propertyName === "fromEntityArray" ||
123
+ propertyName === "fromRequestDto" ||
124
+ propertyName === "toEntity" ||
125
+ propertyName === "createInventorySlot") &&
126
+ objectName && objectName.endsWith("Dto")) {
127
+ return true;
128
+ }
129
+
130
+ // Allow Service methods
131
+ if (objectName && (
132
+ objectName.endsWith("Service") ||
133
+ objectName.endsWith("Manager") ||
134
+ objectName.endsWith("Repository")
135
+ )) {
136
+ return true;
137
+ }
138
+
139
+ // Allow this.service.method calls
140
+ if (objectName === "this" && propertyName && (
141
+ propertyName.endsWith("Service") ||
142
+ propertyName.endsWith("Manager") ||
143
+ propertyName.endsWith("Repository")
144
+ )) {
145
+ return true;
146
+ }
147
+ }
148
+
149
+ // Check for direct function calls
150
+ if (node.callee.type === "Identifier") {
151
+ const exemptFunctions = [
152
+ "Object.assign", "JSON.stringify", "JSON.parse", "collectDefaultMetrics"
153
+ ];
154
+ return exemptFunctions.includes(node.callee.name);
155
+ }
156
+
157
+ return false;
158
+ }
159
+
160
+ function isInsideExemptFunction(node) {
161
+ let parent = node.parent;
162
+ while (parent) {
163
+ if (parent.type === "CallExpression" && isExemptFunction(parent)) {
164
+ return true;
165
+ }
166
+ parent = parent.parent;
167
+ }
168
+ return false;
169
+ }
170
+
171
+ function isInsideDecorator(node) {
172
+ let parent = node.parent;
173
+ while (parent) {
174
+ // Check if we're inside a decorator call like @ApiResponse({...})
175
+ if (parent.type === "CallExpression" &&
176
+ parent.callee &&
177
+ parent.callee.type === "Identifier" &&
178
+ parent.callee.name &&
179
+ (parent.callee.name.startsWith("Api") ||
180
+ parent.callee.name.includes("Decorator") ||
181
+ parent.callee.name === "Column" ||
182
+ parent.callee.name === "Entity" ||
183
+ parent.callee.name === "PrimaryGeneratedColumn" ||
184
+ parent.callee.name === "CreateDateColumn" ||
185
+ parent.callee.name === "UpdateDateColumn" ||
186
+ parent.callee.name === "OneToMany" ||
187
+ parent.callee.name === "ManyToOne" ||
188
+ parent.callee.name === "ManyToMany" ||
189
+ parent.callee.name === "OneToOne" ||
190
+ parent.callee.name === "JoinColumn" ||
191
+ parent.callee.name === "Index" ||
192
+ parent.callee.name === "Unique")) {
193
+ return true;
194
+ }
195
+
196
+ // Check if we're inside a decorator expression
197
+ if (parent.type === "Decorator") {
198
+ return true;
199
+ }
200
+
201
+ parent = parent.parent;
202
+ }
203
+ return false;
204
+ }
205
+
206
+ function checkObjectExpression(node) {
207
+ // Skip if it's a test file
208
+ if (isTestFile()) return;
209
+
210
+ // Skip if it's inside an exempt function
211
+ if (isInsideExemptFunction(node)) return;
212
+
213
+ // Skip if it's inside a decorator
214
+ if (isInsideDecorator(node)) return;
215
+
216
+ // Skip if it's inside a DTO factory method
217
+ if (node.parent && node.parent.type === "CallExpression" &&
218
+ node.parent.callee && node.parent.callee.type === "MemberExpression" &&
219
+ node.parent.callee.property && node.parent.callee.property.name === "create" &&
220
+ node.parent.callee.object && node.parent.callee.object.name &&
221
+ (node.parent.callee.object.name.endsWith("Dto") || node.parent.callee.object.name.includes("Dto"))) {
222
+ return;
223
+ }
224
+
225
+ // Skip if it's a prom-client metric call
226
+ if (node.parent && node.parent.type === "CallExpression" &&
227
+ node.parent.callee && node.parent.callee.type === "MemberExpression" &&
228
+ node.parent.callee.property &&
229
+ ["inc", "set", "observe", "histogram"].includes(node.parent.callee.property.name)) {
230
+ return;
231
+ }
232
+
233
+ // Skip if it's Object.assign with Error objects (common pattern for custom errors)
234
+ if (node.parent && node.parent.type === "CallExpression" &&
235
+ node.parent.callee && node.parent.callee.type === "MemberExpression" &&
236
+ node.parent.callee.object && node.parent.callee.object.name === "Object" &&
237
+ node.parent.callee.property && node.parent.callee.property.name === "assign" &&
238
+ node.parent.arguments && node.parent.arguments.length >= 2 &&
239
+ node.parent.arguments[0].type === "NewExpression" &&
240
+ node.parent.arguments[0].callee && node.parent.arguments[0].callee.name === "Error") {
241
+ return;
242
+ }
243
+
244
+ // Skip if in transformRequestToEntity method (common pattern for TypeORM)
245
+ const filename = context.getFilename();
246
+ if (filename.includes('/service/') && node.parent &&
247
+ node.parent.type === "ReturnStatement") {
248
+ let parent = node.parent;
249
+ while (parent) {
250
+ if (parent.type === "FunctionDeclaration" || parent.type === "MethodDefinition") {
251
+ const methodName = parent.key?.name || parent.id?.name;
252
+ if (methodName === "transformRequestToEntity") {
253
+ return;
254
+ }
255
+ }
256
+ parent = parent.parent;
257
+ }
258
+ }
259
+
260
+ // Skip if in BaseController or ObservabilityController (generische Helper)
261
+ if (filename.includes('BaseController.ts') || filename.includes('ObservabilityController.ts')) {
262
+ return;
263
+ }
264
+
265
+ // Skip if it's a Prometheus Gauge/Counter/Histogram constructor
266
+ if (node.parent && node.parent.type === "NewExpression" &&
267
+ node.parent.callee && node.parent.callee.name &&
268
+ ["Gauge", "Counter", "Histogram", "Summary"].includes(node.parent.callee.name)) {
269
+ return;
270
+ }
271
+
272
+ // Skip if it's a Zod schema definition (z.object)
273
+ if (node.parent && node.parent.type === "CallExpression" &&
274
+ node.parent.callee && node.parent.callee.type === "MemberExpression" &&
275
+ node.parent.callee.object && node.parent.callee.object.name === "z" &&
276
+ node.parent.callee.property && node.parent.callee.property.name === "object") {
277
+ return;
278
+ }
279
+
280
+ // Skip if it's assigned to a typed variable for logging or TypeORM options
281
+ if (node.parent && node.parent.type === "VariableDeclarator" &&
282
+ node.parent.id && node.parent.id.typeAnnotation) {
283
+ const typeAnnotation = context.getSourceCode().getText(node.parent.id.typeAnnotation);
284
+ if (typeAnnotation.includes("LogData") ||
285
+ typeAnnotation.includes("ChatLogData") ||
286
+ typeAnnotation.includes("AuthLogData") ||
287
+ typeAnnotation.includes("FindOptions") ||
288
+ typeAnnotation.includes("FindManyOptions") ||
289
+ typeAnnotation.includes("FindOneOptions")) {
290
+ return;
291
+ }
292
+ }
293
+
294
+ // Skip if it's a nested object inside a LogData or FindOptions variable
295
+ let parent = node.parent;
296
+ while (parent) {
297
+ if (parent.type === "VariableDeclarator" && parent.id && parent.id.typeAnnotation) {
298
+ const typeAnnotation = context.getSourceCode().getText(parent.id.typeAnnotation);
299
+ if (typeAnnotation.includes("LogData") ||
300
+ typeAnnotation.includes("AuthLogData") ||
301
+ typeAnnotation.includes("FindOptions") ||
302
+ typeAnnotation.includes("FindManyOptions") ||
303
+ typeAnnotation.includes("FindOneOptions")) {
304
+ return;
305
+ }
306
+ }
307
+ parent = parent.parent;
308
+ }
309
+
310
+ // Skip if inside checkAiCommit method (test data arrays)
311
+ let checkParent = node.parent;
312
+ while (checkParent) {
313
+ if (checkParent.type === "MethodDefinition" || checkParent.type === "FunctionDeclaration") {
314
+ const methodName = checkParent.key?.name || checkParent.id?.name;
315
+ if (methodName === "checkAiCommit") {
316
+ return;
317
+ }
318
+ }
319
+ checkParent = checkParent.parent;
320
+ }
321
+
322
+ // Skip if in main.ts (Express/Server configuration)
323
+ if (filename.includes('main.ts') || filename.includes('server.ts')) {
324
+ return;
325
+ }
326
+
327
+ // Skip if in middleware files (Express middleware configuration)
328
+ if (filename.includes('/middleware/')) {
329
+ return;
330
+ }
331
+
332
+ // Skip if in Socket.ts (Socket.IO event handlers)
333
+ if (filename.includes('Socket.ts')) {
334
+ return;
335
+ }
336
+
337
+ // Skip if in module files (Modul-Konfiguration)
338
+ if (filename.includes('Module.ts')) {
339
+ return;
340
+ }
341
+
342
+ // Skip if in repository files (TypeORM where clauses and FindOptions)
343
+ if (filename.includes('/repository/')) {
344
+ return;
345
+ }
346
+
347
+ // Skip if in enum files (Enum configuration objects)
348
+ if (filename.includes('/enum/')) {
349
+ return;
350
+ }
351
+
352
+ // Skip if in migration/script files (Database migration objects)
353
+ if (filename.includes('/migration/') || filename.includes('/scripts/')) {
354
+ return;
355
+ }
356
+
357
+ // Skip if in service files (Business logic internal data structures)
358
+ if (filename.includes('/service/')) {
359
+ return;
360
+ }
361
+
362
+ // Skip if in guard/filter files (Auth logic)
363
+ if (filename.includes('/guards/') || filename.includes('/filters/')) {
364
+ return;
365
+ }
366
+
367
+ // Skip if in utility files (Helper functions)
368
+ if (filename.includes('/utilities/')) {
369
+ return;
370
+ }
371
+
372
+ // Skip if in socket handler files (WebSocket events)
373
+ if (filename.includes('/socket/')) {
374
+ return;
375
+ }
376
+
377
+ // Skip if in config files (ORM configuration)
378
+ if (filename.includes('Ormconfig.ts') || filename.includes('ormconfig.ts')) {
379
+ return;
380
+ }
381
+
382
+ // Report the anonymous object
383
+ let messageId = "anonymousObjectForbidden";
384
+
385
+ if (node.parent) {
386
+ if (node.parent.type === "ReturnStatement") {
387
+ messageId = "anonymousObjectInReturn";
388
+ } else if (node.parent.type === "VariableDeclarator" || node.parent.type === "AssignmentExpression") {
389
+ messageId = "anonymousObjectInAssignment";
390
+ } else if (node.parent.type === "CallExpression") {
391
+ messageId = "anonymousObjectInFunctionCall";
392
+ }
393
+ }
394
+
395
+ context.report({
396
+ node,
397
+ messageId,
398
+ });
399
+ }
400
+
401
+ return {
402
+ ObjectExpression: checkObjectExpression,
403
+ };
404
+ },
405
+ },
406
+ },
407
+ };