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

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 +2 -20
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +2 -5
  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 +38 -2
  41. package/jest.config.ts +12 -0
  42. package/package.json +22 -14
  43. package/src/index.ts +1 -1
  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
@@ -1,112 +0,0 @@
1
- import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
-
3
- import { createRule } from "../utils/createRule";
4
-
5
- export default createRule({
6
- meta: {
7
- type: "problem",
8
- docs: {
9
- description: "实体字段可为空时属性类型",
10
- },
11
- fixable: "code",
12
- schema: [],
13
- messages: {
14
- entityPropertyNullable:
15
- "@Property({ nullable: true }) 属性类型需包含 null。",
16
- },
17
- },
18
- defaultOptions: [{}],
19
- create(context) {
20
- return {
21
- ClassDeclaration(node) {
22
- // 检查是否有 @Entity 装饰器
23
- if (
24
- node.decorators.some((decorator) => {
25
- return (
26
- decorator.expression.type === AST_NODE_TYPES.CallExpression &&
27
- decorator.expression.callee.type === AST_NODE_TYPES.Identifier &&
28
- decorator.expression.callee.name === "Entity"
29
- );
30
- })
31
- ) {
32
- // 遍历类属性
33
- node.body.body.forEach((property) => {
34
- // 检查是否有 @Property() 装饰器
35
- if (property.type === AST_NODE_TYPES.PropertyDefinition) {
36
- const propertyDecorator = property.decorators.find(
37
- (decorator) => {
38
- return (
39
- decorator.expression.type ===
40
- AST_NODE_TYPES.CallExpression &&
41
- decorator.expression.callee.type ===
42
- AST_NODE_TYPES.Identifier &&
43
- decorator.expression.callee.name === "Property"
44
- );
45
- },
46
- );
47
-
48
- if (typeof propertyDecorator === "undefined") {
49
- return;
50
- }
51
-
52
- // 检查 @Property() 装饰器 nullable 参数是否为 true
53
- if (
54
- propertyDecorator.expression.type ===
55
- AST_NODE_TYPES.CallExpression &&
56
- propertyDecorator.expression.arguments[0]?.type ===
57
- AST_NODE_TYPES.ObjectExpression &&
58
- propertyDecorator.expression.arguments[0]?.properties?.some(
59
- (prop) => {
60
- return (
61
- prop.type === AST_NODE_TYPES.Property &&
62
- prop.key.type === AST_NODE_TYPES.Identifier &&
63
- prop.key.name === "nullable" &&
64
- prop.value.type === AST_NODE_TYPES.Literal &&
65
- prop.value.value === true
66
- );
67
- },
68
- )
69
- ) {
70
- const typeAnnotation = property.typeAnnotation;
71
-
72
- if (typeof typeAnnotation === "undefined") {
73
- return;
74
- }
75
-
76
- // 检查属性类型是否包含 null
77
- if (
78
- !(
79
- typeAnnotation.type === AST_NODE_TYPES.TSTypeAnnotation &&
80
- typeAnnotation.typeAnnotation.type ===
81
- AST_NODE_TYPES.TSUnionType &&
82
- typeAnnotation.typeAnnotation.types.some(
83
- (type) => type.type === AST_NODE_TYPES.TSNullKeyword,
84
- )
85
- )
86
- ) {
87
- context.report({
88
- node: property,
89
- messageId: "entityPropertyNullable",
90
- fix: (fixer) => {
91
- const typeAnnotationStart = typeAnnotation.range[0];
92
- const typeAnnotationEnd = typeAnnotation.range[1];
93
- const originalType =
94
- context.sourceCode.getText(typeAnnotation);
95
-
96
- return fixer.replaceTextRange(
97
- [typeAnnotationStart, typeAnnotationEnd],
98
- `${originalType} | null${
99
- property.value ? "" : " = null"
100
- }`,
101
- );
102
- },
103
- });
104
- }
105
- }
106
- }
107
- });
108
- }
109
- },
110
- };
111
- },
112
- });
@@ -1,186 +0,0 @@
1
- import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
-
3
- import { createRule } from "../utils/createRule";
4
-
5
- const scalarTypeAlias: Record<string, string> = {
6
- Boolean: "boolean",
7
- Int: "number",
8
- Float: "number",
9
- String: "string",
10
- };
11
-
12
- const astTypeAlias: Record<string, string> = {
13
- TSBooleanKeyword: "boolean",
14
- TSNumberKeyword: "number",
15
- TSStringKeyword: "string",
16
- };
17
-
18
- export default createRule({
19
- meta: {
20
- type: "problem",
21
- docs: {
22
- description: "@Field() 装饰器参数需要和字段类型相符。",
23
- },
24
- fixable: "code",
25
- schema: [],
26
- messages: {
27
- fieldArgumentsMatchPropertyType:
28
- "@Field() 装饰器类型需要和字段类型声明相符。",
29
- propertyNoExplicitTypeDeclaration:
30
- "属性未显式类型声明时 @Field() 装饰器需要提供类型。",
31
- },
32
- },
33
- defaultOptions: [{}],
34
- create(context) {
35
- return {
36
- ClassDeclaration(node) {
37
- // 检查是否有 @ObjectType 或者 @InputType 装饰器
38
- if (
39
- node.decorators.some((decorator) => {
40
- return (
41
- decorator.expression.type === AST_NODE_TYPES.CallExpression &&
42
- decorator.expression.callee.type === AST_NODE_TYPES.Identifier &&
43
- ["ObjectType", "InputType"].includes(
44
- decorator.expression.callee.name,
45
- )
46
- );
47
- })
48
- ) {
49
- // 遍历类属性
50
- node.body.body.forEach((property) => {
51
- // 检查是否有 @Field() 装饰器
52
- if (property.type === AST_NODE_TYPES.PropertyDefinition) {
53
- const propertyDecorator = property.decorators.find(
54
- (decorator) => {
55
- return (
56
- decorator.expression.type ===
57
- AST_NODE_TYPES.CallExpression &&
58
- decorator.expression.callee.type ===
59
- AST_NODE_TYPES.Identifier &&
60
- decorator.expression.callee.name === "Field"
61
- );
62
- },
63
- );
64
-
65
- if (typeof propertyDecorator === "undefined") {
66
- return;
67
- }
68
-
69
- // 检查 @Field 装饰器是否声明类型
70
- if (
71
- propertyDecorator.expression.type ===
72
- AST_NODE_TYPES.CallExpression &&
73
- propertyDecorator.expression.arguments[0]?.type !==
74
- AST_NODE_TYPES.ArrowFunctionExpression
75
- ) {
76
- if (
77
- typeof property.typeAnnotation === "undefined" &&
78
- property.value !== null &&
79
- property.value.type === AST_NODE_TYPES.Literal
80
- ) {
81
- const propertyTypeName = typeof property.value.value;
82
-
83
- const expectedScalarType =
84
- Object.entries(scalarTypeAlias).find(
85
- ([, value]) => value === propertyTypeName,
86
- )?.[0] ?? propertyTypeName;
87
-
88
- if (typeof expectedScalarType !== "undefined") {
89
- context.report({
90
- node: property,
91
- messageId: "propertyNoExplicitTypeDeclaration",
92
- fix: (fixer) => {
93
- const fixes = [];
94
-
95
- if (["Int", "Float"].includes(expectedScalarType)) {
96
- fixes.push(
97
- fixer.insertTextBeforeRange(
98
- [0, 0],
99
- `import { ${expectedScalarType} } from "@nestjs/graphql";\n`,
100
- ),
101
- );
102
- }
103
-
104
- fixes.push(
105
- fixer.replaceText(
106
- propertyDecorator,
107
- `@Field(() => ${expectedScalarType})`,
108
- ),
109
- );
110
-
111
- return fixes;
112
- },
113
- });
114
- }
115
- } else if (
116
- property.typeAnnotation?.type ===
117
- AST_NODE_TYPES.TSTypeAnnotation &&
118
- property.typeAnnotation.typeAnnotation.type ===
119
- AST_NODE_TYPES.TSUnionType
120
- ) {
121
- const typeAnnotation =
122
- property.typeAnnotation.typeAnnotation.types.find(
123
- (item) =>
124
- ![
125
- AST_NODE_TYPES.TSNullKeyword,
126
- AST_NODE_TYPES.TSUndefinedKeyword,
127
- ].includes(item.type),
128
- );
129
-
130
- if (typeof typeAnnotation !== "undefined") {
131
- const propertyTypeAnnotationHasNullType =
132
- property.typeAnnotation.typeAnnotation.types.some(
133
- (item) => item.type === AST_NODE_TYPES.TSNullKeyword,
134
- );
135
-
136
- const propertyTypeName =
137
- astTypeAlias[typeAnnotation.type] ??
138
- (typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&
139
- typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier
140
- ? typeAnnotation.typeName.name
141
- : typeAnnotation.type);
142
-
143
- const expectedScalarType =
144
- Object.entries(scalarTypeAlias).find(
145
- ([, value]) => value === propertyTypeName,
146
- )?.[0] ?? propertyTypeName;
147
-
148
- context.report({
149
- node: property,
150
- messageId: "fieldArgumentsMatchPropertyType",
151
- fix: (fixer) => {
152
- const fixes = [];
153
-
154
- if (["Int", "Float"].includes(expectedScalarType)) {
155
- fixes.push(
156
- fixer.insertTextBeforeRange(
157
- [0, 0],
158
- `import { ${expectedScalarType} } from "@nestjs/graphql";\n`,
159
- ),
160
- );
161
- }
162
-
163
- fixes.push(
164
- fixer.replaceText(
165
- propertyDecorator,
166
- `@Field(() => ${expectedScalarType}${
167
- propertyTypeAnnotationHasNullType
168
- ? ", { nullable: true }"
169
- : ""
170
- })`,
171
- ),
172
- );
173
-
174
- return fixes;
175
- },
176
- });
177
- }
178
- }
179
- }
180
- }
181
- });
182
- }
183
- },
184
- };
185
- },
186
- });
@@ -1,207 +0,0 @@
1
- import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
-
3
- import { createRule } from "../utils/createRule";
4
-
5
- const scalarTypeAlias: Record<string, string> = {
6
- Boolean: "boolean",
7
- Int: "number",
8
- Float: "number",
9
- String: "string",
10
- };
11
-
12
- const astTypeAlias: Record<string, string> = {
13
- TSBooleanKeyword: "boolean",
14
- TSNumberKeyword: "number",
15
- TSStringKeyword: "string",
16
- };
17
-
18
- export default createRule({
19
- meta: {
20
- type: "problem",
21
- docs: {
22
- description: "GraphQL 解决器的方法装饰器类型需要和返回类型需要一致",
23
- },
24
- fixable: "code",
25
- schema: [],
26
- messages: {
27
- resolveMethodReturnType: "解决器的方法装饰器类型需要和返回类型需要一致",
28
- },
29
- },
30
- defaultOptions: [{}],
31
- create(context) {
32
- return {
33
- ClassDeclaration(node) {
34
- // 检查是否有 @Resolver 装饰器
35
- if (
36
- node.decorators.some((decorator) => {
37
- return (
38
- decorator.expression.type === AST_NODE_TYPES.CallExpression &&
39
- decorator.expression.callee.type === AST_NODE_TYPES.Identifier &&
40
- decorator.expression.callee.name === "Resolver"
41
- );
42
- })
43
- ) {
44
- // 遍历类属性
45
- node.body.body.forEach((method) => {
46
- // 仅检查方法
47
- if (method.type === AST_NODE_TYPES.MethodDefinition) {
48
- const isAsync = method.value.async;
49
-
50
- const methodDecorator = method.decorators.find((decorator) => {
51
- return (
52
- decorator.expression.type === AST_NODE_TYPES.CallExpression &&
53
- decorator.expression.callee.type ===
54
- AST_NODE_TYPES.Identifier &&
55
- ["Query", "Mutation", "ResolveField"].includes(
56
- decorator.expression.callee.name,
57
- )
58
- );
59
- });
60
-
61
- // 检查是否有 @Query, @Mutation, @ResolveField 装饰器
62
- if (typeof methodDecorator === "undefined") {
63
- return;
64
- }
65
-
66
- const methodDecoratorExpression = methodDecorator.expression;
67
-
68
- if (
69
- methodDecoratorExpression.type ===
70
- AST_NODE_TYPES.CallExpression &&
71
- methodDecoratorExpression.arguments[0]?.type ===
72
- AST_NODE_TYPES.ArrowFunctionExpression
73
- ) {
74
- let actualReturnTypeAnnotation =
75
- method.value.returnType?.typeAnnotation ?? null;
76
- const expectedReturnTypeFunctionBody =
77
- methodDecoratorExpression.arguments[0].body;
78
-
79
- const isNullable =
80
- methodDecoratorExpression.arguments[1]?.type ===
81
- AST_NODE_TYPES.ObjectExpression &&
82
- methodDecoratorExpression.arguments[1]?.properties?.some(
83
- (prop) => {
84
- return (
85
- prop.type === AST_NODE_TYPES.Property &&
86
- prop.key.type === AST_NODE_TYPES.Identifier &&
87
- prop.key.name === "nullable" &&
88
- prop.value.type === AST_NODE_TYPES.Literal &&
89
- prop.value.value === true
90
- );
91
- },
92
- );
93
-
94
- // 如果没有定义返回类型,或者返回类型不是标识符,跳过检查
95
- if (
96
- typeof expectedReturnTypeFunctionBody === "undefined" ||
97
- expectedReturnTypeFunctionBody.type !==
98
- AST_NODE_TYPES.Identifier
99
- ) {
100
- return;
101
- }
102
-
103
- // 获取期望返回类型
104
- const expectedReturnType =
105
- scalarTypeAlias[expectedReturnTypeFunctionBody.name] ??
106
- expectedReturnTypeFunctionBody.name;
107
-
108
- // 获取实际返回类型
109
- let actualReturnType: string | null = null;
110
- let actualHasPromise = false;
111
- let actualHasNullable = false;
112
-
113
- if (
114
- actualReturnTypeAnnotation?.type ===
115
- AST_NODE_TYPES.TSTypeReference &&
116
- actualReturnTypeAnnotation.typeName.type ===
117
- AST_NODE_TYPES.Identifier &&
118
- actualReturnTypeAnnotation.typeName.name === "Promise"
119
- ) {
120
- actualHasPromise = true;
121
- actualReturnTypeAnnotation =
122
- actualReturnTypeAnnotation.typeArguments?.params[0] ?? null;
123
- }
124
-
125
- if (
126
- actualReturnTypeAnnotation?.type ===
127
- AST_NODE_TYPES.TSUnionType
128
- ) {
129
- actualHasNullable = actualReturnTypeAnnotation.types.some(
130
- ({ type }) => type === AST_NODE_TYPES.TSNullKeyword,
131
- );
132
-
133
- actualReturnTypeAnnotation =
134
- actualReturnTypeAnnotation.types.find(
135
- ({ type }) => type !== AST_NODE_TYPES.TSNullKeyword,
136
- ) ?? null;
137
- }
138
-
139
- if (actualReturnTypeAnnotation !== null) {
140
- actualReturnType =
141
- astTypeAlias[actualReturnTypeAnnotation.type] ??
142
- (actualReturnTypeAnnotation.type ===
143
- AST_NODE_TYPES.TSTypeReference &&
144
- actualReturnTypeAnnotation.typeName.type ===
145
- AST_NODE_TYPES.Identifier
146
- ? actualReturnTypeAnnotation.typeName.name
147
- : actualReturnTypeAnnotation.type);
148
- }
149
-
150
- // 如果期望返回类型和实际返回类型不一致,则报告错误。
151
- if (
152
- expectedReturnType !== actualReturnType ||
153
- isNullable !== actualHasNullable ||
154
- isAsync !== actualHasPromise
155
- ) {
156
- context.report({
157
- node: method,
158
- messageId: "resolveMethodReturnType",
159
- fix: (fixer) => {
160
- const fixes = [];
161
-
162
- let returnTypeString = expectedReturnType;
163
-
164
- if (isNullable) {
165
- returnTypeString += " | null";
166
- }
167
-
168
- if (isAsync) {
169
- returnTypeString = `Promise<${returnTypeString}>`;
170
- }
171
-
172
- if (
173
- typeof method.value.returnType === "undefined" ||
174
- actualReturnType === null
175
- ) {
176
- if (
177
- method.value.type ===
178
- AST_NODE_TYPES.FunctionExpression
179
- ) {
180
- fixes.push(
181
- fixer.insertTextBefore(
182
- method.value.body,
183
- `: ${returnTypeString} `,
184
- ),
185
- );
186
- }
187
- } else {
188
- fixes.push(
189
- fixer.replaceText(
190
- method.value.returnType.typeAnnotation,
191
- returnTypeString,
192
- ),
193
- );
194
- }
195
-
196
- return fixes;
197
- },
198
- });
199
- }
200
- }
201
- }
202
- });
203
- }
204
- },
205
- };
206
- },
207
- });