@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.
- package/README.md +1 -1
- package/dist/core/Types.d.ts +7 -0
- package/dist/core/Types.js +7 -1
- package/dist/core/analyzers/ClassAnalyzer.js +35 -4
- package/dist/core/constants/DecoratorConstants.d.ts +1 -0
- package/dist/core/constants/DecoratorConstants.js +2 -1
- package/dist/core/handlers/CustomClassHandler.js +0 -1
- package/dist/core/services/CodeGenerationService/CodeGenerationService.js +1 -1
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +0 -1
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +0 -20
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +2 -4
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +4 -30
- package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +20 -15
- package/dist/core/template/HandlebarsTemplateEngine.js +3 -0
- package/dist/core/utils/DeepCopyUtil.js +3 -1
- package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +1 -0
- package/dist/core/utils/GenericTypeSubstitutionUtil.js +27 -1
- package/dist/core/utils/TsMorphUtil.js +4 -0
- package/package.json +1 -1
- package/src/core/Types.ts +9 -1
- package/src/core/analyzers/ClassAnalyzer.ts +74 -18
- package/src/core/analyzers/CustomTypeAnalyzer.ts +0 -1
- package/src/core/constants/DecoratorConstants.ts +2 -1
- package/src/core/constants/StringConstants.ts +0 -2
- package/src/core/handlers/CustomClassHandler.ts +0 -3
- package/src/core/handlers/TypeHandlerRegistry.ts +1 -1
- package/src/core/import-rewrite/services/BuildProfileUpdater.ts +1 -1
- package/src/core/import-rewrite/services/ImportRewriteService.ts +0 -2
- package/src/core/services/CodeAnalysisService.ts +1 -1
- package/src/core/services/CodeGenerationService/CodeGenerationService.ts +1 -2
- package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +0 -29
- package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +6 -42
- package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +26 -19
- package/src/core/template/HandlebarsTemplateEngine.ts +5 -0
- package/src/core/utils/DeepCopyUtil.ts +3 -1
- package/src/core/utils/GenericTypeSubstitutionUtil.ts +51 -1
- package/src/core/utils/TsMorphUtil.ts +5 -1
- package/src/json-plugin/tasks/BaseTask.ts +0 -1
- package/template/SerializerPerformanceTemplate.hbs +14 -4
- package/template/SerializerStrictTemplate.hbs +8 -0
- package/template/SerializerTemplate.hbs +14 -6
package/README.md
CHANGED
package/dist/core/Types.d.ts
CHANGED
|
@@ -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 {
|
package/dist/core/Types.js
CHANGED
|
@@ -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
|
|
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 ?
|
|
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',
|
|
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
|
};
|
|
@@ -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.
|
|
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
|
|
40
|
+
this.originalClassGenerator.generate(outputSourceFile, originalSourceFile, results);
|
|
41
41
|
for (const content of serializableGeneratorContext) {
|
|
42
42
|
this.serializerGenerator.generateRegistration(outputSourceFile, content);
|
|
43
43
|
}
|
package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts
CHANGED
|
@@ -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
|
|
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[]
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
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', '
|
|
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(
|
|
183
|
+
generateCustomSerializerRegistration(result) {
|
|
177
184
|
this.importManager.registerCoreImports(['registerAutoGeneratedSerializerEntry']);
|
|
178
185
|
const customSerializer = result.decorators.serializable.with;
|
|
179
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
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时)
|