@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.
Files changed (195) hide show
  1. package/LICENSE +177 -0
  2. package/README.md +253 -0
  3. package/dist/core/Types.d.ts +196 -0
  4. package/dist/core/Types.js +47 -0
  5. package/dist/core/analyzers/ClassAnalyzer.d.ts +23 -0
  6. package/dist/core/analyzers/ClassAnalyzer.js +480 -0
  7. package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +21 -0
  8. package/dist/core/analyzers/CustomTypeAnalyzer.js +243 -0
  9. package/dist/core/analyzers/SendableMergeChecker.d.ts +9 -0
  10. package/dist/core/analyzers/SendableMergeChecker.js +100 -0
  11. package/dist/core/analyzers/SendableMergeabilityRegistry.d.ts +7 -0
  12. package/dist/core/analyzers/SendableMergeabilityRegistry.js +23 -0
  13. package/dist/core/constants/DecoratorConstants.d.ts +7 -0
  14. package/dist/core/constants/DecoratorConstants.js +13 -0
  15. package/dist/core/constants/PathConstants.d.ts +6 -0
  16. package/dist/core/constants/PathConstants.js +10 -0
  17. package/dist/core/constants/StringConstants.d.ts +83 -0
  18. package/dist/core/constants/StringConstants.js +87 -0
  19. package/dist/core/constants/index.d.ts +3 -0
  20. package/dist/core/constants/index.js +19 -0
  21. package/dist/core/handlers/BaseTypeHandler.d.ts +23 -0
  22. package/dist/core/handlers/BaseTypeHandler.js +57 -0
  23. package/dist/core/handlers/CustomClassHandler.d.ts +21 -0
  24. package/dist/core/handlers/CustomClassHandler.js +191 -0
  25. package/dist/core/handlers/DateHandler.d.ts +2 -0
  26. package/dist/core/handlers/DateHandler.js +60 -0
  27. package/dist/core/handlers/DecimalHandler.d.ts +2 -0
  28. package/dist/core/handlers/DecimalHandler.js +60 -0
  29. package/dist/core/handlers/EnumHandler.d.ts +2 -0
  30. package/dist/core/handlers/EnumHandler.js +89 -0
  31. package/dist/core/handlers/GenericContainerHandler.d.ts +2 -0
  32. package/dist/core/handlers/GenericContainerHandler.js +440 -0
  33. package/dist/core/handlers/GenericHandler.d.ts +18 -0
  34. package/dist/core/handlers/GenericHandler.js +92 -0
  35. package/dist/core/handlers/HandlerBootstrap.d.ts +2 -0
  36. package/dist/core/handlers/HandlerBootstrap.js +28 -0
  37. package/dist/core/handlers/ITypeHandler.d.ts +23 -0
  38. package/dist/core/handlers/ITypeHandler.js +8 -0
  39. package/dist/core/handlers/PrimitiveHandler.d.ts +2 -0
  40. package/dist/core/handlers/PrimitiveHandler.js +127 -0
  41. package/dist/core/handlers/TupleHandler.d.ts +2 -0
  42. package/dist/core/handlers/TupleHandler.js +98 -0
  43. package/dist/core/handlers/TypeHandlerRegistry.d.ts +20 -0
  44. package/dist/core/handlers/TypeHandlerRegistry.js +113 -0
  45. package/dist/core/handlers/UnionTypeHandler.d.ts +2 -0
  46. package/dist/core/handlers/UnionTypeHandler.js +263 -0
  47. package/dist/core/handlers/index.d.ts +2 -0
  48. package/dist/core/handlers/index.js +5 -0
  49. package/dist/core/import-rewrite/services/BuildProfileUpdater.d.ts +8 -0
  50. package/dist/core/import-rewrite/services/BuildProfileUpdater.js +92 -0
  51. package/dist/core/import-rewrite/services/ImportRewriteService.d.ts +9 -0
  52. package/dist/core/import-rewrite/services/ImportRewriteService.js +61 -0
  53. package/dist/core/import-rewrite/services/ImportTransformService.d.ts +15 -0
  54. package/dist/core/import-rewrite/services/ImportTransformService.js +109 -0
  55. package/dist/core/import-rewrite/strategies/ImportScanStrategy.d.ts +17 -0
  56. package/dist/core/import-rewrite/strategies/ImportScanStrategy.js +137 -0
  57. package/dist/core/import-rewrite/types/ImportRewriteTypes.d.ts +17 -0
  58. package/dist/core/import-rewrite/types/ImportRewriteTypes.js +2 -0
  59. package/dist/core/index.d.ts +9 -0
  60. package/dist/core/index.js +27 -0
  61. package/dist/core/interfaces/ITask.d.ts +7 -0
  62. package/dist/core/interfaces/ITask.js +2 -0
  63. package/dist/core/interfaces/ITaskContext.d.ts +11 -0
  64. package/dist/core/interfaces/ITaskContext.js +2 -0
  65. package/dist/core/interfaces/index.d.ts +2 -0
  66. package/dist/core/interfaces/index.js +2 -0
  67. package/dist/core/logger/Logger.d.ts +13 -0
  68. package/dist/core/logger/Logger.js +78 -0
  69. package/dist/core/services/CodeAnalysisService.d.ts +7 -0
  70. package/dist/core/services/CodeAnalysisService.js +43 -0
  71. package/dist/core/services/CodeGenerationEngine.d.ts +12 -0
  72. package/dist/core/services/CodeGenerationEngine.js +102 -0
  73. package/dist/core/services/CodeGenerationService/CodeGenerationService.d.ts +13 -0
  74. package/dist/core/services/CodeGenerationService/CodeGenerationService.js +110 -0
  75. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +13 -0
  76. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +119 -0
  77. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +21 -0
  78. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +224 -0
  79. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +24 -0
  80. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +307 -0
  81. package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.d.ts +28 -0
  82. package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +259 -0
  83. package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.d.ts +19 -0
  84. package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +178 -0
  85. package/dist/core/services/CodeGenerationService/index.d.ts +1 -0
  86. package/dist/core/services/CodeGenerationService/index.js +5 -0
  87. package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +27 -0
  88. package/dist/core/services/CodeGenerationService/shared/ImportManager.js +127 -0
  89. package/dist/core/template/HandlebarsTemplateEngine.d.ts +26 -0
  90. package/dist/core/template/HandlebarsTemplateEngine.js +226 -0
  91. package/dist/core/utils/ConfigManager.d.ts +10 -0
  92. package/dist/core/utils/ConfigManager.js +32 -0
  93. package/dist/core/utils/CustomError.d.ts +30 -0
  94. package/dist/core/utils/CustomError.js +37 -0
  95. package/dist/core/utils/DeepCopyUtil.d.ts +15 -0
  96. package/dist/core/utils/DeepCopyUtil.js +138 -0
  97. package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +9 -0
  98. package/dist/core/utils/GenericTypeSubstitutionUtil.js +68 -0
  99. package/dist/core/utils/SerializationPathUtil.d.ts +18 -0
  100. package/dist/core/utils/SerializationPathUtil.js +107 -0
  101. package/dist/core/utils/TsMorphUtil.d.ts +8 -0
  102. package/dist/core/utils/TsMorphUtil.js +34 -0
  103. package/dist/index.d.ts +4 -0
  104. package/dist/index.js +57 -0
  105. package/dist/json-plugin/JSONExecuteController.d.ts +13 -0
  106. package/dist/json-plugin/JSONExecuteController.js +103 -0
  107. package/dist/json-plugin/constants/TaskConstants.d.ts +7 -0
  108. package/dist/json-plugin/constants/TaskConstants.js +11 -0
  109. package/dist/json-plugin/interfaces/IModuleContext.d.ts +10 -0
  110. package/dist/json-plugin/interfaces/IModuleContext.js +2 -0
  111. package/dist/json-plugin/interfaces/ITargetContext.d.ts +8 -0
  112. package/dist/json-plugin/interfaces/ITargetContext.js +2 -0
  113. package/dist/json-plugin/interfaces/impl/ModuleContext.d.ts +12 -0
  114. package/dist/json-plugin/interfaces/impl/ModuleContext.js +24 -0
  115. package/dist/json-plugin/interfaces/impl/TargetContext.d.ts +23 -0
  116. package/dist/json-plugin/interfaces/impl/TargetContext.js +113 -0
  117. package/dist/json-plugin/tasks/BaseTask.d.ts +14 -0
  118. package/dist/json-plugin/tasks/BaseTask.js +53 -0
  119. package/dist/json-plugin/tasks/CleanTask.d.ts +8 -0
  120. package/dist/json-plugin/tasks/CleanTask.js +25 -0
  121. package/dist/json-plugin/tasks/CodeProcessingTask.d.ts +8 -0
  122. package/dist/json-plugin/tasks/CodeProcessingTask.js +26 -0
  123. package/dist/json-plugin/tasks/SyncTask.d.ts +8 -0
  124. package/dist/json-plugin/tasks/SyncTask.js +21 -0
  125. package/dist/json-plugin/tasks/WatchTask.d.ts +11 -0
  126. package/dist/json-plugin/tasks/WatchTask.js +102 -0
  127. package/package.json +46 -0
  128. package/src/core/Types.ts +356 -0
  129. package/src/core/analyzers/ClassAnalyzer.ts +824 -0
  130. package/src/core/analyzers/CustomTypeAnalyzer.ts +337 -0
  131. package/src/core/analyzers/SendableMergeChecker.ts +195 -0
  132. package/src/core/analyzers/SendableMergeabilityRegistry.ts +72 -0
  133. package/src/core/constants/DecoratorConstants.ts +27 -0
  134. package/src/core/constants/PathConstants.ts +31 -0
  135. package/src/core/constants/StringConstants.ts +152 -0
  136. package/src/core/constants/index.ts +21 -0
  137. package/src/core/handlers/BaseTypeHandler.ts +121 -0
  138. package/src/core/handlers/CustomClassHandler.ts +278 -0
  139. package/src/core/handlers/DateHandler.ts +75 -0
  140. package/src/core/handlers/DecimalHandler.ts +75 -0
  141. package/src/core/handlers/EnumHandler.ts +142 -0
  142. package/src/core/handlers/GenericContainerHandler.ts +621 -0
  143. package/src/core/handlers/GenericHandler.ts +130 -0
  144. package/src/core/handlers/HandlerBootstrap.ts +64 -0
  145. package/src/core/handlers/ITypeHandler.ts +133 -0
  146. package/src/core/handlers/PrimitiveHandler.ts +159 -0
  147. package/src/core/handlers/TupleHandler.ts +145 -0
  148. package/src/core/handlers/TypeHandlerRegistry.ts +236 -0
  149. package/src/core/handlers/UnionTypeHandler.ts +400 -0
  150. package/src/core/handlers/index.ts +18 -0
  151. package/src/core/import-rewrite/services/BuildProfileUpdater.ts +145 -0
  152. package/src/core/import-rewrite/services/ImportRewriteService.ts +129 -0
  153. package/src/core/import-rewrite/services/ImportTransformService.ts +200 -0
  154. package/src/core/import-rewrite/strategies/ImportScanStrategy.ts +303 -0
  155. package/src/core/import-rewrite/types/ImportRewriteTypes.ts +100 -0
  156. package/src/core/index.ts +31 -0
  157. package/src/core/interfaces/ITask.ts +23 -0
  158. package/src/core/interfaces/ITaskContext.ts +94 -0
  159. package/src/core/interfaces/index.ts +17 -0
  160. package/src/core/logger/Logger.ts +149 -0
  161. package/src/core/services/CodeAnalysisService.ts +67 -0
  162. package/src/core/services/CodeGenerationEngine.ts +181 -0
  163. package/src/core/services/CodeGenerationService/CodeGenerationService.ts +159 -0
  164. package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +189 -0
  165. package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +314 -0
  166. package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +421 -0
  167. package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +392 -0
  168. package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +277 -0
  169. package/src/core/services/CodeGenerationService/index.ts +16 -0
  170. package/src/core/services/CodeGenerationService/shared/ImportManager.ts +191 -0
  171. package/src/core/template/HandlebarsTemplateEngine.ts +282 -0
  172. package/src/core/utils/ConfigManager.ts +49 -0
  173. package/src/core/utils/CustomError.ts +51 -0
  174. package/src/core/utils/DeepCopyUtil.ts +185 -0
  175. package/src/core/utils/GenericTypeSubstitutionUtil.ts +136 -0
  176. package/src/core/utils/SerializationPathUtil.ts +142 -0
  177. package/src/core/utils/TsMorphUtil.ts +50 -0
  178. package/src/index.ts +81 -0
  179. package/src/json-plugin/JSONExecuteController.ts +134 -0
  180. package/src/json-plugin/constants/TaskConstants.ts +22 -0
  181. package/src/json-plugin/interfaces/IModuleContext.ts +27 -0
  182. package/src/json-plugin/interfaces/ITargetContext.ts +25 -0
  183. package/src/json-plugin/interfaces/impl/ModuleContext.ts +45 -0
  184. package/src/json-plugin/interfaces/impl/TargetContext.ts +196 -0
  185. package/src/json-plugin/tasks/BaseTask.ts +94 -0
  186. package/src/json-plugin/tasks/CleanTask.ts +36 -0
  187. package/src/json-plugin/tasks/CodeProcessingTask.ts +41 -0
  188. package/src/json-plugin/tasks/SyncTask.ts +33 -0
  189. package/src/json-plugin/tasks/WatchTask.ts +99 -0
  190. package/template/SerializerPerformanceTemplate.hbs +35 -0
  191. package/template/SerializerRegisterTemplate.hbs +10 -0
  192. package/template/SerializerStrictTemplate.hbs +89 -0
  193. package/template/SerializerTemplate.hbs +176 -0
  194. package/tsconfig.json +17 -0
  195. package/tslint.json +3 -0
@@ -0,0 +1,392 @@
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 { SourceFile } from 'ts-morph';
17
+ import { ImportManager } from '../shared/ImportManager';
18
+ import {
19
+ ClassAnalysis,
20
+ ClassDetails,
21
+ DependencySource,
22
+ DeserializationMode,
23
+ GenerationContext,
24
+ InterfaceAnalysis,
25
+ InterfaceDetails,
26
+ ITaskContext,
27
+ Logger,
28
+ PropertyAnalysis,
29
+ PropertyGenerationInfo,
30
+ PropertyKind,
31
+ StringConstants,
32
+ TypeDependency,
33
+ TypeKind,
34
+ TypeStructure
35
+ } from '../../..';
36
+ import { HandlebarsTemplateEngine } from '../../../template/HandlebarsTemplateEngine';
37
+ import { ConfigManager } from '../../../utils/ConfigManager';
38
+ import { ClassAnalyzer } from '../../../analyzers/ClassAnalyzer';
39
+ import { TempSerializerGenerator } from './TempSerializerGenerator';
40
+ import { TypeHandlerRegistry } from '../../../handlers';
41
+ import SerializationPathUtil from '../../../utils/SerializationPathUtil';
42
+
43
+ export class SerializerGenerator {
44
+ private readonly importManager: ImportManager;
45
+ private readonly templateEngine: HandlebarsTemplateEngine;
46
+ private readonly registry = TypeHandlerRegistry.getInstance();
47
+
48
+ constructor(importManager: ImportManager) {
49
+ this.importManager = importManager;
50
+ this.templateEngine = new HandlebarsTemplateEngine();
51
+ }
52
+
53
+ generate(sourceFile: SourceFile, result: ClassAnalysis | InterfaceAnalysis, context: ITaskContext): GenerationContext | string {
54
+ // 检查是否使用自定义序列化器
55
+ if (result.decorators?.serializable?.with) {
56
+ sourceFile.addStatements(this.generateBuiltinSerializerRegistrationForSupplementary(context, result as ClassAnalysis));
57
+ // 使用自定义序列化器,仅生成注册语句
58
+ return this.generateCustomSerializerRegistration(sourceFile, result as ClassAnalysis);
59
+ }
60
+
61
+ // 1. 注册必要的导入
62
+ this.registerImports(result);
63
+
64
+ // 2. 使用模板引擎生成代码
65
+ const templateContext: GenerationContext = {
66
+ class: result,
67
+ properties: this.propertyAnalysisToPropertyGenerationInfo(result.properties),
68
+ serialNameConstant: this.generateSerialNameConstant(result, context)
69
+ };
70
+ const templateMode = result.decorators?.serializable?.deserializationMode
71
+ ? result.decorators.serializable?.deserializationMode
72
+ : ConfigManager.getInstance().getConfig().deserializationMode;
73
+
74
+ const generatedCode = this.templateEngine.render(templateMode, templateContext);
75
+
76
+ // 3. 将生成的代码添加到源文件
77
+ sourceFile.addStatements(generatedCode);
78
+
79
+ return templateContext;
80
+ }
81
+
82
+ /**
83
+ * 生成注册语句
84
+ * @param sourceFile
85
+ * @param content
86
+ */
87
+ generateRegistration(sourceFile: SourceFile, content: GenerationContext | string): void {
88
+ // 添加到源文件
89
+ if (typeof content === 'string') {
90
+ sourceFile.addStatements(content);
91
+ } else {
92
+ const generatedCode = this.templateEngine.renderRegister(content);
93
+ sourceFile.addStatements(generatedCode);
94
+ }
95
+ }
96
+
97
+ private registerImports(result: ClassAnalysis | InterfaceAnalysis): void {
98
+ Logger.debug('SerializerGenerator', 'registerImports', `注册导入: ${result.className}`);
99
+
100
+ // 收集所有需要的内置序列化器
101
+ const requiredBuiltinSerializers = this.getAllRequiredSerializers(result.properties);
102
+
103
+ // 基础导入 + 动态内置序列化器导入
104
+ this.importManager.registerCoreImports([
105
+ 'Serializer', 'SerialDescriptor', 'buildClassSerialDescriptor',
106
+ 'Encoder', 'Decoder', 'registerAutoGeneratedSerializerEntry', 'registerAutoGeneratedSerializerEntryProviderForSupplementary',
107
+ ...requiredBuiltinSerializers
108
+ ]);
109
+
110
+ this.registerDecoratorsImports(result);
111
+
112
+ const deserializationMode =
113
+ result.decorators?.serializable?.deserializationMode ||
114
+ ConfigManager.getInstance().getConfig().deserializationMode;
115
+
116
+ // PreciseTemplate 需要的额外导入
117
+ if (deserializationMode === DeserializationMode.STRICT) {
118
+ this.importManager.registerCoreImports([
119
+ 'SerializationError', 'SerializationErrorCodes',
120
+ 'TypeUtils', 'DecodedElementIndex', 'TurboTransLogger'
121
+ ]);
122
+ }
123
+
124
+ if (result.generics.isGeneric) {
125
+ this.importManager.registerCoreImports(['BaseSerializerFactory']);
126
+ }
127
+
128
+ this.registerPropertyImports(result);
129
+
130
+ this.registerInheritancePropertyImports(result);
131
+ }
132
+
133
+ private registerDecoratorsImports(result: ClassAnalysis | InterfaceAnalysis): void {
134
+ // 注册装饰器导入
135
+ result.ownProperties.forEach(property => {
136
+ if (property.decorators?.serialName) {
137
+ this.importManager.registerCoreImports(['SerialName']);
138
+ }
139
+ if (property.decorators?.isRequired) {
140
+ this.importManager.registerCoreImports(['Required']);
141
+ }
142
+ if (property.decorators?.isTransient) {
143
+ this.importManager.registerCoreImports(['Transient']);
144
+ }
145
+ });
146
+ }
147
+
148
+ private registerInheritancePropertyImports(result: ClassAnalysis | InterfaceAnalysis): void {
149
+ const baseClass = result.inheritance.baseClassAnalysis;
150
+ // 注册继承类导入
151
+ if (baseClass && baseClass.sourceFilePath !== result.sourceFilePath) {
152
+ // 导入继承的类
153
+ this.importManager.registerCustomTypeImport(baseClass.sourceFilePath, baseClass.className);
154
+
155
+ // 导入继承类中属性需要的导入
156
+ baseClass.ownProperties.forEach(property => {
157
+ this.execInheritancePropertyImports(property.type.dependencies);
158
+ });
159
+ }
160
+ }
161
+
162
+ private execInheritancePropertyImports(dependencies: TypeDependency[]): void {
163
+ dependencies.forEach((dependency: TypeDependency) => {
164
+ const source = dependency.source;
165
+ if (source.type === 'local') {
166
+ this.importManager.registerCustomTypeImport(source.sourceFilePath!, dependency.typeName);
167
+
168
+ const classDetails = dependency.details as ClassDetails;
169
+ const tempClassAnalysis = ClassAnalyzer.analyzeClass(classDetails.classDecl);
170
+
171
+ if (!tempClassAnalysis.decorators.serializable) {
172
+ TempSerializerGenerator.getInstance().generateSerializer(tempClassAnalysis);
173
+ }
174
+
175
+ const serializerName = classDetails.isGeneric ? StringConstants.SERIALIZER_FACTORY :
176
+ StringConstants.SERIALIZER;
177
+
178
+ if (tempClassAnalysis.decorators.serializable) {
179
+ this.importManager.registerCustomTypeImport(
180
+ source.sourceFilePath!,
181
+ `${dependency.typeName}${serializerName}`
182
+ );
183
+ }
184
+ }
185
+ });
186
+ }
187
+
188
+ private registerPropertyImports(result: ClassAnalysis | InterfaceAnalysis): void {
189
+ // 根据属性注册序列化器导入
190
+ for (const property of result.properties) {
191
+ if (property.decorators?.isTransient) {
192
+ continue;
193
+ }
194
+
195
+ if (property.decorators?.with) {
196
+ if (this.containsGenericType(property.type)) {
197
+ this.importManager.registerCoreImports(['WithEntrySerializer']);
198
+ } else {
199
+ this.importManager.registerCoreImports(['WithEntryContextualSerializer']);
200
+ }
201
+ }
202
+
203
+ // 注册属性相关的序列化器导入
204
+ this.execPropertyImports(property.type.dependencies);
205
+ }
206
+ }
207
+
208
+ private execPropertyImports(dependencies: TypeDependency[]): void {
209
+ dependencies.forEach((dependency: TypeDependency) => {
210
+ this.processDependency(dependency);
211
+ });
212
+ }
213
+
214
+ private processDependency(dependency: TypeDependency): void {
215
+ const source = dependency.source;
216
+
217
+ // 提前返回,减少嵌套
218
+ if (source.type !== 'imported' && source.type !== 'local') {
219
+ return;
220
+ }
221
+
222
+ if (source.type === 'imported') {
223
+ this.importManager.registerCustomTypeImport(source.sourceFilePath!, dependency.typeName);
224
+ }
225
+
226
+ // 根据类型种类分别处理
227
+ switch (dependency.typeKind) {
228
+ case TypeKind.CLASS:
229
+ this.processClassDependency(dependency, source);
230
+ break;
231
+
232
+ case TypeKind.INTERFACE:
233
+ this.processInterfaceDependency(dependency);
234
+ break;
235
+ }
236
+ }
237
+
238
+ private processClassDependency(dependency: TypeDependency, source: DependencySource): void {
239
+ const classDetails = dependency.details as ClassDetails;
240
+ const tempClassAnalysis = ClassAnalyzer.analyzeClass(classDetails.classDecl);
241
+
242
+ if (!tempClassAnalysis.decorators.serializable) {
243
+ TempSerializerGenerator.getInstance().generateSerializer(tempClassAnalysis);
244
+ }
245
+
246
+ const serializerName = classDetails.isGeneric ? StringConstants.SERIALIZER_FACTORY :
247
+ StringConstants.SERIALIZER;
248
+
249
+ if (tempClassAnalysis.decorators.serializable) {
250
+ this.handleSerializableClass(dependency, source, serializerName);
251
+ } else {
252
+ // 从 tempSerializer 目录(index.ets)导入
253
+ this.importManager.registerTempSerializerImport(`${dependency.typeName}${serializerName}`);
254
+ }
255
+ }
256
+
257
+ private handleSerializableClass(dependency: TypeDependency, source: DependencySource, serializerName: string): void {
258
+ if (source.type === 'imported') {
259
+ this.importManager.registerCustomTypeImport(
260
+ source.sourceFilePath!,
261
+ `${dependency.typeName}${serializerName}`
262
+ );
263
+ }
264
+ }
265
+
266
+ private processInterfaceDependency(dependency: TypeDependency): void {
267
+ const interfaceDetails = dependency.details as InterfaceDetails;
268
+ const tempClassAnalysis = ClassAnalyzer.analyzeInterface(interfaceDetails.interfaceDecl);
269
+ TempSerializerGenerator.getInstance().generateSerializer(tempClassAnalysis);
270
+
271
+ const serializerName = (dependency.details as ClassDetails).isGeneric ? StringConstants.SERIALIZER_FACTORY :
272
+ StringConstants.SERIALIZER;
273
+
274
+ // 从 tempSerializer 目录(index.ets)导入
275
+ this.importManager.registerTempSerializerImport(`${dependency.typeName}${serializerName}`);
276
+ }
277
+
278
+ private generateCustomSerializerRegistration(sourceFile: SourceFile, result: ClassAnalysis): string {
279
+ this.importManager.registerCoreImports(['registerAutoGeneratedSerializerEntry']);
280
+
281
+ const customSerializer = result.decorators.serializable!.with;
282
+ const registrationCode = `registerAutoGeneratedSerializerEntry(${result.className}, ${customSerializer});`;
283
+
284
+ return registrationCode;
285
+ }
286
+
287
+ private generateBuiltinSerializerRegistrationForSupplementary(context: ITaskContext, result: ClassAnalysis): string {
288
+ this.importManager.registerCoreImports(['registerAutoGeneratedSerializerEntryProviderForSupplementary']);
289
+ const serialNameConstant = this.generateSerialNameConstant(result, context);
290
+
291
+ const customSerializer = result.decorators.serializable!.with;
292
+ const registrationCode = `const ${result.className}_SERIAL_NAME = '${serialNameConstant}';\n
293
+ registerAutoGeneratedSerializerEntryProviderForSupplementary(${result.className}_SERIAL_NAME, () => [${result.className}, ${customSerializer}]);`;
294
+
295
+ return registrationCode;
296
+ }
297
+
298
+ private getAllRequiredSerializers(properties: PropertyAnalysis[]): string[] {
299
+ const requiredSerializers = new Set<string>();
300
+
301
+ properties.forEach(property => {
302
+ // 递归检查所有属性中需要的序列化器
303
+ const nestedSerializers = this.analyzeNestedSerializers(property.type);
304
+ nestedSerializers.forEach(serializer => requiredSerializers.add(serializer));
305
+ });
306
+
307
+ return Array.from(requiredSerializers);
308
+ }
309
+
310
+ private analyzeNestedSerializers(structure: TypeStructure): string[] {
311
+ const requiredSerializers = new Set<string>();
312
+
313
+ // 递归分析函数
314
+ const analyzeType = (type: TypeStructure): void => {
315
+ // 容错机制:跳过 UNKNOWN 类型
316
+ if (type.kind === PropertyKind.UNKNOWN) {
317
+ return;
318
+ }
319
+
320
+ if (type.kind === PropertyKind.GENERIC) {
321
+ return; // 跳过类和泛型,这俩没有内置序列化器
322
+ }
323
+ // 获取当前类型的序列化器名称
324
+ const handler = this.registry.getHandlerForKind(type.kind);
325
+ const metadata = handler.getSerializerMetadata(type);
326
+ Logger.debug(`Analyzing type ${type.sourceText}, metadata ${metadata.name}`);
327
+ if (type.kind !== PropertyKind.OBJECT) { // Object类型需要判断泛型类型对应序列化器
328
+ requiredSerializers.add(metadata.name);
329
+ }
330
+
331
+ // 递归分析泛型参数
332
+ if (type.args && type.args.length > 0) {
333
+ type.args.forEach(arg => analyzeType(arg));
334
+ }
335
+
336
+ // 递归分析联合类型成员
337
+ if (type.unionDetails && type.unionDetails.length > 0) {
338
+ type.unionDetails.forEach(member => analyzeType(member));
339
+ }
340
+ };
341
+
342
+ // 开始递归分析
343
+ analyzeType(structure);
344
+ return Array.from(requiredSerializers);
345
+ }
346
+
347
+ private containsGenericType(structure: TypeStructure): boolean {
348
+ // 检查当前节点是否为泛型
349
+ if (structure.kind === PropertyKind.GENERIC) {
350
+ return true;
351
+ }
352
+
353
+ // 递归检查泛型参数(如 Array<T>, Map<K,V>)
354
+ if (structure.args) {
355
+ return structure.args.some(arg => this.containsGenericType(arg));
356
+ }
357
+
358
+ // 递归检查联合类型的成员(如 T | string | number)
359
+ if (structure.unionDetails) {
360
+ return structure.unionDetails.some(member => this.containsGenericType(member));
361
+ }
362
+
363
+ return false;
364
+ }
365
+
366
+ private propertyAnalysisToPropertyGenerationInfo(properties: PropertyAnalysis[]): PropertyGenerationInfo[] {
367
+ return properties.filter((prop) => {
368
+ // 排除@Transient的属性
369
+ if (prop.decorators?.isTransient) {
370
+ return false;
371
+ }
372
+ // 容错机制:排除 UNKNOWN 类型(双保险,理论上分析阶段已强制要求有 @Transient)
373
+ if (prop.type.kind === PropertyKind.UNKNOWN) {
374
+ Logger.warn(`属性 ${prop.name} 类型为 UNKNOWN,已自动跳过序列化生成`);
375
+ return false;
376
+ }
377
+ return true;
378
+ }).map((prop) => {
379
+ const handler = this.registry.getHandlerForKind(prop.type.kind);
380
+ // ✅ 传递with参数给Handler,让Handler处理自定义序列化器
381
+ const serializer = handler.getSerializerMetadata(prop.type, prop.decorators?.with);
382
+ return { analysis: prop, serializer };
383
+ });
384
+ };
385
+
386
+ private generateSerialNameConstant(result: ClassAnalysis | InterfaceAnalysis, context: ITaskContext): string {
387
+ const relativePath = context.calculateSourceRootToModuleRoot(result.sourceFilePath);
388
+ const serialName = SerializationPathUtil.join(context.getPackageName(), relativePath, result.className + '.class')
389
+ .replaceAll(SerializationPathUtil.sep, '/');
390
+ return result.decorators?.serialName || serialName;
391
+ }
392
+ }
@@ -0,0 +1,277 @@
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 { SourceFile } from 'ts-morph';
17
+ import { ITaskContext, ClassAnalysis, StringConstants, InterfaceAnalysis } from '../../..';
18
+ import { ImportManager } from '../shared/ImportManager';
19
+ import { SerializerGenerator } from './SerializerGenerator';
20
+ import SerializationPathUtil from '../../../utils/SerializationPathUtil';
21
+ import { TsMorphUtil } from '../../../utils/TsMorphUtil';
22
+
23
+ /**
24
+ * 序列化器文件信息
25
+ */
26
+ interface SerializerFileInfo {
27
+ className: string; // 类名(如 "Person")
28
+ isGeneric: boolean;
29
+ sourceFile: SourceFile; // ts-morph SourceFile
30
+ importManager: ImportManager; // 独立的导入管理器
31
+ uniqueFileName: string; // 唯一文件名(如 "model_user_PersonSerializer.ets")
32
+ pathPrefix: string; // 路径前缀(如 "model_user")
33
+ }
34
+
35
+ export class TempSerializerGenerator {
36
+ private static INSTANCE: TempSerializerGenerator = new TempSerializerGenerator();
37
+ private readonly TEMP_SERIALIZER_DIR_NAME: string = 'tempSerializer';
38
+ private context: ITaskContext | null = null;
39
+ private serializerFiles: Map<string, SerializerFileInfo> = new Map();
40
+
41
+ private constructor() { }
42
+
43
+ static getInstance(): TempSerializerGenerator {
44
+ return this.INSTANCE;
45
+ }
46
+
47
+ init(context: ITaskContext): void {
48
+ this.context = context;
49
+ // 确保 tempSerializer 目录存在
50
+ const tempDir = this.getTempSerializerDir();
51
+ if (!SerializationPathUtil.exist(tempDir)) {
52
+ SerializationPathUtil.ensureDirSync(tempDir);
53
+ }
54
+
55
+ // 清空文件映射(支持多次调用init)
56
+ this.serializerFiles.clear();
57
+ }
58
+
59
+ getTempSerializerDir(): string {
60
+ return SerializationPathUtil.pathResolve(this.context!.getOutputRoot(), this.TEMP_SERIALIZER_DIR_NAME);
61
+ }
62
+
63
+ /**
64
+ * 生成单个类的序列化器文件
65
+ */
66
+ generateSerializer(classAnalysis: ClassAnalysis | InterfaceAnalysis): void {
67
+ const uniqueKey = this.getUniqueKey(classAnalysis);
68
+
69
+ // 检查是否已生成,避免重复
70
+ if (this.serializerFiles.has(uniqueKey)) {
71
+ return;
72
+ }
73
+
74
+ // 生成唯一文件名
75
+ const uniqueFileName = this.generateUniqueFileName(classAnalysis);
76
+ const filePath = SerializationPathUtil.pathResolve(this.getTempSerializerDir(), uniqueFileName);
77
+
78
+ // 创建独立的 SourceFile 和 ImportManager
79
+ const sourceFile = TsMorphUtil.getProject().createSourceFile(filePath, '', { overwrite: true });
80
+ const importManager = new ImportManager();
81
+ importManager.setContext(this.context!);
82
+
83
+ // 注册导入
84
+ this.registerImports(classAnalysis, importManager);
85
+
86
+ // 生成序列化器代码
87
+ const serializerGenerator = new SerializerGenerator(importManager);
88
+ const serializableGeneratorContext = serializerGenerator.generate(sourceFile, classAnalysis, this.context!);
89
+ serializerGenerator.generateRegistration(sourceFile, serializableGeneratorContext);
90
+
91
+ // 提取路径前缀用于别名生成
92
+ const pathPrefix = this.extractPathPrefix(classAnalysis.sourceFilePath);
93
+
94
+ // 保存文件信息
95
+ this.serializerFiles.set(uniqueKey, {
96
+ className: classAnalysis.className,
97
+ isGeneric: classAnalysis.generics.isGeneric,
98
+ sourceFile,
99
+ importManager,
100
+ uniqueFileName,
101
+ pathPrefix
102
+ });
103
+ }
104
+
105
+ private registerImports(classAnalysis: ClassAnalysis | InterfaceAnalysis, importManager: ImportManager) {
106
+ // 注册源文件导入
107
+ importManager.registerCustomTypeImport(classAnalysis.sourceFilePath, classAnalysis.className);
108
+ // 拷贝源文件导入
109
+ let sourceFile: SourceFile;
110
+ if ((classAnalysis as ClassAnalysis).originalClass) {
111
+ sourceFile = (classAnalysis as ClassAnalysis).originalClass!.getSourceFile();
112
+ } else {
113
+ sourceFile = (classAnalysis as InterfaceAnalysis).originalInterface!.getSourceFile();
114
+ }
115
+
116
+ sourceFile.getSourceFile().getImportDeclarations().forEach(importDecl => {
117
+ const specifier = importDecl.getModuleSpecifierValue();
118
+ const names = importDecl.getNamedImports().map((names) => names.getName());
119
+ const defaultImport = importDecl.getDefaultImport();
120
+ const originalDir = SerializationPathUtil.dirname(classAnalysis.sourceFilePath);
121
+
122
+ const importOriginAbs = SerializationPathUtil.pathResolve(originalDir, specifier);
123
+ if (SerializationPathUtil.exist(importOriginAbs + '.ets')) {
124
+ // 路径存在,使用模块化路径计算
125
+ const importOriginAbsWithExt = importOriginAbs + '.ets';
126
+ names.forEach((name) => {
127
+ importManager.registerCustomTypeImport(importOriginAbsWithExt, name);
128
+ });
129
+ if (defaultImport) {
130
+ importManager.registerDefaultImport(importOriginAbsWithExt, defaultImport.getText());
131
+ }
132
+ } else {
133
+ // 不存在该路径,说明可能为包名,暂时不动
134
+ names.forEach((name) => {
135
+ importManager.registerCustomImport(specifier, name);
136
+ });
137
+ if (defaultImport) {
138
+ importManager.registerDefaultImport(specifier, defaultImport.getText());
139
+ }
140
+ }
141
+ });
142
+ }
143
+
144
+ saveFile(): void {
145
+ // 1. 保存所有序列化器文件
146
+ for (const [_, fileInfo] of this.serializerFiles) {
147
+ // 添加导入语句
148
+ fileInfo.importManager.getImportDeclarations().forEach((importDeclaration) => {
149
+ fileInfo.sourceFile.addImportDeclaration({
150
+ moduleSpecifier: importDeclaration.specifier,
151
+ namedImports: [...new Set(importDeclaration.names)]
152
+ });
153
+ });
154
+ fileInfo.importManager.getDefaultImport().forEach((importDeclaration) => {
155
+ fileInfo.sourceFile.addImportDeclaration({
156
+ moduleSpecifier: importDeclaration.specifier,
157
+ defaultImport: importDeclaration.name
158
+ });
159
+ });
160
+ // 格式化代码
161
+ fileInfo.sourceFile.formatText();
162
+ // 保存文件
163
+ fileInfo.sourceFile.saveSync();
164
+ }
165
+
166
+ // 2. 生成 index.ets 统一导出文件
167
+ this.generateIndexFile();
168
+ }
169
+
170
+ private generateIndexFile(): void {
171
+ const indexFilePath = SerializationPathUtil.pathResolve(this.getTempSerializerDir(), 'index.ets');
172
+ const indexSourceFile = TsMorphUtil.getProject().createSourceFile(indexFilePath, '', { overwrite: true });
173
+
174
+ // 检测类名冲突
175
+ const classNameMap = new Map<string, SerializerFileInfo[]>();
176
+ for (const [_, fileInfo] of this.serializerFiles) {
177
+ const serializerName = `${fileInfo.className}${fileInfo.isGeneric ? StringConstants.SERIALIZER_FACTORY : StringConstants.SERIALIZER}`;
178
+ if (!classNameMap.has(serializerName)) {
179
+ classNameMap.set(serializerName, []);
180
+ }
181
+ classNameMap.get(serializerName)!.push(fileInfo);
182
+ }
183
+
184
+ // 生成导出语句
185
+ const exportStatements: string[] = [];
186
+ for (const [serializerName, fileInfos] of classNameMap) {
187
+ if (fileInfos.length === 1) {
188
+ // 无冲突:直接导出
189
+ const fileInfo = fileInfos[0];
190
+ const importPath = `./${fileInfo.uniqueFileName.replace('.ets', '')}`;
191
+ exportStatements.push(`export { ${serializerName} } from '${importPath}';`);
192
+ } else {
193
+ // 有冲突:使用别名导出
194
+ for (const fileInfo of fileInfos) {
195
+ const alias = this.generateExportAlias(fileInfo);
196
+ const importPath = `./${fileInfo.uniqueFileName.replace('.ets', '')}`;
197
+ exportStatements.push(`export { ${serializerName} as ${alias} } from '${importPath}';`);
198
+ }
199
+ }
200
+ }
201
+
202
+ // 添加导出语句到 index.ets
203
+ indexSourceFile.addStatements(exportStatements.join('\n'));
204
+ indexSourceFile.formatText();
205
+ indexSourceFile.saveSync();
206
+ }
207
+
208
+ /**
209
+ * 生成导出别名(用于冲突情况)
210
+ * 示例:model_user_PersonSerializer → ModelUserPersonSerializer
211
+ */
212
+ private generateExportAlias(fileInfo: SerializerFileInfo): string {
213
+ if (!fileInfo.pathPrefix) {
214
+ return `${fileInfo.className}${StringConstants.SERIALIZER}`;
215
+ }
216
+
217
+ // 将路径前缀转换为 PascalCase
218
+ const pascalPrefix = fileInfo.pathPrefix
219
+ .split('_')
220
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
221
+ .join('');
222
+
223
+ return `${pascalPrefix}${fileInfo.className}${StringConstants.SERIALIZER}`;
224
+ }
225
+
226
+ /**
227
+ * 生成唯一的序列化器文件名
228
+ * 示例:model/user/Person.ets → model_user_PersonSerializer.ets
229
+ */
230
+ private generateUniqueFileName(classAnalysis: ClassAnalysis | InterfaceAnalysis): string {
231
+ const prefix = this.extractPathPrefix(classAnalysis.sourceFilePath);
232
+
233
+ if (prefix) {
234
+ return `${prefix}_${classAnalysis.className}${StringConstants.SERIALIZER}.ets`;
235
+ } else {
236
+ return `${classAnalysis.className}${StringConstants.SERIALIZER}.ets`;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * 从源文件路径提取唯一前缀
242
+ * 使用 context.calculateSourceRootToModuleRoot() 计算相对路径
243
+ * @param sourceFilePath 源文件绝对路径
244
+ * @returns 相对路径的父目录名称(如 "model_user")
245
+ */
246
+ private extractPathPrefix(sourceFilePath: string): string {
247
+ // 使用 context 的方法计算相对路径(自动剔除 src/main 等前缀)
248
+ // 例如:E:\project\module\src\main\ets\model\user\Person.ets → ets/model/user/Person.ets
249
+ const relativePath = this.context!.calculateSourceRootToModuleRoot(sourceFilePath);
250
+
251
+ // 提取父目录路径(去掉文件名)
252
+ const dirPath = SerializationPathUtil.dirname(relativePath);
253
+
254
+ // 如果在根目录(例如 ets 或 .),返回空字符串
255
+ if (dirPath === '.' || dirPath === '' || dirPath === 'ets') {
256
+ return '';
257
+ }
258
+
259
+ // 去掉 ets/ 前缀(如果存在)
260
+ let cleanedDirPath = dirPath;
261
+ if (cleanedDirPath.startsWith('ets/') || cleanedDirPath.startsWith('ets\\')) {
262
+ cleanedDirPath = cleanedDirPath.substring(4); // 移除 "ets/" 或 "ets\"
263
+ }
264
+
265
+ // 如果清理后为空,返回空字符串
266
+ if (cleanedDirPath === '' || cleanedDirPath === '.') {
267
+ return '';
268
+ }
269
+
270
+ // 转换路径分隔符为下划线,仅保留字母数字和下划线
271
+ return cleanedDirPath.replace(/[\\/]/g, '_').replace(/[^a-zA-Z0-9_]/g, '_');
272
+ }
273
+
274
+ private getUniqueKey(classAnalysis: ClassAnalysis | InterfaceAnalysis): string {
275
+ return `${classAnalysis.sourceFilePath}#${classAnalysis.className}`;
276
+ }
277
+ }
@@ -0,0 +1,16 @@
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
+ export { CodeGenerationService } from './CodeGenerationService';