@buaa_smat/hometrans 0.1.4 → 0.1.6

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 (80) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +17 -18
  3. package/agents/build-fixer.md +6 -5
  4. package/agents/{logic-coding.md → logic-coder.md} +2 -2
  5. package/agents/logic-context-builder.md +1 -1
  6. package/agents/self-tester.md +19 -8
  7. package/package.json +1 -1
  8. package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/SKILL.md +3 -3
  9. package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/conversion-procedure.md +2 -2
  10. package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mappings/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +3 -5
  11. package/skills/{convert_pipeline → hmos-convert-pipeline}/SKILL.md +4 -4
  12. package/skills/hmos-fix-build-errors/SKILL.md +265 -0
  13. package/skills/hmos-fix-build-errors/references/arkts-strict-patterns.md +219 -0
  14. package/skills/hmos-fix-build-errors/references/known-patterns.md +157 -0
  15. package/skills/hmos-fix-build-errors/references/rdb-entity-pattern.md +131 -0
  16. package/skills/{hmos-ui-align → hmos-incremental-ui-align}/SKILL.md +4 -2
  17. package/skills/{hmos-ui-align → hmos-incremental-ui-align}/readme.md +5 -6
  18. package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +3 -5
  19. package/skills/{self-test → hmos-integration-test}/SKILL.md +1 -1
  20. package/skills/{self-test → hmos-integration-test}/readme.md +3 -3
  21. package/skills/{spec-generator-skill → hmos-spec-generate}/SKILL.md +1 -1
  22. package/agents/code-review-fix.md +0 -356
  23. package/dist/cli/config-store.js +0 -143
  24. package/dist/cli/config.js +0 -40
  25. package/dist/cli/index.js +0 -43
  26. package/dist/cli/init.js +0 -366
  27. package/dist/cli/mcp-setup.js +0 -262
  28. package/dist/cli/mcp.js +0 -94
  29. package/dist/cli/uninstall.js +0 -310
  30. package/dist/context/index.js +0 -788
  31. package/skills/code-dev-review-fix/SKILL.md +0 -279
  32. package/skills/code-dev-review-fix-workspace/evals/evals.json +0 -56
  33. package/skills/code-dev-review-fix-workspace/iteration-1/routing-results.md +0 -23
  34. package/skills/hmos-ui-align/config.json +0 -11
  35. /package/agents/{logic-coding → logic-coder}/scripts/platform_context_query.py +0 -0
  36. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mappings/android-to-harmonyOS-ui-interaction-mapping-reference.md +0 -0
  37. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mappings/android-to-harmonyOS-ui-layout-mapping-reference.md +0 -0
  38. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
  39. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md" +0 -0
  40. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md" +0 -0
  41. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
  42. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md" +0 -0
  43. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md" +0 -0
  44. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md" +0 -0
  45. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
  46. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md" +0 -0
  47. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
  48. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md" +0 -0
  49. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md" +0 -0
  50. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md" +0 -0
  51. /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/scripts/android_parse_fast.py +0 -0
  52. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/config-example.json +0 -0
  53. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/diff_analysis.md +0 -0
  54. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/page_align.md +0 -0
  55. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/Comparison_Template.md +0 -0
  56. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
  57. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md" +0 -0
  58. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md" +0 -0
  59. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
  60. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md" +0 -0
  61. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md" +0 -0
  62. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md" +0 -0
  63. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
  64. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md" +0 -0
  65. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
  66. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217V1.md" +0 -0
  67. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md" +0 -0
  68. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md" +0 -0
  69. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md" +0 -0
  70. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/UI_Analysis_Template.md +0 -0
  71. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +0 -0
  72. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/android-to-harmonyOS-ui-layout-mapping-reference.md +0 -0
  73. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/scripts/app_feature_verify.py +0 -0
  74. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/scripts/navigation-capure.md +0 -0
  75. /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/scripts/page_capture.py +0 -0
  76. /package/skills/{spec-generator-skill → hmos-spec-generate}/references/android-platform-tokens.md +0 -0
  77. /package/skills/{spec-generator-skill → hmos-spec-generate}/references/spec-sample-1.md +0 -0
  78. /package/skills/{spec-generator-skill → hmos-spec-generate}/references/spec-sample-2.md +0 -0
  79. /package/skills/{spec-generator-skill → hmos-spec-generate}/references/spec-sample-3.md +0 -0
  80. /package/skills/{spec-generator-skill → hmos-spec-generate}/references/step4-report-template.md +0 -0
@@ -1,788 +0,0 @@
1
- import { createRequire as _htCreateRequire } from 'module'; const require = _htCreateRequire(import.meta.url);
2
-
3
- // src/context/index.ts
4
- import path4 from "node:path";
5
- import {
6
- CallGraph as CallGraph2,
7
- CallGraphBuilder,
8
- Scene as Scene2,
9
- SceneConfig
10
- } from "arkanalyzer";
11
-
12
- // src/cli/config-store.ts
13
- import fs from "node:fs/promises";
14
- import path from "node:path";
15
- import os from "node:os";
16
- function getConfigDir() {
17
- return path.join(os.homedir(), ".hometrans");
18
- }
19
- function getConfigPath() {
20
- return path.join(getConfigDir(), "config.json");
21
- }
22
- function expandHome(p) {
23
- if (!p) return p;
24
- if (p === "~") return os.homedir();
25
- if (p.startsWith("~/") || p.startsWith("~\\")) {
26
- return path.join(os.homedir(), p.slice(2));
27
- }
28
- return p;
29
- }
30
- function defaultEditors() {
31
- return [
32
- {
33
- name: "Claude Code",
34
- markerDir: "~/.claude",
35
- skillsDir: "~/.claude/skills",
36
- agentsDir: "~/.claude/agents",
37
- mcp: {
38
- format: "jsonc-object",
39
- path: "~/.claude.json",
40
- keyPath: ["mcpServers", "hometrans"]
41
- }
42
- },
43
- {
44
- name: "Cursor",
45
- markerDir: "~/.cursor",
46
- skillsDir: "~/.cursor/skills",
47
- agentsDir: "~/.cursor/agents",
48
- mcp: {
49
- format: "jsonc-object",
50
- path: "~/.cursor/mcp.json",
51
- keyPath: ["mcpServers", "hometrans"]
52
- }
53
- },
54
- {
55
- name: "OpenCode",
56
- markerDir: "~/.config/opencode",
57
- skillsDir: "~/.config/opencode/skills",
58
- agentsDir: "~/.config/opencode/agents",
59
- mcp: {
60
- format: "jsonc-command-array",
61
- path: "~/.config/opencode/opencode.json",
62
- keyPath: ["mcp", "hometrans"]
63
- }
64
- },
65
- {
66
- name: "Codex",
67
- markerDir: "~/.codex",
68
- // Codex 复用 Agent Skills 公共目录,agent 定义独立。
69
- skillsDir: "~/.agents/skills",
70
- agentsDir: "~/.codex/agents",
71
- mcp: {
72
- format: "codex-cli",
73
- path: "~/.codex/config.toml",
74
- section: "mcp_servers.hometrans"
75
- }
76
- }
77
- ];
78
- }
79
- async function fileExists(p) {
80
- try {
81
- await fs.access(p);
82
- return true;
83
- } catch {
84
- return false;
85
- }
86
- }
87
- function defaultUserParams() {
88
- return {
89
- OHOS_SDK_PATH: "",
90
- HMS_SDK_PATH: "",
91
- TEST_API_KEY: ""
92
- };
93
- }
94
- async function loadHomeTransConfig() {
95
- const configPath = getConfigPath();
96
- if (!await fileExists(configPath)) {
97
- const config2 = {
98
- editors: defaultEditors(),
99
- params: defaultUserParams(),
100
- tool_path: ""
101
- };
102
- await fs.mkdir(getConfigDir(), { recursive: true });
103
- await fs.writeFile(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
104
- return config2;
105
- }
106
- const raw = await fs.readFile(configPath, "utf-8");
107
- let parsed;
108
- try {
109
- parsed = JSON.parse(raw);
110
- } catch (err) {
111
- throw new Error(
112
- `Failed to parse ${configPath}: ${err.message}. Fix the JSON or delete the file to restore defaults.`
113
- );
114
- }
115
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.editors)) {
116
- throw new Error(
117
- `Invalid config.json shape at ${configPath}: top-level must be { "editors": [...] }.`
118
- );
119
- }
120
- const config = parsed;
121
- const legacy = parsed.sdkPaths;
122
- if (!config.params) {
123
- config.params = { ...defaultUserParams(), ...legacy ?? {} };
124
- } else {
125
- config.params = { ...defaultUserParams(), ...config.params };
126
- }
127
- if (typeof config.tool_path !== "string") {
128
- config.tool_path = "";
129
- }
130
- delete config.sdkPaths;
131
- return config;
132
- }
133
-
134
- // src/context/analysis/ArkTsGitInfoAnalysis.ts
135
- import {
136
- AbstractInvokeExpr,
137
- ArkAssignStmt,
138
- CallGraphNode,
139
- ArkInvokeStmt,
140
- fetchDependenciesFromFile,
141
- FunctionType,
142
- parseJsonText
143
- } from "arkanalyzer";
144
- import path3 from "path";
145
- import fs3 from "fs";
146
-
147
- // src/context/utils/util.ts
148
- import LoggerMod, { LOG_MODULE_TYPE } from "arkanalyzer/lib/utils/logger.js";
149
- import path2 from "path";
150
- import fs2 from "fs";
151
- var Logger = LoggerMod.default ?? LoggerMod;
152
- var logger = Logger.getLogger(LOG_MODULE_TYPE.DEFAULT, "util");
153
- function safePush(target, source, maxBatchSize = 1e4) {
154
- for (let i = 0; i < source.length; i += maxBatchSize) {
155
- const batch = source.slice(i, i + maxBatchSize);
156
- target.push(...batch);
157
- }
158
- }
159
- function getAllFiles(dirPath, exts, filenameArr = [], visited = /* @__PURE__ */ new Set()) {
160
- if (!fs2.existsSync(dirPath)) {
161
- logger.error(`'${dirPath}' is not exist, please check!`);
162
- return filenameArr;
163
- }
164
- const realSrc = fs2.realpathSync(dirPath);
165
- if (visited.has(realSrc)) {
166
- return filenameArr;
167
- }
168
- visited.add(realSrc);
169
- fs2.readdirSync(realSrc).forEach((fileName) => {
170
- if (shouldSkipFile(fileName)) {
171
- return;
172
- }
173
- const realFile = path2.resolve(realSrc, fileName);
174
- if (fs2.statSync(realFile).isDirectory()) {
175
- getAllFiles(realFile, exts, filenameArr, visited);
176
- } else {
177
- if (exts.length === 0) {
178
- filenameArr.push(realFile);
179
- } else if (shouldAddFile(realFile, exts)) {
180
- filenameArr.push(realFile);
181
- }
182
- }
183
- });
184
- return filenameArr;
185
- }
186
- function shouldSkipFile(fileName) {
187
- return ["oh_modules", "node_modules", "hvigorfile.ts", "ohosTest"].includes(fileName);
188
- }
189
- function shouldAddFile(filePath, exts) {
190
- if (exts.length === 0) {
191
- return true;
192
- }
193
- const ext = path2.extname(filePath).toLowerCase();
194
- return exts.includes(ext);
195
- }
196
- function getFilePath(parts) {
197
- return path2.join(...parts);
198
- }
199
- function toUnixPath(p) {
200
- return p.replace(/\\/g, "/");
201
- }
202
-
203
- // src/context/analysis/ArkTsGitInfoAnalysis.ts
204
- var ModuleDependency = class {
205
- moduleName;
206
- modulePath;
207
- pluralJsons;
208
- stringJsons;
209
- strArrayJsons;
210
- };
211
- var Resource = class {
212
- resource = /* @__PURE__ */ new Map();
213
- };
214
- var GitItem = class {
215
- mode;
216
- path;
217
- lineInterval;
218
- contentAfter;
219
- contentBefore;
220
- };
221
- var ArkTsGitInfoAnalysis = class {
222
- scene;
223
- mode;
224
- callGraph;
225
- originLines;
226
- copiedLines;
227
- dependencyFileDict = /* @__PURE__ */ new Map();
228
- dependencyResourceMap = /* @__PURE__ */ new Map();
229
- gitItem;
230
- moduleDependencies;
231
- modulePathDependenciesMap = /* @__PURE__ */ new Map();
232
- maxCallDepth = 2;
233
- analysis = (arkFile, gitItem, callGraph, mode) => {
234
- this.callGraph = callGraph;
235
- this.mode = mode;
236
- this.originLines = arkFile.getCode().split("\n");
237
- let copiedLinesInDict = this.dependencyFileDict.get(arkFile);
238
- if (!copiedLinesInDict) {
239
- this.copiedLines = new Array(this.originLines.length);
240
- this.dependencyFileDict.set(arkFile, this.copiedLines);
241
- } else {
242
- this.copiedLines = copiedLinesInDict;
243
- }
244
- this.gitItem = gitItem;
245
- this.scene = arkFile.getScene();
246
- const modulePath = arkFile.getModuleScene().getModulePath();
247
- if (this.modulePathDependenciesMap.has(modulePath)) {
248
- this.moduleDependencies = this.modulePathDependenciesMap.get(modulePath);
249
- } else {
250
- this.moduleDependencies = /* @__PURE__ */ new Map();
251
- this.getModuleDependency(arkFile.getModuleScene().getModulePath());
252
- this.modulePathDependenciesMap.set(modulePath, this.moduleDependencies);
253
- }
254
- this.analysisFileStructureTree(arkFile);
255
- for (let i = gitItem.lineInterval[0]; i <= gitItem.lineInterval[1]; i++) {
256
- if (this.copiedLines[i - 1] === void 0) {
257
- this.copiedLines[i - 1] = this.originLines[i - 1];
258
- }
259
- }
260
- return this.dependencyFileDict;
261
- };
262
- getModuleDependency(modulePath) {
263
- let OhPkgFilePath = path3.join(modulePath, "oh-package.json5");
264
- console.log(`modulePath ${modulePath} OhPkgFilePath ${OhPkgFilePath}`);
265
- let libOhPkgContent = fetchDependenciesFromFile(OhPkgFilePath);
266
- let dependencies = libOhPkgContent.dependencies;
267
- console.dir(dependencies, { depth: null });
268
- if (!dependencies) {
269
- return;
270
- }
271
- Object.entries(dependencies).forEach(([key, value]) => {
272
- if (key.startsWith("@ohos") && value.startsWith("file:")) {
273
- const targetModulePath = path3.resolve(modulePath, value.replace("file:", ""));
274
- if (!this.moduleDependencies.has(targetModulePath)) {
275
- const targetModuleResourcePath = path3.join(targetModulePath, "src", "main", "resources");
276
- const moduleDependency = new ModuleDependency();
277
- moduleDependency.moduleName = key.replace("@ohos/", "");
278
- moduleDependency.modulePath = targetModulePath;
279
- moduleDependency.pluralJsons = this.loadJsonResources(targetModuleResourcePath, "plural.json");
280
- moduleDependency.strArrayJsons = this.loadJsonResources(targetModuleResourcePath, "strarray.json");
281
- moduleDependency.stringJsons = this.loadJsonResources(targetModuleResourcePath, "string.json");
282
- this.moduleDependencies.set(moduleDependency.modulePath, moduleDependency);
283
- this.getModuleDependency(targetModulePath);
284
- }
285
- }
286
- });
287
- }
288
- resolveAnonymousMethod(arkMethod, arkClass) {
289
- let callStmtStartLine = arkMethod.getLine();
290
- let callStmtEndLine = this.getEndLine(callStmtStartLine, arkMethod.getCode());
291
- let outerArkMethod = arkMethod.getOuterMethod();
292
- while (outerArkMethod && outerArkMethod.getName().startsWith("%AM")) {
293
- arkMethod = outerArkMethod;
294
- outerArkMethod = arkMethod.getOuterMethod();
295
- }
296
- if (outerArkMethod) {
297
- if (outerArkMethod.getName() === "%instInit") {
298
- let targetArkField;
299
- for (let arkField of arkClass.getFields()) {
300
- const stmts = arkField.getInitializer() ?? [];
301
- for (let stmt of stmts) {
302
- if (stmt instanceof ArkAssignStmt) {
303
- const rightOp = stmt.getRightOp();
304
- let type = rightOp.getType();
305
- if (type instanceof FunctionType && type.getMethodSignature() === arkMethod.getSignature()) {
306
- arkMethod = this.scene.getMethod(type.getMethodSignature());
307
- targetArkField = arkField;
308
- callStmtStartLine = targetArkField.getOriginPosition().getLineNo();
309
- callStmtEndLine = this.getEndLine(callStmtStartLine, targetArkField.getCode());
310
- break;
311
- }
312
- }
313
- }
314
- if (targetArkField) {
315
- break;
316
- }
317
- }
318
- } else if (outerArkMethod.getName() === "%dflt") {
319
- let locals = outerArkMethod.getBody().getLocals();
320
- locals.forEach((local, str) => {
321
- let stmt = local.getDeclaringStmt();
322
- if (stmt instanceof ArkAssignStmt) {
323
- const rightOp = stmt.getRightOp();
324
- let type = rightOp.getType();
325
- if (type instanceof FunctionType && type.getMethodSignature() === arkMethod.getSignature()) {
326
- arkMethod = this.scene.getMethod(type.getMethodSignature());
327
- callStmtStartLine = stmt.getOriginPositionInfo().getLineNo();
328
- callStmtEndLine = this.getEndLine(callStmtStartLine, stmt.getOriginalText());
329
- }
330
- }
331
- });
332
- } else {
333
- callStmtStartLine = outerArkMethod.getLine();
334
- callStmtEndLine = this.getEndLine(callStmtStartLine, outerArkMethod.getCode());
335
- }
336
- }
337
- return { arkMethod, startLine: callStmtStartLine, endLine: callStmtEndLine };
338
- }
339
- copyClassHeader(arkClass, copiedLines, originLines, includeMinLine) {
340
- let classStartLine = arkClass.getLine();
341
- let classEndLine = this.getEndLine(classStartLine, arkClass.getCode());
342
- let minLineNumber = classEndLine;
343
- if (arkClass.getFields().length !== 0) {
344
- let fields = arkClass.getFields();
345
- fields.sort((a, b) => a.getOriginPosition().getLineNo() - b.getOriginPosition().getLineNo());
346
- let firstFieldLine = fields[0].getOriginPosition().getLineNo();
347
- minLineNumber = Math.min(firstFieldLine, minLineNumber);
348
- }
349
- if (arkClass.getMethods().length !== 0) {
350
- let methods = arkClass.getMethods();
351
- methods = methods.filter((method) => this.isMethodValid(method)).sort((a, b) => a.getLine() - b.getLine());
352
- if (methods.length !== 0) {
353
- let firstMethodLine = methods[0].getLine();
354
- if (firstMethodLine !== void 0 && firstMethodLine !== null) {
355
- minLineNumber = Math.min(firstMethodLine, minLineNumber);
356
- }
357
- }
358
- }
359
- const end = includeMinLine ? minLineNumber : minLineNumber - 1;
360
- for (let i = classStartLine; i <= end; i++) {
361
- copiedLines[i - 1] = originLines[i - 1];
362
- }
363
- copiedLines[classEndLine - 1] = originLines[classEndLine - 1];
364
- }
365
- loadJsonResources(resourcePath, fileName) {
366
- const jsonItems = [];
367
- const results = getAllFiles(resourcePath, [fileName]);
368
- for (const result of results) {
369
- const configText = fs3.readFileSync(result, "utf8");
370
- const json = parseJsonText(configText);
371
- jsonItems.push({ path: result, content: json });
372
- }
373
- return jsonItems;
374
- }
375
- getEndLine(startLine, code) {
376
- return startLine + (code ? code.split("\n").length - 1 : 0);
377
- }
378
- isMethodValid(method) {
379
- return !(method.getName() === "constructor" && method.getCode() === "") && method.getLine() !== -1 && method.getCode() !== void 0;
380
- }
381
- analysisFileStructureTree(arkFile) {
382
- let arkClasses = arkFile.getClasses().filter((cls) => cls.getName() === "%dflt" || !cls.getName().startsWith("%"));
383
- for (const arkClass of arkClasses) {
384
- if (arkClass.getName() === "%dflt") {
385
- this.analysisClassStructureTree(arkClass);
386
- } else {
387
- let classStartLine = arkClass.getLine();
388
- if (classStartLine === -1) {
389
- this.analysisClassStructureTree(arkClass);
390
- } else {
391
- let classEndLine = this.getEndLine(classStartLine, arkClass.getCode());
392
- let classLineInterval = [classStartLine, classEndLine];
393
- if (!(classLineInterval[0] > this.gitItem.lineInterval[1] || classLineInterval[1] < this.gitItem.lineInterval[0])) {
394
- this.copyClassHeader(arkClass, this.copiedLines, this.originLines, false);
395
- this.analysisClassStructureTree(arkClass);
396
- }
397
- }
398
- }
399
- }
400
- }
401
- getInvokeExprFromStmt(stmt) {
402
- if (stmt instanceof ArkInvokeStmt) {
403
- return stmt.getInvokeExpr();
404
- } else if (stmt instanceof ArkAssignStmt) {
405
- const rightOp = stmt.getRightOp();
406
- if (rightOp instanceof AbstractInvokeExpr) {
407
- return rightOp;
408
- }
409
- }
410
- }
411
- analysisMethodResource(method) {
412
- const stmts = method.getBody()?.getCfg().getStmts();
413
- if (!stmts) {
414
- return;
415
- }
416
- for (let stmt of stmts) {
417
- const invokeExpr = this.getInvokeExprFromStmt(stmt);
418
- if (!invokeExpr) {
419
- continue;
420
- }
421
- const invokeSignature = invokeExpr.getMethodSignature();
422
- let clazz = method.getDeclaringArkClass();
423
- let methodName = invokeSignature.getMethodSubSignature().getMethodName();
424
- let moduleName = clazz.getDeclaringArkFile().getModuleName();
425
- if (moduleName === void 0) {
426
- continue;
427
- }
428
- if (methodName === "$r") {
429
- const resourceLabel = invokeExpr.getArgs()[0].toString().slice(1, -1);
430
- const array = resourceLabel.split(".");
431
- if (array.length === 3) {
432
- const scope = array[0];
433
- if (scope !== "app") {
434
- continue;
435
- }
436
- const category = array[1];
437
- const name = array[2];
438
- for (const moduleDependency of this.moduleDependencies.values()) {
439
- if (category === "string" && moduleDependency.stringJsons.length !== 0) {
440
- for (const jsonItem of moduleDependency.stringJsons) {
441
- this.extracted(jsonItem, name);
442
- }
443
- } else if (category === "strarray" && moduleDependency.strArrayJsons.length !== 0) {
444
- for (const jsonItem of moduleDependency.strArrayJsons) {
445
- this.extracted(jsonItem, name);
446
- }
447
- } else if (category === "plural" && moduleDependency.pluralJsons.length !== 0) {
448
- for (const jsonItem of moduleDependency.pluralJsons) {
449
- this.extracted(jsonItem, name);
450
- }
451
- }
452
- }
453
- }
454
- }
455
- }
456
- }
457
- extracted(jsonItem, name) {
458
- for (const descriptor of jsonItem.content["string"]) {
459
- if (descriptor["name"] === name) {
460
- let stringResourceItem = this.dependencyResourceMap.get(jsonItem.path);
461
- if (!stringResourceItem) {
462
- stringResourceItem = new Resource();
463
- }
464
- if (!stringResourceItem.resource.has(name)) {
465
- stringResourceItem.resource.set(name, descriptor);
466
- this.dependencyResourceMap.set(jsonItem.path, stringResourceItem);
467
- }
468
- return true;
469
- }
470
- }
471
- return false;
472
- }
473
- analysisClassStructureTree(arkClass) {
474
- let callgraph = this.callGraph;
475
- let arkMethods = arkClass.getMethods();
476
- for (let arkMethod of arkMethods) {
477
- let methodStartLine = arkMethod.getLine();
478
- let methodEndLine = this.getEndLine(methodStartLine, arkMethod.getCode());
479
- let methodLineInterval = [];
480
- methodLineInterval = [methodStartLine, methodEndLine];
481
- if (!(methodLineInterval[0] > this.gitItem.lineInterval[1] || methodLineInterval[1] < this.gitItem.lineInterval[0])) {
482
- let callStmtStartLine = arkMethod.getLine();
483
- let callStmtEndLine = this.getEndLine(callStmtStartLine, arkMethod.getCode());
484
- if (arkMethod.getName().startsWith("%AM")) {
485
- const resolved = this.resolveAnonymousMethod(arkMethod, arkClass);
486
- arkMethod = resolved.arkMethod;
487
- callStmtStartLine = resolved.startLine;
488
- callStmtEndLine = resolved.endLine;
489
- }
490
- if (this.isMethodValid(arkMethod)) {
491
- for (let i = callStmtStartLine; i <= callStmtEndLine; i++) {
492
- this.copiedLines[i - 1] = this.originLines[i - 1];
493
- }
494
- }
495
- this.analysisMethodResource(arkMethod);
496
- if (this.mode === "default") {
497
- let invokeStmts = callgraph.getInvokeStmtByMethod(arkMethod.getSignature());
498
- if (invokeStmts) {
499
- for (let invokeStmt of invokeStmts) {
500
- let dstMethod = invokeStmt.getCfg().getDeclaringMethod();
501
- console.log(`[caller] ${arkMethod.getSignature()} is called by ${dstMethod.getSignature()} in ${dstMethod.getDeclaringArkClass().getDeclaringArkFile().getName()}`);
502
- this.analysisCallArkFile(dstMethod, 1);
503
- }
504
- }
505
- let setEdges = callgraph.getCallGraphNodeByMethod(arkMethod.getSignature()).getOutgoingEdges();
506
- if (setEdges) {
507
- setEdges.forEach((edge) => {
508
- let dst = edge.getDstNode();
509
- if (dst instanceof CallGraphNode && !dst.isSdkMethod()) {
510
- let dstMethodSignature = dst.getMethod();
511
- let dstMethod = this.scene.getMethod(dstMethodSignature);
512
- console.log(`[callee] ${arkMethod.getSignature()} calls ${dstMethodSignature} in ${dstMethod.getDeclaringArkClass().getDeclaringArkFile().getName()}`);
513
- this.analysisCallArkFile(dstMethod, 1);
514
- }
515
- });
516
- }
517
- }
518
- }
519
- }
520
- }
521
- analysisCallArkFile = (arkMethod, currentDepth = 1) => {
522
- let arkClass = arkMethod.getDeclaringArkClass();
523
- let callArkFile = arkClass.getDeclaringArkFile();
524
- let originLines = callArkFile.getCode().split("\n");
525
- let copiedLines = this.dependencyFileDict.get(callArkFile);
526
- if (!copiedLines) {
527
- copiedLines = new Array(originLines.length);
528
- this.dependencyFileDict.set(callArkFile, copiedLines);
529
- }
530
- if (arkClass.getName() != "%dlft") {
531
- this.copyClassHeader(arkClass, copiedLines, originLines, true);
532
- }
533
- let callStmtStartLine = arkMethod.getLine();
534
- let callStmtEndLine = this.getEndLine(callStmtStartLine, arkMethod.getCode());
535
- if (arkMethod.getName().startsWith("%AM")) {
536
- const resolved = this.resolveAnonymousMethod(arkMethod, arkClass);
537
- arkMethod = resolved.arkMethod;
538
- callStmtStartLine = resolved.startLine;
539
- callStmtEndLine = resolved.endLine;
540
- }
541
- if (this.isMethodValid(arkMethod)) {
542
- for (let i = callStmtStartLine; i <= callStmtEndLine; ++i) {
543
- copiedLines[i - 1] = originLines[i - 1];
544
- }
545
- }
546
- if (this.mode === "default" && currentDepth < this.maxCallDepth) {
547
- let invokeStmts = this.callGraph.getInvokeStmtByMethod(arkMethod.getSignature());
548
- if (invokeStmts) {
549
- for (let invokeStmt of invokeStmts) {
550
- let dstMethod = invokeStmt.getCfg().getDeclaringMethod();
551
- console.log(`[caller][depth=${currentDepth}] ${arkMethod.getSignature()} is called by ${dstMethod.getSignature()} in ${dstMethod.getDeclaringArkClass().getDeclaringArkFile().getName()}`);
552
- this.analysisCallArkFile(dstMethod, currentDepth + 1);
553
- }
554
- }
555
- let setEdges = this.callGraph.getCallGraphNodeByMethod(arkMethod.getSignature()).getOutgoingEdges();
556
- if (setEdges) {
557
- setEdges.forEach((edge) => {
558
- let dst = edge.getDstNode();
559
- if (dst instanceof CallGraphNode && !dst.isSdkMethod()) {
560
- let dstMethodSignature = dst.getMethod();
561
- let dstMethod = this.scene.getMethod(dstMethodSignature);
562
- console.log(`[callee][depth=${currentDepth}] ${arkMethod.getSignature()} calls ${dstMethodSignature} in ${dstMethod.getDeclaringArkClass().getDeclaringArkFile().getName()}`);
563
- this.analysisCallArkFile(dstMethod, currentDepth + 1);
564
- }
565
- });
566
- }
567
- }
568
- return copiedLines;
569
- };
570
- };
571
-
572
- // src/context/git/GitDiffExtractor.ts
573
- import simpleGit from "simple-git";
574
- var ALLOWED_EXTS = [".ets", ".ts", ".c", ".cpp", ".h", ".hpp"];
575
- function hasAllowedExt(filePath) {
576
- if (!filePath) return false;
577
- const lower = filePath.toLowerCase();
578
- return ALLOWED_EXTS.some((ext) => lower.endsWith(ext));
579
- }
580
- function normalize(content) {
581
- return content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/-\n textPara/g, "-\n textPara");
582
- }
583
- function parseNameStatus(raw) {
584
- const out = [];
585
- if (!raw) return out;
586
- for (const rawLine of raw.split("\n")) {
587
- const line = rawLine.trim();
588
- if (!line) continue;
589
- const parts = line.split(" ");
590
- const status = parts[0];
591
- if (!status) continue;
592
- if (status.startsWith("R") || status.startsWith("C")) {
593
- out.push({ status, oldPath: parts[1] ?? "", newPath: parts[2] ?? "" });
594
- } else if (status === "A") {
595
- out.push({ status, oldPath: "", newPath: parts[1] ?? "" });
596
- } else if (status === "D") {
597
- out.push({ status, oldPath: parts[1] ?? "", newPath: "" });
598
- } else {
599
- out.push({ status, oldPath: parts[1] ?? "", newPath: parts[1] ?? "" });
600
- }
601
- }
602
- return out;
603
- }
604
- function resolveFileMode(change) {
605
- if (change.status.startsWith("R")) return "rename";
606
- if (change.status === "A") return "add";
607
- if (change.status === "D") return "delete";
608
- return "modify";
609
- }
610
- function parseHunks(patch, newFilePath) {
611
- const items = [];
612
- if (!patch) return items;
613
- const lines = patch.split("\n");
614
- let current = new GitItem();
615
- let oldLines = [];
616
- let newLines = [];
617
- for (const line of lines) {
618
- if (line.startsWith("---") || line.startsWith("+++")) {
619
- continue;
620
- }
621
- if (line.startsWith("@@")) {
622
- current.contentBefore = normalize(oldLines.join("\n"));
623
- current.contentAfter = normalize(newLines.join("\n"));
624
- items.push(current);
625
- current = new GitItem();
626
- oldLines = [];
627
- newLines = [];
628
- const parts = line.split(" ");
629
- const oldInfo = parts[1].substring(1).split(",");
630
- const oldRow = parseInt(oldInfo[0], 10);
631
- const oldAffected = oldInfo.length === 2 ? parseInt(oldInfo[1], 10) : 1;
632
- const newInfo = parts[2].substring(1).split(",");
633
- const newRow = parseInt(newInfo[0], 10);
634
- const newAffected = newInfo.length === 2 ? parseInt(newInfo[1], 10) : 1;
635
- current.path = newFilePath;
636
- current.lineInterval = [newRow, newRow + newAffected - 1];
637
- if (oldAffected === 0) current.mode = "add";
638
- if (newAffected === 0) {
639
- current.mode = "delete";
640
- } else {
641
- current.mode = "modify";
642
- }
643
- } else if (line.startsWith("-")) {
644
- oldLines.push(line.substring(1));
645
- } else if (line.startsWith("+")) {
646
- newLines.push(line.substring(1));
647
- }
648
- }
649
- current.contentBefore = normalize(oldLines.join("\n"));
650
- current.contentAfter = normalize(newLines.join("\n"));
651
- items.push(current);
652
- items.shift();
653
- return items;
654
- }
655
- async function extractCommitDiff(repoPath, commitId) {
656
- const git = simpleGit(repoPath);
657
- const parentId = (await git.raw(["rev-parse", `${commitId}^`])).trim();
658
- console.log(`commit: ${commitId} parent: ${parentId}`);
659
- const nameStatus = await git.raw(["diff", "--name-status", "-M", parentId, commitId]);
660
- const changes = parseNameStatus(nameStatus);
661
- const results = [];
662
- for (const change of changes) {
663
- if (change.oldPath && !hasAllowedExt(change.oldPath)) continue;
664
- if (change.newPath && !hasAllowedExt(change.newPath)) continue;
665
- const reportPath = change.newPath || change.oldPath;
666
- const filePaths = [change.oldPath, change.newPath].filter((p) => p);
667
- const patchArgs = ["diff", "-U0", "-M", parentId, commitId, "--", ...new Set(filePaths)];
668
- const patch = await git.raw(patchArgs);
669
- const hunkItems = parseHunks(patch, reportPath);
670
- const fileMode = resolveFileMode(change);
671
- for (const item of hunkItems) {
672
- item.file_mode = fileMode;
673
- }
674
- results.push(...hunkItems);
675
- }
676
- return results;
677
- }
678
-
679
- // src/context/index.ts
680
- function linesToRanges(lines) {
681
- const ranges = [];
682
- let start = -1;
683
- for (let i = 0; i < lines.length; i++) {
684
- const defined = lines[i] !== void 0;
685
- if (defined && start === -1) {
686
- start = i + 1;
687
- } else if (!defined && start !== -1) {
688
- ranges.push([start, i]);
689
- start = -1;
690
- }
691
- }
692
- if (start !== -1) {
693
- ranges.push([start, lines.length]);
694
- }
695
- return ranges;
696
- }
697
- function loadSdks(ohosSdkPath, hmsSdkPath) {
698
- return [
699
- { name: "ohosSdk", path: ohosSdkPath, moduleName: "" },
700
- { name: "hmsSdk", path: hmsSdkPath, moduleName: "" }
701
- ];
702
- }
703
- async function extractCommitContext(input) {
704
- const { projectPath, commitId } = input;
705
- const mode = input.mode ?? "default";
706
- const config = await loadHomeTransConfig();
707
- const ohosSdkPath = expandHome(
708
- input.ohosSdkPath ?? config.params.OHOS_SDK_PATH ?? process.env.OHOS_SDK_PATH ?? ""
709
- );
710
- const hmsSdkPath = expandHome(
711
- input.hmsSdkPath ?? config.params.HMS_SDK_PATH ?? process.env.HMS_SDK_PATH ?? ""
712
- );
713
- if (!projectPath) {
714
- throw new Error("extractCommitContext: projectPath is required");
715
- }
716
- if (!commitId) {
717
- throw new Error("extractCommitContext: commitId is required");
718
- }
719
- if (!ohosSdkPath && !hmsSdkPath) {
720
- throw new Error(
721
- "extractCommitContext: ohosSdkPath/hmsSdkPath not provided. Set params.OHOS_SDK_PATH / params.HMS_SDK_PATH in ~/.hometrans/config.json (view with `ht config`), pass them as tool input, or set OHOS_SDK_PATH / HMS_SDK_PATH env vars (e.g. D:\\DevEco Studio\\sdk\\default\\openharmony\\ets)."
722
- );
723
- }
724
- console.error(
725
- `[hometrans/context] analyzing commit=${commitId} project=${projectPath} mode=${mode}`
726
- );
727
- const gitItems = await extractCommitDiff(projectPath, commitId);
728
- console.error(`[hometrans/context] extracted ${gitItems.length} diff items`);
729
- const scene = new Scene2();
730
- const analysisResult = [];
731
- const sceneConfig = new SceneConfig({ enableAST: false });
732
- const sdkList = loadSdks(ohosSdkPath, hmsSdkPath);
733
- const fileList = getAllFiles(projectPath, [".ts", ".ets", ".js", ".json5"]);
734
- sceneConfig.buildFromProjectFiles("hometrans_target", projectPath, fileList, sdkList);
735
- scene.buildSceneFromFiles(sceneConfig);
736
- scene.inferTypes();
737
- const callGraph = new CallGraph2(scene);
738
- if (mode === "default") {
739
- const callGraphBuilder = new CallGraphBuilder(callGraph, scene);
740
- const entryPoints = [];
741
- const totalMethodSignatures = scene.getFiles().filter(
742
- (arkFile) => arkFile.getFilePath().endsWith(".ets") || arkFile.getFilePath().endsWith(".ts")
743
- ).flatMap((arkFile) => arkFile.getClasses()).flatMap((arkClass) => arkClass.getMethods()).map((arkMethod) => arkMethod.getSignature());
744
- safePush(entryPoints, totalMethodSignatures);
745
- callGraphBuilder.buildClassHierarchyCallGraph(entryPoints, false);
746
- }
747
- const arkFiles = scene.getFiles();
748
- const gitAnalysis = new ArkTsGitInfoAnalysis();
749
- for (const gitItem of gitItems) {
750
- for (const arkFile of arkFiles) {
751
- const segments = gitItem.path.split(/[\\/]+/).filter(Boolean);
752
- const gitFilePath = getFilePath([arkFile.getProjectDir(), ...segments]);
753
- if (toUnixPath(arkFile.getFilePath()) === toUnixPath(gitFilePath)) {
754
- gitAnalysis.analysis(arkFile, gitItem, callGraph, mode);
755
- }
756
- }
757
- }
758
- const dependencyResourceMap = gitAnalysis.dependencyResourceMap;
759
- dependencyResourceMap.forEach((resource, filePath) => {
760
- const base = path4.basename(filePath);
761
- if (base === "string.json" || base === "plural.json" || base === "strarray.json") {
762
- analysisResult.push({
763
- path: filePath,
764
- kind: "resource",
765
- resourceNames: Array.from(resource.resource.keys())
766
- });
767
- }
768
- });
769
- const dependencyFileDict = gitAnalysis.dependencyFileDict;
770
- dependencyFileDict.forEach((lines, arkFile) => {
771
- const ranges = linesToRanges(lines);
772
- if (ranges.length === 0) {
773
- return;
774
- }
775
- analysisResult.push({
776
- path: arkFile.getFilePath(),
777
- kind: "source",
778
- ranges
779
- });
780
- });
781
- console.error(
782
- `[hometrans/context] produced ${analysisResult.length} context entries`
783
- );
784
- return analysisResult;
785
- }
786
- export {
787
- extractCommitContext
788
- };