gitnexus 1.4.0 → 1.4.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/README.md +19 -18
- package/dist/cli/analyze.js +37 -28
- package/dist/cli/augment.js +1 -1
- package/dist/cli/eval-server.d.ts +1 -1
- package/dist/cli/eval-server.js +1 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/mcp.js +1 -1
- package/dist/cli/setup.js +25 -13
- package/dist/cli/status.js +13 -4
- package/dist/cli/tool.d.ts +1 -1
- package/dist/cli/tool.js +2 -2
- package/dist/cli/wiki.js +2 -2
- package/dist/config/ignore-service.d.ts +25 -0
- package/dist/config/ignore-service.js +76 -0
- package/dist/config/supported-languages.d.ts +1 -0
- package/dist/config/supported-languages.js +1 -1
- package/dist/core/augmentation/engine.js +94 -67
- package/dist/core/embeddings/embedder.d.ts +1 -1
- package/dist/core/embeddings/embedder.js +1 -1
- package/dist/core/embeddings/embedding-pipeline.d.ts +3 -3
- package/dist/core/embeddings/embedding-pipeline.js +52 -25
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/ingestion/call-processor.d.ts +6 -7
- package/dist/core/ingestion/call-processor.js +490 -127
- package/dist/core/ingestion/call-routing.d.ts +53 -0
- package/dist/core/ingestion/call-routing.js +108 -0
- package/dist/core/ingestion/entry-point-scoring.js +13 -2
- package/dist/core/ingestion/export-detection.js +1 -0
- package/dist/core/ingestion/filesystem-walker.js +4 -3
- package/dist/core/ingestion/framework-detection.js +9 -0
- package/dist/core/ingestion/heritage-processor.d.ts +3 -4
- package/dist/core/ingestion/heritage-processor.js +40 -50
- package/dist/core/ingestion/import-processor.d.ts +3 -5
- package/dist/core/ingestion/import-processor.js +41 -10
- package/dist/core/ingestion/parsing-processor.d.ts +2 -1
- package/dist/core/ingestion/parsing-processor.js +41 -4
- package/dist/core/ingestion/pipeline.d.ts +5 -1
- package/dist/core/ingestion/pipeline.js +174 -121
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/index.d.ts +2 -0
- package/dist/core/ingestion/resolvers/index.js +2 -0
- package/dist/core/ingestion/resolvers/python.d.ts +19 -0
- package/dist/core/ingestion/resolvers/python.js +52 -0
- package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
- package/dist/core/ingestion/resolvers/ruby.js +15 -0
- package/dist/core/ingestion/resolvers/standard.js +0 -22
- package/dist/core/ingestion/resolvers/utils.js +2 -0
- package/dist/core/ingestion/symbol-table.d.ts +3 -0
- package/dist/core/ingestion/symbol-table.js +1 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +3 -2
- package/dist/core/ingestion/tree-sitter-queries.js +53 -1
- package/dist/core/ingestion/type-env.d.ts +32 -10
- package/dist/core/ingestion/type-env.js +520 -47
- package/dist/core/ingestion/type-extractors/c-cpp.js +326 -1
- package/dist/core/ingestion/type-extractors/csharp.js +282 -2
- package/dist/core/ingestion/type-extractors/go.js +333 -2
- package/dist/core/ingestion/type-extractors/index.d.ts +3 -2
- package/dist/core/ingestion/type-extractors/index.js +3 -1
- package/dist/core/ingestion/type-extractors/jvm.js +537 -4
- package/dist/core/ingestion/type-extractors/php.js +387 -7
- package/dist/core/ingestion/type-extractors/python.js +356 -5
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +389 -0
- package/dist/core/ingestion/type-extractors/rust.js +399 -2
- package/dist/core/ingestion/type-extractors/shared.d.ts +116 -1
- package/dist/core/ingestion/type-extractors/shared.js +488 -14
- package/dist/core/ingestion/type-extractors/swift.js +95 -1
- package/dist/core/ingestion/type-extractors/types.d.ts +81 -0
- package/dist/core/ingestion/type-extractors/typescript.js +436 -2
- package/dist/core/ingestion/utils.d.ts +33 -2
- package/dist/core/ingestion/utils.js +399 -27
- package/dist/core/ingestion/workers/parse-worker.d.ts +18 -1
- package/dist/core/ingestion/workers/parse-worker.js +169 -19
- package/dist/core/{kuzu → lbug}/csv-generator.d.ts +1 -1
- package/dist/core/{kuzu → lbug}/csv-generator.js +1 -1
- package/dist/core/{kuzu/kuzu-adapter.d.ts → lbug/lbug-adapter.d.ts} +19 -19
- package/dist/core/{kuzu/kuzu-adapter.js → lbug/lbug-adapter.js} +70 -65
- package/dist/core/{kuzu → lbug}/schema.d.ts +1 -1
- package/dist/core/{kuzu → lbug}/schema.js +1 -1
- package/dist/core/search/bm25-index.d.ts +4 -4
- package/dist/core/search/bm25-index.js +10 -10
- package/dist/core/search/hybrid-search.d.ts +2 -2
- package/dist/core/search/hybrid-search.js +6 -6
- package/dist/core/tree-sitter/parser-loader.js +9 -2
- package/dist/core/wiki/generator.d.ts +2 -2
- package/dist/core/wiki/generator.js +4 -4
- package/dist/core/wiki/graph-queries.d.ts +4 -4
- package/dist/core/wiki/graph-queries.js +7 -7
- package/dist/mcp/core/{kuzu-adapter.d.ts → lbug-adapter.d.ts} +7 -7
- package/dist/mcp/core/{kuzu-adapter.js → lbug-adapter.js} +72 -43
- package/dist/mcp/local/local-backend.d.ts +6 -6
- package/dist/mcp/local/local-backend.js +25 -18
- package/dist/server/api.js +12 -12
- package/dist/server/mcp-http.d.ts +1 -1
- package/dist/server/mcp-http.js +1 -1
- package/dist/storage/repo-manager.d.ts +20 -2
- package/dist/storage/repo-manager.js +55 -1
- package/dist/types/pipeline.d.ts +1 -1
- package/package.json +5 -3
- package/dist/core/ingestion/symbol-resolver.d.ts +0 -32
- package/dist/core/ingestion/symbol-resolver.js +0 -83
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Ruby call routing logic.
|
|
3
|
+
*
|
|
4
|
+
* Ruby expresses imports, heritage (mixins), and property definitions as
|
|
5
|
+
* method calls rather than syntax-level constructs. This module provides a
|
|
6
|
+
* routing function used by the CLI call-processor, CLI parse-worker, and
|
|
7
|
+
* the web call-processor so that the classification logic lives in one place.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: This file is intentionally duplicated in gitnexus-web/ because the
|
|
10
|
+
* two packages have separate build targets (Node native vs WASM/browser).
|
|
11
|
+
* Keep both copies in sync until a shared package is introduced.
|
|
12
|
+
*/
|
|
13
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
14
|
+
/** null = this call was not routed; fall through to default call handling */
|
|
15
|
+
export type CallRoutingResult = RubyCallRouting | null;
|
|
16
|
+
export type CallRouter = (calledName: string, callNode: any) => CallRoutingResult;
|
|
17
|
+
/** Per-language call routing. noRouting = no special routing (normal call processing) */
|
|
18
|
+
export declare const callRouters: Record<SupportedLanguages, CallRouter>;
|
|
19
|
+
export type RubyCallRouting = {
|
|
20
|
+
kind: 'import';
|
|
21
|
+
importPath: string;
|
|
22
|
+
isRelative: boolean;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'heritage';
|
|
25
|
+
items: RubyHeritageItem[];
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'properties';
|
|
28
|
+
items: RubyPropertyItem[];
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'call';
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'skip';
|
|
33
|
+
};
|
|
34
|
+
export interface RubyHeritageItem {
|
|
35
|
+
enclosingClass: string;
|
|
36
|
+
mixinName: string;
|
|
37
|
+
heritageKind: 'include' | 'extend' | 'prepend';
|
|
38
|
+
}
|
|
39
|
+
export type RubyAccessorType = 'attr_accessor' | 'attr_reader' | 'attr_writer';
|
|
40
|
+
export interface RubyPropertyItem {
|
|
41
|
+
propName: string;
|
|
42
|
+
accessorType: RubyAccessorType;
|
|
43
|
+
startLine: number;
|
|
44
|
+
endLine: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Classify a Ruby call node and extract its semantic payload.
|
|
48
|
+
*
|
|
49
|
+
* @param calledName - The method name (e.g. 'require', 'include', 'attr_accessor')
|
|
50
|
+
* @param callNode - The tree-sitter `call` AST node
|
|
51
|
+
* @returns A discriminated union describing the call's semantic role
|
|
52
|
+
*/
|
|
53
|
+
export declare function routeRubyCall(calledName: string, callNode: any): RubyCallRouting;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Ruby call routing logic.
|
|
3
|
+
*
|
|
4
|
+
* Ruby expresses imports, heritage (mixins), and property definitions as
|
|
5
|
+
* method calls rather than syntax-level constructs. This module provides a
|
|
6
|
+
* routing function used by the CLI call-processor, CLI parse-worker, and
|
|
7
|
+
* the web call-processor so that the classification logic lives in one place.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: This file is intentionally duplicated in gitnexus-web/ because the
|
|
10
|
+
* two packages have separate build targets (Node native vs WASM/browser).
|
|
11
|
+
* Keep both copies in sync until a shared package is introduced.
|
|
12
|
+
*/
|
|
13
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
14
|
+
/** No-op router: returns null for every call (passthrough to normal processing) */
|
|
15
|
+
const noRouting = () => null;
|
|
16
|
+
/** Per-language call routing. noRouting = no special routing (normal call processing) */
|
|
17
|
+
export const callRouters = {
|
|
18
|
+
[SupportedLanguages.JavaScript]: noRouting,
|
|
19
|
+
[SupportedLanguages.TypeScript]: noRouting,
|
|
20
|
+
[SupportedLanguages.Python]: noRouting,
|
|
21
|
+
[SupportedLanguages.Java]: noRouting,
|
|
22
|
+
[SupportedLanguages.Kotlin]: noRouting,
|
|
23
|
+
[SupportedLanguages.Go]: noRouting,
|
|
24
|
+
[SupportedLanguages.Rust]: noRouting,
|
|
25
|
+
[SupportedLanguages.CSharp]: noRouting,
|
|
26
|
+
[SupportedLanguages.PHP]: noRouting,
|
|
27
|
+
[SupportedLanguages.Swift]: noRouting,
|
|
28
|
+
[SupportedLanguages.CPlusPlus]: noRouting,
|
|
29
|
+
[SupportedLanguages.C]: noRouting,
|
|
30
|
+
[SupportedLanguages.Ruby]: routeRubyCall,
|
|
31
|
+
};
|
|
32
|
+
// ── Pre-allocated singletons for common return values ────────────────────────
|
|
33
|
+
const CALL_RESULT = { kind: 'call' };
|
|
34
|
+
const SKIP_RESULT = { kind: 'skip' };
|
|
35
|
+
/** Max depth for parent-walking loops to prevent pathological AST traversals */
|
|
36
|
+
const MAX_PARENT_DEPTH = 50;
|
|
37
|
+
// ── Routing function ────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Classify a Ruby call node and extract its semantic payload.
|
|
40
|
+
*
|
|
41
|
+
* @param calledName - The method name (e.g. 'require', 'include', 'attr_accessor')
|
|
42
|
+
* @param callNode - The tree-sitter `call` AST node
|
|
43
|
+
* @returns A discriminated union describing the call's semantic role
|
|
44
|
+
*/
|
|
45
|
+
export function routeRubyCall(calledName, callNode) {
|
|
46
|
+
// ── require / require_relative → import ─────────────────────────────────
|
|
47
|
+
if (calledName === 'require' || calledName === 'require_relative') {
|
|
48
|
+
const argList = callNode.childForFieldName?.('arguments');
|
|
49
|
+
const stringNode = argList?.children?.find((c) => c.type === 'string');
|
|
50
|
+
const contentNode = stringNode?.children?.find((c) => c.type === 'string_content');
|
|
51
|
+
if (!contentNode)
|
|
52
|
+
return SKIP_RESULT;
|
|
53
|
+
let importPath = contentNode.text;
|
|
54
|
+
// Validate: reject null bytes, control chars, excessively long paths
|
|
55
|
+
if (!importPath || importPath.length > 1024 || /[\x00-\x1f]/.test(importPath)) {
|
|
56
|
+
return SKIP_RESULT;
|
|
57
|
+
}
|
|
58
|
+
const isRelative = calledName === 'require_relative';
|
|
59
|
+
if (isRelative && !importPath.startsWith('.')) {
|
|
60
|
+
importPath = './' + importPath;
|
|
61
|
+
}
|
|
62
|
+
return { kind: 'import', importPath, isRelative };
|
|
63
|
+
}
|
|
64
|
+
// ── include / extend / prepend → heritage (mixin) ──────────────────────
|
|
65
|
+
if (calledName === 'include' || calledName === 'extend' || calledName === 'prepend') {
|
|
66
|
+
let enclosingClass = null;
|
|
67
|
+
let current = callNode.parent;
|
|
68
|
+
let depth = 0;
|
|
69
|
+
while (current && ++depth <= MAX_PARENT_DEPTH) {
|
|
70
|
+
if (current.type === 'class' || current.type === 'module') {
|
|
71
|
+
const nameNode = current.childForFieldName?.('name');
|
|
72
|
+
if (nameNode) {
|
|
73
|
+
enclosingClass = nameNode.text;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
current = current.parent;
|
|
78
|
+
}
|
|
79
|
+
if (!enclosingClass)
|
|
80
|
+
return SKIP_RESULT;
|
|
81
|
+
const items = [];
|
|
82
|
+
const argList = callNode.childForFieldName?.('arguments');
|
|
83
|
+
for (const arg of (argList?.children ?? [])) {
|
|
84
|
+
if (arg.type === 'constant' || arg.type === 'scope_resolution') {
|
|
85
|
+
items.push({ enclosingClass, mixinName: arg.text, heritageKind: calledName });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return items.length > 0 ? { kind: 'heritage', items } : SKIP_RESULT;
|
|
89
|
+
}
|
|
90
|
+
// ── attr_accessor / attr_reader / attr_writer → property definitions ───
|
|
91
|
+
if (calledName === 'attr_accessor' || calledName === 'attr_reader' || calledName === 'attr_writer') {
|
|
92
|
+
const items = [];
|
|
93
|
+
const argList = callNode.childForFieldName?.('arguments');
|
|
94
|
+
for (const arg of (argList?.children ?? [])) {
|
|
95
|
+
if (arg.type === 'simple_symbol') {
|
|
96
|
+
items.push({
|
|
97
|
+
propName: arg.text.startsWith(':') ? arg.text.slice(1) : arg.text,
|
|
98
|
+
accessorType: calledName,
|
|
99
|
+
startLine: arg.startPosition.row,
|
|
100
|
+
endLine: arg.endPosition.row,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return items.length > 0 ? { kind: 'properties', items } : SKIP_RESULT;
|
|
105
|
+
}
|
|
106
|
+
// ── Everything else → regular call ─────────────────────────────────────
|
|
107
|
+
return CALL_RESULT;
|
|
108
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { detectFrameworkFromPath } from './framework-detection.js';
|
|
13
13
|
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
14
14
|
// ============================================================================
|
|
15
|
-
// NAME PATTERNS - All
|
|
15
|
+
// NAME PATTERNS - All 11 supported languages
|
|
16
16
|
// ============================================================================
|
|
17
17
|
/**
|
|
18
18
|
* Common entry point naming patterns by language
|
|
@@ -178,6 +178,12 @@ const ENTRY_POINT_PATTERNS = {
|
|
|
178
178
|
/^save$/, // Repository::save()
|
|
179
179
|
/^delete$/, // Repository::delete()
|
|
180
180
|
],
|
|
181
|
+
// Ruby
|
|
182
|
+
[SupportedLanguages.Ruby]: [
|
|
183
|
+
/^call$/, // Service objects (MyService.call)
|
|
184
|
+
/^perform$/, // Background jobs (Sidekiq, ActiveJob)
|
|
185
|
+
/^execute$/, // Command pattern
|
|
186
|
+
],
|
|
181
187
|
};
|
|
182
188
|
/** Pre-computed merged patterns (universal + language-specific) to avoid per-call array allocation. */
|
|
183
189
|
const MERGED_ENTRY_POINT_PATTERNS = {};
|
|
@@ -318,7 +324,12 @@ export function isTestFile(filePath) {
|
|
|
318
324
|
p.endsWith('test.php') ||
|
|
319
325
|
p.endsWith('spec.php') ||
|
|
320
326
|
p.includes('/tests/feature/') ||
|
|
321
|
-
p.includes('/tests/unit/')
|
|
327
|
+
p.includes('/tests/unit/') ||
|
|
328
|
+
// Ruby test patterns
|
|
329
|
+
p.endsWith('_spec.rb') ||
|
|
330
|
+
p.endsWith('_test.rb') ||
|
|
331
|
+
p.includes('/spec/') ||
|
|
332
|
+
p.includes('/test/fixtures/'));
|
|
322
333
|
}
|
|
323
334
|
/**
|
|
324
335
|
* Check if a file path is likely a utility/helper file
|
|
@@ -211,6 +211,7 @@ const exportCheckers = {
|
|
|
211
211
|
[SupportedLanguages.CPlusPlus]: cCppExportChecker,
|
|
212
212
|
[SupportedLanguages.PHP]: phpExportChecker,
|
|
213
213
|
[SupportedLanguages.Swift]: swiftExportChecker,
|
|
214
|
+
[SupportedLanguages.Ruby]: (_node, _name) => true,
|
|
214
215
|
};
|
|
215
216
|
// ============================================================================
|
|
216
217
|
// Public API
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { glob } from 'glob';
|
|
4
|
-
import {
|
|
4
|
+
import { createIgnoreFilter } from '../../config/ignore-service.js';
|
|
5
5
|
const READ_CONCURRENCY = 32;
|
|
6
6
|
/** Skip files larger than 512KB — they're usually generated/vendored and crash tree-sitter */
|
|
7
7
|
const MAX_FILE_SIZE = 512 * 1024;
|
|
@@ -10,12 +10,13 @@ const MAX_FILE_SIZE = 512 * 1024;
|
|
|
10
10
|
* Memory: ~10MB for 100K files vs ~1GB+ with content.
|
|
11
11
|
*/
|
|
12
12
|
export const walkRepositoryPaths = async (repoPath, onProgress) => {
|
|
13
|
-
const
|
|
13
|
+
const ignoreFilter = await createIgnoreFilter(repoPath);
|
|
14
|
+
const filtered = await glob('**/*', {
|
|
14
15
|
cwd: repoPath,
|
|
15
16
|
nodir: true,
|
|
16
17
|
dot: false,
|
|
18
|
+
ignore: ignoreFilter,
|
|
17
19
|
});
|
|
18
|
-
const filtered = files.filter(file => !shouldIgnorePath(file));
|
|
19
20
|
const entries = [];
|
|
20
21
|
let processed = 0;
|
|
21
22
|
let skippedLarge = 0;
|
|
@@ -255,6 +255,15 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
255
255
|
if (p.includes('/repositories/') && p.endsWith('.php')) {
|
|
256
256
|
return { framework: 'laravel', entryPointMultiplier: 1.5, reason: 'laravel-repository' };
|
|
257
257
|
}
|
|
258
|
+
// ========== RUBY ==========
|
|
259
|
+
// Ruby: bin/ or exe/ (CLI entry points)
|
|
260
|
+
if ((p.includes('/bin/') || p.includes('/exe/')) && p.endsWith('.rb')) {
|
|
261
|
+
return { framework: 'ruby', entryPointMultiplier: 2.5, reason: 'ruby-executable' };
|
|
262
|
+
}
|
|
263
|
+
// Ruby: Rakefile or *.rake (task definitions)
|
|
264
|
+
if (p.endsWith('/rakefile') || p.endsWith('.rake')) {
|
|
265
|
+
return { framework: 'ruby', entryPointMultiplier: 1.5, reason: 'ruby-rake' };
|
|
266
|
+
}
|
|
258
267
|
// ========== SWIFT / iOS ==========
|
|
259
268
|
// iOS App entry points (highest priority)
|
|
260
269
|
if (p.endsWith('/appdelegate.swift') || p.endsWith('/scenedelegate.swift') || p.endsWith('/app.swift')) {
|
|
@@ -15,15 +15,14 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { KnowledgeGraph } from '../graph/types.js';
|
|
17
17
|
import { ASTCache } from './ast-cache.js';
|
|
18
|
-
import { SymbolTable } from './symbol-table.js';
|
|
19
18
|
import type { ExtractedHeritage } from './workers/parse-worker.js';
|
|
20
|
-
import type {
|
|
19
|
+
import type { ResolutionContext } from './resolution-context.js';
|
|
21
20
|
export declare const processHeritage: (graph: KnowledgeGraph, files: {
|
|
22
21
|
path: string;
|
|
23
22
|
content: string;
|
|
24
|
-
}[], astCache: ASTCache,
|
|
23
|
+
}[], astCache: ASTCache, ctx: ResolutionContext, onProgress?: (current: number, total: number) => void) => Promise<void>;
|
|
25
24
|
/**
|
|
26
25
|
* Fast path: resolve pre-extracted heritage from workers.
|
|
27
26
|
* No AST parsing — workers already extracted className + parentName + kind.
|
|
28
27
|
*/
|
|
29
|
-
export declare const processHeritageFromExtracted: (graph: KnowledgeGraph, extractedHeritage: ExtractedHeritage[],
|
|
28
|
+
export declare const processHeritageFromExtracted: (graph: KnowledgeGraph, extractedHeritage: ExtractedHeritage[], ctx: ResolutionContext, onProgress?: (current: number, total: number) => void) => Promise<void>;
|
|
@@ -20,7 +20,6 @@ import { generateId } from '../../lib/utils.js';
|
|
|
20
20
|
import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
|
|
21
21
|
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
22
22
|
import { getTreeSitterBufferSize } from './constants.js';
|
|
23
|
-
import { resolveSymbol } from './symbol-resolver.js';
|
|
24
23
|
/** C#/Java convention: interfaces start with I followed by an uppercase letter */
|
|
25
24
|
const INTERFACE_NAME_RE = /^I[A-Z]/;
|
|
26
25
|
/**
|
|
@@ -31,10 +30,10 @@ const INTERFACE_NAME_RE = /^I[A-Z]/;
|
|
|
31
30
|
* - Swift: default IMPLEMENTS (protocol conformance is the norm)
|
|
32
31
|
* - All others: default EXTENDS
|
|
33
32
|
*/
|
|
34
|
-
const resolveExtendsType = (parentName, currentFilePath,
|
|
35
|
-
const resolved =
|
|
36
|
-
if (resolved) {
|
|
37
|
-
const isInterface = resolved.type === 'Interface';
|
|
33
|
+
const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
|
|
34
|
+
const resolved = ctx.resolve(parentName, currentFilePath);
|
|
35
|
+
if (resolved && resolved.candidates.length > 0) {
|
|
36
|
+
const isInterface = resolved.candidates[0].type === 'Interface';
|
|
38
37
|
return isInterface
|
|
39
38
|
? { type: 'IMPLEMENTS', idPrefix: 'Interface' }
|
|
40
39
|
: { type: 'EXTENDS', idPrefix: 'Class' };
|
|
@@ -51,7 +50,22 @@ const resolveExtendsType = (parentName, currentFilePath, symbolTable, importMap,
|
|
|
51
50
|
}
|
|
52
51
|
return { type: 'EXTENDS', idPrefix: 'Class' };
|
|
53
52
|
};
|
|
54
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a symbol ID for heritage, with fallback to generated ID.
|
|
55
|
+
* Uses ctx.resolve() → pick first candidate's nodeId → generate synthetic ID.
|
|
56
|
+
*/
|
|
57
|
+
const resolveHeritageId = (name, filePath, ctx, fallbackLabel, fallbackKey) => {
|
|
58
|
+
const resolved = ctx.resolve(name, filePath);
|
|
59
|
+
if (resolved && resolved.candidates.length > 0) {
|
|
60
|
+
// For global with multiple candidates, refuse (a wrong edge is worse than no edge)
|
|
61
|
+
if (resolved.tier === 'global' && resolved.candidates.length > 1) {
|
|
62
|
+
return generateId(fallbackLabel, fallbackKey ?? name);
|
|
63
|
+
}
|
|
64
|
+
return resolved.candidates[0].nodeId;
|
|
65
|
+
}
|
|
66
|
+
return generateId(fallbackLabel, fallbackKey ?? name);
|
|
67
|
+
};
|
|
68
|
+
export const processHeritage = async (graph, files, astCache, ctx, onProgress) => {
|
|
55
69
|
const parser = await loadParser();
|
|
56
70
|
const logSkipped = isVerboseIngestionEnabled();
|
|
57
71
|
const skippedByLang = logSkipped ? new Map() : null;
|
|
@@ -77,7 +91,6 @@ export const processHeritage = async (graph, files, astCache, symbolTable, impor
|
|
|
77
91
|
await loadLanguage(language, file.path);
|
|
78
92
|
// 3. Get AST
|
|
79
93
|
let tree = astCache.get(file.path);
|
|
80
|
-
let wasReparsed = false;
|
|
81
94
|
if (!tree) {
|
|
82
95
|
// Use larger bufferSize for files > 32KB
|
|
83
96
|
try {
|
|
@@ -87,7 +100,6 @@ export const processHeritage = async (graph, files, astCache, symbolTable, impor
|
|
|
87
100
|
// Skip files that can't be parsed
|
|
88
101
|
continue;
|
|
89
102
|
}
|
|
90
|
-
wasReparsed = true;
|
|
91
103
|
// Cache re-parsed tree for potential future use
|
|
92
104
|
astCache.set(file.path, tree);
|
|
93
105
|
}
|
|
@@ -119,12 +131,9 @@ export const processHeritage = async (graph, files, astCache, symbolTable, impor
|
|
|
119
131
|
}
|
|
120
132
|
const className = captureMap['heritage.class'].text;
|
|
121
133
|
const parentClassName = captureMap['heritage.extends'].text;
|
|
122
|
-
const { type: relType, idPrefix } = resolveExtendsType(parentClassName, file.path,
|
|
123
|
-
const childId =
|
|
124
|
-
|
|
125
|
-
generateId('Class', `${file.path}:${className}`);
|
|
126
|
-
const parentId = resolveSymbol(parentClassName, file.path, symbolTable, importMap, packageMap)?.nodeId ||
|
|
127
|
-
generateId(idPrefix, `${parentClassName}`);
|
|
134
|
+
const { type: relType, idPrefix } = resolveExtendsType(parentClassName, file.path, ctx, language);
|
|
135
|
+
const childId = resolveHeritageId(className, file.path, ctx, 'Class', `${file.path}:${className}`);
|
|
136
|
+
const parentId = resolveHeritageId(parentClassName, file.path, ctx, idPrefix);
|
|
128
137
|
if (childId && parentId && childId !== parentId) {
|
|
129
138
|
graph.addRelationship({
|
|
130
139
|
id: generateId(relType, `${childId}->${parentId}`),
|
|
@@ -140,16 +149,11 @@ export const processHeritage = async (graph, files, astCache, symbolTable, impor
|
|
|
140
149
|
if (captureMap['heritage.class'] && captureMap['heritage.implements']) {
|
|
141
150
|
const className = captureMap['heritage.class'].text;
|
|
142
151
|
const interfaceName = captureMap['heritage.implements'].text;
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
resolveSymbol(className, file.path, symbolTable, importMap, packageMap)?.nodeId ||
|
|
146
|
-
generateId('Class', `${file.path}:${className}`);
|
|
147
|
-
const interfaceId = resolveSymbol(interfaceName, file.path, symbolTable, importMap, packageMap)?.nodeId ||
|
|
148
|
-
generateId('Interface', `${interfaceName}`);
|
|
152
|
+
const classId = resolveHeritageId(className, file.path, ctx, 'Class', `${file.path}:${className}`);
|
|
153
|
+
const interfaceId = resolveHeritageId(interfaceName, file.path, ctx, 'Interface');
|
|
149
154
|
if (classId && interfaceId) {
|
|
150
|
-
const relId = generateId('IMPLEMENTS', `${classId}->${interfaceId}`);
|
|
151
155
|
graph.addRelationship({
|
|
152
|
-
id:
|
|
156
|
+
id: generateId('IMPLEMENTS', `${classId}->${interfaceId}`),
|
|
153
157
|
sourceId: classId,
|
|
154
158
|
targetId: interfaceId,
|
|
155
159
|
type: 'IMPLEMENTS',
|
|
@@ -162,16 +166,11 @@ export const processHeritage = async (graph, files, astCache, symbolTable, impor
|
|
|
162
166
|
if (captureMap['heritage.trait'] && captureMap['heritage.class']) {
|
|
163
167
|
const structName = captureMap['heritage.class'].text;
|
|
164
168
|
const traitName = captureMap['heritage.trait'].text;
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
resolveSymbol(structName, file.path, symbolTable, importMap, packageMap)?.nodeId ||
|
|
168
|
-
generateId('Struct', `${file.path}:${structName}`);
|
|
169
|
-
const traitId = resolveSymbol(traitName, file.path, symbolTable, importMap, packageMap)?.nodeId ||
|
|
170
|
-
generateId('Trait', `${traitName}`);
|
|
169
|
+
const structId = resolveHeritageId(structName, file.path, ctx, 'Struct', `${file.path}:${structName}`);
|
|
170
|
+
const traitId = resolveHeritageId(traitName, file.path, ctx, 'Trait');
|
|
171
171
|
if (structId && traitId) {
|
|
172
|
-
const relId = generateId('IMPLEMENTS', `${structId}->${traitId}`);
|
|
173
172
|
graph.addRelationship({
|
|
174
|
-
id:
|
|
173
|
+
id: generateId('IMPLEMENTS', `${structId}->${traitId}`),
|
|
175
174
|
sourceId: structId,
|
|
176
175
|
targetId: traitId,
|
|
177
176
|
type: 'IMPLEMENTS',
|
|
@@ -193,7 +192,7 @@ export const processHeritage = async (graph, files, astCache, symbolTable, impor
|
|
|
193
192
|
* Fast path: resolve pre-extracted heritage from workers.
|
|
194
193
|
* No AST parsing — workers already extracted className + parentName + kind.
|
|
195
194
|
*/
|
|
196
|
-
export const processHeritageFromExtracted = async (graph, extractedHeritage,
|
|
195
|
+
export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx, onProgress) => {
|
|
197
196
|
const total = extractedHeritage.length;
|
|
198
197
|
for (let i = 0; i < extractedHeritage.length; i++) {
|
|
199
198
|
if (i % 500 === 0) {
|
|
@@ -205,12 +204,9 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, sym
|
|
|
205
204
|
const fileLanguage = getLanguageFromFilename(h.filePath);
|
|
206
205
|
if (!fileLanguage)
|
|
207
206
|
continue;
|
|
208
|
-
const { type: relType, idPrefix } = resolveExtendsType(h.parentName, h.filePath,
|
|
209
|
-
const childId =
|
|
210
|
-
|
|
211
|
-
generateId('Class', `${h.filePath}:${h.className}`);
|
|
212
|
-
const parentId = resolveSymbol(h.parentName, h.filePath, symbolTable, importMap, packageMap)?.nodeId ||
|
|
213
|
-
generateId(idPrefix, `${h.parentName}`);
|
|
207
|
+
const { type: relType, idPrefix } = resolveExtendsType(h.parentName, h.filePath, ctx, fileLanguage);
|
|
208
|
+
const childId = resolveHeritageId(h.className, h.filePath, ctx, 'Class', `${h.filePath}:${h.className}`);
|
|
209
|
+
const parentId = resolveHeritageId(h.parentName, h.filePath, ctx, idPrefix);
|
|
214
210
|
if (childId && parentId && childId !== parentId) {
|
|
215
211
|
graph.addRelationship({
|
|
216
212
|
id: generateId(relType, `${childId}->${parentId}`),
|
|
@@ -223,11 +219,8 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, sym
|
|
|
223
219
|
}
|
|
224
220
|
}
|
|
225
221
|
else if (h.kind === 'implements') {
|
|
226
|
-
const classId =
|
|
227
|
-
|
|
228
|
-
generateId('Class', `${h.filePath}:${h.className}`);
|
|
229
|
-
const interfaceId = resolveSymbol(h.parentName, h.filePath, symbolTable, importMap, packageMap)?.nodeId ||
|
|
230
|
-
generateId('Interface', `${h.parentName}`);
|
|
222
|
+
const classId = resolveHeritageId(h.className, h.filePath, ctx, 'Class', `${h.filePath}:${h.className}`);
|
|
223
|
+
const interfaceId = resolveHeritageId(h.parentName, h.filePath, ctx, 'Interface');
|
|
231
224
|
if (classId && interfaceId) {
|
|
232
225
|
graph.addRelationship({
|
|
233
226
|
id: generateId('IMPLEMENTS', `${classId}->${interfaceId}`),
|
|
@@ -239,20 +232,17 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, sym
|
|
|
239
232
|
});
|
|
240
233
|
}
|
|
241
234
|
}
|
|
242
|
-
else if (h.kind === 'trait-impl') {
|
|
243
|
-
const structId =
|
|
244
|
-
|
|
245
|
-
generateId('Struct', `${h.filePath}:${h.className}`);
|
|
246
|
-
const traitId = resolveSymbol(h.parentName, h.filePath, symbolTable, importMap, packageMap)?.nodeId ||
|
|
247
|
-
generateId('Trait', `${h.parentName}`);
|
|
235
|
+
else if (h.kind === 'trait-impl' || h.kind === 'include' || h.kind === 'extend' || h.kind === 'prepend') {
|
|
236
|
+
const structId = resolveHeritageId(h.className, h.filePath, ctx, 'Struct', `${h.filePath}:${h.className}`);
|
|
237
|
+
const traitId = resolveHeritageId(h.parentName, h.filePath, ctx, 'Trait');
|
|
248
238
|
if (structId && traitId) {
|
|
249
239
|
graph.addRelationship({
|
|
250
|
-
id: generateId('IMPLEMENTS', `${structId}->${traitId}`),
|
|
240
|
+
id: generateId('IMPLEMENTS', `${structId}->${traitId}:${h.kind}`),
|
|
251
241
|
sourceId: structId,
|
|
252
242
|
targetId: traitId,
|
|
253
243
|
type: 'IMPLEMENTS',
|
|
254
244
|
confidence: 1.0,
|
|
255
|
-
reason:
|
|
245
|
+
reason: h.kind,
|
|
256
246
|
});
|
|
257
247
|
}
|
|
258
248
|
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { KnowledgeGraph } from '../graph/types.js';
|
|
2
2
|
import { ASTCache } from './ast-cache.js';
|
|
3
3
|
import type { ExtractedImport } from './workers/parse-worker.js';
|
|
4
|
+
import type { ResolutionContext } from './resolution-context.js';
|
|
4
5
|
import type { SuffixIndex } from './resolvers/index.js';
|
|
5
6
|
export type { SuffixIndex, TsconfigPaths, GoModuleConfig, CSharpProjectConfig, ComposerConfig } from './resolvers/index.js';
|
|
6
7
|
export type ImportMap = Map<string, Set<string>>;
|
|
7
|
-
export declare const createImportMap: () => ImportMap;
|
|
8
8
|
export type PackageMap = Map<string, Set<string>>;
|
|
9
|
-
export declare const createPackageMap: () => PackageMap;
|
|
10
9
|
export interface NamedImportBinding {
|
|
11
10
|
sourcePath: string;
|
|
12
11
|
exportedName: string;
|
|
13
12
|
}
|
|
14
13
|
export type NamedImportMap = Map<string, Map<string, NamedImportBinding>>;
|
|
15
|
-
export declare const createNamedImportMap: () => NamedImportMap;
|
|
16
14
|
/**
|
|
17
15
|
* Check if a file path is directly inside a package directory identified by its suffix.
|
|
18
16
|
* Used by the symbol resolver for Go and C# directory-level import matching.
|
|
@@ -30,7 +28,7 @@ export declare function buildImportResolutionContext(allPaths: string[]): Import
|
|
|
30
28
|
export declare const processImports: (graph: KnowledgeGraph, files: {
|
|
31
29
|
path: string;
|
|
32
30
|
content: string;
|
|
33
|
-
}[], astCache: ASTCache,
|
|
31
|
+
}[], astCache: ASTCache, ctx: ResolutionContext, onProgress?: (current: number, total: number) => void, repoRoot?: string, allPaths?: string[]) => Promise<void>;
|
|
34
32
|
export declare const processImportsFromExtracted: (graph: KnowledgeGraph, files: {
|
|
35
33
|
path: string;
|
|
36
|
-
}[], extractedImports: ExtractedImport[],
|
|
34
|
+
}[], extractedImports: ExtractedImport[], ctx: ResolutionContext, onProgress?: (current: number, total: number) => void, repoRoot?: string, prebuiltCtx?: ImportResolutionContext) => Promise<void>;
|
|
@@ -7,11 +7,9 @@ import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
|
7
7
|
import { extractNamedBindings } from './named-binding-extraction.js';
|
|
8
8
|
import { getTreeSitterBufferSize } from './constants.js';
|
|
9
9
|
import { loadTsconfigPaths, loadGoModulePath, loadComposerConfig, loadCSharpProjectConfig, loadSwiftPackageConfig, } from './language-config.js';
|
|
10
|
-
import { buildSuffixIndex, resolveImportPath, appendKotlinWildcard, KOTLIN_EXTENSIONS, resolveJvmWildcard, resolveJvmMemberImport, resolveGoPackageDir, resolveGoPackage, resolveCSharpImport, resolveCSharpNamespaceDir, resolvePhpImport, resolveRustImport, } from './resolvers/index.js';
|
|
10
|
+
import { buildSuffixIndex, resolveImportPath, appendKotlinWildcard, KOTLIN_EXTENSIONS, resolveJvmWildcard, resolveJvmMemberImport, resolveGoPackageDir, resolveGoPackage, resolveCSharpImport, resolveCSharpNamespaceDir, resolvePhpImport, resolveRustImport, resolveRubyImport, resolvePythonImport, } from './resolvers/index.js';
|
|
11
|
+
import { callRouters } from './call-routing.js';
|
|
11
12
|
const isDev = process.env.NODE_ENV === 'development';
|
|
12
|
-
export const createImportMap = () => new Map();
|
|
13
|
-
export const createPackageMap = () => new Map();
|
|
14
|
-
export const createNamedImportMap = () => new Map();
|
|
15
13
|
/**
|
|
16
14
|
* Check if a file path is directly inside a package directory identified by its suffix.
|
|
17
15
|
* Used by the symbol resolver for Go and C# directory-level import matching.
|
|
@@ -107,6 +105,20 @@ function resolveLanguageImport(filePath, rawImportPath, language, configs, ctx)
|
|
|
107
105
|
}
|
|
108
106
|
return null; // External framework (Foundation, UIKit, etc.)
|
|
109
107
|
}
|
|
108
|
+
// Python: relative imports (PEP 328) + proximity-based bare imports
|
|
109
|
+
// Falls through to standard suffix resolution when proximity finds no match.
|
|
110
|
+
if (language === SupportedLanguages.Python) {
|
|
111
|
+
const resolved = resolvePythonImport(filePath, rawImportPath, allFilePaths);
|
|
112
|
+
if (resolved)
|
|
113
|
+
return { kind: 'files', files: [resolved] };
|
|
114
|
+
if (rawImportPath.startsWith('.'))
|
|
115
|
+
return null; // relative but unresolved — don't suffix-match
|
|
116
|
+
}
|
|
117
|
+
// Ruby: require / require_relative
|
|
118
|
+
if (language === SupportedLanguages.Ruby) {
|
|
119
|
+
const resolved = resolveRubyImport(rawImportPath, normalizedFileList, allFileList, index);
|
|
120
|
+
return resolved ? { kind: 'files', files: [resolved] } : null;
|
|
121
|
+
}
|
|
110
122
|
// Rust: expand top-level grouped imports: use {crate::a, crate::b}
|
|
111
123
|
if (language === SupportedLanguages.Rust && rawImportPath.startsWith('{') && rawImportPath.endsWith('}')) {
|
|
112
124
|
const inner = rawImportPath.slice(1, -1);
|
|
@@ -161,7 +173,10 @@ function applyImportResult(result, filePath, importMap, packageMap, addImportEdg
|
|
|
161
173
|
// ============================================================================
|
|
162
174
|
// MAIN IMPORT PROCESSOR
|
|
163
175
|
// ============================================================================
|
|
164
|
-
export const processImports = async (graph, files, astCache,
|
|
176
|
+
export const processImports = async (graph, files, astCache, ctx, onProgress, repoRoot, allPaths) => {
|
|
177
|
+
const importMap = ctx.importMap;
|
|
178
|
+
const packageMap = ctx.packageMap;
|
|
179
|
+
const namedImportMap = ctx.namedImportMap;
|
|
165
180
|
// Use allPaths (full repo) when available for cross-chunk resolution, else fall back to chunk files
|
|
166
181
|
const allFileList = allPaths ?? files.map(f => f.path);
|
|
167
182
|
const allFilePaths = new Set(allFileList);
|
|
@@ -185,7 +200,7 @@ export const processImports = async (graph, files, astCache, importMap, onProgre
|
|
|
185
200
|
swiftPackageConfig: await loadSwiftPackageConfig(effectiveRoot),
|
|
186
201
|
csharpConfigs: await loadCSharpProjectConfig(effectiveRoot),
|
|
187
202
|
};
|
|
188
|
-
const
|
|
203
|
+
const resolveCtx = { allFilePaths, allFileList, normalizedFileList, index, resolveCache };
|
|
189
204
|
// Helper: add an IMPORTS edge to the graph only (no ImportMap update)
|
|
190
205
|
const addImportGraphEdge = (filePath, resolvedPath) => {
|
|
191
206
|
const sourceId = generateId('File', filePath);
|
|
@@ -281,10 +296,23 @@ export const processImports = async (graph, files, astCache, importMap, onProgre
|
|
|
281
296
|
? appendKotlinWildcard(sourceNode.text.replace(/['"<>]/g, ''), captureMap['import'])
|
|
282
297
|
: sourceNode.text.replace(/['"<>]/g, '');
|
|
283
298
|
totalImportsFound++;
|
|
284
|
-
const result = resolveLanguageImport(file.path, rawImportPath, language, configs,
|
|
299
|
+
const result = resolveLanguageImport(file.path, rawImportPath, language, configs, resolveCtx);
|
|
285
300
|
const bindings = namedImportMap ? extractNamedBindings(captureMap['import'], language) : undefined;
|
|
286
301
|
applyImportResult(result, file.path, importMap, packageMap, addImportEdge, addImportGraphEdge, bindings, namedImportMap);
|
|
287
302
|
}
|
|
303
|
+
// ---- Language-specific call-as-import routing (Ruby require, etc.) ----
|
|
304
|
+
if (captureMap['call']) {
|
|
305
|
+
const callNameNode = captureMap['call.name'];
|
|
306
|
+
if (callNameNode) {
|
|
307
|
+
const callRouter = callRouters[language];
|
|
308
|
+
const routed = callRouter(callNameNode.text, captureMap['call']);
|
|
309
|
+
if (routed && routed.kind === 'import') {
|
|
310
|
+
totalImportsFound++;
|
|
311
|
+
const result = resolveLanguageImport(file.path, routed.importPath, language, configs, resolveCtx);
|
|
312
|
+
applyImportResult(result, file.path, importMap, packageMap, addImportEdge, addImportGraphEdge);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
288
316
|
});
|
|
289
317
|
// Tree is now owned by the LRU cache — no manual delete needed
|
|
290
318
|
}
|
|
@@ -300,9 +328,12 @@ export const processImports = async (graph, files, astCache, importMap, onProgre
|
|
|
300
328
|
// ============================================================================
|
|
301
329
|
// FAST PATH: Resolve pre-extracted imports (no parsing needed)
|
|
302
330
|
// ============================================================================
|
|
303
|
-
export const processImportsFromExtracted = async (graph, files, extractedImports,
|
|
304
|
-
const
|
|
305
|
-
const
|
|
331
|
+
export const processImportsFromExtracted = async (graph, files, extractedImports, ctx, onProgress, repoRoot, prebuiltCtx) => {
|
|
332
|
+
const importMap = ctx.importMap;
|
|
333
|
+
const packageMap = ctx.packageMap;
|
|
334
|
+
const namedImportMap = ctx.namedImportMap;
|
|
335
|
+
const importCtx = prebuiltCtx ?? buildImportResolutionContext(files.map(f => f.path));
|
|
336
|
+
const { allFilePaths, allFileList, normalizedFileList, suffixIndex: index, resolveCache } = importCtx;
|
|
306
337
|
let totalImportsFound = 0;
|
|
307
338
|
let totalImportsResolved = 0;
|
|
308
339
|
const effectiveRoot = repoRoot || '';
|
|
@@ -2,13 +2,14 @@ import { KnowledgeGraph } from '../graph/types.js';
|
|
|
2
2
|
import { SymbolTable } from './symbol-table.js';
|
|
3
3
|
import { ASTCache } from './ast-cache.js';
|
|
4
4
|
import { WorkerPool } from './workers/worker-pool.js';
|
|
5
|
-
import type { ExtractedImport, ExtractedCall, ExtractedHeritage, ExtractedRoute } from './workers/parse-worker.js';
|
|
5
|
+
import type { ExtractedImport, ExtractedCall, ExtractedHeritage, ExtractedRoute, FileConstructorBindings } from './workers/parse-worker.js';
|
|
6
6
|
export type FileProgressCallback = (current: number, total: number, filePath: string) => void;
|
|
7
7
|
export interface WorkerExtractedData {
|
|
8
8
|
imports: ExtractedImport[];
|
|
9
9
|
calls: ExtractedCall[];
|
|
10
10
|
heritage: ExtractedHeritage[];
|
|
11
11
|
routes: ExtractedRoute[];
|
|
12
|
+
constructorBindings: FileConstructorBindings[];
|
|
12
13
|
}
|
|
13
14
|
export { isNodeExported } from './export-detection.js';
|
|
14
15
|
export declare const processParsing: (graph: KnowledgeGraph, files: {
|