homegraph 1.5.2 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +131 -0
- package/README.md +15 -8
- package/dist/arkui/index.d.ts +4 -0
- package/dist/arkui/index.d.ts.map +1 -0
- package/dist/arkui/index.js +23 -0
- package/dist/arkui/index.js.map +1 -0
- package/dist/arkui/migrate-passage.d.ts +28 -0
- package/dist/arkui/migrate-passage.d.ts.map +1 -0
- package/dist/arkui/migrate-passage.js +310 -0
- package/dist/arkui/migrate-passage.js.map +1 -0
- package/dist/arkui/migrate-semantics.d.ts +47 -0
- package/dist/arkui/migrate-semantics.d.ts.map +1 -0
- package/dist/arkui/migrate-semantics.js +229 -0
- package/dist/arkui/migrate-semantics.js.map +1 -0
- package/dist/arkui/migrate-snapshot.d.ts +79 -0
- package/dist/arkui/migrate-snapshot.d.ts.map +1 -0
- package/dist/arkui/migrate-snapshot.js +340 -0
- package/dist/arkui/migrate-snapshot.js.map +1 -0
- package/dist/bin/fatal-handler.js +2 -2
- package/dist/bin/homegraph.js +105 -156
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/bin/node-version-check.d.ts +6 -15
- package/dist/bin/node-version-check.d.ts.map +1 -1
- package/dist/bin/node-version-check.js +8 -37
- package/dist/bin/node-version-check.js.map +1 -1
- package/dist/db/index.d.ts +36 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +92 -6
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +15 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +42 -0
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +177 -10
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +6 -1
- package/dist/db/sqlite-adapter.d.ts +8 -3
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +45 -3
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/extraction/extraction-version.d.ts +1 -1
- package/dist/extraction/extraction-version.js +1 -1
- package/dist/extraction/generated-detection.d.ts +42 -11
- package/dist/extraction/generated-detection.d.ts.map +1 -1
- package/dist/extraction/generated-detection.js +141 -20
- package/dist/extraction/generated-detection.js.map +1 -1
- package/dist/extraction/index.d.ts +42 -0
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +96 -0
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +19 -2
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +460 -110
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/dist/extraction/wasm-runtime-flags.js +9 -6
- package/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/dist/graph-sources.d.ts +41 -0
- package/dist/graph-sources.d.ts.map +1 -0
- package/dist/graph-sources.js +82 -0
- package/dist/graph-sources.js.map +1 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +79 -9
- package/dist/index.js.map +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +0 -48
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/targets/antigravity.js +1 -1
- package/dist/installer/targets/antigravity.js.map +1 -1
- package/dist/installer/targets/deveco.js +1 -1
- package/dist/installer/targets/deveco.js.map +1 -1
- package/dist/installer/targets/hermes.d.ts +1 -1
- package/dist/installer/targets/hermes.js +2 -2
- package/dist/installer/targets/hermes.js.map +1 -1
- package/dist/installer/targets/opencode.js +1 -1
- package/dist/installer/targets/opencode.js.map +1 -1
- package/dist/installer/targets/shared.js +1 -1
- package/dist/installer/targets/shared.js.map +1 -1
- package/dist/mcp/daemon-paths.d.ts +5 -4
- package/dist/mcp/daemon-paths.d.ts.map +1 -1
- package/dist/mcp/daemon-paths.js +28 -13
- package/dist/mcp/daemon-paths.js.map +1 -1
- package/dist/mcp/daemon-registry.d.ts.map +1 -1
- package/dist/mcp/daemon-registry.js +4 -1
- package/dist/mcp/daemon-registry.js.map +1 -1
- package/dist/mcp/daemon.d.ts +1 -1
- package/dist/mcp/daemon.js +1 -1
- package/dist/mcp/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +12 -3
- package/dist/mcp/engine.js.map +1 -1
- package/dist/mcp/explore-dedup.d.ts +137 -0
- package/dist/mcp/explore-dedup.d.ts.map +1 -0
- package/dist/mcp/explore-dedup.js +236 -0
- package/dist/mcp/explore-dedup.js.map +1 -0
- package/dist/mcp/explore-session-state.d.ts +217 -0
- package/dist/mcp/explore-session-state.d.ts.map +1 -0
- package/dist/mcp/explore-session-state.js +322 -0
- package/dist/mcp/explore-session-state.js.map +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +4 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/proxy.d.ts.map +1 -1
- package/dist/mcp/proxy.js +5 -14
- package/dist/mcp/proxy.js.map +1 -1
- package/dist/mcp/query-worker.d.ts +1 -1
- package/dist/mcp/query-worker.js +1 -1
- package/dist/mcp/server-instructions.d.ts +7 -2
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +104 -28
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/session.d.ts +14 -3
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +17 -14
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/startup-handshake.d.ts +1 -1
- package/dist/mcp/startup-handshake.js +1 -1
- package/dist/mcp/tools.d.ts +117 -7
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +3056 -503
- package/dist/mcp/tools.js.map +1 -1
- package/dist/resolution/frameworks/arkts-napi.d.ts +14 -0
- package/dist/resolution/frameworks/arkts-napi.d.ts.map +1 -1
- package/dist/resolution/frameworks/arkts-napi.js +169 -49
- package/dist/resolution/frameworks/arkts-napi.js.map +1 -1
- package/dist/search/query-utils.d.ts +116 -4
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +869 -60
- package/dist/search/query-utils.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/upgrade/index.d.ts +14 -26
- package/dist/upgrade/index.d.ts.map +1 -1
- package/dist/upgrade/index.js +28 -123
- package/dist/upgrade/index.js.map +1 -1
- package/dist/upgrade/remove-binary.d.ts +19 -19
- package/dist/upgrade/remove-binary.d.ts.map +1 -1
- package/dist/upgrade/remove-binary.js +20 -21
- package/dist/upgrade/remove-binary.js.map +1 -1
- package/dist/upgrade/update-check.d.ts +4 -3
- package/dist/upgrade/update-check.d.ts.map +1 -1
- package/dist/upgrade/update-check.js +4 -3
- package/dist/upgrade/update-check.js.map +1 -1
- package/package.json +12 -8
- package/dist/telemetry/index.d.ts +0 -143
- package/dist/telemetry/index.d.ts.map +0 -1
- package/dist/telemetry/index.js +0 -541
- package/dist/telemetry/index.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to HomeGraph are documented here. Each entry also ships as
|
|
4
|
+
a [GitCode Release](https://gitcode.com/ProgramAnalysis/homegraph) tagged
|
|
5
|
+
`vX.Y.Z`, which is where most people will look.
|
|
6
|
+
|
|
7
|
+
This project follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
8
|
+
and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [1.5.3] - 2026-08-11
|
|
13
|
+
|
|
14
|
+
### New Features
|
|
15
|
+
|
|
16
|
+
- Ported selected post-1.5.0 CodeGraph fixes (through upstream `c6aaa20`): incremental **sync rebind** so long-lived indexes stop drifting from a fresh rebuild (`HOMEGRAPH_NO_REBIND=1` to opt out); **explore session dedup** so a follow-up `homegraph_explore` points at source already returned instead of re-sending it (`HOMEGRAPH_EXPLORE_DEDUP=0` to opt out); **stale-slice guards** so node/explore never serve a wrong body when a file changed on disk after the last sync; **WAL self-heal** on open when a killed session left an oversized write-ahead log (`homegraph status` reports WAL size); and explore **ranking/budget fairness** (generated-file banners, top-level `test/`/`spec/` demotion, ambient `.d.ts` down-rank, fair per-file budgets, long-function windows, note-first truncation).
|
|
17
|
+
- ArkTS ↔ C/C++ NAPI bridging recognizes more registration styles (camelCase `napi_property_descriptor` rows, `napi_define_class` / `napi_define_sendable_class`, `DECLARE_NAPI_*` macros, `napi_create_function`, and `.c` `NAPI_MODULE` modules), not only photos-style `Class_method` names, so `homegraph_explore` can follow calls through `lib*.so` into native wrappers (and a conservative same-file `NapiFoo` → `Foo` hop when safe). ArkTS extraction also emits call refs for camelCase methods on `lib*.so` imports (e.g. `multimodalinput.getTidByName`), not only `Class_method` names.
|
|
18
|
+
- `homegraph_arkui_migrate` returns a one-shot ArkUI migrate / state-semantics snapshot (component decorators, state fields + decorator args, data-passage types, Provide/Consume/Storage key channels, `@Observed` classes) for a component name or `.ets` path — so agents need not stitch those facts with explore.
|
|
19
|
+
- MCP can limit which graphs answer queries via `--sources both|project|sdk|none` on `homegraph serve mcp` (or `HOMEGRAPH_SOURCES`; CLI wins). Default remains **both** (project index + OHOS SDK API db when bound). Use `project` / `sdk` for eval arms; `none` leaves tools registered but returns guidance. Different sources use separate daemon sockets so arms do not share state. `homegraph status` / `homegraph_status` report the active mode.
|
|
20
|
+
|
|
21
|
+
- Node.js **18+** is supported again (`engines: >=18.0.0`), and **Node 25+** is no longer hard-blocked. Tree-sitter WASM Zone OOM on Node ≥22 (including 25+) continues to be mitigated by the `--liftoff-only` relaunch. Prefer Node 22.5+ for built-in `node:sqlite`. Optional `better-sqlite3` is pinned to 11.x so Node 18 can still use a native WAL backend when the addon builds; otherwise SQLite falls back to wasm. CLI prompts use `@clack/prompts@1.0.0` (avoids Node 20+ `util.styleText`). Use `npm run test:node-matrix` (nvm) to exercise majors 18–25 locally.
|
|
22
|
+
- MCP tools now **short-circuit unsuitable question shapes** (topic file-lists, concept/existence/UI-behavior compares without named symbols, SDK/`@kit` feature catalogs): `homegraph_explore` / `homegraph_search` return a short **Skip HomeGraph** note instead of a large graph dump, and tell the agent not to retry. Startup instructions list these skip shapes (shape-driven, not corpus-specific), clarify that in-repo `@kit` **usages** are explore-first (opposite of SDK catalogs), and prefer **lean tools** (`callers` / `node` before a full explore).
|
|
23
|
+
- In-repo `@kit`/`@ohos` **usage** questions no longer get misclassified as `Type.member` (dotted module paths), so explore returns the usage inventory instead of falling through. Compact explore for `Type.member` expands callers on the **member** across packages and surfaces text use sites, so UI-marking questions need fewer Grep/Read follow-ups.
|
|
24
|
+
- `@kit.X的foo` named-export focus is extracted structurally so usage inventories list only matching import sites (full list, ANSWER NOW) instead of dumping every import from a popular kit module. Light mechanism explore seeds distinctive-token imports first (skips SDK stubs) so how-wired answers cover real convert/parse entry files without a Grep/Read loop.
|
|
25
|
+
- Hover/悬停 questions without a named Type soft-skip (including agent-rewritten bags), named UI controls with hover/click go through compact explore (not light-mechanism), `Type.member` compact prefers the member owned by the named Type, and generic NL nouns (`dialog`/`application`/…) no longer inflate focused-anchor counts.
|
|
26
|
+
- Hover/悬停 without a named Type now returns an **onHover / Hover\*** handler inventory (soft-skip→Grep was losing accuracy). Named Page/Component overviews (`ThemeHome`, UI children / navigation) render the full component body in compact explore instead of a bare-id callers stub + self-reference noise.
|
|
27
|
+
- `Type.member` compact explore now **prioritizes the defining package** when scanning text call sites (large monorepos no longer miss nearby `Type.member` filters), surfaces those sites + their source, and tells the agent not to follow up with Grep/`homegraph_callers`.
|
|
28
|
+
- Multi-Type UI composition bags (`*Page` + `*Dialog`, embed/preview/load) stay on **compact explore**: framework decorator names (`@CustomDialog`) are ignored as anchors, co-located Types rank first, and a short Flow no longer kicks the bag into a full related-file dump.
|
|
29
|
+
- Cross-cutting **usage inventories** now own more shapes before Grep: named Type declaration/id sites, `.member` / DrawContext-style API hunts, ALL_CAPS constant scenarios, field/mutex co-use, and path-module NAPI/export or inter-deps. Named Type **state/lifecycle** questions keep a full-body compact path instead of a thin callers stub.
|
|
30
|
+
- Compact explore is leaner for Page/Component surfaces and `Type.member`: prefer `build`/`aboutToAppear` digests (+imports) over whole-struct dumps, tighter char caps, trail-only neighbors for surface questions, and a harder **ANSWER NOW / do not Read-search-again** footer so agents stop stacking a second HomeGraph call.
|
|
31
|
+
- Page/Dialog surface digests now emit **per-method** chunks (`build` / `PageMap` / preview helpers) plus a short **UI/nav inventory**, instead of one aboutToAppear→build window that always trimmed before the answer. Bare type names with no subtypes no longer return an empty inheritance **ANSWER NOW** (that blocked definition/visibility follows like `IntGrid`). C++ subtype lists prefer **public** inheritance. Empty `homegraph_callers` falls back to compact body + use sites for callback-style symbols.
|
|
32
|
+
- API-usage inventories recognize English agent rewrites (`API usages` / `call methods in the project`), expand `Telephony`→`@ohos.telephony`, prefer project files over `.d.ts` stubs, and skip the compact-on-`usages` dead end. UI surface inventories add **Image/preview load** cues; `homegraph_callers` appends include/import lines at call sites for visibility questions; Manager **data-source** answers no longer prepend unrelated badge import floods.
|
|
33
|
+
- Shape routing (agent-rewrite resilient): system-setting **howto** stays a lean `@ohos`/System call inventory (not a light-mechanism dump of every `language` import); **declaration/id/binding** surveys recognize English rewrites; **return-value consumers** become member callers (not create→get flow); PascalCase API bags drop `call`/`radio` noise; compact seeds prefer in-repo defs over SDK `.d.ts`; named-Type **NAPI expose** works without a path segment. Startup instructions call out `.drawModifier` / Kit-deps / return-value / declaration shapes.
|
|
34
|
+
- Step/download→parse→install questions ("会走到哪些代码") route to **light mechanism**, not a domain file-list. Manager **data-source** inventories always keep same-file `@ohos`/`@kit` imports; API usage lists include one-line snippets so Telephony-style usage answers need fewer Grep/Read follow-ups.
|
|
35
|
+
- MCP startup instructions now put **how/mechanism/wiring first**: call `homegraph_explore` immediately with the question or domain keywords (no Grep-first, no parallel Grep). Skip shapes stay listed second. Domain-term extraction keeps mixed ASCII tokens like `xml` so light-mechanism explore can seed without PascalCase names.
|
|
36
|
+
- `homegraph_explore` no longer lets rewritten mechanism bags like `xml parse` collapse into a **compact `parse`-method dump** (that missed `convertxml` and forced Grep/Read). Light-mechanism runs before compact; generic verbs (`parse`/`load`/…) are not local-detail anchors or import-inventory filters, so Import sites follow distinctive tokens like `xml` instead of every `Parse*` notification helper.
|
|
37
|
+
- `homegraph_explore` mechanism / "how is it implemented" answers stay compact (~12K ceiling, light-mechanism ~10K) and end with **ANSWER NOW — do not node/Read the same symbols**, so agents stop stacking a second explore + node + Read that used to inflate session tokens.
|
|
38
|
+
|
|
39
|
+
### Breaking Changes
|
|
40
|
+
|
|
41
|
+
- Standalone installers (`install.sh` / `install.ps1`) and self-contained platform bundles are retired. Install and upgrade with `npm i -g homegraph`; `homegraph upgrade` on a leftover bundle install refuses and points you at npm. `homegraph uninstall` still removes leftover bundle artifacts.
|
|
42
|
+
- Anonymous usage telemetry is removed. HomeGraph no longer records or sends usage stats; `homegraph telemetry` and the installer share-stats prompt are gone. `DO_NOT_TRACK=1` still disables the background update check.
|
|
43
|
+
|
|
44
|
+
### Fixes
|
|
45
|
+
|
|
46
|
+
- SQLite no longer picks built-in `node:sqlite` when that Node build lacks **FTS5** (seen on Node 23.x). Selection probes FTS5 and falls through to `better-sqlite3` / wasm so `init` and indexing work again. Off-thread WAL checkpoint workers now open with the **same** backend as the main connection, so a native primary is not checkpointed via a mismatched `node:sqlite` handle.
|
|
47
|
+
- `homegraph serve mcp --path <repo>` again honors `--path`. A nested Commander subcommand had been dropping it, so the shared daemon keyed off the process cwd instead of the project — MCP prewarm looked timed out and agents attached to the wrong index.
|
|
48
|
+
- Explore inventories stop **wrong-tool fallthrough** that raised tokens and hurt accuracy: declaration-site surveys no longer become include-path "API usage" dumps; return-value consumers prefer the `通过/via` member (with text call-site fallback) instead of SDK `.d.ts` bodies; circular/`*common` module-dep questions get a lean cycle survey; `Type::method` and enum `Type.MEMBER` route as named anchors. Startup instructions match these shapes.
|
|
49
|
+
- Field **new/delete** lifetime questions (`m_eglCore` …) route to a field usage inventory instead of seeding unrelated `new`/`delete` methods; `lib*.so` is not treated as a member access; GLES/EGL **thread** questions take light-mechanism (EGLCore/PluginRender); Type + listed methods (Set/Test/Fill) stay on that type's caller inventory; conditional `Export` fail wiring skips `logInfo` fan-out; API usage lists prefer call-site snippets over imports.
|
|
50
|
+
- Field/mutex co-use inventories **seed scan files from co-named methods** when the field has no FTS hit (avoids a 20k dump); path-module **NAPI export** surveys replace domain file floods; module **cycle** surveys require two named leaf `*common` modules (not a shared parent path); named `.d.ts` wraps get import/call inventories; assigned-flag impact and Toggle state-sync stay on compact explore.
|
|
51
|
+
- Wrong-route fixes that cut token↑ / accuracy↓: kit **extra-deps** and caller+**visibility** no longer lose to light-mechanism; Type + co-named PascalCase methods (`CanPlace`/`Place` ↔ owner Type) stay compact instead of a 13k mechanism dump; constants/fields prefer explore over Grep-first; kit surveys surface `oh-package` dep lines; listed-method caller inventories include a unique-file summary; flag/UI-cluster compact budgets are leaner.
|
|
52
|
+
- Explore **route mutual-exclusion** hardened so inventory/member surveys cannot steal Type×method interaction, Export-fail wiring, or Release↔destructor compares; Manager **状态来源** goes to data-source inventory; repo-wide literal/`text` import hunts defer to Grep (never light); light-mechanism output capped leaner; system-language / hover / kit-deps prefer explore-first. Regression corpus lives under `test/explore-routing/` (`npm run test:explore-routing`; set `HOMEGRAPH_PROBE_ROOT` for live size checks).
|
|
53
|
+
- Light-mechanism **XML howto** seeds `convertxml` / `XmlParseUtil` and caps import/source size so explore stays lean enough that agents need not stack Grep/Read.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## [1.5.2] - 2026-08-05
|
|
57
|
+
|
|
58
|
+
### New Features
|
|
59
|
+
|
|
60
|
+
- MCP **`homegraph_diff_impact`**: pass a unified `diff` (or explicit `hunks`) to get a code-review evidence pack — only symbols whose spans intersect changed **new-side** lines, plus capped callers, impact summary, ArkUI/ViewTree UI edges, and optional Commit4Spec links (`includeSpecs`). Does not dump every symbol in touched files.
|
|
61
|
+
- HarmonyOS / ArkTS `init`/`index` now builds the OHOS API db from a **local DevEco/OpenHarmony SDK** (via `OHOS_SDK_HOME` / `DEVECO_SDK_HOME` / `HOMEGRAPH_OHOS_SDK` or common install paths) into `~/.homegraph/api/` instead of downloading an npm package. Missing SDK still only warns — project indexing continues.
|
|
62
|
+
|
|
63
|
+
### Fixes
|
|
64
|
+
|
|
65
|
+
- MCP tools now treat recoverable bad arguments (missing/empty required fields, wrong types, oversize strings) as **success-shaped guidance with a retry example**, not `isError` — so agents fix the call instead of abandoning HomeGraph for the session. Tool descriptions and required-parameter docs were tightened to match. Security refusals and real faults still use `isError`.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## [1.5.1] - 2026-07-30
|
|
69
|
+
|
|
70
|
+
### Fixes
|
|
71
|
+
|
|
72
|
+
- Large HarmonyOS / ArkTS projects no longer get killed mid-index with "Main thread unresponsive" while ArkAnalyzer is still building the Scene. That work is native and can block the event loop for well over a minute between modules on a big multi-module tree; the safety watchdog now pauses for the Scene build and arms again afterward, so a healthy index finishes without needing `HOMEGRAPH_NO_WATCHDOG` or a raised timeout. A genuinely stuck process outside that span is still caught as before.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
## [1.5.0] - 2026-07-27
|
|
76
|
+
|
|
77
|
+
### New Features
|
|
78
|
+
|
|
79
|
+
- Indexing and sync are substantially faster on large projects (ported from upstream CodeGraph 1.5.0 performance work, HomeGraph naming kept): adaptive watcher debounce with scoped path sync, WAL checkpoint deferral + valve, parallel reference resolution with memory-aware worker pools, fresh-DB store-writer offload, resolution memos / empty synthesis short-circuits, and batch-loop de-quadratic cleanup. Kill switches: `HOMEGRAPH_NO_WAL_DEFER`, `HOMEGRAPH_NO_FAST_INIT`, `HOMEGRAPH_NO_PARALLEL_RESOLVE`, `HOMEGRAPH_NO_STORE_WORKER`, `HOMEGRAPH_RESOLVE_WORKERS`, `HOMEGRAPH_WAL_VALVE_MB`.
|
|
80
|
+
- Field-name explore/search queries (`profileInfo billingMethod` …) now surface the methods/files that define those fields instead of missing them (#1196).
|
|
81
|
+
- ArkTS modular call graphs stay RTA-sparse under a memory budget: each Harmony module gets **intra-module RTA only** for normal calls (CFG same-module stitching is off — that was the ~150k `direct` flood past unlimited RTA). Cross-module edges come from RTA with an exact signature map. A CFG bridge recovers `%unk` invokes when HomeGraph can still read a name from the call site: short `Lib.use(...)` / `const x = Lib.use(...)` text, PascalCase invoke base, `UnclearReferenceType` class names (`b: Base` → `Base.foo`), or imported free functions (`getOpaque()`), always gated by import + unique indexed target and fan-out blocklists. No unresolved name-match call seeds. Deps stay at SIGNATURES; scene aggregator RTA stays skipped. Name-matcher gates remain: no bare exact/fuzzy, Strategy 1 same-file-or-import, same-file `instantiates`, ArkUI IR / stdlib seed drops.
|
|
82
|
+
- Large HarmonyOS (multi-module) ArkTS projects index via ArkAnalyzer `analyseByModule` — each newly loaded module is the baseline for symbols + ViewTree + RTA, with cross-module edges resolved against still-resident deps or previously indexed `signature→nodeId` maps (so B→A still links after A is unloaded). When a dependency was already evicted, ViewTree stubs that still carry class/method signatures are linked through those maps (instead of dropping the edge). Unresolved stub signatures that still say `@%unk/... ComponentName` also fall back to the already-indexed component by class name (and the parent file's import when the name is ambiguous), so parent→child ViewTree edges survive type-inference gaps. Custom-view IR (`View.create`) is still emitted for imported PascalCase calls in `build`/`@Builder` even when the callee module was already unloaded (previously those became plain `staticinvoke` with no stitchable signature). ForEach / LazyForEach / Repeat item builders still expand when FunctionType was lost under eviction, as long as the local is an anonymous UI lambda (`%AM…` / `*$build`) — plain temp names are ignored so unrelated methods are not attached. Same-file children (e.g. `Item` inside `ForEach`) resolve even when the name is ambiguous project-wide, and a single bad ViewTree signature no longer aborts the rest of that class's child-component edges. Process RSS target is 4GB: V8 heap defaults to `--max-old-space-size=3584` (override `HOMEGRAPH_MAX_OLD_SPACE_MB`); Scene `memoryLimitMB` defaults to heap−256MB (override `HOMEGRAPH_ARKTS_MEMORY_LIMIT_MB`). Projects without `build-profile.json5` keep the previous full-Scene path.
|
|
83
|
+
- HarmonyOS multi-module ArkTS sync can now re-index **only dirty modules** (via ArkAnalyzer `analyseByModule` target IDs) instead of rebuilding every PROJECT module when a `.ets` file changes. Unchanged modules stay in the graph; cross-file edges into the dirty module are re-bound. `build-profile.json5` / root `oh-package.json5` edits, or sources outside every module, still force a full ArkTS batch.
|
|
84
|
+
- HomeGraph's MCP startup instructions and tool descriptions now lead with a **closed set of when to call** (in-repo structure, callers/callees, named-symbol wiring, Type.member usage, click→handler flows, in-repo `@kit` usages). Everything outside that set defaults to Read/Grep — no exhaustive "don't call for X/Y/Z" list.
|
|
85
|
+
- `homegraph_explore` no longer treats property/event names like `isExpired` / `onClick` as **import-inventory** queries (that returned useless dependency lists and forced Grep). Named `Type.member` / UI-control+event questions take a **compact path**: definition + caller/callee trail + a few source windows.
|
|
86
|
+
- `homegraph_explore` now keeps **local one-symbol / contract questions compact** (definition-focused windows, ~9K cap) and trims meta sections on no-flow answers — avoiding the previous ~24K related-file dump that often still led to extra grep/read.
|
|
87
|
+
|
|
88
|
+
### Fixes
|
|
89
|
+
|
|
90
|
+
- HarmonyOS / ArkTS indexing no longer walks `build/` (and other default-ignored dirs) when collecting `.ets` files for the Scene batch. That mismatch used to leave extra generated files in the index so non-git `homegraph status` reported Pending Removed right after a fresh `init`.
|
|
91
|
+
- ArkTS Scene builds now run **in-process by default** (including large Windows repos). The isolated child + stack-size retry ladder is opt-in via `HOMEGRAPH_ARKTS_ISOLATED=1`, so `init`/`index` no longer burn minutes on failed isolated retries before users can get a working index.
|
|
92
|
+
- SQLite picks a backend in order: built-in **`node:sqlite`** (Node 22.5+, real WAL), then **better-sqlite3**, then **node-sqlite3-wasm** as last resort so library hosts on older Node still work. `homegraph status` reports `node-sqlite`, `native`, or `wasm`. Override with `HOMEGRAPH_SQLITE_BACKEND`.
|
|
93
|
+
- Type / caller inventory only fires on **real survey intent** (子类 / callers / methods…call). Bare PascalCase callbacks like `OnSurfaceChangedCB` no longer get classified as empty type-inventory (that skipped compact and dumped a 15K full explore). Long NL explore anchors are capped and path/verb noise (`cpp`, `calls`, `render`…) is dropped so neighbor fan-out cannot balloon tokens.
|
|
94
|
+
- Caller surveys that also ask how a **second named type becomes visible/used** (definition visible / include / 定义可见) no longer stop at path-only caller inventory — they take compact explore (callers + bodies) so the agent does not Read/Grep to finish the answer.
|
|
95
|
+
- PascalCase SDK module questions ("which methods does the project use on X") now take an **API usage inventory** instead of an empty class→callers list that fell through to "No relevant code found".
|
|
96
|
+
- Bare-name `homegraph_search` / compact explore no longer fan out every callee neighbor into a multi-file dump (that ballooned token cost when agents search a single symbol). Caller-shaped answers stay on callers + the definition body.
|
|
97
|
+
- On large indexes where catch-up sync is deferred for memory, the staleness banner no longer tells the agent to abandon homegraph and Read whole files for structural caller/def questions.
|
|
98
|
+
- `homegraph_callers` / `homegraph_callees` / `homegraph_impact` no longer resolve an ambiguous name to the top FTS hit when no exact symbol matches — that could return callees of an unrelated function and force Grep/Read to recover.
|
|
99
|
+
- `homegraph_callees` and compact explore call trails prefer **same-package** targets when those exist, so cross-package logger name collisions (`logError` / `logInfo`) do not drown the real upstream/downstream.
|
|
100
|
+
- Type-name and method-caller questions answer from a **type surface inventory** first (subtypes + method→caller lists) when intent is clear. Inventory still runs before compact on explore/search.
|
|
101
|
+
- `homegraph_explore` inheritance / subtype questions (子类, `subclass`, `extends Type`) no longer miss the compact survey because of a regex that matched only `subclasses` (not `subclass`), and no longer first FTS-search the words `extends`/`subclass` as import symbols — which previously fell through to a full explore and pushed large-index RSS into multi-GB.
|
|
102
|
+
- HomeGraph tool calls no longer die as empty MCP client timeouts (~60s `-32001`) on large projects. Heavy tools (`explore` / impact) run on the worker pool with a soft deadline (default 15s, clamped ≤20s). Soft-timeout / tool-deadline callbacks return **static** success-shaped Partial guidance only — they never touch the DB or FTS on the transport thread (any sync work there can freeze the reply flush). Light tools (`search` / `node` / callers) stay on the already-warm main connection.
|
|
103
|
+
- Compact explore for named members now adds **text usage sites** when the graph has no caller edges (common for static `Type.member(...)` reads) — a bounded scan of nearby indexed files — so agents do not need a Grep round-trip for those names.
|
|
104
|
+
- Named-symbol explore/search answers on the warm main connection **before** the worker pool, so compact member questions are not lost to cold-worker / wedged-daemon empty MCP timeouts. Soft deadline default is **15s** (clamped ≤20s); the stdio↔daemon proxy also returns success-shaped Partial if the daemon does not answer in time.
|
|
105
|
+
- ArkTS (HarmonyOS) indexing no longer requires a separate `arkanalyzer` install after `npm install -g homegraph`. The published bundle now ships the dependency automatically.
|
|
106
|
+
- **DevEco Code:** `homegraph install` now writes the global MCP config to `~/.config/deveco` on every platform, including Windows. Earlier versions put it under `%APPDATA%\deveco`, which DevEco Code never reads — so a global install could look successful while DevEco saw no MCP server. Re-run `homegraph install --target=deveco --location=global` to fix an existing setup; stale entries under the old location are cleaned up automatically.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## [1.4.1] - 2026-07-10
|
|
110
|
+
|
|
111
|
+
### New Features
|
|
112
|
+
|
|
113
|
+
- The MCP server now notices when a newer HomeGraph release exists and tells you — a long-running server used to drift behind releases silently until something broke. On startup it checks the latest release in the background (never blocking, at most once a day, cached across all servers on the machine) and surfaces a one-line "update available — run `homegraph upgrade`" notice in the server log, in the instructions your agent sees on connect, and in `homegraph_status`. Nothing updates by itself, and being offline just means no notice. Opt out with `HOMEGRAPH_NO_UPDATE_CHECK=1`; `DO_NOT_TRACK=1` disables it too. (#1243)
|
|
114
|
+
|
|
115
|
+
### Fixes
|
|
116
|
+
|
|
117
|
+
- `homegraph upgrade` on a Windows npm install actually runs npm again — modern Node refuses to launch `npm.cmd` directly, so the upgrade failed with a spawn error before doing anything. npm is now invoked the way a terminal would run it. (#1238)
|
|
118
|
+
- `homegraph uninstall` now actually uninstalls HomeGraph. It used to remove only the agent configurations and leave every installed binary behind, so `homegraph` still ran afterward — especially confusing when both an npm global install and a standalone install were present and removing one still left the other answering on PATH. Uninstall now finds every install on the machine (the standalone bundle, the npm global package, the launcher link) and removes them all, after showing you exactly what it found and asking first (`--yes` skips the prompt). Machine-level settings like your telemetry choice are preserved, a source checkout is never touched, and the new `--keep-cli` flag restores the old configs-only behavior. (#1071)
|
|
119
|
+
- `homegraph_explore` no longer lets ordinary English words in a natural-language question hijack the ranking when they happen to match a code symbol's name. A question like "how does the upgrade flow check the latest version" used to treat "check" as a symbol the agent asked for by name, rank that unrelated definition's file first, and crowd the files the question is actually about out of the answer entirely. Precisely written symbol names (camelCase, PascalCase, snake_case, qualified names) still get top billing exactly as before, as do plain-word symbol bags whose words belong together in the same file.
|
|
120
|
+
- PHP method calls made through a class property — `$this->dep->method()`, the dominant call shape in constructor-injection codebases (Symfony, Laravel) — now resolve to the method on the property's declared type, so callers and impact analysis see production call sites instead of reporting a DI-heavy method as uncalled or test-only. Promoted constructor parameters, typed properties, classic constructor assignment (including multi-line signatures), and typed setter injection all count; interface-typed properties resolve to the interface method, and inherited methods resolve through the type hierarchy. Only property-shaped declarations are consulted — a same-named local variable or parameter elsewhere can never mistype the property — and a property whose type can't be recovered statically stays unlinked rather than guessed. Thanks @w0lan. (#1220)
|
|
121
|
+
- `homegraph upgrade` now also refreshes what previous versions installed into your agents — the HomeGraph section in CLAUDE.md / AGENTS.md / GEMINI.md and the MCP entry — so upgrading no longer leaves agents following instructions written for tools that have since been renamed or removed. Refresh-only: agents you never configured are not touched, and your permission and hook choices are preserved. Also available manually as `homegraph install --refresh`, and skippable with `HOMEGRAPH_NO_INSTALL_REFRESH=1`. (#1238)
|
|
122
|
+
- `homegraph upgrade` on an npm install now upgrades through npm again instead of quietly creating a second copy that never wins the PATH race — previously `homegraph --version` kept reporting the old version forever, no matter how many times you upgraded. (#1238)
|
|
123
|
+
- After every upgrade, HomeGraph now checks that the `homegraph` command your terminal resolves actually serves the freshly installed version — confirming you don't need a new terminal, or telling you exactly which stale install is shadowing the new one. (#1071)
|
|
124
|
+
- The safety watchdog no longer kills a healthy index on severely degraded storage. It used to judge liveness purely by the event loop, so one long database write on a struggling disk looked identical to a hung process and could get a valid, in-progress index terminated. During `homegraph index`/`homegraph init` the watchdog now also checks whether the index files on disk are advancing before it acts: slow-but-progressing work is left alone (bounded by a hard cap), while a genuinely hung process is still killed exactly as fast as before. (#1231)
|
|
125
|
+
- Incremental sync now picks up cross-file relationships that only become resolvable after an edit — for example, when a file gains an export that another, unchanged file was already importing or calling. Previously the reference in the unchanged file was never revisited, so callers, impact, and flow results silently omitted the new edge (while status reported a clean index) until a full re-index. References that can't be resolved yet are now remembered and automatically retried whenever a change introduces a symbol that could satisfy them — this also covers a class gaining a new method that other files already call. Thanks @loadcosmos for the report with a minimal reproduction. (#1240)
|
|
126
|
+
- The reverse case is fixed too: when an edit removes or moves a symbol (or deletes its file), callers in unchanged files now re-resolve during the same sync — rebinding to the symbol's new home when it moved, or waiting to reconnect automatically when it comes back — instead of silently losing their relationship until a full re-index. (#1240)
|
|
127
|
+
|
|
128
|
+
[1.5.2]: https://gitcode.com/ProgramAnalysis/homegraph/tags/v1.5.2
|
|
129
|
+
[1.5.1]: https://gitcode.com/ProgramAnalysis/homegraph/tags/v1.5.1
|
|
130
|
+
[1.5.0]: https://gitcode.com/ProgramAnalysis/homegraph/tags/v1.5.0
|
|
131
|
+
[1.4.1]: https://gitcode.com/ProgramAnalysis/homegraph/tags/v1.4.1
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
在开源知识图谱能力之上,**HomeGraph 新增了对 ArkTS(HarmonyOS)的支持**,通过 [arkanalyzer](https://www.npmjs.com/package/arkanalyzer) 解析 `.ets` / `.ts` 工程中的符号、调用关系与模块结构。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
项目索引保存在工程根目录的 `.homegraph/` 中,不上传云端。
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/homegraph)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
### 1. 安装 CLI
|
|
17
17
|
|
|
18
|
-
需要 **Node.js
|
|
18
|
+
需要 **Node.js 18+**(推荐 22.5+ 或 24)。SQLite 优先用内置 `node:sqlite`(≥22.5),否则 `better-sqlite3`(11.x,含 Node 18),再不行回退 `node-sqlite3-wasm`。
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
npm install -g homegraph
|
|
@@ -156,7 +156,10 @@ homegraph spec stats # 查看Spec知识图谱状态
|
|
|
156
156
|
homegraph spec evolve install # 安装 post-commit 钩子(默认累计 3 次提交后触发演进)
|
|
157
157
|
homegraph spec evolve uninstall# 移除 post-commit 钩子
|
|
158
158
|
homegraph spec evolve process # 手动触发一次Spec演化
|
|
159
|
-
homegraph serve
|
|
159
|
+
homegraph serve mcp # 启动 MCP 服务(一般由 Agent 自动拉起;兼容 serve --mcp)
|
|
160
|
+
# 可选:限制查询用的图 — both(默认)|project|sdk|none
|
|
161
|
+
# homegraph serve mcp --sources sdk
|
|
162
|
+
# 或 HOMEGRAPH_SOURCES=project
|
|
160
163
|
```
|
|
161
164
|
|
|
162
165
|
`explore` / `node` 等命令与同名 MCP 工具共享同一套输出,适合没有 MCP 的子 Agent 或脚本直接调用。
|
|
@@ -171,6 +174,8 @@ Agent 侧工具名前缀为 `homegraph_`。
|
|
|
171
174
|
|
|
172
175
|
**跨项目查询:** 所有工具均支持可选参数 `projectPath`(绝对路径),用于在 monorepo 中查询子项目,或当 MCP 服务器根目录没有索引时指定目标项目。
|
|
173
176
|
|
|
177
|
+
**图谱数据源(`--sources` / `HOMEGRAPH_SOURCES`):** 控制 MCP 查询是否使用工程索引、OHOS SDK API 库,或两者。取值 `both`(默认)| `project` | `sdk` | `none`。CLI 优先于环境变量。评测示例:`homegraph serve mcp --path <app> --sources sdk`。`homegraph_status` 会打印当前模式。
|
|
178
|
+
|
|
174
179
|
| 工具 | 用途 |
|
|
175
180
|
|------|------|
|
|
176
181
|
| `homegraph_explore` | **主工具**:一次调用返回相关符号的完整源码、调用路径与影响范围;支持自然语言问题或符号/文件名列表 |
|
|
@@ -178,8 +183,10 @@ Agent 侧工具名前缀为 `homegraph_`。
|
|
|
178
183
|
| `homegraph_node` | 读取单个符号或整个文件的源码(带行号)及调用关系;可替代 Read 读文件 |
|
|
179
184
|
| `homegraph_callers` / `homegraph_callees` | 查看调用方 / 被调用方 |
|
|
180
185
|
| `homegraph_impact` | 变更影响分析(重构前使用) |
|
|
186
|
+
| `homegraph_diff_impact` | 传入 unified diff(或 hunks),返回与变更行相交的符号及调用/影响证据包(代码审查用) |
|
|
187
|
+
| `homegraph_arkui_migrate` | 一次返回 ArkUI 组件迁移/状态语义快照(装饰器、状态字段、Provide/Consume 等) |
|
|
181
188
|
| `homegraph_files` | 已索引的文件树(支持 glob 过滤、按语言分组) |
|
|
182
|
-
| `homegraph_status` |
|
|
189
|
+
| `homegraph_status` | 索引健康状态(调试用;含 WAL 大小等) |
|
|
183
190
|
| `homegraph_spec_match` | 将新需求描述与 Commit4Spec 知识图谱做全文匹配,返回相似历史Spec及关联提交与代码片段 |
|
|
184
191
|
| `homegraph_spec_find` | 根据文件路径反向查找关联的Spec |
|
|
185
192
|
| `homegraph_spec_trace` | 根据代码符号追溯回关联的Spec |
|
|
@@ -241,7 +248,7 @@ TypeScript / JavaScript、Python、Go、Rust、Java、C#、PHP、Ruby、C / C++
|
|
|
241
248
|
|
|
242
249
|
## 从源码构建
|
|
243
250
|
|
|
244
|
-
|
|
251
|
+
适用于开发或二次修改。协作约定(代码拉取、Commit、PR 清单)见 [DEVELOPMENT.md](./DEVELOPMENT.md)。
|
|
245
252
|
|
|
246
253
|
```bash
|
|
247
254
|
git clone <your-repo-url>
|
|
@@ -271,7 +278,7 @@ npm run cli
|
|
|
271
278
|
"homegraph": {
|
|
272
279
|
"type": "stdio",
|
|
273
280
|
"command": "homegraph",
|
|
274
|
-
"args": ["serve", "
|
|
281
|
+
"args": ["serve", "mcp"]
|
|
275
282
|
}
|
|
276
283
|
}
|
|
277
284
|
}
|
|
@@ -287,14 +294,14 @@ Cursor 等项目级配置写入 `./.cursor/mcp.json`,格式相同。推荐使
|
|
|
287
294
|
|------|------|
|
|
288
295
|
| 上游 | 持续同步 colbymchenry 开源知识图谱项目 main 分支 |
|
|
289
296
|
| 包名 / CLI | `homegraph`(npm:`npm install -g homegraph`) |
|
|
290
|
-
| 数据目录 | `.homegraph/` |
|
|
297
|
+
| 数据目录 | 工程根目录 `.homegraph/` |
|
|
291
298
|
| 主要差异 | 新增 **ArkTS** 语言支持与相关索引逻辑 |
|
|
292
299
|
|
|
293
300
|
---
|
|
294
301
|
|
|
295
302
|
## 环境要求
|
|
296
303
|
|
|
297
|
-
- Node.js **
|
|
304
|
+
- Node.js **18+**(推荐 22.5+ 或 24;SQLite:`node:sqlite` → better-sqlite3 11.x → wasm)
|
|
298
305
|
- 首次索引时会对项目源码做 AST 解析,大型仓库首次 `init -i` 可能需要数分钟
|
|
299
306
|
- WSL2 下若项目位于 Windows 盘符(`/mnt/c` 等)且 MCP 连接不稳定,可设置 `HOMEGRAPH_NO_DAEMON=1` 跳过共享后台服务,每个会话独立运行
|
|
300
307
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/arkui/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,8BAA8B,EAC9B,yBAAyB,EACzB,KAAK,WAAW,GACjB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.resolveObjectLiteralClass = exports.collectPassagesForViewTreeNode = void 0;
|
|
18
|
+
__exportStar(require("./migrate-semantics"), exports);
|
|
19
|
+
__exportStar(require("./migrate-snapshot"), exports);
|
|
20
|
+
var migrate_passage_1 = require("./migrate-passage");
|
|
21
|
+
Object.defineProperty(exports, "collectPassagesForViewTreeNode", { enumerable: true, get: function () { return migrate_passage_1.collectPassagesForViewTreeNode; } });
|
|
22
|
+
Object.defineProperty(exports, "resolveObjectLiteralClass", { enumerable: true, get: function () { return migrate_passage_1.resolveObjectLiteralClass; } });
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/arkui/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,qDAAmC;AACnC,qDAI2B;AAHzB,iIAAA,8BAA8B,OAAA;AAC9B,4HAAA,yBAAyB,OAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewTree data-passage classification for ArkUI migrate (spec 0007).
|
|
3
|
+
* Ports migration-graph object-literal + transfer fallbacks with duck typing.
|
|
4
|
+
*/
|
|
5
|
+
import { type Scene, type ArkClass, type ArkField } from 'arkanalyzer';
|
|
6
|
+
import type { ViewTreeNode } from 'arkanalyzer';
|
|
7
|
+
import { type PassageType, type ValueTypeKind } from './migrate-semantics';
|
|
8
|
+
export interface PassageEmit {
|
|
9
|
+
fromField?: ArkField;
|
|
10
|
+
fromIsParentComponent: boolean;
|
|
11
|
+
toField: ArkField;
|
|
12
|
+
passageType: PassageType;
|
|
13
|
+
valueType: ValueTypeKind;
|
|
14
|
+
forcesMigration: boolean;
|
|
15
|
+
parentExpression: string;
|
|
16
|
+
/** Child decorator via for explore labels: Prop | Link | data-passage | builder-param */
|
|
17
|
+
via: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve anonymous object-literal class from ViewTree `create` attribute
|
|
21
|
+
* (same chain as migration-graph / ViewTreeBuilder).
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveObjectLiteralClass(node: ViewTreeNode, scene: Scene): ArkClass | null;
|
|
24
|
+
/**
|
|
25
|
+
* Emit passage records for a custom-component ViewTree node.
|
|
26
|
+
*/
|
|
27
|
+
export declare function collectPassagesForViewTreeNode(node: ViewTreeNode, scene: Scene, parentCls: ArkClass): PassageEmit[];
|
|
28
|
+
//# sourceMappingURL=migrate-passage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-passage.d.ts","sourceRoot":"","sources":["../../src/arkui/migrate-passage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAc,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAkB,MAAM,aAAa,CAAC;AACnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,OAAO,EAAE,QAAQ,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,aAAa,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAC;CACb;AA6ED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,KAAK,GACX,QAAQ,GAAG,IAAI,CAmDjB;AAyCD;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,QAAQ,GAClB,WAAW,EAAE,CA4Gf"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ViewTree data-passage classification for ArkUI migrate (spec 0007).
|
|
4
|
+
* Ports migration-graph object-literal + transfer fallbacks with duck typing.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.resolveObjectLiteralClass = resolveObjectLiteralClass;
|
|
8
|
+
exports.collectPassagesForViewTreeNode = collectPassagesForViewTreeNode;
|
|
9
|
+
const arkanalyzer_1 = require("arkanalyzer");
|
|
10
|
+
const migrate_semantics_1 = require("./migrate-semantics");
|
|
11
|
+
/** ArkAnalyzer ClassCategory.OBJECT */
|
|
12
|
+
const CLASS_CATEGORY_OBJECT = 5;
|
|
13
|
+
function hasFn(v, ...names) {
|
|
14
|
+
if (!v || typeof v !== 'object')
|
|
15
|
+
return false;
|
|
16
|
+
return names.every((n) => typeof v[n] === 'function');
|
|
17
|
+
}
|
|
18
|
+
function backtraceLocalInitValue(value, depth = 0) {
|
|
19
|
+
if (depth > 8 || !value)
|
|
20
|
+
return value;
|
|
21
|
+
if (!hasFn(value, 'getDeclaringStmt'))
|
|
22
|
+
return value;
|
|
23
|
+
try {
|
|
24
|
+
const stmt = value.getDeclaringStmt();
|
|
25
|
+
if (!stmt || !hasFn(stmt, 'getRightOp'))
|
|
26
|
+
return value;
|
|
27
|
+
const right = stmt.getRightOp();
|
|
28
|
+
return backtraceLocalInitValue(right, depth + 1);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function valueText(v) {
|
|
35
|
+
try {
|
|
36
|
+
if (v != null && typeof v.toString === 'function') {
|
|
37
|
+
return String(v.toString());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
/* ignore */
|
|
42
|
+
}
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
function isInstanceFieldRef(v) {
|
|
46
|
+
return hasFn(v, 'getFieldName') && hasFn(v, 'getBase');
|
|
47
|
+
}
|
|
48
|
+
function classifyRightOp(rightOp, childDecorator, parentCls) {
|
|
49
|
+
const text = valueText(rightOp);
|
|
50
|
+
if (text.includes('$$') || text.includes('!!'))
|
|
51
|
+
return 'two_way_binding';
|
|
52
|
+
if (childDecorator === 'BuilderParam')
|
|
53
|
+
return 'callback';
|
|
54
|
+
if (isInstanceFieldRef(rightOp)) {
|
|
55
|
+
const name = rightOp.getFieldName();
|
|
56
|
+
if (parentCls && !parentCls.getFieldWithName(name))
|
|
57
|
+
return 'callback';
|
|
58
|
+
return 'state_variable_ref';
|
|
59
|
+
}
|
|
60
|
+
if (hasFn(rightOp, 'getClassType') || /^new\s+/.test(text.trim())) {
|
|
61
|
+
if (hasFn(rightOp, 'getArgs') || text.trim().startsWith('new '))
|
|
62
|
+
return 'new_instance';
|
|
63
|
+
}
|
|
64
|
+
// Constant-like
|
|
65
|
+
if (hasFn(rightOp, 'getValue') && hasFn(rightOp, 'getType') && !hasFn(rightOp, 'getFieldName')) {
|
|
66
|
+
return 'literal';
|
|
67
|
+
}
|
|
68
|
+
if (hasFn(rightOp, 'getMethodSignature') || hasFn(rightOp, 'getInvokeExpr')) {
|
|
69
|
+
return 'function_call';
|
|
70
|
+
}
|
|
71
|
+
if (hasFn(rightOp, 'getType')) {
|
|
72
|
+
try {
|
|
73
|
+
const t = rightOp.getType();
|
|
74
|
+
const ts = t?.toString?.() ?? '';
|
|
75
|
+
if (/Function|=>/.test(ts))
|
|
76
|
+
return 'callback';
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
/* ignore */
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return (0, migrate_semantics_1.classifyPassageFromText)(text, {
|
|
83
|
+
childDecorator,
|
|
84
|
+
parentHasField: parentCls
|
|
85
|
+
? (n) => !!parentCls.getFieldWithName(n)
|
|
86
|
+
: undefined,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Resolve anonymous object-literal class from ViewTree `create` attribute
|
|
91
|
+
* (same chain as migration-graph / ViewTreeBuilder).
|
|
92
|
+
*/
|
|
93
|
+
function resolveObjectLiteralClass(node, scene) {
|
|
94
|
+
const createEntry = node.attributes?.get('create');
|
|
95
|
+
if (!createEntry)
|
|
96
|
+
return null;
|
|
97
|
+
const stmt = createEntry[0];
|
|
98
|
+
let expr;
|
|
99
|
+
try {
|
|
100
|
+
if (hasFn(stmt, 'getRightOp')) {
|
|
101
|
+
expr = stmt.getRightOp();
|
|
102
|
+
}
|
|
103
|
+
else if (hasFn(stmt, 'getInvokeExpr')) {
|
|
104
|
+
expr = stmt.getInvokeExpr();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (!hasFn(expr, 'getArg'))
|
|
111
|
+
return null;
|
|
112
|
+
let temp;
|
|
113
|
+
try {
|
|
114
|
+
temp = expr.getArg(0);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (!hasFn(temp, 'getUsedStmts'))
|
|
120
|
+
return null;
|
|
121
|
+
let arg;
|
|
122
|
+
try {
|
|
123
|
+
for (const usedStmt of temp.getUsedStmts()) {
|
|
124
|
+
if (!hasFn(usedStmt, 'getRightOp'))
|
|
125
|
+
continue;
|
|
126
|
+
const rightOp = usedStmt.getRightOp();
|
|
127
|
+
if (!hasFn(rightOp, 'getMethodSignature') || !hasFn(rightOp, 'getArg'))
|
|
128
|
+
continue;
|
|
129
|
+
try {
|
|
130
|
+
const ms = rightOp.getMethodSignature();
|
|
131
|
+
if (ms.getMethodSubSignature().getMethodName() !== 'constructor')
|
|
132
|
+
continue;
|
|
133
|
+
arg = rightOp.getArg(0);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
if (!arg || !hasFn(arg, 'getType'))
|
|
145
|
+
return null;
|
|
146
|
+
try {
|
|
147
|
+
const argType = arg.getType();
|
|
148
|
+
const objectCls = arkanalyzer_1.ModelUtils.getArkClassInBuild(scene, argType);
|
|
149
|
+
if (!objectCls || objectCls.getCategory() !== CLASS_CATEGORY_OBJECT)
|
|
150
|
+
return null;
|
|
151
|
+
return objectCls;
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function childDecoratorKind(field) {
|
|
158
|
+
try {
|
|
159
|
+
const decs = field.getStateDecorators?.();
|
|
160
|
+
if (decs) {
|
|
161
|
+
for (const d of decs) {
|
|
162
|
+
const k = d.getKind();
|
|
163
|
+
if (k)
|
|
164
|
+
return k;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
/* ignore */
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
for (const d of field.getDecorators?.() ?? []) {
|
|
173
|
+
const k = d.getKind();
|
|
174
|
+
if (k === 'Prop' || k === 'Link' || k === 'Param' || k === 'ObjectLink' || k === 'BuilderParam') {
|
|
175
|
+
return k;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
/* ignore */
|
|
181
|
+
}
|
|
182
|
+
return '';
|
|
183
|
+
}
|
|
184
|
+
function viaForChildDecorator(kind) {
|
|
185
|
+
if (kind === 'Prop' || kind === 'Link')
|
|
186
|
+
return kind;
|
|
187
|
+
if (kind === 'BuilderParam')
|
|
188
|
+
return 'builder-param';
|
|
189
|
+
return 'data-passage';
|
|
190
|
+
}
|
|
191
|
+
function valueTypeOfField(field) {
|
|
192
|
+
try {
|
|
193
|
+
return (0, migrate_semantics_1.classifyValueType)(field.getType()?.toString());
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return 'unknown';
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Emit passage records for a custom-component ViewTree node.
|
|
201
|
+
*/
|
|
202
|
+
function collectPassagesForViewTreeNode(node, scene, parentCls) {
|
|
203
|
+
const out = [];
|
|
204
|
+
const seen = new Set();
|
|
205
|
+
const objectCls = resolveObjectLiteralClass(node, scene);
|
|
206
|
+
if (objectCls) {
|
|
207
|
+
for (const field of objectCls.getFields()) {
|
|
208
|
+
const childName = field.getName();
|
|
209
|
+
// Map object-literal field → child component field by name
|
|
210
|
+
const childField = (() => {
|
|
211
|
+
// Prefer signature's declaring class fields via stateValuesTransfer keys
|
|
212
|
+
if (node.stateValuesTransfer) {
|
|
213
|
+
for (const [cf] of node.stateValuesTransfer) {
|
|
214
|
+
if (cf.getName() === childName)
|
|
215
|
+
return cf;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
})();
|
|
220
|
+
// If transfer map missing this name, still try to use literal field as stand-in
|
|
221
|
+
// only when we can resolve real child field from transfer.
|
|
222
|
+
if (!childField)
|
|
223
|
+
continue;
|
|
224
|
+
const initializers = field.getInitializer?.() ?? [];
|
|
225
|
+
if (initializers.length === 0)
|
|
226
|
+
continue;
|
|
227
|
+
const assign = initializers[initializers.length - 1];
|
|
228
|
+
if (!hasFn(assign, 'getRightOp'))
|
|
229
|
+
continue;
|
|
230
|
+
const rightOp = backtraceLocalInitValue(assign.getRightOp());
|
|
231
|
+
const childDec = childDecoratorKind(childField);
|
|
232
|
+
const passageType = classifyRightOp(rightOp, childDec, parentCls);
|
|
233
|
+
const valueType = valueTypeOfField(childField);
|
|
234
|
+
const forcesMigration = (0, migrate_semantics_1.computeForcesMigration)(passageType, valueType);
|
|
235
|
+
const parentExpression = valueText(rightOp);
|
|
236
|
+
let fromField;
|
|
237
|
+
let fromIsParentComponent = true;
|
|
238
|
+
if ((passageType === 'state_variable_ref' || passageType === 'two_way_binding') &&
|
|
239
|
+
isInstanceFieldRef(rightOp)) {
|
|
240
|
+
const pf = parentCls.getFieldWithName(rightOp.getFieldName());
|
|
241
|
+
if (pf) {
|
|
242
|
+
fromField = pf;
|
|
243
|
+
fromIsParentComponent = false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const key = `${fromField?.getName() ?? 'comp'}|${childField.getName()}|${passageType}`;
|
|
247
|
+
if (seen.has(key))
|
|
248
|
+
continue;
|
|
249
|
+
seen.add(key);
|
|
250
|
+
out.push({
|
|
251
|
+
fromField,
|
|
252
|
+
fromIsParentComponent,
|
|
253
|
+
toField: childField,
|
|
254
|
+
passageType,
|
|
255
|
+
valueType,
|
|
256
|
+
forcesMigration,
|
|
257
|
+
parentExpression,
|
|
258
|
+
via: viaForChildDecorator(childDec),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (out.length > 0)
|
|
262
|
+
return out;
|
|
263
|
+
}
|
|
264
|
+
// Fallback: stateValuesTransfer
|
|
265
|
+
if (!node.stateValuesTransfer)
|
|
266
|
+
return out;
|
|
267
|
+
for (const [childField, value] of node.stateValuesTransfer) {
|
|
268
|
+
const childDec = childDecoratorKind(childField);
|
|
269
|
+
const valueType = valueTypeOfField(childField);
|
|
270
|
+
let passageType;
|
|
271
|
+
let fromField;
|
|
272
|
+
let fromIsParentComponent = true;
|
|
273
|
+
let parentExpression;
|
|
274
|
+
let via;
|
|
275
|
+
if (value && typeof value.getName === 'function' && hasFn(value, 'getDeclaringArkClass')) {
|
|
276
|
+
// ArkField
|
|
277
|
+
passageType = 'state_variable_ref';
|
|
278
|
+
fromField = value;
|
|
279
|
+
fromIsParentComponent = false;
|
|
280
|
+
parentExpression = `this.${fromField.getName()}`;
|
|
281
|
+
via = viaForChildDecorator(childDec) || 'Prop';
|
|
282
|
+
}
|
|
283
|
+
else if (value && hasFn(value, 'getSignature')) {
|
|
284
|
+
// ArkMethod builder
|
|
285
|
+
passageType = 'callback';
|
|
286
|
+
parentExpression = `<builder:${value.getName?.() ?? 'builder'}>`;
|
|
287
|
+
via = 'builder-param';
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const forcesMigration = (0, migrate_semantics_1.computeForcesMigration)(passageType, valueType);
|
|
293
|
+
const key = `${fromField?.getName() ?? 'comp'}|${childField.getName()}|${passageType}`;
|
|
294
|
+
if (seen.has(key))
|
|
295
|
+
continue;
|
|
296
|
+
seen.add(key);
|
|
297
|
+
out.push({
|
|
298
|
+
fromField,
|
|
299
|
+
fromIsParentComponent,
|
|
300
|
+
toField: childField,
|
|
301
|
+
passageType,
|
|
302
|
+
valueType,
|
|
303
|
+
forcesMigration,
|
|
304
|
+
parentExpression,
|
|
305
|
+
via,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
return out;
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=migrate-passage.js.map
|