#
tokens: 45767/50000 7/367 files (page 9/18)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 9 of 18. Use http://codebase.md/shashankss1205/codegraphcontext?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .github
│   └── workflows
│       ├── e2e-tests.yml
│       ├── post_discord_invite.yml
│       ├── test.yml
│       └── update-contributors.yml
├── .gitignore
├── 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
│   ├── mkdocs.yml
│   └── site
│       ├── 404.html
│       ├── architecture
│       │   └── index.html
│       ├── assets
│       │   ├── images
│       │   │   └── favicon.png
│       │   ├── javascripts
│       │   │   ├── bundle.f55a23d4.min.js
│       │   │   ├── bundle.f55a23d4.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.973d3a69.min.js
│       │   │       └── search.973d3a69.min.js.map
│       │   └── stylesheets
│       │       ├── main.2a3383ac.min.css
│       │       ├── main.2a3383ac.min.css.map
│       │       ├── palette.06af60db.min.css
│       │       └── palette.06af60db.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
├── 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
├── package-lock.json
├── pyproject.toml
├── README.md
├── scripts
│   ├── generate_lang_contributors.py
│   └── post_install_fix.sh
├── SECURITY.md
├── src
│   └── codegraphcontext
│       ├── __init__.py
│       ├── __main__.py
│       ├── cli
│       │   ├── __init__.py
│       │   ├── cli_helpers.py
│       │   ├── main.py
│       │   ├── setup_macos.py
│       │   └── setup_wizard.py
│       ├── core
│       │   ├── __init__.py
│       │   ├── database.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
│       │   │   ├── go.py
│       │   │   ├── java.py
│       │   │   ├── javascript.py
│       │   │   ├── python.py
│       │   │   ├── ruby.py
│       │   │   ├── rust.py
│       │   │   └── typescript.py
│       │   ├── package_resolver.py
│       │   ├── query_tool_languages
│       │   │   ├── c_toolkit.py
│       │   │   ├── cpp_toolkit.py
│       │   │   ├── go_toolkit.py
│       │   │   ├── java_toolkit.py
│       │   │   ├── javascript_toolkit.py
│       │   │   ├── python_toolkit.py
│       │   │   ├── ruby_toolkit.py
│       │   │   ├── rust_toolkit.py
│       │   │   └── typescript_toolkit.py
│       │   └── system.py
│       └── utils
│           └── debug_log.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_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_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_typescript
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── 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_tree_sitter
│   │   ├── __init__.py
│   │   ├── class_instantiation.py
│   │   ├── complex_classes.py
│   │   └── test_file.py
│   └── test_typescript_parser.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
    │   │   ├── 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
```

# Files

--------------------------------------------------------------------------------
/src/codegraphcontext/tools/languages/cpp.py:
--------------------------------------------------------------------------------

```python
  1 | 
  2 | from pathlib import Path
  3 | from typing import Any, Dict, Optional, Tuple
  4 | from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
  5 | 
  6 | CPP_QUERIES = {
  7 |     "functions": """
  8 |         (function_definition
  9 |             declarator: (function_declarator
 10 |                 declarator: (identifier) @name
 11 |             )
 12 |         ) @function_node
 13 |     """,
 14 |     "classes": """
 15 |         (class_specifier
 16 |             name: (type_identifier) @name
 17 |         ) @class
 18 |     """,
 19 |     "imports": """
 20 |         (preproc_include
 21 |             path: [
 22 |                 (string_literal) @path
 23 |                 (system_lib_string) @path
 24 |             ]
 25 |         ) @import
 26 |     """,
 27 |     "calls": """
 28 |         (call_expression
 29 |             function: [
 30 |                 (identifier) @function_name
 31 |                 (field_expression
 32 |                     field: (field_identifier) @method_name
 33 |                 )
 34 |             ]
 35 |         arguments: (argument_list) @args
 36 |     )
 37 |     """,
 38 |     "enums":"""
 39 |         (enum_specifier
 40 |             name: (type_identifier) @name
 41 |             body: (enumerator_list
 42 |                 (enumerator
 43 |                     name: (identifier) @value
 44 |                     )*
 45 |                 )? @body
 46 |         ) @enum
 47 |     """,
 48 |     "structs":"""
 49 |         (struct_specifier
 50 |             name: (type_identifier) @name
 51 |             body: (field_declaration_list)? @body
 52 |         ) @struct
 53 |     """,
 54 |     "unions": """
 55 |     (union_specifier
 56 |     name: (type_identifier)? @name
 57 |     body: (field_declaration_list
 58 |         (field_declaration
 59 |             declarator: [
 60 |                 (field_identifier) @value
 61 |                 (pointer_declarator (field_identifier) @value)
 62 |                 (array_declarator (field_identifier) @value)
 63 |                 ]
 64 |             )*
 65 |         )? @body
 66 |     ) @union
 67 |   
 68 |     """,
 69 |     "macros": """
 70 |         (preproc_def
 71 |             name: (identifier) @name
 72 |         ) @macro
 73 |     """,
 74 |     "variables": """
 75 |     (declaration
 76 |         declarator: (init_declarator
 77 |                         declarator: (identifier) @name))
 78 | 
 79 |     (declaration
 80 |         declarator: (init_declarator
 81 |                         declarator: (pointer_declarator
 82 |                             declarator: (identifier) @name)))
 83 |     """,
 84 |     "lambda_assignments": """
 85 |     ; Match a lambda assigned to a variable
 86 |     (declaration
 87 |         declarator: (init_declarator
 88 |             declarator: (identifier) @name
 89 |             value: (lambda_expression) @lambda_node))
 90 |     """
 91 |     
 92 | }
 93 | 
 94 | class CppTreeSitterParser:
 95 |     """A C++-specific parser using tree-sitter."""
 96 | 
 97 |     def __init__(self, generic_parser_wrapper):
 98 |         self.generic_parser_wrapper = generic_parser_wrapper
 99 |         self.language_name = "cpp"
100 |         self.language = generic_parser_wrapper.language
101 |         self.parser = generic_parser_wrapper.parser
102 | 
103 |         self.queries = {
104 |             name: self.language.query(query_str)
105 |             for name, query_str in CPP_QUERIES.items()
106 |         }
107 | 
108 |     def _get_node_text(self, node) -> str:
109 |         return node.text.decode('utf-8')
110 | 
111 |     def parse(self, file_path: Path, is_dependency: bool = False, **kwargs) -> Dict:
112 |         """Parses a C++ file and returns its structure."""
113 |         with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
114 |             source_code = f.read()
115 | 
116 |         tree = self.parser.parse(bytes(source_code, "utf8"))
117 |         root_node = tree.root_node
118 | 
119 |         functions = self._find_functions(root_node)
120 |         functions.extend(self._find_lambda_assignments(root_node))
121 |         function_calls = self._find_calls(root_node)
122 |         classes = self._find_classes(root_node)
123 |         imports = self._find_imports(root_node)
124 |         structs = self._find_structs(root_node)
125 |         enums = self._find_enums(root_node)
126 |         unions = self._find_unions(root_node)
127 |         macros = self._find_macros(root_node)
128 |         variables = self._find_variables(root_node)
129 |         
130 |         return {
131 |             "file_path": str(file_path),
132 |             "functions": functions,
133 |             "classes": classes,
134 |             "structs": structs,
135 |             "enums": enums,
136 |             "unions": unions,
137 |             "macros": macros,
138 |             "variables": variables,  
139 |             "declarations": [], # Placeholder
140 |             "imports": imports,
141 |             "function_calls": function_calls, 
142 |             "is_dependency": is_dependency,
143 |             "lang": self.language_name,
144 |         }
145 | 
146 |     def _find_functions(self, root_node):
147 |         functions = []
148 |         query = self.queries['functions']
149 |         for match in query.captures(root_node):
150 |             capture_name = match[1]
151 |             node = match[0]
152 |             if capture_name == 'name':
153 |                 func_node = node.parent.parent.parent
154 |                 name = self._get_node_text(node)
155 |                 functions.append({
156 |                     "name": name,
157 |                     "line_number": node.start_point[0] + 1,
158 |                     "end_line": func_node.end_point[0] + 1,
159 |                     "source_code": self._get_node_text(func_node),
160 |                     "args": [], # Placeholder
161 |                 })
162 |         return functions
163 | 
164 |     def _find_classes(self, root_node):
165 |         classes = []
166 |         query = self.queries['classes']
167 |         for match in query.captures(root_node):
168 |             capture_name = match[1]
169 |             node = match[0]
170 |             if capture_name == 'name':
171 |                 class_node = node.parent
172 |                 name = self._get_node_text(node)
173 |                 classes.append({
174 |                     "name": name,
175 |                     "line_number": node.start_point[0] + 1,
176 |                     "end_line": class_node.end_point[0] + 1,
177 |                     "source_code": self._get_node_text(class_node),
178 |                     "bases": [], # Placeholder
179 |                 })
180 |         return classes
181 | 
182 |     def _find_imports(self, root_node):
183 |         imports = []
184 |         query = self.queries['imports']
185 |         for match in query.captures(root_node):
186 |             capture_name = match[1]
187 |             node = match[0]
188 |             if capture_name == 'path':
189 |                 path = self._get_node_text(node).strip('<>')
190 |                 imports.append({
191 |                     "name": path,
192 |                     "full_import_name": path,
193 |                     "line_number": node.start_point[0] + 1,
194 |                     "alias": None,
195 |                 })
196 |         return imports
197 |     
198 |     def _find_enums(self, root_node):
199 |         enums = []
200 |         query = self.queries['enums']
201 |         for node, capture_name in query.captures(root_node):
202 |             if capture_name == 'name':
203 |                 name = self._get_node_text(node)
204 |                 enum_node = node.parent
205 |                 enums.append({
206 |                     "name": name,
207 |                     "line_number": node.start_point[0] + 1,
208 |                     "end_line": enum_node.end_point[0] + 1,
209 |                     "source_code": self._get_node_text(enum_node),
210 |                 })
211 |         return enums
212 |  
213 |     def _find_structs(self, root_node):
214 |         structs = []
215 |         query = self.queries['structs']
216 |         for node, capture_name in query.captures(root_node):
217 |             if capture_name == 'name':
218 |                 name = self._get_node_text(node)
219 |                 struct_node = node.parent
220 |                 structs.append({
221 |                     "name": name,
222 |                     "line_number": node.start_point[0] + 1,
223 |                     "end_line": struct_node.end_point[0] + 1,
224 |                     "source_code": self._get_node_text(struct_node),
225 |                 })
226 |         return structs
227 | 
228 |     def _find_unions(self, root_node):
229 |         unions = []
230 |         query = self.queries['unions']
231 |         for node, capture_name in query.captures(root_node):
232 |             if capture_name == 'name':
233 |                 name = self._get_node_text(node)
234 |                 union_node = node.parent
235 |                 unions.append({
236 |                     "name": name,
237 |                     "line_number": node.start_point[0] + 1,
238 |                     "end_line": union_node.end_point[0] + 1,
239 |                     "source_code": self._get_node_text(union_node),
240 |                 })
241 |         return unions
242 | 
243 |     def _find_macros(self, root_node):
244 |         macros = []
245 |         query = self.queries['macros']
246 |         for match in query.captures(root_node):
247 |             capture_name = match[1]
248 |             node = match[0]
249 |             if capture_name == 'name':
250 |                 macro_node = node.parent
251 |                 name = self._get_node_text(node)
252 |                 macros.append({
253 |                     "name": name,
254 |                     "line_number": node.start_point[0] + 1,
255 |                     "end_line": macro_node.end_point[0] + 1,
256 |                     "source_code": self._get_node_text(macro_node),
257 |                 })
258 |         return macros
259 |     
260 |     def _find_lambda_assignments(self, root_node):
261 |         functions = []
262 |         query = self.queries.get('lambda_assignments')
263 |         if not query: return []
264 | 
265 |         for match in query.captures(root_node):
266 |             capture_name = match[1]
267 |             node = match[0]
268 | 
269 |             if capture_name == 'name':
270 |                 assignment_node = node.parent
271 |                 lambda_node = assignment_node.child_by_field_name('value')
272 |             if lambda_node is None or lambda_node.type != 'lambda_expression':
273 |                 continue
274 | 
275 |             params_node = lambda_node.child_by_field_name('declarator')
276 |             if params_node:
277 |                 params_node = params_node.child_by_field_name('parameters')
278 |                 name = self._get_node_text(node)
279 |                 params_node = lambda_node.child_by_field_name('parameters')
280 |                 
281 |                 context, context_type, _ = self._get_parent_context(assignment_node)
282 |                 class_context, _, _ = self._get_parent_context(assignment_node, types=('class_definition',))
283 | 
284 |                 func_data = {
285 |                     "name": name,
286 |                     "line_number": node.start_point[0] + 1,
287 |                     "end_line": assignment_node.end_point[0] + 1,
288 |                     "args": [p for p in [self._get_node_text(p) for p in params_node.children if p.type == 'identifier'] if p] if params_node else [],
289 |                     "source": self._get_node_text(assignment_node),
290 |                     "source_code": self._get_node_text(assignment_node),
291 |                     "docstring": None,
292 |                     "cyclomatic_complexity": 1,
293 |                     "context": context,
294 |                     "context_type": context_type,
295 |                     "class_context": class_context,
296 |                     "decorators": [],
297 |                     "lang": self.language_name,
298 |                     "is_dependency": False,
299 |                 }
300 |                 functions.append(func_data)
301 |         return functions
302 |     
303 |     def _find_variables(self, root_node):
304 |         variables = []
305 |         query = self.queries['variables']
306 |         for match in query.captures(root_node):
307 |             capture_name = match[1]
308 |             node = match[0]
309 | 
310 |             if capture_name == 'name':
311 |                 assignment_node = node.parent
312 | 
313 |                 # Skip lambda assignments, they are handled by _find_lambda_assignments
314 |                 right_node = assignment_node.child_by_field_name('value')
315 |                 if right_node and right_node.type == 'lambda_expression':
316 |                     continue
317 | 
318 |                 name = self._get_node_text(node)
319 |                 value = self._get_node_text(right_node) if right_node else None
320 |                 
321 |                 type_node = assignment_node.child_by_field_name('type')
322 |                 type_text = self._get_node_text(type_node) if type_node else None
323 | 
324 |                 context, _, _ = self._get_parent_context(node)
325 |                 class_context, _, _ = self._get_parent_context(node, types=('class_definition',))
326 | 
327 |                 variable_data = {
328 |                     "name": name,
329 |                     "line_number": node.start_point[0] + 1,
330 |                     "value": value,
331 |                     "type": type_text,
332 |                     "context": context,
333 |                     "class_context": class_context,
334 |                     "lang": self.language_name,
335 |                     "is_dependency": False,
336 |                 }
337 |                 variables.append(variable_data)
338 |         return variables
339 |     
340 |     def _get_parent_context(self, node, types=('function_definition', 'class_definition')):
341 |         curr = node.parent
342 |         while curr:
343 |             if curr.type in types:
344 |                 name_node = curr.child_by_field_name('name')
345 |                 return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
346 |             curr = curr.parent
347 |         return None, None, None
348 |     
349 |     def _find_calls(self, root_node):
350 |         calls = []
351 |         query = self.queries['calls']
352 |         for node, capture_name in query.captures(root_node):
353 |             if capture_name == "function_name":
354 |                 func_name = self._get_node_text(node)
355 |                 func_node = node.parent.parent  # function_declarator -> function_definition
356 |                 full_name = self._get_full_name(func_node) or func_name
357 | 
358 |                 # Find return type node (captured separately)
359 |                 return_type_node = None
360 |                 for n, cap in query.captures(func_node):
361 |                     if cap == "return_type":
362 |                         return_type_node = n
363 |                         break
364 |                 return_type = self._get_node_text(return_type_node) if return_type_node else None
365 | 
366 |                 # Extract parameters
367 |                 args = []
368 |                 parameters_node = func_node.child_by_field_name("declarator")
369 |                 if parameters_node:
370 |                     param_list_node = parameters_node.child_by_field_name("parameters")
371 |                     if param_list_node:
372 |                         for param in param_list_node.children:
373 |                             if param.type == "parameter_declaration":
374 |                                 type_node = param.child_by_field_name("type")
375 |                                 name_node = param.child_by_field_name("declarator")
376 | 
377 |                                 param_type = self._get_node_text(type_node) if type_node else None
378 |                                 param_name = self._get_node_text(name_node) if name_node else None
379 | 
380 |                                 args.append({
381 |                                     "type": param_type,
382 |                                     "name": param_name
383 |                                 })
384 |                 
385 | 
386 |                 # Get context info (function may be inside class)
387 |                 context, _, _ = self._get_parent_context(node)
388 |                 class_context, _, _ = self._get_parent_context(node, types=("class_definition",))
389 | 
390 |                 call_data = {
391 |                     "name": func_name,
392 |                     "full_name": full_name,
393 |                     "line_number": node.start_point[0] + 1,
394 |                     "args": args,
395 |                     "inferred_obj_type": None,
396 |                     "context": context,
397 |                     "class_context": class_context,
398 |                     "lang": self.language_name,
399 |                     "is_dependency": False,
400 |                 }
401 |                 calls.append(call_data)
402 |         return calls
403 |     
404 |     def _get_full_name(self, node):
405 |         "Builds a fully qualified name for a function or call node."
406 | 
407 |         name_parts = []
408 | 
409 |         # Move upward and collect parent scopes
410 |         curr = node
411 |         while curr:
412 |             if curr.type in ("function_definition", "function_declarator"):
413 |                 id_node = curr.child_by_field_name("declarator")
414 |                 if id_node and id_node.type == "identifier":
415 |                     name_parts.insert(0, id_node.text.decode("utf8"))
416 |             elif curr.type == "class_specifier":
417 |                 name_node = curr.child_by_field_name("name")
418 |                 if name_node:
419 |                     name_parts.insert(0, name_node.text.decode("utf8"))
420 |             elif curr.type == "namespace_definition":
421 |                 name_node = curr.child_by_field_name("name")
422 |                 if name_node:
423 |                     name_parts.insert(0, name_node.text.decode("utf8"))
424 |             curr = curr.parent
425 | 
426 |         return "::".join(name_parts) if name_parts else None
427 | 
428 | 
429 | def pre_scan_cpp(files: list[Path], parser_wrapper) -> dict:
430 |     """
431 |     Quickly scans C++ files to build a map of top-level class, struct, and function names
432 |     to their file paths.
433 |     """
434 |     imports_map = {}
435 | 
436 |     query_str = """
437 |         (class_specifier name: (type_identifier) @name)
438 |         (struct_specifier name: (type_identifier) @name)
439 |         (function_definition declarator: (function_declarator declarator: (identifier) @name))
440 |     """
441 |     query = parser_wrapper.language.query(query_str)
442 | 
443 |     for file_path in files:
444 |         try:
445 |             with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
446 |                 source_bytes = f.read().encode("utf-8")
447 |                 tree = parser_wrapper.parser.parse(source_bytes)
448 | 
449 |             for node, capture_name in query.captures(tree.root_node):
450 |                 if capture_name == "name":
451 |                     name = node.text.decode("utf-8")
452 |                     imports_map.setdefault(name, []).append(str(file_path.resolve()))
453 |         except Exception as e:
454 |             warning_logger(f"Tree-sitter pre-scan failed for {file_path}: {e}")
455 | 
456 |     return imports_map
457 | 
```

--------------------------------------------------------------------------------
/src/codegraphcontext/tools/package_resolver.py:
--------------------------------------------------------------------------------

```python
  1 | # src/codegraphcontext/tools/package_resolver.py
  2 | import importlib
  3 | import stdlibs
  4 | from pathlib import Path
  5 | import subprocess
  6 | from typing import Optional
  7 | 
  8 | from ..utils.debug_log import debug_log
  9 | 
 10 | def _get_python_package_path(package_name: str) -> Optional[str]:
 11 |     """
 12 |     Finds the local installation path of a Python package.
 13 |     """
 14 |     try:
 15 |         debug_log(f"Getting local path for Python package: {package_name}")
 16 |         module = importlib.import_module(package_name)
 17 |         if hasattr(module, '__file__') and module.__file__:
 18 |             module_file = Path(module.__file__)
 19 |             if module_file.name == '__init__.py':
 20 |                 return str(module_file.parent)
 21 |             elif package_name in stdlibs.module_names:
 22 |                 return str(module_file)
 23 |             else:
 24 |                 return str(module_file.parent)
 25 |         elif hasattr(module, '__path__'):
 26 |             if isinstance(module.__path__, list) and module.__path__:
 27 |                 return str(Path(module.__path__[0]))
 28 |             else:
 29 |                 return str(Path(str(module.__path__)))
 30 |         return None
 31 |     except ImportError:
 32 |         return None
 33 |     except Exception as e:
 34 |         debug_log(f"Error getting local path for {package_name}: {e}")
 35 |         return None
 36 | 
 37 | def _get_npm_package_path(package_name: str) -> Optional[str]:
 38 |     """
 39 |     Finds the local installation path of a Node.js package using `npm root`.
 40 |     """
 41 |     try:
 42 |         debug_log(f"Getting local path for npm package: {package_name}")
 43 |         local_path = Path(f"./node_modules/{package_name}")
 44 |         if local_path.exists():
 45 |             return str(local_path.resolve())
 46 | 
 47 |         result = subprocess.run(["npm", "root", "-g"], capture_output=True, text=True)
 48 |         if result.returncode == 0:
 49 |             global_root = result.stdout.strip()
 50 |             package_path = Path(global_root) / package_name
 51 |             if package_path.exists():
 52 |                 return str(package_path.resolve())
 53 |         return None
 54 |     except Exception as e:
 55 |         debug_log(f"Error getting npm package path for {package_name}: {e}")
 56 |         return None
 57 | 
 58 | def _get_typescript_package_path(package_name: str) -> Optional[str]:
 59 |     """
 60 |     Finds the local installation path of a TypeScript package.
 61 |     TypeScript packages are typically npm packages, so this uses the same logic as npm.
 62 |     """
 63 |     try:
 64 |         debug_log(f"Getting local path for TypeScript package: {package_name}")
 65 |         
 66 |         # Check local node_modules first
 67 |         local_path = Path(f"./node_modules/{package_name}")
 68 |         if local_path.exists():
 69 |             return str(local_path.resolve())
 70 | 
 71 |         # Check global npm packages
 72 |         result = subprocess.run(["npm", "root", "-g"], capture_output=True, text=True, timeout=5)
 73 |         if result.returncode == 0:
 74 |             global_root = result.stdout.strip()
 75 |             package_path = Path(global_root) / package_name
 76 |             if package_path.exists():
 77 |                 return str(package_path.resolve())
 78 |         
 79 |         return None
 80 |     except subprocess.TimeoutExpired:
 81 |         debug_log(f"npm command timed out for {package_name}")
 82 |         return None
 83 |     except Exception as e:
 84 |         debug_log(f"Error getting TypeScript package path for {package_name}: {e}")
 85 |         return None
 86 | 
 87 | def _get_java_package_path(package_name: str) -> Optional[str]:
 88 |     """
 89 |     Finds the local installation path of a Java package (JAR).
 90 |     Searches in Maven and Gradle cache directories.
 91 |     
 92 |     Args:
 93 |         package_name: Package name in format "groupId:artifactId" (e.g., "com.google.code.gson:gson")
 94 |                      or just "artifactId" for simple search.
 95 |     """
 96 |     try:
 97 |         debug_log(f"Getting local path for Java package: {package_name}")
 98 |         
 99 |         # Parse package name - expect format "groupId:artifactId" or just "artifactId"
100 |         if ':' in package_name:
101 |             group_id, artifact_id = package_name.split(':', 1)
102 |             # Convert group_id dots to path separators (e.g., com.google.gson -> com/google/gson)
103 |             group_path = group_id.replace('.', '/')
104 |         else:
105 |             # If only artifact_id provided, search for it
106 |             artifact_id = package_name
107 |             group_path = None
108 |         
109 |         search_paths = []
110 |         
111 |         # Maven repository (~/.m2/repository)
112 |         maven_repo = Path.home() / ".m2" / "repository"
113 |         if maven_repo.exists():
114 |             if group_path:
115 |                 # Search for specific group/artifact
116 |                 package_path = maven_repo / group_path / artifact_id
117 |                 if package_path.exists():
118 |                     # Find the latest version directory
119 |                     version_dirs = [d for d in package_path.iterdir() if d.is_dir()]
120 |                     if version_dirs:
121 |                         # Sort by name (assumes semantic versioning) and get the latest
122 |                         latest_version = sorted(version_dirs, key=lambda x: x.name)[-1]
123 |                         return str(latest_version.resolve())
124 |             else:
125 |                 # Search for artifact_id in the entire Maven repo
126 |                 search_paths.append(maven_repo)
127 |         
128 |         # Gradle cache (~/.gradle/caches/modules-2/files-2.1)
129 |         gradle_cache = Path.home() / ".gradle" / "caches" / "modules-2" / "files-2.1"
130 |         if gradle_cache.exists():
131 |             if group_path:
132 |                 group_id_full = group_id if ':' in package_name else None
133 |                 if group_id_full:
134 |                     package_path = gradle_cache / group_id_full / artifact_id
135 |                     if package_path.exists():
136 |                         # Find the latest version directory
137 |                         version_dirs = [d for d in package_path.iterdir() if d.is_dir()]
138 |                         if version_dirs:
139 |                             latest_version = sorted(version_dirs, key=lambda x: x.name)[-1]
140 |                             # Gradle stores files in hash subdirectories
141 |                             hash_dirs = [d for d in latest_version.iterdir() if d.is_dir()]
142 |                             if hash_dirs:
143 |                                 return str(hash_dirs[0].resolve())
144 |             else:
145 |                 search_paths.append(gradle_cache)
146 |         
147 |         # If group_path wasn't provided or not found, search in the cache directories
148 |         if not group_path or search_paths:
149 |             for base_path in search_paths:
150 |                 for jar_file in base_path.rglob(f"*{artifact_id}*.jar"):
151 |                     return str(jar_file.parent.resolve())
152 |         
153 |         # Check local lib directories
154 |         local_lib_paths = [
155 |             Path("./lib"),
156 |             Path("./libs"),
157 |             Path("/usr/local/lib/java"),
158 |             Path("/opt/java/lib"),
159 |         ]
160 |         
161 |         for lib_path in local_lib_paths:
162 |             if not lib_path.exists():
163 |                 continue
164 |             
165 |             # Look for JAR files matching the artifact name
166 |             for jar_file in lib_path.glob(f"*{artifact_id}*.jar"):
167 |                 return str(jar_file.resolve())
168 |         
169 |         return None
170 |     except Exception as e:
171 |         debug_log(f"Error getting Java package path for {package_name}: {e}")
172 | def _get_c_package_path(package_name: str) -> Optional[str]:
173 |     """
174 |     Finds the local installation path of a C package.
175 |     """
176 |     try:
177 |         debug_log(f"Getting local path for C package: {package_name}")
178 |         
179 |         # Try using pkg-config to find the package
180 |         try:
181 |             result = subprocess.run(
182 |                 ["pkg-config", "--variable=includedir", package_name],
183 |                 capture_output=True,
184 |                 text=True,
185 |                 timeout=5
186 |             )
187 |             if result.returncode == 0 and result.stdout.strip():
188 |                 include_dir = Path(result.stdout.strip())
189 |                 package_path = include_dir / package_name
190 |                 if package_path.exists():
191 |                     return str(package_path.resolve())
192 |                 if include_dir.exists():
193 |                     return str(include_dir.resolve())
194 |         except (subprocess.TimeoutExpired, FileNotFoundError):
195 |             debug_log(f"pkg-config not available or timed out for {package_name}")
196 |         
197 |         # Search in standard system include directories
198 |         common_include_paths = [
199 |             "/usr/include",
200 |             "/usr/local/include",
201 |             "/opt/homebrew/include",
202 |             "/opt/local/include",
203 |             Path.home() / ".local" / "include",
204 |         ]
205 |         
206 |         for base_path in common_include_paths:
207 |             base_path = Path(base_path)
208 |             if not base_path.exists():
209 |                 continue
210 |             
211 |             # Check if package exists as a directory
212 |             package_dir = base_path / package_name
213 |             if package_dir.exists() and package_dir.is_dir():
214 |                 return str(package_dir.resolve())
215 |             
216 |             # Check for header files with package name
217 |             header_file = base_path / f"{package_name}.h"
218 |             if header_file.exists():
219 |                 return str(header_file.resolve())
220 |         
221 |         # Check current directory for local installations
222 |         local_package = Path(f"./{package_name}")
223 |         if local_package.exists():
224 |             return str(local_package.resolve())
225 |         
226 |         return None
227 |     except Exception as e:
228 |         debug_log(f"Error getting C package path for {package_name}: {e}")
229 |         return None
230 |     
231 | def _get_ruby_package_path(package_name: str) -> Optional[str]:
232 |     """
233 |     Finds the local installation path of a Ruby gem.
234 |     """
235 |     try:
236 |         debug_log(f"Getting local path for Ruby gem: {package_name}")
237 |         result = subprocess.run(
238 |             ["gem", "which", package_name],
239 |             capture_output=True,
240 |             text=True,
241 |             timeout=5
242 |         )
243 |         if result.returncode == 0 and result.stdout.strip():
244 |             gem_path = Path(result.stdout.strip())
245 |             if gem_path.exists():
246 |                 lib_dir = gem_path.parent if gem_path.is_file() else gem_path
247 |                 # If we are inside a gem (…/gems/foo-x.y.z/lib/foo.rb), prefer the lib/ dir:
248 |                 if (lib_dir.name == "lib") and lib_dir.is_dir():
249 |                     return str(lib_dir.resolve())
250 |                 # Try parent/lib in case `gem which` returned .../lib/foo.rb
251 |                 if (lib_dir / "lib").is_dir():
252 |                     return str((lib_dir / "lib").resolve())
253 |                 # Fallback: just return the directory containing the file (stdlib case like 'json')
254 |                 return str(lib_dir.resolve())
255 |         return None
256 |     except (subprocess.TimeoutExpired, FileNotFoundError):
257 |         debug_log(f"gem command not available or timed out for {package_name}")
258 |         return None
259 |     except Exception as e:
260 |         debug_log(f"Error getting Ruby gem path for {package_name}: {e}")
261 |         return None
262 | 
263 | def _get_go_package_path(package_name: str) -> Optional[str]:
264 |     """
265 |     Finds the local installation path of a Go package using `go list`.
266 |     Tries multiple approaches in sequence to handle different package scenarios:
267 |       1) package dir:   go list -f '{{.Dir}}' <pkg>             (works for stdlib, GOPATH, or module subpackages)
268 |       2) module root:   go list -m -f '{{.Dir}}' <module>       (works for full module paths)
269 |       3) force mod:     go list -mod=mod -f '{{.Dir}}' <pkg>    (works when outside a module context)
270 |       4) GOROOT check:  for standard library packages
271 |       5) GOPATH check:  for packages in GOPATH
272 |     """
273 | 
274 |     def _first_existing_dir(output: str) -> Optional[str]:
275 |         for line in (l.strip().strip("'\"") for l in output.splitlines() if l.strip()):
276 |             p = Path(line)
277 |             if p.exists() and p.is_dir():
278 |                 return str(p.resolve())
279 |         return None
280 | 
281 |     try:
282 |         debug_log(f"Getting local path for Go package: {package_name}")
283 |         
284 |         # 1. Package directory (works for stdlib, GOPATH, or subpackages)
285 |         cp = subprocess.run(
286 |             ["go", "list", "-f", "{{.Dir}}", package_name],
287 |             capture_output=True, text=True, timeout=15
288 |         )
289 |         if cp.returncode == 0:
290 |             d = _first_existing_dir(cp.stdout)
291 |             if d:
292 |                 return d
293 | 
294 |         # 2. Module root directory (where go.mod lives)
295 |         cp2 = subprocess.run(
296 |             ["go", "list", "-m", "-f", "{{.Dir}}", package_name],
297 |             capture_output=True, text=True, timeout=15
298 |         )
299 |         if cp2.returncode == 0:
300 |             d = _first_existing_dir(cp2.stdout)
301 |             if d:
302 |                 debug_log(f"Found Go module {package_name} at {d}")
303 |                 return d
304 | 
305 |         # 3. Retry forcing module mode
306 |         cp3 = subprocess.run(
307 |             ["go", "list", "-mod=mod", "-f", "{{.Dir}}", package_name],
308 |             capture_output=True, text=True, timeout=15
309 |         )
310 |         if cp3.returncode == 0:
311 |             d = _first_existing_dir(cp3.stdout)
312 |             if d:
313 |                 return d
314 |         
315 |         # 4. Check in GOROOT for standard library packages
316 |         try:
317 |             cp4 = subprocess.run(
318 |                 ["go", "env", "GOROOT"],
319 |                 capture_output=True, text=True, timeout=5
320 |             )
321 |             if cp4.returncode == 0:
322 |                 goroot = cp4.stdout.strip()
323 |                 if goroot:
324 |                     std_lib_path = Path(goroot) / "src" / package_name
325 |                     if std_lib_path.exists() and std_lib_path.is_dir():
326 |                         return str(std_lib_path.resolve())
327 |         except Exception as e:
328 |             debug_log(f"Error checking GOROOT for {package_name}: {e}")
329 |         
330 |         # 5. Check in GOPATH as fallback
331 |         try:
332 |             cp5 = subprocess.run(
333 |                 ["go", "env", "GOPATH"],
334 |                 capture_output=True, text=True, timeout=5
335 |             )
336 |             if cp5.returncode == 0:
337 |                 gopath = cp5.stdout.strip()
338 |                 if gopath:
339 |                     gopath_lib_path = Path(gopath) / "src" / package_name
340 |                     if gopath_lib_path.exists() and gopath_lib_path.is_dir():
341 |                         debug_log(f"Found Go package in GOPATH {package_name} at {gopath_lib_path}")
342 |                         return str(gopath_lib_path.resolve())
343 |         except Exception as e:
344 |             debug_log(f"Error checking GOPATH for {package_name}: {e}")
345 | 
346 |         debug_log(f"Could not find Go package: {package_name}")
347 |         return None
348 | 
349 |     except (subprocess.TimeoutExpired, FileNotFoundError):
350 |         debug_log(f"go command not available or timed out for {package_name}")
351 |         return None
352 |     except Exception as e:
353 |         debug_log(f"Error getting Go package path for {package_name}: {e}")
354 |         return None
355 | 
356 | def _get_php_package_path(package_name: str) -> Optional[str]:
357 |     try:
358 |         debug_log(f"Getting local path for PHP package: {package_name}")
359 |         
360 |         local_vendor = Path("./vendor") / package_name
361 |         if local_vendor.exists() and local_vendor.is_dir():
362 |             return str(local_vendor.resolve())
363 |         
364 |         current_dir = Path.cwd()
365 |         for parent in [current_dir] + list(current_dir.parents):
366 |             vendor_path = parent / "vendor" / package_name
367 |             if vendor_path.exists() and vendor_path.is_dir():
368 |                 return str(vendor_path.resolve())
369 |             
370 |             if (parent / "composer.json").exists():
371 |                 break
372 |         
373 |         composer_home = Path.home() / ".composer" / "vendor" / package_name
374 |         if composer_home.exists() and composer_home.is_dir():
375 |             return str(composer_home.resolve())
376 |         
377 |         composer_global = Path.home() / ".config" / "composer" / "vendor" / package_name
378 |         if composer_global.exists() and composer_global.is_dir():
379 |             return str(composer_global.resolve())
380 |         
381 |         return None
382 |     except Exception as e:
383 |         debug_log(f"Error getting PHP package path for {package_name}: {e}")
384 |         return None
385 | 
386 | 
387 | def get_local_package_path(package_name: str, language: str) -> Optional[str]:
388 |     """
389 |     Dispatches to the correct package path finder based on the language.
390 |     """
391 |     finders = {
392 |         "python": _get_python_package_path,
393 |         "javascript": _get_npm_package_path,
394 |         "typescript": _get_typescript_package_path,
395 |         "java": _get_java_package_path,
396 |         "c": _get_c_package_path,
397 |         "go": _get_go_package_path,  
398 |         "ruby": _get_ruby_package_path,
399 |         "php": _get_php_package_path,
400 |         "cpp": _get_cpp_package_path,
401 | 
402 |     }
403 |     finder = finders.get(language)
404 |     if finder:
405 |         return finder(package_name)
406 |     return None
407 | 
408 | def _get_cpp_package_path(package_name: str) -> Optional[str]:
409 |     """
410 |     C++ package ka local path find karta hai.
411 |     Pehle pkg-config try karta hai, fir common system paths check karta hai.
412 |     """
413 |     import subprocess
414 |     import os
415 | 
416 |     # Try pkg-config
417 |     try:
418 |         result = subprocess.run(
419 |             ["pkg-config", "--variable=includedir", package_name],
420 |             capture_output=True,
421 |             text=True,
422 |             check=False
423 |         )
424 |         path = result.stdout.strip()
425 |         if path and os.path.exists(path):
426 |             return path
427 |     except FileNotFoundError:
428 |         pass
429 | 
430 |     # Common system include/lib folders
431 |     common_paths = [
432 |         f"/usr/include/{package_name}",
433 |         f"/usr/local/include/{package_name}",
434 |         f"/usr/lib/{package_name}",
435 |         f"/usr/local/lib/{package_name}",
436 |     ]
437 |     for path in common_paths:
438 |         if os.path.exists(path):
439 |             return path
440 | 
441 |     return None
442 | 
443 | 
```

--------------------------------------------------------------------------------
/src/codegraphcontext/tools/languages/go.py:
--------------------------------------------------------------------------------

```python
  1 | from pathlib import Path
  2 | from typing import Any, Dict, Optional, Tuple
  3 | from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
  4 | 
  5 | 
  6 | GO_QUERIES = {
  7 |     "functions": """
  8 |         (function_declaration
  9 |             name: (identifier) @name
 10 |             parameters: (parameter_list) @params
 11 |         ) @function_node
 12 |         
 13 |         (method_declaration
 14 |             receiver: (parameter_list) @receiver
 15 |             name: (field_identifier) @name
 16 |             parameters: (parameter_list) @params
 17 |         ) @function_node
 18 |     """,
 19 |     "structs": """
 20 |         (type_declaration
 21 |             (type_spec
 22 |                 name: (type_identifier) @name
 23 |                 type: (struct_type) @struct_body
 24 |             )
 25 |         ) @struct_node
 26 |     """,
 27 |     "interfaces": """
 28 |         (type_declaration
 29 |             (type_spec
 30 |                 name: (type_identifier) @name
 31 |                 type: (interface_type) @interface_body
 32 |             )
 33 |         ) @interface_node
 34 |     """,
 35 |     "imports": """
 36 |         (import_declaration
 37 |             (import_spec
 38 |                 path: (interpreted_string_literal) @path
 39 |             )
 40 |         ) @import
 41 |         
 42 |         (import_declaration
 43 |             (import_spec
 44 |                 name: (package_identifier) @alias
 45 |                 path: (interpreted_string_literal) @path
 46 |             )
 47 |         ) @import_alias
 48 |     """,
 49 |     "calls": """
 50 |         (call_expression
 51 |             function: (identifier) @name
 52 |         )
 53 |         (call_expression
 54 |             function: (selector_expression
 55 |                 field: (field_identifier) @name
 56 |             )
 57 |         )
 58 |     """,
 59 |     "variables": """
 60 |         (var_declaration
 61 |             (var_spec
 62 |                 name: (identifier) @name
 63 |             )
 64 |         )
 65 |         (short_var_declaration
 66 |             left: (expression_list
 67 |                 (identifier) @name
 68 |             )
 69 |         )
 70 |     """,
 71 | }
 72 | 
 73 | class GoTreeSitterParser:
 74 |     """A Go-specific parser using tree-sitter, encapsulating language-specific logic."""
 75 | 
 76 |     def __init__(self, generic_parser_wrapper):
 77 |         self.generic_parser_wrapper = generic_parser_wrapper
 78 |         self.language_name = generic_parser_wrapper.language_name
 79 |         self.language = generic_parser_wrapper.language
 80 |         self.parser = generic_parser_wrapper.parser
 81 | 
 82 |         self.queries = {
 83 |             name: self.language.query(query_str)
 84 |             for name, query_str in GO_QUERIES.items()
 85 |         }
 86 | 
 87 |     def _get_node_text(self, node) -> str:
 88 |         return node.text.decode('utf-8')
 89 | 
 90 |     def _get_parent_context(self, node, types=('function_declaration', 'method_declaration', 'type_declaration')):
 91 |         curr = node.parent
 92 |         while curr:
 93 |             if curr.type in types:
 94 |                 if curr.type == 'type_declaration':
 95 |                     type_spec = curr.child_by_field_name('type_spec')
 96 |                     if type_spec:
 97 |                         name_node = type_spec.child_by_field_name('name')
 98 |                         return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
 99 |                 else:
100 |                     name_node = curr.child_by_field_name('name')
101 |                     return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
102 |             curr = curr.parent
103 |         return None, None, None
104 | 
105 |     def _calculate_complexity(self, node):
106 |         complexity_nodes = {
107 |             "if_statement", "for_statement", "switch_statement", "case_clause",
108 |             "expression_switch_statement", "type_switch_statement",
109 |             "binary_expression", "call_expression"
110 |         }
111 |         count = 1
112 | 
113 |         def traverse(n):
114 |             nonlocal count
115 |             if n.type in complexity_nodes:
116 |                 count += 1
117 |             for child in n.children:
118 |                 traverse(child)
119 | 
120 |         traverse(node)
121 |         return count
122 | 
123 |     def _get_docstring(self, func_node):
124 |         """Extract Go doc comment preceding the function."""
125 |         prev_sibling = func_node.prev_sibling
126 |         while prev_sibling and prev_sibling.type in ('comment', '\n', ' '):
127 |             if prev_sibling.type == 'comment':
128 |                 comment_text = self._get_node_text(prev_sibling)
129 |                 if comment_text.startswith('//'):
130 |                     return comment_text.strip()
131 |             prev_sibling = prev_sibling.prev_sibling
132 |         return None
133 | 
134 |     def parse(self, file_path: Path, is_dependency: bool = False) -> Dict:
135 |         """Parses a file and returns its structure in a standardized dictionary format."""
136 |         # This method orchestrates the parsing of a single file.
137 |         # It calls specialized `_find_*` methods for each language construct.
138 |         # The returned dictionary should map a specific key (e.g., 'functions', 'interfaces')
139 |         # to a list of dictionaries, where each dictionary represents a single code construct.
140 |         # The GraphBuilder will then use these keys to create nodes with corresponding labels.
141 |         with open(file_path, "r", encoding="utf-8") as f:
142 |             source_code = f.read()
143 | 
144 |         tree = self.parser.parse(bytes(source_code, "utf8"))
145 |         root_node = tree.root_node
146 | 
147 |         functions = self._find_functions(root_node)
148 |         structs = self._find_structs(root_node)
149 |         interfaces = self._find_interfaces(root_node)
150 |         imports = self._find_imports(root_node)
151 |         function_calls = self._find_calls(root_node)
152 |         variables = self._find_variables(root_node)
153 | 
154 |         return {
155 |             "file_path": str(file_path),
156 |             "functions": functions,
157 |             "classes": structs,
158 |             "interfaces": interfaces,
159 |             "variables": variables,
160 |             "imports": imports,
161 |             "function_calls": function_calls,
162 |             "is_dependency": is_dependency,
163 |             "lang": self.language_name,
164 |         }
165 | 
166 |     def _find_functions(self, root_node):
167 |         functions = []
168 |         query = self.queries['functions']
169 | 
170 |         captures_by_function = {}
171 | 
172 |         for node, capture_name in query.captures(root_node):
173 |             if capture_name == 'function_node':
174 |                 func_id = id(node)
175 |                 if func_id not in captures_by_function:
176 |                     captures_by_function[func_id] = {
177 |                         'node': node,
178 |                         'name': None,
179 |                         'params': None,
180 |                         'receiver': None
181 |                     }
182 |             elif capture_name == 'name':
183 |                 func_node = self._find_function_node_for_name(node)
184 |                 if func_node:
185 |                     func_id = id(func_node)
186 |                     if func_id not in captures_by_function:
187 |                         captures_by_function[func_id] = {
188 |                             'node': func_node,
189 |                             'name': None,
190 |                             'params': None,
191 |                             'receiver': None
192 |                         }
193 |                     captures_by_function[func_id]['name'] = self._get_node_text(node)
194 |             elif capture_name == 'params':
195 |                 func_node = self._find_function_node_for_params(node)
196 |                 if func_node:
197 |                     func_id = id(func_node)
198 |                     if func_id not in captures_by_function:
199 |                         captures_by_function[func_id] = {
200 |                             'node': func_node,
201 |                             'name': None,
202 |                             'params': None,
203 |                             'receiver': None
204 |                         }
205 |                     captures_by_function[func_id]['params'] = node
206 |             elif capture_name == 'receiver':
207 |                 func_node = node.parent
208 |                 if func_node and func_node.type == 'method_declaration':
209 |                     func_id = id(func_node)
210 |                     if func_id not in captures_by_function:
211 |                         captures_by_function[func_id] = {
212 |                             'node': func_node,
213 |                             'name': None,
214 |                             'params': None,
215 |                             'receiver': None
216 |                         }
217 |                     captures_by_function[func_id]['receiver'] = node
218 | 
219 |         for func_id, data in captures_by_function.items():
220 |             if data['name']:
221 |                 func_node = data['node']
222 |                 name = data['name']
223 | 
224 |                 args = []
225 |                 if data['params']:
226 |                     args = self._extract_parameters(data['params'])
227 | 
228 |                 receiver_type = None
229 |                 if data['receiver']:
230 |                     receiver_type = self._extract_receiver(data['receiver'])
231 | 
232 |                 context, context_type, context_line = self._get_parent_context(func_node)
233 |                 class_context = receiver_type or (context if context_type == 'type_declaration' else None)
234 | 
235 |                 docstring = self._get_docstring(func_node)
236 | 
237 |                 func_data = {
238 |                     "name": name,
239 |                     "line_number": func_node.start_point[0] + 1,
240 |                     "end_line": func_node.end_point[0] + 1,
241 |                     "args": args,
242 |                     "source": self._get_node_text(func_node),
243 |                     "source_code": self._get_node_text(func_node),
244 |                     "docstring": docstring,
245 |                     "cyclomatic_complexity": self._calculate_complexity(func_node),
246 |                     "context": context,
247 |                     "context_type": context_type,
248 |                     "class_context": class_context,
249 |                     "decorators": [],
250 |                     "lang": self.language_name,
251 |                     "is_dependency": False,
252 |                 }
253 |                 functions.append(func_data)
254 | 
255 |         return functions
256 | 
257 |     def _find_function_node_for_name(self, name_node):
258 |         current = name_node.parent
259 |         while current:
260 |             if current.type in ('function_declaration', 'method_declaration'):
261 |                 return current
262 |             current = current.parent
263 |         return None
264 | 
265 |     def _find_function_node_for_params(self, params_node):
266 |         current = params_node.parent
267 |         while current:
268 |             if current.type in ('function_declaration', 'method_declaration'):
269 |                 return current
270 |             current = current.parent
271 |         return None
272 | 
273 |     def _extract_parameters(self, params_node):
274 |         params = []
275 |         if params_node.type == 'parameter_list':
276 |             for child in params_node.children:
277 |                 if child.type == 'parameter_declaration':
278 |                     name_node = child.child_by_field_name('name')
279 |                     if name_node:
280 |                         params.append(self._get_node_text(name_node))
281 |                 elif child.type == 'variadic_parameter_declaration':
282 |                     name_node = child.child_by_field_name('name')
283 |                     if name_node:
284 |                         params.append(f"...{self._get_node_text(name_node)}")
285 |         return params
286 | 
287 |     def _extract_receiver(self, receiver_node):
288 |         if receiver_node.type == 'parameter_list' and receiver_node.named_child_count > 0:
289 |             param = receiver_node.named_child(0)
290 |             type_node = param.child_by_field_name('type')
291 |             if type_node:
292 |                 type_text = self._get_node_text(type_node)
293 |                 return type_text.strip('*')
294 |         return None
295 | 
296 |     def _find_structs(self, root_node):
297 |         structs = []
298 |         struct_query = self.queries['structs']
299 |         for node, capture_name in struct_query.captures(root_node):
300 |             if capture_name == 'name':
301 |                 struct_node = self._find_type_declaration_for_name(node)
302 |                 if struct_node:
303 |                     name = self._get_node_text(node)
304 |                     class_data = {
305 |                         "name": name,
306 |                         "line_number": struct_node.start_point[0] + 1,
307 |                         "end_line": struct_node.end_point[0] + 1,
308 |                         "bases": [],
309 |                         "source": self._get_node_text(struct_node),
310 |                         "docstring": self._get_docstring(struct_node),
311 |                         "context": None,
312 |                         "decorators": [],
313 |                         "lang": self.language_name,
314 |                         "is_dependency": False,
315 |                     }
316 |                     structs.append(class_data)
317 |         return structs
318 | 
319 |     def _find_interfaces(self, root_node):
320 |         interfaces = []
321 |         interface_query = self.queries['interfaces']
322 |         for node, capture_name in interface_query.captures(root_node):
323 |             if capture_name == 'name':
324 |                 interface_node = self._find_type_declaration_for_name(node)
325 |                 if interface_node:
326 |                     name = self._get_node_text(node)
327 |                     class_data = {
328 |                         "name": name,
329 |                         "line_number": interface_node.start_point[0] + 1,
330 |                         "end_line": interface_node.end_point[0] + 1,
331 |                         "bases": [],
332 |                         "source": self._get_node_text(interface_node),
333 |                         "docstring": self._get_docstring(interface_node),
334 |                         "context": None,
335 |                         "decorators": [],
336 |                         "lang": self.language_name,
337 |                         "is_dependency": False,
338 |                     }
339 |                     interfaces.append(class_data)
340 |         return interfaces
341 | 
342 |     def _find_type_declaration_for_name(self, name_node):
343 |         current = name_node.parent
344 |         while current:
345 |             if current.type == 'type_declaration':
346 |                 return current
347 |             current = current.parent
348 |         return None
349 | 
350 |     def _find_imports(self, root_node):
351 |         imports = []
352 |         query = self.queries['imports']
353 |         
354 |         for node, capture_name in query.captures(root_node):
355 |             line_number = node.start_point[0] + 1
356 |             
357 |             if capture_name == 'path':
358 |                 path_text = self._get_node_text(node).strip('"')
359 |                 package_name = path_text.split('/')[-1]
360 |                 
361 |                 alias = None
362 |                 import_spec = node.parent
363 |                 if import_spec and import_spec.type == 'import_spec':
364 |                     alias_node = import_spec.child_by_field_name('name')
365 |                     if alias_node:
366 |                         alias = self._get_node_text(alias_node)
367 |                 
368 |                 imports.append({
369 |                     'name': package_name,
370 |                     'source': path_text,
371 |                     'alias': alias,
372 |                     'line_number': line_number,
373 |                     'lang': self.language_name
374 |                 })
375 | 
376 |         return imports
377 | 
378 |     def _find_calls(self, root_node):
379 |         calls = []
380 |         query = self.queries['calls']
381 |         
382 |         for node, capture_name in query.captures(root_node):
383 |             if capture_name == 'name':
384 |                 call_node = node.parent
385 |                 while call_node and call_node.type != 'call_expression':
386 |                     call_node = call_node.parent
387 |                 
388 |                 if call_node:
389 |                     name = self._get_node_text(node)
390 |                     
391 |                     call_data = {
392 |                         "name": name,
393 |                         "full_name": self._get_node_text(call_node.child_by_field_name('function')) if call_node.child_by_field_name('function') else name,
394 |                         "line_number": node.start_point[0] + 1,
395 |                         "args": [],
396 |                         "inferred_obj_type": None,
397 |                         "context": None,
398 |                         "class_context": None,
399 |                         "lang": self.language_name,
400 |                         "is_dependency": False,
401 |                     }
402 |                     calls.append(call_data)
403 |         
404 |         return calls
405 | 
406 |     def _find_variables(self, root_node):
407 |         variables = []
408 |         query = self.queries['variables']
409 |         
410 |         for node, capture_name in query.captures(root_node):
411 |             if capture_name == 'name':
412 |                 name = self._get_node_text(node)
413 |                 
414 |                 variable_data = {
415 |                     "name": name,
416 |                     "line_number": node.start_point[0] + 1,
417 |                     "value": None,
418 |                     "type": None,
419 |                     "context": None,
420 |                     "class_context": None,
421 |                     "lang": self.language_name,
422 |                     "is_dependency": False,
423 |                 }
424 |                 variables.append(variable_data)
425 |         
426 |         return variables
427 | 
428 | def pre_scan_go(files: list[Path], parser_wrapper) -> dict:
429 |     """Scans Go files to create a map of function/struct names to their file paths."""
430 |     imports_map = {}
431 |     query_str = """
432 |         (function_declaration name: (identifier) @name)
433 |         (method_declaration name: (field_identifier) @name)
434 |         (type_declaration (type_spec name: (type_identifier) @name))
435 |     """
436 |     query = parser_wrapper.language.query(query_str)
437 | 
438 |     for file_path in files:
439 |         try:
440 |             with open(file_path, "r", encoding="utf-8") as f:
441 |                 tree = parser_wrapper.parser.parse(bytes(f.read(), "utf8"))
442 | 
443 |             for capture, _ in query.captures(tree.root_node):
444 |                 name = capture.text.decode('utf-8')
445 |                 if name not in imports_map:
446 |                     imports_map[name] = []
447 |                 imports_map[name].append(str(file_path.resolve()))
448 |         except Exception as e:
449 |             warning_logger(f"Tree-sitter pre-scan failed for {file_path}: {e}")
450 |     
451 |     return imports_map
```

--------------------------------------------------------------------------------
/tests/sample_project_typescript/src/utilities-helpers.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Utilities and Helpers
  3 |  * Demonstrates common utility functions, type helpers, and patterns
  4 |  * used in TypeScript projects for enhanced development experience
  5 |  */
  6 | 
  7 | // ========== String Utilities ==========
  8 | export const StringUtils = {
  9 |   /**
 10 |    * Capitalizes the first letter of a string
 11 |    */
 12 |   capitalize: (str: string): string => 
 13 |     str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(),
 14 | 
 15 |   /**
 16 |    * Converts string to camelCase
 17 |    */
 18 |   camelCase: (str: string): string =>
 19 |     str.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : '')),
 20 | 
 21 |   /**
 22 |    * Converts string to kebab-case
 23 |    */
 24 |   kebabCase: (str: string): string =>
 25 |     str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`).replace(/^-/, ''),
 26 | 
 27 |   /**
 28 |    * Converts string to snake_case
 29 |    */
 30 |   snakeCase: (str: string): string =>
 31 |     str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`).replace(/^_/, ''),
 32 | 
 33 |   /**
 34 |    * Truncates a string to specified length with ellipsis
 35 |    */
 36 |   truncate: (str: string, length: number, suffix: string = '...'): string =>
 37 |     str.length <= length ? str : str.slice(0, length) + suffix,
 38 | 
 39 |   /**
 40 |    * Removes extra whitespace and trims
 41 |    */
 42 |   normalize: (str: string): string =>
 43 |     str.replace(/\s+/g, ' ').trim(),
 44 | 
 45 |   /**
 46 |    * Pluralizes a word (simple English rules)
 47 |    */
 48 |   pluralize: (word: string, count: number = 2): string => {
 49 |     if (count === 1) return word;
 50 |     if (word.endsWith('y')) return word.slice(0, -1) + 'ies';
 51 |     if (word.endsWith('s') || word.endsWith('x') || word.endsWith('ch') || word.endsWith('sh')) {
 52 |       return word + 'es';
 53 |     }
 54 |     return word + 's';
 55 |   }
 56 | };
 57 | 
 58 | // ========== Array Utilities ==========
 59 | export const ArrayUtils = {
 60 |   /**
 61 |    * Chunks array into smaller arrays of specified size
 62 |    */
 63 |   chunk: <T>(array: T[], size: number): T[][] => {
 64 |     const chunks: T[][] = [];
 65 |     for (let i = 0; i < array.length; i += size) {
 66 |       chunks.push(array.slice(i, i + size));
 67 |     }
 68 |     return chunks;
 69 |   },
 70 | 
 71 |   /**
 72 |    * Removes duplicate values from array
 73 |    */
 74 |   unique: <T>(array: T[]): T[] => [...new Set(array)],
 75 | 
 76 |   /**
 77 |    * Groups array items by a key function
 78 |    */
 79 |   groupBy: <T, K extends string | number | symbol>(
 80 |     array: T[],
 81 |     keyFn: (item: T) => K
 82 |   ): Record<K, T[]> => {
 83 |     return array.reduce((groups, item) => {
 84 |       const key = keyFn(item);
 85 |       groups[key] = groups[key] || [];
 86 |       groups[key]!.push(item);
 87 |       return groups;
 88 |     }, {} as Record<K, T[]>);
 89 |   },
 90 | 
 91 |   /**
 92 |    * Flattens nested arrays by one level
 93 |    */
 94 |   flatten: <T>(array: (T | T[])[]): T[] => array.flat() as T[],
 95 | 
 96 |   /**
 97 |    * Deeply flattens nested arrays
 98 |    */
 99 |   flattenDeep: <T>(array: any[]): T[] => {
100 |     return array.reduce((acc, val) => 
101 |       Array.isArray(val) ? acc.concat(ArrayUtils.flattenDeep(val)) : acc.concat(val), []
102 |     );
103 |   },
104 | 
105 |   /**
106 |    * Shuffles array elements randomly
107 |    */
108 |   shuffle: <T>(array: T[]): T[] => {
109 |     const result = [...array];
110 |     for (let i = result.length - 1; i > 0; i--) {
111 |       const j = Math.floor(Math.random() * (i + 1));
112 |       [result[i], result[j]] = [result[j]!, result[i]!];
113 |     }
114 |     return result;
115 |   },
116 | 
117 |   /**
118 |    * Returns random element from array
119 |    */
120 |   sample: <T>(array: T[]): T | undefined => {
121 |     return array[Math.floor(Math.random() * array.length)];
122 |   },
123 | 
124 |   /**
125 |    * Returns multiple random elements from array
126 |    */
127 |   sampleSize: <T>(array: T[], n: number): T[] => {
128 |     const shuffled = ArrayUtils.shuffle(array);
129 |     return shuffled.slice(0, Math.min(n, array.length));
130 |   }
131 | };
132 | 
133 | // ========== Object Utilities ==========
134 | export const ObjectUtils = {
135 |   /**
136 |    * Deep clones an object
137 |    */
138 |   deepClone: <T>(obj: T): T => {
139 |     if (obj === null || typeof obj !== 'object') return obj;
140 |     if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T;
141 |     if (obj instanceof Array) return obj.map(item => ObjectUtils.deepClone(item)) as unknown as T;
142 |     if (typeof obj === 'object') {
143 |       const copy = {} as T;
144 |       Object.keys(obj).forEach(key => {
145 |         (copy as any)[key] = ObjectUtils.deepClone((obj as any)[key]);
146 |       });
147 |       return copy;
148 |     }
149 |     return obj;
150 |   },
151 | 
152 |   /**
153 |    * Merges objects deeply
154 |    */
155 |   deepMerge: <T extends Record<string, any>, U extends Record<string, any>>(
156 |     target: T,
157 |     source: U
158 |   ): T & U => {
159 |     const result = { ...target } as T & U;
160 |     
161 |     Object.keys(source).forEach(key => {
162 |       if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
163 |         if (result[key as keyof (T & U)] && typeof result[key as keyof (T & U)] === 'object') {
164 |           (result as any)[key] = ObjectUtils.deepMerge(
165 |             result[key as keyof (T & U)] as any,
166 |             source[key]
167 |           );
168 |         } else {
169 |           (result as any)[key] = ObjectUtils.deepClone(source[key]);
170 |         }
171 |       } else {
172 |         (result as any)[key] = source[key];
173 |       }
174 |     });
175 |     
176 |     return result;
177 |   },
178 | 
179 |   /**
180 |    * Picks specified keys from object
181 |    */
182 |   pick: <T extends Record<string, any>, K extends keyof T>(
183 |     obj: T,
184 |     keys: K[]
185 |   ): Pick<T, K> => {
186 |     const result = {} as Pick<T, K>;
187 |     keys.forEach(key => {
188 |       if (key in obj) {
189 |         result[key] = obj[key];
190 |       }
191 |     });
192 |     return result;
193 |   },
194 | 
195 |   /**
196 |    * Omits specified keys from object
197 |    */
198 |   omit: <T extends Record<string, any>, K extends keyof T>(
199 |     obj: T,
200 |     keys: K[]
201 |   ): Omit<T, K> => {
202 |     const result = { ...obj };
203 |     keys.forEach(key => {
204 |       delete result[key];
205 |     });
206 |     return result as Omit<T, K>;
207 |   },
208 | 
209 |   /**
210 |    * Gets nested value from object using dot notation
211 |    */
212 |   get: <T>(obj: any, path: string, defaultValue?: T): T | undefined => {
213 |     const keys = path.split('.');
214 |     let result = obj;
215 |     
216 |     for (const key of keys) {
217 |       if (result == null || typeof result !== 'object') {
218 |         return defaultValue;
219 |       }
220 |       result = result[key];
221 |     }
222 |     
223 |     return result !== undefined ? result : defaultValue;
224 |   },
225 | 
226 |   /**
227 |    * Sets nested value in object using dot notation
228 |    */
229 |   set: (obj: any, path: string, value: any): void => {
230 |     const keys = path.split('.');
231 |     const lastKey = keys.pop()!;
232 |     let current = obj;
233 |     
234 |     for (const key of keys) {
235 |       if (!(key in current) || typeof current[key] !== 'object') {
236 |         current[key] = {};
237 |       }
238 |       current = current[key];
239 |     }
240 |     
241 |     current[lastKey] = value;
242 |   },
243 | 
244 |   /**
245 |    * Checks if object has nested property
246 |    */
247 |   has: (obj: any, path: string): boolean => {
248 |     const keys = path.split('.');
249 |     let current = obj;
250 |     
251 |     for (const key of keys) {
252 |       if (current == null || typeof current !== 'object' || !(key in current)) {
253 |         return false;
254 |       }
255 |       current = current[key];
256 |     }
257 |     
258 |     return true;
259 |   }
260 | };
261 | 
262 | // ========== Function Utilities ==========
263 | export const FunctionUtils = {
264 |   /**
265 |    * Debounces function execution
266 |    */
267 |   debounce: <T extends (...args: any[]) => any>(
268 |     fn: T,
269 |     delay: number
270 |   ): ((...args: Parameters<T>) => void) => {
271 |     let timeoutId: NodeJS.Timeout;
272 |     return (...args: Parameters<T>) => {
273 |       clearTimeout(timeoutId);
274 |       timeoutId = setTimeout(() => fn(...args), delay);
275 |     };
276 |   },
277 | 
278 |   /**
279 |    * Throttles function execution
280 |    */
281 |   throttle: <T extends (...args: any[]) => any>(
282 |     fn: T,
283 |     limit: number
284 |   ): ((...args: Parameters<T>) => void) => {
285 |     let inThrottle: boolean;
286 |     return (...args: Parameters<T>) => {
287 |       if (!inThrottle) {
288 |         fn(...args);
289 |         inThrottle = true;
290 |         setTimeout(() => (inThrottle = false), limit);
291 |       }
292 |     };
293 |   },
294 | 
295 |   /**
296 |    * Memoizes function results
297 |    */
298 |   memoize: <T extends (...args: any[]) => any>(fn: T): T => {
299 |     const cache = new Map();
300 |     return ((...args: any[]) => {
301 |       const key = JSON.stringify(args);
302 |       if (cache.has(key)) {
303 |         return cache.get(key);
304 |       }
305 |       const result = fn(...args);
306 |       cache.set(key, result);
307 |       return result;
308 |     }) as T;
309 |   },
310 | 
311 |   /**
312 |    * Creates a curried version of function
313 |    */
314 |   curry: <T extends (...args: any[]) => any>(
315 |     fn: T,
316 |     arity: number = fn.length
317 |   ): any => {
318 |     return (...args: any[]) => {
319 |       if (args.length >= arity) {
320 |         return fn(...args);
321 |       }
322 |       return FunctionUtils.curry(fn.bind(null, ...args), arity - args.length);
323 |     };
324 |   },
325 | 
326 |   /**
327 |    * Composes functions from right to left
328 |    */
329 |   compose: <T>(...fns: Function[]): (arg: T) => any => {
330 |     return (arg: T) => fns.reduceRight((result, fn) => fn(result), arg);
331 |   },
332 | 
333 |   /**
334 |    * Pipes functions from left to right
335 |    */
336 |   pipe: <T>(...fns: Function[]): (arg: T) => any => {
337 |     return (arg: T) => fns.reduce((result, fn) => fn(result), arg);
338 |   }
339 | };
340 | 
341 | // ========== Date Utilities ==========
342 | export const DateUtils = {
343 |   /**
344 |    * Formats date to ISO string with timezone
345 |    */
346 |   toISOString: (date: Date): string => date.toISOString(),
347 | 
348 |   /**
349 |    * Formats date to readable string
350 |    */
351 |   format: (date: Date, locale: string = 'en-US'): string => 
352 |     date.toLocaleDateString(locale),
353 | 
354 |   /**
355 |    * Gets difference between dates in various units
356 |    */
357 |   diff: (date1: Date, date2: Date, unit: 'days' | 'hours' | 'minutes' | 'seconds' = 'days'): number => {
358 |     const diffMs = Math.abs(date1.getTime() - date2.getTime());
359 |     switch (unit) {
360 |       case 'seconds': return Math.floor(diffMs / 1000);
361 |       case 'minutes': return Math.floor(diffMs / (1000 * 60));
362 |       case 'hours': return Math.floor(diffMs / (1000 * 60 * 60));
363 |       case 'days': return Math.floor(diffMs / (1000 * 60 * 60 * 24));
364 |     }
365 |   },
366 | 
367 |   /**
368 |    * Adds time to date
369 |    */
370 |   add: (date: Date, amount: number, unit: 'days' | 'hours' | 'minutes' | 'seconds'): Date => {
371 |     const result = new Date(date);
372 |     switch (unit) {
373 |       case 'seconds': result.setSeconds(result.getSeconds() + amount); break;
374 |       case 'minutes': result.setMinutes(result.getMinutes() + amount); break;
375 |       case 'hours': result.setHours(result.getHours() + amount); break;
376 |       case 'days': result.setDate(result.getDate() + amount); break;
377 |     }
378 |     return result;
379 |   },
380 | 
381 |   /**
382 |    * Checks if date is between two dates
383 |    */
384 |   isBetween: (date: Date, start: Date, end: Date): boolean =>
385 |     date >= start && date <= end,
386 | 
387 |   /**
388 |    * Gets start of day
389 |    */
390 |   startOfDay: (date: Date): Date => {
391 |     const result = new Date(date);
392 |     result.setHours(0, 0, 0, 0);
393 |     return result;
394 |   },
395 | 
396 |   /**
397 |    * Gets end of day
398 |    */
399 |   endOfDay: (date: Date): Date => {
400 |     const result = new Date(date);
401 |     result.setHours(23, 59, 59, 999);
402 |     return result;
403 |   }
404 | };
405 | 
406 | // ========== Number Utilities ==========
407 | export const NumberUtils = {
408 |   /**
409 |    * Clamps number between min and max
410 |    */
411 |   clamp: (value: number, min: number, max: number): number =>
412 |     Math.min(Math.max(value, min), max),
413 | 
414 |   /**
415 |    * Rounds to specified decimal places
416 |    */
417 |   round: (value: number, decimals: number = 0): number =>
418 |     Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals),
419 | 
420 |   /**
421 |    * Generates random number between min and max
422 |    */
423 |   random: (min: number, max: number): number =>
424 |     Math.random() * (max - min) + min,
425 | 
426 |   /**
427 |    * Generates random integer between min and max (inclusive)
428 |    */
429 |   randomInt: (min: number, max: number): number =>
430 |     Math.floor(Math.random() * (max - min + 1)) + min,
431 | 
432 |   /**
433 |    * Checks if number is in range
434 |    */
435 |   inRange: (value: number, min: number, max: number): boolean =>
436 |     value >= min && value <= max,
437 | 
438 |   /**
439 |    * Converts number to percentage string
440 |    */
441 |   toPercent: (value: number, decimals: number = 2): string =>
442 |     `${NumberUtils.round(value * 100, decimals)}%`,
443 | 
444 |   /**
445 |    * Formats number with thousands separators
446 |    */
447 |   format: (value: number, locale: string = 'en-US'): string =>
448 |     value.toLocaleString(locale)
449 | };
450 | 
451 | // ========== Type Utilities ==========
452 | export type DeepPartial<T> = {
453 |   [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
454 | };
455 | 
456 | export type DeepRequired<T> = {
457 |   [P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P];
458 | };
459 | 
460 | export type KeysOfType<T, U> = {
461 |   [K in keyof T]: T[K] extends U ? K : never;
462 | }[keyof T];
463 | 
464 | export type Writeable<T> = {
465 |   -readonly [P in keyof T]: T[P];
466 | };
467 | 
468 | export type OptionalExcept<T, K extends keyof T> = Partial<T> & Pick<T, K>;
469 | 
470 | export type RequiredExcept<T, K extends keyof T> = Required<Omit<T, K>> & Partial<Pick<T, K>>;
471 | 
472 | // ========== Validation Helpers ==========
473 | export const ValidationHelpers = {
474 |   /**
475 |    * Email validation
476 |    */
477 |   isEmail: (value: string): boolean =>
478 |     /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
479 | 
480 |   /**
481 |    * URL validation
482 |    */
483 |   isUrl: (value: string): boolean => {
484 |     try {
485 |       new URL(value);
486 |       return true;
487 |     } catch {
488 |       return false;
489 |     }
490 |   },
491 | 
492 |   /**
493 |    * UUID validation
494 |    */
495 |   isUuid: (value: string): boolean =>
496 |     /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value),
497 | 
498 |   /**
499 |    * Credit card number validation (Luhn algorithm)
500 |    */
501 |   isCreditCard: (value: string): boolean => {
502 |     const num = value.replace(/\D/g, '');
503 |     if (num.length < 13 || num.length > 19) return false;
504 |     
505 |     let sum = 0;
506 |     let isEven = false;
507 |     
508 |     for (let i = num.length - 1; i >= 0; i--) {
509 |       let digit = parseInt(num[i]!);
510 |       
511 |       if (isEven) {
512 |         digit *= 2;
513 |         if (digit > 9) digit -= 9;
514 |       }
515 |       
516 |       sum += digit;
517 |       isEven = !isEven;
518 |     }
519 |     
520 |     return sum % 10 === 0;
521 |   },
522 | 
523 |   /**
524 |    * Strong password validation
525 |    */
526 |   isStrongPassword: (value: string): boolean => {
527 |     const minLength = value.length >= 8;
528 |     const hasLower = /[a-z]/.test(value);
529 |     const hasUpper = /[A-Z]/.test(value);
530 |     const hasNumber = /\d/.test(value);
531 |     const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(value);
532 |     
533 |     return minLength && hasLower && hasUpper && hasNumber && hasSpecial;
534 |   }
535 | };
536 | 
537 | // ========== Color Utilities ==========
538 | export const ColorUtils = {
539 |   /**
540 |    * Converts hex to RGB
541 |    */
542 |   hexToRgb: (hex: string): { r: number; g: number; b: number } | null => {
543 |     const match = hex.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);
544 |     return match ? {
545 |       r: parseInt(match[1]!, 16),
546 |       g: parseInt(match[2]!, 16),
547 |       b: parseInt(match[3]!, 16)
548 |     } : null;
549 |   },
550 | 
551 |   /**
552 |    * Converts RGB to hex
553 |    */
554 |   rgbToHex: (r: number, g: number, b: number): string => {
555 |     const componentToHex = (c: number) => {
556 |       const hex = c.toString(16);
557 |       return hex.length === 1 ? '0' + hex : hex;
558 |     };
559 |     return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`;
560 |   },
561 | 
562 |   /**
563 |    * Lightens a color by percentage
564 |    */
565 |   lighten: (hex: string, percent: number): string => {
566 |     const rgb = ColorUtils.hexToRgb(hex);
567 |     if (!rgb) return hex;
568 |     
569 |     const factor = 1 + percent / 100;
570 |     return ColorUtils.rgbToHex(
571 |       Math.min(255, Math.round(rgb.r * factor)),
572 |       Math.min(255, Math.round(rgb.g * factor)),
573 |       Math.min(255, Math.round(rgb.b * factor))
574 |     );
575 |   }
576 | };
577 | 
578 | // ========== Performance Utilities ==========
579 | export const PerformanceUtils = {
580 |   /**
581 |    * Measures execution time of a function
582 |    */
583 |   measure: async <T>(fn: () => T | Promise<T>): Promise<{ result: T; duration: number }> => {
584 |     const start = performance.now();
585 |     const result = await fn();
586 |     const end = performance.now();
587 |     return { result, duration: end - start };
588 |   },
589 | 
590 |   /**
591 |    * Creates a performance timer
592 |    */
593 |   timer: () => {
594 |     const start = performance.now();
595 |     return {
596 |       stop: () => performance.now() - start,
597 |       lap: () => {
598 |         const current = performance.now();
599 |         return current - start;
600 |       }
601 |     };
602 |   },
603 | 
604 |   /**
605 |    * Batches synchronous operations
606 |    */
607 |   batch: <T, R>(
608 |     items: T[],
609 |     processor: (batch: T[]) => R[],
610 |     batchSize: number = 100
611 |   ): R[] => {
612 |     const results: R[] = [];
613 |     for (let i = 0; i < items.length; i += batchSize) {
614 |       const batch = items.slice(i, i + batchSize);
615 |       results.push(...processor(batch));
616 |     }
617 |     return results;
618 |   }
619 | };
620 | 
621 | // ========== Usage Examples ==========
622 | export const utilityExamples = {
623 |   // String utilities
624 |   camelCased: StringUtils.camelCase("hello-world-example"),
625 |   kebabCased: StringUtils.kebabCase("HelloWorldExample"),
626 |   truncated: StringUtils.truncate("This is a very long string", 15),
627 |   
628 |   // Array utilities
629 |   chunked: ArrayUtils.chunk([1, 2, 3, 4, 5, 6, 7], 3),
630 |   unique: ArrayUtils.unique([1, 2, 2, 3, 3, 3, 4]),
631 |   grouped: ArrayUtils.groupBy(
632 |     [{ type: 'fruit', name: 'apple' }, { type: 'vegetable', name: 'carrot' }],
633 |     item => item.type
634 |   ),
635 |   
636 |   // Object utilities
637 |   picked: ObjectUtils.pick({ a: 1, b: 2, c: 3 }, ['a', 'c']),
638 |   deepValue: ObjectUtils.get({ user: { profile: { name: 'John' } } }, 'user.profile.name'),
639 |   
640 |   // Function utilities
641 |   debouncedLog: FunctionUtils.debounce((message: string) => console.log(message), 1000),
642 |   memoizedFib: FunctionUtils.memoize((n: number): number => {
643 |     if (n <= 1) return n;
644 |     return utilityExamples.memoizedFib(n - 1) + utilityExamples.memoizedFib(n - 2);
645 |   }),
646 |   
647 |   // Date utilities
648 |   futureDate: DateUtils.add(new Date(), 7, 'days'),
649 |   daysDiff: DateUtils.diff(new Date('2023-12-31'), new Date('2023-01-01')),
650 |   
651 |   // Number utilities
652 |   clamped: NumberUtils.clamp(150, 0, 100),
653 |   rounded: NumberUtils.round(3.14159, 2),
654 |   percentage: NumberUtils.toPercent(0.85),
655 |   
656 |   // Validation
657 |   emailValid: ValidationHelpers.isEmail('[email protected]'),
658 |   strongPassword: ValidationHelpers.isStrongPassword('StrongPass123!'),
659 |   
660 |   // Colors
661 |   rgbColor: ColorUtils.hexToRgb('#ff0000'),
662 |   lighterColor: ColorUtils.lighten('#ff0000', 20)
663 | };
664 | 
665 | // Initialize some examples
666 | console.log('Utility examples initialized:', {
667 |   camelCased: utilityExamples.camelCased,
668 |   chunked: utilityExamples.chunked,
669 |   deepValue: utilityExamples.deepValue
670 | });
```

--------------------------------------------------------------------------------
/docs/site/use_cases/index.html:
--------------------------------------------------------------------------------

```html
  1 | 
  2 | <!doctype html>
  3 | <html lang="en" class="no-js">
  4 |   <head>
  5 |     
  6 |       <meta charset="utf-8">
  7 |       <meta name="viewport" content="width=device-width,initial-scale=1">
  8 |       
  9 |       
 10 |       
 11 |       
 12 |         <link rel="prev" href="../installation/">
 13 |       
 14 |       
 15 |         <link rel="next" href="../architecture/">
 16 |       
 17 |       
 18 |       <link rel="icon" href="../assets/images/favicon.png">
 19 |       <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.21">
 20 |     
 21 |     
 22 |       
 23 |         <title>Use Cases - CodeGraphContext</title>
 24 |       
 25 |     
 26 |     
 27 |       <link rel="stylesheet" href="../assets/stylesheets/main.2a3383ac.min.css">
 28 |       
 29 |       
 30 | 
 31 | 
 32 |     
 33 |     
 34 |       
 35 |     
 36 |     
 37 |       
 38 |         
 39 |         
 40 |         <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 41 |         <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
 42 |         <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
 43 |       
 44 |     
 45 |     
 46 |     <script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
 47 |     
 48 |       
 49 | 
 50 |     
 51 |     
 52 |     
 53 |   </head>
 54 |   
 55 |   
 56 |     <body dir="ltr">
 57 |   
 58 |     
 59 |     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
 60 |     <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
 61 |     <label class="md-overlay" for="__drawer"></label>
 62 |     <div data-md-component="skip">
 63 |       
 64 |         
 65 |         <a href="#real-world-use-cases" class="md-skip">
 66 |           Skip to content
 67 |         </a>
 68 |       
 69 |     </div>
 70 |     <div data-md-component="announce">
 71 |       
 72 |     </div>
 73 |     
 74 |     
 75 |       
 76 | 
 77 |   
 78 | 
 79 | <header class="md-header md-header--shadow" data-md-component="header">
 80 |   <nav class="md-header__inner md-grid" aria-label="Header">
 81 |     <a href=".." title="CodeGraphContext" class="md-header__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
 82 |       
 83 |   
 84 |   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
 85 | 
 86 |     </a>
 87 |     <label class="md-header__button md-icon" for="__drawer">
 88 |       
 89 |       <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
 90 |     </label>
 91 |     <div class="md-header__title" data-md-component="header-title">
 92 |       <div class="md-header__ellipsis">
 93 |         <div class="md-header__topic">
 94 |           <span class="md-ellipsis">
 95 |             CodeGraphContext
 96 |           </span>
 97 |         </div>
 98 |         <div class="md-header__topic" data-md-component="header-topic">
 99 |           <span class="md-ellipsis">
100 |             
101 |               Use Cases
102 |             
103 |           </span>
104 |         </div>
105 |       </div>
106 |     </div>
107 |     
108 |     
109 |       <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
110 |     
111 |     
112 |     
113 |       
114 |       
115 |         <label class="md-header__button md-icon" for="__search">
116 |           
117 |           <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
118 |         </label>
119 |         <div class="md-search" data-md-component="search" role="dialog">
120 |   <label class="md-search__overlay" for="__search"></label>
121 |   <div class="md-search__inner" role="search">
122 |     <form class="md-search__form" name="search">
123 |       <input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
124 |       <label class="md-search__icon md-icon" for="__search">
125 |         
126 |         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
127 |         
128 |         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
129 |       </label>
130 |       <nav class="md-search__options" aria-label="Search">
131 |         
132 |         <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
133 |           
134 |           <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
135 |         </button>
136 |       </nav>
137 |       
138 |     </form>
139 |     <div class="md-search__output">
140 |       <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
141 |         <div class="md-search-result" data-md-component="search-result">
142 |           <div class="md-search-result__meta">
143 |             Initializing search
144 |           </div>
145 |           <ol class="md-search-result__list" role="presentation"></ol>
146 |         </div>
147 |       </div>
148 |     </div>
149 |   </div>
150 | </div>
151 |       
152 |     
153 |     
154 |   </nav>
155 |   
156 | </header>
157 |     
158 |     <div class="md-container" data-md-component="container">
159 |       
160 |       
161 |         
162 |           
163 |         
164 |       
165 |       <main class="md-main" data-md-component="main">
166 |         <div class="md-main__inner md-grid">
167 |           
168 |             
169 |               
170 |               <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
171 |                 <div class="md-sidebar__scrollwrap">
172 |                   <div class="md-sidebar__inner">
173 |                     
174 | 
175 | 
176 | 
177 | <nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
178 |   <label class="md-nav__title" for="__drawer">
179 |     <a href=".." title="CodeGraphContext" class="md-nav__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
180 |       
181 |   
182 |   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
183 | 
184 |     </a>
185 |     CodeGraphContext
186 |   </label>
187 |   
188 |   <ul class="md-nav__list" data-md-scrollfix>
189 |     
190 |       
191 |       
192 |   
193 |   
194 |   
195 |   
196 |     <li class="md-nav__item">
197 |       <a href=".." class="md-nav__link">
198 |         
199 |   
200 |   
201 |   <span class="md-ellipsis">
202 |     Home
203 |     
204 |   </span>
205 |   
206 | 
207 |       </a>
208 |     </li>
209 |   
210 | 
211 |     
212 |       
213 |       
214 |   
215 |   
216 |   
217 |   
218 |     <li class="md-nav__item">
219 |       <a href="../installation/" class="md-nav__link">
220 |         
221 |   
222 |   
223 |   <span class="md-ellipsis">
224 |     Installation
225 |     
226 |   </span>
227 |   
228 | 
229 |       </a>
230 |     </li>
231 |   
232 | 
233 |     
234 |       
235 |       
236 |   
237 |   
238 |     
239 |   
240 |   
241 |   
242 |     <li class="md-nav__item md-nav__item--active">
243 |       
244 |       <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
245 |       
246 |       
247 |         
248 |       
249 |       
250 |       <a href="./" class="md-nav__link md-nav__link--active">
251 |         
252 |   
253 |   
254 |   <span class="md-ellipsis">
255 |     Use Cases
256 |     
257 |   </span>
258 |   
259 | 
260 |       </a>
261 |       
262 |     </li>
263 |   
264 | 
265 |     
266 |       
267 |       
268 |   
269 |   
270 |   
271 |   
272 |     <li class="md-nav__item">
273 |       <a href="../architecture/" class="md-nav__link">
274 |         
275 |   
276 |   
277 |   <span class="md-ellipsis">
278 |     Architecture
279 |     
280 |   </span>
281 |   
282 | 
283 |       </a>
284 |     </li>
285 |   
286 | 
287 |     
288 |       
289 |       
290 |   
291 |   
292 |   
293 |   
294 |     <li class="md-nav__item">
295 |       <a href="../cli/" class="md-nav__link">
296 |         
297 |   
298 |   
299 |   <span class="md-ellipsis">
300 |     CLI Reference
301 |     
302 |   </span>
303 |   
304 | 
305 |       </a>
306 |     </li>
307 |   
308 | 
309 |     
310 |       
311 |       
312 |   
313 |   
314 |   
315 |   
316 |     <li class="md-nav__item">
317 |       <a href="../server/" class="md-nav__link">
318 |         
319 |   
320 |   
321 |   <span class="md-ellipsis">
322 |     Server
323 |     
324 |   </span>
325 |   
326 | 
327 |       </a>
328 |     </li>
329 |   
330 | 
331 |     
332 |       
333 |       
334 |   
335 |   
336 |   
337 |   
338 |     <li class="md-nav__item">
339 |       <a href="../core/" class="md-nav__link">
340 |         
341 |   
342 |   
343 |   <span class="md-ellipsis">
344 |     Core Concepts
345 |     
346 |   </span>
347 |   
348 | 
349 |       </a>
350 |     </li>
351 |   
352 | 
353 |     
354 |       
355 |       
356 |   
357 |   
358 |   
359 |   
360 |     <li class="md-nav__item">
361 |       <a href="../tools/" class="md-nav__link">
362 |         
363 |   
364 |   
365 |   <span class="md-ellipsis">
366 |     Tools
367 |     
368 |   </span>
369 |   
370 | 
371 |       </a>
372 |     </li>
373 |   
374 | 
375 |     
376 |       
377 |       
378 |   
379 |   
380 |   
381 |   
382 |     <li class="md-nav__item">
383 |       <a href="../cookbook/" class="md-nav__link">
384 |         
385 |   
386 |   
387 |   <span class="md-ellipsis">
388 |     Cookbook
389 |     
390 |   </span>
391 |   
392 | 
393 |       </a>
394 |     </li>
395 |   
396 | 
397 |     
398 |       
399 |       
400 |   
401 |   
402 |   
403 |   
404 |     
405 |     
406 |     
407 |     
408 |     
409 |     <li class="md-nav__item md-nav__item--nested">
410 |       
411 |         
412 |         
413 |         <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_10" >
414 |         
415 |           
416 |           <label class="md-nav__link" for="__nav_10" id="__nav_10_label" tabindex="0">
417 |             
418 |   
419 |   
420 |   <span class="md-ellipsis">
421 |     Contributing
422 |     
423 |   </span>
424 |   
425 | 
426 |             <span class="md-nav__icon md-icon"></span>
427 |           </label>
428 |         
429 |         <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_10_label" aria-expanded="false">
430 |           <label class="md-nav__title" for="__nav_10">
431 |             <span class="md-nav__icon md-icon"></span>
432 |             Contributing
433 |           </label>
434 |           <ul class="md-nav__list" data-md-scrollfix>
435 |             
436 |               
437 |                 
438 |   
439 |   
440 |   
441 |   
442 |     <li class="md-nav__item">
443 |       <a href="../contributing/" class="md-nav__link">
444 |         
445 |   
446 |   
447 |   <span class="md-ellipsis">
448 |     Overview
449 |     
450 |   </span>
451 |   
452 | 
453 |       </a>
454 |     </li>
455 |   
456 | 
457 |               
458 |             
459 |               
460 |                 
461 |   
462 |   
463 |   
464 |   
465 |     <li class="md-nav__item">
466 |       <a href="../contributing_languages/" class="md-nav__link">
467 |         
468 |   
469 |   
470 |   <span class="md-ellipsis">
471 |     Adding New Languages
472 |     
473 |   </span>
474 |   
475 | 
476 |       </a>
477 |     </li>
478 |   
479 | 
480 |               
481 |             
482 |           </ul>
483 |         </nav>
484 |       
485 |     </li>
486 |   
487 | 
488 |     
489 |       
490 |       
491 |   
492 |   
493 |   
494 |   
495 |     <li class="md-nav__item">
496 |       <a href="../troubleshooting/" class="md-nav__link">
497 |         
498 |   
499 |   
500 |   <span class="md-ellipsis">
501 |     Troubleshooting
502 |     
503 |   </span>
504 |   
505 | 
506 |       </a>
507 |     </li>
508 |   
509 | 
510 |     
511 |       
512 |       
513 |   
514 |   
515 |   
516 |   
517 |     <li class="md-nav__item">
518 |       <a href="../future_work/" class="md-nav__link">
519 |         
520 |   
521 |   
522 |   <span class="md-ellipsis">
523 |     Future Work
524 |     
525 |   </span>
526 |   
527 | 
528 |       </a>
529 |     </li>
530 |   
531 | 
532 |     
533 |       
534 |       
535 |   
536 |   
537 |   
538 |   
539 |     <li class="md-nav__item">
540 |       <a href="../license/" class="md-nav__link">
541 |         
542 |   
543 |   
544 |   <span class="md-ellipsis">
545 |     License
546 |     
547 |   </span>
548 |   
549 | 
550 |       </a>
551 |     </li>
552 |   
553 | 
554 |     
555 |   </ul>
556 | </nav>
557 |                   </div>
558 |                 </div>
559 |               </div>
560 |             
561 |             
562 |               
563 |               <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
564 |                 <div class="md-sidebar__scrollwrap">
565 |                   <div class="md-sidebar__inner">
566 |                     
567 | 
568 | <nav class="md-nav md-nav--secondary" aria-label="Table of contents">
569 |   
570 |   
571 |   
572 |     
573 |   
574 |   
575 | </nav>
576 |                   </div>
577 |                 </div>
578 |               </div>
579 |             
580 |           
581 |           
582 |             <div class="md-content" data-md-component="content">
583 |               <article class="md-content__inner md-typeset">
584 |                 
585 |                   
586 | 
587 | 
588 | 
589 | <h1 id="real-world-use-cases">Real World Use Cases</h1>
590 | <p>CodeGraphContext can be a powerful ally in your daily coding journey. Here are some real-world scenarios where it can significantly boost your productivity and understanding of a codebase:</p>
591 | <ol>
592 | <li>
593 | <p><strong>Onboarding New Developers:</strong> A new team member can quickly get up to speed by asking questions like:</p>
594 | <ul>
595 | <li>"Where is the authentication logic handled?"</li>
596 | <li>"Show me the main entry point of the application."</li>
597 | </ul>
598 | </li>
599 | <li>
600 | <p><strong>Impact Analysis:</strong> Before making a change, assess the potential ripple effects:</p>
601 | <ul>
602 | <li>"What other parts of the code will be affected if I change the <code>calculate_total</code> function?"</li>
603 | </ul>
604 | </li>
605 | <li>
606 | <p><strong>Code Review:</strong> Gain context on pull requests faster:</p>
607 | <ul>
608 | <li>"Show me the callers of this new function."</li>
609 | <li>"Does this change introduce any new dependencies?"</li>
610 | </ul>
611 | </li>
612 | <li>
613 | <p><strong>Debugging:</strong> Trace execution flows to pinpoint the source of a bug:</p>
614 | <ul>
615 | <li>"Show me the call chain from <code>handle_request</code> to <code>process_payment</code>."</li>
616 | </ul>
617 | </li>
618 | <li>
619 | <p><strong>Refactoring:</strong> Identify and plan large-scale code changes:</p>
620 | <ul>
621 | <li>"Find all instances of the deprecated <code>OldApiClass</code>."</li>
622 | <li>"List all functions that use the <code>urllib</code> library so I can replace them with <code>requests</code>."</li>
623 | </ul>
624 | </li>
625 | <li>
626 | <p><strong>Identifying Code Smells:</strong> Proactively find areas that need improvement:</p>
627 | <ul>
628 | <li>"Find the 10 most complex functions in the codebase."</li>
629 | <li>"Show me functions with more than 5 arguments."</li>
630 | </ul>
631 | </li>
632 | <li>
633 | <p><strong>Security Audits:</strong> Search for potentially vulnerable code patterns:</p>
634 | <ul>
635 | <li>"Find all functions that use the <code>eval</code> function."</li>
636 | <li>"Show me where raw SQL queries are being executed."</li>
637 | </ul>
638 | </li>
639 | <li>
640 | <p><strong>Automated Documentation:</strong> Use the tool's understanding of the code to generate documentation. (This is what this agent is doing!)</p>
641 | </li>
642 | <li>
643 | <p><strong>Dependency Management:</strong> Understand how your project uses its dependencies:</p>
644 | <ul>
645 | <li>"Which files import the <code>requests</code> library?"</li>
646 | <li>"Are there any circular dependencies between modules?"</li>
647 | </ul>
648 | </li>
649 | <li>
650 | <p><strong>Cleaning Up Unused Code:</strong> Keep your codebase lean and maintainable:</p>
651 | <ul>
652 | <li>"Is there any dead or unused code in this project?"</li>
653 | </ul>
654 | </li>
655 | <li>
656 | <p><strong>Exploring a Large Codebase:</strong> Navigate large, unfamiliar projects with ease:</p>
657 | <ul>
658 | <li>"List all the classes in the <code>core</code> module."</li>
659 | <li>"What are the top-level functions in the <code>utils</code> directory?"</li>
660 | </ul>
661 | </li>
662 | <li>
663 | <p><strong>Enforcing Coding Standards:</strong> Check for adherence to team conventions:</p>
664 | <ul>
665 | <li>"Find all functions that are not decorated with <code>@log_execution</code>."</li>
666 | <li>"Show me all public methods that don't have a docstring."</li>
667 | </ul>
668 | </li>
669 | <li>
670 | <p><strong>Discovering API Usage:</strong> Find examples of how to use internal or external APIs:</p>
671 | <ul>
672 | <li>"Show me how other parts of the code use the <code>UserService</code>."</li>
673 | </ul>
674 | </li>
675 | <li>
676 | <p><strong>Improving Test Coverage:</strong> Identify areas that may lack test coverage:</p>
677 | <ul>
678 | <li>"Find all functions that are not called by any test files."</li>
679 | </ul>
680 | </li>
681 | <li>
682 | <p><strong>Visualizing Code Structure:</strong> Get a bird's-eye view of your project's architecture:</p>
683 | <ul>
684 | <li>"Generate a graph visualization of the <code>auth</code> module and its dependencies."</li>
685 | </ul>
686 | </li>
687 | <li>
688 | <p><strong>Learning a New Framework:</strong> Understand how a new framework operates by exploring its source code.</p>
689 | </li>
690 | <li>
691 | <p><strong>Code Archeology:</strong> Investigate legacy code to understand its history and purpose.</p>
692 | </li>
693 | <li>
694 | <p><strong>Planning a Migration:</strong> Identify all points of contact when migrating a library or framework:</p>
695 | <ul>
696 | <li>"Find all the places where the <code>old_payment_gateway</code> is used."</li>
697 | </ul>
698 | </li>
699 | <li>
700 | <p><strong>Knowledge Sharing:</strong> Use the code graph as a centralized, always-up-to-date knowledge base for your team.</p>
701 | </li>
702 | <li>
703 | <p><strong>Automated Code Reviews:</strong> Integrate CodeGraphContext into your CI/CD pipeline to automatically flag potential issues in pull requests.</p>
704 | </li>
705 | </ol>
706 | 
707 | 
708 | 
709 | 
710 | 
711 | 
712 | 
713 | 
714 | 
715 | 
716 | 
717 | 
718 |                 
719 |               </article>
720 |             </div>
721 |           
722 |           
723 | <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
724 |         </div>
725 |         
726 |       </main>
727 |       
728 |         <footer class="md-footer">
729 |   
730 |   <div class="md-footer-meta md-typeset">
731 |     <div class="md-footer-meta__inner md-grid">
732 |       <div class="md-copyright">
733 |   
734 |   
735 |     Made with
736 |     <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
737 |       Material for MkDocs
738 |     </a>
739 |   
740 | </div>
741 |       
742 |     </div>
743 |   </div>
744 | </footer>
745 |       
746 |     </div>
747 |     <div class="md-dialog" data-md-component="dialog">
748 |       <div class="md-dialog__inner md-typeset"></div>
749 |     </div>
750 |     
751 |     
752 |     
753 |       
754 |       <script id="__config" type="application/json">{"base": "..", "features": [], "search": "../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
755 |     
756 |     
757 |       <script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
758 |       
759 |     
760 |   </body>
761 | </html>
```

--------------------------------------------------------------------------------
/docs/site/contributing/index.html:
--------------------------------------------------------------------------------

```html
  1 | 
  2 | <!doctype html>
  3 | <html lang="en" class="no-js">
  4 |   <head>
  5 |     
  6 |       <meta charset="utf-8">
  7 |       <meta name="viewport" content="width=device-width,initial-scale=1">
  8 |       
  9 |       
 10 |       
 11 |       
 12 |         <link rel="prev" href="../cookbook/">
 13 |       
 14 |       
 15 |         <link rel="next" href="../contributing_languages/">
 16 |       
 17 |       
 18 |       <link rel="icon" href="../assets/images/favicon.png">
 19 |       <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.21">
 20 |     
 21 |     
 22 |       
 23 |         <title>Overview - CodeGraphContext</title>
 24 |       
 25 |     
 26 |     
 27 |       <link rel="stylesheet" href="../assets/stylesheets/main.2a3383ac.min.css">
 28 |       
 29 |       
 30 | 
 31 | 
 32 |     
 33 |     
 34 |       
 35 |     
 36 |     
 37 |       
 38 |         
 39 |         
 40 |         <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 41 |         <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
 42 |         <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
 43 |       
 44 |     
 45 |     
 46 |     <script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
 47 |     
 48 |       
 49 | 
 50 |     
 51 |     
 52 |     
 53 |   </head>
 54 |   
 55 |   
 56 |     <body dir="ltr">
 57 |   
 58 |     
 59 |     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
 60 |     <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
 61 |     <label class="md-overlay" for="__drawer"></label>
 62 |     <div data-md-component="skip">
 63 |       
 64 |         
 65 |         <a href="#contributing-to-codegraphcontext" class="md-skip">
 66 |           Skip to content
 67 |         </a>
 68 |       
 69 |     </div>
 70 |     <div data-md-component="announce">
 71 |       
 72 |     </div>
 73 |     
 74 |     
 75 |       
 76 | 
 77 |   
 78 | 
 79 | <header class="md-header md-header--shadow" data-md-component="header">
 80 |   <nav class="md-header__inner md-grid" aria-label="Header">
 81 |     <a href=".." title="CodeGraphContext" class="md-header__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
 82 |       
 83 |   
 84 |   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
 85 | 
 86 |     </a>
 87 |     <label class="md-header__button md-icon" for="__drawer">
 88 |       
 89 |       <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
 90 |     </label>
 91 |     <div class="md-header__title" data-md-component="header-title">
 92 |       <div class="md-header__ellipsis">
 93 |         <div class="md-header__topic">
 94 |           <span class="md-ellipsis">
 95 |             CodeGraphContext
 96 |           </span>
 97 |         </div>
 98 |         <div class="md-header__topic" data-md-component="header-topic">
 99 |           <span class="md-ellipsis">
100 |             
101 |               Overview
102 |             
103 |           </span>
104 |         </div>
105 |       </div>
106 |     </div>
107 |     
108 |     
109 |       <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
110 |     
111 |     
112 |     
113 |       
114 |       
115 |         <label class="md-header__button md-icon" for="__search">
116 |           
117 |           <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
118 |         </label>
119 |         <div class="md-search" data-md-component="search" role="dialog">
120 |   <label class="md-search__overlay" for="__search"></label>
121 |   <div class="md-search__inner" role="search">
122 |     <form class="md-search__form" name="search">
123 |       <input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
124 |       <label class="md-search__icon md-icon" for="__search">
125 |         
126 |         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
127 |         
128 |         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
129 |       </label>
130 |       <nav class="md-search__options" aria-label="Search">
131 |         
132 |         <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
133 |           
134 |           <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
135 |         </button>
136 |       </nav>
137 |       
138 |     </form>
139 |     <div class="md-search__output">
140 |       <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
141 |         <div class="md-search-result" data-md-component="search-result">
142 |           <div class="md-search-result__meta">
143 |             Initializing search
144 |           </div>
145 |           <ol class="md-search-result__list" role="presentation"></ol>
146 |         </div>
147 |       </div>
148 |     </div>
149 |   </div>
150 | </div>
151 |       
152 |     
153 |     
154 |   </nav>
155 |   
156 | </header>
157 |     
158 |     <div class="md-container" data-md-component="container">
159 |       
160 |       
161 |         
162 |           
163 |         
164 |       
165 |       <main class="md-main" data-md-component="main">
166 |         <div class="md-main__inner md-grid">
167 |           
168 |             
169 |               
170 |               <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
171 |                 <div class="md-sidebar__scrollwrap">
172 |                   <div class="md-sidebar__inner">
173 |                     
174 | 
175 | 
176 | 
177 | <nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
178 |   <label class="md-nav__title" for="__drawer">
179 |     <a href=".." title="CodeGraphContext" class="md-nav__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
180 |       
181 |   
182 |   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
183 | 
184 |     </a>
185 |     CodeGraphContext
186 |   </label>
187 |   
188 |   <ul class="md-nav__list" data-md-scrollfix>
189 |     
190 |       
191 |       
192 |   
193 |   
194 |   
195 |   
196 |     <li class="md-nav__item">
197 |       <a href=".." class="md-nav__link">
198 |         
199 |   
200 |   
201 |   <span class="md-ellipsis">
202 |     Home
203 |     
204 |   </span>
205 |   
206 | 
207 |       </a>
208 |     </li>
209 |   
210 | 
211 |     
212 |       
213 |       
214 |   
215 |   
216 |   
217 |   
218 |     <li class="md-nav__item">
219 |       <a href="../installation/" class="md-nav__link">
220 |         
221 |   
222 |   
223 |   <span class="md-ellipsis">
224 |     Installation
225 |     
226 |   </span>
227 |   
228 | 
229 |       </a>
230 |     </li>
231 |   
232 | 
233 |     
234 |       
235 |       
236 |   
237 |   
238 |   
239 |   
240 |     <li class="md-nav__item">
241 |       <a href="../use_cases/" class="md-nav__link">
242 |         
243 |   
244 |   
245 |   <span class="md-ellipsis">
246 |     Use Cases
247 |     
248 |   </span>
249 |   
250 | 
251 |       </a>
252 |     </li>
253 |   
254 | 
255 |     
256 |       
257 |       
258 |   
259 |   
260 |   
261 |   
262 |     <li class="md-nav__item">
263 |       <a href="../architecture/" class="md-nav__link">
264 |         
265 |   
266 |   
267 |   <span class="md-ellipsis">
268 |     Architecture
269 |     
270 |   </span>
271 |   
272 | 
273 |       </a>
274 |     </li>
275 |   
276 | 
277 |     
278 |       
279 |       
280 |   
281 |   
282 |   
283 |   
284 |     <li class="md-nav__item">
285 |       <a href="../cli/" class="md-nav__link">
286 |         
287 |   
288 |   
289 |   <span class="md-ellipsis">
290 |     CLI Reference
291 |     
292 |   </span>
293 |   
294 | 
295 |       </a>
296 |     </li>
297 |   
298 | 
299 |     
300 |       
301 |       
302 |   
303 |   
304 |   
305 |   
306 |     <li class="md-nav__item">
307 |       <a href="../server/" class="md-nav__link">
308 |         
309 |   
310 |   
311 |   <span class="md-ellipsis">
312 |     Server
313 |     
314 |   </span>
315 |   
316 | 
317 |       </a>
318 |     </li>
319 |   
320 | 
321 |     
322 |       
323 |       
324 |   
325 |   
326 |   
327 |   
328 |     <li class="md-nav__item">
329 |       <a href="../core/" class="md-nav__link">
330 |         
331 |   
332 |   
333 |   <span class="md-ellipsis">
334 |     Core Concepts
335 |     
336 |   </span>
337 |   
338 | 
339 |       </a>
340 |     </li>
341 |   
342 | 
343 |     
344 |       
345 |       
346 |   
347 |   
348 |   
349 |   
350 |     <li class="md-nav__item">
351 |       <a href="../tools/" class="md-nav__link">
352 |         
353 |   
354 |   
355 |   <span class="md-ellipsis">
356 |     Tools
357 |     
358 |   </span>
359 |   
360 | 
361 |       </a>
362 |     </li>
363 |   
364 | 
365 |     
366 |       
367 |       
368 |   
369 |   
370 |   
371 |   
372 |     <li class="md-nav__item">
373 |       <a href="../cookbook/" class="md-nav__link">
374 |         
375 |   
376 |   
377 |   <span class="md-ellipsis">
378 |     Cookbook
379 |     
380 |   </span>
381 |   
382 | 
383 |       </a>
384 |     </li>
385 |   
386 | 
387 |     
388 |       
389 |       
390 |   
391 |   
392 |     
393 |   
394 |   
395 |   
396 |     
397 |     
398 |     
399 |     
400 |     
401 |     <li class="md-nav__item md-nav__item--active md-nav__item--nested">
402 |       
403 |         
404 |         
405 |         <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_10" checked>
406 |         
407 |           
408 |           <label class="md-nav__link" for="__nav_10" id="__nav_10_label" tabindex="0">
409 |             
410 |   
411 |   
412 |   <span class="md-ellipsis">
413 |     Contributing
414 |     
415 |   </span>
416 |   
417 | 
418 |             <span class="md-nav__icon md-icon"></span>
419 |           </label>
420 |         
421 |         <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_10_label" aria-expanded="true">
422 |           <label class="md-nav__title" for="__nav_10">
423 |             <span class="md-nav__icon md-icon"></span>
424 |             Contributing
425 |           </label>
426 |           <ul class="md-nav__list" data-md-scrollfix>
427 |             
428 |               
429 |                 
430 |   
431 |   
432 |     
433 |   
434 |   
435 |   
436 |     <li class="md-nav__item md-nav__item--active">
437 |       
438 |       <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
439 |       
440 |       
441 |         
442 |       
443 |       
444 |         <label class="md-nav__link md-nav__link--active" for="__toc">
445 |           
446 |   
447 |   
448 |   <span class="md-ellipsis">
449 |     Overview
450 |     
451 |   </span>
452 |   
453 | 
454 |           <span class="md-nav__icon md-icon"></span>
455 |         </label>
456 |       
457 |       <a href="./" class="md-nav__link md-nav__link--active">
458 |         
459 |   
460 |   
461 |   <span class="md-ellipsis">
462 |     Overview
463 |     
464 |   </span>
465 |   
466 | 
467 |       </a>
468 |       
469 |         
470 | 
471 | <nav class="md-nav md-nav--secondary" aria-label="Table of contents">
472 |   
473 |   
474 |   
475 |     
476 |   
477 |   
478 |     <label class="md-nav__title" for="__toc">
479 |       <span class="md-nav__icon md-icon"></span>
480 |       Table of contents
481 |     </label>
482 |     <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
483 |       
484 |         <li class="md-nav__item">
485 |   <a href="#general-guidelines" class="md-nav__link">
486 |     <span class="md-ellipsis">
487 |       General Guidelines
488 |     </span>
489 |   </a>
490 |   
491 | </li>
492 |       
493 |         <li class="md-nav__item">
494 |   <a href="#setting-up-your-development-environment" class="md-nav__link">
495 |     <span class="md-ellipsis">
496 |       Setting up Your Development Environment
497 |     </span>
498 |   </a>
499 |   
500 | </li>
501 |       
502 |         <li class="md-nav__item">
503 |   <a href="#debugging" class="md-nav__link">
504 |     <span class="md-ellipsis">
505 |       Debugging
506 |     </span>
507 |   </a>
508 |   
509 | </li>
510 |       
511 |         <li class="md-nav__item">
512 |   <a href="#running-tests" class="md-nav__link">
513 |     <span class="md-ellipsis">
514 |       Running Tests
515 |     </span>
516 |   </a>
517 |   
518 | </li>
519 |       
520 |         <li class="md-nav__item">
521 |   <a href="#submitting-changes" class="md-nav__link">
522 |     <span class="md-ellipsis">
523 |       Submitting Changes
524 |     </span>
525 |   </a>
526 |   
527 | </li>
528 |       
529 |     </ul>
530 |   
531 | </nav>
532 |       
533 |     </li>
534 |   
535 | 
536 |               
537 |             
538 |               
539 |                 
540 |   
541 |   
542 |   
543 |   
544 |     <li class="md-nav__item">
545 |       <a href="../contributing_languages/" class="md-nav__link">
546 |         
547 |   
548 |   
549 |   <span class="md-ellipsis">
550 |     Adding New Languages
551 |     
552 |   </span>
553 |   
554 | 
555 |       </a>
556 |     </li>
557 |   
558 | 
559 |               
560 |             
561 |           </ul>
562 |         </nav>
563 |       
564 |     </li>
565 |   
566 | 
567 |     
568 |       
569 |       
570 |   
571 |   
572 |   
573 |   
574 |     <li class="md-nav__item">
575 |       <a href="../troubleshooting/" class="md-nav__link">
576 |         
577 |   
578 |   
579 |   <span class="md-ellipsis">
580 |     Troubleshooting
581 |     
582 |   </span>
583 |   
584 | 
585 |       </a>
586 |     </li>
587 |   
588 | 
589 |     
590 |       
591 |       
592 |   
593 |   
594 |   
595 |   
596 |     <li class="md-nav__item">
597 |       <a href="../future_work/" class="md-nav__link">
598 |         
599 |   
600 |   
601 |   <span class="md-ellipsis">
602 |     Future Work
603 |     
604 |   </span>
605 |   
606 | 
607 |       </a>
608 |     </li>
609 |   
610 | 
611 |     
612 |       
613 |       
614 |   
615 |   
616 |   
617 |   
618 |     <li class="md-nav__item">
619 |       <a href="../license/" class="md-nav__link">
620 |         
621 |   
622 |   
623 |   <span class="md-ellipsis">
624 |     License
625 |     
626 |   </span>
627 |   
628 | 
629 |       </a>
630 |     </li>
631 |   
632 | 
633 |     
634 |   </ul>
635 | </nav>
636 |                   </div>
637 |                 </div>
638 |               </div>
639 |             
640 |             
641 |               
642 |               <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
643 |                 <div class="md-sidebar__scrollwrap">
644 |                   <div class="md-sidebar__inner">
645 |                     
646 | 
647 | <nav class="md-nav md-nav--secondary" aria-label="Table of contents">
648 |   
649 |   
650 |   
651 |     
652 |   
653 |   
654 |     <label class="md-nav__title" for="__toc">
655 |       <span class="md-nav__icon md-icon"></span>
656 |       Table of contents
657 |     </label>
658 |     <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
659 |       
660 |         <li class="md-nav__item">
661 |   <a href="#general-guidelines" class="md-nav__link">
662 |     <span class="md-ellipsis">
663 |       General Guidelines
664 |     </span>
665 |   </a>
666 |   
667 | </li>
668 |       
669 |         <li class="md-nav__item">
670 |   <a href="#setting-up-your-development-environment" class="md-nav__link">
671 |     <span class="md-ellipsis">
672 |       Setting up Your Development Environment
673 |     </span>
674 |   </a>
675 |   
676 | </li>
677 |       
678 |         <li class="md-nav__item">
679 |   <a href="#debugging" class="md-nav__link">
680 |     <span class="md-ellipsis">
681 |       Debugging
682 |     </span>
683 |   </a>
684 |   
685 | </li>
686 |       
687 |         <li class="md-nav__item">
688 |   <a href="#running-tests" class="md-nav__link">
689 |     <span class="md-ellipsis">
690 |       Running Tests
691 |     </span>
692 |   </a>
693 |   
694 | </li>
695 |       
696 |         <li class="md-nav__item">
697 |   <a href="#submitting-changes" class="md-nav__link">
698 |     <span class="md-ellipsis">
699 |       Submitting Changes
700 |     </span>
701 |   </a>
702 |   
703 | </li>
704 |       
705 |     </ul>
706 |   
707 | </nav>
708 |                   </div>
709 |                 </div>
710 |               </div>
711 |             
712 |           
713 |           
714 |             <div class="md-content" data-md-component="content">
715 |               <article class="md-content__inner md-typeset">
716 |                 
717 |                   
718 | 
719 | 
720 | 
721 | <h1 id="contributing-to-codegraphcontext">Contributing to CodeGraphContext</h1>
722 | <p>We welcome contributions! Please follow these steps:</p>
723 | <h2 id="general-guidelines">General Guidelines</h2>
724 | <ul>
725 | <li>Ensure your code adheres to the existing style and conventions of the project.</li>
726 | <li>Write clear, concise, and well-documented code.</li>
727 | <li>All new features or bug fixes should be accompanied by appropriate tests.</li>
728 | <li>Keep your pull requests focused on a single feature or bug fix.</li>
729 | </ul>
730 | <h2 id="setting-up-your-development-environment">Setting up Your Development Environment</h2>
731 | <ol>
732 | <li>Fork the repository.</li>
733 | <li>Set up your development environment: <code>pip install -e ".[dev]"</code></li>
734 | <li>Create a new branch for your feature or bugfix (e.g., <code>git checkout -b feature/my-new-feature</code>).</li>
735 | </ol>
736 | <h2 id="debugging">Debugging</h2>
737 | <p>To enable debug mode for detailed logging, locate the <code>debug_mode</code> variable in <code>src/codegraphcontext/tools/graph_builder.py</code> and set its value to <code>1</code>.</p>
738 | <pre><code class="language-python"># src/codegraphcontext/tools/graph_builder.py
739 | debug_mode = 1
740 | </code></pre>
741 | <h2 id="running-tests">Running Tests</h2>
742 | <p>Tests are located in the <code>tests/</code> directory and are run using <code>pytest</code>.</p>
743 | <ol>
744 | <li>Navigate to the root of the <code>CodeGraphContext</code> directory.</li>
745 | <li>Run all tests using the command: <code>pytest</code></li>
746 | <li>To run specific tests, you can provide the path to the test file, for example: <code>pytest tests/test_tools.py</code></li>
747 | <li><strong>Skipping Re-indexing:</strong> To speed up test runs, especially during development, you can set the <code>CGC_SKIP_REINDEX</code> environment variable to <code>true</code>. This will prevent the test suite from re-indexing the sample project if it's already indexed.
748 |     <code>bash
749 |     CGC_SKIP_REINDEX=true pytest</code></li>
750 | </ol>
751 | <h2 id="submitting-changes">Submitting Changes</h2>
752 | <ol>
753 | <li>Write your code and add corresponding tests in the <code>tests/</code> directory.</li>
754 | <li>Ensure all tests pass and your code lints without errors.</li>
755 | <li>Commit your changes with a descriptive commit message.</li>
756 | <li>Submit a pull request to the <code>main</code> branch.</li>
757 | </ol>
758 | <!-- "Failed to check job status: 'JobManager' object has no attribute 'JobStatus'" -->
759 | 
760 | 
761 | 
762 | 
763 | 
764 | 
765 | 
766 | 
767 | 
768 | 
769 | 
770 | 
771 |                 
772 |               </article>
773 |             </div>
774 |           
775 |           
776 | <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
777 |         </div>
778 |         
779 |       </main>
780 |       
781 |         <footer class="md-footer">
782 |   
783 |   <div class="md-footer-meta md-typeset">
784 |     <div class="md-footer-meta__inner md-grid">
785 |       <div class="md-copyright">
786 |   
787 |   
788 |     Made with
789 |     <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
790 |       Material for MkDocs
791 |     </a>
792 |   
793 | </div>
794 |       
795 |     </div>
796 |   </div>
797 | </footer>
798 |       
799 |     </div>
800 |     <div class="md-dialog" data-md-component="dialog">
801 |       <div class="md-dialog__inner md-typeset"></div>
802 |     </div>
803 |     
804 |     
805 |     
806 |       
807 |       <script id="__config" type="application/json">{"base": "..", "features": [], "search": "../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
808 |     
809 |     
810 |       <script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
811 |       
812 |     
813 |   </body>
814 | </html>
```

--------------------------------------------------------------------------------
/src/codegraphcontext/tools/languages/ruby.py:
--------------------------------------------------------------------------------

```python
  1 | from pathlib import Path
  2 | from typing import Any, Dict, Optional, Tuple
  3 | from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger, debug_logger
  4 | 
  5 | RUBY_QUERIES = {
  6 |     "functions": """
  7 |         (method
  8 |             name: (identifier) @name
  9 |         ) @function_node
 10 |     """,
 11 |     "classes": """
 12 |         (class
 13 |             name: (constant) @name
 14 |         ) @class
 15 |     """,
 16 |     "modules": """
 17 |         (module
 18 |             name: (constant) @name
 19 |         ) @module_node
 20 |     """,
 21 |     "imports": """
 22 |         (call
 23 |             method: (identifier) @method_name
 24 |             arguments: (argument_list
 25 |                 (string) @path
 26 |             )
 27 |         ) @import
 28 |     """,
 29 |     "calls": """
 30 |         (call
 31 |             method: (identifier) @name
 32 |         )
 33 |     """,
 34 |     "variables": """
 35 |         (assignment
 36 |             left: (identifier) @name
 37 |             right: (_) @value
 38 |         )
 39 |         (assignment
 40 |             left: (instance_variable) @name
 41 |             right: (_) @value
 42 |         )
 43 |     """,
 44 |     "comments": """
 45 |         (comment) @comment
 46 |     """,
 47 |     "module_includes": """
 48 |         (call
 49 |           method: (identifier) @method
 50 |           arguments: (argument_list (constant) @module)
 51 |         ) @include_call
 52 |     """,
 53 | }
 54 | 
 55 | 
 56 | class RubyTreeSitterParser:
 57 |     """A Ruby-specific parser using tree-sitter."""
 58 | 
 59 |     def __init__(self, generic_parser_wrapper: Any):
 60 |         self.generic_parser_wrapper = generic_parser_wrapper
 61 |         self.language_name = "ruby"
 62 |         self.language = generic_parser_wrapper.language
 63 |         self.parser = generic_parser_wrapper.parser
 64 | 
 65 |         self.queries = {
 66 |             name: self.language.query(query_str)
 67 |             for name, query_str in RUBY_QUERIES.items()
 68 |         }
 69 | 
 70 |     def _get_node_text(self, node: Any) -> str:
 71 |         return node.text.decode("utf-8")
 72 |     
 73 |     def _enclosing_class_name(self, node: Any) -> Optional[str]:
 74 |         name, typ, _ = self._get_parent_context(node, ('class',))
 75 |         return name
 76 |     
 77 |     def _find_modules(self, root_node: Any) -> list[Dict[str, Any]]:
 78 |         modules = []
 79 |         query = self.queries["modules"]
 80 |         # name via captures
 81 |         captures = list(query.captures(root_node))
 82 |         for node, cap in captures:
 83 |             if cap == "module_node":
 84 |                 name = None
 85 |                 for n, c in captures:
 86 |                     if c == "name":
 87 |                         if n.start_byte >= node.start_byte and n.end_byte <= node.end_byte:
 88 |                             name = self._get_node_text(n)
 89 |                             break
 90 |                 if name:
 91 |                     modules.append({
 92 |                         "name": name,
 93 |                         "line_number": node.start_point[0] + 1,
 94 |                         "end_line": node.end_point[0] + 1,
 95 |                         "source": self._get_node_text(node),
 96 |                         "source_code": self._get_node_text(node),
 97 |                         "lang": self.language_name,
 98 |                         "is_dependency": False,
 99 |                     })
100 |         return modules
101 | 
102 |     def _find_module_inclusions(self, root_node: Any) -> list[Dict[str, Any]]:
103 |         includes = []
104 |         query = self.queries["module_includes"]
105 |         for node, cap in query.captures(root_node):
106 |             if cap == "method":
107 |                 method_name = self._get_node_text(node)
108 |                 if method_name != "include":
109 |                     continue
110 |             if cap == "include_call":
111 |                 method = None
112 |                 module = None
113 |                 for n, c in query.captures(node):
114 |                     if c == "method":
115 |                         method = self._get_node_text(n)
116 |                     elif c == "module":
117 |                         module = self._get_node_text(n)
118 |                 if method == "include" and module:
119 |                     cls = self._enclosing_class_name(node)
120 |                     if cls:
121 |                         includes.append({
122 |                             "class": cls,
123 |                             "module": module,
124 |                             "line_number": node.start_point[0] + 1,
125 |                             "lang": self.language_name,
126 |                             "is_dependency": False,
127 |                         })
128 |         return includes
129 | 
130 | 
131 |     def _get_parent_context(self, node: Any, types: Tuple[str, ...] = ('class', 'module', 'method')):
132 |         """Find parent context for Ruby constructs."""
133 |         curr = node.parent
134 |         while curr:
135 |             if curr.type in types:
136 |                 name_node = curr.child_by_field_name('name')
137 |                 if name_node:
138 |                     return self._get_node_text(name_node), curr.type, curr.start_point[0] + 1
139 |             curr = curr.parent
140 |         return None, None, None
141 | 
142 |     def _calculate_complexity(self, node: Any) -> int:
143 |         """Calculate cyclomatic complexity for Ruby constructs."""
144 |         complexity_nodes = {
145 |             "if", "unless", "case", "when", "while", "until", "for", "rescue", "ensure",
146 |             "and", "or", "&&", "||", "?", "ternary"
147 |         }
148 |         count = 1
149 | 
150 |         def traverse(n):
151 |             nonlocal count
152 |             if n.type in complexity_nodes:
153 |                 count += 1
154 |             for child in n.children:
155 |                 traverse(child)
156 | 
157 |         traverse(node)
158 |         return count
159 | 
160 |     def _get_docstring(self, node: Any) -> Optional[str]:
161 |         """Extract comments as docstrings for Ruby constructs."""
162 |         # Look for comments before the node
163 |         prev_sibling = node.prev_sibling
164 |         while prev_sibling and prev_sibling.type in ('comment', '\n', ' '):
165 |             if prev_sibling.type == 'comment':
166 |                 comment_text = self._get_node_text(prev_sibling)
167 |                 if comment_text.startswith('#') and not comment_text.startswith('#!'):
168 |                     return comment_text.strip()
169 |             prev_sibling = prev_sibling.prev_sibling
170 |         return None
171 | 
172 |     def _parse_method_parameters(self, method_node: Any) -> list[str]:
173 |         """Parse method parameters from a method node."""
174 |         params = []
175 |         # Look for parameters in the method node
176 |         for child in method_node.children:
177 |             if child.type == 'identifier' and child != method_node.child_by_field_name('name'):
178 |                 # This is likely a parameter
179 |                 params.append(self._get_node_text(child))
180 |         return params
181 | 
182 |     def parse(self, file_path: Path, is_dependency: bool = False) -> Dict[str, Any]:
183 |         """Parses a Ruby file and returns its structure."""
184 |         with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
185 |             source_code = f.read()
186 | 
187 |         tree = self.parser.parse(bytes(source_code, "utf8"))
188 |         root_node = tree.root_node
189 | 
190 |         functions = self._find_functions(root_node)
191 |         classes = self._find_classes(root_node)
192 |         imports = self._find_imports(root_node)
193 |         function_calls = self._find_calls(root_node)
194 |         variables = self._find_variables(root_node)
195 |         modules = self._find_modules(root_node)
196 |         module_inclusions = self._find_module_inclusions(root_node)
197 | 
198 |         return {
199 |             "file_path": str(file_path),
200 |             "functions": functions,
201 |             "classes": classes,
202 |             "variables": variables,
203 |             "imports": imports,
204 |             "function_calls": function_calls,
205 |             "is_dependency": is_dependency,
206 |             "lang": self.language_name,
207 |             "modules": modules,
208 |             "module_inclusions": module_inclusions,
209 |         }
210 | 
211 |     def _find_functions(self, root_node: Any) -> list[Dict[str, Any]]:
212 |         """Find all function/method definitions."""
213 |         functions = []
214 |         query = self.queries["functions"]
215 |         
216 |         # Collect all captures first
217 |         all_captures = list(query.captures(root_node))
218 |         
219 |         # Group captures by function node using a different approach
220 |         captures_by_function = {}
221 |         for node, capture_name in all_captures:
222 |             if capture_name == 'function_node':
223 |                 captures_by_function[id(node)] = {'node': node, 'name': None}
224 |         
225 |         # Now find names for each function
226 |         for node, capture_name in all_captures:
227 |             if capture_name == 'name':
228 |                 # Find which function this name belongs to
229 |                 for func_id, func_data in captures_by_function.items():
230 |                     func_node = func_data['node']
231 |                     # Check if this name node is within the function node
232 |                     if (node.start_byte >= func_node.start_byte and 
233 |                         node.end_byte <= func_node.end_byte):
234 |                         captures_by_function[func_id]['name'] = self._get_node_text(node)
235 |                         break
236 | 
237 |         # Build function entries
238 |         for func_data in captures_by_function.values():
239 |             func_node = func_data['node']
240 |             name = func_data['name']
241 |             
242 |             if name:
243 |                 args = self._parse_method_parameters(func_node)
244 | 
245 |                 # Get context and docstring
246 |                 context, context_type, _ = self._get_parent_context(func_node)
247 |                 class_context = context if context_type in ('class', 'module') else None
248 |                 docstring = self._get_docstring(func_node)
249 | 
250 |                 functions.append({
251 |                     "name": name,
252 |                     "line_number": func_node.start_point[0] + 1,
253 |                     "end_line": func_node.end_point[0] + 1,
254 |                     "args": args,
255 |                     "source": self._get_node_text(func_node),
256 |                     "source_code": self._get_node_text(func_node),
257 |                     "docstring": docstring,
258 |                     "cyclomatic_complexity": self._calculate_complexity(func_node),
259 |                     "context": context,
260 |                     "context_type": context_type,
261 |                     "class_context": class_context,
262 |                     "decorators": [],
263 |                     "lang": self.language_name,
264 |                     "is_dependency": False,
265 |                 })
266 | 
267 |         return functions
268 | 
269 |     def _find_classes(self, root_node: Any) -> list[Dict[str, Any]]:
270 |         """Find all class and module definitions."""
271 |         classes = []
272 |         query = self.queries["classes"]
273 |         
274 |         # Collect all captures first
275 |         all_captures = list(query.captures(root_node))
276 |         
277 |         # Group captures by class node using a different approach
278 |         captures_by_class = {}
279 |         for node, capture_name in all_captures:
280 |             if capture_name == 'class':
281 |                 captures_by_class[id(node)] = {'node': node, 'name': None}
282 |         
283 |         # Now find names for each class
284 |         for node, capture_name in all_captures:
285 |             if capture_name == 'name':
286 |                 # Find which class this name belongs to
287 |                 for class_id, class_data in captures_by_class.items():
288 |                     class_node = class_data['node']
289 |                     # Check if this name node is within the class node
290 |                     if (node.start_byte >= class_node.start_byte and 
291 |                         node.end_byte <= class_node.end_byte):
292 |                         captures_by_class[class_id]['name'] = self._get_node_text(node)
293 |                         break
294 | 
295 |         # Build class entries
296 |         for class_data in captures_by_class.values():
297 |             class_node = class_data['node']
298 |             name = class_data['name']
299 |             
300 |             if name:
301 |                 # Get superclass for inheritance (simplified)
302 |                 bases = []
303 | 
304 |                 # Get docstring
305 |                 docstring = self._get_docstring(class_node)
306 | 
307 |                 classes.append({
308 |                     "name": name,
309 |                     "line_number": class_node.start_point[0] + 1,
310 |                     "end_line": class_node.end_point[0] + 1,
311 |                     "bases": bases,
312 |                     "source": self._get_node_text(class_node),
313 |                     "source_code": self._get_node_text(class_node),
314 |                     "docstring": docstring,
315 |                     "context": None,
316 |                     "decorators": [],
317 |                     "lang": self.language_name,
318 |                     "is_dependency": False,
319 |                 })
320 | 
321 |         return classes
322 | 
323 |     def _find_imports(self, root_node: Any) -> list[Dict[str, Any]]:
324 |         """Find all require/load statements."""
325 |         imports = []
326 |         query = self.queries["imports"]
327 |         
328 |         # Collect all captures first
329 |         all_captures = list(query.captures(root_node))
330 |         
331 |         # Group captures by import node using a different approach
332 |         captures_by_import = {}
333 |         for node, capture_name in all_captures:
334 |             if capture_name == 'import':
335 |                 captures_by_import[id(node)] = {'node': node, 'method_name': None, 'path': None}
336 |         
337 |         # Now find method names and paths for each import
338 |         for node, capture_name in all_captures:
339 |             if capture_name == 'method_name':
340 |                 # Find which import this method name belongs to
341 |                 for import_id, import_data in captures_by_import.items():
342 |                     import_node = import_data['node']
343 |                     # Check if this method name node is within the import node
344 |                     if (node.start_byte >= import_node.start_byte and 
345 |                         node.end_byte <= import_node.end_byte):
346 |                         captures_by_import[import_id]['method_name'] = self._get_node_text(node)
347 |                         break
348 |             elif capture_name == 'path':
349 |                 # Find which import this path belongs to
350 |                 for import_id, import_data in captures_by_import.items():
351 |                     import_node = import_data['node']
352 |                     # Check if this path node is within the import node
353 |                     if (node.start_byte >= import_node.start_byte and 
354 |                         node.end_byte <= import_node.end_byte):
355 |                         captures_by_import[import_id]['path'] = self._get_node_text(node)
356 |                         break
357 | 
358 |         # Build import entries
359 |         for import_data in captures_by_import.values():
360 |             import_node = import_data['node']
361 |             method_name = import_data['method_name']
362 |             path = import_data['path']
363 |             
364 |             if method_name and path:
365 |                 path = path.strip('\'"')
366 |                 
367 |                 # Only process require/load statements
368 |                 if method_name in ('require', 'require_relative', 'load'):
369 |                     imports.append({
370 |                         "name": path,
371 |                         "full_import_name": f"{method_name} '{path}'",
372 |                         "line_number": import_node.start_point[0] + 1,
373 |                         "alias": None,
374 |                         "lang": self.language_name,
375 |                         "is_dependency": False,
376 |                     })
377 | 
378 |         return imports
379 | 
380 |     def _find_calls(self, root_node: Any) -> list[Dict[str, Any]]:
381 |         """Find all function and method calls."""
382 |         calls = []
383 |         query = self.queries["calls"]
384 |         
385 |         for node, capture_name in query.captures(root_node):
386 |             if capture_name == 'name':
387 |                 name = self._get_node_text(node)
388 |                 full_name = name
389 | 
390 |                 calls.append({
391 |                     "name": name,
392 |                     "full_name": full_name,
393 |                     "line_number": node.start_point[0] + 1,
394 |                     "args": [],  # Placeholder - could be enhanced to extract arguments
395 |                     "inferred_obj_type": None,
396 |                     "context": None,  # Placeholder
397 |                     "class_context": None,  # Placeholder
398 |                     "lang": self.language_name,
399 |                     "is_dependency": False,
400 |                 })
401 | 
402 |         return calls
403 | 
404 |     def _find_variables(self, root_node: Any) -> list[Dict[str, Any]]:
405 |         """Find all variable assignments."""
406 |         variables = []
407 |         query = self.queries["variables"]
408 |         
409 |         # Group captures by assignment node
410 |         captures_by_assignment = {}
411 |         for node, capture_name in query.captures(root_node):
412 |             if capture_name == 'name':
413 |                 # Find the parent assignment node
414 |                 current = node.parent
415 |                 while current and current.type != 'assignment':
416 |                     current = current.parent
417 |                 if current:
418 |                     assignment_id = id(current)
419 |                     if assignment_id not in captures_by_assignment:
420 |                         captures_by_assignment[assignment_id] = {'node': current, 'name': None, 'value': None}
421 |                     captures_by_assignment[assignment_id]['name'] = self._get_node_text(node)
422 |             elif capture_name == 'value':
423 |                 # Find the parent assignment node
424 |                 current = node.parent
425 |                 while current and current.type != 'assignment':
426 |                     current = current.parent
427 |                 if current:
428 |                     assignment_id = id(current)
429 |                     if assignment_id not in captures_by_assignment:
430 |                         captures_by_assignment[assignment_id] = {'node': current, 'name': None, 'value': None}
431 |                     captures_by_assignment[assignment_id]['value'] = self._get_node_text(node)
432 | 
433 |         # Build variable entries
434 |         for var_data in captures_by_assignment.values():
435 |             name = var_data['name']
436 |             value = var_data['value']
437 |             
438 |             if name:
439 |                 # Determine variable type based on name prefix
440 |                 var_type = "local"
441 |                 if name.startswith("@"):
442 |                     var_type = "instance"
443 |                 elif name.startswith("@@"):
444 |                     var_type = "class"
445 |                 elif name.startswith("$"):
446 |                     var_type = "global"
447 | 
448 |                 variables.append({
449 |                     "name": name,
450 |                     "line_number": var_data['node'].start_point[0] + 1,
451 |                     "value": value,
452 |                     "type": var_type,
453 |                     "context": None,  # Placeholder
454 |                     "class_context": None,  # Placeholder
455 |                     "lang": self.language_name,
456 |                     "is_dependency": False,
457 |                 })
458 | 
459 |         return variables
460 | 
461 | 
462 | def pre_scan_ruby(files: list[Path], parser_wrapper) -> dict:
463 |     """Scans Ruby files to create a map of class/method names to their file paths."""
464 |     imports_map = {}
465 |     query_str = """
466 |         (class
467 |             name: (constant) @name
468 |         )
469 |         (module
470 |             name: (constant) @name
471 |         )
472 |         (method
473 |             name: (identifier) @name
474 |         )
475 |     """
476 |     query = parser_wrapper.language.query(query_str)
477 | 
478 |     for file_path in files:
479 |         try:
480 |             with open(file_path, "r", encoding="utf-8") as f:
481 |                 tree = parser_wrapper.parser.parse(bytes(f.read(), "utf8"))
482 | 
483 |             for capture, _ in query.captures(tree.root_node):
484 |                 name = capture.text.decode('utf-8')
485 |                 if name not in imports_map:
486 |                     imports_map[name] = []
487 |                 imports_map[name].append(str(file_path.resolve()))
488 |         except Exception as e:
489 |             warning_logger(f"Tree-sitter pre-scan failed for {file_path}: {e}")
490 |     
491 |     return imports_map
492 | 
```
Page 9/18FirstPrevNextLast