@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,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
+ }