@qwe8652591/abap-recursive-query 1.1.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 (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +223 -0
  3. package/dist/cli/consumer-cli.d.ts +8 -0
  4. package/dist/cli/consumer-cli.d.ts.map +1 -0
  5. package/dist/cli/consumer-cli.js +180 -0
  6. package/dist/cli/producer-cli.d.ts +8 -0
  7. package/dist/cli/producer-cli.d.ts.map +1 -0
  8. package/dist/cli/producer-cli.js +249 -0
  9. package/dist/cli/query-object.d.ts +3 -0
  10. package/dist/cli/query-object.d.ts.map +1 -0
  11. package/dist/cli/query-object.js +486 -0
  12. package/dist/common/FilterCache.d.ts +62 -0
  13. package/dist/common/FilterCache.d.ts.map +1 -0
  14. package/dist/common/FilterCache.js +119 -0
  15. package/dist/common/RedisQueueManager.d.ts +170 -0
  16. package/dist/common/RedisQueueManager.d.ts.map +1 -0
  17. package/dist/common/RedisQueueManager.js +663 -0
  18. package/dist/common/abapStructures.d.ts +391 -0
  19. package/dist/common/abapStructures.d.ts.map +1 -0
  20. package/dist/common/abapStructures.js +2 -0
  21. package/dist/common/config.d.ts +66 -0
  22. package/dist/common/config.d.ts.map +1 -0
  23. package/dist/common/config.js +56 -0
  24. package/dist/common/index.d.ts +13 -0
  25. package/dist/common/index.d.ts.map +1 -0
  26. package/dist/common/index.js +38 -0
  27. package/dist/common/recursiveQueryConfig.d.ts +77 -0
  28. package/dist/common/recursiveQueryConfig.d.ts.map +1 -0
  29. package/dist/common/recursiveQueryConfig.js +129 -0
  30. package/dist/common/tableStructures.d.ts +176 -0
  31. package/dist/common/tableStructures.d.ts.map +1 -0
  32. package/dist/common/tableStructures.js +10 -0
  33. package/dist/common/types.d.ts +104 -0
  34. package/dist/common/types.d.ts.map +1 -0
  35. package/dist/common/types.js +31 -0
  36. package/dist/common/utils.d.ts +57 -0
  37. package/dist/common/utils.d.ts.map +1 -0
  38. package/dist/common/utils.js +300 -0
  39. package/dist/consumer/FileDownloadConsumer.d.ts +127 -0
  40. package/dist/consumer/FileDownloadConsumer.d.ts.map +1 -0
  41. package/dist/consumer/FileDownloadConsumer.js +1003 -0
  42. package/dist/consumer/generators/baseGenerator.d.ts +38 -0
  43. package/dist/consumer/generators/baseGenerator.d.ts.map +1 -0
  44. package/dist/consumer/generators/baseGenerator.js +103 -0
  45. package/dist/consumer/generators/domainGenerator.d.ts +78 -0
  46. package/dist/consumer/generators/domainGenerator.d.ts.map +1 -0
  47. package/dist/consumer/generators/domainGenerator.js +241 -0
  48. package/dist/consumer/generators/guiStatusGenerator.d.ts +16 -0
  49. package/dist/consumer/generators/guiStatusGenerator.d.ts.map +1 -0
  50. package/dist/consumer/generators/guiStatusGenerator.js +48 -0
  51. package/dist/consumer/generators/guiTitleGenerator.d.ts +16 -0
  52. package/dist/consumer/generators/guiTitleGenerator.d.ts.map +1 -0
  53. package/dist/consumer/generators/guiTitleGenerator.js +48 -0
  54. package/dist/consumer/generators/index.d.ts +14 -0
  55. package/dist/consumer/generators/index.d.ts.map +1 -0
  56. package/dist/consumer/generators/index.js +38 -0
  57. package/dist/consumer/generators/messageGenerator.d.ts +16 -0
  58. package/dist/consumer/generators/messageGenerator.d.ts.map +1 -0
  59. package/dist/consumer/generators/messageGenerator.js +73 -0
  60. package/dist/consumer/generators/metadataGenerator.d.ts +29 -0
  61. package/dist/consumer/generators/metadataGenerator.d.ts.map +1 -0
  62. package/dist/consumer/generators/metadataGenerator.js +135 -0
  63. package/dist/consumer/generators/screenGenerator.d.ts +173 -0
  64. package/dist/consumer/generators/screenGenerator.d.ts.map +1 -0
  65. package/dist/consumer/generators/screenGenerator.js +859 -0
  66. package/dist/consumer/generators/structureGenerator.d.ts +36 -0
  67. package/dist/consumer/generators/structureGenerator.d.ts.map +1 -0
  68. package/dist/consumer/generators/structureGenerator.js +131 -0
  69. package/dist/consumer/generators/textElementGenerator.d.ts +16 -0
  70. package/dist/consumer/generators/textElementGenerator.d.ts.map +1 -0
  71. package/dist/consumer/generators/textElementGenerator.js +70 -0
  72. package/dist/consumer/handlers/handleGetClass.d.ts +8 -0
  73. package/dist/consumer/handlers/handleGetClass.d.ts.map +1 -0
  74. package/dist/consumer/handlers/handleGetClass.js +18 -0
  75. package/dist/consumer/handlers/handleGetFunction.d.ts +8 -0
  76. package/dist/consumer/handlers/handleGetFunction.d.ts.map +1 -0
  77. package/dist/consumer/handlers/handleGetFunction.js +19 -0
  78. package/dist/consumer/handlers/handleGetFunctionGroup.d.ts +8 -0
  79. package/dist/consumer/handlers/handleGetFunctionGroup.d.ts.map +1 -0
  80. package/dist/consumer/handlers/handleGetFunctionGroup.js +19 -0
  81. package/dist/consumer/handlers/handleGetInclude.d.ts +8 -0
  82. package/dist/consumer/handlers/handleGetInclude.d.ts.map +1 -0
  83. package/dist/consumer/handlers/handleGetInclude.js +18 -0
  84. package/dist/consumer/handlers/handleGetProgram.d.ts +8 -0
  85. package/dist/consumer/handlers/handleGetProgram.d.ts.map +1 -0
  86. package/dist/consumer/handlers/handleGetProgram.js +27 -0
  87. package/dist/consumer/handlers/handleZTableQuery.d.ts +8 -0
  88. package/dist/consumer/handlers/handleZTableQuery.d.ts.map +1 -0
  89. package/dist/consumer/handlers/handleZTableQuery.js +20 -0
  90. package/dist/consumer/handlers/index.d.ts +10 -0
  91. package/dist/consumer/handlers/index.d.ts.map +1 -0
  92. package/dist/consumer/handlers/index.js +27 -0
  93. package/dist/consumer/index.d.ts +9 -0
  94. package/dist/consumer/index.d.ts.map +1 -0
  95. package/dist/consumer/index.js +24 -0
  96. package/dist/consumer/utils/download.d.ts +13 -0
  97. package/dist/consumer/utils/download.d.ts.map +1 -0
  98. package/dist/consumer/utils/download.js +38 -0
  99. package/dist/consumer/utils/index.d.ts +5 -0
  100. package/dist/consumer/utils/index.d.ts.map +1 -0
  101. package/dist/consumer/utils/index.js +20 -0
  102. package/dist/handlers/handleGetClass.d.ts +8 -0
  103. package/dist/handlers/handleGetClass.d.ts.map +1 -0
  104. package/dist/handlers/handleGetClass.js +19 -0
  105. package/dist/handlers/handleGetFunction.d.ts +8 -0
  106. package/dist/handlers/handleGetFunction.d.ts.map +1 -0
  107. package/dist/handlers/handleGetFunction.js +20 -0
  108. package/dist/handlers/handleGetFunctionGroup.d.ts +8 -0
  109. package/dist/handlers/handleGetFunctionGroup.d.ts.map +1 -0
  110. package/dist/handlers/handleGetFunctionGroup.js +19 -0
  111. package/dist/handlers/handleGetInclude.d.ts +8 -0
  112. package/dist/handlers/handleGetInclude.d.ts.map +1 -0
  113. package/dist/handlers/handleGetInclude.js +19 -0
  114. package/dist/handlers/handleGetInterface.d.ts +8 -0
  115. package/dist/handlers/handleGetInterface.d.ts.map +1 -0
  116. package/dist/handlers/handleGetInterface.js +19 -0
  117. package/dist/handlers/handleGetPackage.d.ts +8 -0
  118. package/dist/handlers/handleGetPackage.d.ts.map +1 -0
  119. package/dist/handlers/handleGetPackage.js +42 -0
  120. package/dist/handlers/handleGetProgram.d.ts +8 -0
  121. package/dist/handlers/handleGetProgram.d.ts.map +1 -0
  122. package/dist/handlers/handleGetProgram.js +19 -0
  123. package/dist/handlers/handleGetStructure.d.ts +8 -0
  124. package/dist/handlers/handleGetStructure.d.ts.map +1 -0
  125. package/dist/handlers/handleGetStructure.js +19 -0
  126. package/dist/handlers/handleGetTable.d.ts +8 -0
  127. package/dist/handlers/handleGetTable.d.ts.map +1 -0
  128. package/dist/handlers/handleGetTable.js +19 -0
  129. package/dist/handlers/handleGetTableContents.d.ts +8 -0
  130. package/dist/handlers/handleGetTableContents.d.ts.map +1 -0
  131. package/dist/handlers/handleGetTableContents.js +22 -0
  132. package/dist/handlers/handleGetTransaction.d.ts +8 -0
  133. package/dist/handlers/handleGetTransaction.d.ts.map +1 -0
  134. package/dist/handlers/handleGetTransaction.js +19 -0
  135. package/dist/handlers/handleGetTypeInfo.d.ts +8 -0
  136. package/dist/handlers/handleGetTypeInfo.d.ts.map +1 -0
  137. package/dist/handlers/handleGetTypeInfo.js +32 -0
  138. package/dist/handlers/handleSearchObject.d.ts +8 -0
  139. package/dist/handlers/handleSearchObject.d.ts.map +1 -0
  140. package/dist/handlers/handleSearchObject.js +20 -0
  141. package/dist/handlers/handleZObjectQuery.d.ts +8 -0
  142. package/dist/handlers/handleZObjectQuery.d.ts.map +1 -0
  143. package/dist/handlers/handleZObjectQuery.js +25 -0
  144. package/dist/handlers/handleZTableQuery.d.ts +8 -0
  145. package/dist/handlers/handleZTableQuery.d.ts.map +1 -0
  146. package/dist/handlers/handleZTableQuery.js +20 -0
  147. package/dist/index.d.ts +17 -0
  148. package/dist/index.d.ts.map +1 -0
  149. package/dist/index.js +45 -0
  150. package/dist/lib/download.d.ts +49 -0
  151. package/dist/lib/download.d.ts.map +1 -0
  152. package/dist/lib/download.js +78 -0
  153. package/dist/lib/index.d.ts +9 -0
  154. package/dist/lib/index.d.ts.map +1 -0
  155. package/dist/lib/index.js +23 -0
  156. package/dist/lib/utils.d.ts +31 -0
  157. package/dist/lib/utils.d.ts.map +1 -0
  158. package/dist/lib/utils.js +272 -0
  159. package/dist/producer/RecursiveQueryProducer.d.ts +92 -0
  160. package/dist/producer/RecursiveQueryProducer.d.ts.map +1 -0
  161. package/dist/producer/RecursiveQueryProducer.js +496 -0
  162. package/dist/producer/handlers/handleZObjectQuery.d.ts +8 -0
  163. package/dist/producer/handlers/handleZObjectQuery.d.ts.map +1 -0
  164. package/dist/producer/handlers/handleZObjectQuery.js +24 -0
  165. package/dist/producer/handlers/index.d.ts +6 -0
  166. package/dist/producer/handlers/index.d.ts.map +1 -0
  167. package/dist/producer/handlers/index.js +21 -0
  168. package/dist/producer/index.d.ts +7 -0
  169. package/dist/producer/index.d.ts.map +1 -0
  170. package/dist/producer/index.js +22 -0
  171. package/dist/recursive/abapStructures.d.ts +377 -0
  172. package/dist/recursive/abapStructures.d.ts.map +1 -0
  173. package/dist/recursive/abapStructures.js +2 -0
  174. package/dist/recursive/generate/baseGenerator.d.ts +34 -0
  175. package/dist/recursive/generate/baseGenerator.d.ts.map +1 -0
  176. package/dist/recursive/generate/baseGenerator.js +112 -0
  177. package/dist/recursive/generate/domainGenerator.d.ts +26 -0
  178. package/dist/recursive/generate/domainGenerator.d.ts.map +1 -0
  179. package/dist/recursive/generate/domainGenerator.js +128 -0
  180. package/dist/recursive/generate/functionGroupGenerator.d.ts +30 -0
  181. package/dist/recursive/generate/functionGroupGenerator.d.ts.map +1 -0
  182. package/dist/recursive/generate/functionGroupGenerator.js +90 -0
  183. package/dist/recursive/generate/index.d.ts +12 -0
  184. package/dist/recursive/generate/index.d.ts.map +1 -0
  185. package/dist/recursive/generate/index.js +34 -0
  186. package/dist/recursive/generate/messageGenerator.d.ts +16 -0
  187. package/dist/recursive/generate/messageGenerator.d.ts.map +1 -0
  188. package/dist/recursive/generate/messageGenerator.js +73 -0
  189. package/dist/recursive/generate/screenGenerator.d.ts +173 -0
  190. package/dist/recursive/generate/screenGenerator.d.ts.map +1 -0
  191. package/dist/recursive/generate/screenGenerator.js +858 -0
  192. package/dist/recursive/generate/structureGenerator.d.ts +22 -0
  193. package/dist/recursive/generate/structureGenerator.d.ts.map +1 -0
  194. package/dist/recursive/generate/structureGenerator.js +88 -0
  195. package/dist/recursive/generate/textElementGenerator.d.ts +16 -0
  196. package/dist/recursive/generate/textElementGenerator.d.ts.map +1 -0
  197. package/dist/recursive/generate/textElementGenerator.js +68 -0
  198. package/dist/recursive/handleRecursiveObjectQuery.d.ts +94 -0
  199. package/dist/recursive/handleRecursiveObjectQuery.d.ts.map +1 -0
  200. package/dist/recursive/handleRecursiveObjectQuery.js +219 -0
  201. package/dist/recursive/recursiveObjectQuery.d.ts +159 -0
  202. package/dist/recursive/recursiveObjectQuery.d.ts.map +1 -0
  203. package/dist/recursive/recursiveObjectQuery.js +1358 -0
  204. package/dist/recursive/recursiveQueryConfig.d.ts +129 -0
  205. package/dist/recursive/recursiveQueryConfig.d.ts.map +1 -0
  206. package/dist/recursive/recursiveQueryConfig.js +133 -0
  207. package/dist/recursive/tableStructures.d.ts +196 -0
  208. package/dist/recursive/tableStructures.d.ts.map +1 -0
  209. package/dist/recursive/tableStructures.js +10 -0
  210. package/package.json +47 -0
@@ -0,0 +1,1358 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RecursiveObjectQuery = void 0;
4
+ const handleGetInclude_1 = require("../handlers/handleGetInclude");
5
+ const handleGetClass_1 = require("../handlers/handleGetClass");
6
+ const handleGetFunction_1 = require("../handlers/handleGetFunction");
7
+ const handleGetProgram_1 = require("../handlers/handleGetProgram");
8
+ const handleZObjectQuery_1 = require("../handlers/handleZObjectQuery");
9
+ const handleZTableQuery_1 = require("../handlers/handleZTableQuery");
10
+ const download_1 = require("../lib/download");
11
+ const core_1 = require("@abaplint/core");
12
+ const recursiveQueryConfig_1 = require("./recursiveQueryConfig");
13
+ const path_1 = require("path");
14
+ const fs_1 = require("fs");
15
+ // 导入所有生成器模块 - 统一从 index.ts 导入
16
+ const generate_1 = require("./generate");
17
+ /**
18
+ * 异步任务队列管理器 - 修复死锁和任务丢失问题
19
+ * 优化版本:解决竞态条件、死锁和任务丢失问题
20
+ */
21
+ class AsyncTaskQueue {
22
+ queue = [];
23
+ running = 0;
24
+ maxConcurrent;
25
+ taskResults = new Map(); // 改为存储Promise,支持多个调用者等待同一任务
26
+ processing = false;
27
+ processingRequests = 0; // 跟踪待处理的processQueue请求
28
+ waiters = []; // 用于通知等待者
29
+ constructor(maxConcurrent) {
30
+ this.maxConcurrent = Math.max(1, maxConcurrent); // 确保至少为1
31
+ }
32
+ async add(taskId, task) {
33
+ // 如果任务已存在,直接返回缓存的Promise(支持多个调用者等待同一任务)
34
+ if (this.taskResults.has(taskId)) {
35
+ return this.taskResults.get(taskId);
36
+ }
37
+ // 创建任务Promise并立即缓存
38
+ const taskPromise = new Promise((resolve, reject) => {
39
+ const wrappedTask = async () => {
40
+ try {
41
+ this.running++;
42
+ const result = await task();
43
+ resolve(result);
44
+ return result;
45
+ }
46
+ catch (error) {
47
+ reject(error);
48
+ throw error;
49
+ }
50
+ finally {
51
+ this.running--;
52
+ // 通知等待者
53
+ this.notifyWaiters();
54
+ // 任务完成后立即尝试处理队列中的下一个任务
55
+ // 使用 process.nextTick 而不是 setImmediate,优先级更高
56
+ process.nextTick(() => this.processQueue());
57
+ }
58
+ };
59
+ this.queue.push(wrappedTask);
60
+ });
61
+ // 缓存Promise,这样同一任务的多个调用者可以共享结果
62
+ this.taskResults.set(taskId, taskPromise);
63
+ // 立即尝试处理队列
64
+ this.processQueue();
65
+ return taskPromise;
66
+ }
67
+ processQueue() {
68
+ // 记录处理请求
69
+ this.processingRequests++;
70
+ // 避免重复处理,但记录请求数
71
+ if (this.processing) {
72
+ return;
73
+ }
74
+ this.processing = true;
75
+ // 使用异步处理避免阻塞
76
+ process.nextTick(() => {
77
+ try {
78
+ // 尽可能多地处理队列中的任务,直到达到并发限制
79
+ while (this.running < this.maxConcurrent && this.queue.length > 0) {
80
+ const task = this.queue.shift();
81
+ if (task) {
82
+ // 启动任务但不等待
83
+ task().catch(() => {
84
+ // 错误已在wrappedTask中处理,这里只是防止未捕获的Promise rejection
85
+ });
86
+ }
87
+ }
88
+ }
89
+ finally {
90
+ this.processing = false;
91
+ this.processingRequests--;
92
+ // 如果还有待处理的请求或队列中还有任务,继续处理
93
+ if (this.processingRequests > 0 || (this.queue.length > 0 && this.running < this.maxConcurrent)) {
94
+ this.processingRequests = 0; // 重置计数
95
+ this.processQueue();
96
+ }
97
+ }
98
+ });
99
+ }
100
+ getQueueSize() {
101
+ return this.queue.length;
102
+ }
103
+ getRunningCount() {
104
+ return this.running;
105
+ }
106
+ /**
107
+ * 通知所有等待者
108
+ */
109
+ notifyWaiters() {
110
+ const waiters = [...this.waiters];
111
+ this.waiters = [];
112
+ waiters.forEach(waiter => waiter());
113
+ }
114
+ /**
115
+ * 等待所有任务完成(包括正在运行的和队列中的)
116
+ * 使用事件通知机制而不是轮询,避免死锁和CPU浪费
117
+ */
118
+ async waitForAll() {
119
+ while (this.queue.length > 0 || this.running > 0) {
120
+ // 如果还有任务,等待任务完成的通知
121
+ await new Promise((resolve) => {
122
+ // 检查是否已经完成
123
+ if (this.queue.length === 0 && this.running === 0) {
124
+ resolve();
125
+ return;
126
+ }
127
+ // 添加到等待者列表
128
+ this.waiters.push(resolve);
129
+ // 设置超时保护,避免永久等待
130
+ const timeout = setTimeout(() => {
131
+ const index = this.waiters.indexOf(resolve);
132
+ if (index !== -1) {
133
+ this.waiters.splice(index, 1);
134
+ }
135
+ resolve();
136
+ }, 100); // 100ms超时
137
+ // 清理超时
138
+ const originalResolve = resolve;
139
+ this.waiters[this.waiters.length - 1] = () => {
140
+ clearTimeout(timeout);
141
+ originalResolve();
142
+ };
143
+ });
144
+ // 尝试处理队列中的剩余任务
145
+ if (this.queue.length > 0 && this.running < this.maxConcurrent) {
146
+ this.processQueue();
147
+ }
148
+ }
149
+ // 最终确保所有缓存的Promise都已完成
150
+ if (this.taskResults.size > 0) {
151
+ await Promise.allSettled(Array.from(this.taskResults.values()));
152
+ }
153
+ }
154
+ /**
155
+ * 清理已完成的任务缓存(可选,用于内存管理)
156
+ */
157
+ clearCache() {
158
+ this.taskResults.clear();
159
+ }
160
+ }
161
+ /**
162
+ * 递归对象查询器
163
+ * 用于查询ABAP对象及其引用的所有相关对象
164
+ */
165
+ class RecursiveObjectQuery {
166
+ config;
167
+ result;
168
+ context;
169
+ taskQueue;
170
+ objectCache = new Map(); // 对象数据缓存
171
+ screenCache; // 屏幕缓存实例,每个查询进程独立
172
+ constructor(config = {}) {
173
+ this.config = { ...recursiveQueryConfig_1.defaultConfig, ...config };
174
+ // 始终合并默认过滤规则和用户配置的过滤规则
175
+ const userFilters = config.recursionFilters || {};
176
+ this.config.recursionFilters = {
177
+ // 合并 excludeNames:默认 + 用户配置
178
+ excludeNames: [
179
+ ...(recursiveQueryConfig_1.defaultFilters?.excludeNames || []),
180
+ ...(userFilters.excludeNames || [])
181
+ ],
182
+ // 合并 excludeNamePatterns:默认 + 用户配置
183
+ excludeNamePatterns: [
184
+ ...(recursiveQueryConfig_1.defaultFilters?.excludeNamePatterns || []),
185
+ ...(userFilters.excludeNamePatterns || [])
186
+ ]
187
+ };
188
+ const defaultCount = (recursiveQueryConfig_1.defaultFilters?.excludeNames?.length || 0) + (recursiveQueryConfig_1.defaultFilters?.excludeNamePatterns?.length || 0);
189
+ const userCount = (userFilters.excludeNames?.length || 0) + (userFilters.excludeNamePatterns?.length || 0);
190
+ console.error(`[过滤配置] 使用默认过滤规则 + 用户配置规则`);
191
+ console.error(` - 默认规则: ${defaultCount} 个 (${recursiveQueryConfig_1.defaultFilters?.excludeNames?.length || 0} 精确 + ${recursiveQueryConfig_1.defaultFilters?.excludeNamePatterns?.length || 0} 模式)`);
192
+ console.error(` - 用户规则: ${userCount} 个 (${userFilters.excludeNames?.length || 0} 精确 + ${userFilters.excludeNamePatterns?.length || 0} 模式)`);
193
+ console.error(` - 总计规则: ${this.config.recursionFilters.excludeNames?.length || 0} 精确 + ${this.config.recursionFilters.excludeNamePatterns?.length || 0} 模式`);
194
+ this.result = {
195
+ originalObject: null,
196
+ allObjects: new Map(),
197
+ downloadedFiles: [],
198
+ filteredObjects: [],
199
+ statistics: {
200
+ totalObjects: 0,
201
+ totalClasses: 0,
202
+ totalFunctions: 0,
203
+ totalPrograms: 0,
204
+ totalIncludes: 0,
205
+ totalStructures: 0,
206
+ totalDomains: 0,
207
+ downloadedIncludes: 0,
208
+ downloadedStructures: 0,
209
+ downloadedDomains: 0,
210
+ maxDepthReached: 0,
211
+ circularReferences: 0
212
+ },
213
+ errors: [],
214
+ // 以下字段保留以保持接口兼容性,但在当前实现中未使用
215
+ totalObjects: 0,
216
+ downloadedObjects: 0,
217
+ failedObjects: 0,
218
+ skippedObjects: 0,
219
+ totalFiles: 0,
220
+ downloadedFilesCount: 0,
221
+ failedFiles: 0,
222
+ objectDetails: [],
223
+ startTime: new Date(),
224
+ endTime: new Date()
225
+ };
226
+ this.context = {
227
+ currentDepth: 0,
228
+ visitedPaths: new Set(),
229
+ dependencyGraph: new Map(),
230
+ config: this.config
231
+ };
232
+ this.taskQueue = new AsyncTaskQueue(this.config.concurrentRequestLimit);
233
+ this.screenCache = new generate_1.ScreenCache(); // 为每个查询实例创建独立的屏幕缓存
234
+ // 确保下载目录存在
235
+ if (this.config.downloadIncludes && !(0, fs_1.existsSync)(this.config.downloadRootPath)) {
236
+ (0, fs_1.mkdirSync)(this.config.downloadRootPath, { recursive: true });
237
+ }
238
+ }
239
+ /**
240
+ * 等待所有任务完成
241
+ */
242
+ async waitForAllTasks() {
243
+ console.error(`[等待完成] 等待所有任务完成,当前运行中: ${this.taskQueue.getRunningCount()}, 等待中: ${this.taskQueue.getQueueSize()}`);
244
+ // 使用队列的内置等待方法,确保所有任务都完成
245
+ await this.taskQueue.waitForAll();
246
+ console.error(`[等待完成] 所有任务已完成`);
247
+ }
248
+ /**
249
+ * 检查对象是否应该被过滤(不进行递归查询)
250
+ * @param objectType 对象类型
251
+ * @param objectName 对象名称
252
+ * @returns true表示应该过滤(不递归),false表示可以递归
253
+ */
254
+ shouldFilterRecursion(objectType, objectName) {
255
+ const filters = this.config.recursionFilters;
256
+ if (!filters) {
257
+ return false;
258
+ }
259
+ // 1. 检查是否在排除名称列表中(精确匹配)
260
+ if (filters.excludeNames && filters.excludeNames.length > 0) {
261
+ for (const name of filters.excludeNames) {
262
+ if (objectName.toUpperCase() === name.toUpperCase()) {
263
+ const reason = `对象名称在排除列表中`;
264
+ console.error(`[递归过滤] ${objectType}:${objectName} - ${reason}`);
265
+ // 记录到结果中
266
+ this.result.filteredObjects.push({
267
+ objectType,
268
+ objectName,
269
+ reason,
270
+ filterType: 'exact',
271
+ filterRule: name,
272
+ timestamp: new Date()
273
+ });
274
+ return true;
275
+ }
276
+ }
277
+ }
278
+ // 2. 检查对象名称是否匹配排除模式(支持通配符)
279
+ if (filters.excludeNamePatterns && filters.excludeNamePatterns.length > 0) {
280
+ for (const pattern of filters.excludeNamePatterns) {
281
+ if (this.matchPattern(objectName, pattern)) {
282
+ const reason = `对象名称匹配排除模式 ${pattern}`;
283
+ console.error(`[递归过滤] ${objectType}:${objectName} - ${reason}`);
284
+ // 记录到结果中
285
+ this.result.filteredObjects.push({
286
+ objectType,
287
+ objectName,
288
+ reason,
289
+ filterType: 'pattern',
290
+ filterRule: pattern,
291
+ timestamp: new Date()
292
+ });
293
+ return true;
294
+ }
295
+ }
296
+ }
297
+ return false;
298
+ }
299
+ /**
300
+ * 模式匹配(支持通配符 * 和 ?)
301
+ * @param text 要匹配的文本
302
+ * @param pattern 模式字符串
303
+ * @returns 是否匹配
304
+ */
305
+ matchPattern(text, pattern) {
306
+ // 将通配符模式转换为正则表达式
307
+ // * 匹配任意字符(0个或多个)
308
+ // ? 匹配单个字符
309
+ const regexPattern = pattern
310
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&') // 转义特殊字符
311
+ .replace(/\*/g, '.*') // * 转换为 .*
312
+ .replace(/\?/g, '.'); // ? 转换为 .
313
+ const regex = new RegExp(`^${regexPattern}$`, 'i'); // 不区分大小写
314
+ return regex.test(text);
315
+ }
316
+ /**
317
+ * 执行递归查询(优化版本)
318
+ * @param objectType 对象类型
319
+ * @param objectName 对象名称
320
+ * @returns 查询结果
321
+ */
322
+ async execute(objectType, objectName) {
323
+ console.error(`[开始查询] 开始递归查询: ${objectType} - ${objectName}`);
324
+ console.error(`[配置信息] ${JSON.stringify(this.config, null, 2)}`);
325
+ const startTime = Date.now();
326
+ try {
327
+ // 启动主处理任务
328
+ await this.processObjectRecursively(objectType, objectName, 0);
329
+ // 等待所有并发任务完成
330
+ await this.waitForAllTasks();
331
+ // 生成所有缓存的屏幕XML文件(整合到一个文件中)
332
+ await (0, generate_1.finalizeScreenGeneration)(this.screenCache, this.config.downloadRootPath, this.result.downloadedFiles);
333
+ }
334
+ catch (error) {
335
+ const errorMessage = `递归查询失败: ${error instanceof Error ? error.message : String(error)}`;
336
+ this.result.errors.push(errorMessage);
337
+ console.error(errorMessage);
338
+ }
339
+ const endTime = Date.now();
340
+ const duration = endTime - startTime;
341
+ console.error(`[查询完成] 递归查询完成,耗时: ${duration}ms`);
342
+ console.error(`[统计信息] ${JSON.stringify(this.result.statistics, null, 2)}`);
343
+ console.error(`[缓存信息] 缓存命中: ${this.objectCache.size} 个对象`);
344
+ // 输出过滤对象统计
345
+ if (this.result.filteredObjects.length > 0) {
346
+ console.error(`\n[递归过滤] 共过滤 ${this.result.filteredObjects.length} 个对象,未进行递归查询`);
347
+ // 按过滤类型分组统计
348
+ const exactFiltered = this.result.filteredObjects.filter(obj => obj.filterType === 'exact');
349
+ const patternFiltered = this.result.filteredObjects.filter(obj => obj.filterType === 'pattern');
350
+ if (exactFiltered.length > 0) {
351
+ console.error(` 📌 精确匹配过滤: ${exactFiltered.length} 个`);
352
+ }
353
+ if (patternFiltered.length > 0) {
354
+ console.error(` 🔍 模式匹配过滤: ${patternFiltered.length} 个`);
355
+ }
356
+ }
357
+ // 输出下载失败的文件列表
358
+ const failedFiles = this.result.downloadedFiles.filter(file => !file.success);
359
+ if (failedFiles.length > 0) {
360
+ console.error(`\n[下载失败] 共有 ${failedFiles.length} 个文件下载失败:`);
361
+ failedFiles.forEach(file => {
362
+ console.error(` ❌ ${file.objectType}/${file.objectName}.abap - ${file.error}`);
363
+ });
364
+ }
365
+ else {
366
+ console.error(`\n[下载成功] 所有文件下载成功,共 ${this.result.downloadedFiles.length} 个文件`);
367
+ }
368
+ return this.result;
369
+ }
370
+ /**
371
+ * 递归处理对象(优化版本)
372
+ * 采用并发队列 + 缓存机制,提高执行效率
373
+ * 修复死锁问题:
374
+ * 1. 避免在任务队列内部进行递归调用
375
+ * 2. 使用正确的循环引用检测机制
376
+ * 3. 分离查询和递归处理逻辑
377
+ */
378
+ async processObjectRecursively(objectType, objectName, depth) {
379
+ if (depth > this.config.maxRecursionDepth) {
380
+ console.error(`达到最大递归深度 ${this.config.maxRecursionDepth},停止处理`);
381
+ return;
382
+ }
383
+ const objectKey = this.generateObjectKey(objectType, objectName);
384
+ // 检查对象缓存,避免重复处理
385
+ if (this.objectCache.has(objectKey)) {
386
+ console.error(`对象已缓存,跳过处理: ${objectKey}`);
387
+ return;
388
+ }
389
+ // 检查循环引用 - 修复:使用永久标记,不在finally中删除
390
+ if (this.context.visitedPaths.has(objectKey)) {
391
+ this.result.statistics.circularReferences++;
392
+ console.error(`检测到循环引用: ${objectKey}`);
393
+ return;
394
+ }
395
+ // 标记为已访问(永久标记,防止循环引用)
396
+ this.context.visitedPaths.add(objectKey);
397
+ // 先标记缓存,防止并发时重复处理
398
+ this.objectCache.set(objectKey, null);
399
+ try {
400
+ // 使用任务队列进行并发处理 - 只处理当前对象,不在队列内递归
401
+ await this.taskQueue.add(objectKey, async () => {
402
+ this.context.currentDepth = depth;
403
+ this.result.statistics.maxDepthReached = Math.max(this.result.statistics.maxDepthReached, depth);
404
+ console.error(`[并发处理] 开始处理对象: ${objectType} - ${objectName} (深度: ${depth})`);
405
+ console.error(`[队列状态] 运行中: ${this.taskQueue.getRunningCount()}, 等待中: ${this.taskQueue.getQueueSize()}`);
406
+ // 1. 查询对象引用内容(包含函数组信息)
407
+ const queryResult = await this.queryObjectReferences(objectType, objectName);
408
+ if (!queryResult.success || !queryResult.data) {
409
+ console.error(`查询对象失败: ${objectType} - ${objectName}, 错误: ${queryResult.error}`);
410
+ throw new Error(queryResult.error || '查询失败');
411
+ }
412
+ const objectData = queryResult.data;
413
+ // 更新缓存为实际数据
414
+ this.objectCache.set(objectKey, objectData);
415
+ // 设置原始对象(仅在第一次调用时)
416
+ if (depth === 0) {
417
+ this.result.originalObject = objectData;
418
+ }
419
+ // 存储对象数据
420
+ this.result.allObjects.set(objectKey, objectData);
421
+ this.result.statistics.totalObjects++;
422
+ console.error(`[并发处理] 完成查询对象: ${objectType} - ${objectName}`);
423
+ return objectData;
424
+ });
425
+ // 2. 在队列外部处理递归调用,避免嵌套死锁
426
+ const objectData = this.objectCache.get(objectKey);
427
+ if (!objectData) {
428
+ return; // 查询失败,已记录错误
429
+ }
430
+ // 智能请求间隔控制:只在队列压力过大时添加延迟
431
+ const queueSize = this.taskQueue.getQueueSize();
432
+ const runningCount = this.taskQueue.getRunningCount();
433
+ const totalPending = queueSize + runningCount;
434
+ if (this.config.requestInterval > 0 && totalPending > this.config.concurrentRequestLimit * 2) {
435
+ console.error(`[智能延迟] 队列积压严重(等待:${queueSize}, 运行中:${runningCount}),添加 ${this.config.requestInterval}ms 延迟`);
436
+ await this.delay(this.config.requestInterval);
437
+ }
438
+ // 3. 收集需要递归处理的子对象
439
+ const childObjects = [];
440
+ // 收集类引用
441
+ if (this.config.recursiveClasses && objectData.ET_REFCLASS && Array.isArray(objectData.ET_REFCLASS)) {
442
+ if (depth < this.config.maxRecursionDepth) {
443
+ this.result.statistics.totalClasses += objectData.ET_REFCLASS.length;
444
+ console.error(`[递归检查] 当前深度 ${depth},最大深度 ${this.config.maxRecursionDepth},准备递归处理 ${objectData.ET_REFCLASS.length} 个类`);
445
+ for (const cls of objectData.ET_REFCLASS) {
446
+ if (cls.CLSNAME) {
447
+ childObjects.push({ type: 'CLASS', name: cls.CLSNAME });
448
+ }
449
+ }
450
+ }
451
+ else {
452
+ console.error(`[递归限制] 已达到最大递归深度 ${this.config.maxRecursionDepth},跳过类递归处理`);
453
+ }
454
+ }
455
+ // 收集函数引用
456
+ if (this.config.recursiveFunctions && objectData.ET_REFFUNCTION && Array.isArray(objectData.ET_REFFUNCTION)) {
457
+ if (depth < this.config.maxRecursionDepth) {
458
+ this.result.statistics.totalFunctions += objectData.ET_REFFUNCTION.length;
459
+ console.error(`[递归检查] 当前深度 ${depth},最大深度 ${this.config.maxRecursionDepth},准备递归处理 ${objectData.ET_REFFUNCTION.length} 个函数`);
460
+ for (const func of objectData.ET_REFFUNCTION) {
461
+ if (func.FUNCTIONNAME) {
462
+ childObjects.push({ type: 'FUNCTION', name: func.FUNCTIONNAME });
463
+ }
464
+ }
465
+ }
466
+ else {
467
+ console.error(`[递归限制] 已达到最大递归深度 ${this.config.maxRecursionDepth},跳过函数递归处理`);
468
+ }
469
+ }
470
+ // 收集程序引用
471
+ if (this.config.recursivePrograms && objectData.ET_REFPROGRAM && Array.isArray(objectData.ET_REFPROGRAM)) {
472
+ if (depth < this.config.maxRecursionDepth) {
473
+ this.result.statistics.totalPrograms += objectData.ET_REFPROGRAM.length;
474
+ console.error(`[递归检查] 当前深度 ${depth},最大深度 ${this.config.maxRecursionDepth},准备递归处理 ${objectData.ET_REFPROGRAM.length} 个程序`);
475
+ for (const prog of objectData.ET_REFPROGRAM) {
476
+ if (prog.PROGNAME) {
477
+ childObjects.push({ type: 'PROGRAM', name: prog.PROGNAME });
478
+ }
479
+ }
480
+ }
481
+ else {
482
+ console.error(`[递归限制] 已达到最大递归深度 ${this.config.maxRecursionDepth},跳过程序递归处理`);
483
+ }
484
+ }
485
+ // 4. 在队列外部递归处理子对象,避免死锁
486
+ if (childObjects.length > 0) {
487
+ console.error(`[批量递归] 准备递归处理 ${childObjects.length} 个子对象 (深度: ${depth + 1})`);
488
+ // 应用过滤条件,排除不需要递归的对象
489
+ const filteredChildObjects = childObjects.filter(child => {
490
+ const shouldFilter = this.shouldFilterRecursion(child.type, child.name);
491
+ if (shouldFilter) {
492
+ console.error(`[递归过滤] 跳过子对象 ${child.type}:${child.name} 的递归处理`);
493
+ }
494
+ return !shouldFilter;
495
+ });
496
+ if (filteredChildObjects.length > 0) {
497
+ console.error(`[批量递归] 经过过滤后剩余 ${filteredChildObjects.length} 个子对象需要递归处理`);
498
+ // 使用 Promise.allSettled 并发处理所有子对象
499
+ // 这里的递归调用会再次进入任务队列,由队列控制并发
500
+ const childPromises = filteredChildObjects.map(child => this.processObjectRecursively(child.type, child.name, depth + 1)
501
+ .catch(error => {
502
+ const errorMessage = `递归处理 ${child.type}:${child.name} 失败: ${error instanceof Error ? error.message : String(error)}`;
503
+ console.error(errorMessage);
504
+ }));
505
+ await Promise.allSettled(childPromises);
506
+ console.error(`[批量递归] 完成递归处理 ${filteredChildObjects.length} 个子对象`);
507
+ }
508
+ else if (childObjects.length > 0) {
509
+ console.error(`[批量递归] 所有 ${childObjects.length} 个子对象都被过滤,不进行递归处理`);
510
+ }
511
+ }
512
+ console.error(`[并发处理] 完全完成对象处理: ${objectType} - ${objectName}`);
513
+ }
514
+ catch (error) {
515
+ const errorMessage = `处理对象 ${objectKey} 失败: ${error instanceof Error ? error.message : String(error)}`;
516
+ this.result.errors.push(errorMessage);
517
+ console.error(errorMessage);
518
+ // 不删除 visitedPaths,保持循环引用保护
519
+ // 但清理无效的缓存
520
+ if (!this.objectCache.get(objectKey)) {
521
+ this.objectCache.delete(objectKey);
522
+ }
523
+ }
524
+ }
525
+ /**
526
+ * 处理函数组
527
+ * 当处理函数时,提取函数组信息并生成函数组文件
528
+ */
529
+ async processFunctionGroup(functions, objectName) {
530
+ if (!functions || functions.length === 0) {
531
+ return;
532
+ }
533
+ // 提取函数组名称
534
+ const functionGroup = functions[0]?.FUNCTIONGROUP;
535
+ if (!functionGroup) {
536
+ console.error(`函数 ${objectName} 没有函数组信息,跳过函数组文件生成`);
537
+ return;
538
+ }
539
+ console.error(`处理函数组: ${functionGroup},包含 ${functions.length} 个函数`);
540
+ try {
541
+ // 准备函数列表数据
542
+ const functionList = functions.map(func => ({
543
+ FUNCNAME: func.FUNCTIONNAME || objectName,
544
+ FMODE: func.FMODE || '',
545
+ STEXT: func.SHORT_TEXT || func.STEXT || '',
546
+ REMOTE_CALL: func.REMOTE_CALL || ''
547
+ }));
548
+ // 使用 functionGroupGenerator 生成函数组文件
549
+ await (0, generate_1.generateFunctionGroupFiles)(functionGroup, functionList, this.config.downloadRootPath, this.result.downloadedFiles);
550
+ console.error(`函数组 ${functionGroup} 处理完成`);
551
+ }
552
+ catch (error) {
553
+ const errorMessage = `处理函数组 ${functionGroup} 失败: ${error instanceof Error ? error.message : String(error)}`;
554
+ this.result.errors.push(errorMessage);
555
+ console.error(errorMessage);
556
+ }
557
+ }
558
+ /**
559
+ * 处理包含文件
560
+ */
561
+ async processIncludes(includes) {
562
+ this.result.statistics.totalIncludes += includes.length;
563
+ for (const include of includes) {
564
+ if (!include.INCLUDENAME)
565
+ continue;
566
+ const includeName = include.INCLUDENAME;
567
+ console.error(`处理包含文件: ${includeName}`);
568
+ // 下载包含文件(如果配置了)
569
+ if (this.config.downloadIncludes) {
570
+ await this.downloadIncludeWithTypeDetection(includeName);
571
+ }
572
+ }
573
+ }
574
+ /**
575
+ * 下载 include 文件并根据内容自动检测类型,添加符合 abaplint 规范的后缀
576
+ */
577
+ async downloadIncludeWithTypeDetection(includeName) {
578
+ const expectedFilePath = this.generateFilePath(includeName, 'INCLUDE');
579
+ try {
580
+ // 1. 获取 include 文件内容
581
+ const includeResult = await (0, handleGetInclude_1.handleGetInclude)({ include_name: includeName });
582
+ // 统一处理错误情况
583
+ if (!includeResult) {
584
+ throw new Error(`获取包含文件 ${includeName} 失败: 无响应数据`);
585
+ }
586
+ if (includeResult.isError) {
587
+ const errorText = Array.isArray(includeResult.content) && includeResult.content.length > 0
588
+ ? includeResult.content[0].text || '未知错误'
589
+ : '未知错误';
590
+ throw new Error(`获取包含文件 ${includeName} 失败: ${errorText}`);
591
+ }
592
+ if (!includeResult.content) {
593
+ throw new Error(`获取包含文件 ${includeName} 失败: 无有效内容返回`);
594
+ }
595
+ const content = Array.isArray(includeResult.content)
596
+ ? includeResult.content.map(item => item.text || '').join('\n')
597
+ : String(includeResult.content || '');
598
+ // 2. 分析内容类型
599
+ const includeType = this.detectIncludeType(content, includeName);
600
+ console.error(`检测到包含文件 ${includeName} 的类型: ${includeType}`);
601
+ // 3. 根据类型生成文件路径
602
+ const finalFilePath = this.generateIncludeFilePath(includeName, includeType);
603
+ // 确保目录存在
604
+ const dirPath = (0, path_1.dirname)(finalFilePath);
605
+ if (!(0, fs_1.existsSync)(dirPath)) {
606
+ (0, fs_1.mkdirSync)(dirPath, { recursive: true });
607
+ }
608
+ // 4. 下载文件
609
+ const downloadResult = await (0, download_1.downloadFile)(content, finalFilePath, 'abap');
610
+ this.result.downloadedFiles.push({
611
+ objectName: includeName,
612
+ objectType: 'INCLUDE',
613
+ filePath: finalFilePath,
614
+ success: downloadResult.success,
615
+ error: downloadResult.success ? undefined : downloadResult.message,
616
+ metadata: {
617
+ detectedType: includeType
618
+ }
619
+ });
620
+ if (downloadResult.success) {
621
+ this.result.statistics.downloadedIncludes++;
622
+ console.error(`包含文件下载成功: ${includeName} [${includeType}] -> ${downloadResult.filePath}`);
623
+ }
624
+ else {
625
+ console.error(`包含文件下载失败: ${includeName} - ${downloadResult.message}`);
626
+ }
627
+ }
628
+ catch (error) {
629
+ this.handleDownloadError(includeName, 'INCLUDE', expectedFilePath, error);
630
+ }
631
+ }
632
+ /**
633
+ * 使用 abaplint 进行精确的语法分析来检测 include 文件类型
634
+ * 这是最准确的方法,因为它真正解析了 ABAP 语法
635
+ */
636
+ detectIncludeType(content, fileName) {
637
+ console.error(`[类型检测] 使用 abaplint 分析文件: ${fileName}`);
638
+ try {
639
+ // 创建临时 Registry 和文件
640
+ const tempRegistry = new core_1.Registry(core_1.Config.getDefault());
641
+ // abaplint 需要 .prog.abap 或类似后缀才能识别
642
+ const tempFileName = `${fileName}.prog.abap`;
643
+ const memFile = new core_1.MemoryFile(tempFileName, content);
644
+ tempRegistry.addFile(memFile);
645
+ tempRegistry.parse();
646
+ // 获取对象(abaplint 会尝试识别文件类型)
647
+ const obj = tempRegistry.findObjectForFile(memFile);
648
+ console.error(`[abaplint] 对象类型: ${obj ? obj.getType() : 'null'}`);
649
+ if (obj && obj instanceof core_1.ABAPObject) {
650
+ const abapFiles = obj.getABAPFiles();
651
+ console.error(`[abaplint] ABAP 文件数: ${abapFiles.length}`);
652
+ if (abapFiles.length > 0) {
653
+ const file = abapFiles[0];
654
+ const fileInfo = file.getInfo();
655
+ // 检查是否包含测试类
656
+ const testClasses = fileInfo.listClassDefinitions().filter(cls => cls.isForTesting);
657
+ if (testClasses.length > 0) {
658
+ console.error(`[abaplint] 检测到 ${testClasses.length} 个测试类 -> TESTCLASSES`);
659
+ return 'TESTCLASSES';
660
+ }
661
+ // 检查类定义和实现
662
+ const classDefinitions = fileInfo.listClassDefinitions();
663
+ const classImplementations = fileInfo.listClassImplementations();
664
+ console.error(`[abaplint] 类定义: ${classDefinitions.length}, 类实现: ${classImplementations.length}`);
665
+ if (classDefinitions.length > 0 && classImplementations.length === 0) {
666
+ console.error(`[abaplint] 检测为: LOCALS_DEF`);
667
+ return 'LOCALS_DEF';
668
+ }
669
+ if (classImplementations.length > 0) {
670
+ console.error(`[abaplint] 检测为: LOCALS_IMP`);
671
+ return 'LOCALS_IMP';
672
+ }
673
+ // 检查接口定义
674
+ const interfaces = fileInfo.listInterfaceDefinitions();
675
+ if (interfaces.length > 0) {
676
+ console.error(`[abaplint] 检测到 ${interfaces.length} 个接口定义 -> LOCALS_DEF`);
677
+ return 'LOCALS_DEF'; // 接口定义也使用 locals_def
678
+ }
679
+ // 检查 FORM 子例程
680
+ const forms = fileInfo.listFormDefinitions();
681
+ console.error(`[abaplint] FORM 子例程数: ${forms.length}`);
682
+ if (forms.length >= 1) {
683
+ console.error(`[abaplint] 检测到 ${forms.length} 个子例程 -> SUBROUTINES`);
684
+ return 'SUBROUTINES';
685
+ }
686
+ }
687
+ }
688
+ else {
689
+ console.error(`[abaplint] 无法识别为 ABAPObject`);
690
+ }
691
+ console.error(`[abaplint] 未检测到特殊类型 -> STANDARD`);
692
+ return 'STANDARD';
693
+ }
694
+ catch (error) {
695
+ console.error(`[abaplint] 解析失败: ${error instanceof Error ? error.message : String(error)}`);
696
+ if (error instanceof Error && error.stack) {
697
+ console.error(`[abaplint] 堆栈: ${error.stack.substring(0, 500)}`);
698
+ }
699
+ // 解析失败时返回标准类型
700
+ return 'STANDARD';
701
+ }
702
+ }
703
+ /**
704
+ * 根据 include 类型生成符合 abaplint 规范的文件路径
705
+ */
706
+ generateIncludeFilePath(includeName, includeType) {
707
+ const sanitizedName = includeName
708
+ .replace(/[/\\]/g, '_')
709
+ .replace(/[<>]/g, '#')
710
+ .replace(/[^a-zA-Z0-9_#]/g, '_');
711
+ let extension;
712
+ switch (includeType) {
713
+ case 'LOCALS_DEF':
714
+ extension = 'clas.locals_def.abap';
715
+ break;
716
+ case 'LOCALS_IMP':
717
+ extension = 'clas.locals_imp.abap';
718
+ break;
719
+ case 'TESTCLASSES':
720
+ extension = 'clas.testclasses.abap';
721
+ break;
722
+ case 'MACROS':
723
+ extension = 'clas.macros.abap';
724
+ break;
725
+ case 'SCREENS':
726
+ extension = 'prog.screens.abap';
727
+ break;
728
+ case 'SUBROUTINES':
729
+ extension = 'prog.subs.abap';
730
+ break;
731
+ case 'STANDARD':
732
+ default:
733
+ extension = 'prog.abap';
734
+ break;
735
+ }
736
+ return (0, path_1.join)(this.config.downloadRootPath, 'includes', `${sanitizedName}.${extension}`);
737
+ }
738
+ /**
739
+ * 处理文本元素
740
+ * 按照abapGit协议,文本元素应该单独导出为XML文件
741
+ */
742
+ async processTextElements(textElements, objectName, objectType) {
743
+ if (!textElements || textElements.length === 0) {
744
+ return;
745
+ }
746
+ console.error(`处理${objectType} ${objectName} 的文本元素,共 ${textElements.length} 个`);
747
+ try {
748
+ // 使用textElementGenerator生成XML文件
749
+ await (0, generate_1.generateTextElementsXml)(textElements, objectName, objectType, this.config.downloadRootPath, this.result.downloadedFiles);
750
+ }
751
+ catch (error) {
752
+ const errorMessage = `处理${objectType} ${objectName} 的文本元素失败: ${error instanceof Error ? error.message : String(error)}`;
753
+ this.result.errors.push(errorMessage);
754
+ console.error(errorMessage);
755
+ }
756
+ }
757
+ /**
758
+ * 处理消息
759
+ * 按照abapGit协议,消息应该使用MSAG XML格式单独导出
760
+ */
761
+ async processMessages(messages, objectName, objectType) {
762
+ if (!messages || messages.length === 0) {
763
+ return;
764
+ }
765
+ console.error(`处理${objectType} ${objectName} 的消息,共 ${messages.length} 个`);
766
+ try {
767
+ // 使用messageGenerator生成XML文件
768
+ await (0, generate_1.generateMessageClassXml)(messages, objectName, this.config.downloadRootPath, this.result.downloadedFiles);
769
+ }
770
+ catch (error) {
771
+ const errorMessage = `处理${objectType} ${objectName} 的消息失败: ${error instanceof Error ? error.message : String(error)}`;
772
+ this.result.errors.push(errorMessage);
773
+ console.error(errorMessage);
774
+ }
775
+ }
776
+ /**
777
+ * 处理GUI标题
778
+ */
779
+ async processGuiTitles(guiTitles, objectName, objectType) {
780
+ if (!guiTitles || guiTitles.length === 0) {
781
+ return;
782
+ }
783
+ console.error(`处理${objectType} ${objectName} 的GUI标题,共 ${guiTitles.length} 个`);
784
+ try {
785
+ // 导出到JSON文件 - 下载到guiTitles目录下
786
+ const baseDir = (0, path_1.join)(this.config.downloadRootPath, 'guiTitles');
787
+ if (!(0, fs_1.existsSync)(baseDir)) {
788
+ (0, fs_1.mkdirSync)(baseDir, { recursive: true });
789
+ }
790
+ const safeObjectName = objectName.replace(/[/\\]/g, '_');
791
+ const guiTitlesPath = (0, path_1.join)(baseDir, `${safeObjectName}_${objectType.toLowerCase()}_guititles.json`);
792
+ (0, fs_1.writeFileSync)(guiTitlesPath, JSON.stringify(guiTitles, null, 2), 'utf-8');
793
+ console.error(`导出${objectType} ${objectName} 的GUI标题到: ${guiTitlesPath}`);
794
+ // 记录下载统计
795
+ this.result.downloadedFiles.push({
796
+ objectName: objectName,
797
+ objectType: 'GUI_TITLE',
798
+ filePath: guiTitlesPath,
799
+ success: true,
800
+ metadata: {
801
+ titleCount: guiTitles.length,
802
+ exportType: 'separate',
803
+ objectType: objectType
804
+ }
805
+ });
806
+ }
807
+ catch (error) {
808
+ const errorMessage = `处理${objectType} ${objectName} 的GUI标题失败: ${error instanceof Error ? error.message : String(error)}`;
809
+ this.result.errors.push(errorMessage);
810
+ console.error(errorMessage);
811
+ }
812
+ }
813
+ /**
814
+ * 处理结构体
815
+ */
816
+ async processStructures(structures) {
817
+ this.result.statistics.totalStructures += structures.length;
818
+ if (!this.config.downloadStructures) {
819
+ return;
820
+ }
821
+ for (const structure of structures) {
822
+ if (!structure.TABLENAME)
823
+ continue;
824
+ await this.processSingleStructure(structure);
825
+ }
826
+ }
827
+ /**
828
+ * 处理单个结构体
829
+ */
830
+ async processSingleStructure(structure) {
831
+ const structureName = structure.TABLENAME;
832
+ console.error(`处理结构体: ${structureName}`);
833
+ const expectedFilePath = this.generateFilePath(structureName, 'STRUCTURE');
834
+ try {
835
+ // 使用structureGenerator生成结构体内容
836
+ const structureContent = (0, generate_1.generateStructureContent)(structure);
837
+ await this.downloadStructureFile(structureContent, expectedFilePath, structureName);
838
+ // 处理结构体字段中的domain定义
839
+ if (structure.ISTRUCTURE && structure.ISTRUCTURE.length > 0) {
840
+ await this.processStructureDomains(structure.ISTRUCTURE, structureName);
841
+ }
842
+ // 如果是透明表(TRANSP),则调用Z_TABLE_QUERY获取完整表结构信息
843
+ if (structure.TABLECLASS === 'TRANSP') {
844
+ console.error(`检测到透明表 ${structureName},开始获取完整表结构信息`);
845
+ await this.processTransparentTable(structureName);
846
+ }
847
+ }
848
+ catch (error) {
849
+ this.handleDownloadError(structureName, 'STRUCTURE', expectedFilePath, error);
850
+ }
851
+ }
852
+ /**
853
+ * 处理透明表,获取并保存完整表结构信息
854
+ */
855
+ async processTransparentTable(tableName) {
856
+ try {
857
+ const response = await (0, handleZTableQuery_1.handleZTableQuery)({ name: tableName });
858
+ if (response && response.content && response.content.length > 0) {
859
+ const tableData = response.content[0].text;
860
+ // 解析JSON数据
861
+ let parsedData;
862
+ try {
863
+ parsedData = tableData;
864
+ }
865
+ catch (parseError) {
866
+ console.error(`解析表结构数据失败: ${tableName}, 错误: ${parseError}`);
867
+ return;
868
+ }
869
+ // 转换为 TableData 格式(单表结构:表信息 + 字段列表 + 索引列表)
870
+ const tableInfo = parsedData.GT_TABLES && parsedData.GT_TABLES.length > 0
871
+ ? parsedData.GT_TABLES[0]
872
+ : { TABNAME: tableName };
873
+ const finalTableData = {
874
+ IDX: tableInfo.IDX,
875
+ TABNAME: tableInfo.TABNAME,
876
+ TABCLASS: tableInfo.TABCLASS,
877
+ DDTEXT_ZH: tableInfo.DDTEXT_ZH,
878
+ DDTEXT_EN: tableInfo.DDTEXT_EN,
879
+ GT_FIELDS: parsedData.GT_FIELDS || [],
880
+ GT_INDEXS: parsedData.GT_INDEXS || []
881
+ };
882
+ // 生成文件路径:downloadRootPath/tables/表名.json
883
+ const tablesDir = (0, path_1.join)(this.config.downloadRootPath, 'tables');
884
+ if (!(0, fs_1.existsSync)(tablesDir)) {
885
+ (0, fs_1.mkdirSync)(tablesDir, { recursive: true });
886
+ }
887
+ const sanitizedName = tableName
888
+ .replace(/[/\\]/g, '_')
889
+ .replace(/[<>]/g, '#')
890
+ .replace(/[^a-zA-Z0-9_#]/g, '_');
891
+ const tableFilePath = (0, path_1.join)(tablesDir, `${sanitizedName}.json`);
892
+ // 保存JSON文件
893
+ (0, fs_1.writeFileSync)(tableFilePath, JSON.stringify(finalTableData, null, 2), 'utf-8');
894
+ console.error(`透明表结构已保存: ${tableFilePath}`);
895
+ // 记录下载结果
896
+ this.result.downloadedFiles.push({
897
+ objectName: tableName,
898
+ objectType: 'TABLE',
899
+ filePath: tableFilePath,
900
+ success: true
901
+ });
902
+ }
903
+ else {
904
+ console.error(`获取透明表结构失败: ${tableName}, 无有效数据返回`);
905
+ }
906
+ }
907
+ catch (error) {
908
+ console.error(`处理透明表失败: ${tableName}, 错误: ${error instanceof Error ? error.message : String(error)}`);
909
+ // 记录错误
910
+ this.result.downloadedFiles.push({
911
+ objectName: tableName,
912
+ objectType: 'TABLE',
913
+ filePath: (0, path_1.join)(this.config.downloadRootPath, 'tables', `${tableName}.json`),
914
+ success: false,
915
+ error: error instanceof Error ? error.message : String(error)
916
+ });
917
+ }
918
+ }
919
+ /**
920
+ * 处理结构体字段中的domain定义
921
+ */
922
+ async processStructureDomains(fields, structureName) {
923
+ const domainsMap = new Map();
924
+ // 收集所有需要处理的domain及其数据
925
+ for (const field of fields) {
926
+ if (field.IDOMAINS && field.IDOMAINS.length > 0) {
927
+ for (const domain of field.IDOMAINS) {
928
+ if (domain.DOMNAME) {
929
+ if (!domainsMap.has(domain.DOMNAME)) {
930
+ domainsMap.set(domain.DOMNAME, []);
931
+ }
932
+ domainsMap.get(domain.DOMNAME).push(domain);
933
+ }
934
+ }
935
+ }
936
+ }
937
+ if (domainsMap.size === 0) {
938
+ return;
939
+ }
940
+ console.error(`结构体 ${structureName} 包含 ${domainsMap.size} 个domain定义,开始导出...`);
941
+ // 更新统计信息
942
+ this.result.statistics.totalDomains += domainsMap.size;
943
+ // 确保domain目录存在
944
+ const domainsDir = (0, path_1.join)(this.config.downloadRootPath, 'structures', 'domains');
945
+ if (!(0, fs_1.existsSync)(domainsDir)) {
946
+ (0, fs_1.mkdirSync)(domainsDir, { recursive: true });
947
+ }
948
+ // 处理每个domain
949
+ for (const [domainName, domainData] of domainsMap) {
950
+ await this.processSingleDomain(domainName, structureName, domainData);
951
+ }
952
+ }
953
+ /**
954
+ * 处理单个domain定义
955
+ */
956
+ async processSingleDomain(domainName, structureName, domainData) {
957
+ try {
958
+ console.error(`处理domain: ${domainName} (来自结构体 ${structureName})`);
959
+ // 使用domainGenerator生成domain文件内容
960
+ const domainContent = (0, generate_1.generateDomainContent)(domainName, domainData);
961
+ // 获取domain文件路径
962
+ const domainFilePath = this.generateFilePath(domainName, 'DOMAIN');
963
+ // 下载domain文件
964
+ await this.downloadDomainFile(domainContent, domainFilePath, domainName, structureName);
965
+ }
966
+ catch (error) {
967
+ const errorMessage = `处理domain ${domainName} 失败: ${error instanceof Error ? error.message : String(error)}`;
968
+ this.result.errors.push(errorMessage);
969
+ console.error(errorMessage);
970
+ }
971
+ }
972
+ /**
973
+ * 统一的文件路径生成器 - 根据对象类型和名称生成标准文件路径
974
+ * 支持多种ABAP对象类型:DOMAIN, STRUCTURE, CLASS, FUNCTION, PROGRAM, INCLUDE
975
+ */
976
+ generateFilePath(objectName, objectType, extension) {
977
+ const sanitizedName = objectName
978
+ .replace(/[/\\]/g, '_') // 路径分隔符替换为下划线
979
+ .replace(/[<>]/g, '#') // 命名空间尖括号替换为#
980
+ .replace(/[^a-zA-Z0-9_#]/g, '_'); // 其他特殊字符替换为下划线
981
+ const defaultExtension = this.getDefaultExtension(objectType);
982
+ const fileExtension = extension || defaultExtension;
983
+ const directory = this.getObjectDirectory(objectType);
984
+ return (0, path_1.join)(this.config.downloadRootPath, directory, `${sanitizedName}.${fileExtension}`);
985
+ }
986
+ /**
987
+ * 获取ABAP对象类型的默认文件扩展名
988
+ */
989
+ getDefaultExtension(objectType) {
990
+ const extensionMap = {
991
+ 'DOMAIN': 'dom.abap',
992
+ 'STRUCTURE': 'tabl.abap',
993
+ 'CLASS': 'clas.abap',
994
+ 'FUNCTION': 'func.abap',
995
+ 'PROGRAM': 'prog.abap',
996
+ 'INCLUDE': 'abap'
997
+ };
998
+ return extensionMap[objectType.toUpperCase()] || 'abap';
999
+ }
1000
+ /**
1001
+ * 获取ABAP对象类型的标准目录名
1002
+ */
1003
+ getObjectDirectory(objectType) {
1004
+ const directoryMap = {
1005
+ 'DOMAIN': 'structures/domains',
1006
+ 'STRUCTURE': 'structures',
1007
+ 'CLASS': 'classes',
1008
+ 'FUNCTION': 'functions',
1009
+ 'PROGRAM': 'programs',
1010
+ 'INCLUDE': 'includes'
1011
+ };
1012
+ return directoryMap[objectType.toUpperCase()] || 'others';
1013
+ }
1014
+ /**
1015
+ * 下载domain文件
1016
+ */
1017
+ async downloadDomainFile(content, filePath, domainName, structureName) {
1018
+ const dirPath = (0, path_1.dirname)(filePath);
1019
+ if (!(0, fs_1.existsSync)(dirPath)) {
1020
+ (0, fs_1.mkdirSync)(dirPath, { recursive: true });
1021
+ }
1022
+ const downloadResult = await (0, download_1.downloadFile)(content, filePath, 'abap');
1023
+ this.result.downloadedFiles.push({
1024
+ objectName: domainName,
1025
+ objectType: 'DOMAIN',
1026
+ filePath: filePath,
1027
+ success: downloadResult.success,
1028
+ error: downloadResult.success ? undefined : downloadResult.message
1029
+ });
1030
+ if (downloadResult.success) {
1031
+ this.result.statistics.downloadedDomains++;
1032
+ console.error(`domain生成成功: ${domainName} (来自结构体 ${structureName}) -> ${downloadResult.filePath}`);
1033
+ }
1034
+ else {
1035
+ console.error(`domain生成失败: ${domainName} (来自结构体 ${structureName}) - ${downloadResult.message}`);
1036
+ }
1037
+ }
1038
+ /**
1039
+ * 下载结构文件
1040
+ */
1041
+ async downloadStructureFile(content, filePath, structureName) {
1042
+ const dirPath = (0, path_1.dirname)(filePath);
1043
+ if (!(0, fs_1.existsSync)(dirPath)) {
1044
+ (0, fs_1.mkdirSync)(dirPath, { recursive: true });
1045
+ }
1046
+ const downloadResult = await (0, download_1.downloadFile)(content, filePath, 'abap');
1047
+ this.result.downloadedFiles.push({
1048
+ objectName: structureName,
1049
+ objectType: 'STRUCTURE',
1050
+ filePath: filePath,
1051
+ success: downloadResult.success,
1052
+ error: downloadResult.success ? undefined : downloadResult.message
1053
+ });
1054
+ if (downloadResult.success) {
1055
+ this.result.statistics.downloadedStructures++;
1056
+ console.error(`结构体生成成功: ${structureName} -> ${downloadResult.filePath}`);
1057
+ }
1058
+ else {
1059
+ console.error(`结构体生成失败: ${structureName} - ${downloadResult.message}`);
1060
+ }
1061
+ }
1062
+ /**
1063
+ * 通用下载错误处理方法
1064
+ */
1065
+ handleDownloadError(objectName, objectType, expectedFilePath, error) {
1066
+ const errorMessage = `下载${objectType} ${objectName} 失败: ${error instanceof Error ? error.message : String(error)}`;
1067
+ this.result.errors.push(errorMessage);
1068
+ console.error(errorMessage);
1069
+ this.result.downloadedFiles.push({
1070
+ objectName: objectName,
1071
+ objectType: objectType,
1072
+ filePath: expectedFilePath,
1073
+ success: false,
1074
+ error: errorMessage
1075
+ });
1076
+ }
1077
+ /**
1078
+ * 从对象数据中提取函数组信息
1079
+ */
1080
+ extractFunctionGroup(objectData) {
1081
+ console.error(objectData.ET_FUNCTION);
1082
+ if (objectData.ET_FUNCTION && Array.isArray(objectData.ET_FUNCTION) && objectData.ET_FUNCTION.length > 0) {
1083
+ const func = objectData.ET_FUNCTION[0];
1084
+ return func.FUNCTIONGROUP ?? null;
1085
+ }
1086
+ else {
1087
+ return null;
1088
+ }
1089
+ }
1090
+ /**
1091
+ * 使用已有的对象数据下载对象源代码(包含正确的函数组信息)
1092
+ */
1093
+ async downloadObjectSourceWithData(objectType, objectName, objectData) {
1094
+ // 使用统一的文件路径生成器
1095
+ const expectedFilePath = this.generateFilePath(objectName, objectType);
1096
+ try {
1097
+ console.error(`使用对象数据下载源代码: ${objectType} - ${objectName}`);
1098
+ let sourceResult;
1099
+ let functionGroup = null;
1100
+ switch (objectType.toUpperCase()) {
1101
+ case 'CLASS':
1102
+ sourceResult = await (0, handleGetClass_1.handleGetClass)({ class_name: objectName });
1103
+ break;
1104
+ case 'FUNCTION':
1105
+ let functionGroup = this.extractFunctionGroup(objectData);
1106
+ console.error(functionGroup);
1107
+ // 如果无法从对象数据中提取函数组,尝试使用函数名前缀作为函数组
1108
+ if (!functionGroup) {
1109
+ functionGroup = objectName.split('_')[0] || objectName;
1110
+ console.error(`无法从对象数据中提取函数组,使用函数名前缀作为函数组: ${functionGroup}`);
1111
+ }
1112
+ else {
1113
+ console.error(`从对象数据中提取到函数组: ${functionGroup}`);
1114
+ }
1115
+ // 使用正确的函数组和函数名调用handleGetFunction
1116
+ sourceResult = await (0, handleGetFunction_1.handleGetFunction)({
1117
+ function_name: objectName,
1118
+ function_group: functionGroup
1119
+ });
1120
+ break;
1121
+ case 'PROGRAM':
1122
+ sourceResult = await (0, handleGetProgram_1.handleGetProgram)({ program_name: objectName });
1123
+ break;
1124
+ default:
1125
+ console.error(`不支持的下载对象类型: ${objectType}`);
1126
+ return { success: true }; // 不支持的类型不视为错误
1127
+ }
1128
+ // handlers 统一返回 return_response 格式,需要检查错误和提取内容
1129
+ if (!sourceResult) {
1130
+ throw new Error(`对象源代码获取失败: ${objectType} - ${objectName} - 无响应数据`);
1131
+ }
1132
+ // 检查是否是错误响应
1133
+ if (sourceResult.isError) {
1134
+ const errorText = Array.isArray(sourceResult.content) && sourceResult.content.length > 0
1135
+ ? sourceResult.content[0].text || '未知错误'
1136
+ : '未知错误';
1137
+ throw new Error(`对象源代码获取失败: ${objectType} - ${objectName} - ${errorText}`);
1138
+ }
1139
+ // 检查是否有有效内容
1140
+ if (!sourceResult.content || !Array.isArray(sourceResult.content) || sourceResult.content.length === 0) {
1141
+ throw new Error(`对象源代码为空: ${objectType} - ${objectName}`);
1142
+ }
1143
+ // 从 return_response 格式中提取源代码
1144
+ const sourceContent = sourceResult.content.map((item) => item.text || '').join('\n');
1145
+ // 确保目录存在 - 直接使用expectedFilePath的目录,保持与generateFilePath一致
1146
+ const dirPath = (0, path_1.dirname)(expectedFilePath);
1147
+ if (!(0, fs_1.existsSync)(dirPath)) {
1148
+ (0, fs_1.mkdirSync)(dirPath, { recursive: true });
1149
+ }
1150
+ // 直接使用expectedFilePath作为文件路径,避免路径不一致问题
1151
+ const filePath = expectedFilePath;
1152
+ const downloadResult = await (0, download_1.downloadFile)(sourceContent, filePath, 'abap');
1153
+ this.result.downloadedFiles.push({
1154
+ objectName: objectName,
1155
+ objectType: objectType,
1156
+ filePath: expectedFilePath,
1157
+ success: downloadResult.success,
1158
+ error: downloadResult.success ? undefined : downloadResult.message
1159
+ });
1160
+ if (downloadResult.success) {
1161
+ console.error(`对象源代码下载成功: ${objectType} - ${objectName} -> ${downloadResult.filePath}`);
1162
+ return { success: true };
1163
+ }
1164
+ else {
1165
+ console.error(`对象源代码下载失败: ${objectType} - ${objectName} - ${downloadResult.message}`);
1166
+ return { success: false, error: downloadResult.message };
1167
+ }
1168
+ }
1169
+ catch (error) {
1170
+ return { success: false, error: `下载对象源代码失败: ${objectType} - ${objectName} - ${error instanceof Error ? error.message : String(error)}` };
1171
+ }
1172
+ }
1173
+ /**
1174
+ * 查询对象引用内容(包含下载源代码)
1175
+ * 现在包含下载逻辑,因为需要函数组信息来正确下载函数源代码
1176
+ */
1177
+ async queryObjectReferences(objectType, objectName) {
1178
+ try {
1179
+ console.error(`查询对象引用内容: ${objectType} - ${objectName}`);
1180
+ const result = await (0, handleZObjectQuery_1.handleZObjectQuery)({
1181
+ query_type: objectType,
1182
+ query_name: objectName
1183
+ });
1184
+ // 成功: { isError: false, content: [{ type: 'text', text: data }] }
1185
+ // 失败: { isError: true, content: [{ type: 'text', text: 'Error: ...' }] }
1186
+ // 检查是否是错误响应
1187
+ if (result && typeof result === 'object' && 'isError' in result && result.isError) {
1188
+ const errorText = Array.isArray(result.content) && result.content.length > 0
1189
+ ? result.content[0].text || '未知错误'
1190
+ : '未知错误';
1191
+ throw new Error(`查询对象失败: ${objectType} - ${objectName}, ${errorText}`);
1192
+ }
1193
+ // 从 return_response 格式中提取数据
1194
+ let actualData;
1195
+ if (result && typeof result === 'object' && 'content' in result && Array.isArray(result.content)) {
1196
+ if (result.content.length > 0 && result.content[0].text) {
1197
+ actualData = result.content[0].text;
1198
+ }
1199
+ }
1200
+ if (actualData !== undefined && actualData !== null) {
1201
+ // 如果配置了下载包含文件,现在下载源代码(此时已有函数组信息)
1202
+ const downloadResult = await this.downloadObjectSourceWithData(objectType, objectName, actualData);
1203
+ if (!downloadResult.success) {
1204
+ const errorMessage = `对象源代码下载失败: ${objectType} - ${objectName}, 错误: ${downloadResult.error}`;
1205
+ console.warn(errorMessage);
1206
+ // 记录下载失败到错误列表
1207
+ // 使用统一的文件路径生成器
1208
+ const expectedFilePath = this.generateFilePath(objectName, objectType);
1209
+ this.handleDownloadError(objectName, objectType, expectedFilePath, downloadResult.error);
1210
+ }
1211
+ // 处理函数引用内容
1212
+ if (objectType.toUpperCase() === 'FUNCTION' && actualData.ET_FUNCTION && Array.isArray(actualData.ET_FUNCTION)) {
1213
+ // 提取函数组信息并生成函数组文件
1214
+ await this.processFunctionGroup(actualData.ET_FUNCTION, objectName);
1215
+ for (const func of actualData.ET_FUNCTION) {
1216
+ const functionName = func.FUNCTIONNAME || objectName;
1217
+ const progName = func.PROGNAME ? func.PROGNAME : ''; // 获取PROGNAME用于屏幕缓存
1218
+ // 处理包含文件
1219
+ if (func.IINCLUDES && Array.isArray(func.IINCLUDES) && func.IINCLUDES.length > 0) {
1220
+ console.error(`处理函数 ${functionName} 的包含文件,共 ${func.IINCLUDES.length} 个`);
1221
+ await this.processIncludes(func.IINCLUDES);
1222
+ }
1223
+ // 处理结构体
1224
+ if (func.IDICTSTRUCT && Array.isArray(func.IDICTSTRUCT) && func.IDICTSTRUCT.length > 0) {
1225
+ console.error(`处理函数 ${functionName} 的结构体,共 ${func.IDICTSTRUCT.length} 个`);
1226
+ await this.processStructures(func.IDICTSTRUCT);
1227
+ }
1228
+ // 处理文本元素
1229
+ if (func.ITEXTELEMENTS && Array.isArray(func.ITEXTELEMENTS) && func.ITEXTELEMENTS.length > 0) {
1230
+ await this.processTextElements(func.ITEXTELEMENTS, functionName, 'FUNCTION');
1231
+ }
1232
+ // 处理消息
1233
+ if (func.IMESSAGES && Array.isArray(func.IMESSAGES) && func.IMESSAGES.length > 0) {
1234
+ await this.processMessages(func.IMESSAGES, functionName, 'FUNCTION');
1235
+ }
1236
+ // 处理GUI标题
1237
+ if (func.IGUITITLE && Array.isArray(func.IGUITITLE) && func.IGUITITLE.length > 0) {
1238
+ await this.processGuiTitles(func.IGUITITLE, functionName, 'FUNCTION');
1239
+ }
1240
+ // 直接添加屏幕数据到缓存(使用PROGNAME)
1241
+ (0, generate_1.addScreenDataToCache)(this.screenCache, progName, func.ISCREENFIELD, func.ISCREENFLOW, func.ISCREENDESC);
1242
+ }
1243
+ }
1244
+ // 处理程序引用内容
1245
+ if (objectType.toUpperCase() === 'PROGRAM' && actualData.ET_PROGRAM && Array.isArray(actualData.ET_PROGRAM)) {
1246
+ for (const prog of actualData.ET_PROGRAM) {
1247
+ const programName = prog.PROGNAME || objectName;
1248
+ // 处理包含文件
1249
+ if (prog.IINCLUDES && Array.isArray(prog.IINCLUDES) && prog.IINCLUDES.length > 0) {
1250
+ console.error(`处理程序 ${programName} 的包含文件,共 ${prog.IINCLUDES.length} 个`);
1251
+ await this.processIncludes(prog.IINCLUDES);
1252
+ }
1253
+ // 处理结构体
1254
+ if (prog.IDICTSTRUCT && Array.isArray(prog.IDICTSTRUCT) && prog.IDICTSTRUCT.length > 0) {
1255
+ console.error(`处理程序 ${programName} 的结构体,共 ${prog.IDICTSTRUCT.length} 个`);
1256
+ await this.processStructures(prog.IDICTSTRUCT);
1257
+ }
1258
+ // 处理文本元素
1259
+ if (prog.ITEXTELEMENTS && Array.isArray(prog.ITEXTELEMENTS) && prog.ITEXTELEMENTS.length > 0) {
1260
+ await this.processTextElements(prog.ITEXTELEMENTS, programName, 'PROGRAM');
1261
+ }
1262
+ // 处理消息
1263
+ if (prog.IMESSAGES && Array.isArray(prog.IMESSAGES) && prog.IMESSAGES.length > 0) {
1264
+ await this.processMessages(prog.IMESSAGES, programName, 'PROGRAM');
1265
+ }
1266
+ // 处理GUI标题
1267
+ if (prog.IGUITITLE && Array.isArray(prog.IGUITITLE) && prog.IGUITITLE.length > 0) {
1268
+ await this.processGuiTitles(prog.IGUITITLE, programName, 'PROGRAM');
1269
+ }
1270
+ // 直接添加屏幕数据到缓存
1271
+ (0, generate_1.addScreenDataToCache)(this.screenCache, programName, prog.ISCREENFIELD, prog.ISCREENFLOW, prog.ISCREENDESC);
1272
+ }
1273
+ }
1274
+ // 处理类引用内容
1275
+ if (objectType.toUpperCase() === 'CLASS' && actualData.ET_CLASSES && Array.isArray(actualData.ET_CLASSES)) {
1276
+ for (const cls of actualData.ET_CLASSES) {
1277
+ const className = cls.CLSNAME || objectName;
1278
+ // 处理结构体
1279
+ if (cls.IDICTSTRUCT && Array.isArray(cls.IDICTSTRUCT) && cls.IDICTSTRUCT.length > 0) {
1280
+ console.error(`处理类 ${className} 的结构体,共 ${cls.IDICTSTRUCT.length} 个`);
1281
+ await this.processStructures(cls.IDICTSTRUCT);
1282
+ }
1283
+ // 处理文本元素
1284
+ if (cls.ITEXTELEMENTS && Array.isArray(cls.ITEXTELEMENTS) && cls.ITEXTELEMENTS.length > 0) {
1285
+ await this.processTextElements(cls.ITEXTELEMENTS, className, 'CLASS');
1286
+ }
1287
+ // 处理消息
1288
+ if (cls.IMESSAGES && Array.isArray(cls.IMESSAGES) && cls.IMESSAGES.length > 0) {
1289
+ await this.processMessages(cls.IMESSAGES, className, 'CLASS');
1290
+ }
1291
+ }
1292
+ }
1293
+ return { success: true, data: actualData };
1294
+ }
1295
+ else {
1296
+ return { success: false, error: '无有效数据返回' };
1297
+ }
1298
+ }
1299
+ catch (error) {
1300
+ const errorMessage = `查询对象引用内容失败: ${objectType} - ${objectName}, 错误: ${error instanceof Error ? error.message : String(error)}`;
1301
+ return { success: false, error: errorMessage };
1302
+ }
1303
+ }
1304
+ /**
1305
+ * 生成对象键
1306
+ */
1307
+ generateObjectKey(objectType, objectName) {
1308
+ return `${objectType}:${objectName}`;
1309
+ }
1310
+ /**
1311
+ * 延迟函数
1312
+ */
1313
+ delay(ms) {
1314
+ return new Promise(resolve => setTimeout(resolve, ms));
1315
+ }
1316
+ /**
1317
+ * 获取结果摘要
1318
+ */
1319
+ getResultSummary() {
1320
+ const stats = this.result.statistics;
1321
+ const fileErrorCount = this.result.downloadedFiles.filter(f => !f.success).length;
1322
+ return `
1323
+ 递归查询结果摘要:
1324
+ ========================
1325
+ 总对象数: ${stats.totalObjects}
1326
+ 总类数: ${stats.totalClasses}
1327
+ 总函数数: ${stats.totalFunctions}
1328
+ 总包含文件数: ${stats.totalIncludes}
1329
+ 已下载包含文件: ${stats.downloadedIncludes}
1330
+ 总结构体数: ${stats.totalStructures}
1331
+ 已下载结构体数: ${stats.downloadedStructures}
1332
+ 总domain数: ${stats.totalDomains}
1333
+ 已下载domain数: ${stats.downloadedDomains}
1334
+ 最大递归深度: ${stats.maxDepthReached}
1335
+ 循环引用数: ${stats.circularReferences}
1336
+ 错误数: ${this.result.errors.length}
1337
+ 文件错误数: ${fileErrorCount}
1338
+ `.trim();
1339
+ }
1340
+ /**
1341
+ * 获取文件错误详细信息
1342
+ */
1343
+ getFileErrorDetails() {
1344
+ const failedFiles = this.result.downloadedFiles.filter(f => !f.success);
1345
+ if (failedFiles.length === 0) {
1346
+ return '';
1347
+ }
1348
+ let details = '\n文件错误详情:\n';
1349
+ details += '========================\n';
1350
+ failedFiles.forEach((file, index) => {
1351
+ details += `${index + 1}. ${file.objectType} - ${file.objectName}\n`;
1352
+ details += ` 错误: ${file.error || '未知错误'}\n`;
1353
+ details += ` 路径: ${file.filePath}\n\n`;
1354
+ });
1355
+ return details;
1356
+ }
1357
+ }
1358
+ exports.RecursiveObjectQuery = RecursiveObjectQuery;