@hadss/turbo-trans-json-plugin 1.0.0-rc.0 → 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 (88) hide show
  1. package/README.md +1 -1
  2. package/dist/core/Types.d.ts +7 -0
  3. package/dist/core/Types.js +7 -1
  4. package/dist/core/analyzers/ClassAnalyzer.d.ts +15 -0
  5. package/dist/core/analyzers/ClassAnalyzer.js +200 -120
  6. package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +3 -0
  7. package/dist/core/analyzers/CustomTypeAnalyzer.js +65 -60
  8. package/dist/core/constants/DecoratorConstants.d.ts +1 -0
  9. package/dist/core/constants/DecoratorConstants.js +3 -1
  10. package/dist/core/handlers/CustomClassHandler.js +0 -1
  11. package/dist/core/import-rewrite/services/BuildProfileUpdater.js +1 -1
  12. package/dist/core/import-rewrite/services/ImportRewriteService.js +1 -1
  13. package/dist/core/interfaces/index.d.ts +2 -2
  14. package/dist/core/services/CodeAnalysisService.js +2 -1
  15. package/dist/core/services/CodeGenerationService/CodeGenerationService.js +1 -1
  16. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +0 -1
  17. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +0 -20
  18. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +4 -4
  19. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +26 -45
  20. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +22 -0
  21. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +194 -129
  22. package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +20 -15
  23. package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +2 -1
  24. package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +2 -2
  25. package/dist/core/template/HandlebarsTemplateEngine.d.ts +2 -0
  26. package/dist/core/template/HandlebarsTemplateEngine.js +24 -2
  27. package/dist/core/utils/DeepCopyUtil.js +4 -2
  28. package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +1 -0
  29. package/dist/core/utils/GenericTypeSubstitutionUtil.js +27 -1
  30. package/dist/core/utils/SerializationPathUtil.d.ts +1 -1
  31. package/dist/core/utils/TsMorphUtil.js +6 -1
  32. package/dist/json-plugin/JSONExecuteController.d.ts +4 -0
  33. package/dist/json-plugin/JSONExecuteController.js +46 -36
  34. package/dist/json-plugin/interfaces/impl/TargetContext.js +4 -2
  35. package/dist/json-plugin/tasks/BaseTask.d.ts +2 -2
  36. package/dist/json-plugin/tasks/WatchTask.js +2 -1
  37. package/package.json +1 -1
  38. package/src/core/Types.ts +97 -89
  39. package/src/core/analyzers/ClassAnalyzer.ts +358 -197
  40. package/src/core/analyzers/CustomTypeAnalyzer.ts +145 -74
  41. package/src/core/constants/DecoratorConstants.ts +7 -5
  42. package/src/core/constants/PathConstants.ts +7 -7
  43. package/src/core/constants/StringConstants.ts +95 -97
  44. package/src/core/handlers/BaseTypeHandler.ts +11 -2
  45. package/src/core/handlers/CustomClassHandler.ts +4 -7
  46. package/src/core/handlers/DateHandler.ts +54 -46
  47. package/src/core/handlers/DecimalHandler.ts +53 -45
  48. package/src/core/handlers/EnumHandler.ts +2 -1
  49. package/src/core/handlers/GenericContainerHandler.ts +3 -1
  50. package/src/core/handlers/TupleHandler.ts +2 -1
  51. package/src/core/handlers/TypeHandlerRegistry.ts +3 -2
  52. package/src/core/handlers/UnionTypeHandler.ts +8 -7
  53. package/src/core/import-rewrite/services/BuildProfileUpdater.ts +7 -5
  54. package/src/core/import-rewrite/services/ImportRewriteService.ts +1 -3
  55. package/src/core/import-rewrite/services/ImportTransformService.ts +2 -2
  56. package/src/core/import-rewrite/types/ImportRewriteTypes.ts +3 -3
  57. package/src/core/index.ts +4 -4
  58. package/src/core/interfaces/ITask.ts +6 -5
  59. package/src/core/interfaces/ITaskContext.ts +9 -9
  60. package/src/core/interfaces/index.ts +2 -2
  61. package/src/core/logger/Logger.ts +28 -28
  62. package/src/core/services/CodeAnalysisService.ts +3 -2
  63. package/src/core/services/CodeGenerationEngine.ts +42 -42
  64. package/src/core/services/CodeGenerationService/CodeGenerationService.ts +1 -2
  65. package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +0 -29
  66. package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +31 -64
  67. package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +261 -170
  68. package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +26 -19
  69. package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +5 -3
  70. package/src/core/services/CodeGenerationService/shared/ImportManager.ts +8 -8
  71. package/src/core/template/HandlebarsTemplateEngine.ts +43 -10
  72. package/src/core/utils/ConfigManager.ts +2 -1
  73. package/src/core/utils/DeepCopyUtil.ts +4 -2
  74. package/src/core/utils/GenericTypeSubstitutionUtil.ts +45 -2
  75. package/src/core/utils/SerializationPathUtil.ts +7 -6
  76. package/src/core/utils/TsMorphUtil.ts +9 -2
  77. package/src/index.ts +2 -2
  78. package/src/json-plugin/JSONExecuteController.ts +51 -38
  79. package/src/json-plugin/interfaces/IModuleContext.ts +8 -8
  80. package/src/json-plugin/interfaces/ITargetContext.ts +6 -6
  81. package/src/json-plugin/interfaces/impl/ModuleContext.ts +10 -10
  82. package/src/json-plugin/interfaces/impl/TargetContext.ts +63 -58
  83. package/src/json-plugin/tasks/BaseTask.ts +5 -4
  84. package/src/json-plugin/tasks/CleanTask.ts +7 -7
  85. package/src/json-plugin/tasks/WatchTask.ts +20 -18
  86. package/template/SerializerPerformanceTemplate.hbs +14 -4
  87. package/template/SerializerStrictTemplate.hbs +9 -1
  88. package/template/SerializerTemplate.hbs +71 -46
@@ -14,28 +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
- InterfaceAnalysis,
30
- ClassDecorators,
31
- ConstructorParam,
32
- DeserializationMode,
33
- GenericInfo,
34
- InheritanceInfo,
35
- PropertyAnalysis,
36
- PropertyDecorators,
37
- PropertyKind,
38
- SerializableOptions,
21
+ ClassAnalysis, ClassDecorators, ConstructorParam, DeserializationMode, GenericInfo, InheritanceInfo,
22
+ InterfaceAnalysis, PropertyAnalysis, PropertyDecorators, PropertyKind, PropertyVisibility, SerializableOptions,
39
23
  TypeStructure
40
24
  } from '../Types';
41
25
  import { DecoratorConstants } from '../constants';
@@ -45,7 +29,6 @@ import { CustomTypeAnalyzer } from './CustomTypeAnalyzer';
45
29
  import { CustomError, ErrorCodes } from '../utils/CustomError';
46
30
  import { Logger } from '../logger/Logger';
47
31
  import { TsMorphUtil } from '../utils/TsMorphUtil';
48
- import { logger } from 'handlebars';
49
32
 
50
33
  export class ClassAnalyzer {
51
34
  /**
@@ -97,14 +80,15 @@ export class ClassAnalyzer {
97
80
  }
98
81
 
99
82
  /**
100
- * 分析接口的完整结构,包括属性、继承关系等信息
101
- * @param interfaceDecl 接口声明节点
102
- * @returns 接口分析结果
103
- */
83
+ * 分析接口的完整结构,包括属性、继承关系等信息
84
+ * @param interfaceDecl 接口声明节点
85
+ * @returns 接口分析结果
86
+ */
104
87
  public static analyzeInterface(interfaceDecl: InterfaceDeclaration): InterfaceAnalysis {
105
88
  const interfaceName = interfaceDecl.getName();
106
89
  if (!interfaceName) {
107
- throw new CustomError(`Interface name is undefined in ${interfaceDecl.getSourceFile().getFilePath()}`, ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
90
+ throw new CustomError(`Interface name is undefined in ${interfaceDecl.getSourceFile().getFilePath()}`,
91
+ ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
108
92
  }
109
93
  const sourceFilePath = interfaceDecl.getSourceFile().getFilePath();
110
94
  const generics: GenericInfo = {
@@ -141,7 +125,8 @@ export class ClassAnalyzer {
141
125
  */
142
126
  private static analyzeInheritanceInfo(cls: ClassDeclaration | InterfaceDeclaration): InheritanceInfo {
143
127
  const heritageClaus = cls.getHeritageClauses();
144
- Logger.debug(`分析类的继承信息: ${cls.getName()} ${heritageClaus.length} ${heritageClaus.map(c => c.getText()).join(',')}`);
128
+ Logger.debug(
129
+ `分析类的继承信息: ${cls.getName()} ${heritageClaus.length} ${heritageClaus.map(c => c.getText()).join(',')}`);
145
130
  for (const clause of heritageClaus) {
146
131
  const token = clause.getToken();
147
132
  // 接口实现
@@ -155,7 +140,8 @@ export class ClassAnalyzer {
155
140
  Logger.debug(`继承信息: text: ${className} getTypeArguments: ${args.map(type => type.getText()).join(', ')}`);
156
141
  const classDecl = CustomTypeAnalyzer.getInstance().findClassDeclFromClassName(className, cls.getSourceFile());
157
142
  if (!classDecl) {
158
- throw new CustomError(`class ${className} decl does not exist ${cls.getName} implement ${className}`, ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
143
+ throw new CustomError(`class ${className} decl does not exist ${cls.getName} implement ${className}`,
144
+ ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
159
145
  }
160
146
  if (classDecl instanceof InterfaceDeclaration) {
161
147
  const baseClassAnalysis = this.analyzeInterface(classDecl);
@@ -219,45 +205,69 @@ export class ClassAnalyzer {
219
205
  return undefined;
220
206
  }
221
207
  const args = decorator.getArguments();
222
- let generateSendable: boolean | undefined;
223
- let _with: string | undefined;
224
- let deserializationMode: DeserializationMode | undefined;
225
-
226
208
  const firstArg = args[0];
227
209
 
228
- if (!firstArg) {
210
+ if (!firstArg || firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) {
229
211
  return {};
230
212
  }
231
213
 
232
- // 处理对象形式:@Serializable({ generateSendable: true })
233
- if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {
234
- const properties = firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression).getProperties();
235
-
236
- for (const prop of properties) {
237
- if (prop.getKind() === SyntaxKind.PropertyAssignment) {
238
- const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
239
- const propertyName = propAssignment.getName();
240
- const initializer = propAssignment.getInitializer();
241
- if (propertyName === 'generateSendable' && initializer) {
242
- if (initializer.getKind() === SyntaxKind.TrueKeyword) {
243
- generateSendable = true;
244
- } else if (initializer.getKind() === SyntaxKind.FalseKeyword) {
245
- generateSendable = false;
246
- }
247
- } else if (propertyName === 'with' && initializer) {
248
- // 处理 with 参数,存储完整的表达式文本
249
- _with = initializer.getText();
250
- } else if (propertyName === 'deserializationMode' && initializer) {
251
- // 处理 deserializationMode 参数:'performance' | 'strict'
252
- const modeText = initializer.getText().replace(/['"]/g, ''); // 去掉引号
253
- if (modeText === DeserializationMode.PERFORMANCE || modeText === DeserializationMode.STRICT) {
254
- deserializationMode = modeText as DeserializationMode;
255
- }
256
- }
257
- }
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;
258
225
  }
226
+ const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
227
+ const initializer = propAssignment.getInitializer();
228
+ // early return: 无初始化器
229
+ if (!initializer) {
230
+ continue;
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;
259
270
  }
260
- return { with: _with, generateSendable, deserializationMode };
261
271
  }
262
272
 
263
273
  /**
@@ -266,36 +276,53 @@ export class ClassAnalyzer {
266
276
  * @returns 序列化名称
267
277
  */
268
278
  private static parseSerialNameOptions(decorator?: Decorator): string | undefined {
279
+ // early return: 无装饰器
269
280
  if (!decorator) {
270
281
  return undefined;
271
282
  }
272
283
  const args = decorator.getArguments();
284
+ // early return: 无参数
273
285
  if (args.length === 0) {
274
286
  return undefined;
275
287
  }
276
288
 
277
289
  const firstArg = args[0];
278
290
 
291
+ // early return: 非对象字面量
292
+ if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) {
293
+ return undefined;
294
+ }
295
+
279
296
  // 处理对象形式:@SerialName({ name: 'xxx' })
280
- if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {
281
- const properties = firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression).getProperties();
282
-
283
- for (const prop of properties) {
284
- if (prop.getKind() === SyntaxKind.PropertyAssignment) {
285
- const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
286
- const name = propAssignment.getName();
287
-
288
- if (name === 'name') {
289
- const initializer = propAssignment.getInitializer();
290
- if (initializer && initializer.getKind() === SyntaxKind.StringLiteral) {
291
- const stringLiteral = initializer.asKindOrThrow(SyntaxKind.StringLiteral);
292
- return stringLiteral.getLiteralValue();
293
- }
294
- }
295
- }
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;
316
+ }
317
+
318
+ const initializer = propAssignment.getInitializer();
319
+ // early return: 非字符串字面量
320
+ if (!initializer || initializer.getKind() !== SyntaxKind.StringLiteral) {
321
+ continue;
296
322
  }
297
- }
298
323
 
324
+ return initializer.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
325
+ }
299
326
  return undefined;
300
327
  }
301
328
 
@@ -320,40 +347,49 @@ export class ClassAnalyzer {
320
347
  genericParameters
321
348
  );
322
349
 
323
- // 检测 UNKNOWN 类型
324
- if (propertyAnalysis.type.kind === PropertyKind.UNKNOWN) {
325
- const hasTransient = propertyAnalysis.decorators?.isTransient;
326
- const hasCustomSerializer = !!propertyAnalysis.decorators?.with;
327
-
328
- if (!hasTransient && !hasCustomSerializer) {
329
- if (prop instanceof PropertyDeclaration) {
330
- // 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
331
- throw new CustomError(
332
- `不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
333
- }' (类: ${cls.getName()})。\n` +
334
- `请选择以下任一解决方案:\n` +
335
- ` 1. 添加 @Transient() 跳过序列化(属性仍会参与 Sendable 转换和对象拷贝):\n` +
336
- ` @Transient()\n` +
337
- ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};\n\n` +
338
- ` 2. 添加 @Serializable({with: CustomSerializer}) 指定自定义序列化器:\n` +
339
- ` @Serializable({with: DateSerializer.INSTANCE})\n` +
340
- ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};`,
341
- ErrorCodes.TYPE_NOT_SUPPORT
342
- );
343
- } else {
344
- // 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
345
- throw new CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
346
- }' (接口: ${cls.getName()})`, ErrorCodes.TYPE_NOT_SUPPORT);
347
- }
348
- }
349
- }
350
-
351
- // 保留所有属性(包括 UNKNOWN 类型),生成阶段再筛选
350
+ this.checkUnknownType(cls, prop, propertyAnalysis);
352
351
  ownProperties.push(propertyAnalysis);
353
352
  }
354
353
  return ownProperties;
355
354
  }
356
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
+
357
393
  /**
358
394
  * 对属性进行分类,区分继承属性、重写属性和自有属性
359
395
  * @param ownProperties 自有属性数组
@@ -370,8 +406,8 @@ export class ClassAnalyzer {
370
406
  overriddenProperties: PropertyAnalysis[];
371
407
  properties: PropertyAnalysis[];
372
408
  } {
409
+ // early return: 没有继承,所有属性都是自有属性
373
410
  if (!inheritance.isInherited || !inheritance.baseClassAnalysis) {
374
- // 没有继承,所有属性都是自有属性
375
411
  return {
376
412
  inheritedProperties: [],
377
413
  overriddenProperties: [],
@@ -382,22 +418,34 @@ export class ClassAnalyzer {
382
418
  // 递归收集所有祖先属性 - 传递泛型参数进行替换
383
419
  const allAncestorProperties = this.collectAllAncestorProperties(
384
420
  inheritance.baseClassAnalysis,
385
- inheritance.genericTypeArguments || [], // 传递子类指定的泛型参数
386
- currentClassGenericParams // 传递当前类的泛型参数列表
421
+ inheritance.genericTypeArguments || [],
422
+ currentClassGenericParams
387
423
  );
388
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
+ } {
389
442
  // 构建自有属性名称集合,用于快速查找重写
390
443
  const ownPropertyNames = new Set(ownProperties.map((prop) => prop.name));
391
444
 
392
- // 分类祖先属性:被重写的 vs 继承的
393
- const inheritedProperties: PropertyAnalysis[] = [];
394
-
395
- for (const ancestorProp of allAncestorProperties) {
396
- if (!ownPropertyNames.has(ancestorProp.name)) {
397
- // 被当前类继承了
398
- inheritedProperties.push(ancestorProp);
399
- }
400
- }
445
+ // 分类祖先属性:过滤出被继承的(未被重写的)
446
+ const inheritedProperties = allAncestorProperties.filter(
447
+ (ancestorProp) => !ownPropertyNames.has(ancestorProp.name)
448
+ );
401
449
 
402
450
  // 确定当前类中的重写属性
403
451
  const overriddenProperties = ownProperties.filter((prop) =>
@@ -407,11 +455,7 @@ export class ClassAnalyzer {
407
455
  // 合并最终属性:继承的 + 当前类的(重写优先)
408
456
  const properties = [...inheritedProperties, ...ownProperties];
409
457
 
410
- return {
411
- inheritedProperties,
412
- overriddenProperties,
413
- properties
414
- };
458
+ return { inheritedProperties, overriddenProperties, properties };
415
459
  }
416
460
 
417
461
  /**
@@ -436,22 +480,82 @@ export class ClassAnalyzer {
436
480
  const substitutedProperties = classAnalysis.ownProperties.map((property) =>
437
481
  GenericTypeSubstitutionUtil.substitutePropertyType(property, genericMapping, currentClassGenericParams)
438
482
  );
439
-
440
483
  allProperties.push(...substitutedProperties);
441
484
 
442
- // 3. 递归处理更上层祖先,传递泛型参数
443
- if (classAnalysis.inheritance.isInherited && classAnalysis.inheritance.baseClassAnalysis) {
444
- const ancestorProperties = this.collectAllAncestorProperties(
445
- classAnalysis.inheritance.baseClassAnalysis,
446
- classAnalysis.inheritance.genericTypeArguments || [], // 传递当前层的泛型参数
447
- currentClassGenericParams // 保持传递当前类的泛型参数
448
- );
449
- allProperties.push(...ancestorProperties);
450
- }
485
+ // 3. 递归处理更上层祖先
486
+ this.collectAncestorPropertiesRecursively(
487
+ classAnalysis, parentGenericParams, genericMapping, currentClassGenericParams, allProperties
488
+ );
451
489
 
452
490
  return allProperties;
453
491
  }
454
492
 
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
+ );
518
+
519
+ Logger.debug(
520
+ `[CollectAncestors] Resolved parent generic args: ${resolvedParentGenericArgs.map(a => a.getText()).join(', ')}`);
521
+
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
+ });
557
+ }
558
+
455
559
  /**
456
560
  * 提取构造函数参数信息
457
561
  * @param constructor 构造函数声明
@@ -485,45 +589,75 @@ export class ClassAnalyzer {
485
589
  genericParameters: string[]
486
590
  ): PropertyAnalysis {
487
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 {
488
619
  let typeNode = prop.getTypeNode();
489
620
  if (!typeNode) {
490
621
  typeNode = this.analyzePropertyType(prop);
491
622
  }
492
-
493
623
  if (!typeNode) {
494
- throw new CustomError(`无法分析属性 '${name}' 的类型。请检查属性声明。`, ErrorCodes.TYPE_NOT_SUPPORT);
624
+ throw new CustomError(`无法分析属性 '${prop.getName()}' 的类型。请检查属性声明。`, ErrorCodes.TYPE_NOT_SUPPORT);
495
625
  }
626
+ return typeNode;
627
+ }
496
628
 
497
- const defaultValue: string | undefined = prop instanceof PropertyDeclaration ? this.analyzeDefaultValue(prop, constructorParams) : undefined;
498
- const decorators = prop instanceof PropertyDeclaration ? this.analyzePropertyDecorators(prop) : undefined;
499
- const type = TypeHandlerRegistry.getInstance().parseType(typeNode, { genericParams: genericParameters, depth: 0 });
500
- type.isOptional = prop.hasQuestionToken();
501
-
502
- const constructorParam = constructorParams.find((param) => param.name === name);
503
-
504
- // 计算构造函数参数的可选性(用于后续验证)
505
- const isParamOptional = constructorParam
506
- ? constructorParam.isOptional ||
507
- constructorParam.defaultValue !== undefined ||
508
- this.hasUndefinedInUnion(constructorParam.type)
509
- : 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
+ }
510
638
 
511
- 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 {
512
646
  if (constructorParam) {
513
- // 属性在构造函数参数中,以构造函数参数的必要性为准
514
- // 构造函数参数可选的条件:
515
- // 1. 有显式的?标记(isOptional为true)
516
- // 2. 有默认值
517
- // 3. 类型字符串中包含undefined作为联合类型成员
518
- isMust = !isParamOptional;
519
- } else {
520
- // 属性不在构造函数中,判断属性本身的必要性
521
- 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;
522
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);
523
659
 
524
- // @Transient 属性的构造函数参数验证
525
- // 检查构造函数参数是否可选或有默认值
526
- if (decorators?.isTransient && constructorParam && !isParamOptional) {
660
+ if (!isParamOptional) {
527
661
  throw new CustomError(
528
662
  `@Transient 属性 '${name}' 的构造函数参数必须是可选的或有默认值。\n` +
529
663
  `因为 @Transient 属性不参与序列化,反序列化时无法从外部数据获取值。\n` +
@@ -533,14 +667,6 @@ export class ClassAnalyzer {
533
667
  ErrorCodes.TRANSIENT_ATTR_OPTIONAL
534
668
  );
535
669
  }
536
-
537
- return {
538
- name,
539
- defaultValue,
540
- decorators,
541
- type,
542
- isMust
543
- };
544
670
  }
545
671
 
546
672
  private static analyzePropertyType(prop: PropertyDeclaration | PropertySignature): TypeNode | undefined {
@@ -598,7 +724,8 @@ export class ClassAnalyzer {
598
724
  return typeText;
599
725
  }
600
726
 
601
- private static getTypeFromInitializer(prop: PropertyDeclaration | PropertySignature, propName: string): TypeNode | undefined {
727
+ private static getTypeFromInitializer(prop: PropertyDeclaration | PropertySignature,
728
+ propName: string): TypeNode | undefined {
602
729
  const initializer = prop.getInitializer();
603
730
  if (!initializer) {
604
731
  return undefined;
@@ -626,7 +753,8 @@ export class ClassAnalyzer {
626
753
  }
627
754
 
628
755
  const exprText = expression.getText();
629
- const supportedTypes = ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array', 'Object', 'ArrayList', 'HashMap', 'HashSet', 'LinkedList', 'Decimal', 'List'];
756
+ const supportedTypes = ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array', 'Object', 'ArrayList', 'HashMap', 'HashSet',
757
+ 'LinkedList', 'Decimal', 'List'];
630
758
 
631
759
  if (!supportedTypes.includes(exprText)) {
632
760
  return undefined;
@@ -651,7 +779,8 @@ export class ClassAnalyzer {
651
779
  * @param type 类型结构
652
780
  * @returns 是否为可选属性
653
781
  */
654
- private static isOptional(node: PropertyDeclaration | PropertySignature, defaultValue: string | undefined, type: TypeStructure): boolean {
782
+ private static isOptional(node: PropertyDeclaration | PropertySignature, defaultValue: string | undefined,
783
+ type: TypeStructure): boolean {
655
784
  // 1. 语法上带 ?(prop?: T, param?: T)
656
785
  if (node.hasQuestionToken()) {
657
786
  return true;
@@ -768,14 +897,14 @@ export class ClassAnalyzer {
768
897
  */
769
898
  private static analyzePropertyDecorators(prop: PropertyDeclaration): PropertyDecorators {
770
899
  const decorators = prop.getDecorators();
771
- let isRequired: boolean = false;
772
- let isTransient: boolean = false;
900
+ let isRequired = false;
901
+ let isTransient = false;
902
+ let isPlainValue = false;
773
903
  let serialName: string | undefined;
774
904
  let _with: string | undefined;
775
905
 
776
906
  decorators.forEach((decorator) => {
777
907
  const name = decorator.getName();
778
-
779
908
  switch (name) {
780
909
  case DecoratorConstants.SERIAL_NAME:
781
910
  serialName = this.parseSerialNameOptions(decorator);
@@ -786,39 +915,71 @@ export class ClassAnalyzer {
786
915
  case DecoratorConstants.TRANSIENT:
787
916
  isTransient = true;
788
917
  break;
918
+ case DecoratorConstants.PLAIN_VALUE:
919
+ isPlainValue = true;
920
+ break;
789
921
  case DecoratorConstants.SERIALIZABLE:
790
922
  _with = this.parseSerializableOptions(decorator)!.with;
923
+ break;
791
924
  }
792
925
  });
793
926
 
794
- // 注解互斥检查:@Transient 与其他序列化注解互斥
795
- if (isTransient) {
796
- const conflictingDecorators: string[] = [];
797
- if (isRequired) {
798
- conflictingDecorators.push('@Required');
799
- }
800
- if (serialName) {
801
- conflictingDecorators.push('@SerialName');
802
- }
803
- if (_with) {
804
- conflictingDecorators.push('@Serializable');
805
- }
806
-
807
- if (conflictingDecorators.length > 0) {
808
- throw new CustomError(
809
- `属性 '${prop.getName()}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
810
- `@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
811
- `请移除 @Transient 或移除其他序列化注解。`,
812
- ErrorCodes.ANNOTATION_CONFLICT
813
- );
814
- }
815
- }
927
+ this.checkTransientConflicts(prop.getName(), isTransient, isRequired, !!serialName, !!_with, isPlainValue);
928
+ this.checkPlainValueConflicts(prop.getName(), isPlainValue, !!_with);
816
929
 
817
930
  return {
818
931
  isRequired,
819
932
  isTransient,
933
+ isPlainValue,
820
934
  serialName,
821
935
  with: _with
822
936
  };
823
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
+ );
972
+ }
973
+ }
974
+
975
+ private static checkPlainValueConflicts(propName: string, isPlainValue: boolean, hasWith: boolean): void {
976
+ if (isPlainValue && hasWith) {
977
+ throw new CustomError(
978
+ `属性 '${propName}' 的注解冲突:@PlainValue 与 @Serializable(with:) 不能同时使用。\n` +
979
+ `@PlainValue 跳过类型转换直接使用原始值,与自定义序列化器冲突。\n` +
980
+ `请移除 @PlainValue 或移除自定义序列化器。`,
981
+ ErrorCodes.ANNOTATION_CONFLICT
982
+ );
983
+ }
984
+ }
824
985
  }