@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,149 @@
|
|
|
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 { HvigorLogger } from '@ohos/hvigor'
|
|
17
|
+
|
|
18
|
+
const PREFIX = '[TSerialization]'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* TSerialization 日志工具类
|
|
22
|
+
* 自动添加项目前缀和模块信息,简化日志输出
|
|
23
|
+
*/
|
|
24
|
+
export class Logger {
|
|
25
|
+
/** 当前模块上下文 */
|
|
26
|
+
private static currentModule: string = ''
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 设置当前模块上下文
|
|
30
|
+
* @param moduleName 模块名称
|
|
31
|
+
*/
|
|
32
|
+
static setModuleContext(moduleName: string): void {
|
|
33
|
+
this.currentModule = moduleName
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 清除当前模块上下文
|
|
38
|
+
*/
|
|
39
|
+
static clearModuleContext(): void {
|
|
40
|
+
this.currentModule = ''
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 获取当前模块上下文
|
|
45
|
+
*/
|
|
46
|
+
static getCurrentModule(): string {
|
|
47
|
+
return this.currentModule
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 格式化日志消息
|
|
52
|
+
* @param msg 原始消息
|
|
53
|
+
* @returns 格式化后的消息
|
|
54
|
+
*/
|
|
55
|
+
private static formatMessage(msg: string): string {
|
|
56
|
+
const modulePrefix = this.currentModule ? `[${this.currentModule}]` : ''
|
|
57
|
+
return `${PREFIX}${modulePrefix} ${msg}`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 输出错误日志
|
|
62
|
+
* @param msg 错误消息
|
|
63
|
+
* @param args 额外参数
|
|
64
|
+
*/
|
|
65
|
+
static error(msg: string, ...args: unknown[]): void {
|
|
66
|
+
const formattedMsg = this.formatMessage(msg)
|
|
67
|
+
if (args.length > 0) {
|
|
68
|
+
HvigorLogger.getLogger().error(formattedMsg, ...args)
|
|
69
|
+
} else {
|
|
70
|
+
HvigorLogger.getLogger().error(formattedMsg)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 输出信息日志
|
|
76
|
+
* @param msg 信息消息
|
|
77
|
+
* @param args 额外参数
|
|
78
|
+
*/
|
|
79
|
+
static info(msg: string, ...args: unknown[]): void {
|
|
80
|
+
const formattedMsg = this.formatMessage(msg)
|
|
81
|
+
if (args.length > 0) {
|
|
82
|
+
HvigorLogger.getLogger().info(formattedMsg, ...args)
|
|
83
|
+
} else {
|
|
84
|
+
HvigorLogger.getLogger().info(formattedMsg)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 输出警告日志
|
|
90
|
+
* @param msg 警告消息
|
|
91
|
+
* @param args 额外参数
|
|
92
|
+
*/
|
|
93
|
+
static warn(msg: string, ...args: unknown[]): void {
|
|
94
|
+
const formattedMsg = this.formatMessage(msg)
|
|
95
|
+
if (args.length > 0) {
|
|
96
|
+
HvigorLogger.getLogger().warn(formattedMsg, ...args)
|
|
97
|
+
} else {
|
|
98
|
+
HvigorLogger.getLogger().warn(formattedMsg)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 输出调试日志
|
|
104
|
+
* @param msg 调试消息
|
|
105
|
+
* @param args 额外参数
|
|
106
|
+
*/
|
|
107
|
+
static debug(msg: string, ...args: unknown[]): void {
|
|
108
|
+
const formattedMsg = this.formatMessage(msg)
|
|
109
|
+
if (args.length > 0) {
|
|
110
|
+
HvigorLogger.getLogger().debug(formattedMsg, ...args)
|
|
111
|
+
} else {
|
|
112
|
+
HvigorLogger.getLogger().debug(formattedMsg)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 在指定模块上下文中执行函数,执行完毕后自动清理上下文
|
|
118
|
+
* @param moduleName 模块名称
|
|
119
|
+
* @param fn 要执行的函数
|
|
120
|
+
* @returns 函数执行结果
|
|
121
|
+
*/
|
|
122
|
+
static withModuleContext<T>(moduleName: string, fn: () => T): T {
|
|
123
|
+
const previousModule = this.currentModule
|
|
124
|
+
try {
|
|
125
|
+
this.setModuleContext(moduleName)
|
|
126
|
+
return fn()
|
|
127
|
+
} finally {
|
|
128
|
+
// 恢复之前的模块上下文
|
|
129
|
+
this.currentModule = previousModule
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 在指定模块上下文中执行异步函数,执行完毕后自动清理上下文
|
|
135
|
+
* @param moduleName 模块名称
|
|
136
|
+
* @param fn 要执行的异步函数
|
|
137
|
+
* @returns Promise
|
|
138
|
+
*/
|
|
139
|
+
static async withModuleContextAsync<T>(moduleName: string, fn: () => Promise<T>): Promise<T> {
|
|
140
|
+
const previousModule = this.currentModule
|
|
141
|
+
try {
|
|
142
|
+
this.setModuleContext(moduleName)
|
|
143
|
+
return await fn()
|
|
144
|
+
} finally {
|
|
145
|
+
// 恢复之前的模块上下文
|
|
146
|
+
this.currentModule = previousModule
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
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 { ClassDeclaration, ModuleKind, Project, ScriptTarget } from 'ts-morph';
|
|
17
|
+
import { ClassAnalysis, DecoratorConstants, Logger } from '..';
|
|
18
|
+
import { ClassAnalyzer } from '../analyzers/ClassAnalyzer';
|
|
19
|
+
import { TsMorphUtil } from '../utils/TsMorphUtil';
|
|
20
|
+
|
|
21
|
+
export class CodeAnalysisService {
|
|
22
|
+
constructor() { }
|
|
23
|
+
|
|
24
|
+
analyzeFile(filePath: string): ClassAnalysis[] {
|
|
25
|
+
Logger.debug(`开始分析文件: ${filePath}`);
|
|
26
|
+
|
|
27
|
+
const sourceFile = TsMorphUtil.getProject().addSourceFileAtPath(filePath);
|
|
28
|
+
const classes = sourceFile.getClasses();
|
|
29
|
+
const results: ClassAnalysis[] = [];
|
|
30
|
+
|
|
31
|
+
for (const cls of classes) {
|
|
32
|
+
const classAnalysis = this.analyzeClass(cls);
|
|
33
|
+
if (classAnalysis) {
|
|
34
|
+
results.push(classAnalysis);
|
|
35
|
+
} else {
|
|
36
|
+
Logger.debug(`${cls.getName()}无@Serializable装饰器,跳过分析`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Logger.debug(`文件分析完成: ${filePath}, 发现 ${results.length} 个@Serializable类`);
|
|
41
|
+
|
|
42
|
+
return results;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private analyzeClass(cls: ClassDeclaration): ClassAnalysis | null {
|
|
46
|
+
const decorators = cls.getDecorators();
|
|
47
|
+
|
|
48
|
+
for (const decorator of decorators) {
|
|
49
|
+
if (decorator.getName() === DecoratorConstants.SERIALIZABLE) {
|
|
50
|
+
// 找到@Serializable装饰器,开始分析
|
|
51
|
+
return ClassAnalyzer.analyzeClass(cls);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 没有@Serializable装饰器,跳过
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
dispose(): void {
|
|
60
|
+
// 清理项目资源
|
|
61
|
+
const sourceFiles = TsMorphUtil.getProject().getSourceFiles();
|
|
62
|
+
Logger.info(`code analysis Clearing ${sourceFiles.length} source files...`);
|
|
63
|
+
sourceFiles.forEach((sourceFile) => {
|
|
64
|
+
TsMorphUtil.getProject().removeSourceFile(sourceFile);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
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 { ClassAnalysis, IGeneratedFile, IGenerationResult, Logger, ITaskContext, GeneratedFileInfo } from '..';
|
|
17
|
+
import { CodeAnalysisService } from './CodeAnalysisService';
|
|
18
|
+
import { CodeGenerationService } from './CodeGenerationService';
|
|
19
|
+
import { SendableMergeabilityRegistry } from '../analyzers/SendableMergeabilityRegistry';
|
|
20
|
+
import { SendableMergeChecker } from '../analyzers/SendableMergeChecker';
|
|
21
|
+
import { CustomTypeAnalyzer } from '../analyzers/CustomTypeAnalyzer';
|
|
22
|
+
|
|
23
|
+
export class CodeGenerationEngine {
|
|
24
|
+
private readonly analysisService: CodeAnalysisService
|
|
25
|
+
private readonly generationService: CodeGenerationService
|
|
26
|
+
|
|
27
|
+
// 保存分析结果供导入重写使用
|
|
28
|
+
private allClassAnalysis: ClassAnalysis[] = []
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
this.analysisService = new CodeAnalysisService()
|
|
32
|
+
this.generationService = new CodeGenerationService()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param scanFiles 待处理的源文件路径列表
|
|
37
|
+
* @param context 任务上下文
|
|
38
|
+
* @returns 生成结果详情
|
|
39
|
+
*/
|
|
40
|
+
processFilesUnified(scanFiles: string[], context: ITaskContext): IGenerationResult {
|
|
41
|
+
if (!scanFiles || scanFiles.length === 0) {
|
|
42
|
+
Logger.info('没有待处理的源文件')
|
|
43
|
+
return {
|
|
44
|
+
generatedFiles: [],
|
|
45
|
+
skippedFiles: []
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const generatedFiles: IGeneratedFile[] = []
|
|
50
|
+
const skippedFiles: string[] = []
|
|
51
|
+
|
|
52
|
+
// 重置分析结果和合并性注册表
|
|
53
|
+
this.allClassAnalysis = []
|
|
54
|
+
SendableMergeabilityRegistry.clear()
|
|
55
|
+
|
|
56
|
+
Logger.info(`开始处理 ${scanFiles.length} 个源文件`)
|
|
57
|
+
|
|
58
|
+
// ========== 阶段1:分析所有文件并检查合并性 ==========
|
|
59
|
+
Logger.debug(`[阶段1] 开始分析所有文件`)
|
|
60
|
+
const fileAnalysisMap = new Map<string, ClassAnalysis[]>()
|
|
61
|
+
|
|
62
|
+
// 步骤1.1:分析所有文件的基本信息
|
|
63
|
+
for (const filePath of scanFiles) {
|
|
64
|
+
const classAnalysis = this.analysisService.analyzeFile(filePath)
|
|
65
|
+
|
|
66
|
+
if (classAnalysis.length === 0) {
|
|
67
|
+
skippedFiles.push(filePath)
|
|
68
|
+
Logger.debug(`跳过文件(无@Serializable类): ${filePath}`)
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 保存分析结果
|
|
73
|
+
fileAnalysisMap.set(filePath, classAnalysis)
|
|
74
|
+
this.allClassAnalysis.push(...classAnalysis)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Logger.debug(`[阶段1.1] 完成基本分析,共 ${this.allClassAnalysis.length} 个类`)
|
|
78
|
+
|
|
79
|
+
// 步骤1.2:检查所有类的合并性并注册到全局注册表
|
|
80
|
+
Logger.debug(`[阶段1.2] 开始检查合并性并注册`)
|
|
81
|
+
for (const analysis of this.allClassAnalysis) {
|
|
82
|
+
// 仅对启用 generateSendable 的类检查合并性
|
|
83
|
+
if (analysis.decorators.serializable?.generateSendable) {
|
|
84
|
+
analysis.canMerge = SendableMergeChecker.check(analysis)
|
|
85
|
+
SendableMergeabilityRegistry.register(analysis.className, analysis.canMerge)
|
|
86
|
+
} else {
|
|
87
|
+
// 未启用 generateSendable 的类,注册为不可合并
|
|
88
|
+
SendableMergeabilityRegistry.register(analysis.className, false)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ========== 阶段2:生成所有文件 ==========
|
|
93
|
+
Logger.debug(`[阶段2] 开始生成所有文件`)
|
|
94
|
+
|
|
95
|
+
for (const [filePath, classAnalysis] of fileAnalysisMap.entries()) {
|
|
96
|
+
const generatedFile = this.generationService.generateForSourceFile(filePath, classAnalysis, context)
|
|
97
|
+
if (generatedFile) {
|
|
98
|
+
generatedFiles.push(generatedFile)
|
|
99
|
+
Logger.debug(`成功处理文件: ${filePath}`)
|
|
100
|
+
} else {
|
|
101
|
+
Logger.warn(`文件生成失败: ${filePath}`)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
Logger.info(`处理完成,成功 ${generatedFiles.length} 个,跳过 ${skippedFiles.length} 个`)
|
|
106
|
+
|
|
107
|
+
return { generatedFiles, skippedFiles }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param filePath 源文件路径
|
|
112
|
+
* @param context 任务上下文
|
|
113
|
+
* @returns 生成的文件信息,如果无需生成则返回null
|
|
114
|
+
*/
|
|
115
|
+
processFileUnified(filePath: string, context: ITaskContext): IGeneratedFile | null {
|
|
116
|
+
const classAnalysis = this.analysisService.analyzeFile(filePath)
|
|
117
|
+
|
|
118
|
+
// 如果没有@Serializable类,跳过生成
|
|
119
|
+
if (classAnalysis.length === 0) {
|
|
120
|
+
Logger.debug(`源文件 ${filePath} 无@Serializable类,跳过生成`)
|
|
121
|
+
return null
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 保存分析结果供导入重写使用
|
|
125
|
+
this.allClassAnalysis.push(...classAnalysis)
|
|
126
|
+
|
|
127
|
+
// 生成对应文件
|
|
128
|
+
return this.generationService.generateForSourceFile(filePath, classAnalysis, context)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 收集所有生成的文件信息
|
|
134
|
+
* 供导入重写功能使用
|
|
135
|
+
* @param context 任务上下文
|
|
136
|
+
* @returns 生成文件信息列表
|
|
137
|
+
*/
|
|
138
|
+
collectGeneratedFileInfos(context: ITaskContext): GeneratedFileInfo[] {
|
|
139
|
+
// 按源文件路径分组收集类名
|
|
140
|
+
const fileInfoMap = new Map<string, GeneratedFileInfo>();
|
|
141
|
+
|
|
142
|
+
for (const analysisResult of this.allClassAnalysis) {
|
|
143
|
+
const sourceFilePath = analysisResult.sourceFilePath;
|
|
144
|
+
|
|
145
|
+
if (!fileInfoMap.has(sourceFilePath)) {
|
|
146
|
+
// 为新文件创建 GeneratedFileInfo
|
|
147
|
+
const generatedFilePath = context.mapToOutputPath(sourceFilePath);
|
|
148
|
+
fileInfoMap.set(sourceFilePath, {
|
|
149
|
+
sourceFilePath,
|
|
150
|
+
generatedFilePath,
|
|
151
|
+
classNames: new Set<string>()
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 添加类名到对应文件的集合中
|
|
156
|
+
const fileInfo = fileInfoMap.get(sourceFilePath)!;
|
|
157
|
+
fileInfo.classNames.add(analysisResult.className);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return Array.from(fileInfoMap.values());
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 获取所有分析结果
|
|
165
|
+
* 供外部使用(如调试)
|
|
166
|
+
*/
|
|
167
|
+
getAllAnalysisResults(): ClassAnalysis[] {
|
|
168
|
+
return [...this.allClassAnalysis]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 清理资源
|
|
173
|
+
* 注意:这个方法应该在整个流程(包括导入重写)完成后调用
|
|
174
|
+
*/
|
|
175
|
+
cleanup(): void {
|
|
176
|
+
this.analysisService.dispose()
|
|
177
|
+
this.allClassAnalysis = []
|
|
178
|
+
CustomTypeAnalyzer.getInstance().clearCache()
|
|
179
|
+
SendableMergeabilityRegistry.clear()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
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 { IndentationText, Project, QuoteKind } from 'ts-morph';
|
|
17
|
+
import { OriginalClassGenerator } from './generators/OriginalClassGenerator';
|
|
18
|
+
import { SendableClassGenerator } from './generators/SendableClassGenerator';
|
|
19
|
+
import { SerializerGenerator } from './generators/SerializerGenerator';
|
|
20
|
+
import { ImportManager } from './shared/ImportManager';
|
|
21
|
+
import { ClassAnalysis, IGeneratedFile, Logger, ITaskContext, GenerationContext } from '../..';
|
|
22
|
+
import SerializationPathUtil from '../../utils/SerializationPathUtil';
|
|
23
|
+
import { CustomError, ErrorCodes } from '../../utils/CustomError';
|
|
24
|
+
import { TsMorphUtil } from '../../utils/TsMorphUtil';
|
|
25
|
+
|
|
26
|
+
export class CodeGenerationService {
|
|
27
|
+
private readonly importManger: ImportManager;
|
|
28
|
+
private readonly originalClassGenerator: OriginalClassGenerator;
|
|
29
|
+
private readonly serializerGenerator: SerializerGenerator;
|
|
30
|
+
private readonly sendableGenerator: SendableClassGenerator;
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
this.importManger = new ImportManager();
|
|
34
|
+
|
|
35
|
+
this.originalClassGenerator = new OriginalClassGenerator(this.importManger);
|
|
36
|
+
this.serializerGenerator = new SerializerGenerator(this.importManger);
|
|
37
|
+
this.sendableGenerator = new SendableClassGenerator();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
generateForSourceFile(sourcePath: string, results: ClassAnalysis[], context: ITaskContext): IGeneratedFile | null {
|
|
41
|
+
Logger.debug(`开始为 ${sourcePath} 文件生成代码: ${results.length} 个类`);
|
|
42
|
+
this.importManger.setContext(context);
|
|
43
|
+
// 1. 生成Sendable文件(sendableModel目录)- 包含Sendable类
|
|
44
|
+
this.generateSendableModelFiles(results, context);
|
|
45
|
+
// 2. 生成主文件(model目录)- 包含原始类、序列化器、toSendable方法
|
|
46
|
+
return this.generateMainModelFile(sourcePath, results, context);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private generateMainModelFile(
|
|
50
|
+
sourceFileAbs: string,
|
|
51
|
+
results: ClassAnalysis[],
|
|
52
|
+
context: ITaskContext
|
|
53
|
+
): IGeneratedFile | null {
|
|
54
|
+
const originalSourceFile = TsMorphUtil.getProject().addSourceFileAtPath(sourceFileAbs);
|
|
55
|
+
// 计算输出路径
|
|
56
|
+
const outputPath = context.mapToOutputPath(sourceFileAbs);
|
|
57
|
+
// 确保输出目录存在
|
|
58
|
+
context.ensureOutputDirectory(outputPath);
|
|
59
|
+
// 验证输出路径有效性
|
|
60
|
+
if (!context.isValidOutputPath(outputPath)) {
|
|
61
|
+
throw new CustomError(`输出路径无效: ${outputPath}`, ErrorCodes.INVALID_OUTPUT_FAIL);
|
|
62
|
+
}
|
|
63
|
+
// 创建输出文件
|
|
64
|
+
const outputSourceFile = TsMorphUtil.getProject().createSourceFile(outputPath, '', { overwrite: true });
|
|
65
|
+
|
|
66
|
+
const serializableGeneratorContext: (GenerationContext | string)[] = [];
|
|
67
|
+
for (const classAnalysis of results) {
|
|
68
|
+
serializableGeneratorContext.push(this.serializerGenerator.generate(outputSourceFile, classAnalysis, context));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 生成原始类结构
|
|
72
|
+
this.originalClassGenerator.generate(outputSourceFile, originalSourceFile, results, context);
|
|
73
|
+
|
|
74
|
+
for (const content of serializableGeneratorContext) {
|
|
75
|
+
this.serializerGenerator.generateRegistration(outputSourceFile, content);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 添加导入语句
|
|
79
|
+
this.importManger.getImportDeclarations().forEach((importDeclaration) => {
|
|
80
|
+
outputSourceFile.addImportDeclaration({
|
|
81
|
+
moduleSpecifier: importDeclaration.specifier,
|
|
82
|
+
namedImports: [...new Set(importDeclaration.names)]
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
this.importManger.getDefaultImport().forEach((importDeclaration) => {
|
|
86
|
+
outputSourceFile.addImportDeclaration({
|
|
87
|
+
moduleSpecifier: importDeclaration.specifier,
|
|
88
|
+
defaultImport: importDeclaration.name
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
// 格式化代码
|
|
92
|
+
outputSourceFile.formatText();
|
|
93
|
+
// 保存文件
|
|
94
|
+
outputSourceFile.saveSync();
|
|
95
|
+
// 返回生成结果
|
|
96
|
+
this.cleanup();
|
|
97
|
+
return {
|
|
98
|
+
sourcePath: sourceFileAbs,
|
|
99
|
+
outputPath,
|
|
100
|
+
contentLength: outputSourceFile.getFullText().length,
|
|
101
|
+
serializerCount: results.length,
|
|
102
|
+
generatedAt: Date.now()
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private generateSendableModelFiles(results: ClassAnalysis[], context: ITaskContext): void {
|
|
107
|
+
for (const classAnalysis of results) {
|
|
108
|
+
// 跳过可合并的类(它们已经在主文件中生成为Sendable类)
|
|
109
|
+
if (classAnalysis.canMerge) {
|
|
110
|
+
Logger.debug(`类 ${classAnalysis.className} 采用合并策略,跳过独立Sendable文件生成`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 双版本策略:生成独立的Sendable文件
|
|
115
|
+
if (this.sendableGenerator.canHandle(classAnalysis)) {
|
|
116
|
+
this.generateSendableFile(classAnalysis, context);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private generateSendableFile(result: ClassAnalysis, context: ITaskContext): void {
|
|
122
|
+
Logger.debug(`类 ${result.className} 采用独立Sendable文件生成`);
|
|
123
|
+
const sendableOutputPath = SerializationPathUtil.mapToSendableOutputPath(result.className, context);
|
|
124
|
+
context.ensureOutputDirectory(sendableOutputPath);
|
|
125
|
+
const sendableImportManager = new ImportManager();
|
|
126
|
+
sendableImportManager.setContext(context);
|
|
127
|
+
sendableImportManager.registerArkTSImports(['lang']);
|
|
128
|
+
const sendableSourceFile = TsMorphUtil.getProject().createSourceFile(sendableOutputPath, '', { overwrite: true });
|
|
129
|
+
this.sendableGenerator.generate(sendableSourceFile, result, sendableImportManager);
|
|
130
|
+
if (this.sendableGenerator.needsCollectionsImport(result)) {
|
|
131
|
+
this.importManger.registerArkTSImports(['collections']);
|
|
132
|
+
}
|
|
133
|
+
this.importManger.registerCustomTypeImport(sendableOutputPath, `Sendable${result.className}`);
|
|
134
|
+
sendableImportManager.getImportDeclarations().forEach((importDeclaration) => {
|
|
135
|
+
sendableSourceFile.addImportDeclaration({
|
|
136
|
+
moduleSpecifier: importDeclaration.specifier,
|
|
137
|
+
namedImports: [...new Set(importDeclaration.names)]
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
sendableImportManager.getDefaultImport().forEach((importDeclaration) => {
|
|
141
|
+
sendableSourceFile.addImportDeclaration({
|
|
142
|
+
moduleSpecifier: importDeclaration.specifier,
|
|
143
|
+
defaultImport: importDeclaration.name
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
sendableSourceFile.formatText();
|
|
147
|
+
sendableSourceFile.saveSync();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============= 验证和清理 =============
|
|
151
|
+
|
|
152
|
+
private cleanup(): void {
|
|
153
|
+
// 注意import是共享的,所以每个文件生成结束以后需要清空
|
|
154
|
+
this.importManger.clear();
|
|
155
|
+
|
|
156
|
+
// 清理项目缓存
|
|
157
|
+
// 注意:不要完全dispose project,因为它可能被重复使用
|
|
158
|
+
}
|
|
159
|
+
}
|