@hadss/turbo-trans-json-plugin 1.0.0-rc.1 → 1.0.0-rc.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 (76) hide show
  1. package/dist/core/analyzers/ClassAnalyzer.d.ts +15 -0
  2. package/dist/core/analyzers/ClassAnalyzer.js +193 -144
  3. package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +3 -0
  4. package/dist/core/analyzers/CustomTypeAnalyzer.js +65 -60
  5. package/dist/core/constants/DecoratorConstants.js +2 -1
  6. package/dist/core/import-rewrite/services/BuildProfileUpdater.js +1 -1
  7. package/dist/core/import-rewrite/services/ImportRewriteService.js +1 -1
  8. package/dist/core/interfaces/index.d.ts +2 -2
  9. package/dist/core/services/CodeAnalysisService.js +2 -1
  10. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +2 -0
  11. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +22 -15
  12. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +22 -0
  13. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +194 -129
  14. package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +1 -1
  15. package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +2 -1
  16. package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +2 -2
  17. package/dist/core/template/HandlebarsTemplateEngine.d.ts +2 -0
  18. package/dist/core/template/HandlebarsTemplateEngine.js +21 -2
  19. package/dist/core/utils/DeepCopyUtil.js +1 -1
  20. package/dist/core/utils/SerializationPathUtil.d.ts +1 -1
  21. package/dist/core/utils/TsMorphUtil.js +2 -1
  22. package/dist/json-plugin/JSONExecuteController.d.ts +4 -0
  23. package/dist/json-plugin/JSONExecuteController.js +46 -36
  24. package/dist/json-plugin/interfaces/impl/TargetContext.js +4 -2
  25. package/dist/json-plugin/tasks/BaseTask.d.ts +2 -2
  26. package/dist/json-plugin/tasks/WatchTask.js +2 -1
  27. package/package.json +1 -1
  28. package/src/core/Types.ts +90 -90
  29. package/src/core/analyzers/ClassAnalyzer.ts +335 -230
  30. package/src/core/analyzers/CustomTypeAnalyzer.ts +145 -73
  31. package/src/core/constants/DecoratorConstants.ts +7 -6
  32. package/src/core/constants/PathConstants.ts +7 -7
  33. package/src/core/constants/StringConstants.ts +95 -95
  34. package/src/core/handlers/BaseTypeHandler.ts +11 -2
  35. package/src/core/handlers/CustomClassHandler.ts +4 -4
  36. package/src/core/handlers/DateHandler.ts +54 -46
  37. package/src/core/handlers/DecimalHandler.ts +53 -45
  38. package/src/core/handlers/EnumHandler.ts +2 -1
  39. package/src/core/handlers/GenericContainerHandler.ts +3 -1
  40. package/src/core/handlers/TupleHandler.ts +2 -1
  41. package/src/core/handlers/TypeHandlerRegistry.ts +2 -1
  42. package/src/core/handlers/UnionTypeHandler.ts +8 -7
  43. package/src/core/import-rewrite/services/BuildProfileUpdater.ts +6 -4
  44. package/src/core/import-rewrite/services/ImportRewriteService.ts +1 -1
  45. package/src/core/import-rewrite/services/ImportTransformService.ts +2 -2
  46. package/src/core/import-rewrite/types/ImportRewriteTypes.ts +3 -3
  47. package/src/core/index.ts +4 -4
  48. package/src/core/interfaces/ITask.ts +6 -5
  49. package/src/core/interfaces/ITaskContext.ts +9 -9
  50. package/src/core/interfaces/index.ts +2 -2
  51. package/src/core/logger/Logger.ts +28 -28
  52. package/src/core/services/CodeAnalysisService.ts +2 -1
  53. package/src/core/services/CodeGenerationEngine.ts +42 -42
  54. package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +25 -22
  55. package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +261 -170
  56. package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +1 -1
  57. package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +5 -3
  58. package/src/core/services/CodeGenerationService/shared/ImportManager.ts +8 -8
  59. package/src/core/template/HandlebarsTemplateEngine.ts +39 -11
  60. package/src/core/utils/ConfigManager.ts +2 -1
  61. package/src/core/utils/DeepCopyUtil.ts +1 -1
  62. package/src/core/utils/GenericTypeSubstitutionUtil.ts +1 -8
  63. package/src/core/utils/SerializationPathUtil.ts +7 -6
  64. package/src/core/utils/TsMorphUtil.ts +4 -1
  65. package/src/index.ts +2 -2
  66. package/src/json-plugin/JSONExecuteController.ts +51 -38
  67. package/src/json-plugin/interfaces/IModuleContext.ts +8 -8
  68. package/src/json-plugin/interfaces/ITargetContext.ts +6 -6
  69. package/src/json-plugin/interfaces/impl/ModuleContext.ts +10 -10
  70. package/src/json-plugin/interfaces/impl/TargetContext.ts +63 -58
  71. package/src/json-plugin/tasks/BaseTask.ts +5 -3
  72. package/src/json-plugin/tasks/CleanTask.ts +7 -7
  73. package/src/json-plugin/tasks/WatchTask.ts +20 -18
  74. package/template/SerializerPerformanceTemplate.hbs +5 -5
  75. package/template/SerializerStrictTemplate.hbs +1 -1
  76. package/template/SerializerTemplate.hbs +59 -42
@@ -14,29 +14,12 @@
14
14
  */
15
15
 
16
16
  import {
17
- ClassDeclaration,
18
- ConstructorDeclaration,
19
- Decorator,
20
- InterfaceDeclaration,
21
- NewExpression,
22
- PropertyDeclaration,
23
- PropertySignature,
24
- SyntaxKind,
25
- TypeNode
17
+ ClassDeclaration, ConstructorDeclaration, Decorator, InterfaceDeclaration, NewExpression, ObjectLiteralExpression,
18
+ PropertyDeclaration, PropertySignature, SyntaxKind, TypeNode
26
19
  } from 'ts-morph';
27
20
  import {
28
- ClassAnalysis,
29
- ClassDecorators,
30
- ConstructorParam,
31
- DeserializationMode,
32
- GenericInfo,
33
- InheritanceInfo,
34
- InterfaceAnalysis,
35
- PropertyAnalysis,
36
- PropertyDecorators,
37
- PropertyKind,
38
- PropertyVisibility,
39
- SerializableOptions,
21
+ ClassAnalysis, ClassDecorators, ConstructorParam, DeserializationMode, GenericInfo, InheritanceInfo,
22
+ InterfaceAnalysis, PropertyAnalysis, PropertyDecorators, PropertyKind, PropertyVisibility, SerializableOptions,
40
23
  TypeStructure
41
24
  } from '../Types';
42
25
  import { DecoratorConstants } from '../constants';
@@ -222,45 +205,69 @@ export class ClassAnalyzer {
222
205
  return undefined;
223
206
  }
224
207
  const args = decorator.getArguments();
225
- let generateSendable: boolean | undefined;
226
- let _with: string | undefined;
227
- let deserializationMode: DeserializationMode | undefined;
228
-
229
208
  const firstArg = args[0];
230
209
 
231
- if (!firstArg) {
210
+ if (!firstArg || firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) {
232
211
  return {};
233
212
  }
234
213
 
235
- // 处理对象形式:@Serializable({ generateSendable: true })
236
- if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {
237
- const properties = firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression).getProperties();
238
-
239
- for (const prop of properties) {
240
- if (prop.getKind() === SyntaxKind.PropertyAssignment) {
241
- const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
242
- const propertyName = propAssignment.getName();
243
- const initializer = propAssignment.getInitializer();
244
- if (propertyName === 'generateSendable' && initializer) {
245
- if (initializer.getKind() === SyntaxKind.TrueKeyword) {
246
- generateSendable = true;
247
- } else if (initializer.getKind() === SyntaxKind.FalseKeyword) {
248
- generateSendable = false;
249
- }
250
- } else if (propertyName === 'with' && initializer) {
251
- // 处理 with 参数,存储完整的表达式文本
252
- _with = initializer.getText();
253
- } else if (propertyName === 'deserializationMode' && initializer) {
254
- // 处理 deserializationMode 参数:'performance' | 'strict'
255
- const modeText = initializer.getText().replace(/['"]/g, ''); // 去掉引号
256
- if (modeText === DeserializationMode.PERFORMANCE || modeText === DeserializationMode.STRICT) {
257
- deserializationMode = modeText as DeserializationMode;
258
- }
259
- }
260
- }
214
+ return this.extractOptionsFromObjectLiteral(firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression));
215
+ }
216
+
217
+ private static extractOptionsFromObjectLiteral(objectLiteral: ObjectLiteralExpression): SerializableOptions {
218
+ const options: SerializableOptions = {};
219
+ const properties = objectLiteral.getProperties();
220
+
221
+ for (const prop of properties) {
222
+ // early return: 非属性赋值节点
223
+ if (prop.getKind() !== SyntaxKind.PropertyAssignment) {
224
+ continue;
225
+ }
226
+ const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
227
+ const initializer = propAssignment.getInitializer();
228
+ // early return: 无初始化器
229
+ if (!initializer) {
230
+ continue;
261
231
  }
232
+
233
+ this.extractSingleOption(options, propAssignment.getName(), initializer);
234
+ }
235
+ return options;
236
+ }
237
+
238
+ private static extractSingleOption(
239
+ options: SerializableOptions,
240
+ propertyName: string,
241
+ initializer: ReturnType<typeof Object.prototype.valueOf>
242
+ ): void {
243
+ if (propertyName === 'generateSendable') {
244
+ options.generateSendable = this.parseBooleanInitializer(initializer);
245
+ } else if (propertyName === 'with') {
246
+ options.with = (initializer as { getText(): string }).getText();
247
+ } else if (propertyName === 'deserializationMode') {
248
+ this.parseDeserializationMode(options, initializer);
249
+ }
250
+ }
251
+
252
+ private static parseBooleanInitializer(initializer: ReturnType<typeof Object.prototype.valueOf>): boolean | undefined {
253
+ const kind = (initializer as { getKind(): SyntaxKind }).getKind();
254
+ if (kind === SyntaxKind.TrueKeyword) {
255
+ return true;
256
+ }
257
+ if (kind === SyntaxKind.FalseKeyword) {
258
+ return false;
259
+ }
260
+ return undefined;
261
+ }
262
+
263
+ private static parseDeserializationMode(
264
+ options: SerializableOptions,
265
+ initializer: ReturnType<typeof Object.prototype.valueOf>
266
+ ): void {
267
+ const modeText = (initializer as { getText(): string }).getText().replace(/['"]/g, '');
268
+ if (modeText === DeserializationMode.PERFORMANCE || modeText === DeserializationMode.STRICT) {
269
+ options.deserializationMode = modeText as DeserializationMode;
262
270
  }
263
- return { with: _with, generateSendable, deserializationMode };
264
271
  }
265
272
 
266
273
  /**
@@ -269,36 +276,53 @@ export class ClassAnalyzer {
269
276
  * @returns 序列化名称
270
277
  */
271
278
  private static parseSerialNameOptions(decorator?: Decorator): string | undefined {
279
+ // early return: 无装饰器
272
280
  if (!decorator) {
273
281
  return undefined;
274
282
  }
275
283
  const args = decorator.getArguments();
284
+ // early return: 无参数
276
285
  if (args.length === 0) {
277
286
  return undefined;
278
287
  }
279
288
 
280
289
  const firstArg = args[0];
281
290
 
291
+ // early return: 非对象字面量
292
+ if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) {
293
+ return undefined;
294
+ }
295
+
282
296
  // 处理对象形式:@SerialName({ name: 'xxx' })
283
- if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {
284
- const properties = firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression).getProperties();
285
-
286
- for (const prop of properties) {
287
- if (prop.getKind() === SyntaxKind.PropertyAssignment) {
288
- const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
289
- const name = propAssignment.getName();
290
-
291
- if (name === 'name') {
292
- const initializer = propAssignment.getInitializer();
293
- if (initializer && initializer.getKind() === SyntaxKind.StringLiteral) {
294
- const stringLiteral = initializer.asKindOrThrow(SyntaxKind.StringLiteral);
295
- return stringLiteral.getLiteralValue();
296
- }
297
- }
298
- }
297
+ const properties = firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression).getProperties();
298
+ return this.extractNameFromProperties(properties);
299
+ }
300
+
301
+ /**
302
+ * 从属性列表中提取name属性的值
303
+ * @param properties 属性列表
304
+ * @returns name属性的字符串值
305
+ */
306
+ private static extractNameFromProperties(properties: ReturnType<ObjectLiteralExpression['getProperties']>): string | undefined {
307
+ for (const prop of properties) {
308
+ // early return: 非属性赋值节点
309
+ if (prop.getKind() !== SyntaxKind.PropertyAssignment) {
310
+ continue;
311
+ }
312
+ const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
313
+ // early return: 非name属性
314
+ if (propAssignment.getName() !== 'name') {
315
+ continue;
299
316
  }
300
- }
301
317
 
318
+ const initializer = propAssignment.getInitializer();
319
+ // early return: 非字符串字面量
320
+ if (!initializer || initializer.getKind() !== SyntaxKind.StringLiteral) {
321
+ continue;
322
+ }
323
+
324
+ return initializer.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
325
+ }
302
326
  return undefined;
303
327
  }
304
328
 
@@ -323,40 +347,49 @@ export class ClassAnalyzer {
323
347
  genericParameters
324
348
  );
325
349
 
326
- // 检测 UNKNOWN 类型
327
- if (propertyAnalysis.type.kind === PropertyKind.UNKNOWN) {
328
- const hasTransient = propertyAnalysis.decorators?.isTransient;
329
- const hasCustomSerializer = !!propertyAnalysis.decorators?.with;
330
-
331
- if (!hasTransient && !hasCustomSerializer) {
332
- if (prop instanceof PropertyDeclaration) {
333
- // 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
334
- throw new CustomError(
335
- `不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
336
- }' (类: ${cls.getName()})。\n` +
337
- `请选择以下任一解决方案:\n` +
338
- ` 1. 添加 @Transient() 跳过序列化(属性仍会参与 Sendable 转换和对象拷贝):\n` +
339
- ` @Transient()\n` +
340
- ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};\n\n` +
341
- ` 2. 添加 @Serializable({with: CustomSerializer}) 指定自定义序列化器:\n` +
342
- ` @Serializable({with: DateSerializer.INSTANCE})\n` +
343
- ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};`,
344
- ErrorCodes.TYPE_NOT_SUPPORT
345
- );
346
- } else {
347
- // 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
348
- throw new CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
349
- }' (接口: ${cls.getName()})`, ErrorCodes.TYPE_NOT_SUPPORT);
350
- }
351
- }
352
- }
353
-
354
- // 保留所有属性(包括 UNKNOWN 类型),生成阶段再筛选
350
+ this.checkUnknownType(cls, prop, propertyAnalysis);
355
351
  ownProperties.push(propertyAnalysis);
356
352
  }
357
353
  return ownProperties;
358
354
  }
359
355
 
356
+ private static checkUnknownType(
357
+ cls: ClassDeclaration | InterfaceDeclaration,
358
+ prop: PropertyDeclaration | PropertySignature,
359
+ propertyAnalysis: PropertyAnalysis
360
+ ): void {
361
+ if (propertyAnalysis.type.kind !== PropertyKind.UNKNOWN) {
362
+ return;
363
+ }
364
+
365
+ const hasTransient = propertyAnalysis.decorators?.isTransient;
366
+ const hasCustomSerializer = !!propertyAnalysis.decorators?.with;
367
+
368
+ if (hasTransient || hasCustomSerializer) {
369
+ return;
370
+ }
371
+
372
+ if (prop instanceof PropertyDeclaration) {
373
+ // 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
374
+ throw new CustomError(
375
+ `不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
376
+ }' (类: ${cls.getName()})。\n` +
377
+ `请选择以下任一解决方案:\n` +
378
+ ` 1. 添加 @Transient() 跳过序列化(属性仍会参与 Sendable 转换和对象拷贝):\n` +
379
+ ` @Transient()\n` +
380
+ ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};\n\n` +
381
+ ` 2. 添加 @Serializable({with: CustomSerializer}) 指定自定义序列化器:\n` +
382
+ ` @Serializable({with: DateSerializer.INSTANCE})\n` +
383
+ ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};`,
384
+ ErrorCodes.TYPE_NOT_SUPPORT
385
+ );
386
+ } else {
387
+ // 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
388
+ throw new CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
389
+ }' (接口: ${cls.getName()})`, ErrorCodes.TYPE_NOT_SUPPORT);
390
+ }
391
+ }
392
+
360
393
  /**
361
394
  * 对属性进行分类,区分继承属性、重写属性和自有属性
362
395
  * @param ownProperties 自有属性数组
@@ -373,8 +406,8 @@ export class ClassAnalyzer {
373
406
  overriddenProperties: PropertyAnalysis[];
374
407
  properties: PropertyAnalysis[];
375
408
  } {
409
+ // early return: 没有继承,所有属性都是自有属性
376
410
  if (!inheritance.isInherited || !inheritance.baseClassAnalysis) {
377
- // 没有继承,所有属性都是自有属性
378
411
  return {
379
412
  inheritedProperties: [],
380
413
  overriddenProperties: [],
@@ -385,22 +418,34 @@ export class ClassAnalyzer {
385
418
  // 递归收集所有祖先属性 - 传递泛型参数进行替换
386
419
  const allAncestorProperties = this.collectAllAncestorProperties(
387
420
  inheritance.baseClassAnalysis,
388
- inheritance.genericTypeArguments || [], // 传递子类指定的泛型参数
389
- currentClassGenericParams // 传递当前类的泛型参数列表
421
+ inheritance.genericTypeArguments || [],
422
+ currentClassGenericParams
390
423
  );
391
424
 
425
+ return this.buildPropertyClassification(ownProperties, allAncestorProperties);
426
+ }
427
+
428
+ /**
429
+ * 根据自有属性和祖先属性构建属性分类结果
430
+ * @param ownProperties 自有属性数组
431
+ * @param allAncestorProperties 所有祖先属性数组
432
+ * @returns 分类后的属性对象
433
+ */
434
+ private static buildPropertyClassification(
435
+ ownProperties: PropertyAnalysis[],
436
+ allAncestorProperties: PropertyAnalysis[]
437
+ ): {
438
+ inheritedProperties: PropertyAnalysis[];
439
+ overriddenProperties: PropertyAnalysis[];
440
+ properties: PropertyAnalysis[];
441
+ } {
392
442
  // 构建自有属性名称集合,用于快速查找重写
393
443
  const ownPropertyNames = new Set(ownProperties.map((prop) => prop.name));
394
444
 
395
- // 分类祖先属性:被重写的 vs 继承的
396
- const inheritedProperties: PropertyAnalysis[] = [];
397
-
398
- for (const ancestorProp of allAncestorProperties) {
399
- if (!ownPropertyNames.has(ancestorProp.name)) {
400
- // 被当前类继承了
401
- inheritedProperties.push(ancestorProp);
402
- }
403
- }
445
+ // 分类祖先属性:过滤出被继承的(未被重写的)
446
+ const inheritedProperties = allAncestorProperties.filter(
447
+ (ancestorProp) => !ownPropertyNames.has(ancestorProp.name)
448
+ );
404
449
 
405
450
  // 确定当前类中的重写属性
406
451
  const overriddenProperties = ownProperties.filter((prop) =>
@@ -410,11 +455,7 @@ export class ClassAnalyzer {
410
455
  // 合并最终属性:继承的 + 当前类的(重写优先)
411
456
  const properties = [...inheritedProperties, ...ownProperties];
412
457
 
413
- return {
414
- inheritedProperties,
415
- overriddenProperties,
416
- properties
417
- };
458
+ return { inheritedProperties, overriddenProperties, properties };
418
459
  }
419
460
 
420
461
  /**
@@ -439,44 +480,80 @@ export class ClassAnalyzer {
439
480
  const substitutedProperties = classAnalysis.ownProperties.map((property) =>
440
481
  GenericTypeSubstitutionUtil.substitutePropertyType(property, genericMapping, currentClassGenericParams)
441
482
  );
442
-
443
483
  allProperties.push(...substitutedProperties);
444
484
 
445
- // 3. 递归处理更上层祖先,传递泛型参数
446
- if (classAnalysis.inheritance.isInherited && classAnalysis.inheritance.baseClassAnalysis) {
447
- // 关键修复: 需要解析父类的泛型参数,将其中的泛型引用替换为当前映射的具体类型
448
- const parentGenericTypeArgs = classAnalysis.inheritance.genericTypeArguments || [];
449
-
450
- // 对父类的泛型参数进行替换,解决泛型参数引用问题
451
- // 例如: CrudRepository<T> extends Repository<T, number>
452
- // 这里的 T 需要替换为当前映射中的 UserEntity
453
- const resolvedParentGenericArgs = parentGenericTypeArgs.map(typeArg => {
454
- // 解析类型参数为 TypeStructure
455
- const typeStructure = TypeHandlerRegistry.getInstance().parseType(typeArg, {
456
- depth: 0,
457
- genericParams: parentGenericParams // 使用父类的泛型参数上下文
458
- });
459
-
460
- // 如果是泛型引用,进行替换
461
- if (typeStructure.kind === PropertyKind.GENERIC && genericMapping.has(typeStructure.sourceText)) {
462
- return genericMapping.get(typeStructure.sourceText)!;
463
- }
485
+ // 3. 递归处理更上层祖先
486
+ this.collectAncestorPropertiesRecursively(
487
+ classAnalysis, parentGenericParams, genericMapping, currentClassGenericParams, allProperties
488
+ );
464
489
 
465
- // 否则保持原样
466
- return typeArg;
467
- });
490
+ return allProperties;
491
+ }
468
492
 
469
- Logger.debug(`[CollectAncestors] Resolved parent generic args: ${resolvedParentGenericArgs.map(a => a.getText()).join(', ')}`);
493
+ /**
494
+ * 递归收集更上层祖先的属性
495
+ * @param classAnalysis 当前类分析结果
496
+ * @param parentGenericParams 父类泛型参数
497
+ * @param genericMapping 泛型映射
498
+ * @param currentClassGenericParams 当前类泛型参数列表
499
+ * @param allProperties 属性收集数组
500
+ */
501
+ private static collectAncestorPropertiesRecursively(
502
+ classAnalysis: ClassAnalysis | InterfaceAnalysis,
503
+ parentGenericParams: string[],
504
+ genericMapping: Map<string, TypeNode>,
505
+ currentClassGenericParams: string[],
506
+ allProperties: PropertyAnalysis[]
507
+ ): void {
508
+ // early return: 没有继承关系
509
+ if (!classAnalysis.inheritance.isInherited || !classAnalysis.inheritance.baseClassAnalysis) {
510
+ return;
511
+ }
512
+
513
+ // 解析父类的泛型参数,将泛型引用替换为具体类型
514
+ const parentGenericTypeArgs = classAnalysis.inheritance.genericTypeArguments || [];
515
+ const resolvedParentGenericArgs = this.resolveGenericTypeArgs(
516
+ parentGenericTypeArgs, parentGenericParams, genericMapping
517
+ );
470
518
 
471
- const ancestorProperties = this.collectAllAncestorProperties(
472
- classAnalysis.inheritance.baseClassAnalysis,
473
- resolvedParentGenericArgs, // 传递解析后的泛型参数
474
- currentClassGenericParams // 保持传递当前类的泛型参数
475
- );
476
- allProperties.push(...ancestorProperties);
477
- }
519
+ Logger.debug(
520
+ `[CollectAncestors] Resolved parent generic args: ${resolvedParentGenericArgs.map(a => a.getText()).join(', ')}`);
478
521
 
479
- return allProperties;
522
+ const ancestorProperties = this.collectAllAncestorProperties(
523
+ classAnalysis.inheritance.baseClassAnalysis,
524
+ resolvedParentGenericArgs,
525
+ currentClassGenericParams
526
+ );
527
+ allProperties.push(...ancestorProperties);
528
+ }
529
+
530
+ /**
531
+ * 解析泛型类型参数,将泛型引用替换为具体类型
532
+ * @param typeArgs 类型参数数组
533
+ * @param parentGenericParams 父类泛型参数
534
+ * @param genericMapping 泛型映射
535
+ * @returns 解析后的类型参数数组
536
+ */
537
+ private static resolveGenericTypeArgs(
538
+ typeArgs: TypeNode[],
539
+ parentGenericParams: string[],
540
+ genericMapping: Map<string, TypeNode>
541
+ ): TypeNode[] {
542
+ return typeArgs.map(typeArg => {
543
+ // 解析类型参数为 TypeStructure
544
+ const typeStructure = TypeHandlerRegistry.getInstance().parseType(typeArg, {
545
+ depth: 0,
546
+ genericParams: parentGenericParams
547
+ });
548
+
549
+ // 如果是泛型引用,进行替换
550
+ if (typeStructure.kind === PropertyKind.GENERIC && genericMapping.has(typeStructure.sourceText)) {
551
+ return genericMapping.get(typeStructure.sourceText)!;
552
+ }
553
+
554
+ // 否则保持原样
555
+ return typeArg;
556
+ });
480
557
  }
481
558
 
482
559
  /**
@@ -512,52 +589,75 @@ export class ClassAnalyzer {
512
589
  genericParameters: string[]
513
590
  ): PropertyAnalysis {
514
591
  const name = prop.getName();
592
+ const typeNode = this.getTypeNode(prop);
593
+ const type = TypeHandlerRegistry.getInstance().parseType(typeNode, { genericParams: genericParameters, depth: 0 });
594
+ type.isOptional = prop.hasQuestionToken();
595
+
596
+ const defaultValue = prop instanceof PropertyDeclaration ?
597
+ this.analyzeDefaultValue(prop, constructorParams) : undefined;
598
+ const decorators = prop instanceof PropertyDeclaration ? this.analyzePropertyDecorators(prop) : undefined;
599
+ const visibility = this.getPropertyVisibility(prop);
600
+
601
+ const constructorParam = constructorParams.find((param) => param.name === name);
602
+ const isMust = this.calculateIsMust(prop, type, constructorParam, decorators, defaultValue);
603
+
604
+ if (decorators?.isTransient && constructorParam) {
605
+ this.validateTransientConstructorParam(name, constructorParam);
606
+ }
607
+
608
+ return {
609
+ name,
610
+ defaultValue,
611
+ decorators,
612
+ type,
613
+ isMust,
614
+ visibility
615
+ };
616
+ }
617
+
618
+ private static getTypeNode(prop: PropertyDeclaration | PropertySignature): TypeNode {
515
619
  let typeNode = prop.getTypeNode();
516
620
  if (!typeNode) {
517
621
  typeNode = this.analyzePropertyType(prop);
518
622
  }
519
-
520
623
  if (!typeNode) {
521
- throw new CustomError(`无法分析属性 '${name}' 的类型。请检查属性声明。`, ErrorCodes.TYPE_NOT_SUPPORT);
624
+ throw new CustomError(`无法分析属性 '${prop.getName()}' 的类型。请检查属性声明。`, ErrorCodes.TYPE_NOT_SUPPORT);
522
625
  }
626
+ return typeNode;
627
+ }
523
628
 
524
- const defaultValue: string | undefined = prop instanceof PropertyDeclaration ?
525
- this.analyzeDefaultValue(prop, constructorParams) : undefined;
526
- const decorators = prop instanceof PropertyDeclaration ? this.analyzePropertyDecorators(prop) : undefined;
527
- const type = TypeHandlerRegistry.getInstance().parseType(typeNode, { genericParams: genericParameters, depth: 0 });
528
- type.isOptional = prop.hasQuestionToken();
529
-
530
- // 检测属性可见性修饰符
531
- const visibility: PropertyVisibility =
532
- prop.hasModifier(SyntaxKind.PrivateKeyword) ? PropertyVisibility.PRIVATE :
533
- prop.hasModifier(SyntaxKind.ProtectedKeyword) ? PropertyVisibility.PROTECTED :
534
- PropertyVisibility.PUBLIC;
535
-
536
- const constructorParam = constructorParams.find((param) => param.name === name);
537
-
538
- // 计算构造函数参数的可选性(用于后续验证)
539
- const isParamOptional = constructorParam
540
- ? constructorParam.isOptional ||
541
- constructorParam.defaultValue !== undefined ||
542
- this.hasUndefinedInUnion(constructorParam.type)
543
- : true;
629
+ private static getPropertyVisibility(prop: PropertyDeclaration | PropertySignature): PropertyVisibility {
630
+ if (prop.hasModifier(SyntaxKind.PrivateKeyword)) {
631
+ return PropertyVisibility.PRIVATE;
632
+ }
633
+ if (prop.hasModifier(SyntaxKind.ProtectedKeyword)) {
634
+ return PropertyVisibility.PROTECTED;
635
+ }
636
+ return PropertyVisibility.PUBLIC;
637
+ }
544
638
 
545
- let isMust: boolean;
639
+ private static calculateIsMust(
640
+ prop: PropertyDeclaration | PropertySignature,
641
+ type: TypeStructure,
642
+ constructorParam: ConstructorParam | undefined,
643
+ decorators: PropertyDecorators | undefined,
644
+ defaultValue: string | undefined
645
+ ): boolean {
546
646
  if (constructorParam) {
547
- // 属性在构造函数参数中,以构造函数参数的必要性为准
548
- // 构造函数参数可选的条件:
549
- // 1. 有显式的?标记(isOptional为true)
550
- // 2. 有默认值
551
- // 3. 类型字符串中包含undefined作为联合类型成员
552
- isMust = !isParamOptional;
553
- } else {
554
- // 属性不在构造函数中,判断属性本身的必要性
555
- isMust = decorators?.isRequired || !this.isOptional(prop, defaultValue, type);
647
+ const isParamOptional = constructorParam.isOptional ||
648
+ constructorParam.defaultValue !== undefined ||
649
+ this.hasUndefinedInUnion(constructorParam.type);
650
+ return !isParamOptional;
556
651
  }
652
+ return decorators?.isRequired || !this.isOptional(prop, defaultValue, type);
653
+ }
654
+
655
+ private static validateTransientConstructorParam(name: string, constructorParam: ConstructorParam): void {
656
+ const isParamOptional = constructorParam.isOptional ||
657
+ constructorParam.defaultValue !== undefined ||
658
+ this.hasUndefinedInUnion(constructorParam.type);
557
659
 
558
- // @Transient 属性的构造函数参数验证
559
- // 检查构造函数参数是否可选或有默认值
560
- if (decorators?.isTransient && constructorParam && !isParamOptional) {
660
+ if (!isParamOptional) {
561
661
  throw new CustomError(
562
662
  `@Transient 属性 '${name}' 的构造函数参数必须是可选的或有默认值。\n` +
563
663
  `因为 @Transient 属性不参与序列化,反序列化时无法从外部数据获取值。\n` +
@@ -567,15 +667,6 @@ export class ClassAnalyzer {
567
667
  ErrorCodes.TRANSIENT_ATTR_OPTIONAL
568
668
  );
569
669
  }
570
-
571
- return {
572
- name,
573
- defaultValue,
574
- decorators,
575
- type,
576
- isMust,
577
- visibility
578
- };
579
670
  }
580
671
 
581
672
  private static analyzePropertyType(prop: PropertyDeclaration | PropertySignature): TypeNode | undefined {
@@ -806,15 +897,14 @@ export class ClassAnalyzer {
806
897
  */
807
898
  private static analyzePropertyDecorators(prop: PropertyDeclaration): PropertyDecorators {
808
899
  const decorators = prop.getDecorators();
809
- let isRequired: boolean = false;
810
- let isTransient: boolean = false;
811
- let isPlainValue: boolean = false;
900
+ let isRequired = false;
901
+ let isTransient = false;
902
+ let isPlainValue = false;
812
903
  let serialName: string | undefined;
813
904
  let _with: string | undefined;
814
905
 
815
906
  decorators.forEach((decorator) => {
816
907
  const name = decorator.getName();
817
-
818
908
  switch (name) {
819
909
  case DecoratorConstants.SERIAL_NAME:
820
910
  serialName = this.parseSerialNameOptions(decorator);
@@ -830,51 +920,66 @@ export class ClassAnalyzer {
830
920
  break;
831
921
  case DecoratorConstants.SERIALIZABLE:
832
922
  _with = this.parseSerializableOptions(decorator)!.with;
923
+ break;
833
924
  }
834
925
  });
835
926
 
836
- // 注解互斥检查:@Transient 与其他序列化注解互斥
837
- if (isTransient) {
838
- const conflictingDecorators: string[] = [];
839
- if (isRequired) {
840
- conflictingDecorators.push('@Required');
841
- }
842
- if (serialName) {
843
- conflictingDecorators.push('@SerialName');
844
- }
845
- if (_with) {
846
- conflictingDecorators.push('@Serializable');
847
- }
848
- if (isPlainValue) {
849
- conflictingDecorators.push('@PlainValue');
850
- }
927
+ this.checkTransientConflicts(prop.getName(), isTransient, isRequired, !!serialName, !!_with, isPlainValue);
928
+ this.checkPlainValueConflicts(prop.getName(), isPlainValue, !!_with);
851
929
 
852
- if (conflictingDecorators.length > 0) {
853
- throw new CustomError(
854
- `属性 '${prop.getName()}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
855
- `@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
856
- `请移除 @Transient 或移除其他序列化注解。`,
857
- ErrorCodes.ANNOTATION_CONFLICT
858
- );
859
- }
930
+ return {
931
+ isRequired,
932
+ isTransient,
933
+ isPlainValue,
934
+ serialName,
935
+ with: _with
936
+ };
937
+ }
938
+
939
+ private static checkTransientConflicts(
940
+ propName: string,
941
+ isTransient: boolean,
942
+ isRequired: boolean,
943
+ hasSerialName: boolean,
944
+ hasWith: boolean,
945
+ isPlainValue: boolean
946
+ ): void {
947
+ if (!isTransient) {
948
+ return;
949
+ }
950
+
951
+ const conflictingDecorators: string[] = [];
952
+ if (isRequired) {
953
+ conflictingDecorators.push('@Required');
954
+ }
955
+ if (hasSerialName) {
956
+ conflictingDecorators.push('@SerialName');
957
+ }
958
+ if (hasWith) {
959
+ conflictingDecorators.push('@Serializable');
960
+ }
961
+ if (isPlainValue) {
962
+ conflictingDecorators.push('@PlainValue');
963
+ }
964
+
965
+ if (conflictingDecorators.length > 0) {
966
+ throw new CustomError(
967
+ `属性 '${propName}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
968
+ `@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
969
+ `请移除 @Transient 或移除其他序列化注解。`,
970
+ ErrorCodes.ANNOTATION_CONFLICT
971
+ );
860
972
  }
973
+ }
861
974
 
862
- // 注解互斥检查:@PlainValue 与自定义序列化器互斥
863
- if (isPlainValue && _with) {
975
+ private static checkPlainValueConflicts(propName: string, isPlainValue: boolean, hasWith: boolean): void {
976
+ if (isPlainValue && hasWith) {
864
977
  throw new CustomError(
865
- `属性 '${prop.getName()}' 的注解冲突:@PlainValue 与 @Serializable(with:) 不能同时使用。\n` +
978
+ `属性 '${propName}' 的注解冲突:@PlainValue 与 @Serializable(with:) 不能同时使用。\n` +
866
979
  `@PlainValue 跳过类型转换直接使用原始值,与自定义序列化器冲突。\n` +
867
980
  `请移除 @PlainValue 或移除自定义序列化器。`,
868
981
  ErrorCodes.ANNOTATION_CONFLICT
869
982
  );
870
983
  }
871
-
872
- return {
873
- isRequired,
874
- isTransient,
875
- isPlainValue,
876
- serialName,
877
- with: _with
878
- };
879
984
  }
880
985
  }