1use anyhow::Result;
2use infigraph_core::lang::{CustomEdgeDef, LanguagePack, LanguageRegistry};
3
4const PYTHON_ENTITIES: &str = include_str!("../languages/python/entities.scm");
5const PYTHON_RELATIONS: &str = include_str!("../languages/python/relations.scm");
6
7const RUST_ENTITIES: &str = include_str!("../languages/rust/entities.scm");
8const RUST_RELATIONS: &str = include_str!("../languages/rust/relations.scm");
9
10const TYPESCRIPT_ENTITIES: &str = include_str!("../languages/typescript/entities.scm");
11const TYPESCRIPT_RELATIONS: &str = include_str!("../languages/typescript/relations.scm");
12
13const JAVASCRIPT_ENTITIES: &str = include_str!("../languages/javascript/entities.scm");
14const JAVASCRIPT_RELATIONS: &str = include_str!("../languages/javascript/relations.scm");
15
16const GO_ENTITIES: &str = include_str!("../languages/go/entities.scm");
17const GO_RELATIONS: &str = include_str!("../languages/go/relations.scm");
18
19const JAVA_ENTITIES: &str = include_str!("../languages/java/entities.scm");
20const JAVA_RELATIONS: &str = include_str!("../languages/java/relations.scm");
21
22const C_ENTITIES: &str = include_str!("../languages/c/entities.scm");
23const C_RELATIONS: &str = include_str!("../languages/c/relations.scm");
24
25const CPP_ENTITIES: &str = include_str!("../languages/cpp/entities.scm");
26const CPP_RELATIONS: &str = include_str!("../languages/cpp/relations.scm");
27
28const RUBY_ENTITIES: &str = include_str!("../languages/ruby/entities.scm");
29const RUBY_RELATIONS: &str = include_str!("../languages/ruby/relations.scm");
30
31const PHP_ENTITIES: &str = include_str!("../languages/php/entities.scm");
32const PHP_RELATIONS: &str = include_str!("../languages/php/relations.scm");
33
34const SWIFT_ENTITIES: &str = include_str!("../languages/swift/entities.scm");
35const SWIFT_RELATIONS: &str = include_str!("../languages/swift/relations.scm");
36
37const KOTLIN_ENTITIES: &str = include_str!("../languages/kotlin/entities.scm");
38const KOTLIN_RELATIONS: &str = include_str!("../languages/kotlin/relations.scm");
39
40const CSHARP_ENTITIES: &str = include_str!("../languages/csharp/entities.scm");
41const CSHARP_RELATIONS: &str = include_str!("../languages/csharp/relations.scm");
42
43const SCALA_ENTITIES: &str = include_str!("../languages/scala/entities.scm");
44const SCALA_RELATIONS: &str = include_str!("../languages/scala/relations.scm");
45
46const LUA_ENTITIES: &str = include_str!("../languages/lua/entities.scm");
47const LUA_RELATIONS: &str = include_str!("../languages/lua/relations.scm");
48
49const ZIG_ENTITIES: &str = include_str!("../languages/zig/entities.scm");
50const ZIG_RELATIONS: &str = include_str!("../languages/zig/relations.scm");
51
52const ELIXIR_ENTITIES: &str = include_str!("../languages/elixir/entities.scm");
53const ELIXIR_RELATIONS: &str = include_str!("../languages/elixir/relations.scm");
54
55const DART_ENTITIES: &str = include_str!("../languages/dart/entities.scm");
56const DART_RELATIONS: &str = include_str!("../languages/dart/relations.scm");
57
58const OBJC_ENTITIES: &str = include_str!("../languages/objc/entities.scm");
59const OBJC_RELATIONS: &str = include_str!("../languages/objc/relations.scm");
60
61const HASKELL_ENTITIES: &str = include_str!("../languages/haskell/entities.scm");
62const HASKELL_RELATIONS: &str = include_str!("../languages/haskell/relations.scm");
63
64const PERL_ENTITIES: &str = include_str!("../languages/perl/entities.scm");
65const PERL_RELATIONS: &str = include_str!("../languages/perl/relations.scm");
66
67const R_ENTITIES: &str = include_str!("../languages/r/entities.scm");
68const R_RELATIONS: &str = include_str!("../languages/r/relations.scm");
69
70const OCAML_ENTITIES: &str = include_str!("../languages/ocaml/entities.scm");
71const OCAML_RELATIONS: &str = include_str!("../languages/ocaml/relations.scm");
72
73const BASH_ENTITIES: &str = include_str!("../languages/bash/entities.scm");
74const BASH_RELATIONS: &str = include_str!("../languages/bash/relations.scm");
75
76const SQL_ENTITIES: &str = include_str!("../languages/sql/entities.scm");
77const SQL_RELATIONS: &str = include_str!("../languages/sql/relations.scm");
78
79const JULIA_ENTITIES: &str = include_str!("../languages/julia/entities.scm");
80const JULIA_RELATIONS: &str = include_str!("../languages/julia/relations.scm");
81
82const PROTO_ENTITIES: &str = include_str!("../languages/proto/entities.scm");
83const PROTO_RELATIONS: &str = include_str!("../languages/proto/relations.scm");
84
85const POWERSHELL_ENTITIES: &str = include_str!("../languages/powershell/entities.scm");
86const POWERSHELL_RELATIONS: &str = include_str!("../languages/powershell/relations.scm");
87
88const VERILOG_ENTITIES: &str = include_str!("../languages/verilog/entities.scm");
89const VERILOG_RELATIONS: &str = include_str!("../languages/verilog/relations.scm");
90
91const HCL_ENTITIES: &str = include_str!("../languages/hcl/entities.scm");
92const HCL_RELATIONS: &str = include_str!("../languages/hcl/relations.scm");
93
94const TOML_ENTITIES: &str = include_str!("../languages/toml/entities.scm");
95const TOML_RELATIONS: &str = include_str!("../languages/toml/relations.scm");
96
97const YAML_ENTITIES: &str = include_str!("../languages/yaml/entities.scm");
98const YAML_RELATIONS: &str = include_str!("../languages/yaml/relations.scm");
99
100const ERLANG_ENTITIES: &str = include_str!("../languages/erlang/entities.scm");
101const ERLANG_RELATIONS: &str = include_str!("../languages/erlang/relations.scm");
102
103const DOCKERFILE_ENTITIES: &str = include_str!("../languages/dockerfile/entities.scm");
104const DOCKERFILE_RELATIONS: &str = include_str!("../languages/dockerfile/relations.scm");
105
106const FORTRAN_ENTITIES: &str = include_str!("../languages/fortran/entities.scm");
107const FORTRAN_RELATIONS: &str = include_str!("../languages/fortran/relations.scm");
108
109const NIX_ENTITIES: &str = include_str!("../languages/nix/entities.scm");
110const NIX_RELATIONS: &str = include_str!("../languages/nix/relations.scm");
111
112const SVELTE_ENTITIES: &str = include_str!("../languages/svelte/entities.scm");
113const SVELTE_RELATIONS: &str = include_str!("../languages/svelte/relations.scm");
114
115const FSHARP_ENTITIES: &str = include_str!("../languages/fsharp/entities.scm");
116const FSHARP_RELATIONS: &str = include_str!("../languages/fsharp/relations.scm");
117
118const GROOVY_ENTITIES: &str = include_str!("../languages/groovy/entities.scm");
119const GROOVY_RELATIONS: &str = include_str!("../languages/groovy/relations.scm");
120
121const CSS_ENTITIES: &str = include_str!("../languages/css/entities.scm");
122const CSS_RELATIONS: &str = include_str!("../languages/css/relations.scm");
123
124const HTML_ENTITIES: &str = include_str!("../languages/html/entities.scm");
125const HTML_RELATIONS: &str = include_str!("../languages/html/relations.scm");
126
127const JSON_ENTITIES: &str = include_str!("../languages/json/entities.scm");
128const JSON_RELATIONS: &str = include_str!("../languages/json/relations.scm");
129
130const XML_ENTITIES: &str = include_str!("../languages/xml/entities.scm");
131const XML_RELATIONS: &str = include_str!("../languages/xml/relations.scm");
132
133const MAKEFILE_ENTITIES: &str = include_str!("../languages/makefile/entities.scm");
134const MAKEFILE_RELATIONS: &str = include_str!("../languages/makefile/relations.scm");
135
136const CMAKE_ENTITIES: &str = include_str!("../languages/cmake/entities.scm");
137const CMAKE_RELATIONS: &str = include_str!("../languages/cmake/relations.scm");
138
139const GRAPHQL_ENTITIES: &str = include_str!("../languages/graphql/entities.scm");
140const GRAPHQL_RELATIONS: &str = include_str!("../languages/graphql/relations.scm");
141
142const GLSL_ENTITIES: &str = include_str!("../languages/glsl/entities.scm");
143const GLSL_RELATIONS: &str = include_str!("../languages/glsl/relations.scm");
144
145const COMMONLISP_ENTITIES: &str = include_str!("../languages/commonlisp/entities.scm");
146const COMMONLISP_RELATIONS: &str = include_str!("../languages/commonlisp/relations.scm");
147
148const ELM_ENTITIES: &str = include_str!("../languages/elm/entities.scm");
149const ELM_RELATIONS: &str = include_str!("../languages/elm/relations.scm");
150
151const ELISP_ENTITIES: &str = include_str!("../languages/elisp/entities.scm");
152const ELISP_RELATIONS: &str = include_str!("../languages/elisp/relations.scm");
153
154const INI_ENTITIES: &str = include_str!("../languages/ini/entities.scm");
155const INI_RELATIONS: &str = include_str!("../languages/ini/relations.scm");
156
157const TSX_ENTITIES: &str = include_str!("../languages/tsx/entities.scm");
158const TSX_RELATIONS: &str = include_str!("../languages/tsx/relations.scm");
159
160const STARLARK_ENTITIES: &str = include_str!("../languages/starlark/entities.scm");
161const STARLARK_RELATIONS: &str = include_str!("../languages/starlark/relations.scm");
162
163const MATLAB_ENTITIES: &str = include_str!("../languages/matlab/entities.scm");
164const MATLAB_RELATIONS: &str = include_str!("../languages/matlab/relations.scm");
165
166const MARKDOWN_ENTITIES: &str = include_str!("../languages/markdown/entities.scm");
167const MARKDOWN_RELATIONS: &str = include_str!("../languages/markdown/relations.scm");
168
169const CLOJURE_ENTITIES: &str = include_str!("../languages/clojure/entities.scm");
170const CLOJURE_RELATIONS: &str = include_str!("../languages/clojure/relations.scm");
171
172const CUDA_ENTITIES: &str = include_str!("../languages/cuda/entities.scm");
173const CUDA_RELATIONS: &str = include_str!("../languages/cuda/relations.scm");
174
175const PASCAL_ENTITIES: &str = include_str!("../languages/pascal/entities.scm");
176const PASCAL_RELATIONS: &str = include_str!("../languages/pascal/relations.scm");
177
178const VB6_ENTITIES: &str = include_str!("../languages/vb6/entities.scm");
179const VB6_RELATIONS: &str = include_str!("../languages/vb6/relations.scm");
180
181pub fn bundled_registry() -> Result<LanguageRegistry> {
183 let mut registry = LanguageRegistry::new();
184
185 registry.register(python_pack()?);
186
187 match rust_pack() {
189 Ok(pack) => registry.register(pack),
190 Err(e) => eprintln!("warning: failed to load Rust language pack: {e}"),
191 }
192 match typescript_pack() {
193 Ok(pack) => registry.register(pack),
194 Err(e) => eprintln!("warning: failed to load TypeScript language pack: {e}"),
195 }
196 if let Ok(pack) = javascript_pack() {
197 registry.register(pack);
198 } else {
199 eprintln!("warning: failed to load JavaScript language pack");
200 }
201 if let Ok(pack) = go_pack() {
202 registry.register(pack);
203 } else {
204 eprintln!("warning: failed to load Go language pack");
205 }
206 if let Ok(pack) = java_pack() {
207 registry.register(pack);
208 } else {
209 eprintln!("warning: failed to load Java language pack");
210 }
211 match c_pack() {
212 Ok(pack) => registry.register(pack),
213 Err(e) => eprintln!("warning: failed to load C language pack: {e}"),
214 }
215 match cpp_pack() {
216 Ok(pack) => registry.register(pack),
217 Err(e) => eprintln!("warning: failed to load C++ language pack: {e}"),
218 }
219 match ruby_pack() {
220 Ok(pack) => registry.register(pack),
221 Err(e) => eprintln!("warning: failed to load Ruby language pack: {e}"),
222 }
223 match php_pack() {
224 Ok(pack) => registry.register(pack),
225 Err(e) => eprintln!("warning: failed to load PHP language pack: {e}"),
226 }
227 match swift_pack() {
228 Ok(pack) => registry.register(pack),
229 Err(e) => eprintln!("warning: failed to load Swift language pack: {e}"),
230 }
231 match kotlin_pack() {
232 Ok(pack) => registry.register(pack),
233 Err(e) => eprintln!("warning: failed to load Kotlin language pack: {e}"),
234 }
235 match csharp_pack() {
236 Ok(pack) => registry.register(pack),
237 Err(e) => eprintln!("warning: failed to load C# language pack: {e}"),
238 }
239 match scala_pack() {
240 Ok(pack) => registry.register(pack),
241 Err(e) => eprintln!("warning: failed to load Scala language pack: {e}"),
242 }
243 match lua_pack() {
244 Ok(pack) => registry.register(pack),
245 Err(e) => eprintln!("warning: failed to load Lua language pack: {e}"),
246 }
247 match zig_pack() {
248 Ok(pack) => registry.register(pack),
249 Err(e) => eprintln!("warning: failed to load Zig language pack: {e}"),
250 }
251 match elixir_pack() {
252 Ok(pack) => registry.register(pack),
253 Err(e) => eprintln!("warning: failed to load Elixir language pack: {e}"),
254 }
255 match dart_pack() {
256 Ok(pack) => registry.register(pack),
257 Err(e) => eprintln!("warning: failed to load Dart language pack: {e}"),
258 }
259 match objc_pack() {
260 Ok(pack) => registry.register(pack),
261 Err(e) => eprintln!("warning: failed to load Objective-C language pack: {e}"),
262 }
263 match haskell_pack() {
264 Ok(pack) => registry.register(pack),
265 Err(e) => eprintln!("warning: failed to load Haskell language pack: {e}"),
266 }
267 match perl_pack() {
268 Ok(pack) => registry.register(pack),
269 Err(e) => eprintln!("warning: failed to load Perl language pack: {e}"),
270 }
271 match r_pack() {
272 Ok(pack) => registry.register(pack),
273 Err(e) => eprintln!("warning: failed to load R language pack: {e}"),
274 }
275 match ocaml_pack() {
276 Ok(pack) => registry.register(pack),
277 Err(e) => eprintln!("warning: failed to load OCaml language pack: {e}"),
278 }
279 match bash_pack() {
280 Ok(pack) => registry.register(pack),
281 Err(e) => eprintln!("warning: failed to load Bash language pack: {e}"),
282 }
283 match sql_pack() {
284 Ok(pack) => registry.register(pack),
285 Err(e) => eprintln!("warning: failed to load SQL language pack: {e}"),
286 }
287 match julia_pack() {
288 Ok(pack) => registry.register(pack),
289 Err(e) => eprintln!("warning: failed to load Julia language pack: {e}"),
290 }
291 match proto_pack() {
292 Ok(pack) => registry.register(pack),
293 Err(e) => eprintln!("warning: failed to load Protobuf language pack: {e}"),
294 }
295 match powershell_pack() {
296 Ok(pack) => registry.register(pack),
297 Err(e) => eprintln!("warning: failed to load PowerShell language pack: {e}"),
298 }
299 match verilog_pack() {
300 Ok(pack) => registry.register(pack),
301 Err(e) => eprintln!("warning: failed to load Verilog language pack: {e}"),
302 }
303 match hcl_pack() {
304 Ok(pack) => registry.register(pack),
305 Err(e) => eprintln!("warning: failed to load HCL language pack: {e}"),
306 }
307 match toml_pack() {
308 Ok(pack) => registry.register(pack),
309 Err(e) => eprintln!("warning: failed to load TOML language pack: {e}"),
310 }
311 match yaml_pack() {
312 Ok(pack) => registry.register(pack),
313 Err(e) => eprintln!("warning: failed to load YAML language pack: {e}"),
314 }
315 match erlang_pack() {
316 Ok(pack) => registry.register(pack),
317 Err(e) => eprintln!("warning: failed to load Erlang language pack: {e}"),
318 }
319 match dockerfile_pack() {
320 Ok(pack) => registry.register(pack),
321 Err(e) => eprintln!("warning: failed to load Dockerfile language pack: {e}"),
322 }
323 match fortran_pack() {
324 Ok(pack) => registry.register(pack),
325 Err(e) => eprintln!("warning: failed to load Fortran language pack: {e}"),
326 }
327 match nix_pack() {
328 Ok(pack) => registry.register(pack),
329 Err(e) => eprintln!("warning: failed to load Nix language pack: {e}"),
330 }
331 match svelte_pack() {
332 Ok(pack) => registry.register(pack),
333 Err(e) => eprintln!("warning: failed to load Svelte language pack: {e}"),
334 }
335 match fsharp_pack() {
336 Ok(pack) => registry.register(pack),
337 Err(e) => eprintln!("warning: failed to load F# language pack: {e}"),
338 }
339 match groovy_pack() {
340 Ok(pack) => registry.register(pack),
341 Err(e) => eprintln!("warning: failed to load Groovy language pack: {e}"),
342 }
343 match css_pack() {
344 Ok(pack) => registry.register(pack),
345 Err(e) => eprintln!("warning: failed to load CSS language pack: {e}"),
346 }
347 match html_pack() {
348 Ok(pack) => registry.register(pack),
349 Err(e) => eprintln!("warning: failed to load HTML language pack: {e}"),
350 }
351 match json_pack() {
352 Ok(pack) => registry.register(pack),
353 Err(e) => eprintln!("warning: failed to load JSON language pack: {e}"),
354 }
355 match xml_pack() {
356 Ok(pack) => registry.register(pack),
357 Err(e) => eprintln!("warning: failed to load XML language pack: {e}"),
358 }
359 match makefile_pack() {
360 Ok(pack) => registry.register(pack),
361 Err(e) => eprintln!("warning: failed to load Makefile language pack: {e}"),
362 }
363 match cmake_pack() {
364 Ok(pack) => registry.register(pack),
365 Err(e) => eprintln!("warning: failed to load CMake language pack: {e}"),
366 }
367 match graphql_pack() {
368 Ok(pack) => registry.register(pack),
369 Err(e) => eprintln!("warning: failed to load GraphQL language pack: {e}"),
370 }
371 match glsl_pack() {
372 Ok(pack) => registry.register(pack),
373 Err(e) => eprintln!("warning: failed to load GLSL language pack: {e}"),
374 }
375 match commonlisp_pack() {
376 Ok(pack) => registry.register(pack),
377 Err(e) => eprintln!("warning: failed to load Common Lisp language pack: {e}"),
378 }
379 match elm_pack() {
380 Ok(pack) => registry.register(pack),
381 Err(e) => eprintln!("warning: failed to load Elm language pack: {e}"),
382 }
383 match elisp_pack() {
384 Ok(pack) => registry.register(pack),
385 Err(e) => eprintln!("warning: failed to load Emacs Lisp language pack: {e}"),
386 }
387 match ini_pack() {
388 Ok(pack) => registry.register(pack),
389 Err(e) => eprintln!("warning: failed to load INI language pack: {e}"),
390 }
391 match tsx_pack() {
392 Ok(pack) => registry.register(pack),
393 Err(e) => eprintln!("warning: failed to load TSX language pack: {e}"),
394 }
395 match starlark_pack() {
396 Ok(pack) => registry.register(pack),
397 Err(e) => eprintln!("warning: failed to load Starlark language pack: {e}"),
398 }
399 match matlab_pack() {
400 Ok(pack) => registry.register(pack),
401 Err(e) => eprintln!("warning: failed to load MATLAB language pack: {e}"),
402 }
403 match markdown_pack() {
404 Ok(pack) => registry.register(pack),
405 Err(e) => eprintln!("warning: failed to load Markdown language pack: {e}"),
406 }
407 match clojure_pack() {
408 Ok(pack) => registry.register(pack),
409 Err(e) => eprintln!("warning: failed to load Clojure language pack: {e}"),
410 }
411 match cuda_pack() {
412 Ok(pack) => registry.register(pack),
413 Err(e) => eprintln!("warning: failed to load CUDA language pack: {e}"),
414 }
415 match pascal_pack() {
416 Ok(pack) => registry.register(pack),
417 Err(e) => eprintln!("warning: failed to load Pascal/Delphi language pack: {e}"),
418 }
419 match vb6_pack() {
420 Ok(pack) => registry.register(pack),
421 Err(e) => eprintln!("warning: failed to load VB6 language pack: {e}"),
422 }
423
424 Ok(registry)
425}
426
427fn python_pack() -> Result<LanguagePack> {
428 let grammar = tree_sitter_python::LANGUAGE.into();
429 LanguagePack::new_with_custom_edges(
430 "python",
431 vec![".py"],
432 grammar,
433 PYTHON_ENTITIES,
434 PYTHON_RELATIONS,
435 vec![CustomEdgeDef {
436 name: "DECORATED_BY".to_string(),
437 capture: "decorates".to_string(),
438 }],
439 )
440}
441
442fn rust_pack() -> Result<LanguagePack> {
443 let grammar = tree_sitter_rust::LANGUAGE.into();
444 LanguagePack::new("rust", vec![".rs"], grammar, RUST_ENTITIES, RUST_RELATIONS)
445}
446
447fn typescript_pack() -> Result<LanguagePack> {
448 let grammar = tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into();
449 LanguagePack::new(
450 "typescript",
451 vec![".ts"],
452 grammar,
453 TYPESCRIPT_ENTITIES,
454 TYPESCRIPT_RELATIONS,
455 )
456}
457
458fn javascript_pack() -> Result<LanguagePack> {
459 let grammar = tree_sitter_javascript::LANGUAGE.into();
460 LanguagePack::new(
461 "javascript",
462 vec![".js", ".jsx", ".mjs"],
463 grammar,
464 JAVASCRIPT_ENTITIES,
465 JAVASCRIPT_RELATIONS,
466 )
467}
468
469fn go_pack() -> Result<LanguagePack> {
470 let grammar = tree_sitter_go::LANGUAGE.into();
471 LanguagePack::new_with_custom_edges(
472 "go",
473 vec![".go"],
474 grammar,
475 GO_ENTITIES,
476 GO_RELATIONS,
477 vec![CustomEdgeDef {
478 name: "SPAWNS".to_string(),
479 capture: "goroutine".to_string(),
480 }],
481 )
482}
483
484fn java_pack() -> Result<LanguagePack> {
485 let grammar = tree_sitter_java::LANGUAGE.into();
486 LanguagePack::new(
487 "java",
488 vec![".java"],
489 grammar,
490 JAVA_ENTITIES,
491 JAVA_RELATIONS,
492 )
493}
494
495fn c_pack() -> Result<LanguagePack> {
496 let grammar = tree_sitter_c::LANGUAGE.into();
497 LanguagePack::new("c", vec![".c", ".h"], grammar, C_ENTITIES, C_RELATIONS)
498}
499
500fn cpp_pack() -> Result<LanguagePack> {
501 let grammar = tree_sitter_cpp::LANGUAGE.into();
502 LanguagePack::new(
503 "cpp",
504 vec![".cpp", ".cc", ".cxx", ".hpp", ".hxx", ".hh"],
505 grammar,
506 CPP_ENTITIES,
507 CPP_RELATIONS,
508 )
509}
510
511fn ruby_pack() -> Result<LanguagePack> {
512 let grammar = tree_sitter_ruby::LANGUAGE.into();
513 LanguagePack::new(
514 "ruby",
515 vec![".rb", ".rake", ".gemspec"],
516 grammar,
517 RUBY_ENTITIES,
518 RUBY_RELATIONS,
519 )
520}
521
522fn php_pack() -> Result<LanguagePack> {
523 let grammar = tree_sitter_php::LANGUAGE_PHP.into();
524 LanguagePack::new("php", vec![".php"], grammar, PHP_ENTITIES, PHP_RELATIONS)
525}
526
527fn swift_pack() -> Result<LanguagePack> {
528 let grammar = tree_sitter_swift::LANGUAGE.into();
529 LanguagePack::new(
530 "swift",
531 vec![".swift"],
532 grammar,
533 SWIFT_ENTITIES,
534 SWIFT_RELATIONS,
535 )
536}
537
538fn kotlin_pack() -> Result<LanguagePack> {
539 let grammar = tree_sitter_kotlin_ng::LANGUAGE.into();
540 LanguagePack::new(
541 "kotlin",
542 vec![".kt", ".kts"],
543 grammar,
544 KOTLIN_ENTITIES,
545 KOTLIN_RELATIONS,
546 )
547}
548
549fn csharp_pack() -> Result<LanguagePack> {
550 let grammar = tree_sitter_c_sharp::LANGUAGE.into();
551 LanguagePack::new(
552 "csharp",
553 vec![".cs"],
554 grammar,
555 CSHARP_ENTITIES,
556 CSHARP_RELATIONS,
557 )
558}
559
560fn scala_pack() -> Result<LanguagePack> {
561 let grammar = tree_sitter_scala::LANGUAGE.into();
562 LanguagePack::new(
563 "scala",
564 vec![".scala", ".sc"],
565 grammar,
566 SCALA_ENTITIES,
567 SCALA_RELATIONS,
568 )
569}
570
571fn lua_pack() -> Result<LanguagePack> {
572 let grammar = tree_sitter_lua::LANGUAGE.into();
573 LanguagePack::new("lua", vec![".lua"], grammar, LUA_ENTITIES, LUA_RELATIONS)
574}
575
576fn zig_pack() -> Result<LanguagePack> {
577 let grammar = tree_sitter_zig::LANGUAGE.into();
578 LanguagePack::new("zig", vec![".zig"], grammar, ZIG_ENTITIES, ZIG_RELATIONS)
579}
580
581fn elixir_pack() -> Result<LanguagePack> {
582 let grammar = tree_sitter_elixir::LANGUAGE.into();
583 LanguagePack::new(
584 "elixir",
585 vec![".ex", ".exs"],
586 grammar,
587 ELIXIR_ENTITIES,
588 ELIXIR_RELATIONS,
589 )
590}
591
592fn dart_pack() -> Result<LanguagePack> {
593 let grammar = tree_sitter_dart::LANGUAGE.into();
594 LanguagePack::new(
595 "dart",
596 vec![".dart"],
597 grammar,
598 DART_ENTITIES,
599 DART_RELATIONS,
600 )
601}
602
603fn objc_pack() -> Result<LanguagePack> {
604 let grammar = tree_sitter_objc::LANGUAGE.into();
605 LanguagePack::new(
606 "objc",
607 vec![".m", ".mm"],
608 grammar,
609 OBJC_ENTITIES,
610 OBJC_RELATIONS,
611 )
612}
613
614fn haskell_pack() -> Result<LanguagePack> {
615 let grammar = tree_sitter_haskell::LANGUAGE.into();
616 LanguagePack::new(
617 "haskell",
618 vec![".hs", ".lhs"],
619 grammar,
620 HASKELL_ENTITIES,
621 HASKELL_RELATIONS,
622 )
623}
624
625fn perl_pack() -> Result<LanguagePack> {
626 let grammar = tree_sitter_perl::LANGUAGE.into();
627 LanguagePack::new(
628 "perl",
629 vec![".pl", ".pm", ".t"],
630 grammar,
631 PERL_ENTITIES,
632 PERL_RELATIONS,
633 )
634}
635
636fn r_pack() -> Result<LanguagePack> {
637 let grammar = tree_sitter_r::LANGUAGE.into();
638 LanguagePack::new(
639 "r",
640 vec![".r", ".R", ".Rmd"],
641 grammar,
642 R_ENTITIES,
643 R_RELATIONS,
644 )
645}
646
647fn ocaml_pack() -> Result<LanguagePack> {
648 let grammar = tree_sitter_ocaml::LANGUAGE_OCAML.into();
649 LanguagePack::new(
650 "ocaml",
651 vec![".ml", ".mli"],
652 grammar,
653 OCAML_ENTITIES,
654 OCAML_RELATIONS,
655 )
656}
657
658fn bash_pack() -> Result<LanguagePack> {
659 let grammar = tree_sitter_bash::LANGUAGE.into();
660 LanguagePack::new(
661 "bash",
662 vec![".sh", ".bash", ".zsh"],
663 grammar,
664 BASH_ENTITIES,
665 BASH_RELATIONS,
666 )
667}
668
669fn sql_pack() -> Result<LanguagePack> {
670 let grammar = tree_sitter_sequel::LANGUAGE.into();
671 LanguagePack::new("sql", vec![".sql"], grammar, SQL_ENTITIES, SQL_RELATIONS)
672}
673
674fn julia_pack() -> Result<LanguagePack> {
675 let grammar = tree_sitter_julia::LANGUAGE.into();
676 LanguagePack::new(
677 "julia",
678 vec![".jl"],
679 grammar,
680 JULIA_ENTITIES,
681 JULIA_RELATIONS,
682 )
683}
684
685fn proto_pack() -> Result<LanguagePack> {
686 let grammar = tree_sitter_proto::LANGUAGE.into();
687 LanguagePack::new(
688 "proto",
689 vec![".proto"],
690 grammar,
691 PROTO_ENTITIES,
692 PROTO_RELATIONS,
693 )
694}
695
696fn powershell_pack() -> Result<LanguagePack> {
697 let grammar = tree_sitter_powershell::LANGUAGE.into();
698 LanguagePack::new(
699 "powershell",
700 vec![".ps1", ".psm1", ".psd1"],
701 grammar,
702 POWERSHELL_ENTITIES,
703 POWERSHELL_RELATIONS,
704 )
705}
706
707fn verilog_pack() -> Result<LanguagePack> {
708 let grammar = tree_sitter_verilog::LANGUAGE.into();
709 LanguagePack::new(
710 "verilog",
711 vec![".v", ".sv", ".svh", ".vh"],
712 grammar,
713 VERILOG_ENTITIES,
714 VERILOG_RELATIONS,
715 )
716}
717
718fn hcl_pack() -> Result<LanguagePack> {
719 let grammar = tree_sitter_hcl::LANGUAGE.into();
720 LanguagePack::new(
721 "hcl",
722 vec![".hcl", ".tf", ".tfvars"],
723 grammar,
724 HCL_ENTITIES,
725 HCL_RELATIONS,
726 )
727}
728
729fn toml_pack() -> Result<LanguagePack> {
730 let grammar = tree_sitter_toml_ng::LANGUAGE.into();
731 LanguagePack::new(
732 "toml",
733 vec![".toml"],
734 grammar,
735 TOML_ENTITIES,
736 TOML_RELATIONS,
737 )
738}
739
740fn yaml_pack() -> Result<LanguagePack> {
741 let grammar = tree_sitter_yaml::LANGUAGE.into();
742 LanguagePack::new(
743 "yaml",
744 vec![".yml", ".yaml"],
745 grammar,
746 YAML_ENTITIES,
747 YAML_RELATIONS,
748 )
749}
750
751fn erlang_pack() -> Result<LanguagePack> {
752 let grammar = tree_sitter_erlang::LANGUAGE.into();
753 LanguagePack::new(
754 "erlang",
755 vec![".erl", ".hrl"],
756 grammar,
757 ERLANG_ENTITIES,
758 ERLANG_RELATIONS,
759 )
760}
761
762fn dockerfile_pack() -> Result<LanguagePack> {
763 let grammar = tree_sitter_containerfile::LANGUAGE.into();
764 LanguagePack::new(
765 "dockerfile",
766 vec!["Dockerfile", "Containerfile", ".dockerfile"],
767 grammar,
768 DOCKERFILE_ENTITIES,
769 DOCKERFILE_RELATIONS,
770 )
771}
772
773fn fortran_pack() -> Result<LanguagePack> {
774 let grammar = tree_sitter_fortran::LANGUAGE.into();
775 LanguagePack::new(
776 "fortran",
777 vec![".f90", ".f95", ".f03", ".f08", ".f", ".for"],
778 grammar,
779 FORTRAN_ENTITIES,
780 FORTRAN_RELATIONS,
781 )
782}
783
784fn nix_pack() -> Result<LanguagePack> {
785 let grammar = tree_sitter_nix::LANGUAGE.into();
786 LanguagePack::new("nix", vec![".nix"], grammar, NIX_ENTITIES, NIX_RELATIONS)
787}
788
789fn svelte_pack() -> Result<LanguagePack> {
790 let grammar = tree_sitter_svelte_ng::LANGUAGE.into();
791 LanguagePack::new(
792 "svelte",
793 vec![".svelte"],
794 grammar,
795 SVELTE_ENTITIES,
796 SVELTE_RELATIONS,
797 )
798}
799
800fn fsharp_pack() -> Result<LanguagePack> {
801 let grammar = tree_sitter_fsharp::LANGUAGE_FSHARP.into();
802 LanguagePack::new(
803 "fsharp",
804 vec![".fs", ".fsi", ".fsx"],
805 grammar,
806 FSHARP_ENTITIES,
807 FSHARP_RELATIONS,
808 )
809}
810
811fn groovy_pack() -> Result<LanguagePack> {
812 let grammar = tree_sitter_groovy::LANGUAGE.into();
813 LanguagePack::new(
814 "groovy",
815 vec![".groovy", ".gradle"],
816 grammar,
817 GROOVY_ENTITIES,
818 GROOVY_RELATIONS,
819 )
820}
821
822fn css_pack() -> Result<LanguagePack> {
823 let grammar = tree_sitter_css::LANGUAGE.into();
824 LanguagePack::new("css", vec![".css"], grammar, CSS_ENTITIES, CSS_RELATIONS)
825}
826
827fn html_pack() -> Result<LanguagePack> {
828 let grammar = tree_sitter_html::LANGUAGE.into();
829 LanguagePack::new(
830 "html",
831 vec![".html", ".htm"],
832 grammar,
833 HTML_ENTITIES,
834 HTML_RELATIONS,
835 )
836}
837
838fn json_pack() -> Result<LanguagePack> {
839 let grammar = tree_sitter_json::LANGUAGE.into();
840 LanguagePack::new(
841 "json",
842 vec![".json"],
843 grammar,
844 JSON_ENTITIES,
845 JSON_RELATIONS,
846 )
847}
848
849fn xml_pack() -> Result<LanguagePack> {
850 let grammar = tree_sitter_xml::LANGUAGE_XML.into();
851 LanguagePack::new(
852 "xml",
853 vec![".xml", ".xsl", ".xsd", ".svg", ".plist"],
854 grammar,
855 XML_ENTITIES,
856 XML_RELATIONS,
857 )
858}
859
860fn makefile_pack() -> Result<LanguagePack> {
861 let grammar = tree_sitter_make::LANGUAGE.into();
862 LanguagePack::new(
863 "makefile",
864 vec!["Makefile", "makefile", "GNUmakefile", ".mk"],
865 grammar,
866 MAKEFILE_ENTITIES,
867 MAKEFILE_RELATIONS,
868 )
869}
870
871fn cmake_pack() -> Result<LanguagePack> {
872 let grammar = tree_sitter_cmake::LANGUAGE.into();
873 LanguagePack::new(
874 "cmake",
875 vec!["CMakeLists.txt", ".cmake"],
876 grammar,
877 CMAKE_ENTITIES,
878 CMAKE_RELATIONS,
879 )
880}
881
882fn graphql_pack() -> Result<LanguagePack> {
883 let grammar = tree_sitter_graphql::LANGUAGE.into();
884 LanguagePack::new(
885 "graphql",
886 vec![".graphql", ".gql"],
887 grammar,
888 GRAPHQL_ENTITIES,
889 GRAPHQL_RELATIONS,
890 )
891}
892
893fn glsl_pack() -> Result<LanguagePack> {
894 let grammar = tree_sitter_glsl::LANGUAGE_GLSL.into();
895 LanguagePack::new(
896 "glsl",
897 vec![".glsl", ".vert", ".frag", ".geom", ".comp"],
898 grammar,
899 GLSL_ENTITIES,
900 GLSL_RELATIONS,
901 )
902}
903
904fn commonlisp_pack() -> Result<LanguagePack> {
905 let grammar = tree_sitter_commonlisp::LANGUAGE_COMMONLISP.into();
906 LanguagePack::new(
907 "commonlisp",
908 vec![".lisp", ".lsp", ".cl", ".asd"],
909 grammar,
910 COMMONLISP_ENTITIES,
911 COMMONLISP_RELATIONS,
912 )
913}
914
915fn elm_pack() -> Result<LanguagePack> {
916 let grammar = tree_sitter_elm::LANGUAGE.into();
917 LanguagePack::new("elm", vec![".elm"], grammar, ELM_ENTITIES, ELM_RELATIONS)
918}
919
920fn elisp_pack() -> Result<LanguagePack> {
921 let grammar = tree_sitter_elisp::LANGUAGE.into();
922 LanguagePack::new(
923 "elisp",
924 vec![".el"],
925 grammar,
926 ELISP_ENTITIES,
927 ELISP_RELATIONS,
928 )
929}
930
931fn ini_pack() -> Result<LanguagePack> {
932 let grammar = tree_sitter_ini::LANGUAGE.into();
933 LanguagePack::new(
934 "ini",
935 vec![".ini", ".cfg", ".conf"],
936 grammar,
937 INI_ENTITIES,
938 INI_RELATIONS,
939 )
940}
941
942fn tsx_pack() -> Result<LanguagePack> {
943 let grammar = tree_sitter_typescript::LANGUAGE_TSX.into();
944 LanguagePack::new("tsx", vec![".tsx"], grammar, TSX_ENTITIES, TSX_RELATIONS)
945}
946
947fn starlark_pack() -> Result<LanguagePack> {
948 let grammar = tree_sitter_starlark::LANGUAGE.into();
949 LanguagePack::new(
950 "starlark",
951 vec![".bzl", ".star", "BUILD", "BUILD.bazel", "WORKSPACE"],
952 grammar,
953 STARLARK_ENTITIES,
954 STARLARK_RELATIONS,
955 )
956}
957
958fn matlab_pack() -> Result<LanguagePack> {
959 let grammar = tree_sitter_matlab::LANGUAGE.into();
960 LanguagePack::new(
961 "matlab",
962 vec![".mlx", ".mat"],
963 grammar,
964 MATLAB_ENTITIES,
965 MATLAB_RELATIONS,
966 )
967}
968
969fn markdown_pack() -> Result<LanguagePack> {
970 let grammar = tree_sitter_md::LANGUAGE.into();
971 LanguagePack::new(
972 "markdown",
973 vec![".md", ".markdown"],
974 grammar,
975 MARKDOWN_ENTITIES,
976 MARKDOWN_RELATIONS,
977 )
978}
979
980fn clojure_pack() -> Result<LanguagePack> {
981 let grammar = tree_sitter_clojure_orchard::LANGUAGE.into();
982 LanguagePack::new(
983 "clojure",
984 vec![".clj", ".cljs", ".cljc", ".edn"],
985 grammar,
986 CLOJURE_ENTITIES,
987 CLOJURE_RELATIONS,
988 )
989}
990
991fn cuda_pack() -> Result<LanguagePack> {
992 let grammar = tree_sitter_cuda::LANGUAGE.into();
993 LanguagePack::new(
994 "cuda",
995 vec![".cu", ".cuh"],
996 grammar,
997 CUDA_ENTITIES,
998 CUDA_RELATIONS,
999 )
1000}
1001
1002fn pascal_pack() -> Result<LanguagePack> {
1003 let grammar = tree_sitter_pascal::LANGUAGE.into();
1004 LanguagePack::new(
1005 "pascal",
1006 vec![".pas", ".pp", ".dpr", ".dpk", ".inc", ".lpr"],
1007 grammar,
1008 PASCAL_ENTITIES,
1009 PASCAL_RELATIONS,
1010 )
1011}
1012
1013fn vb6_pack() -> Result<LanguagePack> {
1014 let grammar = tree_sitter_vb6::language();
1015 LanguagePack::new(
1016 "vb6",
1017 vec![".bas", ".cls", ".frm"],
1018 grammar,
1019 VB6_ENTITIES,
1020 VB6_RELATIONS,
1021 )
1022}
1023
1024#[cfg(test)]
1025mod tests {
1026 use super::*;
1027
1028 #[test]
1029 fn test_all_packs_load() {
1030 let registry = bundled_registry().expect("bundled_registry should succeed");
1032 assert!(
1033 registry.languages().count() > 0,
1034 "registry should have at least one language"
1035 );
1036 }
1037
1038 #[test]
1039 fn test_powershell_pack() {
1040 powershell_pack().expect("PowerShell pack should load");
1041 }
1042
1043 #[test]
1044 fn test_verilog_pack() {
1045 verilog_pack().expect("Verilog pack should load");
1046 }
1047
1048 #[test]
1049 fn test_hcl_pack() {
1050 hcl_pack().expect("HCL pack should load");
1051 }
1052
1053 #[test]
1054 fn test_toml_pack() {
1055 toml_pack().expect("TOML pack should load");
1056 }
1057
1058 #[test]
1059 fn test_yaml_pack() {
1060 yaml_pack().expect("YAML pack should load");
1061 }
1062
1063 #[test]
1064 fn test_erlang_pack() {
1065 erlang_pack().expect("Erlang pack should load");
1066 }
1067
1068 #[test]
1069 fn test_dockerfile_pack() {
1070 dockerfile_pack().expect("Dockerfile pack should load");
1071 }
1072
1073 #[test]
1074 fn test_fortran_pack() {
1075 fortran_pack().expect("Fortran pack should load");
1076 }
1077
1078 #[test]
1079 fn test_nix_pack() {
1080 nix_pack().expect("Nix pack should load");
1081 }
1082
1083 #[test]
1084 fn test_svelte_pack() {
1085 svelte_pack().expect("Svelte pack should load");
1086 }
1087
1088 #[test]
1089 fn test_fsharp_pack() {
1090 fsharp_pack().expect("F# pack should load");
1091 }
1092
1093 #[test]
1094 fn test_groovy_pack() {
1095 groovy_pack().expect("Groovy pack should load");
1096 }
1097
1098 #[test]
1099 fn test_css_pack() {
1100 css_pack().expect("CSS pack should load");
1101 }
1102
1103 #[test]
1104 fn test_html_pack() {
1105 html_pack().expect("HTML pack should load");
1106 }
1107
1108 #[test]
1109 fn test_json_pack() {
1110 json_pack().expect("JSON pack should load");
1111 }
1112
1113 #[test]
1114 fn test_xml_pack() {
1115 xml_pack().expect("XML pack should load");
1116 }
1117
1118 #[test]
1119 fn test_makefile_pack() {
1120 makefile_pack().expect("Makefile pack should load");
1121 }
1122
1123 #[test]
1124 fn test_cmake_pack() {
1125 cmake_pack().expect("CMake pack should load");
1126 }
1127
1128 #[test]
1129 fn test_graphql_pack() {
1130 graphql_pack().expect("GraphQL pack should load");
1131 }
1132
1133 #[test]
1134 fn test_glsl_pack() {
1135 glsl_pack().expect("GLSL pack should load");
1136 }
1137
1138 #[test]
1139 fn test_commonlisp_pack() {
1140 commonlisp_pack().expect("Common Lisp pack should load");
1141 }
1142
1143 #[test]
1144 fn test_elm_pack() {
1145 elm_pack().expect("Elm pack should load");
1146 }
1147
1148 #[test]
1149 fn test_elisp_pack() {
1150 elisp_pack().expect("Emacs Lisp pack should load");
1151 }
1152
1153 #[test]
1154 fn test_ini_pack() {
1155 ini_pack().expect("INI pack should load");
1156 }
1157
1158 #[test]
1159 fn test_tsx_pack() {
1160 tsx_pack().expect("TSX pack should load");
1161 }
1162
1163 #[test]
1164 fn test_matlab_pack() {
1165 matlab_pack().expect("MATLAB pack should load");
1166 }
1167
1168 #[test]
1169 fn test_markdown_pack() {
1170 markdown_pack().expect("Markdown pack should load");
1171 }
1172
1173 #[test]
1174 fn test_clojure_pack() {
1175 clojure_pack().expect("Clojure pack should load");
1176 }
1177
1178 #[test]
1179 fn test_cuda_pack() {
1180 cuda_pack().expect("CUDA pack should load");
1181 }
1182
1183 #[test]
1184 fn test_vb6_pack() {
1185 vb6_pack().expect("VB6 pack should load");
1186 }
1187
1188 #[test]
1189 fn test_vb6_e2e_smoke() {
1190 let pack = vb6_pack().expect("VB6 pack should load");
1191 let src = r#"VERSION 1.0 CLASS
1194BEGIN
1195 MultiUse = -1
1196END
1197Attribute VB_Name = "TestClass"
1198Option Explicit
1199
1200Private mName As String
1201
1202Public Sub Initialize(name As String)
1203 mName = name
1204End Sub
1205
1206Public Function GetName() As String
1207 GetName = mName
1208End Function
1209
1210Private Sub Helper()
1211 Dim result As String
1212 result = GetName()
1213 Initialize(result)
1214End Sub
1215"#;
1216 let extraction =
1217 infigraph_core::extract::extract_file("TestClass.cls", src.as_bytes(), &pack)
1218 .expect("extract_file should succeed");
1219
1220 let symbol_names: Vec<&str> = extraction.symbols.iter().map(|s| s.name.as_str()).collect();
1221 println!("Symbols: {:?}", symbol_names);
1222 println!(
1223 "Symbol kinds: {:?}",
1224 extraction
1225 .symbols
1226 .iter()
1227 .map(|s| format!("{} ({:?})", s.name, s.kind))
1228 .collect::<Vec<_>>()
1229 );
1230 println!(
1231 "Relations: {:?}",
1232 extraction
1233 .relations
1234 .iter()
1235 .map(|r| format!("{} -> {}", r.source_id, r.target_id))
1236 .collect::<Vec<_>>()
1237 );
1238
1239 let module = extraction.symbols.iter().find(|s| s.name == "TestClass");
1241 assert!(
1242 module.is_some(),
1243 "Expected Module symbol 'TestClass', got: {:?}",
1244 symbol_names
1245 );
1246 assert_eq!(
1247 module.unwrap().kind,
1248 infigraph_core::model::SymbolKind::Module
1249 );
1250
1251 assert!(
1253 symbol_names.contains(&"Initialize"),
1254 "Expected 'Initialize'"
1255 );
1256 assert!(symbol_names.contains(&"GetName"), "Expected 'GetName'");
1257 assert!(symbol_names.contains(&"Helper"), "Expected 'Helper'");
1258
1259 assert!(symbol_names.contains(&"mName"), "Expected 'mName'");
1261
1262 assert!(
1264 !extraction.relations.is_empty(),
1265 "Expected call relations from Helper"
1266 );
1267
1268 let relation_pairs: Vec<(&str, &str)> = extraction
1269 .relations
1270 .iter()
1271 .map(|r| (r.source_id.as_str(), r.target_id.as_str()))
1272 .collect();
1273 println!("Relation pairs: {:?}", relation_pairs);
1274
1275 let helper_calls_getname = extraction
1276 .relations
1277 .iter()
1278 .any(|r| r.source_id.ends_with("::Helper") && r.target_id.ends_with("::GetName"));
1279 let helper_calls_initialize = extraction
1280 .relations
1281 .iter()
1282 .any(|r| r.source_id.ends_with("::Helper") && r.target_id.ends_with("::Initialize"));
1283
1284 assert!(
1285 helper_calls_getname,
1286 "Expected Helper -> GetName call edge, got: {:?}",
1287 relation_pairs
1288 );
1289 assert!(
1290 helper_calls_initialize,
1291 "Expected Helper -> Initialize call edge, got: {:?}",
1292 relation_pairs
1293 );
1294 }
1295
1296 #[test]
1297 fn test_sql_table_lineage() {
1298 let pack = sql_pack().unwrap();
1299 let sql = b"CREATE TABLE output AS SELECT col1 FROM source_a INNER JOIN source_b ON source_a.id = source_b.id;
1300WITH cte1 AS (SELECT * FROM base_table), cte2 AS (SELECT * FROM cte1) SELECT * FROM cte2;
1301INSERT INTO target_table SELECT * FROM input_table;";
1302
1303 let extraction = infigraph_core::extract::extract_file("test.sql", sql, &pack).unwrap();
1304
1305 let sym_names: Vec<&str> = extraction.symbols.iter().map(|s| s.name.as_str()).collect();
1306 assert!(
1307 sym_names.contains(&"output"),
1308 "expected CREATE TABLE output"
1309 );
1310 assert!(sym_names.contains(&"cte1"), "expected CTE cte1");
1311 assert!(sym_names.contains(&"cte2"), "expected CTE cte2");
1312
1313 let has_edge = |src_suffix: &str, tgt_suffix: &str| {
1314 extraction
1315 .relations
1316 .iter()
1317 .any(|r| r.source_id.ends_with(src_suffix) && r.target_id.ends_with(tgt_suffix))
1318 };
1319 assert!(
1320 has_edge("::output", "::source_a"),
1321 "expected output -> source_a"
1322 );
1323 assert!(
1324 has_edge("::output", "::source_b"),
1325 "expected output -> source_b"
1326 );
1327 assert!(
1328 has_edge("::cte1", "::base_table"),
1329 "expected cte1 -> base_table"
1330 );
1331 assert!(has_edge("::cte2", "::cte1"), "expected cte2 -> cte1");
1332 }
1333
1334 #[test]
1335 fn test_sql_spark_extraction_real() {
1336 let sample_dir = std::path::Path::new("/tmp/efp-group-sql-samples");
1337 if !sample_dir.exists() {
1338 println!("skipping — samples not found");
1339 return;
1340 }
1341 let pack = sql_pack().unwrap();
1342 for entry in std::fs::read_dir(sample_dir).unwrap().flatten() {
1343 let p = entry.path();
1344 if p.extension().and_then(|e| e.to_str()) != Some("sql") {
1345 continue;
1346 }
1347 let Ok(src) = std::fs::read(&p) else {
1348 continue;
1349 };
1350 if src.is_empty() {
1351 continue;
1352 }
1353 let fname = p.file_name().unwrap().to_string_lossy().to_string();
1354 match infigraph_core::extract::extract_file(&fname, &src, &pack) {
1355 Ok(e) => println!(
1356 "{fname}: {} symbols, {} relations",
1357 e.symbols.len(),
1358 e.relations.len()
1359 ),
1360 Err(err) => println!("{fname}: EXTRACT ERROR: {err}"),
1361 }
1362 }
1363 }
1364
1365 #[test]
1366 fn test_sql_notebook_file_level_refs() {
1367 let pack = sql_pack().unwrap();
1368 let sql = b"-- Databricks notebook source
1369SELECT * FROM fraud_360_rpt WHERE year='2023';
1370
1371-- COMMAND ----------
1372
1373SELECT a.*, b.score FROM risk_assessment a
1374LEFT JOIN risk_rules b ON a.id = b.assessment_id;";
1375
1376 let extraction = infigraph_core::extract::extract_file("notebook.sql", sql, &pack).unwrap();
1377
1378 assert!(
1379 !extraction.relations.is_empty(),
1380 "expected file-level relations from notebook SQL"
1381 );
1382 let has_edge = |tgt: &str| {
1383 extraction
1384 .relations
1385 .iter()
1386 .any(|r| r.target_id.ends_with(tgt))
1387 };
1388 assert!(has_edge("::fraud_360_rpt"), "expected ref to fraud_360_rpt");
1389 assert!(
1390 has_edge("::risk_assessment"),
1391 "expected ref to risk_assessment"
1392 );
1393 assert!(has_edge("::risk_rules"), "expected ref to risk_rules");
1394
1395 let file_sourced = extraction
1396 .relations
1397 .iter()
1398 .any(|r| r.source_id.contains("notebook.sql"));
1399 assert!(
1400 file_sourced,
1401 "expected file-level source for notebook relations"
1402 );
1403 }
1404
1405 #[test]
1406 fn test_sql_dialect_coverage() {
1407 let pack = sql_pack().unwrap();
1408
1409 #[allow(clippy::type_complexity)]
1410 let cases: Vec<(&str, &[u8], &[&str], &[(&str, &str)])> = vec![
1411 (
1415 "spark_ctas",
1416 b"CREATE TABLE output AS SELECT * FROM src_a JOIN src_b ON a.id = b.id;" as &[u8],
1417 &["src_a", "src_b"],
1418 &[("::output", "::src_a"), ("::output", "::src_b")],
1419 ),
1420 (
1421 "spark_insert_overwrite",
1422 b"INSERT OVERWRITE TABLE target SELECT * FROM source;",
1423 &["source"],
1424 &[],
1425 ),
1426 (
1427 "spark_cte",
1428 b"WITH stg AS (SELECT * FROM raw_events) SELECT * FROM stg;",
1429 &["raw_events", "stg"],
1430 &[("::stg", "::raw_events")],
1431 ),
1432 (
1434 "tsql_select_into",
1435 b"SELECT * INTO new_table FROM old_table;",
1436 &["old_table"],
1437 &[],
1438 ),
1439 (
1440 "tsql_cte_insert",
1441 b"WITH cte AS (SELECT * FROM src) INSERT INTO tgt SELECT * FROM cte;",
1442 &["src", "cte"],
1443 &[("::cte", "::src")],
1444 ),
1445 (
1447 "pg_ctas",
1448 b"CREATE TABLE summary AS SELECT dept, count(*) FROM employees GROUP BY dept;",
1449 &["employees"],
1450 &[("::summary", "::employees")],
1451 ),
1452 (
1453 "pg_with_insert",
1454 b"WITH src AS (SELECT * FROM raw) INSERT INTO clean SELECT * FROM src;",
1455 &["raw", "src"],
1456 &[("::src", "::raw")],
1457 ),
1458 (
1460 "mysql_insert_ignore",
1461 b"INSERT IGNORE INTO users SELECT * FROM staging_users;",
1462 &["staging_users"],
1463 &[],
1464 ),
1465 (
1467 "bq_create_or_replace",
1468 b"CREATE OR REPLACE TABLE output AS SELECT * FROM input;",
1469 &["input"],
1470 &[],
1471 ),
1472 (
1474 "subquery",
1475 b"SELECT * FROM (SELECT id FROM raw_data) sub;",
1476 &["raw_data"],
1477 &[],
1478 ),
1479 (
1480 "multi_join",
1481 b"SELECT * FROM a JOIN b ON a.id = b.id LEFT JOIN c ON b.id = c.id;",
1482 &["a", "b", "c"],
1483 &[],
1484 ),
1485 (
1486 "union_all",
1487 b"SELECT * FROM t1 UNION ALL SELECT * FROM t2;",
1488 &["t1", "t2"],
1489 &[],
1490 ),
1491 ];
1492
1493 let mut failures = Vec::new();
1494
1495 for (label, sql, expected_targets, expected_edges) in &cases {
1496 let extraction = infigraph_core::extract::extract_file("test.sql", sql, &pack).unwrap();
1497 let all_targets: Vec<&str> = extraction
1498 .relations
1499 .iter()
1500 .map(|r| r.target_id.as_str())
1501 .collect();
1502
1503 for tgt in *expected_targets {
1504 let suffix = format!("::{}", tgt);
1505 if !extraction
1506 .relations
1507 .iter()
1508 .any(|r| r.target_id.ends_with(&suffix))
1509 {
1510 failures.push(format!(
1511 "{}: missing target ref to {}, got {:?}",
1512 label, tgt, all_targets
1513 ));
1514 }
1515 }
1516
1517 for (src_suf, tgt_suf) in *expected_edges {
1518 if !extraction
1519 .relations
1520 .iter()
1521 .any(|r| r.source_id.ends_with(src_suf) && r.target_id.ends_with(tgt_suf))
1522 {
1523 let edges: Vec<_> = extraction
1524 .relations
1525 .iter()
1526 .map(|r| format!("{} -> {}", r.source_id, r.target_id))
1527 .collect();
1528 failures.push(format!(
1529 "{}: missing edge {} -> {}, got {:?}",
1530 label, src_suf, tgt_suf, edges
1531 ));
1532 }
1533 }
1534 }
1535
1536 if !failures.is_empty() {
1537 panic!("SQL dialect coverage failures:\n{}", failures.join("\n"));
1538 }
1539 }
1540
1541 #[test]
1542 fn test_sql_notebook_formats() {
1543 let pack = sql_pack().unwrap();
1544
1545 let cases: Vec<(&str, &[u8], &[&str])> = vec![
1546 ("databricks", b"-- Databricks notebook source\nSELECT * FROM table_a;\n-- COMMAND ----------\nSELECT * FROM table_b;" as &[u8],
1548 &["table_a", "table_b"]),
1549
1550 ("jupyter_plain", b"SELECT * FROM dataset_1;\nSELECT * FROM dataset_2 JOIN dataset_3 ON d2.id = d3.id;",
1552 &["dataset_1", "dataset_2", "dataset_3"]),
1553
1554 ("zeppelin", b"%sql\nSELECT * FROM zep_table_1;\n\n%sql\nSELECT a.* FROM zep_table_2 a LEFT JOIN zep_table_3 b ON a.id = b.id;",
1556 &["zep_table_1", "zep_table_2", "zep_table_3"]),
1557
1558 ("dbt_ref", b"SELECT * FROM {{ ref('stg_orders') }}\nJOIN raw_customers ON orders.cust_id = raw_customers.id;",
1560 &["raw_customers"]),
1561
1562 ("mixed", b"CREATE TABLE output AS SELECT * FROM src;\nSELECT * FROM standalone_ref;",
1564 &["src", "standalone_ref"]),
1565 ];
1566
1567 let mut failures = Vec::new();
1568
1569 for (label, sql, expected_targets) in &cases {
1570 let extraction =
1571 infigraph_core::extract::extract_file("notebook.sql", sql, &pack).unwrap();
1572 let all_targets: Vec<String> = extraction
1573 .relations
1574 .iter()
1575 .map(|r| r.target_id.clone())
1576 .collect();
1577
1578 for tgt in *expected_targets {
1579 let suffix = format!("::{}", tgt);
1580 if !extraction
1581 .relations
1582 .iter()
1583 .any(|r| r.target_id.ends_with(&suffix))
1584 {
1585 failures.push(format!(
1586 "{}: missing target ref to {}, got {:?}",
1587 label, tgt, all_targets
1588 ));
1589 }
1590 }
1591
1592 let all_file_sourced = extraction
1593 .relations
1594 .iter()
1595 .filter(|r| !r.source_id.contains("::"))
1596 .count()
1597 == 0;
1598 if !all_file_sourced {
1599 let non_qualified: Vec<_> = extraction
1600 .relations
1601 .iter()
1602 .filter(|r| !r.source_id.contains("::"))
1603 .map(|r| r.source_id.as_str())
1604 .collect();
1605 if !non_qualified.is_empty() {
1606 failures.push(format!(
1607 "{}: source_ids without '::': {:?}",
1608 label, non_qualified
1609 ));
1610 }
1611 }
1612 }
1613
1614 if !failures.is_empty() {
1615 panic!("Notebook format failures:\n{}", failures.join("\n"));
1616 }
1617 }
1618
1619 #[test]
1620 fn test_sql_complex_nested_and_dml() {
1621 let pack = sql_pack().unwrap();
1622
1623 #[allow(clippy::type_complexity)]
1624 let cases: Vec<(&str, &[u8], &[&str], &[(&str, &str)])> = vec![
1625 ("nested_subquery",
1627 b"SELECT * FROM (SELECT id FROM (SELECT id FROM deep_source) inner_q) outer_q;" as &[u8],
1628 &["deep_source"], &[]),
1629
1630 ("cte_chain",
1632 b"WITH cte1 AS (SELECT * FROM raw_data), \
1633 cte2 AS (SELECT * FROM cte1), \
1634 cte3 AS (SELECT a.* FROM cte2 a JOIN dim_table b ON a.id = b.id) \
1635 SELECT * FROM cte3;",
1636 &["raw_data", "cte1", "cte2", "dim_table", "cte3"],
1637 &[("::cte1", "::raw_data"), ("::cte2", "::cte1"), ("::cte3", "::cte2"), ("::cte3", "::dim_table")]),
1638
1639 ("ctas_with_cte",
1641 b"CREATE TABLE final_output AS \
1642 WITH stg AS (SELECT * FROM staging_table) \
1643 SELECT * FROM stg JOIN lookup ON stg.key = lookup.key;",
1644 &["staging_table", "stg", "lookup"],
1645 &[("::stg", "::staging_table")]),
1646
1647 ("insert_subquery_join",
1649 b"INSERT INTO target_table \
1650 SELECT a.*, b.score FROM \
1651 (SELECT * FROM base_facts) a \
1652 JOIN scoring_model b ON a.id = b.id;",
1653 &["base_facts", "scoring_model"],
1654 &[]),
1655
1656 ("multi_dml",
1658 b"CREATE TABLE dim_users AS SELECT * FROM raw_users; \
1659 INSERT INTO fact_orders SELECT * FROM staging_orders JOIN dim_users ON so.uid = du.uid; \
1660 SELECT * FROM fact_orders WHERE dt = '2024-01-01';",
1661 &["raw_users", "staging_orders", "dim_users", "fact_orders"],
1662 &[("::dim_users", "::raw_users")]),
1663
1664 ("correlated_subquery",
1666 b"SELECT * FROM orders o WHERE EXISTS (SELECT 1 FROM returns r WHERE r.order_id = o.id);",
1667 &["orders", "returns"], &[]),
1668
1669 ("cte_union",
1671 b"WITH combined AS ( \
1672 SELECT id, amount FROM source_a \
1673 UNION ALL \
1674 SELECT id, amount FROM source_b \
1675 ) SELECT * FROM combined;",
1676 &["source_a", "source_b", "combined"],
1677 &[]),
1678
1679 ("deep_nesting",
1681 b"WITH prep AS ( \
1682 SELECT * FROM ( \
1683 SELECT a.*, b.cat FROM raw_events a \
1684 LEFT JOIN categories b ON a.cat_id = b.id \
1685 ) sub WHERE sub.cat IS NOT NULL \
1686 ) \
1687 INSERT INTO clean_events SELECT * FROM prep;",
1688 &["raw_events", "categories", "prep"],
1689 &[("::prep", "::raw_events"), ("::prep", "::categories")]),
1690
1691 ("multi_join_4way",
1693 b"SELECT * FROM t1 \
1694 JOIN t2 ON t1.id = t2.id \
1695 LEFT JOIN t3 ON t2.id = t3.id \
1696 INNER JOIN t4 ON t3.id = t4.id;",
1697 &["t1", "t2", "t3", "t4"], &[]),
1698
1699 ("insert_multi_join",
1701 b"INSERT INTO report \
1702 SELECT f.*, d.name, p.category FROM fact_sales f \
1703 JOIN dim_date d ON f.date_id = d.id \
1704 JOIN dim_product p ON f.prod_id = p.id;",
1705 &["fact_sales", "dim_date", "dim_product"],
1706 &[("::report", "::fact_sales")]),
1707 ];
1708
1709 let mut failures = Vec::new();
1710
1711 for (label, sql, expected_targets, expected_edges) in &cases {
1712 let extraction = infigraph_core::extract::extract_file("test.sql", sql, &pack).unwrap();
1713 let all_targets: Vec<String> = extraction
1714 .relations
1715 .iter()
1716 .map(|r| r.target_id.clone())
1717 .collect();
1718 let all_edges: Vec<String> = extraction
1719 .relations
1720 .iter()
1721 .map(|r| format!("{} -> {}", r.source_id, r.target_id))
1722 .collect();
1723
1724 for tgt in *expected_targets {
1725 let suffix = format!("::{}", tgt);
1726 if !extraction
1727 .relations
1728 .iter()
1729 .any(|r| r.target_id.ends_with(&suffix))
1730 {
1731 failures.push(format!(
1732 "{}: missing target ref to '{}', targets: {:?}",
1733 label, tgt, all_targets
1734 ));
1735 }
1736 }
1737
1738 for (src_suf, tgt_suf) in *expected_edges {
1739 if !extraction
1740 .relations
1741 .iter()
1742 .any(|r| r.source_id.ends_with(src_suf) && r.target_id.ends_with(tgt_suf))
1743 {
1744 failures.push(format!(
1745 "{}: missing edge {} -> {}, edges: {:?}",
1746 label, src_suf, tgt_suf, all_edges
1747 ));
1748 }
1749 }
1750 }
1751
1752 if !failures.is_empty() {
1753 panic!("Complex nested/DML failures:\n{}", failures.join("\n"));
1754 }
1755 }
1756
1757 #[test]
1758 fn test_pascal_relations() {
1759 let pack = pascal_pack().expect("Pascal pack should load");
1760 let src = br#"unit Test;
1761interface
1762uses SysUtils, Classes;
1763type
1764 TMyClass = class(TObject)
1765 procedure DoStuff;
1766 end;
1767implementation
1768procedure TMyClass.DoStuff;
1769begin
1770 WriteLn('hello');
1771 SomeObj.Method(42);
1772 inherited Create;
1773end;
1774end."#;
1775
1776 let extraction = infigraph_core::extract::extract_file(
1777 "test.pas",
1778 &src[..],
1779 &pack,
1780 ).expect("extract_file should succeed for Pascal");
1781
1782 let calls: Vec<_> = extraction.relations.iter()
1783 .filter(|r| r.kind == infigraph_core::model::RelationKind::Calls)
1784 .collect();
1785
1786 let imports: Vec<_> = extraction.relations.iter()
1787 .filter(|r| r.kind == infigraph_core::model::RelationKind::Imports)
1788 .collect();
1789
1790 let inherits: Vec<_> = extraction.relations.iter()
1791 .filter(|r| r.kind == infigraph_core::model::RelationKind::Inherits)
1792 .collect();
1793
1794 assert!(!calls.is_empty(), "Expected CALLS relations from Pascal code");
1795 assert!(!imports.is_empty(), "Expected IMPORTS relations from Pascal code");
1796 assert!(!inherits.is_empty(), "Expected INHERITS relations from Pascal code");
1797 }
1798
1799 #[test]
1800 fn test_csharp_inheritance() {
1801 let pack = csharp_pack().expect("C# pack should load");
1802 let src = br#"using System;
1803using System.Collections.Generic;
1804
1805namespace Intuit.Applications.PTG.DatabaseService
1806{
1807 public class SqliteDataLayer : IDataLayer
1808 {
1809 public void AddNewClient(string name) { }
1810 public void DeleteClient(int id) { }
1811 }
1812}
1813"#;
1814 let extraction = infigraph_core::extract::extract_file("test.cs", &src[..], &pack)
1815 .expect("extract_file should succeed for C#");
1816
1817 let inherits: Vec<_> = extraction.relations.iter()
1818 .filter(|r| r.kind == infigraph_core::model::RelationKind::Inherits)
1819 .collect();
1820 assert!(!inherits.is_empty(), "Expected INHERITS relations from C# class : interface");
1821 }
1822
1823 #[test]
1824 fn test_rust_test_extraction() {
1825 let pack = rust_pack().unwrap();
1826 let src = br#"
1827#[test]
1828fn test_add() {
1829 assert_eq!(1 + 1, 2);
1830}
1831
1832pub fn public_fn() -> i32 {
1833 42
1834}
1835
1836fn private_fn() {}
1837
1838pub(crate) fn crate_fn() {}
1839"#;
1840 let extraction = infigraph_core::extract::extract_file("lib.rs", src, &pack).unwrap();
1841 let syms = &extraction.symbols;
1842
1843 let test_add = syms.iter().find(|s| s.name == "test_add");
1844 assert!(test_add.is_some(), "test_add should be extracted");
1845 assert_eq!(test_add.unwrap().kind, infigraph_core::model::SymbolKind::Test,
1846 "test_add should have Test kind, got {:?}", test_add.unwrap().kind);
1847
1848 let public_fn = syms.iter().find(|s| s.name == "public_fn");
1849 assert!(public_fn.is_some(), "public_fn should be extracted");
1850 assert_eq!(public_fn.unwrap().visibility.as_deref(), Some("pub"),
1851 "public_fn should have pub visibility, got {:?}", public_fn.unwrap().visibility);
1852
1853 let private_fn = syms.iter().find(|s| s.name == "private_fn");
1854 assert!(private_fn.is_some(), "private_fn should be extracted");
1855 assert!(private_fn.unwrap().visibility.is_none(),
1856 "private_fn should have no visibility modifier");
1857
1858 let crate_fn = syms.iter().find(|s| s.name == "crate_fn");
1859 assert!(crate_fn.is_some(), "crate_fn should be extracted");
1860 assert_eq!(crate_fn.unwrap().visibility.as_deref(), Some("pub(crate)"),
1861 "crate_fn should have pub(crate) visibility, got {:?}", crate_fn.unwrap().visibility);
1862 }
1863
1864 #[test]
1865 fn test_rust_tokio_test_extraction() {
1866 let pack = rust_pack().unwrap();
1867 let src = br#"
1868#[tokio::test]
1869async fn test_async_op() {
1870 let x = 1;
1871}
1872"#;
1873 let extraction = infigraph_core::extract::extract_file("lib.rs", src, &pack).unwrap();
1874 let test_fn = extraction.symbols.iter().find(|s| s.name == "test_async_op");
1875 assert!(test_fn.is_some(), "test_async_op should be extracted");
1876 assert_eq!(test_fn.unwrap().kind, infigraph_core::model::SymbolKind::Test,
1877 "tokio::test should produce Test kind, got {:?}", test_fn.unwrap().kind);
1878 }
1879}