@nest-boot/eslint-plugin 7.0.2 → 7.0.4
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/rules/mikro-orm/entity-field-definite-assignment.js +2 -0
- package/dist/rules/mikro-orm/entity-field-definite-assignment.js.map +1 -1
- package/dist/rules/mikro-orm/entity-property-config-from-types.js +53 -20
- package/dist/rules/mikro-orm/entity-property-config-from-types.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +9 -3
- package/src/rules/mikro-orm/entity-field-definite-assignment.ts +2 -0
- package/src/rules/mikro-orm/entity-property-config-from-types.spec.ts +3 -3
- package/src/rules/mikro-orm/entity-property-config-from-types.ts +71 -18
package/package.json
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nest-boot/eslint-plugin",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": "./dist/index.js",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@typescript-eslint/utils": "^8.44.1"
|
|
9
9
|
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
12
|
+
"eslint": "^9.0.0",
|
|
13
|
+
"typescript": "^5.0.0"
|
|
14
|
+
},
|
|
10
15
|
"devDependencies": {
|
|
11
16
|
"@eslint/eslintrc": "^3.3.1",
|
|
12
17
|
"@eslint/js": "^9.36.0",
|
|
13
18
|
"@jest/globals": "^30.2.0",
|
|
14
|
-
"@nest-boot/tsconfig": "^7.0.0",
|
|
15
19
|
"@types/node": "^22.18.6",
|
|
20
|
+
"@typescript-eslint/parser": "^8.44.1",
|
|
16
21
|
"@typescript-eslint/rule-tester": "^8.44.1",
|
|
17
22
|
"eslint": "^9.36.0",
|
|
18
23
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -20,7 +25,8 @@
|
|
|
20
25
|
"jest": "^29.7.0",
|
|
21
26
|
"ts-jest": "^29.4.4",
|
|
22
27
|
"typescript": "^5.9.3",
|
|
23
|
-
"typescript-eslint": "^8.46.2"
|
|
28
|
+
"typescript-eslint": "^8.46.2",
|
|
29
|
+
"@nest-boot/tsconfig": "^7.0.1"
|
|
24
30
|
},
|
|
25
31
|
"publishConfig": {
|
|
26
32
|
"access": "public"
|
|
@@ -43,13 +43,13 @@ tester.run("entity-property-config-from-types", rule, {
|
|
|
43
43
|
author!: User;
|
|
44
44
|
}
|
|
45
45
|
`,
|
|
46
|
-
// PrimaryKey
|
|
46
|
+
// PrimaryKey 需要 type 配置
|
|
47
47
|
/* typescript */ `
|
|
48
|
-
import { Entity, PrimaryKey } from "@mikro-orm/core";
|
|
48
|
+
import { Entity, PrimaryKey, t } from "@mikro-orm/core";
|
|
49
49
|
|
|
50
50
|
@Entity()
|
|
51
51
|
class User {
|
|
52
|
-
@PrimaryKey()
|
|
52
|
+
@PrimaryKey({ type: t.integer })
|
|
53
53
|
id!: number;
|
|
54
54
|
}
|
|
55
55
|
`,
|
|
@@ -112,10 +112,11 @@ export default createRule<
|
|
|
112
112
|
const isValidStringType = (typeConfig: string | null): boolean => {
|
|
113
113
|
if (!typeConfig) return false;
|
|
114
114
|
|
|
115
|
-
// 接受 t.string, t.text, t.decimal, t.bigint
|
|
115
|
+
// 接受 t.string, t.text, t.uuid, t.decimal, t.bigint
|
|
116
116
|
if (
|
|
117
117
|
typeConfig === "t.string" ||
|
|
118
118
|
typeConfig === "t.text" ||
|
|
119
|
+
typeConfig === "t.uuid" ||
|
|
119
120
|
typeConfig === "t.decimal" ||
|
|
120
121
|
typeConfig === "t.bigint"
|
|
121
122
|
) {
|
|
@@ -572,6 +573,7 @@ export default createRule<
|
|
|
572
573
|
const buildPropertyDecorator = (
|
|
573
574
|
info: TypeInfo,
|
|
574
575
|
otherProps: { key: string; value: string }[] = [],
|
|
576
|
+
decoratorName = "Property",
|
|
575
577
|
): string => {
|
|
576
578
|
const options: string[] = [];
|
|
577
579
|
|
|
@@ -590,10 +592,10 @@ export default createRule<
|
|
|
590
592
|
}
|
|
591
593
|
|
|
592
594
|
if (options.length === 0) {
|
|
593
|
-
return
|
|
595
|
+
return `@${decoratorName}()`;
|
|
594
596
|
}
|
|
595
597
|
|
|
596
|
-
return
|
|
598
|
+
return `@${decoratorName}({ ${options.join(", ")} })`;
|
|
597
599
|
};
|
|
598
600
|
|
|
599
601
|
const addPropertyDecorator = (
|
|
@@ -622,11 +624,21 @@ export default createRule<
|
|
|
622
624
|
nullable: boolean;
|
|
623
625
|
otherProps: { key: string; value: string }[];
|
|
624
626
|
},
|
|
627
|
+
decoratorName = "Property",
|
|
625
628
|
) => {
|
|
626
629
|
const fixes: CustomFix[] = [];
|
|
627
630
|
|
|
628
631
|
// 如果当前已经有有效的配置,保留它而不是替换成默认值
|
|
629
632
|
const finalInfo = { ...info };
|
|
633
|
+
|
|
634
|
+
// PrimaryKey 的 number 类型默认使用 t.integer
|
|
635
|
+
if (
|
|
636
|
+
decoratorName === "PrimaryKey" &&
|
|
637
|
+
finalInfo.propertyType === "t.float"
|
|
638
|
+
) {
|
|
639
|
+
finalInfo.propertyType = "t.integer";
|
|
640
|
+
}
|
|
641
|
+
|
|
630
642
|
if (
|
|
631
643
|
info.propertyType === "t.string" &&
|
|
632
644
|
isValidStringType(currentConfig.type)
|
|
@@ -634,7 +646,8 @@ export default createRule<
|
|
|
634
646
|
// 保留有效的 string 类型配置
|
|
635
647
|
finalInfo.propertyType = currentConfig.type;
|
|
636
648
|
} else if (
|
|
637
|
-
info.propertyType === "t.float"
|
|
649
|
+
(info.propertyType === "t.float" ||
|
|
650
|
+
info.propertyType === "t.integer") &&
|
|
638
651
|
isValidNumberType(currentConfig.type)
|
|
639
652
|
) {
|
|
640
653
|
// 保留有效的 number 类型配置
|
|
@@ -658,6 +671,7 @@ export default createRule<
|
|
|
658
671
|
const newDecoratorText = buildPropertyDecorator(
|
|
659
672
|
finalInfo,
|
|
660
673
|
currentConfig.otherProps,
|
|
674
|
+
decoratorName,
|
|
661
675
|
);
|
|
662
676
|
|
|
663
677
|
fixes.push({
|
|
@@ -855,7 +869,7 @@ export default createRule<
|
|
|
855
869
|
node.body.body.forEach((member: TSESTree.ClassElement) => {
|
|
856
870
|
if (member.type !== AST_NODE_TYPES.PropertyDefinition) return;
|
|
857
871
|
|
|
858
|
-
// 检查关系装饰器(
|
|
872
|
+
// 检查关系装饰器(OneToOne, OneToMany, ManyToOne, ManyToMany)
|
|
859
873
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
860
874
|
const hasRelationDecorator = member.decorators?.some(
|
|
861
875
|
(decorator: TSESTree.Decorator) => {
|
|
@@ -865,7 +879,6 @@ export default createRule<
|
|
|
865
879
|
) {
|
|
866
880
|
const decoratorName = decorator.expression.callee.name;
|
|
867
881
|
return [
|
|
868
|
-
"PrimaryKey",
|
|
869
882
|
"OneToOne",
|
|
870
883
|
"OneToMany",
|
|
871
884
|
"ManyToOne",
|
|
@@ -879,31 +892,62 @@ export default createRule<
|
|
|
879
892
|
// 如果有关系装饰器,跳过检查(这些属性不需要 @Property 装饰器)
|
|
880
893
|
if (hasRelationDecorator) return;
|
|
881
894
|
|
|
882
|
-
//
|
|
895
|
+
// 类 Property 装饰器列表(需要类型检查的装饰器)
|
|
896
|
+
const propertyLikeDecorators = [
|
|
897
|
+
"Property",
|
|
898
|
+
"PrimaryKey",
|
|
899
|
+
"EncryptedProperty",
|
|
900
|
+
"HashedProperty",
|
|
901
|
+
];
|
|
902
|
+
|
|
903
|
+
// 查找类 Property 装饰器
|
|
883
904
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
884
|
-
const
|
|
905
|
+
const propertyLikeDecorator = member.decorators?.find(
|
|
885
906
|
(decorator: TSESTree.Decorator) => {
|
|
886
|
-
|
|
907
|
+
if (
|
|
887
908
|
decorator.expression.type === AST_NODE_TYPES.CallExpression &&
|
|
888
|
-
decorator.expression.callee.type ===
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
909
|
+
decorator.expression.callee.type === AST_NODE_TYPES.Identifier
|
|
910
|
+
) {
|
|
911
|
+
return propertyLikeDecorators.includes(
|
|
912
|
+
decorator.expression.callee.name,
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
return false;
|
|
892
916
|
},
|
|
893
917
|
);
|
|
894
918
|
|
|
919
|
+
// 获取装饰器名称
|
|
920
|
+
const getDecoratorName = (
|
|
921
|
+
decorator: TSESTree.Decorator,
|
|
922
|
+
): string | null => {
|
|
923
|
+
if (
|
|
924
|
+
decorator.expression.type === AST_NODE_TYPES.CallExpression &&
|
|
925
|
+
decorator.expression.callee.type === AST_NODE_TYPES.Identifier
|
|
926
|
+
) {
|
|
927
|
+
return decorator.expression.callee.name;
|
|
928
|
+
}
|
|
929
|
+
return null;
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
// 检查 @Enum 装饰器
|
|
895
933
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
896
|
-
const
|
|
934
|
+
const enumDecorator = member.decorators?.find(
|
|
897
935
|
(decorator: TSESTree.Decorator) => {
|
|
898
936
|
return (
|
|
899
937
|
decorator.expression.type === AST_NODE_TYPES.CallExpression &&
|
|
900
938
|
decorator.expression.callee.type ===
|
|
901
939
|
AST_NODE_TYPES.Identifier &&
|
|
902
|
-
decorator.expression.callee.name === "
|
|
940
|
+
decorator.expression.callee.name === "Enum"
|
|
903
941
|
);
|
|
904
942
|
},
|
|
905
943
|
);
|
|
906
944
|
|
|
945
|
+
// 使用类 Property 装饰器
|
|
946
|
+
const propertyDecorator = propertyLikeDecorator;
|
|
947
|
+
const currentDecoratorName = propertyDecorator
|
|
948
|
+
? getDecoratorName(propertyDecorator)
|
|
949
|
+
: null;
|
|
950
|
+
|
|
907
951
|
const typeInfo = computeTypeInfo(member);
|
|
908
952
|
|
|
909
953
|
if (!typeInfo?.typeName) return;
|
|
@@ -1065,9 +1109,17 @@ export default createRule<
|
|
|
1065
1109
|
return;
|
|
1066
1110
|
}
|
|
1067
1111
|
|
|
1068
|
-
//
|
|
1112
|
+
// 检查现有装饰器是否与类型匹配
|
|
1069
1113
|
const currentConfig = parsePropertyDecorator(propertyDecorator);
|
|
1070
|
-
|
|
1114
|
+
let expectedType = typeInfo.propertyType;
|
|
1115
|
+
|
|
1116
|
+
// PrimaryKey 的 number 类型期望 t.integer
|
|
1117
|
+
if (
|
|
1118
|
+
currentDecoratorName === "PrimaryKey" &&
|
|
1119
|
+
expectedType === "t.float"
|
|
1120
|
+
) {
|
|
1121
|
+
expectedType = "t.integer";
|
|
1122
|
+
}
|
|
1071
1123
|
|
|
1072
1124
|
let needReport = false;
|
|
1073
1125
|
|
|
@@ -1080,7 +1132,7 @@ export default createRule<
|
|
|
1080
1132
|
) {
|
|
1081
1133
|
// 当前配置是有效的 string 类型配置,不需要修改
|
|
1082
1134
|
} else if (
|
|
1083
|
-
expectedType === "t.float" &&
|
|
1135
|
+
(expectedType === "t.float" || expectedType === "t.integer") &&
|
|
1084
1136
|
isValidNumberType(currentConfig.type)
|
|
1085
1137
|
) {
|
|
1086
1138
|
// 当前配置是有效的 number 类型配置,不需要修改
|
|
@@ -1126,6 +1178,7 @@ export default createRule<
|
|
|
1126
1178
|
propertyDecorator,
|
|
1127
1179
|
typeInfo,
|
|
1128
1180
|
currentConfig,
|
|
1181
|
+
currentDecoratorName ?? "Property",
|
|
1129
1182
|
);
|
|
1130
1183
|
return applyFixes(fixer, fixes);
|
|
1131
1184
|
},
|