@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,236 @@
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 { TypeNode, SyntaxKind, InferTypeNode } from 'ts-morph';
17
+ import { ITypeHandler, TypeContext } from './ITypeHandler';
18
+ import { PropertyKind, TypeStructure, Logger } from '..';
19
+ import { CustomError, ErrorCodes } from '../utils/CustomError';
20
+
21
+ export class TypeHandlerRegistry {
22
+ private static instance: TypeHandlerRegistry;
23
+
24
+ /** 所有已注册的处理器(按注册顺序) */
25
+ private handlers: ITypeHandler[] = [];
26
+
27
+ /** Kind到Handler的快速查找表 */
28
+ private kindMap: Map<PropertyKind, ITypeHandler> = new Map();
29
+
30
+ /** 类型名称到Handler的快速查找表(支持多个候选) */
31
+ private nameMap: Map<string, ITypeHandler[]> = new Map();
32
+
33
+ private constructor() { }
34
+
35
+ /**
36
+ * 获取单例实例
37
+ */
38
+ static getInstance(): TypeHandlerRegistry {
39
+ if (!TypeHandlerRegistry.instance) {
40
+ TypeHandlerRegistry.instance = new TypeHandlerRegistry();
41
+ }
42
+ return TypeHandlerRegistry.instance;
43
+ }
44
+
45
+ // ==================== 注册管理 ====================
46
+
47
+ /**
48
+ * 注册类型处理器
49
+ * @param handler 类型处理器实例
50
+ */
51
+ register(handler: ITypeHandler): void {
52
+ // 添加到列表
53
+ this.handlers.push(handler);
54
+
55
+ // 按优先级排序(优先级高的在前)
56
+ this.handlers.sort((a, b) => b.priority - a.priority);
57
+
58
+ // 更新Kind映射(只保留最高优先级)
59
+ const existingHandler = this.kindMap.get(handler.kind);
60
+ if (!existingHandler || handler.priority > existingHandler.priority) {
61
+ this.kindMap.set(handler.kind, handler);
62
+ }
63
+
64
+ // 更新类型名称映射(支持多个候选)
65
+ const typeName = this.extractTypeName(handler.kind);
66
+ const candidates = this.nameMap.get(typeName) || [];
67
+ candidates.push(handler);
68
+ candidates.sort((a, b) => b.priority - a.priority);
69
+ this.nameMap.set(typeName, candidates);
70
+ }
71
+
72
+ /**
73
+ * 批量注册处理器
74
+ * @param handlers 处理器数组
75
+ */
76
+ registerAll(handlers: ITypeHandler[]): void {
77
+ handlers.forEach((handler) => this.register(handler));
78
+ }
79
+
80
+ // ==================== 处理器查找 ====================
81
+
82
+ /**
83
+ * 根据PropertyKind查找处理器
84
+ * @param kind PropertyKind
85
+ * @returns 对应的处理器,如果不存在返回undefined
86
+ */
87
+ getHandlerForKind(kind: PropertyKind): ITypeHandler {
88
+ const handler = this.kindMap.get(kind);
89
+ if (!handler) {
90
+ // 理论上走不到这里来
91
+ throw new CustomError(`No handler for kind: ${kind}`, ErrorCodes.HANDLER_NOT_FOUND);
92
+ }
93
+ return handler;
94
+ }
95
+
96
+ /**
97
+ * 根据类型节点查找匹配的处理器
98
+ * @param typeNode AST类型节点
99
+ * @param context 上下文
100
+ * @returns 匹配的处理器,如果没有匹配返回undefined
101
+ */
102
+ findHandler(typeNode: TypeNode, context: TypeContext): ITypeHandler | undefined {
103
+ const typeName = typeNode.getText();
104
+
105
+ // 策略1: 先尝试类型名称精确匹配
106
+ const candidates = this.nameMap.get(this.normalizeTypeName(typeName));
107
+ if (candidates && candidates.length > 0) {
108
+ for (const handler of candidates) {
109
+ if (handler.matches(typeNode, context)) {
110
+ return handler;
111
+ }
112
+ }
113
+ }
114
+
115
+ // 策略2: 遍历所有处理器(按优先级顺序)
116
+ for (const handler of this.handlers) {
117
+ if (handler.matches(typeNode, context)) {
118
+ return handler;
119
+ }
120
+ }
121
+
122
+ Logger.warn(`No handler found for type: ${typeName}`);
123
+ return undefined;
124
+ }
125
+
126
+ // ==================== 类型解析入口 ====================
127
+
128
+ /**
129
+ * 解析类型节点为类型结构
130
+ * @param typeNode AST类型节点
131
+ * @param context 类型上下文
132
+ * @returns 类型结构
133
+ */
134
+ parseType(typeNode: TypeNode, context: TypeContext): TypeStructure {
135
+
136
+ // 字面量类型检测:除了 null 和 undefined,其他字面量类型都不支持
137
+ if (typeNode.getKind() === SyntaxKind.LiteralType) {
138
+ const literal = typeNode.asKindOrThrow(SyntaxKind.LiteralType);
139
+ const literalValue = literal.getLiteral();
140
+ const literalKind = literalValue.getKind();
141
+
142
+ // 允许 null 和 undefined 字面量
143
+ if (literalKind !== SyntaxKind.NullKeyword && literalKind !== SyntaxKind.UndefinedKeyword) {
144
+ throw new CustomError(
145
+ `不支持字面量类型 '${typeNode.getText()}'(无论出现在何处)。\n` +
146
+ `不支持的字面量类型包括:字符串字面量(如 'admin')、数字字面量(如 123)、布尔字面量(如 true)。\n` +
147
+ `即使在联合类型、Type 别名、泛型参数中使用字面量也不支持。\n` +
148
+ `请使用基础类型:string、number、boolean 替代字面量类型。`,
149
+ ErrorCodes.LITERAL_NOT_SOPPORT);
150
+ }
151
+ }
152
+
153
+ // 处理 ParenthesizedType (括号类型)例如 (string|number)
154
+ if (typeNode.getKind() === SyntaxKind.ParenthesizedType) {
155
+ // 对于括号类型,我们解析其内部的类型
156
+ const parenthesizedType = typeNode.asKindOrThrow(SyntaxKind.ParenthesizedType);
157
+ const innerTypeNode = parenthesizedType.getTypeNode();
158
+
159
+ // 递归解析括号内的类型
160
+ return this.parseType(innerTypeNode, context);
161
+ }
162
+
163
+ const handler = this.findHandler(typeNode, context);
164
+ if (!handler) {
165
+ // 容错机制:找不到处理器时返回 UNKNOWN 类型
166
+ // ClassAnalyzer 会检查是否有 @Transient 注解来决定如何处理
167
+ const typeName = typeNode.getText();
168
+ Logger.warn(`No handler found for type: ${typeName}, marking as UNKNOWN`);
169
+
170
+ return {
171
+ kind: PropertyKind.UNKNOWN,
172
+ depth: 0,
173
+ sourceText: typeName,
174
+ args: [],
175
+ dependencies: []
176
+ };
177
+ }
178
+
179
+ return handler.parse(typeNode, context);
180
+ }
181
+
182
+ // ==================== 代码生成入口 ====================
183
+
184
+ /**
185
+ * 生成序列化器实例化代码
186
+ * @param structure 类型结构
187
+ * @returns 实例化代码字符串
188
+ */
189
+ generateInstantiation(structure: TypeStructure): string {
190
+ const handler = this.getHandlerForKind(structure.kind);
191
+
192
+ return handler.generateInstantiation(structure);
193
+ }
194
+
195
+ generateTypeKey(structure: TypeStructure): string {
196
+ const handler = this.getHandlerForKind(structure.kind);
197
+
198
+ return handler.generateTypeKey(structure);
199
+ }
200
+
201
+ // ==================== 辅助方法 ====================
202
+
203
+ /**
204
+ * 从PropertyKind提取类型名称
205
+ * @param kind PropertyKind
206
+ * @returns 类型名称
207
+ * @example 'string' -> 'string', 'array' -> 'Array', 'collections.Array' -> 'Array'
208
+ */
209
+ private extractTypeName(kind: PropertyKind): string {
210
+ // 处理collections.*类型
211
+ if (kind.startsWith('collections.')) {
212
+ return kind.split('.')[1];
213
+ }
214
+
215
+ // 基础类型直接返回
216
+ return kind;
217
+ }
218
+
219
+ /**
220
+ * 规范化类型名称(用于查找)
221
+ * @param typeName 原始类型名称
222
+ * @returns 规范化后的名称
223
+ * @example 'Array<string>' -> 'Array', 'collections.Array<T>' -> 'Array'
224
+ */
225
+ private normalizeTypeName(typeName: string): string {
226
+ // 移除泛型参数
227
+ const withoutGenerics = typeName.split('<')[0].trim();
228
+
229
+ // 处理collections.*
230
+ if (withoutGenerics.startsWith('collections.')) {
231
+ return withoutGenerics.split('.')[1];
232
+ }
233
+
234
+ return withoutGenerics;
235
+ }
236
+ }
@@ -0,0 +1,400 @@
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 { TypeNode, SyntaxKind, UnionTypeNode } from 'ts-morph';
17
+ import { PropertyKind, TypeStructure, SerializerMetadata, TypeDependency } from '../Types';
18
+ import { ITypeHandler, TypeContext, ConversionDirection } from './ITypeHandler';
19
+ import { BaseTypeHandler } from './BaseTypeHandler';
20
+ import { CustomError, ErrorCodes } from '../utils/CustomError';
21
+
22
+ type UnionPattern = 'optional' | 'nullable' | 'union' | 'optionalNullable';
23
+
24
+ abstract class UnionTypeHandler extends BaseTypeHandler implements ITypeHandler {
25
+ abstract readonly name: string;
26
+ abstract readonly kind: PropertyKind;
27
+ abstract readonly priority: number;
28
+
29
+ /**
30
+ * 子类指定支持的联合类型模式
31
+ */
32
+ protected abstract readonly supportedPattern: UnionPattern;
33
+
34
+ // ==================== 阶段1: 类型识别 ====================
35
+
36
+ matches(typeNode: TypeNode): boolean {
37
+ // 必须是UnionType
38
+ if (typeNode.getKind() !== SyntaxKind.UnionType) {
39
+ return false;
40
+ }
41
+
42
+ const unionType = typeNode as UnionTypeNode;
43
+ const memberTypes = unionType.getTypeNodes();
44
+
45
+ // 辅助函数:检查是否为 null 类型节点
46
+ const isNullType = (t: TypeNode): boolean => {
47
+ return t.getKind() === SyntaxKind.LiteralType && t.getText() === 'null';
48
+ };
49
+
50
+ // 辅助函数:检查是否为 undefined 类型节点
51
+ const isUndefinedType = (t: TypeNode): boolean => {
52
+ return t.getKind() === SyntaxKind.UndefinedKeyword;
53
+ };
54
+
55
+ // 根据supportedPattern匹配不同的联合类型模式
56
+ switch (this.supportedPattern) {
57
+ case 'optional':
58
+ // T | undefined (必须是2个成员,其中一个是undefined,另一个不是null)
59
+ if (memberTypes.length !== 2) {
60
+ return false;
61
+ }
62
+ const hasUndefined = memberTypes.some(isUndefinedType);
63
+ const hasNull = memberTypes.some(isNullType);
64
+ // 确保有undefined,但另一个成员不是null
65
+ return hasUndefined && !hasNull;
66
+
67
+ case 'nullable':
68
+ // T | null (必须是2个成员,其中一个是null,另一个不是undefined)
69
+ if (memberTypes.length !== 2) {
70
+ return false;
71
+ }
72
+ const hasNullable = memberTypes.some(isNullType);
73
+ const hasUndefinedNullable = memberTypes.some(isUndefinedType);
74
+ // 确保有null,但另一个成员不是undefined
75
+ return hasNullable && !hasUndefinedNullable;
76
+
77
+ case 'optionalNullable':
78
+ // T | null | undefined (必须是3个成员,包含null和undefined,还有一个其他类型)
79
+ return memberTypes.length === 3 &&
80
+ memberTypes.some(isNullType) &&
81
+ memberTypes.some(isUndefinedType);
82
+
83
+ case 'union':
84
+ // 普通联合类型(其他所有联合类型)
85
+ return true;
86
+
87
+ default:
88
+ return false;
89
+ }
90
+ }
91
+
92
+ // ==================== 阶段2: 类型解析 ====================
93
+
94
+ parse(typeNode: TypeNode, context: TypeContext): TypeStructure {
95
+ const unionType = typeNode as UnionTypeNode;
96
+
97
+ // 统一解析所有成员类型
98
+ const members = this.parseUnionMembers(unionType, context);
99
+
100
+ // 收集所有依赖
101
+ const allDependencies: TypeDependency[] = [];
102
+ let maxDepth = 0;
103
+ members.forEach(member => {
104
+ allDependencies.push(...member.dependencies);
105
+ maxDepth = Math.max(maxDepth, member.depth);
106
+ });
107
+
108
+ return {
109
+ kind: this.kind,
110
+ depth: this.supportedPattern === 'union' ? 0 : maxDepth + 1,
111
+ sourceText: typeNode.getText(),
112
+ args: [],
113
+ dependencies: allDependencies,
114
+ unionDetails: members
115
+ };
116
+ }
117
+
118
+ // ==================== 阶段3: 序列化器配置 ====================
119
+
120
+ getSerializerMetadata(structure: TypeStructure, withParam?: string): SerializerMetadata {
121
+ const serializerName = this.getSerializerName();
122
+ const defaultInstantiation = this.generateInstantiation(structure);
123
+
124
+ return {
125
+ name: serializerName,
126
+ typeDeclaration: this.generateTypeDeclaration(structure),
127
+ instantiationTemplate: this.applyWithParam(withParam, defaultInstantiation, structure),
128
+ encodeMethod: 'encodeSerializableElement',
129
+ decodeMethod: 'deserialize',
130
+ decoderType: `${structure.sourceText} | undefined`,
131
+ needsTypeAssertion: false
132
+ };
133
+ }
134
+
135
+ // ==================== 阶段4: 代码生成 ====================
136
+
137
+ generateInstantiation(structure: TypeStructure): string {
138
+ if (!structure.unionDetails || structure.unionDetails.length === 0) {
139
+ throw new CustomError(`${this.name}: missing unionDetails`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
140
+ }
141
+
142
+ const serializerName = this.getSerializerName();
143
+
144
+ // 处理Optional/Nullable/OptionalNullable模式
145
+ if (this.isOptionalOrNullablePattern()) {
146
+ return this.generateOptionalNullableInstantiation(structure);
147
+ }
148
+
149
+ // Union: 所有成员类型
150
+ const primitiveTypes = ['undefined', 'null', 'boolean', 'number', 'string', 'bigint'];
151
+ const unionTypes = structure.unionDetails.map(member => {
152
+ return primitiveTypes.includes(member.sourceText)
153
+ ? `'${member.sourceText}'`
154
+ : member.sourceText;
155
+ }).join(', ');
156
+
157
+ const typeDeclaration = structure.unionDetails.map(member => member.sourceText).join(' | ');
158
+ return `new ${serializerName}<${typeDeclaration}>([${unionTypes}])`;
159
+ }
160
+
161
+ generateTypeDeclaration(structure: TypeStructure): string {
162
+ if (!structure.unionDetails || structure.unionDetails.length === 0) {
163
+ throw new CustomError(`${this.name}: missing unionDetails`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
164
+ }
165
+
166
+ const serializerName = this.getSerializerName();
167
+
168
+ // 处理Optional/Nullable/OptionalNullable模式
169
+ if (this.isOptionalOrNullablePattern()) {
170
+ const innerMember = this.getInnerMember(structure);
171
+ if (!innerMember) {
172
+ throw new CustomError(`${this.name}: cannot find inner member`, ErrorCodes.UNION_INNER_NOT_FOUND);
173
+ }
174
+
175
+ return `${serializerName}<${innerMember.sourceText}>`;
176
+ }
177
+
178
+ // Union: 所有成员类型
179
+ const typeDeclaration = structure.unionDetails.map(member => member.sourceText).join(' | ');
180
+ return `${serializerName}<${typeDeclaration}>`;
181
+ }
182
+
183
+ generateTypeKey(structure: TypeStructure): string {
184
+ if (!structure.unionDetails || structure.unionDetails.length === 0) {
185
+ throw new CustomError(`${this.name}: missing unionDetails`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
186
+ }
187
+
188
+ // 处理Optional/Nullable/OptionalNullable模式
189
+ if (this.isOptionalOrNullablePattern()) {
190
+ return this.generateOptionalNullableTypeKey(structure);
191
+ }
192
+
193
+ // Union: 所有成员typeKey的数组
194
+ const memberTypeKeys = structure.unionDetails.map(member => {
195
+ const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
196
+ const handler = TypeHandlerRegistry.getInstance().getHandlerForKind(member.kind);
197
+ return handler.generateTypeKey(member);
198
+ });
199
+
200
+ return `[${memberTypeKeys.join(', ')}]`;
201
+ }
202
+
203
+ // ==================== Protected 工具方法 ====================
204
+
205
+ /**
206
+ * 检查是否为Optional、Nullable或OptionalNullable模式
207
+ */
208
+ protected isOptionalOrNullablePattern(): boolean {
209
+ return this.supportedPattern === 'optional' ||
210
+ this.supportedPattern === 'nullable' ||
211
+ this.supportedPattern === 'optionalNullable';
212
+ }
213
+
214
+ /**
215
+ * 获取Optional/Nullable/OptionalNullable模式的内部成员类型
216
+ */
217
+ protected getInnerMember(structure: TypeStructure): TypeStructure | undefined {
218
+ switch (this.supportedPattern) {
219
+ case 'optional':
220
+ return structure.unionDetails?.find(m => m.kind !== PropertyKind.UNDEFINED);
221
+ case 'nullable':
222
+ return structure.unionDetails?.find(m => m.kind !== PropertyKind.NULL);
223
+ case 'optionalNullable':
224
+ return structure.unionDetails?.find(m =>
225
+ m.kind !== PropertyKind.NULL && m.kind !== PropertyKind.UNDEFINED
226
+ );
227
+ default:
228
+ return undefined;
229
+ }
230
+ }
231
+
232
+ /**
233
+ * 生成Optional/Nullable/OptionalNullable模式的实例化代码
234
+ */
235
+ protected generateOptionalNullableInstantiation(structure: TypeStructure): string {
236
+ if (this.supportedPattern === 'optionalNullable' && structure.unionDetails?.length !== 3) {
237
+ throw new CustomError(`${this.name}: expected 3 union members`, ErrorCodes.UNION_EXPEDTED_THREE);
238
+ }
239
+
240
+ if (this.supportedPattern !== 'optionalNullable' && structure.unionDetails?.length !== 2) {
241
+ throw new CustomError(`${this.name}: expected 2 union members`, ErrorCodes.UNION_EXPEDTED_TWO);
242
+ }
243
+
244
+ const innerMember = this.getInnerMember(structure);
245
+ if (!innerMember) {
246
+ throw new CustomError(`${this.name}: cannot find inner member`, ErrorCodes.UNION_INNER_NOT_FOUND);
247
+ }
248
+
249
+ const innerType = innerMember.sourceText;
250
+ const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
251
+ const innerHandler = TypeHandlerRegistry.getInstance().getHandlerForKind(innerMember.kind);
252
+
253
+ const innerSerializer = innerHandler.generateInstantiation(innerMember);
254
+ const serializerName = this.getSerializerName();
255
+ return `new ${serializerName}<${innerType}>(${innerSerializer})`;
256
+ }
257
+
258
+ /**
259
+ * 生成Optional/Nullable/OptionalNullable模式的类型键
260
+ */
261
+ protected generateOptionalNullableTypeKey(structure: TypeStructure): string {
262
+ const innerMember = this.getInnerMember(structure);
263
+ if (!innerMember) {
264
+ throw new CustomError(`${this.name}: cannot find inner member`, ErrorCodes.UNION_INNER_NOT_FOUND);
265
+ }
266
+
267
+ const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
268
+ const innerHandler = TypeHandlerRegistry.getInstance().getHandlerForKind(innerMember.kind);
269
+ const innerTypeKey = innerHandler.generateTypeKey(innerMember);
270
+
271
+ switch (this.supportedPattern) {
272
+ case 'optional':
273
+ return `[${innerTypeKey}, "'undefined'"]`;
274
+ case 'nullable':
275
+ return `[${innerTypeKey}, "'null'"]`;
276
+ case 'optionalNullable':
277
+ return `[${innerTypeKey}, "'null'", "'undefined'"]`;
278
+ default:
279
+ throw new CustomError(`${this.name}: unsupported pattern`, ErrorCodes.UNION_UNSUPPORTED_PATTERN);
280
+ }
281
+ }
282
+
283
+ /**
284
+ * 解析联合类型的所有成员
285
+ */
286
+ protected parseUnionMembers(typeNode: UnionTypeNode, context: TypeContext): TypeStructure[] {
287
+ const memberTypes = typeNode.getTypeNodes();
288
+ const members: TypeStructure[] = [];
289
+
290
+ for (const memberType of memberTypes) {
291
+ const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
292
+ const memberStructure = TypeHandlerRegistry.getInstance().parseType(memberType, {
293
+ ...context,
294
+ depth: context.depth + 1
295
+ });
296
+ members.push(memberStructure);
297
+ }
298
+
299
+ return members;
300
+ }
301
+
302
+ // ==================== Sendable转换 ====================
303
+
304
+ generateSendableTypeDeclaration(structure: TypeStructure): string {
305
+ if (!structure.unionDetails || structure.unionDetails.length === 0) {
306
+ throw new CustomError(`${this.name}: missing unionDetails for Sendable type declaration`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
307
+ }
308
+
309
+ // 递归获取TypeHandlerRegistry
310
+ const registry = require('./TypeHandlerRegistry').TypeHandlerRegistry.getInstance();
311
+
312
+ // 递归转换每个成员类型为Sendable类型
313
+ const sendableMemberTypes = structure.unionDetails.map(member => {
314
+ const handler = registry.getHandlerForKind(member.kind);
315
+ if (!handler) {
316
+ throw new CustomError(`${this.name}: no handler for member type: ${member.kind}`, ErrorCodes.HANDLER_NOT_FOUND);
317
+ }
318
+ return handler.generateSendableTypeDeclaration(member);
319
+ });
320
+
321
+ // 联合所有Sendable成员类型
322
+ return sendableMemberTypes.join(' | ');
323
+ }
324
+
325
+ generatePropertyConversion(structure: TypeStructure, sourceValue: string, direction: ConversionDirection): string {
326
+ // 联合类型的转换无法在编译时确定具体类型,直接传递
327
+ // 实际转换由运行时的具体类型决定
328
+ // 注意:这可能需要在运行时检查类型并调用相应的转换方法
329
+ return sourceValue;
330
+ }
331
+ }
332
+
333
+ class NullableHandler extends UnionTypeHandler {
334
+ readonly name = 'NullableHandler';
335
+ readonly kind = PropertyKind.NULLABLE;
336
+ readonly priority = 95; // 高于普通UnionHandler
337
+ protected readonly supportedPattern = 'nullable' as const;
338
+
339
+ protected getSerializerName(): string {
340
+ return 'NullableSerializer';
341
+ }
342
+ }
343
+
344
+ class OptionalHandler extends UnionTypeHandler {
345
+ readonly name = 'OptionalHandler';
346
+ readonly kind = PropertyKind.OPTIONAL;
347
+ readonly priority = 95; // 高于普通UnionHandler
348
+ protected readonly supportedPattern = 'optional' as const;
349
+
350
+ protected getSerializerName(): string {
351
+ return 'OptionalSerializer';
352
+ }
353
+ }
354
+
355
+ class OptionalNullableHandler extends UnionTypeHandler {
356
+ readonly name = 'OptionalNullableHandler';
357
+ readonly kind = PropertyKind.OPTIONAL_NULLABLE;
358
+ readonly priority = 95; // 高于普通UnionHandler
359
+ protected readonly supportedPattern = 'optionalNullable' as const;
360
+
361
+ protected getSerializerName(): string {
362
+ return 'OptionalNullableSerializer';
363
+ }
364
+ }
365
+
366
+ class UnionHandler extends UnionTypeHandler {
367
+ readonly name = 'UnionHandler';
368
+ readonly kind = PropertyKind.UNION;
369
+ readonly priority = 85; // 低于Optional和Nullable,作为fallback
370
+ protected readonly supportedPattern = 'union' as const;
371
+
372
+ protected getSerializerName(): string {
373
+ return 'UnionTypeSerializer';
374
+ }
375
+ }
376
+
377
+ /**
378
+ * 工厂函数:创建所有联合类型Handler
379
+ * @returns 4个联合类型Handler实例
380
+ *
381
+ * 优先级顺序(从高到低):
382
+ * 1. OptionalHandler (95) - T | undefined (T不为null)
383
+ * 2. NullableHandler (95) - T | null (T不为undefined)
384
+ * 3. OptionalNullableHandler (95) - T | null | undefined (T为其他类型)
385
+ * 4. UnionHandler (85) - 其他所有联合类型 (包括 null | undefined)
386
+ *
387
+ * 特殊情况说明:
388
+ * - `null | undefined` 会被 UnionHandler 处理,生成 UnionTypeSerializer<null | undefined>
389
+ * - `T | undefined` (T非null) 会被 OptionalHandler 处理,生成 OptionalSerializer<T>
390
+ * - `T | null` (T非undefined) 会被 NullableHandler 处理,生成 NullableSerializer<T>
391
+ * - `T | null | undefined` 会被 OptionalNullableHandler 处理,生成 OptionalNullableSerializer<T>
392
+ */
393
+ export function createUnionTypeHandlers(): ITypeHandler[] {
394
+ return [
395
+ new OptionalHandler(),
396
+ new NullableHandler(),
397
+ new OptionalNullableHandler(),
398
+ new UnionHandler()
399
+ ];
400
+ }
@@ -0,0 +1,18 @@
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 type { ITypeHandler, TypeContext } from './ITypeHandler';
17
+
18
+ export { TypeHandlerRegistry } from './TypeHandlerRegistry';