@hadss/turbo-trans-json-plugin 1.0.0-rc.0 → 1.0.0-rc.1

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 (41) 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.js +35 -4
  5. package/dist/core/constants/DecoratorConstants.d.ts +1 -0
  6. package/dist/core/constants/DecoratorConstants.js +2 -1
  7. package/dist/core/handlers/CustomClassHandler.js +0 -1
  8. package/dist/core/services/CodeGenerationService/CodeGenerationService.js +1 -1
  9. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +0 -1
  10. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +0 -20
  11. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +2 -4
  12. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +4 -30
  13. package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +20 -15
  14. package/dist/core/template/HandlebarsTemplateEngine.js +3 -0
  15. package/dist/core/utils/DeepCopyUtil.js +3 -1
  16. package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +1 -0
  17. package/dist/core/utils/GenericTypeSubstitutionUtil.js +27 -1
  18. package/dist/core/utils/TsMorphUtil.js +4 -0
  19. package/package.json +1 -1
  20. package/src/core/Types.ts +9 -1
  21. package/src/core/analyzers/ClassAnalyzer.ts +74 -18
  22. package/src/core/analyzers/CustomTypeAnalyzer.ts +0 -1
  23. package/src/core/constants/DecoratorConstants.ts +2 -1
  24. package/src/core/constants/StringConstants.ts +0 -2
  25. package/src/core/handlers/CustomClassHandler.ts +0 -3
  26. package/src/core/handlers/TypeHandlerRegistry.ts +1 -1
  27. package/src/core/import-rewrite/services/BuildProfileUpdater.ts +1 -1
  28. package/src/core/import-rewrite/services/ImportRewriteService.ts +0 -2
  29. package/src/core/services/CodeAnalysisService.ts +1 -1
  30. package/src/core/services/CodeGenerationService/CodeGenerationService.ts +1 -2
  31. package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +0 -29
  32. package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +6 -42
  33. package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +26 -19
  34. package/src/core/template/HandlebarsTemplateEngine.ts +5 -0
  35. package/src/core/utils/DeepCopyUtil.ts +3 -1
  36. package/src/core/utils/GenericTypeSubstitutionUtil.ts +51 -1
  37. package/src/core/utils/TsMorphUtil.ts +5 -1
  38. package/src/json-plugin/tasks/BaseTask.ts +0 -1
  39. package/template/SerializerPerformanceTemplate.hbs +14 -4
  40. package/template/SerializerStrictTemplate.hbs +8 -0
  41. package/template/SerializerTemplate.hbs +14 -6
package/README.md CHANGED
@@ -23,7 +23,7 @@ TurboTransJSONPlugin 是一个基于 Hvigor 构建系统的编译时插件,专
23
23
  {
24
24
  "modelVersion": "6.0.0",
25
25
  "dependencies": {
26
- "@hadss/turbo-trans-json-plugin": "^1.0.0",
26
+ "@hadss/turbo-trans-json-plugin": "latest",
27
27
  // 使用npm仓版本号
28
28
  }
29
29
  // ...其余配置
@@ -90,11 +90,18 @@ export interface PropertyAnalysis {
90
90
  decorators?: PropertyDecorators;
91
91
  isMust: boolean;
92
92
  type: TypeStructure;
93
+ visibility: PropertyVisibility;
94
+ }
95
+ export declare enum PropertyVisibility {
96
+ PUBLIC = "public",
97
+ PRIVATE = "private",
98
+ PROTECTED = "protected"
93
99
  }
94
100
  export interface PropertyDecorators {
95
101
  serialName?: string;
96
102
  isRequired: boolean;
97
103
  isTransient: boolean;
104
+ isPlainValue: boolean;
98
105
  with?: string;
99
106
  }
100
107
  export interface TypeStructure {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TypeKind = exports.DeserializationMode = exports.PropertyKind = void 0;
3
+ exports.TypeKind = exports.PropertyVisibility = exports.DeserializationMode = exports.PropertyKind = void 0;
4
4
  var PropertyKind;
5
5
  (function (PropertyKind) {
6
6
  PropertyKind["STRING"] = "string";
@@ -38,6 +38,12 @@ var DeserializationMode;
38
38
  DeserializationMode["PERFORMANCE"] = "performance";
39
39
  DeserializationMode["STRICT"] = "strict";
40
40
  })(DeserializationMode || (exports.DeserializationMode = DeserializationMode = {}));
41
+ var PropertyVisibility;
42
+ (function (PropertyVisibility) {
43
+ PropertyVisibility["PUBLIC"] = "public";
44
+ PropertyVisibility["PRIVATE"] = "private";
45
+ PropertyVisibility["PROTECTED"] = "protected";
46
+ })(PropertyVisibility || (exports.PropertyVisibility = PropertyVisibility = {}));
41
47
  var TypeKind;
42
48
  (function (TypeKind) {
43
49
  TypeKind["CLASS"] = "class";
@@ -240,7 +240,19 @@ class ClassAnalyzer {
240
240
  const substitutedProperties = classAnalysis.ownProperties.map((property) => GenericTypeSubstitutionUtil_1.GenericTypeSubstitutionUtil.substitutePropertyType(property, genericMapping, currentClassGenericParams));
241
241
  allProperties.push(...substitutedProperties);
242
242
  if (classAnalysis.inheritance.isInherited && classAnalysis.inheritance.baseClassAnalysis) {
243
- const ancestorProperties = this.collectAllAncestorProperties(classAnalysis.inheritance.baseClassAnalysis, classAnalysis.inheritance.genericTypeArguments || [], currentClassGenericParams);
243
+ const parentGenericTypeArgs = classAnalysis.inheritance.genericTypeArguments || [];
244
+ const resolvedParentGenericArgs = parentGenericTypeArgs.map(typeArg => {
245
+ const typeStructure = handlers_1.TypeHandlerRegistry.getInstance().parseType(typeArg, {
246
+ depth: 0,
247
+ genericParams: parentGenericParams
248
+ });
249
+ if (typeStructure.kind === Types_1.PropertyKind.GENERIC && genericMapping.has(typeStructure.sourceText)) {
250
+ return genericMapping.get(typeStructure.sourceText);
251
+ }
252
+ return typeArg;
253
+ });
254
+ Logger_1.Logger.debug(`[CollectAncestors] Resolved parent generic args: ${resolvedParentGenericArgs.map(a => a.getText()).join(', ')}`);
255
+ const ancestorProperties = this.collectAllAncestorProperties(classAnalysis.inheritance.baseClassAnalysis, resolvedParentGenericArgs, currentClassGenericParams);
244
256
  allProperties.push(...ancestorProperties);
245
257
  }
246
258
  return allProperties;
@@ -266,10 +278,14 @@ class ClassAnalyzer {
266
278
  if (!typeNode) {
267
279
  throw new CustomError_1.CustomError(`无法分析属性 '${name}' 的类型。请检查属性声明。`, CustomError_1.ErrorCodes.TYPE_NOT_SUPPORT);
268
280
  }
269
- const defaultValue = prop instanceof ts_morph_1.PropertyDeclaration ? this.analyzeDefaultValue(prop, constructorParams) : undefined;
281
+ const defaultValue = prop instanceof ts_morph_1.PropertyDeclaration ?
282
+ this.analyzeDefaultValue(prop, constructorParams) : undefined;
270
283
  const decorators = prop instanceof ts_morph_1.PropertyDeclaration ? this.analyzePropertyDecorators(prop) : undefined;
271
284
  const type = handlers_1.TypeHandlerRegistry.getInstance().parseType(typeNode, { genericParams: genericParameters, depth: 0 });
272
285
  type.isOptional = prop.hasQuestionToken();
286
+ const visibility = prop.hasModifier(ts_morph_1.SyntaxKind.PrivateKeyword) ? Types_1.PropertyVisibility.PRIVATE :
287
+ prop.hasModifier(ts_morph_1.SyntaxKind.ProtectedKeyword) ? Types_1.PropertyVisibility.PROTECTED :
288
+ Types_1.PropertyVisibility.PUBLIC;
273
289
  const constructorParam = constructorParams.find((param) => param.name === name);
274
290
  const isParamOptional = constructorParam
275
291
  ? constructorParam.isOptional ||
@@ -295,7 +311,8 @@ class ClassAnalyzer {
295
311
  defaultValue,
296
312
  decorators,
297
313
  type,
298
- isMust
314
+ isMust,
315
+ visibility
299
316
  };
300
317
  }
301
318
  static analyzePropertyType(prop) {
@@ -352,7 +369,8 @@ class ClassAnalyzer {
352
369
  return undefined;
353
370
  }
354
371
  const exprText = expression.getText();
355
- const supportedTypes = ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array', 'Object', 'ArrayList', 'HashMap', 'HashSet', 'LinkedList', 'Decimal', 'List'];
372
+ const supportedTypes = ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array', 'Object', 'ArrayList', 'HashMap', 'HashSet',
373
+ 'LinkedList', 'Decimal', 'List'];
356
374
  if (!supportedTypes.includes(exprText)) {
357
375
  return undefined;
358
376
  }
@@ -434,6 +452,7 @@ class ClassAnalyzer {
434
452
  const decorators = prop.getDecorators();
435
453
  let isRequired = false;
436
454
  let isTransient = false;
455
+ let isPlainValue = false;
437
456
  let serialName;
438
457
  let _with;
439
458
  decorators.forEach((decorator) => {
@@ -448,6 +467,9 @@ class ClassAnalyzer {
448
467
  case constants_1.DecoratorConstants.TRANSIENT:
449
468
  isTransient = true;
450
469
  break;
470
+ case constants_1.DecoratorConstants.PLAIN_VALUE:
471
+ isPlainValue = true;
472
+ break;
451
473
  case constants_1.DecoratorConstants.SERIALIZABLE:
452
474
  _with = this.parseSerializableOptions(decorator).with;
453
475
  }
@@ -463,15 +485,24 @@ class ClassAnalyzer {
463
485
  if (_with) {
464
486
  conflictingDecorators.push('@Serializable');
465
487
  }
488
+ if (isPlainValue) {
489
+ conflictingDecorators.push('@PlainValue');
490
+ }
466
491
  if (conflictingDecorators.length > 0) {
467
492
  throw new CustomError_1.CustomError(`属性 '${prop.getName()}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
468
493
  `@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
469
494
  `请移除 @Transient 或移除其他序列化注解。`, CustomError_1.ErrorCodes.ANNOTATION_CONFLICT);
470
495
  }
471
496
  }
497
+ if (isPlainValue && _with) {
498
+ throw new CustomError_1.CustomError(`属性 '${prop.getName()}' 的注解冲突:@PlainValue 与 @Serializable(with:) 不能同时使用。\n` +
499
+ `@PlainValue 跳过类型转换直接使用原始值,与自定义序列化器冲突。\n` +
500
+ `请移除 @PlainValue 或移除自定义序列化器。`, CustomError_1.ErrorCodes.ANNOTATION_CONFLICT);
501
+ }
472
502
  return {
473
503
  isRequired,
474
504
  isTransient,
505
+ isPlainValue,
475
506
  serialName,
476
507
  with: _with
477
508
  };
@@ -3,5 +3,6 @@ export declare class DecoratorConstants {
3
3
  static readonly SERIAL_NAME = "SerialName";
4
4
  static readonly REQUIRED = "Required";
5
5
  static readonly TRANSIENT = "Transient";
6
+ static readonly PLAIN_VALUE = "PlainValue";
6
7
  static readonly SERIAL_DECORATORS: string[];
7
8
  }
@@ -10,4 +10,5 @@ DecoratorConstants.SERIALIZABLE = 'Serializable';
10
10
  DecoratorConstants.SERIAL_NAME = 'SerialName';
11
11
  DecoratorConstants.REQUIRED = 'Required';
12
12
  DecoratorConstants.TRANSIENT = 'Transient';
13
- DecoratorConstants.SERIAL_DECORATORS = [_a.SERIALIZABLE, _a.SERIAL_NAME, _a.REQUIRED, _a.TRANSIENT];
13
+ DecoratorConstants.PLAIN_VALUE = 'PlainValue';
14
+ DecoratorConstants.SERIAL_DECORATORS = [_a.SERIALIZABLE, _a.SERIAL_NAME, _a.REQUIRED, _a.TRANSIENT, _a.PLAIN_VALUE];
@@ -166,7 +166,6 @@ class CustomClassHandler extends BaseTypeHandler_1.BaseTypeHandler {
166
166
  throw new CustomError_1.CustomError(`Type ${classDetails.classDecl.getName()} is not sendable.
167
167
  please add @Sendable or @Serializable({ generateSendable: true })`, CustomError_1.ErrorCodes.NOT_SENDABLE);
168
168
  }
169
- return structure.sourceText;
170
169
  }
171
170
  generatePropertyConversion(structure, sourceValue, direction) {
172
171
  const classDetails = structure.classDetails;
@@ -37,7 +37,7 @@ class CodeGenerationService {
37
37
  for (const classAnalysis of results) {
38
38
  serializableGeneratorContext.push(this.serializerGenerator.generate(outputSourceFile, classAnalysis, context));
39
39
  }
40
- this.originalClassGenerator.generate(outputSourceFile, originalSourceFile, results, context);
40
+ this.originalClassGenerator.generate(outputSourceFile, originalSourceFile, results);
41
41
  for (const content of serializableGeneratorContext) {
42
42
  this.serializerGenerator.generateRegistration(outputSourceFile, content);
43
43
  }
@@ -6,7 +6,6 @@ export declare class MergedSendableClassGenerator {
6
6
  private removeTurboTransDecorators;
7
7
  private addSendableDecorator;
8
8
  private addITSerializableInterface;
9
- private generateGetTypeMethod;
10
9
  private generateConvertToSendableMethod;
11
10
  private generateToOriginMethod;
12
11
  private generateToJsonMethod;
@@ -45,18 +45,6 @@ class MergedSendableClassGenerator {
45
45
  }
46
46
  classDecl.addImplements(['ITSerializable', 'lang.ISendable']);
47
47
  }
48
- generateGetTypeMethod(classDecl, classAnalysis) {
49
- if (classDecl.getMethod('getType')) {
50
- __1.Logger.warn(`类 ${classAnalysis.className} 已存在getType方法,跳过生成`);
51
- return;
52
- }
53
- const methodBody = `return ${classAnalysis.className};`;
54
- classDecl.addMethod({
55
- name: 'getType',
56
- returnType: 'Function',
57
- statements: [methodBody]
58
- });
59
- }
60
48
  generateConvertToSendableMethod(classDecl, classAnalysis) {
61
49
  if (classDecl.getMethod('toSendable')) {
62
50
  __1.Logger.warn(`类 ${classAnalysis.className} 已存在toSendable方法,跳过生成`);
@@ -95,14 +83,6 @@ class MergedSendableClassGenerator {
95
83
  return;
96
84
  }
97
85
  const methodBody = 'return TJSON.toString(this, typeKey)';
98
- const genericParameters = classAnalysis.generics.parameters;
99
- let fullTypeName;
100
- if (genericParameters.length > 0) {
101
- fullTypeName = `${classDecl.getNameOrThrow()}<${genericParameters.join(', ')}>`;
102
- }
103
- else {
104
- fullTypeName = classDecl.getNameOrThrow();
105
- }
106
86
  classDecl.addMethod({
107
87
  name: 'toJson',
108
88
  returnType: 'string',
@@ -1,16 +1,14 @@
1
1
  import { SourceFile } from 'ts-morph';
2
- import { ClassAnalysis, ITaskContext } from '../../..';
2
+ import { ClassAnalysis } from '../../..';
3
3
  import { ImportManager } from '../shared/ImportManager';
4
4
  export declare class OriginalClassGenerator {
5
5
  private readonly importManager;
6
6
  private readonly mergedSendableGenerator;
7
7
  constructor(importManager: ImportManager);
8
- generate(outputSourceFile: SourceFile, originalSourceFile: SourceFile, results: ClassAnalysis[], context: ITaskContext): void;
8
+ generate(outputSourceFile: SourceFile, originalSourceFile: SourceFile, results: ClassAnalysis[]): void;
9
9
  private copySourceFileContentWithoutImports;
10
10
  private addITSerializableInterface;
11
- private generateSerialNameConstant;
12
11
  private addStaticSerialName;
13
- private generateGetTypeMethod;
14
12
  private generateConvertToSendableMethod;
15
13
  private generateToJsonMethod;
16
14
  private registerImports;
@@ -16,7 +16,7 @@ class OriginalClassGenerator {
16
16
  this.importManager = importManager;
17
17
  this.mergedSendableGenerator = new MergedSendableClassGenerator_1.MergedSendableClassGenerator();
18
18
  }
19
- generate(outputSourceFile, originalSourceFile, results, context) {
19
+ generate(outputSourceFile, originalSourceFile, results) {
20
20
  this.registerImports();
21
21
  const contentWithoutImports = this.copySourceFileContentWithoutImports(originalSourceFile);
22
22
  const tempSourceFile = TsMorphUtil_1.TsMorphUtil.getProject().createSourceFile('temp.ts', contentWithoutImports, {
@@ -31,7 +31,7 @@ class OriginalClassGenerator {
31
31
  }
32
32
  else {
33
33
  this.addITSerializableInterface(targetClass);
34
- this.addStaticSerialName(targetClass, result, context);
34
+ this.addStaticSerialName(targetClass, result);
35
35
  this.generateConvertToSendableMethod(targetClass, result);
36
36
  this.generateToJsonMethod(targetClass, result);
37
37
  }
@@ -85,13 +85,7 @@ class OriginalClassGenerator {
85
85
  classDecl.addImplements('ITSerializable');
86
86
  __1.Logger.debug(`为类 ${classDecl.getName()} 添加ITSerializable接口实现`);
87
87
  }
88
- generateSerialNameConstant(result, context) {
89
- const relativePath = context.calculateSourceRootToModuleRoot(result.sourceFilePath);
90
- const serialName = SerializationPathUtil_1.default.join(context.getPackageName(), relativePath, result.className + '.class')
91
- .replaceAll(SerializationPathUtil_1.default.sep, '/');
92
- return result.decorators.serialName || serialName;
93
- }
94
- addStaticSerialName(classDecl, result, context) {
88
+ addStaticSerialName(classDecl, result) {
95
89
  classDecl.addProperty({
96
90
  name: 'SERIAL_NAME',
97
91
  type: 'string',
@@ -101,18 +95,6 @@ class OriginalClassGenerator {
101
95
  });
102
96
  __1.Logger.debug(`为类 ${classDecl.getName()} 添加静态属性 serialName`);
103
97
  }
104
- generateGetTypeMethod(classDecl, result) {
105
- if (classDecl.getMethod('getType')) {
106
- __1.Logger.warn(`类 ${result.className} 已存在getType方法,跳过生成`);
107
- return;
108
- }
109
- const methodBody = `return ${result.className};`;
110
- classDecl.addMethod({
111
- name: 'getType',
112
- returnType: 'Function',
113
- statements: [methodBody]
114
- });
115
- }
116
98
  generateConvertToSendableMethod(classDecl, result) {
117
99
  if (classDecl.getMethod('toSendable')) {
118
100
  __1.Logger.warn(`类 ${result.className} 已存在toSendable方法,跳过生成`);
@@ -144,14 +126,6 @@ class OriginalClassGenerator {
144
126
  return;
145
127
  }
146
128
  const methodBody = 'return TJSON.toString(this, typeKey)';
147
- const genericParameters = result.generics.parameters;
148
- let fullTypeName;
149
- if (genericParameters.length > 0) {
150
- fullTypeName = `${classDecl.getNameOrThrow()}<${genericParameters.join(', ')}>`;
151
- }
152
- else {
153
- fullTypeName = classDecl.getNameOrThrow();
154
- }
155
129
  classDecl.addMethod({
156
130
  name: 'toJson',
157
131
  returnType: 'string',
@@ -165,7 +139,7 @@ class OriginalClassGenerator {
165
139
  }
166
140
  registerImports() {
167
141
  this.importManager.registerJsonImports(['ITSerializable', 'TJSON']);
168
- this.importManager.registerCoreImports(['TypeKey', 'Serializable']);
142
+ this.importManager.registerCoreImports(['TypeKey', 'Serializable', 'Encoder', 'SerialDescriptor']);
169
143
  }
170
144
  generateConvertToSendableMethodBody(classAnalysis, returnType) {
171
145
  const constructorProps = [];
@@ -20,7 +20,7 @@ class SerializerGenerator {
20
20
  generate(sourceFile, result, context) {
21
21
  if (result.decorators?.serializable?.with) {
22
22
  sourceFile.addStatements(this.generateBuiltinSerializerRegistrationForSupplementary(context, result));
23
- return this.generateCustomSerializerRegistration(sourceFile, result);
23
+ return this.generateCustomSerializerRegistration(result);
24
24
  }
25
25
  this.registerImports(result);
26
26
  const templateContext = {
@@ -49,7 +49,8 @@ class SerializerGenerator {
49
49
  const requiredBuiltinSerializers = this.getAllRequiredSerializers(result.properties);
50
50
  this.importManager.registerCoreImports([
51
51
  'Serializer', 'SerialDescriptor', 'buildClassSerialDescriptor',
52
- 'Encoder', 'Decoder', 'registerAutoGeneratedSerializerEntry', 'registerAutoGeneratedSerializerEntryProviderForSupplementary',
52
+ 'Encoder', 'Decoder', 'registerAutoGeneratedSerializerEntry', 'ObjectUtils',
53
+ 'registerAutoGeneratedSerializerEntryProviderForSupplementary',
53
54
  ...requiredBuiltinSerializers
54
55
  ]);
55
56
  this.registerDecoratorsImports(result);
@@ -120,15 +121,15 @@ class SerializerGenerator {
120
121
  this.importManager.registerCoreImports(['WithEntryContextualSerializer']);
121
122
  }
122
123
  }
123
- this.execPropertyImports(property.type.dependencies);
124
+ this.execPropertyImports(property.type.dependencies, !!property.decorators?.with);
124
125
  }
125
126
  }
126
- execPropertyImports(dependencies) {
127
+ execPropertyImports(dependencies, hasWithParam) {
127
128
  dependencies.forEach((dependency) => {
128
- this.processDependency(dependency);
129
+ this.processDependency(dependency, hasWithParam);
129
130
  });
130
131
  }
131
- processDependency(dependency) {
132
+ processDependency(dependency, hasWithParam) {
132
133
  const source = dependency.source;
133
134
  if (source.type !== 'imported' && source.type !== 'local') {
134
135
  return;
@@ -138,14 +139,14 @@ class SerializerGenerator {
138
139
  }
139
140
  switch (dependency.typeKind) {
140
141
  case __1.TypeKind.CLASS:
141
- this.processClassDependency(dependency, source);
142
+ this.processClassDependency(dependency, source, hasWithParam);
142
143
  break;
143
144
  case __1.TypeKind.INTERFACE:
144
- this.processInterfaceDependency(dependency);
145
+ this.processInterfaceDependency(dependency, hasWithParam);
145
146
  break;
146
147
  }
147
148
  }
148
- processClassDependency(dependency, source) {
149
+ processClassDependency(dependency, source, hasWithParam) {
149
150
  const classDetails = dependency.details;
150
151
  const tempClassAnalysis = ClassAnalyzer_1.ClassAnalyzer.analyzeClass(classDetails.classDecl);
151
152
  if (!tempClassAnalysis.decorators.serializable) {
@@ -157,6 +158,9 @@ class SerializerGenerator {
157
158
  this.handleSerializableClass(dependency, source, serializerName);
158
159
  }
159
160
  else {
161
+ if (hasWithParam) {
162
+ return;
163
+ }
160
164
  this.importManager.registerTempSerializerImport(`${dependency.typeName}${serializerName}`);
161
165
  }
162
166
  }
@@ -165,7 +169,10 @@ class SerializerGenerator {
165
169
  this.importManager.registerCustomTypeImport(source.sourceFilePath, `${dependency.typeName}${serializerName}`);
166
170
  }
167
171
  }
168
- processInterfaceDependency(dependency) {
172
+ processInterfaceDependency(dependency, hasWithParam) {
173
+ if (hasWithParam) {
174
+ return;
175
+ }
169
176
  const interfaceDetails = dependency.details;
170
177
  const tempClassAnalysis = ClassAnalyzer_1.ClassAnalyzer.analyzeInterface(interfaceDetails.interfaceDecl);
171
178
  TempSerializerGenerator_1.TempSerializerGenerator.getInstance().generateSerializer(tempClassAnalysis);
@@ -173,19 +180,17 @@ class SerializerGenerator {
173
180
  __1.StringConstants.SERIALIZER;
174
181
  this.importManager.registerTempSerializerImport(`${dependency.typeName}${serializerName}`);
175
182
  }
176
- generateCustomSerializerRegistration(sourceFile, result) {
183
+ generateCustomSerializerRegistration(result) {
177
184
  this.importManager.registerCoreImports(['registerAutoGeneratedSerializerEntry']);
178
185
  const customSerializer = result.decorators.serializable.with;
179
- const registrationCode = `registerAutoGeneratedSerializerEntry(${result.className}, ${customSerializer});`;
180
- return registrationCode;
186
+ return `registerAutoGeneratedSerializerEntry(${result.className}, ${customSerializer});`;
181
187
  }
182
188
  generateBuiltinSerializerRegistrationForSupplementary(context, result) {
183
189
  this.importManager.registerCoreImports(['registerAutoGeneratedSerializerEntryProviderForSupplementary']);
184
190
  const serialNameConstant = this.generateSerialNameConstant(result, context);
185
191
  const customSerializer = result.decorators.serializable.with;
186
- const registrationCode = `const ${result.className}_SERIAL_NAME = '${serialNameConstant}';\n
192
+ return `const ${result.className}_SERIAL_NAME = '${serialNameConstant}';\n
187
193
  registerAutoGeneratedSerializerEntryProviderForSupplementary(${result.className}_SERIAL_NAME, () => [${result.className}, ${customSerializer}]);`;
188
- return registrationCode;
189
194
  }
190
195
  getAllRequiredSerializers(properties) {
191
196
  const requiredSerializers = new Set();
@@ -188,6 +188,9 @@ class HandlebarsTemplateEngine {
188
188
  this.registerHelper('genericParametersESObjString', (parameters) => {
189
189
  return parameters.map(() => 'ESObject').join(', ');
190
190
  });
191
+ this.registerHelper('filterGenericProperties', (properties) => {
192
+ return properties.filter(p => p.analysis.type.kind === __1.PropertyKind.GENERIC && !p.analysis.decorators?.isTransient);
193
+ });
191
194
  }
192
195
  registerPropertyAnalysisHelpers() {
193
196
  this.registerHelper('getPropertyIndex', (property, properties) => {
@@ -8,7 +8,8 @@ class DeepCopyUtil {
8
8
  defaultValue: original.defaultValue,
9
9
  decorators: this.copyPropertyDecorators(original.decorators),
10
10
  isMust: original.isMust,
11
- type: this.copyTypeStructure(original.type)
11
+ type: this.copyTypeStructure(original.type),
12
+ visibility: original.visibility
12
13
  };
13
14
  }
14
15
  static copyPropertyDecorators(original) {
@@ -19,6 +20,7 @@ class DeepCopyUtil {
19
20
  serialName: original.serialName,
20
21
  isRequired: original.isRequired,
21
22
  isTransient: original.isTransient,
23
+ isPlainValue: original.isPlainValue,
22
24
  with: original.with
23
25
  };
24
26
  }
@@ -5,5 +5,6 @@ export declare class GenericTypeSubstitutionUtil {
5
5
  static substitutePropertyType(property: PropertyAnalysis, genericMapping: Map<string, TypeNode>, currentClassGenericParams?: string[]): PropertyAnalysis;
6
6
  private static substituteTypeStructure;
7
7
  private static constructTypeStructureFromTypeName;
8
+ private static regenerateSourceText;
8
9
  private static collectDependenciesFromChildren;
9
10
  }
@@ -4,11 +4,14 @@ exports.GenericTypeSubstitutionUtil = void 0;
4
4
  const __1 = require("..");
5
5
  const handlers_1 = require("../handlers");
6
6
  const DeepCopyUtil_1 = require("./DeepCopyUtil");
7
+ const Logger_1 = require("../logger/Logger");
7
8
  class GenericTypeSubstitutionUtil {
8
9
  static buildGenericMapping(parentGenericParams, childTypeArguments) {
9
10
  const mapping = new Map();
10
11
  const length = Math.min(parentGenericParams.length, childTypeArguments.length);
12
+ Logger_1.Logger.debug(`[GenericMapping] Building mapping with ${length} parameters`);
11
13
  for (let i = 0; i < length; i++) {
14
+ Logger_1.Logger.debug(`[GenericMapping] ${parentGenericParams[i]} -> ${childTypeArguments[i].getText()}`);
12
15
  mapping.set(parentGenericParams[i], childTypeArguments[i]);
13
16
  }
14
17
  return mapping;
@@ -24,10 +27,17 @@ class GenericTypeSubstitutionUtil {
24
27
  static substituteTypeStructure(typeStructure, mapping, currentClassGenericParams = []) {
25
28
  if (typeStructure.kind === __1.PropertyKind.GENERIC) {
26
29
  const genericTypeName = typeStructure.sourceText;
30
+ Logger_1.Logger.debug(`[GenericSubstitution] Processing generic type: ${genericTypeName}`);
31
+ Logger_1.Logger.debug(`[GenericSubstitution] Available mappings: ${Array.from(mapping.keys()).join(', ')}`);
32
+ Logger_1.Logger.debug(`[GenericSubstitution] Current class generic params: ${currentClassGenericParams.join(', ')}`);
27
33
  if (mapping.has(genericTypeName)) {
28
34
  const substitutedTypeNode = mapping.get(genericTypeName);
29
- return this.constructTypeStructureFromTypeName(substitutedTypeNode, currentClassGenericParams);
35
+ Logger_1.Logger.debug(`[GenericSubstitution] Found mapping for ${genericTypeName} -> ${substitutedTypeNode.getText()}`);
36
+ const result = this.constructTypeStructureFromTypeName(substitutedTypeNode, currentClassGenericParams);
37
+ Logger_1.Logger.debug(`[GenericSubstitution] Result kind: ${result.kind}, sourceText: ${result.sourceText}`);
38
+ return result;
30
39
  }
40
+ Logger_1.Logger.warn(`[GenericSubstitution] No mapping found for generic type: ${genericTypeName}, keeping as-is`);
31
41
  return typeStructure;
32
42
  }
33
43
  const newStructure = DeepCopyUtil_1.DeepCopyUtil.copyTypeStructure(typeStructure);
@@ -36,6 +46,7 @@ class GenericTypeSubstitutionUtil {
36
46
  }
37
47
  if (newStructure.args) {
38
48
  newStructure.args = newStructure.args.map(arg => this.substituteTypeStructure(arg, mapping, currentClassGenericParams));
49
+ newStructure.sourceText = this.regenerateSourceText(newStructure);
39
50
  }
40
51
  newStructure.dependencies = this.collectDependenciesFromChildren(newStructure);
41
52
  return newStructure;
@@ -46,6 +57,21 @@ class GenericTypeSubstitutionUtil {
46
57
  genericParams: currentClassGenericParams
47
58
  });
48
59
  }
60
+ static regenerateSourceText(structure) {
61
+ if (!structure.args || structure.args.length === 0) {
62
+ return structure.sourceText;
63
+ }
64
+ if (structure.sourceText.endsWith('[]')) {
65
+ return `${structure.args[0].sourceText}[]`;
66
+ }
67
+ const genericStart = structure.sourceText.indexOf('<');
68
+ if (genericStart > 0) {
69
+ const containerName = structure.sourceText.substring(0, genericStart);
70
+ const argsText = structure.args.map(arg => arg.sourceText).join(', ');
71
+ return `${containerName}<${argsText}>`;
72
+ }
73
+ return structure.sourceText;
74
+ }
49
75
  static collectDependenciesFromChildren(children) {
50
76
  const allDependencies = [];
51
77
  if (children.unionDetails) {
@@ -9,6 +9,10 @@ class TsMorphUtil {
9
9
  if (!this.project) {
10
10
  Logger_1.Logger.info('创建ts-morph项目');
11
11
  this.project = new ts_morph_1.Project(options || {
12
+ manipulationSettings: {
13
+ indentationText: ts_morph_1.IndentationText.TwoSpaces,
14
+ quoteKind: ts_morph_1.QuoteKind.Single
15
+ },
12
16
  compilerOptions: {
13
17
  allowNonTsExtensions: true
14
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hadss/turbo-trans-json-plugin",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "TurboTransJSON Compiler Plugin for automatic serialization code generation",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/core/Types.ts CHANGED
@@ -172,6 +172,13 @@ export interface PropertyAnalysis {
172
172
  decorators?: PropertyDecorators; // 装饰器信息
173
173
  isMust: boolean; // 精确模式下反序列化时的必要性
174
174
  type: TypeStructure; // 完整的类型分析结果(详细类型信息)
175
+ visibility: PropertyVisibility; // 属性可见性修饰符
176
+ }
177
+
178
+ export enum PropertyVisibility {
179
+ PUBLIC = 'public',
180
+ PRIVATE = 'private',
181
+ PROTECTED = 'protected',
175
182
  }
176
183
 
177
184
  /**
@@ -182,6 +189,7 @@ export interface PropertyDecorators {
182
189
  serialName?: string; // @SerialName 自定义序列化名称
183
190
  isRequired: boolean; // @Required 是否必需字段
184
191
  isTransient: boolean; // @Transient 是否跳过序列化
192
+ isPlainValue: boolean; // @PlainValue 是否使用原始值(跳过类型转换)
185
193
  with?: string; // @Serializable 自定义序列化器
186
194
  }
187
195
 
@@ -195,7 +203,7 @@ export interface TypeStructure {
195
203
  kind: PropertyKind; // 类型种类(STRING, ARRAY, MAP等)
196
204
  depth: number; // 嵌套深度(用于复杂度控制)
197
205
  sourceText: string; // 原始类型文本(如 "Array<Map<string, User>>")
198
- args: TypeStructure[] // 泛型参数的类型
206
+ args: TypeStructure[]; // 泛型参数的类型
199
207
  // 类型依赖和特殊信息
200
208
  dependencies: TypeDependency[]; // 依赖信息列表(包含完整导入信息)
201
209
  enumDetails?: EnumDetails; // 枚举类型详细信息(仅当kind=ENUM时)