@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,104 @@
1
+ /**
2
+ * @fileoverview Verbot von Type-Casting für Entity-Assignments
3
+ * @author Echoes of Order Team
4
+ */
5
+
6
+ export default {
7
+ meta: {
8
+ type: "problem",
9
+ docs: {
10
+ description: "Verbot von Type-Casting für Entity-Assignments. Verwende echte DB-Lookups statt { id: value } as EntityType",
11
+ category: "Best Practices",
12
+ recommended: true,
13
+ },
14
+ fixable: null,
15
+ schema: [],
16
+ messages: {
17
+ noEntityTypeCasting: "Type-Casting für Entity-Assignments ist verboten. Verwende echte DB-Lookups statt '{{ pattern }}' als '{{ entityType }}'",
18
+ suggestDbLookup: "Verwende stattdessen: const entity = await this.getEntityById(id); assignment.entity = entity;",
19
+ },
20
+ },
21
+
22
+ create(context) {
23
+ return {
24
+ // Erkennt Assignment-Expressions mit Type-Casting
25
+ AssignmentExpression(node) {
26
+ // Prüfe ob es ein Type-Casting ist
27
+ if (node.right.type === "TSAsExpression") {
28
+ const asExpression = node.right;
29
+ const objectExpression = asExpression.expression;
30
+ const entityType = asExpression.typeAnnotation;
31
+
32
+ // Prüfe ob es ein Object-Literal mit nur 'id' Property ist
33
+ if (objectExpression.type === "ObjectExpression" &&
34
+ objectExpression.properties.length === 1) {
35
+
36
+ const property = objectExpression.properties[0];
37
+
38
+ // Prüfe ob es eine 'id' Property ist
39
+ if (property.type === "Property" &&
40
+ property.key.type === "Identifier" &&
41
+ property.key.name === "id") {
42
+
43
+ // Prüfe ob der Type eine Entity ist (endet mit "Entity")
44
+ if (entityType.type === "TSTypeReference" &&
45
+ entityType.typeName.type === "Identifier" &&
46
+ entityType.typeName.name.endsWith("Entity")) {
47
+
48
+ const entityTypeName = entityType.typeName.name;
49
+ const pattern = `{ id: ${property.value.name || 'value'} }`;
50
+
51
+ context.report({
52
+ node,
53
+ messageId: "noEntityTypeCasting",
54
+ data: {
55
+ pattern,
56
+ entityType: entityTypeName,
57
+ },
58
+ });
59
+ }
60
+ }
61
+ }
62
+ }
63
+ },
64
+
65
+ // Erkennt auch Variable-Declarations mit Type-Casting
66
+ VariableDeclarator(node) {
67
+ if (node.init && node.init.type === "TSAsExpression") {
68
+ const asExpression = node.init;
69
+ const objectExpression = asExpression.expression;
70
+ const entityType = asExpression.typeAnnotation;
71
+
72
+ // Gleiche Logik wie bei AssignmentExpression
73
+ if (objectExpression.type === "ObjectExpression" &&
74
+ objectExpression.properties.length === 1) {
75
+
76
+ const property = objectExpression.properties[0];
77
+
78
+ if (property.type === "Property" &&
79
+ property.key.type === "Identifier" &&
80
+ property.key.name === "id") {
81
+
82
+ if (entityType.type === "TSTypeReference" &&
83
+ entityType.typeName.type === "Identifier" &&
84
+ entityType.typeName.name.endsWith("Entity")) {
85
+
86
+ const entityTypeName = entityType.typeName.name;
87
+ const pattern = `{ id: ${property.value.name || 'value'} }`;
88
+
89
+ context.report({
90
+ node,
91
+ messageId: "noEntityTypeCasting",
92
+ data: {
93
+ pattern,
94
+ entityType: entityTypeName,
95
+ },
96
+ });
97
+ }
98
+ }
99
+ }
100
+ }
101
+ },
102
+ };
103
+ },
104
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * ESLint Custom Rule: no-fetch
3
+ *
4
+ * Verbietet die direkte Verwendung von fetch() und erzwingt die Nutzung
5
+ * des ApiClient aus @echoes-of-order/api-client.
6
+ *
7
+ * @see https://eslint.org/docs/developer-guide/working-with-rules
8
+ */
9
+
10
+ export default {
11
+ meta: {
12
+ type: "problem",
13
+ docs: {
14
+ description: "Verbietet direkte fetch()-Aufrufe und erzwingt ApiClient-Nutzung",
15
+ category: "Best Practices",
16
+ recommended: true,
17
+ },
18
+ messages: {
19
+ noFetch: "Direkte Verwendung von fetch() ist nicht erlaubt. Verwende stattdessen den ApiClient aus @echoes-of-order/api-client oder erstelle einen Repository in /infrastructure/: " +
20
+ "import { ApiClient } from '@echoes-of-order/api-client'; " +
21
+ "const client = new ApiClient(); " +
22
+ "client.get/post/put/delete(url, options).",
23
+ },
24
+ schema: [],
25
+ },
26
+
27
+ create (context) {
28
+ return {
29
+ CallExpression (node) {
30
+ // Prüfe, ob es ein fetch()-Aufruf ist
31
+ if (
32
+ node.callee.type === "Identifier" &&
33
+ node.callee.name === "fetch"
34
+ ) {
35
+ const filename = context.getFilename();
36
+
37
+ // Ausnahmen: Api.ts und Test-Dateien
38
+ const isApiFile = filename.includes("/utilities/Api/Api.ts") ||
39
+ filename.includes("\\utilities\\Api\\Api.ts");
40
+ const isTestFile = filename.match(/\.(test|spec)\.(ts|tsx)$/);
41
+
42
+ if (!isApiFile && !isTestFile) {
43
+ context.report({
44
+ node,
45
+ messageId: "noFetch",
46
+ });
47
+ }
48
+ }
49
+
50
+ // Prüfe auch window.fetch() und globalThis.fetch()
51
+ if (
52
+ node.callee.type === "MemberExpression" &&
53
+ node.callee.property.type === "Identifier" &&
54
+ node.callee.property.name === "fetch" &&
55
+ (
56
+ (node.callee.object.type === "Identifier" && node.callee.object.name === "window") ||
57
+ (node.callee.object.type === "Identifier" && node.callee.object.name === "globalThis")
58
+ )
59
+ ) {
60
+ const filename = context.getFilename();
61
+
62
+ const isApiFile = filename.includes("/utilities/Api/Api.ts") ||
63
+ filename.includes("\\utilities\\Api\\Api.ts");
64
+ const isTestFile = filename.match(/\.(test|spec)\.(ts|tsx)$/);
65
+
66
+ if (!isApiFile && !isTestFile) {
67
+ context.report({
68
+ node,
69
+ messageId: "noFetch",
70
+ });
71
+ }
72
+ }
73
+ },
74
+ };
75
+ },
76
+ };
77
+
@@ -0,0 +1,151 @@
1
+ export default {
2
+ meta: {
3
+ type: "problem",
4
+ docs: {
5
+ description: "Forbid direct usage of import.meta.env, use ConfigProvider instead",
6
+ category: "Best Practices",
7
+ recommended: true,
8
+ },
9
+ fixable: "code",
10
+ schema: [],
11
+ messages: {
12
+ noImportMetaEnv: "Direct usage of import.meta.env is forbidden. Use ConfigProvider methods instead to ensure proper validation and error handling.",
13
+ },
14
+ },
15
+ create (context) {
16
+ let hasConfigProviderImport = false;
17
+
18
+ return {
19
+ ImportDeclaration (node) {
20
+ // Check if ConfigProvider is already imported
21
+ if (node.source.value.includes("ConfigProvider")) {
22
+ hasConfigProviderImport = true;
23
+ }
24
+ },
25
+
26
+ MemberExpression (node) {
27
+ if (
28
+ node.object &&
29
+ node.object.type === "MetaProperty" &&
30
+ node.object.meta &&
31
+ node.object.meta.name === "import" &&
32
+ node.object.property &&
33
+ node.object.property.name === "meta" &&
34
+ node.property &&
35
+ node.property.name === "env"
36
+ ) {
37
+ context.report({
38
+ node,
39
+ messageId: "noImportMetaEnv",
40
+ fix (fixer) {
41
+ const fixes = [];
42
+
43
+ // Add ConfigProvider import if not present
44
+ if (!hasConfigProviderImport) {
45
+ const program = context.getSourceCode().ast;
46
+ const lastImport = program.body.filter(n => n.type === "ImportDeclaration").slice(-1)[0] || null;
47
+
48
+ if (lastImport) {
49
+ fixes.push(
50
+ fixer.insertTextAfter(
51
+ lastImport,
52
+ '\nimport { ConfigProvider } from "@/config/ConfigProvider";'
53
+ )
54
+ );
55
+ } else {
56
+ fixes.push(
57
+ fixer.insertTextBeforeRange([0, 0], 'import { ConfigProvider } from "@/config/ConfigProvider";\n')
58
+ );
59
+ }
60
+ }
61
+
62
+ // Check if this is accessing a specific environment variable
63
+ const parent = node.parent;
64
+ if (parent && parent.type === "MemberExpression" && parent.property) {
65
+ const rawName = parent.property.name || parent.property.value;
66
+ const toCamel = (name) => {
67
+ const lower = String(name).toLowerCase();
68
+ if (lower === "node_env") return "NodeEnv";
69
+ if (lower === "db_host") return "DbHost";
70
+ if (lower === "db_port") return "DbPort";
71
+ if (lower === "db_timeout") return "DbTimeout";
72
+ if (lower === "database_url" || lower === "db_url") return "DatabaseUrl";
73
+ if (lower === "log_level") return "LogLevel";
74
+ if (lower === "api_url") return "ApiUrl";
75
+ if (lower === "secret_key") return "SecretKey";
76
+ if (lower === "primary_db_url") return "PrimaryDbUrl";
77
+ if (lower === "replica_db_url") return "ReplicaDbUrl";
78
+ if (lower === "redis_url") return "RedisUrl";
79
+ if (lower === "redis_ttl") return "RedisTtl";
80
+ const parts = String(name).split(/[_-]+/);
81
+ return parts.map((p, i) => i === 0 ? p.charAt(0).toUpperCase() + p.slice(1).toLowerCase() : p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join("");
82
+ };
83
+ const envVarName = toCamel(rawName);
84
+ if (envVarName) {
85
+ // Convert to ConfigProvider method call
86
+ const methodName = `get${envVarName}`;
87
+ fixes.push(fixer.replaceText(parent, `ConfigProvider.${methodName}()`));
88
+ } else {
89
+ // Fallback: replace with generic ConfigProvider call
90
+ fixes.push(fixer.replaceText(node, "ConfigProvider"));
91
+ }
92
+ } else {
93
+ // Replace the entire import.meta.env with ConfigProvider
94
+ fixes.push(fixer.replaceText(node, "ConfigProvider"));
95
+ }
96
+
97
+ return fixes;
98
+ },
99
+ });
100
+ }
101
+ },
102
+
103
+ CallExpression (node) {
104
+ if (
105
+ node.callee &&
106
+ node.callee.type === "MemberExpression" &&
107
+ node.callee.object &&
108
+ node.callee.object.type === "MetaProperty" &&
109
+ node.callee.object.meta &&
110
+ node.callee.object.meta.name === "import" &&
111
+ node.callee.object.property &&
112
+ node.callee.object.property.name === "meta" &&
113
+ node.callee.property &&
114
+ node.callee.property.name === "env"
115
+ ) {
116
+ context.report({
117
+ node,
118
+ messageId: "noImportMetaEnv",
119
+ fix (fixer) {
120
+ const fixes = [];
121
+
122
+ // Add ConfigProvider import if not present
123
+ if (!hasConfigProviderImport) {
124
+ const program = context.getSourceCode().ast;
125
+ const lastImport = program.body.filter(n => n.type === "ImportDeclaration").slice(-1)[0] || null;
126
+
127
+ if (lastImport) {
128
+ fixes.push(
129
+ fixer.insertTextAfter(
130
+ lastImport,
131
+ '\nimport { ConfigProvider } from "@/config/ConfigProvider";'
132
+ )
133
+ );
134
+ } else {
135
+ fixes.push(
136
+ fixer.insertTextBeforeRange([0, 0], 'import { ConfigProvider } from "@/config/ConfigProvider";\n')
137
+ );
138
+ }
139
+ }
140
+
141
+ // Replace the call with ConfigProvider
142
+ fixes.push(fixer.replaceText(node.callee, "ConfigProvider"));
143
+
144
+ return fixes;
145
+ },
146
+ });
147
+ }
148
+ },
149
+ };
150
+ },
151
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ rules: {
3
+ "no-inline-styles/no-inline-styles": "error",
4
+ },
5
+ };
@@ -0,0 +1,85 @@
1
+ export default {
2
+ rules: {
3
+ "no-magic-values": {
4
+ meta: {
5
+ type: "problem",
6
+ docs: {
7
+ description: "Disallow magic numbers and magic strings",
8
+ category: "Best Practices",
9
+ recommended: true,
10
+ },
11
+ messages: {
12
+ magicNumber: "Magic Number '{{value}}' found. Use a named constant instead.",
13
+ magicString: "Magic String '{{value}}' found. Use a named constant instead.",
14
+ },
15
+ schema: [
16
+ {
17
+ type: "object",
18
+ properties: {
19
+ ignoreNumbers: {
20
+ type: "array",
21
+ items: { type: "number" },
22
+ description: "Numbers to ignore (e.g., 0, 1, -1)",
23
+ default: [0, 1, -1]
24
+ },
25
+ ignoreStrings: {
26
+ type: "array",
27
+ items: { type: "string" },
28
+ description: "Strings to ignore (e.g., empty string)",
29
+ default: [""]
30
+ }
31
+ },
32
+ additionalProperties: false
33
+ }
34
+ ]
35
+ },
36
+
37
+ create(context) {
38
+ const options = context.options[0] || {};
39
+ const ignoreNumbers = options.ignoreNumbers || [0, 1, -1];
40
+ const ignoreStrings = options.ignoreStrings || [""];
41
+
42
+ function checkLiteral(node) {
43
+ if (node.type === "Literal") {
44
+ // Skip if it's inside a variable declaration (constant definition)
45
+ if (node.parent && node.parent.type === "VariableDeclarator") {
46
+ return;
47
+ }
48
+
49
+ if (typeof node.value === "number") {
50
+ // Ignore configured numbers
51
+ if (ignoreNumbers.includes(node.value)) {
52
+ return;
53
+ }
54
+
55
+ context.report({
56
+ node,
57
+ messageId: "magicNumber",
58
+ data: {
59
+ value: node.value,
60
+ },
61
+ });
62
+ } else if (typeof node.value === "string") {
63
+ // Ignore configured strings
64
+ if (ignoreStrings.includes(node.value)) {
65
+ return;
66
+ }
67
+
68
+ context.report({
69
+ node,
70
+ messageId: "magicString",
71
+ data: {
72
+ value: node.value,
73
+ },
74
+ });
75
+ }
76
+ }
77
+ }
78
+
79
+ return {
80
+ Literal: checkLiteral,
81
+ };
82
+ },
83
+ },
84
+ },
85
+ };
@@ -0,0 +1,168 @@
1
+ const noPartialTypeRule = {
2
+ meta: {
3
+ type: "problem",
4
+ docs: {
5
+ description: "Verbietet die Verwendung von Partial<T> Utility Type",
6
+ category: "Type Safety",
7
+ recommended: true,
8
+ },
9
+ schema: [],
10
+ messages: {
11
+ noPartialType: "Partial<T> ist verboten. Verwende stattdessen explizite optionale Properties oder separate DTOs für Update-Operationen.",
12
+ noPartialTypeInParameter: "Partial<T> in Funktionsparametern ist verboten. Definiere ein explizites Update-DTO mit nur den benötigten Properties.",
13
+ noPartialTypeInReturnType: "Partial<T> in Rückgabetypen ist verboten. Verwende vollständig typisierte DTOs.",
14
+ noPartialTypeInProperty: "Partial<T> in Property-Definitionen ist verboten. Definiere Properties explizit als optional.",
15
+ },
16
+ },
17
+ create(context) {
18
+ const checkTypeAnnotation = (node, messageId) => {
19
+ if (!node.typeAnnotation) return;
20
+
21
+ const typeAnnotation = node.typeAnnotation.typeAnnotation || node.typeAnnotation;
22
+
23
+ // Prüfe auf Partial<T>
24
+ if (
25
+ typeAnnotation.type === "TSTypeReference" &&
26
+ typeAnnotation.typeName &&
27
+ typeAnnotation.typeName.name === "Partial"
28
+ ) {
29
+ context.report({
30
+ node: typeAnnotation,
31
+ messageId: messageId || "noPartialType",
32
+ });
33
+ }
34
+
35
+ // Prüfe auf Partial in Union Types (z.B. SomeType | Partial<OtherType>)
36
+ if (typeAnnotation.type === "TSUnionType") {
37
+ typeAnnotation.types.forEach((type) => {
38
+ if (
39
+ type.type === "TSTypeReference" &&
40
+ type.typeName &&
41
+ type.typeName.name === "Partial"
42
+ ) {
43
+ context.report({
44
+ node: type,
45
+ messageId: messageId || "noPartialType",
46
+ });
47
+ }
48
+ });
49
+ }
50
+
51
+ // Prüfe auf Partial in Intersection Types (z.B. SomeType & Partial<OtherType>)
52
+ if (typeAnnotation.type === "TSIntersectionType") {
53
+ typeAnnotation.types.forEach((type) => {
54
+ if (
55
+ type.type === "TSTypeReference" &&
56
+ type.typeName &&
57
+ type.typeName.name === "Partial"
58
+ ) {
59
+ context.report({
60
+ node: type,
61
+ messageId: messageId || "noPartialType",
62
+ });
63
+ }
64
+ });
65
+ }
66
+ };
67
+
68
+ return {
69
+ // Prüfe Funktionsparameter
70
+ "FunctionDeclaration > :matches(Identifier, RestElement)"(node) {
71
+ checkTypeAnnotation(node, "noPartialTypeInParameter");
72
+ },
73
+
74
+ // Prüfe Arrow Function Parameter
75
+ "ArrowFunctionExpression > :matches(Identifier, RestElement)"(node) {
76
+ checkTypeAnnotation(node, "noPartialTypeInParameter");
77
+ },
78
+
79
+ // Prüfe Methoden-Parameter
80
+ "MethodDefinition > FunctionExpression > :matches(Identifier, RestElement)"(node) {
81
+ checkTypeAnnotation(node, "noPartialTypeInParameter");
82
+ },
83
+
84
+ // Prüfe Rückgabetypen von Funktionen
85
+ "FunctionDeclaration[returnType]"(node) {
86
+ if (node.returnType) {
87
+ const returnTypeAnnotation = node.returnType.typeAnnotation;
88
+ if (
89
+ returnTypeAnnotation.type === "TSTypeReference" &&
90
+ returnTypeAnnotation.typeName &&
91
+ returnTypeAnnotation.typeName.name === "Partial"
92
+ ) {
93
+ context.report({
94
+ node: returnTypeAnnotation,
95
+ messageId: "noPartialTypeInReturnType",
96
+ });
97
+ }
98
+ }
99
+ },
100
+
101
+ // Prüfe Rückgabetypen von Arrow Functions
102
+ "ArrowFunctionExpression[returnType]"(node) {
103
+ if (node.returnType) {
104
+ const returnTypeAnnotation = node.returnType.typeAnnotation;
105
+ if (
106
+ returnTypeAnnotation.type === "TSTypeReference" &&
107
+ returnTypeAnnotation.typeName &&
108
+ returnTypeAnnotation.typeName.name === "Partial"
109
+ ) {
110
+ context.report({
111
+ node: returnTypeAnnotation,
112
+ messageId: "noPartialTypeInReturnType",
113
+ });
114
+ }
115
+ }
116
+ },
117
+
118
+ // Prüfe Rückgabetypen von Methoden
119
+ "MethodDefinition[returnType]"(node) {
120
+ if (node.returnType) {
121
+ const returnTypeAnnotation = node.returnType.typeAnnotation;
122
+ if (
123
+ returnTypeAnnotation.type === "TSTypeReference" &&
124
+ returnTypeAnnotation.typeName &&
125
+ returnTypeAnnotation.typeName.name === "Partial"
126
+ ) {
127
+ context.report({
128
+ node: returnTypeAnnotation,
129
+ messageId: "noPartialTypeInReturnType",
130
+ });
131
+ }
132
+ }
133
+ },
134
+
135
+ // Prüfe Class Properties
136
+ "PropertyDefinition[typeAnnotation]"(node) {
137
+ checkTypeAnnotation(node, "noPartialTypeInProperty");
138
+ },
139
+
140
+ // Prüfe Variable Declarations
141
+ "VariableDeclarator > Identifier[typeAnnotation]"(node) {
142
+ checkTypeAnnotation(node, "noPartialType");
143
+ },
144
+
145
+ // Prüfe Type Aliases
146
+ "TSTypeAliasDeclaration"(node) {
147
+ if (
148
+ node.typeAnnotation.type === "TSTypeReference" &&
149
+ node.typeAnnotation.typeName &&
150
+ node.typeAnnotation.typeName.name === "Partial"
151
+ ) {
152
+ context.report({
153
+ node: node.typeAnnotation,
154
+ messageId: "noPartialType",
155
+ });
156
+ }
157
+ },
158
+ };
159
+ },
160
+ };
161
+
162
+ export default {
163
+ rules: {
164
+ "no-partial-type": noPartialTypeRule,
165
+ },
166
+ };
167
+
168
+
@@ -0,0 +1,31 @@
1
+ export default {
2
+ meta: {
3
+ type: "problem",
4
+ docs: {
5
+ description: "Disallow relative imports with parent directory references",
6
+ category: "Best Practices",
7
+ recommended: true,
8
+ },
9
+ fixable: null,
10
+ schema: [],
11
+ messages: {
12
+ noRelativeImport: "Relative imports with parent directory references (../) are not allowed. Use absolute imports with @/ prefix instead.",
13
+ },
14
+ },
15
+
16
+ create(context) {
17
+ return {
18
+ ImportDeclaration(node) {
19
+ const source = node.source.value;
20
+
21
+ // Check if the import path contains parent directory references
22
+ if (typeof source === "string" && source.includes("../")) {
23
+ context.report({
24
+ node: node.source,
25
+ messageId: "noRelativeImport",
26
+ });
27
+ }
28
+ },
29
+ };
30
+ },
31
+ };