@nest-boot/eslint-plugin 7.0.0-beta.1 → 7.0.0-beta.3

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 (80) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/CHANGELOG.md +4 -16
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +4 -6
  5. package/dist/index.js.map +1 -1
  6. package/dist/rules/graphql/graphql-field-config-from-types.d.ts +6 -0
  7. package/dist/rules/graphql/graphql-field-config-from-types.js +417 -0
  8. package/dist/rules/graphql/graphql-field-config-from-types.js.map +1 -0
  9. package/dist/rules/graphql/graphql-field-definite-assignment.d.ts +2 -0
  10. package/dist/rules/graphql/graphql-field-definite-assignment.js +125 -0
  11. package/dist/rules/graphql/graphql-field-definite-assignment.js.map +1 -0
  12. package/dist/rules/import/import-bullmq.d.ts +2 -0
  13. package/dist/rules/import/import-bullmq.js +36 -0
  14. package/dist/rules/import/import-bullmq.js.map +1 -0
  15. package/dist/rules/import/import-graphql.d.ts +2 -0
  16. package/dist/rules/import/import-graphql.js +36 -0
  17. package/dist/rules/import/import-graphql.js.map +1 -0
  18. package/dist/rules/import/import-mikro-orm.d.ts +2 -0
  19. package/dist/rules/import/import-mikro-orm.js +36 -0
  20. package/dist/rules/import/import-mikro-orm.js.map +1 -0
  21. package/dist/rules/index.d.ts +9 -0
  22. package/dist/rules/index.js +16 -11
  23. package/dist/rules/index.js.map +1 -1
  24. package/dist/rules/mikro-orm/entity-field-definite-assignment.d.ts +2 -0
  25. package/dist/rules/mikro-orm/entity-field-definite-assignment.js +125 -0
  26. package/dist/rules/mikro-orm/entity-field-definite-assignment.js.map +1 -0
  27. package/dist/rules/mikro-orm/entity-property-config-from-types.d.ts +3 -0
  28. package/dist/rules/mikro-orm/entity-property-config-from-types.js +881 -0
  29. package/dist/rules/mikro-orm/entity-property-config-from-types.js.map +1 -0
  30. package/dist/tsconfig.build.tsbuildinfo +1 -0
  31. package/dist/utils/createRule.d.ts +2 -0
  32. package/dist/utils/createRule.js +1 -1
  33. package/dist/utils/createRule.js.map +1 -1
  34. package/dist/utils/decorators.d.ts +29 -0
  35. package/dist/utils/decorators.js +74 -0
  36. package/dist/utils/decorators.js.map +1 -0
  37. package/dist/utils/tester.d.ts +2 -0
  38. package/dist/utils/tester.js +27 -0
  39. package/dist/utils/tester.js.map +1 -0
  40. package/eslint.config.mjs +28 -2
  41. package/jest.config.ts +12 -0
  42. package/package.json +22 -17
  43. package/src/index.ts +8 -2
  44. package/src/rules/graphql/graphql-field-config-from-types.spec.ts +242 -0
  45. package/src/rules/graphql/graphql-field-config-from-types.ts +557 -0
  46. package/src/rules/graphql/graphql-field-definite-assignment.spec.ts +135 -0
  47. package/src/rules/graphql/graphql-field-definite-assignment.ts +147 -0
  48. package/src/rules/import/import-bullmq.spec.ts +69 -0
  49. package/src/rules/import/import-bullmq.ts +35 -0
  50. package/src/rules/import/import-graphql.spec.ts +65 -0
  51. package/src/rules/import/import-graphql.ts +36 -0
  52. package/src/rules/import/import-mikro-orm.spec.ts +65 -0
  53. package/src/rules/import/import-mikro-orm.ts +36 -0
  54. package/src/rules/index.ts +15 -13
  55. package/src/rules/mikro-orm/entity-field-definite-assignment.spec.ts +91 -0
  56. package/src/rules/mikro-orm/entity-field-definite-assignment.ts +141 -0
  57. package/src/rules/mikro-orm/entity-property-config-from-types.spec.ts +262 -0
  58. package/src/rules/mikro-orm/entity-property-config-from-types.ts +1111 -0
  59. package/src/utils/createRule.ts +3 -1
  60. package/src/utils/decorators.spec.ts +214 -0
  61. package/src/utils/decorators.ts +93 -0
  62. package/src/utils/tester.ts +22 -0
  63. package/tsconfig.build.json +5 -0
  64. package/tsconfig.json +6 -7
  65. package/dist/rules/entity-constructor.js +0 -78
  66. package/dist/rules/entity-constructor.js.map +0 -1
  67. package/dist/rules/entity-property-no-optional-or-non-null-assertion.js +0 -63
  68. package/dist/rules/entity-property-no-optional-or-non-null-assertion.js.map +0 -1
  69. package/dist/rules/entity-property-nullable.js +0 -81
  70. package/dist/rules/entity-property-nullable.js.map +0 -1
  71. package/dist/rules/graphql-field-arguments-match-property-type.js +0 -118
  72. package/dist/rules/graphql-field-arguments-match-property-type.js.map +0 -1
  73. package/dist/rules/graphql-resolver-method-return-type.js +0 -145
  74. package/dist/rules/graphql-resolver-method-return-type.js.map +0 -1
  75. package/dist/tsconfig.tsbuildinfo +0 -1
  76. package/src/rules/entity-constructor.ts +0 -97
  77. package/src/rules/entity-property-no-optional-or-non-null-assertion.ts +0 -81
  78. package/src/rules/entity-property-nullable.ts +0 -112
  79. package/src/rules/graphql-field-arguments-match-property-type.ts +0 -186
  80. package/src/rules/graphql-resolver-method-return-type.ts +0 -207
@@ -0,0 +1,141 @@
1
+ import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/utils";
2
+
3
+ import { createRule } from "../../utils/createRule";
4
+ import {
5
+ hasClassDecorator,
6
+ hasPropertyDecorator,
7
+ } from "../../utils/decorators";
8
+
9
+ export default createRule({
10
+ name: "entity-field-definite-assignment",
11
+ meta: {
12
+ type: "suggestion",
13
+ fixable: "code",
14
+ schema: [],
15
+ docs: {
16
+ description: "Avoid looping over enums.",
17
+ },
18
+ messages: {
19
+ addDefiniteAssignment: "Add definite assignment assertion (!).",
20
+ removeDefiniteAssignment: "Remove definite assignment assertion (!).",
21
+ },
22
+ },
23
+ defaultOptions: [],
24
+ create(context) {
25
+ const source = context.sourceCode;
26
+
27
+ const isEntityClass = (node: TSESTree.ClassDeclaration): boolean => {
28
+ return hasClassDecorator(node, "Entity");
29
+ };
30
+
31
+ const getPropertyName = (
32
+ member: TSESTree.PropertyDefinition,
33
+ ): string | null => {
34
+ if (member.key.type === AST_NODE_TYPES.Identifier) {
35
+ return member.key.name;
36
+ }
37
+ return null;
38
+ };
39
+
40
+ const hasInitializer = (member: TSESTree.PropertyDefinition): boolean => {
41
+ return !!member.value;
42
+ };
43
+
44
+ const hasDefiniteAssignment = (
45
+ member: TSESTree.PropertyDefinition,
46
+ ): boolean => {
47
+ return member.definite;
48
+ };
49
+
50
+ const isOptionalProperty = (
51
+ member: TSESTree.PropertyDefinition,
52
+ ): boolean => {
53
+ // 检查 AST 节点的 optional 标记
54
+ if (member.optional) return true;
55
+
56
+ // 检查源代码中是否有 ? 符号(在属性名和冒号之间)
57
+ const keyEnd = member.key.range[1];
58
+ const text = source.text;
59
+ for (let i = keyEnd; i < member.range[1]; i++) {
60
+ if (text[i] === "?") return true;
61
+ if (text[i] === ":" || text[i] === "!") break;
62
+ }
63
+
64
+ return false;
65
+ };
66
+
67
+ return {
68
+ ClassDeclaration(node) {
69
+ if (!isEntityClass(node)) return;
70
+
71
+ node.body.body.forEach((member: TSESTree.ClassElement) => {
72
+ if (member.type !== AST_NODE_TYPES.PropertyDefinition) return;
73
+ if (!hasPropertyDecorator(member, "Property")) return;
74
+
75
+ const propertyName = getPropertyName(member);
76
+ if (!propertyName) return;
77
+
78
+ // 可选属性(?:)不需要 definite assignment assertion
79
+ if (isOptionalProperty(member)) return;
80
+
81
+ const hasInit = hasInitializer(member);
82
+ const hasDefinite = hasDefiniteAssignment(member);
83
+
84
+ // 情况1: 没有初始化值,但也没有 definite assignment assertion
85
+ if (!hasInit && !hasDefinite) {
86
+ context.report({
87
+ node: member,
88
+ messageId: "addDefiniteAssignment",
89
+ data: {
90
+ propertyName,
91
+ },
92
+ fix: (fixer) => {
93
+ // 找到属性名称的结束位置
94
+ const keyEnd = member.key.range[1];
95
+ // 在属性名称后添加 !
96
+ return fixer.insertTextAfterRange([keyEnd, keyEnd], "!");
97
+ },
98
+ });
99
+ }
100
+
101
+ // 情况2: 有初始化值,但也有 definite assignment assertion
102
+ if (hasInit && hasDefinite) {
103
+ context.report({
104
+ node: member,
105
+ messageId: "removeDefiniteAssignment",
106
+ data: {
107
+ propertyName,
108
+ },
109
+ fix: (fixer) => {
110
+ // 找到 ! 的位置并移除
111
+ const keyEnd = member.key.range[1];
112
+ const text = source.text;
113
+
114
+ // 查找 ! 的位置(在属性名称和冒号之间)
115
+ let exclamationPos = -1;
116
+ for (let i = keyEnd; i < member.range[1]; i++) {
117
+ if (text[i] === "!") {
118
+ exclamationPos = i;
119
+ break;
120
+ }
121
+ // 如果遇到冒号,说明没有 !
122
+ if (text[i] === ":") {
123
+ break;
124
+ }
125
+ }
126
+
127
+ if (exclamationPos !== -1) {
128
+ return fixer.removeRange([
129
+ exclamationPos,
130
+ exclamationPos + 1,
131
+ ]);
132
+ }
133
+ return null;
134
+ },
135
+ });
136
+ }
137
+ });
138
+ },
139
+ };
140
+ },
141
+ });
@@ -0,0 +1,262 @@
1
+ import { tester } from "../../utils/tester";
2
+ import rule from "./entity-property-config-from-types";
3
+
4
+ tester.run("entity-property-config-from-types", rule, {
5
+ valid: [
6
+ // 正确的 string 类型
7
+ /* typescript */ `
8
+ import { Entity, Property } from "@mikro-orm/core";
9
+
10
+ @Entity()
11
+ class User {
12
+ @Property({ type: t.string })
13
+ name!: string;
14
+ }
15
+ `,
16
+ // 正确的 nullable 配置
17
+ /* typescript */ `
18
+ import { Entity, Property } from "@mikro-orm/core";
19
+
20
+ @Entity()
21
+ class User {
22
+ @Property({ type: t.string, nullable: true })
23
+ name?: string;
24
+ }
25
+ `,
26
+ // 使用 Opt<T> 类型且有初始化值
27
+ /* typescript */ `
28
+ import { Entity, Property, Opt } from "@mikro-orm/core";
29
+
30
+ @Entity()
31
+ class User {
32
+ @Property({ type: t.boolean })
33
+ isActive: Opt<boolean> = false;
34
+ }
35
+ `,
36
+ // 关系装饰器不需要 @Property
37
+ /* typescript */ `
38
+ import { Entity, ManyToOne } from "@mikro-orm/core";
39
+
40
+ @Entity()
41
+ class Post {
42
+ @ManyToOne()
43
+ author!: User;
44
+ }
45
+ `,
46
+ // PrimaryKey 不需要 @Property
47
+ /* typescript */ `
48
+ import { Entity, PrimaryKey } from "@mikro-orm/core";
49
+
50
+ @Entity()
51
+ class User {
52
+ @PrimaryKey()
53
+ id!: number;
54
+ }
55
+ `,
56
+ // 枚举类型使用 @Enum
57
+ /* typescript */ `
58
+ import { Entity, Enum } from "@mikro-orm/core";
59
+
60
+ enum Role {
61
+ Admin,
62
+ User
63
+ }
64
+
65
+ @Entity()
66
+ class User {
67
+ @Enum({ items: () => Role })
68
+ role!: Role;
69
+ }
70
+ `,
71
+ // 数组类型
72
+ /* typescript */ `
73
+ import { Entity, Property } from "@mikro-orm/core";
74
+
75
+ @Entity()
76
+ class User {
77
+ @Property({ type: t.array })
78
+ tags!: number[];
79
+ }
80
+ `,
81
+ // boolean 类型
82
+ /* typescript */ `
83
+ import { Entity, Property } from "@mikro-orm/core";
84
+
85
+ @Entity()
86
+ class User {
87
+ @Property({ type: t.boolean })
88
+ isActive!: boolean;
89
+ }
90
+ `,
91
+ // 使用 t.text 代替 t.string(有效的 string 类型配置)
92
+ /* typescript */ `
93
+ import { Entity, Property } from "@mikro-orm/core";
94
+
95
+ @Entity()
96
+ class User {
97
+ @Property({ type: t.text })
98
+ description!: string;
99
+ }
100
+ `,
101
+ // 非 Entity 类不检查
102
+ /* typescript */ `
103
+ class NotAnEntity {
104
+ field: string;
105
+ }
106
+ `,
107
+ ],
108
+ invalid: [
109
+ // type 配置不匹配
110
+ {
111
+ code: /* typescript */ `
112
+ import { Entity, Property } from "@mikro-orm/core";
113
+
114
+ @Entity()
115
+ class User {
116
+ @Property({ type: t.float })
117
+ name!: string;
118
+ }
119
+ `,
120
+ output: /* typescript */ `
121
+ import { Entity, Property } from "@mikro-orm/core";
122
+
123
+ @Entity()
124
+ class User {
125
+ @Property({ type: t.string })
126
+ name!: string;
127
+ }
128
+ `,
129
+ errors: [{ messageId: "alignPropertyDecoratorWithTsType" }],
130
+ },
131
+ // nullable 配置不匹配
132
+ {
133
+ code: /* typescript */ `
134
+ import { Entity, Property } from "@mikro-orm/core";
135
+
136
+ @Entity()
137
+ class User {
138
+ @Property({ type: t.string })
139
+ name?: string;
140
+ }
141
+ `,
142
+ output: /* typescript */ `
143
+ import { Entity, Property } from "@mikro-orm/core";
144
+
145
+ @Entity()
146
+ class User {
147
+ @Property({ type: t.string, nullable: true })
148
+ name?: string;
149
+ }
150
+ `,
151
+ errors: [{ messageId: "alignPropertyDecoratorWithTsType" }],
152
+ },
153
+ // 有初始化值但没有使用 Opt<T>
154
+ {
155
+ code: /* typescript */ `
156
+ import { Entity, Property } from "@mikro-orm/core";
157
+
158
+ @Entity()
159
+ class User {
160
+ @Property({ type: t.boolean })
161
+ isActive: boolean = false;
162
+ }
163
+ `,
164
+ output: /* typescript */ `
165
+ import { Entity, Property, Opt } from "@mikro-orm/core";
166
+
167
+ @Entity()
168
+ class User {
169
+ @Property({ type: t.boolean })
170
+ isActive: Opt<boolean> = false;
171
+ }
172
+ `,
173
+ errors: [{ messageId: "useOptTypeForInitializedProperty" }],
174
+ },
175
+ // 枚举类型应该使用 @Enum 装饰器
176
+ {
177
+ code: /* typescript */ `
178
+ import { Entity, Property } from "@mikro-orm/core";
179
+
180
+ enum Role {
181
+ Admin,
182
+ User
183
+ }
184
+
185
+ @Entity()
186
+ class User {
187
+ @Property()
188
+ role!: Role;
189
+ }
190
+ `,
191
+ output: /* typescript */ `
192
+ import { Entity, Property } from "@mikro-orm/core";
193
+
194
+ enum Role {
195
+ Admin,
196
+ User
197
+ }
198
+
199
+ @Entity()
200
+ class User {
201
+ @Enum({ items: () => Role })
202
+ role!: Role;
203
+ }
204
+ `,
205
+ errors: [{ messageId: "useEnumDecorator" }],
206
+ },
207
+ // @Enum 的 nullable 配置不匹配
208
+ {
209
+ code: /* typescript */ `
210
+ import { Entity, Enum } from "@mikro-orm/core";
211
+
212
+ enum Role {
213
+ Admin,
214
+ User
215
+ }
216
+
217
+ @Entity()
218
+ class User {
219
+ @Enum({ items: () => Role })
220
+ role?: Role;
221
+ }
222
+ `,
223
+ output: /* typescript */ `
224
+ import { Entity, Enum } from "@mikro-orm/core";
225
+
226
+ enum Role {
227
+ Admin,
228
+ User
229
+ }
230
+
231
+ @Entity()
232
+ class User {
233
+ @Enum({ items: () => Role, nullable: true })
234
+ role?: Role;
235
+ }
236
+ `,
237
+ errors: [{ messageId: "alignPropertyDecoratorWithTsType" }],
238
+ },
239
+ // 数组类型配置不匹配
240
+ {
241
+ code: /* typescript */ `
242
+ import { Entity, Property } from "@mikro-orm/core";
243
+
244
+ @Entity()
245
+ class User {
246
+ @Property({ type: t.string })
247
+ tags!: number[];
248
+ }
249
+ `,
250
+ output: /* typescript */ `
251
+ import { Entity, Property } from "@mikro-orm/core";
252
+
253
+ @Entity()
254
+ class User {
255
+ @Property({ type: t.array })
256
+ tags!: number[];
257
+ }
258
+ `,
259
+ errors: [{ messageId: "alignPropertyDecoratorWithTsType" }],
260
+ },
261
+ ],
262
+ });