@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,145 @@
|
|
|
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 { ITaskContext, Logger } from '../..';
|
|
17
|
+
import { ITargetContext } from '../../../json-plugin/interfaces/ITargetContext';
|
|
18
|
+
import SerializationPathUtil from '../../utils/SerializationPathUtil';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* build-profile.json5 配置更新服务实现
|
|
22
|
+
*/
|
|
23
|
+
export class BuildProfileUpdaterImpl {
|
|
24
|
+
|
|
25
|
+
updateSourceRoots(targetContext: ITargetContext): void {
|
|
26
|
+
try {
|
|
27
|
+
// 获取模块根目录和 build-profile.json5 路径
|
|
28
|
+
const moduleRoot = this.getModuleRootFromContext(targetContext);
|
|
29
|
+
const buildProfilePath = SerializationPathUtil.join(moduleRoot, 'build-profile.json5');
|
|
30
|
+
|
|
31
|
+
Logger.debug(`准备更新 build-profile.json5: ${buildProfilePath}`);
|
|
32
|
+
|
|
33
|
+
if (!SerializationPathUtil.exist(buildProfilePath)) {
|
|
34
|
+
Logger.warn(`build-profile.json5 文件不存在: ${buildProfilePath}`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 读取现有配置
|
|
39
|
+
const config = targetContext.context.buildProfileOpt;
|
|
40
|
+
Logger.debug(`当前配置: ${JSON.stringify(config, null, 2)}`);
|
|
41
|
+
|
|
42
|
+
// 更新 sourceRoots 配置
|
|
43
|
+
const updated = this.updateSourceRootsConfig(config);
|
|
44
|
+
|
|
45
|
+
if (updated) {
|
|
46
|
+
// 写回配置文件
|
|
47
|
+
this.writeBuildProfile(targetContext, buildProfilePath, config);
|
|
48
|
+
Logger.info(`已更新 build-profile.json5 的 sourceRoots 配置: ${buildProfilePath}`);
|
|
49
|
+
} else {
|
|
50
|
+
Logger.debug('sourceRoots 配置无需更新');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
} catch (error) {
|
|
54
|
+
Logger.error(`更新 build-profile.json5 失败: ${error}`);
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 从任务上下文获取模块根目录
|
|
61
|
+
*/
|
|
62
|
+
private getModuleRootFromContext(context: ITargetContext): string {
|
|
63
|
+
// 通过输出根目录推断模块根目录
|
|
64
|
+
// 输出根目录通常是 moduleName/src/generated
|
|
65
|
+
// 模块根目录应该是 moduleName/
|
|
66
|
+
const outputRoot = context.getOutputRoot();
|
|
67
|
+
|
|
68
|
+
// 向上查找包含 build-profile.json5 的目录
|
|
69
|
+
let currentDir = SerializationPathUtil.dirname(outputRoot);
|
|
70
|
+
|
|
71
|
+
while (currentDir && currentDir !== SerializationPathUtil.dirname(currentDir)) {
|
|
72
|
+
const buildProfilePath = SerializationPathUtil.join(currentDir, 'build-profile.json5');
|
|
73
|
+
if (SerializationPathUtil.exist(buildProfilePath)) {
|
|
74
|
+
return currentDir;
|
|
75
|
+
}
|
|
76
|
+
currentDir = SerializationPathUtil.dirname(currentDir);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 如果找不到,使用输出根目录的父目录的父目录作为fallback
|
|
80
|
+
return SerializationPathUtil.dirname(SerializationPathUtil.dirname(outputRoot));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 读取 build-profile.json5 配置
|
|
85
|
+
*/
|
|
86
|
+
private readBuildProfile(buildProfilePath: string): any {
|
|
87
|
+
try {
|
|
88
|
+
// 使用继承自 FileUtil 的方法读取 JSON5
|
|
89
|
+
return SerializationPathUtil.readJson5(buildProfilePath);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
Logger.error(`读取 build-profile.json5 失败: ${buildProfilePath}, 错误: ${error}`);
|
|
92
|
+
throw new Error(`无法读取配置文件: ${buildProfilePath}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 写入 build-profile.json5 配置
|
|
98
|
+
*/
|
|
99
|
+
private writeBuildProfile(targetContext: ITargetContext, buildProfilePath: string, config: any): void {
|
|
100
|
+
try {
|
|
101
|
+
// 不需要修改源代码,仅重写构建过程中的buildProfile文件,修改源码方式SerializationPathUtil.writeFileSync(buildProfilePath, JSON.stringify(config, null, 2));
|
|
102
|
+
targetContext.context.moduleContext.setBuildProfileOpt(config);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
Logger.error(`写入 build-profile.json5 失败: ${buildProfilePath}, 错误: ${error}`);
|
|
105
|
+
throw new Error(`无法写入配置文件: ${buildProfilePath}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 更新 sourceRoots 配置
|
|
111
|
+
* @param config 配置对象
|
|
112
|
+
* @returns 是否进行了更新
|
|
113
|
+
*/
|
|
114
|
+
private updateSourceRootsConfig(config: any): boolean {
|
|
115
|
+
let updated = false;
|
|
116
|
+
const generatedSourceRoot = "./src/generated";
|
|
117
|
+
Logger.info(`target.source.sourceRoots start`);
|
|
118
|
+
|
|
119
|
+
// 更新 targets 中的 source.sourceRoots
|
|
120
|
+
if (config.targets && Array.isArray(config.targets)) {
|
|
121
|
+
for (const target of config.targets) {
|
|
122
|
+
Logger.info(`target.source.sourceRoots is target: ${target}`);
|
|
123
|
+
if (!target.source) {
|
|
124
|
+
target.source = {};
|
|
125
|
+
}
|
|
126
|
+
if (!target.source.sourceRoots) {
|
|
127
|
+
target.source.sourceRoots = [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!Array.isArray(target.source.sourceRoots)) {
|
|
131
|
+
Logger.warn('target.source.sourceRoots 不是数组,将重置为数组');
|
|
132
|
+
target.source.sourceRoots = [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!target.source.sourceRoots.includes(generatedSourceRoot)) {
|
|
136
|
+
target.source.sourceRoots.unshift(generatedSourceRoot);
|
|
137
|
+
Logger.info(`添加 target.source.sourceRoots: ${generatedSourceRoot}`);
|
|
138
|
+
updated = true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return updated;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
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 { ITaskContext, ImportRewriteOptions, Logger } from '../..';
|
|
17
|
+
import { GeneratedFileInfo, ImportRewriteService as IImportRewriteService } from '../types/ImportRewriteTypes';
|
|
18
|
+
import { ImportTransformServiceImpl } from './ImportTransformService';
|
|
19
|
+
import SerializationPathUtil from '../../utils/SerializationPathUtil';
|
|
20
|
+
import { BuildProfileUpdaterImpl } from './BuildProfileUpdater';
|
|
21
|
+
import { ITargetContext } from '../../../json-plugin/interfaces/ITargetContext';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 导入重写主服务实现
|
|
25
|
+
* 协调扫描策略和转换服务
|
|
26
|
+
*/
|
|
27
|
+
export class ImportRewriteServiceImpl implements IImportRewriteService {
|
|
28
|
+
private readonly transformService: ImportTransformServiceImpl;
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
this.transformService = new ImportTransformServiceImpl();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 重写项目中的导入语句
|
|
36
|
+
* @param context 任务上下文
|
|
37
|
+
* @param generatedFileInfos 生成文件信息列表
|
|
38
|
+
* @param options 导入重写选项
|
|
39
|
+
*/
|
|
40
|
+
rewriteImports(
|
|
41
|
+
context: ITaskContext,
|
|
42
|
+
generatedFileInfos: GeneratedFileInfo[],
|
|
43
|
+
options: ImportRewriteOptions
|
|
44
|
+
): void {
|
|
45
|
+
// 1. 扫描找到需要修改的文件
|
|
46
|
+
const filesToUpdate = this.scanFilesWithModelImports(options.scanPaths, generatedFileInfos, context);
|
|
47
|
+
|
|
48
|
+
if (filesToUpdate.length === 0) {
|
|
49
|
+
Logger.info('未找到需要重写导入的文件');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Logger.info(`找到 ${filesToUpdate.length} 个文件需要重写导入`);
|
|
54
|
+
|
|
55
|
+
// 2. 为每个文件重写导入语句
|
|
56
|
+
let successCount = 0;
|
|
57
|
+
let errorCount = 0;
|
|
58
|
+
|
|
59
|
+
for (const filePath of filesToUpdate) {
|
|
60
|
+
try {
|
|
61
|
+
this.transformService.rewriteFileImports(
|
|
62
|
+
filePath,
|
|
63
|
+
context,
|
|
64
|
+
generatedFileInfos,
|
|
65
|
+
options.preserveOriginalImports
|
|
66
|
+
);
|
|
67
|
+
successCount++;
|
|
68
|
+
} catch (error: any) {
|
|
69
|
+
errorCount++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Logger.info(`导入重写完成: 成功 ${successCount} 个,失败 ${errorCount} 个`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 扫描找到包含模型导入的文件
|
|
78
|
+
* @param scanPaths 扫描路径列表
|
|
79
|
+
* @param generatedFileInfos 生成文件信息列表
|
|
80
|
+
* @param context 任务上下文
|
|
81
|
+
* @returns 需要更新的文件路径列表
|
|
82
|
+
*/
|
|
83
|
+
private scanFilesWithModelImports(
|
|
84
|
+
scanPaths: string[],
|
|
85
|
+
generatedFileInfos: GeneratedFileInfo[],
|
|
86
|
+
context: ITaskContext
|
|
87
|
+
): string[] {
|
|
88
|
+
const filesToUpdate: string[] = [];
|
|
89
|
+
|
|
90
|
+
for (const scanPath of scanPaths) {
|
|
91
|
+
const absoluteScanPath = SerializationPathUtil.isAbsolute(scanPath)
|
|
92
|
+
? scanPath
|
|
93
|
+
: SerializationPathUtil.pathResolve(context.getModulePath(), scanPath);
|
|
94
|
+
|
|
95
|
+
if (!SerializationPathUtil.exist(absoluteScanPath)) {
|
|
96
|
+
Logger.warn(`扫描路径不存在: ${absoluteScanPath}`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const files = SerializationPathUtil.scanEtsFiles(absoluteScanPath);
|
|
101
|
+
|
|
102
|
+
// 过滤出可能包含需要重写导入的文件
|
|
103
|
+
for (const filePath of files) {
|
|
104
|
+
if (this.shouldCheckFile(filePath, generatedFileInfos)) {
|
|
105
|
+
filesToUpdate.push(filePath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 添加Index.ets文件
|
|
111
|
+
const IndexFilePath = SerializationPathUtil.pathResolve(context.getModulePath(), 'Index.ets');
|
|
112
|
+
if (SerializationPathUtil.exist(IndexFilePath)) {
|
|
113
|
+
filesToUpdate.push(IndexFilePath);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return filesToUpdate;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 判断文件是否应该被检查
|
|
121
|
+
* 排除生成的文件本身
|
|
122
|
+
*/
|
|
123
|
+
private shouldCheckFile(filePath: string, generatedFileInfos: GeneratedFileInfo[]): boolean {
|
|
124
|
+
// 排除生成文件目录中的文件
|
|
125
|
+
return !generatedFileInfos.some(info =>
|
|
126
|
+
filePath.startsWith(SerializationPathUtil.dirname(info.generatedFilePath))
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
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 { ImportDeclaration, ExportDeclaration, SourceFile } from 'ts-morph';
|
|
17
|
+
import { ITaskContext, Logger } from '../..';
|
|
18
|
+
import { GeneratedFileInfo, ImportTransformService } from '../types/ImportRewriteTypes';
|
|
19
|
+
import { ImportScanStrategyImpl } from '../strategies/ImportScanStrategy';
|
|
20
|
+
import SerializationPathUtil from '../../utils/SerializationPathUtil';
|
|
21
|
+
import { ErrorCodes } from '../../utils/CustomError';
|
|
22
|
+
import { TsMorphUtil } from '../../utils/TsMorphUtil';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 导入转换服务实现
|
|
26
|
+
* 基于 ts-morph 的导入语句重写服务
|
|
27
|
+
*/
|
|
28
|
+
export class ImportTransformServiceImpl implements ImportTransformService {
|
|
29
|
+
private readonly scanStrategy: ImportScanStrategyImpl;
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
this.scanStrategy = new ImportScanStrategyImpl();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
rewriteFileImports(
|
|
36
|
+
filePath: string,
|
|
37
|
+
context: ITaskContext,
|
|
38
|
+
generatedFileInfos: GeneratedFileInfo[],
|
|
39
|
+
preserveOriginalImports: boolean = false
|
|
40
|
+
): void {
|
|
41
|
+
try {
|
|
42
|
+
const sourceFile = TsMorphUtil.getProject().addSourceFileAtPath(filePath);
|
|
43
|
+
|
|
44
|
+
const importRewriteCount = this.processImportDeclarations(
|
|
45
|
+
sourceFile,
|
|
46
|
+
context,
|
|
47
|
+
generatedFileInfos,
|
|
48
|
+
preserveOriginalImports
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const exportRewriteCount = this.processExportDeclarations(
|
|
52
|
+
sourceFile,
|
|
53
|
+
context,
|
|
54
|
+
generatedFileInfos,
|
|
55
|
+
preserveOriginalImports
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const totalRewriteCount = importRewriteCount + exportRewriteCount;
|
|
59
|
+
this.handleRewriteResult(sourceFile, filePath, totalRewriteCount);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
this.handleRewriteError(error, filePath);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private processImportDeclarations(
|
|
67
|
+
sourceFile: SourceFile,
|
|
68
|
+
context: ITaskContext,
|
|
69
|
+
generatedFileInfos: GeneratedFileInfo[],
|
|
70
|
+
preserveOriginalImports: boolean
|
|
71
|
+
): number {
|
|
72
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
73
|
+
let rewriteCount = 0;
|
|
74
|
+
|
|
75
|
+
for (const importDecl of importDeclarations) {
|
|
76
|
+
// 传递 context 到扫描策略,以支持模块化导入处理
|
|
77
|
+
const matchedInfo = this.scanStrategy.shouldRewriteImport(
|
|
78
|
+
importDecl,
|
|
79
|
+
sourceFile.getFilePath(),
|
|
80
|
+
generatedFileInfos,
|
|
81
|
+
context
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (matchedInfo) {
|
|
85
|
+
this.rewriteSingleImport(importDecl, context, matchedInfo, preserveOriginalImports);
|
|
86
|
+
rewriteCount++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return rewriteCount;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private processExportDeclarations(
|
|
94
|
+
sourceFile: SourceFile,
|
|
95
|
+
context: ITaskContext,
|
|
96
|
+
generatedFileInfos: GeneratedFileInfo[],
|
|
97
|
+
preserveOriginalImports: boolean
|
|
98
|
+
): number {
|
|
99
|
+
const exportDeclarations = sourceFile.getExportDeclarations();
|
|
100
|
+
let rewriteCount = 0;
|
|
101
|
+
|
|
102
|
+
for (const exportDecl of exportDeclarations) {
|
|
103
|
+
const moduleSpecifier = exportDecl.getModuleSpecifierValue();
|
|
104
|
+
|
|
105
|
+
// 没有 moduleSpecifier 说明没有 from 子句,跳过
|
|
106
|
+
if (!moduleSpecifier) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 使用相同的扫描策略检查导出
|
|
111
|
+
const matchedInfo = this.scanStrategy.shouldRewriteExport(
|
|
112
|
+
moduleSpecifier,
|
|
113
|
+
sourceFile.getFilePath(),
|
|
114
|
+
generatedFileInfos,
|
|
115
|
+
context
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (matchedInfo) {
|
|
119
|
+
this.rewriteSingleExport(exportDecl, context, matchedInfo, preserveOriginalImports);
|
|
120
|
+
rewriteCount++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return rewriteCount;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private rewriteSingleExport(
|
|
128
|
+
exportDecl: ExportDeclaration,
|
|
129
|
+
context: ITaskContext,
|
|
130
|
+
matchedInfo: GeneratedFileInfo,
|
|
131
|
+
preserveOriginalImports: boolean
|
|
132
|
+
): void {
|
|
133
|
+
const originalModuleSpecifier = exportDecl.getModuleSpecifierValue();
|
|
134
|
+
if (!originalModuleSpecifier) {
|
|
135
|
+
// 如果没有 moduleSpecifier,说明没有 from 子句,不应该到这里
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const newModuleSpecifier = SerializationPathUtil.calculateModularImportPath(matchedInfo.generatedFilePath, context);
|
|
140
|
+
|
|
141
|
+
if (preserveOriginalImports) {
|
|
142
|
+
this.replaceWithCommentedOriginal(exportDecl, originalModuleSpecifier, newModuleSpecifier);
|
|
143
|
+
} else {
|
|
144
|
+
exportDecl.setModuleSpecifier(newModuleSpecifier);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private rewriteSingleImport(
|
|
149
|
+
importDecl: ImportDeclaration,
|
|
150
|
+
context: ITaskContext,
|
|
151
|
+
matchedInfo: GeneratedFileInfo,
|
|
152
|
+
preserveOriginalImports: boolean
|
|
153
|
+
): void {
|
|
154
|
+
const originalModuleSpecifier = importDecl.getModuleSpecifierValue();
|
|
155
|
+
const newModuleSpecifier = SerializationPathUtil.calculateModularImportPath(matchedInfo.generatedFilePath, context);
|
|
156
|
+
|
|
157
|
+
if (preserveOriginalImports) {
|
|
158
|
+
this.replaceWithCommentedOriginal(importDecl, originalModuleSpecifier, newModuleSpecifier);
|
|
159
|
+
} else {
|
|
160
|
+
importDecl.setModuleSpecifier(newModuleSpecifier);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private replaceWithCommentedOriginal(
|
|
165
|
+
importDecl: any,
|
|
166
|
+
originalModuleSpecifier: string,
|
|
167
|
+
newModuleSpecifier: string
|
|
168
|
+
): void {
|
|
169
|
+
const originalImportText = importDecl.getFullText().trim();
|
|
170
|
+
const commentedOriginal = `// ${originalImportText}`;
|
|
171
|
+
|
|
172
|
+
const newImportText = importDecl
|
|
173
|
+
.getFullText()
|
|
174
|
+
.replace(new RegExp(`(['"]?)${this.escapeRegExp(originalModuleSpecifier)}\\1`, 'g'), `'${newModuleSpecifier}'`);
|
|
175
|
+
|
|
176
|
+
importDecl.replaceWithText(`${commentedOriginal}\n${newImportText.trim()}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private handleRewriteResult(sourceFile: any, filePath: string, rewriteCount: number): void {
|
|
180
|
+
if (rewriteCount > 0) {
|
|
181
|
+
sourceFile.saveSync();
|
|
182
|
+
Logger.info(`文件 ${filePath} 重写了 ${rewriteCount} 个导入语句`);
|
|
183
|
+
}
|
|
184
|
+
sourceFile.forget();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private handleRewriteError(error: unknown, filePath: string): void {
|
|
188
|
+
if (error instanceof Error) {
|
|
189
|
+
Logger.error(`Error: ${error.constructor.name}: ${ErrorCodes.REWRITE_IMPORT_FAIL}`);
|
|
190
|
+
Logger.error(`Error Message: 重写文件导入失败: ${filePath}`);
|
|
191
|
+
Logger.error(`错误信息: ${error.message}\n${error.stack}`);
|
|
192
|
+
} else {
|
|
193
|
+
Logger.error(`重写文件导入失败: ${filePath}, 未知错误: ${error}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private escapeRegExp(string: string): string {
|
|
198
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
199
|
+
}
|
|
200
|
+
}
|