dsh-plugin-codegraph-tree-sitter 0.1.0 → 0.1.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/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/lib/watcher.js CHANGED
@@ -275,7 +275,19 @@ export function createWatcher(config, primitive = nodeWatch) {
275
275
  syncFailureCount = 0;
276
276
  pendingPaths.clear();
277
277
  if (process.platform === 'darwin' || process.platform === 'win32') {
278
+ // Started immediately, unlike the per-directory branch below, because the recursive `fs.watch`
279
+ // call itself must stay synchronous within start() — nothing here should make callers await a
280
+ // gitignore read just to get a watch installed. `gitignoreRules` starts empty and is filled in
281
+ // once the read resolves; every event that arrives before then is a startup-window race no
282
+ // different in kind from the FSEvents kernel-side warm-up delay already documented above, and
283
+ // resolves in the time to read one small file, not the time a human takes to edit one.
278
284
  startRecursive();
285
+ if (config.respectGitignore) {
286
+ void loadGitignore(config.root).then(rules => {
287
+ if (running)
288
+ gitignoreRules = rules;
289
+ });
290
+ }
279
291
  return;
280
292
  }
281
293
  void (async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-codegraph-tree-sitter",
3
- "version": "0.1.0",
3
+ "version": "0.1.4",
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.0"
54
+ "dsh-plugin-codegraph-service": "^0.1.4"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@deepseek-ai/cordis": ">=4.0.1",