@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,181 @@
|
|
|
1
|
+
const noTsyringeRule = {
|
|
2
|
+
meta: {
|
|
3
|
+
type: "problem",
|
|
4
|
+
docs: {
|
|
5
|
+
description: "Verbietet die Verwendung von TSyringe und erzwingt NestJS Dependency Injection",
|
|
6
|
+
category: "Best Practices",
|
|
7
|
+
recommended: true,
|
|
8
|
+
},
|
|
9
|
+
fixable: "code",
|
|
10
|
+
schema: [],
|
|
11
|
+
messages: {
|
|
12
|
+
noTsyringeImport: "TSyringe-Imports sind verboten. Verwende stattdessen NestJS Dependency Injection mit @Injectable() aus '@nestjs/common'",
|
|
13
|
+
noTsyringeContainer: "TSyringe Container ist verboten. Verwende NestJS Module und Constructor Injection",
|
|
14
|
+
noTsyringeDecorator: "TSyringe @injectable() ist verboten. Verwende @Injectable() aus '@nestjs/common'",
|
|
15
|
+
requireNestjsInjectable: "Controller und Services müssen @Injectable() aus '@nestjs/common' verwenden",
|
|
16
|
+
noTsyringeResolve: "container.resolve() ist verboten. Verwende NestJS Constructor Injection",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
create(context) {
|
|
21
|
+
|
|
22
|
+
let hasNestjsInjectableImport = false;
|
|
23
|
+
let hasInjectableDecorator = false;
|
|
24
|
+
let isControllerOrService = false;
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
// Überprüfe Imports
|
|
28
|
+
ImportDeclaration(node) {
|
|
29
|
+
const source = node.source.value;
|
|
30
|
+
|
|
31
|
+
// Verbiete TSyringe-Imports
|
|
32
|
+
if (source === "tsyringe") {
|
|
33
|
+
context.report({
|
|
34
|
+
node,
|
|
35
|
+
messageId: "noTsyringeImport",
|
|
36
|
+
fix(fixer) {
|
|
37
|
+
// Entferne TSyringe-Import und ersetze durch NestJS
|
|
38
|
+
const specifiers = node.specifiers
|
|
39
|
+
.map(spec => spec.imported?.name || spec.local?.name)
|
|
40
|
+
.filter(name => name === "injectable" || name === "Injectable");
|
|
41
|
+
|
|
42
|
+
if (specifiers.includes("injectable") || specifiers.includes("Injectable")) {
|
|
43
|
+
return fixer.replaceText(
|
|
44
|
+
node,
|
|
45
|
+
'import { Injectable } from "@nestjs/common";'
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return fixer.remove(node);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Überprüfe NestJS Injectable Import
|
|
55
|
+
if (source === "@nestjs/common") {
|
|
56
|
+
const injectableImport = node.specifiers.find(
|
|
57
|
+
spec => spec.imported?.name === "Injectable"
|
|
58
|
+
);
|
|
59
|
+
if (injectableImport) {
|
|
60
|
+
hasNestjsInjectableImport = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// Überprüfe Dekoratoren
|
|
66
|
+
Decorator(node) {
|
|
67
|
+
if (node.expression?.name === "injectable") {
|
|
68
|
+
context.report({
|
|
69
|
+
node,
|
|
70
|
+
messageId: "noTsyringeDecorator",
|
|
71
|
+
fix(fixer) {
|
|
72
|
+
return fixer.replaceText(node, "@Injectable()");
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (node.expression?.name === "Injectable" ||
|
|
78
|
+
(node.expression?.callee?.name === "Injectable")) {
|
|
79
|
+
hasInjectableDecorator = true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (node.expression?.name === "Controller" ||
|
|
83
|
+
node.expression?.name === "Service" ||
|
|
84
|
+
(node.expression?.callee?.name === "Controller")) {
|
|
85
|
+
isControllerOrService = true;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
// Überprüfe TSyringe Container-Verwendung
|
|
90
|
+
MemberExpression(node) {
|
|
91
|
+
if (
|
|
92
|
+
node.object?.name === "container" &&
|
|
93
|
+
(node.property?.name === "resolve" ||
|
|
94
|
+
node.property?.name === "register" ||
|
|
95
|
+
node.property?.name === "registerInstance")
|
|
96
|
+
) {
|
|
97
|
+
context.report({
|
|
98
|
+
node,
|
|
99
|
+
messageId: "noTsyringeContainer",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// Überprüfe am Ende der Datei
|
|
105
|
+
"Program:exit"() {
|
|
106
|
+
const filename = context.getFilename();
|
|
107
|
+
const isControllerFile = filename.includes("Controller.ts") && !filename.includes("test");
|
|
108
|
+
const isServiceFile = filename.includes("Service.ts") && !filename.includes("test");
|
|
109
|
+
|
|
110
|
+
// BaseController ausschließen
|
|
111
|
+
if (filename.includes("BaseController.ts")) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if ((isControllerFile || isServiceFile || isControllerOrService) &&
|
|
116
|
+
!hasInjectableDecorator &&
|
|
117
|
+
!filename.includes("test") &&
|
|
118
|
+
!filename.includes("spec")) {
|
|
119
|
+
|
|
120
|
+
// Finde die erste Klassen-Deklaration
|
|
121
|
+
const program = context.getSourceCode().ast;
|
|
122
|
+
const classDeclaration = program.body.find(node =>
|
|
123
|
+
node.type === "ExportDefaultDeclaration" &&
|
|
124
|
+
node.declaration?.type === "ClassDeclaration"
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (classDeclaration) {
|
|
128
|
+
context.report({
|
|
129
|
+
node: classDeclaration,
|
|
130
|
+
messageId: "requireNestjsInjectable",
|
|
131
|
+
fix(fixer) {
|
|
132
|
+
const fixes = [];
|
|
133
|
+
|
|
134
|
+
// Füge Injectable Import hinzu, falls nicht vorhanden
|
|
135
|
+
if (!hasNestjsInjectableImport) {
|
|
136
|
+
const imports = program.body.filter(node => node.type === "ImportDeclaration");
|
|
137
|
+
const nestjsImport = imports.find(imp => imp.source.value === "@nestjs/common");
|
|
138
|
+
|
|
139
|
+
if (nestjsImport) {
|
|
140
|
+
// Erweitere existierenden NestJS Import
|
|
141
|
+
const specifiers = nestjsImport.specifiers.map(spec => spec.imported?.name || spec.local?.name);
|
|
142
|
+
if (!specifiers.includes("Injectable")) {
|
|
143
|
+
const newSpecifiers = [...specifiers, "Injectable"].join(", ");
|
|
144
|
+
fixes.push(fixer.replaceText(
|
|
145
|
+
nestjsImport,
|
|
146
|
+
`import { ${newSpecifiers} } from "@nestjs/common";`
|
|
147
|
+
));
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
// Füge neuen Injectable Import hinzu
|
|
151
|
+
const firstImport = imports[0];
|
|
152
|
+
if (firstImport) {
|
|
153
|
+
fixes.push(fixer.insertTextBefore(
|
|
154
|
+
firstImport,
|
|
155
|
+
'import { Injectable } from "@nestjs/common";\n'
|
|
156
|
+
));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Füge @Injectable() Dekorator hinzu
|
|
162
|
+
fixes.push(fixer.insertTextBefore(
|
|
163
|
+
classDeclaration,
|
|
164
|
+
"@Injectable()\n"
|
|
165
|
+
));
|
|
166
|
+
|
|
167
|
+
return fixes;
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export default {
|
|
178
|
+
rules: {
|
|
179
|
+
"no-tsyringe": noTsyringeRule,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
rules: {
|
|
3
|
+
"no-type-assertion": {
|
|
4
|
+
meta: {
|
|
5
|
+
type: "problem",
|
|
6
|
+
docs: {
|
|
7
|
+
description: "Verbietet Type Assertions mit 'as'",
|
|
8
|
+
category: "Best Practices",
|
|
9
|
+
recommended: true,
|
|
10
|
+
},
|
|
11
|
+
schema: [],
|
|
12
|
+
messages: {
|
|
13
|
+
noTypeAssertion: "Type Assertions mit 'as' sind verboten. Verwende stattdessen Typ-Guards oder Validierung.",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
create(context) {
|
|
18
|
+
// Prüfe, ob wir in einer Validierungsfunktion sind
|
|
19
|
+
const isInValidationFunction = (node) => {
|
|
20
|
+
let current = node;
|
|
21
|
+
while (current) {
|
|
22
|
+
if (current.type === 'MethodDefinition' && current.key.name && current.key.name.includes('Valid')) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
if (current.type === 'FunctionDeclaration' && current.id.name && current.id.name.includes('Valid')) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
current = current.parent;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Prüfe, ob wir in einer DTO-Entity-Mapping-Methode sind
|
|
34
|
+
const isInDtoEntityMappingMethod = (node) => {
|
|
35
|
+
let current = node;
|
|
36
|
+
while (current) {
|
|
37
|
+
if (current.type === 'MethodDefinition' && current.key.name &&
|
|
38
|
+
(current.key.name === 'fromEntity' || current.key.name === 'toEntity' || current.key.name === 'fromEntityArray')) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (current.type === 'FunctionDeclaration' && current.id.name &&
|
|
42
|
+
(current.id.name === 'fromEntity' || current.id.name === 'toEntity' || current.id.name === 'fromEntityArray')) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
current = current.parent;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Prüfe, ob es sich um eine Conditional Type Assertion handelt
|
|
51
|
+
const isConditionalTypeAssertion = (node) => {
|
|
52
|
+
if (node.typeAnnotation && node.typeAnnotation.type === 'TSConditionalType') {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Prüfe, ob es sich um eine Generic Type Assertion handelt
|
|
59
|
+
const isGenericTypeAssertion = (node) => {
|
|
60
|
+
if (node.typeAnnotation && node.typeAnnotation.type === 'TSTypeReference') {
|
|
61
|
+
// Prüfe auf generische Parameter
|
|
62
|
+
if (node.typeAnnotation.typeParameters && node.typeAnnotation.typeParameters.params) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Prüfe, ob es sich um eine DTO-Entity-Mapping Type Assertion handelt
|
|
70
|
+
const isDtoEntityMappingAssertion = (node) => {
|
|
71
|
+
if (node.typeAnnotation) {
|
|
72
|
+
const typeAnnotation = node.typeAnnotation;
|
|
73
|
+
|
|
74
|
+
// Prüfe auf Conditional Types mit "extends"
|
|
75
|
+
if (typeAnnotation.type === 'TSConditionalType') {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Prüfe auf Type References mit generischen Parametern
|
|
80
|
+
if (typeAnnotation.type === 'TSTypeReference') {
|
|
81
|
+
// Prüfe auf "T extends" Pattern
|
|
82
|
+
if (typeAnnotation.typeName && typeAnnotation.typeName.name === 'T') {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Prüfe auf EntityDto oder EntityDto<...> Pattern
|
|
87
|
+
if (typeAnnotation.typeName &&
|
|
88
|
+
typeAnnotation.typeName.name &&
|
|
89
|
+
(typeAnnotation.typeName.name.includes('EntityDto') ||
|
|
90
|
+
typeAnnotation.typeName.name.includes('Entity'))) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
TSAsExpression(node) {
|
|
100
|
+
const filename = context.getFilename();
|
|
101
|
+
|
|
102
|
+
// Erlaube Type Assertions in bestimmten Dateien
|
|
103
|
+
if (filename.includes('BaseController.ts') ||
|
|
104
|
+
filename.includes('openapi.ts') ||
|
|
105
|
+
filename.includes('/setup/') ||
|
|
106
|
+
filename.includes('/config/')) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Erlaube Type Assertions in Validierungsfunktionen
|
|
111
|
+
if (isInValidationFunction(node)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Erlaube Type Assertions in DTO-Entity-Mapping-Methoden
|
|
116
|
+
if (isInDtoEntityMappingMethod(node)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Erlaube Conditional Type Assertions (für Generics)
|
|
121
|
+
if (isConditionalTypeAssertion(node)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Erlaube Generic Type Assertions (für Generics)
|
|
126
|
+
if (isGenericTypeAssertion(node)) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Erlaube DTO-Entity-Mapping Type Assertions (für Generics)
|
|
131
|
+
if (isDtoEntityMappingAssertion(node)) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
context.report({
|
|
136
|
+
node,
|
|
137
|
+
messageId: "noTypeAssertion",
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
TSTypeAssertion(node) {
|
|
141
|
+
// Erlaube Type Assertions in Validierungsfunktionen
|
|
142
|
+
if (isInValidationFunction(node)) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Erlaube Type Assertions in DTO-Entity-Mapping-Methoden
|
|
147
|
+
if (isInDtoEntityMappingMethod(node)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Erlaube Conditional Type Assertions (für Generics)
|
|
152
|
+
if (isConditionalTypeAssertion(node)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Erlaube Generic Type Assertions (für Generics)
|
|
157
|
+
if (isGenericTypeAssertion(node)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Erlaube DTO-Entity-Mapping Type Assertions (für Generics)
|
|
162
|
+
if (isDtoEntityMappingAssertion(node)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
context.report({
|
|
167
|
+
node,
|
|
168
|
+
messageId: "noTypeAssertion",
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Verhindert undefined Properties in Entity-Klassen
|
|
3
|
+
* Entities sollten niemals undefined Properties haben - verwende stattdessen null oder entferne das Property
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
7
|
+
const noUndefinedEntityPropertiesRule = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
docs: {
|
|
11
|
+
description: "Verhindert undefined Properties in Entity-Klassen",
|
|
12
|
+
category: "TypeORM",
|
|
13
|
+
recommended: true,
|
|
14
|
+
},
|
|
15
|
+
hasSuggestions: true,
|
|
16
|
+
schema: [],
|
|
17
|
+
messages: {
|
|
18
|
+
undefinedPropertyInEntity: "Entity '{{entityName}}' hat undefined Property '{{propertyName}}'. Verwende stattdessen '{{propertyName}}: {{type}} | null' oder entferne das Property.",
|
|
19
|
+
suggestUseNull: "Verwende '| null' statt 'undefined'",
|
|
20
|
+
suggestRemoveOptional: "Entferne das '?' und verwende '| null'",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
create(context) {
|
|
25
|
+
const filename = context.getFilename();
|
|
26
|
+
|
|
27
|
+
// Nur Entity-Dateien prüfen
|
|
28
|
+
const isEntityFile = filename.includes("/entity/") || filename.includes("fixtures/");
|
|
29
|
+
const hasEntityExtension = filename.includes("Entity") && filename.endsWith(".ts");
|
|
30
|
+
|
|
31
|
+
if (!isEntityFile || !hasEntityExtension) {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
ClassDeclaration(node) {
|
|
37
|
+
const className = node.id?.name;
|
|
38
|
+
|
|
39
|
+
// Nur Entity-Klassen prüfen
|
|
40
|
+
if (!className || !className.endsWith("Entity")) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Durchsuche alle Properties der Klasse
|
|
45
|
+
node.body.body.forEach(member => {
|
|
46
|
+
if (member.type === "PropertyDefinition" || member.type === "TSParameterProperty") {
|
|
47
|
+
const propertyName = member.key?.name;
|
|
48
|
+
const propertyType = member.typeAnnotation?.typeAnnotation;
|
|
49
|
+
|
|
50
|
+
if (!propertyName || !propertyType) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Prüfe auf undefined in Union Types
|
|
55
|
+
if (propertyType.type === "TSUnionType") {
|
|
56
|
+
const hasUndefined = propertyType.types.some(type =>
|
|
57
|
+
type.type === "TSUndefinedKeyword"
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (hasUndefined) {
|
|
61
|
+
const typeString = context.getSourceCode().getText(propertyType);
|
|
62
|
+
const correctedType = typeString.replace(/\|\s*undefined/g, " | null");
|
|
63
|
+
|
|
64
|
+
context.report({
|
|
65
|
+
node: member,
|
|
66
|
+
messageId: "undefinedPropertyInEntity",
|
|
67
|
+
data: {
|
|
68
|
+
entityName: className,
|
|
69
|
+
propertyName,
|
|
70
|
+
type: correctedType.replace(/\|\s*null/g, "").trim()
|
|
71
|
+
},
|
|
72
|
+
suggest: [
|
|
73
|
+
{
|
|
74
|
+
desc: "Verwende '| null' statt 'undefined'",
|
|
75
|
+
fix(fixer) {
|
|
76
|
+
return fixer.replaceText(propertyType, correctedType);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Prüfe auf optional Properties (?) - diese sollten in Entities vermieden werden
|
|
85
|
+
if (member.optional) {
|
|
86
|
+
const typeString = context.getSourceCode().getText(propertyType);
|
|
87
|
+
|
|
88
|
+
context.report({
|
|
89
|
+
node: member,
|
|
90
|
+
messageId: "undefinedPropertyInEntity",
|
|
91
|
+
data: {
|
|
92
|
+
entityName: className,
|
|
93
|
+
propertyName,
|
|
94
|
+
type: typeString
|
|
95
|
+
},
|
|
96
|
+
suggest: [
|
|
97
|
+
{
|
|
98
|
+
desc: "Entferne das '?' und verwende '| null'",
|
|
99
|
+
fix(fixer) {
|
|
100
|
+
const newType = `${typeString} | null`;
|
|
101
|
+
return fixer.replaceTextRange(
|
|
102
|
+
[member.typeAnnotation.range[0], member.typeAnnotation.range[1]],
|
|
103
|
+
`: ${newType}`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export default {
|
|
118
|
+
rules: {
|
|
119
|
+
"no-undefined-entity-properties": noUndefinedEntityPropertiesRule,
|
|
120
|
+
},
|
|
121
|
+
};
|
package/rules/node.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Node.js Rules
|
|
2
|
+
export default {
|
|
3
|
+
env: {
|
|
4
|
+
node: true
|
|
5
|
+
},
|
|
6
|
+
|
|
7
|
+
rules: {
|
|
8
|
+
// enforce return after a callback
|
|
9
|
+
'callback-return': 'off',
|
|
10
|
+
|
|
11
|
+
// require all requires be top-level
|
|
12
|
+
// https://eslint.org/docs/rules/global-require
|
|
13
|
+
'global-require': 'error',
|
|
14
|
+
|
|
15
|
+
// enforces error handling in callbacks (node environment)
|
|
16
|
+
'handle-callback-err': 'off',
|
|
17
|
+
|
|
18
|
+
// disallow use of the Buffer() constructor
|
|
19
|
+
// https://eslint.org/docs/rules/no-buffer-constructor
|
|
20
|
+
'no-buffer-constructor': 'error',
|
|
21
|
+
|
|
22
|
+
// disallow mixing regular variable and require declarations
|
|
23
|
+
'no-mixed-requires': ['off', false],
|
|
24
|
+
|
|
25
|
+
// disallow use of new operator with the require function
|
|
26
|
+
'no-new-require': 'error',
|
|
27
|
+
|
|
28
|
+
// disallow string concatenation with __dirname and __filename
|
|
29
|
+
// https://eslint.org/docs/rules/no-path-concat
|
|
30
|
+
'no-path-concat': 'error',
|
|
31
|
+
|
|
32
|
+
// disallow use of process.env
|
|
33
|
+
'no-process-env': 'off',
|
|
34
|
+
|
|
35
|
+
// disallow process.exit()
|
|
36
|
+
'no-process-exit': 'off',
|
|
37
|
+
|
|
38
|
+
// restrict usage of specified node modules
|
|
39
|
+
'no-restricted-modules': 'off',
|
|
40
|
+
|
|
41
|
+
// disallow use of synchronous methods (off by default)
|
|
42
|
+
'no-sync': 'off',
|
|
43
|
+
}
|
|
44
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Perfectionist Rules
|
|
3
|
+
*
|
|
4
|
+
* Perfectionist-Regeln für konsistente Code-Formatierung
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
rules: {
|
|
9
|
+
// Perfectionist-Regeln
|
|
10
|
+
"perfectionist/sort-imports": ["error", {
|
|
11
|
+
type: "alphabetical",
|
|
12
|
+
order: "asc",
|
|
13
|
+
ignoreCase: true,
|
|
14
|
+
newlinesBetween: "always",
|
|
15
|
+
maxLineLength: undefined,
|
|
16
|
+
groups: [
|
|
17
|
+
"type",
|
|
18
|
+
["builtin", "external"],
|
|
19
|
+
"internal-type",
|
|
20
|
+
"internal",
|
|
21
|
+
["parent-type", "sibling-type", "index-type"],
|
|
22
|
+
["parent", "sibling", "index"],
|
|
23
|
+
"object",
|
|
24
|
+
"unknown",
|
|
25
|
+
],
|
|
26
|
+
}],
|
|
27
|
+
"perfectionist/sort-object-types": ["error", {
|
|
28
|
+
type: "alphabetical",
|
|
29
|
+
order: "asc",
|
|
30
|
+
ignoreCase: true,
|
|
31
|
+
}],
|
|
32
|
+
"perfectionist/sort-interfaces": ["error", {
|
|
33
|
+
type: "alphabetical",
|
|
34
|
+
order: "asc",
|
|
35
|
+
ignoreCase: true,
|
|
36
|
+
}],
|
|
37
|
+
"perfectionist/sort-enums": ["error", {
|
|
38
|
+
type: "alphabetical",
|
|
39
|
+
order: "asc",
|
|
40
|
+
ignoreCase: true,
|
|
41
|
+
}],
|
|
42
|
+
"perfectionist/sort-array-includes": ["error", {
|
|
43
|
+
type: "alphabetical",
|
|
44
|
+
order: "asc",
|
|
45
|
+
ignoreCase: true,
|
|
46
|
+
}],
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
|