@duytransipher/gitnexus 1.4.6-sipher.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.
- package/LICENSE +73 -0
- package/README.md +261 -0
- package/dist/cli/ai-context.d.ts +23 -0
- package/dist/cli/ai-context.js +265 -0
- package/dist/cli/analyze.d.ts +12 -0
- package/dist/cli/analyze.js +345 -0
- package/dist/cli/augment.d.ts +13 -0
- package/dist/cli/augment.js +33 -0
- package/dist/cli/clean.d.ts +10 -0
- package/dist/cli/clean.js +60 -0
- package/dist/cli/eval-server.d.ts +37 -0
- package/dist/cli/eval-server.js +389 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +137 -0
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +30 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +36 -0
- package/dist/cli/serve.d.ts +4 -0
- package/dist/cli/serve.js +6 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +367 -0
- package/dist/cli/sipher-patched.d.ts +2 -0
- package/dist/cli/sipher-patched.js +77 -0
- package/dist/cli/skill-gen.d.ts +26 -0
- package/dist/cli/skill-gen.js +549 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.js +36 -0
- package/dist/cli/tool.d.ts +60 -0
- package/dist/cli/tool.js +180 -0
- package/dist/cli/wiki.d.ts +15 -0
- package/dist/cli/wiki.js +365 -0
- package/dist/config/ignore-service.d.ts +26 -0
- package/dist/config/ignore-service.js +284 -0
- package/dist/config/supported-languages.d.ts +15 -0
- package/dist/config/supported-languages.js +16 -0
- package/dist/core/augmentation/engine.d.ts +26 -0
- package/dist/core/augmentation/engine.js +240 -0
- package/dist/core/embeddings/embedder.d.ts +60 -0
- package/dist/core/embeddings/embedder.js +251 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
- package/dist/core/embeddings/embedding-pipeline.js +356 -0
- package/dist/core/embeddings/index.d.ts +9 -0
- package/dist/core/embeddings/index.js +9 -0
- package/dist/core/embeddings/text-generator.d.ts +24 -0
- package/dist/core/embeddings/text-generator.js +182 -0
- package/dist/core/embeddings/types.d.ts +87 -0
- package/dist/core/embeddings/types.js +32 -0
- package/dist/core/graph/graph.d.ts +2 -0
- package/dist/core/graph/graph.js +66 -0
- package/dist/core/graph/types.d.ts +66 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/ingestion/ast-cache.d.ts +11 -0
- package/dist/core/ingestion/ast-cache.js +35 -0
- package/dist/core/ingestion/call-processor.d.ts +23 -0
- package/dist/core/ingestion/call-processor.js +793 -0
- package/dist/core/ingestion/call-routing.d.ts +68 -0
- package/dist/core/ingestion/call-routing.js +129 -0
- package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
- package/dist/core/ingestion/cluster-enricher.js +170 -0
- package/dist/core/ingestion/community-processor.d.ts +39 -0
- package/dist/core/ingestion/community-processor.js +312 -0
- package/dist/core/ingestion/constants.d.ts +16 -0
- package/dist/core/ingestion/constants.js +16 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +40 -0
- package/dist/core/ingestion/entry-point-scoring.js +353 -0
- package/dist/core/ingestion/export-detection.d.ts +18 -0
- package/dist/core/ingestion/export-detection.js +231 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
- package/dist/core/ingestion/filesystem-walker.js +81 -0
- package/dist/core/ingestion/framework-detection.d.ts +54 -0
- package/dist/core/ingestion/framework-detection.js +411 -0
- package/dist/core/ingestion/heritage-processor.d.ts +28 -0
- package/dist/core/ingestion/heritage-processor.js +251 -0
- package/dist/core/ingestion/import-processor.d.ts +34 -0
- package/dist/core/ingestion/import-processor.js +398 -0
- package/dist/core/ingestion/language-config.d.ts +46 -0
- package/dist/core/ingestion/language-config.js +167 -0
- package/dist/core/ingestion/mro-processor.d.ts +45 -0
- package/dist/core/ingestion/mro-processor.js +369 -0
- package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
- package/dist/core/ingestion/named-binding-extraction.js +363 -0
- package/dist/core/ingestion/parsing-processor.d.ts +19 -0
- package/dist/core/ingestion/parsing-processor.js +315 -0
- package/dist/core/ingestion/pipeline.d.ts +6 -0
- package/dist/core/ingestion/pipeline.js +401 -0
- package/dist/core/ingestion/process-processor.d.ts +51 -0
- package/dist/core/ingestion/process-processor.js +315 -0
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
- package/dist/core/ingestion/resolvers/csharp.js +109 -0
- package/dist/core/ingestion/resolvers/go.d.ts +19 -0
- package/dist/core/ingestion/resolvers/go.js +42 -0
- package/dist/core/ingestion/resolvers/index.d.ts +18 -0
- package/dist/core/ingestion/resolvers/index.js +13 -0
- package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
- package/dist/core/ingestion/resolvers/jvm.js +87 -0
- package/dist/core/ingestion/resolvers/php.d.ts +15 -0
- package/dist/core/ingestion/resolvers/php.js +35 -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/rust.d.ts +15 -0
- package/dist/core/ingestion/resolvers/rust.js +73 -0
- package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
- package/dist/core/ingestion/resolvers/standard.js +123 -0
- package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
- package/dist/core/ingestion/resolvers/utils.js +122 -0
- package/dist/core/ingestion/structure-processor.d.ts +2 -0
- package/dist/core/ingestion/structure-processor.js +36 -0
- package/dist/core/ingestion/symbol-table.d.ts +63 -0
- package/dist/core/ingestion/symbol-table.js +85 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +15 -0
- package/dist/core/ingestion/tree-sitter-queries.js +888 -0
- package/dist/core/ingestion/type-env.d.ts +49 -0
- package/dist/core/ingestion/type-env.js +613 -0
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
- package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/csharp.js +383 -0
- package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/go.js +467 -0
- package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
- package/dist/core/ingestion/type-extractors/index.js +31 -0
- package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
- package/dist/core/ingestion/type-extractors/jvm.js +681 -0
- package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/php.js +549 -0
- package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/python.js +455 -0
- 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.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/rust.js +456 -0
- package/dist/core/ingestion/type-extractors/shared.d.ts +145 -0
- package/dist/core/ingestion/type-extractors/shared.js +810 -0
- package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/swift.js +137 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
- package/dist/core/ingestion/type-extractors/types.js +1 -0
- package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/typescript.js +494 -0
- package/dist/core/ingestion/utils.d.ts +138 -0
- package/dist/core/ingestion/utils.js +1290 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +122 -0
- package/dist/core/ingestion/workers/parse-worker.js +1126 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
- package/dist/core/ingestion/workers/worker-pool.js +128 -0
- package/dist/core/lbug/csv-generator.d.ts +33 -0
- package/dist/core/lbug/csv-generator.js +366 -0
- package/dist/core/lbug/lbug-adapter.d.ts +103 -0
- package/dist/core/lbug/lbug-adapter.js +769 -0
- package/dist/core/lbug/schema.d.ts +53 -0
- package/dist/core/lbug/schema.js +430 -0
- package/dist/core/search/bm25-index.d.ts +23 -0
- package/dist/core/search/bm25-index.js +96 -0
- package/dist/core/search/hybrid-search.d.ts +49 -0
- package/dist/core/search/hybrid-search.js +118 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +5 -0
- package/dist/core/tree-sitter/parser-loader.js +63 -0
- package/dist/core/wiki/generator.d.ts +120 -0
- package/dist/core/wiki/generator.js +939 -0
- package/dist/core/wiki/graph-queries.d.ts +80 -0
- package/dist/core/wiki/graph-queries.js +238 -0
- package/dist/core/wiki/html-viewer.d.ts +10 -0
- package/dist/core/wiki/html-viewer.js +297 -0
- package/dist/core/wiki/llm-client.d.ts +43 -0
- package/dist/core/wiki/llm-client.js +186 -0
- package/dist/core/wiki/prompts.d.ts +53 -0
- package/dist/core/wiki/prompts.js +174 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +3 -0
- package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
- package/dist/mcp/compatible-stdio-transport.js +200 -0
- package/dist/mcp/core/embedder.d.ts +27 -0
- package/dist/mcp/core/embedder.js +108 -0
- package/dist/mcp/core/lbug-adapter.d.ts +57 -0
- package/dist/mcp/core/lbug-adapter.js +455 -0
- package/dist/mcp/local/local-backend.d.ts +181 -0
- package/dist/mcp/local/local-backend.js +1722 -0
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +411 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +296 -0
- package/dist/mcp/staleness.d.ts +15 -0
- package/dist/mcp/staleness.js +29 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/mcp/tools.js +292 -0
- package/dist/server/api.d.ts +10 -0
- package/dist/server/api.js +344 -0
- package/dist/server/mcp-http.d.ts +13 -0
- package/dist/server/mcp-http.js +100 -0
- package/dist/storage/git.d.ts +6 -0
- package/dist/storage/git.js +35 -0
- package/dist/storage/repo-manager.d.ts +138 -0
- package/dist/storage/repo-manager.js +299 -0
- package/dist/types/pipeline.d.ts +32 -0
- package/dist/types/pipeline.js +18 -0
- package/dist/unreal/bridge.d.ts +4 -0
- package/dist/unreal/bridge.js +113 -0
- package/dist/unreal/config.d.ts +6 -0
- package/dist/unreal/config.js +55 -0
- package/dist/unreal/types.d.ts +105 -0
- package/dist/unreal/types.js +1 -0
- package/hooks/claude/gitnexus-hook.cjs +238 -0
- package/hooks/claude/pre-tool-use.sh +79 -0
- package/hooks/claude/session-start.sh +42 -0
- package/package.json +100 -0
- package/scripts/ensure-cli-executable.cjs +21 -0
- package/scripts/patch-tree-sitter-swift.cjs +74 -0
- package/scripts/setup-unreal-gitnexus.ps1 +191 -0
- package/skills/gitnexus-cli.md +82 -0
- package/skills/gitnexus-debugging.md +89 -0
- package/skills/gitnexus-exploring.md +78 -0
- package/skills/gitnexus-guide.md +64 -0
- package/skills/gitnexus-impact-analysis.md +97 -0
- package/skills/gitnexus-pr-review.md +163 -0
- package/skills/gitnexus-refactoring.md +121 -0
- package/vendor/leiden/index.cjs +355 -0
- package/vendor/leiden/utils.cjs +392 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
import { createIgnoreFilter } from '../../config/ignore-service.js';
|
|
5
|
+
const READ_CONCURRENCY = 32;
|
|
6
|
+
/** Skip files larger than 512KB — they're usually generated/vendored and crash tree-sitter */
|
|
7
|
+
const MAX_FILE_SIZE = 512 * 1024;
|
|
8
|
+
/**
|
|
9
|
+
* Phase 1: Scan repository — stat files to get paths + sizes, no content loaded.
|
|
10
|
+
* Memory: ~10MB for 100K files vs ~1GB+ with content.
|
|
11
|
+
*/
|
|
12
|
+
export const walkRepositoryPaths = async (repoPath, onProgress) => {
|
|
13
|
+
const ignoreFilter = await createIgnoreFilter(repoPath);
|
|
14
|
+
const filtered = await glob('**/*', {
|
|
15
|
+
cwd: repoPath,
|
|
16
|
+
nodir: true,
|
|
17
|
+
dot: false,
|
|
18
|
+
ignore: ignoreFilter,
|
|
19
|
+
});
|
|
20
|
+
const entries = [];
|
|
21
|
+
let processed = 0;
|
|
22
|
+
let skippedLarge = 0;
|
|
23
|
+
for (let start = 0; start < filtered.length; start += READ_CONCURRENCY) {
|
|
24
|
+
const batch = filtered.slice(start, start + READ_CONCURRENCY);
|
|
25
|
+
const results = await Promise.allSettled(batch.map(async (relativePath) => {
|
|
26
|
+
const fullPath = path.join(repoPath, relativePath);
|
|
27
|
+
const stat = await fs.stat(fullPath);
|
|
28
|
+
if (stat.size > MAX_FILE_SIZE) {
|
|
29
|
+
skippedLarge++;
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return { path: relativePath.replace(/\\/g, '/'), size: stat.size };
|
|
33
|
+
}));
|
|
34
|
+
for (const result of results) {
|
|
35
|
+
processed++;
|
|
36
|
+
if (result.status === 'fulfilled' && result.value !== null) {
|
|
37
|
+
entries.push(result.value);
|
|
38
|
+
onProgress?.(processed, filtered.length, result.value.path);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
onProgress?.(processed, filtered.length, batch[results.indexOf(result)]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (skippedLarge > 0) {
|
|
46
|
+
console.warn(` Skipped ${skippedLarge} large files (>${MAX_FILE_SIZE / 1024}KB, likely generated/vendored)`);
|
|
47
|
+
}
|
|
48
|
+
return entries;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Phase 2: Read file contents for a specific set of relative paths.
|
|
52
|
+
* Returns a Map for O(1) lookup. Silently skips files that fail to read.
|
|
53
|
+
*/
|
|
54
|
+
export const readFileContents = async (repoPath, relativePaths) => {
|
|
55
|
+
const contents = new Map();
|
|
56
|
+
for (let start = 0; start < relativePaths.length; start += READ_CONCURRENCY) {
|
|
57
|
+
const batch = relativePaths.slice(start, start + READ_CONCURRENCY);
|
|
58
|
+
const results = await Promise.allSettled(batch.map(async (relativePath) => {
|
|
59
|
+
const fullPath = path.join(repoPath, relativePath);
|
|
60
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
61
|
+
return { path: relativePath, content };
|
|
62
|
+
}));
|
|
63
|
+
for (const result of results) {
|
|
64
|
+
if (result.status === 'fulfilled') {
|
|
65
|
+
contents.set(result.value.path, result.value.content);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return contents;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Legacy API — scans and reads everything into memory.
|
|
73
|
+
* Used by sequential fallback path only.
|
|
74
|
+
*/
|
|
75
|
+
export const walkRepository = async (repoPath, onProgress) => {
|
|
76
|
+
const scanned = await walkRepositoryPaths(repoPath, onProgress);
|
|
77
|
+
const contents = await readFileContents(repoPath, scanned.map(f => f.path));
|
|
78
|
+
return scanned
|
|
79
|
+
.filter(f => contents.has(f.path))
|
|
80
|
+
.map(f => ({ path: f.path, content: contents.get(f.path) }));
|
|
81
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects frameworks from:
|
|
5
|
+
* 1) file path patterns
|
|
6
|
+
* 2) AST definition text (decorators/annotations/attributes)
|
|
7
|
+
* and provides entry point multipliers for process scoring.
|
|
8
|
+
*
|
|
9
|
+
* DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
|
|
10
|
+
* (no bonus, no penalty) - same behavior as before this feature.
|
|
11
|
+
*/
|
|
12
|
+
export interface FrameworkHint {
|
|
13
|
+
framework: string;
|
|
14
|
+
entryPointMultiplier: number;
|
|
15
|
+
reason: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Detect framework from file path patterns
|
|
19
|
+
*
|
|
20
|
+
* This provides entry point multipliers based on well-known framework conventions.
|
|
21
|
+
* Returns null if no framework pattern is detected (falls back to 1.0 multiplier).
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectFrameworkFromPath(filePath: string): FrameworkHint | null;
|
|
24
|
+
/**
|
|
25
|
+
* Patterns that indicate framework entry points within code definitions.
|
|
26
|
+
* These are matched against AST node text (class/method/function declaration text).
|
|
27
|
+
*/
|
|
28
|
+
export declare const FRAMEWORK_AST_PATTERNS: {
|
|
29
|
+
nestjs: string[];
|
|
30
|
+
express: string[];
|
|
31
|
+
fastapi: string[];
|
|
32
|
+
flask: string[];
|
|
33
|
+
spring: string[];
|
|
34
|
+
jaxrs: string[];
|
|
35
|
+
aspnet: string[];
|
|
36
|
+
signalr: string[];
|
|
37
|
+
blazor: string[];
|
|
38
|
+
efcore: string[];
|
|
39
|
+
'go-http': string[];
|
|
40
|
+
laravel: string[];
|
|
41
|
+
actix: string[];
|
|
42
|
+
axum: string[];
|
|
43
|
+
rocket: string[];
|
|
44
|
+
uikit: string[];
|
|
45
|
+
swiftui: string[];
|
|
46
|
+
combine: string[];
|
|
47
|
+
};
|
|
48
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
49
|
+
/**
|
|
50
|
+
* Detect framework entry points from AST definition text (decorators/annotations/attributes).
|
|
51
|
+
* Returns null if no known pattern is found.
|
|
52
|
+
* Note: callers should slice definitionText to ~300 chars since annotations appear at the start.
|
|
53
|
+
*/
|
|
54
|
+
export declare function detectFrameworkFromAST(language: SupportedLanguages, definitionText: string): FrameworkHint | null;
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects frameworks from:
|
|
5
|
+
* 1) file path patterns
|
|
6
|
+
* 2) AST definition text (decorators/annotations/attributes)
|
|
7
|
+
* and provides entry point multipliers for process scoring.
|
|
8
|
+
*
|
|
9
|
+
* DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
|
|
10
|
+
* (no bonus, no penalty) - same behavior as before this feature.
|
|
11
|
+
*/
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// PATH-BASED FRAMEWORK DETECTION
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Detect framework from file path patterns
|
|
17
|
+
*
|
|
18
|
+
* This provides entry point multipliers based on well-known framework conventions.
|
|
19
|
+
* Returns null if no framework pattern is detected (falls back to 1.0 multiplier).
|
|
20
|
+
*/
|
|
21
|
+
export function detectFrameworkFromPath(filePath) {
|
|
22
|
+
// Normalize path separators and ensure leading slash for consistent matching
|
|
23
|
+
let p = filePath.toLowerCase().replace(/\\/g, '/');
|
|
24
|
+
if (!p.startsWith('/')) {
|
|
25
|
+
p = '/' + p; // Add leading slash so patterns like '/app/' match 'app/...'
|
|
26
|
+
}
|
|
27
|
+
// ========== JAVASCRIPT / TYPESCRIPT FRAMEWORKS ==========
|
|
28
|
+
// Next.js - Pages Router (high confidence)
|
|
29
|
+
if (p.includes('/pages/') && !p.includes('/_') && !p.includes('/api/')) {
|
|
30
|
+
if (p.endsWith('.tsx') || p.endsWith('.ts') || p.endsWith('.jsx') || p.endsWith('.js')) {
|
|
31
|
+
return { framework: 'nextjs-pages', entryPointMultiplier: 3.0, reason: 'nextjs-page' };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Next.js - App Router (page.tsx files)
|
|
35
|
+
if (p.includes('/app/') && (p.endsWith('page.tsx') || p.endsWith('page.ts') ||
|
|
36
|
+
p.endsWith('page.jsx') || p.endsWith('page.js'))) {
|
|
37
|
+
return { framework: 'nextjs-app', entryPointMultiplier: 3.0, reason: 'nextjs-app-page' };
|
|
38
|
+
}
|
|
39
|
+
// Next.js - API Routes
|
|
40
|
+
if (p.includes('/pages/api/') || (p.includes('/app/') && p.includes('/api/') && p.endsWith('route.ts'))) {
|
|
41
|
+
return { framework: 'nextjs-api', entryPointMultiplier: 3.0, reason: 'nextjs-api-route' };
|
|
42
|
+
}
|
|
43
|
+
// Next.js - Layout files (moderate - they're entry-ish but not the main entry)
|
|
44
|
+
if (p.includes('/app/') && (p.endsWith('layout.tsx') || p.endsWith('layout.ts'))) {
|
|
45
|
+
return { framework: 'nextjs-app', entryPointMultiplier: 2.0, reason: 'nextjs-layout' };
|
|
46
|
+
}
|
|
47
|
+
// Express / Node.js routes
|
|
48
|
+
if (p.includes('/routes/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
|
|
49
|
+
return { framework: 'express', entryPointMultiplier: 2.5, reason: 'routes-folder' };
|
|
50
|
+
}
|
|
51
|
+
// Generic controllers (MVC pattern)
|
|
52
|
+
if (p.includes('/controllers/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
|
|
53
|
+
return { framework: 'mvc', entryPointMultiplier: 2.5, reason: 'controllers-folder' };
|
|
54
|
+
}
|
|
55
|
+
// Generic handlers
|
|
56
|
+
if (p.includes('/handlers/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
|
|
57
|
+
return { framework: 'handlers', entryPointMultiplier: 2.5, reason: 'handlers-folder' };
|
|
58
|
+
}
|
|
59
|
+
// React components (lower priority - not all are entry points)
|
|
60
|
+
if ((p.includes('/components/') || p.includes('/views/')) &&
|
|
61
|
+
(p.endsWith('.tsx') || p.endsWith('.jsx'))) {
|
|
62
|
+
// Only boost if PascalCase filename (likely a component, not util)
|
|
63
|
+
const fileName = p.split('/').pop() || '';
|
|
64
|
+
if (/^[A-Z]/.test(fileName)) {
|
|
65
|
+
return { framework: 'react', entryPointMultiplier: 1.5, reason: 'react-component' };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// ========== PYTHON FRAMEWORKS ==========
|
|
69
|
+
// Django views (high confidence)
|
|
70
|
+
if (p.endsWith('views.py')) {
|
|
71
|
+
return { framework: 'django', entryPointMultiplier: 3.0, reason: 'django-views' };
|
|
72
|
+
}
|
|
73
|
+
// Django URL configs
|
|
74
|
+
if (p.endsWith('urls.py')) {
|
|
75
|
+
return { framework: 'django', entryPointMultiplier: 2.0, reason: 'django-urls' };
|
|
76
|
+
}
|
|
77
|
+
// FastAPI / Flask routers
|
|
78
|
+
if ((p.includes('/routers/') || p.includes('/endpoints/') || p.includes('/routes/')) &&
|
|
79
|
+
p.endsWith('.py')) {
|
|
80
|
+
return { framework: 'fastapi', entryPointMultiplier: 2.5, reason: 'api-routers' };
|
|
81
|
+
}
|
|
82
|
+
// Python API folder
|
|
83
|
+
if (p.includes('/api/') && p.endsWith('.py') && !p.endsWith('__init__.py')) {
|
|
84
|
+
return { framework: 'python-api', entryPointMultiplier: 2.0, reason: 'api-folder' };
|
|
85
|
+
}
|
|
86
|
+
// ========== JAVA FRAMEWORKS ==========
|
|
87
|
+
// Spring Boot controllers
|
|
88
|
+
if ((p.includes('/controller/') || p.includes('/controllers/')) && p.endsWith('.java')) {
|
|
89
|
+
return { framework: 'spring', entryPointMultiplier: 3.0, reason: 'spring-controller' };
|
|
90
|
+
}
|
|
91
|
+
// Spring Boot - files ending in Controller.java
|
|
92
|
+
if (p.endsWith('controller.java')) {
|
|
93
|
+
return { framework: 'spring', entryPointMultiplier: 3.0, reason: 'spring-controller-file' };
|
|
94
|
+
}
|
|
95
|
+
// Java service layer (often entry points for business logic)
|
|
96
|
+
if ((p.includes('/service/') || p.includes('/services/')) && p.endsWith('.java')) {
|
|
97
|
+
return { framework: 'java-service', entryPointMultiplier: 1.8, reason: 'java-service' };
|
|
98
|
+
}
|
|
99
|
+
// ========== KOTLIN FRAMEWORKS ==========
|
|
100
|
+
// Spring Boot Kotlin controllers
|
|
101
|
+
if ((p.includes('/controller/') || p.includes('/controllers/')) && p.endsWith('.kt')) {
|
|
102
|
+
return { framework: 'spring-kotlin', entryPointMultiplier: 3.0, reason: 'spring-kotlin-controller' };
|
|
103
|
+
}
|
|
104
|
+
// Spring Boot - files ending in Controller.kt
|
|
105
|
+
if (p.endsWith('controller.kt')) {
|
|
106
|
+
return { framework: 'spring-kotlin', entryPointMultiplier: 3.0, reason: 'spring-kotlin-controller-file' };
|
|
107
|
+
}
|
|
108
|
+
// Ktor routes
|
|
109
|
+
if (p.includes('/routes/') && p.endsWith('.kt')) {
|
|
110
|
+
return { framework: 'ktor', entryPointMultiplier: 2.5, reason: 'ktor-routes' };
|
|
111
|
+
}
|
|
112
|
+
// Ktor plugins folder or Routing.kt files
|
|
113
|
+
if (p.includes('/plugins/') && p.endsWith('.kt')) {
|
|
114
|
+
return { framework: 'ktor', entryPointMultiplier: 2.0, reason: 'ktor-plugin' };
|
|
115
|
+
}
|
|
116
|
+
if (p.endsWith('routing.kt') || p.endsWith('routes.kt')) {
|
|
117
|
+
return { framework: 'ktor', entryPointMultiplier: 2.5, reason: 'ktor-routing-file' };
|
|
118
|
+
}
|
|
119
|
+
// Android Activities, Fragments
|
|
120
|
+
if ((p.includes('/activity/') || p.includes('/ui/')) && p.endsWith('.kt')) {
|
|
121
|
+
return { framework: 'android-kotlin', entryPointMultiplier: 2.5, reason: 'android-ui' };
|
|
122
|
+
}
|
|
123
|
+
if (p.endsWith('activity.kt') || p.endsWith('fragment.kt')) {
|
|
124
|
+
return { framework: 'android-kotlin', entryPointMultiplier: 2.5, reason: 'android-component' };
|
|
125
|
+
}
|
|
126
|
+
// Kotlin main entry point
|
|
127
|
+
if (p.endsWith('/main.kt')) {
|
|
128
|
+
return { framework: 'kotlin', entryPointMultiplier: 3.0, reason: 'kotlin-main' };
|
|
129
|
+
}
|
|
130
|
+
// Kotlin Application entry point (common naming)
|
|
131
|
+
if (p.endsWith('/application.kt')) {
|
|
132
|
+
return { framework: 'kotlin', entryPointMultiplier: 2.5, reason: 'kotlin-application' };
|
|
133
|
+
}
|
|
134
|
+
// ========== C# / .NET FRAMEWORKS ==========
|
|
135
|
+
// ASP.NET Controllers
|
|
136
|
+
if (p.includes('/controllers/') && p.endsWith('.cs')) {
|
|
137
|
+
return { framework: 'aspnet', entryPointMultiplier: 3.0, reason: 'aspnet-controller' };
|
|
138
|
+
}
|
|
139
|
+
// ASP.NET - files ending in Controller.cs
|
|
140
|
+
if (p.endsWith('controller.cs')) {
|
|
141
|
+
return { framework: 'aspnet', entryPointMultiplier: 3.0, reason: 'aspnet-controller-file' };
|
|
142
|
+
}
|
|
143
|
+
// ASP.NET Services
|
|
144
|
+
if ((p.includes('/services/') || p.includes('/service/')) && p.endsWith('.cs')) {
|
|
145
|
+
return { framework: 'aspnet', entryPointMultiplier: 1.8, reason: 'aspnet-service' };
|
|
146
|
+
}
|
|
147
|
+
// ASP.NET Middleware
|
|
148
|
+
if (p.includes('/middleware/') && p.endsWith('.cs')) {
|
|
149
|
+
return { framework: 'aspnet', entryPointMultiplier: 2.5, reason: 'aspnet-middleware' };
|
|
150
|
+
}
|
|
151
|
+
// SignalR Hubs
|
|
152
|
+
if (p.includes('/hubs/') && p.endsWith('.cs')) {
|
|
153
|
+
return { framework: 'signalr', entryPointMultiplier: 2.5, reason: 'signalr-hub' };
|
|
154
|
+
}
|
|
155
|
+
if (p.endsWith('hub.cs')) {
|
|
156
|
+
return { framework: 'signalr', entryPointMultiplier: 2.5, reason: 'signalr-hub-file' };
|
|
157
|
+
}
|
|
158
|
+
// Minimal API / Program.cs / Startup.cs
|
|
159
|
+
if (p.endsWith('/program.cs') || p.endsWith('/startup.cs')) {
|
|
160
|
+
return { framework: 'aspnet', entryPointMultiplier: 3.0, reason: 'aspnet-entry' };
|
|
161
|
+
}
|
|
162
|
+
// Background services / Hosted services
|
|
163
|
+
if ((p.includes('/backgroundservices/') || p.includes('/hostedservices/')) && p.endsWith('.cs')) {
|
|
164
|
+
return { framework: 'aspnet', entryPointMultiplier: 2.0, reason: 'aspnet-background-service' };
|
|
165
|
+
}
|
|
166
|
+
// Blazor pages
|
|
167
|
+
if (p.includes('/pages/') && p.endsWith('.razor')) {
|
|
168
|
+
return { framework: 'blazor', entryPointMultiplier: 2.5, reason: 'blazor-page' };
|
|
169
|
+
}
|
|
170
|
+
// ========== GO FRAMEWORKS ==========
|
|
171
|
+
// Go handlers
|
|
172
|
+
if ((p.includes('/handlers/') || p.includes('/handler/')) && p.endsWith('.go')) {
|
|
173
|
+
return { framework: 'go-http', entryPointMultiplier: 2.5, reason: 'go-handlers' };
|
|
174
|
+
}
|
|
175
|
+
// Go routes
|
|
176
|
+
if (p.includes('/routes/') && p.endsWith('.go')) {
|
|
177
|
+
return { framework: 'go-http', entryPointMultiplier: 2.5, reason: 'go-routes' };
|
|
178
|
+
}
|
|
179
|
+
// Go controllers
|
|
180
|
+
if (p.includes('/controllers/') && p.endsWith('.go')) {
|
|
181
|
+
return { framework: 'go-mvc', entryPointMultiplier: 2.5, reason: 'go-controller' };
|
|
182
|
+
}
|
|
183
|
+
// Go main.go files (THE entry point)
|
|
184
|
+
if (p.endsWith('/main.go') || p.endsWith('/cmd/') && p.endsWith('.go')) {
|
|
185
|
+
return { framework: 'go', entryPointMultiplier: 3.0, reason: 'go-main' };
|
|
186
|
+
}
|
|
187
|
+
// ========== RUST FRAMEWORKS ==========
|
|
188
|
+
// Rust handlers/routes
|
|
189
|
+
if ((p.includes('/handlers/') || p.includes('/routes/')) && p.endsWith('.rs')) {
|
|
190
|
+
return { framework: 'rust-web', entryPointMultiplier: 2.5, reason: 'rust-handlers' };
|
|
191
|
+
}
|
|
192
|
+
// Rust main.rs (THE entry point)
|
|
193
|
+
if (p.endsWith('/main.rs')) {
|
|
194
|
+
return { framework: 'rust', entryPointMultiplier: 3.0, reason: 'rust-main' };
|
|
195
|
+
}
|
|
196
|
+
// Rust bin folder (executables)
|
|
197
|
+
if (p.includes('/bin/') && p.endsWith('.rs')) {
|
|
198
|
+
return { framework: 'rust', entryPointMultiplier: 2.5, reason: 'rust-bin' };
|
|
199
|
+
}
|
|
200
|
+
// ========== C / C++ ==========
|
|
201
|
+
// C/C++ main files
|
|
202
|
+
if (p.endsWith('/main.c') || p.endsWith('/main.cpp') || p.endsWith('/main.cc')) {
|
|
203
|
+
return { framework: 'c-cpp', entryPointMultiplier: 3.0, reason: 'c-main' };
|
|
204
|
+
}
|
|
205
|
+
// C/C++ src folder entry points (if named specifically)
|
|
206
|
+
if ((p.includes('/src/') && (p.endsWith('/app.c') || p.endsWith('/app.cpp')))) {
|
|
207
|
+
return { framework: 'c-cpp', entryPointMultiplier: 2.5, reason: 'c-app' };
|
|
208
|
+
}
|
|
209
|
+
// ========== PHP / LARAVEL FRAMEWORKS ==========
|
|
210
|
+
// Laravel routes (highest - these ARE the entry point definitions)
|
|
211
|
+
if (p.includes('/routes/') && p.endsWith('.php')) {
|
|
212
|
+
return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-routes' };
|
|
213
|
+
}
|
|
214
|
+
// Laravel controllers (very high - receive HTTP requests)
|
|
215
|
+
if ((p.includes('/http/controllers/') || p.includes('/controllers/')) && p.endsWith('.php')) {
|
|
216
|
+
return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-controller' };
|
|
217
|
+
}
|
|
218
|
+
// Laravel controller by file name convention
|
|
219
|
+
if (p.endsWith('controller.php')) {
|
|
220
|
+
return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-controller-file' };
|
|
221
|
+
}
|
|
222
|
+
// Laravel console commands
|
|
223
|
+
if ((p.includes('/console/commands/') || p.includes('/commands/')) && p.endsWith('.php')) {
|
|
224
|
+
return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-command' };
|
|
225
|
+
}
|
|
226
|
+
// Laravel jobs (queue entry points)
|
|
227
|
+
if (p.includes('/jobs/') && p.endsWith('.php')) {
|
|
228
|
+
return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-job' };
|
|
229
|
+
}
|
|
230
|
+
// Laravel listeners (event-driven entry points)
|
|
231
|
+
if (p.includes('/listeners/') && p.endsWith('.php')) {
|
|
232
|
+
return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-listener' };
|
|
233
|
+
}
|
|
234
|
+
// Laravel middleware
|
|
235
|
+
if (p.includes('/http/middleware/') && p.endsWith('.php')) {
|
|
236
|
+
return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-middleware' };
|
|
237
|
+
}
|
|
238
|
+
// Laravel service providers
|
|
239
|
+
if (p.includes('/providers/') && p.endsWith('.php')) {
|
|
240
|
+
return { framework: 'laravel', entryPointMultiplier: 1.8, reason: 'laravel-provider' };
|
|
241
|
+
}
|
|
242
|
+
// Laravel policies
|
|
243
|
+
if (p.includes('/policies/') && p.endsWith('.php')) {
|
|
244
|
+
return { framework: 'laravel', entryPointMultiplier: 2.0, reason: 'laravel-policy' };
|
|
245
|
+
}
|
|
246
|
+
// Laravel models (important but not entry points per se)
|
|
247
|
+
if (p.includes('/models/') && p.endsWith('.php')) {
|
|
248
|
+
return { framework: 'laravel', entryPointMultiplier: 1.5, reason: 'laravel-model' };
|
|
249
|
+
}
|
|
250
|
+
// Laravel services (Service Repository pattern)
|
|
251
|
+
if (p.includes('/services/') && p.endsWith('.php')) {
|
|
252
|
+
return { framework: 'laravel', entryPointMultiplier: 1.8, reason: 'laravel-service' };
|
|
253
|
+
}
|
|
254
|
+
// Laravel repositories (Service Repository pattern)
|
|
255
|
+
if (p.includes('/repositories/') && p.endsWith('.php')) {
|
|
256
|
+
return { framework: 'laravel', entryPointMultiplier: 1.5, reason: 'laravel-repository' };
|
|
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
|
+
}
|
|
267
|
+
// ========== SWIFT / iOS ==========
|
|
268
|
+
// iOS App entry points (highest priority)
|
|
269
|
+
if (p.endsWith('/appdelegate.swift') || p.endsWith('/scenedelegate.swift') || p.endsWith('/app.swift')) {
|
|
270
|
+
return { framework: 'ios', entryPointMultiplier: 3.0, reason: 'ios-app-entry' };
|
|
271
|
+
}
|
|
272
|
+
// SwiftUI App entry (@main)
|
|
273
|
+
if (p.endsWith('app.swift') && p.includes('/sources/')) {
|
|
274
|
+
return { framework: 'swiftui', entryPointMultiplier: 3.0, reason: 'swiftui-app' };
|
|
275
|
+
}
|
|
276
|
+
// UIKit ViewControllers (high priority - screen entry points)
|
|
277
|
+
if ((p.includes('/viewcontrollers/') || p.includes('/controllers/') || p.includes('/screens/')) && p.endsWith('.swift')) {
|
|
278
|
+
return { framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-viewcontroller' };
|
|
279
|
+
}
|
|
280
|
+
// ViewController by filename convention
|
|
281
|
+
if (p.endsWith('viewcontroller.swift') || p.endsWith('vc.swift')) {
|
|
282
|
+
return { framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-viewcontroller-file' };
|
|
283
|
+
}
|
|
284
|
+
// Coordinator pattern (navigation entry points)
|
|
285
|
+
if (p.includes('/coordinators/') && p.endsWith('.swift')) {
|
|
286
|
+
return { framework: 'ios-coordinator', entryPointMultiplier: 2.5, reason: 'ios-coordinator' };
|
|
287
|
+
}
|
|
288
|
+
// Coordinator by filename
|
|
289
|
+
if (p.endsWith('coordinator.swift')) {
|
|
290
|
+
return { framework: 'ios-coordinator', entryPointMultiplier: 2.5, reason: 'ios-coordinator-file' };
|
|
291
|
+
}
|
|
292
|
+
// SwiftUI Views (moderate - reusable components)
|
|
293
|
+
if ((p.includes('/views/') || p.includes('/scenes/')) && p.endsWith('.swift')) {
|
|
294
|
+
return { framework: 'swiftui', entryPointMultiplier: 1.8, reason: 'swiftui-view' };
|
|
295
|
+
}
|
|
296
|
+
// Service layer
|
|
297
|
+
if (p.includes('/services/') && p.endsWith('.swift')) {
|
|
298
|
+
return { framework: 'ios-service', entryPointMultiplier: 1.8, reason: 'ios-service' };
|
|
299
|
+
}
|
|
300
|
+
// Router / navigation
|
|
301
|
+
if (p.includes('/router/') && p.endsWith('.swift')) {
|
|
302
|
+
return { framework: 'ios-router', entryPointMultiplier: 2.0, reason: 'ios-router' };
|
|
303
|
+
}
|
|
304
|
+
// ========== GENERIC PATTERNS ==========
|
|
305
|
+
// Any language: index files in API folders
|
|
306
|
+
if (p.includes('/api/') && (p.endsWith('/index.ts') || p.endsWith('/index.js') ||
|
|
307
|
+
p.endsWith('/__init__.py'))) {
|
|
308
|
+
return { framework: 'api', entryPointMultiplier: 1.8, reason: 'api-index' };
|
|
309
|
+
}
|
|
310
|
+
// No framework detected - return null for graceful fallback (1.0 multiplier)
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
// ============================================================================
|
|
314
|
+
// AST-BASED FRAMEWORK DETECTION
|
|
315
|
+
// ============================================================================
|
|
316
|
+
/**
|
|
317
|
+
* Patterns that indicate framework entry points within code definitions.
|
|
318
|
+
* These are matched against AST node text (class/method/function declaration text).
|
|
319
|
+
*/
|
|
320
|
+
export const FRAMEWORK_AST_PATTERNS = {
|
|
321
|
+
// JavaScript/TypeScript decorators
|
|
322
|
+
'nestjs': ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
|
|
323
|
+
'express': ['app.get', 'app.post', 'app.put', 'app.delete', 'router.get', 'router.post'],
|
|
324
|
+
// Python decorators
|
|
325
|
+
'fastapi': ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
|
|
326
|
+
'flask': ['@app.route', '@blueprint.route'],
|
|
327
|
+
// Java annotations
|
|
328
|
+
'spring': ['@RestController', '@Controller', '@GetMapping', '@PostMapping', '@RequestMapping'],
|
|
329
|
+
'jaxrs': ['@Path', '@GET', '@POST', '@PUT', '@DELETE'],
|
|
330
|
+
// C# attributes
|
|
331
|
+
'aspnet': ['[ApiController]', '[HttpGet]', '[HttpPost]', '[HttpPut]', '[HttpDelete]',
|
|
332
|
+
'[Route]', '[Authorize]', '[AllowAnonymous]'],
|
|
333
|
+
'signalr': ['[HubMethodName]', ': Hub', ': Hub<'],
|
|
334
|
+
'blazor': ['@page', '[Parameter]', '@inject'],
|
|
335
|
+
'efcore': ['DbContext', 'DbSet<', 'OnModelCreating'],
|
|
336
|
+
// Go patterns (function signatures)
|
|
337
|
+
'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP'],
|
|
338
|
+
// PHP/Laravel
|
|
339
|
+
'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete',
|
|
340
|
+
'Route::resource', 'Route::apiResource', '#[Route('],
|
|
341
|
+
// Rust macros
|
|
342
|
+
'actix': ['#[get', '#[post', '#[put', '#[delete'],
|
|
343
|
+
'axum': ['Router::new'],
|
|
344
|
+
'rocket': ['#[get', '#[post'],
|
|
345
|
+
// Swift/iOS
|
|
346
|
+
'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController'],
|
|
347
|
+
'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject'],
|
|
348
|
+
'combine': ['sink', 'assign', 'Publisher', 'Subscriber'],
|
|
349
|
+
};
|
|
350
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
351
|
+
const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
352
|
+
[SupportedLanguages.JavaScript]: [
|
|
353
|
+
{ framework: 'nestjs', entryPointMultiplier: 3.2, reason: 'nestjs-decorator', patterns: FRAMEWORK_AST_PATTERNS.nestjs },
|
|
354
|
+
],
|
|
355
|
+
[SupportedLanguages.TypeScript]: [
|
|
356
|
+
{ framework: 'nestjs', entryPointMultiplier: 3.2, reason: 'nestjs-decorator', patterns: FRAMEWORK_AST_PATTERNS.nestjs },
|
|
357
|
+
],
|
|
358
|
+
[SupportedLanguages.Python]: [
|
|
359
|
+
{ framework: 'fastapi', entryPointMultiplier: 3.0, reason: 'fastapi-decorator', patterns: FRAMEWORK_AST_PATTERNS.fastapi },
|
|
360
|
+
{ framework: 'flask', entryPointMultiplier: 2.8, reason: 'flask-decorator', patterns: FRAMEWORK_AST_PATTERNS.flask },
|
|
361
|
+
],
|
|
362
|
+
[SupportedLanguages.Java]: [
|
|
363
|
+
{ framework: 'spring', entryPointMultiplier: 3.2, reason: 'spring-annotation', patterns: FRAMEWORK_AST_PATTERNS.spring },
|
|
364
|
+
{ framework: 'jaxrs', entryPointMultiplier: 3.0, reason: 'jaxrs-annotation', patterns: FRAMEWORK_AST_PATTERNS.jaxrs },
|
|
365
|
+
],
|
|
366
|
+
[SupportedLanguages.Kotlin]: [
|
|
367
|
+
{ framework: 'spring-kotlin', entryPointMultiplier: 3.2, reason: 'spring-kotlin-annotation', patterns: FRAMEWORK_AST_PATTERNS.spring },
|
|
368
|
+
{ framework: 'jaxrs', entryPointMultiplier: 3.0, reason: 'jaxrs-annotation', patterns: FRAMEWORK_AST_PATTERNS.jaxrs },
|
|
369
|
+
{ framework: 'ktor', entryPointMultiplier: 2.8, reason: 'ktor-routing', patterns: ['routing', 'embeddedServer', 'Application.module'] },
|
|
370
|
+
{ framework: 'android-kotlin', entryPointMultiplier: 2.5, reason: 'android-annotation', patterns: ['@AndroidEntryPoint', 'AppCompatActivity', 'Fragment('] },
|
|
371
|
+
],
|
|
372
|
+
[SupportedLanguages.CSharp]: [
|
|
373
|
+
{ framework: 'aspnet', entryPointMultiplier: 3.2, reason: 'aspnet-attribute', patterns: FRAMEWORK_AST_PATTERNS.aspnet },
|
|
374
|
+
{ framework: 'signalr', entryPointMultiplier: 2.8, reason: 'signalr-attribute', patterns: FRAMEWORK_AST_PATTERNS.signalr },
|
|
375
|
+
{ framework: 'blazor', entryPointMultiplier: 2.5, reason: 'blazor-attribute', patterns: FRAMEWORK_AST_PATTERNS.blazor },
|
|
376
|
+
{ framework: 'efcore', entryPointMultiplier: 2.0, reason: 'efcore-pattern', patterns: FRAMEWORK_AST_PATTERNS.efcore },
|
|
377
|
+
],
|
|
378
|
+
[SupportedLanguages.PHP]: [
|
|
379
|
+
{ framework: 'laravel', entryPointMultiplier: 3.0, reason: 'php-route-attribute', patterns: FRAMEWORK_AST_PATTERNS.laravel },
|
|
380
|
+
],
|
|
381
|
+
};
|
|
382
|
+
/** Pre-lowercased patterns for O(1) pattern matching at runtime */
|
|
383
|
+
const AST_PATTERNS_LOWERED = Object.fromEntries(Object.entries(AST_FRAMEWORK_PATTERNS_BY_LANGUAGE).map(([lang, cfgs]) => [
|
|
384
|
+
lang,
|
|
385
|
+
cfgs.map(cfg => ({ ...cfg, patterns: cfg.patterns.map(p => p.toLowerCase()) })),
|
|
386
|
+
]));
|
|
387
|
+
/**
|
|
388
|
+
* Detect framework entry points from AST definition text (decorators/annotations/attributes).
|
|
389
|
+
* Returns null if no known pattern is found.
|
|
390
|
+
* Note: callers should slice definitionText to ~300 chars since annotations appear at the start.
|
|
391
|
+
*/
|
|
392
|
+
export function detectFrameworkFromAST(language, definitionText) {
|
|
393
|
+
if (!language || !definitionText)
|
|
394
|
+
return null;
|
|
395
|
+
const configs = AST_PATTERNS_LOWERED[language.toLowerCase()];
|
|
396
|
+
if (!configs || configs.length === 0)
|
|
397
|
+
return null;
|
|
398
|
+
const normalized = definitionText.toLowerCase();
|
|
399
|
+
for (const cfg of configs) {
|
|
400
|
+
for (const pattern of cfg.patterns) {
|
|
401
|
+
if (normalized.includes(pattern)) {
|
|
402
|
+
return {
|
|
403
|
+
framework: cfg.framework,
|
|
404
|
+
entryPointMultiplier: cfg.entryPointMultiplier,
|
|
405
|
+
reason: cfg.reason,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heritage Processor
|
|
3
|
+
*
|
|
4
|
+
* Extracts class inheritance relationships:
|
|
5
|
+
* - EXTENDS: Class extends another Class (TS, JS, Python, C#, C++)
|
|
6
|
+
* - IMPLEMENTS: Class implements an Interface (TS, C#, Java, Kotlin, PHP)
|
|
7
|
+
*
|
|
8
|
+
* Languages like C# use a single `base_list` for both class and interface parents.
|
|
9
|
+
* We resolve the correct edge type by checking the symbol table: if the parent is
|
|
10
|
+
* registered as an Interface, we emit IMPLEMENTS; otherwise EXTENDS. For unresolved
|
|
11
|
+
* external symbols, the fallback heuristic is language-gated:
|
|
12
|
+
* - C# / Java: apply the `I[A-Z]` naming convention (e.g. IDisposable → IMPLEMENTS)
|
|
13
|
+
* - Swift: default to IMPLEMENTS (protocol conformance is more common than class inheritance)
|
|
14
|
+
* - All other languages: default to EXTENDS
|
|
15
|
+
*/
|
|
16
|
+
import { KnowledgeGraph } from '../graph/types.js';
|
|
17
|
+
import { ASTCache } from './ast-cache.js';
|
|
18
|
+
import type { ExtractedHeritage } from './workers/parse-worker.js';
|
|
19
|
+
import type { ResolutionContext } from './resolution-context.js';
|
|
20
|
+
export declare const processHeritage: (graph: KnowledgeGraph, files: {
|
|
21
|
+
path: string;
|
|
22
|
+
content: string;
|
|
23
|
+
}[], astCache: ASTCache, ctx: ResolutionContext, onProgress?: (current: number, total: number) => void) => Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Fast path: resolve pre-extracted heritage from workers.
|
|
26
|
+
* No AST parsing — workers already extracted className + parentName + kind.
|
|
27
|
+
*/
|
|
28
|
+
export declare const processHeritageFromExtracted: (graph: KnowledgeGraph, extractedHeritage: ExtractedHeritage[], ctx: ResolutionContext, onProgress?: (current: number, total: number) => void) => Promise<void>;
|