@nest-boot/eslint-plugin 7.0.4 → 7.0.5

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 (44) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +6 -0
  3. package/dist/rules/graphql/graphql-field-config-from-types.d.ts +3 -1
  4. package/dist/rules/graphql/graphql-field-config-from-types.js +36 -36
  5. package/dist/rules/graphql/graphql-field-config-from-types.js.map +1 -1
  6. package/dist/rules/graphql/graphql-field-definite-assignment.d.ts +3 -1
  7. package/dist/rules/graphql/graphql-field-definite-assignment.js +13 -13
  8. package/dist/rules/graphql/graphql-field-definite-assignment.js.map +1 -1
  9. package/dist/rules/import/import-bullmq.d.ts +3 -1
  10. package/dist/rules/import/import-bullmq.js +4 -4
  11. package/dist/rules/import/import-bullmq.js.map +1 -1
  12. package/dist/rules/import/import-graphql.d.ts +3 -1
  13. package/dist/rules/import/import-graphql.js +4 -4
  14. package/dist/rules/import/import-graphql.js.map +1 -1
  15. package/dist/rules/import/import-mikro-orm.d.ts +3 -1
  16. package/dist/rules/import/import-mikro-orm.js +4 -4
  17. package/dist/rules/import/import-mikro-orm.js.map +1 -1
  18. package/dist/rules/index.d.ts +21 -7
  19. package/dist/rules/mikro-orm/entity-field-definite-assignment.d.ts +3 -1
  20. package/dist/rules/mikro-orm/entity-field-definite-assignment.js +10 -10
  21. package/dist/rules/mikro-orm/entity-field-definite-assignment.js.map +1 -1
  22. package/dist/rules/mikro-orm/entity-property-config-from-types.d.ts +3 -1
  23. package/dist/rules/mikro-orm/entity-property-config-from-types.js +105 -105
  24. package/dist/rules/mikro-orm/entity-property-config-from-types.js.map +1 -1
  25. package/dist/tsconfig.build.tsbuildinfo +1 -1
  26. package/dist/utils/createRule.d.ts +3 -1
  27. package/dist/utils/decorators.d.ts +16 -16
  28. package/dist/utils/decorators.js +16 -16
  29. package/package.json +12 -7
  30. package/src/rules/graphql/graphql-field-config-from-types.spec.ts +18 -18
  31. package/src/rules/graphql/graphql-field-config-from-types.ts +37 -37
  32. package/src/rules/graphql/graphql-field-definite-assignment.spec.ts +11 -11
  33. package/src/rules/graphql/graphql-field-definite-assignment.ts +13 -13
  34. package/src/rules/import/import-bullmq.spec.ts +9 -9
  35. package/src/rules/import/import-bullmq.ts +5 -4
  36. package/src/rules/import/import-graphql.spec.ts +8 -8
  37. package/src/rules/import/import-graphql.ts +4 -4
  38. package/src/rules/import/import-mikro-orm.spec.ts +8 -8
  39. package/src/rules/import/import-mikro-orm.ts +4 -4
  40. package/src/rules/mikro-orm/entity-field-definite-assignment.spec.ts +18 -18
  41. package/src/rules/mikro-orm/entity-field-definite-assignment.ts +10 -10
  42. package/src/rules/mikro-orm/entity-property-config-from-types.spec.ts +22 -22
  43. package/src/rules/mikro-orm/entity-property-config-from-types.ts +110 -109
  44. package/src/utils/decorators.ts +16 -16
@@ -42,16 +42,16 @@ exports.default = (0, createRule_1.createRule)({
42
42
  meta: {
43
43
  type: "problem",
44
44
  docs: {
45
- description: "根据 TypeScript 类型自动生成或修正 @Property 装饰器的类型与 nullable 配置(支持数组),以及 @Enum 装饰器的 nullable 配置。检查有初始化值的属性是否使用 Opt<T> 类型。",
45
+ description: "Automatically generate or fix @Property decorator type and nullable configuration based on TypeScript types (with array support), as well as @Enum decorator nullable configuration. Checks whether properties with initializers use the Opt<T> type.",
46
46
  },
47
47
  fixable: "code",
48
48
  schema: [],
49
49
  messages: {
50
- alignPropertyDecoratorWithTsType: "@Property 装饰器应与 TypeScript 类型保持一致(类型与 nullable)。",
51
- removePropertyDecorator: "属性带有 @{{decoratorName}} 装饰器,应移除 @Property 装饰器。",
52
- useEnumDecorator: "枚举类型应使用 @Enum 装饰器而不是 @Property 装饰器。",
53
- useOptTypeForInitializedProperty: "有非 null 初始化值的属性应使用 Opt<T> 类型包装。",
54
- removeOptTypeForNonInitializedProperty: "没有初始化值或初始化为 null 的属性不应使用 Opt<T> 类型包装。",
50
+ alignPropertyDecoratorWithTsType: "@Property decorator should align with the TypeScript type (type and nullable).",
51
+ removePropertyDecorator: "Property has a @{{decoratorName}} decorator, @Property decorator should be removed.",
52
+ useEnumDecorator: "Enum types should use @Enum decorator instead of @Property decorator.",
53
+ useOptTypeForInitializedProperty: "Properties with non-null initializers should use the Opt<T> type wrapper.",
54
+ removeOptTypeForNonInitializedProperty: "Properties without initializers or initialized to null should not use the Opt<T> type wrapper.",
55
55
  },
56
56
  },
57
57
  defaultOptions: [],
@@ -59,16 +59,16 @@ exports.default = (0, createRule_1.createRule)({
59
59
  const source = context.sourceCode;
60
60
  const parserServices = utils_1.ESLintUtils.getParserServices(context);
61
61
  const checker = parserServices.program.getTypeChecker();
62
- // 检查是否为枚举类型
62
+ // Check if the type is an enum
63
63
  const isEnumType = (node) => {
64
64
  try {
65
65
  const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
66
66
  const type = checker.getTypeAtLocation(tsNode);
67
- // 检查是否是枚举类型
67
+ // Check if it is an enum type
68
68
  if (type.symbol.flags & ts.SymbolFlags.Enum) {
69
69
  return true;
70
70
  }
71
- // 检查联合类型中的每个成员
71
+ // Check each member in a union type
72
72
  if (type.isUnion()) {
73
73
  return type.types.some((t) => t.symbol.flags & ts.SymbolFlags.EnumMember ||
74
74
  t.symbol.flags & ts.SymbolFlags.Enum);
@@ -85,15 +85,15 @@ exports.default = (0, createRule_1.createRule)({
85
85
  switch (typeName) {
86
86
  case "String":
87
87
  case "string":
88
- return "t.string"; // 默认使用 t.string
88
+ return "t.string"; // Default to t.string
89
89
  case "Number":
90
90
  case "number":
91
- return "t.float"; // 默认使用 t.float
91
+ return "t.float"; // Default to t.float
92
92
  case "Boolean":
93
93
  case "boolean":
94
- return "t.boolean"; // 默认使用 t.boolean
94
+ return "t.boolean"; // Default to t.boolean
95
95
  case "Date":
96
- return "t.datetime"; // 默认使用 t.datetime
96
+ return "t.datetime"; // Default to t.datetime
97
97
  case "GraphQLJSONObject":
98
98
  case "Record":
99
99
  return "t.json";
@@ -104,7 +104,7 @@ exports.default = (0, createRule_1.createRule)({
104
104
  const isValidStringType = (typeConfig) => {
105
105
  if (!typeConfig)
106
106
  return false;
107
- // 接受 t.string, t.text, t.uuid, t.decimal, t.bigint
107
+ // Accept t.string, t.text, t.uuid, t.decimal, t.bigint
108
108
  if (typeConfig === "t.string" ||
109
109
  typeConfig === "t.text" ||
110
110
  typeConfig === "t.uuid" ||
@@ -112,20 +112,20 @@ exports.default = (0, createRule_1.createRule)({
112
112
  typeConfig === "t.bigint") {
113
113
  return true;
114
114
  }
115
- // 接受 DecimalType(类引用,不带参数)
115
+ // Accept DecimalType (class reference, without arguments)
116
116
  if (typeConfig === "DecimalType") {
117
117
  return true;
118
118
  }
119
- // 接受 new DecimalType('string') new BigIntType('string')
120
- // 但排除 new BigIntType('number')
119
+ // Accept new DecimalType('string') and new BigIntType('string')
120
+ // but exclude new BigIntType('number')
121
121
  if (typeConfig.includes("DecimalType") ||
122
122
  typeConfig.includes("BigIntType")) {
123
- // 如果是 new BigIntType('number'),则无效
123
+ // If it's new BigIntType('number'), it's invalid
124
124
  if (typeConfig.includes("BigIntType") &&
125
125
  (typeConfig.includes("'number'") || typeConfig.includes('"number"'))) {
126
126
  return false;
127
127
  }
128
- // 其他情况(包括 new XXXType('string') DecimalType)都有效
128
+ // Other cases (including new XXXType('string') and DecimalType) are valid
129
129
  return true;
130
130
  }
131
131
  return false;
@@ -133,27 +133,27 @@ exports.default = (0, createRule_1.createRule)({
133
133
  const isValidNumberType = (typeConfig) => {
134
134
  if (!typeConfig)
135
135
  return false;
136
- // 接受 t.integer, t.float, t.double, t.decimal
136
+ // Accept t.integer, t.float, t.double, t.decimal
137
137
  if (typeConfig === "t.integer" ||
138
138
  typeConfig === "t.float" ||
139
139
  typeConfig === "t.double" ||
140
140
  typeConfig === "t.decimal") {
141
141
  return true;
142
142
  }
143
- // 接受 BigIntType DecimalType(类引用,不带参数)
143
+ // Accept BigIntType and DecimalType (class reference, without arguments)
144
144
  if (typeConfig === "BigIntType" || typeConfig === "DecimalType") {
145
145
  return true;
146
146
  }
147
- // 接受 new DecimalType('number') new BigIntType('number')
148
- // 但排除 new XXXType('string')
147
+ // Accept new DecimalType('number') and new BigIntType('number')
148
+ // but exclude new XXXType('string')
149
149
  if (typeConfig.includes("DecimalType") ||
150
150
  typeConfig.includes("BigIntType")) {
151
- // 如果包含 'string',则对 number 类型无效
151
+ // If it contains 'string', it's invalid for number type
152
152
  if (typeConfig.includes("'string'") ||
153
153
  typeConfig.includes('"string"')) {
154
154
  return false;
155
155
  }
156
- // 其他情况(包括 new XXXType('number'))都有效
156
+ // Other cases (including new XXXType('number')) are valid
157
157
  return true;
158
158
  }
159
159
  return false;
@@ -161,15 +161,15 @@ exports.default = (0, createRule_1.createRule)({
161
161
  const isValidNumberArrayType = (typeConfig) => {
162
162
  if (!typeConfig)
163
163
  return false;
164
- // 接受 t.array(默认)
164
+ // Accept t.array (default)
165
165
  if (typeConfig === "t.array") {
166
166
  return true;
167
167
  }
168
- // 接受 VectorType(类引用)
168
+ // Accept VectorType (class reference)
169
169
  if (typeConfig === "VectorType") {
170
170
  return true;
171
171
  }
172
- // 接受 new VectorType(...)
172
+ // Accept new VectorType(...)
173
173
  if (typeConfig.includes("VectorType")) {
174
174
  return true;
175
175
  }
@@ -178,7 +178,7 @@ exports.default = (0, createRule_1.createRule)({
178
178
  const isValidDateType = (typeConfig) => {
179
179
  if (!typeConfig)
180
180
  return false;
181
- // 接受 t.datetime, t.date, t.time
181
+ // Accept t.datetime, t.date, t.time
182
182
  if (typeConfig === "t.datetime" ||
183
183
  typeConfig === "t.date" ||
184
184
  typeConfig === "t.time") {
@@ -209,7 +209,7 @@ exports.default = (0, createRule_1.createRule)({
209
209
  node.typeName.type === utils_1.AST_NODE_TYPES.Identifier &&
210
210
  node.typeName.name === "Collection");
211
211
  };
212
- // 检查类型是否被 Opt<T> 包装
212
+ // Check if the type is wrapped with Opt<T>
213
213
  const isWrappedWithOpt = (property) => {
214
214
  const typeAnnotation = property.typeAnnotation;
215
215
  if (typeAnnotation?.type !== utils_1.AST_NODE_TYPES.TSTypeAnnotation) {
@@ -220,13 +220,13 @@ exports.default = (0, createRule_1.createRule)({
220
220
  typeNode.typeName.type === utils_1.AST_NODE_TYPES.Identifier &&
221
221
  typeNode.typeName.name === "Opt");
222
222
  };
223
- // 检查是否已导入 Opt
223
+ // Check if Opt is imported
224
224
  const hasOptImport = () => {
225
225
  const program = context.sourceCode.ast;
226
226
  for (const statement of program.body) {
227
227
  if (statement.type === utils_1.AST_NODE_TYPES.ImportDeclaration) {
228
228
  const importSource = statement.source.value;
229
- // 检查从 @mikro-orm/* 导入的语句
229
+ // Check imports from @mikro-orm/*
230
230
  if (typeof importSource === "string" &&
231
231
  importSource.startsWith("@mikro-orm/")) {
232
232
  const hasOpt = statement.specifiers.some((spec) => {
@@ -241,10 +241,10 @@ exports.default = (0, createRule_1.createRule)({
241
241
  }
242
242
  return false;
243
243
  };
244
- // 添加 Opt @mikro-orm/core 的导入
244
+ // Add Opt to the @mikro-orm/core import
245
245
  const addOptImport = (fixer) => {
246
246
  const program = context.sourceCode.ast;
247
- // 查找 @mikro-orm/core 的导入语句
247
+ // Find the @mikro-orm/core import statement
248
248
  let coreImport = null;
249
249
  for (const statement of program.body) {
250
250
  if (statement.type === utils_1.AST_NODE_TYPES.ImportDeclaration) {
@@ -256,23 +256,23 @@ exports.default = (0, createRule_1.createRule)({
256
256
  }
257
257
  }
258
258
  if (coreImport) {
259
- // 已有 @mikro-orm/core 导入,添加 Opt 到导入列表
259
+ // Already has @mikro-orm/core import, add Opt to the import list
260
260
  const lastSpecifier = coreImport.specifiers[coreImport.specifiers.length - 1];
261
- // 检查是否是多行导入
261
+ // Check if it's a multiline import
262
262
  const importText = source.getText(coreImport);
263
263
  const isMultiline = importText.includes("\n");
264
264
  if (isMultiline) {
265
- // 多行导入:在最后一个导入项后添加,保持缩进
266
- const indent = " "; // 假设使用 2 个空格缩进
265
+ // Multiline import: add after the last import item, keeping indentation
266
+ const indent = " "; // Assuming 2-space indentation
267
267
  return fixer.insertTextAfter(lastSpecifier, `,\n${indent}Opt`);
268
268
  }
269
269
  else {
270
- // 单行导入:直接添加
270
+ // Single-line import: add directly
271
271
  return fixer.insertTextAfter(lastSpecifier, ", Opt");
272
272
  }
273
273
  }
274
274
  else {
275
- // 没有 @mikro-orm/core 导入,在文件开头添加新的导入语句
275
+ // No @mikro-orm/core import, add a new import statement at the top
276
276
  const firstImport = program.body.find((node) => node.type === utils_1.AST_NODE_TYPES.ImportDeclaration);
277
277
  if (firstImport) {
278
278
  return fixer.insertTextBefore(firstImport, "import { Opt } from '@mikro-orm/core';\n");
@@ -287,11 +287,11 @@ exports.default = (0, createRule_1.createRule)({
287
287
  let baseTypeNode = property.typeAnnotation?.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation
288
288
  ? property.typeAnnotation.typeAnnotation
289
289
  : null;
290
- // 可选属性(?)视为可空
290
+ // Optional property (?) is treated as nullable
291
291
  if (property.optional) {
292
292
  isNullable = true;
293
293
  }
294
- // 处理联合类型中的 null/undefined
294
+ // Handle null/undefined in union types
295
295
  if (baseTypeNode?.type === utils_1.AST_NODE_TYPES.TSUnionType) {
296
296
  const hasNullish = baseTypeNode.types.some((t) => {
297
297
  return (t.type === utils_1.AST_NODE_TYPES.TSNullKeyword ||
@@ -305,7 +305,7 @@ exports.default = (0, createRule_1.createRule)({
305
305
  t.type !== utils_1.AST_NODE_TYPES.TSUndefinedKeyword);
306
306
  }) ?? null;
307
307
  }
308
- // 先解包 Ref<T> Opt<T> → T,并在内部再次处理 null/undefined
308
+ // First unwrap Ref<T> and Opt<T> → T, and handle null/undefined within
309
309
  if (baseTypeNode?.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
310
310
  baseTypeNode.typeName.type === utils_1.AST_NODE_TYPES.Identifier &&
311
311
  (baseTypeNode.typeName.name === "Ref" ||
@@ -326,11 +326,11 @@ exports.default = (0, createRule_1.createRule)({
326
326
  }
327
327
  baseTypeNode = inner ?? baseTypeNode;
328
328
  }
329
- // 跳过 Collection<T> 类型(这些应该由 OneToMany 等装饰器处理)
329
+ // Skip Collection<T> types (these should be handled by OneToMany etc. decorators)
330
330
  if (baseTypeNode && isCollectionType(baseTypeNode)) {
331
331
  return null;
332
332
  }
333
- // 数组类型(T[] Array<T>)- 在解包 Opt/Ref 之后检查
333
+ // Array type (T[] or Array<T>) - checked after unwrapping Opt/Ref
334
334
  const elementTypeNode = baseTypeNode
335
335
  ? extractArrayElementType(baseTypeNode)
336
336
  : null;
@@ -338,11 +338,11 @@ exports.default = (0, createRule_1.createRule)({
338
338
  isArray = true;
339
339
  }
340
340
  const targetTypeNode = elementTypeNode ?? baseTypeNode;
341
- // 检查目标类型是否为枚举
341
+ // Check if target type is an enum
342
342
  if (targetTypeNode) {
343
343
  isEnum = isEnumType(targetTypeNode);
344
344
  }
345
- // 无显式类型时,尝试从字面量初始值推断
345
+ // When no explicit type, try to infer from literal initializer
346
346
  if (!targetTypeNode) {
347
347
  if (property.value?.type === utils_1.AST_NODE_TYPES.Literal) {
348
348
  const value = property.value.value;
@@ -390,7 +390,7 @@ exports.default = (0, createRule_1.createRule)({
390
390
  arrayElementTypeName: isArray ? "Record" : undefined,
391
391
  };
392
392
  }
393
- // 关键字类型
393
+ // Keyword types
394
394
  if (targetTypeNode.type === utils_1.AST_NODE_TYPES.TSStringKeyword) {
395
395
  return {
396
396
  typeName: "string",
@@ -421,10 +421,10 @@ exports.default = (0, createRule_1.createRule)({
421
421
  arrayElementTypeName: isArray ? "boolean" : undefined,
422
422
  };
423
423
  }
424
- // 标识符(类/自定义类型)
424
+ // Identifier (class/custom type)
425
425
  const ident = getIdentifierName(targetTypeNode);
426
426
  if (ident) {
427
- // 如果是数组,自定义类型数组使用 t.json
427
+ // For arrays, custom type arrays use t.json
428
428
  if (isArray) {
429
429
  return {
430
430
  typeName: ident,
@@ -446,7 +446,7 @@ exports.default = (0, createRule_1.createRule)({
446
446
  }
447
447
  return null;
448
448
  };
449
- // 将类型包装为 Opt<T>
449
+ // Wrap type with Opt<T>
450
450
  const wrapWithOpt = (typeString) => {
451
451
  return `Opt<${typeString}>`;
452
452
  };
@@ -465,11 +465,11 @@ exports.default = (0, createRule_1.createRule)({
465
465
  };
466
466
  const buildPropertyDecorator = (info, otherProps = [], decoratorName = "Property") => {
467
467
  const options = [];
468
- // 如果有 propertyType 配置,添加 type
468
+ // If there is a propertyType configuration, add type
469
469
  if (info.propertyType) {
470
470
  options.push(`type: ${info.propertyType}`);
471
471
  }
472
- // 添加其他属性(保持原有顺序)
472
+ // Add other properties (keeping original order)
473
473
  for (const prop of otherProps) {
474
474
  options.push(`${prop.key}: ${prop.value}`);
475
475
  }
@@ -493,36 +493,36 @@ exports.default = (0, createRule_1.createRule)({
493
493
  };
494
494
  const fixWithTypeInfo = (property, propertyDecorator, info, currentConfig, decoratorName = "Property") => {
495
495
  const fixes = [];
496
- // 如果当前已经有有效的配置,保留它而不是替换成默认值
496
+ // If current config already has a valid value, keep it instead of replacing with default
497
497
  const finalInfo = { ...info };
498
- // PrimaryKey number 类型默认使用 t.integer
498
+ // PrimaryKey number type defaults to t.integer
499
499
  if (decoratorName === "PrimaryKey" &&
500
500
  finalInfo.propertyType === "t.float") {
501
501
  finalInfo.propertyType = "t.integer";
502
502
  }
503
503
  if (info.propertyType === "t.string" &&
504
504
  isValidStringType(currentConfig.type)) {
505
- // 保留有效的 string 类型配置
505
+ // Keep valid string type config
506
506
  finalInfo.propertyType = currentConfig.type;
507
507
  }
508
508
  else if ((info.propertyType === "t.float" ||
509
509
  info.propertyType === "t.integer") &&
510
510
  isValidNumberType(currentConfig.type)) {
511
- // 保留有效的 number 类型配置
511
+ // Keep valid number type config
512
512
  finalInfo.propertyType = currentConfig.type;
513
513
  }
514
514
  else if (info.propertyType === "t.datetime" &&
515
515
  isValidDateType(currentConfig.type)) {
516
- // 保留有效的 Date 类型配置
516
+ // Keep valid Date type config
517
517
  finalInfo.propertyType = currentConfig.type;
518
518
  }
519
519
  else if (info.isArray &&
520
520
  info.arrayElementTypeName === "number" &&
521
521
  isValidNumberArrayType(currentConfig.type)) {
522
- // 保留有效的 number[] 类型配置(VectorType
522
+ // Keep valid number[] type config (VectorType)
523
523
  finalInfo.propertyType = currentConfig.type;
524
524
  }
525
- // 保留其他属性配置
525
+ // Keep other property configs
526
526
  const newDecoratorText = buildPropertyDecorator(finalInfo, currentConfig.otherProps, decoratorName);
527
527
  fixes.push({
528
528
  type: "replace",
@@ -572,7 +572,7 @@ exports.default = (0, createRule_1.createRule)({
572
572
  }
573
573
  }
574
574
  else {
575
- // 保留其他所有属性
575
+ // Keep all other properties
576
576
  otherProps.push({
577
577
  key: prop.key.name,
578
578
  value: source.getText(prop.value),
@@ -610,38 +610,38 @@ exports.default = (0, createRule_1.createRule)({
610
610
  }
611
611
  return { items, nullable };
612
612
  };
613
- // 检查文件中是否使用了 Opt 类型但没有导入
613
+ // Check if the file uses the Opt type but hasn't imported it
614
614
  const checkOptUsageWithoutImport = (node) => {
615
615
  let usesOpt = false;
616
- // 遍历所有成员,检查是否有使用 Opt<T> 的类型注解
616
+ // Iterate through all members to check for Opt<T> type annotations
617
617
  node.body.body.forEach((member) => {
618
618
  if (member.type !== utils_1.AST_NODE_TYPES.PropertyDefinition)
619
619
  return;
620
620
  const typeAnnotation = member.typeAnnotation?.typeAnnotation;
621
621
  if (!typeAnnotation)
622
622
  return;
623
- // 递归检查类型节点中是否包含 Opt
623
+ // Recursively check if the type node contains Opt
624
624
  const containsOpt = (typeNode) => {
625
625
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
626
626
  if (!typeNode)
627
627
  return false;
628
- // 检查是否是 Opt<T>
628
+ // Check if it's Opt<T>
629
629
  if (typeNode.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
630
630
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
631
631
  typeNode.typeName?.type === utils_1.AST_NODE_TYPES.Identifier &&
632
632
  typeNode.typeName.name === "Opt") {
633
633
  return true;
634
634
  }
635
- // 递归检查联合类型
635
+ // Recursively check union types
636
636
  if (typeNode.type === utils_1.AST_NODE_TYPES.TSUnionType) {
637
637
  return typeNode.types.some((t) => containsOpt(t));
638
638
  }
639
- // 递归检查类型参数
639
+ // Recursively check type parameters
640
640
  if (typeNode.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
641
641
  typeNode.typeArguments?.params) {
642
642
  return typeNode.typeArguments.params.some((param) => containsOpt(param));
643
643
  }
644
- // 递归检查数组元素类型
644
+ // Recursively check array element type
645
645
  if (typeNode.type === utils_1.AST_NODE_TYPES.TSArrayType) {
646
646
  return containsOpt(typeNode.elementType);
647
647
  }
@@ -651,7 +651,7 @@ exports.default = (0, createRule_1.createRule)({
651
651
  usesOpt = true;
652
652
  }
653
653
  });
654
- // 如果使用了 Opt 但没有导入,报告错误
654
+ // If Opt is used but not imported, report an error
655
655
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
656
656
  if (usesOpt && !hasOptImport()) {
657
657
  context.report({
@@ -668,12 +668,12 @@ exports.default = (0, createRule_1.createRule)({
668
668
  ClassDeclaration(node) {
669
669
  if (!isEntityClass(node))
670
670
  return;
671
- // 首先检查是否使用了 Opt 但没有导入
671
+ // First check if Opt is used but not imported
672
672
  checkOptUsageWithoutImport(node);
673
673
  node.body.body.forEach((member) => {
674
674
  if (member.type !== utils_1.AST_NODE_TYPES.PropertyDefinition)
675
675
  return;
676
- // 检查关系装饰器(OneToOne, OneToMany, ManyToOne, ManyToMany
676
+ // Check relation decorators (OneToOne, OneToMany, ManyToOne, ManyToMany)
677
677
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
678
678
  const hasRelationDecorator = member.decorators?.some((decorator) => {
679
679
  if (decorator.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
@@ -688,17 +688,17 @@ exports.default = (0, createRule_1.createRule)({
688
688
  }
689
689
  return false;
690
690
  });
691
- // 如果有关系装饰器,跳过检查(这些属性不需要 @Property 装饰器)
691
+ // If there are relation decorators, skip checking (these properties don't need @Property)
692
692
  if (hasRelationDecorator)
693
693
  return;
694
- // Property 装饰器列表(需要类型检查的装饰器)
694
+ // Property-like decorators (decorators that need type checking)
695
695
  const propertyLikeDecorators = [
696
696
  "Property",
697
697
  "PrimaryKey",
698
698
  "EncryptedProperty",
699
699
  "HashedProperty",
700
700
  ];
701
- // 查找类 Property 装饰器
701
+ // Find property-like decorator
702
702
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
703
703
  const propertyLikeDecorator = member.decorators?.find((decorator) => {
704
704
  if (decorator.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
@@ -707,7 +707,7 @@ exports.default = (0, createRule_1.createRule)({
707
707
  }
708
708
  return false;
709
709
  });
710
- // 获取装饰器名称
710
+ // Get decorator name
711
711
  const getDecoratorName = (decorator) => {
712
712
  if (decorator.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
713
713
  decorator.expression.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
@@ -715,7 +715,7 @@ exports.default = (0, createRule_1.createRule)({
715
715
  }
716
716
  return null;
717
717
  };
718
- // 检查 @Enum 装饰器
718
+ // Check @Enum decorator
719
719
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
720
720
  const enumDecorator = member.decorators?.find((decorator) => {
721
721
  return (decorator.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
@@ -723,7 +723,7 @@ exports.default = (0, createRule_1.createRule)({
723
723
  utils_1.AST_NODE_TYPES.Identifier &&
724
724
  decorator.expression.callee.name === "Enum");
725
725
  });
726
- // 使用类 Property 装饰器
726
+ // Use property-like decorator
727
727
  const propertyDecorator = propertyLikeDecorator;
728
728
  const currentDecoratorName = propertyDecorator
729
729
  ? getDecoratorName(propertyDecorator)
@@ -731,20 +731,20 @@ exports.default = (0, createRule_1.createRule)({
731
731
  const typeInfo = computeTypeInfo(member);
732
732
  if (!typeInfo?.typeName)
733
733
  return;
734
- // 检查初始化值和 Opt<T> 类型的匹配
734
+ // Check initializer and Opt<T> type match
735
735
  const hasInitializer = member.value !== null;
736
736
  const isOptWrapped = isWrappedWithOpt(member);
737
- // 检查初始化值是否为 null
737
+ // Check if the initializer is null
738
738
  const isInitializedToNull = hasInitializer &&
739
739
  member.value?.type === utils_1.AST_NODE_TYPES.Literal &&
740
740
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
741
741
  member.value?.value === null;
742
- // 情况 1:有非 null 初始化值但没有使用 Opt<T>
742
+ // Case 1: Has non-null initializer but not wrapped with Opt<T>
743
743
  if (hasInitializer &&
744
744
  !isInitializedToNull &&
745
745
  !isOptWrapped &&
746
746
  !member.optional) {
747
- // 有初始化值但没有使用 Opt<T> 包装,需要报错
747
+ // Has initializer but not wrapped with Opt<T>, needs to report error
748
748
  const typeAnnotation = member.typeAnnotation?.typeAnnotation;
749
749
  const needsImport = !hasOptImport();
750
750
  if (typeAnnotation) {
@@ -757,7 +757,7 @@ exports.default = (0, createRule_1.createRule)({
757
757
  const fixes = [
758
758
  fixer.replaceText(typeAnnotation, wrappedType),
759
759
  ];
760
- // 如果需要,添加 Opt 导入
760
+ // If needed, add Opt import
761
761
  if (needsImport) {
762
762
  const importFix = addOptImport(fixer);
763
763
  if (importFix)
@@ -768,7 +768,7 @@ exports.default = (0, createRule_1.createRule)({
768
768
  });
769
769
  }
770
770
  else if (member.value) {
771
- // 没有类型注解,从初始化值推断类型
771
+ // No type annotation, infer type from initializer
772
772
  let inferredType = null;
773
773
  if (member.value.type === utils_1.AST_NODE_TYPES.Literal) {
774
774
  const valueType = typeof member.value.value;
@@ -780,11 +780,11 @@ exports.default = (0, createRule_1.createRule)({
780
780
  inferredType = "string";
781
781
  }
782
782
  else if (member.value.type === utils_1.AST_NODE_TYPES.ArrayExpression) {
783
- // 空数组 [] 的情况,需要从 @Property 装饰器推断类型
783
+ // Empty array [] case, need to infer type from @Property decorator
784
784
  inferredType = "unknown[]";
785
785
  }
786
786
  else if (member.value.type === utils_1.AST_NODE_TYPES.NewExpression) {
787
- // new Date() 的情况
787
+ // new Date() case
788
788
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
789
789
  if (member.value.callee?.type === utils_1.AST_NODE_TYPES.Identifier) {
790
790
  inferredType = member.value.callee.name;
@@ -800,7 +800,7 @@ exports.default = (0, createRule_1.createRule)({
800
800
  const fixes = [
801
801
  fixer.insertTextAfter(propertyName, `: ${wrappedType}`),
802
802
  ];
803
- // 如果需要,添加 Opt 导入
803
+ // If needed, add Opt import
804
804
  if (needsImport) {
805
805
  const importFix = addOptImport(fixer);
806
806
  if (importFix)
@@ -812,10 +812,10 @@ exports.default = (0, createRule_1.createRule)({
812
812
  }
813
813
  }
814
814
  }
815
- // 如果有 @Enum 装饰器,无论是否识别为枚举类型,都检查其配置
815
+ // If there is an @Enum decorator, check its configuration regardless of whether the type is recognized as enum
816
816
  if (enumDecorator) {
817
817
  const enumConfig = parseEnumDecorator(enumDecorator);
818
- // 检查 nullable 配置是否与 TypeScript 类型匹配
818
+ // Check if nullable configuration matches the TypeScript type
819
819
  if (enumConfig.nullable !== typeInfo.isNullable) {
820
820
  const expectedEnumText = buildEnumDecorator(typeInfo);
821
821
  context.report({
@@ -826,12 +826,12 @@ exports.default = (0, createRule_1.createRule)({
826
826
  },
827
827
  });
828
828
  }
829
- // @Enum 装饰器的属性,不需要 @Property 装饰器
829
+ // Properties with @Enum decorator do not need @Property decorator
830
830
  return;
831
831
  }
832
- // 如果是枚举类型但没有 @Enum 装饰器
832
+ // If it's an enum type but doesn't have @Enum decorator
833
833
  if (typeInfo.isEnum) {
834
- // 如果有 @Property 装饰器,建议替换为 @Enum
834
+ // If it has @Property decorator, suggest replacing with @Enum
835
835
  if (propertyDecorator) {
836
836
  context.report({
837
837
  node: propertyDecorator,
@@ -843,7 +843,7 @@ exports.default = (0, createRule_1.createRule)({
843
843
  });
844
844
  return;
845
845
  }
846
- // 如果没有 @Enum 装饰器,添加它
846
+ // If it doesn't have @Enum decorator, add one
847
847
  context.report({
848
848
  node: member,
849
849
  messageId: "useEnumDecorator",
@@ -854,7 +854,7 @@ exports.default = (0, createRule_1.createRule)({
854
854
  });
855
855
  return;
856
856
  }
857
- // 非枚举类型:如果没有 @Property 装饰器,添加它
857
+ // Non-enum type: if no @Property decorator, add one
858
858
  if (!propertyDecorator) {
859
859
  context.report({
860
860
  node: member,
@@ -866,39 +866,39 @@ exports.default = (0, createRule_1.createRule)({
866
866
  });
867
867
  return;
868
868
  }
869
- // 检查现有装饰器是否与类型匹配
869
+ // Check if existing decorator matches the type
870
870
  const currentConfig = parsePropertyDecorator(propertyDecorator);
871
871
  let expectedType = typeInfo.propertyType;
872
- // PrimaryKey number 类型期望 t.integer
872
+ // PrimaryKey number type expects t.integer
873
873
  if (currentDecoratorName === "PrimaryKey" &&
874
874
  expectedType === "t.float") {
875
875
  expectedType = "t.integer";
876
876
  }
877
877
  let needReport = false;
878
- // 检查 type 配置
878
+ // Check type configuration
879
879
  if (expectedType && currentConfig.type !== expectedType) {
880
- // 对于 string 类型,接受多种有效配置
880
+ // For string type, accept multiple valid configurations
881
881
  if (expectedType === "t.string" &&
882
882
  isValidStringType(currentConfig.type)) {
883
- // 当前配置是有效的 string 类型配置,不需要修改
883
+ // Current config is a valid string type configuration, no modification needed
884
884
  }
885
885
  else if ((expectedType === "t.float" || expectedType === "t.integer") &&
886
886
  isValidNumberType(currentConfig.type)) {
887
- // 当前配置是有效的 number 类型配置,不需要修改
887
+ // Current config is a valid number type configuration, no modification needed
888
888
  }
889
889
  else if (expectedType === "t.datetime" &&
890
890
  isValidDateType(currentConfig.type)) {
891
- // 当前配置是有效的 Date 类型配置,不需要修改
891
+ // Current config is a valid Date type configuration, no modification needed
892
892
  }
893
893
  else if (expectedType === "t.array" &&
894
894
  typeInfo.arrayElementTypeName === "number" &&
895
895
  isValidNumberArrayType(currentConfig.type)) {
896
- // 当前配置是有效的 number[] 类型配置(t.array VectorType),不需要修改
896
+ // Current config is a valid number[] type configuration (t.array or VectorType), no modification needed
897
897
  }
898
898
  else if (expectedType === "t.json") {
899
- // 对于 t.json 类型(Record 或自定义类型数组)
899
+ // For t.json type (Record or custom type arrays)
900
900
  if (currentConfig.type === "t.json") {
901
- // t.json 配置正确,不需要修改
901
+ // t.json config is correct, no modification needed
902
902
  }
903
903
  else {
904
904
  needReport = true;
@@ -909,10 +909,10 @@ exports.default = (0, createRule_1.createRule)({
909
909
  }
910
910
  }
911
911
  else if (!expectedType && currentConfig.type) {
912
- // 如果不需要 type 但当前有 type,也需要修正
912
+ // If type is not needed but currently has one, needs correction
913
913
  needReport = true;
914
914
  }
915
- // 检查 nullable 配置
915
+ // Check nullable configuration
916
916
  if (currentConfig.nullable !== typeInfo.isNullable) {
917
917
  needReport = true;
918
918
  }