@colbymchenry/codegraph 0.6.6 → 0.7.2
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 +180 -502
- package/dist/bin/codegraph.d.ts +0 -5
- package/dist/bin/codegraph.d.ts.map +1 -1
- package/dist/bin/codegraph.js +217 -263
- package/dist/bin/codegraph.js.map +1 -1
- package/dist/bin/uninstall.d.ts +0 -1
- package/dist/bin/uninstall.d.ts.map +1 -1
- package/dist/bin/uninstall.js +3 -29
- package/dist/bin/uninstall.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -3
- package/dist/config.js.map +1 -1
- package/dist/context/index.d.ts +3 -5
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +497 -46
- package/dist/context/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +10 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +53 -0
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +244 -24
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +1 -16
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -7
- package/dist/errors.js.map +1 -1
- package/dist/extraction/dfm-extractor.d.ts +31 -0
- package/dist/extraction/dfm-extractor.d.ts.map +1 -0
- package/dist/extraction/dfm-extractor.js +151 -0
- package/dist/extraction/dfm-extractor.js.map +1 -0
- package/dist/extraction/grammars.d.ts +9 -1
- package/dist/extraction/grammars.d.ts.map +1 -1
- package/dist/extraction/grammars.js +34 -2
- package/dist/extraction/grammars.js.map +1 -1
- package/dist/extraction/index.d.ts +7 -1
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +373 -29
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/c-cpp.d.ts +4 -0
- package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
- package/dist/extraction/languages/c-cpp.js +126 -0
- package/dist/extraction/languages/c-cpp.js.map +1 -0
- package/dist/extraction/languages/csharp.d.ts +3 -0
- package/dist/extraction/languages/csharp.d.ts.map +1 -0
- package/dist/extraction/languages/csharp.js +72 -0
- package/dist/extraction/languages/csharp.js.map +1 -0
- package/dist/extraction/languages/dart.d.ts +3 -0
- package/dist/extraction/languages/dart.d.ts.map +1 -0
- package/dist/extraction/languages/dart.js +192 -0
- package/dist/extraction/languages/dart.js.map +1 -0
- package/dist/extraction/languages/go.d.ts +3 -0
- package/dist/extraction/languages/go.d.ts.map +1 -0
- package/dist/extraction/languages/go.js +58 -0
- package/dist/extraction/languages/go.js.map +1 -0
- package/dist/extraction/languages/index.d.ts +10 -0
- package/dist/extraction/languages/index.d.ts.map +1 -0
- package/dist/extraction/languages/index.js +43 -0
- package/dist/extraction/languages/index.js.map +1 -0
- package/dist/extraction/languages/java.d.ts +3 -0
- package/dist/extraction/languages/java.d.ts.map +1 -0
- package/dist/extraction/languages/java.js +64 -0
- package/dist/extraction/languages/java.js.map +1 -0
- package/dist/extraction/languages/javascript.d.ts +3 -0
- package/dist/extraction/languages/javascript.d.ts.map +1 -0
- package/dist/extraction/languages/javascript.js +90 -0
- package/dist/extraction/languages/javascript.js.map +1 -0
- package/dist/extraction/languages/kotlin.d.ts +3 -0
- package/dist/extraction/languages/kotlin.d.ts.map +1 -0
- package/dist/extraction/languages/kotlin.js +253 -0
- package/dist/extraction/languages/kotlin.js.map +1 -0
- package/dist/extraction/languages/pascal.d.ts +3 -0
- package/dist/extraction/languages/pascal.d.ts.map +1 -0
- package/dist/extraction/languages/pascal.js +66 -0
- package/dist/extraction/languages/pascal.js.map +1 -0
- package/dist/extraction/languages/php.d.ts +3 -0
- package/dist/extraction/languages/php.d.ts.map +1 -0
- package/dist/extraction/languages/php.js +107 -0
- package/dist/extraction/languages/php.js.map +1 -0
- package/dist/extraction/languages/python.d.ts +3 -0
- package/dist/extraction/languages/python.d.ts.map +1 -0
- package/dist/extraction/languages/python.js +56 -0
- package/dist/extraction/languages/python.js.map +1 -0
- package/dist/extraction/languages/ruby.d.ts +3 -0
- package/dist/extraction/languages/ruby.d.ts.map +1 -0
- package/dist/extraction/languages/ruby.js +114 -0
- package/dist/extraction/languages/ruby.js.map +1 -0
- package/dist/extraction/languages/rust.d.ts +3 -0
- package/dist/extraction/languages/rust.d.ts.map +1 -0
- package/dist/extraction/languages/rust.js +109 -0
- package/dist/extraction/languages/rust.js.map +1 -0
- package/dist/extraction/languages/swift.d.ts +3 -0
- package/dist/extraction/languages/swift.d.ts.map +1 -0
- package/dist/extraction/languages/swift.js +91 -0
- package/dist/extraction/languages/swift.js.map +1 -0
- package/dist/extraction/languages/typescript.d.ts +3 -0
- package/dist/extraction/languages/typescript.d.ts.map +1 -0
- package/dist/extraction/languages/typescript.js +129 -0
- package/dist/extraction/languages/typescript.js.map +1 -0
- package/dist/extraction/liquid-extractor.d.ts +52 -0
- package/dist/extraction/liquid-extractor.d.ts.map +1 -0
- package/dist/extraction/liquid-extractor.js +313 -0
- package/dist/extraction/liquid-extractor.js.map +1 -0
- package/dist/extraction/parse-worker.d.ts +8 -0
- package/dist/extraction/parse-worker.d.ts.map +1 -0
- package/dist/extraction/parse-worker.js +57 -0
- package/dist/extraction/parse-worker.js.map +1 -0
- package/dist/extraction/svelte-extractor.d.ts +47 -0
- package/dist/extraction/svelte-extractor.d.ts.map +1 -0
- package/dist/extraction/svelte-extractor.js +230 -0
- package/dist/extraction/svelte-extractor.js.map +1 -0
- package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
- package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
- package/dist/extraction/tree-sitter-helpers.js +103 -0
- package/dist/extraction/tree-sitter-helpers.js.map +1 -0
- package/dist/extraction/tree-sitter-types.d.ts +179 -0
- package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
- package/dist/extraction/tree-sitter-types.js +10 -0
- package/dist/extraction/tree-sitter-types.js.map +1 -0
- package/dist/extraction/tree-sitter.d.ts +67 -125
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +1052 -1860
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/graph/traversal.d.ts.map +1 -1
- package/dist/graph/traversal.js +20 -2
- package/dist/graph/traversal.js.map +1 -1
- package/dist/index.d.ts +29 -53
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -117
- package/dist/index.js.map +1 -1
- package/dist/installer/claude-md-template.d.ts +1 -1
- package/dist/installer/claude-md-template.d.ts.map +1 -1
- package/dist/installer/claude-md-template.js +15 -15
- package/dist/installer/config-writer.d.ts +2 -13
- package/dist/installer/config-writer.d.ts.map +1 -1
- package/dist/installer/config-writer.js +4 -87
- package/dist/installer/config-writer.js.map +1 -1
- package/dist/installer/index.d.ts +3 -4
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +118 -127
- package/dist/installer/index.js.map +1 -1
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +25 -4
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/tools.d.ts +33 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +405 -26
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/transport.d.ts.map +1 -1
- package/dist/mcp/transport.js +0 -2
- package/dist/mcp/transport.js.map +1 -1
- package/dist/resolution/frameworks/csharp.js +29 -84
- package/dist/resolution/frameworks/csharp.js.map +1 -1
- package/dist/resolution/frameworks/express.js +44 -48
- package/dist/resolution/frameworks/express.js.map +1 -1
- package/dist/resolution/frameworks/go.js +34 -70
- package/dist/resolution/frameworks/go.js.map +1 -1
- package/dist/resolution/frameworks/java.js +29 -87
- package/dist/resolution/frameworks/java.js.map +1 -1
- package/dist/resolution/frameworks/laravel.js +6 -6
- package/dist/resolution/frameworks/laravel.js.map +1 -1
- package/dist/resolution/frameworks/python.js +33 -98
- package/dist/resolution/frameworks/python.js.map +1 -1
- package/dist/resolution/frameworks/react.js +53 -76
- package/dist/resolution/frameworks/react.js.map +1 -1
- package/dist/resolution/frameworks/ruby.js +12 -24
- package/dist/resolution/frameworks/ruby.js.map +1 -1
- package/dist/resolution/frameworks/rust.js +26 -66
- package/dist/resolution/frameworks/rust.js.map +1 -1
- package/dist/resolution/frameworks/svelte.js +11 -31
- package/dist/resolution/frameworks/svelte.js.map +1 -1
- package/dist/resolution/frameworks/swift.js +42 -160
- package/dist/resolution/frameworks/swift.js.map +1 -1
- package/dist/resolution/index.d.ts +19 -6
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +300 -144
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/name-matcher.d.ts +5 -0
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +148 -8
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/resolution/types.d.ts +1 -1
- package/dist/resolution/types.d.ts.map +1 -1
- package/dist/search/query-utils.d.ts +26 -1
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +209 -9
- package/dist/search/query-utils.js.map +1 -1
- package/dist/sync/index.d.ts +2 -4
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +4 -3
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/watcher.d.ts +81 -0
- package/dist/sync/watcher.d.ts.map +1 -0
- package/dist/sync/watcher.js +184 -0
- package/dist/sync/watcher.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/dist/ui/shimmer-progress.d.ts +11 -0
- package/dist/ui/shimmer-progress.d.ts.map +1 -0
- package/dist/ui/shimmer-progress.js +90 -0
- package/dist/ui/shimmer-progress.js.map +1 -0
- package/dist/ui/shimmer-worker.d.ts +2 -0
- package/dist/ui/shimmer-worker.d.ts.map +1 -0
- package/dist/ui/shimmer-worker.js +112 -0
- package/dist/ui/shimmer-worker.js.map +1 -0
- package/dist/ui/types.d.ts +17 -0
- package/dist/ui/types.d.ts.map +1 -0
- package/dist/ui/types.js +3 -0
- package/dist/ui/types.js.map +1 -0
- package/dist/vectors/embedder.js +1 -1
- package/dist/vectors/embedder.js.map +1 -1
- package/dist/visualizer/server.d.ts.map +1 -1
- package/dist/visualizer/server.js +3 -11
- package/dist/visualizer/server.js.map +1 -1
- package/package.json +7 -12
- package/scripts/postinstall.js +0 -68
package/dist/resolution/index.js
CHANGED
|
@@ -45,13 +45,88 @@ exports.ReferenceResolver = void 0;
|
|
|
45
45
|
exports.createResolver = createResolver;
|
|
46
46
|
const fs = __importStar(require("fs"));
|
|
47
47
|
const path = __importStar(require("path"));
|
|
48
|
-
const sentry_1 = require("../sentry");
|
|
49
48
|
const name_matcher_1 = require("./name-matcher");
|
|
50
49
|
const import_resolver_1 = require("./import-resolver");
|
|
51
50
|
const frameworks_1 = require("./frameworks");
|
|
52
51
|
const errors_1 = require("../errors");
|
|
53
52
|
// Re-export types
|
|
54
53
|
__exportStar(require("./types"), exports);
|
|
54
|
+
// Pre-built Sets for O(1) built-in lookups (allocated once, shared across all instances)
|
|
55
|
+
const JS_BUILT_INS = new Set([
|
|
56
|
+
'console', 'window', 'document', 'global', 'process',
|
|
57
|
+
'Promise', 'Array', 'Object', 'String', 'Number', 'Boolean',
|
|
58
|
+
'Date', 'Math', 'JSON', 'RegExp', 'Error', 'Map', 'Set',
|
|
59
|
+
'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
|
|
60
|
+
'fetch', 'require', 'module', 'exports', '__dirname', '__filename',
|
|
61
|
+
]);
|
|
62
|
+
const REACT_HOOKS = new Set([
|
|
63
|
+
'useState', 'useEffect', 'useContext', 'useReducer', 'useCallback',
|
|
64
|
+
'useMemo', 'useRef', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
|
|
65
|
+
]);
|
|
66
|
+
const PYTHON_BUILT_INS = new Set([
|
|
67
|
+
'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
|
|
68
|
+
'open', 'input', 'type', 'isinstance', 'hasattr', 'getattr', 'setattr',
|
|
69
|
+
'super', 'self', 'cls', 'None', 'True', 'False',
|
|
70
|
+
]);
|
|
71
|
+
const PYTHON_BUILT_IN_TYPES = new Set([
|
|
72
|
+
'list', 'dict', 'set', 'tuple', 'str', 'int', 'float', 'bool',
|
|
73
|
+
'bytes', 'bytearray', 'frozenset', 'object', 'super',
|
|
74
|
+
]);
|
|
75
|
+
const PYTHON_BUILT_IN_METHODS = new Set([
|
|
76
|
+
'append', 'extend', 'insert', 'remove', 'pop', 'clear', 'sort', 'reverse', 'copy',
|
|
77
|
+
'update', 'keys', 'values', 'items', 'get',
|
|
78
|
+
'add', 'discard', 'union', 'intersection', 'difference',
|
|
79
|
+
'split', 'join', 'strip', 'lstrip', 'rstrip', 'replace', 'lower', 'upper',
|
|
80
|
+
'startswith', 'endswith', 'find', 'index', 'count', 'encode', 'decode',
|
|
81
|
+
'format', 'isdigit', 'isalpha', 'isalnum',
|
|
82
|
+
'read', 'write', 'readline', 'readlines', 'close', 'flush', 'seek',
|
|
83
|
+
]);
|
|
84
|
+
const GO_STDLIB_PACKAGES = new Set([
|
|
85
|
+
'fmt', 'os', 'io', 'net', 'http', 'log', 'math', 'sort', 'sync',
|
|
86
|
+
'time', 'path', 'bytes', 'strings', 'strconv', 'errors', 'context',
|
|
87
|
+
'json', 'xml', 'csv', 'html', 'template', 'regexp', 'reflect',
|
|
88
|
+
'runtime', 'testing', 'flag', 'bufio', 'crypto', 'encoding',
|
|
89
|
+
'filepath', 'hash', 'mime', 'rand', 'signal', 'sql', 'syscall',
|
|
90
|
+
'unicode', 'unsafe', 'atomic', 'binary', 'debug', 'exec', 'heap',
|
|
91
|
+
'ring', 'scanner', 'tar', 'zip', 'gzip', 'zlib', 'tls', 'url',
|
|
92
|
+
'user', 'pprof', 'trace', 'ast', 'build', 'parser', 'printer',
|
|
93
|
+
'token', 'types', 'cgo', 'plugin', 'race', 'ioutil',
|
|
94
|
+
// Kubernetes-common stdlib aliases
|
|
95
|
+
'utilruntime', 'utilwait', 'utilnet',
|
|
96
|
+
]);
|
|
97
|
+
const GO_BUILT_INS = new Set([
|
|
98
|
+
'make', 'new', 'len', 'cap', 'append', 'copy', 'delete', 'close',
|
|
99
|
+
'panic', 'recover', 'print', 'println', 'complex', 'real', 'imag',
|
|
100
|
+
'error', 'nil', 'true', 'false', 'iota',
|
|
101
|
+
'int', 'int8', 'int16', 'int32', 'int64',
|
|
102
|
+
'uint', 'uint8', 'uint16', 'uint32', 'uint64', 'uintptr',
|
|
103
|
+
'float32', 'float64', 'complex64', 'complex128',
|
|
104
|
+
'string', 'bool', 'byte', 'rune', 'any',
|
|
105
|
+
]);
|
|
106
|
+
const PASCAL_UNIT_PREFIXES = [
|
|
107
|
+
'System.', 'Winapi.', 'Vcl.', 'Fmx.', 'Data.', 'Datasnap.',
|
|
108
|
+
'Soap.', 'Xml.', 'Web.', 'REST.', 'FireDAC.', 'IBX.',
|
|
109
|
+
'IdHTTP', 'IdTCP', 'IdSSL',
|
|
110
|
+
];
|
|
111
|
+
const PASCAL_BUILT_INS = new Set([
|
|
112
|
+
'System', 'SysUtils', 'Classes', 'Types', 'Variants', 'StrUtils',
|
|
113
|
+
'Math', 'DateUtils', 'IOUtils', 'Generics.Collections', 'Generics.Defaults',
|
|
114
|
+
'Rtti', 'TypInfo', 'SyncObjs', 'RegularExpressions',
|
|
115
|
+
'SysInit', 'Windows', 'Messages', 'Graphics', 'Controls', 'Forms',
|
|
116
|
+
'Dialogs', 'StdCtrls', 'ExtCtrls', 'ComCtrls', 'Menus', 'ActnList',
|
|
117
|
+
'WriteLn', 'Write', 'ReadLn', 'Read', 'Inc', 'Dec', 'Ord', 'Chr',
|
|
118
|
+
'Length', 'SetLength', 'High', 'Low', 'Assigned', 'FreeAndNil',
|
|
119
|
+
'Format', 'IntToStr', 'StrToInt', 'FloatToStr', 'StrToFloat',
|
|
120
|
+
'Trim', 'UpperCase', 'LowerCase', 'Pos', 'Copy', 'Delete', 'Insert',
|
|
121
|
+
'Now', 'Date', 'Time', 'DateToStr', 'StrToDate',
|
|
122
|
+
'Raise', 'Exit', 'Break', 'Continue', 'Abort',
|
|
123
|
+
'True', 'False', 'nil', 'Self', 'Result',
|
|
124
|
+
'Create', 'Destroy', 'Free',
|
|
125
|
+
'TObject', 'TComponent', 'TPersistent', 'TInterfacedObject',
|
|
126
|
+
'TList', 'TStringList', 'TStrings', 'TStream', 'TMemoryStream', 'TFileStream',
|
|
127
|
+
'Exception', 'EAbort', 'EConvertError', 'EAccessViolation',
|
|
128
|
+
'IInterface', 'IUnknown',
|
|
129
|
+
]);
|
|
55
130
|
/**
|
|
56
131
|
* Reference Resolver
|
|
57
132
|
*
|
|
@@ -62,14 +137,13 @@ class ReferenceResolver {
|
|
|
62
137
|
queries;
|
|
63
138
|
context;
|
|
64
139
|
frameworks = [];
|
|
65
|
-
nodeCache = new Map();
|
|
66
|
-
fileCache = new Map();
|
|
67
|
-
nameCache = new Map();
|
|
68
|
-
qualifiedNameCache = new Map();
|
|
69
|
-
kindCache = new Map();
|
|
70
|
-
nodeByIdCache = new Map();
|
|
71
|
-
lowerNameCache = new Map();
|
|
140
|
+
nodeCache = new Map(); // per-file node cache (bounded)
|
|
141
|
+
fileCache = new Map(); // per-file content cache (bounded)
|
|
72
142
|
importMappingCache = new Map();
|
|
143
|
+
nameCache = new Map(); // name → nodes cache
|
|
144
|
+
lowerNameCache = new Map(); // lower(name) → nodes cache
|
|
145
|
+
qualifiedNameCache = new Map(); // qualified_name → nodes cache
|
|
146
|
+
knownNames = null; // all known symbol names for fast pre-filtering
|
|
73
147
|
knownFiles = null;
|
|
74
148
|
cachesWarmed = false;
|
|
75
149
|
constructor(projectRoot, queries) {
|
|
@@ -85,52 +159,18 @@ class ReferenceResolver {
|
|
|
85
159
|
this.clearCaches();
|
|
86
160
|
}
|
|
87
161
|
/**
|
|
88
|
-
* Pre-
|
|
89
|
-
*
|
|
162
|
+
* Pre-build lightweight caches for resolution.
|
|
163
|
+
* Node lookups are now handled by indexed SQLite queries instead of
|
|
164
|
+
* loading all nodes into memory (which caused OOM on large codebases).
|
|
165
|
+
* We cache the set of known symbol names for fast pre-filtering.
|
|
90
166
|
*/
|
|
91
167
|
warmCaches() {
|
|
92
168
|
if (this.cachesWarmed)
|
|
93
169
|
return;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (byName) {
|
|
99
|
-
byName.push(node);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
this.nameCache.set(node.name, [node]);
|
|
103
|
-
}
|
|
104
|
-
// Index by qualified name
|
|
105
|
-
const byQName = this.qualifiedNameCache.get(node.qualifiedName);
|
|
106
|
-
if (byQName) {
|
|
107
|
-
byQName.push(node);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
this.qualifiedNameCache.set(node.qualifiedName, [node]);
|
|
111
|
-
}
|
|
112
|
-
// Index by kind
|
|
113
|
-
const byKind = this.kindCache.get(node.kind);
|
|
114
|
-
if (byKind) {
|
|
115
|
-
byKind.push(node);
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
this.kindCache.set(node.kind, [node]);
|
|
119
|
-
}
|
|
120
|
-
// Index by ID
|
|
121
|
-
this.nodeByIdCache.set(node.id, node);
|
|
122
|
-
// Index by lowercase name (for fuzzy matching)
|
|
123
|
-
const lowerName = node.name.toLowerCase();
|
|
124
|
-
const byLower = this.lowerNameCache.get(lowerName);
|
|
125
|
-
if (byLower) {
|
|
126
|
-
byLower.push(node);
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
this.lowerNameCache.set(lowerName, [node]);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// Pre-build known files set from index
|
|
133
|
-
this.knownFiles = new Set(this.queries.getAllFiles().map((f) => f.path));
|
|
170
|
+
// Only cache the set of known file paths (lightweight string set)
|
|
171
|
+
this.knownFiles = new Set(this.queries.getAllFilePaths());
|
|
172
|
+
// Cache all distinct symbol names for fast pre-filtering (just strings, not full nodes)
|
|
173
|
+
this.knownNames = new Set(this.queries.getAllNodeNames());
|
|
134
174
|
this.cachesWarmed = true;
|
|
135
175
|
}
|
|
136
176
|
/**
|
|
@@ -139,12 +179,11 @@ class ReferenceResolver {
|
|
|
139
179
|
clearCaches() {
|
|
140
180
|
this.nodeCache.clear();
|
|
141
181
|
this.fileCache.clear();
|
|
182
|
+
this.importMappingCache.clear();
|
|
142
183
|
this.nameCache.clear();
|
|
143
|
-
this.qualifiedNameCache.clear();
|
|
144
|
-
this.kindCache.clear();
|
|
145
|
-
this.nodeByIdCache.clear();
|
|
146
184
|
this.lowerNameCache.clear();
|
|
147
|
-
this.
|
|
185
|
+
this.qualifiedNameCache.clear();
|
|
186
|
+
this.knownNames = null;
|
|
148
187
|
this.knownFiles = null;
|
|
149
188
|
this.cachesWarmed = false;
|
|
150
189
|
}
|
|
@@ -160,26 +199,22 @@ class ReferenceResolver {
|
|
|
160
199
|
return this.nodeCache.get(filePath);
|
|
161
200
|
},
|
|
162
201
|
getNodesByName: (name) => {
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
return
|
|
166
|
-
|
|
167
|
-
|
|
202
|
+
const cached = this.nameCache.get(name);
|
|
203
|
+
if (cached !== undefined)
|
|
204
|
+
return cached;
|
|
205
|
+
const result = this.queries.getNodesByName(name);
|
|
206
|
+
this.nameCache.set(name, result);
|
|
207
|
+
return result;
|
|
168
208
|
},
|
|
169
209
|
getNodesByQualifiedName: (qualifiedName) => {
|
|
170
|
-
|
|
171
|
-
if (
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
.filter((r) => r.node.qualifiedName === qualifiedName)
|
|
177
|
-
.map((r) => r.node);
|
|
210
|
+
const cached = this.qualifiedNameCache.get(qualifiedName);
|
|
211
|
+
if (cached !== undefined)
|
|
212
|
+
return cached;
|
|
213
|
+
const result = this.queries.getNodesByQualifiedNameExact(qualifiedName);
|
|
214
|
+
this.qualifiedNameCache.set(qualifiedName, result);
|
|
215
|
+
return result;
|
|
178
216
|
},
|
|
179
217
|
getNodesByKind: (kind) => {
|
|
180
|
-
if (this.cachesWarmed) {
|
|
181
|
-
return this.kindCache.get(kind) ?? [];
|
|
182
|
-
}
|
|
183
218
|
return this.queries.getNodesByKind(kind);
|
|
184
219
|
},
|
|
185
220
|
fileExists: (filePath) => {
|
|
@@ -196,7 +231,6 @@ class ReferenceResolver {
|
|
|
196
231
|
return fs.existsSync(fullPath);
|
|
197
232
|
}
|
|
198
233
|
catch (error) {
|
|
199
|
-
(0, sentry_1.captureException)(error, { operation: 'resolution-file-exists', filePath });
|
|
200
234
|
(0, errors_1.logDebug)('Error checking file existence', { filePath, error: String(error) });
|
|
201
235
|
return false;
|
|
202
236
|
}
|
|
@@ -212,7 +246,6 @@ class ReferenceResolver {
|
|
|
212
246
|
return content;
|
|
213
247
|
}
|
|
214
248
|
catch (error) {
|
|
215
|
-
(0, sentry_1.captureException)(error, { operation: 'resolution-read-file', filePath });
|
|
216
249
|
(0, errors_1.logDebug)('Failed to read file for resolution', { filePath, error: String(error) });
|
|
217
250
|
this.fileCache.set(filePath, null);
|
|
218
251
|
return null;
|
|
@@ -220,14 +253,15 @@ class ReferenceResolver {
|
|
|
220
253
|
},
|
|
221
254
|
getProjectRoot: () => this.projectRoot,
|
|
222
255
|
getAllFiles: () => {
|
|
223
|
-
return this.queries.
|
|
256
|
+
return this.queries.getAllFilePaths();
|
|
224
257
|
},
|
|
225
258
|
getNodesByLowerName: (lowerName) => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
259
|
+
const cached = this.lowerNameCache.get(lowerName);
|
|
260
|
+
if (cached !== undefined)
|
|
261
|
+
return cached;
|
|
262
|
+
const result = this.queries.getNodesByLowerName(lowerName);
|
|
263
|
+
this.lowerNameCache.set(lowerName, result);
|
|
264
|
+
return result;
|
|
231
265
|
},
|
|
232
266
|
getImportMappings: (filePath, language) => {
|
|
233
267
|
const cacheKey = filePath;
|
|
@@ -300,6 +334,45 @@ class ReferenceResolver {
|
|
|
300
334
|
},
|
|
301
335
|
};
|
|
302
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* Check if a reference name has any possible match in the codebase.
|
|
339
|
+
* Uses the pre-built knownNames set to skip expensive resolution
|
|
340
|
+
* for names that definitely don't exist as symbols.
|
|
341
|
+
*/
|
|
342
|
+
hasAnyPossibleMatch(name) {
|
|
343
|
+
if (!this.knownNames)
|
|
344
|
+
return true; // no pre-filter available
|
|
345
|
+
// Direct name match
|
|
346
|
+
if (this.knownNames.has(name))
|
|
347
|
+
return true;
|
|
348
|
+
// For qualified names like "obj.method" or "Class::method", check the parts
|
|
349
|
+
const dotIdx = name.indexOf('.');
|
|
350
|
+
if (dotIdx > 0) {
|
|
351
|
+
const receiver = name.substring(0, dotIdx);
|
|
352
|
+
const member = name.substring(dotIdx + 1);
|
|
353
|
+
if (this.knownNames.has(receiver) || this.knownNames.has(member))
|
|
354
|
+
return true;
|
|
355
|
+
// Also check capitalized receiver (instance-method resolution)
|
|
356
|
+
const capitalized = receiver.charAt(0).toUpperCase() + receiver.slice(1);
|
|
357
|
+
if (this.knownNames.has(capitalized))
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
const colonIdx = name.indexOf('::');
|
|
361
|
+
if (colonIdx > 0) {
|
|
362
|
+
const receiver = name.substring(0, colonIdx);
|
|
363
|
+
const member = name.substring(colonIdx + 2);
|
|
364
|
+
if (this.knownNames.has(receiver) || this.knownNames.has(member))
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
// For path-like references (e.g., "snippets/drawer-menu.liquid"), check the filename
|
|
368
|
+
const slashIdx = name.lastIndexOf('/');
|
|
369
|
+
if (slashIdx > 0) {
|
|
370
|
+
const fileName = name.substring(slashIdx + 1);
|
|
371
|
+
if (this.knownNames.has(fileName))
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
303
376
|
/**
|
|
304
377
|
* Resolve a single reference
|
|
305
378
|
*/
|
|
@@ -308,6 +381,10 @@ class ReferenceResolver {
|
|
|
308
381
|
if (this.isBuiltInOrExternal(ref)) {
|
|
309
382
|
return null;
|
|
310
383
|
}
|
|
384
|
+
// Fast pre-filter: skip if no symbol with this name exists anywhere
|
|
385
|
+
if (!this.hasAnyPossibleMatch(ref.referenceName)) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
311
388
|
const candidates = [];
|
|
312
389
|
// Strategy 1: Try framework-specific resolution
|
|
313
390
|
for (const framework of this.frameworks) {
|
|
@@ -339,17 +416,30 @@ class ReferenceResolver {
|
|
|
339
416
|
* Create edges from resolved references
|
|
340
417
|
*/
|
|
341
418
|
createEdges(resolved) {
|
|
342
|
-
return resolved.map((ref) =>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
kind
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
419
|
+
return resolved.map((ref) => {
|
|
420
|
+
let kind = ref.original.referenceKind;
|
|
421
|
+
// Promote "extends" to "implements" when a class/struct targets an interface
|
|
422
|
+
if (kind === 'extends') {
|
|
423
|
+
const targetNode = this.queries.getNodeById(ref.targetNodeId);
|
|
424
|
+
if (targetNode && (targetNode.kind === 'interface' || targetNode.kind === 'protocol')) {
|
|
425
|
+
const sourceNode = this.queries.getNodeById(ref.original.fromNodeId);
|
|
426
|
+
if (sourceNode && sourceNode.kind !== 'interface' && sourceNode.kind !== 'protocol') {
|
|
427
|
+
kind = 'implements';
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
source: ref.original.fromNodeId,
|
|
433
|
+
target: ref.targetNodeId,
|
|
434
|
+
kind,
|
|
435
|
+
line: ref.original.line,
|
|
436
|
+
column: ref.original.column,
|
|
437
|
+
metadata: {
|
|
438
|
+
confidence: ref.confidence,
|
|
439
|
+
resolvedBy: ref.resolvedBy,
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
});
|
|
353
443
|
}
|
|
354
444
|
/**
|
|
355
445
|
* Resolve and persist edges to database
|
|
@@ -362,8 +452,82 @@ class ReferenceResolver {
|
|
|
362
452
|
if (edges.length > 0) {
|
|
363
453
|
this.queries.insertEdges(edges);
|
|
364
454
|
}
|
|
455
|
+
// Clean up resolved refs from unresolved_refs table so metrics are accurate
|
|
456
|
+
if (result.resolved.length > 0) {
|
|
457
|
+
this.queries.deleteSpecificResolvedReferences(result.resolved.map((r) => ({
|
|
458
|
+
fromNodeId: r.original.fromNodeId,
|
|
459
|
+
referenceName: r.original.referenceName,
|
|
460
|
+
referenceKind: r.original.referenceKind,
|
|
461
|
+
})));
|
|
462
|
+
}
|
|
365
463
|
return result;
|
|
366
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* Resolve and persist in batches to keep memory bounded.
|
|
467
|
+
* Processes unresolved references in chunks, persisting edges and cleaning
|
|
468
|
+
* up resolved refs after each batch to avoid accumulating large arrays.
|
|
469
|
+
*/
|
|
470
|
+
async resolveAndPersistBatched(onProgress, batchSize = 5000) {
|
|
471
|
+
this.warmCaches();
|
|
472
|
+
const total = this.queries.getUnresolvedReferencesCount();
|
|
473
|
+
let processed = 0;
|
|
474
|
+
const aggregateStats = {
|
|
475
|
+
total: 0,
|
|
476
|
+
resolved: 0,
|
|
477
|
+
unresolved: 0,
|
|
478
|
+
byMethod: {},
|
|
479
|
+
};
|
|
480
|
+
// Process in batches. We always read from offset 0 because resolved refs
|
|
481
|
+
// are deleted after each batch, shifting the remaining rows forward.
|
|
482
|
+
while (true) {
|
|
483
|
+
const batch = this.queries.getUnresolvedReferencesBatch(0, batchSize);
|
|
484
|
+
if (batch.length === 0)
|
|
485
|
+
break;
|
|
486
|
+
const result = this.resolveAll(batch);
|
|
487
|
+
// Persist edges immediately
|
|
488
|
+
const edges = this.createEdges(result.resolved);
|
|
489
|
+
if (edges.length > 0) {
|
|
490
|
+
this.queries.insertEdges(edges);
|
|
491
|
+
}
|
|
492
|
+
// Clean up resolved refs so they don't appear in the next batch
|
|
493
|
+
if (result.resolved.length > 0) {
|
|
494
|
+
this.queries.deleteSpecificResolvedReferences(result.resolved.map((r) => ({
|
|
495
|
+
fromNodeId: r.original.fromNodeId,
|
|
496
|
+
referenceName: r.original.referenceName,
|
|
497
|
+
referenceKind: r.original.referenceKind,
|
|
498
|
+
})));
|
|
499
|
+
}
|
|
500
|
+
// Delete unresolvable refs from this batch to avoid re-processing them
|
|
501
|
+
if (result.unresolved.length > 0) {
|
|
502
|
+
this.queries.deleteSpecificResolvedReferences(result.unresolved.map((r) => ({
|
|
503
|
+
fromNodeId: r.fromNodeId,
|
|
504
|
+
referenceName: r.referenceName,
|
|
505
|
+
referenceKind: r.referenceKind,
|
|
506
|
+
})));
|
|
507
|
+
}
|
|
508
|
+
// Aggregate stats
|
|
509
|
+
aggregateStats.total += result.stats.total;
|
|
510
|
+
aggregateStats.resolved += result.stats.resolved;
|
|
511
|
+
aggregateStats.unresolved += result.stats.unresolved;
|
|
512
|
+
for (const [method, count] of Object.entries(result.stats.byMethod)) {
|
|
513
|
+
aggregateStats.byMethod[method] = (aggregateStats.byMethod[method] || 0) + count;
|
|
514
|
+
}
|
|
515
|
+
processed += batch.length;
|
|
516
|
+
onProgress?.(processed, total);
|
|
517
|
+
// Yield so progress UI can render between batches
|
|
518
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
519
|
+
// If nothing was resolved or removed in this batch, we'd loop forever
|
|
520
|
+
// on the same rows. Break to avoid infinite loop.
|
|
521
|
+
if (result.resolved.length === 0 && result.unresolved.length === batch.length) {
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return {
|
|
526
|
+
resolved: [],
|
|
527
|
+
unresolved: [],
|
|
528
|
+
stats: aggregateStats,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
367
531
|
/**
|
|
368
532
|
* Get detected frameworks
|
|
369
533
|
*/
|
|
@@ -375,67 +539,67 @@ class ReferenceResolver {
|
|
|
375
539
|
*/
|
|
376
540
|
isBuiltInOrExternal(ref) {
|
|
377
541
|
const name = ref.referenceName;
|
|
542
|
+
const isJsTs = ref.language === 'typescript' || ref.language === 'javascript'
|
|
543
|
+
|| ref.language === 'tsx' || ref.language === 'jsx';
|
|
378
544
|
// JavaScript/TypeScript built-ins
|
|
379
|
-
|
|
380
|
-
'console', 'window', 'document', 'global', 'process',
|
|
381
|
-
'Promise', 'Array', 'Object', 'String', 'Number', 'Boolean',
|
|
382
|
-
'Date', 'Math', 'JSON', 'RegExp', 'Error', 'Map', 'Set',
|
|
383
|
-
'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
|
|
384
|
-
'fetch', 'require', 'module', 'exports', '__dirname', '__filename',
|
|
385
|
-
];
|
|
386
|
-
if (jsBuiltIns.includes(name)) {
|
|
545
|
+
if (isJsTs && JS_BUILT_INS.has(name)) {
|
|
387
546
|
return true;
|
|
388
547
|
}
|
|
389
|
-
// Common library calls
|
|
390
|
-
if (name.startsWith('console.') || name.startsWith('Math.') || name.startsWith('JSON.')) {
|
|
548
|
+
// Common JS/TS library calls (console.log, Math.floor, JSON.parse)
|
|
549
|
+
if (isJsTs && (name.startsWith('console.') || name.startsWith('Math.') || name.startsWith('JSON.'))) {
|
|
391
550
|
return true;
|
|
392
551
|
}
|
|
393
552
|
// React hooks from React itself
|
|
394
|
-
|
|
395
|
-
if (reactHooks.includes(name)) {
|
|
553
|
+
if (isJsTs && REACT_HOOKS.has(name)) {
|
|
396
554
|
return true;
|
|
397
555
|
}
|
|
398
|
-
// Python built-ins
|
|
399
|
-
|
|
400
|
-
'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
|
|
401
|
-
'open', 'input', 'type', 'isinstance', 'hasattr', 'getattr', 'setattr',
|
|
402
|
-
'super', 'self', 'cls', 'None', 'True', 'False',
|
|
403
|
-
];
|
|
404
|
-
if (ref.language === 'python' && pythonBuiltIns.includes(name)) {
|
|
556
|
+
// Python built-ins (bare calls only — dotted calls like console.print are method calls)
|
|
557
|
+
if (ref.language === 'python' && PYTHON_BUILT_INS.has(name)) {
|
|
405
558
|
return true;
|
|
406
559
|
}
|
|
560
|
+
// Python built-in method calls (e.g., list.extend, dict.update)
|
|
561
|
+
if (ref.language === 'python') {
|
|
562
|
+
const dotIdx = name.indexOf('.');
|
|
563
|
+
if (dotIdx > 0) {
|
|
564
|
+
const receiver = name.substring(0, dotIdx);
|
|
565
|
+
const method = name.substring(dotIdx + 1);
|
|
566
|
+
// Filter calls on built-in types (list.append, dict.update, etc.)
|
|
567
|
+
if (PYTHON_BUILT_IN_TYPES.has(receiver)) {
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
// Filter built-in methods on non-class receivers
|
|
571
|
+
// (e.g., items.append where items is a local list variable)
|
|
572
|
+
// But allow if the capitalized receiver matches a known codebase class
|
|
573
|
+
if (PYTHON_BUILT_IN_METHODS.has(method)) {
|
|
574
|
+
const capitalized = receiver.charAt(0).toUpperCase() + receiver.slice(1);
|
|
575
|
+
if (!this.knownNames?.has(capitalized)) {
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (PYTHON_BUILT_IN_METHODS.has(name)) {
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
// Go standard library packages — refs like "fmt.Println", "http.ListenAndServe", etc.
|
|
585
|
+
if (ref.language === 'go') {
|
|
586
|
+
const dotIdx = name.indexOf('.');
|
|
587
|
+
if (dotIdx > 0) {
|
|
588
|
+
const pkg = name.substring(0, dotIdx);
|
|
589
|
+
if (GO_STDLIB_PACKAGES.has(pkg)) {
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (GO_BUILT_INS.has(name)) {
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
407
597
|
// Pascal/Delphi built-ins and standard library units
|
|
408
598
|
if (ref.language === 'pascal') {
|
|
409
|
-
|
|
410
|
-
const pascalUnitPrefixes = [
|
|
411
|
-
'System.', 'Winapi.', 'Vcl.', 'Fmx.', 'Data.', 'Datasnap.',
|
|
412
|
-
'Soap.', 'Xml.', 'Web.', 'REST.', 'FireDAC.', 'IBX.',
|
|
413
|
-
'IdHTTP', 'IdTCP', 'IdSSL',
|
|
414
|
-
];
|
|
415
|
-
if (pascalUnitPrefixes.some((p) => name.startsWith(p))) {
|
|
599
|
+
if (PASCAL_UNIT_PREFIXES.some((p) => name.startsWith(p))) {
|
|
416
600
|
return true;
|
|
417
601
|
}
|
|
418
|
-
|
|
419
|
-
const pascalBuiltIns = [
|
|
420
|
-
'System', 'SysUtils', 'Classes', 'Types', 'Variants', 'StrUtils',
|
|
421
|
-
'Math', 'DateUtils', 'IOUtils', 'Generics.Collections', 'Generics.Defaults',
|
|
422
|
-
'Rtti', 'TypInfo', 'SyncObjs', 'RegularExpressions',
|
|
423
|
-
'SysInit', 'Windows', 'Messages', 'Graphics', 'Controls', 'Forms',
|
|
424
|
-
'Dialogs', 'StdCtrls', 'ExtCtrls', 'ComCtrls', 'Menus', 'ActnList',
|
|
425
|
-
'WriteLn', 'Write', 'ReadLn', 'Read', 'Inc', 'Dec', 'Ord', 'Chr',
|
|
426
|
-
'Length', 'SetLength', 'High', 'Low', 'Assigned', 'FreeAndNil',
|
|
427
|
-
'Format', 'IntToStr', 'StrToInt', 'FloatToStr', 'StrToFloat',
|
|
428
|
-
'Trim', 'UpperCase', 'LowerCase', 'Pos', 'Copy', 'Delete', 'Insert',
|
|
429
|
-
'Now', 'Date', 'Time', 'DateToStr', 'StrToDate',
|
|
430
|
-
'Raise', 'Exit', 'Break', 'Continue', 'Abort',
|
|
431
|
-
'True', 'False', 'nil', 'Self', 'Result',
|
|
432
|
-
'Create', 'Destroy', 'Free',
|
|
433
|
-
'TObject', 'TComponent', 'TPersistent', 'TInterfacedObject',
|
|
434
|
-
'TList', 'TStringList', 'TStrings', 'TStream', 'TMemoryStream', 'TFileStream',
|
|
435
|
-
'Exception', 'EAbort', 'EConvertError', 'EAccessViolation',
|
|
436
|
-
'IInterface', 'IUnknown',
|
|
437
|
-
];
|
|
438
|
-
if (pascalBuiltIns.includes(name)) {
|
|
602
|
+
if (PASCAL_BUILT_INS.has(name)) {
|
|
439
603
|
return true;
|
|
440
604
|
}
|
|
441
605
|
}
|
|
@@ -445,10 +609,6 @@ class ReferenceResolver {
|
|
|
445
609
|
* Get file path from node ID
|
|
446
610
|
*/
|
|
447
611
|
getFilePathFromNodeId(nodeId) {
|
|
448
|
-
// Check warm cache first
|
|
449
|
-
const cached = this.nodeByIdCache.get(nodeId);
|
|
450
|
-
if (cached)
|
|
451
|
-
return cached.filePath;
|
|
452
612
|
const node = this.queries.getNodeById(nodeId);
|
|
453
613
|
return node?.filePath || '';
|
|
454
614
|
}
|
|
@@ -456,10 +616,6 @@ class ReferenceResolver {
|
|
|
456
616
|
* Get language from node ID
|
|
457
617
|
*/
|
|
458
618
|
getLanguageFromNodeId(nodeId) {
|
|
459
|
-
// Check warm cache first
|
|
460
|
-
const cached = this.nodeByIdCache.get(nodeId);
|
|
461
|
-
if (cached)
|
|
462
|
-
return cached.language;
|
|
463
619
|
const node = this.queries.getNodeById(nodeId);
|
|
464
620
|
return node?.language || 'unknown';
|
|
465
621
|
}
|