@remnic/coding-graph 9.6.37 → 9.6.38
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/dist/{chunk-ABDBWCXU.js → chunk-I56SG643.js} +92 -1
- package/dist/{chunk-ABDBWCXU.js.map → chunk-I56SG643.js.map} +1 -1
- package/dist/{chunk-I4R6GAAA.js → chunk-WOPWVODJ.js} +2 -2
- package/dist/cypher/query-parser.js +2 -2
- package/dist/graph-store.d.ts +30 -0
- package/dist/graph-store.js +1 -1
- package/dist/index.js +2 -2
- package/package.json +3 -3
- package/src/graph-store.ts +122 -0
- /package/dist/{chunk-I4R6GAAA.js.map → chunk-WOPWVODJ.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MAX_TRAVERSE_PATHS_HOPS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-I56SG643.js";
|
|
4
4
|
|
|
5
5
|
// src/cypher/query-parser.ts
|
|
6
6
|
var CYPHER_LABEL_TO_DB_LABEL = {
|
|
@@ -1039,4 +1039,4 @@ export {
|
|
|
1039
1039
|
executeAst,
|
|
1040
1040
|
executeCypher
|
|
1041
1041
|
};
|
|
1042
|
-
//# sourceMappingURL=chunk-
|
|
1042
|
+
//# sourceMappingURL=chunk-WOPWVODJ.js.map
|
package/dist/graph-store.d.ts
CHANGED
|
@@ -866,6 +866,36 @@ declare class GraphStore {
|
|
|
866
866
|
* `exports` and `routes` arrays feed.
|
|
867
867
|
*/
|
|
868
868
|
deadCode(): DeadCodeResult;
|
|
869
|
+
/**
|
|
870
|
+
* Find the innermost node whose span contains a byte offset in a file
|
|
871
|
+
* (issue #1917). Used by the LSP resolution pass's NodeLocator to map
|
|
872
|
+
* definition locations back to indexed nodes. Returns the node's
|
|
873
|
+
* qualified name, or null when no node contains the offset.
|
|
874
|
+
*/
|
|
875
|
+
findNodeBySpan(filePath: string, byteOffset: number): string | null;
|
|
876
|
+
/**
|
|
877
|
+
* Callee NAMES already linked from a caller symbol via CALLS edges of a
|
|
878
|
+
* given provenance (issue #1917 wiring). The LSP pass uses this to skip
|
|
879
|
+
* call sites Phase A (provenance "heuristic") already resolved WITHOUT
|
|
880
|
+
* also skipping sites whose only edge is a prior "lsp" edge — those must
|
|
881
|
+
* be re-asserted each run or reconciliation would retire them.
|
|
882
|
+
*/
|
|
883
|
+
resolvedCalleeNames(srcQualifiedName: string, provenance: string, filePath?: string): string[];
|
|
884
|
+
/**
|
|
885
|
+
* Current CALLS edges of a given provenance owned by a caller symbol in
|
|
886
|
+
* a file (#1923 review threads). The LSP pass uses this two ways:
|
|
887
|
+
* provenance "lsp" lists a filtered caller's existing lsp edges, and
|
|
888
|
+
* provenance "heuristic" lists its current Phase-A resolutions — an lsp
|
|
889
|
+
* edge is preserved at reconcile time only when it duplicates a current
|
|
890
|
+
* heuristic resolution (same dst), so removed member calls' edges retire
|
|
891
|
+
* while a filtered bare call's covering edge survives.
|
|
892
|
+
*/
|
|
893
|
+
callEdgesForCaller(srcQualifiedName: string, filePath: string, provenance: string): Array<{
|
|
894
|
+
srcQualifiedName: string;
|
|
895
|
+
dstQualifiedName: string;
|
|
896
|
+
dstName: string;
|
|
897
|
+
type: string;
|
|
898
|
+
}>;
|
|
869
899
|
/**
|
|
870
900
|
* Read a symbol's source span from disk. The store NEVER persists
|
|
871
901
|
* file contents (privacy + DB size — issue #1552 design); this
|
package/dist/graph-store.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
executeAst,
|
|
4
4
|
executeCypher,
|
|
5
5
|
parseCypher
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WOPWVODJ.js";
|
|
7
7
|
import {
|
|
8
8
|
DEAD_CODE_EXCLUSION,
|
|
9
9
|
DEFAULT_TRAVERSE_PATHS_MAX,
|
|
10
10
|
GraphStore,
|
|
11
11
|
MAX_TRAVERSE_PATHS_HOPS,
|
|
12
12
|
nodeIdFor
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-I56SG643.js";
|
|
14
14
|
import {
|
|
15
15
|
CODING_GRAPH_SCHEMA_VERSION,
|
|
16
16
|
EDGE_PROVENANCE_VALUES,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/coding-graph",
|
|
3
|
-
"version": "9.6.
|
|
3
|
+
"version": "9.6.38",
|
|
4
4
|
"description": "Web-tree-sitter powered symbol-extraction engine + SQLite knowledge-graph store for codebase memory (Tier 1: TypeScript, TSX, JavaScript, Python, Go, Rust, Java, C, C++, C#, Ruby, PHP, Kotlin, Swift, Bash). Optional companion of @remnic/core — install only when coding-graph features are needed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"web-tree-sitter": "^0.25.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"@remnic/core": "^9.6.
|
|
44
|
+
"@remnic/core": "^9.6.38"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/node": "^22.10.0",
|
|
48
48
|
"tsup": "^8.5.1",
|
|
49
49
|
"tsx": "^4.19.0",
|
|
50
50
|
"typescript": "^5.7.0",
|
|
51
|
-
"@remnic/core": "9.6.
|
|
51
|
+
"@remnic/core": "9.6.38"
|
|
52
52
|
},
|
|
53
53
|
"license": "MIT",
|
|
54
54
|
"repository": {
|
package/src/graph-store.ts
CHANGED
|
@@ -2909,6 +2909,128 @@ export class GraphStore {
|
|
|
2909
2909
|
}
|
|
2910
2910
|
}
|
|
2911
2911
|
|
|
2912
|
+
/**
|
|
2913
|
+
* Find the innermost node whose span contains a byte offset in a file
|
|
2914
|
+
* (issue #1917). Used by the LSP resolution pass's NodeLocator to map
|
|
2915
|
+
* definition locations back to indexed nodes. Returns the node's
|
|
2916
|
+
* qualified name, or null when no node contains the offset.
|
|
2917
|
+
*/
|
|
2918
|
+
findNodeBySpan(filePath: string, byteOffset: number): string | null {
|
|
2919
|
+
if (this.closed) return null;
|
|
2920
|
+
try {
|
|
2921
|
+
// Fetch the two smallest containing spans: nested containment is
|
|
2922
|
+
// normal (a method inside a class both contain the offset) and the
|
|
2923
|
+
// INNERMOST (smallest) wins — but a TIE at the smallest size means
|
|
2924
|
+
// the offset cannot be attributed to exactly one node, and the
|
|
2925
|
+
// NodeLocator contract requires null over an arbitrary pick
|
|
2926
|
+
// (review thread: a wrong winner persists incorrect CALLS edges).
|
|
2927
|
+
const rows = expectRows<{ qualified_name: string; size: number }>(
|
|
2928
|
+
this.db
|
|
2929
|
+
.prepare(
|
|
2930
|
+
`SELECT n.qualified_name, (n.span_end - n.span_start) AS size FROM nodes n
|
|
2931
|
+
JOIN files f ON n.file_id = f.id
|
|
2932
|
+
WHERE f.path = ? AND n.span_start <= ? AND n.span_end > ?
|
|
2933
|
+
ORDER BY size ASC
|
|
2934
|
+
LIMIT 2`,
|
|
2935
|
+
)
|
|
2936
|
+
.all(filePath, byteOffset, byteOffset),
|
|
2937
|
+
["qualified_name", "size"],
|
|
2938
|
+
);
|
|
2939
|
+
if (rows.length === 0) return null;
|
|
2940
|
+
if (rows.length > 1 && rows[1] !== undefined && rows[0]!.size === rows[1].size) return null;
|
|
2941
|
+
const qualifiedName = rows[0]!.qualified_name;
|
|
2942
|
+
// The span lookup disambiguated by file, but the returned QUALIFIED
|
|
2943
|
+
// NAME is the edge key downstream (upsertEdges resolves names, not
|
|
2944
|
+
// ids). If another file defines the same qualified name (common for
|
|
2945
|
+
// top-level `main`/`handler`/`init`), an edge written against the
|
|
2946
|
+
// name could bind to the wrong node — return null and skip the
|
|
2947
|
+
// upgrade instead (conservative; id-carrying upgrades are the
|
|
2948
|
+
// follow-up, review thread on #1923).
|
|
2949
|
+
const dupRow = expectRow<{ n: number }>(
|
|
2950
|
+
this.db
|
|
2951
|
+
.prepare(`SELECT COUNT(*) AS n FROM nodes WHERE qualified_name = ?`)
|
|
2952
|
+
.get(qualifiedName),
|
|
2953
|
+
["n"],
|
|
2954
|
+
);
|
|
2955
|
+
if (dupRow && dupRow.n > 1) return null;
|
|
2956
|
+
return qualifiedName;
|
|
2957
|
+
} catch {
|
|
2958
|
+
return null;
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
/**
|
|
2963
|
+
* Callee NAMES already linked from a caller symbol via CALLS edges of a
|
|
2964
|
+
* given provenance (issue #1917 wiring). The LSP pass uses this to skip
|
|
2965
|
+
* call sites Phase A (provenance "heuristic") already resolved WITHOUT
|
|
2966
|
+
* also skipping sites whose only edge is a prior "lsp" edge — those must
|
|
2967
|
+
* be re-asserted each run or reconciliation would retire them.
|
|
2968
|
+
*/
|
|
2969
|
+
resolvedCalleeNames(srcQualifiedName: string, provenance: string, filePath?: string): string[] {
|
|
2970
|
+
if (this.closed) return [];
|
|
2971
|
+
try {
|
|
2972
|
+
// Scoped to the caller FILE when provided: two files defining the
|
|
2973
|
+
// same top-level qualified name (main/handler/init) must not leak
|
|
2974
|
+
// each other's resolutions (#1923 review thread).
|
|
2975
|
+
const fileClause = filePath !== undefined ? " AND f.path = ?" : "";
|
|
2976
|
+
const bind = filePath !== undefined ? [srcQualifiedName, provenance, filePath] : [srcQualifiedName, provenance];
|
|
2977
|
+
const rows = expectRows<{ name: string }>(
|
|
2978
|
+
this.db
|
|
2979
|
+
.prepare(
|
|
2980
|
+
`SELECT DISTINCT dn.name AS name FROM edges e
|
|
2981
|
+
JOIN nodes sn ON e.src = sn.id
|
|
2982
|
+
JOIN files f ON sn.file_id = f.id
|
|
2983
|
+
JOIN nodes dn ON e.dst = dn.id
|
|
2984
|
+
WHERE sn.qualified_name = ? AND e.type = 'CALLS' AND e.provenance = ?${fileClause}`,
|
|
2985
|
+
)
|
|
2986
|
+
.all(...bind),
|
|
2987
|
+
["name"],
|
|
2988
|
+
);
|
|
2989
|
+
return rows.map((r) => r.name);
|
|
2990
|
+
} catch {
|
|
2991
|
+
return [];
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
/**
|
|
2996
|
+
* Current CALLS edges of a given provenance owned by a caller symbol in
|
|
2997
|
+
* a file (#1923 review threads). The LSP pass uses this two ways:
|
|
2998
|
+
* provenance "lsp" lists a filtered caller's existing lsp edges, and
|
|
2999
|
+
* provenance "heuristic" lists its current Phase-A resolutions — an lsp
|
|
3000
|
+
* edge is preserved at reconcile time only when it duplicates a current
|
|
3001
|
+
* heuristic resolution (same dst), so removed member calls' edges retire
|
|
3002
|
+
* while a filtered bare call's covering edge survives.
|
|
3003
|
+
*/
|
|
3004
|
+
callEdgesForCaller(
|
|
3005
|
+
srcQualifiedName: string,
|
|
3006
|
+
filePath: string,
|
|
3007
|
+
provenance: string,
|
|
3008
|
+
): Array<{ srcQualifiedName: string; dstQualifiedName: string; dstName: string; type: string }> {
|
|
3009
|
+
if (this.closed) return [];
|
|
3010
|
+
try {
|
|
3011
|
+
const rows = expectRows<{ src_q: string; dst_q: string; dst_n: string; type: string }>(
|
|
3012
|
+
this.db
|
|
3013
|
+
.prepare(
|
|
3014
|
+
`SELECT sn.qualified_name AS src_q, dn.qualified_name AS dst_q, dn.name AS dst_n, e.type AS type FROM edges e
|
|
3015
|
+
JOIN nodes sn ON e.src = sn.id
|
|
3016
|
+
JOIN files f ON sn.file_id = f.id
|
|
3017
|
+
JOIN nodes dn ON e.dst = dn.id
|
|
3018
|
+
WHERE sn.qualified_name = ? AND f.path = ? AND e.provenance = ? AND e.type = 'CALLS'`,
|
|
3019
|
+
)
|
|
3020
|
+
.all(srcQualifiedName, filePath, provenance),
|
|
3021
|
+
["src_q", "dst_q", "dst_n", "type"],
|
|
3022
|
+
);
|
|
3023
|
+
return rows.map((r) => ({
|
|
3024
|
+
srcQualifiedName: r.src_q,
|
|
3025
|
+
dstQualifiedName: r.dst_q,
|
|
3026
|
+
dstName: r.dst_n,
|
|
3027
|
+
type: r.type,
|
|
3028
|
+
}));
|
|
3029
|
+
} catch {
|
|
3030
|
+
return [];
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
|
|
2912
3034
|
/**
|
|
2913
3035
|
* Read a symbol's source span from disk. The store NEVER persists
|
|
2914
3036
|
* file contents (privacy + DB size — issue #1552 design); this
|
|
File without changes
|