dsh-plugin-codegraph-tree-sitter 0.1.1 → 0.1.5

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/lib/resolve.d.ts CHANGED
@@ -45,6 +45,9 @@ export interface GraphNode {
45
45
  readonly isExported: boolean;
46
46
  readonly isAsync: boolean;
47
47
  readonly isStatic: boolean;
48
+ /** Decorator names applied to this declaration — see `RawDefinition.decorators`. Empty for a file
49
+ * node and for every declaration this package does not currently extract decorators from. */
50
+ readonly decorators: readonly string[];
48
51
  readonly updatedAt: number;
49
52
  }
50
53
  /** One resolved graph edge. */
package/lib/resolve.js CHANGED
@@ -99,6 +99,28 @@ function buildNameIndex(nodesByFile) {
99
99
  }
100
100
  return index;
101
101
  }
102
+ /**
103
+ * A name index restricted to `class`/`interface` nodes, for `extends`/`implements` resolution.
104
+ * `extractHeritage` only ever names a base class or interface, never a function or variable — indexing
105
+ * only those kinds keeps a same-named function or module-level `const` (`packages/tree-sitter/src/
106
+ * languages.ts` extracts those now too) from ever winning a heritage reference by coincidence, tighter
107
+ * than `buildNameIndex`'s workspace-wide, any-kind index that call resolution already accepts.
108
+ */
109
+ function buildTypeNameIndex(nodesByFile) {
110
+ const index = new Map();
111
+ for (const nodes of nodesByFile.values()) {
112
+ for (const node of nodes) {
113
+ if (node.kind !== 'class' && node.kind !== 'interface')
114
+ continue;
115
+ const existing = index.get(node.name);
116
+ if (existing === undefined)
117
+ index.set(node.name, [node]);
118
+ else
119
+ existing.push(node);
120
+ }
121
+ }
122
+ return index;
123
+ }
102
124
  /** Resolve one file's raw imports against the indexed workspace. */
103
125
  function resolveImports(path, language, imports, indexed) {
104
126
  const byLocalName = new Map();
@@ -143,6 +165,7 @@ export function resolveWorkspace(files, now) {
143
165
  isExported: false,
144
166
  isAsync: false,
145
167
  isStatic: false,
168
+ decorators: [],
146
169
  updatedAt: now,
147
170
  };
148
171
  nodes.push(fileNode);
@@ -168,6 +191,7 @@ export function resolveWorkspace(files, now) {
168
191
  isExported: def.isExported,
169
192
  isAsync: def.isAsync,
170
193
  isStatic: def.isStatic,
194
+ decorators: def.decorators,
171
195
  updatedAt: now,
172
196
  });
173
197
  }
@@ -180,6 +204,7 @@ export function resolveWorkspace(files, now) {
180
204
  }
181
205
  }
182
206
  const nameIndex = buildNameIndex(nodesByFile);
207
+ const typeNameIndex = buildTypeNameIndex(nodesByFile);
183
208
  const unresolved = [];
184
209
  for (const file of files) {
185
210
  const bindings = resolveImports(file.path, file.language, file.extraction.imports, indexed);
@@ -190,7 +215,7 @@ export function resolveWorkspace(files, now) {
190
215
  const importedLocalNames = new Set(file.extraction.imports.map(binding => binding.localName));
191
216
  for (const call of file.extraction.calls) {
192
217
  const callerId = call.callerKey === null ? mustGet(fileNodeId, file.path) : mustGet(keyToId, call.callerKey);
193
- const resolved = resolveCall(call.calleeName, bindings, nodesByFile, nameIndex);
218
+ const resolved = resolveName(call.calleeName, bindings, nodesByFile, nameIndex);
194
219
  if (resolved === undefined) {
195
220
  const likelyExternal = call.isMemberCall || importedLocalNames.has(call.calleeName);
196
221
  unresolved.push({ source: callerId, filePath: file.path, calleeName: call.calleeName, line: call.line, col: call.column, likelyExternal });
@@ -198,11 +223,27 @@ export function resolveWorkspace(files, now) {
198
223
  }
199
224
  edges.push({ source: callerId, target: resolved, kind: 'calls', line: call.line, col: call.column, provenance: 'tree-sitter' });
200
225
  }
226
+ // An unresolved `extends`/`implements` reference is dropped silently, not routed through
227
+ // `unresolved` — that array (and the `unresolvedCount`/`unresolvedLikelyInternalCount` split built
228
+ // on it) is a calibrated signal specifically about call-resolution gaps; folding in a different edge
229
+ // kind would change what that count measures.
230
+ for (const ref of file.extraction.heritage) {
231
+ const resolved = resolveName(ref.targetName, bindings, nodesByFile, typeNameIndex);
232
+ if (resolved === undefined)
233
+ continue;
234
+ edges.push({ source: mustGet(keyToId, ref.sourceKey), target: resolved, kind: ref.relation, provenance: 'tree-sitter' });
235
+ }
201
236
  }
202
237
  return { nodes, edges, unresolved };
203
238
  }
204
- /** Resolve one call's callee name to exactly one declaration, or `undefined` per rule 3. */
205
- function resolveCall(calleeName, bindings, nodesByFile, nameIndex) {
239
+ /**
240
+ * Resolve a bare name to exactly one declaration, or `undefined` per rule 3 — shared by call
241
+ * resolution (against the workspace-wide, any-kind `nameIndex`) and `extends`/`implements` resolution
242
+ * (against the `class`/`interface`-only {@link buildTypeNameIndex}); the two-tier rule itself (an
243
+ * imported binding wins if unambiguous in its target file, else a workspace-wide-unique name wins) does
244
+ * not depend on which candidate pool the caller passes in.
245
+ */
246
+ function resolveName(calleeName, bindings, nodesByFile, nameIndex) {
206
247
  const bound = bindings.byLocalName.get(calleeName);
207
248
  if (bound !== undefined) {
208
249
  const targetNodes = mustGet(nodesByFile, bound.targetFile);
package/lib/schema.js CHANGED
@@ -75,10 +75,10 @@ export async function writeGraph(databasePath, input) {
75
75
  .run(SCHEMA_VERSION, input.indexedAt, 'dsh-codegraph-tree-sitter');
76
76
  const insertNode = db.prepare(`INSERT INTO nodes
77
77
  (id, kind, name, qualified_name, file_path, language, start_line, end_line, start_column,
78
- end_column, is_exported, is_async, is_static, updated_at)
79
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
78
+ end_column, is_exported, is_async, is_static, decorators, updated_at)
79
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
80
80
  for (const node of input.nodes) {
81
- insertNode.run(node.id, node.kind, node.name, node.qualifiedName, node.filePath, node.language, node.startLine, node.endLine, node.startColumn, node.endColumn, node.isExported ? 1 : 0, node.isAsync ? 1 : 0, node.isStatic ? 1 : 0, node.updatedAt);
81
+ insertNode.run(node.id, node.kind, node.name, node.qualifiedName, node.filePath, node.language, node.startLine, node.endLine, node.startColumn, node.endColumn, node.isExported ? 1 : 0, node.isAsync ? 1 : 0, node.isStatic ? 1 : 0, JSON.stringify(node.decorators), node.updatedAt);
82
82
  }
83
83
  const insertEdge = db.prepare('INSERT INTO edges (source, target, kind, line, col, provenance) VALUES (?, ?, ?, ?, ?, ?)');
84
84
  for (const edge of input.edges) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-codegraph-tree-sitter",
3
- "version": "0.1.1",
3
+ "version": "0.1.5",
4
4
  "description": "Self-built code-graph indexer for DeepSeek Harness — parses a workspace with web-tree-sitter and writes schema version 4 to .codegraph/codegraph.db, the same on-disk format the codegraph CLI writes, so no external indexer is required",
5
5
  "keywords": [
6
6
  "dsh",
@@ -51,7 +51,7 @@
51
51
  "@deepseek-ai/schemastery": "^3.18.1",
52
52
  "tree-sitter-wasms": "^0.1.13",
53
53
  "web-tree-sitter": "^0.25.10",
54
- "dsh-plugin-codegraph-service": "^0.1.1"
54
+ "dsh-plugin-codegraph-service": "^0.1.5"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@deepseek-ai/cordis": ">=4.0.1",