#
tokens: 47449/50000 8/367 files (page 8/14)
lines: off (toggle) GitHub
raw markdown copy
This is page 8 of 14. Use http://codebase.md/shashankss1205/codegraphcontext?lines=false&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/python.py:
--------------------------------------------------------------------------------

```python
import os
import tempfile
import nbformat
from nbconvert import PythonExporter
from pathlib import Path
from typing import Any, Dict, Optional, Tuple
import ast
from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger, debug_logger


PY_QUERIES = {
    "imports": """
        (import_statement name: (_) @import)
        (import_from_statement) @from_import_stmt
    """,
    "classes": """
        (class_definition
            name: (identifier) @name
            superclasses: (argument_list)? @superclasses
            body: (block) @body)
    """,
    "functions": """
        (function_definition
            name: (identifier) @name
            parameters: (parameters) @parameters
            body: (block) @body
            return_type: (_)? @return_type)
    """,
    "calls": """
        (call
            function: (identifier) @name)
        (call
            function: (attribute attribute: (identifier) @name) @full_call)
    """,
    "variables": """
        (assignment
            left: (identifier) @name)
    """,
    "lambda_assignments": """
        (assignment
            left: (identifier) @name
            right: (lambda) @lambda_node)
    """,
    "docstrings": """
        (expression_statement (string) @docstring)
    """,
}

class PythonTreeSitterParser:
    """A Python-specific parser using tree-sitter, encapsulating language-specific logic."""

    def __init__(self, generic_parser_wrapper):
        self.generic_parser_wrapper = generic_parser_wrapper
        self.language_name = generic_parser_wrapper.language_name
        self.language = generic_parser_wrapper.language
        self.parser = generic_parser_wrapper.parser

        self.queries = {
            name: self.language.query(query_str)
            for name, query_str in PY_QUERIES.items()
        }

    def _get_node_text(self, node) -> str:
        return node.text.decode('utf-8')

    def _get_parent_context(self, node, types=('function_definition', 'class_definition')):
        curr = node.parent
        while curr:
            if curr.type in types:
                name_node = curr.child_by_field_name('name')
                return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
            curr = curr.parent
        return None, None, None

    def _calculate_complexity(self, node):
        complexity_nodes = {
            "if_statement", "for_statement", "while_statement", "except_clause",
            "with_statement", "boolean_operator", "list_comprehension", 
            "generator_expression", "case_clause"
        }
        count = 1
        
        def traverse(n):
            nonlocal count
            if n.type in complexity_nodes:
                count += 1
            for child in n.children:
                traverse(child)
        
        traverse(node)
        return count

    def _get_docstring(self, body_node):
        if body_node and body_node.child_count > 0:
            first_child = body_node.children[0]
            if first_child.type == 'expression_statement' and first_child.children[0].type == 'string':
                try:
                    return ast.literal_eval(self._get_node_text(first_child.children[0]))
                except (ValueError, SyntaxError):
                    return self._get_node_text(first_child.children[0])
        return None

    def parse(self, file_path: Path, is_dependency: bool = False, is_notebook: bool = False) -> Dict:
        """Parses a file and returns its structure in a standardized dictionary format."""
        original_file_path = file_path
        temp_py_file = None
        source_code = None

        try:
            if is_notebook:
                info_logger(f"Converting notebook {file_path} to temporary Python file.")
                with open(file_path, 'r', encoding='utf-8') as f:
                    notebook_node = nbformat.read(f, as_version=4)
                
                exporter = PythonExporter()
                python_code, _ = exporter.from_notebook_node(notebook_node)

                with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.py', encoding='utf-8') as tf:
                    tf.write(python_code)
                    temp_py_file = Path(tf.name)
                
                # The file to be parsed is now the temporary file
                file_path = temp_py_file

            with open(file_path, "r", encoding="utf-8") as f:
                source_code = f.read()
            
            tree = self.parser.parse(bytes(source_code, "utf8"))
            root_node = tree.root_node

            functions = self._find_functions(root_node)
            functions.extend(self._find_lambda_assignments(root_node))
            classes = self._find_classes(root_node)
            imports = self._find_imports(root_node)
            function_calls = self._find_calls(root_node)
            variables = self._find_variables(root_node)

            return {
                "file_path": str(original_file_path), # Always return the original path
                "functions": functions,
                "classes": classes,
                "variables": variables,
                "imports": imports,
                "function_calls": function_calls,
                "is_dependency": is_dependency,
                "lang": self.language_name,
            }
        except Exception as e:
            error_logger(f"Failed to parse {original_file_path}: {e}")
            return {"file_path": str(original_file_path), "error": str(e)}
        finally:
            if temp_py_file and temp_py_file.exists():
                os.remove(temp_py_file)
                info_logger(f"Removed temporary file: {temp_py_file}")

    def _find_lambda_assignments(self, root_node):
        functions = []
        query = self.queries.get('lambda_assignments')
        if not query: return []

        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]

            if capture_name == 'name':
                assignment_node = node.parent
                lambda_node = assignment_node.child_by_field_name('right')
                name = self._get_node_text(node)
                params_node = lambda_node.child_by_field_name('parameters')
                
                context, context_type, _ = self._get_parent_context(assignment_node)
                class_context, _, _ = self._get_parent_context(assignment_node, types=('class_definition',))

                func_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": assignment_node.end_point[0] + 1,
                    "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 [],
                    "source": self._get_node_text(assignment_node),
                    "source_code": self._get_node_text(assignment_node),
                    "docstring": None,
                    "cyclomatic_complexity": 1,
                    "context": context,
                    "context_type": context_type,
                    "class_context": class_context,
                    "decorators": [],
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                functions.append(func_data)
        return functions

    def _find_functions(self, root_node):
        functions = []
        query = self.queries['functions']
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]

            if capture_name == 'name':
                func_node = node.parent
                name = self._get_node_text(node)
                params_node = func_node.child_by_field_name('parameters')
                body_node = func_node.child_by_field_name('body')
                
                decorators = [self._get_node_text(child) for child in func_node.children if child.type == 'decorator']

                context, context_type, _ = self._get_parent_context(func_node)
                class_context, _, _ = self._get_parent_context(func_node, types=('class_definition',))

                args = []
                if params_node:
                    for p in params_node.children:
                        arg_text = None
                        if p.type == 'identifier':
                            arg_text = self._get_node_text(p)
                        elif p.type == 'default_parameter':
                            name_node = p.child_by_field_name('name')
                            if name_node:
                                arg_text = self._get_node_text(name_node)
                        if arg_text:
                            args.append(arg_text)

                func_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": func_node.end_point[0] + 1,
                    "args": args,
                    "source": self._get_node_text(func_node),
                    "source_code": self._get_node_text(func_node),
                    "docstring": self._get_docstring(body_node),
                    "cyclomatic_complexity": self._calculate_complexity(func_node),
                    "context": context,
                    "context_type": context_type,
                    "class_context": class_context,
                    "decorators": [d for d in decorators if d],
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                functions.append(func_data)
        return functions

    def _find_classes(self, root_node):
        classes = []
        query = self.queries['classes']
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]

            if capture_name == 'name':
                class_node = node.parent
                name = self._get_node_text(node)
                body_node = class_node.child_by_field_name('body')
                superclasses_node = class_node.child_by_field_name('superclasses')
                
                bases = []
                if superclasses_node:
                    bases = [self._get_node_text(child) for child in superclasses_node.children if child.type in ('identifier', 'attribute')]

                decorators = [self._get_node_text(child) for child in class_node.children if child.type == 'decorator']

                context, _, _ = self._get_parent_context(class_node)

                class_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": class_node.end_point[0] + 1,
                    "bases": [b for b in bases if b],
                    "source": self._get_node_text(class_node),
                    "docstring": self._get_docstring(body_node),
                    "context": context,
                    "decorators": [d for d in decorators if d],
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                classes.append(class_data)
        return classes

    def _find_imports(self, root_node):
        imports = []
        seen_modules = set()
        query = self.queries['imports']
        for node, capture_name in query.captures(root_node):
            if capture_name in ('import', 'from_import_stmt'):
                # For 'import_statement'
                if capture_name == 'import':
                    node_text = self._get_node_text(node)
                    alias = None
                    if ' as ' in node_text:
                        parts = node_text.split(' as ')
                        full_name = parts[0].strip()
                        alias = parts[1].strip()
                    else:
                        full_name = node_text.strip()

                    if full_name in seen_modules:
                        continue
                    seen_modules.add(full_name)

                    import_data = {
                        "name": full_name,
                        "full_import_name": full_name,
                        "line_number": node.start_point[0] + 1,
                        "alias": alias,
                        "context": self._get_parent_context(node)[:2],
                        "lang": self.language_name,
                        "is_dependency": False,
                    }
                    imports.append(import_data)
                # For 'import_from_statement'
                elif capture_name == 'from_import_stmt':
                    module_name_node = node.child_by_field_name('module_name')
                    if not module_name_node: continue
                    
                    module_name = self._get_node_text(module_name_node)
                    
                    # Handle 'from ... import ...'
                    import_list_node = node.child_by_field_name('name')
                    if import_list_node:
                        for child in import_list_node.children:
                            imported_name = None
                            alias = None
                            if child.type == 'aliased_import':
                                name_node = child.child_by_field_name('name')
                                alias_node = child.child_by_field_name('alias')
                                if name_node: imported_name = self._get_node_text(name_node)
                                if alias_node: alias = self._get_node_text(alias_node)
                            elif child.type == 'dotted_name' or child.type == 'identifier':
                                imported_name = self._get_node_text(child)
                            
                            if imported_name:
                                full_import_name = f"{module_name}.{imported_name}"
                                if full_import_name in seen_modules:                                                                                                
                                    continue                                                                                                                        
                                seen_modules.add(full_import_name) 
                                imports.append({
                                    "name": imported_name,
                                    "full_import_name": full_import_name,
                                    "line_number": child.start_point[0] + 1,
                                    "alias": alias,
                                    "context": self._get_parent_context(child)[:2],
                                    "lang": self.language_name,
                                    "is_dependency": False,
                                })

        return imports

    def _find_calls(self, root_node):
        calls = []
        query = self.queries['calls']
        for node, capture_name in query.captures(root_node):
            if capture_name == 'name':
                call_node = node.parent if node.parent.type == 'call' else node.parent.parent
                full_call_node = call_node.child_by_field_name('function')
                
                args = []
                arguments_node = call_node.child_by_field_name('arguments')
                if arguments_node:
                    for arg in arguments_node.children:
                        arg_text = self._get_node_text(arg)
                        if arg_text is not None:
                            args.append(arg_text)

                call_data = {
                    "name": self._get_node_text(node),
                    "full_name": self._get_node_text(full_call_node),
                    "line_number": node.start_point[0] + 1,
                    "args": args,
                    "inferred_obj_type": None, # Type inference is a complex topic to be added
                    "context": self._get_parent_context(node),
                    "class_context": self._get_parent_context(node, types=('class_definition',))[:2],
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                calls.append(call_data)
        return calls

    def _find_variables(self, root_node):
        variables = []
        query = self.queries['variables']
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]

            if capture_name == 'name':
                assignment_node = node.parent

                # Skip lambda assignments, they are handled by _find_lambda_assignments
                right_node = assignment_node.child_by_field_name('right')
                if right_node and right_node.type == 'lambda':
                    continue

                name = self._get_node_text(node)
                value = self._get_node_text(right_node) if right_node else None
                
                type_node = assignment_node.child_by_field_name('type')
                type_text = self._get_node_text(type_node) if type_node else None

                context, _, _ = self._get_parent_context(node)
                class_context, _, _ = self._get_parent_context(node, types=('class_definition',))

                variable_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "value": value,
                    "type": type_text,
                    "context": context,
                    "class_context": class_context,
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                variables.append(variable_data)
        return variables

def pre_scan_python(files: list[Path], parser_wrapper) -> dict:
    """Scans Python files to create a map of class/function names to their file paths."""
    imports_map = {}
    query_str = """
        (class_definition name: (identifier) @name)
        (function_definition name: (identifier) @name)
    """
    query = parser_wrapper.language.query(query_str)
    
    for file_path in files:
        temp_py_file = None
        try:
            source_to_parse = ""
            if file_path.suffix == '.ipynb':
                with open(file_path, 'r', encoding='utf-8') as f:
                    notebook_node = nbformat.read(f, as_version=4)
                exporter = PythonExporter()
                python_code, _ = exporter.from_notebook_node(notebook_node)
                with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.py', encoding='utf-8') as tf:
                    tf.write(python_code)
                    temp_py_file = Path(tf.name)
                with open(temp_py_file, "r", encoding="utf-8") as f:
                    source_to_parse = f.read()
            else:
                with open(file_path, "r", encoding="utf-8") as f:
                    source_to_parse = f.read()

            tree = parser_wrapper.parser.parse(bytes(source_to_parse, "utf8"))
            
            for capture, _ in query.captures(tree.root_node):
                name = capture.text.decode('utf-8')
                if name not in imports_map:
                    imports_map[name] = []
                imports_map[name].append(str(file_path.resolve()))
        except Exception as e:
            warning_logger(f"Tree-sitter pre-scan failed for {file_path}: {e}")
        finally:
            if temp_py_file and temp_py_file.exists():
                os.remove(temp_py_file)
    return imports_map
```

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

```python
from pathlib import Path
from typing import Any, Dict, Optional, Tuple
from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger

C_QUERIES = {
    "functions": """
        (function_definition
            declarator: (function_declarator
                declarator: (identifier) @name
            )
        ) @function_node
        
        (function_definition
            declarator: (function_declarator
                declarator: (pointer_declarator
                    declarator: (identifier) @name
                )
            )
        ) @function_node
    """,
    "structs": """
        (struct_specifier
            name: (type_identifier) @name
        ) @struct
    """,
    "unions": """
        (union_specifier
            name: (type_identifier) @name
        ) @union
    """,
    "enums": """
        (enum_specifier
            name: (type_identifier) @name
        ) @enum
    """,
    "typedefs": """
        (type_definition
            declarator: (type_identifier) @name
        ) @typedef
    """,
    "imports": """
        (preproc_include
            path: [
                (string_literal) @path
                (system_lib_string) @path
            ]
        ) @import
    """,
    "calls": """
        (call_expression
            function: (identifier) @name
        )
    """,
    "variables": """
        (declaration
            declarator: (init_declarator
                declarator: (identifier) @name
            )
        )
        
        (declaration
            declarator: (init_declarator
                declarator: (pointer_declarator
                    declarator: (identifier) @name
                )
            )
        )
        
        (declaration
            declarator: (identifier) @name
        )
        
        (declaration
            declarator: (pointer_declarator
                declarator: (identifier) @name
            )
        )
    """,
    "macros": """
        (preproc_def
            name: (identifier) @name
        ) @macro
    """,
}

class CTreeSitterParser:
    """A C-specific parser using tree-sitter."""

    def __init__(self, generic_parser_wrapper: Any):
        self.generic_parser_wrapper = generic_parser_wrapper
        self.language_name = "c"
        self.language = generic_parser_wrapper.language
        self.parser = generic_parser_wrapper.parser

        self.queries = {
            name: self.language.query(query_str)
            for name, query_str in C_QUERIES.items()
        }

    def _get_node_text(self, node: Any) -> str:
        return node.text.decode("utf-8")

    def parse(self, file_path: Path, is_dependency: bool = False) -> Dict[str, Any]:
        """Parses a C file and returns its structure."""
        with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
            source_code = f.read()

        tree = self.parser.parse(bytes(source_code, "utf8"))
        root_node = tree.root_node

        functions = self._find_functions(root_node)
        classes = self._find_structs_unions_enums(root_node)
        imports = self._find_imports(root_node)
        function_calls = self._find_calls(root_node)
        variables = self._find_variables(root_node)
        macros = self._find_macros(root_node)

        return {
            "file_path": str(file_path),
            "functions": functions,
            "classes": classes,
            "variables": variables,
            "imports": imports,
            "function_calls": function_calls,
            "macros": macros,
            "is_dependency": is_dependency,
            "lang": self.language_name,
        }

    def _get_parent_context(self, node: Any, types: tuple = ('function_definition', 'struct_specifier', 'union_specifier', 'enum_specifier')) -> tuple:
        """Get parent context for nested constructs."""
        curr = node.parent
        while curr:
            if curr.type in types:
                name_node = curr.child_by_field_name('name')
                if name_node:
                    return self._get_node_text(name_node), curr.type, curr.start_point[0] + 1
            curr = curr.parent
        return None, None, None

    def _calculate_complexity(self, node: Any) -> int:
        """Calculate cyclomatic complexity for C functions."""
        complexity_nodes = {
            "if_statement", "for_statement", "while_statement", "do_statement",
            "switch_statement", "case_statement", "conditional_expression",
            "logical_expression", "binary_expression", "goto_statement"
        }
        count = 1
        
        def traverse(n):
            nonlocal count
            if n.type in complexity_nodes:
                count += 1
            for child in n.children:
                traverse(child)
        
        traverse(node)
        return count

    def _get_docstring(self, node: Any) -> Optional[str]:
        """Extract comments as documentation."""
        # Look for comments before the node
        if node.parent:
            for child in node.parent.children:
                if child.type == 'comment' and child.start_point[0] < node.start_point[0]:
                    return self._get_node_text(child)
        return None

    def _parse_function_args(self, params_node: Any) -> list[Dict[str, Any]]:
        """Enhanced helper to parse function arguments from a (parameter_list) node."""
        args = []
        if not params_node:
            return args
            
        for param in params_node.named_children:
            if param.type == "parameter_declaration":
                arg_info: Dict[str, Any] = {"name": "", "type": None, "is_pointer": False, "is_array": False}
                
                # Find the declarator (variable name)
                declarator = param.child_by_field_name("declarator")
                if declarator:
                    if declarator.type == "identifier":
                        arg_info["name"] = self._get_node_text(declarator)
                    elif declarator.type == "pointer_declarator":
                        arg_info["is_pointer"] = True
                        inner_declarator = declarator.child_by_field_name("declarator")
                        if inner_declarator and inner_declarator.type == "identifier":
                            arg_info["name"] = self._get_node_text(inner_declarator)
                    elif declarator.type == "array_declarator":
                        arg_info["is_array"] = True
                        inner_declarator = declarator.child_by_field_name("declarator")
                        if inner_declarator and inner_declarator.type == "identifier":
                            arg_info["name"] = self._get_node_text(inner_declarator)
                
                # Find the type
                type_node = param.child_by_field_name("type")
                if type_node:
                    arg_info["type"] = self._get_node_text(type_node)
                
                # Handle variadic arguments
                if param.type == "variadic_parameter":
                    arg_info["name"] = "..."
                    arg_info["type"] = "variadic"
                
                args.append(arg_info)
        return args

    def _find_functions(self, root_node: Any) -> list[Dict[str, Any]]:
        functions = []
        query = self.queries["functions"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == 'name':
                func_node = node.parent.parent.parent
                name = self._get_node_text(node)
                
                # Find parameters
                params_node = None
                body_node = None
                for child in func_node.children:
                    if child.type == "function_declarator":
                        params_node = child.child_by_field_name("parameters")
                    elif child.type == "compound_statement":
                        body_node = child
                
                args = self._parse_function_args(params_node) if params_node else []
                context, context_type, _ = self._get_parent_context(func_node)

                functions.append({
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": func_node.end_point[0] + 1,
                    "args": [arg["name"] for arg in args if arg["name"]],  # Simplified args for compatibility
                    "source": self._get_node_text(func_node),
                    "source_code": self._get_node_text(func_node),
                    "docstring": self._get_docstring(func_node),
                    "cyclomatic_complexity": self._calculate_complexity(func_node),
                    "context": context,
                    "context_type": context_type,
                    "class_context": None,
                    "decorators": [],
                    "lang": self.language_name,
                    "is_dependency": False,
                    "detailed_args": args,  # Keep detailed args for future use
                })
        return functions

    def _find_structs_unions_enums(self, root_node: Any) -> list[Dict[str, Any]]:
        """Find structs, unions, and enums (treated as classes in C)."""
        classes = []
        
        # Find structs
        query = self.queries["structs"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == 'name':
                struct_node = node.parent
                name = self._get_node_text(node)
                context, context_type, _ = self._get_parent_context(struct_node)
                
                classes.append({
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": struct_node.end_point[0] + 1,
                    "bases": [],  # C doesn't have inheritance
                    "source": self._get_node_text(struct_node),
                    "docstring": self._get_docstring(struct_node),
                    "context": context,
                    "decorators": [],
                    "lang": self.language_name,
                    "is_dependency": False,
                    "type": "struct",
                })

        # Find unions
        query = self.queries["unions"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == 'name':
                union_node = node.parent
                name = self._get_node_text(node)
                context, context_type, _ = self._get_parent_context(union_node)
                
                classes.append({
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": union_node.end_point[0] + 1,
                    "bases": [],
                    "source": self._get_node_text(union_node),
                    "docstring": self._get_docstring(union_node),
                    "context": context,
                    "decorators": [],
                    "lang": self.language_name,
                    "is_dependency": False,
                    "type": "union",
                })

        # Find enums
        query = self.queries["enums"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == 'name':
                enum_node = node.parent
                name = self._get_node_text(node)
                context, context_type, _ = self._get_parent_context(enum_node)
                
                classes.append({
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": enum_node.end_point[0] + 1,
                    "bases": [],
                    "source": self._get_node_text(enum_node),
                    "docstring": self._get_docstring(enum_node),
                    "context": context,
                    "decorators": [],
                    "lang": self.language_name,
                    "is_dependency": False,
                    "type": "enum",
                })

        return classes

    def _find_imports(self, root_node: Any) -> list[Dict[str, Any]]:
        imports = []
        query = self.queries["imports"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == 'path':
                path = self._get_node_text(node).strip('"<>')
                context, context_type, _ = self._get_parent_context(node)
                
                imports.append({
                    "name": path,
                    "full_import_name": path,
                    "line_number": node.start_point[0] + 1,
                    "alias": None,
                    "context": context,
                    "lang": self.language_name,
                    "is_dependency": False,
                })
        return imports

    def _find_calls(self, root_node: Any) -> list[Dict[str, Any]]:
        """Enhanced function call detection."""
        calls = []
        query = self.queries["calls"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == "name":
                call_node = node.parent if node.parent.type == "call_expression" else node.parent.parent
                call_name = self._get_node_text(node)
                
                # Extract arguments
                args = []
                args_node = call_node.child_by_field_name("arguments")
                if args_node:
                    for child in args_node.children:
                        if child.type not in ['(', ')', ',']:
                            args.append(self._get_node_text(child))
                
                context, context_type, _ = self._get_parent_context(call_node)
                
                calls.append({
                    "name": call_name,
                    "full_name": call_name,  # For C, function name is the same as full name
                    "line_number": node.start_point[0] + 1,
                    "args": args,
                    "inferred_obj_type": None,
                    "context": context,
                    "class_context": None,
                    "lang": self.language_name,
                    "is_dependency": False,
                })
        return calls

    def _find_variables(self, root_node: Any) -> list[Dict[str, Any]]:
        """Enhanced variable declaration detection."""
        variables = []
        query = self.queries["variables"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == "name":
                var_name = self._get_node_text(node)
                
                # Find the declaration node
                decl_node = node.parent
                while decl_node and decl_node.type != "declaration":
                    decl_node = decl_node.parent
                
                # Extract type information
                var_type = None
                is_pointer = False
                is_array = False
                value = None
                
                if decl_node:
                    # Find type
                    for child in decl_node.children:
                        if child.type in ["primitive_type", "type_identifier", "sized_type_specifier"]:
                            var_type = self._get_node_text(child)
                        elif child.type == "init_declarator":
                            # Check for pointer/array
                            if child.child_by_field_name("declarator"):
                                declarator = child.child_by_field_name("declarator")
                                if declarator.type == "pointer_declarator":
                                    is_pointer = True
                                elif declarator.type == "array_declarator":
                                    is_array = True
                            
                            # Check for initial value
                            if child.child_by_field_name("value"):
                                value = self._get_node_text(child.child_by_field_name("value"))
                
                context, context_type, _ = self._get_parent_context(node)
                class_context, _, _ = self._get_parent_context(node, types=('struct_specifier', 'union_specifier', 'enum_specifier'))
                
                variables.append({
                    "name": var_name,
                    "line_number": node.start_point[0] + 1,
                    "value": value,
                    "type": var_type,
                    "context": context,
                    "class_context": class_context,
                    "lang": self.language_name,
                    "is_dependency": False,
                    "is_pointer": is_pointer,
                    "is_array": is_array,
                })
        return variables

    def _find_macros(self, root_node: Any) -> list[Dict[str, Any]]:
        """Enhanced preprocessor macro detection."""
        macros = []
        query = self.queries["macros"]
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == 'name':
                macro_node = node.parent
                name = self._get_node_text(node)
                
                # Extract macro value
                value = None
                if macro_node.child_by_field_name("value"):
                    value = self._get_node_text(macro_node.child_by_field_name("value"))
                
                # Extract parameters for function-like macros
                params = []
                if macro_node.child_by_field_name("parameters"):
                    params_node = macro_node.child_by_field_name("parameters")
                    for child in params_node.children:
                        if child.type == "identifier":
                            params.append(self._get_node_text(child))
                
                context, context_type, _ = self._get_parent_context(macro_node)
                
                macros.append({
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": macro_node.end_point[0] + 1,
                    "source": self._get_node_text(macro_node),
                    "value": value,
                    "params": params,
                    "context": context,
                    "lang": self.language_name,
                    "is_dependency": False,
                })
        return macros


def pre_scan_c(files: list[Path], parser_wrapper) -> dict:
    """Scans C files to create a map of function/struct/union/enum names to their file paths."""
    imports_map = {}
    query_str = """
        (function_definition
            declarator: (function_declarator
                declarator: (identifier) @name
            )
        )
        
        (function_definition
            declarator: (function_declarator
                declarator: (pointer_declarator
                    declarator: (identifier) @name
                )
            )
        )
        
        (struct_specifier
            name: (type_identifier) @name
        )
        
        (union_specifier
            name: (type_identifier) @name
        )
        
        (enum_specifier
            name: (type_identifier) @name
        )
        
        (type_definition
            declarator: (type_identifier) @name
        )
        
        (preproc_def
            name: (identifier) @name
        )
    """
    query = parser_wrapper.language.query(query_str)
    
    for file_path in files:
        try:
            with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
                tree = parser_wrapper.parser.parse(bytes(f.read(), "utf8"))
            
            for capture, _ in query.captures(tree.root_node):
                name = capture.text.decode('utf-8')
                if name not in imports_map:
                    imports_map[name] = []
                imports_map[name].append(str(file_path.resolve()))
        except Exception as e:
            warning_logger(f"Tree-sitter pre-scan failed for {file_path}: {e}")
    return imports_map

```

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

```html

<!doctype html>
<html lang="en" class="no-js">
  <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      
      
      
      
        <link rel="prev" href="../server/">
      
      
        <link rel="next" href="../tools/">
      
      
      <link rel="icon" href="../assets/images/favicon.png">
      <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.21">
    
    
      
        <title>Core Concepts - CodeGraphContext</title>
      
    
    
      <link rel="stylesheet" href="../assets/stylesheets/main.2a3383ac.min.css">
      
      


    
    
      
    
    
      
        
        
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <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">
        <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
      
    
    
    <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>
    
      

    
    
    
  </head>
  
  
    <body dir="ltr">
  
    
    <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
    <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
    <label class="md-overlay" for="__drawer"></label>
    <div data-md-component="skip">
      
        
        <a href="#core-concepts" class="md-skip">
          Skip to content
        </a>
      
    </div>
    <div data-md-component="announce">
      
    </div>
    
    
      

  

<header class="md-header md-header--shadow" data-md-component="header">
  <nav class="md-header__inner md-grid" aria-label="Header">
    <a href=".." title="CodeGraphContext" class="md-header__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    <label class="md-header__button md-icon" for="__drawer">
      
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
    </label>
    <div class="md-header__title" data-md-component="header-title">
      <div class="md-header__ellipsis">
        <div class="md-header__topic">
          <span class="md-ellipsis">
            CodeGraphContext
          </span>
        </div>
        <div class="md-header__topic" data-md-component="header-topic">
          <span class="md-ellipsis">
            
              Core Concepts
            
          </span>
        </div>
      </div>
    </div>
    
    
      <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>
    
    
    
      
      
        <label class="md-header__button md-icon" for="__search">
          
          <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>
        </label>
        <div class="md-search" data-md-component="search" role="dialog">
  <label class="md-search__overlay" for="__search"></label>
  <div class="md-search__inner" role="search">
    <form class="md-search__form" name="search">
      <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>
      <label class="md-search__icon md-icon" for="__search">
        
        <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>
        
        <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>
      </label>
      <nav class="md-search__options" aria-label="Search">
        
        <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
          
          <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>
        </button>
      </nav>
      
    </form>
    <div class="md-search__output">
      <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
        <div class="md-search-result" data-md-component="search-result">
          <div class="md-search-result__meta">
            Initializing search
          </div>
          <ol class="md-search-result__list" role="presentation"></ol>
        </div>
      </div>
    </div>
  </div>
</div>
      
    
    
  </nav>
  
</header>
    
    <div class="md-container" data-md-component="container">
      
      
        
          
        
      
      <main class="md-main" data-md-component="main">
        <div class="md-main__inner md-grid">
          
            
              
              <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    



<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
  <label class="md-nav__title" for="__drawer">
    <a href=".." title="CodeGraphContext" class="md-nav__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    CodeGraphContext
  </label>
  
  <ul class="md-nav__list" data-md-scrollfix>
    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href=".." class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Home
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../installation/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Installation
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../use_cases/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Use Cases
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../architecture/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Architecture
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cli/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    CLI Reference
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../server/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Server
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
    
  
  
  
    <li class="md-nav__item md-nav__item--active">
      
      <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
      
      
        
      
      
        <label class="md-nav__link md-nav__link--active" for="__toc">
          
  
  
  <span class="md-ellipsis">
    Core Concepts
    
  </span>
  

          <span class="md-nav__icon md-icon"></span>
        </label>
      
      <a href="./" class="md-nav__link md-nav__link--active">
        
  
  
  <span class="md-ellipsis">
    Core Concepts
    
  </span>
  

      </a>
      
        

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
    
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#databasemanager" class="md-nav__link">
    <span class="md-ellipsis">
      DatabaseManager
    </span>
  </a>
  
    <nav class="md-nav" aria-label="DatabaseManager">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#key-methods" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#jobmanager" class="md-nav__link">
    <span class="md-ellipsis">
      JobManager
    </span>
  </a>
  
    <nav class="md-nav" aria-label="JobManager">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#jobstatus" class="md-nav__link">
    <span class="md-ellipsis">
      JobStatus
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#jobinfo" class="md-nav__link">
    <span class="md-ellipsis">
      JobInfo
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#key-methods_1" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#codewatcher" class="md-nav__link">
    <span class="md-ellipsis">
      CodeWatcher
    </span>
  </a>
  
    <nav class="md-nav" aria-label="CodeWatcher">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#repositoryeventhandler" class="md-nav__link">
    <span class="md-ellipsis">
      RepositoryEventHandler
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#key-methods_2" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
    </ul>
  
</nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../tools/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Tools
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cookbook/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Cookbook
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    
    
    
    
    
    <li class="md-nav__item md-nav__item--nested">
      
        
        
        <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_10" >
        
          
          <label class="md-nav__link" for="__nav_10" id="__nav_10_label" tabindex="0">
            
  
  
  <span class="md-ellipsis">
    Contributing
    
  </span>
  

            <span class="md-nav__icon md-icon"></span>
          </label>
        
        <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_10_label" aria-expanded="false">
          <label class="md-nav__title" for="__nav_10">
            <span class="md-nav__icon md-icon"></span>
            Contributing
          </label>
          <ul class="md-nav__list" data-md-scrollfix>
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Overview
    
  </span>
  

      </a>
    </li>
  

              
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing_languages/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Adding New Languages
    
  </span>
  

      </a>
    </li>
  

              
            
          </ul>
        </nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../troubleshooting/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Troubleshooting
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../future_work/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Future Work
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../license/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    License
    
  </span>
  

      </a>
    </li>
  

    
  </ul>
</nav>
                  </div>
                </div>
              </div>
            
            
              
              <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
    
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#databasemanager" class="md-nav__link">
    <span class="md-ellipsis">
      DatabaseManager
    </span>
  </a>
  
    <nav class="md-nav" aria-label="DatabaseManager">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#key-methods" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#jobmanager" class="md-nav__link">
    <span class="md-ellipsis">
      JobManager
    </span>
  </a>
  
    <nav class="md-nav" aria-label="JobManager">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#jobstatus" class="md-nav__link">
    <span class="md-ellipsis">
      JobStatus
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#jobinfo" class="md-nav__link">
    <span class="md-ellipsis">
      JobInfo
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#key-methods_1" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#codewatcher" class="md-nav__link">
    <span class="md-ellipsis">
      CodeWatcher
    </span>
  </a>
  
    <nav class="md-nav" aria-label="CodeWatcher">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#repositoryeventhandler" class="md-nav__link">
    <span class="md-ellipsis">
      RepositoryEventHandler
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#key-methods_2" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
    </ul>
  
</nav>
                  </div>
                </div>
              </div>
            
          
          
            <div class="md-content" data-md-component="content">
              <article class="md-content__inner md-typeset">
                
                  



<h1 id="core-concepts">Core Concepts</h1>
<p>The core of CodeGraphContext is built upon a few key components that manage the database connection, handle background tasks, and watch for file system changes.</p>
<h2 id="databasemanager"><code>DatabaseManager</code></h2>
<p>The <code>DatabaseManager</code> class in <code>database.py</code> is a thread-safe singleton responsible for managing the connection to the Neo4j database. This ensures that only one connection pool is created and shared across the application, which is crucial for performance and resource management.</p>
<h3 id="key-methods">Key Methods</h3>
<ul>
<li><code>get_driver()</code>: Returns the active Neo4j Driver instance, creating it if it doesn't exist.</li>
<li><code>close_driver()</code>: Closes the Neo4j driver connection.</li>
<li><code>is_connected()</code>: Checks if the database connection is currently active.</li>
</ul>
<h2 id="jobmanager"><code>JobManager</code></h2>
<p>The <code>JobManager</code> class in <code>jobs.py</code> handles long-running, background jobs, such as code indexing. It stores job information in memory and provides a thread-safe way to create, update, and retrieve information about these jobs.</p>
<h3 id="jobstatus"><code>JobStatus</code></h3>
<p>An enumeration for the possible statuses of a background job:
- <code>PENDING</code>
- <code>RUNNING</code>
- <code>COMPLETED</code>
- <code>FAILED</code>
- <code>CANCELLED</code></p>
<h3 id="jobinfo"><code>JobInfo</code></h3>
<p>A data class that holds all information about a single background job, including its ID, status, start/end times, progress, and any errors.</p>
<h3 id="key-methods_1">Key Methods</h3>
<ul>
<li><code>create_job()</code>: Creates a new job with a unique ID.</li>
<li><code>update_job()</code>: Updates the information for a specific job.</li>
<li><code>get_job()</code>: Retrieves the information for a single job.</li>
<li><code>list_jobs()</code>: Returns a list of all jobs.</li>
<li><code>cleanup_old_jobs()</code>: Removes old, completed jobs from memory.</li>
</ul>
<h2 id="codewatcher"><code>CodeWatcher</code></h2>
<p>The <code>CodeWatcher</code> class in <code>watcher.py</code> implements the live file-watching functionality using the <code>watchdog</code> library. It observes directories for changes and triggers updates to the code graph.</p>
<h3 id="repositoryeventhandler"><code>RepositoryEventHandler</code></h3>
<p>A dedicated event handler for a single repository. It performs an initial scan and then uses a debouncing mechanism to efficiently handle file changes, creations, or deletions.</p>
<h3 id="key-methods_2">Key Methods</h3>
<ul>
<li><code>watch_directory()</code>: Schedules a directory to be watched for changes.</li>
<li><code>unwatch_directory()</code>: Stops watching a directory.</li>
<li><code>list_watched_paths()</code>: Returns a list of all currently watched directory paths.</li>
<li><code>start()</code>: Starts the observer thread.</li>
<li><code>stop()</code>: Stops the observer thread gracefully.</li>
</ul>












                
              </article>
            </div>
          
          
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
        </div>
        
      </main>
      
        <footer class="md-footer">
  
  <div class="md-footer-meta md-typeset">
    <div class="md-footer-meta__inner md-grid">
      <div class="md-copyright">
  
  
    Made with
    <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
      Material for MkDocs
    </a>
  
</div>
      
    </div>
  </div>
</footer>
      
    </div>
    <div class="md-dialog" data-md-component="dialog">
      <div class="md-dialog__inner md-typeset"></div>
    </div>
    
    
    
      
      <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>
    
    
      <script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
      
    
  </body>
</html>
```

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

```python
from pathlib import Path
from typing import Dict
from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger, debug_logger

TS_QUERIES = {
    "functions": """
        (function_declaration
            name: (identifier) @name
            parameters: (formal_parameters) @params
        ) @function_node

        (variable_declarator
            name: (identifier) @name
            value: (function
                parameters: (formal_parameters) @params
            ) @function_node
        )

        (variable_declarator
            name: (identifier) @name
            value: (arrow_function
                parameters: (formal_parameters) @params
            ) @function_node
        )

        (variable_declarator
            name: (identifier) @name
            value: (arrow_function
                parameter: (identifier) @single_param
            ) @function_node
        )

        (method_definition
            name: (property_identifier) @name
            parameters: (formal_parameters) @params
        ) @function_node

        (assignment_expression
            left: (member_expression
                property: (property_identifier) @name
            )
            right: (function
                parameters: (formal_parameters) @params
            ) @function_node
        )

        (assignment_expression
            left: (member_expression
                property: (property_identifier) @name
            )
            right: (arrow_function
                parameters: (formal_parameters) @params
            ) @function_node
        )
    """,
    "classes": """
        (class_declaration) @class
        (class) @class
    """,
    "interfaces": """
        (interface_declaration
            name: (type_identifier) @name
        ) @interface_node
    """,
    "type_aliases": """
        (type_alias_declaration
            name: (type_identifier) @name
        ) @type_alias_node
    """,
    "imports": """
        (import_statement) @import
        (call_expression
            function: (identifier) @require_call (#eq? @require_call "require")
        ) @import
    """,
    "calls": """
        (call_expression function: (identifier) @name)
        (call_expression function: (member_expression property: (property_identifier) @name))
    """,
    "variables": """
        (variable_declarator name: (identifier) @name)
    """,
    "docstrings": """
        (comment) @docstring_comment
    """,
}

def is_typescript_file(file_path: Path) -> bool:
    return file_path.suffix in {".ts", ".tsx"}

class TypescriptTreeSitterParser:
    """A TypeScript-specific parser using tree-sitter, encapsulating language-specific logic."""

    def __init__(self, generic_parser_wrapper):
        self.generic_parser_wrapper = generic_parser_wrapper
        self.language_name = generic_parser_wrapper.language_name
        self.language = generic_parser_wrapper.language
        self.parser = generic_parser_wrapper.parser

        self.queries = {
            name: self.language.query(query_str)
            for name, query_str in TS_QUERIES.items()
        }

    def _get_node_text(self, node) -> str:
        return node.text.decode('utf-8')

    def _get_parent_context(self, node, types=('function_declaration', 'class_declaration')):
        curr = node.parent
        while curr:
            if curr.type in types:
                name_node = curr.child_by_field_name('name')
                return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
            curr = curr.parent
        return None, None, None

    def _calculate_complexity(self, node):
        complexity_nodes = {
            "if_statement", "for_statement", "while_statement", "do_statement",
            "switch_statement", "case_statement", "conditional_expression",
            "logical_expression", "binary_expression", "catch_clause"
        }
        count = 1
        def traverse(n):
            nonlocal count
            if n.type in complexity_nodes:
                count += 1
            for child in n.children:
                traverse(child)
        traverse(node)
        return count

    def _get_docstring(self, body_node):
        return None

    def parse(self, file_path: Path, is_dependency: bool = False) -> Dict:
        with open(file_path, "r", encoding="utf-8") as f:
            source_code = f.read()
        tree = self.parser.parse(bytes(source_code, "utf8"))
        root_node = tree.root_node

        functions = self._find_functions(root_node)
        classes = self._find_classes(root_node)
        interfaces = self._find_interfaces(root_node)
        type_aliases = self._find_type_aliases(root_node)
        imports = self._find_imports(root_node)
        function_calls = self._find_calls(root_node)
        variables = self._find_variables(root_node)

        return {
            "file_path": str(file_path),
            "functions": functions,
            "classes": classes,
            "interfaces": interfaces,
            "type_aliases": type_aliases,
            "variables": variables,
            "imports": imports,
            "function_calls": function_calls,
            "is_dependency": is_dependency,
            "lang": self.language_name,
        }


    def _find_functions(self, root_node):
        functions = []
        query = self.queries['functions']
        def _fn_for_name(name_node):
            current = name_node.parent
            while current:
                if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
                    return current
                elif current.type in ('variable_declarator', 'assignment_expression'):
                    for child in current.children:
                        if child.type in ('function', 'arrow_function'):
                            return child
                current = current.parent
            return None
        def _fn_for_params(params_node):
            current = params_node.parent
            while current:
                if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
                    return current
                current = current.parent
            return None
        def _key(n):
            return (n.start_byte, n.end_byte, n.type)
        captures_by_function = {}
        def _bucket_for(node):
            fid = id(node)
            return captures_by_function.setdefault(fid, {
                'node': node, 'name': None, 'params': None, 'single_param': None
            })
        for node, capture_name in query.captures(root_node):
            if capture_name == 'function_node':
                _bucket_for(node)
            elif capture_name == 'name':
                fn = _fn_for_name(node)
                if fn:
                    b = _bucket_for(fn)
                    b['name'] = self._get_node_text(node)
            elif capture_name == 'params':
                fn = _fn_for_params(node)
                if fn:
                    b = _bucket_for(fn)
                    b['params'] = node
            elif capture_name == 'single_param':
                fn = _fn_for_params(node)
                if fn:
                    b = _bucket_for(fn)
                    b['single_param'] = node
        for _, data in captures_by_function.items():
            func_node = data['node']
            name = data.get('name')
            if not name and func_node.type == 'method_definition':
                nm = func_node.child_by_field_name('name')
                if nm:
                    name = self._get_node_text(nm)
            if not name:
                continue
            args = []
            if data.get('params'):
                args = self._extract_parameters(data['params'])
            elif data.get('single_param'):
                args = [self._get_node_text(data['single_param'])]
            context, context_type, _ = self._get_parent_context(func_node)
            class_context = context if context_type == 'class_declaration' else None
            docstring = None
            func_data = {
                "name": name,
                "line_number": func_node.start_point[0] + 1,
                "end_line": func_node.end_point[0] + 1,
                "args": args,
                "source": self._get_node_text(func_node),
                "source_code": self._get_node_text(func_node),
                "docstring": docstring,
                "cyclomatic_complexity": self._calculate_complexity(func_node),
                "context": context,
                "context_type": context_type,
                "class_context": class_context,
                "decorators": [],
                "lang": self.language_name,
                "is_dependency": False,
            }
            functions.append(func_data)
        return functions

    def _extract_parameters(self, params_node):
        params = []
        if params_node.type == 'formal_parameters':
            for child in params_node.children:
                if child.type == 'identifier':
                    params.append(self._get_node_text(child))
                elif child.type == 'assignment_pattern':
                    left_child = child.child_by_field_name('left')
                    if left_child and left_child.type == 'identifier':
                        params.append(self._get_node_text(left_child))
                elif child.type == 'rest_pattern':
                    argument = child.child_by_field_name('argument')
                    if argument and argument.type == 'identifier':
                        params.append(f"...{self._get_node_text(argument)}")
        return params

    def _find_classes(self, root_node):
        classes = []
        query = self.queries['classes']
        for class_node, capture_name in query.captures(root_node):
            if capture_name == 'class':
                name_node = class_node.child_by_field_name('name')
                if not name_node: continue
                name = self._get_node_text(name_node)
                bases = []
                heritage_node = next((child for child in class_node.children if child.type == 'class_heritage'), None)
                if heritage_node:
                    if heritage_node.named_child_count > 0:
                        base_expr_node = heritage_node.named_child(0)
                        bases.append(self._get_node_text(base_expr_node))
                    elif heritage_node.child_count > 0:
                        base_expr_node = heritage_node.child(heritage_node.child_count - 1)
                        bases.append(self._get_node_text(base_expr_node))
                class_data = {
                    "name": name,
                    "line_number": class_node.start_point[0] + 1,
                    "end_line": class_node.end_point[0] + 1,
                    "bases": bases,
                    "source": self._get_node_text(class_node),
                    "docstring": self._get_docstring(class_node),
                    "context": None,
                    "decorators": [],
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                classes.append(class_data)
        return classes
    
    def _find_interfaces(self, root_node):
        interfaces = []
        query = self.queries['interfaces']
        for node, capture_name in query.captures(root_node):
            if capture_name == 'interface_node':
                name_node = node.child_by_field_name('name')
                if not name_node: continue
                
                name = self._get_node_text(name_node)
                interface_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": node.end_point[0] + 1,
                    "source_code": self._get_node_text(node),
                }
                interfaces.append(interface_data)
        return interfaces

    def _find_type_aliases(self, root_node):
        type_aliases = []
        query = self.queries['type_aliases']
        for node, capture_name in query.captures(root_node):
            if capture_name == 'type_alias_node':
                name_node = node.child_by_field_name('name')
                if not name_node: continue

                name = self._get_node_text(name_node)
                type_alias_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "end_line": node.end_point[0] + 1,
                    "source_code": self._get_node_text(node),
                }
                type_aliases.append(type_alias_data)
        return type_aliases

    def _find_imports(self, root_node):
        imports = []
        query = self.queries['imports']
        for node, capture_name in query.captures(root_node):
            if capture_name != 'import':
                continue
            line_number = node.start_point[0] + 1
            if node.type == 'import_statement':
                source = self._get_node_text(node.child_by_field_name('source')).strip('\'"')
                import_clause = node.child_by_field_name('import')
                if not import_clause:
                    imports.append({'name': source, 'source': source, 'alias': None, 'line_number': line_number,
                                    'lang': self.language_name})
                    continue
                if import_clause.type == 'identifier':
                    alias = self._get_node_text(import_clause)
                    imports.append({'name': 'default', 'source': source, 'alias': alias, 'line_number': line_number,
                                    'lang': self.language_name})
                elif import_clause.type == 'namespace_import':
                    alias_node = import_clause.child_by_field_name('alias')
                    if alias_node:
                        alias = self._get_node_text(alias_node)
                        imports.append({'name': '*', 'source': source, 'alias': alias, 'line_number': line_number,
                                        'lang': self.language_name})
                elif import_clause.type == 'named_imports':
                    for specifier in import_clause.children:
                        if specifier.type == 'import_specifier':
                            name_node = specifier.child_by_field_name('name')
                            alias_node = specifier.child_by_field_name('alias')
                            original_name = self._get_node_text(name_node)
                            alias = self._get_node_text(alias_node) if alias_node else None
                            imports.append(
                                {'name': original_name, 'source': source, 'alias': alias, 'line_number': line_number,
                                 'lang': self.language_name})
            elif node.type == 'call_expression':
                args = node.child_by_field_name('arguments')
                if not args or args.named_child_count == 0: continue
                source_node = args.named_child(0)
                if not source_node or source_node.type != 'string': continue
                source = self._get_node_text(source_node).strip('\'"')
                alias = None
                if node.parent.type == 'variable_declarator':
                    alias_node = node.parent.child_by_field_name('name')
                    if alias_node:
                        alias = self._get_node_text(alias_node)
                imports.append({'name': source, 'source': source, 'alias': alias, 'line_number': line_number,
                                'lang': self.language_name})
        return imports

    def _find_calls(self, root_node):
        calls = []
        query = self.queries['calls']
        for node, capture_name in query.captures(root_node):
            if capture_name == 'name':
                call_node = node.parent
                name = self._get_node_text(node)
                args = []
                call_data = {
                    "name": name,
                    "full_name": self._get_node_text(call_node),
                    "line_number": node.start_point[0] + 1,
                    "args": args,
                    "inferred_obj_type": None,
                    "context": None,
                    "class_context": None,
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                calls.append(call_data)
        return calls

    def _find_variables(self, root_node):
        variables = []
        query = self.queries['variables']
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]
            if capture_name == 'name':
                var_node = node.parent
                name = self._get_node_text(node)
                value = None
                type_text = None
                variable_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "value": value,
                    "type": type_text,
                    "context": None,
                    "class_context": None,
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                variables.append(variable_data)
        return variables

def pre_scan_typescript(files: list[Path], parser_wrapper) -> dict:
    """Scans TypeScript files to create a map of class/function names to their file paths."""
    imports_map = {}
    
    # Simplified queries that capture the parent nodes, then extract names manually
    query_strings = [
        "(class_declaration) @class",
        "(function_declaration) @function",
        "(variable_declarator) @var_decl",
        "(method_definition) @method",
        "(interface_declaration) @interface",
        "(type_alias_declaration) @type_alias",
    ]
    
    for file_path in files:
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                source_code = f.read()
                tree = parser_wrapper.parser.parse(bytes(source_code, "utf8"))
            
            # Run each query separately
            for query_str in query_strings:
                try:
                    query = parser_wrapper.language.query(query_str)
                    for node, capture_name in query.captures(tree.root_node):
                        name = None
                        
                        # Extract name based on node type
                        if capture_name == 'class':
                            name_node = node.child_by_field_name('name')
                            if name_node:
                                name = name_node.text.decode('utf-8')
                        
                        elif capture_name == 'function':
                            name_node = node.child_by_field_name('name')
                            if name_node:
                                name = name_node.text.decode('utf-8')
                        
                        elif capture_name == 'var_decl':
                            # Check if it's a function or arrow function
                            name_node = node.child_by_field_name('name')
                            value_node = node.child_by_field_name('value')
                            if name_node and value_node:
                                if value_node.type in ('function', 'arrow_function'):
                                    name = name_node.text.decode('utf-8')
                        
                        elif capture_name == 'method':
                            name_node = node.child_by_field_name('name')
                            if name_node:
                                name = name_node.text.decode('utf-8')
                        
                        elif capture_name == 'interface':
                            name_node = node.child_by_field_name('name')
                            if name_node:
                                name = name_node.text.decode('utf-8')
                        
                        elif capture_name == 'type_alias':
                            name_node = node.child_by_field_name('name')
                            if name_node:
                                name = name_node.text.decode('utf-8')
                        
                        # Add to imports map if we found a name
                        if name:
                            if name not in imports_map:
                                imports_map[name] = []
                            file_path_str = str(file_path.resolve())
                            if file_path_str not in imports_map[name]:
                                imports_map[name].append(file_path_str)
                                
                except Exception as query_error:
                    warning_logger(f"Query failed for pattern '{query_str}': {query_error}")
                    
        except Exception as e:
            warning_logger(f"Tree-sitter pre-scan failed for {file_path}: {e}")
    
    return imports_map
```

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

```html

<!doctype html>
<html lang="en" class="no-js">
  <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      
      
      
      
        <link rel="prev" href="../use_cases/">
      
      
        <link rel="next" href="../cli/">
      
      
      <link rel="icon" href="../assets/images/favicon.png">
      <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.21">
    
    
      
        <title>Architecture - CodeGraphContext</title>
      
    
    
      <link rel="stylesheet" href="../assets/stylesheets/main.2a3383ac.min.css">
      
      


    
    
      
    
    
      
        
        
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <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">
        <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
      
    
    
    <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>
    
      

    
    
    
  </head>
  
  
    <body dir="ltr">
  
    
    <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
    <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
    <label class="md-overlay" for="__drawer"></label>
    <div data-md-component="skip">
      
        
        <a href="#architecture-documentation" class="md-skip">
          Skip to content
        </a>
      
    </div>
    <div data-md-component="announce">
      
    </div>
    
    
      

  

<header class="md-header md-header--shadow" data-md-component="header">
  <nav class="md-header__inner md-grid" aria-label="Header">
    <a href=".." title="CodeGraphContext" class="md-header__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    <label class="md-header__button md-icon" for="__drawer">
      
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
    </label>
    <div class="md-header__title" data-md-component="header-title">
      <div class="md-header__ellipsis">
        <div class="md-header__topic">
          <span class="md-ellipsis">
            CodeGraphContext
          </span>
        </div>
        <div class="md-header__topic" data-md-component="header-topic">
          <span class="md-ellipsis">
            
              Architecture
            
          </span>
        </div>
      </div>
    </div>
    
    
      <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>
    
    
    
      
      
        <label class="md-header__button md-icon" for="__search">
          
          <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>
        </label>
        <div class="md-search" data-md-component="search" role="dialog">
  <label class="md-search__overlay" for="__search"></label>
  <div class="md-search__inner" role="search">
    <form class="md-search__form" name="search">
      <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>
      <label class="md-search__icon md-icon" for="__search">
        
        <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>
        
        <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>
      </label>
      <nav class="md-search__options" aria-label="Search">
        
        <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
          
          <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>
        </button>
      </nav>
      
    </form>
    <div class="md-search__output">
      <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
        <div class="md-search-result" data-md-component="search-result">
          <div class="md-search-result__meta">
            Initializing search
          </div>
          <ol class="md-search-result__list" role="presentation"></ol>
        </div>
      </div>
    </div>
  </div>
</div>
      
    
    
  </nav>
  
</header>
    
    <div class="md-container" data-md-component="container">
      
      
        
          
        
      
      <main class="md-main" data-md-component="main">
        <div class="md-main__inner md-grid">
          
            
              
              <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    



<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
  <label class="md-nav__title" for="__drawer">
    <a href=".." title="CodeGraphContext" class="md-nav__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    CodeGraphContext
  </label>
  
  <ul class="md-nav__list" data-md-scrollfix>
    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href=".." class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Home
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../installation/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Installation
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../use_cases/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Use Cases
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
    
  
  
  
    <li class="md-nav__item md-nav__item--active">
      
      <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
      
      
        
      
      
        <label class="md-nav__link md-nav__link--active" for="__toc">
          
  
  
  <span class="md-ellipsis">
    Architecture
    
  </span>
  

          <span class="md-nav__icon md-icon"></span>
        </label>
      
      <a href="./" class="md-nav__link md-nav__link--active">
        
  
  
  <span class="md-ellipsis">
    Architecture
    
  </span>
  

      </a>
      
        

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
    
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#high-level-overview" class="md-nav__link">
    <span class="md-ellipsis">
      High-Level Overview
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#backend-architecture" class="md-nav__link">
    <span class="md-ellipsis">
      Backend Architecture
    </span>
  </a>
  
    <nav class="md-nav" aria-label="Backend Architecture">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#core-components" class="md-nav__link">
    <span class="md-ellipsis">
      Core Components
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#tools" class="md-nav__link">
    <span class="md-ellipsis">
      Tools
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#server" class="md-nav__link">
    <span class="md-ellipsis">
      Server
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#cli" class="md-nav__link">
    <span class="md-ellipsis">
      CLI
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#frontend-architecture" class="md-nav__link">
    <span class="md-ellipsis">
      Frontend Architecture
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#testing" class="md-nav__link">
    <span class="md-ellipsis">
      Testing
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cli/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    CLI Reference
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../server/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Server
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../core/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Core Concepts
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../tools/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Tools
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cookbook/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Cookbook
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    
    
    
    
    
    <li class="md-nav__item md-nav__item--nested">
      
        
        
        <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_10" >
        
          
          <label class="md-nav__link" for="__nav_10" id="__nav_10_label" tabindex="0">
            
  
  
  <span class="md-ellipsis">
    Contributing
    
  </span>
  

            <span class="md-nav__icon md-icon"></span>
          </label>
        
        <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_10_label" aria-expanded="false">
          <label class="md-nav__title" for="__nav_10">
            <span class="md-nav__icon md-icon"></span>
            Contributing
          </label>
          <ul class="md-nav__list" data-md-scrollfix>
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Overview
    
  </span>
  

      </a>
    </li>
  

              
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing_languages/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Adding New Languages
    
  </span>
  

      </a>
    </li>
  

              
            
          </ul>
        </nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../troubleshooting/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Troubleshooting
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../future_work/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Future Work
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../license/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    License
    
  </span>
  

      </a>
    </li>
  

    
  </ul>
</nav>
                  </div>
                </div>
              </div>
            
            
              
              <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
    
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#high-level-overview" class="md-nav__link">
    <span class="md-ellipsis">
      High-Level Overview
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#backend-architecture" class="md-nav__link">
    <span class="md-ellipsis">
      Backend Architecture
    </span>
  </a>
  
    <nav class="md-nav" aria-label="Backend Architecture">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#core-components" class="md-nav__link">
    <span class="md-ellipsis">
      Core Components
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#tools" class="md-nav__link">
    <span class="md-ellipsis">
      Tools
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#server" class="md-nav__link">
    <span class="md-ellipsis">
      Server
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#cli" class="md-nav__link">
    <span class="md-ellipsis">
      CLI
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#frontend-architecture" class="md-nav__link">
    <span class="md-ellipsis">
      Frontend Architecture
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#testing" class="md-nav__link">
    <span class="md-ellipsis">
      Testing
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
                  </div>
                </div>
              </div>
            
          
          
            <div class="md-content" data-md-component="content">
              <article class="md-content__inner md-typeset">
                
                  



<h1 id="architecture-documentation">Architecture Documentation</h1>
<p>This document provides a detailed overview of the architecture of the CodeGraphContext project.</p>
<h2 id="high-level-overview">High-Level Overview</h2>
<p>The project is a client-server application designed to analyze and visualize codebases. It consists of:</p>
<ul>
<li><strong>A Python backend:</strong> This is the core of the application, responsible for parsing and analyzing code, building a graph representation of the codebase, and exposing this data through an API.</li>
<li><strong>A web-based frontend:</strong> A user interface for interacting with the backend, visualizing the code graph, and exploring the codebase.</li>
<li><strong>A command-line interface (CLI):</strong> For managing the backend and performing analysis from the terminal.</li>
</ul>
<h2 id="backend-architecture">Backend Architecture</h2>
<p>The backend is a Python application located in the <code>src/codegraphcontext</code> directory.</p>
<h3 id="core-components">Core Components</h3>
<p>The <code>src/codegraphcontext/core</code> directory contains the fundamental building blocks of the backend:</p>
<ul>
<li><strong>Database:</strong> A graph database is used to store the code graph. This allows for efficient querying of relationships between code elements (e.g., function calls, class inheritance).</li>
<li><strong>Jobs:</strong> Asynchronous jobs are used for long-running tasks like indexing a new codebase. This prevents the application from becoming unresponsive.</li>
<li><strong>Watcher:</strong> A file system watcher monitors the codebase for changes and triggers re-indexing, keeping the code graph up-to-date.</li>
</ul>
<h3 id="tools">Tools</h3>
<p>The <code>src/codegraphcontext/tools</code> directory contains the logic for code analysis:</p>
<ul>
<li><strong>Graph Builder:</strong> This component is responsible for parsing the code and building the graph representation that is stored in the database.</li>
<li><strong>Code Finder:</strong> Provides functionality to search for specific code elements within the indexed codebase.</li>
<li><strong>Import Extractor:</strong> This tool analyzes the import statements in the code to understand dependencies between modules.</li>
</ul>
<h3 id="server">Server</h3>
<p>The <code>src/codegraphcontext/server.py</code> file implements the API server. It exposes the functionality of the backend to the frontend through a JSON-RPC API.</p>
<h3 id="cli">CLI</h3>
<p>The <code>src/codegraphcontext/cli</code> directory contains the implementation of the command-line interface. It allows users to:</p>
<ul>
<li>Start and stop the backend server.</li>
<li>Index new projects.</li>
<li>Run analysis tools from the command line.</li>
</ul>
<h2 id="frontend-architecture">Frontend Architecture</h2>
<p>The frontend is a modern web application located in the <code>website/</code> directory.</p>
<ul>
<li><strong>Framework:</strong> It is built using React and TypeScript.</li>
<li><strong>Build Tool:</strong> Vite is used for fast development and building the application.</li>
<li><strong>Component-Based:</strong> The UI is organized into reusable components, located in <code>website/src/components</code>. This includes UI elements like buttons and dialogs, as well as higher-level components for different sections of the application.</li>
<li><strong>Styling:</strong> Tailwind CSS is used for styling the application.</li>
</ul>
<h2 id="testing">Testing</h2>
<p>The <code>tests/</code> directory contains the test suite for the project.</p>
<ul>
<li><strong>Integration Tests:</strong> <code>test_cgc_integration.py</code> contains tests that verify the interaction between different components of the backend.</li>
<li><strong>Unit Tests:</strong> Other files in this directory contain unit tests for specific modules and functions.</li>
<li><strong>Sample Project:</strong> The <code>tests/sample_project</code> directory contains a variety of Python files used as input for testing the code analysis tools.</li>
</ul>












                
              </article>
            </div>
          
          
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
        </div>
        
      </main>
      
        <footer class="md-footer">
  
  <div class="md-footer-meta md-typeset">
    <div class="md-footer-meta__inner md-grid">
      <div class="md-copyright">
  
  
    Made with
    <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
      Material for MkDocs
    </a>
  
</div>
      
    </div>
  </div>
</footer>
      
    </div>
    <div class="md-dialog" data-md-component="dialog">
      <div class="md-dialog__inner md-typeset"></div>
    </div>
    
    
    
      
      <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>
    
    
      <script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
      
    
  </body>
</html>
```

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

```html

<!doctype html>
<html lang="en" class="no-js">
  <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      
      
      
      
        <link rel="prev" href="..">
      
      
        <link rel="next" href="../use_cases/">
      
      
      <link rel="icon" href="../assets/images/favicon.png">
      <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.21">
    
    
      
        <title>Installation - CodeGraphContext</title>
      
    
    
      <link rel="stylesheet" href="../assets/stylesheets/main.2a3383ac.min.css">
      
      


    
    
      
    
    
      
        
        
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <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">
        <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
      
    
    
    <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>
    
      

    
    
    
  </head>
  
  
    <body dir="ltr">
  
    
    <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
    <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
    <label class="md-overlay" for="__drawer"></label>
    <div data-md-component="skip">
      
        
        <a href="#installation-guide" class="md-skip">
          Skip to content
        </a>
      
    </div>
    <div data-md-component="announce">
      
    </div>
    
    
      

  

<header class="md-header md-header--shadow" data-md-component="header">
  <nav class="md-header__inner md-grid" aria-label="Header">
    <a href=".." title="CodeGraphContext" class="md-header__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    <label class="md-header__button md-icon" for="__drawer">
      
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
    </label>
    <div class="md-header__title" data-md-component="header-title">
      <div class="md-header__ellipsis">
        <div class="md-header__topic">
          <span class="md-ellipsis">
            CodeGraphContext
          </span>
        </div>
        <div class="md-header__topic" data-md-component="header-topic">
          <span class="md-ellipsis">
            
              Installation
            
          </span>
        </div>
      </div>
    </div>
    
    
      <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>
    
    
    
      
      
        <label class="md-header__button md-icon" for="__search">
          
          <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>
        </label>
        <div class="md-search" data-md-component="search" role="dialog">
  <label class="md-search__overlay" for="__search"></label>
  <div class="md-search__inner" role="search">
    <form class="md-search__form" name="search">
      <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>
      <label class="md-search__icon md-icon" for="__search">
        
        <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>
        
        <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>
      </label>
      <nav class="md-search__options" aria-label="Search">
        
        <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
          
          <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>
        </button>
      </nav>
      
    </form>
    <div class="md-search__output">
      <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
        <div class="md-search-result" data-md-component="search-result">
          <div class="md-search-result__meta">
            Initializing search
          </div>
          <ol class="md-search-result__list" role="presentation"></ol>
        </div>
      </div>
    </div>
  </div>
</div>
      
    
    
  </nav>
  
</header>
    
    <div class="md-container" data-md-component="container">
      
      
        
          
        
      
      <main class="md-main" data-md-component="main">
        <div class="md-main__inner md-grid">
          
            
              
              <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    



<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
  <label class="md-nav__title" for="__drawer">
    <a href=".." title="CodeGraphContext" class="md-nav__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    CodeGraphContext
  </label>
  
  <ul class="md-nav__list" data-md-scrollfix>
    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href=".." class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Home
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
    
  
  
  
    <li class="md-nav__item md-nav__item--active">
      
      <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
      
      
      
        <label class="md-nav__link md-nav__link--active" for="__toc">
          
  
  
  <span class="md-ellipsis">
    Installation
    
  </span>
  

          <span class="md-nav__icon md-icon"></span>
        </label>
      
      <a href="./" class="md-nav__link md-nav__link--active">
        
  
  
  <span class="md-ellipsis">
    Installation
    
  </span>
  

      </a>
      
        

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#installation-guide" class="md-nav__link">
    <span class="md-ellipsis">
      🧩 Installation Guide
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#prerequisites" class="md-nav__link">
    <span class="md-ellipsis">
      ⚙️ Prerequisites
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#getting-started" class="md-nav__link">
    <span class="md-ellipsis">
      🚀 Getting Started
    </span>
  </a>
  
    <nav class="md-nav" aria-label="🚀 Getting Started">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#1-install-from-pypi" class="md-nav__link">
    <span class="md-ellipsis">
      1. Install from PyPI
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#2-run-the-setup-wizard" class="md-nav__link">
    <span class="md-ellipsis">
      2. Run the Setup Wizard
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#step-by-step-guide-for-the-setup-wizard" class="md-nav__link">
    <span class="md-ellipsis">
      🧭 "Step-by-Step Guide for the Setup Wizard"
    </span>
  </a>
  
    <nav class="md-nav" aria-label="🧭 &#34;Step-by-Step Guide for the Setup Wizard&#34;">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#3-start-the-server" class="md-nav__link">
    <span class="md-ellipsis">
      3. Start the Server
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#next-steps" class="md-nav__link">
    <span class="md-ellipsis">
      Next Steps
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../use_cases/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Use Cases
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../architecture/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Architecture
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cli/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    CLI Reference
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../server/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Server
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../core/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Core Concepts
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../tools/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Tools
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cookbook/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Cookbook
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    
    
    
    
    
    <li class="md-nav__item md-nav__item--nested">
      
        
        
        <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_10" >
        
          
          <label class="md-nav__link" for="__nav_10" id="__nav_10_label" tabindex="0">
            
  
  
  <span class="md-ellipsis">
    Contributing
    
  </span>
  

            <span class="md-nav__icon md-icon"></span>
          </label>
        
        <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_10_label" aria-expanded="false">
          <label class="md-nav__title" for="__nav_10">
            <span class="md-nav__icon md-icon"></span>
            Contributing
          </label>
          <ul class="md-nav__list" data-md-scrollfix>
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Overview
    
  </span>
  

      </a>
    </li>
  

              
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing_languages/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Adding New Languages
    
  </span>
  

      </a>
    </li>
  

              
            
          </ul>
        </nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../troubleshooting/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Troubleshooting
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../future_work/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Future Work
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../license/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    License
    
  </span>
  

      </a>
    </li>
  

    
  </ul>
</nav>
                  </div>
                </div>
              </div>
            
            
              
              <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#installation-guide" class="md-nav__link">
    <span class="md-ellipsis">
      🧩 Installation Guide
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#prerequisites" class="md-nav__link">
    <span class="md-ellipsis">
      ⚙️ Prerequisites
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#getting-started" class="md-nav__link">
    <span class="md-ellipsis">
      🚀 Getting Started
    </span>
  </a>
  
    <nav class="md-nav" aria-label="🚀 Getting Started">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#1-install-from-pypi" class="md-nav__link">
    <span class="md-ellipsis">
      1. Install from PyPI
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#2-run-the-setup-wizard" class="md-nav__link">
    <span class="md-ellipsis">
      2. Run the Setup Wizard
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#step-by-step-guide-for-the-setup-wizard" class="md-nav__link">
    <span class="md-ellipsis">
      🧭 "Step-by-Step Guide for the Setup Wizard"
    </span>
  </a>
  
    <nav class="md-nav" aria-label="🧭 &#34;Step-by-Step Guide for the Setup Wizard&#34;">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#3-start-the-server" class="md-nav__link">
    <span class="md-ellipsis">
      3. Start the Server
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#next-steps" class="md-nav__link">
    <span class="md-ellipsis">
      Next Steps
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
                  </div>
                </div>
              </div>
            
          
          
            <div class="md-content" data-md-component="content">
              <article class="md-content__inner md-typeset">
                
                  



  <h1>Installation</h1>

<h2 id="installation-guide">🧩 Installation Guide</h2>
<p>Welcome to <strong>CodeGraphContext</strong>! This guide provides a clear and seamless path to installing and configuring the tool, from prerequisites to launching your server.</p>
<h2 id="prerequisites">⚙️ Prerequisites</h2>
<p>Ensure the following are installed before you begin:</p>
<ul>
<li><strong>Python</strong>: Version 3.8 or higher.</li>
<li><strong>AI Agentic Coding Tool</strong>: An MCP-compatible AI assistant (e.g., Gemini, Claude) if you plan to use the MCP server.</li>
</ul>
<h2 id="getting-started">🚀 Getting Started</h2>
<p>Follow these steps to set up <strong>CodeGraphContext</strong> effortlessly.</p>
<h3 id="1-install-from-pypi">1. Install from PyPI</h3>
<p>Install the <code>codegraphcontext</code> package directly from PyPI using pip:</p>
<pre><code class="language-bash">pip install codegraphcontext
</code></pre>
<h3 id="2-run-the-setup-wizard">2. Run the Setup Wizard</h3>
<p>Launch the interactive setup wizard to configure your Neo4j database and development environment:</p>
<pre><code class="language-bash">cgc setup
</code></pre>
<p>The wizard guides you through a series of intuitive prompts to tailor your setup.</p>
<h2 id="step-by-step-guide-for-the-setup-wizard">🧭 "Step-by-Step Guide for the Setup Wizard"</h2>
<p>When you run <code>cgc setup</code>, the wizard offers a thoughtful journey through configuration. Follow these steps to complete your setup with ease:</p>
<p><strong>1. Select Your Database Location</strong></p>
<p>Choose where your Neo4j database will reside:</p>
<ul>
<li><strong>Local (Recommended)</strong>: Host Neo4j on your machine for simplicity.  </li>
<li><strong>Docker</strong>: With Docker installed, the wizard crafts a <code>docker-compose.yml</code> file and launches a Neo4j container seamlessly.  </li>
<li><strong>Local Binary</strong>: On Debian-based systems (e.g., Ubuntu) or Mac Systems, the wizard installs Neo4j directly with your permission.  </li>
<li><strong>Hosted</strong>: Connect to a remote Neo4j instance, such as AuraDB, by providing your database URI, username, and password.  </li>
<li><strong>Existing Instance</strong>: For an existing Neo4j server (local or remote), enter its connection credentials.</li>
</ul>
<p><strong>2. Configure Your Development Environment</strong></p>
<p>Integrate CodeGraphContext with your preferred development tool for a harmonious workflow. Select from supported options:</p>
<ul>
<li>VS Code</li>
<li>Cursor</li>
<li>Windsurf</li>
<li>Claude</li>
<li>Gemini CLI</li>
<li>ChatGPT Codex</li>
<li>Cline</li>
<li>RooCode</li>
<li>Amazon Q Developer</li>
</ul>
<p>The wizard automatically updates configuration files to align with your choice.
Upon completing the prompts, the wizard creates two essential files:</p>
<ul>
<li><strong><code>mcp.json</code></strong>: Placed in your working directory, this file configures the MCP server.  </li>
<li><strong><code>.env</code></strong>: Stored securely in <code>~/.codegraphcontext</code>, this file safeguards your Neo4j credentials.</li>
</ul>
<p>These files ensure smooth communication between CodeGraphContext, your Neo4j instance, and your AI assistant.</p>
<h3 id="3-start-the-server">3. Start the Server</h3>
<p>Once configuration is complete, launch the MCP server with:</p>
<pre><code class="language-bash">cgc start
</code></pre>
<p>Your <strong>CodeGraphContext</strong> server is now active, ready to power AI-assisted graph queries.</p>
<h2 id="next-steps">Next Steps</h2>
<p>With <strong>CodeGraphContext</strong> installed and configured, you’re ready to explore its AI-powered capabilities. Happy coding ✨!</p>












                
              </article>
            </div>
          
          
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
        </div>
        
      </main>
      
        <footer class="md-footer">
  
  <div class="md-footer-meta md-typeset">
    <div class="md-footer-meta__inner md-grid">
      <div class="md-copyright">
  
  
    Made with
    <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
      Material for MkDocs
    </a>
  
</div>
      
    </div>
  </div>
</footer>
      
    </div>
    <div class="md-dialog" data-md-component="dialog">
      <div class="md-dialog__inner md-typeset"></div>
    </div>
    
    
    
      
      <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>
    
    
      <script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
      
    
  </body>
</html>
```

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

```python
from pathlib import Path
from typing import Any, Dict, Optional, Tuple
import re
from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger

# --- Helpers to classify JS methods ---
_GETTER_RE = re.compile(r"^\s*(?:static\s+)?get\b")
_SETTER_RE = re.compile(r"^\s*(?:static\s+)?set\b")
_STATIC_RE = re.compile(r"^\s*static\b")


def _first_line_before_body(text: str) -> str:
    """
    Best-effort header extraction: take text before the first '{'
    (covers class/object methods). Fallback to the first line.
    """
    head = text.split("{", 1)[0]
    if not head.strip():
        return text.splitlines()[0] if text.splitlines() else text
    return head


def _classify_method_kind(header: str) -> Optional[str]:
    """
    Return 'getter' | 'setter' | 'static' | None.
    Prefer 'getter'/'setter' over 'static' when both appear.
    """
    if _GETTER_RE.search(header):
        return "getter"
    if _SETTER_RE.search(header):
        return "setter"
    if _STATIC_RE.search(header):
        return "static"
    return None


JS_QUERIES = {
    "functions": """
        (function_declaration 
            name: (identifier) @name
            parameters: (formal_parameters) @params
        ) @function_node
        
        (variable_declarator 
            name: (identifier) @name 
            value: (function 
                parameters: (formal_parameters) @params
            ) @function_node
        )
        
        (variable_declarator 
            name: (identifier) @name 
            value: (arrow_function 
                parameters: (formal_parameters) @params
            ) @function_node
        )
        
        (variable_declarator 
            name: (identifier) @name 
            value: (arrow_function 
                parameter: (identifier) @single_param
            ) @function_node
        )
        
        (method_definition 
            name: (property_identifier) @name
            parameters: (formal_parameters) @params
        ) @function_node
        
        (assignment_expression
            left: (member_expression 
                property: (property_identifier) @name
            )
            right: (function
                parameters: (formal_parameters) @params
            ) @function_node
        )
        
        (assignment_expression
            left: (member_expression 
                property: (property_identifier) @name
            )
            right: (arrow_function
                parameters: (formal_parameters) @params
            ) @function_node
        )
    """,
    "classes": """
        (class_declaration) @class
        (class) @class
    """,
    "imports": """
        (import_statement) @import
        (call_expression
            function: (identifier) @require_call (#eq? @require_call "require")
        ) @import
    """,
    "calls": """
        (call_expression function: (identifier) @name)
        (call_expression function: (member_expression property: (property_identifier) @name))
    """,
    "variables": """
        (variable_declarator name: (identifier) @name)
    """,
    "docstrings": """
        (comment) @docstring_comment
    """,
}


class JavascriptTreeSitterParser:
    """A JavaScript-specific parser using tree-sitter, encapsulating language-specific logic."""

    def __init__(self, generic_parser_wrapper):
        self.generic_parser_wrapper = generic_parser_wrapper
        self.language_name = generic_parser_wrapper.language_name
        self.language = generic_parser_wrapper.language
        self.parser = generic_parser_wrapper.parser

        self.queries = {
            name: self.language.query(query_str)
            for name, query_str in JS_QUERIES.items()
        }

    def _get_node_text(self, node) -> str:
        return node.text.decode('utf-8')

    def _get_parent_context(self, node, types=('function_declaration', 'class_declaration')):
        # JS specific context types
        curr = node.parent
        while curr:
            if curr.type in types:
                name_node = curr.child_by_field_name('name')
                return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
            curr = curr.parent
        return None, None, None

    def _calculate_complexity(self, node):
        # JS specific complexity nodes
        complexity_nodes = {
            "if_statement", "for_statement", "while_statement", "do_statement",
            "switch_statement", "case_statement", "conditional_expression",
            "logical_expression", "binary_expression", "catch_clause"
        }
        count = 1

        def traverse(n):
            nonlocal count
            if n.type in complexity_nodes:
                count += 1
            for child in n.children:
                traverse(child)

        traverse(node)
        return count

    def _get_docstring(self, body_node):
        # JS specific docstring extraction (e.g., JSDoc comments)
        # This is a placeholder and needs more sophisticated logic
        return None

    def parse(self, file_path: Path, is_dependency: bool = False) -> Dict:
        """Parses a file and returns its structure in a standardized dictionary format."""
        with open(file_path, "r", encoding="utf-8") as f:
            source_code = f.read()

        tree = self.parser.parse(bytes(source_code, "utf8"))
        root_node = tree.root_node

        functions = self._find_functions(root_node)
        classes = self._find_classes(root_node)
        imports = self._find_imports(root_node)
        function_calls = self._find_calls(root_node)
        variables = self._find_variables(root_node)

        return {
            "file_path": str(file_path),
            "functions": functions,
            "classes": classes,
            "variables": variables,
            "imports": imports,
            "function_calls": function_calls,
            "is_dependency": is_dependency,
            "lang": self.language_name,
        }

    def _find_functions(self, root_node):
        functions = []
        query = self.queries['functions']

    # Local helpers so we don't depend on class attrs being present
        def _fn_for_name(name_node):
            current = name_node.parent
            while current:
                if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
                    return current
                elif current.type in ('variable_declarator', 'assignment_expression'):
                    for child in current.children:
                        if child.type in ('function', 'arrow_function'):
                            return child
                current = current.parent
            return None

        def _fn_for_params(params_node):
            current = params_node.parent
            while current:
                if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
                    return current
                current = current.parent
            return None
        # stable keys so the same function only gets one bucket
        def _key(n):  # start/end byte + type is stable across captures
            return (n.start_byte, n.end_byte, n.type)

        # Collect captures grouped by function node
        captures_by_function = {}
        def _bucket_for(node):
            fid = id(node)
            return captures_by_function.setdefault(fid, {
                'node': node, 'name': None, 'params': None, 'single_param': None
            })

        for node, capture_name in query.captures(root_node):
            if capture_name == 'function_node':
                _bucket_for(node)
            elif capture_name == 'name':
                fn = _fn_for_name(node)
                if fn:
                    b = _bucket_for(fn)
                    b['name'] = self._get_node_text(node)
            elif capture_name == 'params':
                fn = _fn_for_params(node)
                if fn:
                    b = _bucket_for(fn)
                    b['params'] = node
            elif capture_name == 'single_param':
                fn = _fn_for_params(node)
                if fn:
                    b = _bucket_for(fn)
                    b['single_param'] = node

        # Build Function entries
        for _, data in captures_by_function.items():
            func_node = data['node']

            # Backfill name for method_definition if query didn't capture it
            name = data.get('name')
            if not name and func_node.type == 'method_definition':
                nm = func_node.child_by_field_name('name')
                if nm:
                    name = self._get_node_text(nm)
            if not name:
                continue  # skip nameless functions

            # Parameters
            args = []
            if data.get('params'):
                args = self._extract_parameters(data['params'])
            elif data.get('single_param'):
                args = [self._get_node_text(data['single_param'])]

            # Context & docstring
            context, context_type, _ = self._get_parent_context(func_node)
            class_context = context if context_type == 'class_declaration' else None
            docstring = self._get_jsdoc_comment(func_node)

            # Classify getter/setter/static (methods only)
            js_kind = None
            if func_node.type == 'method_definition':
                header = _first_line_before_body(self._get_node_text(func_node))
                js_kind = _classify_method_kind(header)

            func_data = {
                "name": name,
                "line_number": func_node.start_point[0] + 1,
                "end_line": func_node.end_point[0] + 1,
                "args": args,
                "source": self._get_node_text(func_node),
                "source_code": self._get_node_text(func_node),
                "docstring": docstring,
                "cyclomatic_complexity": self._calculate_complexity(func_node),
                "context": context,
                "context_type": context_type,
                "class_context": class_context,
                "decorators": [],
                "lang": self.language_name,
                "is_dependency": False,
            }
            if js_kind is not None:
                func_data["type"] = js_kind

            functions.append(func_data)

        return functions



    def _find_function_node_for_name(self, name_node):
        """Find the function node that contains this name node."""
        current = name_node.parent
        while current:
            if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
                return current
            elif current.type in ('variable_declarator', 'assignment_expression'):
                # Check if this declarator/assignment contains a function
                for child in current.children:
                    if child.type in ('function', 'arrow_function'):
                        return child
            current = current.parent
        return None


    def _find_function_node_for_params(self, params_node):
        """Find the function node that contains this parameters node."""
        current = params_node.parent
        while current:
            if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
                return current
            current = current.parent

        return None


    def _extract_parameters(self, params_node):
        """Extract parameter names from formal_parameters node."""
        params = []
        if params_node.type == 'formal_parameters':
            for child in params_node.children:
                if child.type == 'identifier':
                    params.append(self._get_node_text(child))
                elif child.type == 'assignment_pattern':
                    # Default parameter: param = defaultValue
                    left_child = child.child_by_field_name('left')
                    if left_child and left_child.type == 'identifier':
                        params.append(self._get_node_text(left_child))
                elif child.type == 'rest_pattern':
                    # Rest parameter: ...args
                    argument = child.child_by_field_name('argument')
                    if argument and argument.type == 'identifier':
                        params.append(f"...{self._get_node_text(argument)}")
        return params


    def _get_jsdoc_comment(self, func_node):
        """Extract JSDoc comment preceding the function."""
        # Look for comments before the function
        prev_sibling = func_node.prev_sibling
        while prev_sibling and prev_sibling.type in ('comment', '\n', ' '):
            if prev_sibling.type == 'comment':
                comment_text = self._get_node_text(prev_sibling)
                if comment_text.startswith('/**') and comment_text.endswith('*/'):
                    return comment_text.strip()
            prev_sibling = prev_sibling.prev_sibling
        return None


    def _find_classes(self, root_node):
        classes = []
        query = self.queries['classes']
        for class_node, capture_name in query.captures(root_node):
            if capture_name == 'class':
                name_node = class_node.child_by_field_name('name')
                if not name_node: continue
                name = self._get_node_text(name_node)

                bases = []
                heritage_node = next((child for child in class_node.children if child.type == 'class_heritage'), None)
                if heritage_node:
                    if heritage_node.named_child_count > 0:
                        base_expr_node = heritage_node.named_child(0)
                        bases.append(self._get_node_text(base_expr_node))
                    elif heritage_node.child_count > 0:
                        # Fallback for anonymous nodes
                        base_expr_node = heritage_node.child(heritage_node.child_count - 1)
                        bases.append(self._get_node_text(base_expr_node))

                class_data = {
                    "name": name,
                    "line_number": class_node.start_point[0] + 1,
                    "end_line": class_node.end_point[0] + 1,
                    "bases": bases,
                    "source": self._get_node_text(class_node),
                    "docstring": self._get_docstring(class_node),
                    "context": None,
                    "decorators": [],
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                classes.append(class_data)
        return classes


    def _find_imports(self, root_node):
        imports = []
        query = self.queries['imports']
        for node, capture_name in query.captures(root_node):
            if capture_name != 'import':
                continue

            line_number = node.start_point[0] + 1

            if node.type == 'import_statement':
                source = self._get_node_text(node.child_by_field_name('source')).strip('\'"')

                # Look for different import structures
                import_clause = node.child_by_field_name('import')
                if not import_clause:
                    imports.append({'name': source, 'source': source, 'alias': None, 'line_number': line_number,
                                    'lang': self.language_name})
                    continue

                # Default import: import defaultExport from '...'
                if import_clause.type == 'identifier':
                    alias = self._get_node_text(import_clause)
                    imports.append({'name': 'default', 'source': source, 'alias': alias, 'line_number': line_number,
                                    'lang': self.language_name})

                # Namespace import: import * as name from '...'
                elif import_clause.type == 'namespace_import':
                    alias_node = import_clause.child_by_field_name('alias')
                    if alias_node:
                        alias = self._get_node_text(alias_node)
                        imports.append({'name': '*', 'source': source, 'alias': alias, 'line_number': line_number,
                                        'lang': self.language_name})

                # Named imports: import { name, name as alias } from '...'
                elif import_clause.type == 'named_imports':
                    for specifier in import_clause.children:
                        if specifier.type == 'import_specifier':
                            name_node = specifier.child_by_field_name('name')
                            alias_node = specifier.child_by_field_name('alias')
                            original_name = self._get_node_text(name_node)
                            alias = self._get_node_text(alias_node) if alias_node else None
                            imports.append(
                                {'name': original_name, 'source': source, 'alias': alias, 'line_number': line_number,
                                 'lang': self.language_name})

            elif node.type == 'call_expression':  # require('...')
                args = node.child_by_field_name('arguments')
                if not args or args.named_child_count == 0: continue
                source_node = args.named_child(0)
                if not source_node or source_node.type != 'string': continue
                source = self._get_node_text(source_node).strip('\'"')

                alias = None
                if node.parent.type == 'variable_declarator':
                    alias_node = node.parent.child_by_field_name('name')
                    if alias_node:
                        alias = self._get_node_text(alias_node)
                imports.append({'name': source, 'source': source, 'alias': alias, 'line_number': line_number,
                                'lang': self.language_name})

        return imports


    def _find_calls(self, root_node):
        calls = []
        query = self.queries['calls']
        for node, capture_name in query.captures(root_node):
            # Placeholder for JS call extraction logic
            if capture_name == 'name':
                call_node = node.parent
                name = self._get_node_text(node)

                # Simplified args extraction for now
                args = []

                call_data = {
                    "name": name,
                    "full_name": self._get_node_text(call_node),  # This might need refinement
                    "line_number": node.start_point[0] + 1,
                    "args": args,
                    "inferred_obj_type": None,
                    "context": None,  # Placeholder
                    "class_context": None,  # Placeholder
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                calls.append(call_data)
        return calls


    def _find_variables(self, root_node):
        variables = []
        query = self.queries['variables']
        for match in query.captures(root_node):
            capture_name = match[1]
            node = match[0]

            # Placeholder for JS variable extraction logic
            if capture_name == 'name':
                var_node = node.parent
                name = self._get_node_text(node)
                value = None 
                type_text = None  # Placeholder


                # Detect if variable assigned to a function
                value_node = var_node.child_by_field_name("value") if var_node else None

                if value_node:
                    value_type = value_node.type

                    # --- Skip variables that are assigned a function ---
                    if value_type in ("function_expression", "arrow_function"):
                        continue

                    # --- Handle various assignment types ---
                    if value_type == "call_expression":
                        func_name_node = value_node.child_by_field_name("name")
                        func_name = (
                            self._get_node_text(func_name_node) 
                            if func_name_node
                            else name
                        )
                        value = func_name
                    else:
                        # Anything else (e.g. binary expressions)
                        value = self._get_node_text(value_node)

                variable_data = {
                    "name": name,
                    "line_number": node.start_point[0] + 1,
                    "value": value,
                    "type": type_text,
                    "context": None,  # Placeholder
                    "class_context": None,  # Placeholder
                    "lang": self.language_name,
                    "is_dependency": False,
                }
                variables.append(variable_data)
        return variables


def pre_scan_javascript(files: list[Path], parser_wrapper) -> dict:
    """Scans JavaScript files to create a map of class/function names to their file paths."""
    imports_map = {}
    query_str = """
        (class_declaration name: (identifier) @name)
        (function_declaration name: (identifier) @name)
        (variable_declarator name: (identifier) @name value: (function))
        (variable_declarator name: (identifier) @name value: (arrow_function))
        (method_definition name: (property_identifier) @name)
        (assignment_expression
            left: (member_expression 
                property: (property_identifier) @name
            )
            right: (function)
        )
        (assignment_expression
            left: (member_expression 
                property: (property_identifier) @name
            )
            right: (arrow_function)
        )
    """
    query = parser_wrapper.language.query(query_str)

    for file_path in files:
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                tree = parser_wrapper.parser.parse(bytes(f.read(), "utf8"))

            for capture, _ in query.captures(tree.root_node):
                name = capture.text.decode('utf-8')
                if name not in imports_map:
                    imports_map[name] = []
                imports_map[name].append(str(file_path.resolve()))
        except Exception as e:
            warning_logger(f"Tree-sitter pre-scan failed for {file_path}: {e}")
    return imports_map

```

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

```html

<!doctype html>
<html lang="en" class="no-js">
  <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      
      
      
      
        <link rel="prev" href="../core/">
      
      
        <link rel="next" href="../cookbook/">
      
      
      <link rel="icon" href="../assets/images/favicon.png">
      <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.21">
    
    
      
        <title>Tools - CodeGraphContext</title>
      
    
    
      <link rel="stylesheet" href="../assets/stylesheets/main.2a3383ac.min.css">
      
      


    
    
      
    
    
      
        
        
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <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">
        <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
      
    
    
    <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>
    
      

    
    
    
  </head>
  
  
    <body dir="ltr">
  
    
    <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
    <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
    <label class="md-overlay" for="__drawer"></label>
    <div data-md-component="skip">
      
        
        <a href="#tools" class="md-skip">
          Skip to content
        </a>
      
    </div>
    <div data-md-component="announce">
      
    </div>
    
    
      

  

<header class="md-header md-header--shadow" data-md-component="header">
  <nav class="md-header__inner md-grid" aria-label="Header">
    <a href=".." title="CodeGraphContext" class="md-header__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    <label class="md-header__button md-icon" for="__drawer">
      
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
    </label>
    <div class="md-header__title" data-md-component="header-title">
      <div class="md-header__ellipsis">
        <div class="md-header__topic">
          <span class="md-ellipsis">
            CodeGraphContext
          </span>
        </div>
        <div class="md-header__topic" data-md-component="header-topic">
          <span class="md-ellipsis">
            
              Tools
            
          </span>
        </div>
      </div>
    </div>
    
    
      <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>
    
    
    
      
      
        <label class="md-header__button md-icon" for="__search">
          
          <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>
        </label>
        <div class="md-search" data-md-component="search" role="dialog">
  <label class="md-search__overlay" for="__search"></label>
  <div class="md-search__inner" role="search">
    <form class="md-search__form" name="search">
      <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>
      <label class="md-search__icon md-icon" for="__search">
        
        <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>
        
        <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>
      </label>
      <nav class="md-search__options" aria-label="Search">
        
        <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
          
          <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>
        </button>
      </nav>
      
    </form>
    <div class="md-search__output">
      <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
        <div class="md-search-result" data-md-component="search-result">
          <div class="md-search-result__meta">
            Initializing search
          </div>
          <ol class="md-search-result__list" role="presentation"></ol>
        </div>
      </div>
    </div>
  </div>
</div>
      
    
    
  </nav>
  
</header>
    
    <div class="md-container" data-md-component="container">
      
      
        
          
        
      
      <main class="md-main" data-md-component="main">
        <div class="md-main__inner md-grid">
          
            
              
              <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    



<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
  <label class="md-nav__title" for="__drawer">
    <a href=".." title="CodeGraphContext" class="md-nav__button md-logo" aria-label="CodeGraphContext" data-md-component="logo">
      
  
  <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>

    </a>
    CodeGraphContext
  </label>
  
  <ul class="md-nav__list" data-md-scrollfix>
    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href=".." class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Home
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../installation/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Installation
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../use_cases/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Use Cases
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../architecture/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Architecture
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cli/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    CLI Reference
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../server/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Server
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../core/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Core Concepts
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
    
  
  
  
    <li class="md-nav__item md-nav__item--active">
      
      <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
      
      
        
      
      
        <label class="md-nav__link md-nav__link--active" for="__toc">
          
  
  
  <span class="md-ellipsis">
    Tools
    
  </span>
  

          <span class="md-nav__icon md-icon"></span>
        </label>
      
      <a href="./" class="md-nav__link md-nav__link--active">
        
  
  
  <span class="md-ellipsis">
    Tools
    
  </span>
  

      </a>
      
        

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
    
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#graphbuilder" class="md-nav__link">
    <span class="md-ellipsis">
      GraphBuilder
    </span>
  </a>
  
    <nav class="md-nav" aria-label="GraphBuilder">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#treesitterparser" class="md-nav__link">
    <span class="md-ellipsis">
      TreeSitterParser
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#graph-building-process" class="md-nav__link">
    <span class="md-ellipsis">
      Graph Building Process
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#codefinder" class="md-nav__link">
    <span class="md-ellipsis">
      CodeFinder
    </span>
  </a>
  
    <nav class="md-nav" aria-label="CodeFinder">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#key-methods" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#importextractor" class="md-nav__link">
    <span class="md-ellipsis">
      ImportExtractor
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../cookbook/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Cookbook
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    
    
    
    
    
    <li class="md-nav__item md-nav__item--nested">
      
        
        
        <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_10" >
        
          
          <label class="md-nav__link" for="__nav_10" id="__nav_10_label" tabindex="0">
            
  
  
  <span class="md-ellipsis">
    Contributing
    
  </span>
  

            <span class="md-nav__icon md-icon"></span>
          </label>
        
        <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_10_label" aria-expanded="false">
          <label class="md-nav__title" for="__nav_10">
            <span class="md-nav__icon md-icon"></span>
            Contributing
          </label>
          <ul class="md-nav__list" data-md-scrollfix>
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Overview
    
  </span>
  

      </a>
    </li>
  

              
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../contributing_languages/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Adding New Languages
    
  </span>
  

      </a>
    </li>
  

              
            
          </ul>
        </nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../troubleshooting/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Troubleshooting
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../future_work/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Future Work
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../license/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    License
    
  </span>
  

      </a>
    </li>
  

    
  </ul>
</nav>
                  </div>
                </div>
              </div>
            
            
              
              <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
    
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#graphbuilder" class="md-nav__link">
    <span class="md-ellipsis">
      GraphBuilder
    </span>
  </a>
  
    <nav class="md-nav" aria-label="GraphBuilder">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#treesitterparser" class="md-nav__link">
    <span class="md-ellipsis">
      TreeSitterParser
    </span>
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#graph-building-process" class="md-nav__link">
    <span class="md-ellipsis">
      Graph Building Process
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#codefinder" class="md-nav__link">
    <span class="md-ellipsis">
      CodeFinder
    </span>
  </a>
  
    <nav class="md-nav" aria-label="CodeFinder">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#key-methods" class="md-nav__link">
    <span class="md-ellipsis">
      Key Methods
    </span>
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
        <li class="md-nav__item">
  <a href="#importextractor" class="md-nav__link">
    <span class="md-ellipsis">
      ImportExtractor
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
                  </div>
                </div>
              </div>
            
          
          
            <div class="md-content" data-md-component="content">
              <article class="md-content__inner md-typeset">
                
                  



<h1 id="tools">Tools</h1>
<p>The <code>tools</code> directory contains the logic for code analysis, including building the graph, finding code, and extracting imports.</p>
<h2 id="graphbuilder"><code>GraphBuilder</code></h2>
<p>The <code>GraphBuilder</code> class in <code>graph_builder.py</code> is responsible for parsing the source code and building the graph representation that is stored in the Neo4j database.</p>
<h3 id="treesitterparser"><code>TreeSitterParser</code></h3>
<p><code>GraphBuilder</code> uses the <code>TreeSitterParser</code> class, which is a generic parser wrapper for a specific language using the tree-sitter library. This allows CodeGraphContext to support multiple programming languages in a modular way.</p>
<h3 id="graph-building-process">Graph Building Process</h3>
<p>The graph building process consists of several steps:</p>
<ol>
<li><strong>Pre-scan for Imports:</strong> A quick scan of all files to build a global map of where every symbol is defined.</li>
<li><strong>Parse Files:</strong> Each file is parsed in detail to extract its structure, including functions, classes, variables, and imports.</li>
<li><strong>Add Nodes to Graph:</strong> The extracted code elements are added to the graph as nodes.</li>
<li><strong>Create Relationships:</strong> Relationships between the nodes are created, such as <code>CALLS</code> for function calls and <code>INHERITS</code> for class inheritance.</li>
</ol>
<h2 id="codefinder"><code>CodeFinder</code></h2>
<p>The <code>CodeFinder</code> class in <code>code_finder.py</code> provides functionality to search for specific code elements and analyze their relationships within the indexed codebase.</p>
<h3 id="key-methods">Key Methods</h3>
<ul>
<li><code>find_by_function_name()</code>: Finds functions by name.</li>
<li><code>find_by_class_name()</code>: Finds classes by name.</li>
<li><code>find_by_variable_name()</code>: Finds variables by name.</li>
<li><code>find_by_content()</code>: Finds code by content matching in source or docstrings.</li>
<li><code>find_related_code()</code>: Finds code related to a query using multiple search strategies.</li>
<li><code>analyze_code_relationships()</code>: Analyzes different types of code relationships, such as callers, callees, importers, and class hierarchies.</li>
</ul>
<h2 id="importextractor"><code>ImportExtractor</code></h2>
<p>The <code>ImportExtractor</code> class in <code>import_extractor.py</code> is a utility for extracting package and module imports from source code files of various programming languages. It uses the most appropriate parsing technique for each language, such as AST for Python and regular expressions for JavaScript.</p>
<h1 id="tools-exploration">Tools Exploration</h1>
<p>There are a total of 14 tools available to the users, and here we have attached illustrative demos for each one of them.</p>
<h2 id="find_code-tool">find_code Tool</h2>
<p>The <code>find_code</code> tool allows users to search for code snippets, functions, classes, and variables within the codebase using natural language queries. This tool helps developers understand and navigate large codebases efficiently.</p>
<p>Below is an embedded link to a demo video showcasing the usage of the <code>find_code</code> tool in action.
<a href="https://drive.google.com/file/d/1ojCDIIAwcir9e3jgHHIVC5weZ9nuIQcs/view?usp=drive_link"><img alt="Watch the demo video" src="../images/tool_images/1.png" /></a></p>
<hr />
<h2 id="watch_directory-tool">watch_directory Tool</h2>
<p>The <code>watch_directory</code> tool allows users to monitor a specified directory for file changes, additions, or deletions in real-time. It helps developers automate workflows such as triggering scripts, updating indexes, or syncing files whenever changes occur in the directory.</p>
<p>Below is an embedded link to a demo video showcasing the usage of the <code>watch_directory</code> tool in a development environment.
<a href="https://drive.google.com/file/d/1OEjcS2iwwymss99zLidbeBjcblferKBX/view?usp=drive_link"><img alt="Watch the demo" src="../images/tool_images/2.png" /></a> </p>
<hr />
<h2 id="analyze_code_relationships-tool">analyze_code_relationships Tool</h2>
<p>The <code>analyze_code_relationships</code> tool in CodeGraphContext is designed to let users query and explore the various relationships between code elements in a codebase, represented as a graph in Neo4j. </p>
<h3 id="relationship-types-that-can-be-analyzed">Relationship Types That Can Be Analyzed</h3>
<ul>
<li><strong>CALLS:</strong> Finds which functions call or are called by a function.</li>
<li><strong>CALLED_BY:</strong> Finds all functions that directly or indirectly call a target function (inverse of CALLS).</li>
<li><strong>INHERITS_FROM:</strong> Finds class inheritance relationships; which classes inherit from which.</li>
<li><strong>CONTAINS:</strong> Shows containment (which classes/functions are inside which modules or files).</li>
<li><strong>IMPLEMENTS:</strong> Shows which classes implement an interface.</li>
<li><strong>IMPORTS:</strong> Identifies which files or modules import a specific module.</li>
<li><strong>DEFINED_IN:</strong> Locates where an entity (function/class) is defined.</li>
<li><strong>HAS_ARGUMENT:</strong> Shows relationships from functions to their arguments.</li>
<li><strong>DECLARES:</strong> Finds variables declared in functions or classes.</li>
</ul>
<p>Below is an embedded link to a demo video showcasing the usage of the <code>analyse_code_relationships</code> tool.
<a href="https://drive.google.com/file/d/154M_lTPbg9_Gj9bd2ErnAVbJArSbcb2M/view?usp=drive_link"><img alt="Watch the demo" src="../images/tool_images/3.png" /></a> </p>
<hr />












                
              </article>
            </div>
          
          
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
        </div>
        
      </main>
      
        <footer class="md-footer">
  
  <div class="md-footer-meta md-typeset">
    <div class="md-footer-meta__inner md-grid">
      <div class="md-copyright">
  
  
    Made with
    <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
      Material for MkDocs
    </a>
  
</div>
      
    </div>
  </div>
</footer>
      
    </div>
    <div class="md-dialog" data-md-component="dialog">
      <div class="md-dialog__inner md-typeset"></div>
    </div>
    
    
    
      
      <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>
    
    
      <script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
      
    
  </body>
</html>
```
Page 8/14FirstPrevNextLast