homegraph 1.6.2 → 1.6.4
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 +26 -0
- package/dist/bin/homegraph.js +15 -9
- package/dist/db/index.d.ts +21 -0
- package/dist/db/index.js +56 -0
- package/dist/directory.d.ts +17 -0
- package/dist/directory.js +40 -0
- package/dist/extraction/grammars.js +7 -0
- package/dist/extraction/index.d.ts +5 -0
- package/dist/extraction/index.js +162 -116
- package/dist/extraction/jsdoc-type-tags.d.ts +19 -0
- package/dist/extraction/jsdoc-type-tags.js +115 -0
- package/dist/extraction/languages/arkts.js +198 -31
- package/dist/extraction/store-flush-guard.d.ts +11 -0
- package/dist/extraction/store-flush-guard.js +19 -0
- package/dist/extraction/store-worker.d.ts +3 -2
- package/dist/extraction/store-worker.js +3 -2
- package/dist/extraction/tree-sitter.d.ts +8 -1
- package/dist/extraction/tree-sitter.js +52 -11
- package/dist/index.js +31 -1
- package/dist/resolution/callback-synthesizer.d.ts +12 -0
- package/dist/resolution/callback-synthesizer.js +5 -8
- package/dist/resolution/name-matcher.d.ts +5 -0
- package/dist/resolution/name-matcher.js +60 -1
- package/package.json +3 -1
|
@@ -47,6 +47,7 @@ const function_ref_1 = require("./function-ref");
|
|
|
47
47
|
const generated_detection_1 = require("./generated-detection");
|
|
48
48
|
const languages_1 = require("./languages");
|
|
49
49
|
const c_cpp_1 = require("./languages/c-cpp");
|
|
50
|
+
const jsdoc_type_tags_1 = require("./jsdoc-type-tags");
|
|
50
51
|
const liquid_extractor_1 = require("./liquid-extractor");
|
|
51
52
|
const razor_extractor_1 = require("./razor-extractor");
|
|
52
53
|
const svelte_extractor_1 = require("./svelte-extractor");
|
|
@@ -1511,6 +1512,8 @@ class TreeSitterExtractor {
|
|
|
1511
1512
|
return;
|
|
1512
1513
|
// Extract type annotations (parameter types and return type)
|
|
1513
1514
|
this.extractTypeAnnotations(node, funcNode.id);
|
|
1515
|
+
// Spec 0066: JSDoc @returns/@param when the signature omitted types.
|
|
1516
|
+
this.emitJsdocTypeFallbacks(funcNode.id, docstring);
|
|
1514
1517
|
// Extract decorators applied to the function (rare in JS/TS but
|
|
1515
1518
|
// present in Python `@decorator def f():` and Java/Kotlin
|
|
1516
1519
|
// annotations on free functions).
|
|
@@ -1712,6 +1715,8 @@ class TreeSitterExtractor {
|
|
|
1712
1715
|
}
|
|
1713
1716
|
// Extract type annotations (parameter types and return type)
|
|
1714
1717
|
this.extractTypeAnnotations(node, methodNode.id);
|
|
1718
|
+
// Spec 0066: JSDoc @returns/@param when the signature omitted types.
|
|
1719
|
+
this.emitJsdocTypeFallbacks(methodNode.id, docstring);
|
|
1715
1720
|
// Extract decorators (`@Get('/list') list() {}`).
|
|
1716
1721
|
this.extractDecoratorsFor(node, methodNode.id);
|
|
1717
1722
|
// Push to stack and visit body
|
|
@@ -5636,7 +5641,8 @@ class TreeSitterExtractor {
|
|
|
5636
5641
|
]);
|
|
5637
5642
|
/**
|
|
5638
5643
|
* Extract type references from type annotations on a function/method/field node.
|
|
5639
|
-
*
|
|
5644
|
+
* Spec 0066: parameter / field types → `type_of`; return types → `returns`.
|
|
5645
|
+
* Dart / Scala mixed signature walks stay `references` (out of this Spec).
|
|
5640
5646
|
*/
|
|
5641
5647
|
extractTypeAnnotations(node, nodeId) {
|
|
5642
5648
|
if (!this.extractor)
|
|
@@ -5668,6 +5674,7 @@ class TreeSitterExtractor {
|
|
|
5668
5674
|
// `type_identifier` child, not a `type` field — so getChildByField below
|
|
5669
5675
|
// finds neither. Walk the inner signature: param names / the method name are
|
|
5670
5676
|
// `identifier` (not `type_identifier`), so only types surface.
|
|
5677
|
+
// Spec 0066: leave as `references` (mixed return+param walk).
|
|
5671
5678
|
if (this.language === 'dart') {
|
|
5672
5679
|
let sig = node;
|
|
5673
5680
|
if (node.type === 'method_signature') {
|
|
@@ -5677,7 +5684,7 @@ class TreeSitterExtractor {
|
|
|
5677
5684
|
c.type === 'constructor_signature' ||
|
|
5678
5685
|
c.type === 'factory_constructor_signature') ?? node;
|
|
5679
5686
|
}
|
|
5680
|
-
this.extractTypeRefsFromSubtree(sig, nodeId);
|
|
5687
|
+
this.extractTypeRefsFromSubtree(sig, nodeId, 'references');
|
|
5681
5688
|
return;
|
|
5682
5689
|
}
|
|
5683
5690
|
// Extract parameter type annotations. Scala curries — `def f(a)(implicit
|
|
@@ -5687,19 +5694,19 @@ class TreeSitterExtractor {
|
|
|
5687
5694
|
if (this.language === 'scala') {
|
|
5688
5695
|
for (const pc of node.namedChildren) {
|
|
5689
5696
|
if (pc.type === 'parameters')
|
|
5690
|
-
this.extractTypeRefsFromSubtree(pc, nodeId);
|
|
5697
|
+
this.extractTypeRefsFromSubtree(pc, nodeId, 'type_of');
|
|
5691
5698
|
}
|
|
5692
5699
|
}
|
|
5693
5700
|
else {
|
|
5694
5701
|
const params = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.paramsField || 'parameters');
|
|
5695
5702
|
if (params) {
|
|
5696
|
-
this.extractTypeRefsFromSubtree(params, nodeId);
|
|
5703
|
+
this.extractTypeRefsFromSubtree(params, nodeId, 'type_of');
|
|
5697
5704
|
}
|
|
5698
5705
|
}
|
|
5699
5706
|
// Extract return type annotation
|
|
5700
5707
|
const returnType = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.returnField || 'return_type');
|
|
5701
5708
|
if (returnType) {
|
|
5702
|
-
this.extractTypeRefsFromSubtree(returnType, nodeId);
|
|
5709
|
+
this.extractTypeRefsFromSubtree(returnType, nodeId, 'returns');
|
|
5703
5710
|
}
|
|
5704
5711
|
// Scala context bounds / type-parameter bounds: `def f[A: Monoid]`,
|
|
5705
5712
|
// `[F[_]: Monad]`, `[A <: Foo]` carry the bound type inside `type_parameters`.
|
|
@@ -5711,13 +5718,46 @@ class TreeSitterExtractor {
|
|
|
5711
5718
|
if (this.language === 'scala') {
|
|
5712
5719
|
const typeParams = node.namedChildren.find((c) => c.type === 'type_parameters');
|
|
5713
5720
|
if (typeParams) {
|
|
5714
|
-
this.extractTypeRefsFromSubtree(typeParams, nodeId);
|
|
5721
|
+
this.extractTypeRefsFromSubtree(typeParams, nodeId, 'type_of');
|
|
5715
5722
|
}
|
|
5716
5723
|
}
|
|
5717
5724
|
// Extract direct type annotation (for class fields like `model: ITextModel`)
|
|
5718
5725
|
const typeAnnotation = node.namedChildren.find((c) => c.type === 'type_annotation');
|
|
5719
5726
|
if (typeAnnotation) {
|
|
5720
|
-
this.extractTypeRefsFromSubtree(typeAnnotation, nodeId);
|
|
5727
|
+
this.extractTypeRefsFromSubtree(typeAnnotation, nodeId, 'type_of');
|
|
5728
|
+
}
|
|
5729
|
+
}
|
|
5730
|
+
/**
|
|
5731
|
+
* Spec 0066: when the AST omitted return/param types, emit unresolved
|
|
5732
|
+
* `returns` / `type_of` refs from JSDoc `@returns` / `@param {Type}`.
|
|
5733
|
+
*/
|
|
5734
|
+
emitJsdocTypeFallbacks(fromNodeId, docstring) {
|
|
5735
|
+
if (!docstring)
|
|
5736
|
+
return;
|
|
5737
|
+
const hasReturns = this.unresolvedReferences.some((r) => r.fromNodeId === fromNodeId && r.referenceKind === 'returns');
|
|
5738
|
+
if (!hasReturns) {
|
|
5739
|
+
const ret = (0, jsdoc_type_tags_1.parseJsdocReturns)(docstring);
|
|
5740
|
+
if (ret) {
|
|
5741
|
+
this.unresolvedReferences.push({
|
|
5742
|
+
fromNodeId,
|
|
5743
|
+
referenceName: ret,
|
|
5744
|
+
referenceKind: 'returns',
|
|
5745
|
+
line: 1,
|
|
5746
|
+
column: 0,
|
|
5747
|
+
});
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
const hasTypeOf = this.unresolvedReferences.some((r) => r.fromNodeId === fromNodeId && r.referenceKind === 'type_of');
|
|
5751
|
+
if (!hasTypeOf) {
|
|
5752
|
+
for (const p of (0, jsdoc_type_tags_1.parseJsdocParams)(docstring)) {
|
|
5753
|
+
this.unresolvedReferences.push({
|
|
5754
|
+
fromNodeId,
|
|
5755
|
+
referenceName: p.typeName,
|
|
5756
|
+
referenceKind: 'type_of',
|
|
5757
|
+
line: 1,
|
|
5758
|
+
column: 0,
|
|
5759
|
+
});
|
|
5760
|
+
}
|
|
5721
5761
|
}
|
|
5722
5762
|
}
|
|
5723
5763
|
/**
|
|
@@ -5923,21 +5963,22 @@ class TreeSitterExtractor {
|
|
|
5923
5963
|
// Find type_annotation child (covers TS `: Type`, Rust `: Type`, etc.)
|
|
5924
5964
|
const typeAnnotation = node.namedChildren.find((c) => c.type === 'type_annotation');
|
|
5925
5965
|
if (typeAnnotation) {
|
|
5926
|
-
this.extractTypeRefsFromSubtree(typeAnnotation, nodeId);
|
|
5966
|
+
this.extractTypeRefsFromSubtree(typeAnnotation, nodeId, 'type_of');
|
|
5927
5967
|
}
|
|
5928
5968
|
}
|
|
5929
5969
|
/**
|
|
5930
5970
|
* Recursively walk a subtree and extract all type_identifier references.
|
|
5931
5971
|
* Handles unions, intersections, generics, arrays, etc.
|
|
5972
|
+
* Spec 0066: callers pass `returns` / `type_of` for signature positions.
|
|
5932
5973
|
*/
|
|
5933
|
-
extractTypeRefsFromSubtree(node, fromNodeId) {
|
|
5974
|
+
extractTypeRefsFromSubtree(node, fromNodeId, referenceKind = 'references') {
|
|
5934
5975
|
if (node.type === 'type_identifier') {
|
|
5935
5976
|
const typeName = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
|
|
5936
5977
|
if (typeName && !this.BUILTIN_TYPES.has(typeName)) {
|
|
5937
5978
|
this.unresolvedReferences.push({
|
|
5938
5979
|
fromNodeId,
|
|
5939
5980
|
referenceName: typeName,
|
|
5940
|
-
referenceKind
|
|
5981
|
+
referenceKind,
|
|
5941
5982
|
line: node.startPosition.row + 1,
|
|
5942
5983
|
column: node.startPosition.column,
|
|
5943
5984
|
});
|
|
@@ -5948,7 +5989,7 @@ class TreeSitterExtractor {
|
|
|
5948
5989
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
5949
5990
|
const child = node.namedChild(i);
|
|
5950
5991
|
if (child) {
|
|
5951
|
-
this.extractTypeRefsFromSubtree(child, fromNodeId);
|
|
5992
|
+
this.extractTypeRefsFromSubtree(child, fromNodeId, referenceKind);
|
|
5952
5993
|
}
|
|
5953
5994
|
}
|
|
5954
5995
|
}
|
package/dist/index.js
CHANGED
|
@@ -490,7 +490,37 @@ class HomeGraph {
|
|
|
490
490
|
this.db.beginBulkParseLoad();
|
|
491
491
|
let result;
|
|
492
492
|
try {
|
|
493
|
-
result = await this.orchestrator.indexAll(options.onProgress, options.signal, options.verbose, walValve ? () => walValve.backpressure() : undefined, freshDb
|
|
493
|
+
result = await this.orchestrator.indexAll(options.onProgress, options.signal, options.verbose, walValve ? () => walValve.backpressure() : undefined, freshDb
|
|
494
|
+
? {
|
|
495
|
+
dbPath: this.db.getPath(),
|
|
496
|
+
fastInit,
|
|
497
|
+
// Spec 0065: exclusive store-worker handoff (close main → worker → reopen).
|
|
498
|
+
exclusiveHandoff: {
|
|
499
|
+
release: () => {
|
|
500
|
+
this.db.closeForExclusiveWriter();
|
|
501
|
+
},
|
|
502
|
+
reclaim: () => {
|
|
503
|
+
this.db.reopenAfterExclusiveWriter({ fastInit });
|
|
504
|
+
this.queries.rebind(this.db.getDb());
|
|
505
|
+
(0, context_1.bindExtractionContext)(this.projectRoot, this.queries);
|
|
506
|
+
// ATTACH is per-connection. ohosApiDbPath survives rebind and
|
|
507
|
+
// would make attachOhosApiDb early-return while the schema
|
|
508
|
+
// is gone → "no such table: ohos_api.nodes". Clear then reattach.
|
|
509
|
+
const priorOhos = this.queries.getOhosApiDbPath();
|
|
510
|
+
this.queries.attachOhosApiDb(null);
|
|
511
|
+
if (priorOhos) {
|
|
512
|
+
this.queries.attachOhosApiDb(priorOhos);
|
|
513
|
+
}
|
|
514
|
+
else if ((0, graph_sources_1.graphSourceFlags)(this.graphSources).sdk) {
|
|
515
|
+
(0, arkts_1.restoreOhosApiDbAttach)(this.queries);
|
|
516
|
+
if (!this.queries.getOhosApiDbPath()) {
|
|
517
|
+
(0, arkts_1.attachExistingOhosApiDbForProject)(this.projectRoot, this.queries);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
},
|
|
522
|
+
}
|
|
523
|
+
: null);
|
|
494
524
|
}
|
|
495
525
|
finally {
|
|
496
526
|
if (freshDb) {
|
|
@@ -25,6 +25,18 @@ import type { Edge } from '../types';
|
|
|
25
25
|
import type { QueryBuilder } from '../db/queries';
|
|
26
26
|
import type { ResolutionContext } from './types';
|
|
27
27
|
import { type MaybeYield } from './cooperative-yield';
|
|
28
|
+
/**
|
|
29
|
+
* Spec 0045 A — ArkUI parent build/@Builder → child @Component/@Builder.
|
|
30
|
+
* Analog of react jsx-child: only static PascalCase call names that resolve to
|
|
31
|
+
* a unique in-repo component/builder; ambiguous names are dropped.
|
|
32
|
+
*
|
|
33
|
+
* Scan the enclosing @Component/@Builder struct (or Builder function) body —
|
|
34
|
+
* not only the `build()` method span — because ArkUI trailing lambdas
|
|
35
|
+
* (`Column() { Child() }`) are often attributed with tight method ranges that
|
|
36
|
+
* omit nested call sites.
|
|
37
|
+
*/
|
|
38
|
+
/** @internal exported for PERF kind-scan regression tests (resolveChild name-miss path). */
|
|
39
|
+
export declare function arkuiChildComponentEdges(ctx: ResolutionContext, onYield: MaybeYield): Promise<Edge[]>;
|
|
28
40
|
/** `has(...)` shape passed to pass gates — true when the project contains any of the languages. */
|
|
29
41
|
type HasLang = (...ls: string[]) => boolean;
|
|
30
42
|
/**
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.SYNTH_PROGRESS_STEPS = exports.SYNTH_PASSES = void 0;
|
|
37
|
+
exports.arkuiChildComponentEdges = arkuiChildComponentEdges;
|
|
37
38
|
exports.synthesizeCallbackEdges = synthesizeCallbackEdges;
|
|
38
39
|
const generated_detection_1 = require("../extraction/generated-detection");
|
|
39
40
|
const strip_comments_1 = require("./strip-comments");
|
|
@@ -1018,6 +1019,7 @@ function isArkuiBuildParent(n) {
|
|
|
1018
1019
|
* (`Column() { Child() }`) are often attributed with tight method ranges that
|
|
1019
1020
|
* omit nested call sites.
|
|
1020
1021
|
*/
|
|
1022
|
+
/** @internal exported for PERF kind-scan regression tests (resolveChild name-miss path). */
|
|
1021
1023
|
async function arkuiChildComponentEdges(ctx, onYield) {
|
|
1022
1024
|
const edges = [];
|
|
1023
1025
|
const seen = new Set();
|
|
@@ -1033,15 +1035,10 @@ async function arkuiChildComponentEdges(ctx, onYield) {
|
|
|
1033
1035
|
return '';
|
|
1034
1036
|
};
|
|
1035
1037
|
const resolveChild = (name, fromFile, parentId) => {
|
|
1038
|
+
// Name index only — miss returns null. Framework PascalCase calls
|
|
1039
|
+
// (Column/Button/Text/…) dominate misses and must not full-scan kinds
|
|
1040
|
+
// (Spec 0063). Same drop policy as ambiguous multi-match below.
|
|
1036
1041
|
let candidates = ctx.getNodesByName(name).filter(isArkuiChildTarget);
|
|
1037
|
-
if (candidates.length === 0) {
|
|
1038
|
-
candidates = [
|
|
1039
|
-
...ctx.getNodesByKind('struct'),
|
|
1040
|
-
...ctx.getNodesByKind('component'),
|
|
1041
|
-
...ctx.getNodesByKind('function'),
|
|
1042
|
-
...ctx.getNodesByKind('method'),
|
|
1043
|
-
].filter((n) => n.name === name && isArkuiChildTarget(n));
|
|
1044
|
-
}
|
|
1045
1042
|
candidates = candidates.filter((n) => n.id !== parentId);
|
|
1046
1043
|
// Dedupe by id — name index can surface the same row twice across caches.
|
|
1047
1044
|
candidates = [...new Map(candidates.map((n) => [n.id, n])).values()];
|
|
@@ -30,6 +30,11 @@ export declare function isKnownLanguageFamily(lang: string): boolean;
|
|
|
30
30
|
* returns `false` here and is left alone.
|
|
31
31
|
*/
|
|
32
32
|
export declare function crossesKnownFamily(a: string, b: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Spec 0066: resolve a return/param type name to a unique type node.
|
|
35
|
+
* Ambiguous same-named types → no edge (wrong type hub is worse than none).
|
|
36
|
+
*/
|
|
37
|
+
export declare function matchTypeEdge(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null;
|
|
33
38
|
/**
|
|
34
39
|
* Resolve a function-as-value reference (#756) — a function name used as a
|
|
35
40
|
* callback/function-pointer value (`register(handler)`, `o->cb = handler`,
|
|
@@ -9,6 +9,7 @@ exports.matchByFilePath = matchByFilePath;
|
|
|
9
9
|
exports.sameLanguageFamily = sameLanguageFamily;
|
|
10
10
|
exports.isKnownLanguageFamily = isKnownLanguageFamily;
|
|
11
11
|
exports.crossesKnownFamily = crossesKnownFamily;
|
|
12
|
+
exports.matchTypeEdge = matchTypeEdge;
|
|
12
13
|
exports.matchFunctionRef = matchFunctionRef;
|
|
13
14
|
exports.matchByExactName = matchByExactName;
|
|
14
15
|
exports.matchByQualifiedName = matchByQualifiedName;
|
|
@@ -193,7 +194,10 @@ function crossesKnownFamily(a, b) {
|
|
|
193
194
|
* both-known filter so `.vue`/`.svelte` (own tag) importing `.ts` survives.
|
|
194
195
|
*/
|
|
195
196
|
function applyLanguageGate(candidates, ref) {
|
|
196
|
-
if (ref.referenceKind === 'references' ||
|
|
197
|
+
if (ref.referenceKind === 'references' ||
|
|
198
|
+
ref.referenceKind === 'function_ref' ||
|
|
199
|
+
ref.referenceKind === 'returns' ||
|
|
200
|
+
ref.referenceKind === 'type_of') {
|
|
197
201
|
return candidates.filter((c) => sameLanguageFamily(c.language, ref.language));
|
|
198
202
|
}
|
|
199
203
|
if (ref.referenceKind === 'imports') {
|
|
@@ -201,6 +205,57 @@ function applyLanguageGate(candidates, ref) {
|
|
|
201
205
|
}
|
|
202
206
|
return candidates;
|
|
203
207
|
}
|
|
208
|
+
/** Spec 0066 — targets for `returns` / `type_of` edges (type-as-node). */
|
|
209
|
+
const TYPE_EDGE_KINDS = new Set([
|
|
210
|
+
'class',
|
|
211
|
+
'interface',
|
|
212
|
+
'type_alias',
|
|
213
|
+
'enum',
|
|
214
|
+
'struct',
|
|
215
|
+
'protocol',
|
|
216
|
+
'trait',
|
|
217
|
+
'component',
|
|
218
|
+
]);
|
|
219
|
+
/**
|
|
220
|
+
* Spec 0066: resolve a return/param type name to a unique type node.
|
|
221
|
+
* Ambiguous same-named types → no edge (wrong type hub is worse than none).
|
|
222
|
+
*/
|
|
223
|
+
function matchTypeEdge(ref, context) {
|
|
224
|
+
if (ref.referenceKind !== 'returns' && ref.referenceKind !== 'type_of')
|
|
225
|
+
return null;
|
|
226
|
+
const simple = ref.referenceName.includes('.') || ref.referenceName.includes('::')
|
|
227
|
+
? (ref.referenceName.split(/[.:]+/).filter(Boolean).pop() ?? ref.referenceName)
|
|
228
|
+
: ref.referenceName;
|
|
229
|
+
let candidates = context
|
|
230
|
+
.getNodesByName(simple)
|
|
231
|
+
.filter((n) => TYPE_EDGE_KINDS.has(n.kind) && n.id !== ref.fromNodeId);
|
|
232
|
+
candidates = applyLanguageGate(candidates, ref);
|
|
233
|
+
if (candidates.length === 0)
|
|
234
|
+
return null;
|
|
235
|
+
// Qualified exact: unique_id-style `A.B.Foo` / `A::Foo` against qualifiedName.
|
|
236
|
+
if (ref.referenceName.includes('.') || ref.referenceName.includes('::')) {
|
|
237
|
+
const qnHits = candidates.filter((n) => n.qualifiedName === ref.referenceName ||
|
|
238
|
+
n.qualifiedName.endsWith(`.${simple}`) ||
|
|
239
|
+
n.qualifiedName.endsWith(`::${simple}`));
|
|
240
|
+
if (qnHits.length === 1) {
|
|
241
|
+
return {
|
|
242
|
+
original: ref,
|
|
243
|
+
targetNodeId: qnHits[0].id,
|
|
244
|
+
confidence: 0.95,
|
|
245
|
+
resolvedBy: 'qualified-name',
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const ordered = preferCallSiteFile(candidates, ref.filePath);
|
|
250
|
+
if (ordered.length !== 1)
|
|
251
|
+
return null;
|
|
252
|
+
return {
|
|
253
|
+
original: ref,
|
|
254
|
+
targetNodeId: ordered[0].id,
|
|
255
|
+
confidence: 0.9,
|
|
256
|
+
resolvedBy: 'exact-match',
|
|
257
|
+
};
|
|
258
|
+
}
|
|
204
259
|
/**
|
|
205
260
|
* Resolve a function-as-value reference (#756) — a function name used as a
|
|
206
261
|
* callback/function-pointer value (`register(handler)`, `o->cb = handler`,
|
|
@@ -2078,6 +2133,10 @@ function matchReference(ref, context) {
|
|
|
2078
2133
|
if (ref.referenceKind === 'function_ref') {
|
|
2079
2134
|
return matchFunctionRef(ref, context);
|
|
2080
2135
|
}
|
|
2136
|
+
// Spec 0066: returns / type_of — unique type node only; no fuzzy fallthrough.
|
|
2137
|
+
if (ref.referenceKind === 'returns' || ref.referenceKind === 'type_of') {
|
|
2138
|
+
return matchTypeEdge(ref, context);
|
|
2139
|
+
}
|
|
2081
2140
|
// ArkTS chained UI attributes — emitted with a leading dot (`.titleStyle`,
|
|
2082
2141
|
// `.width`) by the extractor — resolve ONLY to decorator-marked attribute
|
|
2083
2142
|
// helpers: `@Extend`/`@Styles`/`@AnimatableExtend` functions (and global
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homegraph",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "Supercharge AI coding agents with semantic code intelligence — surgical context, fewer tool calls, faster answers. 100% local.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"test:node-matrix": "bash scripts/test-node-matrix.sh",
|
|
26
26
|
"test:explore-routing": "node scripts/run-explore-routing.mjs",
|
|
27
27
|
"eval": "npm run build && npx tsx test/evaluation/runner.ts",
|
|
28
|
+
"eval:peak-mem": "node --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --experimental-strip-types test/evaluation/index-peak-mem.ts",
|
|
29
|
+
"soak:photos": "node test/harmony-callgraph-soak/run.mjs",
|
|
28
30
|
"clean": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true})\""
|
|
29
31
|
},
|
|
30
32
|
"keywords": [
|