@hadss/turbo-trans-json-plugin 1.0.0-rc.0
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/LICENSE +177 -0
- package/README.md +253 -0
- package/dist/core/Types.d.ts +196 -0
- package/dist/core/Types.js +47 -0
- package/dist/core/analyzers/ClassAnalyzer.d.ts +23 -0
- package/dist/core/analyzers/ClassAnalyzer.js +480 -0
- package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +21 -0
- package/dist/core/analyzers/CustomTypeAnalyzer.js +243 -0
- package/dist/core/analyzers/SendableMergeChecker.d.ts +9 -0
- package/dist/core/analyzers/SendableMergeChecker.js +100 -0
- package/dist/core/analyzers/SendableMergeabilityRegistry.d.ts +7 -0
- package/dist/core/analyzers/SendableMergeabilityRegistry.js +23 -0
- package/dist/core/constants/DecoratorConstants.d.ts +7 -0
- package/dist/core/constants/DecoratorConstants.js +13 -0
- package/dist/core/constants/PathConstants.d.ts +6 -0
- package/dist/core/constants/PathConstants.js +10 -0
- package/dist/core/constants/StringConstants.d.ts +83 -0
- package/dist/core/constants/StringConstants.js +87 -0
- package/dist/core/constants/index.d.ts +3 -0
- package/dist/core/constants/index.js +19 -0
- package/dist/core/handlers/BaseTypeHandler.d.ts +23 -0
- package/dist/core/handlers/BaseTypeHandler.js +57 -0
- package/dist/core/handlers/CustomClassHandler.d.ts +21 -0
- package/dist/core/handlers/CustomClassHandler.js +191 -0
- package/dist/core/handlers/DateHandler.d.ts +2 -0
- package/dist/core/handlers/DateHandler.js +60 -0
- package/dist/core/handlers/DecimalHandler.d.ts +2 -0
- package/dist/core/handlers/DecimalHandler.js +60 -0
- package/dist/core/handlers/EnumHandler.d.ts +2 -0
- package/dist/core/handlers/EnumHandler.js +89 -0
- package/dist/core/handlers/GenericContainerHandler.d.ts +2 -0
- package/dist/core/handlers/GenericContainerHandler.js +440 -0
- package/dist/core/handlers/GenericHandler.d.ts +18 -0
- package/dist/core/handlers/GenericHandler.js +92 -0
- package/dist/core/handlers/HandlerBootstrap.d.ts +2 -0
- package/dist/core/handlers/HandlerBootstrap.js +28 -0
- package/dist/core/handlers/ITypeHandler.d.ts +23 -0
- package/dist/core/handlers/ITypeHandler.js +8 -0
- package/dist/core/handlers/PrimitiveHandler.d.ts +2 -0
- package/dist/core/handlers/PrimitiveHandler.js +127 -0
- package/dist/core/handlers/TupleHandler.d.ts +2 -0
- package/dist/core/handlers/TupleHandler.js +98 -0
- package/dist/core/handlers/TypeHandlerRegistry.d.ts +20 -0
- package/dist/core/handlers/TypeHandlerRegistry.js +113 -0
- package/dist/core/handlers/UnionTypeHandler.d.ts +2 -0
- package/dist/core/handlers/UnionTypeHandler.js +263 -0
- package/dist/core/handlers/index.d.ts +2 -0
- package/dist/core/handlers/index.js +5 -0
- package/dist/core/import-rewrite/services/BuildProfileUpdater.d.ts +8 -0
- package/dist/core/import-rewrite/services/BuildProfileUpdater.js +92 -0
- package/dist/core/import-rewrite/services/ImportRewriteService.d.ts +9 -0
- package/dist/core/import-rewrite/services/ImportRewriteService.js +61 -0
- package/dist/core/import-rewrite/services/ImportTransformService.d.ts +15 -0
- package/dist/core/import-rewrite/services/ImportTransformService.js +109 -0
- package/dist/core/import-rewrite/strategies/ImportScanStrategy.d.ts +17 -0
- package/dist/core/import-rewrite/strategies/ImportScanStrategy.js +137 -0
- package/dist/core/import-rewrite/types/ImportRewriteTypes.d.ts +17 -0
- package/dist/core/import-rewrite/types/ImportRewriteTypes.js +2 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +27 -0
- package/dist/core/interfaces/ITask.d.ts +7 -0
- package/dist/core/interfaces/ITask.js +2 -0
- package/dist/core/interfaces/ITaskContext.d.ts +11 -0
- package/dist/core/interfaces/ITaskContext.js +2 -0
- package/dist/core/interfaces/index.d.ts +2 -0
- package/dist/core/interfaces/index.js +2 -0
- package/dist/core/logger/Logger.d.ts +13 -0
- package/dist/core/logger/Logger.js +78 -0
- package/dist/core/services/CodeAnalysisService.d.ts +7 -0
- package/dist/core/services/CodeAnalysisService.js +43 -0
- package/dist/core/services/CodeGenerationEngine.d.ts +12 -0
- package/dist/core/services/CodeGenerationEngine.js +102 -0
- package/dist/core/services/CodeGenerationService/CodeGenerationService.d.ts +13 -0
- package/dist/core/services/CodeGenerationService/CodeGenerationService.js +110 -0
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +13 -0
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +119 -0
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +21 -0
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +224 -0
- package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +24 -0
- package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +307 -0
- package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.d.ts +28 -0
- package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +259 -0
- package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.d.ts +19 -0
- package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +178 -0
- package/dist/core/services/CodeGenerationService/index.d.ts +1 -0
- package/dist/core/services/CodeGenerationService/index.js +5 -0
- package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +27 -0
- package/dist/core/services/CodeGenerationService/shared/ImportManager.js +127 -0
- package/dist/core/template/HandlebarsTemplateEngine.d.ts +26 -0
- package/dist/core/template/HandlebarsTemplateEngine.js +226 -0
- package/dist/core/utils/ConfigManager.d.ts +10 -0
- package/dist/core/utils/ConfigManager.js +32 -0
- package/dist/core/utils/CustomError.d.ts +30 -0
- package/dist/core/utils/CustomError.js +37 -0
- package/dist/core/utils/DeepCopyUtil.d.ts +15 -0
- package/dist/core/utils/DeepCopyUtil.js +138 -0
- package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +9 -0
- package/dist/core/utils/GenericTypeSubstitutionUtil.js +68 -0
- package/dist/core/utils/SerializationPathUtil.d.ts +18 -0
- package/dist/core/utils/SerializationPathUtil.js +107 -0
- package/dist/core/utils/TsMorphUtil.d.ts +8 -0
- package/dist/core/utils/TsMorphUtil.js +34 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +57 -0
- package/dist/json-plugin/JSONExecuteController.d.ts +13 -0
- package/dist/json-plugin/JSONExecuteController.js +103 -0
- package/dist/json-plugin/constants/TaskConstants.d.ts +7 -0
- package/dist/json-plugin/constants/TaskConstants.js +11 -0
- package/dist/json-plugin/interfaces/IModuleContext.d.ts +10 -0
- package/dist/json-plugin/interfaces/IModuleContext.js +2 -0
- package/dist/json-plugin/interfaces/ITargetContext.d.ts +8 -0
- package/dist/json-plugin/interfaces/ITargetContext.js +2 -0
- package/dist/json-plugin/interfaces/impl/ModuleContext.d.ts +12 -0
- package/dist/json-plugin/interfaces/impl/ModuleContext.js +24 -0
- package/dist/json-plugin/interfaces/impl/TargetContext.d.ts +23 -0
- package/dist/json-plugin/interfaces/impl/TargetContext.js +113 -0
- package/dist/json-plugin/tasks/BaseTask.d.ts +14 -0
- package/dist/json-plugin/tasks/BaseTask.js +53 -0
- package/dist/json-plugin/tasks/CleanTask.d.ts +8 -0
- package/dist/json-plugin/tasks/CleanTask.js +25 -0
- package/dist/json-plugin/tasks/CodeProcessingTask.d.ts +8 -0
- package/dist/json-plugin/tasks/CodeProcessingTask.js +26 -0
- package/dist/json-plugin/tasks/SyncTask.d.ts +8 -0
- package/dist/json-plugin/tasks/SyncTask.js +21 -0
- package/dist/json-plugin/tasks/WatchTask.d.ts +11 -0
- package/dist/json-plugin/tasks/WatchTask.js +102 -0
- package/package.json +46 -0
- package/src/core/Types.ts +356 -0
- package/src/core/analyzers/ClassAnalyzer.ts +824 -0
- package/src/core/analyzers/CustomTypeAnalyzer.ts +337 -0
- package/src/core/analyzers/SendableMergeChecker.ts +195 -0
- package/src/core/analyzers/SendableMergeabilityRegistry.ts +72 -0
- package/src/core/constants/DecoratorConstants.ts +27 -0
- package/src/core/constants/PathConstants.ts +31 -0
- package/src/core/constants/StringConstants.ts +152 -0
- package/src/core/constants/index.ts +21 -0
- package/src/core/handlers/BaseTypeHandler.ts +121 -0
- package/src/core/handlers/CustomClassHandler.ts +278 -0
- package/src/core/handlers/DateHandler.ts +75 -0
- package/src/core/handlers/DecimalHandler.ts +75 -0
- package/src/core/handlers/EnumHandler.ts +142 -0
- package/src/core/handlers/GenericContainerHandler.ts +621 -0
- package/src/core/handlers/GenericHandler.ts +130 -0
- package/src/core/handlers/HandlerBootstrap.ts +64 -0
- package/src/core/handlers/ITypeHandler.ts +133 -0
- package/src/core/handlers/PrimitiveHandler.ts +159 -0
- package/src/core/handlers/TupleHandler.ts +145 -0
- package/src/core/handlers/TypeHandlerRegistry.ts +236 -0
- package/src/core/handlers/UnionTypeHandler.ts +400 -0
- package/src/core/handlers/index.ts +18 -0
- package/src/core/import-rewrite/services/BuildProfileUpdater.ts +145 -0
- package/src/core/import-rewrite/services/ImportRewriteService.ts +129 -0
- package/src/core/import-rewrite/services/ImportTransformService.ts +200 -0
- package/src/core/import-rewrite/strategies/ImportScanStrategy.ts +303 -0
- package/src/core/import-rewrite/types/ImportRewriteTypes.ts +100 -0
- package/src/core/index.ts +31 -0
- package/src/core/interfaces/ITask.ts +23 -0
- package/src/core/interfaces/ITaskContext.ts +94 -0
- package/src/core/interfaces/index.ts +17 -0
- package/src/core/logger/Logger.ts +149 -0
- package/src/core/services/CodeAnalysisService.ts +67 -0
- package/src/core/services/CodeGenerationEngine.ts +181 -0
- package/src/core/services/CodeGenerationService/CodeGenerationService.ts +159 -0
- package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +189 -0
- package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +314 -0
- package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +421 -0
- package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +392 -0
- package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +277 -0
- package/src/core/services/CodeGenerationService/index.ts +16 -0
- package/src/core/services/CodeGenerationService/shared/ImportManager.ts +191 -0
- package/src/core/template/HandlebarsTemplateEngine.ts +282 -0
- package/src/core/utils/ConfigManager.ts +49 -0
- package/src/core/utils/CustomError.ts +51 -0
- package/src/core/utils/DeepCopyUtil.ts +185 -0
- package/src/core/utils/GenericTypeSubstitutionUtil.ts +136 -0
- package/src/core/utils/SerializationPathUtil.ts +142 -0
- package/src/core/utils/TsMorphUtil.ts +50 -0
- package/src/index.ts +81 -0
- package/src/json-plugin/JSONExecuteController.ts +134 -0
- package/src/json-plugin/constants/TaskConstants.ts +22 -0
- package/src/json-plugin/interfaces/IModuleContext.ts +27 -0
- package/src/json-plugin/interfaces/ITargetContext.ts +25 -0
- package/src/json-plugin/interfaces/impl/ModuleContext.ts +45 -0
- package/src/json-plugin/interfaces/impl/TargetContext.ts +196 -0
- package/src/json-plugin/tasks/BaseTask.ts +94 -0
- package/src/json-plugin/tasks/CleanTask.ts +36 -0
- package/src/json-plugin/tasks/CodeProcessingTask.ts +41 -0
- package/src/json-plugin/tasks/SyncTask.ts +33 -0
- package/src/json-plugin/tasks/WatchTask.ts +99 -0
- package/template/SerializerPerformanceTemplate.hbs +35 -0
- package/template/SerializerRegisterTemplate.hbs +10 -0
- package/template/SerializerStrictTemplate.hbs +89 -0
- package/template/SerializerTemplate.hbs +176 -0
- package/tsconfig.json +17 -0
- package/tslint.json +3 -0
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Huawei Device Co., Ltd.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
ClassDeclaration,
|
|
18
|
+
ConstructorDeclaration,
|
|
19
|
+
Decorator,
|
|
20
|
+
InterfaceDeclaration,
|
|
21
|
+
NewExpression,
|
|
22
|
+
PropertyDeclaration,
|
|
23
|
+
PropertySignature,
|
|
24
|
+
SyntaxKind,
|
|
25
|
+
TypeNode
|
|
26
|
+
} from 'ts-morph';
|
|
27
|
+
import {
|
|
28
|
+
ClassAnalysis,
|
|
29
|
+
InterfaceAnalysis,
|
|
30
|
+
ClassDecorators,
|
|
31
|
+
ConstructorParam,
|
|
32
|
+
DeserializationMode,
|
|
33
|
+
GenericInfo,
|
|
34
|
+
InheritanceInfo,
|
|
35
|
+
PropertyAnalysis,
|
|
36
|
+
PropertyDecorators,
|
|
37
|
+
PropertyKind,
|
|
38
|
+
SerializableOptions,
|
|
39
|
+
TypeStructure
|
|
40
|
+
} from '../Types';
|
|
41
|
+
import { DecoratorConstants } from '../constants';
|
|
42
|
+
import { GenericTypeSubstitutionUtil } from '../utils/GenericTypeSubstitutionUtil';
|
|
43
|
+
import { TypeHandlerRegistry } from '../handlers';
|
|
44
|
+
import { CustomTypeAnalyzer } from './CustomTypeAnalyzer';
|
|
45
|
+
import { CustomError, ErrorCodes } from '../utils/CustomError';
|
|
46
|
+
import { Logger } from '../logger/Logger';
|
|
47
|
+
import { TsMorphUtil } from '../utils/TsMorphUtil';
|
|
48
|
+
import { logger } from 'handlebars';
|
|
49
|
+
|
|
50
|
+
export class ClassAnalyzer {
|
|
51
|
+
/**
|
|
52
|
+
* 分析类的完整结构,包括属性、构造函数、继承关系、装饰器等信息
|
|
53
|
+
* @param classDecl 类声明节点
|
|
54
|
+
* @returns 类分析结果
|
|
55
|
+
*/
|
|
56
|
+
public static analyzeClass(classDecl: ClassDeclaration): ClassAnalysis {
|
|
57
|
+
Logger.debug(`Analyzing class ${classDecl.wasForgotten()}`);
|
|
58
|
+
const className = classDecl.getNameOrThrow(`Class name is undefined in ${classDecl.getSourceFile().getFilePath()}`);
|
|
59
|
+
const sourceFilePath = classDecl.getSourceFile().getFilePath();
|
|
60
|
+
Logger.warn(`Analyzing class ${className} ${sourceFilePath}`);
|
|
61
|
+
|
|
62
|
+
const generics: GenericInfo = {
|
|
63
|
+
isGeneric: classDecl.getTypeParameters().length > 0,
|
|
64
|
+
parameters: classDecl.getTypeParameters().map((p) => p.getName())
|
|
65
|
+
};
|
|
66
|
+
// 分析继承信息
|
|
67
|
+
const inheritance: InheritanceInfo = this.analyzeInheritanceInfo(classDecl);
|
|
68
|
+
|
|
69
|
+
// 分析构造函数 - 传递继承信息
|
|
70
|
+
const constructorParams: ConstructorParam[] = this.analyzeConstructorParameters(classDecl, inheritance);
|
|
71
|
+
|
|
72
|
+
// 解析@Serializable注解的参数
|
|
73
|
+
const decorators: ClassDecorators = {
|
|
74
|
+
serializable: this.parseSerializableOptions(classDecl.getDecorator(DecoratorConstants.SERIALIZABLE)),
|
|
75
|
+
serialName: this.parseSerialNameOptions(classDecl.getDecorator(DecoratorConstants.SERIAL_NAME))
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// 分析自己的属性
|
|
79
|
+
const ownProperties = this.analyzeOwnProperties(classDecl, constructorParams, generics.parameters);
|
|
80
|
+
|
|
81
|
+
// 属性分类
|
|
82
|
+
const propertyClassification = this.classifyProperties(ownProperties, inheritance, generics.parameters);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
className,
|
|
86
|
+
sourceFilePath,
|
|
87
|
+
originalClass: classDecl,
|
|
88
|
+
generics,
|
|
89
|
+
inheritance,
|
|
90
|
+
decorators,
|
|
91
|
+
ownProperties,
|
|
92
|
+
inheritedProperties: propertyClassification.inheritedProperties,
|
|
93
|
+
overriddenProperties: propertyClassification.overriddenProperties,
|
|
94
|
+
properties: propertyClassification.properties,
|
|
95
|
+
constructorParams
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 分析接口的完整结构,包括属性、继承关系等信息
|
|
101
|
+
* @param interfaceDecl 接口声明节点
|
|
102
|
+
* @returns 接口分析结果
|
|
103
|
+
*/
|
|
104
|
+
public static analyzeInterface(interfaceDecl: InterfaceDeclaration): InterfaceAnalysis {
|
|
105
|
+
const interfaceName = interfaceDecl.getName();
|
|
106
|
+
if (!interfaceName) {
|
|
107
|
+
throw new CustomError(`Interface name is undefined in ${interfaceDecl.getSourceFile().getFilePath()}`, ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
|
|
108
|
+
}
|
|
109
|
+
const sourceFilePath = interfaceDecl.getSourceFile().getFilePath();
|
|
110
|
+
const generics: GenericInfo = {
|
|
111
|
+
isGeneric: interfaceDecl.getTypeParameters().length > 0,
|
|
112
|
+
parameters: interfaceDecl.getTypeParameters().map((p) => p.getName())
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// 分析继承信息 - 接口不需要分析继承信息
|
|
116
|
+
const inheritance: InheritanceInfo = this.analyzeInheritanceInfo(interfaceDecl);
|
|
117
|
+
|
|
118
|
+
// 分析自己的属性
|
|
119
|
+
const ownProperties = this.analyzeOwnProperties(interfaceDecl, [], generics.parameters);
|
|
120
|
+
|
|
121
|
+
// 属性分类
|
|
122
|
+
const propertyClassification = this.classifyProperties(ownProperties, inheritance, generics.parameters);
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
className: interfaceName,
|
|
126
|
+
sourceFilePath,
|
|
127
|
+
originalInterface: interfaceDecl,
|
|
128
|
+
generics,
|
|
129
|
+
inheritance,
|
|
130
|
+
ownProperties,
|
|
131
|
+
inheritedProperties: propertyClassification.inheritedProperties,
|
|
132
|
+
overriddenProperties: propertyClassification.overriddenProperties,
|
|
133
|
+
properties: propertyClassification.properties,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 分析类的继承信息
|
|
139
|
+
* @param cls 类声明
|
|
140
|
+
* @returns 继承信息对象
|
|
141
|
+
*/
|
|
142
|
+
private static analyzeInheritanceInfo(cls: ClassDeclaration | InterfaceDeclaration): InheritanceInfo {
|
|
143
|
+
const heritageClaus = cls.getHeritageClauses();
|
|
144
|
+
Logger.debug(`分析类的继承信息: ${cls.getName()} ${heritageClaus.length} ${heritageClaus.map(c => c.getText()).join(',')}`);
|
|
145
|
+
for (const clause of heritageClaus) {
|
|
146
|
+
const token = clause.getToken();
|
|
147
|
+
// 接口实现
|
|
148
|
+
if (token !== SyntaxKind.ExtendsKeyword) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const typeNode = clause.getTypeNodes()[0]; // 继承关系只能继承一个类或者接口
|
|
152
|
+
|
|
153
|
+
const className = typeNode.getExpression().getText();
|
|
154
|
+
const args = typeNode.getTypeArguments();
|
|
155
|
+
Logger.debug(`继承信息: text: ${className} getTypeArguments: ${args.map(type => type.getText()).join(', ')}`);
|
|
156
|
+
const classDecl = CustomTypeAnalyzer.getInstance().findClassDeclFromClassName(className, cls.getSourceFile());
|
|
157
|
+
if (!classDecl) {
|
|
158
|
+
throw new CustomError(`class ${className} decl does not exist ${cls.getName} implement ${className}`, ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
|
|
159
|
+
}
|
|
160
|
+
if (classDecl instanceof InterfaceDeclaration) {
|
|
161
|
+
const baseClassAnalysis = this.analyzeInterface(classDecl);
|
|
162
|
+
return {
|
|
163
|
+
isInherited: true,
|
|
164
|
+
baseClassAnalysis,
|
|
165
|
+
genericTypeArguments: args
|
|
166
|
+
};
|
|
167
|
+
} else {
|
|
168
|
+
const baseClassAnalysis = this.analyzeClass(classDecl);
|
|
169
|
+
return {
|
|
170
|
+
isInherited: true,
|
|
171
|
+
baseClassAnalysis,
|
|
172
|
+
genericTypeArguments: args
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
return { isInherited: false };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 分析类的构造函数参数
|
|
182
|
+
* @param classDecl 类声明
|
|
183
|
+
* @param inheritanceInfo 继承信息
|
|
184
|
+
* @returns 构造函数参数数组
|
|
185
|
+
*/
|
|
186
|
+
private static analyzeConstructorParameters(
|
|
187
|
+
classDecl: ClassDeclaration,
|
|
188
|
+
inheritanceInfo?: InheritanceInfo
|
|
189
|
+
): ConstructorParam[] {
|
|
190
|
+
// 1. 首先检查当前类是否有显式构造函数
|
|
191
|
+
const constructors = classDecl.getConstructors();
|
|
192
|
+
|
|
193
|
+
if (constructors.length > 0) {
|
|
194
|
+
// 当前类有显式构造函数,直接分析
|
|
195
|
+
return this.extractConstructorParams(constructors[0]);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 2. 当前类没有显式构造函数,查找继承链
|
|
199
|
+
if (inheritanceInfo && inheritanceInfo.isInherited) {
|
|
200
|
+
const baseClassAnalysis = inheritanceInfo.baseClassAnalysis as ClassAnalysis;
|
|
201
|
+
// 递归查找父类的构造函数
|
|
202
|
+
return this.analyzeConstructorParameters(
|
|
203
|
+
baseClassAnalysis.originalClass!,
|
|
204
|
+
baseClassAnalysis.inheritance
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 3. 整个继承链都没有构造函数,返回空数组
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 解析@Serializable装饰器选项
|
|
214
|
+
* @param decorator 装饰器节点
|
|
215
|
+
* @returns 可序列化选项
|
|
216
|
+
*/
|
|
217
|
+
private static parseSerializableOptions(decorator?: Decorator): SerializableOptions | undefined {
|
|
218
|
+
if (!decorator) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
const args = decorator.getArguments();
|
|
222
|
+
let generateSendable: boolean | undefined;
|
|
223
|
+
let _with: string | undefined;
|
|
224
|
+
let deserializationMode: DeserializationMode | undefined;
|
|
225
|
+
|
|
226
|
+
const firstArg = args[0];
|
|
227
|
+
|
|
228
|
+
if (!firstArg) {
|
|
229
|
+
return {};
|
|
230
|
+
}
|
|
231
|
+
|
|
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
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return { with: _with, generateSendable, deserializationMode };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* 解析@SerialName装饰器选项
|
|
265
|
+
* @param decorator 装饰器节点
|
|
266
|
+
* @returns 序列化名称
|
|
267
|
+
*/
|
|
268
|
+
private static parseSerialNameOptions(decorator?: Decorator): string | undefined {
|
|
269
|
+
if (!decorator) {
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
const args = decorator.getArguments();
|
|
273
|
+
if (args.length === 0) {
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const firstArg = args[0];
|
|
278
|
+
|
|
279
|
+
// 处理对象形式:@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
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* 分析类自身的属性
|
|
304
|
+
* @param cls 类声明
|
|
305
|
+
* @param constructorParams 构造函数参数
|
|
306
|
+
* @param genericParameters 泛型参数
|
|
307
|
+
* @returns 属性分析数组
|
|
308
|
+
*/
|
|
309
|
+
private static analyzeOwnProperties(
|
|
310
|
+
cls: ClassDeclaration | InterfaceDeclaration,
|
|
311
|
+
constructorParams: ConstructorParam[],
|
|
312
|
+
genericParameters: string[]
|
|
313
|
+
): PropertyAnalysis[] {
|
|
314
|
+
const ownProperties: PropertyAnalysis[] = [];
|
|
315
|
+
const props = cls.getProperties();
|
|
316
|
+
for (const prop of props) {
|
|
317
|
+
const propertyAnalysis: PropertyAnalysis = this.createPropertyAnalysis(
|
|
318
|
+
prop,
|
|
319
|
+
constructorParams,
|
|
320
|
+
genericParameters
|
|
321
|
+
);
|
|
322
|
+
|
|
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 类型),生成阶段再筛选
|
|
352
|
+
ownProperties.push(propertyAnalysis);
|
|
353
|
+
}
|
|
354
|
+
return ownProperties;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 对属性进行分类,区分继承属性、重写属性和自有属性
|
|
359
|
+
* @param ownProperties 自有属性数组
|
|
360
|
+
* @param inheritance 继承信息
|
|
361
|
+
* @param currentClassGenericParams 当前类的泛型参数列表
|
|
362
|
+
* @returns 分类后的属性对象
|
|
363
|
+
*/
|
|
364
|
+
private static classifyProperties(
|
|
365
|
+
ownProperties: PropertyAnalysis[],
|
|
366
|
+
inheritance: InheritanceInfo,
|
|
367
|
+
currentClassGenericParams: string[] = []
|
|
368
|
+
): {
|
|
369
|
+
inheritedProperties: PropertyAnalysis[];
|
|
370
|
+
overriddenProperties: PropertyAnalysis[];
|
|
371
|
+
properties: PropertyAnalysis[];
|
|
372
|
+
} {
|
|
373
|
+
if (!inheritance.isInherited || !inheritance.baseClassAnalysis) {
|
|
374
|
+
// 没有继承,所有属性都是自有属性
|
|
375
|
+
return {
|
|
376
|
+
inheritedProperties: [],
|
|
377
|
+
overriddenProperties: [],
|
|
378
|
+
properties: [...ownProperties]
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// 递归收集所有祖先属性 - 传递泛型参数进行替换
|
|
383
|
+
const allAncestorProperties = this.collectAllAncestorProperties(
|
|
384
|
+
inheritance.baseClassAnalysis,
|
|
385
|
+
inheritance.genericTypeArguments || [], // 传递子类指定的泛型参数
|
|
386
|
+
currentClassGenericParams // 传递当前类的泛型参数列表
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
// 构建自有属性名称集合,用于快速查找重写
|
|
390
|
+
const ownPropertyNames = new Set(ownProperties.map((prop) => prop.name));
|
|
391
|
+
|
|
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
|
+
}
|
|
401
|
+
|
|
402
|
+
// 确定当前类中的重写属性
|
|
403
|
+
const overriddenProperties = ownProperties.filter((prop) =>
|
|
404
|
+
allAncestorProperties.some((ancestorProp) => ancestorProp.name === prop.name)
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
// 合并最终属性:继承的 + 当前类的(重写优先)
|
|
408
|
+
const properties = [...inheritedProperties, ...ownProperties];
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
inheritedProperties,
|
|
412
|
+
overriddenProperties,
|
|
413
|
+
properties
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* 递归收集所有祖先类的属性,并进行泛型替换
|
|
419
|
+
* @param classAnalysis 类分析结果
|
|
420
|
+
* @param childGenericArguments 子类泛型参数
|
|
421
|
+
* @param currentClassGenericParams 当前类的泛型参数列表
|
|
422
|
+
* @returns 所有祖先属性数组
|
|
423
|
+
*/
|
|
424
|
+
private static collectAllAncestorProperties(
|
|
425
|
+
classAnalysis: ClassAnalysis | InterfaceAnalysis,
|
|
426
|
+
childGenericArguments: TypeNode[] = [],
|
|
427
|
+
currentClassGenericParams: string[] = []
|
|
428
|
+
): PropertyAnalysis[] {
|
|
429
|
+
const allProperties: PropertyAnalysis[] = [];
|
|
430
|
+
|
|
431
|
+
// 1. 构建泛型替换映射
|
|
432
|
+
const parentGenericParams = classAnalysis.generics.parameters || [];
|
|
433
|
+
const genericMapping = GenericTypeSubstitutionUtil.buildGenericMapping(parentGenericParams, childGenericArguments);
|
|
434
|
+
|
|
435
|
+
// 2. 对父类自有属性进行泛型替换
|
|
436
|
+
const substitutedProperties = classAnalysis.ownProperties.map((property) =>
|
|
437
|
+
GenericTypeSubstitutionUtil.substitutePropertyType(property, genericMapping, currentClassGenericParams)
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
allProperties.push(...substitutedProperties);
|
|
441
|
+
|
|
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
|
+
}
|
|
451
|
+
|
|
452
|
+
return allProperties;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* 提取构造函数参数信息
|
|
457
|
+
* @param constructor 构造函数声明
|
|
458
|
+
* @returns 构造函数参数数组
|
|
459
|
+
*/
|
|
460
|
+
private static extractConstructorParams(constructor: ConstructorDeclaration): ConstructorParam[] {
|
|
461
|
+
const parameters: ConstructorParam[] = [];
|
|
462
|
+
|
|
463
|
+
for (const param of constructor.getParameters()) {
|
|
464
|
+
parameters.push({
|
|
465
|
+
name: param.getName(),
|
|
466
|
+
type: param.getTypeNodeOrThrow().getText(),
|
|
467
|
+
isOptional: param.hasQuestionToken(),
|
|
468
|
+
defaultValue: param.hasInitializer() ? param.getInitializerOrThrow().getText() : undefined
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return parameters;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* 创建属性分析对象
|
|
477
|
+
* @param prop 属性声明
|
|
478
|
+
* @param constructorParams 构造函数参数
|
|
479
|
+
* @param genericParameters 泛型参数
|
|
480
|
+
* @returns 属性分析对象
|
|
481
|
+
*/
|
|
482
|
+
private static createPropertyAnalysis(
|
|
483
|
+
prop: PropertyDeclaration | PropertySignature,
|
|
484
|
+
constructorParams: ConstructorParam[],
|
|
485
|
+
genericParameters: string[]
|
|
486
|
+
): PropertyAnalysis {
|
|
487
|
+
const name = prop.getName();
|
|
488
|
+
let typeNode = prop.getTypeNode();
|
|
489
|
+
if (!typeNode) {
|
|
490
|
+
typeNode = this.analyzePropertyType(prop);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (!typeNode) {
|
|
494
|
+
throw new CustomError(`无法分析属性 '${name}' 的类型。请检查属性声明。`, ErrorCodes.TYPE_NOT_SUPPORT);
|
|
495
|
+
}
|
|
496
|
+
|
|
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;
|
|
510
|
+
|
|
511
|
+
let isMust: boolean;
|
|
512
|
+
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);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// @Transient 属性的构造函数参数验证
|
|
525
|
+
// 检查构造函数参数是否可选或有默认值
|
|
526
|
+
if (decorators?.isTransient && constructorParam && !isParamOptional) {
|
|
527
|
+
throw new CustomError(
|
|
528
|
+
`@Transient 属性 '${name}' 的构造函数参数必须是可选的或有默认值。\n` +
|
|
529
|
+
`因为 @Transient 属性不参与序列化,反序列化时无法从外部数据获取值。\n` +
|
|
530
|
+
`请修改构造函数参数为以下任一形式:\n` +
|
|
531
|
+
` 1. 可选参数: constructor(..., ${name}?: ${constructorParam.type})\n` +
|
|
532
|
+
` 2. 带默认值: constructor(..., ${name}: ${constructorParam.type} = defaultValue)`,
|
|
533
|
+
ErrorCodes.TRANSIENT_ATTR_OPTIONAL
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
name,
|
|
539
|
+
defaultValue,
|
|
540
|
+
decorators,
|
|
541
|
+
type,
|
|
542
|
+
isMust
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
private static analyzePropertyType(prop: PropertyDeclaration | PropertySignature): TypeNode | undefined {
|
|
547
|
+
const name = prop.getName();
|
|
548
|
+
let typeNode = prop.getTypeNode();
|
|
549
|
+
|
|
550
|
+
// 如果已经能获取到类型节点,则直接返回
|
|
551
|
+
if (typeNode) {
|
|
552
|
+
return typeNode;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
Logger.warn(`无法获取属性${name}的类型,使用typeChecker方式获取类型`);
|
|
556
|
+
let type = TsMorphUtil.getTypeChecker().getTypeAtLocation(prop);
|
|
557
|
+
let typeText = type.getText();
|
|
558
|
+
|
|
559
|
+
Logger.warn(`typeChecker方式获取类型: ${typeText} `);
|
|
560
|
+
|
|
561
|
+
// 处理 import('...').Type 格式
|
|
562
|
+
typeText = this.simplifyImportType(typeText);
|
|
563
|
+
|
|
564
|
+
// 如果类型是 any,尝试通过初始化器获取更具体的类型
|
|
565
|
+
if (typeText === 'any') {
|
|
566
|
+
const result = this.getTypeFromInitializer(prop, name);
|
|
567
|
+
if (result) {
|
|
568
|
+
return result;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// 如果仍然无法确定类型,则抛出异常
|
|
573
|
+
if (typeText === 'any') {
|
|
574
|
+
throw new CustomError(`无法获取属性${name}的类型,需要显示声明`, ErrorCodes.TYPE_NOT_SUPPORT);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
Logger.info(`使用typeChecker方式获取类型成功: ${typeText}`);
|
|
578
|
+
prop.setType(typeText);
|
|
579
|
+
return prop.getTypeNode();
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* 简化 import('...').Type 格式的类型名称
|
|
584
|
+
* @param typeText 完整的类型文本
|
|
585
|
+
* @returns 简化后的类型名称
|
|
586
|
+
*/
|
|
587
|
+
private static simplifyImportType(typeText: string): string {
|
|
588
|
+
// 匹配 import('...').Type 或 import("...").Type 模式
|
|
589
|
+
const importPattern = /import\s*\(\s*['"][^'"]*['"]\s*\)\.(.+)/;
|
|
590
|
+
const match = typeText.match(importPattern);
|
|
591
|
+
|
|
592
|
+
if (match) {
|
|
593
|
+
// 返回简化后的类型名称
|
|
594
|
+
return match[1];
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// 如果不是 import 形式,返回原类型名
|
|
598
|
+
return typeText;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
private static getTypeFromInitializer(prop: PropertyDeclaration | PropertySignature, propName: string): TypeNode | undefined {
|
|
602
|
+
const initializer = prop.getInitializer();
|
|
603
|
+
if (!initializer) {
|
|
604
|
+
return undefined;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
Logger.warn(`无法获取属性${propName}的类型,使用初始化器获取类型: ${initializer.getText()}`);
|
|
608
|
+
const initializerType = TsMorphUtil.getTypeChecker().getTypeAtLocation(initializer);
|
|
609
|
+
let typeText = initializerType.getText();
|
|
610
|
+
Logger.warn(`使用初始化器获取类型: ${typeText}`);
|
|
611
|
+
|
|
612
|
+
if (typeText !== 'any') {
|
|
613
|
+
prop.setType(typeText);
|
|
614
|
+
return prop.getTypeNode();
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
if (initializer.getKind() !== SyntaxKind.NewExpression) {
|
|
619
|
+
return undefined;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const newExpression = initializer as NewExpression;
|
|
623
|
+
const expression = newExpression.getExpression();
|
|
624
|
+
if (!expression) {
|
|
625
|
+
return undefined;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const exprText = expression.getText();
|
|
629
|
+
const supportedTypes = ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array', 'Object', 'ArrayList', 'HashMap', 'HashSet', 'LinkedList', 'Decimal', 'List'];
|
|
630
|
+
|
|
631
|
+
if (!supportedTypes.includes(exprText)) {
|
|
632
|
+
return undefined;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// 获取完整的类型参数信息
|
|
636
|
+
const typeArgs = newExpression.getTypeArguments();
|
|
637
|
+
if (typeArgs.length > 0) {
|
|
638
|
+
typeText = `${exprText}<${typeArgs.map(arg => arg.getText()).join(', ')}>`;
|
|
639
|
+
} else {
|
|
640
|
+
typeText = exprText;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
prop.setType(typeText);
|
|
644
|
+
return prop.getTypeNode();
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* 判断属性是否为可选属性
|
|
649
|
+
* @param node 属性声明节点
|
|
650
|
+
* @param defaultValue 默认值
|
|
651
|
+
* @param type 类型结构
|
|
652
|
+
* @returns 是否为可选属性
|
|
653
|
+
*/
|
|
654
|
+
private static isOptional(node: PropertyDeclaration | PropertySignature, defaultValue: string | undefined, type: TypeStructure): boolean {
|
|
655
|
+
// 1. 语法上带 ?(prop?: T, param?: T)
|
|
656
|
+
if (node.hasQuestionToken()) {
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// 2. 有默认值(不管是定义属性声明的还是构造函数形参中定义的)
|
|
661
|
+
if (defaultValue !== undefined) {
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// 3. 类型是undefined或者是 T | undefined
|
|
666
|
+
if (type.kind === PropertyKind.UNDEFINED || type.kind === PropertyKind.OPTIONAL) {
|
|
667
|
+
return true;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// 4. 联合类型判断
|
|
671
|
+
if (
|
|
672
|
+
type.kind === PropertyKind.UNION &&
|
|
673
|
+
type.unionDetails &&
|
|
674
|
+
type.unionDetails.some((member) => member.kind === PropertyKind.UNDEFINED)
|
|
675
|
+
) {
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* 分析属性的默认值
|
|
684
|
+
* @param prop 属性声明
|
|
685
|
+
* @param constructorParams 构造函数参数
|
|
686
|
+
* @returns 默认值字符串
|
|
687
|
+
*/
|
|
688
|
+
private static analyzeDefaultValue(
|
|
689
|
+
prop: PropertyDeclaration,
|
|
690
|
+
constructorParams: ConstructorParam[]
|
|
691
|
+
): string | undefined {
|
|
692
|
+
// 1. 优先构造函数默认值
|
|
693
|
+
const param = constructorParams.find((item) => item.name === prop.getName());
|
|
694
|
+
if (param && param.defaultValue) {
|
|
695
|
+
return param.defaultValue;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// 2. 声明的默认值
|
|
699
|
+
if (prop.hasInitializer()) {
|
|
700
|
+
return prop.getInitializerOrThrow().getText();
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
return undefined;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* 检查类型字符串是否包含undefined作为联合类型成员
|
|
708
|
+
* @param typeText 类型字符串
|
|
709
|
+
* @returns 是否包含undefined作为联合类型成员
|
|
710
|
+
*/
|
|
711
|
+
private static hasUndefinedInUnion(typeText: string): boolean {
|
|
712
|
+
// 移除所有空白字符
|
|
713
|
+
const normalized = typeText.replace(/\s/g, '');
|
|
714
|
+
|
|
715
|
+
// 如果类型字符串本身就是undefined
|
|
716
|
+
if (normalized === 'undefined') {
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// 分割联合类型,但要考虑泛型中的嵌套
|
|
721
|
+
const parts = this.splitUnionType(normalized);
|
|
722
|
+
|
|
723
|
+
// 检查是否有部分恰好是undefined
|
|
724
|
+
return parts.some(part => part === 'undefined');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* 分割联合类型,考虑泛型、数组、括号等嵌套结构
|
|
729
|
+
* @param typeText 标准化后的类型字符串(无空格)
|
|
730
|
+
* @returns 联合类型的各个部分
|
|
731
|
+
*/
|
|
732
|
+
private static splitUnionType(typeText: string): string[] {
|
|
733
|
+
const parts: string[] = [];
|
|
734
|
+
let current = '';
|
|
735
|
+
let depth = 0; // 跟踪<>、[]、()的嵌套深度
|
|
736
|
+
|
|
737
|
+
for (let i = 0; i < typeText.length; i++) {
|
|
738
|
+
const char = typeText[i];
|
|
739
|
+
|
|
740
|
+
if (char === '<' || char === '[' || char === '(') {
|
|
741
|
+
depth++;
|
|
742
|
+
current += char;
|
|
743
|
+
} else if (char === '>' || char === ']' || char === ')') {
|
|
744
|
+
depth--;
|
|
745
|
+
current += char;
|
|
746
|
+
} else if (char === '|' && depth === 0) {
|
|
747
|
+
// 只在顶层分割联合类型
|
|
748
|
+
if (current) {
|
|
749
|
+
parts.push(current);
|
|
750
|
+
current = '';
|
|
751
|
+
}
|
|
752
|
+
} else {
|
|
753
|
+
current += char;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if (current) {
|
|
758
|
+
parts.push(current);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return parts;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* 分析属性装饰器
|
|
766
|
+
* @param prop 属性声明
|
|
767
|
+
* @returns 属性装饰器对象
|
|
768
|
+
*/
|
|
769
|
+
private static analyzePropertyDecorators(prop: PropertyDeclaration): PropertyDecorators {
|
|
770
|
+
const decorators = prop.getDecorators();
|
|
771
|
+
let isRequired: boolean = false;
|
|
772
|
+
let isTransient: boolean = false;
|
|
773
|
+
let serialName: string | undefined;
|
|
774
|
+
let _with: string | undefined;
|
|
775
|
+
|
|
776
|
+
decorators.forEach((decorator) => {
|
|
777
|
+
const name = decorator.getName();
|
|
778
|
+
|
|
779
|
+
switch (name) {
|
|
780
|
+
case DecoratorConstants.SERIAL_NAME:
|
|
781
|
+
serialName = this.parseSerialNameOptions(decorator);
|
|
782
|
+
break;
|
|
783
|
+
case DecoratorConstants.REQUIRED:
|
|
784
|
+
isRequired = true;
|
|
785
|
+
break;
|
|
786
|
+
case DecoratorConstants.TRANSIENT:
|
|
787
|
+
isTransient = true;
|
|
788
|
+
break;
|
|
789
|
+
case DecoratorConstants.SERIALIZABLE:
|
|
790
|
+
_with = this.parseSerializableOptions(decorator)!.with;
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
|
|
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
|
+
}
|
|
816
|
+
|
|
817
|
+
return {
|
|
818
|
+
isRequired,
|
|
819
|
+
isTransient,
|
|
820
|
+
serialName,
|
|
821
|
+
with: _with
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
}
|