@zuvia-software-solutions/code-mapper 2.6.5 → 2.7.0
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.
|
@@ -147,6 +147,113 @@ function extractParamNames(content) {
|
|
|
147
147
|
.map(p => expandIdentifier(p))
|
|
148
148
|
.join(', ');
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Extract domain-relevant content from node source code.
|
|
152
|
+
* Pulls string literals, object keys, numbers, and identifiers that carry
|
|
153
|
+
* semantic meaning — DI tokens, event names, FSM states, permissions,
|
|
154
|
+
* error codes, route paths, feature flags, etc.
|
|
155
|
+
*/
|
|
156
|
+
function extractContentKeywords(content) {
|
|
157
|
+
if (!content)
|
|
158
|
+
return '';
|
|
159
|
+
const keywords = new Set();
|
|
160
|
+
// 1. String literals: 'booking.created', 'leads.create', '/api/bookings', 'INVOICE_NOT_FOUND'
|
|
161
|
+
// Also match template literal parts before ${}: `Invoice ${id} not found`
|
|
162
|
+
const stringLiterals = content.match(/['"`]([^'"`\n]{2,120}?)['"`$]/g);
|
|
163
|
+
if (stringLiterals) {
|
|
164
|
+
for (const lit of stringLiterals) {
|
|
165
|
+
const val = lit.slice(1, -1);
|
|
166
|
+
// Skip imports and actual file paths (must have / or start with ./)
|
|
167
|
+
if (val.includes('from ') || (/\.\w{1,4}$/.test(val) && val.includes('/')))
|
|
168
|
+
continue;
|
|
169
|
+
// Split on dots, underscores, hyphens, slashes, spaces → individual words
|
|
170
|
+
const words = val.split(/[._\-/\s]/).map(w => w.trim().toLowerCase()).filter(w => w.length >= 2 && !/^\d+$/.test(w));
|
|
171
|
+
for (const w of words)
|
|
172
|
+
keywords.add(w);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// 2. Object keys (identifier: value patterns) — expand camelCase/PascalCase
|
|
176
|
+
const objKeys = content.match(/(?:^|[{,\n])\s*(\w{2,})\s*[=:]/gm);
|
|
177
|
+
if (objKeys) {
|
|
178
|
+
for (const k of objKeys) {
|
|
179
|
+
const name = k.replace(/^[{,\n\s]+/, '').replace(/\s*[=:]$/, '').trim();
|
|
180
|
+
if (name.length >= 2 && !/^(const|export|return|type|let|var|if|else|new|async|await|function|class|interface)$/.test(name)) {
|
|
181
|
+
const expanded = expandIdentifier(name);
|
|
182
|
+
for (const w of expanded.split(' '))
|
|
183
|
+
if (w.length >= 2)
|
|
184
|
+
keywords.add(w);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// 3. Member access targets: TOKENS.BookingsRepository, S.PENDING → extract after dot
|
|
189
|
+
const memberAccess = content.match(/\w+\.([A-Z]\w{2,})/g);
|
|
190
|
+
if (memberAccess) {
|
|
191
|
+
for (const m of memberAccess) {
|
|
192
|
+
const target = m.split('.').pop();
|
|
193
|
+
const expanded = expandIdentifier(target);
|
|
194
|
+
for (const w of expanded.split(' '))
|
|
195
|
+
if (w.length >= 2)
|
|
196
|
+
keywords.add(w);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// 4. Numeric literals that look like HTTP codes or business constants
|
|
200
|
+
const numbers = content.match(/\b([2-5]\d{2})\b/g);
|
|
201
|
+
if (numbers) {
|
|
202
|
+
for (const n of numbers)
|
|
203
|
+
keywords.add(n);
|
|
204
|
+
}
|
|
205
|
+
// 5. UPPER_CASE constants (error codes, permission names, status names)
|
|
206
|
+
// Keep both the full constant (e.g. "invoice_not_found") and individual words
|
|
207
|
+
const upperConsts = content.match(/\b[A-Z][A-Z0-9_]{2,}\b/g);
|
|
208
|
+
if (upperConsts) {
|
|
209
|
+
for (const c of upperConsts) {
|
|
210
|
+
if (/^(GET|POST|PUT|DELETE|NULL|TRUE|FALSE|AND|NOT|SQL)$/.test(c))
|
|
211
|
+
continue;
|
|
212
|
+
// Full constant name as one token (for exact matching)
|
|
213
|
+
keywords.add(c.toLowerCase().replace(/_/g, '_'));
|
|
214
|
+
// Also expanded (for word matching)
|
|
215
|
+
const expanded = c.toLowerCase().replace(/_/g, ' ');
|
|
216
|
+
for (const w of expanded.split(' '))
|
|
217
|
+
if (w.length >= 2)
|
|
218
|
+
keywords.add(w);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Common English stop words that appear in code as string literals (e.g. stop word lists)
|
|
222
|
+
const EMBED_STOP = new Set([
|
|
223
|
+
'the', 'and', 'for', 'from', 'with', 'this', 'that', 'have', 'has', 'not', 'are', 'was',
|
|
224
|
+
'were', 'been', 'being', 'will', 'would', 'could', 'should', 'may', 'might', 'can',
|
|
225
|
+
'does', 'did', 'let', 'var', 'new', 'return', 'else', 'case', 'break', 'while',
|
|
226
|
+
'throw', 'catch', 'try', 'finally', 'typeof', 'instanceof', 'void', 'null',
|
|
227
|
+
'undefined', 'true', 'false', 'require', 'string', 'number', 'boolean', 'object',
|
|
228
|
+
'any', 'never', 'unknown', 'symbol', 'import', 'export', 'default', 'const',
|
|
229
|
+
'function', 'class', 'interface', 'type', 'enum', 'extends', 'implements',
|
|
230
|
+
'static', 'private', 'public', 'protected', 'abstract', 'readonly', 'async',
|
|
231
|
+
'await', 'yield', 'delete', 'switch', 'continue', 'declare', 'module',
|
|
232
|
+
'namespace', 'override',
|
|
233
|
+
]);
|
|
234
|
+
// Clean: remove noise + stop words, dedupe, cap at 30
|
|
235
|
+
const cleaned = [];
|
|
236
|
+
const seen = new Set();
|
|
237
|
+
for (const kw of keywords) {
|
|
238
|
+
if (kw.length < 2 || kw.length > 40)
|
|
239
|
+
continue;
|
|
240
|
+
if (seen.has(kw))
|
|
241
|
+
continue;
|
|
242
|
+
if (EMBED_STOP.has(kw))
|
|
243
|
+
continue;
|
|
244
|
+
if (/[\x00-\x1f\\{}$`\u2588\u2591]/.test(kw))
|
|
245
|
+
continue;
|
|
246
|
+
if (/^[^a-z0-9]+$/.test(kw))
|
|
247
|
+
continue;
|
|
248
|
+
if (/[(\[<>)\]]/.test(kw))
|
|
249
|
+
continue;
|
|
250
|
+
if (/^\d+$/.test(kw) && !/^[2-5]\d{2}$/.test(kw))
|
|
251
|
+
continue;
|
|
252
|
+
seen.add(kw);
|
|
253
|
+
cleaned.push(kw);
|
|
254
|
+
}
|
|
255
|
+
return cleaned.slice(0, 30).join(' ');
|
|
256
|
+
}
|
|
150
257
|
/** Strip noise tokens that waste tokenizer budget without adding semantic value */
|
|
151
258
|
function condense(text) {
|
|
152
259
|
return text
|
|
@@ -154,28 +261,47 @@ function condense(text) {
|
|
|
154
261
|
.replace(/[{}[\]()'",;:]/g, '') // punctuation
|
|
155
262
|
.replace(/\. /g, ' ') // sentence separators
|
|
156
263
|
.replace(/\s{2,}/g, ' ') // collapse whitespace
|
|
264
|
+
.split(' ')
|
|
265
|
+
.filter(w => !CONDENSE_STOP.has(w.toLowerCase()))
|
|
266
|
+
.join(' ')
|
|
157
267
|
.trim();
|
|
158
268
|
}
|
|
269
|
+
/** Words to strip from condensed embedding text — TS/JS keywords and common English stop words */
|
|
270
|
+
const CONDENSE_STOP = new Set([
|
|
271
|
+
'the', 'and', 'for', 'from', 'with', 'this', 'that', 'have', 'has', 'not', 'are', 'was',
|
|
272
|
+
'were', 'been', 'being', 'will', 'would', 'could', 'should', 'may', 'might', 'can',
|
|
273
|
+
'does', 'did', 'let', 'var', 'new', 'return', 'else', 'case', 'break', 'while',
|
|
274
|
+
'throw', 'catch', 'try', 'finally', 'typeof', 'instanceof', 'void', 'null',
|
|
275
|
+
'undefined', 'true', 'false', 'require', 'string', 'number', 'boolean', 'object',
|
|
276
|
+
'any', 'never', 'unknown', 'symbol', 'import', 'export', 'default', 'const',
|
|
277
|
+
'function', 'class', 'interface', 'type', 'enum', 'extends', 'implements',
|
|
278
|
+
'static', 'private', 'public', 'protected', 'abstract', 'readonly', 'async',
|
|
279
|
+
'await', 'yield', 'delete', 'switch', 'continue', 'declare', 'module',
|
|
280
|
+
'namespace', 'override',
|
|
281
|
+
]);
|
|
159
282
|
/** Build NL documents from a node — keyword-dense, minimal tokens */
|
|
160
283
|
export function extractNlTexts(node) {
|
|
161
284
|
const docs = [];
|
|
162
285
|
const expandedName = expandIdentifier(node.name);
|
|
163
286
|
const dir = node.filePath.split('/').slice(-3, -1).join('/');
|
|
287
|
+
const contentKw = extractContentKeywords(node.content);
|
|
164
288
|
// 1. Comment-based NL text (primary)
|
|
165
289
|
const comment = extractFullComment(node.content);
|
|
166
290
|
if (comment) {
|
|
167
291
|
docs.push({
|
|
168
292
|
nodeId: node.id,
|
|
169
293
|
source: 'comment',
|
|
170
|
-
text: condense(`${expandedName} ${comment} ${dir}`),
|
|
294
|
+
text: condense(`${expandedName} ${comment} ${contentKw} ${dir}`),
|
|
171
295
|
});
|
|
172
296
|
}
|
|
173
|
-
// 2. Name + params (always available)
|
|
297
|
+
// 2. Name + params + content keywords (always available)
|
|
174
298
|
const params = extractParamNames(node.content);
|
|
175
299
|
if (!comment) {
|
|
176
300
|
const parts = [expandedName];
|
|
177
301
|
if (params)
|
|
178
302
|
parts.push(params);
|
|
303
|
+
if (contentKw)
|
|
304
|
+
parts.push(contentKw);
|
|
179
305
|
if (dir)
|
|
180
306
|
parts.push(dir);
|
|
181
307
|
docs.push({
|
|
@@ -216,10 +342,10 @@ export async function buildNlEmbeddings(db, onProgress) {
|
|
|
216
342
|
const labels = ['Function', 'Class', 'Method', 'Interface', 'Const', 'Enum', 'TypeAlias', 'Namespace', 'Module', 'Struct'];
|
|
217
343
|
const placeholders = labels.map(() => '?').join(',');
|
|
218
344
|
const rows = db.prepare(`SELECT id, name, label, filePath, content, startLine, description FROM nodes WHERE label IN (${placeholders})`).all(...labels);
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
const filteredRows = rows;
|
|
345
|
+
// Skip test/fixture files — BM25 keyword search already covers them well.
|
|
346
|
+
// Saves ~40% embedding time on test-heavy codebases.
|
|
347
|
+
const { isTestFile } = await import('./types.js');
|
|
348
|
+
const filteredRows = rows.filter(r => !isTestFile(r.filePath));
|
|
223
349
|
// Extract NL documents
|
|
224
350
|
const allDocs = [];
|
|
225
351
|
for (const row of filteredRows) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* some grammars (typescript vs tsx vs javascript) have slightly different node types
|
|
5
5
|
*/
|
|
6
6
|
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
7
|
-
export declare const TYPESCRIPT_QUERIES = "\n(class_declaration\n name: (type_identifier) @name) @definition.class\n\n(abstract_class_declaration\n name: (type_identifier) @name) @definition.class\n\n(interface_declaration\n name: (type_identifier) @name) @definition.interface\n\n(type_alias_declaration\n name: (type_identifier) @name) @definition.type\n\n(enum_declaration\n name: (identifier) @name) @definition.enum\n\n(function_declaration\n name: (identifier) @name) @definition.function\n\n(method_definition\n name: (property_identifier) @name) @definition.method\n\n; Interface method signatures: interface Foo { method(): void }\n(method_signature\n name: (property_identifier) @name) @definition.method\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function))) @definition.function\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function)))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression)))) @definition.function\n\n; Namespace / internal module\n(internal_module\n name: (identifier) @name) @definition.namespace\n\n; Ambient declarations: declare function foo(): void\n(ambient_declaration\n (function_signature\n name: (identifier) @name)) @definition.function\n\n(import_statement\n source: (string) @import.source) @import\n\n; Re-export statements: export { X } from './y'\n(export_statement\n source: (string) @import.source) @import\n\n(call_expression\n function: (identifier) @call.name) @call\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @call.name)) @call\n\n; Await calls: await foo() \u2014 tree-sitter wraps await inside the function position\n(call_expression\n function: (await_expression\n (identifier) @call.name)) @call\n\n; Await member calls: await obj.method()\n(call_expression\n function: (await_expression\n (member_expression\n property: (property_identifier) @call.name))) @call\n\n; B3: Dynamic import calls: const { foo } = await import('./module.js')\n(call_expression\n function: (import) @call.name) @call\n\n; Constructor calls: new Foo()\n(new_expression\n constructor: (identifier) @call.name) @call\n\n; Exported const from call: export const Schema = z.object({...})\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression)))) @definition.const\n\n; Exported const from new: export const client = new PrismaClient()\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (new_expression)))) @definition.const\n\n; Module-level const from new: const prisma = new PrismaClient()\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (new_expression))) @definition.const\n\n; Exported const from
|
|
7
|
+
export declare const TYPESCRIPT_QUERIES = "\n(class_declaration\n name: (type_identifier) @name) @definition.class\n\n(abstract_class_declaration\n name: (type_identifier) @name) @definition.class\n\n(interface_declaration\n name: (type_identifier) @name) @definition.interface\n\n(type_alias_declaration\n name: (type_identifier) @name) @definition.type\n\n(enum_declaration\n name: (identifier) @name) @definition.enum\n\n(function_declaration\n name: (identifier) @name) @definition.function\n\n(method_definition\n name: (property_identifier) @name) @definition.method\n\n; Interface method signatures: interface Foo { method(): void }\n(method_signature\n name: (property_identifier) @name) @definition.method\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function))) @definition.function\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function)))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression)))) @definition.function\n\n; Namespace / internal module\n(internal_module\n name: (identifier) @name) @definition.namespace\n\n; Ambient declarations: declare function foo(): void\n(ambient_declaration\n (function_signature\n name: (identifier) @name)) @definition.function\n\n(import_statement\n source: (string) @import.source) @import\n\n; Re-export statements: export { X } from './y'\n(export_statement\n source: (string) @import.source) @import\n\n(call_expression\n function: (identifier) @call.name) @call\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @call.name)) @call\n\n; Await calls: await foo() \u2014 tree-sitter wraps await inside the function position\n(call_expression\n function: (await_expression\n (identifier) @call.name)) @call\n\n; Await member calls: await obj.method()\n(call_expression\n function: (await_expression\n (member_expression\n property: (property_identifier) @call.name))) @call\n\n; B3: Dynamic import calls: const { foo } = await import('./module.js')\n(call_expression\n function: (import) @call.name) @call\n\n; Constructor calls: new Foo()\n(new_expression\n constructor: (identifier) @call.name) @call\n\n; Exported const from call: export const Schema = z.object({...})\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression)))) @definition.const\n\n; Exported const from new: export const client = new PrismaClient()\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (new_expression)))) @definition.const\n\n; Module-level const from new: const prisma = new PrismaClient()\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (new_expression))) @definition.const\n\n; Exported const from as_expression: export const EDGE_TYPES = [...] as const\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (as_expression)))) @definition.const\n\n; Exported const from satisfies_expression: export const X = {...} as const satisfies Record<...>\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (satisfies_expression)))) @definition.const\n\n; Exported const from array literal: export const FOO = [1, 2, 3]\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (array)))) @definition.const\n\n; Exported const from object literal: export const CONFIG = { port: 3000 }\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (object)))) @definition.const\n\n; Exported const from number/string: export const MAX_DEPTH = 10\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (number)))) @definition.const\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string)))) @definition.const\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (template_string)))) @definition.const\n\n; Object literal arrow function methods: const x = { method: () => {} }\n(pair\n key: (property_identifier) @name\n value: (arrow_function)) @definition.function\n\n; Object literal function expression methods: const x = { method: function() {} }\n(pair\n key: (property_identifier) @name\n value: (function_expression)) @definition.function\n\n; Heritage queries - class extends\n(class_declaration\n name: (type_identifier) @heritage.class\n (class_heritage\n (extends_clause\n value: (identifier) @heritage.extends))) @heritage\n\n; Heritage queries - class implements interface\n(class_declaration\n name: (type_identifier) @heritage.class\n (class_heritage\n (implements_clause\n (type_identifier) @heritage.implements))) @heritage.impl\n";
|
|
8
8
|
export declare const JAVASCRIPT_QUERIES = "\n(class_declaration\n name: (identifier) @name) @definition.class\n\n(function_declaration\n name: (identifier) @name) @definition.function\n\n(method_definition\n name: (property_identifier) @name) @definition.method\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function))) @definition.function\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function)))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression)))) @definition.function\n\n(import_statement\n source: (string) @import.source) @import\n\n; Re-export statements: export { X } from './y'\n(export_statement\n source: (string) @import.source) @import\n\n(call_expression\n function: (identifier) @call.name) @call\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @call.name)) @call\n\n; Await calls: await foo()\n(call_expression\n function: (await_expression\n (identifier) @call.name)) @call\n\n; Await member calls: await obj.method()\n(call_expression\n function: (await_expression\n (member_expression\n property: (property_identifier) @call.name))) @call\n\n; B3: Dynamic import calls: const { foo } = await import('./module.js')\n(call_expression\n function: (import) @call.name) @call\n\n; Constructor calls: new Foo()\n(new_expression\n constructor: (identifier) @call.name) @call\n\n; Exported const from call: export const schema = z.object({...})\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression)))) @definition.const\n\n; Exported const from new: export const client = new Client()\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (new_expression)))) @definition.const\n\n; Module-level const from new: const instance = new Class()\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (new_expression))) @definition.const\n\n; Exported const from array: export const ITEMS = [...]\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (array)))) @definition.const\n\n; Exported const from object: export const CONFIG = { ... }\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (object)))) @definition.const\n\n; Exported const from number/string\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (number)))) @definition.const\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string)))) @definition.const\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (template_string)))) @definition.const\n\n; Object literal arrow function methods: const x = { method: () => {} }\n(pair\n key: (property_identifier) @name\n value: (arrow_function)) @definition.function\n\n; Object literal function expression methods: const x = { method: function() {} }\n(pair\n key: (property_identifier) @name\n value: (function_expression)) @definition.function\n\n; Heritage queries - class extends (JavaScript uses different AST than TypeScript)\n; In tree-sitter-javascript, class_heritage directly contains the parent identifier\n(class_declaration\n name: (identifier) @heritage.class\n (class_heritage\n (identifier) @heritage.extends)) @heritage\n";
|
|
9
9
|
export declare const PYTHON_QUERIES = "\n(class_definition\n name: (identifier) @name) @definition.class\n\n(function_definition\n name: (identifier) @name) @definition.function\n\n(import_statement\n name: (dotted_name) @import.source) @import\n\n(import_from_statement\n module_name: (dotted_name) @import.source) @import\n\n(import_from_statement\n module_name: (relative_import) @import.source) @import\n\n(call\n function: (identifier) @call.name) @call\n\n(call\n function: (attribute\n attribute: (identifier) @call.name)) @call\n\n; Heritage queries - Python class inheritance\n(class_definition\n name: (identifier) @heritage.class\n superclasses: (argument_list\n (identifier) @heritage.extends)) @heritage\n";
|
|
10
10
|
export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n\n; Constructor calls: new Foo()\n(object_creation_expression type: (type_identifier) @call.name) @call\n\n; Heritage - extends class\n(class_declaration name: (identifier) @heritage.class\n (superclass (type_identifier) @heritage.extends)) @heritage\n\n; Heritage - implements interfaces\n(class_declaration name: (identifier) @heritage.class\n (super_interfaces (type_list (type_identifier) @heritage.implements))) @heritage.impl\n";
|
|
@@ -116,13 +116,20 @@ export const TYPESCRIPT_QUERIES = `
|
|
|
116
116
|
name: (identifier) @name
|
|
117
117
|
value: (new_expression))) @definition.const
|
|
118
118
|
|
|
119
|
-
; Exported const from
|
|
119
|
+
; Exported const from as_expression: export const EDGE_TYPES = [...] as const
|
|
120
120
|
(export_statement
|
|
121
121
|
declaration: (lexical_declaration
|
|
122
122
|
(variable_declarator
|
|
123
123
|
name: (identifier) @name
|
|
124
124
|
value: (as_expression)))) @definition.const
|
|
125
125
|
|
|
126
|
+
; Exported const from satisfies_expression: export const X = {...} as const satisfies Record<...>
|
|
127
|
+
(export_statement
|
|
128
|
+
declaration: (lexical_declaration
|
|
129
|
+
(variable_declarator
|
|
130
|
+
name: (identifier) @name
|
|
131
|
+
value: (satisfies_expression)))) @definition.const
|
|
132
|
+
|
|
126
133
|
; Exported const from array literal: export const FOO = [1, 2, 3]
|
|
127
134
|
(export_statement
|
|
128
135
|
declaration: (lexical_declaration
|
|
@@ -923,6 +923,30 @@ export class LocalBackend {
|
|
|
923
923
|
lines.push(` ${this.shortPath(fp)}${statSuffix} — ${syms.length} symbols: ${names}${more}`);
|
|
924
924
|
}
|
|
925
925
|
}
|
|
926
|
+
// Deleted files (in git diff but no longer on disk)
|
|
927
|
+
const deleted = result.deleted_files || [];
|
|
928
|
+
if (deleted.length > 0) {
|
|
929
|
+
lines.push('');
|
|
930
|
+
lines.push(`### Deleted files (${deleted.length})`);
|
|
931
|
+
for (const fp of deleted) {
|
|
932
|
+
const basename = fp.split('/').slice(-1)[0] ?? '';
|
|
933
|
+
const stat = diffStats[fp] || diffStats[basename] || '';
|
|
934
|
+
const statSuffix = stat ? ` (${stat})` : '';
|
|
935
|
+
lines.push(` ${this.shortPath(fp)}${statSuffix}`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
// Changed files with no indexed symbols (e.g. config, assets)
|
|
939
|
+
const unindexed = result.unindexed_files || [];
|
|
940
|
+
if (unindexed.length > 0) {
|
|
941
|
+
lines.push('');
|
|
942
|
+
lines.push(`### Other changed files (${unindexed.length})`);
|
|
943
|
+
for (const fp of unindexed) {
|
|
944
|
+
const basename = fp.split('/').slice(-1)[0] ?? '';
|
|
945
|
+
const stat = diffStats[fp] || diffStats[basename] || '';
|
|
946
|
+
const statSuffix = stat ? ` (${stat})` : '';
|
|
947
|
+
lines.push(` ${this.shortPath(fp)}${statSuffix}`);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
926
950
|
// Affected processes
|
|
927
951
|
const procs = result.affected_processes || [];
|
|
928
952
|
if (procs.length > 0) {
|
|
@@ -2237,9 +2261,12 @@ export class LocalBackend {
|
|
|
2237
2261
|
// Map changed files to indexed symbols
|
|
2238
2262
|
const db = this.getDb(repo.id);
|
|
2239
2263
|
const changedSymbols = [];
|
|
2264
|
+
const filesWithSymbols = new Set();
|
|
2240
2265
|
for (const file of changedFiles) {
|
|
2241
2266
|
const normalizedFile = file.replace(/\\/g, '/');
|
|
2242
2267
|
const nodes = findNodesByFile(db, normalizedFile);
|
|
2268
|
+
if (nodes.length > 0)
|
|
2269
|
+
filesWithSymbols.add(normalizedFile);
|
|
2243
2270
|
for (const node of nodes) {
|
|
2244
2271
|
changedSymbols.push({
|
|
2245
2272
|
id: node.id, name: node.name, type: node.label,
|
|
@@ -2247,6 +2274,22 @@ export class LocalBackend {
|
|
|
2247
2274
|
});
|
|
2248
2275
|
}
|
|
2249
2276
|
}
|
|
2277
|
+
// Categorize changed files that have no indexed symbols
|
|
2278
|
+
const deletedFiles = [];
|
|
2279
|
+
const unindexedFiles = [];
|
|
2280
|
+
for (const file of changedFiles) {
|
|
2281
|
+
const normalizedFile = file.replace(/\\/g, '/');
|
|
2282
|
+
if (!filesWithSymbols.has(normalizedFile)) {
|
|
2283
|
+
const fullPath = path.resolve(repo.repoPath, normalizedFile);
|
|
2284
|
+
try {
|
|
2285
|
+
await fs.access(fullPath);
|
|
2286
|
+
unindexedFiles.push(normalizedFile);
|
|
2287
|
+
}
|
|
2288
|
+
catch {
|
|
2289
|
+
deletedFiles.push(normalizedFile);
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2250
2293
|
// Fix 7: Detect REAL interface changes by comparing signature text
|
|
2251
2294
|
// Read each changed file from disk and compare the declaration line against
|
|
2252
2295
|
// the stored n.content signature. Only flags symbols whose actual signature changed,
|
|
@@ -2338,6 +2381,8 @@ export class LocalBackend {
|
|
|
2338
2381
|
changed_symbols: changedSymbols,
|
|
2339
2382
|
affected_processes: Array.from(affectedProcesses.values()),
|
|
2340
2383
|
diff_stats: Object.fromEntries(diffStatMap), // F3: line stats per file
|
|
2384
|
+
deleted_files: deletedFiles,
|
|
2385
|
+
unindexed_files: unindexedFiles,
|
|
2341
2386
|
};
|
|
2342
2387
|
}
|
|
2343
2388
|
/** Rename tool: multi-file coordinated rename using graph (high confidence) + text search */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zuvia-software-solutions/code-mapper",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": "Abhigyan Patwari",
|
|
6
6
|
"license": "PolyForm-Noncommercial-1.0.0",
|