@danielblomma/cortex-mcp 0.4.5 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -42
- package/bin/cortex.mjs +32 -60
- package/package.json +15 -3
- package/scaffold/.context/ontology.cypher +47 -0
- package/scaffold/.githooks/post-commit +14 -0
- package/scaffold/.githooks/post-rewrite +23 -0
- package/scaffold/mcp/package-lock.json +16 -16
- package/scaffold/mcp/package.json +4 -1
- package/scaffold/mcp/src/contextEntities.ts +311 -0
- package/scaffold/mcp/src/defaults.ts +6 -0
- package/scaffold/mcp/src/embed.ts +163 -37
- package/scaffold/mcp/src/frontmatter.ts +39 -0
- package/scaffold/mcp/src/graph.ts +253 -130
- package/scaffold/mcp/src/graphMetrics.ts +12 -0
- package/scaffold/mcp/src/impactPresentation.ts +202 -0
- package/scaffold/mcp/src/impactRanking.ts +237 -0
- package/scaffold/mcp/src/impactResponse.ts +47 -0
- package/scaffold/mcp/src/impactResults.ts +173 -0
- package/scaffold/mcp/src/impactSeed.ts +33 -0
- package/scaffold/mcp/src/impactTraversal.ts +83 -0
- package/scaffold/mcp/src/jsonl.ts +34 -0
- package/scaffold/mcp/src/loadGraph.ts +345 -86
- package/scaffold/mcp/src/paths.ts +17 -1
- package/scaffold/mcp/src/presets.ts +137 -0
- package/scaffold/mcp/src/relatedResponse.ts +30 -0
- package/scaffold/mcp/src/relatedTraversal.ts +101 -0
- package/scaffold/mcp/src/rules.ts +27 -0
- package/scaffold/mcp/src/search.ts +186 -455
- package/scaffold/mcp/src/searchCore.ts +274 -0
- package/scaffold/mcp/src/searchResults.ts +133 -0
- package/scaffold/mcp/src/server.ts +95 -3
- package/scaffold/mcp/src/types.ts +82 -3
- package/scaffold/scripts/context.sh +12 -46
- package/scaffold/scripts/dashboard.mjs +797 -0
- package/scaffold/scripts/dashboard.sh +13 -0
- package/scaffold/scripts/ingest.mjs +2227 -59
- package/scaffold/scripts/install-git-hooks.sh +3 -1
- package/scaffold/scripts/memory-compile.mjs +232 -0
- package/scaffold/scripts/memory-compile.sh +20 -0
- package/scaffold/scripts/memory-lint.mjs +375 -0
- package/scaffold/scripts/memory-lint.sh +20 -0
- package/scaffold/scripts/parsers/config.mjs +178 -0
- package/scaffold/scripts/parsers/cpp.mjs +316 -0
- package/scaffold/scripts/parsers/dotnet/VbNetParser/Program.cs +374 -0
- package/scaffold/scripts/parsers/dotnet/VbNetParser/VbNetParser.csproj +13 -0
- package/scaffold/scripts/parsers/javascript/ast.mjs +61 -0
- package/scaffold/scripts/parsers/javascript/calls.mjs +53 -0
- package/scaffold/scripts/parsers/javascript/chunks.mjs +388 -0
- package/scaffold/scripts/parsers/javascript/imports.mjs +162 -0
- package/scaffold/scripts/parsers/javascript/patterns.mjs +82 -0
- package/scaffold/scripts/parsers/javascript/scope-analysis.mjs +3 -0
- package/scaffold/scripts/parsers/javascript/scope-builder.mjs +305 -0
- package/scaffold/scripts/parsers/javascript/scope-resolver.mjs +82 -0
- package/scaffold/scripts/parsers/javascript.mjs +27 -350
- package/scaffold/scripts/parsers/resources.mjs +166 -0
- package/scaffold/scripts/parsers/rust.mjs +515 -0
- package/scaffold/scripts/parsers/sql.mjs +137 -0
- package/scaffold/scripts/parsers/vbnet.mjs +143 -0
- package/scaffold/scripts/status.sh +0 -7
- package/scaffold/scripts/capture-note.sh +0 -55
- package/scaffold/scripts/plan-state-engine.cjs +0 -310
- package/scaffold/scripts/plan-state.sh +0 -71
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using Microsoft.CodeAnalysis;
|
|
3
|
+
using Microsoft.CodeAnalysis.Text;
|
|
4
|
+
using Microsoft.CodeAnalysis.VisualBasic;
|
|
5
|
+
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
|
|
6
|
+
|
|
7
|
+
var options = ParseArgs(args);
|
|
8
|
+
if (string.IsNullOrWhiteSpace(options.FilePath))
|
|
9
|
+
{
|
|
10
|
+
Console.Error.WriteLine("Missing required --file argument.");
|
|
11
|
+
Environment.Exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
var source = options.UseStdin
|
|
15
|
+
? Console.In.ReadToEnd()
|
|
16
|
+
: File.ReadAllText(options.FilePath);
|
|
17
|
+
|
|
18
|
+
var parseResult = ParseVisualBasic(source, options.FilePath, options.Language);
|
|
19
|
+
var json = JsonSerializer.Serialize(parseResult, new JsonSerializerOptions
|
|
20
|
+
{
|
|
21
|
+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
22
|
+
WriteIndented = false
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
Console.WriteLine(json);
|
|
26
|
+
|
|
27
|
+
return;
|
|
28
|
+
|
|
29
|
+
static ParseOptions ParseArgs(string[] args)
|
|
30
|
+
{
|
|
31
|
+
var options = new ParseOptions();
|
|
32
|
+
for (var index = 0; index < args.Length; index += 1)
|
|
33
|
+
{
|
|
34
|
+
var arg = args[index];
|
|
35
|
+
switch (arg)
|
|
36
|
+
{
|
|
37
|
+
case "--stdin":
|
|
38
|
+
options.UseStdin = true;
|
|
39
|
+
break;
|
|
40
|
+
case "--file":
|
|
41
|
+
if (index + 1 < args.Length)
|
|
42
|
+
{
|
|
43
|
+
options.FilePath = args[++index];
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
case "--language":
|
|
47
|
+
if (index + 1 < args.Length)
|
|
48
|
+
{
|
|
49
|
+
options.Language = args[++index];
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return options;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static ParserOutput ParseVisualBasic(string source, string filePath, string language)
|
|
59
|
+
{
|
|
60
|
+
var tree = VisualBasicSyntaxTree.ParseText(SourceText.From(source), path: filePath);
|
|
61
|
+
var root = tree.GetCompilationUnitRoot();
|
|
62
|
+
var diagnostics = tree.GetDiagnostics()
|
|
63
|
+
.Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)
|
|
64
|
+
.Select(diagnostic => new ParserError(
|
|
65
|
+
diagnostic.GetMessage(),
|
|
66
|
+
diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1,
|
|
67
|
+
diagnostic.Location.GetLineSpan().StartLinePosition.Character + 1
|
|
68
|
+
))
|
|
69
|
+
.ToList();
|
|
70
|
+
|
|
71
|
+
if (diagnostics.Count > 0)
|
|
72
|
+
{
|
|
73
|
+
return new ParserOutput(new List<ChunkOutput>(), diagnostics);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
var collector = new VbChunkCollector(tree, root, source, language);
|
|
77
|
+
return new ParserOutput(collector.Collect(), diagnostics);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
sealed class VbChunkCollector
|
|
81
|
+
{
|
|
82
|
+
private readonly SyntaxTree _tree;
|
|
83
|
+
private readonly CompilationUnitSyntax _root;
|
|
84
|
+
private readonly string _source;
|
|
85
|
+
private readonly string _language;
|
|
86
|
+
private readonly string[] _imports;
|
|
87
|
+
|
|
88
|
+
public VbChunkCollector(SyntaxTree tree, CompilationUnitSyntax root, string source, string language)
|
|
89
|
+
{
|
|
90
|
+
_tree = tree;
|
|
91
|
+
_root = root;
|
|
92
|
+
_source = source;
|
|
93
|
+
_language = language;
|
|
94
|
+
_imports = root.Imports
|
|
95
|
+
.SelectMany(importStatement => importStatement.ImportsClauses)
|
|
96
|
+
.Select(GetImportName)
|
|
97
|
+
.Where(name => !string.IsNullOrWhiteSpace(name))
|
|
98
|
+
.Distinct(StringComparer.Ordinal)
|
|
99
|
+
.ToArray();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public List<ChunkOutput> Collect()
|
|
103
|
+
{
|
|
104
|
+
var chunks = new List<ChunkOutput>();
|
|
105
|
+
|
|
106
|
+
foreach (var declaration in _root.Members)
|
|
107
|
+
{
|
|
108
|
+
CollectMember(chunks, declaration, null);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return chunks;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private void CollectMember(List<ChunkOutput> chunks, StatementSyntax member, string? parentName)
|
|
115
|
+
{
|
|
116
|
+
switch (member)
|
|
117
|
+
{
|
|
118
|
+
case NamespaceBlockSyntax namespaceBlock:
|
|
119
|
+
foreach (var nested in namespaceBlock.Members)
|
|
120
|
+
{
|
|
121
|
+
CollectMember(chunks, nested, parentName);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
|
|
125
|
+
case ClassBlockSyntax classBlock:
|
|
126
|
+
AddTypeChunk(chunks, classBlock.ClassStatement.Identifier.Text, "class", classBlock, parentName);
|
|
127
|
+
foreach (var nested in classBlock.Members)
|
|
128
|
+
{
|
|
129
|
+
CollectTypeMember(chunks, nested, classBlock.ClassStatement.Identifier.Text);
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
|
|
133
|
+
case ModuleBlockSyntax moduleBlock:
|
|
134
|
+
AddTypeChunk(chunks, moduleBlock.ModuleStatement.Identifier.Text, "module", moduleBlock, parentName);
|
|
135
|
+
foreach (var nested in moduleBlock.Members)
|
|
136
|
+
{
|
|
137
|
+
CollectTypeMember(chunks, nested, moduleBlock.ModuleStatement.Identifier.Text);
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
|
|
141
|
+
case StructureBlockSyntax structureBlock:
|
|
142
|
+
AddTypeChunk(chunks, structureBlock.StructureStatement.Identifier.Text, "structure", structureBlock, parentName);
|
|
143
|
+
foreach (var nested in structureBlock.Members)
|
|
144
|
+
{
|
|
145
|
+
CollectTypeMember(chunks, nested, structureBlock.StructureStatement.Identifier.Text);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
|
|
149
|
+
case InterfaceBlockSyntax interfaceBlock:
|
|
150
|
+
AddTypeChunk(chunks, interfaceBlock.InterfaceStatement.Identifier.Text, "interface", interfaceBlock, parentName);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private void CollectTypeMember(List<ChunkOutput> chunks, StatementSyntax member, string parentTypeName)
|
|
156
|
+
{
|
|
157
|
+
switch (member)
|
|
158
|
+
{
|
|
159
|
+
case MethodBlockSyntax methodBlock:
|
|
160
|
+
AddMethodChunk(chunks, methodBlock, parentTypeName);
|
|
161
|
+
break;
|
|
162
|
+
case ConstructorBlockSyntax constructorBlock:
|
|
163
|
+
AddConstructorChunk(chunks, constructorBlock, parentTypeName);
|
|
164
|
+
break;
|
|
165
|
+
case PropertyBlockSyntax propertyBlock:
|
|
166
|
+
AddPropertyChunk(chunks, propertyBlock, parentTypeName);
|
|
167
|
+
break;
|
|
168
|
+
case PropertyStatementSyntax propertyStatement:
|
|
169
|
+
AddSimplePropertyChunk(chunks, propertyStatement, parentTypeName);
|
|
170
|
+
break;
|
|
171
|
+
case EventBlockSyntax eventBlock:
|
|
172
|
+
AddTypeChunk(chunks, $"{parentTypeName}.{eventBlock.EventStatement.Identifier.Text}", "event", eventBlock, null);
|
|
173
|
+
break;
|
|
174
|
+
case FieldDeclarationSyntax fieldDeclaration:
|
|
175
|
+
foreach (var declarator in fieldDeclaration.Declarators)
|
|
176
|
+
{
|
|
177
|
+
foreach (var name in declarator.Names)
|
|
178
|
+
{
|
|
179
|
+
AddTypeChunk(chunks, $"{parentTypeName}.{name.Identifier.Text}", "field", fieldDeclaration, null);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
case ClassBlockSyntax nestedClass:
|
|
184
|
+
AddTypeChunk(chunks, $"{parentTypeName}.{nestedClass.ClassStatement.Identifier.Text}", "class", nestedClass, null);
|
|
185
|
+
foreach (var nested in nestedClass.Members)
|
|
186
|
+
{
|
|
187
|
+
CollectTypeMember(chunks, nested, nestedClass.ClassStatement.Identifier.Text);
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private void AddTypeChunk(List<ChunkOutput> chunks, string name, string kind, SyntaxNode node, string? parentName)
|
|
194
|
+
{
|
|
195
|
+
chunks.Add(BuildChunk(
|
|
196
|
+
parentName is null ? name : $"{parentName}.{name}",
|
|
197
|
+
kind,
|
|
198
|
+
BuildSignature(kind, name, node),
|
|
199
|
+
node,
|
|
200
|
+
GetCalls(node),
|
|
201
|
+
_imports,
|
|
202
|
+
IsExported(node)
|
|
203
|
+
));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private void AddMethodChunk(List<ChunkOutput> chunks, MethodBlockSyntax node, string parentTypeName)
|
|
207
|
+
{
|
|
208
|
+
var statement = node.BlockStatement;
|
|
209
|
+
var name = $"{parentTypeName}.{statement.Identifier.Text}";
|
|
210
|
+
var kind = statement.Kind() == SyntaxKind.SubStatement ? "method" : "function";
|
|
211
|
+
chunks.Add(BuildChunk(
|
|
212
|
+
name,
|
|
213
|
+
kind,
|
|
214
|
+
statement.ToString(),
|
|
215
|
+
node,
|
|
216
|
+
GetCalls(node),
|
|
217
|
+
_imports,
|
|
218
|
+
IsExported(statement)
|
|
219
|
+
));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private void AddConstructorChunk(List<ChunkOutput> chunks, ConstructorBlockSyntax node, string parentTypeName)
|
|
223
|
+
{
|
|
224
|
+
chunks.Add(BuildChunk(
|
|
225
|
+
$"{parentTypeName}.New",
|
|
226
|
+
"constructor",
|
|
227
|
+
node.BlockStatement.ToString(),
|
|
228
|
+
node,
|
|
229
|
+
GetCalls(node),
|
|
230
|
+
_imports,
|
|
231
|
+
IsExported(node.BlockStatement)
|
|
232
|
+
));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private void AddPropertyChunk(List<ChunkOutput> chunks, PropertyBlockSyntax node, string parentTypeName)
|
|
236
|
+
{
|
|
237
|
+
chunks.Add(BuildChunk(
|
|
238
|
+
$"{parentTypeName}.{node.PropertyStatement.Identifier.Text}",
|
|
239
|
+
"property",
|
|
240
|
+
node.PropertyStatement.ToString(),
|
|
241
|
+
node,
|
|
242
|
+
GetCalls(node),
|
|
243
|
+
_imports,
|
|
244
|
+
IsExported(node.PropertyStatement)
|
|
245
|
+
));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private void AddSimplePropertyChunk(List<ChunkOutput> chunks, PropertyStatementSyntax node, string parentTypeName)
|
|
249
|
+
{
|
|
250
|
+
chunks.Add(BuildChunk(
|
|
251
|
+
$"{parentTypeName}.{node.Identifier.Text}",
|
|
252
|
+
"property",
|
|
253
|
+
node.ToString(),
|
|
254
|
+
node,
|
|
255
|
+
Array.Empty<string>(),
|
|
256
|
+
_imports,
|
|
257
|
+
IsExported(node)
|
|
258
|
+
));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private ChunkOutput BuildChunk(
|
|
262
|
+
string name,
|
|
263
|
+
string kind,
|
|
264
|
+
string signature,
|
|
265
|
+
SyntaxNode node,
|
|
266
|
+
IReadOnlyCollection<string> calls,
|
|
267
|
+
IReadOnlyCollection<string> imports,
|
|
268
|
+
bool exported)
|
|
269
|
+
{
|
|
270
|
+
var span = node.GetLocation().GetLineSpan();
|
|
271
|
+
return new ChunkOutput(
|
|
272
|
+
name,
|
|
273
|
+
kind,
|
|
274
|
+
signature,
|
|
275
|
+
node.ToFullString(),
|
|
276
|
+
span.StartLinePosition.Line + 1,
|
|
277
|
+
span.EndLinePosition.Line + 1,
|
|
278
|
+
_language,
|
|
279
|
+
exported,
|
|
280
|
+
calls.ToArray(),
|
|
281
|
+
imports.ToArray()
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private static string BuildSignature(string kind, string name, SyntaxNode node)
|
|
286
|
+
{
|
|
287
|
+
return node switch
|
|
288
|
+
{
|
|
289
|
+
ClassBlockSyntax classBlock => classBlock.ClassStatement.ToString(),
|
|
290
|
+
ModuleBlockSyntax moduleBlock => moduleBlock.ModuleStatement.ToString(),
|
|
291
|
+
StructureBlockSyntax structureBlock => structureBlock.StructureStatement.ToString(),
|
|
292
|
+
InterfaceBlockSyntax interfaceBlock => interfaceBlock.InterfaceStatement.ToString(),
|
|
293
|
+
_ => $"{kind} {name}"
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private static string GetImportName(ImportsClauseSyntax clause)
|
|
298
|
+
{
|
|
299
|
+
return clause switch
|
|
300
|
+
{
|
|
301
|
+
SimpleImportsClauseSyntax simpleClause => simpleClause.Name.ToString(),
|
|
302
|
+
XmlNamespaceImportsClauseSyntax xmlClause => xmlClause.XmlNamespace.ToString(),
|
|
303
|
+
AliasImportsClauseSyntax aliasClause => aliasClause.Name.ToString(),
|
|
304
|
+
_ => clause.ToString()
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private static bool IsExported(SyntaxNode node)
|
|
309
|
+
{
|
|
310
|
+
SyntaxTokenList modifiers = node switch
|
|
311
|
+
{
|
|
312
|
+
TypeStatementSyntax typeStatement => typeStatement.Modifiers,
|
|
313
|
+
MethodStatementSyntax methodStatement => methodStatement.Modifiers,
|
|
314
|
+
PropertyStatementSyntax propertyStatement => propertyStatement.Modifiers,
|
|
315
|
+
EventStatementSyntax eventStatement => eventStatement.Modifiers,
|
|
316
|
+
FieldDeclarationSyntax fieldDeclaration => fieldDeclaration.Modifiers,
|
|
317
|
+
_ => default
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
if (modifiers.Count == 0)
|
|
321
|
+
{
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PublicKeyword));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private static IReadOnlyCollection<string> GetCalls(SyntaxNode node)
|
|
329
|
+
{
|
|
330
|
+
return node.DescendantNodes()
|
|
331
|
+
.OfType<InvocationExpressionSyntax>()
|
|
332
|
+
.Select(invocation => invocation.Expression)
|
|
333
|
+
.Select(GetInvocationName)
|
|
334
|
+
.Where(name => !string.IsNullOrWhiteSpace(name))
|
|
335
|
+
.Distinct(StringComparer.Ordinal)
|
|
336
|
+
.ToArray();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
private static string? GetInvocationName(ExpressionSyntax expression)
|
|
340
|
+
{
|
|
341
|
+
return expression switch
|
|
342
|
+
{
|
|
343
|
+
IdentifierNameSyntax identifier => identifier.Identifier.Text,
|
|
344
|
+
GenericNameSyntax genericName => genericName.Identifier.Text,
|
|
345
|
+
MemberAccessExpressionSyntax memberAccess => memberAccess.Name.Identifier.Text,
|
|
346
|
+
InvocationExpressionSyntax nestedInvocation => GetInvocationName(nestedInvocation.Expression),
|
|
347
|
+
_ => null
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
sealed record ParseOptions
|
|
353
|
+
{
|
|
354
|
+
public bool UseStdin { get; set; }
|
|
355
|
+
public string FilePath { get; set; } = "";
|
|
356
|
+
public string Language { get; set; } = "vbnet";
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
sealed record ChunkOutput(
|
|
360
|
+
string Name,
|
|
361
|
+
string Kind,
|
|
362
|
+
string Signature,
|
|
363
|
+
string Body,
|
|
364
|
+
int StartLine,
|
|
365
|
+
int EndLine,
|
|
366
|
+
string Language,
|
|
367
|
+
bool Exported,
|
|
368
|
+
string[] Calls,
|
|
369
|
+
string[] Imports
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
sealed record ParserError(string Message, int Line, int Column);
|
|
373
|
+
|
|
374
|
+
sealed record ParserOutput(List<ChunkOutput> Chunks, List<ParserError> Errors);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
|
2
|
+
<PropertyGroup>
|
|
3
|
+
<OutputType>Exe</OutputType>
|
|
4
|
+
<TargetFramework>net8.0</TargetFramework>
|
|
5
|
+
<ImplicitUsings>enable</ImplicitUsings>
|
|
6
|
+
<Nullable>enable</Nullable>
|
|
7
|
+
<LangVersion>latest</LangVersion>
|
|
8
|
+
</PropertyGroup>
|
|
9
|
+
|
|
10
|
+
<ItemGroup>
|
|
11
|
+
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.11.0" />
|
|
12
|
+
</ItemGroup>
|
|
13
|
+
</Project>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Parser } from "acorn";
|
|
2
|
+
import tsPlugin from "acorn-typescript";
|
|
3
|
+
import { base } from "acorn-walk";
|
|
4
|
+
|
|
5
|
+
const tsNodeHandlers = {
|
|
6
|
+
TSAsExpression(node, st, visit) { visit(node.expression, st); },
|
|
7
|
+
TSTypeAnnotation() {},
|
|
8
|
+
TSTypeParameterInstantiation() {},
|
|
9
|
+
TSTypeParameterDeclaration() {},
|
|
10
|
+
TSTypeReference() {},
|
|
11
|
+
TSInterfaceDeclaration() {},
|
|
12
|
+
TSTypeAliasDeclaration() {},
|
|
13
|
+
TSEnumDeclaration() {},
|
|
14
|
+
TSModuleDeclaration() {},
|
|
15
|
+
TSDeclareFunction() {},
|
|
16
|
+
TSPropertySignature() {},
|
|
17
|
+
TSMethodSignature() {},
|
|
18
|
+
TSIndexSignature() {},
|
|
19
|
+
TSTypeLiteral() {},
|
|
20
|
+
TSUnionType() {},
|
|
21
|
+
TSIntersectionType() {},
|
|
22
|
+
TSArrayType() {},
|
|
23
|
+
TSTupleType() {},
|
|
24
|
+
TSOptionalType() {},
|
|
25
|
+
TSRestType() {},
|
|
26
|
+
TSFunctionType() {},
|
|
27
|
+
TSConstructorType() {},
|
|
28
|
+
TSNonNullExpression(node, st, visit) { visit(node.expression, st); },
|
|
29
|
+
TSInstantiationExpression(node, st, visit) { visit(node.expression, st); }
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
Object.assign(base, tsNodeHandlers);
|
|
33
|
+
|
|
34
|
+
export const WALK_BASE = base;
|
|
35
|
+
|
|
36
|
+
export function parseAst(code) {
|
|
37
|
+
try {
|
|
38
|
+
const TSParser = Parser.extend(tsPlugin());
|
|
39
|
+
const ast = TSParser.parse(code, {
|
|
40
|
+
ecmaVersion: "latest",
|
|
41
|
+
sourceType: "module",
|
|
42
|
+
locations: true,
|
|
43
|
+
allowHashBang: true,
|
|
44
|
+
allowImportExportEverywhere: true,
|
|
45
|
+
allowAwaitOutsideFunction: true
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return { ast, errors: [] };
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return {
|
|
51
|
+
ast: null,
|
|
52
|
+
errors: [
|
|
53
|
+
{
|
|
54
|
+
message: `Parse error: ${error.message}`,
|
|
55
|
+
line: error.loc?.line,
|
|
56
|
+
column: error.loc?.column
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { simple as walkSimple } from "acorn-walk";
|
|
2
|
+
|
|
3
|
+
import { WALK_BASE } from "./ast.mjs";
|
|
4
|
+
|
|
5
|
+
export function extractCalls(bodyNode) {
|
|
6
|
+
if (!bodyNode) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const calls = new Set();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
walkSimple(
|
|
14
|
+
bodyNode,
|
|
15
|
+
{
|
|
16
|
+
CallExpression(node) {
|
|
17
|
+
const callee = node.callee;
|
|
18
|
+
|
|
19
|
+
if (callee.type === "Identifier") {
|
|
20
|
+
calls.add(callee.name);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (callee.type === "MemberExpression" && callee.property.type === "Identifier") {
|
|
25
|
+
const objectName = getObjectName(callee.object);
|
|
26
|
+
calls.add(objectName ? `${objectName}.${callee.property.name}` : callee.property.name);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
WALK_BASE
|
|
31
|
+
);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
// Ignore walk errors for incomplete ASTs.
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return [...calls].sort();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getObjectName(node) {
|
|
40
|
+
if (node.type === "Identifier") {
|
|
41
|
+
return node.name;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (node.type === "ThisExpression") {
|
|
45
|
+
return "this";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (node.type === "MemberExpression" && node.property.type === "Identifier") {
|
|
49
|
+
return node.property.name;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null;
|
|
53
|
+
}
|