This is page 4 of 22. Use http://codebase.md/shashankss1205/codegraphcontext?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .cgcignore
├── .github
│ ├── FUNDING.yml
│ └── workflows
│ ├── e2e-tests.yml
│ ├── post_discord_invite.yml
│ ├── test.yml
│ └── update-contributors.yml
├── .gitignore
├── CLI_Commands.md
├── CONTRIBUTING.md
├── contributors.md
├── docs
│ ├── docs
│ │ ├── architecture.md
│ │ ├── cli.md
│ │ ├── contributing_languages.md
│ │ ├── contributing.md
│ │ ├── cookbook.md
│ │ ├── core.md
│ │ ├── future_work.md
│ │ ├── images
│ │ │ ├── 1.png
│ │ │ ├── 11.png
│ │ │ ├── 12.png
│ │ │ ├── 13.png
│ │ │ ├── 14.png
│ │ │ ├── 16.png
│ │ │ ├── 19.png
│ │ │ ├── 2.png
│ │ │ ├── 20.png
│ │ │ ├── 21.png
│ │ │ ├── 22.png
│ │ │ ├── 23.png
│ │ │ ├── 24.png
│ │ │ ├── 26.png
│ │ │ ├── 28.png
│ │ │ ├── 29.png
│ │ │ ├── 3.png
│ │ │ ├── 30.png
│ │ │ ├── 31.png
│ │ │ ├── 32.png
│ │ │ ├── 33.png
│ │ │ ├── 34.png
│ │ │ ├── 35.png
│ │ │ ├── 36.png
│ │ │ ├── 38.png
│ │ │ ├── 39.png
│ │ │ ├── 4.png
│ │ │ ├── 40.png
│ │ │ ├── 41.png
│ │ │ ├── 42.png
│ │ │ ├── 43.png
│ │ │ ├── 44.png
│ │ │ ├── 5.png
│ │ │ ├── 6.png
│ │ │ ├── 7.png
│ │ │ ├── 8.png
│ │ │ ├── 9.png
│ │ │ ├── Indexing.gif
│ │ │ ├── tool_images
│ │ │ │ ├── 1.png
│ │ │ │ ├── 2.png
│ │ │ │ └── 3.png
│ │ │ └── Usecase.gif
│ │ ├── index.md
│ │ ├── installation.md
│ │ ├── license.md
│ │ ├── server.md
│ │ ├── tools.md
│ │ ├── troubleshooting.md
│ │ ├── use_cases.md
│ │ └── watching.md
│ ├── mkdocs.yml
│ └── site
│ ├── 404.html
│ ├── architecture
│ │ └── index.html
│ ├── assets
│ │ ├── images
│ │ │ └── favicon.png
│ │ ├── javascripts
│ │ │ ├── bundle.79ae519e.min.js
│ │ │ ├── bundle.79ae519e.min.js.map
│ │ │ ├── lunr
│ │ │ │ ├── min
│ │ │ │ │ ├── lunr.ar.min.js
│ │ │ │ │ ├── lunr.da.min.js
│ │ │ │ │ ├── lunr.de.min.js
│ │ │ │ │ ├── lunr.du.min.js
│ │ │ │ │ ├── lunr.el.min.js
│ │ │ │ │ ├── lunr.es.min.js
│ │ │ │ │ ├── lunr.fi.min.js
│ │ │ │ │ ├── lunr.fr.min.js
│ │ │ │ │ ├── lunr.he.min.js
│ │ │ │ │ ├── lunr.hi.min.js
│ │ │ │ │ ├── lunr.hu.min.js
│ │ │ │ │ ├── lunr.hy.min.js
│ │ │ │ │ ├── lunr.it.min.js
│ │ │ │ │ ├── lunr.ja.min.js
│ │ │ │ │ ├── lunr.jp.min.js
│ │ │ │ │ ├── lunr.kn.min.js
│ │ │ │ │ ├── lunr.ko.min.js
│ │ │ │ │ ├── lunr.multi.min.js
│ │ │ │ │ ├── lunr.nl.min.js
│ │ │ │ │ ├── lunr.no.min.js
│ │ │ │ │ ├── lunr.pt.min.js
│ │ │ │ │ ├── lunr.ro.min.js
│ │ │ │ │ ├── lunr.ru.min.js
│ │ │ │ │ ├── lunr.sa.min.js
│ │ │ │ │ ├── lunr.stemmer.support.min.js
│ │ │ │ │ ├── lunr.sv.min.js
│ │ │ │ │ ├── lunr.ta.min.js
│ │ │ │ │ ├── lunr.te.min.js
│ │ │ │ │ ├── lunr.th.min.js
│ │ │ │ │ ├── lunr.tr.min.js
│ │ │ │ │ ├── lunr.vi.min.js
│ │ │ │ │ └── lunr.zh.min.js
│ │ │ │ ├── tinyseg.js
│ │ │ │ └── wordcut.js
│ │ │ └── workers
│ │ │ ├── search.2c215733.min.js
│ │ │ └── search.2c215733.min.js.map
│ │ └── stylesheets
│ │ ├── main.484c7ddc.min.css
│ │ ├── main.484c7ddc.min.css.map
│ │ ├── palette.ab4e12ef.min.css
│ │ └── palette.ab4e12ef.min.css.map
│ ├── cli
│ │ └── index.html
│ ├── contributing
│ │ └── index.html
│ ├── contributing_languages
│ │ └── index.html
│ ├── cookbook
│ │ └── index.html
│ ├── core
│ │ └── index.html
│ ├── future_work
│ │ └── index.html
│ ├── images
│ │ ├── 1.png
│ │ ├── 11.png
│ │ ├── 12.png
│ │ ├── 13.png
│ │ ├── 14.png
│ │ ├── 16.png
│ │ ├── 19.png
│ │ ├── 2.png
│ │ ├── 20.png
│ │ ├── 21.png
│ │ ├── 22.png
│ │ ├── 23.png
│ │ ├── 24.png
│ │ ├── 26.png
│ │ ├── 28.png
│ │ ├── 29.png
│ │ ├── 3.png
│ │ ├── 30.png
│ │ ├── 31.png
│ │ ├── 32.png
│ │ ├── 33.png
│ │ ├── 34.png
│ │ ├── 35.png
│ │ ├── 36.png
│ │ ├── 38.png
│ │ ├── 39.png
│ │ ├── 4.png
│ │ ├── 40.png
│ │ ├── 41.png
│ │ ├── 42.png
│ │ ├── 43.png
│ │ ├── 44.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ ├── 9.png
│ │ ├── Indexing.gif
│ │ ├── tool_images
│ │ │ ├── 1.png
│ │ │ ├── 2.png
│ │ │ └── 3.png
│ │ └── Usecase.gif
│ ├── index.html
│ ├── installation
│ │ └── index.html
│ ├── license
│ │ └── index.html
│ ├── search
│ │ └── search_index.json
│ ├── server
│ │ └── index.html
│ ├── sitemap.xml
│ ├── sitemap.xml.gz
│ ├── tools
│ │ └── index.html
│ ├── troubleshooting
│ │ └── index.html
│ ├── use_cases
│ │ └── index.html
│ └── watching
│ └── index.html
├── funding.json
├── images
│ ├── 1.png
│ ├── 11.png
│ ├── 12.png
│ ├── 13.png
│ ├── 14.png
│ ├── 16.png
│ ├── 19.png
│ ├── 2.png
│ ├── 20.png
│ ├── 21.png
│ ├── 22.png
│ ├── 23.png
│ ├── 24.png
│ ├── 26.png
│ ├── 28.png
│ ├── 29.png
│ ├── 3.png
│ ├── 30.png
│ ├── 31.png
│ ├── 32.png
│ ├── 33.png
│ ├── 34.png
│ ├── 35.png
│ ├── 36.png
│ ├── 38.png
│ ├── 39.png
│ ├── 4.png
│ ├── 40.png
│ ├── 41.png
│ ├── 42.png
│ ├── 43.png
│ ├── 44.png
│ ├── 5.png
│ ├── 6.png
│ ├── 7.png
│ ├── 8.png
│ ├── 9.png
│ ├── Indexing.gif
│ ├── tool_images
│ │ ├── 1.png
│ │ ├── 2.png
│ │ └── 3.png
│ └── Usecase.gif
├── LICENSE
├── MANIFEST.in
├── organizer
│ ├── CONTRIBUTING_LANGUAGES.md
│ ├── cookbook.md
│ ├── docs.md
│ ├── language_specific_nodes.md
│ ├── Tools_Exploration.md
│ └── troubleshoot.md
├── pyproject.toml
├── README.md
├── scripts
│ ├── generate_lang_contributors.py
│ ├── post_install_fix.sh
│ ├── test_all_parsers.py
│ └── update_language_parsers.py
├── SECURITY.md
├── src
│ └── codegraphcontext
│ ├── __init__.py
│ ├── __main__.py
│ ├── cli
│ │ ├── __init__.py
│ │ ├── cli_helpers.py
│ │ ├── config_manager.py
│ │ ├── main.py
│ │ ├── setup_macos.py
│ │ └── setup_wizard.py
│ ├── core
│ │ ├── __init__.py
│ │ ├── database_falkordb.py
│ │ ├── database.py
│ │ ├── falkor_worker.py
│ │ ├── jobs.py
│ │ └── watcher.py
│ ├── prompts.py
│ ├── server.py
│ ├── tools
│ │ ├── __init__.py
│ │ ├── advanced_language_query_tool.py
│ │ ├── code_finder.py
│ │ ├── graph_builder.py
│ │ ├── languages
│ │ │ ├── c.py
│ │ │ ├── cpp.py
│ │ │ ├── csharp.py
│ │ │ ├── go.py
│ │ │ ├── java.py
│ │ │ ├── javascript.py
│ │ │ ├── kotlin.py
│ │ │ ├── php.py
│ │ │ ├── python.py
│ │ │ ├── ruby.py
│ │ │ ├── rust.py
│ │ │ ├── scala.py
│ │ │ ├── swift.py
│ │ │ ├── typescript.py
│ │ │ └── typescriptjsx.py
│ │ ├── package_resolver.py
│ │ ├── query_tool_languages
│ │ │ ├── c_toolkit.py
│ │ │ ├── cpp_toolkit.py
│ │ │ ├── csharp_toolkit.py
│ │ │ ├── go_toolkit.py
│ │ │ ├── java_toolkit.py
│ │ │ ├── javascript_toolkit.py
│ │ │ ├── python_toolkit.py
│ │ │ ├── ruby_toolkit.py
│ │ │ ├── rust_toolkit.py
│ │ │ ├── scala_toolkit.py
│ │ │ ├── swift_toolkit.py
│ │ │ └── typescript_toolkit.py
│ │ └── system.py
│ └── utils
│ ├── debug_log.py
│ └── tree_sitter_manager.py
├── tests
│ ├── __init__.py
│ ├── conftest.py
│ ├── sample_project
│ │ ├── advanced_calls.py
│ │ ├── advanced_classes.py
│ │ ├── advanced_classes2.py
│ │ ├── advanced_functions.py
│ │ ├── advanced_imports.py
│ │ ├── async_features.py
│ │ ├── callbacks_decorators.py
│ │ ├── circular1.py
│ │ ├── circular2.py
│ │ ├── class_instantiation.py
│ │ ├── cli_and_dunder.py
│ │ ├── complex_classes.py
│ │ ├── comprehensions_generators.py
│ │ ├── context_managers.py
│ │ ├── control_flow.py
│ │ ├── datatypes.py
│ │ ├── dynamic_dispatch.py
│ │ ├── dynamic_imports.py
│ │ ├── edge_cases
│ │ │ ├── comments_only.py
│ │ │ ├── docstring_only.py
│ │ │ ├── empty.py
│ │ │ ├── hardcoded_secrets.py
│ │ │ ├── long_functions.py
│ │ │ └── syntax_error.py
│ │ ├── function_chains.py
│ │ ├── generators.py
│ │ ├── import_reexports.py
│ │ ├── mapping_calls.py
│ │ ├── module_a.py
│ │ ├── module_b.py
│ │ ├── module_c
│ │ │ ├── __init__.py
│ │ │ ├── submodule1.py
│ │ │ └── submodule2.py
│ │ ├── namespace_pkg
│ │ │ └── ns_module.py
│ │ ├── pattern_matching.py
│ │ └── typing_examples.py
│ ├── sample_project_c
│ │ ├── cgc_sample
│ │ ├── include
│ │ │ ├── config.h
│ │ │ ├── math
│ │ │ │ └── vec.h
│ │ │ ├── module.h
│ │ │ ├── platform.h
│ │ │ └── util.h
│ │ ├── Makefile
│ │ ├── README.md
│ │ └── src
│ │ ├── main.c
│ │ ├── math
│ │ │ └── vec.c
│ │ ├── module.c
│ │ └── util.c
│ ├── sample_project_cpp
│ │ ├── class_features.cpp
│ │ ├── classes.cpp
│ │ ├── control_flow.cpp
│ │ ├── edge_cases.cpp
│ │ ├── enum_struct_union.cpp
│ │ ├── exceptions.cpp
│ │ ├── file_io.cpp
│ │ ├── function_chain.cpp
│ │ ├── function_chain.h
│ │ ├── function_types.cpp
│ │ ├── main.cpp
│ │ ├── main.exe
│ │ ├── namespaces.cpp
│ │ ├── raii_example.cpp
│ │ ├── README.md
│ │ ├── sample_project.exe
│ │ ├── stl_usage.cpp
│ │ ├── templates.cpp
│ │ └── types_variable_assignments.cpp
│ ├── sample_project_csharp
│ │ ├── README.md
│ │ └── src
│ │ └── Example.App
│ │ ├── Attributes
│ │ │ └── CustomAttributes.cs
│ │ ├── Example.App.csproj
│ │ ├── Models
│ │ │ ├── Person.cs
│ │ │ ├── Point.cs
│ │ │ ├── Role.cs
│ │ │ └── User.cs
│ │ ├── OuterClass.cs
│ │ ├── Program.cs
│ │ ├── Services
│ │ │ ├── GreetingService.cs
│ │ │ ├── IGreetingService.cs
│ │ │ └── LegacyService.cs
│ │ └── Utils
│ │ ├── CollectionHelper.cs
│ │ └── FileHelper.cs
│ ├── sample_project_go
│ │ ├── advanced_types.go
│ │ ├── basic_functions.go
│ │ ├── embedded_composition.go
│ │ ├── error_handling.go
│ │ ├── generics.go
│ │ ├── go.mod
│ │ ├── goroutines_channels.go
│ │ ├── interfaces.go
│ │ ├── packages_imports.go
│ │ ├── README.md
│ │ ├── structs_methods.go
│ │ └── util
│ │ └── helpers.go
│ ├── sample_project_java
│ │ ├── out
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── annotations
│ │ │ │ └── Logged.class
│ │ │ ├── Main.class
│ │ │ ├── misc
│ │ │ │ ├── Outer.class
│ │ │ │ └── Outer$Inner.class
│ │ │ ├── model
│ │ │ │ ├── Role.class
│ │ │ │ └── User.class
│ │ │ ├── service
│ │ │ │ ├── AbstractGreeter.class
│ │ │ │ ├── GreetingService.class
│ │ │ │ └── impl
│ │ │ │ └── GreetingServiceImpl.class
│ │ │ └── util
│ │ │ ├── CollectionUtils.class
│ │ │ └── IOHelper.class
│ │ ├── README.md
│ │ ├── sources.txt
│ │ └── src
│ │ └── com
│ │ └── example
│ │ └── app
│ │ ├── annotations
│ │ │ └── Logged.java
│ │ ├── Main.java
│ │ ├── misc
│ │ │ └── Outer.java
│ │ ├── model
│ │ │ ├── Role.java
│ │ │ └── User.java
│ │ ├── service
│ │ │ ├── AbstractGreeter.java
│ │ │ ├── GreetingService.java
│ │ │ └── impl
│ │ │ └── GreetingServiceImpl.java
│ │ └── util
│ │ ├── CollectionUtils.java
│ │ └── IOHelper.java
│ ├── sample_project_javascript
│ │ ├── arrays.js
│ │ ├── asyncAwait.js
│ │ ├── classes.js
│ │ ├── dom.js
│ │ ├── errorHandling.js
│ │ ├── events.js
│ │ ├── exporter.js
│ │ ├── fetchAPI.js
│ │ ├── fixtures
│ │ │ └── js
│ │ │ └── accessors.js
│ │ ├── functions.js
│ │ ├── importer.js
│ │ ├── objects.js
│ │ ├── promises.js
│ │ ├── README.md
│ │ └── variables.js
│ ├── sample_project_kotlin
│ │ ├── AdvancedClasses.kt
│ │ ├── Annotations.kt
│ │ ├── Coroutines.kt
│ │ ├── EdgeCases.kt
│ │ ├── Functions.kt
│ │ ├── Main.kt
│ │ ├── Properties.kt
│ │ └── User.kt
│ ├── sample_project_misc
│ │ ├── index.html
│ │ ├── README.md
│ │ ├── styles.css
│ │ ├── tables.css
│ │ └── tables.html
│ ├── sample_project_php
│ │ ├── classes_objects.php
│ │ ├── database.php
│ │ ├── edgecases.php
│ │ ├── error_handling.php
│ │ ├── file_handling.php
│ │ ├── functions.php
│ │ ├── generators_iterators.php
│ │ ├── globals_superglobals.php
│ │ ├── Inheritance.php
│ │ ├── interface_traits.php
│ │ └── README.md
│ ├── sample_project_ruby
│ │ ├── class_example.rb
│ │ ├── enumerables.rb
│ │ ├── error_handling.rb
│ │ ├── file_io.rb
│ │ ├── inheritance_example.rb
│ │ ├── main.rb
│ │ ├── metaprogramming.rb
│ │ ├── mixins_example.rb
│ │ ├── module_example.rb
│ │ └── tests
│ │ ├── test_mixins.py
│ │ └── test_sample.rb
│ ├── sample_project_rust
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src
│ │ ├── basic_functions.rs
│ │ ├── concurrency.rs
│ │ ├── error_handling.rs
│ │ ├── generics.rs
│ │ ├── iterators_closures.rs
│ │ ├── lib.rs
│ │ ├── lifetimes_references.rs
│ │ ├── modules.rs
│ │ ├── smart_pointers.rs
│ │ ├── structs_enums.rs
│ │ └── traits.rs
│ ├── sample_project_scala
│ │ ├── Animals.scala
│ │ ├── Complex.scala
│ │ ├── Functional.scala
│ │ ├── Geometry.scala
│ │ ├── Main.scala
│ │ ├── PackageObject.scala
│ │ ├── Script.sc
│ │ ├── Services.scala
│ │ ├── Shapes.scala
│ │ ├── Utils.scala
│ │ └── Variables.scala
│ ├── sample_project_swift
│ │ ├── Generics.swift
│ │ ├── Main.swift
│ │ ├── README.md
│ │ ├── Shapes.swift
│ │ ├── User.swift
│ │ └── Vehicles.swift
│ ├── sample_project_typescript
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── sample_tsx.tsx
│ │ ├── src
│ │ │ ├── advanced-types.ts
│ │ │ ├── async-promises.ts
│ │ │ ├── classes-inheritance.ts
│ │ │ ├── decorators-metadata.ts
│ │ │ ├── error-validation.ts
│ │ │ ├── functions-generics.ts
│ │ │ ├── index.ts
│ │ │ ├── modules-namespaces.ts
│ │ │ ├── types-interfaces.ts
│ │ │ └── utilities-helpers.ts
│ │ └── tsconfig.json
│ ├── test_cpp_parser.py
│ ├── test_database_validation.py
│ ├── test_end_to_end.py
│ ├── test_graph_indexing_js.py
│ ├── test_graph_indexing.py
│ ├── test_kotlin_parser.py
│ ├── test_swift_parser.py
│ ├── test_tree_sitter
│ │ ├── __init__.py
│ │ ├── class_instantiation.py
│ │ ├── complex_classes.py
│ │ └── test_file.py
│ ├── test_tree_sitter_manager.py
│ └── test_typescript_parser.py
├── visualize_graph.py
├── website
│ ├── .example.env
│ ├── .gitignore
│ ├── api
│ │ └── pypi.ts
│ ├── bun.lockb
│ ├── components.json
│ ├── eslint.config.js
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── placeholder.svg
│ │ └── robots.txt
│ ├── README.md
│ ├── src
│ │ ├── App.css
│ │ ├── App.tsx
│ │ ├── assets
│ │ │ ├── function-calls.png
│ │ │ ├── graph-total.png
│ │ │ ├── hero-graph.jpg
│ │ │ └── hierarchy.png
│ │ ├── components
│ │ │ ├── ComparisonTable.tsx
│ │ │ ├── CookbookSection.tsx
│ │ │ ├── DemoSection.tsx
│ │ │ ├── ExamplesSection.tsx
│ │ │ ├── FeaturesSection.tsx
│ │ │ ├── Footer.tsx
│ │ │ ├── HeroSection.tsx
│ │ │ ├── InstallationSection.tsx
│ │ │ ├── MoveToTop.tsx
│ │ │ ├── ShowDownloads.tsx
│ │ │ ├── ShowStarGraph.tsx
│ │ │ ├── SocialMentionsTimeline.tsx
│ │ │ ├── TestimonialSection.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── ThemeToggle.tsx
│ │ │ └── ui
│ │ │ ├── accordion.tsx
│ │ │ ├── alert-dialog.tsx
│ │ │ ├── alert.tsx
│ │ │ ├── aspect-ratio.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── badge.tsx
│ │ │ ├── breadcrumb.tsx
│ │ │ ├── button.tsx
│ │ │ ├── calendar.tsx
│ │ │ ├── card.tsx
│ │ │ ├── carousel.tsx
│ │ │ ├── chart.tsx
│ │ │ ├── checkbox.tsx
│ │ │ ├── collapsible.tsx
│ │ │ ├── command.tsx
│ │ │ ├── context-menu.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── drawer.tsx
│ │ │ ├── dropdown-menu.tsx
│ │ │ ├── form.tsx
│ │ │ ├── hover-card.tsx
│ │ │ ├── input-otp.tsx
│ │ │ ├── input.tsx
│ │ │ ├── label.tsx
│ │ │ ├── menubar.tsx
│ │ │ ├── navigation-menu.tsx
│ │ │ ├── orbiting-circles.tsx
│ │ │ ├── pagination.tsx
│ │ │ ├── popover.tsx
│ │ │ ├── progress.tsx
│ │ │ ├── radio-group.tsx
│ │ │ ├── resizable.tsx
│ │ │ ├── scroll-area.tsx
│ │ │ ├── select.tsx
│ │ │ ├── separator.tsx
│ │ │ ├── sheet.tsx
│ │ │ ├── sidebar.tsx
│ │ │ ├── skeleton.tsx
│ │ │ ├── slider.tsx
│ │ │ ├── sonner.tsx
│ │ │ ├── switch.tsx
│ │ │ ├── table.tsx
│ │ │ ├── tabs.tsx
│ │ │ ├── textarea.tsx
│ │ │ ├── toast.tsx
│ │ │ ├── toaster.tsx
│ │ │ ├── toggle-group.tsx
│ │ │ ├── toggle.tsx
│ │ │ ├── tooltip.tsx
│ │ │ └── use-toast.ts
│ │ ├── hooks
│ │ │ ├── use-mobile.tsx
│ │ │ └── use-toast.ts
│ │ ├── index.css
│ │ ├── lib
│ │ │ └── utils.ts
│ │ ├── main.tsx
│ │ ├── pages
│ │ │ ├── Index.tsx
│ │ │ └── NotFound.tsx
│ │ └── vite-env.d.ts
│ ├── tailwind.config.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ ├── vercel.json
│ └── vite.config.ts
└── windows_setup_guide.md
```
# Files
--------------------------------------------------------------------------------
/tests/sample_project_javascript/classes.js:
--------------------------------------------------------------------------------
```javascript
1 | /**
2 | * Sample JavaScript file demonstrating class definitions and methods
3 | * This file tests class declarations, methods, static methods, and inheritance
4 | */
5 |
6 | // Basic class declaration
7 | class Person {
8 | constructor(name, age) {
9 | this.name = name;
10 | this.age = age;
11 | }
12 |
13 | // Instance method
14 | greet() {
15 | return `Hello, I'm ${this.name} and I'm ${this.age} years old`;
16 | }
17 |
18 | /**
19 | * Method with JSDoc documentation
20 | * @param {number} years - Number of years to add
21 | * @returns {void}
22 | */
23 | celebrateBirthday(years = 1) {
24 | this.age += years;
25 | console.log(`Happy birthday! Now ${this.age} years old`);
26 | }
27 |
28 | // Getter method
29 | get info() {
30 | return `${this.name} (${this.age})`;
31 | }
32 |
33 | // Setter method
34 | set info(value) {
35 | const [name, age] = value.split(' ');
36 | this.name = name;
37 | this.age = parseInt(age);
38 | }
39 |
40 | // Static method
41 | static createAdult(name) {
42 | return new Person(name, 18);
43 | }
44 |
45 | // Static method with parameters
46 | static compare(person1, person2) {
47 | return person1.age - person2.age;
48 | }
49 | }
50 |
51 | // Class inheritance
52 | class Employee extends Person {
53 | constructor(name, age, jobTitle, salary) {
54 | super(name, age);
55 | this.jobTitle = jobTitle;
56 | this.salary = salary;
57 | }
58 |
59 | // Override parent method
60 | greet() {
61 | return `${super.greet()}. I work as a ${this.jobTitle}`;
62 | }
63 |
64 | // New method specific to Employee
65 | work() {
66 | console.log(`${this.name} is working as a ${this.jobTitle}`);
67 | }
68 |
69 | // Method with complex parameters
70 | updateSalary(newSalary, reason = 'performance review') {
71 | const oldSalary = this.salary;
72 | this.salary = newSalary;
73 | console.log(`Salary updated from ${oldSalary} to ${newSalary} due to ${reason}`);
74 | }
75 |
76 | // Static method in child class
77 | static createIntern(name, age) {
78 | return new Employee(name, age, 'Intern', 0);
79 | }
80 | }
81 |
82 | // Class with private fields (modern JavaScript)
83 | class BankAccount {
84 | #balance = 0;
85 | #accountNumber;
86 |
87 | constructor(accountNumber, initialBalance = 0) {
88 | this.#accountNumber = accountNumber;
89 | this.#balance = initialBalance;
90 | }
91 |
92 | // Public method accessing private field
93 | deposit(amount) {
94 | if (amount > 0) {
95 | this.#balance += amount;
96 | return this.#balance;
97 | }
98 | throw new Error('Amount must be positive');
99 | }
100 |
101 | // Public method accessing private field
102 | withdraw(amount) {
103 | if (amount > 0 && amount <= this.#balance) {
104 | this.#balance -= amount;
105 | return this.#balance;
106 | }
107 | throw new Error('Invalid withdrawal amount');
108 | }
109 |
110 | // Getter for private field
111 | get balance() {
112 | return this.#balance;
113 | }
114 |
115 | // Private method
116 | #validateTransaction(amount) {
117 | return amount > 0 && amount <= this.#balance;
118 | }
119 | }
120 |
121 | // Class with static properties and methods
122 | class MathUtils {
123 | static PI = 3.14159;
124 | static E = 2.71828;
125 |
126 | static add(a, b) {
127 | return a + b;
128 | }
129 |
130 | static multiply(a, b) {
131 | return a * b;
132 | }
133 |
134 | static circleArea(radius) {
135 | return MathUtils.PI * radius * radius;
136 | }
137 | }
138 |
139 | // Class expression assigned to variable
140 | const AnonymousClass = class {
141 | constructor(value) {
142 | this.value = value;
143 | }
144 |
145 | getValue() {
146 | return this.value;
147 | }
148 | };
149 |
150 | // Mixin pattern using classes
151 | const Flyable = (Base) => class extends Base {
152 | fly() {
153 | console.log(`${this.name} is flying!`);
154 | }
155 | };
156 |
157 | const Swimmable = (Base) => class extends Base {
158 | swim() {
159 | console.log(`${this.name} is swimming!`);
160 | }
161 | };
162 |
163 | // Class using mixins
164 | class Duck extends Swimmable(Flyable(Person)) {
165 | constructor(name) {
166 | super(name, 0); // Ducks don't have human age
167 | this.species = 'Duck';
168 | }
169 |
170 | quack() {
171 | console.log(`${this.name} says: Quack!`);
172 | }
173 | }
174 |
175 | // Function that creates and uses class instances
176 | function demonstrateClasses() {
177 | const person = new Person('Alice', 30);
178 | const employee = new Employee('Bob', 25, 'Developer', 75000);
179 | const account = new BankAccount('12345', 1000);
180 | const duck = new Duck('Donald');
181 |
182 | // Call various methods
183 | console.log(person.greet());
184 | console.log(employee.greet());
185 | employee.work();
186 |
187 | account.deposit(500);
188 | console.log('Balance:', account.balance);
189 |
190 | duck.quack();
191 | duck.fly();
192 | duck.swim();
193 |
194 | return {
195 | person,
196 | employee,
197 | account,
198 | duck
199 | };
200 | }
201 |
202 | // Export classes
203 | export { Person, Employee, BankAccount, MathUtils, Duck };
204 | export default demonstrateClasses;
205 |
206 |
```
--------------------------------------------------------------------------------
/website/src/components/ui/toast.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import * as ToastPrimitives from "@radix-ui/react-toast";
3 | import { cva, type VariantProps } from "class-variance-authority";
4 | import { X } from "lucide-react";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | const ToastProvider = ToastPrimitives.Provider;
9 |
10 | const ToastViewport = React.forwardRef<
11 | React.ElementRef<typeof ToastPrimitives.Viewport>,
12 | React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
13 | >(({ className, ...props }, ref) => (
14 | <ToastPrimitives.Viewport
15 | ref={ref}
16 | className={cn(
17 | "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
18 | className,
19 | )}
20 | {...props}
21 | />
22 | ));
23 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
24 |
25 | const toastVariants = cva(
26 | "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
27 | {
28 | variants: {
29 | variant: {
30 | default: "border bg-background text-foreground",
31 | destructive: "destructive group border-destructive bg-destructive text-destructive-foreground",
32 | },
33 | },
34 | defaultVariants: {
35 | variant: "default",
36 | },
37 | },
38 | );
39 |
40 | const Toast = React.forwardRef<
41 | React.ElementRef<typeof ToastPrimitives.Root>,
42 | React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
43 | >(({ className, variant, ...props }, ref) => {
44 | return <ToastPrimitives.Root ref={ref} className={cn(toastVariants({ variant }), className)} {...props} />;
45 | });
46 | Toast.displayName = ToastPrimitives.Root.displayName;
47 |
48 | const ToastAction = React.forwardRef<
49 | React.ElementRef<typeof ToastPrimitives.Action>,
50 | React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
51 | >(({ className, ...props }, ref) => (
52 | <ToastPrimitives.Action
53 | ref={ref}
54 | className={cn(
55 | "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors group-[.destructive]:border-muted/40 hover:bg-secondary group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 group-[.destructive]:focus:ring-destructive disabled:pointer-events-none disabled:opacity-50",
56 | className,
57 | )}
58 | {...props}
59 | />
60 | ));
61 | ToastAction.displayName = ToastPrimitives.Action.displayName;
62 |
63 | const ToastClose = React.forwardRef<
64 | React.ElementRef<typeof ToastPrimitives.Close>,
65 | React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
66 | >(({ className, ...props }, ref) => (
67 | <ToastPrimitives.Close
68 | ref={ref}
69 | className={cn(
70 | "absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity group-hover:opacity-100 group-[.destructive]:text-red-300 hover:text-foreground group-[.destructive]:hover:text-red-50 focus:opacity-100 focus:outline-none focus:ring-2 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
71 | className,
72 | )}
73 | toast-close=""
74 | {...props}
75 | >
76 | <X className="h-4 w-4" />
77 | </ToastPrimitives.Close>
78 | ));
79 | ToastClose.displayName = ToastPrimitives.Close.displayName;
80 |
81 | const ToastTitle = React.forwardRef<
82 | React.ElementRef<typeof ToastPrimitives.Title>,
83 | React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
84 | >(({ className, ...props }, ref) => (
85 | <ToastPrimitives.Title ref={ref} className={cn("text-sm font-semibold", className)} {...props} />
86 | ));
87 | ToastTitle.displayName = ToastPrimitives.Title.displayName;
88 |
89 | const ToastDescription = React.forwardRef<
90 | React.ElementRef<typeof ToastPrimitives.Description>,
91 | React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
92 | >(({ className, ...props }, ref) => (
93 | <ToastPrimitives.Description ref={ref} className={cn("text-sm opacity-90", className)} {...props} />
94 | ));
95 | ToastDescription.displayName = ToastPrimitives.Description.displayName;
96 |
97 | type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
98 |
99 | type ToastActionElement = React.ReactElement<typeof ToastAction>;
100 |
101 | export {
102 | type ToastProps,
103 | type ToastActionElement,
104 | ToastProvider,
105 | ToastViewport,
106 | Toast,
107 | ToastTitle,
108 | ToastDescription,
109 | ToastClose,
110 | ToastAction,
111 | };
112 |
```
--------------------------------------------------------------------------------
/src/codegraphcontext/core/jobs.py:
--------------------------------------------------------------------------------
```python
1 | # src/codegraphcontext/core/jobs.py
2 | """
3 | This module defines the data structures and manager for handling long-running,
4 | background jobs, such as code indexing.
5 | """
6 | import uuid
7 | import threading
8 | from datetime import datetime, timedelta
9 | from dataclasses import dataclass, asdict
10 | from enum import Enum
11 | from typing import Any, Dict, List, Optional
12 | from pathlib import Path
13 |
14 |
15 | class JobStatus(Enum):
16 | """Enumeration for the possible statuses of a background job."""
17 | PENDING = "pending"
18 | RUNNING = "running"
19 | COMPLETED = "completed"
20 | FAILED = "failed"
21 | CANCELLED = "cancelled"
22 |
23 | @dataclass
24 | class JobInfo:
25 | """
26 | A data class to hold all information about a single background job.
27 | This makes it easy to track the job's progress, status, and results.
28 | """
29 | job_id: str
30 | status: JobStatus
31 | start_time: datetime
32 | end_time: Optional[datetime] = None
33 | total_files: int = 0
34 | processed_files: int = 0
35 | current_file: Optional[str] = None
36 | estimated_duration: Optional[float] = None
37 | actual_duration: Optional[float] = None
38 | errors: List[str] = None
39 | result: Optional[Dict[str, Any]] = None
40 | path: Optional[str] = None
41 | is_dependency: bool = False
42 |
43 | def __post_init__(self):
44 | """Ensures the errors list is initialized after the object is created."""
45 | if self.errors is None:
46 | self.errors = []
47 |
48 | @property
49 | def progress_percentage(self) -> float:
50 | """Calculates the completion percentage of the job."""
51 | if self.total_files == 0:
52 | return 0.0
53 | return (self.processed_files / self.total_files) * 100
54 |
55 | @property
56 | def estimated_time_remaining(self) -> Optional[float]:
57 | """Calculates the estimated time remaining based on the average time per file."""
58 | if self.status != JobStatus.RUNNING or self.processed_files == 0:
59 | return None
60 | elapsed = (datetime.now() - self.start_time).total_seconds()
61 | avg_time_per_file = elapsed / self.processed_files
62 | remaining_files = self.total_files - self.processed_files
63 | return remaining_files * avg_time_per_file
64 |
65 | class JobManager:
66 | """
67 | A thread-safe manager for creating, updating, and retrieving information
68 | about background jobs. It stores job information in memory.
69 | """
70 | def __init__(self):
71 | self.jobs: Dict[str, JobInfo] = {}
72 | self.lock = threading.Lock() # A lock to ensure thread-safe access to the jobs dictionary.
73 |
74 | def create_job(self, path: str, is_dependency: bool = False) -> str:
75 | """Creates a new job, assigns it a unique ID, and stores it."""
76 | job_id = str(uuid.uuid4())
77 | with self.lock:
78 | self.jobs[job_id] = JobInfo(
79 | job_id=job_id,
80 | status=JobStatus.PENDING,
81 | start_time=datetime.now(),
82 | path=path,
83 | is_dependency=is_dependency
84 | )
85 | return job_id
86 |
87 | def update_job(self, job_id: str, **kwargs):
88 | """Updates the information for a specific job in a thread-safe manner."""
89 | with self.lock:
90 | if job_id in self.jobs:
91 | job = self.jobs[job_id]
92 | for key, value in kwargs.items():
93 | if hasattr(job, key):
94 | setattr(job, key, value)
95 |
96 | def get_job(self, job_id: str) -> Optional[JobInfo]:
97 | """Retrieves the information for a single job."""
98 | with self.lock:
99 | return self.jobs.get(job_id)
100 |
101 | def list_jobs(self) -> List[JobInfo]:
102 | """Returns a list of all jobs currently in the manager."""
103 | with self.lock:
104 | return list(self.jobs.values())
105 |
106 | def find_active_job_by_path(self, path: str) -> Optional[JobInfo]:
107 | """Finds the most recent, currently active (pending or running) job for a given path."""
108 | with self.lock:
109 | path_obj = Path(path).resolve()
110 |
111 | matching_jobs = sorted(
112 | [job for job in self.jobs.values() if job.path and Path(job.path).resolve() == path_obj],
113 | key=lambda j: j.start_time,
114 | reverse=True
115 | )
116 |
117 | for job in matching_jobs:
118 | if job.status in [JobStatus.PENDING, JobStatus.RUNNING]:
119 | return job
120 |
121 | return None
122 |
123 | def cleanup_old_jobs(self, max_age_hours: int = 24):
124 | """Removes old, completed jobs from memory to prevent memory leaks."""
125 | cutoff_time = datetime.now() - timedelta(hours=max_age_hours)
126 | with self.lock:
127 | jobs_to_remove = [
128 | job_id for job_id, job in self.jobs.items()
129 | if job.end_time and job.end_time < cutoff_time
130 | ]
131 | for job_id in jobs_to_remove:
132 | del self.jobs[job_id]
133 |
```
--------------------------------------------------------------------------------
/website/src/components/ui/command.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import { type DialogProps } from "@radix-ui/react-dialog";
3 | import { Command as CommandPrimitive } from "cmdk";
4 | import { Search } from "lucide-react";
5 |
6 | import { cn } from "@/lib/utils";
7 | import { Dialog, DialogContent } from "@/components/ui/dialog";
8 |
9 | const Command = React.forwardRef<
10 | React.ElementRef<typeof CommandPrimitive>,
11 | React.ComponentPropsWithoutRef<typeof CommandPrimitive>
12 | >(({ className, ...props }, ref) => (
13 | <CommandPrimitive
14 | ref={ref}
15 | className={cn(
16 | "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
17 | className,
18 | )}
19 | {...props}
20 | />
21 | ));
22 | Command.displayName = CommandPrimitive.displayName;
23 |
24 | interface CommandDialogProps extends DialogProps {}
25 |
26 | const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
27 | return (
28 | <Dialog {...props}>
29 | <DialogContent className="overflow-hidden p-0 shadow-lg">
30 | <Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
31 | {children}
32 | </Command>
33 | </DialogContent>
34 | </Dialog>
35 | );
36 | };
37 |
38 | const CommandInput = React.forwardRef<
39 | React.ElementRef<typeof CommandPrimitive.Input>,
40 | React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
41 | >(({ className, ...props }, ref) => (
42 | <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
43 | <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
44 | <CommandPrimitive.Input
45 | ref={ref}
46 | className={cn(
47 | "flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
48 | className,
49 | )}
50 | {...props}
51 | />
52 | </div>
53 | ));
54 |
55 | CommandInput.displayName = CommandPrimitive.Input.displayName;
56 |
57 | const CommandList = React.forwardRef<
58 | React.ElementRef<typeof CommandPrimitive.List>,
59 | React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
60 | >(({ className, ...props }, ref) => (
61 | <CommandPrimitive.List
62 | ref={ref}
63 | className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
64 | {...props}
65 | />
66 | ));
67 |
68 | CommandList.displayName = CommandPrimitive.List.displayName;
69 |
70 | const CommandEmpty = React.forwardRef<
71 | React.ElementRef<typeof CommandPrimitive.Empty>,
72 | React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
73 | >((props, ref) => <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />);
74 |
75 | CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
76 |
77 | const CommandGroup = React.forwardRef<
78 | React.ElementRef<typeof CommandPrimitive.Group>,
79 | React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
80 | >(({ className, ...props }, ref) => (
81 | <CommandPrimitive.Group
82 | ref={ref}
83 | className={cn(
84 | "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
85 | className,
86 | )}
87 | {...props}
88 | />
89 | ));
90 |
91 | CommandGroup.displayName = CommandPrimitive.Group.displayName;
92 |
93 | const CommandSeparator = React.forwardRef<
94 | React.ElementRef<typeof CommandPrimitive.Separator>,
95 | React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
96 | >(({ className, ...props }, ref) => (
97 | <CommandPrimitive.Separator ref={ref} className={cn("-mx-1 h-px bg-border", className)} {...props} />
98 | ));
99 | CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
100 |
101 | const CommandItem = React.forwardRef<
102 | React.ElementRef<typeof CommandPrimitive.Item>,
103 | React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
104 | >(({ className, ...props }, ref) => (
105 | <CommandPrimitive.Item
106 | ref={ref}
107 | className={cn(
108 | "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50",
109 | className,
110 | )}
111 | {...props}
112 | />
113 | ));
114 |
115 | CommandItem.displayName = CommandPrimitive.Item.displayName;
116 |
117 | const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
118 | return <span className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />;
119 | };
120 | CommandShortcut.displayName = "CommandShortcut";
121 |
122 | export {
123 | Command,
124 | CommandDialog,
125 | CommandInput,
126 | CommandList,
127 | CommandEmpty,
128 | CommandGroup,
129 | CommandItem,
130 | CommandShortcut,
131 | CommandSeparator,
132 | };
133 |
```
--------------------------------------------------------------------------------
/scripts/update_language_parsers.py:
--------------------------------------------------------------------------------
```python
1 | #!/usr/bin/env python3
2 | """
3 | Script to update all language parsers to use the new tree-sitter 0.25+ API.
4 |
5 | This script:
6 | 1. Adds import for execute_query
7 | 2. Removes query dictionary initialization
8 | 3. Replaces query.captures() with execute_query()
9 | """
10 |
11 | import re
12 | from pathlib import Path
13 |
14 | # Language files to update
15 | LANGUAGE_FILES = [
16 | "javascript.py",
17 | "typescript.py",
18 | "go.py",
19 | "rust.py",
20 | "c.py",
21 | "cpp.py",
22 | "java.py",
23 | "ruby.py",
24 | "csharp.py",
25 | ]
26 |
27 | LANGUAGES_DIR = Path(__file__).resolve().parent.parent / "src" / "codegraphcontext" / "tools" / "languages"
28 |
29 |
30 | def update_imports(content: str) -> str:
31 | """Add execute_query import if not present."""
32 | if "from codegraphcontext.utils.tree_sitter_manager import execute_query" in content:
33 | return content
34 |
35 | # Find the last import statement
36 | import_pattern = r"(from codegraphcontext\.utils\.debug_log import[^\n]+)"
37 | match = re.search(import_pattern, content)
38 |
39 | if match:
40 | # Add our import after the debug_log import
41 | new_import = match.group(1) + "\nfrom codegraphcontext.utils.tree_sitter_manager import execute_query"
42 | content = content.replace(match.group(1), new_import)
43 |
44 | return content
45 |
46 |
47 | def remove_query_dict_init(content: str) -> str:
48 | """Remove self.queries dictionary initialization."""
49 | # Pattern to match the queries dictionary initialization
50 | pattern = r"\s+self\.queries\s*=\s*\{[^}]+\}\s*"
51 | content = re.sub(pattern, "\n", content, flags=re.DOTALL)
52 | return content
53 |
54 |
55 | def replace_query_usage(content: str, query_dict_name: str) -> str:
56 | """Replace query.captures() with execute_query()."""
57 |
58 | # Pattern 1: self.queries.get('name') or self.queries['name']
59 | # Replace: query = self.queries.get('lambda_assignments')
60 | # With: query_str = LANG_QUERIES.get('lambda_assignments')
61 | content = re.sub(
62 | r"query\s*=\s*self\.queries\.get\('([^']+)'\)",
63 | r"query_str = " + query_dict_name + ".get('\\1')",
64 | content
65 | )
66 | content = re.sub(
67 | r"query\s*=\s*self\.queries\['([^']+)'\]",
68 | r"query_str = " + query_dict_name + "['\\1']",
69 | content
70 | )
71 |
72 | # Pattern 2: if not query: return []
73 | # Replace with: if not query_str: return []
74 | content = content.replace("if not query:", "if not query_str:")
75 |
76 | # Pattern 3: query.captures(node)
77 | # Replace with: execute_query(self.language, query_str, node)
78 | content = re.sub(
79 | r"query\.captures\(([^)]+)\)",
80 | r"execute_query(self.language, query_str, \1)",
81 | content
82 | )
83 |
84 | # Pattern 4: In pre_scan functions, replace parser_wrapper.language.query(query_str)
85 | content = re.sub(
86 | r"query\s*=\s*parser_wrapper\.language\.query\(query_str\)",
87 | "",
88 | content
89 | )
90 |
91 | # Pattern 5: In pre_scan functions, replace query.captures with execute_query
92 | content = re.sub(
93 | r"for\s+([^,]+),\s+([^)]+)\s+in\s+query\.captures\(tree\.root_node\):",
94 | r"for \1, \2 in execute_query(parser_wrapper.language, query_str, tree.root_node):",
95 | content
96 | )
97 | content = re.sub(
98 | r"for\s+([^,]+),\s+([^)]+)\s+in\s+query\.captures\(([^)]+)\):",
99 | r"for \1, \2 in execute_query(parser_wrapper.language, query_str, \3):",
100 | content
101 | )
102 |
103 | return content
104 |
105 |
106 | def get_query_dict_name(content: str) -> str:
107 | """Detect the query dictionary name (e.g., PY_QUERIES, JS_QUERIES, etc.)."""
108 | match = re.search(r"([A-Z_]+QUERIES)\s*=\s*\{", content)
109 | if match:
110 | return match.group(1)
111 | return "QUERIES"
112 |
113 |
114 | def update_language_file(file_path: Path):
115 | """Update a single language file."""
116 | print(f"Updating {file_path.name}...")
117 |
118 | content = file_path.read_text()
119 | original_content = content
120 |
121 | # Detect query dictionary name
122 | query_dict_name = get_query_dict_name(content)
123 | print(f" Query dict name: {query_dict_name}")
124 |
125 | # Apply transformations
126 | content = update_imports(content)
127 | content = remove_query_dict_init(content)
128 | content = replace_query_usage(content, query_dict_name)
129 |
130 | # Write back if changed
131 | if content != original_content:
132 | file_path.write_text(content)
133 | print(f" ✓ Updated {file_path.name}")
134 | else:
135 | print(f" - No changes needed for {file_path.name}")
136 |
137 |
138 | def main():
139 | """Update all language parser files."""
140 | print("Updating language parsers for tree-sitter 0.25+ compatibility\n")
141 |
142 | for lang_file in LANGUAGE_FILES:
143 | file_path = LANGUAGES_DIR / lang_file
144 | if file_path.exists():
145 | try:
146 | update_language_file(file_path)
147 | except Exception as e:
148 | print(f" ✗ Error updating {lang_file}: {e}")
149 | else:
150 | print(f" ✗ File not found: {lang_file}")
151 |
152 | print("\n✓ All language parsers updated!")
153 |
154 |
155 | if __name__ == "__main__":
156 | main()
157 |
```
--------------------------------------------------------------------------------
/visualize_graph.py:
--------------------------------------------------------------------------------
```python
1 | import os
2 | import json
3 | import platform
4 | from pathlib import Path
5 |
6 | if platform.system() == "Windows":
7 | raise RuntimeError(
8 | "CodeGraphContext uses redislite/FalkorDB, which does not support Windows.\n"
9 | "Please run the project using WSL or Docker."
10 | )
11 |
12 | from redislite import FalkorDB
13 |
14 | def generate_visualization():
15 | db_path = os.path.expanduser('~/.codegraphcontext/falkordb.db')
16 | if not os.path.exists(db_path):
17 | print(f"Error: Database not found at {db_path}")
18 | return
19 |
20 | print(f"Reading graph from {db_path}...")
21 | f = FalkorDB(db_path)
22 | g = f.select_graph('codegraph')
23 |
24 | # Fetch nodes
25 | nodes_res = g.query("MATCH (n) RETURN id(n), labels(n)[0], n.name, n.path")
26 | nodes = []
27 | for row in nodes_res.result_set:
28 | node_id, label, name, path = row
29 | # Format label and name for display
30 | display_name = name if name else (os.path.basename(path) if path else label)
31 | nodes.append({
32 | "id": node_id,
33 | "label": display_name,
34 | "group": label,
35 | "title": f"Type: {label}\nPath: {path}"
36 | })
37 |
38 | # Fetch relationships
39 | edges_res = g.query("MATCH (s)-[r]->(t) RETURN id(s), type(r), id(t)")
40 | edges = []
41 | for row in edges_res.result_set:
42 | source, rel_type, target = row
43 | edges.append({
44 | "from": source,
45 | "to": target,
46 | "label": rel_type,
47 | "arrows": "to"
48 | })
49 |
50 | html_content = f"""
51 | <!DOCTYPE html>
52 | <html>
53 | <head>
54 | <title>CGC Graph Visualization</title>
55 | <script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
56 | <style type="text/css">
57 | body {{
58 | margin: 0;
59 | padding: 0;
60 | background-color: #1a1a1a;
61 | color: #ffffff;
62 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
63 | overflow: hidden;
64 | }}
65 | #mynetwork {{
66 | width: 100vw;
67 | height: 100vh;
68 | }}
69 | .header {{
70 | position: absolute;
71 | top: 20px;
72 | left: 20px;
73 | z-index: 10;
74 | background: rgba(0,0,0,0.7);
75 | padding: 15px;
76 | border-radius: 8px;
77 | border: 1px solid #444;
78 | pointer-events: none;
79 | }}
80 | h1 {{ margin: 0; font-size: 1.5em; color: #00d4ff; }}
81 | .stats {{ font-size: 0.9em; color: #aaa; margin-top: 5px; }}
82 | </style>
83 | </head>
84 | <body>
85 | <div class="header">
86 | <h1>CodeGraphContext Visualizer</h1>
87 | <div class="stats">Nodes: {len(nodes)} | Relationships: {len(edges)}</div>
88 | <div style="font-size: 0.8em; margin-top: 10px; color: #888;">Drag to move | Scroll to zoom</div>
89 | </div>
90 | <div id="mynetwork"></div>
91 |
92 | <script type="text/javascript">
93 | var nodes = new vis.DataSet({json.dumps(nodes)});
94 | var edges = new vis.DataSet({json.dumps(edges)});
95 |
96 | var container = document.getElementById('mynetwork');
97 | var data = {{
98 | nodes: nodes,
99 | edges: edges
100 | }};
101 | var options = {{
102 | nodes: {{
103 | shape: 'dot',
104 | size: 16,
105 | font: {{ color: '#ffffff', size: 12 }},
106 | borderWidth: 2,
107 | shadow: true
108 | }},
109 | edges: {{
110 | width: 2,
111 | color: {{ color: '#666666', highlight: '#00d4ff' }},
112 | font: {{ size: 10, align: 'middle', color: '#aaaaaa' }},
113 | smooth: {{ type: 'continuous' }}
114 | }},
115 | groups: {{
116 | Repository: {{ color: {{ background: '#e91e63', border: '#c2185b' }} }},
117 | File: {{ color: {{ background: '#2196f3', border: '#1976d2' }} }},
118 | Function: {{ color: {{ background: '#4caf50', border: '#388e3c' }} }},
119 | Class: {{ color: {{ background: '#ff9800', border: '#f57c00' }} }},
120 | Module: {{ color: {{ background: '#9c27b0', border: '#7b1fa2' }} }},
121 | Variable: {{ color: {{ background: '#607d8b', border: '#455a64' }} }}
122 | }},
123 | physics: {{
124 | forceAtlas2Based: {{
125 | gravitationalConstant: -26,
126 | centralGravity: 0.005,
127 | springLength: 230,
128 | springConstant: 0.18
129 | }},
130 | maxVelocity: 146,
131 | solver: 'forceAtlas2Based',
132 | timestep: 0.35,
133 | stabilization: {{ iterations: 150 }}
134 | }}
135 | }};
136 | var network = new vis.Network(container, data, options);
137 | </script>
138 | </body>
139 | </html>
140 | """
141 |
142 | target_path = Path.cwd() / "graph_viz.html"
143 | with open(target_path, "w") as f:
144 | f.write(html_content)
145 |
146 | print(f"\n✅ Visualization generated successfully!")
147 | print(f"👉 Open this file in your browser: file://{target_path.absolute()}")
148 |
149 | if __name__ == "__main__":
150 | generate_visualization()
151 |
```
--------------------------------------------------------------------------------
/scripts/generate_lang_contributors.py:
--------------------------------------------------------------------------------
```python
1 | import subprocess
2 | import os
3 | from collections import defaultdict
4 |
5 | # Get the absolute path of the script's directory, then go up to the project root.
6 | SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
7 | PROJECT_ROOT = os.path.dirname(SCRIPT_DIR)
8 |
9 | # Define files to track per language. Paths are relative to the project root.
10 | files_by_lang = {
11 | "c": ["src/codegraphcontext/tools/languages/c.py"],
12 | "cpp": ["src/codegraphcontext/tools/languages/cpp.py"],
13 | "go": ["src/codegraphcontext/tools/languages/go.py"],
14 | "java": ["src/codegraphcontext/tools/languages/java.py"],
15 | "javascript": ["src/codegraphcontext/tools/languages/javascript.py"],
16 | "python": ["src/codegraphcontext/tools/languages/python.py"],
17 | "ruby": ["src/codegraphcontext/tools/languages/ruby.py"],
18 | "rust": ["src/codegraphcontext/tools/languages/rust.py"],
19 | "typescript": ["src/codegraphcontext/tools/languages/typescript.py"],
20 | }
21 |
22 | def get_contributor_stats(files):
23 | """
24 | Returns a dictionary of contributors with commit count, lines added, and lines deleted.
25 | This is done by parsing the output of 'git log'.
26 | """
27 | data = defaultdict(lambda: {"commits": 0, "added": 0, "deleted": 0, "email": ""})
28 |
29 | try:
30 | # Use 'git log' with '--numstat' to get file changes, author name, and email in one go.
31 | log_output = subprocess.check_output(
32 | ["git", "log", "--no-merges", "--numstat", "--pretty=format:---%n%an%n%ae", "--"] + files,
33 | text=True,
34 | cwd=PROJECT_ROOT
35 | ).strip()
36 | except subprocess.CalledProcessError as e:
37 | print(f"Error fetching git log for files {files}: {e}")
38 | return data
39 |
40 | if not log_output:
41 | return data
42 |
43 | commits = log_output.split('---')[1:]
44 |
45 | for commit in commits:
46 | lines = commit.strip().split('\n')
47 | author = lines[0].strip()
48 | email = lines[1].strip()
49 | if not author:
50 | continue
51 |
52 | data[author]["commits"] += 1
53 | data[author]["email"] = email
54 |
55 | for line in lines[2:]:
56 | if not line.strip():
57 | continue
58 |
59 | parts = line.split("\t")
60 | if len(parts) >= 3:
61 | added, deleted, _ = parts
62 | added = int(added) if added != "-" else 0
63 | deleted = int(deleted) if deleted != "-" else 0
64 | data[author]["added"] += added
65 | data[author]["deleted"] += deleted
66 |
67 | return data
68 |
69 | def get_username_from_email(email):
70 | if email.endswith('@users.noreply.github.com'):
71 | return email.split('+')[1].split('@')[0]
72 | return None
73 |
74 | def get_repo_url():
75 | try:
76 | url = subprocess.check_output(
77 | ["git", "remote", "get-url", "origin"],
78 | text=True,
79 | cwd=PROJECT_ROOT
80 | ).strip()
81 | if url.endswith(".git"):
82 | url = url[:-4]
83 | if url.startswith("[email protected]:"):
84 | url = url.replace("[email protected]:", "https://github.com/")
85 | return url
86 | except Exception:
87 | return None
88 |
89 | def generate_markdown_table(lang, stats, repo_url, files):
90 | """
91 | Generates a Markdown table for contributors
92 | """
93 | table = f"## {lang.capitalize()} Contributors\n\n"
94 | table += "| Rank | Contributor | Commits | Lines Added | Lines Deleted | Link to Contributions |\n"
95 | table += "|---|---|---|---|---|---|\n"
96 |
97 | for rank, (author, vals) in enumerate(sorted(stats.items(), key=lambda x: (x[1]["commits"], x[1]["added"]), reverse=True), 1):
98 | email = vals["email"]
99 | username = get_username_from_email(email)
100 |
101 | if username:
102 | profile_str = f"[{author}](https://github.com/{username})"
103 | author_for_link = username
104 | else:
105 | profile_str = author
106 | author_for_link = email
107 |
108 | contribution_links = []
109 | for file_path in files:
110 | file_name = os.path.basename(file_path)
111 | link = f"[{file_name}]({repo_url}/commits/main/{file_path}?author={author_for_link})"
112 | contribution_links.append(link)
113 |
114 | links_str = ", ".join(contribution_links)
115 |
116 | table += f"| {rank} | {profile_str} | {vals['commits']} | {vals['added']} | {vals['deleted']} | {links_str} |\n"
117 |
118 | return table
119 |
120 | def main():
121 | repo_url = get_repo_url()
122 | if not repo_url:
123 | print("Could not determine repository URL. Contribution links will not be generated.")
124 |
125 | output_file = os.path.join(PROJECT_ROOT, "contributors.md")
126 | with open(output_file, "w") as f:
127 | f.write("# Language Contributors\n\n")
128 | f.write("This file is auto-generated. Do not edit manually.\n\n")
129 | for lang, files in files_by_lang.items():
130 | stats = get_contributor_stats(files)
131 | if stats:
132 | table = generate_markdown_table(lang, stats, repo_url, files)
133 | f.write(table + "\n\n")
134 | print(f"Contributor stats generated in {output_file}")
135 |
136 | if __name__ == "__main__":
137 | main()
138 |
```
--------------------------------------------------------------------------------
/website/src/components/ui/navigation-menu.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
3 | import { cva } from "class-variance-authority";
4 | import { ChevronDown } from "lucide-react";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | const NavigationMenu = React.forwardRef<
9 | React.ElementRef<typeof NavigationMenuPrimitive.Root>,
10 | React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
11 | >(({ className, children, ...props }, ref) => (
12 | <NavigationMenuPrimitive.Root
13 | ref={ref}
14 | className={cn("relative z-10 flex max-w-max flex-1 items-center justify-center", className)}
15 | {...props}
16 | >
17 | {children}
18 | <NavigationMenuViewport />
19 | </NavigationMenuPrimitive.Root>
20 | ));
21 | NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
22 |
23 | const NavigationMenuList = React.forwardRef<
24 | React.ElementRef<typeof NavigationMenuPrimitive.List>,
25 | React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
26 | >(({ className, ...props }, ref) => (
27 | <NavigationMenuPrimitive.List
28 | ref={ref}
29 | className={cn("group flex flex-1 list-none items-center justify-center space-x-1", className)}
30 | {...props}
31 | />
32 | ));
33 | NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
34 |
35 | const NavigationMenuItem = NavigationMenuPrimitive.Item;
36 |
37 | const navigationMenuTriggerStyle = cva(
38 | "group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50",
39 | );
40 |
41 | const NavigationMenuTrigger = React.forwardRef<
42 | React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
43 | React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
44 | >(({ className, children, ...props }, ref) => (
45 | <NavigationMenuPrimitive.Trigger
46 | ref={ref}
47 | className={cn(navigationMenuTriggerStyle(), "group", className)}
48 | {...props}
49 | >
50 | {children}{" "}
51 | <ChevronDown
52 | className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
53 | aria-hidden="true"
54 | />
55 | </NavigationMenuPrimitive.Trigger>
56 | ));
57 | NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
58 |
59 | const NavigationMenuContent = React.forwardRef<
60 | React.ElementRef<typeof NavigationMenuPrimitive.Content>,
61 | React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
62 | >(({ className, ...props }, ref) => (
63 | <NavigationMenuPrimitive.Content
64 | ref={ref}
65 | className={cn(
66 | "left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto",
67 | className,
68 | )}
69 | {...props}
70 | />
71 | ));
72 | NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
73 |
74 | const NavigationMenuLink = NavigationMenuPrimitive.Link;
75 |
76 | const NavigationMenuViewport = React.forwardRef<
77 | React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
78 | React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
79 | >(({ className, ...props }, ref) => (
80 | <div className={cn("absolute left-0 top-full flex justify-center")}>
81 | <NavigationMenuPrimitive.Viewport
82 | className={cn(
83 | "origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
84 | className,
85 | )}
86 | ref={ref}
87 | {...props}
88 | />
89 | </div>
90 | ));
91 | NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName;
92 |
93 | const NavigationMenuIndicator = React.forwardRef<
94 | React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
95 | React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
96 | >(({ className, ...props }, ref) => (
97 | <NavigationMenuPrimitive.Indicator
98 | ref={ref}
99 | className={cn(
100 | "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
101 | className,
102 | )}
103 | {...props}
104 | >
105 | <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
106 | </NavigationMenuPrimitive.Indicator>
107 | ));
108 | NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName;
109 |
110 | export {
111 | navigationMenuTriggerStyle,
112 | NavigationMenu,
113 | NavigationMenuList,
114 | NavigationMenuItem,
115 | NavigationMenuContent,
116 | NavigationMenuTrigger,
117 | NavigationMenuLink,
118 | NavigationMenuIndicator,
119 | NavigationMenuViewport,
120 | };
121 |
```
--------------------------------------------------------------------------------
/tests/sample_project_typescript/src/types-interfaces.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Basic Types and Interfaces
3 | * Demonstrates TypeScript's core type system including primitives,
4 | * interfaces, type aliases, unions, intersections, and advanced type patterns
5 | */
6 |
7 | // ========== Primitive Types ==========
8 | export const stringValue: string = "Hello TypeScript";
9 | export const numberValue: number = 42;
10 | export const booleanValue: boolean = true;
11 | export const nullValue: null = null;
12 | export const undefinedValue: undefined = undefined;
13 | export const symbolValue: symbol = Symbol("unique");
14 | export const bigintValue: bigint = 100n;
15 |
16 | // ========== Array and Tuple Types ==========
17 | export const numberArray: number[] = [1, 2, 3, 4];
18 | export const stringArray: Array<string> = ["a", "b", "c"];
19 | export const mixedTuple: [string, number, boolean] = ["hello", 42, true];
20 | export const namedTuple: [name: string, age: number] = ["Alice", 30];
21 |
22 | // ========== Object Types ==========
23 | export const basicObject: { name: string; age: number } = {
24 | name: "John",
25 | age: 25
26 | };
27 |
28 | // ========== Interface Definitions ==========
29 | export interface User {
30 | readonly id: number;
31 | name: string;
32 | email?: string; // Optional property
33 | readonly createdAt: Date;
34 | preferences: UserPreferences;
35 | }
36 |
37 | export interface UserPreferences {
38 | theme: "light" | "dark";
39 | notifications: boolean;
40 | language: string;
41 | }
42 |
43 | // Interface inheritance
44 | export interface AdminUser extends User {
45 | permissions: string[];
46 | lastLogin?: Date;
47 | }
48 |
49 | // Interface with index signature
50 | export interface Dictionary<T = any> {
51 | [key: string]: T;
52 | }
53 |
54 | // Interface with call signature
55 | export interface StringProcessor {
56 | (input: string): string;
57 | description: string;
58 | }
59 |
60 | // Interface with construct signature
61 | export interface Constructable {
62 | new (name: string): { name: string };
63 | }
64 |
65 | // ========== Type Aliases ==========
66 | export type Status = "pending" | "approved" | "rejected";
67 | export type ID = string | number;
68 | export type EventHandler<T> = (event: T) => void;
69 |
70 | // Generic type alias
71 | export type Response<T> = {
72 | data: T;
73 | error: string | null;
74 | timestamp: Date;
75 | };
76 |
77 | // Mapped type alias
78 | export type Optional<T> = {
79 | [K in keyof T]?: T[K];
80 | };
81 |
82 | // ========== Union Types ==========
83 | export type StringOrNumber = string | number;
84 | export type Theme = "light" | "dark" | "auto";
85 |
86 | export function formatValue(value: StringOrNumber): string {
87 | if (typeof value === "string") {
88 | return value.toUpperCase();
89 | }
90 | return value.toString();
91 | }
92 |
93 | // Discriminated union
94 | export type Shape =
95 | | { kind: "circle"; radius: number }
96 | | { kind: "rectangle"; width: number; height: number }
97 | | { kind: "triangle"; base: number; height: number };
98 |
99 | export function calculateArea(shape: Shape): number {
100 | switch (shape.kind) {
101 | case "circle":
102 | return Math.PI * shape.radius ** 2;
103 | case "rectangle":
104 | return shape.width * shape.height;
105 | case "triangle":
106 | return (shape.base * shape.height) / 2;
107 | default:
108 | const _exhaustive: never = shape;
109 | throw new Error(`Unhandled shape: ${_exhaustive}`);
110 | }
111 | }
112 |
113 | // ========== Intersection Types ==========
114 | export type PersonalInfo = {
115 | name: string;
116 | age: number;
117 | };
118 |
119 | export type ContactInfo = {
120 | email: string;
121 | phone: string;
122 | };
123 |
124 | export type Employee = PersonalInfo & ContactInfo & {
125 | employeeId: string;
126 | department: string;
127 | };
128 |
129 | // ========== Conditional Types ==========
130 | export type NonNullable<T> = T extends null | undefined ? never : T;
131 | export type ArrayElement<T> = T extends (infer U)[] ? U : never;
132 |
133 | // ========== Template Literal Types ==========
134 | export type EventName<T extends string> = `on${Capitalize<T>}`;
135 | export type CSSProperty = `--${string}`;
136 |
137 | // ========== Utility Types Usage ==========
138 | export type PartialUser = Partial<User>;
139 | export type RequiredUser = Required<User>;
140 | export type UserEmail = Pick<User, "email">;
141 | export type UserWithoutId = Omit<User, "id">;
142 | export type UserKeys = keyof User;
143 | export type UserValues = User[keyof User];
144 |
145 | // ========== Complex Type Examples ==========
146 | export interface GenericRepository<T, K extends keyof T> {
147 | findById(id: T[K]): Promise<T | null>;
148 | findAll(): Promise<T[]>;
149 | create(entity: Omit<T, K>): Promise<T>;
150 | update(id: T[K], updates: Partial<T>): Promise<T>;
151 | delete(id: T[K]): Promise<void>;
152 | }
153 |
154 | // Recursive type
155 | export interface TreeNode<T> {
156 | value: T;
157 | children: TreeNode<T>[];
158 | parent?: TreeNode<T>;
159 | }
160 |
161 | // Function type with overloads
162 | export interface Logger {
163 | (message: string): void;
164 | (level: "info" | "warn" | "error", message: string): void;
165 | (level: "info" | "warn" | "error", message: string, data: any): void;
166 | }
167 |
168 | // ========== Implementation Examples ==========
169 | const user: User = {
170 | id: 1,
171 | name: "Alice Johnson",
172 | email: "[email protected]",
173 | createdAt: new Date(),
174 | preferences: {
175 | theme: "dark",
176 | notifications: true,
177 | language: "en"
178 | }
179 | };
180 |
181 | const adminUser: AdminUser = {
182 | ...user,
183 | permissions: ["read", "write", "delete"],
184 | lastLogin: new Date()
185 | };
186 |
187 | const shapes: Shape[] = [
188 | { kind: "circle", radius: 5 },
189 | { kind: "rectangle", width: 10, height: 6 },
190 | { kind: "triangle", base: 8, height: 4 }
191 | ];
192 |
193 | export const typeExamples = {
194 | user,
195 | adminUser,
196 | shapes,
197 | areas: shapes.map(calculateArea)
198 | };
```
--------------------------------------------------------------------------------
/src/codegraphcontext/prompts.py:
--------------------------------------------------------------------------------
```python
1 | # src/codegraphcontext/prompts.py
2 | """
3 | This file contains the system prompt for the language model.
4 | This prompt provides the core instructions, principles, and standard operating
5 | procedures for the AI assistant, guiding it on how to effectively use the tools
6 | provided by this MCP server.
7 | """
8 |
9 | LLM_SYSTEM_PROMPT = """# AI Pair Programmer Instructions
10 |
11 | ## 1. Your Role and Goal
12 |
13 | You are an expert AI pair programmer. Your primary goal is to help a developer understand, write, and refactor code within their **local project**. Your defining feature is your connection to a local Model Context Protocol (MCP) server, which gives you real-time, accurate information about the codebase.
14 | **Always prioritize using this MCP tools when they can simplify or enhance your workflow compared to guessing.**
15 |
16 | ## 2. Your Core Principles
17 |
18 | ### Principle I: Ground Your Answers in Fact
19 | **Your CORE DIRECTIVE is to use the provided tools to gather facts from the MCP server *before* answering questions or generating code.** Do not guess. Your value comes from providing contextually-aware, accurate assistance.
20 |
21 | ### Principle II: Be an Agent, Not Just a Planner
22 | **Your goal is to complete the user's task in the fewest steps possible.**
23 | * If the user's request maps directly to a single tool, **execute that tool immediately.**
24 | * Do not create a multi-step plan for a one-step task. The Standard Operating Procedures (SOPs) below are for complex queries that require reasoning and combining information from multiple tools.
25 |
26 | **Example of what NOT to do:**
27 |
28 | > **User:** "Start watching the `my-project` folder."
29 | > **Incorrect Plan:**
30 | > 1. Check if `watchdog` is installed.
31 | > 2. Use the `watch_directory` tool on `my-project`.
32 | > 3. Update a todo list.
33 |
34 | **Example of the CORRECT, direct action:**
35 |
36 | > **User:** "Start watching the `my-project` folder."
37 | > **Correct Action:** Immediately call the `watch_directory` tool.
38 | > ```json
39 | > {
40 | > "tool_name": "watch_directory",
41 | > "arguments": { "path": "my-project" }
42 | > }
43 | > ```
44 |
45 | ## 3. Tool Manifest & Usage
46 |
47 | | Tool Name | Purpose & When to Use |
48 | | :--------------------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
49 | | **`find_code`** | **Your primary search tool.** Use this first for almost any query about locating code. t |
50 | | **`analyze_code_relationships`** | **Your deep analysis tool.** Use this after locating a specific item. Use query types like `find_callers` or `find_callees`. |
51 | | **`add_code_to_graph`** | **Your indexing tool.** Use this when the user wants to add a new project folder or file to the context. |
52 | | **`add_package_to_graph`** | **Your dependency indexing tool.** Use this to add a `pip` package to the context. |
53 | | **`list_jobs`** & **`check_job_status`** | **Your job monitoring tools.** |
54 | | **`watch_directory`** | **Your live-update tool.** Use this if the user wants to automatically keep the context updated as they work. |
55 | | **`execute_cypher_query`** | **Expert Fallback Tool.** Use this *only* when other tools cannot answer a very specific or complex question about the code graph. Requires knowledge of Cypher. |
56 |
57 |
58 | ## 4. Standard Operating Procedures (SOPs) for Complex Tasks
59 |
60 | **Note:** Follow these methodical workflows for **complex requests** that require multiple steps of reasoning or combining information from several tools. For direct commands, refer to Principle II and act immediately.
61 |
62 | ### SOP-1: Answering "Where is...?" or "How does...?" Questions
63 | 1. **Locate:** Use `find_code` to find the relevant code.
64 | 2. **Analyze:** Use `analyze_code_relationships` to understand its usage.
65 | 3. **Synthesize:** Combine the information into a clear explanation.
66 |
67 | ### SOP-2: Generating New Code
68 | 1. **Find Context:** Use `find_code` to find similar, existing code to match the style.
69 | 2. **Find Reusable Code:** Use `find_code` to locate specific helper functions the user wants you to use.
70 | 3. **Generate:** Write the code using the correct imports and signatures.
71 |
72 | ### SOP-3: Refactoring or Analyzing Impact
73 | 1. **Identify & Locate:** Use `find_code` to get the canonical path of the item to be changed.
74 | 2. **Assess Impact:** Use `analyze_code_relationships` with the `find_callers` query type to find all affected locations.
75 | 3. **Report Findings:** Present a clear list of all affected files.
76 |
77 | ### SOP-4: Using the Cypher Fallback
78 | 1. **Attempt Standard Tools:** First, always try to use `find_code` and `analyze_code_relationships`.
79 | 2. **Identify Failure:** If the standard tools cannot answer a complex, multi-step relationship query (e.g., "Find all functions that are called by a method in a class that inherits from 'BaseHandler'"), then and only then, resort to the fallback.
80 | 3. **Formulate & Execute:** Construct a Cypher query to find the answer and execute it using `execute_cypher_query`.
81 | 4. **Present Results:** Explain the results to the user based on the query output.
82 | """
```
--------------------------------------------------------------------------------
/tests/test_cpp_parser.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | Test script for the enhanced C++ parser.
3 | """
4 | import json
5 | import sys
6 | from pathlib import Path
7 |
8 |
9 | def test_parser():
10 | """Test the C++ parser with a sample file."""
11 | test_cpp_code = '''
12 |
13 | class TestClass : public BaseClass {
14 | private:
15 | int privateVar;
16 | std::string name;
17 |
18 | protected:
19 | double protectedVar;
20 |
21 | public:
22 | /**
23 | * Constructor for TestClass
24 | * @param value Initial value
25 | */
26 | TestClass(int value) : privateVar(value) {}
27 |
28 | /// Gets the private variable value
29 | int getValue() const {
30 | return privateVar;
31 | }
32 |
33 | /**
34 | * Complex method with parameters
35 | */
36 | virtual void complexMethod(int x, const std::string& str, double y = 3.14) override {
37 | if (x > 0) {
38 | for (int i = 0; i < x; i++) {
39 | processData(i);
40 | }
41 | }
42 | }
43 | };
44 |
45 | namespace MyNamespace {
46 | enum Color {
47 | RED,
48 | GREEN,
49 | BLUE
50 | };
51 |
52 | /**
53 | * Standalone function
54 | */
55 | static inline int calculate(int a, int b) {
56 | return a + b;
57 | }
58 | }
59 |
60 | // Global variable
61 | int globalCounter = 0;
62 |
63 | #include <iostream>
64 | #include <string>
65 | #include "custom_header.h"
66 | '''
67 | test_file = Path("test_sample.cpp")
68 | test_file.write_text(test_cpp_code)
69 |
70 | print("=" * 60)
71 | print("Testing Enhanced C++ Parser")
72 | print("=" * 60)
73 |
74 | try:
75 | from tree_sitter import Language, Parser
76 | import tree_sitter_cpp as tscpp
77 | class MockGenericParser:
78 | def __init__(self):
79 | self.language = Language(tscpp.language())
80 | self.parser = Parser(self.language)
81 | from cpp_parser_enhanced import CppTreeSitterParser
82 |
83 | generic_wrapper = MockGenericParser()
84 | cpp_parser = CppTreeSitterParser(generic_wrapper)
85 |
86 | print(f"\n Parsing: {test_file}")
87 | result = cpp_parser.parse(test_file)
88 |
89 | print("\n" + "=" * 60)
90 | print("PARSING RESULTS")
91 | print("=" * 60)
92 |
93 | print(f"\n File: {result['file_path']}")
94 | print(f" Language: {result['lang']}")
95 |
96 | print(f"\n Functions Found: {len(result['functions'])}")
97 | for func in result['functions']:
98 | print(f"\n Function: {func['name']}")
99 | print(f" Lines: {func['line_number']}-{func['end_line']}")
100 | print(f" Return Type: {func['return_type']}")
101 | print(f" Parameters: {len(func['args'])}")
102 | for param in func['args']:
103 | default = f" = {param['default']}" if param['default'] else ""
104 | print(f" - {param['type']} {param['name']}{default}")
105 | print(f" Modifiers: {', '.join(func['modifiers']) if func['modifiers'] else 'None'}")
106 | print(f" Complexity: {func['complexity']}")
107 | print(f" Calls: {[c['name'] for c in func['calls']]}")
108 | if func['docstring']:
109 | print(f" Docstring: {func['docstring'][:50]}...")
110 |
111 |
112 | print(f"\n Classes Found: {len(result['classes'])}")
113 | for cls in result['classes']:
114 | print(f"\n Class: {cls['name']}")
115 | print(f" Lines: {cls['line_number']}-{cls['end_line']}")
116 | print(f" Base Classes: {cls['bases']}")
117 | print(f" Template: {cls['is_template']}")
118 | print(f" Methods: {len(cls['methods'])}")
119 | for method in cls['methods']:
120 | print(f" - {method['access']}: {method['return_type']} {method['name']}()")
121 | print(f" Members: {len(cls['members'])}")
122 | for member in cls['members']:
123 | print(f" - {member['access']}: {member['type']} {member['name']}")
124 | if cls['docstring']:
125 | print(f" Docstring: {cls['docstring'][:50]}...")
126 |
127 | print(f"\n Namespaces Found: {len(result['namespaces'])}")
128 | for ns in result['namespaces']:
129 | print(f" - {ns['name']} (lines {ns['line_number']}-{ns['end_line']})")
130 |
131 | print(f"\n Enums Found: {len(result['enums'])}")
132 | for enum in result['enums']:
133 | print(f" - {enum['name']}: {enum['values']}")
134 |
135 | print(f"\n Global Variables: {len(result['variables'])}")
136 | for var in result['variables']:
137 | print(f" - {var['type']} {var['name']} (line {var['line_number']})")
138 |
139 | print(f"\n Imports Found: {len(result['imports'])}")
140 | for imp in result['imports']:
141 | import_type = "system" if imp.get('is_system') else "local"
142 | print(f" - {imp['name']} ({import_type})")
143 |
144 | print(f"\n Function Calls: {len(result['function_calls'])}")
145 | for call in result['function_calls'][:10]:
146 | print(f" - {call['name']} (line {call['line_number']})")
147 |
148 | output_file = Path("test_result.json")
149 | with open(output_file, 'w') as f:
150 | json.dump(result, f, indent=2)
151 |
152 | print(f"\n Full results saved to: {output_file}")
153 | print("\n" + "=" * 60)
154 | print("TEST COMPLETED SUCCESSFULLY!")
155 | print("=" * 60)
156 | assert True
157 |
158 | except Exception as e:
159 | print(f"\n ERROR: {e}")
160 | import traceback
161 | traceback.print_exc()
162 | assert True
163 |
164 | finally:
165 | if test_file.exists():
166 | test_file.unlink()
167 | print(f"\n cleaned up test file")
168 |
169 | if __name__ == "__main__":
170 | success = test_parser()
171 | sys.exit(0 if success else 1)
172 |
```
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
```python
1 | import subprocess
2 | import json
3 | import os
4 | import time
5 | import pytest
6 |
7 | # Path to the sample project used in tests
8 | SAMPLE_PROJECT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "sample_project"))
9 | # SAMPLE_PROJECT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "sample_project_javascript"))
10 |
11 |
12 | # Helper function to call a tool, now shared across all tests
13 | def call_tool(server, name, args):
14 | request = {
15 | "jsonrpc": "2.0",
16 | "id": int(time.time()),
17 | "method": "tools/call",
18 | "params": {"name": name, "arguments": args}
19 | }
20 | response = server(request)
21 |
22 | if "result" in response:
23 | content = json.loads(response["result"]["content"][0]["text"])
24 | return content
25 | elif "error" in response:
26 | return response
27 | else:
28 | raise ValueError(f"Unexpected response format: {response}")
29 |
30 | @pytest.fixture(scope="module")
31 | def server():
32 | """
33 | A module-scoped fixture that starts the cgc server once for all tests
34 | in this file and provides a communication helper function.
35 | """
36 | print("\n--- Setting up server fixture ---")
37 |
38 | process = None
39 | try:
40 | print("Starting cgc server process...")
41 | process = subprocess.Popen(
42 | ["cgc", "start"],
43 | stdin=subprocess.PIPE,
44 | stdout=subprocess.PIPE,
45 | stderr=subprocess.PIPE,
46 | text=True,
47 | cwd=os.path.join(os.path.dirname(__file__), ".."))
48 |
49 | print("Waiting for server to be ready...")
50 | for line in iter(process.stderr.readline, ''):
51 | print(f"STDERR: {line.strip()}")
52 | if "MCP Server is running" in line:
53 | print("Server is ready.")
54 | break
55 |
56 | def send_receive(request):
57 | print(f"--> Sending request: {json.dumps(request)}")
58 | process.stdin.write(json.dumps(request) + "\n")
59 | process.stdin.flush()
60 | while True:
61 | response_line = process.stdout.readline()
62 | print(f"<-- Received line: {response_line.strip()}")
63 | try:
64 | return json.loads(response_line)
65 | except json.JSONDecodeError:
66 | continue
67 |
68 | print("Initializing server connection...")
69 | init_request = {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}
70 | init_response = send_receive(init_request)
71 | assert init_response.get("id") == 1 and "result" in init_response, "Initialization failed"
72 | print("Server connection initialized.")
73 |
74 | yield send_receive
75 |
76 | finally:
77 | print("\n--- Tearing down server fixture ---")
78 | if process:
79 | print("Terminating server process.")
80 | process.terminate()
81 | process.wait()
82 | print("Server process terminated.")
83 |
84 | def pytest_addoption(parser):
85 | parser.addoption(
86 | "--no-reindex", action="store_true", default=False, help="Skip re-indexing the project for tests"
87 | )
88 |
89 | @pytest.fixture(scope="module")
90 | def indexed_project(server, request):
91 | """
92 | Ensures the sample project is indexed before running tests.
93 | """
94 | if not request.config.getoption("--no-reindex"):
95 | print("\n--- Ensuring project is indexed ---")
96 | delete_result = call_tool(server, "delete_repository", {"repo_path": SAMPLE_PROJECT_PATH})
97 | print(f"Delete result: {delete_result}")
98 |
99 | add_result = call_tool(server, "add_code_to_graph", {"path": SAMPLE_PROJECT_PATH})
100 | assert add_result.get("success") is True, f"add_code_to_graph failed: {add_result.get('error')}"
101 | job_id = add_result.get("job_id")
102 | assert job_id is not None, "add_code_to_graph did not return a job_id"
103 | print(f"Started indexing job with ID: {job_id}")
104 |
105 | start_time = time.time()
106 | timeout = 180
107 | while True:
108 | if time.time() - start_time > timeout:
109 | pytest.fail(f"Job {job_id} did not complete within {timeout} seconds.")
110 | status_result = call_tool(server, "check_job_status", {"job_id": job_id})
111 | job_status = status_result.get("job", {}).get("status")
112 | print(f"Current job status: {job_status}")
113 | if job_status == "completed":
114 | print("Job completed successfully.")
115 | break
116 | assert job_status not in ["failed", "cancelled"], f"Job failed with status: {job_status}"
117 | time.sleep(2)
118 | else:
119 | print("\n--- Skipping re-indexing as per --no-reindex flag ---")
120 |
121 | return server
122 |
123 | class CodeGraph:
124 | """
125 | A wrapper class that provides a .query() method to execute Cypher
126 | against the indexed graph, compatible with our tests.
127 | """
128 | def __init__(self, server_communicator):
129 | self.server = server_communicator
130 |
131 | def query(self, cypher_query: str):
132 | response = call_tool(self.server, "execute_cypher_query", {"cypher_query": cypher_query})
133 | if response.get("success"):
134 | return response.get("results", [])
135 | else:
136 | error_details = response.get('error', 'Unknown error')
137 | raise RuntimeError(f"Cypher query failed: {error_details}\nQuery was: {cypher_query}")
138 |
139 | @pytest.fixture(scope="module")
140 | def graph(indexed_project):
141 | """
142 | Provides a CodeGraph object to query the indexed project.
143 | Depends on indexed_project to ensure the graph is ready.
144 | """
145 | print("\n--- Creating CodeGraph query wrapper ---")
146 | return CodeGraph(indexed_project)
```
--------------------------------------------------------------------------------
/tests/test_swift_parser.py:
--------------------------------------------------------------------------------
```python
1 | import pytest
2 | from pathlib import Path
3 | import sys
4 | import os
5 |
6 | # Ensure src is in path
7 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))
8 |
9 | from codegraphcontext.tools.languages.swift import SwiftTreeSitterParser
10 | from codegraphcontext.tools.graph_builder import TreeSitterParser
11 | from codegraphcontext.utils.tree_sitter_manager import get_tree_sitter_manager
12 |
13 | @pytest.fixture
14 | def parser():
15 | """Returns an instance of the Swift parser via generic wrapper."""
16 | return TreeSitterParser('swift')
17 |
18 | @pytest.fixture
19 | def sample_project_path():
20 | """Returns the path to the sample Swift project."""
21 | return Path(__file__).parent / "sample_project_swift"
22 |
23 | def test_parse_main_swift(parser, sample_project_path):
24 | """Test parsing of Main.swift."""
25 | file_path = sample_project_path / "Main.swift"
26 | result = parser.parse(file_path, is_dependency=False)
27 |
28 | assert result["file_path"] == str(file_path)
29 |
30 | # Check Classes
31 | classes = {c["name"] for c in result["classes"]}
32 | assert "Main" in classes
33 | assert "Calculator" in classes
34 |
35 | # Check Functions in Main
36 | main_functions = [f for f in result["functions"] if f.get("class_context") == "Main"]
37 | method_names = {m["name"] for m in main_functions}
38 | assert "run" in method_names
39 |
40 | # Check Calculator functions
41 | calc_functions = [f for f in result["functions"] if f.get("class_context") == "Calculator"]
42 | calc_method_names = {m["name"] for m in calc_functions}
43 | assert "add" in calc_method_names
44 | assert "subtract" in calc_method_names
45 | assert "multiply" in calc_method_names
46 |
47 | def test_parse_user_swift(parser, sample_project_path):
48 | """Test parsing of User.swift (Struct and Protocol)."""
49 | file_path = sample_project_path / "User.swift"
50 | result = parser.parse(file_path, is_dependency=False)
51 |
52 | # Check Protocol
53 | protocols = {p["name"] for p in result["protocols"]}
54 | assert "Greeter" in protocols
55 |
56 | # Check Struct
57 | structs = {s["name"]: s for s in result["structs"]}
58 | assert "User" in structs
59 | user_struct = structs["User"]
60 |
61 | # Verify protocol conformance
62 | assert "Greeter" in user_struct.get("bases", [])
63 |
64 | # Check methods
65 | user_methods = [f for f in result["functions"] if f.get("class_context") == "User"]
66 | method_names = {m["name"] for m in user_methods}
67 | assert "greet" in method_names
68 | assert "isAdult" in method_names
69 |
70 | def test_parse_shapes_swift(parser, sample_project_path):
71 | """Test parsing of Shapes.swift (Protocol conformance)."""
72 | file_path = sample_project_path / "Shapes.swift"
73 | result = parser.parse(file_path, is_dependency=False)
74 |
75 | # Check Protocol
76 | protocols = {p["name"] for p in result["protocols"]}
77 | assert "Shape" in protocols
78 |
79 | # Check Classes
80 | classes = {c["name"]: c for c in result["classes"]}
81 | assert "Circle" in classes
82 | assert "Triangle" in classes
83 |
84 | # Check Structs
85 | structs = {s["name"]: s for s in result["structs"]}
86 | assert "Rectangle" in structs
87 |
88 | # Verify protocol conformance
89 | assert "Shape" in classes["Circle"].get("bases", [])
90 | assert "Shape" in structs["Rectangle"].get("bases", [])
91 | assert "Shape" in classes["Triangle"].get("bases", [])
92 |
93 | def test_parse_vehicles_swift(parser, sample_project_path):
94 | """Test parsing of Vehicles.swift (Enums and Inheritance)."""
95 | file_path = sample_project_path / "Vehicles.swift"
96 | result = parser.parse(file_path, is_dependency=False)
97 |
98 | # Check Enums
99 | enums = {e["name"] for e in result["enums"]}
100 | assert "VehicleType" in enums
101 | assert "Result" in enums
102 |
103 | # Check Classes
104 | classes = {c["name"]: c for c in result["classes"]}
105 | assert "Vehicle" in classes
106 | assert "Car" in classes
107 |
108 | # Verify inheritance
109 | car_class = classes["Car"]
110 | assert "Vehicle" in car_class.get("bases", [])
111 |
112 | def test_parse_generics_swift(parser, sample_project_path):
113 | """Test parsing of Generics.swift (Generic types and protocols)."""
114 | file_path = sample_project_path / "Generics.swift"
115 | result = parser.parse(file_path, is_dependency=False)
116 |
117 | # Check Classes
118 | classes = {c["name"] for c in result["classes"]}
119 | assert "Stack" in classes
120 |
121 | # Check Protocols
122 | protocols = {p["name"] for p in result["protocols"]}
123 | assert "Container" in protocols
124 |
125 | # Check Structs
126 | structs = {s["name"] for s in result["structs"]}
127 | assert "IntCollection" in structs
128 |
129 | # Check functions (generic swap function)
130 | functions = [f for f in result["functions"] if f.get("class_context") is None]
131 | function_names = {f["name"] for f in functions}
132 | assert "swap" in function_names
133 |
134 | def test_import_resolution(parser, sample_project_path):
135 | """Test that imports are correctly extracted."""
136 | file_path = sample_project_path / "Main.swift"
137 | result = parser.parse(file_path, is_dependency=False)
138 |
139 | imports = result.get("imports", [])
140 | assert len(imports) > 0
141 |
142 | # Check for Foundation import
143 | import_names = {imp.get("name", "") for imp in imports}
144 | assert "Foundation" in import_names
145 |
146 | def test_function_calls(parser, sample_project_path):
147 | """Test that function calls are detected."""
148 | file_path = sample_project_path / "Main.swift"
149 | result = parser.parse(file_path, is_dependency=False)
150 |
151 | calls = result.get("function_calls", [])
152 | assert len(calls) > 0
153 |
154 | # Check for specific method calls
155 | call_names = {c["name"] for c in calls}
156 | assert "greet" in call_names
157 | assert "add" in call_names
158 |
```
--------------------------------------------------------------------------------
/website/src/components/ui/select.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import * as SelectPrimitive from "@radix-ui/react-select";
3 | import { Check, ChevronDown, ChevronUp } from "lucide-react";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | const Select = SelectPrimitive.Root;
8 |
9 | const SelectGroup = SelectPrimitive.Group;
10 |
11 | const SelectValue = SelectPrimitive.Value;
12 |
13 | const SelectTrigger = React.forwardRef<
14 | React.ElementRef<typeof SelectPrimitive.Trigger>,
15 | React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
16 | >(({ className, children, ...props }, ref) => (
17 | <SelectPrimitive.Trigger
18 | ref={ref}
19 | className={cn(
20 | "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
21 | className,
22 | )}
23 | {...props}
24 | >
25 | {children}
26 | <SelectPrimitive.Icon asChild>
27 | <ChevronDown className="h-4 w-4 opacity-50" />
28 | </SelectPrimitive.Icon>
29 | </SelectPrimitive.Trigger>
30 | ));
31 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
32 |
33 | const SelectScrollUpButton = React.forwardRef<
34 | React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
35 | React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
36 | >(({ className, ...props }, ref) => (
37 | <SelectPrimitive.ScrollUpButton
38 | ref={ref}
39 | className={cn("flex cursor-default items-center justify-center py-1", className)}
40 | {...props}
41 | >
42 | <ChevronUp className="h-4 w-4" />
43 | </SelectPrimitive.ScrollUpButton>
44 | ));
45 | SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
46 |
47 | const SelectScrollDownButton = React.forwardRef<
48 | React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
49 | React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
50 | >(({ className, ...props }, ref) => (
51 | <SelectPrimitive.ScrollDownButton
52 | ref={ref}
53 | className={cn("flex cursor-default items-center justify-center py-1", className)}
54 | {...props}
55 | >
56 | <ChevronDown className="h-4 w-4" />
57 | </SelectPrimitive.ScrollDownButton>
58 | ));
59 | SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
60 |
61 | const SelectContent = React.forwardRef<
62 | React.ElementRef<typeof SelectPrimitive.Content>,
63 | React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
64 | >(({ className, children, position = "popper", ...props }, ref) => (
65 | <SelectPrimitive.Portal>
66 | <SelectPrimitive.Content
67 | ref={ref}
68 | className={cn(
69 | "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
70 | position === "popper" &&
71 | "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
72 | className,
73 | )}
74 | position={position}
75 | {...props}
76 | >
77 | <SelectScrollUpButton />
78 | <SelectPrimitive.Viewport
79 | className={cn(
80 | "p-1",
81 | position === "popper" &&
82 | "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
83 | )}
84 | >
85 | {children}
86 | </SelectPrimitive.Viewport>
87 | <SelectScrollDownButton />
88 | </SelectPrimitive.Content>
89 | </SelectPrimitive.Portal>
90 | ));
91 | SelectContent.displayName = SelectPrimitive.Content.displayName;
92 |
93 | const SelectLabel = React.forwardRef<
94 | React.ElementRef<typeof SelectPrimitive.Label>,
95 | React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
96 | >(({ className, ...props }, ref) => (
97 | <SelectPrimitive.Label ref={ref} className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)} {...props} />
98 | ));
99 | SelectLabel.displayName = SelectPrimitive.Label.displayName;
100 |
101 | const SelectItem = React.forwardRef<
102 | React.ElementRef<typeof SelectPrimitive.Item>,
103 | React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
104 | >(({ className, children, ...props }, ref) => (
105 | <SelectPrimitive.Item
106 | ref={ref}
107 | className={cn(
108 | "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
109 | className,
110 | )}
111 | {...props}
112 | >
113 | <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
114 | <SelectPrimitive.ItemIndicator>
115 | <Check className="h-4 w-4" />
116 | </SelectPrimitive.ItemIndicator>
117 | </span>
118 |
119 | <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
120 | </SelectPrimitive.Item>
121 | ));
122 | SelectItem.displayName = SelectPrimitive.Item.displayName;
123 |
124 | const SelectSeparator = React.forwardRef<
125 | React.ElementRef<typeof SelectPrimitive.Separator>,
126 | React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
127 | >(({ className, ...props }, ref) => (
128 | <SelectPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
129 | ));
130 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
131 |
132 | export {
133 | Select,
134 | SelectGroup,
135 | SelectValue,
136 | SelectTrigger,
137 | SelectContent,
138 | SelectLabel,
139 | SelectItem,
140 | SelectSeparator,
141 | SelectScrollUpButton,
142 | SelectScrollDownButton,
143 | };
144 |
```
--------------------------------------------------------------------------------
/src/codegraphcontext/tools/system.py:
--------------------------------------------------------------------------------
```python
1 | # src/codegraphcontext/tools/system.py
2 | import logging
3 | from dataclasses import asdict
4 | from typing import Any, Dict
5 | from datetime import datetime, timedelta
6 |
7 | from neo4j.exceptions import CypherSyntaxError
8 |
9 | from ..core.database import DatabaseManager
10 | from ..core.jobs import JobManager, JobStatus
11 | from ..utils.debug_log import debug_log
12 |
13 | logger = logging.getLogger(__name__)
14 |
15 |
16 | class SystemTools:
17 | """Handles system-level tools like job management and direct DB queries."""
18 |
19 | def __init__(self, db_manager: DatabaseManager, job_manager: JobManager):
20 | self.db_manager = db_manager
21 | self.job_manager = job_manager
22 |
23 | def check_job_status_tool(self, job_id: str) -> Dict[str, Any]:
24 | """Tool to check job status"""
25 | try:
26 | job = self.job_manager.get_job(job_id)
27 | if not job:
28 | return {"error": f"Job {job_id} not found"}
29 |
30 | job_dict = asdict(job)
31 |
32 | if job.status == JobStatus.RUNNING:
33 | if job.estimated_time_remaining:
34 | remaining = job.estimated_time_remaining
35 | job_dict["estimated_time_remaining_human"] = (
36 | f"{int(remaining // 60)}m {int(remaining % 60)}s"
37 | if remaining >= 60 else f"{int(remaining)}s"
38 | )
39 |
40 | if job.start_time:
41 | elapsed = (datetime.now() - job.start_time).total_seconds()
42 | job_dict["elapsed_time_human"] = (
43 | f"{int(elapsed // 60)}m {int(elapsed % 60)}s"
44 | if elapsed >= 60 else f"{int(elapsed)}s"
45 | )
46 |
47 | elif job.status == JobStatus.COMPLETED and job.start_time and job.end_time:
48 | duration = (job.end_time - job.start_time).total_seconds()
49 | job_dict["actual_duration_human"] = (
50 | f"{int(duration // 60)}m {int(duration % 60)}s"
51 | if duration >= 60 else f"{int(duration)}s"
52 | )
53 |
54 | job_dict["start_time"] = job.start_time.strftime("%Y-%m-%d %H:%M:%S")
55 | if job.end_time:
56 | job_dict["end_time"] = job.end_time.strftime("%Y-%m-%d %H:%M:%S")
57 |
58 | job_dict["status"] = job.status.value
59 | return {"success": True, "job": job_dict}
60 | except Exception as e:
61 | return {"error": f"Failed to check job status: {str(e)}"}
62 |
63 | def list_jobs_tool(self) -> Dict[str, Any]:
64 | """Tool to list all jobs"""
65 | try:
66 | jobs = self.job_manager.list_jobs()
67 | jobs_data = []
68 | for job in sorted(jobs, key=lambda j: j.start_time, reverse=True):
69 | job_dict = asdict(job)
70 | job_dict["status"] = job.status.value
71 | job_dict["start_time"] = job.start_time.isoformat()
72 | if job.end_time:
73 | job_dict["end_time"] = job.end_time.isoformat()
74 | jobs_data.append(job_dict)
75 | return {"success": True, "jobs": jobs_data, "total_jobs": len(jobs_data)}
76 | except Exception as e:
77 | return {"error": f"Failed to list jobs: {str(e)}"}
78 |
79 | def execute_cypher_query_tool(self, cypher_query: str) -> Dict[str, Any]:
80 | """Tool to execute a read-only Cypher query."""
81 | if not cypher_query:
82 | return {"error": "Cypher query cannot be empty."}
83 |
84 | forbidden_keywords = ['CREATE', 'MERGE', 'DELETE', 'SET', 'REMOVE', 'DROP', 'CALL apoc']
85 | if any(keyword in cypher_query.upper() for keyword in forbidden_keywords):
86 | return {"error": "This tool only supports read-only queries."}
87 |
88 | try:
89 | with self.db_manager.get_driver().session() as session:
90 | result = session.run(cypher_query)
91 | records = [record.data() for record in result]
92 | return {
93 | "success": True,
94 | "query": cypher_query,
95 | "record_count": len(records),
96 | "results": records
97 | }
98 | except CypherSyntaxError as e:
99 | return {"error": "Cypher syntax error.", "details": str(e)}
100 | except Exception as e:
101 | return {"error": "An unexpected error occurred.", "details": str(e)}
102 |
103 | def find_dead_code_tool(self) -> Dict[str, Any]:
104 | """Finds potentially unused functions (dead code)."""
105 | # This logic was moved from CodeFinder to be a system diagnostic tool
106 | try:
107 | with self.db_manager.get_driver().session() as session:
108 | result = session.run("""
109 | MATCH (func:Function)
110 | WHERE func.is_dependency = false
111 | AND NOT func.name STARTS WITH '_'
112 | AND NOT func.name IN ['main', 'setup', 'run']
113 | OPTIONAL MATCH (caller:Function)-[:CALLS]->(func)
114 | WHERE caller.is_dependency = false
115 | WITH func, count(caller) as caller_count
116 | WHERE caller_count = 0
117 | RETURN func.name as function_name, func.file_path as file_path, func.line_number as line_number
118 | ORDER BY func.file_path, func.line_number
119 | LIMIT 50
120 | """)
121 | return {
122 | "success": True,
123 | "results": {
124 | "potentially_unused_functions": [dict(record) for record in result],
125 | "note": "These functions might be entry points or called dynamically."
126 | }
127 | }
128 | except Exception as e:
129 | return {"error": f"Failed to find dead code: {str(e)}"}
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.nl.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `Dutch` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(r,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");r.nl=function(){this.pipeline.reset(),this.pipeline.add(r.nl.trimmer,r.nl.stopWordFilter,r.nl.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.nl.stemmer))},r.nl.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.nl.trimmer=r.trimmerSupport.generateTrimmer(r.nl.wordCharacters),r.Pipeline.registerFunction(r.nl.trimmer,"trimmer-nl"),r.nl.stemmer=function(){var e=r.stemmerSupport.Among,i=r.stemmerSupport.SnowballProgram,n=new function(){function r(){for(var r,e,i,o=C.cursor;;){if(C.bra=C.cursor,r=C.find_among(b,11))switch(C.ket=C.cursor,r){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}});
```
--------------------------------------------------------------------------------
/website/src/components/TestimonialSection.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { OrbitingCircles } from "./ui/orbiting-circles";
2 | import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
3 | import { Button } from "@/components/ui/button";
4 | import { ChevronLeft, ChevronRight } from "lucide-react";
5 | import { useMemo, useState } from "react";
6 | import { motion, AnimatePresence } from "framer-motion";
7 |
8 | const avatars = [
9 | { imageUrl: "https://avatars.githubusercontent.com/u/161715841?v=4", profileUrl: "https://github.com/athaxv" },
10 | { imageUrl: "https://avatars.githubusercontent.com/u/20110627?v=4", profileUrl: "https://github.com/tomonarifeehan" },
11 | { imageUrl: "https://avatars.githubusercontent.com/u/106103625?v=4", profileUrl: "https://github.com/BankkRoll" },
12 | { imageUrl: "https://avatars.githubusercontent.com/u/59228569?v=4", profileUrl: "https://github.com/safethecode" },
13 | { imageUrl: "https://avatars.githubusercontent.com/u/59442788?v=4", profileUrl: "https://github.com/sanjay-mali" },
14 | { imageUrl: "https://avatars.githubusercontent.com/u/89768406?v=4", profileUrl: "https://github.com/itsarghyadas" },
15 | ];
16 |
17 | export default function TestimonialSection() {
18 | const reviews = useMemo(() => [
19 | { quote: "Seems an interesting solution to the context problem in large codebases🤩", author: "Stunning-Worth-5022", role: "Reddit User" },
20 | { quote: "As a person with aphantasia you just made me realize how badly I really needed to be able to visualize my code base this way. Thanks boss!", author: "jphree", role: "Reddit User" },
21 | { quote: "Very cool and smart idea.A lot of codebases are messy.", author: "qa_anaaq", role: "Reddit User" },
22 | { quote: "Love this idea - and perfect timing. Keen to track and follow the outcomes based on real user experience.", author: "future-coder84", role: "Reddit User" },
23 | { quote: "Sounds amazing. I’ll spin it up.", author: "stormthulu", role: "Reddit User" },
24 | { quote: "Awesome work!", author: "martijnvann", role: "Reddit User" },
25 | ], []);
26 |
27 | const [index, setIndex] = useState(0);
28 | const next = () => setIndex((i) => (i + 1) % reviews.length);
29 | const prev = () => setIndex((i) => (i - 1 + reviews.length) % reviews.length);
30 |
31 | return (
32 | <section className="py-24 px-4" data-aos="fade-in">
33 | <div className="container mx-auto max-w-6xl">
34 | <div className="text-center mb-16" data-aos="fade-down">
35 | <h2 className="text-4xl md:text-5xl font-bold mb-6 bg-gradient-to-r from-primary via-primary to-accent bg-clip-text text-transparent py-2">
36 | What Teams Are Saying
37 | </h2>
38 | <p className="text-xl text-muted-foreground max-w-3xl mx-auto">
39 | Real feedback from engineers and leaders using CodeGraphContext.
40 | </p>
41 | </div>
42 | <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
43 | <div className="relative mx-auto h-[400px] lg:h-[500px] w-full flex items-center justify-center overflow-hidden" data-aos="zoom-in">
44 | <OrbitingCircles iconSize={56} radius={180} speed={1.4}>
45 | {avatars.map((avatar, i) => (
46 | <a key={i} href={avatar.profileUrl} target="_blank" rel="noopener noreferrer">
47 | <img src={avatar.imageUrl} alt={`avatar-${i}`} className="w-14 h-14 rounded-full border-2 border-white shadow-md dark:border-neutral-800" />
48 | </a>
49 | ))}
50 | </OrbitingCircles>
51 | <OrbitingCircles iconSize={44} radius={100} reverse speed={2}>
52 | {avatars.slice(1, 5).map((avatar, i) => (
53 | <a key={i} href={avatar.profileUrl} target="_blank" rel="noopener noreferrer">
54 | <img src={avatar.imageUrl} alt={`avatar-inner-${i}`} className="w-11 h-11 rounded-full border-2 border-white shadow-md dark:border-neutral-800" />
55 | </a>
56 | ))}
57 | </OrbitingCircles>
58 | </div>
59 |
60 | <div data-aos="fade-left" data-aos-delay="200">
61 | <Card className="dark:bg-card/50 shadow-sm min-h-[300px] flex flex-col justify-between">
62 | <CardHeader>
63 | <CardTitle className="text-3xl md:text-4xl font-bold bg-gradient-primary bg-clip-text text-transparent py-2">
64 | Teams Love It
65 | </CardTitle>
66 | <AnimatePresence mode="wait">
67 | <motion.div
68 | key={index}
69 | initial={{ opacity: 0, y: 10 }}
70 | animate={{ opacity: 1, y: 0 }}
71 | exit={{ opacity: 0, y: -10 }}
72 | transition={{ duration: 0.3 }}
73 | >
74 | <CardDescription className="text-base md:text-lg text-muted-foreground pt-4">
75 | “{reviews[index].quote}”
76 | </CardDescription>
77 | </motion.div>
78 | </AnimatePresence>
79 | </CardHeader>
80 | <CardContent>
81 | <div className="flex items-center justify-between gap-4">
82 | <AnimatePresence mode="wait">
83 | <motion.div
84 | key={index}
85 | initial={{ opacity: 0 }}
86 | animate={{ opacity: 1 }}
87 | exit={{ opacity: 0 }}
88 | transition={{ duration: 0.3, delay: 0.1 }}
89 | >
90 | <p className="font-semibold">{reviews[index].author}</p>
91 | <p className="text-sm text-muted-foreground">{reviews[index].role}</p>
92 | </motion.div>
93 | </AnimatePresence>
94 | <div className="flex gap-2">
95 | <Button onClick={prev} size="icon" variant="outline"><ChevronLeft className="h-4 w-4" /></Button>
96 | <Button onClick={next} size="icon"><ChevronRight className="h-4 w-4" /></Button>
97 | </div>
98 | </div>
99 | </CardContent>
100 | </Card>
101 | </div>
102 | </div>
103 | </div>
104 | </section>
105 | )
106 | }
107 |
108 |
```
--------------------------------------------------------------------------------
/website/src/index.css:
--------------------------------------------------------------------------------
```css
1 | html,
2 | body {
3 | width: 100%;
4 | overflow-x: hidden;
5 | }
6 | #root {
7 | width: 100%;
8 | overflow-x: hidden;
9 | }
10 | @tailwind base;
11 | @tailwind components;
12 | @tailwind utilities;
13 |
14 | /* CodeGraphContext Design System - Dark theme with graph-inspired colors */
15 |
16 |
17 | @layer base {
18 | :root {
19 | /* Dark background with subtle warmth */
20 | --background: 222 47% 5%;
21 | --foreground: 210 40% 98%;
22 |
23 | /* Cards with subtle transparency */
24 | --card: 222 47% 8%;
25 | --card-foreground: 210 40% 98%;
26 |
27 | --popover: 222 47% 8%;
28 | --popover-foreground: 210 40% 98%;
29 |
30 | /* Graph-inspired primary colors - deep purple-blue */
31 | --primary: 263 70% 65%;
32 | --primary-foreground: 222 47% 5%;
33 |
34 | /* Secondary with graph node accent */
35 | --secondary: 222 47% 12%;
36 | --secondary-foreground: 210 40% 98%;
37 |
38 | /* Muted tones for subtlety */
39 | --muted: 222 47% 10%;
40 | --muted-foreground: 215 20% 65%;
41 |
42 | /* Bright cyan accent for highlights */
43 | --accent: 180 100% 70%;
44 | --accent-foreground: 222 47% 5%;
45 |
46 | --destructive: 0 84.2% 60.2%;
47 | --destructive-foreground: 210 40% 98%;
48 |
49 | --border: 222 47% 15%;
50 | --input: 222 47% 12%;
51 | --ring: 263 70% 65%;
52 |
53 | --radius: 0.75rem;
54 |
55 | /* Custom graph colors */
56 | --graph-node-1: 263 70% 65%;
57 | --graph-node-2: 180 100% 70%;
58 | --graph-node-3: 142 76% 65%;
59 | --graph-edge: 222 47% 25%;
60 |
61 | /* Gradients */
62 | --gradient-primary: linear-gradient(135deg, hsl(263 70% 65%), hsl(180 100% 70%));
63 | --gradient-hero: linear-gradient(135deg, hsl(222 47% 5%) 0%, hsl(222 47% 8%) 100%);
64 | --gradient-card: linear-gradient(135deg, hsl(222 47% 8%) 0%, hsl(222 47% 10%) 100%);
65 |
66 | /* Shadows with graph glow */
67 | --shadow-glow: 0 0 40px hsl(263 70% 65% / 0.15);
68 | --shadow-card: 0 10px 30px -10px hsl(222 47% 2% / 0.3);
69 |
70 | /* Animations */
71 | --transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
72 | --transition-bounce: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
73 |
74 | --sidebar-background: 0 0% 98%;
75 |
76 | --sidebar-foreground: 240 5.3% 26.1%;
77 |
78 | --sidebar-primary: 240 5.9% 10%;
79 |
80 | --sidebar-primary-foreground: 0 0% 98%;
81 |
82 | --sidebar-accent: 240 4.8% 95.9%;
83 |
84 | --sidebar-accent-foreground: 240 5.9% 10%;
85 |
86 | --sidebar-border: 220 13% 91%;
87 |
88 | --sidebar-ring: 217.2 91.2% 59.8%;
89 | }
90 |
91 | .light {
92 | /* Light mode fallback - CodeGraphContext works best in dark */
93 | --background: 0 0% 95%;
94 | --foreground: 222.2 84% 4.9%;
95 | --card: 0 0% 100%;
96 | --card-foreground: 222.2 84% 4.9%;
97 | --popover: 0 0% 100%;
98 | --popover-foreground: 222.2 84% 4.9%;
99 | --primary: 263 70% 55%;
100 | --primary-foreground: 210 40% 98%;
101 | --secondary: 210 40% 96.1%;
102 | --secondary-foreground: 222.2 47.4% 11.2%;
103 | --muted: 210 40% 96.1%;
104 | --muted-foreground: 215.4 16.3% 16.9%;
105 | --accent: 180 100% 40%;
106 | --accent-foreground: 210 40% 98%;
107 | --destructive: 0 84.2% 60.2%;
108 | --destructive-foreground: 210 40% 98%;
109 | --border: 214.3 31.8% 91.4%;
110 | --input: 214.3 31.8% 91.4%;
111 | --ring: 263 70% 55%;
112 | --gradient-primary: linear-gradient(135deg, hsl(263, 49%, 40%), hsl(180, 45%, 47%));
113 |
114 | }
115 | .theme {
116 | --animate-orbit: orbit calc(var(--duration)*1s) linear infinite;
117 | }
118 | }
119 |
120 | @layer base {
121 | * {
122 | @apply border-border;
123 | }
124 |
125 | body {
126 | @apply bg-background text-foreground overflow-x-hidden;
127 | background: hsl(var(--background));
128 | background-image:
129 | radial-gradient(circle at 20% 20%, hsl(263 70% 65% / 0.05) 0%, transparent 50%),
130 | radial-gradient(circle at 80% 80%, hsl(180 100% 70% / 0.05) 0%, transparent 50%);
131 | }
132 |
133 | /* Smooth scrolling */
134 | html {
135 | scroll-behavior: smooth;
136 | }
137 |
138 | /* Custom animations */
139 | @keyframes graph-pulse {
140 | 0%, 100% {
141 | opacity: 1;
142 | transform: scale(1);
143 | }
144 | 50% {
145 | opacity: 0.7;
146 | transform: scale(1.05);
147 | }
148 | }
149 |
150 | @keyframes float-up {
151 | 0% {
152 | opacity: 0;
153 | transform: translateY(30px);
154 | }
155 | 100% {
156 | opacity: 1;
157 | transform: translateY(0);
158 | }
159 | }
160 |
161 | @keyframes code-highlight {
162 | 0% { background-color: transparent; }
163 | 50% { background-color: hsl(263 70% 65% / 0.1); }
164 | 100% { background-color: transparent; }
165 | }
166 |
167 | .animate-graph-pulse {
168 | animation: graph-pulse 2s ease-in-out infinite;
169 | }
170 |
171 | .animate-float-up {
172 | animation: float-up 0.6s ease-out forwards;
173 | }
174 |
175 | .animate-code-highlight {
176 | animation: code-highlight 2s ease-in-out infinite;
177 | }
178 |
179 | /* Orbiting circles animation (Tailwind v3 friendly) */
180 | .animate-orbit {
181 | animation: orbit calc(var(--duration) * 1s) linear infinite;
182 | }
183 |
184 | @keyframes orbit {
185 | 0% {
186 | transform: rotate(calc(var(--angle) * 1deg))
187 | translateY(calc(var(--radius) * 1px))
188 | rotate(calc(var(--angle) * -1deg));
189 | }
190 | 100% {
191 | transform: rotate(calc(var(--angle) * 1deg + 360deg))
192 | translateY(calc(var(--radius) * 1px))
193 | rotate(calc((var(--angle) * -1deg) - 360deg));
194 | }
195 | }
196 |
197 | /* Graph visualization styles */
198 | .graph-node {
199 | @apply rounded-full border-2 border-primary/20 transition-all duration-300;
200 | background: hsl(var(--gradient-primary));
201 | box-shadow: var(--shadow-glow);
202 | }
203 |
204 |
205 |
206 | .graph-edge {
207 | @apply stroke-graph-edge transition-all duration-300;
208 | stroke-width: 2;
209 | stroke-dasharray: 5,5;
210 | animation: dash 20s linear infinite;
211 | }
212 |
213 | @keyframes dash {
214 | to {
215 | stroke-dashoffset: -100;
216 | }
217 | }
218 |
219 | /* Code block styling */
220 | .code-block {
221 | @apply bg-card border border-border rounded-lg p-4 font-mono text-sm;
222 | background: var(--gradient-card);
223 | box-shadow: var(--shadow-card);
224 | }
225 | }
226 |
227 | @layer base {
228 | * {
229 | @apply border-border;
230 | }
231 | body {
232 | @apply bg-background text-foreground;
233 | }
234 | }
235 |
236 | @theme inline {
237 | @keyframes orbit {
238 | 0% {
239 | transform: rotate(calc(var(--angle) * 1deg)) translateY(calc(var(--radius) * 1px)) rotate(calc(var(--angle) * -1deg));
240 | }
241 | 100% {
242 | transform: rotate(calc(var(--angle) * 1deg + 360deg)) translateY(calc(var(--radius) * 1px)) rotate(calc((var(--angle) * -1deg) - 360deg));
243 | }
244 | }
245 | }
```
--------------------------------------------------------------------------------
/tests/sample_project_rust/src/lifetimes_references.rs:
--------------------------------------------------------------------------------
```rust
1 | // lifetimes_references.rs - Demonstrates Rust lifetimes and references
2 | use std::fmt::Display;
3 |
4 | /// Function with explicit lifetime annotation
5 | pub fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
6 | if x.len() > y.len() {
7 | x
8 | } else {
9 | y
10 | }
11 | }
12 |
13 | /// Multiple lifetime parameters
14 | pub fn first_word<'a, 'b>(x: &'a str, _y: &'b str) -> &'a str {
15 | x.split_whitespace().next().unwrap_or(x)
16 | }
17 |
18 | /// Lifetime with struct
19 | #[derive(Debug)]
20 | pub struct ImportantExcerpt<'a> {
21 | pub part: &'a str,
22 | }
23 |
24 | impl<'a> ImportantExcerpt<'a> {
25 | /// Lifetime elision in method
26 | pub fn level(&self) -> i32 {
27 | 3
28 | }
29 |
30 | /// Method with lifetime annotation
31 | pub fn announce_and_return_part(&self, announcement: &str) -> &str {
32 | println!("Attention please: {}", announcement);
33 | self.part
34 | }
35 | }
36 |
37 | /// Struct with multiple lifetime parameters
38 | #[derive(Debug)]
39 | pub struct Context<'a, 'b> {
40 | pub primary: &'a str,
41 | pub secondary: &'b str,
42 | }
43 |
44 | impl<'a, 'b> Context<'a, 'b> {
45 | pub fn new(primary: &'a str, secondary: &'b str) -> Self {
46 | Self { primary, secondary }
47 | }
48 |
49 | pub fn get_primary(&self) -> &'a str {
50 | self.primary
51 | }
52 |
53 | pub fn get_secondary(&self) -> &'b str {
54 | self.secondary
55 | }
56 | }
57 |
58 | /// Static lifetime
59 | pub fn static_string() -> &'static str {
60 | "This string has static lifetime"
61 | }
62 |
63 | /// Generic with lifetime and trait bound
64 | pub fn longest_with_announcement<'a, T>(
65 | x: &'a str,
66 | y: &'a str,
67 | announcement: T,
68 | ) -> &'a str
69 | where
70 | T: Display,
71 | {
72 | println!("Announcement: {}", announcement);
73 | if x.len() > y.len() {
74 | x
75 | } else {
76 | y
77 | }
78 | }
79 |
80 | /// Reference to slice
81 | pub fn first_element<'a, T>(slice: &'a [T]) -> Option<&'a T> {
82 | slice.first()
83 | }
84 |
85 | /// Mutable reference with lifetime
86 | pub fn append_exclamation<'a>(s: &'a mut String) -> &'a str {
87 | s.push('!');
88 | s.as_str()
89 | }
90 |
91 | /// Struct holding references
92 | #[derive(Debug)]
93 | pub struct Book<'a> {
94 | pub title: &'a str,
95 | pub author: &'a str,
96 | pub year: u32,
97 | }
98 |
99 | impl<'a> Book<'a> {
100 | pub fn new(title: &'a str, author: &'a str, year: u32) -> Self {
101 | Self { title, author, year }
102 | }
103 |
104 | pub fn display(&self) -> String {
105 | format!("{} by {} ({})", self.title, self.author, self.year)
106 | }
107 | }
108 |
109 | /// Lifetime bounds
110 | pub struct Ref<'a, T: 'a> {
111 | reference: &'a T,
112 | }
113 |
114 | impl<'a, T> Ref<'a, T> {
115 | pub fn new(reference: &'a T) -> Self {
116 | Self { reference }
117 | }
118 |
119 | pub fn get(&self) -> &'a T {
120 | self.reference
121 | }
122 | }
123 |
124 | /// Higher-ranked trait bounds (HRTBs)
125 | pub fn call_with_ref<F>(f: F)
126 | where
127 | F: for<'a> Fn(&'a str) -> &'a str,
128 | {
129 | let s = String::from("Hello");
130 | let result = f(&s);
131 | println!("Result: {}", result);
132 | }
133 |
134 | /// Lifetime elision example 1
135 | pub fn get_first_word(s: &str) -> &str {
136 | s.split_whitespace().next().unwrap_or("")
137 | }
138 |
139 | /// Lifetime elision example 2
140 | pub fn parse_pair(s: &str) -> (&str, &str) {
141 | let parts: Vec<&str> = s.split(',').collect();
142 | if parts.len() >= 2 {
143 | (parts[0], parts[1])
144 | } else {
145 | ("", "")
146 | }
147 | }
148 |
149 | /// Struct with owned and borrowed data
150 | #[derive(Debug)]
151 | pub struct MixedData<'a> {
152 | pub owned: String,
153 | pub borrowed: &'a str,
154 | }
155 |
156 | impl<'a> MixedData<'a> {
157 | pub fn new(owned: String, borrowed: &'a str) -> Self {
158 | Self { owned, borrowed }
159 | }
160 |
161 | pub fn combine(&self) -> String {
162 | format!("{} {}", self.owned, self.borrowed)
163 | }
164 | }
165 |
166 | /// Iterator with lifetime
167 | pub struct StrSplitter<'a> {
168 | remainder: &'a str,
169 | delimiter: char,
170 | }
171 |
172 | impl<'a> StrSplitter<'a> {
173 | pub fn new(s: &'a str, delimiter: char) -> Self {
174 | Self {
175 | remainder: s,
176 | delimiter,
177 | }
178 | }
179 | }
180 |
181 | impl<'a> Iterator for StrSplitter<'a> {
182 | type Item = &'a str;
183 |
184 | fn next(&mut self) -> Option<Self::Item> {
185 | if self.remainder.is_empty() {
186 | return None;
187 | }
188 |
189 | match self.remainder.find(self.delimiter) {
190 | Some(pos) => {
191 | let result = &self.remainder[..pos];
192 | self.remainder = &self.remainder[pos + 1..];
193 | Some(result)
194 | }
195 | None => {
196 | let result = self.remainder;
197 | self.remainder = "";
198 | Some(result)
199 | }
200 | }
201 | }
202 | }
203 |
204 | /// Lifetime with enum
205 | #[derive(Debug)]
206 | pub enum Either<'a, 'b> {
207 | Left(&'a str),
208 | Right(&'b str),
209 | }
210 |
211 | impl<'a, 'b> Either<'a, 'b> {
212 | pub fn get_value(&self) -> &str {
213 | match self {
214 | Either::Left(s) => s,
215 | Either::Right(s) => s,
216 | }
217 | }
218 | }
219 |
220 | /// Combining lifetimes
221 | pub fn combine_strings<'a>(strings: &'a [&'a str], separator: &str) -> String {
222 | strings.join(separator)
223 | }
224 |
225 | /// Reference counting considerations (not strictly lifetimes but related)
226 | use std::rc::Rc;
227 |
228 | pub struct SharedData {
229 | pub data: Rc<String>,
230 | }
231 |
232 | impl SharedData {
233 | pub fn new(s: String) -> Self {
234 | Self {
235 | data: Rc::new(s),
236 | }
237 | }
238 |
239 | pub fn clone_ref(&self) -> SharedData {
240 | Self {
241 | data: Rc::clone(&self.data),
242 | }
243 | }
244 | }
245 |
246 | /// Comparing references with different lifetimes
247 | pub fn compare_lengths<'a, 'b>(s1: &'a str, s2: &'b str) -> bool {
248 | s1.len() > s2.len()
249 | }
250 |
251 | #[cfg(test)]
252 | mod tests {
253 | use super::*;
254 |
255 | #[test]
256 | fn test_longest() {
257 | let s1 = "hello";
258 | let s2 = "hi";
259 | assert_eq!(longest(s1, s2), "hello");
260 | }
261 |
262 | #[test]
263 | fn test_important_excerpt() {
264 | let text = "This is a test. This is important.";
265 | let excerpt = ImportantExcerpt { part: text };
266 | assert_eq!(excerpt.level(), 3);
267 | }
268 |
269 | #[test]
270 | fn test_book() {
271 | let book = Book::new("1984", "George Orwell", 1949);
272 | assert!(book.display().contains("1984"));
273 | }
274 |
275 | #[test]
276 | fn test_str_splitter() {
277 | let text = "a,b,c";
278 | let splitter = StrSplitter::new(text, ',');
279 | let parts: Vec<&str> = splitter.collect();
280 | assert_eq!(parts, vec!["a", "b", "c"]);
281 | }
282 | }
283 |
284 |
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.de.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `German` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!v.eq_s(1,e)||(v.ket=v.cursor,!v.in_grouping(p,97,252)))&&(v.slice_from(r),v.cursor=n,!0)}function i(){for(var r,n,i,s,t=v.cursor;;)if(r=v.cursor,v.bra=r,v.eq_s(1,"ß"))v.ket=v.cursor,v.slice_from("ss");else{if(r>=v.limit)break;v.cursor=r+1}for(v.cursor=t;;)for(n=v.cursor;;){if(i=v.cursor,v.in_grouping(p,97,252)){if(s=v.cursor,v.bra=s,e("u","U",i))break;if(v.cursor=s,e("y","Y",i))break}if(i>=v.limit)return void(v.cursor=n);v.cursor=i+1}}function s(){for(;!v.in_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}for(;!v.out_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}function t(){m=v.limit,l=m;var e=v.cursor+3;0<=e&&e<=v.limit&&(d=e,s()||(m=v.cursor,m<d&&(m=d),s()||(l=v.cursor)))}function o(){for(var e,r;;){if(r=v.cursor,v.bra=r,!(e=v.find_among(h,6)))return;switch(v.ket=v.cursor,e){case 1:v.slice_from("y");break;case 2:case 5:v.slice_from("u");break;case 3:v.slice_from("a");break;case 4:v.slice_from("o");break;case 6:if(v.cursor>=v.limit)return;v.cursor++}}}function c(){return m<=v.cursor}function u(){return l<=v.cursor}function a(){var e,r,n,i,s=v.limit-v.cursor;if(v.ket=v.cursor,(e=v.find_among_b(w,7))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:v.slice_del(),v.ket=v.cursor,v.eq_s_b(1,"s")&&(v.bra=v.cursor,v.eq_s_b(3,"nis")&&v.slice_del());break;case 3:v.in_grouping_b(g,98,116)&&v.slice_del()}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(f,4))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:if(v.in_grouping_b(k,98,116)){var t=v.cursor-3;v.limit_backward<=t&&t<=v.limit&&(v.cursor=t,v.slice_del())}}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(_,8))&&(v.bra=v.cursor,u()))switch(e){case 1:v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"ig")&&(v.bra=v.cursor,r=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-r,u()&&v.slice_del()));break;case 2:n=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-n,v.slice_del());break;case 3:if(v.slice_del(),v.ket=v.cursor,i=v.limit-v.cursor,!v.eq_s_b(2,"er")&&(v.cursor=v.limit-i,!v.eq_s_b(2,"en")))break;v.bra=v.cursor,c()&&v.slice_del();break;case 4:v.slice_del(),v.ket=v.cursor,e=v.find_among_b(b,2),e&&(v.bra=v.cursor,u()&&1==e&&v.slice_del())}}var d,l,m,h=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],w=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],f=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],b=[new r("ig",-1,1),new r("lich",-1,1)],_=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],p=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],g=[117,30,5],k=[117,30,4],v=new n;this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var e=v.cursor;return i(),v.cursor=e,t(),v.limit_backward=e,v.cursor=v.limit,a(),v.cursor=v.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}});
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.du.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `Dutch` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e,r,i,o=C.cursor;;){if(C.bra=C.cursor,e=C.find_among(b,11))switch(C.ket=C.cursor,e){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(r=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=r);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=r;else if(n(r))break}else if(n(r))break}function n(e){return C.cursor=e,e>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,f=_,t()||(_=C.cursor,_<3&&(_=3),t()||(f=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var e;;)if(C.bra=C.cursor,e=C.find_among(p,3))switch(C.ket=C.cursor,e){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return f<=C.cursor}function a(){var e=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-e,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var e;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.slice_del(),w=!0,a())))}function m(){var e;u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.eq_s_b(3,"gem")||(C.cursor=C.limit-e,C.slice_del(),a())))}function d(){var e,r,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,e=C.find_among_b(h,5))switch(C.bra=C.cursor,e){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(z,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(r=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-r,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,e=C.find_among_b(k,6))switch(C.bra=C.cursor,e){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(j,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var f,_,w,b=[new r("",-1,6),new r("á",0,1),new r("ä",0,1),new r("é",0,2),new r("ë",0,2),new r("í",0,3),new r("ï",0,3),new r("ó",0,4),new r("ö",0,4),new r("ú",0,5),new r("ü",0,5)],p=[new r("",-1,3),new r("I",0,2),new r("Y",0,1)],g=[new r("dd",-1,-1),new r("kk",-1,-1),new r("tt",-1,-1)],h=[new r("ene",-1,2),new r("se",-1,3),new r("en",-1,2),new r("heden",2,1),new r("s",-1,3)],k=[new r("end",-1,1),new r("ig",-1,2),new r("ing",-1,1),new r("lijk",-1,3),new r("baar",-1,4),new r("bar",-1,5)],v=[new r("aa",-1,-1),new r("ee",-1,-1),new r("oo",-1,-1),new r("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(e){C.setCurrent(e)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var r=C.cursor;return e(),C.cursor=r,o(),C.limit_backward=r,C.cursor=C.limit,d(),C.cursor=C.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}});
```
--------------------------------------------------------------------------------
/docs/docs/watching.md:
--------------------------------------------------------------------------------
```markdown
1 | # Live File Watching
2 |
3 | CodeGraphContext can automatically monitor your codebase for changes and update the code graph in real-time as you develop.
4 |
5 | ## Quick Start
6 |
7 | Start watching your project directory:
8 |
9 | ```bash
10 | cgc watch .
11 | ```
12 |
13 | You'll see:
14 | ```
15 | 🔍 Watching /path/to/your/project for changes...
16 | ✓ Already indexed (no initial scan needed)
17 | 👀 Monitoring for file changes... (Press Ctrl+C to stop)
18 |
19 | 💡 Tip: Open a new terminal window to continue working
20 | ```
21 |
22 | ## How It Works
23 |
24 | The watcher uses file system events to detect when you:
25 |
26 | - Create new files
27 | - Modify existing files
28 | - Delete files
29 | - Move/rename files
30 |
31 | When changes are detected, CodeGraphContext automatically:
32 |
33 | 1. Re-parses the affected files
34 | 2. Updates the code graph
35 | 3. Maintains all relationships and dependencies
36 |
37 | ## Commands
38 |
39 | ### `cgc watch [path]`
40 |
41 | Start watching a directory for changes.
42 |
43 | **Examples:**
44 | ```bash
45 | cgc watch . # Watch current directory
46 | cgc watch /path/to/project # Watch specific directory
47 | cgc w . # Shortcut alias
48 | ```
49 |
50 | **Behavior:**
51 | - Runs in the foreground (blocking mode)
52 | - Performs initial scan if directory is not yet indexed
53 | - Monitors for all file system changes
54 | - Uses 2-second debouncing to batch rapid changes
55 | - Press `Ctrl+C` to stop
56 |
57 | ### `cgc watching`
58 |
59 | List all directories currently being watched.
60 |
61 | ```bash
62 | cgc watching
63 | ```
64 |
65 | **Note:** This command is primarily for MCP server mode. For CLI watch mode, check the terminal where you ran `cgc watch`.
66 |
67 | ### `cgc unwatch <path>`
68 |
69 | Stop watching a directory.
70 |
71 | ```bash
72 | cgc unwatch /path/to/project
73 | ```
74 |
75 | **Note:** This command is primarily for MCP server mode. For CLI watch mode, simply press `Ctrl+C` in the watch terminal.
76 |
77 | ## Best Practices
78 |
79 | ### Development Workflow
80 |
81 | 1. Start watching at the beginning of your coding session
82 | 2. Open a new terminal tab/window for your actual work
83 | 3. Code normally - changes are automatically tracked
84 | 4. Stop watching (Ctrl+C) when you're done
85 |
86 | ### Performance Tips
87 |
88 | - The watcher uses debouncing (2-second delay) to avoid excessive re-indexing
89 | - Only modified files and their dependencies are re-processed
90 | - Large projects may take a moment to process changes
91 |
92 | ### When to Use Watch Mode
93 |
94 | ✅ **Good for:**
95 |
96 | - Active development sessions
97 | - Refactoring work
98 | - Keeping AI assistants up-to-date with latest code
99 | - Live code analysis during development
100 |
101 | ❌ **Not needed for:**
102 |
103 | - One-time indexing
104 | - CI/CD pipelines
105 | - Read-only code analysis
106 | - Batch processing
107 |
108 | ## Example Workflow
109 |
110 | Here's a typical development session using watch mode:
111 |
112 | ```bash
113 | # Terminal 1: Start the watcher
114 | $ cd ~/my-project
115 | $ cgc watch .
116 | 🔍 Watching /home/user/my-project for changes...
117 | ✓ Already indexed (no initial scan needed)
118 | 👀 Monitoring for file changes... (Press Ctrl+C to stop)
119 |
120 | 💡 Tip: Open a new terminal window to continue working
121 |
122 | # ... watcher runs and shows updates as you code ...
123 | [21:15:32] 📝 Modified: src/utils.py (re-indexing...)
124 | [21:15:32] ✓ Updated graph (3 nodes, 2 relationships)
125 | [21:16:45] 📝 Created: src/new_feature.py (re-indexing...)
126 | [21:16:45] ✓ Updated graph (8 nodes, 5 relationships)
127 | ```
128 |
129 | ```bash
130 | # Terminal 2: Do your development work
131 | $ cd ~/my-project
132 | $ code . # Open your editor
133 | $ git checkout -b new-feature # Work normally
134 | $ # ... make changes, save files ...
135 | $ # The watcher in Terminal 1 automatically picks up changes!
136 | ```
137 |
138 | ## Troubleshooting
139 |
140 | ### Watcher not detecting changes
141 |
142 | - Ensure the path is correct and accessible
143 | - Check file permissions
144 | - Some editors use atomic writes which may not trigger events
145 | - Try restarting the watcher
146 |
147 | ### High CPU usage
148 |
149 | - The watcher may be processing too many files
150 | - Consider watching a smaller directory
151 | - Check for file loops or symlinks
152 | - Verify you're not watching `node_modules` or similar large directories
153 |
154 | ### Changes not appearing
155 |
156 | - Wait for the debounce interval (2 seconds)
157 | - Check the watcher output for errors
158 | - Verify the file type is supported (Python, JavaScript, TypeScript, etc.)
159 | - Ensure the file is within the watched directory
160 |
161 | ### "Already watching" message
162 |
163 | If you see this message, it means the directory is already being watched. This can happen if:
164 |
165 | - You're running multiple watch commands
166 | - The MCP server is already watching this directory
167 | - A previous watch session didn't terminate cleanly
168 |
169 | **Solution:** Stop all watch processes and start fresh.
170 |
171 | ## MCP Server vs CLI Watch Mode
172 |
173 | CodeGraphContext supports two watch modes:
174 |
175 | ### CLI Watch Mode (This Guide)
176 |
177 | - **Command:** `cgc watch .`
178 | - **Runs:** In foreground (blocking)
179 | - **Use case:** Active development sessions
180 | - **Control:** Press `Ctrl+C` to stop
181 | - **Best for:** Single project, focused development
182 |
183 | ### MCP Server Watch Mode
184 |
185 | - **Command:** Via MCP tools (`watch_directory`, `unwatch_directory`, `list_watched_paths`)
186 | - **Runs:** In background (as part of MCP server)
187 | - **Use case:** IDE integration, multiple projects
188 | - **Control:** MCP tool calls
189 | - **Best for:** AI assistant integration, persistent watching
190 |
191 | ## Technical Details
192 |
193 | - **Library**: Uses `watchdog` for cross-platform file monitoring
194 | - **Debouncing**: 2-second delay to batch rapid changes
195 | - **Scope**: Watches recursively, respects `.gitignore`
196 | - **Performance**: Only re-indexes changed files and affected relationships
197 | - **Thread-safe**: Uses background threads for file monitoring
198 | - **Graceful shutdown**: Properly cleans up on `Ctrl+C`
199 |
200 | ## Integration with AI Assistants
201 |
202 | Watch mode is particularly powerful when combined with AI coding assistants:
203 |
204 | 1. **Start watching your project:**
205 | ```bash
206 | cgc watch .
207 | ```
208 |
209 | 2. **Configure your AI assistant** to use the CodeGraphContext MCP server
210 |
211 | 3. **Code normally** - your AI assistant always has the latest code context
212 |
213 | 4. **Ask questions** about your code, and the AI will have up-to-date information
214 |
215 | This creates a seamless development experience where your AI assistant stays synchronized with your codebase in real-time!
216 |
217 | ## See Also
218 |
219 | - [CLI Reference](cli.md) - Complete list of CLI commands
220 | - [MCP Tools](mcp-tools.md) - MCP server tools including watch functionality
221 | - [Installation](installation.md) - Getting started with CodeGraphContext
222 |
```
--------------------------------------------------------------------------------
/website/src/components/DemoSection.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { Card, CardContent } from "@/components/ui/card";
2 | import { Badge } from "@/components/ui/badge";
3 | import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
4 | import { motion } from "framer-motion";
5 | import graphTotalImage from "../assets/graph-total.png";
6 | import functionCallsImage from "../assets/function-calls.png";
7 | import hierarchyImage from "../assets/hierarchy.png";
8 | import type { Variants } from "framer-motion";
9 |
10 | const DemoSection = () => {
11 | const visualizations = [
12 | {
13 | title: "Complete Code Graph",
14 | description: "All components and relationships between code elements.",
15 | image: graphTotalImage,
16 | badge: "Full Overview",
17 | aos: "fade-up",
18 | },
19 | {
20 | title: "Function Call Analysis",
21 | description: "Direct and indirect function calls across directories.",
22 | image: functionCallsImage,
23 | badge: "Call Chains",
24 | aos: "zoom-in",
25 | },
26 | {
27 | title: "Project Hierarchy",
28 | description: "Hierarchical structure of files and dependencies.",
29 | image: hierarchyImage,
30 | badge: "File Structure",
31 | aos: "flip-up",
32 | },
33 | ];
34 |
35 | const containerVariants: Variants = {
36 | hidden: { opacity: 0 },
37 | visible: {
38 | opacity: 1,
39 | transition: { staggerChildren: 0.2, delayChildren: 0.1 },
40 | },
41 | };
42 |
43 | const itemVariants: Variants = {
44 | hidden: { y: 20, opacity: 0 },
45 | visible: {
46 | y: 0,
47 | opacity: 1,
48 | transition: { duration: 0.6, ease: "easeOut" },
49 | },
50 | };
51 |
52 |
53 | return (
54 | <section
55 | className="py-20 px-4 bg-gradient-to-b from-background to-secondary/10"
56 | data-aos="fade-in"
57 | data-aos-duration="800"
58 | >
59 | <div className="container mx-auto max-w-7xl">
60 | {/* Heading Section */}
61 | <motion.div
62 | className="text-center mb-16"
63 | initial={{ opacity: 0, y: -20 }}
64 | whileInView={{ opacity: 1, y: 0 }}
65 | viewport={{ once: true, amount: 0.5 }}
66 | transition={{ duration: 0.7 }}
67 | >
68 | <h2
69 | className="text-3xl sm:text-4xl md:text-5xl font-bold mb-6 bg-gradient-to-r from-primary via-primary to-accent bg-clip-text text-transparent py-2"
70 | data-aos="fade-down"
71 | data-aos-duration="1000"
72 | >
73 | See CodeGraphContext in Action
74 | </h2>
75 | <p
76 | className="text-xl text-muted-foreground max-w-3xl mx-auto mb-12"
77 | data-aos="fade-up"
78 | data-aos-delay="200"
79 | >
80 | Watch how CodeGraphContext transforms complex codebases into
81 | interactive knowledge graphs.
82 | </p>
83 | </motion.div>
84 |
85 | {/* Embedded Demo Video */}
86 | <motion.div
87 | className="max-w-4xl mx-auto mb-16"
88 | initial={{ opacity: 0, scale: 0.9 }}
89 | whileInView={{ opacity: 1, scale: 1 }}
90 | viewport={{ once: true, amount: 0.3 }}
91 | transition={{ duration: 0.8, ease: "easeInOut" }}
92 | data-aos="zoom-in"
93 | >
94 | <div className="relative aspect-video rounded-lg overflow-hidden shadow-2xl border border-border/50">
95 | <iframe
96 | src="https://www.youtube.com/embed/KYYSdxhg1xU?autoplay=1&mute=1&loop=1&playlist=KYYSdxhg1xU"
97 | title="CodeGraphContext Demo"
98 | allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
99 | allowFullScreen
100 | className="w-full h-full"
101 | />
102 | </div>
103 | </motion.div>
104 |
105 | {/* Interactive Visualizations Section */}
106 | <div className="mb-12">
107 | <h3
108 | className="text-3xl font-bold text-center mb-8"
109 | data-aos="fade-up"
110 | data-aos-delay="100"
111 | >
112 | Interactive Visualizations
113 | </h3>
114 |
115 | <motion.div
116 | className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
117 | variants={containerVariants}
118 | initial="hidden"
119 | whileInView="visible"
120 | viewport={{ once: true, amount: 0.2 }}
121 | >
122 | {visualizations.map((viz, index) => (
123 | <motion.div
124 | key={index}
125 | variants={itemVariants}
126 | data-aos={viz.aos}
127 | data-aos-delay={index * 150}
128 | >
129 | <Card className="group hover:shadow-xl transition-all duration-300 border-border/50 overflow-hidden w-full h-full bg-background/70 backdrop-blur-sm">
130 | <Dialog>
131 | <DialogTrigger asChild>
132 | <div className="relative cursor-pointer flex flex-col h-full">
133 | <div className="relative">
134 | <img
135 | src={viz.image}
136 | alt={viz.title}
137 | className="w-full h-48 object-cover group-hover:scale-105 transition-transform duration-300"
138 | loading="lazy"
139 | />
140 | <Badge className="absolute top-2 left-2 text-xs">
141 | {viz.badge}
142 | </Badge>
143 | </div>
144 | <CardContent className="p-6 flex-grow flex flex-col">
145 | <h4 className="text-xl font-semibold mb-3 group-hover:text-primary transition-colors">
146 | {viz.title}
147 | </h4>
148 | <p className="text-base text-muted-foreground flex-grow">
149 | {viz.description}
150 | </p>
151 | </CardContent>
152 | </div>
153 | </DialogTrigger>
154 |
155 | {/* Dialog Content */}
156 | <DialogContent className="max-w-5xl w-full">
157 | <img
158 | src={viz.image}
159 | alt={`${viz.title} Visualization`}
160 | className="w-full h-auto max-h-[80vh] object-contain rounded-lg"
161 | />
162 | </DialogContent>
163 | </Dialog>
164 | </Card>
165 | </motion.div>
166 | ))}
167 | </motion.div>
168 | </div>
169 | </div>
170 | </section>
171 | );
172 | };
173 |
174 | export default DemoSection;
175 |
```