codesift-mcp 0.5.24 → 0.5.28
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 +4 -4
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +28 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/help.js +1 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/hooks.d.ts +4 -0
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +15 -4
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/journal-commands.d.ts +9 -0
- package/dist/cli/journal-commands.d.ts.map +1 -0
- package/dist/cli/journal-commands.js +160 -0
- package/dist/cli/journal-commands.js.map +1 -0
- package/dist/cli/wiki-commands.d.ts.map +1 -1
- package/dist/cli/wiki-commands.js +5 -0
- package/dist/cli/wiki-commands.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +41 -47
- package/dist/instructions.js.map +1 -1
- package/dist/parser/extractors/_shared.d.ts +2 -0
- package/dist/parser/extractors/_shared.d.ts.map +1 -1
- package/dist/parser/extractors/_shared.js +4 -0
- package/dist/parser/extractors/_shared.js.map +1 -1
- package/dist/parser/extractors/typescript.d.ts.map +1 -1
- package/dist/parser/extractors/typescript.js +606 -31
- package/dist/parser/extractors/typescript.js.map +1 -1
- package/dist/parser/parse-worker.d.ts +2 -0
- package/dist/parser/parse-worker.d.ts.map +1 -0
- package/dist/parser/parse-worker.js +47 -0
- package/dist/parser/parse-worker.js.map +1 -0
- package/dist/parser/parser-manager.d.ts +10 -1
- package/dist/parser/parser-manager.d.ts.map +1 -1
- package/dist/parser/parser-manager.js +40 -2
- package/dist/parser/parser-manager.js.map +1 -1
- package/dist/parser/parser-pool.d.ts +31 -0
- package/dist/parser/parser-pool.d.ts.map +1 -0
- package/dist/parser/parser-pool.js +211 -0
- package/dist/parser/parser-pool.js.map +1 -0
- package/dist/register-tool-loaders.d.ts +1 -1
- package/dist/register-tool-loaders.d.ts.map +1 -1
- package/dist/register-tool-loaders.js +2 -2
- package/dist/register-tool-loaders.js.map +1 -1
- package/dist/register-tools.d.ts.map +1 -1
- package/dist/register-tools.js +382 -35
- package/dist/register-tools.js.map +1 -1
- package/dist/retrieval/codebase-retrieval.d.ts.map +1 -1
- package/dist/retrieval/codebase-retrieval.js +9 -1
- package/dist/retrieval/codebase-retrieval.js.map +1 -1
- package/dist/search/chunker.d.ts +1 -0
- package/dist/search/chunker.d.ts.map +1 -1
- package/dist/search/chunker.js +8 -1
- package/dist/search/chunker.js.map +1 -1
- package/dist/server-helpers.d.ts +27 -0
- package/dist/server-helpers.d.ts.map +1 -1
- package/dist/server-helpers.js +90 -9
- package/dist/server-helpers.js.map +1 -1
- package/dist/server.js +31 -0
- package/dist/server.js.map +1 -1
- package/dist/storage/index-store.d.ts +41 -4
- package/dist/storage/index-store.d.ts.map +1 -1
- package/dist/storage/index-store.js +89 -6
- package/dist/storage/index-store.js.map +1 -1
- package/dist/storage/watcher.d.ts +33 -6
- package/dist/storage/watcher.d.ts.map +1 -1
- package/dist/storage/watcher.js +73 -34
- package/dist/storage/watcher.js.map +1 -1
- package/dist/storage/workspace-resolver.d.ts +15 -0
- package/dist/storage/workspace-resolver.d.ts.map +1 -0
- package/dist/storage/workspace-resolver.js +130 -0
- package/dist/storage/workspace-resolver.js.map +1 -0
- package/dist/tools/_helpers.d.ts +37 -0
- package/dist/tools/_helpers.d.ts.map +1 -0
- package/dist/tools/_helpers.js +31 -0
- package/dist/tools/_helpers.js.map +1 -0
- package/dist/tools/constant-resolution-tools.d.ts +8 -0
- package/dist/tools/constant-resolution-tools.d.ts.map +1 -0
- package/dist/tools/constant-resolution-tools.js +68 -0
- package/dist/tools/constant-resolution-tools.js.map +1 -0
- package/dist/tools/graph-tools.d.ts +27 -5
- package/dist/tools/graph-tools.d.ts.map +1 -1
- package/dist/tools/graph-tools.js +141 -18
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/hotspot-tools.d.ts +6 -0
- package/dist/tools/hotspot-tools.d.ts.map +1 -1
- package/dist/tools/hotspot-tools.js +48 -8
- package/dist/tools/hotspot-tools.js.map +1 -1
- package/dist/tools/impact-tools.d.ts.map +1 -1
- package/dist/tools/impact-tools.js +9 -2
- package/dist/tools/impact-tools.js.map +1 -1
- package/dist/tools/index-tools.d.ts +15 -1
- package/dist/tools/index-tools.d.ts.map +1 -1
- package/dist/tools/index-tools.js +161 -16
- package/dist/tools/index-tools.js.map +1 -1
- package/dist/tools/journal-generator-helpers.d.ts +55 -0
- package/dist/tools/journal-generator-helpers.d.ts.map +1 -0
- package/dist/tools/journal-generator-helpers.js +250 -0
- package/dist/tools/journal-generator-helpers.js.map +1 -0
- package/dist/tools/journal-generator.d.ts +48 -0
- package/dist/tools/journal-generator.d.ts.map +1 -0
- package/dist/tools/journal-generator.js +204 -0
- package/dist/tools/journal-generator.js.map +1 -0
- package/dist/tools/journal-git-client.d.ts +20 -0
- package/dist/tools/journal-git-client.d.ts.map +1 -0
- package/dist/tools/journal-git-client.js +57 -0
- package/dist/tools/journal-git-client.js.map +1 -0
- package/dist/tools/journal-llm-client.d.ts +57 -0
- package/dist/tools/journal-llm-client.d.ts.map +1 -0
- package/dist/tools/journal-llm-client.js +175 -0
- package/dist/tools/journal-llm-client.js.map +1 -0
- package/dist/tools/journal-migrator.d.ts +22 -0
- package/dist/tools/journal-migrator.d.ts.map +1 -0
- package/dist/tools/journal-migrator.js +183 -0
- package/dist/tools/journal-migrator.js.map +1 -0
- package/dist/tools/journal-phase-detector.d.ts +26 -0
- package/dist/tools/journal-phase-detector.d.ts.map +1 -0
- package/dist/tools/journal-phase-detector.js +126 -0
- package/dist/tools/journal-phase-detector.js.map +1 -0
- package/dist/tools/journal-sentinel.d.ts +15 -0
- package/dist/tools/journal-sentinel.d.ts.map +1 -0
- package/dist/tools/journal-sentinel.js +110 -0
- package/dist/tools/journal-sentinel.js.map +1 -0
- package/dist/tools/journal-templates.d.ts +28 -0
- package/dist/tools/journal-templates.d.ts.map +1 -0
- package/dist/tools/journal-templates.js +93 -0
- package/dist/tools/journal-templates.js.map +1 -0
- package/dist/tools/pattern-tools.d.ts +2 -0
- package/dist/tools/pattern-tools.d.ts.map +1 -1
- package/dist/tools/pattern-tools.js +73 -0
- package/dist/tools/pattern-tools.js.map +1 -1
- package/dist/tools/perf-tools.d.ts.map +1 -1
- package/dist/tools/perf-tools.js +6 -0
- package/dist/tools/perf-tools.js.map +1 -1
- package/dist/tools/plan-turn-tools.d.ts.map +1 -1
- package/dist/tools/plan-turn-tools.js +38 -2
- package/dist/tools/plan-turn-tools.js.map +1 -1
- package/dist/tools/project-tools.d.ts +6 -0
- package/dist/tools/project-tools.d.ts.map +1 -1
- package/dist/tools/project-tools.js +65 -25
- package/dist/tools/project-tools.js.map +1 -1
- package/dist/tools/python-constants-tools.d.ts +6 -0
- package/dist/tools/python-constants-tools.d.ts.map +1 -1
- package/dist/tools/python-constants-tools.js.map +1 -1
- package/dist/tools/react-tools.d.ts +44 -1
- package/dist/tools/react-tools.d.ts.map +1 -1
- package/dist/tools/react-tools.js +142 -9
- package/dist/tools/react-tools.js.map +1 -1
- package/dist/tools/search-tools.d.ts.map +1 -1
- package/dist/tools/search-tools.js +21 -2
- package/dist/tools/search-tools.js.map +1 -1
- package/dist/tools/status-tools.d.ts +10 -0
- package/dist/tools/status-tools.d.ts.map +1 -1
- package/dist/tools/status-tools.js +53 -2
- package/dist/tools/status-tools.js.map +1 -1
- package/dist/tools/symbol-tools.d.ts +13 -0
- package/dist/tools/symbol-tools.d.ts.map +1 -1
- package/dist/tools/symbol-tools.js +38 -0
- package/dist/tools/symbol-tools.js.map +1 -1
- package/dist/tools/typescript-constants-tools.d.ts +6 -0
- package/dist/tools/typescript-constants-tools.d.ts.map +1 -0
- package/dist/tools/typescript-constants-tools.js +687 -0
- package/dist/tools/typescript-constants-tools.js.map +1 -0
- package/dist/tools/wiki-hub-ranker.d.ts +36 -0
- package/dist/tools/wiki-hub-ranker.d.ts.map +1 -0
- package/dist/tools/wiki-hub-ranker.js +72 -0
- package/dist/tools/wiki-hub-ranker.js.map +1 -0
- package/dist/tools/wiki-lint.d.ts +7 -2
- package/dist/tools/wiki-lint.d.ts.map +1 -1
- package/dist/tools/wiki-lint.js +73 -1
- package/dist/tools/wiki-lint.js.map +1 -1
- package/dist/tools/wiki-manifest.d.ts +129 -21
- package/dist/tools/wiki-manifest.d.ts.map +1 -1
- package/dist/tools/wiki-manifest.js +16 -9
- package/dist/tools/wiki-manifest.js.map +1 -1
- package/dist/tools/wiki-module-builder.d.ts +42 -0
- package/dist/tools/wiki-module-builder.d.ts.map +1 -0
- package/dist/tools/wiki-module-builder.js +449 -0
- package/dist/tools/wiki-module-builder.js.map +1 -0
- package/dist/tools/wiki-overview-sources.d.ts +26 -0
- package/dist/tools/wiki-overview-sources.d.ts.map +1 -0
- package/dist/tools/wiki-overview-sources.js +128 -0
- package/dist/tools/wiki-overview-sources.js.map +1 -0
- package/dist/tools/wiki-page-generators.d.ts +19 -3
- package/dist/tools/wiki-page-generators.d.ts.map +1 -1
- package/dist/tools/wiki-page-generators.js +156 -22
- package/dist/tools/wiki-page-generators.js.map +1 -1
- package/dist/tools/wiki-tools.d.ts +20 -0
- package/dist/tools/wiki-tools.d.ts.map +1 -1
- package/dist/tools/wiki-tools.js +181 -29
- package/dist/tools/wiki-tools.js.map +1 -1
- package/dist/tools/workspace-scope-helper.d.ts +21 -0
- package/dist/tools/workspace-scope-helper.d.ts.map +1 -0
- package/dist/tools/workspace-scope-helper.js +50 -0
- package/dist/tools/workspace-scope-helper.js.map +1 -0
- package/dist/tools/workspace-tools.d.ts +74 -0
- package/dist/tools/workspace-tools.d.ts.map +1 -0
- package/dist/tools/workspace-tools.js +366 -0
- package/dist/tools/workspace-tools.js.map +1 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/import-graph.d.ts +27 -0
- package/dist/utils/import-graph.d.ts.map +1 -1
- package/dist/utils/import-graph.js +331 -8
- package/dist/utils/import-graph.js.map +1 -1
- package/dist/utils/ts-imports.d.ts +30 -0
- package/dist/utils/ts-imports.d.ts.map +1 -0
- package/dist/utils/ts-imports.js +168 -0
- package/dist/utils/ts-imports.js.map +1 -0
- package/dist/utils/tsconfig-paths.d.ts +59 -0
- package/dist/utils/tsconfig-paths.d.ts.map +1 -0
- package/dist/utils/tsconfig-paths.js +176 -0
- package/dist/utils/tsconfig-paths.js.map +1 -0
- package/dist/utils/walk.d.ts.map +1 -1
- package/dist/utils/walk.js +1 -0
- package/dist/utils/walk.js.map +1 -1
- package/package.json +13 -3
- package/rules/codesift.md +19 -2
- package/rules/codesift.mdc +2 -2
- package/rules/codex.md +13 -2
- package/rules/gemini.md +13 -2
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { getParser } from "../parser/parser-manager.js";
|
|
4
|
+
import { buildNormalizedPathMap, resolveImportPath } from "../utils/import-graph.js";
|
|
5
|
+
import { getCodeIndex } from "./index-tools.js";
|
|
6
|
+
const MAX_DEFAULT_DEPTH = 8;
|
|
7
|
+
function isTypeScriptFile(filePath) {
|
|
8
|
+
return filePath.endsWith(".ts") || filePath.endsWith(".tsx");
|
|
9
|
+
}
|
|
10
|
+
function stripTypeScriptString(text) {
|
|
11
|
+
const match = text.match(/^(['"`])([\s\S]*)\1$/);
|
|
12
|
+
if (match)
|
|
13
|
+
return match[2] ?? "";
|
|
14
|
+
return text;
|
|
15
|
+
}
|
|
16
|
+
function isObjectKey(value) {
|
|
17
|
+
return typeof value === "string"
|
|
18
|
+
|| typeof value === "number"
|
|
19
|
+
|| typeof value === "boolean"
|
|
20
|
+
|| value === null;
|
|
21
|
+
}
|
|
22
|
+
function computeConfidence(resolved, aliasChain, usedImport) {
|
|
23
|
+
if (!resolved)
|
|
24
|
+
return usedImport || aliasChain.length > 1 ? "low" : "medium";
|
|
25
|
+
if (usedImport || aliasChain.length > 2)
|
|
26
|
+
return "medium";
|
|
27
|
+
return "high";
|
|
28
|
+
}
|
|
29
|
+
function unsupportedNode(node, aliasChain, usedImport) {
|
|
30
|
+
return {
|
|
31
|
+
resolved: false,
|
|
32
|
+
value_text: node.text,
|
|
33
|
+
alias_chain: aliasChain,
|
|
34
|
+
used_import: usedImport,
|
|
35
|
+
reason: `Unsupported TypeScript value node: ${node.type}`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function getBindingLine(binding) {
|
|
39
|
+
return binding.line;
|
|
40
|
+
}
|
|
41
|
+
function getStringLiteralText(node) {
|
|
42
|
+
const fragment = node.namedChildren.find((child) => child.type === "string_fragment");
|
|
43
|
+
if (fragment)
|
|
44
|
+
return fragment.text;
|
|
45
|
+
return stripTypeScriptString(node.text);
|
|
46
|
+
}
|
|
47
|
+
function collectVariableDeclarators(node, assignments) {
|
|
48
|
+
for (const child of node.namedChildren) {
|
|
49
|
+
if (child.type !== "variable_declarator")
|
|
50
|
+
continue;
|
|
51
|
+
const nameNode = child.childForFieldName("name") ?? child.namedChildren[0];
|
|
52
|
+
const valueNode = child.childForFieldName("value") ?? child.namedChildren[1];
|
|
53
|
+
if (!nameNode || !valueNode || nameNode.type !== "identifier")
|
|
54
|
+
continue;
|
|
55
|
+
assignments.set(nameNode.text, {
|
|
56
|
+
rhs: valueNode,
|
|
57
|
+
line: child.startPosition.row + 1,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function collectImportBindings(node, importerFile, normalizedPaths, imports) {
|
|
62
|
+
const stringNode = node.namedChildren.find((child) => child.type === "string");
|
|
63
|
+
if (!stringNode)
|
|
64
|
+
return;
|
|
65
|
+
const rawPath = getStringLiteralText(stringNode);
|
|
66
|
+
if (!rawPath.startsWith("."))
|
|
67
|
+
return;
|
|
68
|
+
const normalized = resolveImportPath(importerFile, rawPath);
|
|
69
|
+
const resolvedFile = normalizedPaths.get(normalized);
|
|
70
|
+
if (!resolvedFile || !isTypeScriptFile(resolvedFile))
|
|
71
|
+
return;
|
|
72
|
+
const importClause = node.namedChildren.find((child) => child.type === "import_clause");
|
|
73
|
+
if (!importClause)
|
|
74
|
+
return;
|
|
75
|
+
for (const child of importClause.namedChildren) {
|
|
76
|
+
if (child.type === "identifier") {
|
|
77
|
+
imports.set(child.text, {
|
|
78
|
+
kind: "default",
|
|
79
|
+
source_file: resolvedFile,
|
|
80
|
+
line: node.startPosition.row + 1,
|
|
81
|
+
});
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (child.type === "named_imports") {
|
|
85
|
+
for (const specifier of child.namedChildren) {
|
|
86
|
+
if (specifier.type !== "import_specifier")
|
|
87
|
+
continue;
|
|
88
|
+
const importedNode = specifier.namedChildren[0];
|
|
89
|
+
const localNode = specifier.namedChildren[1] ?? importedNode;
|
|
90
|
+
if (!importedNode || !localNode || localNode.type !== "identifier" || importedNode.type !== "identifier")
|
|
91
|
+
continue;
|
|
92
|
+
imports.set(localNode.text, {
|
|
93
|
+
kind: "named",
|
|
94
|
+
imported_name: importedNode.text,
|
|
95
|
+
source_file: resolvedFile,
|
|
96
|
+
line: node.startPosition.row + 1,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (child.type === "namespace_import") {
|
|
102
|
+
const localNode = child.namedChildren.find((entry) => entry.type === "identifier");
|
|
103
|
+
if (!localNode)
|
|
104
|
+
continue;
|
|
105
|
+
imports.set(localNode.text, {
|
|
106
|
+
kind: "namespace",
|
|
107
|
+
source_file: resolvedFile,
|
|
108
|
+
line: node.startPosition.row + 1,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function extractDefaultExport(node) {
|
|
114
|
+
if (!node.text.startsWith("export default"))
|
|
115
|
+
return undefined;
|
|
116
|
+
const inner = node.namedChildren[0];
|
|
117
|
+
if (!inner) {
|
|
118
|
+
return {
|
|
119
|
+
line: node.startPosition.row + 1,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (inner.type === "function_declaration" || inner.type === "class_declaration") {
|
|
123
|
+
const nameNode = inner.childForFieldName("name") ?? inner.namedChildren[0];
|
|
124
|
+
if (nameNode?.type === "identifier") {
|
|
125
|
+
return {
|
|
126
|
+
name: nameNode.text,
|
|
127
|
+
line: node.startPosition.row + 1,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (inner.type === "lexical_declaration") {
|
|
132
|
+
const declarator = inner.namedChildren.find((child) => child.type === "variable_declarator");
|
|
133
|
+
const nameNode = declarator?.childForFieldName("name") ?? declarator?.namedChildren[0];
|
|
134
|
+
if (nameNode?.type === "identifier") {
|
|
135
|
+
return {
|
|
136
|
+
name: nameNode.text,
|
|
137
|
+
line: node.startPosition.row + 1,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
node: inner,
|
|
143
|
+
line: node.startPosition.row + 1,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async function loadTypeScriptFileContext(index, parser, filePath, cache) {
|
|
147
|
+
const cached = cache.get(filePath);
|
|
148
|
+
if (cached !== undefined)
|
|
149
|
+
return cached;
|
|
150
|
+
if (!isTypeScriptFile(filePath)) {
|
|
151
|
+
cache.set(filePath, null);
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
let source;
|
|
155
|
+
try {
|
|
156
|
+
source = await readFile(join(index.root, filePath), "utf-8");
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
cache.set(filePath, null);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const tree = parser.parse(source);
|
|
163
|
+
const assignments = new Map();
|
|
164
|
+
const imports = new Map();
|
|
165
|
+
const normalizedPaths = buildNormalizedPathMap(index);
|
|
166
|
+
let defaultExport;
|
|
167
|
+
for (const node of tree.rootNode.namedChildren) {
|
|
168
|
+
if (node.type === "lexical_declaration") {
|
|
169
|
+
collectVariableDeclarators(node, assignments);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (node.type === "import_statement") {
|
|
173
|
+
collectImportBindings(node, filePath, normalizedPaths, imports);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (node.type === "export_statement") {
|
|
177
|
+
const inner = node.namedChildren[0];
|
|
178
|
+
if (inner?.type === "lexical_declaration") {
|
|
179
|
+
collectVariableDeclarators(inner, assignments);
|
|
180
|
+
}
|
|
181
|
+
const exportBinding = extractDefaultExport(node);
|
|
182
|
+
if (exportBinding)
|
|
183
|
+
defaultExport = exportBinding;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const context = {
|
|
187
|
+
source,
|
|
188
|
+
tree,
|
|
189
|
+
assignments,
|
|
190
|
+
imports,
|
|
191
|
+
};
|
|
192
|
+
if (defaultExport)
|
|
193
|
+
context.default_export = defaultExport;
|
|
194
|
+
cache.set(filePath, context);
|
|
195
|
+
return context;
|
|
196
|
+
}
|
|
197
|
+
async function evaluateValueNode(filePath, node, state) {
|
|
198
|
+
switch (node.type) {
|
|
199
|
+
case "string":
|
|
200
|
+
return {
|
|
201
|
+
resolved: true,
|
|
202
|
+
value_kind: "string",
|
|
203
|
+
value: stripTypeScriptString(node.text),
|
|
204
|
+
value_text: node.text,
|
|
205
|
+
alias_chain: [],
|
|
206
|
+
used_import: false,
|
|
207
|
+
};
|
|
208
|
+
case "template_string": {
|
|
209
|
+
if (node.namedChildren.length === 0) {
|
|
210
|
+
return {
|
|
211
|
+
resolved: true,
|
|
212
|
+
value_kind: "string",
|
|
213
|
+
value: stripTypeScriptString(node.text),
|
|
214
|
+
value_text: node.text,
|
|
215
|
+
alias_chain: [],
|
|
216
|
+
used_import: false,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return unsupportedNode(node, [], false);
|
|
220
|
+
}
|
|
221
|
+
case "number":
|
|
222
|
+
return {
|
|
223
|
+
resolved: true,
|
|
224
|
+
value_kind: node.text.includes(".") ? "float" : "integer",
|
|
225
|
+
value: Number(node.text),
|
|
226
|
+
value_text: node.text,
|
|
227
|
+
alias_chain: [],
|
|
228
|
+
used_import: false,
|
|
229
|
+
};
|
|
230
|
+
case "true":
|
|
231
|
+
return {
|
|
232
|
+
resolved: true,
|
|
233
|
+
value_kind: "boolean",
|
|
234
|
+
value: true,
|
|
235
|
+
value_text: node.text,
|
|
236
|
+
alias_chain: [],
|
|
237
|
+
used_import: false,
|
|
238
|
+
};
|
|
239
|
+
case "false":
|
|
240
|
+
return {
|
|
241
|
+
resolved: true,
|
|
242
|
+
value_kind: "boolean",
|
|
243
|
+
value: false,
|
|
244
|
+
value_text: node.text,
|
|
245
|
+
alias_chain: [],
|
|
246
|
+
used_import: false,
|
|
247
|
+
};
|
|
248
|
+
case "null":
|
|
249
|
+
return {
|
|
250
|
+
resolved: true,
|
|
251
|
+
value_kind: "null",
|
|
252
|
+
value: null,
|
|
253
|
+
value_text: node.text,
|
|
254
|
+
alias_chain: [],
|
|
255
|
+
used_import: false,
|
|
256
|
+
};
|
|
257
|
+
case "identifier":
|
|
258
|
+
return await resolveNamedValue(filePath, node.text, state, 0);
|
|
259
|
+
case "array": {
|
|
260
|
+
const items = [];
|
|
261
|
+
let usedImport = false;
|
|
262
|
+
const aliasChain = [];
|
|
263
|
+
for (const child of node.namedChildren) {
|
|
264
|
+
const result = await evaluateValueNode(filePath, child, state);
|
|
265
|
+
aliasChain.push(...result.alias_chain);
|
|
266
|
+
usedImport = usedImport || result.used_import;
|
|
267
|
+
if (!result.resolved || result.value === undefined) {
|
|
268
|
+
return {
|
|
269
|
+
resolved: false,
|
|
270
|
+
value_text: node.text,
|
|
271
|
+
alias_chain: aliasChain,
|
|
272
|
+
used_import: usedImport,
|
|
273
|
+
reason: result.reason ?? `Could not resolve ${child.text}`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
items.push(result.value);
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
resolved: true,
|
|
280
|
+
value_kind: "list",
|
|
281
|
+
value: items,
|
|
282
|
+
value_text: node.text,
|
|
283
|
+
alias_chain: aliasChain,
|
|
284
|
+
used_import: usedImport,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
case "object": {
|
|
288
|
+
const obj = {};
|
|
289
|
+
let usedImport = false;
|
|
290
|
+
const aliasChain = [];
|
|
291
|
+
for (const pair of node.namedChildren) {
|
|
292
|
+
if (pair.type !== "pair")
|
|
293
|
+
continue;
|
|
294
|
+
const keyNode = pair.namedChildren[0];
|
|
295
|
+
const valueNode = pair.namedChildren[1];
|
|
296
|
+
if (!keyNode || !valueNode)
|
|
297
|
+
return unsupportedNode(node, aliasChain, usedImport);
|
|
298
|
+
let keyValue;
|
|
299
|
+
if (keyNode.type === "property_identifier") {
|
|
300
|
+
keyValue = keyNode.text;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
const keyResult = await evaluateValueNode(filePath, keyNode, state);
|
|
304
|
+
aliasChain.push(...keyResult.alias_chain);
|
|
305
|
+
usedImport = usedImport || keyResult.used_import;
|
|
306
|
+
if (!keyResult.resolved || keyResult.value === undefined || !isObjectKey(keyResult.value)) {
|
|
307
|
+
return {
|
|
308
|
+
resolved: false,
|
|
309
|
+
value_text: node.text,
|
|
310
|
+
alias_chain: aliasChain,
|
|
311
|
+
used_import: usedImport,
|
|
312
|
+
reason: keyResult.reason ?? `Unsupported object key: ${keyNode.text}`,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
keyValue = String(keyResult.value);
|
|
316
|
+
}
|
|
317
|
+
const valueResult = await evaluateValueNode(filePath, valueNode, state);
|
|
318
|
+
aliasChain.push(...valueResult.alias_chain);
|
|
319
|
+
usedImport = usedImport || valueResult.used_import;
|
|
320
|
+
if (!valueResult.resolved || valueResult.value === undefined) {
|
|
321
|
+
return {
|
|
322
|
+
resolved: false,
|
|
323
|
+
value_text: node.text,
|
|
324
|
+
alias_chain: aliasChain,
|
|
325
|
+
used_import: usedImport,
|
|
326
|
+
reason: valueResult.reason ?? `Could not resolve ${valueNode.text}`,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
obj[keyValue] = valueResult.value;
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
resolved: true,
|
|
333
|
+
value_kind: "dict",
|
|
334
|
+
value: obj,
|
|
335
|
+
value_text: node.text,
|
|
336
|
+
alias_chain: aliasChain,
|
|
337
|
+
used_import: usedImport,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
case "parenthesized_expression": {
|
|
341
|
+
const inner = node.namedChildren[0];
|
|
342
|
+
return inner ? await evaluateValueNode(filePath, inner, state) : unsupportedNode(node, [], false);
|
|
343
|
+
}
|
|
344
|
+
case "unary_expression": {
|
|
345
|
+
const operand = node.namedChildren[0];
|
|
346
|
+
if (!operand)
|
|
347
|
+
return unsupportedNode(node, [], false);
|
|
348
|
+
const inner = await evaluateValueNode(filePath, operand, state);
|
|
349
|
+
if (!inner.resolved || typeof inner.value !== "number") {
|
|
350
|
+
return {
|
|
351
|
+
resolved: false,
|
|
352
|
+
value_text: node.text,
|
|
353
|
+
alias_chain: inner.alias_chain,
|
|
354
|
+
used_import: inner.used_import,
|
|
355
|
+
reason: inner.reason ?? `Unsupported unary operand: ${operand.text}`,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (node.text.startsWith("-")) {
|
|
359
|
+
return {
|
|
360
|
+
resolved: true,
|
|
361
|
+
value_kind: inner.value_kind === "float" ? "float" : "integer",
|
|
362
|
+
value: -inner.value,
|
|
363
|
+
value_text: node.text,
|
|
364
|
+
alias_chain: inner.alias_chain,
|
|
365
|
+
used_import: inner.used_import,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
return inner;
|
|
369
|
+
}
|
|
370
|
+
case "member_expression":
|
|
371
|
+
return await evaluateMemberExpression(filePath, node, state);
|
|
372
|
+
default:
|
|
373
|
+
return unsupportedNode(node, [], false);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async function evaluateMemberExpression(filePath, node, state) {
|
|
377
|
+
const objectNode = node.childForFieldName("object") ?? node.namedChildren[0];
|
|
378
|
+
const propertyNode = node.childForFieldName("property") ?? node.namedChildren[1];
|
|
379
|
+
if (!objectNode || !propertyNode)
|
|
380
|
+
return unsupportedNode(node, [], false);
|
|
381
|
+
if (objectNode.type === "identifier" && propertyNode.type === "property_identifier") {
|
|
382
|
+
const context = await loadTypeScriptFileContext(state.index, state.parser, filePath, state.fileCache);
|
|
383
|
+
const imported = context?.imports.get(objectNode.text);
|
|
384
|
+
if (imported?.kind === "namespace") {
|
|
385
|
+
const result = await resolveNamedValue(imported.source_file, propertyNode.text, state, 1);
|
|
386
|
+
return {
|
|
387
|
+
...result,
|
|
388
|
+
used_import: true,
|
|
389
|
+
alias_chain: [{ name: node.text, file: filePath, line: node.startPosition.row + 1 }, ...result.alias_chain],
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
const objectResult = await evaluateValueNode(filePath, objectNode, state);
|
|
394
|
+
if (!objectResult.resolved || typeof objectResult.value !== "object" || objectResult.value === null || Array.isArray(objectResult.value)) {
|
|
395
|
+
return {
|
|
396
|
+
resolved: false,
|
|
397
|
+
value_text: node.text,
|
|
398
|
+
alias_chain: objectResult.alias_chain,
|
|
399
|
+
used_import: objectResult.used_import,
|
|
400
|
+
reason: objectResult.reason ?? `Could not resolve ${objectNode.text}`,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
const key = propertyNode.text;
|
|
404
|
+
const propertyValue = objectResult.value[key];
|
|
405
|
+
if (propertyValue === undefined) {
|
|
406
|
+
return {
|
|
407
|
+
resolved: false,
|
|
408
|
+
value_text: node.text,
|
|
409
|
+
alias_chain: objectResult.alias_chain,
|
|
410
|
+
used_import: objectResult.used_import,
|
|
411
|
+
reason: `Property ${key} not found on resolved object`,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const valueKind = Array.isArray(propertyValue)
|
|
415
|
+
? "list"
|
|
416
|
+
: propertyValue === null
|
|
417
|
+
? "null"
|
|
418
|
+
: typeof propertyValue === "string"
|
|
419
|
+
? "string"
|
|
420
|
+
: typeof propertyValue === "number"
|
|
421
|
+
? Number.isInteger(propertyValue) ? "integer" : "float"
|
|
422
|
+
: typeof propertyValue === "boolean"
|
|
423
|
+
? "boolean"
|
|
424
|
+
: "dict";
|
|
425
|
+
return {
|
|
426
|
+
resolved: true,
|
|
427
|
+
value_kind: valueKind,
|
|
428
|
+
value: propertyValue,
|
|
429
|
+
value_text: node.text,
|
|
430
|
+
alias_chain: [...objectResult.alias_chain, { name: node.text, file: filePath, line: node.startPosition.row + 1 }],
|
|
431
|
+
used_import: objectResult.used_import,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
async function resolveNamedValue(filePath, name, state, depth) {
|
|
435
|
+
if (depth > state.maxDepth) {
|
|
436
|
+
return {
|
|
437
|
+
resolved: false,
|
|
438
|
+
value_text: name,
|
|
439
|
+
alias_chain: [],
|
|
440
|
+
used_import: false,
|
|
441
|
+
reason: `Max resolution depth (${state.maxDepth}) exceeded`,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
const visitKey = `${filePath}:${name}`;
|
|
445
|
+
if (state.visited.has(visitKey)) {
|
|
446
|
+
return {
|
|
447
|
+
resolved: false,
|
|
448
|
+
value_text: name,
|
|
449
|
+
alias_chain: [],
|
|
450
|
+
used_import: false,
|
|
451
|
+
reason: `Cycle detected while resolving ${name}`,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
state.visited.add(visitKey);
|
|
455
|
+
try {
|
|
456
|
+
const context = await loadTypeScriptFileContext(state.index, state.parser, filePath, state.fileCache);
|
|
457
|
+
if (!context) {
|
|
458
|
+
return {
|
|
459
|
+
resolved: false,
|
|
460
|
+
value_text: name,
|
|
461
|
+
alias_chain: [],
|
|
462
|
+
used_import: false,
|
|
463
|
+
reason: `Could not load TypeScript file context for ${filePath}`,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
if (name === "default" && context.default_export) {
|
|
467
|
+
if (context.default_export.name) {
|
|
468
|
+
const result = await resolveNamedValue(filePath, context.default_export.name, state, depth + 1);
|
|
469
|
+
return {
|
|
470
|
+
...result,
|
|
471
|
+
alias_chain: [{ name: "default", file: filePath, line: getBindingLine(context.default_export) }, ...result.alias_chain],
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
if (context.default_export.node) {
|
|
475
|
+
const result = await evaluateValueNode(filePath, context.default_export.node, state);
|
|
476
|
+
return {
|
|
477
|
+
...result,
|
|
478
|
+
alias_chain: [{ name: "default", file: filePath, line: getBindingLine(context.default_export) }, ...result.alias_chain],
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const assignment = context.assignments.get(name);
|
|
483
|
+
if (assignment) {
|
|
484
|
+
const result = await evaluateValueNode(filePath, assignment.rhs, state);
|
|
485
|
+
return {
|
|
486
|
+
...result,
|
|
487
|
+
alias_chain: [{ name, file: filePath, line: getBindingLine(assignment) }, ...result.alias_chain],
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
const imported = context.imports.get(name);
|
|
491
|
+
if (imported) {
|
|
492
|
+
if (imported.kind === "namespace") {
|
|
493
|
+
return {
|
|
494
|
+
resolved: false,
|
|
495
|
+
value_text: name,
|
|
496
|
+
alias_chain: [{ name, file: filePath, line: getBindingLine(imported) }],
|
|
497
|
+
used_import: true,
|
|
498
|
+
reason: `Namespace import ${name} requires property access to resolve`,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
const targetName = imported.kind === "default" ? "default" : imported.imported_name;
|
|
502
|
+
if (!targetName) {
|
|
503
|
+
return {
|
|
504
|
+
resolved: false,
|
|
505
|
+
value_text: name,
|
|
506
|
+
alias_chain: [{ name, file: filePath, line: getBindingLine(imported) }],
|
|
507
|
+
used_import: true,
|
|
508
|
+
reason: `Missing imported name for ${name}`,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
const result = await resolveNamedValue(imported.source_file, targetName, state, depth + 1);
|
|
512
|
+
return {
|
|
513
|
+
...result,
|
|
514
|
+
used_import: true,
|
|
515
|
+
alias_chain: [{ name, file: filePath, line: getBindingLine(imported) }, ...result.alias_chain],
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
resolved: false,
|
|
520
|
+
value_text: name,
|
|
521
|
+
alias_chain: [],
|
|
522
|
+
used_import: false,
|
|
523
|
+
reason: `No resolvable binding found for ${name} in ${filePath}`,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
finally {
|
|
527
|
+
state.visited.delete(visitKey);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function findCallableNode(node) {
|
|
531
|
+
if (node.type === "function_declaration" || node.type === "arrow_function" || node.type === "method_definition") {
|
|
532
|
+
return node;
|
|
533
|
+
}
|
|
534
|
+
for (const child of node.namedChildren) {
|
|
535
|
+
const found = findCallableNode(child);
|
|
536
|
+
if (found)
|
|
537
|
+
return found;
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
function getDefaultParameterParts(node) {
|
|
542
|
+
if (node.type !== "required_parameter" && node.type !== "optional_parameter") {
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
if (!node.text.includes("="))
|
|
546
|
+
return null;
|
|
547
|
+
const children = node.namedChildren;
|
|
548
|
+
if (children.length < 2)
|
|
549
|
+
return null;
|
|
550
|
+
const nameNode = children[0];
|
|
551
|
+
const valueNode = children[children.length - 1];
|
|
552
|
+
if (!nameNode || !valueNode || nameNode.type !== "identifier")
|
|
553
|
+
return null;
|
|
554
|
+
return {
|
|
555
|
+
name: nameNode.text,
|
|
556
|
+
valueNode,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
async function resolveConstantSymbol(symbol, state) {
|
|
560
|
+
const result = await resolveNamedValue(symbol.file, symbol.name, state, 0);
|
|
561
|
+
const match = {
|
|
562
|
+
language: "typescript",
|
|
563
|
+
symbol_name: symbol.name,
|
|
564
|
+
symbol_kind: symbol.kind,
|
|
565
|
+
file: symbol.file,
|
|
566
|
+
line: symbol.start_line,
|
|
567
|
+
resolved: result.resolved,
|
|
568
|
+
value_text: result.value_text,
|
|
569
|
+
confidence: computeConfidence(result.resolved, result.alias_chain, result.used_import),
|
|
570
|
+
alias_chain: result.alias_chain,
|
|
571
|
+
};
|
|
572
|
+
if (result.value_kind !== undefined)
|
|
573
|
+
match.value_kind = result.value_kind;
|
|
574
|
+
if (result.value !== undefined)
|
|
575
|
+
match.value = result.value;
|
|
576
|
+
if (result.reason !== undefined)
|
|
577
|
+
match.reason = result.reason;
|
|
578
|
+
return match;
|
|
579
|
+
}
|
|
580
|
+
async function resolveFunctionDefaults(symbol, state) {
|
|
581
|
+
if (!symbol.source) {
|
|
582
|
+
return {
|
|
583
|
+
language: "typescript",
|
|
584
|
+
symbol_name: symbol.name,
|
|
585
|
+
symbol_kind: symbol.kind,
|
|
586
|
+
file: symbol.file,
|
|
587
|
+
line: symbol.start_line,
|
|
588
|
+
resolved: false,
|
|
589
|
+
confidence: "low",
|
|
590
|
+
alias_chain: [],
|
|
591
|
+
reason: `No source captured for ${symbol.name}`,
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
const tree = state.parser.parse(symbol.source);
|
|
595
|
+
const fnNode = findCallableNode(tree.rootNode);
|
|
596
|
+
if (!fnNode) {
|
|
597
|
+
return {
|
|
598
|
+
language: "typescript",
|
|
599
|
+
symbol_name: symbol.name,
|
|
600
|
+
symbol_kind: symbol.kind,
|
|
601
|
+
file: symbol.file,
|
|
602
|
+
line: symbol.start_line,
|
|
603
|
+
resolved: false,
|
|
604
|
+
confidence: "low",
|
|
605
|
+
alias_chain: [],
|
|
606
|
+
reason: `Could not parse function defaults for ${symbol.name}`,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
const params = fnNode.childForFieldName("parameters");
|
|
610
|
+
const defaultParameters = [];
|
|
611
|
+
if (params) {
|
|
612
|
+
for (const child of params.namedChildren) {
|
|
613
|
+
const parts = getDefaultParameterParts(child);
|
|
614
|
+
if (!parts)
|
|
615
|
+
continue;
|
|
616
|
+
const result = await evaluateValueNode(symbol.file, parts.valueNode, state);
|
|
617
|
+
const entry = {
|
|
618
|
+
name: parts.name,
|
|
619
|
+
resolved: result.resolved,
|
|
620
|
+
value_text: result.value_text,
|
|
621
|
+
confidence: computeConfidence(result.resolved, result.alias_chain, result.used_import),
|
|
622
|
+
alias_chain: result.alias_chain,
|
|
623
|
+
};
|
|
624
|
+
if (result.value_kind !== undefined)
|
|
625
|
+
entry.value_kind = result.value_kind;
|
|
626
|
+
if (result.value !== undefined)
|
|
627
|
+
entry.value = result.value;
|
|
628
|
+
if (result.reason !== undefined)
|
|
629
|
+
entry.reason = result.reason;
|
|
630
|
+
defaultParameters.push(entry);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const resolved = defaultParameters.length > 0 && defaultParameters.every((entry) => entry.resolved);
|
|
634
|
+
const flattenedChain = defaultParameters.flatMap((entry) => entry.alias_chain);
|
|
635
|
+
const match = {
|
|
636
|
+
language: "typescript",
|
|
637
|
+
symbol_name: symbol.name,
|
|
638
|
+
symbol_kind: symbol.kind,
|
|
639
|
+
file: symbol.file,
|
|
640
|
+
line: symbol.start_line,
|
|
641
|
+
resolved,
|
|
642
|
+
default_parameters: defaultParameters,
|
|
643
|
+
confidence: computeConfidence(resolved, flattenedChain, defaultParameters.some((entry) => entry.alias_chain.length > 0 && entry.confidence !== "high")),
|
|
644
|
+
alias_chain: flattenedChain,
|
|
645
|
+
};
|
|
646
|
+
if (defaultParameters.length === 0) {
|
|
647
|
+
match.reason = "Function has no default parameters";
|
|
648
|
+
}
|
|
649
|
+
return match;
|
|
650
|
+
}
|
|
651
|
+
export async function resolveTypeScriptConstantValue(repo, symbolName, options) {
|
|
652
|
+
const index = await getCodeIndex(repo);
|
|
653
|
+
if (!index) {
|
|
654
|
+
throw new Error(`Repository "${repo}" not found.`);
|
|
655
|
+
}
|
|
656
|
+
const parser = await getParser("typescript");
|
|
657
|
+
if (!parser) {
|
|
658
|
+
throw new Error("TypeScript parser unavailable");
|
|
659
|
+
}
|
|
660
|
+
const candidates = index.symbols
|
|
661
|
+
.filter((symbol) => isTypeScriptFile(symbol.file))
|
|
662
|
+
.filter((symbol) => symbol.name === symbolName)
|
|
663
|
+
.filter((symbol) => !options?.file_pattern || symbol.file.includes(options.file_pattern))
|
|
664
|
+
.filter((symbol) => ["constant", "variable", "function", "method", "hook", "component"].includes(symbol.kind))
|
|
665
|
+
.sort((a, b) => a.file.localeCompare(b.file) || a.start_line - b.start_line);
|
|
666
|
+
const state = {
|
|
667
|
+
index,
|
|
668
|
+
parser,
|
|
669
|
+
fileCache: new Map(),
|
|
670
|
+
visited: new Set(),
|
|
671
|
+
maxDepth: options?.max_depth ?? MAX_DEFAULT_DEPTH,
|
|
672
|
+
};
|
|
673
|
+
const matches = [];
|
|
674
|
+
for (const candidate of candidates) {
|
|
675
|
+
if (candidate.kind === "constant" || candidate.kind === "variable") {
|
|
676
|
+
matches.push(await resolveConstantSymbol(candidate, state));
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
matches.push(await resolveFunctionDefaults(candidate, state));
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return {
|
|
683
|
+
query: symbolName,
|
|
684
|
+
matches,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
//# sourceMappingURL=typescript-constants-tools.js.map
|