@grafema/util 0.3.0-beta
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 +190 -0
- package/dist/api/GraphAPI.d.ts +87 -0
- package/dist/api/GraphAPI.d.ts.map +1 -0
- package/dist/api/GraphAPI.js +212 -0
- package/dist/api/GraphAPI.js.map +1 -0
- package/dist/api/GuaranteeAPI.d.ts +147 -0
- package/dist/api/GuaranteeAPI.d.ts.map +1 -0
- package/dist/api/GuaranteeAPI.js +290 -0
- package/dist/api/GuaranteeAPI.js.map +1 -0
- package/dist/config/ConfigLoader.d.ts +214 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +441 -0
- package/dist/config/ConfigLoader.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/CoverageAnalyzer.d.ts +65 -0
- package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
- package/dist/core/CoverageAnalyzer.js +199 -0
- package/dist/core/CoverageAnalyzer.js.map +1 -0
- package/dist/core/FileExplainer.d.ts +101 -0
- package/dist/core/FileExplainer.d.ts.map +1 -0
- package/dist/core/FileExplainer.js +140 -0
- package/dist/core/FileExplainer.js.map +1 -0
- package/dist/core/FileOverview.d.ts +124 -0
- package/dist/core/FileOverview.d.ts.map +1 -0
- package/dist/core/FileOverview.js +279 -0
- package/dist/core/FileOverview.js.map +1 -0
- package/dist/core/GrafemaUri.d.ts +66 -0
- package/dist/core/GrafemaUri.d.ts.map +1 -0
- package/dist/core/GrafemaUri.js +191 -0
- package/dist/core/GrafemaUri.js.map +1 -0
- package/dist/core/GraphBackend.d.ts +158 -0
- package/dist/core/GraphBackend.d.ts.map +1 -0
- package/dist/core/GraphBackend.js +85 -0
- package/dist/core/GraphBackend.js.map +1 -0
- package/dist/core/GraphFreshnessChecker.d.ts +33 -0
- package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
- package/dist/core/GraphFreshnessChecker.js +104 -0
- package/dist/core/GraphFreshnessChecker.js.map +1 -0
- package/dist/core/GuaranteeManager.d.ts +254 -0
- package/dist/core/GuaranteeManager.d.ts.map +1 -0
- package/dist/core/GuaranteeManager.js +447 -0
- package/dist/core/GuaranteeManager.js.map +1 -0
- package/dist/core/HashUtils.d.ts +24 -0
- package/dist/core/HashUtils.d.ts.map +1 -0
- package/dist/core/HashUtils.js +46 -0
- package/dist/core/HashUtils.js.map +1 -0
- package/dist/core/IncrementalReanalyzer.d.ts +33 -0
- package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
- package/dist/core/IncrementalReanalyzer.js +67 -0
- package/dist/core/IncrementalReanalyzer.js.map +1 -0
- package/dist/core/ResourceRegistry.d.ts +17 -0
- package/dist/core/ResourceRegistry.d.ts.map +1 -0
- package/dist/core/ResourceRegistry.js +32 -0
- package/dist/core/ResourceRegistry.js.map +1 -0
- package/dist/core/SemanticId.d.ts +159 -0
- package/dist/core/SemanticId.d.ts.map +1 -0
- package/dist/core/SemanticId.js +291 -0
- package/dist/core/SemanticId.js.map +1 -0
- package/dist/core/VersionManager.d.ts +166 -0
- package/dist/core/VersionManager.d.ts.map +1 -0
- package/dist/core/VersionManager.js +239 -0
- package/dist/core/VersionManager.js.map +1 -0
- package/dist/core/brandNodeInternal.d.ts +14 -0
- package/dist/core/brandNodeInternal.d.ts.map +1 -0
- package/dist/core/brandNodeInternal.js +4 -0
- package/dist/core/brandNodeInternal.js.map +1 -0
- package/dist/core/nodes/GuaranteeNode.d.ts +76 -0
- package/dist/core/nodes/GuaranteeNode.d.ts.map +1 -0
- package/dist/core/nodes/GuaranteeNode.js +118 -0
- package/dist/core/nodes/GuaranteeNode.js.map +1 -0
- package/dist/core/nodes/IssueNode.d.ts +73 -0
- package/dist/core/nodes/IssueNode.d.ts.map +1 -0
- package/dist/core/nodes/IssueNode.js +130 -0
- package/dist/core/nodes/IssueNode.js.map +1 -0
- package/dist/core/nodes/NodeKind.d.ts +104 -0
- package/dist/core/nodes/NodeKind.d.ts.map +1 -0
- package/dist/core/nodes/NodeKind.js +166 -0
- package/dist/core/nodes/NodeKind.js.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts +103 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.js +133 -0
- package/dist/diagnostics/DiagnosticCollector.js.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +122 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.js +300 -0
- package/dist/diagnostics/DiagnosticReporter.js.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.js +44 -0
- package/dist/diagnostics/DiagnosticWriter.js.map +1 -0
- package/dist/diagnostics/categories.d.ts +57 -0
- package/dist/diagnostics/categories.d.ts.map +1 -0
- package/dist/diagnostics/categories.js +71 -0
- package/dist/diagnostics/categories.js.map +1 -0
- package/dist/diagnostics/index.d.ts +17 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +15 -0
- package/dist/diagnostics/index.js.map +1 -0
- package/dist/errors/GrafemaError.d.ts +200 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -0
- package/dist/errors/GrafemaError.js +209 -0
- package/dist/errors/GrafemaError.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions/index.d.ts +8 -0
- package/dist/instructions/index.d.ts.map +1 -0
- package/dist/instructions/index.js +20 -0
- package/dist/instructions/index.js.map +1 -0
- package/dist/instructions/onboarding.md +133 -0
- package/dist/knowledge/KnowledgeBase.d.ts +113 -0
- package/dist/knowledge/KnowledgeBase.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeBase.js +420 -0
- package/dist/knowledge/KnowledgeBase.js.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts +59 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.js +160 -0
- package/dist/knowledge/SemanticAddressResolver.js.map +1 -0
- package/dist/knowledge/git-ingest.d.ts +58 -0
- package/dist/knowledge/git-ingest.d.ts.map +1 -0
- package/dist/knowledge/git-ingest.js +301 -0
- package/dist/knowledge/git-ingest.js.map +1 -0
- package/dist/knowledge/git-queries.d.ts +86 -0
- package/dist/knowledge/git-queries.d.ts.map +1 -0
- package/dist/knowledge/git-queries.js +177 -0
- package/dist/knowledge/git-queries.js.map +1 -0
- package/dist/knowledge/index.d.ts +14 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/index.js +10 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge/parser.d.ts +39 -0
- package/dist/knowledge/parser.d.ts.map +1 -0
- package/dist/knowledge/parser.js +292 -0
- package/dist/knowledge/parser.js.map +1 -0
- package/dist/knowledge/types.d.ts +133 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +8 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/logging/Logger.d.ts +98 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/Logger.js +274 -0
- package/dist/logging/Logger.js.map +1 -0
- package/dist/notation/archetypes.d.ts +36 -0
- package/dist/notation/archetypes.d.ts.map +1 -0
- package/dist/notation/archetypes.js +173 -0
- package/dist/notation/archetypes.js.map +1 -0
- package/dist/notation/fold.d.ts +25 -0
- package/dist/notation/fold.d.ts.map +1 -0
- package/dist/notation/fold.js +598 -0
- package/dist/notation/fold.js.map +1 -0
- package/dist/notation/index.d.ts +18 -0
- package/dist/notation/index.d.ts.map +1 -0
- package/dist/notation/index.js +16 -0
- package/dist/notation/index.js.map +1 -0
- package/dist/notation/lodExtractor.d.ts +32 -0
- package/dist/notation/lodExtractor.d.ts.map +1 -0
- package/dist/notation/lodExtractor.js +149 -0
- package/dist/notation/lodExtractor.js.map +1 -0
- package/dist/notation/nameShortener.d.ts +22 -0
- package/dist/notation/nameShortener.d.ts.map +1 -0
- package/dist/notation/nameShortener.js +24 -0
- package/dist/notation/nameShortener.js.map +1 -0
- package/dist/notation/perspectives.d.ts +11 -0
- package/dist/notation/perspectives.d.ts.map +1 -0
- package/dist/notation/perspectives.js +16 -0
- package/dist/notation/perspectives.js.map +1 -0
- package/dist/notation/renderer.d.ts +31 -0
- package/dist/notation/renderer.d.ts.map +1 -0
- package/dist/notation/renderer.js +315 -0
- package/dist/notation/renderer.js.map +1 -0
- package/dist/notation/traceRenderer.d.ts +39 -0
- package/dist/notation/traceRenderer.d.ts.map +1 -0
- package/dist/notation/traceRenderer.js +358 -0
- package/dist/notation/traceRenderer.js.map +1 -0
- package/dist/notation/types.d.ts +66 -0
- package/dist/notation/types.d.ts.map +1 -0
- package/dist/notation/types.js +10 -0
- package/dist/notation/types.js.map +1 -0
- package/dist/queries/NodeContext.d.ts +81 -0
- package/dist/queries/NodeContext.d.ts.map +1 -0
- package/dist/queries/NodeContext.js +196 -0
- package/dist/queries/NodeContext.js.map +1 -0
- package/dist/queries/findCallsInFunction.d.ts +62 -0
- package/dist/queries/findCallsInFunction.d.ts.map +1 -0
- package/dist/queries/findCallsInFunction.js +169 -0
- package/dist/queries/findCallsInFunction.js.map +1 -0
- package/dist/queries/findContainingFunction.d.ts +57 -0
- package/dist/queries/findContainingFunction.d.ts.map +1 -0
- package/dist/queries/findContainingFunction.js +91 -0
- package/dist/queries/findContainingFunction.js.map +1 -0
- package/dist/queries/index.d.ts +18 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +14 -0
- package/dist/queries/index.js.map +1 -0
- package/dist/queries/traceDataflow.d.ts +65 -0
- package/dist/queries/traceDataflow.d.ts.map +1 -0
- package/dist/queries/traceDataflow.js +754 -0
- package/dist/queries/traceDataflow.js.map +1 -0
- package/dist/queries/traceValues.d.ts +70 -0
- package/dist/queries/traceValues.d.ts.map +1 -0
- package/dist/queries/traceValues.js +373 -0
- package/dist/queries/traceValues.js.map +1 -0
- package/dist/queries/types.d.ts +166 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/dist/queries/types.js +10 -0
- package/dist/queries/types.js.map +1 -0
- package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
- package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/GraphSchemaExtractor.js +125 -0
- package/dist/schema/GraphSchemaExtractor.js.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.js +113 -0
- package/dist/schema/InterfaceSchemaExtractor.js.map +1 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +356 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.js +748 -0
- package/dist/storage/backends/RFDBServerBackend.js.map +1 -0
- package/dist/storage/backends/typeValidation.d.ts +47 -0
- package/dist/storage/backends/typeValidation.d.ts.map +1 -0
- package/dist/storage/backends/typeValidation.js +141 -0
- package/dist/storage/backends/typeValidation.js.map +1 -0
- package/dist/utils/findRfdbBinary.d.ts +67 -0
- package/dist/utils/findRfdbBinary.d.ts.map +1 -0
- package/dist/utils/findRfdbBinary.js +261 -0
- package/dist/utils/findRfdbBinary.js.map +1 -0
- package/dist/utils/lazyDownload.d.ts +43 -0
- package/dist/utils/lazyDownload.d.ts.map +1 -0
- package/dist/utils/lazyDownload.js +175 -0
- package/dist/utils/lazyDownload.js.map +1 -0
- package/dist/utils/moduleResolution.d.ts +134 -0
- package/dist/utils/moduleResolution.d.ts.map +1 -0
- package/dist/utils/moduleResolution.js +189 -0
- package/dist/utils/moduleResolution.js.map +1 -0
- package/dist/utils/resolveNodeFile.d.ts +13 -0
- package/dist/utils/resolveNodeFile.d.ts.map +1 -0
- package/dist/utils/resolveNodeFile.js +18 -0
- package/dist/utils/resolveNodeFile.js.map +1 -0
- package/dist/utils/startRfdbServer.d.ts +63 -0
- package/dist/utils/startRfdbServer.d.ts.map +1 -0
- package/dist/utils/startRfdbServer.js +142 -0
- package/dist/utils/startRfdbServer.js.map +1 -0
- package/dist/validation/PathValidator.d.ts +80 -0
- package/dist/validation/PathValidator.d.ts.map +1 -0
- package/dist/validation/PathValidator.js +252 -0
- package/dist/validation/PathValidator.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +26 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -0
- package/src/api/GraphAPI.ts +307 -0
- package/src/api/GuaranteeAPI.ts +402 -0
- package/src/config/ConfigLoader.ts +653 -0
- package/src/config/index.ts +13 -0
- package/src/core/CoverageAnalyzer.ts +243 -0
- package/src/core/FileExplainer.ts +179 -0
- package/src/core/FileOverview.ts +397 -0
- package/src/core/GrafemaUri.ts +216 -0
- package/src/core/GraphBackend.ts +266 -0
- package/src/core/GraphFreshnessChecker.ts +145 -0
- package/src/core/GuaranteeManager.ts +684 -0
- package/src/core/HashUtils.ts +48 -0
- package/src/core/IncrementalReanalyzer.ts +106 -0
- package/src/core/ResourceRegistry.ts +39 -0
- package/src/core/SemanticId.ts +423 -0
- package/src/core/VersionManager.ts +405 -0
- package/src/core/brandNodeInternal.ts +16 -0
- package/src/core/nodes/GuaranteeNode.ts +162 -0
- package/src/core/nodes/IssueNode.ts +177 -0
- package/src/core/nodes/NodeKind.ts +192 -0
- package/src/diagnostics/DiagnosticCollector.ts +170 -0
- package/src/diagnostics/DiagnosticReporter.ts +395 -0
- package/src/diagnostics/DiagnosticWriter.ts +50 -0
- package/src/diagnostics/categories.ts +104 -0
- package/src/diagnostics/index.ts +30 -0
- package/src/errors/GrafemaError.ts +297 -0
- package/src/index.ts +261 -0
- package/src/instructions/index.ts +21 -0
- package/src/instructions/onboarding.md +133 -0
- package/src/knowledge/KnowledgeBase.ts +486 -0
- package/src/knowledge/SemanticAddressResolver.ts +191 -0
- package/src/knowledge/git-ingest.ts +402 -0
- package/src/knowledge/git-queries.ts +269 -0
- package/src/knowledge/index.ts +29 -0
- package/src/knowledge/parser.ts +294 -0
- package/src/knowledge/types.ts +146 -0
- package/src/logging/Logger.ts +303 -0
- package/src/notation/archetypes.ts +189 -0
- package/src/notation/fold.ts +696 -0
- package/src/notation/index.ts +27 -0
- package/src/notation/lodExtractor.ts +177 -0
- package/src/notation/nameShortener.ts +24 -0
- package/src/notation/perspectives.ts +18 -0
- package/src/notation/renderer.ts +394 -0
- package/src/notation/traceRenderer.ts +458 -0
- package/src/notation/types.ts +79 -0
- package/src/queries/NodeContext.ts +280 -0
- package/src/queries/findCallsInFunction.ts +249 -0
- package/src/queries/findContainingFunction.ts +124 -0
- package/src/queries/index.ts +44 -0
- package/src/queries/traceDataflow.ts +838 -0
- package/src/queries/traceValues.ts +531 -0
- package/src/queries/types.ts +191 -0
- package/src/schema/GraphSchemaExtractor.ts +177 -0
- package/src/schema/InterfaceSchemaExtractor.ts +173 -0
- package/src/schema/index.ts +5 -0
- package/src/storage/backends/RFDBServerBackend.ts +895 -0
- package/src/storage/backends/typeValidation.ts +154 -0
- package/src/utils/findRfdbBinary.ts +288 -0
- package/src/utils/lazyDownload.ts +206 -0
- package/src/utils/moduleResolution.ts +271 -0
- package/src/utils/resolveNodeFile.ts +18 -0
- package/src/utils/startRfdbServer.ts +197 -0
- package/src/validation/PathValidator.ts +334 -0
- package/src/version.ts +28 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoverageAnalyzer - Calculates analysis coverage for a project
|
|
3
|
+
*
|
|
4
|
+
* Determines which files in a project have been analyzed and categorizes
|
|
5
|
+
* files into three groups:
|
|
6
|
+
* - Analyzed: Files that appear as MODULE nodes in the graph
|
|
7
|
+
* - Unsupported: Files with extensions that no indexer can handle
|
|
8
|
+
* - Unreachable: Files with supported extensions but not in the graph
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* const analyzer = new CoverageAnalyzer(graphBackend, '/path/to/project');
|
|
12
|
+
* const result = await analyzer.analyze();
|
|
13
|
+
*/
|
|
14
|
+
import { readdirSync, existsSync, lstatSync } from 'fs';
|
|
15
|
+
import { join, relative, extname } from 'path';
|
|
16
|
+
/**
|
|
17
|
+
* Supported file extensions by language
|
|
18
|
+
*/
|
|
19
|
+
const JS_SUPPORTED = ['.js', '.mjs', '.cjs', '.jsx', '.ts', '.tsx'];
|
|
20
|
+
const RUST_SUPPORTED = ['.rs'];
|
|
21
|
+
const SUPPORTED_EXTENSIONS = new Set([...JS_SUPPORTED, ...RUST_SUPPORTED]);
|
|
22
|
+
/**
|
|
23
|
+
* Known code file extensions (for scanning)
|
|
24
|
+
* Files with these extensions are considered source code
|
|
25
|
+
*/
|
|
26
|
+
const CODE_EXTENSIONS = new Set([
|
|
27
|
+
// Supported
|
|
28
|
+
...JS_SUPPORTED,
|
|
29
|
+
...RUST_SUPPORTED,
|
|
30
|
+
// Unsupported but tracked
|
|
31
|
+
'.go', '.kt', '.java', '.py', '.rb', '.php', '.c', '.cpp', '.h', '.hpp',
|
|
32
|
+
'.cs', '.swift', '.scala', '.sql', '.graphql', '.gql',
|
|
33
|
+
]);
|
|
34
|
+
/**
|
|
35
|
+
* Directories to always skip during scanning
|
|
36
|
+
*/
|
|
37
|
+
const SKIP_DIRS = new Set([
|
|
38
|
+
'node_modules',
|
|
39
|
+
'.git',
|
|
40
|
+
'.grafema',
|
|
41
|
+
'dist',
|
|
42
|
+
'build',
|
|
43
|
+
'out',
|
|
44
|
+
'coverage',
|
|
45
|
+
'.next',
|
|
46
|
+
'.nuxt',
|
|
47
|
+
'__pycache__',
|
|
48
|
+
'target', // Rust
|
|
49
|
+
'vendor',
|
|
50
|
+
]);
|
|
51
|
+
/**
|
|
52
|
+
* CoverageAnalyzer calculates what percentage of a codebase has been analyzed.
|
|
53
|
+
*/
|
|
54
|
+
export class CoverageAnalyzer {
|
|
55
|
+
graph;
|
|
56
|
+
projectPath;
|
|
57
|
+
constructor(graph, projectPath) {
|
|
58
|
+
this.graph = graph;
|
|
59
|
+
this.projectPath = projectPath;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Analyze the project and return coverage statistics
|
|
63
|
+
*/
|
|
64
|
+
async analyze() {
|
|
65
|
+
// Step 1: Get all MODULE nodes from the graph
|
|
66
|
+
const analyzedFiles = await this.getAnalyzedFiles();
|
|
67
|
+
const analyzedSet = new Set(analyzedFiles);
|
|
68
|
+
// Step 2: Scan project for all code files
|
|
69
|
+
const allCodeFiles = this.scanProjectFiles();
|
|
70
|
+
// Step 3: Categorize files
|
|
71
|
+
const unsupportedByExt = {};
|
|
72
|
+
const unreachableByExt = {};
|
|
73
|
+
const unreachableFiles = [];
|
|
74
|
+
for (const file of allCodeFiles) {
|
|
75
|
+
if (analyzedSet.has(file)) {
|
|
76
|
+
continue; // Already analyzed
|
|
77
|
+
}
|
|
78
|
+
const ext = extname(file).toLowerCase();
|
|
79
|
+
if (SUPPORTED_EXTENSIONS.has(ext)) {
|
|
80
|
+
// Supported but not in graph = unreachable
|
|
81
|
+
unreachableFiles.push(file);
|
|
82
|
+
if (!unreachableByExt[ext]) {
|
|
83
|
+
unreachableByExt[ext] = [];
|
|
84
|
+
}
|
|
85
|
+
unreachableByExt[ext].push(file);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Not supported = unsupported
|
|
89
|
+
if (!unsupportedByExt[ext]) {
|
|
90
|
+
unsupportedByExt[ext] = [];
|
|
91
|
+
}
|
|
92
|
+
unsupportedByExt[ext].push(file);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Calculate counts
|
|
96
|
+
const unsupportedCount = Object.values(unsupportedByExt)
|
|
97
|
+
.reduce((sum, files) => sum + files.length, 0);
|
|
98
|
+
const unreachableCount = unreachableFiles.length;
|
|
99
|
+
const analyzedCount = analyzedFiles.length;
|
|
100
|
+
const total = analyzedCount + unsupportedCount + unreachableCount;
|
|
101
|
+
// Calculate percentages (handle division by zero)
|
|
102
|
+
const percentages = {
|
|
103
|
+
analyzed: total > 0 ? Math.round((analyzedCount / total) * 100) : 0,
|
|
104
|
+
unsupported: total > 0 ? Math.round((unsupportedCount / total) * 100) : 0,
|
|
105
|
+
unreachable: total > 0 ? Math.round((unreachableCount / total) * 100) : 0,
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
projectPath: this.projectPath,
|
|
109
|
+
total,
|
|
110
|
+
analyzed: {
|
|
111
|
+
count: analyzedCount,
|
|
112
|
+
files: analyzedFiles,
|
|
113
|
+
},
|
|
114
|
+
unsupported: {
|
|
115
|
+
count: unsupportedCount,
|
|
116
|
+
byExtension: unsupportedByExt,
|
|
117
|
+
},
|
|
118
|
+
unreachable: {
|
|
119
|
+
count: unreachableCount,
|
|
120
|
+
files: unreachableFiles,
|
|
121
|
+
byExtension: unreachableByExt,
|
|
122
|
+
},
|
|
123
|
+
percentages,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get list of analyzed files from the graph (MODULE nodes)
|
|
128
|
+
*/
|
|
129
|
+
async getAnalyzedFiles() {
|
|
130
|
+
const files = [];
|
|
131
|
+
// Use queryNodes with type: 'MODULE'
|
|
132
|
+
for await (const node of this.graph.queryNodes({ type: 'MODULE' })) {
|
|
133
|
+
if (node.file) {
|
|
134
|
+
// Store relative path for consistency
|
|
135
|
+
const relativePath = node.file.startsWith(this.projectPath)
|
|
136
|
+
? relative(this.projectPath, node.file)
|
|
137
|
+
: node.file;
|
|
138
|
+
files.push(relativePath);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return files;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Scan project directory for all code files
|
|
145
|
+
* Respects common ignore patterns (node_modules, .git, etc.)
|
|
146
|
+
*/
|
|
147
|
+
scanProjectFiles() {
|
|
148
|
+
const files = [];
|
|
149
|
+
this.walkDirectory(this.projectPath, files);
|
|
150
|
+
return files;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Recursively walk directory and collect code files
|
|
154
|
+
*/
|
|
155
|
+
walkDirectory(dir, files, depth = 0) {
|
|
156
|
+
// Safety: limit recursion depth
|
|
157
|
+
if (depth > 20)
|
|
158
|
+
return;
|
|
159
|
+
if (!existsSync(dir))
|
|
160
|
+
return;
|
|
161
|
+
let entries;
|
|
162
|
+
try {
|
|
163
|
+
entries = readdirSync(dir);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return; // Skip directories we can't read
|
|
167
|
+
}
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
// Skip hidden files and directories
|
|
170
|
+
if (entry.startsWith('.'))
|
|
171
|
+
continue;
|
|
172
|
+
// Skip known non-source directories
|
|
173
|
+
if (SKIP_DIRS.has(entry))
|
|
174
|
+
continue;
|
|
175
|
+
const fullPath = join(dir, entry);
|
|
176
|
+
// Skip symlinks to avoid infinite loops
|
|
177
|
+
try {
|
|
178
|
+
const stat = lstatSync(fullPath);
|
|
179
|
+
if (stat.isSymbolicLink())
|
|
180
|
+
continue;
|
|
181
|
+
if (stat.isDirectory()) {
|
|
182
|
+
this.walkDirectory(fullPath, files, depth + 1);
|
|
183
|
+
}
|
|
184
|
+
else if (stat.isFile()) {
|
|
185
|
+
const ext = extname(entry).toLowerCase();
|
|
186
|
+
if (CODE_EXTENSIONS.has(ext)) {
|
|
187
|
+
// Store relative path
|
|
188
|
+
files.push(relative(this.projectPath, fullPath));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Skip files we can't stat
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=CoverageAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CoverageAnalyzer.js","sourceRoot":"","sources":["../../src/core/CoverageAnalyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileExplainer - Show what nodes exist in a file for discovery
|
|
3
|
+
*
|
|
4
|
+
* Purpose: Help users discover what nodes exist in the graph for a file,
|
|
5
|
+
* displaying semantic IDs so users can query them.
|
|
6
|
+
*
|
|
7
|
+
* This addresses the core UX problem: users can't find nodes because
|
|
8
|
+
* semantic IDs are opaque (e.g., "src/app.ts->fetchData->try#0->VARIABLE->response").
|
|
9
|
+
* This tool shows what's in the graph so users know what they can query.
|
|
10
|
+
*
|
|
11
|
+
* @see _tasks/REG-177/006-don-revised-plan.md for design rationale
|
|
12
|
+
*/
|
|
13
|
+
import type { GraphBackend, BaseNodeRecord } from '@grafema/types';
|
|
14
|
+
/**
|
|
15
|
+
* Result of explaining a file's graph contents
|
|
16
|
+
*/
|
|
17
|
+
export interface FileExplainResult {
|
|
18
|
+
/** The file path that was explained */
|
|
19
|
+
file: string;
|
|
20
|
+
/** Whether the file has been analyzed */
|
|
21
|
+
status: 'ANALYZED' | 'NOT_ANALYZED';
|
|
22
|
+
/** All nodes in the graph for this file, enhanced with context */
|
|
23
|
+
nodes: EnhancedNode[];
|
|
24
|
+
/** Node counts grouped by type */
|
|
25
|
+
byType: Record<string, number>;
|
|
26
|
+
/** Total number of nodes in the file */
|
|
27
|
+
totalCount: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A node record enhanced with scope context information.
|
|
31
|
+
*
|
|
32
|
+
* The context field provides human-readable information about
|
|
33
|
+
* where the node appears (e.g., "inside try block", "catch parameter").
|
|
34
|
+
*/
|
|
35
|
+
export interface EnhancedNode extends BaseNodeRecord {
|
|
36
|
+
/** Human-readable context about the node's scope */
|
|
37
|
+
context?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* FileExplainer class - explains what nodes exist in a file's graph.
|
|
41
|
+
*
|
|
42
|
+
* Use this when:
|
|
43
|
+
* - User can't find a variable/function they expect to be in the graph
|
|
44
|
+
* - User wants to understand what's been analyzed for a file
|
|
45
|
+
* - User needs semantic IDs to construct queries
|
|
46
|
+
*
|
|
47
|
+
* Example:
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const explainer = new FileExplainer(graphBackend);
|
|
50
|
+
* const result = await explainer.explain('src/app.ts');
|
|
51
|
+
*
|
|
52
|
+
* if (result.status === 'NOT_ANALYZED') {
|
|
53
|
+
* console.log('File not in graph. Run: grafema analyze');
|
|
54
|
+
* } else {
|
|
55
|
+
* for (const node of result.nodes) {
|
|
56
|
+
* console.log(`[${node.type}] ${node.name}`);
|
|
57
|
+
* console.log(` ID: ${node.id}`);
|
|
58
|
+
* if (node.context) {
|
|
59
|
+
* console.log(` Context: ${node.context}`);
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare class FileExplainer {
|
|
66
|
+
private graph;
|
|
67
|
+
constructor(graph: GraphBackend);
|
|
68
|
+
/**
|
|
69
|
+
* Explain what nodes exist in the graph for a file.
|
|
70
|
+
*
|
|
71
|
+
* @param filePath - The file path to explain (relative or absolute)
|
|
72
|
+
* @returns FileExplainResult with all nodes, grouped by type, with context
|
|
73
|
+
*/
|
|
74
|
+
explain(filePath: string): Promise<FileExplainResult>;
|
|
75
|
+
/**
|
|
76
|
+
* Query graph for all nodes in a file
|
|
77
|
+
*
|
|
78
|
+
* Note: The server-side file filter may not work correctly in all cases,
|
|
79
|
+
* so we also filter client-side to ensure only nodes from the requested file are returned.
|
|
80
|
+
*/
|
|
81
|
+
private getNodesForFile;
|
|
82
|
+
/**
|
|
83
|
+
* Group nodes by type, counting occurrences
|
|
84
|
+
*/
|
|
85
|
+
private groupByType;
|
|
86
|
+
/**
|
|
87
|
+
* Enhance nodes with human-readable scope context.
|
|
88
|
+
*
|
|
89
|
+
* Detects patterns in semantic IDs like:
|
|
90
|
+
* - "file->func->try#0->VARIABLE->x" → "inside try block"
|
|
91
|
+
* - "file->func->catch#0->VARIABLE->error" → "inside catch block"
|
|
92
|
+
*/
|
|
93
|
+
private enhanceWithContext;
|
|
94
|
+
/**
|
|
95
|
+
* Detect scope context from semantic ID patterns.
|
|
96
|
+
*
|
|
97
|
+
* Returns human-readable context string or undefined if no special scope.
|
|
98
|
+
*/
|
|
99
|
+
private detectScopeContext;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=FileExplainer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileExplainer.d.ts","sourceRoot":"","sources":["../../src/core/FileExplainer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAc,MAAM,gBAAgB,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;IACpC,kEAAkE;IAClE,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,aAAa;IACZ,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY;IAEvC;;;;;OAKG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA0B3D;;;;;OAKG;YACW,eAAe;IAc7B;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;CAQ3B"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileExplainer - Show what nodes exist in a file for discovery
|
|
3
|
+
*
|
|
4
|
+
* Purpose: Help users discover what nodes exist in the graph for a file,
|
|
5
|
+
* displaying semantic IDs so users can query them.
|
|
6
|
+
*
|
|
7
|
+
* This addresses the core UX problem: users can't find nodes because
|
|
8
|
+
* semantic IDs are opaque (e.g., "src/app.ts->fetchData->try#0->VARIABLE->response").
|
|
9
|
+
* This tool shows what's in the graph so users know what they can query.
|
|
10
|
+
*
|
|
11
|
+
* @see _tasks/REG-177/006-don-revised-plan.md for design rationale
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Scope patterns to detect from semantic IDs.
|
|
15
|
+
* Order matters - more specific patterns should come first.
|
|
16
|
+
*/
|
|
17
|
+
const SCOPE_PATTERNS = [
|
|
18
|
+
{ pattern: /->catch#\d+->/, context: 'inside catch block' },
|
|
19
|
+
{ pattern: /->try#\d+->/, context: 'inside try block' },
|
|
20
|
+
{ pattern: /->if#\d+->/, context: 'inside conditional' },
|
|
21
|
+
{ pattern: /->else#\d+->/, context: 'inside else block' },
|
|
22
|
+
{ pattern: /->for#\d+->/, context: 'inside loop' },
|
|
23
|
+
{ pattern: /->while#\d+->/, context: 'inside loop' },
|
|
24
|
+
{ pattern: /->switch#\d+->/, context: 'inside switch' },
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* FileExplainer class - explains what nodes exist in a file's graph.
|
|
28
|
+
*
|
|
29
|
+
* Use this when:
|
|
30
|
+
* - User can't find a variable/function they expect to be in the graph
|
|
31
|
+
* - User wants to understand what's been analyzed for a file
|
|
32
|
+
* - User needs semantic IDs to construct queries
|
|
33
|
+
*
|
|
34
|
+
* Example:
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const explainer = new FileExplainer(graphBackend);
|
|
37
|
+
* const result = await explainer.explain('src/app.ts');
|
|
38
|
+
*
|
|
39
|
+
* if (result.status === 'NOT_ANALYZED') {
|
|
40
|
+
* console.log('File not in graph. Run: grafema analyze');
|
|
41
|
+
* } else {
|
|
42
|
+
* for (const node of result.nodes) {
|
|
43
|
+
* console.log(`[${node.type}] ${node.name}`);
|
|
44
|
+
* console.log(` ID: ${node.id}`);
|
|
45
|
+
* if (node.context) {
|
|
46
|
+
* console.log(` Context: ${node.context}`);
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export class FileExplainer {
|
|
53
|
+
graph;
|
|
54
|
+
constructor(graph) {
|
|
55
|
+
this.graph = graph;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Explain what nodes exist in the graph for a file.
|
|
59
|
+
*
|
|
60
|
+
* @param filePath - The file path to explain (relative or absolute)
|
|
61
|
+
* @returns FileExplainResult with all nodes, grouped by type, with context
|
|
62
|
+
*/
|
|
63
|
+
async explain(filePath) {
|
|
64
|
+
// Query graph for all nodes in this file
|
|
65
|
+
const nodes = await this.getNodesForFile(filePath);
|
|
66
|
+
// Group by type
|
|
67
|
+
const byType = this.groupByType(nodes);
|
|
68
|
+
// Enhance with context from semantic ID parsing
|
|
69
|
+
const enhanced = this.enhanceWithContext(nodes);
|
|
70
|
+
// Sort nodes: by type, then by name
|
|
71
|
+
enhanced.sort((a, b) => {
|
|
72
|
+
const typeCompare = a.type.localeCompare(b.type);
|
|
73
|
+
if (typeCompare !== 0)
|
|
74
|
+
return typeCompare;
|
|
75
|
+
return (a.name || '').localeCompare(b.name || '');
|
|
76
|
+
});
|
|
77
|
+
return {
|
|
78
|
+
file: filePath,
|
|
79
|
+
status: nodes.length > 0 ? 'ANALYZED' : 'NOT_ANALYZED',
|
|
80
|
+
nodes: enhanced,
|
|
81
|
+
byType,
|
|
82
|
+
totalCount: nodes.length,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Query graph for all nodes in a file
|
|
87
|
+
*
|
|
88
|
+
* Note: The server-side file filter may not work correctly in all cases,
|
|
89
|
+
* so we also filter client-side to ensure only nodes from the requested file are returned.
|
|
90
|
+
*/
|
|
91
|
+
async getNodesForFile(filePath) {
|
|
92
|
+
const filter = { file: filePath };
|
|
93
|
+
const nodes = [];
|
|
94
|
+
for await (const node of this.graph.queryNodes(filter)) {
|
|
95
|
+
// Client-side filter as backup (server filter may not work correctly)
|
|
96
|
+
if (node.file === filePath) {
|
|
97
|
+
nodes.push(node);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return nodes;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Group nodes by type, counting occurrences
|
|
104
|
+
*/
|
|
105
|
+
groupByType(nodes) {
|
|
106
|
+
const counts = {};
|
|
107
|
+
for (const node of nodes) {
|
|
108
|
+
const type = node.type || 'UNKNOWN';
|
|
109
|
+
counts[type] = (counts[type] || 0) + 1;
|
|
110
|
+
}
|
|
111
|
+
return counts;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Enhance nodes with human-readable scope context.
|
|
115
|
+
*
|
|
116
|
+
* Detects patterns in semantic IDs like:
|
|
117
|
+
* - "file->func->try#0->VARIABLE->x" → "inside try block"
|
|
118
|
+
* - "file->func->catch#0->VARIABLE->error" → "inside catch block"
|
|
119
|
+
*/
|
|
120
|
+
enhanceWithContext(nodes) {
|
|
121
|
+
return nodes.map((node) => {
|
|
122
|
+
const context = this.detectScopeContext(node.id);
|
|
123
|
+
return context ? { ...node, context } : { ...node };
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Detect scope context from semantic ID patterns.
|
|
128
|
+
*
|
|
129
|
+
* Returns human-readable context string or undefined if no special scope.
|
|
130
|
+
*/
|
|
131
|
+
detectScopeContext(semanticId) {
|
|
132
|
+
for (const { pattern, context } of SCOPE_PATTERNS) {
|
|
133
|
+
if (pattern.test(semanticId)) {
|
|
134
|
+
return context;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=FileExplainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileExplainer.js","sourceRoot":"","sources":["../../src/core/FileExplainer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileOverview - Get a structured overview of all entities in a file.
|
|
3
|
+
*
|
|
4
|
+
* Purpose: Show what a file contains and how its parts relate to each other.
|
|
5
|
+
* Unlike FileExplainer (which lists ALL nodes flat), FileOverview shows only
|
|
6
|
+
* meaningful entities (functions, classes, variables) with their key relationships
|
|
7
|
+
* (calls, extends, assigned-from).
|
|
8
|
+
*
|
|
9
|
+
* Unlike the context command (which shows ONE node's full neighborhood),
|
|
10
|
+
* FileOverview shows ALL entities at file level with curated edges.
|
|
11
|
+
*
|
|
12
|
+
* Use this when:
|
|
13
|
+
* - AI agent needs to understand a file before diving deeper
|
|
14
|
+
* - User wants a table-of-contents of a file with relationships
|
|
15
|
+
* - Quick orientation before using get_context on specific nodes
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const overview = new FileOverview(backend);
|
|
20
|
+
* const result = await overview.getOverview('/abs/path/to/file.js');
|
|
21
|
+
* // result.functions[0].calls -> ["express", "Router"]
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @see REG-412
|
|
25
|
+
*/
|
|
26
|
+
import type { GraphBackend } from '@grafema/types';
|
|
27
|
+
export interface ImportInfo {
|
|
28
|
+
id: string;
|
|
29
|
+
source: string;
|
|
30
|
+
specifiers: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface ExportInfo {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
isDefault: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface FunctionOverview {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
line?: number;
|
|
41
|
+
async: boolean;
|
|
42
|
+
params?: string[];
|
|
43
|
+
calls: string[];
|
|
44
|
+
returnType?: string;
|
|
45
|
+
signature?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ClassOverview {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
line?: number;
|
|
51
|
+
extends?: string;
|
|
52
|
+
exported: boolean;
|
|
53
|
+
methods: FunctionOverview[];
|
|
54
|
+
}
|
|
55
|
+
export interface VariableOverview {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
line?: number;
|
|
59
|
+
kind: string;
|
|
60
|
+
assignedFrom?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface FileOverviewResult {
|
|
63
|
+
file: string;
|
|
64
|
+
status: 'ANALYZED' | 'NOT_ANALYZED';
|
|
65
|
+
imports: ImportInfo[];
|
|
66
|
+
exports: ExportInfo[];
|
|
67
|
+
classes: ClassOverview[];
|
|
68
|
+
functions: FunctionOverview[];
|
|
69
|
+
variables: VariableOverview[];
|
|
70
|
+
}
|
|
71
|
+
export declare class FileOverview {
|
|
72
|
+
private graph;
|
|
73
|
+
constructor(graph: GraphBackend);
|
|
74
|
+
/**
|
|
75
|
+
* Get structured overview of a file's entities and relationships.
|
|
76
|
+
*
|
|
77
|
+
* @param filePath - Absolute file path (after realpath resolution)
|
|
78
|
+
* @param options - Optional: { includeEdges: boolean }
|
|
79
|
+
* @returns FileOverviewResult
|
|
80
|
+
*/
|
|
81
|
+
getOverview(filePath: string, options?: {
|
|
82
|
+
includeEdges?: boolean;
|
|
83
|
+
}): Promise<FileOverviewResult>;
|
|
84
|
+
/**
|
|
85
|
+
* Find the MODULE node for the given file path.
|
|
86
|
+
* Complexity: O(1) - server-side filtered query
|
|
87
|
+
*/
|
|
88
|
+
private findModuleNode;
|
|
89
|
+
/**
|
|
90
|
+
* Get direct children of MODULE node that are "interesting" types.
|
|
91
|
+
* Complexity: O(C) where C = total CONTAINS edges from MODULE
|
|
92
|
+
*/
|
|
93
|
+
private getTopLevelEntities;
|
|
94
|
+
/**
|
|
95
|
+
* Build ImportInfo from an IMPORT node.
|
|
96
|
+
* Data read directly from node record fields.
|
|
97
|
+
* Complexity: O(1)
|
|
98
|
+
*/
|
|
99
|
+
private buildImportInfo;
|
|
100
|
+
/**
|
|
101
|
+
* Build ExportInfo from an EXPORT node.
|
|
102
|
+
* Data read directly from node record fields.
|
|
103
|
+
* Complexity: O(1)
|
|
104
|
+
*/
|
|
105
|
+
private buildExportInfo;
|
|
106
|
+
/**
|
|
107
|
+
* Build FunctionOverview from a FUNCTION node.
|
|
108
|
+
* When includeEdges=true, resolves calls via findCallsInFunction.
|
|
109
|
+
* Complexity: Without edges O(1), with edges O(S + C)
|
|
110
|
+
*/
|
|
111
|
+
private buildFunctionOverview;
|
|
112
|
+
/**
|
|
113
|
+
* Build ClassOverview from a CLASS node.
|
|
114
|
+
* Fetches EXTENDS edge and methods via CONTAINS.
|
|
115
|
+
* Complexity: Without edges O(M), with edges O(M * (S + C))
|
|
116
|
+
*/
|
|
117
|
+
private buildClassOverview;
|
|
118
|
+
/**
|
|
119
|
+
* Build VariableOverview from a VARIABLE or CONSTANT node.
|
|
120
|
+
* Complexity: Without edges O(1), with edges O(1)
|
|
121
|
+
*/
|
|
122
|
+
private buildVariableOverview;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=FileOverview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileOverview.d.ts","sourceRoot":"","sources":["../../src/core/FileOverview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA8B,MAAM,gBAAgB,CAAC;AAM/E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;IACpC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAaD,qBAAa,YAAY;IACX,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY;IAEvC;;;;;;OAMG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAO,GACvC,OAAO,CAAC,kBAAkB,CAAC;IAgE9B;;;OAGG;YACW,cAAc;IAY5B;;;OAGG;YACW,mBAAmB;IAkBjC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAQvB;;;;OAIG;YACW,qBAAqB;IA2DnC;;;;OAIG;YACW,kBAAkB;IAoDhC;;;OAGG;YACW,qBAAqB;CA0BpC"}
|