This is page 6 of 18. Use http://codebase.md/shashankss1205/codegraphcontext?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .github
│ └── workflows
│ ├── e2e-tests.yml
│ ├── post_discord_invite.yml
│ ├── test.yml
│ └── update-contributors.yml
├── .gitignore
├── CONTRIBUTING.md
├── contributors.md
├── docs
│ ├── docs
│ │ ├── architecture.md
│ │ ├── cli.md
│ │ ├── contributing_languages.md
│ │ ├── contributing.md
│ │ ├── cookbook.md
│ │ ├── core.md
│ │ ├── future_work.md
│ │ ├── images
│ │ │ ├── 1.png
│ │ │ ├── 11.png
│ │ │ ├── 12.png
│ │ │ ├── 13.png
│ │ │ ├── 14.png
│ │ │ ├── 16.png
│ │ │ ├── 19.png
│ │ │ ├── 2.png
│ │ │ ├── 20.png
│ │ │ ├── 21.png
│ │ │ ├── 22.png
│ │ │ ├── 23.png
│ │ │ ├── 24.png
│ │ │ ├── 26.png
│ │ │ ├── 28.png
│ │ │ ├── 29.png
│ │ │ ├── 3.png
│ │ │ ├── 30.png
│ │ │ ├── 31.png
│ │ │ ├── 32.png
│ │ │ ├── 33.png
│ │ │ ├── 34.png
│ │ │ ├── 35.png
│ │ │ ├── 36.png
│ │ │ ├── 38.png
│ │ │ ├── 39.png
│ │ │ ├── 4.png
│ │ │ ├── 40.png
│ │ │ ├── 41.png
│ │ │ ├── 42.png
│ │ │ ├── 43.png
│ │ │ ├── 44.png
│ │ │ ├── 5.png
│ │ │ ├── 6.png
│ │ │ ├── 7.png
│ │ │ ├── 8.png
│ │ │ ├── 9.png
│ │ │ ├── Indexing.gif
│ │ │ ├── tool_images
│ │ │ │ ├── 1.png
│ │ │ │ ├── 2.png
│ │ │ │ └── 3.png
│ │ │ └── Usecase.gif
│ │ ├── index.md
│ │ ├── installation.md
│ │ ├── license.md
│ │ ├── server.md
│ │ ├── tools.md
│ │ ├── troubleshooting.md
│ │ └── use_cases.md
│ ├── mkdocs.yml
│ └── site
│ ├── 404.html
│ ├── architecture
│ │ └── index.html
│ ├── assets
│ │ ├── images
│ │ │ └── favicon.png
│ │ ├── javascripts
│ │ │ ├── bundle.f55a23d4.min.js
│ │ │ ├── bundle.f55a23d4.min.js.map
│ │ │ ├── lunr
│ │ │ │ ├── min
│ │ │ │ │ ├── lunr.ar.min.js
│ │ │ │ │ ├── lunr.da.min.js
│ │ │ │ │ ├── lunr.de.min.js
│ │ │ │ │ ├── lunr.du.min.js
│ │ │ │ │ ├── lunr.el.min.js
│ │ │ │ │ ├── lunr.es.min.js
│ │ │ │ │ ├── lunr.fi.min.js
│ │ │ │ │ ├── lunr.fr.min.js
│ │ │ │ │ ├── lunr.he.min.js
│ │ │ │ │ ├── lunr.hi.min.js
│ │ │ │ │ ├── lunr.hu.min.js
│ │ │ │ │ ├── lunr.hy.min.js
│ │ │ │ │ ├── lunr.it.min.js
│ │ │ │ │ ├── lunr.ja.min.js
│ │ │ │ │ ├── lunr.jp.min.js
│ │ │ │ │ ├── lunr.kn.min.js
│ │ │ │ │ ├── lunr.ko.min.js
│ │ │ │ │ ├── lunr.multi.min.js
│ │ │ │ │ ├── lunr.nl.min.js
│ │ │ │ │ ├── lunr.no.min.js
│ │ │ │ │ ├── lunr.pt.min.js
│ │ │ │ │ ├── lunr.ro.min.js
│ │ │ │ │ ├── lunr.ru.min.js
│ │ │ │ │ ├── lunr.sa.min.js
│ │ │ │ │ ├── lunr.stemmer.support.min.js
│ │ │ │ │ ├── lunr.sv.min.js
│ │ │ │ │ ├── lunr.ta.min.js
│ │ │ │ │ ├── lunr.te.min.js
│ │ │ │ │ ├── lunr.th.min.js
│ │ │ │ │ ├── lunr.tr.min.js
│ │ │ │ │ ├── lunr.vi.min.js
│ │ │ │ │ └── lunr.zh.min.js
│ │ │ │ ├── tinyseg.js
│ │ │ │ └── wordcut.js
│ │ │ └── workers
│ │ │ ├── search.973d3a69.min.js
│ │ │ └── search.973d3a69.min.js.map
│ │ └── stylesheets
│ │ ├── main.2a3383ac.min.css
│ │ ├── main.2a3383ac.min.css.map
│ │ ├── palette.06af60db.min.css
│ │ └── palette.06af60db.min.css.map
│ ├── cli
│ │ └── index.html
│ ├── contributing
│ │ └── index.html
│ ├── contributing_languages
│ │ └── index.html
│ ├── cookbook
│ │ └── index.html
│ ├── core
│ │ └── index.html
│ ├── future_work
│ │ └── index.html
│ ├── images
│ │ ├── 1.png
│ │ ├── 11.png
│ │ ├── 12.png
│ │ ├── 13.png
│ │ ├── 14.png
│ │ ├── 16.png
│ │ ├── 19.png
│ │ ├── 2.png
│ │ ├── 20.png
│ │ ├── 21.png
│ │ ├── 22.png
│ │ ├── 23.png
│ │ ├── 24.png
│ │ ├── 26.png
│ │ ├── 28.png
│ │ ├── 29.png
│ │ ├── 3.png
│ │ ├── 30.png
│ │ ├── 31.png
│ │ ├── 32.png
│ │ ├── 33.png
│ │ ├── 34.png
│ │ ├── 35.png
│ │ ├── 36.png
│ │ ├── 38.png
│ │ ├── 39.png
│ │ ├── 4.png
│ │ ├── 40.png
│ │ ├── 41.png
│ │ ├── 42.png
│ │ ├── 43.png
│ │ ├── 44.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ ├── 9.png
│ │ ├── Indexing.gif
│ │ ├── tool_images
│ │ │ ├── 1.png
│ │ │ ├── 2.png
│ │ │ └── 3.png
│ │ └── Usecase.gif
│ ├── index.html
│ ├── installation
│ │ └── index.html
│ ├── license
│ │ └── index.html
│ ├── search
│ │ └── search_index.json
│ ├── server
│ │ └── index.html
│ ├── sitemap.xml
│ ├── sitemap.xml.gz
│ ├── tools
│ │ └── index.html
│ ├── troubleshooting
│ │ └── index.html
│ └── use_cases
│ └── index.html
├── images
│ ├── 1.png
│ ├── 11.png
│ ├── 12.png
│ ├── 13.png
│ ├── 14.png
│ ├── 16.png
│ ├── 19.png
│ ├── 2.png
│ ├── 20.png
│ ├── 21.png
│ ├── 22.png
│ ├── 23.png
│ ├── 24.png
│ ├── 26.png
│ ├── 28.png
│ ├── 29.png
│ ├── 3.png
│ ├── 30.png
│ ├── 31.png
│ ├── 32.png
│ ├── 33.png
│ ├── 34.png
│ ├── 35.png
│ ├── 36.png
│ ├── 38.png
│ ├── 39.png
│ ├── 4.png
│ ├── 40.png
│ ├── 41.png
│ ├── 42.png
│ ├── 43.png
│ ├── 44.png
│ ├── 5.png
│ ├── 6.png
│ ├── 7.png
│ ├── 8.png
│ ├── 9.png
│ ├── Indexing.gif
│ ├── tool_images
│ │ ├── 1.png
│ │ ├── 2.png
│ │ └── 3.png
│ └── Usecase.gif
├── LICENSE
├── MANIFEST.in
├── organizer
│ ├── CONTRIBUTING_LANGUAGES.md
│ ├── cookbook.md
│ ├── docs.md
│ ├── language_specific_nodes.md
│ ├── Tools_Exploration.md
│ └── troubleshoot.md
├── package-lock.json
├── pyproject.toml
├── README.md
├── scripts
│ ├── generate_lang_contributors.py
│ └── post_install_fix.sh
├── SECURITY.md
├── src
│ └── codegraphcontext
│ ├── __init__.py
│ ├── __main__.py
│ ├── cli
│ │ ├── __init__.py
│ │ ├── cli_helpers.py
│ │ ├── main.py
│ │ ├── setup_macos.py
│ │ └── setup_wizard.py
│ ├── core
│ │ ├── __init__.py
│ │ ├── database.py
│ │ ├── jobs.py
│ │ └── watcher.py
│ ├── prompts.py
│ ├── server.py
│ ├── tools
│ │ ├── __init__.py
│ │ ├── advanced_language_query_tool.py
│ │ ├── code_finder.py
│ │ ├── graph_builder.py
│ │ ├── languages
│ │ │ ├── c.py
│ │ │ ├── cpp.py
│ │ │ ├── go.py
│ │ │ ├── java.py
│ │ │ ├── javascript.py
│ │ │ ├── python.py
│ │ │ ├── ruby.py
│ │ │ ├── rust.py
│ │ │ └── typescript.py
│ │ ├── package_resolver.py
│ │ ├── query_tool_languages
│ │ │ ├── c_toolkit.py
│ │ │ ├── cpp_toolkit.py
│ │ │ ├── go_toolkit.py
│ │ │ ├── java_toolkit.py
│ │ │ ├── javascript_toolkit.py
│ │ │ ├── python_toolkit.py
│ │ │ ├── ruby_toolkit.py
│ │ │ ├── rust_toolkit.py
│ │ │ └── typescript_toolkit.py
│ │ └── system.py
│ └── utils
│ └── debug_log.py
├── tests
│ ├── __init__.py
│ ├── conftest.py
│ ├── sample_project
│ │ ├── advanced_calls.py
│ │ ├── advanced_classes.py
│ │ ├── advanced_classes2.py
│ │ ├── advanced_functions.py
│ │ ├── advanced_imports.py
│ │ ├── async_features.py
│ │ ├── callbacks_decorators.py
│ │ ├── circular1.py
│ │ ├── circular2.py
│ │ ├── class_instantiation.py
│ │ ├── cli_and_dunder.py
│ │ ├── complex_classes.py
│ │ ├── comprehensions_generators.py
│ │ ├── context_managers.py
│ │ ├── control_flow.py
│ │ ├── datatypes.py
│ │ ├── dynamic_dispatch.py
│ │ ├── dynamic_imports.py
│ │ ├── edge_cases
│ │ │ ├── comments_only.py
│ │ │ ├── docstring_only.py
│ │ │ ├── empty.py
│ │ │ ├── hardcoded_secrets.py
│ │ │ ├── long_functions.py
│ │ │ └── syntax_error.py
│ │ ├── function_chains.py
│ │ ├── generators.py
│ │ ├── import_reexports.py
│ │ ├── mapping_calls.py
│ │ ├── module_a.py
│ │ ├── module_b.py
│ │ ├── module_c
│ │ │ ├── __init__.py
│ │ │ ├── submodule1.py
│ │ │ └── submodule2.py
│ │ ├── namespace_pkg
│ │ │ └── ns_module.py
│ │ ├── pattern_matching.py
│ │ └── typing_examples.py
│ ├── sample_project_c
│ │ ├── cgc_sample
│ │ ├── include
│ │ │ ├── config.h
│ │ │ ├── math
│ │ │ │ └── vec.h
│ │ │ ├── module.h
│ │ │ ├── platform.h
│ │ │ └── util.h
│ │ ├── Makefile
│ │ ├── README.md
│ │ └── src
│ │ ├── main.c
│ │ ├── math
│ │ │ └── vec.c
│ │ ├── module.c
│ │ └── util.c
│ ├── sample_project_cpp
│ │ ├── class_features.cpp
│ │ ├── classes.cpp
│ │ ├── control_flow.cpp
│ │ ├── edge_cases.cpp
│ │ ├── enum_struct_union.cpp
│ │ ├── exceptions.cpp
│ │ ├── file_io.cpp
│ │ ├── function_chain.cpp
│ │ ├── function_chain.h
│ │ ├── function_types.cpp
│ │ ├── main.cpp
│ │ ├── main.exe
│ │ ├── namespaces.cpp
│ │ ├── raii_example.cpp
│ │ ├── README.md
│ │ ├── sample_project.exe
│ │ ├── stl_usage.cpp
│ │ ├── templates.cpp
│ │ └── types_variable_assignments.cpp
│ ├── sample_project_go
│ │ ├── advanced_types.go
│ │ ├── basic_functions.go
│ │ ├── embedded_composition.go
│ │ ├── error_handling.go
│ │ ├── generics.go
│ │ ├── go.mod
│ │ ├── goroutines_channels.go
│ │ ├── interfaces.go
│ │ ├── packages_imports.go
│ │ ├── README.md
│ │ ├── structs_methods.go
│ │ └── util
│ │ └── helpers.go
│ ├── sample_project_java
│ │ ├── out
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── annotations
│ │ │ │ └── Logged.class
│ │ │ ├── Main.class
│ │ │ ├── misc
│ │ │ │ ├── Outer.class
│ │ │ │ └── Outer$Inner.class
│ │ │ ├── model
│ │ │ │ ├── Role.class
│ │ │ │ └── User.class
│ │ │ ├── service
│ │ │ │ ├── AbstractGreeter.class
│ │ │ │ ├── GreetingService.class
│ │ │ │ └── impl
│ │ │ │ └── GreetingServiceImpl.class
│ │ │ └── util
│ │ │ ├── CollectionUtils.class
│ │ │ └── IOHelper.class
│ │ ├── README.md
│ │ ├── sources.txt
│ │ └── src
│ │ └── com
│ │ └── example
│ │ └── app
│ │ ├── annotations
│ │ │ └── Logged.java
│ │ ├── Main.java
│ │ ├── misc
│ │ │ └── Outer.java
│ │ ├── model
│ │ │ ├── Role.java
│ │ │ └── User.java
│ │ ├── service
│ │ │ ├── AbstractGreeter.java
│ │ │ ├── GreetingService.java
│ │ │ └── impl
│ │ │ └── GreetingServiceImpl.java
│ │ └── util
│ │ ├── CollectionUtils.java
│ │ └── IOHelper.java
│ ├── sample_project_javascript
│ │ ├── arrays.js
│ │ ├── asyncAwait.js
│ │ ├── classes.js
│ │ ├── dom.js
│ │ ├── errorHandling.js
│ │ ├── events.js
│ │ ├── exporter.js
│ │ ├── fetchAPI.js
│ │ ├── fixtures
│ │ │ └── js
│ │ │ └── accessors.js
│ │ ├── functions.js
│ │ ├── importer.js
│ │ ├── objects.js
│ │ ├── promises.js
│ │ ├── README.md
│ │ └── variables.js
│ ├── sample_project_misc
│ │ ├── index.html
│ │ ├── README.md
│ │ ├── styles.css
│ │ ├── tables.css
│ │ └── tables.html
│ ├── sample_project_php
│ │ ├── classes_objects.php
│ │ ├── database.php
│ │ ├── edgecases.php
│ │ ├── error_handling.php
│ │ ├── file_handling.php
│ │ ├── functions.php
│ │ ├── generators_iterators.php
│ │ ├── globals_superglobals.php
│ │ ├── Inheritance.php
│ │ ├── interface_traits.php
│ │ └── README.md
│ ├── sample_project_ruby
│ │ ├── class_example.rb
│ │ ├── enumerables.rb
│ │ ├── error_handling.rb
│ │ ├── file_io.rb
│ │ ├── inheritance_example.rb
│ │ ├── main.rb
│ │ ├── metaprogramming.rb
│ │ ├── mixins_example.rb
│ │ ├── module_example.rb
│ │ └── tests
│ │ ├── test_mixins.py
│ │ └── test_sample.rb
│ ├── sample_project_rust
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src
│ │ ├── basic_functions.rs
│ │ ├── concurrency.rs
│ │ ├── error_handling.rs
│ │ ├── generics.rs
│ │ ├── iterators_closures.rs
│ │ ├── lib.rs
│ │ ├── lifetimes_references.rs
│ │ ├── modules.rs
│ │ ├── smart_pointers.rs
│ │ ├── structs_enums.rs
│ │ └── traits.rs
│ ├── sample_project_typescript
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── src
│ │ │ ├── advanced-types.ts
│ │ │ ├── async-promises.ts
│ │ │ ├── classes-inheritance.ts
│ │ │ ├── decorators-metadata.ts
│ │ │ ├── error-validation.ts
│ │ │ ├── functions-generics.ts
│ │ │ ├── index.ts
│ │ │ ├── modules-namespaces.ts
│ │ │ ├── types-interfaces.ts
│ │ │ └── utilities-helpers.ts
│ │ └── tsconfig.json
│ ├── test_cpp_parser.py
│ ├── test_database_validation.py
│ ├── test_end_to_end.py
│ ├── test_graph_indexing_js.py
│ ├── test_graph_indexing.py
│ ├── test_tree_sitter
│ │ ├── __init__.py
│ │ ├── class_instantiation.py
│ │ ├── complex_classes.py
│ │ └── test_file.py
│ └── test_typescript_parser.py
└── website
├── .example.env
├── .gitignore
├── api
│ └── pypi.ts
├── bun.lockb
├── components.json
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── favicon.ico
│ ├── placeholder.svg
│ └── robots.txt
├── README.md
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ │ ├── function-calls.png
│ │ ├── graph-total.png
│ │ ├── hero-graph.jpg
│ │ └── hierarchy.png
│ ├── components
│ │ ├── ComparisonTable.tsx
│ │ ├── CookbookSection.tsx
│ │ ├── DemoSection.tsx
│ │ ├── ExamplesSection.tsx
│ │ ├── FeaturesSection.tsx
│ │ ├── Footer.tsx
│ │ ├── HeroSection.tsx
│ │ ├── InstallationSection.tsx
│ │ ├── MoveToTop.tsx
│ │ ├── ShowDownloads.tsx
│ │ ├── ShowStarGraph.tsx
│ │ ├── TestimonialSection.tsx
│ │ ├── ThemeProvider.tsx
│ │ ├── ThemeToggle.tsx
│ │ └── ui
│ │ ├── accordion.tsx
│ │ ├── alert-dialog.tsx
│ │ ├── alert.tsx
│ │ ├── aspect-ratio.tsx
│ │ ├── avatar.tsx
│ │ ├── badge.tsx
│ │ ├── breadcrumb.tsx
│ │ ├── button.tsx
│ │ ├── calendar.tsx
│ │ ├── card.tsx
│ │ ├── carousel.tsx
│ │ ├── chart.tsx
│ │ ├── checkbox.tsx
│ │ ├── collapsible.tsx
│ │ ├── command.tsx
│ │ ├── context-menu.tsx
│ │ ├── dialog.tsx
│ │ ├── drawer.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── form.tsx
│ │ ├── hover-card.tsx
│ │ ├── input-otp.tsx
│ │ ├── input.tsx
│ │ ├── label.tsx
│ │ ├── menubar.tsx
│ │ ├── navigation-menu.tsx
│ │ ├── orbiting-circles.tsx
│ │ ├── pagination.tsx
│ │ ├── popover.tsx
│ │ ├── progress.tsx
│ │ ├── radio-group.tsx
│ │ ├── resizable.tsx
│ │ ├── scroll-area.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ ├── sheet.tsx
│ │ ├── sidebar.tsx
│ │ ├── skeleton.tsx
│ │ ├── slider.tsx
│ │ ├── sonner.tsx
│ │ ├── switch.tsx
│ │ ├── table.tsx
│ │ ├── tabs.tsx
│ │ ├── textarea.tsx
│ │ ├── toast.tsx
│ │ ├── toaster.tsx
│ │ ├── toggle-group.tsx
│ │ ├── toggle.tsx
│ │ ├── tooltip.tsx
│ │ └── use-toast.ts
│ ├── hooks
│ │ ├── use-mobile.tsx
│ │ └── use-toast.ts
│ ├── index.css
│ ├── lib
│ │ └── utils.ts
│ ├── main.tsx
│ ├── pages
│ │ ├── Index.tsx
│ │ └── NotFound.tsx
│ └── vite-env.d.ts
├── tailwind.config.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
├── vercel.json
└── vite.config.ts
```
# Files
--------------------------------------------------------------------------------
/organizer/CONTRIBUTING_LANGUAGES.md:
--------------------------------------------------------------------------------
```markdown
1 | # Contributing New Language Support to CodeGraphContext
2 |
3 | This document outlines the steps and best practices for adding support for a new programming language to CodeGraphContext. By following this guide, contributors can efficiently integrate new languages and leverage the Neo4j graph for verification.
4 |
5 | ## 1. Understanding the Architecture
6 |
7 | CodeGraphContext uses a modular architecture for multi-language support:
8 |
9 | * **Generic `TreeSitterParser` (in `graph_builder.py`):** This acts as a wrapper, dispatching parsing tasks to language-specific implementations.
10 | * **Language-Specific Parser Modules (in `src/codegraphcontext/tools/languages/`):** Each language (e.g., Python, JavaScript) has its own module (e.g., `python.py`, `javascript.py`) containing:
11 | * Tree-sitter queries (`<LANG>_QUERIES`).
12 | * A `<Lang>TreeSitterParser` class that encapsulates language-specific parsing logic.
13 | * A `pre_scan_<lang>` function for initial symbol mapping.
14 | * **`GraphBuilder` (in `graph_builder.py`):** Manages the overall graph building process, including file discovery, pre-scanning, and dispatching to the correct language parser.
15 |
16 | ## 2. Steps to Add a New Language (e.g., TypeScript - `.ts`)
17 |
18 | ### Step 2.1: Create the Language Module File
19 |
20 | 1. Create a new file: `src/codegraphcontext/tools/languages/typescript.py`.
21 | 2. Add the necessary imports: `from pathlib import Path`, `from typing import Any, Dict, Optional, Tuple`, `import logging`, `import ast` (if needed for AST manipulation).
22 | 3. Define `TS_QUERIES` (Tree-sitter queries for TypeScript).
23 | 4. Create a `TypescriptTreeSitterParser` class.
24 | 5. Create a `pre_scan_typescript` function.
25 |
26 | ### Step 2.2: Define Tree-sitter Queries (`TS_QUERIES`)
27 |
28 | This is the most critical and often iterative step. You'll need to define queries for:
29 |
30 | * **`functions`**: Function declarations, arrow functions, methods.
31 | * **`classes`**: Class declarations, class expressions.
32 | * **`imports`**: ES6 imports (`import ... from ...`), CommonJS `require()`.
33 | * **`calls`**: Function calls, method calls.
34 | * **`variables`**: Variable declarations (`let`, `const`, `var`).
35 | * **`docstrings`**: (Optional) How documentation comments are identified.
36 | * **`lambda_assignments`**: (Optional, Python-specific) If the language has similar constructs.
37 |
38 | **Tips for Query Writing:**
39 | * **Consult Tree-sitter Grammars:** Find the `node-types.json` or grammar definition for your language (e.g., `tree-sitter-typescript`).
40 | * **Use `tree-sitter parse`:** Use the `tree-sitter parse` command-line tool to inspect the AST of sample code snippets. This is invaluable for identifying correct node types and field names.
41 | * **Start Simple:** Begin with basic queries and gradually add complexity.
42 | * **Test Iteratively:** After each query, test it with sample code.
43 |
44 | ### Step 2.3: Implement `<Lang>TreeSitterParser` Class
45 |
46 | This class (e.g., `TypescriptTreeSitterParser`) will encapsulate the language-specific logic.
47 |
48 | 1. **`__init__(self, generic_parser_wrapper)`**:
49 | * Store `generic_parser_wrapper`, `language_name`, `language`, `parser` from the generic wrapper.
50 | * Load `TS_QUERIES` using `self.language.query(query_str)`.
51 | 2. **Helper Methods**:
52 | * `_get_node_text(self, node)`: Extracts text from a tree-sitter node.
53 | * `_get_parent_context(self, node, types=...)`: (Language-specific node types for context).
54 | * `_calculate_complexity(self, node)`: (Language-specific complexity nodes).
55 | * `_get_docstring(self, body_node)`: (Language-specific docstring extraction).
56 | 3. **`parse(self, file_path: Path, is_dependency: bool = False) -> Dict`**:
57 | * Reads the file, parses it with `self.parser`.
58 | * Calls its own `_find_*` methods (`_find_functions`, `_find_classes`, etc.).
59 | * Returns a standardized dictionary format (as seen in `python.py` and `javascript.py`).
60 | 4. **`_find_*` Methods**:
61 | Implement these for each query type, extracting data from the AST and populating the standardized dictionary.
62 |
63 | ### Step 2.4: Implement `pre_scan_<lang>` Function
64 |
65 | This function (e.g., `pre_scan_typescript`) will quickly scan files to build an initial `imports_map`.
66 |
67 | 1. It takes `files: list[Path]` and `parser_wrapper` (an instance of `TreeSitterParser`).
68 | 2. Uses a simplified query (e.g., for `class_declaration` and `function_declaration`) to quickly find definitions.
69 | 3. Returns a dictionary mapping symbol names to file paths.
70 |
71 | ### Step 2.5: Integrate into `graph_builder.py`
72 |
73 | 1. **`GraphBuilder.__init__`**:
74 | * Add `'.ts': TreeSitterParser('typescript')` to `self.parsers`.
75 | 2. **`TreeSitterParser.__init__`**:
76 | * Add an `elif self.language_name == 'typescript':` block to initialize `self.language_specific_parser` with `TypescriptTreeSitterParser(self)`.
77 | 3. **`GraphBuilder._pre_scan_for_imports`**:
78 | * Add an `elif '.ts' in files_by_lang:` block to import `pre_scan_typescript` and call it.
79 |
80 | ## 3. Verification and Debugging using Neo4j
81 |
82 | After implementing support for a new language, it's crucial to verify that the graph is being built correctly.
83 |
84 | ### Step 3.1: Prepare a Sample Project
85 |
86 | Create a small sample project for your new language (e.g., `tests/sample_project_typescript/`) with:
87 | * Function declarations.
88 | * Class declarations (including inheritance).
89 | * Various import types (if applicable).
90 | * Function calls.
91 | * Variable declarations.
92 |
93 | ### Step 3.2: Index the Sample Project
94 |
95 | 1. **Delete existing data (if any):**
96 | ```bash
97 | # Replace with your sample project path
98 | <tool_code>print(default_api.delete_repository(repo_path='/path/to/your/sample_project'))</tool_code>
99 | 2. **Index the project:**
100 | ```bash
101 | # Replace with your sample project path
102 | <tool_code>print(default_api.add_code_to_graph(path='/path/to/your/sample_project'))</tool_code>
103 | 3. **Monitor job status:**
104 | ```bash
105 | # Use the job_id returned by add_code_to_graph
106 | <tool_code>print(default_api.check_job_status(job_id='<your_job_id>'))</tool_code>
107 |
108 | ### Step 3.3: Query the Neo4j Graph
109 |
110 | Use Cypher queries to inspect the generated graph.
111 |
112 | * **Check for Files and Language Tags:**
113 | ```cypher
114 | MATCH (f:File)
115 | WHERE f.path STARTS WITH '/path/to/your/sample_project'
116 | RETURN f.name, f.path, f.lang
117 | ```
118 | *Expected:* All files from your sample project should be listed with the correct `lang` tag.
119 |
120 | * **Check for Functions:**
121 | ```cypher
122 | MATCH (f:File)-[:CONTAINS]->(fn:Function)
123 | WHERE f.path STARTS WITH '/path/to/your/sample_project'
124 | AND fn.lang = '<your_language_name>'
125 | RETURN f.name AS FileName, fn.name AS FunctionName, fn.line_number AS Line
126 | ```
127 | *Expected:* All functions from your sample project should be listed.
128 |
129 | * **Check for Classes:**
130 | ```cypher
131 | MATCH (f:File)-[:CONTAINS]->(c:Class)
132 | WHERE f.path STARTS WITH '/path/to/your/sample_project'
133 | AND c.lang = '<your_language_name>'
134 | RETURN f.name AS FileName, c.name AS ClassName, c.line_number AS Line
135 | ```
136 | *Expected:* All classes from your sample project should be listed.
137 |
138 | * **Check for Imports (Module-level):**
139 | ```cypher
140 | MATCH (f:File)-[:IMPORTS]->(m:Module)
141 | WHERE f.path STARTS WITH '/path/to/your/sample_project'
142 | AND f.lang = '<your_language_name>'
143 | RETURN f.name AS FileName, m.name AS ImportedModule, m.full_import_name AS FullImportName
144 | ```
145 | *Expected:* All module-level imports should be listed.
146 |
147 | * **Check for Function Calls:**
148 | ```cypher
149 | MATCH (caller:Function)-[:CALLS]->(callee:Function)
150 | WHERE caller.file_path STARTS WITH '/path/to/your/sample_project'
151 | AND caller.lang = '<your_language_name>'
152 | RETURN caller.name AS Caller, callee.name AS Callee, caller.file_path AS CallerFile, callee.file_path AS CalleeFile
153 | ```
154 | *Expected:* All function calls should be correctly linked.
155 |
156 | * **Check for Class Inheritance:**
157 | ```cypher
158 | MATCH (child:Class)-[:INHERITS]->(parent:Class)
159 | WHERE child.file_path STARTS WITH '/path/to/your/sample_project'
160 | AND child.lang = '<your_language_name>'
161 | RETURN child.name AS ChildClass, parent.name AS ParentClass, child.file_path AS ChildFile, parent.file_path AS ParentFile
162 | ```
163 | *Expected:* All inheritance relationships should be correctly linked.
164 |
165 | ### Step 3.4: Debugging Common Issues
166 |
167 | * **`NameError: Invalid node type ...`**: Your tree-sitter query is using a node type that doesn't exist in the language's grammar. Use `tree-sitter parse` to inspect the AST.
168 | * **Missing Relationships (e.g., `CALLS`, `IMPORTS`)**:
169 | * **Check `_find_*` methods**: Ensure your `_find_*` methods are correctly extracting the necessary data.
170 | * **Check `imports_map`**: Verify that the `pre_scan_<lang>` function is correctly populating the `imports_map`.
171 | * **Check `local_imports` map**: Ensure the `local_imports` map (built in `_create_function_calls` and `_create_inheritance_links`) is correctly resolving symbols.
172 | * **Incorrect `lang` tags**: Ensure `self.language_name` is correctly passed and stored.
173 |
174 | By following these steps, contributors can effectively add and verify new language support.
175 |
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.hu.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `Hungarian` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,n=L.cursor;if(d=L.limit,L.in_grouping(W,97,252))for(;;){if(e=L.cursor,L.out_grouping(W,97,252))return L.cursor=e,L.find_among(g,8)||(L.cursor=e,e<L.limit&&L.cursor++),void(d=L.cursor);if(L.cursor=e,e>=L.limit)return void(d=e);L.cursor++}if(L.cursor=n,L.out_grouping(W,97,252)){for(;!L.in_grouping(W,97,252);){if(L.cursor>=L.limit)return;L.cursor++}d=L.cursor}}function i(){return d<=L.cursor}function a(){var e;if(L.ket=L.cursor,(e=L.find_among_b(h,2))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e")}}function t(){var e=L.limit-L.cursor;return!!L.find_among_b(p,23)&&(L.cursor=L.limit-e,!0)}function s(){if(L.cursor>L.limit_backward){L.cursor--,L.ket=L.cursor;var e=L.cursor-1;L.limit_backward<=e&&e<=L.limit&&(L.cursor=e,L.bra=e,L.slice_del())}}function c(){var e;if(L.ket=L.cursor,(e=L.find_among_b(_,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function o(){L.ket=L.cursor,L.find_among_b(v,44)&&(L.bra=L.cursor,i()&&(L.slice_del(),a()))}function w(){var e;if(L.ket=L.cursor,(e=L.find_among_b(z,3))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("e");break;case 2:case 3:L.slice_from("a")}}function l(){var e;if(L.ket=L.cursor,(e=L.find_among_b(y,6))&&(L.bra=L.cursor,i()))switch(e){case 1:case 2:L.slice_del();break;case 3:L.slice_from("a");break;case 4:L.slice_from("e")}}function u(){var e;if(L.ket=L.cursor,(e=L.find_among_b(j,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function m(){var e;if(L.ket=L.cursor,(e=L.find_among_b(C,7))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:L.slice_del()}}function k(){var e;if(L.ket=L.cursor,(e=L.find_among_b(P,12))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 9:L.slice_del();break;case 2:case 5:case 8:L.slice_from("e");break;case 3:case 6:L.slice_from("a")}}function f(){var e;if(L.ket=L.cursor,(e=L.find_among_b(F,31))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:L.slice_del();break;case 2:case 5:case 10:case 14:case 19:L.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:L.slice_from("e")}}function b(){var e;if(L.ket=L.cursor,(e=L.find_among_b(S,42))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:L.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:L.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:L.slice_from("e")}}var d,g=[new n("cs",-1,-1),new n("dzs",-1,-1),new n("gy",-1,-1),new n("ly",-1,-1),new n("ny",-1,-1),new n("sz",-1,-1),new n("ty",-1,-1),new n("zs",-1,-1)],h=[new n("á",-1,1),new n("é",-1,2)],p=[new n("bb",-1,-1),new n("cc",-1,-1),new n("dd",-1,-1),new n("ff",-1,-1),new n("gg",-1,-1),new n("jj",-1,-1),new n("kk",-1,-1),new n("ll",-1,-1),new n("mm",-1,-1),new n("nn",-1,-1),new n("pp",-1,-1),new n("rr",-1,-1),new n("ccs",-1,-1),new n("ss",-1,-1),new n("zzs",-1,-1),new n("tt",-1,-1),new n("vv",-1,-1),new n("ggy",-1,-1),new n("lly",-1,-1),new n("nny",-1,-1),new n("tty",-1,-1),new n("ssz",-1,-1),new n("zz",-1,-1)],_=[new n("al",-1,1),new n("el",-1,2)],v=[new n("ba",-1,-1),new n("ra",-1,-1),new n("be",-1,-1),new n("re",-1,-1),new n("ig",-1,-1),new n("nak",-1,-1),new n("nek",-1,-1),new n("val",-1,-1),new n("vel",-1,-1),new n("ul",-1,-1),new n("nál",-1,-1),new n("nél",-1,-1),new n("ból",-1,-1),new n("ról",-1,-1),new n("tól",-1,-1),new n("bõl",-1,-1),new n("rõl",-1,-1),new n("tõl",-1,-1),new n("ül",-1,-1),new n("n",-1,-1),new n("an",19,-1),new n("ban",20,-1),new n("en",19,-1),new n("ben",22,-1),new n("képpen",22,-1),new n("on",19,-1),new n("ön",19,-1),new n("képp",-1,-1),new n("kor",-1,-1),new n("t",-1,-1),new n("at",29,-1),new n("et",29,-1),new n("ként",29,-1),new n("anként",32,-1),new n("enként",32,-1),new n("onként",32,-1),new n("ot",29,-1),new n("ért",29,-1),new n("öt",29,-1),new n("hez",-1,-1),new n("hoz",-1,-1),new n("höz",-1,-1),new n("vá",-1,-1),new n("vé",-1,-1)],z=[new n("án",-1,2),new n("én",-1,1),new n("ánként",-1,3)],y=[new n("stul",-1,2),new n("astul",0,1),new n("ástul",0,3),new n("stül",-1,2),new n("estül",3,1),new n("éstül",3,4)],j=[new n("á",-1,1),new n("é",-1,2)],C=[new n("k",-1,7),new n("ak",0,4),new n("ek",0,6),new n("ok",0,5),new n("ák",0,1),new n("ék",0,2),new n("ök",0,3)],P=[new n("éi",-1,7),new n("áéi",0,6),new n("ééi",0,5),new n("é",-1,9),new n("ké",3,4),new n("aké",4,1),new n("eké",4,1),new n("oké",4,1),new n("áké",4,3),new n("éké",4,2),new n("öké",4,1),new n("éé",3,8)],F=[new n("a",-1,18),new n("ja",0,17),new n("d",-1,16),new n("ad",2,13),new n("ed",2,13),new n("od",2,13),new n("ád",2,14),new n("éd",2,15),new n("öd",2,13),new n("e",-1,18),new n("je",9,17),new n("nk",-1,4),new n("unk",11,1),new n("ánk",11,2),new n("énk",11,3),new n("ünk",11,1),new n("uk",-1,8),new n("juk",16,7),new n("ájuk",17,5),new n("ük",-1,8),new n("jük",19,7),new n("éjük",20,6),new n("m",-1,12),new n("am",22,9),new n("em",22,9),new n("om",22,9),new n("ám",22,10),new n("ém",22,11),new n("o",-1,18),new n("á",-1,19),new n("é",-1,20)],S=[new n("id",-1,10),new n("aid",0,9),new n("jaid",1,6),new n("eid",0,9),new n("jeid",3,6),new n("áid",0,7),new n("éid",0,8),new n("i",-1,15),new n("ai",7,14),new n("jai",8,11),new n("ei",7,14),new n("jei",10,11),new n("ái",7,12),new n("éi",7,13),new n("itek",-1,24),new n("eitek",14,21),new n("jeitek",15,20),new n("éitek",14,23),new n("ik",-1,29),new n("aik",18,26),new n("jaik",19,25),new n("eik",18,26),new n("jeik",21,25),new n("áik",18,27),new n("éik",18,28),new n("ink",-1,20),new n("aink",25,17),new n("jaink",26,16),new n("eink",25,17),new n("jeink",28,16),new n("áink",25,18),new n("éink",25,19),new n("aitok",-1,21),new n("jaitok",32,20),new n("áitok",-1,22),new n("im",-1,5),new n("aim",35,4),new n("jaim",36,1),new n("eim",35,4),new n("jeim",38,1),new n("áim",35,2),new n("éim",35,3)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var n=L.cursor;return e(),L.limit_backward=n,L.cursor=L.limit,c(),L.cursor=L.limit,o(),L.cursor=L.limit,w(),L.cursor=L.limit,l(),L.cursor=L.limit,u(),L.cursor=L.limit,k(),L.cursor=L.limit,f(),L.cursor=L.limit,b(),L.cursor=L.limit,m(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}});
```
--------------------------------------------------------------------------------
/src/codegraphcontext/cli/main.py:
--------------------------------------------------------------------------------
```python
1 | # src/codegraphcontext/cli/main.py
2 | """
3 | This module defines the command-line interface (CLI) for the CodeGraphContext application.
4 | It uses the Typer library to create a user-friendly and well-documented CLI.
5 |
6 | Commands:
7 | - setup: Runs an interactive wizard to configure the Neo4j database connection.
8 | - start: Launches the main MCP server.
9 | - help: Displays help information.
10 | - version: Show the installed version.
11 | """
12 | import typer
13 | from rich.console import Console
14 | from rich.table import Table
15 | from typing import Optional
16 | import asyncio
17 | import logging
18 | import json
19 | import os
20 | from pathlib import Path
21 | from dotenv import load_dotenv, find_dotenv
22 | from importlib.metadata import version as pkg_version, PackageNotFoundError
23 |
24 | from codegraphcontext.server import MCPServer
25 | from .setup_wizard import run_setup_wizard
26 | # Import the new helper functions
27 | from .cli_helpers import (
28 | index_helper,
29 | add_package_helper,
30 | list_repos_helper,
31 | delete_helper,
32 | cypher_helper,
33 | visualize_helper,
34 | )
35 |
36 | # Set the log level for the noisy neo4j and asyncio logger to WARNING to keep the output clean.
37 | logging.getLogger("neo4j").setLevel(logging.WARNING)
38 | logging.getLogger("asyncio").setLevel(logging.WARNING)
39 |
40 | # Initialize the Typer app and Rich console for formatted output.
41 | app = typer.Typer(
42 | name="cgc",
43 | help="CodeGraphContext: An MCP server for AI-powered code analysis.",
44 | add_completion=True,
45 | )
46 | console = Console(stderr=True)
47 |
48 | # Configure basic logging for the application.
49 | logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
50 |
51 |
52 | def get_version() -> str:
53 | """
54 | Try to read version from the installed package metadata.
55 | Fallback to a dev version if not installed.
56 | """
57 | try:
58 | return pkg_version("codegraphcontext") # must match [project].name in pyproject.toml
59 | except PackageNotFoundError:
60 | return "0.0.0 (dev)"
61 |
62 |
63 | @app.command()
64 | def setup():
65 | """
66 | Runs the interactive setup wizard to configure the server and database connection.
67 | This helps users set up a local Docker-based Neo4j instance or connect to a remote one.
68 | """
69 | run_setup_wizard()
70 |
71 | def _load_credentials():
72 | """
73 | Loads Neo4j credentials from various sources into environment variables.
74 | Priority order:
75 | 1. Local `mcp.json`
76 | 2. Global `~/.codegraphcontext/.env`
77 | 3. Any `.env` file found in the directory tree.
78 | """
79 | # 1. Prefer loading from mcp.json
80 | mcp_file_path = Path.cwd() / "mcp.json"
81 | if mcp_file_path.exists():
82 | try:
83 | with open(mcp_file_path, "r") as f:
84 | mcp_config = json.load(f)
85 | server_env = mcp_config.get("mcpServers", {}).get("CodeGraphContext", {}).get("env", {})
86 | for key, value in server_env.items():
87 | os.environ[key] = value
88 | console.print("[green]Loaded Neo4j credentials from local mcp.json.[/green]")
89 | return
90 | except Exception as e:
91 | console.print(f"[bold red]Error loading mcp.json:[/bold red] {e}")
92 |
93 | # 2. Try global .env file
94 | global_env_path = Path.home() / ".codegraphcontext" / ".env"
95 | if global_env_path.exists():
96 | try:
97 | load_dotenv(dotenv_path=global_env_path)
98 | console.print(f"[green]Loaded Neo4j credentials from global .env file: {global_env_path}[/green]")
99 | return
100 | except Exception as e:
101 | console.print(f"[bold red]Error loading global .env file from {global_env_path}:[/bold red] {e}")
102 |
103 | # 3. Fallback to any discovered .env
104 | try:
105 | dotenv_path = find_dotenv(usecwd=True, raise_error_if_not_found=False)
106 | if dotenv_path:
107 | load_dotenv(dotenv_path)
108 | console.print(f"[green]Loaded Neo4j credentials from discovered .env file: {dotenv_path}[/green]")
109 | else:
110 | console.print("[yellow]No local mcp.json or .env file found. Credentials may not be set.[/yellow]")
111 | except Exception as e:
112 | console.print(f"[bold red]Error loading .env file:[/bold red] {e}")
113 |
114 |
115 | @app.command()
116 | def start():
117 | """
118 | Starts the CodeGraphContext MCP server, which listens for JSON-RPC requests from stdin.
119 | """
120 | console.print("[bold green]Starting CodeGraphContext Server...[/bold green]")
121 | _load_credentials()
122 |
123 | server = None
124 | loop = asyncio.new_event_loop()
125 | asyncio.set_event_loop(loop)
126 | try:
127 | # Initialize and run the main server.
128 | server = MCPServer(loop=loop)
129 | loop.run_until_complete(server.run())
130 | except ValueError as e:
131 | # This typically happens if credentials are still not found after all checks.
132 | console.print(f"[bold red]Configuration Error:[/bold red] {e}")
133 | console.print("Please run `cgc setup` to configure the server.")
134 | except KeyboardInterrupt:
135 | # Handle graceful shutdown on Ctrl+C.
136 | console.print("\n[bold yellow]Server stopped by user.[/bold yellow]")
137 | finally:
138 | # Ensure server and event loop are properly closed.
139 | if server:
140 | server.shutdown()
141 | loop.close()
142 |
143 |
144 | @app.command()
145 | def index(path: Optional[str] = typer.Argument(None, help="Path to the directory or file to index. Defaults to the current directory.")):
146 | """
147 | Indexes a directory or file by adding it to the code graph.
148 | If no path is provided, it indexes the current directory.
149 | """
150 | _load_credentials() # Credentials must be loaded before helpers are called
151 | if path is None:
152 | path = str(Path.cwd())
153 | index_helper(path)
154 |
155 | @app.command()
156 | def delete(path: str = typer.Argument(..., help="Path of the repository to delete from the code graph.")):
157 | """
158 | Deletes a repository from the code graph.
159 | """
160 | _load_credentials()
161 | delete_helper(path)
162 |
163 | @app.command()
164 | def visualize(query: Optional[str] = typer.Argument(None, help="The Cypher query to visualize.")):
165 | """
166 | Generates a URL to visualize a Cypher query in the Neo4j Browser.
167 | If no query is provided, a default query will be used.
168 | """
169 | if query is None:
170 | query = "MATCH p=()-->() RETURN p"
171 | visualize_helper(query)
172 |
173 | @app.command(name="list-repos")
174 | def list_repos():
175 | """
176 | Lists all indexed repositories.
177 | """
178 | _load_credentials()
179 | list_repos_helper()
180 |
181 | @app.command(name="add-package")
182 | def add_package(package_name: str = typer.Argument(..., help="Name of the package to add."), language: str = typer.Argument(..., help="Language of the package." )):
183 | """
184 | Adds a package to the code graph.
185 | """
186 | _load_credentials()
187 | add_package_helper(package_name, language)
188 |
189 | @app.command()
190 | def cypher(query: str = typer.Argument(..., help="The read-only Cypher query to execute.")):
191 | """
192 | Executes a read-only Cypher query.
193 | """
194 | _load_credentials()
195 | cypher_helper(query)
196 |
197 |
198 | @app.command(name="list-mcp-tools")
199 | def list_mcp_tools():
200 | """
201 | Lists all available tools and their descriptions.
202 | """
203 | _load_credentials()
204 | console.print("[bold green]Available Tools:[/bold green]")
205 | try:
206 | # Instantiate the server to access the tool definitions.
207 | server = MCPServer()
208 | tools = server.tools.values()
209 |
210 | table = Table(show_header=True, header_style="bold magenta")
211 | table.add_column("Tool Name", style="dim", width=30)
212 | table.add_column("Description")
213 |
214 | for tool in sorted(tools, key=lambda t: t['name']):
215 | table.add_row(tool['name'], tool['description'])
216 |
217 | console.print(table)
218 |
219 | except ValueError as e:
220 | console.print(f"[bold red]Error loading tools:[/bold red] {e}")
221 | console.print("Please ensure your Neo4j credentials are set up correctly (`cgc setup`), as they are needed to initialize the server.")
222 | except Exception as e:
223 | console.print(f"[bold red]An unexpected error occurred:[/bold red] {e}")
224 |
225 |
226 | @app.command()
227 | def help(ctx: typer.Context):
228 | """Show the main help message and exit."""
229 | root_ctx = ctx.parent or ctx
230 | typer.echo(root_ctx.get_help())
231 |
232 |
233 | @app.command("version")
234 | def version_cmd():
235 | """Show the application version."""
236 | console.print(f"CodeGraphContext [bold cyan]{get_version()}[/bold cyan]")
237 |
238 |
239 | @app.callback(invoke_without_command=True)
240 | def main(
241 | ctx: typer.Context,
242 | version_: bool = typer.Option(
243 | None,
244 | "--version",
245 | "-v",
246 | help="Show the application version and exit.",
247 | is_eager=True,
248 | ),
249 | ):
250 | """
251 | Main entry point for the cgc CLI application.
252 | If no subcommand is provided, it displays a welcome message with instructions.
253 | """
254 | if version_:
255 | console.print(f"CodeGraphContext [bold cyan]{get_version()}[/bold cyan]")
256 | raise typer.Exit()
257 |
258 | if ctx.invoked_subcommand is None:
259 | console.print("[bold green]👋 Welcome to CodeGraphContext (cgc)![/bold green]\n")
260 | console.print("👉 Run [cyan]cgc setup[/cyan] to configure the server and database.")
261 | console.print("👉 Run [cyan]cgc start[/cyan] to launch the server.")
262 | console.print("👉 Run [cyan]cgc help[/cyan] to see all available commands.\n")
263 | console.print("👉 Run [cyan]cgc --version[/cyan] to check the version.\n")
264 | console.print("👉 Running [green]codegraphcontext [white]works the same as using [green]cgc")
265 |
```
--------------------------------------------------------------------------------
/tests/sample_project_typescript/src/classes-inheritance.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Classes and Inheritance
3 | * Demonstrates TypeScript's OOP features including classes, inheritance,
4 | * abstract classes, access modifiers, static members, and advanced patterns
5 | */
6 |
7 | // ========== Basic Class Definition ==========
8 | export class Person {
9 | // Public property (default)
10 | public name: string;
11 |
12 | // Private property (only accessible within this class)
13 | private _id: number;
14 |
15 | // Protected property (accessible in this class and subclasses)
16 | protected age: number;
17 |
18 | // Readonly property
19 | readonly birthDate: Date;
20 |
21 | // Static property
22 | static species: string = "Homo sapiens";
23 |
24 | // Static method
25 | static getSpecies(): string {
26 | return Person.species;
27 | }
28 |
29 | constructor(name: string, age: number, id: number) {
30 | this.name = name;
31 | this.age = age;
32 | this._id = id;
33 | this.birthDate = new Date();
34 | }
35 |
36 | // Public method
37 | public introduce(): string {
38 | return `Hello, I'm ${this.name} and I'm ${this.age} years old.`;
39 | }
40 |
41 | // Private method
42 | private validateAge(age: number): boolean {
43 | return age >= 0 && age <= 150;
44 | }
45 |
46 | // Protected method
47 | protected updateAge(newAge: number): void {
48 | if (this.validateAge(newAge)) {
49 | this.age = newAge;
50 | }
51 | }
52 |
53 | // Getter
54 | get id(): number {
55 | return this._id;
56 | }
57 |
58 | // Setter
59 | set id(value: number) {
60 | if (value > 0) {
61 | this._id = value;
62 | }
63 | }
64 |
65 | // Method with overloads
66 | greet(): string;
67 | greet(formal: boolean): string;
68 | greet(formal: boolean, title: string): string;
69 | greet(formal?: boolean, title?: string): string {
70 | const greeting = formal ? "Good day" : "Hi";
71 | const nameWithTitle = title ? `${title} ${this.name}` : this.name;
72 | return `${greeting}, ${nameWithTitle}!`;
73 | }
74 | }
75 |
76 | // ========== Inheritance ==========
77 | export class Employee extends Person {
78 | private salary: number;
79 | public department: string;
80 |
81 | constructor(name: string, age: number, id: number, department: string, salary: number) {
82 | super(name, age, id); // Call parent constructor
83 | this.department = department;
84 | this.salary = salary;
85 | }
86 |
87 | // Override parent method
88 | public override introduce(): string {
89 | return `${super.introduce()} I work in ${this.department}.`;
90 | }
91 |
92 | // New method specific to Employee
93 | public work(): string {
94 | return `${this.name} is working in the ${this.department} department.`;
95 | }
96 |
97 | // Access protected member from parent
98 | public celebrateBirthday(): void {
99 | this.updateAge(this.age + 1);
100 | console.log(`Happy birthday! Now ${this.age} years old.`);
101 | }
102 |
103 | // Getter for private property
104 | get monthlySalary(): number {
105 | return this.salary;
106 | }
107 |
108 | // Setter with validation
109 | set monthlySalary(value: number) {
110 | if (value >= 0) {
111 | this.salary = value;
112 | } else {
113 | throw new Error("Salary cannot be negative");
114 | }
115 | }
116 | }
117 |
118 | // ========== Abstract Classes ==========
119 | export abstract class Animal {
120 | protected name: string;
121 | protected age: number;
122 |
123 | constructor(name: string, age: number) {
124 | this.name = name;
125 | this.age = age;
126 | }
127 |
128 | // Concrete method
129 | public sleep(): string {
130 | return `${this.name} is sleeping.`;
131 | }
132 |
133 | // Abstract method (must be implemented by subclasses)
134 | abstract makeSound(): string;
135 |
136 | // Abstract method with parameters
137 | abstract move(distance: number): string;
138 | }
139 |
140 | // ========== Concrete Implementation of Abstract Class ==========
141 | export class Dog extends Animal {
142 | private breed: string;
143 |
144 | constructor(name: string, age: number, breed: string) {
145 | super(name, age);
146 | this.breed = breed;
147 | }
148 |
149 | // Implementation of abstract method
150 | public makeSound(): string {
151 | return `${this.name} the ${this.breed} says: Woof! Woof!`;
152 | }
153 |
154 | // Implementation of abstract method
155 | public move(distance: number): string {
156 | return `${this.name} runs ${distance} meters.`;
157 | }
158 |
159 | // Additional method specific to Dog
160 | public fetch(): string {
161 | return `${this.name} fetches the ball!`;
162 | }
163 | }
164 |
165 | export class Cat extends Animal {
166 | private indoor: boolean;
167 |
168 | constructor(name: string, age: number, indoor: boolean = true) {
169 | super(name, age);
170 | this.indoor = indoor;
171 | }
172 |
173 | public makeSound(): string {
174 | return `${this.name} says: Meow!`;
175 | }
176 |
177 | public move(distance: number): string {
178 | const verb = this.indoor ? "walks" : "prowls";
179 | return `${this.name} ${verb} ${distance} meters.`;
180 | }
181 |
182 | public climb(): string {
183 | return `${this.name} climbs up high.`;
184 | }
185 | }
186 |
187 | // ========== Interface Implementation ==========
188 | interface Flyable {
189 | fly(height: number): string;
190 | land(): string;
191 | }
192 |
193 | interface Swimmable {
194 | swim(depth: number): string;
195 | surface(): string;
196 | }
197 |
198 | export class Duck extends Animal implements Flyable, Swimmable {
199 | constructor(name: string, age: number) {
200 | super(name, age);
201 | }
202 |
203 | public makeSound(): string {
204 | return `${this.name} says: Quack! Quack!`;
205 | }
206 |
207 | public move(distance: number): string {
208 | return `${this.name} waddles ${distance} meters.`;
209 | }
210 |
211 | // Implement Flyable
212 | public fly(height: number): string {
213 | return `${this.name} flies at ${height} meters high.`;
214 | }
215 |
216 | public land(): string {
217 | return `${this.name} lands gracefully.`;
218 | }
219 |
220 | // Implement Swimmable
221 | public swim(depth: number): string {
222 | return `${this.name} swims at ${depth} meters deep.`;
223 | }
224 |
225 | public surface(): string {
226 | return `${this.name} surfaces from the water.`;
227 | }
228 | }
229 |
230 | // ========== Generic Classes ==========
231 | export class Container<T> {
232 | private items: T[] = [];
233 |
234 | public add(item: T): void {
235 | this.items.push(item);
236 | }
237 |
238 | public remove(item: T): boolean {
239 | const index = this.items.indexOf(item);
240 | if (index > -1) {
241 | this.items.splice(index, 1);
242 | return true;
243 | }
244 | return false;
245 | }
246 |
247 | public getAll(): readonly T[] {
248 | return [...this.items];
249 | }
250 |
251 | public size(): number {
252 | return this.items.length;
253 | }
254 |
255 | public clear(): void {
256 | this.items = [];
257 | }
258 | }
259 |
260 | // Generic class with constraints
261 | export class NumberContainer<T extends number> extends Container<T> {
262 | public sum(): T {
263 | return this.getAll().reduce((sum, item) => (sum + item) as T, 0 as T);
264 | }
265 |
266 | public average(): number {
267 | const items = this.getAll();
268 | return items.length > 0 ? this.sum() / items.length : 0;
269 | }
270 | }
271 |
272 | // ========== Singleton Pattern ==========
273 | export class Database {
274 | private static instance: Database;
275 | private connections: number = 0;
276 |
277 | private constructor() {
278 | // Private constructor prevents instantiation
279 | }
280 |
281 | public static getInstance(): Database {
282 | if (!Database.instance) {
283 | Database.instance = new Database();
284 | }
285 | return Database.instance;
286 | }
287 |
288 | public connect(): string {
289 | this.connections++;
290 | return `Connected to database. Total connections: ${this.connections}`;
291 | }
292 |
293 | public disconnect(): string {
294 | if (this.connections > 0) {
295 | this.connections--;
296 | return `Disconnected from database. Remaining connections: ${this.connections}`;
297 | }
298 | return "No active connections to disconnect.";
299 | }
300 | }
301 |
302 | // ========== Static Class Pattern ==========
303 | export class MathUtils {
304 | // Prevent instantiation
305 | private constructor() {}
306 |
307 | public static PI: number = Math.PI;
308 |
309 | public static calculateCircleArea(radius: number): number {
310 | return MathUtils.PI * radius * radius;
311 | }
312 |
313 | public static calculateDistance(x1: number, y1: number, x2: number, y2: number): number {
314 | return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
315 | }
316 |
317 | public static clamp(value: number, min: number, max: number): number {
318 | return Math.min(Math.max(value, min), max);
319 | }
320 | }
321 |
322 | // ========== Mixins Pattern ==========
323 | type Constructor<T = {}> = new (...args: any[]) => T;
324 |
325 | // Mixin function
326 | export function Timestamped<TBase extends Constructor>(Base: TBase) {
327 | return class extends Base {
328 | timestamp = Date.now();
329 |
330 | getTimestamp(): number {
331 | return this.timestamp;
332 | }
333 | };
334 | }
335 |
336 | export function Activatable<TBase extends Constructor>(Base: TBase) {
337 | return class extends Base {
338 | isActive = false;
339 |
340 | activate(): void {
341 | this.isActive = true;
342 | }
343 |
344 | deactivate(): void {
345 | this.isActive = false;
346 | }
347 | };
348 | }
349 |
350 | // Base class for mixins
351 | export class BaseUser {
352 | constructor(public name: string) {}
353 | }
354 |
355 | // Apply mixins
356 | export const TimestampedUser = Timestamped(BaseUser);
357 | export const ActivatableUser = Activatable(BaseUser);
358 | export const EnhancedUser = Timestamped(Activatable(BaseUser));
359 |
360 | // ========== Usage Examples ==========
361 | export const classExamples = {
362 | // Basic usage
363 | person: new Person("John Doe", 30, 123),
364 | employee: new Employee("Jane Smith", 28, 456, "Engineering", 75000),
365 |
366 | // Animals
367 | dog: new Dog("Buddy", 3, "Golden Retriever"),
368 | cat: new Cat("Whiskers", 2, true),
369 | duck: new Duck("Quackers", 1),
370 |
371 | // Generic containers
372 | stringContainer: new Container<string>(),
373 | numberContainer: new NumberContainer<number>(),
374 |
375 | // Singleton
376 | database: Database.getInstance(),
377 |
378 | // Mixins
379 | timestampedUser: new TimestampedUser("Alice"),
380 | enhancedUser: new EnhancedUser("Bob")
381 | };
382 |
383 | // Initialize some examples
384 | classExamples.stringContainer.add("Hello");
385 | classExamples.stringContainer.add("World");
386 |
387 | classExamples.numberContainer.add(10);
388 | classExamples.numberContainer.add(20);
389 | classExamples.numberContainer.add(30);
```
--------------------------------------------------------------------------------
/tests/sample_project_typescript/src/functions-generics.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Functions and Generics
3 | * Demonstrates TypeScript's function types, overloads, generics, constraints,
4 | * higher-order functions, and advanced function patterns
5 | */
6 |
7 | // ========== Basic Function Types ==========
8 | export function simpleFunction(x: number, y: number): number {
9 | return x + y;
10 | }
11 |
12 | // Optional parameters
13 | export function greet(name: string, greeting?: string): string {
14 | return `${greeting || "Hello"}, ${name}!`;
15 | }
16 |
17 | // Default parameters
18 | export function createUser(name: string, active: boolean = true): { name: string; active: boolean } {
19 | return { name, active };
20 | }
21 |
22 | // Rest parameters
23 | export function sum(...numbers: number[]): number {
24 | return numbers.reduce((total, num) => total + num, 0);
25 | }
26 |
27 | // ========== Function Overloads ==========
28 | export function parseValue(value: string): number;
29 | export function parseValue(value: number): string;
30 | export function parseValue(value: boolean): string;
31 | export function parseValue(value: string | number | boolean): string | number {
32 | if (typeof value === "string") {
33 | return parseInt(value, 10);
34 | } else if (typeof value === "number") {
35 | return value.toString();
36 | } else {
37 | return value.toString();
38 | }
39 | }
40 |
41 | // Complex overloads
42 | export function processData(data: string[]): string[];
43 | export function processData(data: number[]): number[];
44 | export function processData<T>(data: T[], processor: (item: T) => T): T[];
45 | export function processData<T>(
46 | data: T[],
47 | processor?: (item: T) => T
48 | ): T[] {
49 | if (processor) {
50 | return data.map(processor);
51 | }
52 | return [...data];
53 | }
54 |
55 | // ========== Arrow Functions ==========
56 | export const multiply = (x: number, y: number): number => x * y;
57 |
58 | export const isEven = (n: number): boolean => n % 2 === 0;
59 |
60 | // Higher-order arrow function
61 | export const createMultiplier = (factor: number) => (value: number) => value * factor;
62 |
63 | // ========== Generic Functions ==========
64 | export function identity<T>(arg: T): T {
65 | return arg;
66 | }
67 |
68 | export function getFirstElement<T>(array: T[]): T | undefined {
69 | return array[0];
70 | }
71 |
72 | // Generic with multiple type parameters
73 | export function merge<T, U>(obj1: T, obj2: U): T & U {
74 | return { ...obj1, ...obj2 };
75 | }
76 |
77 | // Generic with default type parameter
78 | export function createArray<T = string>(length: number, defaultValue: T): T[] {
79 | return Array(length).fill(defaultValue);
80 | }
81 |
82 | // ========== Generic Constraints ==========
83 | // Constraint using extends
84 | export function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
85 | return obj[key];
86 | }
87 |
88 | // Constraint with interface
89 | interface Lengthwise {
90 | length: number;
91 | }
92 |
93 | export function logLength<T extends Lengthwise>(arg: T): T {
94 | console.log(arg.length);
95 | return arg;
96 | }
97 |
98 | // Constraint with conditional types
99 | export function processItem<T extends string | number>(
100 | item: T
101 | ): T extends string ? string : number {
102 | if (typeof item === "string") {
103 | return item.toUpperCase() as T extends string ? string : number;
104 | }
105 | return (item * 2) as T extends string ? string : number;
106 | }
107 |
108 | // ========== Advanced Generic Patterns ==========
109 | // Generic factory function
110 | export interface Constructable<T = {}> {
111 | new (...args: any[]): T;
112 | }
113 |
114 | export function createInstance<T>(constructor: Constructable<T>, ...args: any[]): T {
115 | return new constructor(...args);
116 | }
117 |
118 | // Generic with constraint and default
119 | export function sortBy<T, K extends keyof T = keyof T>(
120 | array: T[],
121 | key: K,
122 | ascending: boolean = true
123 | ): T[] {
124 | return array.sort((a, b) => {
125 | const valueA = a[key];
126 | const valueB = b[key];
127 |
128 | if (valueA < valueB) return ascending ? -1 : 1;
129 | if (valueA > valueB) return ascending ? 1 : -1;
130 | return 0;
131 | });
132 | }
133 |
134 | // ========== Function Types ==========
135 | export type UnaryFunction<T, R> = (arg: T) => R;
136 | export type BinaryFunction<T, U, R> = (arg1: T, arg2: U) => R;
137 | export type Predicate<T> = (arg: T) => boolean;
138 | export type Mapper<T, R> = (item: T, index: number, array: T[]) => R;
139 |
140 | // Function that accepts function types
141 | export function pipe<T, R1, R2>(
142 | input: T,
143 | fn1: UnaryFunction<T, R1>,
144 | fn2: UnaryFunction<R1, R2>
145 | ): R2 {
146 | return fn2(fn1(input));
147 | }
148 |
149 | // ========== Higher-Order Functions ==========
150 | export function memoize<T extends (...args: any[]) => any>(fn: T): T {
151 | const cache = new Map();
152 |
153 | return ((...args: any[]) => {
154 | const key = JSON.stringify(args);
155 | if (cache.has(key)) {
156 | return cache.get(key);
157 | }
158 | const result = fn(...args);
159 | cache.set(key, result);
160 | return result;
161 | }) as T;
162 | }
163 |
164 | export function debounce<T extends (...args: any[]) => any>(
165 | fn: T,
166 | delay: number
167 | ): T {
168 | let timeoutId: NodeJS.Timeout;
169 |
170 | return ((...args: any[]) => {
171 | clearTimeout(timeoutId);
172 | timeoutId = setTimeout(() => fn(...args), delay);
173 | }) as T;
174 | }
175 |
176 | export function throttle<T extends (...args: any[]) => any>(
177 | fn: T,
178 | limit: number
179 | ): T {
180 | let inThrottle: boolean;
181 |
182 | return ((...args: any[]) => {
183 | if (!inThrottle) {
184 | fn(...args);
185 | inThrottle = true;
186 | setTimeout(() => inThrottle = false, limit);
187 | }
188 | }) as T;
189 | }
190 |
191 | // ========== Generic Data Structures ==========
192 | export class Stack<T> {
193 | private items: T[] = [];
194 |
195 | push(item: T): void {
196 | this.items.push(item);
197 | }
198 |
199 | pop(): T | undefined {
200 | return this.items.pop();
201 | }
202 |
203 | peek(): T | undefined {
204 | return this.items[this.items.length - 1];
205 | }
206 |
207 | isEmpty(): boolean {
208 | return this.items.length === 0;
209 | }
210 |
211 | size(): number {
212 | return this.items.length;
213 | }
214 | }
215 |
216 | export class Queue<T> {
217 | private items: T[] = [];
218 |
219 | enqueue(item: T): void {
220 | this.items.push(item);
221 | }
222 |
223 | dequeue(): T | undefined {
224 | return this.items.shift();
225 | }
226 |
227 | front(): T | undefined {
228 | return this.items[0];
229 | }
230 |
231 | isEmpty(): boolean {
232 | return this.items.length === 0;
233 | }
234 |
235 | size(): number {
236 | return this.items.length;
237 | }
238 | }
239 |
240 | // Generic with multiple constraints
241 | export interface Comparable<T> {
242 | compareTo(other: T): number;
243 | }
244 |
245 | export class PriorityQueue<T extends Comparable<T>> {
246 | private items: T[] = [];
247 |
248 | enqueue(item: T): void {
249 | this.items.push(item);
250 | this.items.sort((a, b) => a.compareTo(b));
251 | }
252 |
253 | dequeue(): T | undefined {
254 | return this.items.shift();
255 | }
256 |
257 | peek(): T | undefined {
258 | return this.items[0];
259 | }
260 |
261 | isEmpty(): boolean {
262 | return this.items.length === 0;
263 | }
264 | }
265 |
266 | // ========== Utility Functions with Generics ==========
267 | export function arrayChunk<T>(array: T[], size: number): T[][] {
268 | const chunks: T[][] = [];
269 | for (let i = 0; i < array.length; i += size) {
270 | chunks.push(array.slice(i, i + size));
271 | }
272 | return chunks;
273 | }
274 |
275 | export function arrayUnique<T>(array: T[]): T[] {
276 | return [...new Set(array)];
277 | }
278 |
279 | export function arrayGroupBy<T, K extends string | number | symbol>(
280 | array: T[],
281 | keyFn: (item: T) => K
282 | ): Record<K, T[]> {
283 | return array.reduce((groups, item) => {
284 | const key = keyFn(item);
285 | groups[key] = groups[key] || [];
286 | groups[key]!.push(item);
287 | return groups;
288 | }, {} as Record<K, T[]>);
289 | }
290 |
291 | // Curried functions
292 | export const curriedAdd = (x: number) => (y: number) => x + y;
293 | export const curriedFilter = <T>(predicate: Predicate<T>) => (array: T[]) =>
294 | array.filter(predicate);
295 |
296 | // ========== Generic Utility Types Functions ==========
297 | export function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
298 | const result = {} as Pick<T, K>;
299 | keys.forEach(key => {
300 | result[key] = obj[key];
301 | });
302 | return result;
303 | }
304 |
305 | export function omit<T, K extends keyof T>(obj: T, ...keys: K[]): Omit<T, K> {
306 | const result = { ...obj };
307 | keys.forEach(key => {
308 | delete result[key];
309 | });
310 | return result as Omit<T, K>;
311 | }
312 |
313 | export function deepClone<T>(obj: T): T {
314 | if (obj === null || typeof obj !== "object") {
315 | return obj;
316 | }
317 |
318 | if (obj instanceof Date) {
319 | return new Date(obj.getTime()) as T;
320 | }
321 |
322 | if (obj instanceof Array) {
323 | return obj.map(item => deepClone(item)) as T;
324 | }
325 |
326 | if (typeof obj === "object") {
327 | const copy = {} as T;
328 | Object.keys(obj).forEach(key => {
329 | (copy as any)[key] = deepClone((obj as any)[key]);
330 | });
331 | return copy;
332 | }
333 |
334 | return obj;
335 | }
336 |
337 | // ========== Function Composition ==========
338 | export function compose<T, R1, R2>(
339 | fn1: (arg: T) => R1,
340 | fn2: (arg: R1) => R2
341 | ): (arg: T) => R2;
342 | export function compose<T, R1, R2, R3>(
343 | fn1: (arg: T) => R1,
344 | fn2: (arg: R1) => R2,
345 | fn3: (arg: R2) => R3
346 | ): (arg: T) => R3;
347 | export function compose(...fns: Function[]) {
348 | return (arg: any) => fns.reduce((result, fn) => fn(result), arg);
349 | }
350 |
351 | // ========== Usage Examples ==========
352 | export const functionExamples = {
353 | // Basic functions
354 | basicSum: sum(1, 2, 3, 4, 5),
355 | parsedString: parseValue("123"),
356 | parsedNumber: parseValue(456),
357 |
358 | // Generics
359 | identityString: identity("hello"),
360 | identityNumber: identity(42),
361 | mergedObject: merge({ name: "John" }, { age: 30 }),
362 |
363 | // Data structures
364 | numberStack: new Stack<number>(),
365 | stringQueue: new Queue<string>(),
366 |
367 | // Higher-order functions
368 | double: createMultiplier(2),
369 | memoizedFib: memoize((n: number): number => {
370 | if (n <= 1) return n;
371 | return functionExamples.memoizedFib(n - 1) + functionExamples.memoizedFib(n - 2);
372 | }),
373 |
374 | // Array utilities
375 | chunkedArray: arrayChunk([1, 2, 3, 4, 5, 6, 7], 3),
376 | uniqueArray: arrayUnique([1, 2, 2, 3, 3, 3, 4]),
377 | groupedItems: arrayGroupBy(
378 | [{ type: "fruit", name: "apple" }, { type: "fruit", name: "banana" }, { type: "vegetable", name: "carrot" }],
379 | item => item.type
380 | )
381 | };
382 |
383 | // Initialize some examples
384 | functionExamples.numberStack.push(1);
385 | functionExamples.numberStack.push(2);
386 | functionExamples.numberStack.push(3);
387 |
388 | functionExamples.stringQueue.enqueue("first");
389 | functionExamples.stringQueue.enqueue("second");
390 | functionExamples.stringQueue.enqueue("third");
```
--------------------------------------------------------------------------------
/src/codegraphcontext/core/watcher.py:
--------------------------------------------------------------------------------
```python
1 | # src/codegraphcontext/core/watcher.py
2 | """
3 | This module implements the live file-watching functionality using the `watchdog` library.
4 | It observes directories for changes and triggers updates to the code graph.
5 | """
6 | import threading
7 | from pathlib import Path
8 | import typing
9 | from watchdog.observers import Observer
10 | from watchdog.events import FileSystemEventHandler
11 |
12 | if typing.TYPE_CHECKING:
13 | from codegraphcontext.tools.graph_builder import GraphBuilder
14 | from codegraphcontext.core.jobs import JobManager
15 |
16 | from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
17 |
18 | class RepositoryEventHandler(FileSystemEventHandler):
19 | """
20 | A dedicated event handler for a single repository being watched.
21 |
22 | This handler is stateful. It performs an initial scan of the repository
23 | to build a baseline and then uses this cached state to perform efficient
24 | updates when files are changed, created, or deleted.
25 | """
26 | def __init__(self, graph_builder: "GraphBuilder", repo_path: Path, debounce_interval=2.0, perform_initial_scan: bool = True):
27 | """
28 | Initializes the event handler.
29 |
30 | Args:
31 | graph_builder: An instance of the GraphBuilder to perform graph operations.
32 | repo_path: The absolute path to the repository directory to watch.
33 | debounce_interval: The time in seconds to wait for more changes before processing an event.
34 | perform_initial_scan: Whether to perform an initial scan of the repository.
35 | """
36 | super().__init__()
37 | self.graph_builder = graph_builder
38 | self.repo_path = repo_path
39 | self.debounce_interval = debounce_interval
40 | self.timers = {} # A dictionary to manage debounce timers for file paths.
41 |
42 | # Caches for the repository's state.
43 | self.all_file_data = []
44 | self.imports_map = {}
45 |
46 | # Perform the initial scan and linking when the watcher is created.
47 | if perform_initial_scan:
48 | self._initial_scan()
49 |
50 | def _initial_scan(self):
51 | """Scans the entire repository, parses all files, and builds the initial graph."""
52 | info_logger(f"Performing initial scan for watcher: {self.repo_path}")
53 | supported_extensions = self.graph_builder.parsers.keys()
54 | all_files = [f for f in self.repo_path.rglob("*") if f.is_file() and f.suffix in supported_extensions]
55 |
56 | # 1. Pre-scan all files to get a global map of where every symbol is defined.
57 | self.imports_map = self.graph_builder._pre_scan_for_imports(all_files)
58 |
59 | # 2. Parse all files in detail and cache the parsed data.
60 | for f in all_files:
61 | parsed_data = self.graph_builder.parse_file(self.repo_path, f)
62 | if "error" not in parsed_data:
63 | self.all_file_data.append(parsed_data)
64 |
65 | # 3. After all files are parsed, create the relationships (e.g., function calls) between them.
66 | self.graph_builder._create_all_function_calls(self.all_file_data, self.imports_map)
67 | self.graph_builder._create_all_inheritance_links(self.all_file_data, self.imports_map)
68 | info_logger(f"Initial scan and graph linking complete for: {self.repo_path}")
69 |
70 | def _debounce(self, event_path, action):
71 | """
72 | Schedules an action to run after a debounce interval.
73 | This prevents the handler from firing on every single file save event in rapid
74 | succession, which is common in IDEs. It waits for a quiet period before processing.
75 | """
76 | # If a timer already exists for this path, cancel it.
77 | if event_path in self.timers:
78 | self.timers[event_path].cancel()
79 | # Create and start a new timer.
80 | timer = threading.Timer(self.debounce_interval, action)
81 | timer.start()
82 | self.timers[event_path] = timer
83 |
84 | def _handle_modification(self, event_path_str: str):
85 | """
86 | Orchestrates the complete update cycle for a modified or created file.
87 | This involves re-scanning the entire repo to update cross-file relationships.
88 | """
89 | info_logger(f"File change detected, starting full repository refresh for: {event_path_str}")
90 | modified_path = Path(event_path_str)
91 |
92 | # 1. Get all supported files in the repository.
93 | supported_extensions = self.graph_builder.parsers.keys()
94 | all_files = [f for f in self.repo_path.rglob("*") if f.is_file() and f.suffix in supported_extensions]
95 |
96 | # 2. Re-scan all files to get a fresh, global map of all symbols.
97 | self.imports_map = self.graph_builder._pre_scan_for_imports(all_files)
98 | info_logger("Refreshed global imports map.")
99 |
100 | # 3. Update the specific file that changed in the graph.
101 | # This deletes old nodes and adds new ones for the single file.
102 | self.graph_builder.update_file_in_graph(
103 | modified_path, self.repo_path, self.imports_map
104 | )
105 |
106 | # 4. Re-parse all files to have a complete, in-memory representation for the linking pass.
107 | # This is necessary because a change in one file can affect relationships in others.
108 | self.all_file_data = []
109 | for f in all_files:
110 | parsed_data = self.graph_builder.parse_file(self.repo_path, f)
111 | if "error" not in parsed_data:
112 | self.all_file_data.append(parsed_data)
113 | info_logger("Refreshed in-memory cache of all file data.")
114 |
115 | # 5. CRITICAL: Re-link the entire graph using the fully updated cache and imports map.
116 | info_logger("Re-linking the entire graph for calls and inheritance...")
117 | self.graph_builder._create_all_function_calls(self.all_file_data, self.imports_map)
118 | self.graph_builder._create_all_inheritance_links(self.all_file_data, self.imports_map)
119 | info_logger(f"Graph refresh for change in {event_path_str} complete! ✅")
120 |
121 | # The following methods are called by the watchdog observer when a file event occurs.
122 | def on_created(self, event):
123 | if not event.is_directory and Path(event.src_path).suffix in self.graph_builder.parsers:
124 | self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
125 |
126 | def on_modified(self, event):
127 | if not event.is_directory and Path(event.src_path).suffix in self.graph_builder.parsers:
128 | self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
129 |
130 | def on_deleted(self, event):
131 | if not event.is_directory and Path(event.src_path).suffix in self.graph_builder.parsers:
132 | self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
133 |
134 | def on_moved(self, event):
135 | if not event.is_directory:
136 | if Path(event.src_path).suffix in self.graph_builder.parsers:
137 | self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
138 | if Path(event.dest_path).suffix in self.graph_builder.parsers:
139 | self._debounce(event.dest_path, lambda: self._handle_modification(event.dest_path))
140 |
141 |
142 | class CodeWatcher:
143 | """
144 | Manages the file system observer thread. It can watch multiple directories,
145 | assigning a separate `RepositoryEventHandler` to each one.
146 | """
147 | def __init__(self, graph_builder: "GraphBuilder", job_manager= "JobManager"):
148 | self.graph_builder = graph_builder
149 | self.observer = Observer()
150 | self.watched_paths = set() # Keep track of paths already being watched.
151 | self.watches = {} # Store watch objects to allow unscheduling
152 |
153 | def watch_directory(self, path: str, perform_initial_scan: bool = True):
154 | """Schedules a directory to be watched for changes."""
155 | path_obj = Path(path).resolve()
156 | path_str = str(path_obj)
157 |
158 | if path_str in self.watched_paths:
159 | info_logger(f"Path already being watched: {path_str}")
160 | return {"message": f"Path already being watched: {path_str}"}
161 |
162 | # Create a new, dedicated event handler for this specific repository path.
163 | event_handler = RepositoryEventHandler(self.graph_builder, path_obj, perform_initial_scan=perform_initial_scan)
164 |
165 | watch = self.observer.schedule(event_handler, path_str, recursive=True)
166 | self.watches[path_str] = watch
167 | self.watched_paths.add(path_str)
168 | info_logger(f"Started watching for code changes in: {path_str}")
169 |
170 | return {"message": f"Started watching {path_str}."}
171 | def unwatch_directory(self, path: str):
172 | """Stops watching a directory for changes."""
173 | path_obj = Path(path).resolve()
174 | path_str = str(path_obj)
175 |
176 | if path_str not in self.watched_paths:
177 | warning_logger(f"Attempted to unwatch a path that is not being watched: {path_str}")
178 | return {"error": f"Path not currently being watched: {path_str}"}
179 |
180 | watch = self.watches.pop(path_str, None)
181 | if watch:
182 | self.observer.unschedule(watch)
183 |
184 | self.watched_paths.discard(path_str)
185 | info_logger(f"Stopped watching for code changes in: {path_str}")
186 | return {"message": f"Stopped watching {path_str}."}
187 |
188 | def list_watched_paths(self) -> list:
189 | """Returns a list of all currently watched directory paths."""
190 | return list(self.watched_paths)
191 |
192 | def start(self):
193 | """Starts the observer thread."""
194 | if not self.observer.is_alive():
195 | self.observer.start()
196 | info_logger("Code watcher observer thread started.")
197 |
198 | def stop(self):
199 | """Stops the observer thread gracefully."""
200 | if self.observer.is_alive():
201 | self.observer.stop()
202 | self.observer.join() # Wait for the thread to terminate.
203 | info_logger("Code watcher observer thread stopped.")
204 |
```
--------------------------------------------------------------------------------
/src/codegraphcontext/core/database.py:
--------------------------------------------------------------------------------
```python
1 | # src/codegraphcontext/core/database.py
2 | """
3 | This module provides a thread-safe singleton manager for the Neo4j database connection.
4 | """
5 | import os
6 | import re
7 | import threading
8 | from typing import Optional, Tuple
9 | from neo4j import GraphDatabase, Driver
10 |
11 | from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
12 |
13 | class DatabaseManager:
14 | """
15 | Manages the Neo4j database driver as a singleton to ensure only one
16 | connection pool is created and shared across the application.
17 |
18 | This pattern is crucial for performance and resource management in a
19 | multi-threaded or asynchronous application.
20 | """
21 | _instance = None
22 | _driver: Optional[Driver] = None
23 | _lock = threading.Lock() # Lock to ensure thread-safe initialization.
24 |
25 | def __new__(cls):
26 | """Standard singleton pattern implementation."""
27 | if cls._instance is None:
28 | with cls._lock:
29 | # Double-check locking to prevent race conditions.
30 | if cls._instance is None:
31 | cls._instance = super(DatabaseManager, cls).__new__(cls)
32 | return cls._instance
33 |
34 | def __init__(self):
35 | """
36 | Initializes the manager by reading credentials from environment variables.
37 | The `_initialized` flag prevents re-initialization on subsequent calls.
38 | """
39 | if hasattr(self, '_initialized'):
40 | return
41 |
42 | self.neo4j_uri = os.getenv('NEO4J_URI')
43 | self.neo4j_username = os.getenv('NEO4J_USERNAME', 'neo4j')
44 | self.neo4j_password = os.getenv('NEO4J_PASSWORD')
45 | self._initialized = True
46 |
47 | def get_driver(self) -> Driver:
48 | """
49 | Gets the Neo4j driver instance, creating it if it doesn't exist.
50 | This method is thread-safe.
51 |
52 | Raises:
53 | ValueError: If Neo4j credentials are not set in environment variables.
54 |
55 | Returns:
56 | The active Neo4j Driver instance.
57 | """
58 | if self._driver is None:
59 | with self._lock:
60 | if self._driver is None:
61 | # Ensure all necessary credentials are provided.
62 | if not all([self.neo4j_uri, self.neo4j_username, self.neo4j_password]):
63 | raise ValueError(
64 | "Neo4j credentials must be set via environment variables:\n"
65 | "- NEO4J_URI\n"
66 | "- NEO4J_USERNAME\n"
67 | "- NEO4J_PASSWORD"
68 | )
69 |
70 | #validating the config before creating the driver/attempting connection
71 | is_valid, validation_error = self.validate_config(
72 | self.neo4j_uri,
73 | self.neo4j_username,
74 | self.neo4j_password
75 | )
76 |
77 | if not is_valid:
78 | error_logger(f"Configuration validation failed: {validation_error}")
79 | raise ValueError(validation_error)
80 |
81 | info_logger(f"Creating Neo4j driver connection to {self.neo4j_uri}")
82 | self._driver = GraphDatabase.driver(
83 | self.neo4j_uri,
84 | auth=(self.neo4j_username, self.neo4j_password)
85 | )
86 | # Test the connection immediately to fail fast if credentials are wrong.
87 | try:
88 | with self._driver.session() as session:
89 | session.run("RETURN 1").consume()
90 | info_logger("Neo4j connection established successfully")
91 | except Exception as e:
92 | # Use detailed error messages from test_connection
93 | _, detailed_error = self.test_connection(
94 | self.neo4j_uri,
95 | self.neo4j_username,
96 | self.neo4j_password
97 | )
98 | error_logger(f"Failed to connect to Neo4j: {e}")
99 | if self._driver:
100 | self._driver.close()
101 | self._driver = None
102 | raise
103 | return self._driver
104 |
105 | def close_driver(self):
106 | """Closes the Neo4j driver connection if it exists."""
107 | if self._driver is not None:
108 | with self._lock:
109 | if self._driver is not None:
110 | info_logger("Closing Neo4j driver")
111 | self._driver.close()
112 | self._driver = None
113 |
114 | def is_connected(self) -> bool:
115 | """Checks if the database connection is currently active."""
116 | if self._driver is None:
117 | return False
118 | try:
119 | with self._driver.session() as session:
120 | session.run("RETURN 1").consume()
121 | return True
122 | except Exception:
123 | return False
124 |
125 | @staticmethod
126 | def validate_config(uri: str, username: str, password: str) -> Tuple[bool, Optional[str]]:
127 | """
128 | Validates Neo4j configuration parameters.
129 |
130 | Returns:
131 | Tuple[bool, Optional[str]]: (is_valid, error_message)
132 | """
133 | # Validate URI format
134 | uri_pattern = r'^(neo4j|neo4j\+s|neo4j\+ssc|bolt|bolt\+s|bolt\+ssc)://[^:]+:\d+$'
135 | if not re.match(uri_pattern, uri):
136 | return False, (
137 | "Invalid Neo4j URI format.\n"
138 | "Expected format: neo4j://host:port or bolt://host:port\n"
139 | "Example: neo4j://localhost:7687\n"
140 | "Common mistake: Missing 'neo4j://' or 'bolt://' prefix"
141 | )
142 |
143 | # Validate username
144 | if not username or len(username.strip()) == 0:
145 | return False, (
146 | "Username cannot be empty.\n"
147 | "Default Neo4j username is 'neo4j'"
148 | )
149 |
150 | # Validate password
151 | if not password or len(password.strip()) == 0:
152 | return False, (
153 | "Password cannot be empty.\n"
154 | "Tip: If you just set up Neo4j, use the password you configured during setup"
155 | )
156 |
157 | return True, None
158 |
159 | @staticmethod
160 | def test_connection(uri: str, username: str, password: str) -> Tuple[bool, Optional[str]]:
161 | """
162 | Tests the Neo4j database connection.
163 |
164 | Returns:
165 | Tuple[bool, Optional[str]]: (is_connected, error_message)
166 | """
167 | try:
168 | from neo4j import GraphDatabase
169 | import socket
170 |
171 | # First, test if the host is reachable
172 | try:
173 | # Extract host and port from URI
174 | host_port = uri.split('://')[1]
175 | host = host_port.split(':')[0]
176 | port = int(host_port.split(':')[1])
177 |
178 | # Test socket connection
179 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
180 | sock.settimeout(5)
181 | result = sock.connect_ex((host, port))
182 | sock.close()
183 |
184 | if result != 0:
185 | return False, (
186 | f"Cannot reach Neo4j server at {host}:{port}\n"
187 | "Troubleshooting:\n"
188 | " • Is Neo4j running? Check with: docker ps (for Docker)\n"
189 | " • Is the port correct? Default is 7687\n"
190 | " • Is there a firewall blocking the connection?\n"
191 | f" • Try: docker compose up -d (if using Docker)"
192 | )
193 | except Exception as e:
194 | return False, f"Error parsing URI or checking connectivity: {str(e)}"
195 |
196 | # Now test Neo4j authentication
197 | driver = GraphDatabase.driver(uri, auth=(username, password))
198 |
199 | with driver.session() as session:
200 | result = session.run("RETURN 'Connection successful' as status")
201 | result.single()
202 |
203 | driver.close()
204 | return True, None
205 |
206 | except Exception as e:
207 | error_msg = str(e).lower()
208 |
209 | # Provide specific error messages for common issues
210 | if "authentication" in error_msg or "unauthorized" in error_msg:
211 | return False, (
212 | "Authentication failed - Invalid username or password\n"
213 | "Troubleshooting:\n"
214 | " • Default username is 'neo4j'\n"
215 | " • Did you change the password during initial setup?\n"
216 | " • If you forgot the password, you may need to reset Neo4j:\n"
217 | " - Stop: docker compose down\n"
218 | " - Remove data: docker volume rm <volume_name>\n"
219 | " - Restart: docker compose up -d"
220 | )
221 | elif "serviceunAvailable" in error_msg or "failed to establish connection" in error_msg:
222 | return False, (
223 | "Neo4j service is not available\n"
224 | "Troubleshooting:\n"
225 | " • Is Neo4j running? Check: docker ps\n"
226 | " • Start Neo4j: docker compose up -d\n"
227 | " • Check logs: docker compose logs neo4j\n"
228 | " • Wait 30-60 seconds after starting for Neo4j to initialize"
229 | )
230 | elif "unable to retrieve routing information" in error_msg:
231 | return False, (
232 | "Cannot connect to Neo4j routing\n"
233 | "Troubleshooting:\n"
234 | " • Try using 'bolt://' instead of 'neo4j://' in the URI\n"
235 | " • Example: bolt://localhost:7687"
236 | )
237 | else:
238 | return False, f"Connection failed: {str(e)}"
239 |
```
--------------------------------------------------------------------------------
/website/src/components/ui/chart.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import * as RechartsPrimitive from "recharts";
3 |
4 | import { cn } from "@/lib/utils";
5 |
6 | // Format: { THEME_NAME: CSS_SELECTOR }
7 | const THEMES = { light: "", dark: ".dark" } as const;
8 |
9 | export type ChartConfig = {
10 | [k in string]: {
11 | label?: React.ReactNode;
12 | icon?: React.ComponentType;
13 | } & ({ color?: string; theme?: never } | { color?: never; theme: Record<keyof typeof THEMES, string> });
14 | };
15 |
16 | type ChartContextProps = {
17 | config: ChartConfig;
18 | };
19 |
20 | const ChartContext = React.createContext<ChartContextProps | null>(null);
21 |
22 | function useChart() {
23 | const context = React.useContext(ChartContext);
24 |
25 | if (!context) {
26 | throw new Error("useChart must be used within a <ChartContainer />");
27 | }
28 |
29 | return context;
30 | }
31 |
32 | const ChartContainer = React.forwardRef<
33 | HTMLDivElement,
34 | React.ComponentProps<"div"> & {
35 | config: ChartConfig;
36 | children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>["children"];
37 | }
38 | >(({ id, className, children, config, ...props }, ref) => {
39 | const uniqueId = React.useId();
40 | const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
41 |
42 | return (
43 | <ChartContext.Provider value={{ config }}>
44 | <div
45 | data-chart={chartId}
46 | ref={ref}
47 | className={cn(
48 | "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
49 | className,
50 | )}
51 | {...props}
52 | >
53 | <ChartStyle id={chartId} config={config} />
54 | <RechartsPrimitive.ResponsiveContainer>{children}</RechartsPrimitive.ResponsiveContainer>
55 | </div>
56 | </ChartContext.Provider>
57 | );
58 | });
59 | ChartContainer.displayName = "Chart";
60 |
61 | const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
62 | const colorConfig = Object.entries(config).filter(([_, config]) => config.theme || config.color);
63 |
64 | if (!colorConfig.length) {
65 | return null;
66 | }
67 |
68 | return (
69 | <style
70 | dangerouslySetInnerHTML={{
71 | __html: Object.entries(THEMES)
72 | .map(
73 | ([theme, prefix]) => `
74 | ${prefix} [data-chart=${id}] {
75 | ${colorConfig
76 | .map(([key, itemConfig]) => {
77 | const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || itemConfig.color;
78 | return color ? ` --color-${key}: ${color};` : null;
79 | })
80 | .join("\n")}
81 | }
82 | `,
83 | )
84 | .join("\n"),
85 | }}
86 | />
87 | );
88 | };
89 |
90 | const ChartTooltip = RechartsPrimitive.Tooltip;
91 |
92 | const ChartTooltipContent = React.forwardRef<
93 | HTMLDivElement,
94 | React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
95 | React.ComponentProps<"div"> & {
96 | hideLabel?: boolean;
97 | hideIndicator?: boolean;
98 | indicator?: "line" | "dot" | "dashed";
99 | nameKey?: string;
100 | labelKey?: string;
101 | }
102 | >(
103 | (
104 | {
105 | active,
106 | payload,
107 | className,
108 | indicator = "dot",
109 | hideLabel = false,
110 | hideIndicator = false,
111 | label,
112 | labelFormatter,
113 | labelClassName,
114 | formatter,
115 | color,
116 | nameKey,
117 | labelKey,
118 | },
119 | ref,
120 | ) => {
121 | const { config } = useChart();
122 |
123 | const tooltipLabel = React.useMemo(() => {
124 | if (hideLabel || !payload?.length) {
125 | return null;
126 | }
127 |
128 | const [item] = payload;
129 | const key = `${labelKey || item.dataKey || item.name || "value"}`;
130 | const itemConfig = getPayloadConfigFromPayload(config, item, key);
131 | const value =
132 | !labelKey && typeof label === "string"
133 | ? config[label as keyof typeof config]?.label || label
134 | : itemConfig?.label;
135 |
136 | if (labelFormatter) {
137 | return <div className={cn("font-medium", labelClassName)}>{labelFormatter(value, payload)}</div>;
138 | }
139 |
140 | if (!value) {
141 | return null;
142 | }
143 |
144 | return <div className={cn("font-medium", labelClassName)}>{value}</div>;
145 | }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);
146 |
147 | if (!active || !payload?.length) {
148 | return null;
149 | }
150 |
151 | const nestLabel = payload.length === 1 && indicator !== "dot";
152 |
153 | return (
154 | <div
155 | ref={ref}
156 | className={cn(
157 | "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
158 | className,
159 | )}
160 | >
161 | {!nestLabel ? tooltipLabel : null}
162 | <div className="grid gap-1.5">
163 | {payload.map((item, index) => {
164 | const key = `${nameKey || item.name || item.dataKey || "value"}`;
165 | const itemConfig = getPayloadConfigFromPayload(config, item, key);
166 | const indicatorColor = color || item.payload.fill || item.color;
167 |
168 | return (
169 | <div
170 | key={item.dataKey}
171 | className={cn(
172 | "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
173 | indicator === "dot" && "items-center",
174 | )}
175 | >
176 | {formatter && item?.value !== undefined && item.name ? (
177 | formatter(item.value, item.name, item, index, item.payload)
178 | ) : (
179 | <>
180 | {itemConfig?.icon ? (
181 | <itemConfig.icon />
182 | ) : (
183 | !hideIndicator && (
184 | <div
185 | className={cn("shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]", {
186 | "h-2.5 w-2.5": indicator === "dot",
187 | "w-1": indicator === "line",
188 | "w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
189 | "my-0.5": nestLabel && indicator === "dashed",
190 | })}
191 | style={
192 | {
193 | "--color-bg": indicatorColor,
194 | "--color-border": indicatorColor,
195 | } as React.CSSProperties
196 | }
197 | />
198 | )
199 | )}
200 | <div
201 | className={cn(
202 | "flex flex-1 justify-between leading-none",
203 | nestLabel ? "items-end" : "items-center",
204 | )}
205 | >
206 | <div className="grid gap-1.5">
207 | {nestLabel ? tooltipLabel : null}
208 | <span className="text-muted-foreground">{itemConfig?.label || item.name}</span>
209 | </div>
210 | {item.value && (
211 | <span className="font-mono font-medium tabular-nums text-foreground">
212 | {item.value.toLocaleString()}
213 | </span>
214 | )}
215 | </div>
216 | </>
217 | )}
218 | </div>
219 | );
220 | })}
221 | </div>
222 | </div>
223 | );
224 | },
225 | );
226 | ChartTooltipContent.displayName = "ChartTooltip";
227 |
228 | const ChartLegend = RechartsPrimitive.Legend;
229 |
230 | const ChartLegendContent = React.forwardRef<
231 | HTMLDivElement,
232 | React.ComponentProps<"div"> &
233 | Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
234 | hideIcon?: boolean;
235 | nameKey?: string;
236 | }
237 | >(({ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey }, ref) => {
238 | const { config } = useChart();
239 |
240 | if (!payload?.length) {
241 | return null;
242 | }
243 |
244 | return (
245 | <div
246 | ref={ref}
247 | className={cn("flex items-center justify-center gap-4", verticalAlign === "top" ? "pb-3" : "pt-3", className)}
248 | >
249 | {payload.map((item) => {
250 | const key = `${nameKey || item.dataKey || "value"}`;
251 | const itemConfig = getPayloadConfigFromPayload(config, item, key);
252 |
253 | return (
254 | <div
255 | key={item.value}
256 | className={cn("flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground")}
257 | >
258 | {itemConfig?.icon && !hideIcon ? (
259 | <itemConfig.icon />
260 | ) : (
261 | <div
262 | className="h-2 w-2 shrink-0 rounded-[2px]"
263 | style={{
264 | backgroundColor: item.color,
265 | }}
266 | />
267 | )}
268 | {itemConfig?.label}
269 | </div>
270 | );
271 | })}
272 | </div>
273 | );
274 | });
275 | ChartLegendContent.displayName = "ChartLegend";
276 |
277 | // Helper to extract item config from a payload.
278 | function getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {
279 | if (typeof payload !== "object" || payload === null) {
280 | return undefined;
281 | }
282 |
283 | const payloadPayload =
284 | "payload" in payload && typeof payload.payload === "object" && payload.payload !== null
285 | ? payload.payload
286 | : undefined;
287 |
288 | let configLabelKey: string = key;
289 |
290 | if (key in payload && typeof payload[key as keyof typeof payload] === "string") {
291 | configLabelKey = payload[key as keyof typeof payload] as string;
292 | } else if (
293 | payloadPayload &&
294 | key in payloadPayload &&
295 | typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
296 | ) {
297 | configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;
298 | }
299 |
300 | return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config];
301 | }
302 |
303 | export { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle };
304 |
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.pt.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `Portuguese` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(k,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("a~");continue;case 2:z.slice_from("o~");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function n(){if(z.out_grouping(y,97,250)){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!0;z.cursor++}return!1}return!0}function i(){if(z.in_grouping(y,97,250))for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return g=z.cursor,!0}function o(){var e,r,s=z.cursor;if(z.in_grouping(y,97,250))if(e=z.cursor,n()){if(z.cursor=e,i())return}else g=z.cursor;if(z.cursor=s,z.out_grouping(y,97,250)){if(r=z.cursor,n()){if(z.cursor=r,!z.in_grouping(y,97,250)||z.cursor>=z.limit)return;z.cursor++}g=z.cursor}}function t(){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return!0}function a(){var e=z.cursor;g=z.limit,b=g,h=g,o(),z.cursor=e,t()&&(b=z.cursor,t()&&(h=z.cursor))}function u(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(q,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("ã");continue;case 2:z.slice_from("õ");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function w(){return g<=z.cursor}function m(){return b<=z.cursor}function c(){return h<=z.cursor}function l(){var e;if(z.ket=z.cursor,!(e=z.find_among_b(F,45)))return!1;switch(z.bra=z.cursor,e){case 1:if(!c())return!1;z.slice_del();break;case 2:if(!c())return!1;z.slice_from("log");break;case 3:if(!c())return!1;z.slice_from("u");break;case 4:if(!c())return!1;z.slice_from("ente");break;case 5:if(!m())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(j,4),e&&(z.bra=z.cursor,c()&&(z.slice_del(),1==e&&(z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del()))));break;case 6:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(C,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 7:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(P,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 8:if(!c())return!1;z.slice_del(),z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del());break;case 9:if(!w()||!z.eq_s_b(1,"e"))return!1;z.slice_from("ir")}return!0}function f(){var e,r;if(z.cursor>=g){if(r=z.limit_backward,z.limit_backward=g,z.ket=z.cursor,e=z.find_among_b(S,120))return z.bra=z.cursor,1==e&&z.slice_del(),z.limit_backward=r,!0;z.limit_backward=r}return!1}function d(){var e;z.ket=z.cursor,(e=z.find_among_b(W,7))&&(z.bra=z.cursor,1==e&&w()&&z.slice_del())}function v(e,r){if(z.eq_s_b(1,e)){z.bra=z.cursor;var s=z.limit-z.cursor;if(z.eq_s_b(1,r))return z.cursor=z.limit-s,w()&&z.slice_del(),!1}return!0}function p(){var e;if(z.ket=z.cursor,e=z.find_among_b(L,4))switch(z.bra=z.cursor,e){case 1:w()&&(z.slice_del(),z.ket=z.cursor,z.limit-z.cursor,v("u","g")&&v("i","c"));break;case 2:z.slice_from("c")}}function _(){if(!l()&&(z.cursor=z.limit,!f()))return z.cursor=z.limit,void d();z.cursor=z.limit,z.ket=z.cursor,z.eq_s_b(1,"i")&&(z.bra=z.cursor,z.eq_s_b(1,"c")&&(z.cursor=z.limit,w()&&z.slice_del()))}var h,b,g,k=[new r("",-1,3),new r("ã",0,1),new r("õ",0,2)],q=[new r("",-1,3),new r("a~",0,1),new r("o~",0,2)],j=[new r("ic",-1,-1),new r("ad",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],C=[new r("ante",-1,1),new r("avel",-1,1),new r("ível",-1,1)],P=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],F=[new r("ica",-1,1),new r("ância",-1,1),new r("ência",-1,4),new r("ira",-1,9),new r("adora",-1,1),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,8),new r("eza",-1,1),new r("logía",-1,2),new r("idade",-1,7),new r("ante",-1,1),new r("mente",-1,6),new r("amente",12,5),new r("ável",-1,1),new r("ível",-1,1),new r("ución",-1,3),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,1),new r("imento",-1,1),new r("ivo",-1,8),new r("aça~o",-1,1),new r("ador",-1,1),new r("icas",-1,1),new r("ências",-1,4),new r("iras",-1,9),new r("adoras",-1,1),new r("osas",-1,1),new r("istas",-1,1),new r("ivas",-1,8),new r("ezas",-1,1),new r("logías",-1,2),new r("idades",-1,7),new r("uciones",-1,3),new r("adores",-1,1),new r("antes",-1,1),new r("aço~es",-1,1),new r("icos",-1,1),new r("ismos",-1,1),new r("osos",-1,1),new r("amentos",-1,1),new r("imentos",-1,1),new r("ivos",-1,8)],S=[new r("ada",-1,1),new r("ida",-1,1),new r("ia",-1,1),new r("aria",2,1),new r("eria",2,1),new r("iria",2,1),new r("ara",-1,1),new r("era",-1,1),new r("ira",-1,1),new r("ava",-1,1),new r("asse",-1,1),new r("esse",-1,1),new r("isse",-1,1),new r("aste",-1,1),new r("este",-1,1),new r("iste",-1,1),new r("ei",-1,1),new r("arei",16,1),new r("erei",16,1),new r("irei",16,1),new r("am",-1,1),new r("iam",20,1),new r("ariam",21,1),new r("eriam",21,1),new r("iriam",21,1),new r("aram",20,1),new r("eram",20,1),new r("iram",20,1),new r("avam",20,1),new r("em",-1,1),new r("arem",29,1),new r("erem",29,1),new r("irem",29,1),new r("assem",29,1),new r("essem",29,1),new r("issem",29,1),new r("ado",-1,1),new r("ido",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("indo",-1,1),new r("ara~o",-1,1),new r("era~o",-1,1),new r("ira~o",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("ir",-1,1),new r("as",-1,1),new r("adas",47,1),new r("idas",47,1),new r("ias",47,1),new r("arias",50,1),new r("erias",50,1),new r("irias",50,1),new r("aras",47,1),new r("eras",47,1),new r("iras",47,1),new r("avas",47,1),new r("es",-1,1),new r("ardes",58,1),new r("erdes",58,1),new r("irdes",58,1),new r("ares",58,1),new r("eres",58,1),new r("ires",58,1),new r("asses",58,1),new r("esses",58,1),new r("isses",58,1),new r("astes",58,1),new r("estes",58,1),new r("istes",58,1),new r("is",-1,1),new r("ais",71,1),new r("eis",71,1),new r("areis",73,1),new r("ereis",73,1),new r("ireis",73,1),new r("áreis",73,1),new r("éreis",73,1),new r("íreis",73,1),new r("ásseis",73,1),new r("ésseis",73,1),new r("ísseis",73,1),new r("áveis",73,1),new r("íeis",73,1),new r("aríeis",84,1),new r("eríeis",84,1),new r("iríeis",84,1),new r("ados",-1,1),new r("idos",-1,1),new r("amos",-1,1),new r("áramos",90,1),new r("éramos",90,1),new r("íramos",90,1),new r("ávamos",90,1),new r("íamos",90,1),new r("aríamos",95,1),new r("eríamos",95,1),new r("iríamos",95,1),new r("emos",-1,1),new r("aremos",99,1),new r("eremos",99,1),new r("iremos",99,1),new r("ássemos",99,1),new r("êssemos",99,1),new r("íssemos",99,1),new r("imos",-1,1),new r("armos",-1,1),new r("ermos",-1,1),new r("irmos",-1,1),new r("ámos",-1,1),new r("arás",-1,1),new r("erás",-1,1),new r("irás",-1,1),new r("eu",-1,1),new r("iu",-1,1),new r("ou",-1,1),new r("ará",-1,1),new r("erá",-1,1),new r("irá",-1,1)],W=[new r("a",-1,1),new r("i",-1,1),new r("o",-1,1),new r("os",-1,1),new r("á",-1,1),new r("í",-1,1),new r("ó",-1,1)],L=[new r("e",-1,1),new r("ç",-1,2),new r("é",-1,1),new r("ê",-1,1)],y=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],z=new s;this.setCurrent=function(e){z.setCurrent(e)},this.getCurrent=function(){return z.getCurrent()},this.stem=function(){var r=z.cursor;return e(),z.cursor=r,a(),z.limit_backward=r,z.cursor=z.limit,_(),z.cursor=z.limit,p(),z.cursor=z.limit_backward,u(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}});
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.fr.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `French` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,s){return!(!W.eq_s(1,e)||(W.ket=W.cursor,!W.in_grouping(F,97,251)))&&(W.slice_from(r),W.cursor=s,!0)}function i(e,r,s){return!!W.eq_s(1,e)&&(W.ket=W.cursor,W.slice_from(r),W.cursor=s,!0)}function n(){for(var r,s;;){if(r=W.cursor,W.in_grouping(F,97,251)){if(W.bra=W.cursor,s=W.cursor,e("u","U",r))continue;if(W.cursor=s,e("i","I",r))continue;if(W.cursor=s,i("y","Y",r))continue}if(W.cursor=r,W.bra=r,!e("y","Y",r)){if(W.cursor=r,W.eq_s(1,"q")&&(W.bra=W.cursor,i("u","U",r)))continue;if(W.cursor=r,r>=W.limit)return;W.cursor++}}}function t(){for(;!W.in_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}for(;!W.out_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}return!1}function u(){var e=W.cursor;if(q=W.limit,g=q,p=q,W.in_grouping(F,97,251)&&W.in_grouping(F,97,251)&&W.cursor<W.limit)W.cursor++;else if(W.cursor=e,!W.find_among(v,3)){W.cursor=e;do{if(W.cursor>=W.limit){W.cursor=q;break}W.cursor++}while(!W.in_grouping(F,97,251))}q=W.cursor,W.cursor=e,t()||(g=W.cursor,t()||(p=W.cursor))}function o(){for(var e,r;;){if(r=W.cursor,W.bra=r,!(e=W.find_among(h,4)))break;switch(W.ket=W.cursor,e){case 1:W.slice_from("i");break;case 2:W.slice_from("u");break;case 3:W.slice_from("y");break;case 4:if(W.cursor>=W.limit)return;W.cursor++}}}function c(){return q<=W.cursor}function a(){return g<=W.cursor}function l(){return p<=W.cursor}function w(){var e,r;if(W.ket=W.cursor,e=W.find_among_b(C,43)){switch(W.bra=W.cursor,e){case 1:if(!l())return!1;W.slice_del();break;case 2:if(!l())return!1;W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")&&(W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU"));break;case 3:if(!l())return!1;W.slice_from("log");break;case 4:if(!l())return!1;W.slice_from("u");break;case 5:if(!l())return!1;W.slice_from("ent");break;case 6:if(!c())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(z,6))switch(W.bra=W.cursor,e){case 1:l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&W.slice_del()));break;case 2:l()?W.slice_del():a()&&W.slice_from("eux");break;case 3:l()&&W.slice_del();break;case 4:c()&&W.slice_from("i")}break;case 7:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(y,3))switch(W.bra=W.cursor,e){case 1:l()?W.slice_del():W.slice_from("abl");break;case 2:l()?W.slice_del():W.slice_from("iqU");break;case 3:l()&&W.slice_del()}break;case 8:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")))){W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU");break}break;case 9:W.slice_from("eau");break;case 10:if(!a())return!1;W.slice_from("al");break;case 11:if(l())W.slice_del();else{if(!a())return!1;W.slice_from("eux")}break;case 12:if(!a()||!W.out_grouping_b(F,97,251))return!1;W.slice_del();break;case 13:return c()&&W.slice_from("ant"),!1;case 14:return c()&&W.slice_from("ent"),!1;case 15:return r=W.limit-W.cursor,W.in_grouping_b(F,97,251)&&c()&&(W.cursor=W.limit-r,W.slice_del()),!1}return!0}return!1}function f(){var e,r;if(W.cursor<q)return!1;if(r=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,!(e=W.find_among_b(x,35)))return W.limit_backward=r,!1;if(W.bra=W.cursor,1==e){if(!W.out_grouping_b(F,97,251))return W.limit_backward=r,!1;W.slice_del()}return W.limit_backward=r,!0}function m(){var e,r,s;if(W.cursor<q)return!1;if(r=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,!(e=W.find_among_b(I,38)))return W.limit_backward=r,!1;switch(W.bra=W.cursor,e){case 1:if(!l())return W.limit_backward=r,!1;W.slice_del();break;case 2:W.slice_del();break;case 3:W.slice_del(),s=W.limit-W.cursor,W.ket=W.cursor,W.eq_s_b(1,"e")?(W.bra=W.cursor,W.slice_del()):W.cursor=W.limit-s}return W.limit_backward=r,!0}function _(){var e,r,s,i,n=W.limit-W.cursor;if(W.ket=W.cursor,W.eq_s_b(1,"s")?(W.bra=W.cursor,r=W.limit-W.cursor,W.out_grouping_b(S,97,232)?(W.cursor=W.limit-r,W.slice_del()):W.cursor=W.limit-n):W.cursor=W.limit-n,W.cursor>=q){if(s=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,e=W.find_among_b(P,7))switch(W.bra=W.cursor,e){case 1:if(l()){if(i=W.limit-W.cursor,!W.eq_s_b(1,"s")&&(W.cursor=W.limit-i,!W.eq_s_b(1,"t")))break;W.slice_del()}break;case 2:W.slice_from("i");break;case 3:W.slice_del();break;case 4:W.eq_s_b(2,"gu")&&W.slice_del()}W.limit_backward=s}}function b(){var e=W.limit-W.cursor;W.find_among_b(U,5)&&(W.cursor=W.limit-e,W.ket=W.cursor,W.cursor>W.limit_backward&&(W.cursor--,W.bra=W.cursor,W.slice_del()))}function d(){for(var e,r=1;W.out_grouping_b(F,97,251);)r--;if(r<=0){if(W.ket=W.cursor,e=W.limit-W.cursor,!W.eq_s_b(1,"é")&&(W.cursor=W.limit-e,!W.eq_s_b(1,"è")))return;W.bra=W.cursor,W.slice_from("e")}}function k(){if(!w()&&(W.cursor=W.limit,!f()&&(W.cursor=W.limit,!m())))return W.cursor=W.limit,void _();W.cursor=W.limit,W.ket=W.cursor,W.eq_s_b(1,"Y")?(W.bra=W.cursor,W.slice_from("i")):(W.cursor=W.limit,W.eq_s_b(1,"ç")&&(W.bra=W.cursor,W.slice_from("c")))}var p,g,q,v=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],h=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],z=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],y=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],C=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],x=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],I=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],P=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],U=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],F=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],S=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],W=new s;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){var e=W.cursor;return n(),W.cursor=e,u(),W.limit_backward=e,W.cursor=W.limit,k(),W.cursor=W.limit,b(),W.cursor=W.limit,d(),W.cursor=W.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}});
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.ro.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `Romanian` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ro=function(){this.pipeline.reset(),this.pipeline.add(e.ro.trimmer,e.ro.stopWordFilter,e.ro.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ro.stemmer))},e.ro.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.ro.trimmer=e.trimmerSupport.generateTrimmer(e.ro.wordCharacters),e.Pipeline.registerFunction(e.ro.trimmer,"trimmer-ro"),e.ro.stemmer=function(){var i=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){function e(e,i){L.eq_s(1,e)&&(L.ket=L.cursor,L.in_grouping(W,97,259)&&L.slice_from(i))}function n(){for(var i,r;;){if(i=L.cursor,L.in_grouping(W,97,259)&&(r=L.cursor,L.bra=r,e("u","U"),L.cursor=r,e("i","I")),L.cursor=i,L.cursor>=L.limit)break;L.cursor++}}function t(){if(L.out_grouping(W,97,259)){for(;!L.in_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}return!0}function a(){if(L.in_grouping(W,97,259))for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}function o(){var e,i,r=L.cursor;if(L.in_grouping(W,97,259)){if(e=L.cursor,!t())return void(h=L.cursor);if(L.cursor=e,!a())return void(h=L.cursor)}L.cursor=r,L.out_grouping(W,97,259)&&(i=L.cursor,t()&&(L.cursor=i,L.in_grouping(W,97,259)&&L.cursor<L.limit&&L.cursor++),h=L.cursor)}function u(){for(;!L.in_grouping(W,97,259);){if(L.cursor>=L.limit)return!1;L.cursor++}for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!1;L.cursor++}return!0}function c(){var e=L.cursor;h=L.limit,k=h,g=h,o(),L.cursor=e,u()&&(k=L.cursor,u()&&(g=L.cursor))}function s(){for(var e;;){if(L.bra=L.cursor,e=L.find_among(z,3))switch(L.ket=L.cursor,e){case 1:L.slice_from("i");continue;case 2:L.slice_from("u");continue;case 3:if(L.cursor>=L.limit)break;L.cursor++;continue}break}}function w(){return h<=L.cursor}function m(){return k<=L.cursor}function l(){return g<=L.cursor}function f(){var e,i;if(L.ket=L.cursor,(e=L.find_among_b(C,16))&&(L.bra=L.cursor,m()))switch(e){case 1:L.slice_del();break;case 2:L.slice_from("a");break;case 3:L.slice_from("e");break;case 4:L.slice_from("i");break;case 5:i=L.limit-L.cursor,L.eq_s_b(2,"ab")||(L.cursor=L.limit-i,L.slice_from("i"));break;case 6:L.slice_from("at");break;case 7:L.slice_from("aţi")}}function p(){var e,i=L.limit-L.cursor;if(L.ket=L.cursor,(e=L.find_among_b(P,46))&&(L.bra=L.cursor,m())){switch(e){case 1:L.slice_from("abil");break;case 2:L.slice_from("ibil");break;case 3:L.slice_from("iv");break;case 4:L.slice_from("ic");break;case 5:L.slice_from("at");break;case 6:L.slice_from("it")}return _=!0,L.cursor=L.limit-i,!0}return!1}function d(){var e,i;for(_=!1;;)if(i=L.limit-L.cursor,!p()){L.cursor=L.limit-i;break}if(L.ket=L.cursor,(e=L.find_among_b(F,62))&&(L.bra=L.cursor,l())){switch(e){case 1:L.slice_del();break;case 2:L.eq_s_b(1,"ţ")&&(L.bra=L.cursor,L.slice_from("t"));break;case 3:L.slice_from("ist")}_=!0}}function b(){var e,i,r;if(L.cursor>=h){if(i=L.limit_backward,L.limit_backward=h,L.ket=L.cursor,e=L.find_among_b(q,94))switch(L.bra=L.cursor,e){case 1:if(r=L.limit-L.cursor,!L.out_grouping_b(W,97,259)&&(L.cursor=L.limit-r,!L.eq_s_b(1,"u")))break;case 2:L.slice_del()}L.limit_backward=i}}function v(){var e;L.ket=L.cursor,(e=L.find_among_b(S,5))&&(L.bra=L.cursor,w()&&1==e&&L.slice_del())}var _,g,k,h,z=[new i("",-1,3),new i("I",0,1),new i("U",0,2)],C=[new i("ea",-1,3),new i("aţia",-1,7),new i("aua",-1,2),new i("iua",-1,4),new i("aţie",-1,7),new i("ele",-1,3),new i("ile",-1,5),new i("iile",6,4),new i("iei",-1,4),new i("atei",-1,6),new i("ii",-1,4),new i("ului",-1,1),new i("ul",-1,1),new i("elor",-1,3),new i("ilor",-1,4),new i("iilor",14,4)],P=[new i("icala",-1,4),new i("iciva",-1,4),new i("ativa",-1,5),new i("itiva",-1,6),new i("icale",-1,4),new i("aţiune",-1,5),new i("iţiune",-1,6),new i("atoare",-1,5),new i("itoare",-1,6),new i("ătoare",-1,5),new i("icitate",-1,4),new i("abilitate",-1,1),new i("ibilitate",-1,2),new i("ivitate",-1,3),new i("icive",-1,4),new i("ative",-1,5),new i("itive",-1,6),new i("icali",-1,4),new i("atori",-1,5),new i("icatori",18,4),new i("itori",-1,6),new i("ători",-1,5),new i("icitati",-1,4),new i("abilitati",-1,1),new i("ivitati",-1,3),new i("icivi",-1,4),new i("ativi",-1,5),new i("itivi",-1,6),new i("icităi",-1,4),new i("abilităi",-1,1),new i("ivităi",-1,3),new i("icităţi",-1,4),new i("abilităţi",-1,1),new i("ivităţi",-1,3),new i("ical",-1,4),new i("ator",-1,5),new i("icator",35,4),new i("itor",-1,6),new i("ător",-1,5),new i("iciv",-1,4),new i("ativ",-1,5),new i("itiv",-1,6),new i("icală",-1,4),new i("icivă",-1,4),new i("ativă",-1,5),new i("itivă",-1,6)],F=[new i("ica",-1,1),new i("abila",-1,1),new i("ibila",-1,1),new i("oasa",-1,1),new i("ata",-1,1),new i("ita",-1,1),new i("anta",-1,1),new i("ista",-1,3),new i("uta",-1,1),new i("iva",-1,1),new i("ic",-1,1),new i("ice",-1,1),new i("abile",-1,1),new i("ibile",-1,1),new i("isme",-1,3),new i("iune",-1,2),new i("oase",-1,1),new i("ate",-1,1),new i("itate",17,1),new i("ite",-1,1),new i("ante",-1,1),new i("iste",-1,3),new i("ute",-1,1),new i("ive",-1,1),new i("ici",-1,1),new i("abili",-1,1),new i("ibili",-1,1),new i("iuni",-1,2),new i("atori",-1,1),new i("osi",-1,1),new i("ati",-1,1),new i("itati",30,1),new i("iti",-1,1),new i("anti",-1,1),new i("isti",-1,3),new i("uti",-1,1),new i("işti",-1,3),new i("ivi",-1,1),new i("ităi",-1,1),new i("oşi",-1,1),new i("ităţi",-1,1),new i("abil",-1,1),new i("ibil",-1,1),new i("ism",-1,3),new i("ator",-1,1),new i("os",-1,1),new i("at",-1,1),new i("it",-1,1),new i("ant",-1,1),new i("ist",-1,3),new i("ut",-1,1),new i("iv",-1,1),new i("ică",-1,1),new i("abilă",-1,1),new i("ibilă",-1,1),new i("oasă",-1,1),new i("ată",-1,1),new i("ită",-1,1),new i("antă",-1,1),new i("istă",-1,3),new i("ută",-1,1),new i("ivă",-1,1)],q=[new i("ea",-1,1),new i("ia",-1,1),new i("esc",-1,1),new i("ăsc",-1,1),new i("ind",-1,1),new i("ând",-1,1),new i("are",-1,1),new i("ere",-1,1),new i("ire",-1,1),new i("âre",-1,1),new i("se",-1,2),new i("ase",10,1),new i("sese",10,2),new i("ise",10,1),new i("use",10,1),new i("âse",10,1),new i("eşte",-1,1),new i("ăşte",-1,1),new i("eze",-1,1),new i("ai",-1,1),new i("eai",19,1),new i("iai",19,1),new i("sei",-1,2),new i("eşti",-1,1),new i("ăşti",-1,1),new i("ui",-1,1),new i("ezi",-1,1),new i("âi",-1,1),new i("aşi",-1,1),new i("seşi",-1,2),new i("aseşi",29,1),new i("seseşi",29,2),new i("iseşi",29,1),new i("useşi",29,1),new i("âseşi",29,1),new i("işi",-1,1),new i("uşi",-1,1),new i("âşi",-1,1),new i("aţi",-1,2),new i("eaţi",38,1),new i("iaţi",38,1),new i("eţi",-1,2),new i("iţi",-1,2),new i("âţi",-1,2),new i("arăţi",-1,1),new i("serăţi",-1,2),new i("aserăţi",45,1),new i("seserăţi",45,2),new i("iserăţi",45,1),new i("userăţi",45,1),new i("âserăţi",45,1),new i("irăţi",-1,1),new i("urăţi",-1,1),new i("ârăţi",-1,1),new i("am",-1,1),new i("eam",54,1),new i("iam",54,1),new i("em",-1,2),new i("asem",57,1),new i("sesem",57,2),new i("isem",57,1),new i("usem",57,1),new i("âsem",57,1),new i("im",-1,2),new i("âm",-1,2),new i("ăm",-1,2),new i("arăm",65,1),new i("serăm",65,2),new i("aserăm",67,1),new i("seserăm",67,2),new i("iserăm",67,1),new i("userăm",67,1),new i("âserăm",67,1),new i("irăm",65,1),new i("urăm",65,1),new i("ârăm",65,1),new i("au",-1,1),new i("eau",76,1),new i("iau",76,1),new i("indu",-1,1),new i("ându",-1,1),new i("ez",-1,1),new i("ească",-1,1),new i("ară",-1,1),new i("seră",-1,2),new i("aseră",84,1),new i("seseră",84,2),new i("iseră",84,1),new i("useră",84,1),new i("âseră",84,1),new i("iră",-1,1),new i("ură",-1,1),new i("âră",-1,1),new i("ează",-1,1)],S=[new i("a",-1,1),new i("e",-1,1),new i("ie",1,1),new i("i",-1,1),new i("ă",-1,1)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,32,0,0,4],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var e=L.cursor;return n(),L.cursor=e,c(),L.limit_backward=e,L.cursor=L.limit,f(),L.cursor=L.limit,d(),L.cursor=L.limit,_||(L.cursor=L.limit,b(),L.cursor=L.limit),v(),L.cursor=L.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.ro.stemmer,"stemmer-ro"),e.ro.stopWordFilter=e.generateStopWordFilter("acea aceasta această aceea acei aceia acel acela acele acelea acest acesta aceste acestea aceşti aceştia acolo acord acum ai aia aibă aici al ale alea altceva altcineva am ar are asemenea asta astea astăzi asupra au avea avem aveţi azi aş aşadar aţi bine bucur bună ca care caut ce cel ceva chiar cinci cine cineva contra cu cum cumva curând curînd când cât câte câtva câţi cînd cît cîte cîtva cîţi că căci cărei căror cărui către da dacă dar datorită dată dau de deci deja deoarece departe deşi din dinaintea dintr- dintre doi doilea două drept după dă ea ei el ele eram este eu eşti face fata fi fie fiecare fii fim fiu fiţi frumos fără graţie halbă iar ieri la le li lor lui lângă lîngă mai mea mei mele mereu meu mi mie mine mult multă mulţi mulţumesc mâine mîine mă ne nevoie nici nicăieri nimeni nimeri nimic nişte noastre noastră noi noroc nostru nouă noştri nu opt ori oricare orice oricine oricum oricând oricât oricînd oricît oriunde patra patru patrulea pe pentru peste pic poate pot prea prima primul prin puţin puţina puţină până pînă rog sa sale sau se spate spre sub sunt suntem sunteţi sută sînt sîntem sînteţi să săi său ta tale te timp tine toate toată tot totuşi toţi trei treia treilea tu tăi tău un una unde undeva unei uneia unele uneori unii unor unora unu unui unuia unul vi voastre voastră voi vostru vouă voştri vreme vreo vreun vă zece zero zi zice îi îl îmi împotriva în înainte înaintea încotro încât încît între întrucât întrucît îţi ăla ălea ăsta ăstea ăştia şapte şase şi ştiu ţi ţie".split(" ")),e.Pipeline.registerFunction(e.ro.stopWordFilter,"stopWordFilter-ro")}});
```
--------------------------------------------------------------------------------
/docs/site/assets/javascripts/lunr/min/lunr.it.min.js:
--------------------------------------------------------------------------------
```javascript
1 | /*!
2 | * Lunr languages, `Italian` language
3 | * https://github.com/MihaiValentin/lunr-languages
4 | *
5 | * Copyright 2014, Mihai Valentin
6 | * http://www.mozilla.org/MPL/
7 | */
8 | /*!
9 | * based on
10 | * Snowball JavaScript Library v0.3
11 | * http://code.google.com/p/urim/
12 | * http://snowball.tartarus.org/
13 | *
14 | * Copyright 2010, Oleg Mazko
15 | * http://www.mozilla.org/MPL/
16 | */
17 |
18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.it=function(){this.pipeline.reset(),this.pipeline.add(e.it.trimmer,e.it.stopWordFilter,e.it.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.it.stemmer))},e.it.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.it.trimmer=e.trimmerSupport.generateTrimmer(e.it.wordCharacters),e.Pipeline.registerFunction(e.it.trimmer,"trimmer-it"),e.it.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!x.eq_s(1,e)||(x.ket=x.cursor,!x.in_grouping(L,97,249)))&&(x.slice_from(r),x.cursor=n,!0)}function i(){for(var r,n,i,o,t=x.cursor;;){if(x.bra=x.cursor,r=x.find_among(h,7))switch(x.ket=x.cursor,r){case 1:x.slice_from("à");continue;case 2:x.slice_from("è");continue;case 3:x.slice_from("ì");continue;case 4:x.slice_from("ò");continue;case 5:x.slice_from("ù");continue;case 6:x.slice_from("qU");continue;case 7:if(x.cursor>=x.limit)break;x.cursor++;continue}break}for(x.cursor=t;;)for(n=x.cursor;;){if(i=x.cursor,x.in_grouping(L,97,249)){if(x.bra=x.cursor,o=x.cursor,e("u","U",i))break;if(x.cursor=o,e("i","I",i))break}if(x.cursor=i,x.cursor>=x.limit)return void(x.cursor=n);x.cursor++}}function o(e){if(x.cursor=e,!x.in_grouping(L,97,249))return!1;for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function t(){if(x.in_grouping(L,97,249)){var e=x.cursor;if(x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return o(e);x.cursor++}return!0}return o(e)}return!1}function s(){var e,r=x.cursor;if(!t()){if(x.cursor=r,!x.out_grouping(L,97,249))return;if(e=x.cursor,x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return x.cursor=e,void(x.in_grouping(L,97,249)&&x.cursor<x.limit&&x.cursor++);x.cursor++}return void(k=x.cursor)}if(x.cursor=e,!x.in_grouping(L,97,249)||x.cursor>=x.limit)return;x.cursor++}k=x.cursor}function a(){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function u(){var e=x.cursor;k=x.limit,p=k,g=k,s(),x.cursor=e,a()&&(p=x.cursor,a()&&(g=x.cursor))}function c(){for(var e;;){if(x.bra=x.cursor,!(e=x.find_among(q,3)))break;switch(x.ket=x.cursor,e){case 1:x.slice_from("i");break;case 2:x.slice_from("u");break;case 3:if(x.cursor>=x.limit)return;x.cursor++}}}function w(){return k<=x.cursor}function l(){return p<=x.cursor}function m(){return g<=x.cursor}function f(){var e;if(x.ket=x.cursor,x.find_among_b(C,37)&&(x.bra=x.cursor,(e=x.find_among_b(z,5))&&w()))switch(e){case 1:x.slice_del();break;case 2:x.slice_from("e")}}function v(){var e;if(x.ket=x.cursor,!(e=x.find_among_b(S,51)))return!1;switch(x.bra=x.cursor,e){case 1:if(!m())return!1;x.slice_del();break;case 2:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del());break;case 3:if(!m())return!1;x.slice_from("log");break;case 4:if(!m())return!1;x.slice_from("u");break;case 5:if(!m())return!1;x.slice_from("ente");break;case 6:if(!w())return!1;x.slice_del();break;case 7:if(!l())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(P,4),e&&(x.bra=x.cursor,m()&&(x.slice_del(),1==e&&(x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&x.slice_del()))));break;case 8:if(!m())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(F,3),e&&(x.bra=x.cursor,1==e&&m()&&x.slice_del());break;case 9:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del())))}return!0}function b(){var e,r;x.cursor>=k&&(r=x.limit_backward,x.limit_backward=k,x.ket=x.cursor,e=x.find_among_b(W,87),e&&(x.bra=x.cursor,1==e&&x.slice_del()),x.limit_backward=r)}function d(){var e=x.limit-x.cursor;if(x.ket=x.cursor,x.in_grouping_b(y,97,242)&&(x.bra=x.cursor,w()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(1,"i")&&(x.bra=x.cursor,w()))))return void x.slice_del();x.cursor=x.limit-e}function _(){d(),x.ket=x.cursor,x.eq_s_b(1,"h")&&(x.bra=x.cursor,x.in_grouping_b(U,99,103)&&w()&&x.slice_del())}var g,p,k,h=[new r("",-1,7),new r("qu",0,6),new r("á",0,1),new r("é",0,2),new r("í",0,3),new r("ó",0,4),new r("ú",0,5)],q=[new r("",-1,3),new r("I",0,1),new r("U",0,2)],C=[new r("la",-1,-1),new r("cela",0,-1),new r("gliela",0,-1),new r("mela",0,-1),new r("tela",0,-1),new r("vela",0,-1),new r("le",-1,-1),new r("cele",6,-1),new r("gliele",6,-1),new r("mele",6,-1),new r("tele",6,-1),new r("vele",6,-1),new r("ne",-1,-1),new r("cene",12,-1),new r("gliene",12,-1),new r("mene",12,-1),new r("sene",12,-1),new r("tene",12,-1),new r("vene",12,-1),new r("ci",-1,-1),new r("li",-1,-1),new r("celi",20,-1),new r("glieli",20,-1),new r("meli",20,-1),new r("teli",20,-1),new r("veli",20,-1),new r("gli",20,-1),new r("mi",-1,-1),new r("si",-1,-1),new r("ti",-1,-1),new r("vi",-1,-1),new r("lo",-1,-1),new r("celo",31,-1),new r("glielo",31,-1),new r("melo",31,-1),new r("telo",31,-1),new r("velo",31,-1)],z=[new r("ando",-1,1),new r("endo",-1,1),new r("ar",-1,2),new r("er",-1,2),new r("ir",-1,2)],P=[new r("ic",-1,-1),new r("abil",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],F=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],S=[new r("ica",-1,1),new r("logia",-1,3),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,9),new r("anza",-1,1),new r("enza",-1,5),new r("ice",-1,1),new r("atrice",7,1),new r("iche",-1,1),new r("logie",-1,3),new r("abile",-1,1),new r("ibile",-1,1),new r("usione",-1,4),new r("azione",-1,2),new r("uzione",-1,4),new r("atore",-1,2),new r("ose",-1,1),new r("ante",-1,1),new r("mente",-1,1),new r("amente",19,7),new r("iste",-1,1),new r("ive",-1,9),new r("anze",-1,1),new r("enze",-1,5),new r("ici",-1,1),new r("atrici",25,1),new r("ichi",-1,1),new r("abili",-1,1),new r("ibili",-1,1),new r("ismi",-1,1),new r("usioni",-1,4),new r("azioni",-1,2),new r("uzioni",-1,4),new r("atori",-1,2),new r("osi",-1,1),new r("anti",-1,1),new r("amenti",-1,6),new r("imenti",-1,6),new r("isti",-1,1),new r("ivi",-1,9),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,6),new r("imento",-1,6),new r("ivo",-1,9),new r("ità",-1,8),new r("istà",-1,1),new r("istè",-1,1),new r("istì",-1,1)],W=[new r("isca",-1,1),new r("enda",-1,1),new r("ata",-1,1),new r("ita",-1,1),new r("uta",-1,1),new r("ava",-1,1),new r("eva",-1,1),new r("iva",-1,1),new r("erebbe",-1,1),new r("irebbe",-1,1),new r("isce",-1,1),new r("ende",-1,1),new r("are",-1,1),new r("ere",-1,1),new r("ire",-1,1),new r("asse",-1,1),new r("ate",-1,1),new r("avate",16,1),new r("evate",16,1),new r("ivate",16,1),new r("ete",-1,1),new r("erete",20,1),new r("irete",20,1),new r("ite",-1,1),new r("ereste",-1,1),new r("ireste",-1,1),new r("ute",-1,1),new r("erai",-1,1),new r("irai",-1,1),new r("isci",-1,1),new r("endi",-1,1),new r("erei",-1,1),new r("irei",-1,1),new r("assi",-1,1),new r("ati",-1,1),new r("iti",-1,1),new r("eresti",-1,1),new r("iresti",-1,1),new r("uti",-1,1),new r("avi",-1,1),new r("evi",-1,1),new r("ivi",-1,1),new r("isco",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("Yamo",-1,1),new r("iamo",-1,1),new r("avamo",-1,1),new r("evamo",-1,1),new r("ivamo",-1,1),new r("eremo",-1,1),new r("iremo",-1,1),new r("assimo",-1,1),new r("ammo",-1,1),new r("emmo",-1,1),new r("eremmo",54,1),new r("iremmo",54,1),new r("immo",-1,1),new r("ano",-1,1),new r("iscano",58,1),new r("avano",58,1),new r("evano",58,1),new r("ivano",58,1),new r("eranno",-1,1),new r("iranno",-1,1),new r("ono",-1,1),new r("iscono",65,1),new r("arono",65,1),new r("erono",65,1),new r("irono",65,1),new r("erebbero",-1,1),new r("irebbero",-1,1),new r("assero",-1,1),new r("essero",-1,1),new r("issero",-1,1),new r("ato",-1,1),new r("ito",-1,1),new r("uto",-1,1),new r("avo",-1,1),new r("evo",-1,1),new r("ivo",-1,1),new r("ar",-1,1),new r("ir",-1,1),new r("erà",-1,1),new r("irà",-1,1),new r("erò",-1,1),new r("irò",-1,1)],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2,1],y=[17,65,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2],U=[17],x=new n;this.setCurrent=function(e){x.setCurrent(e)},this.getCurrent=function(){return x.getCurrent()},this.stem=function(){var e=x.cursor;return i(),x.cursor=e,u(),x.limit_backward=e,x.cursor=x.limit,f(),x.cursor=x.limit,v()||(x.cursor=x.limit,b()),x.cursor=x.limit,_(),x.cursor=x.limit_backward,c(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.it.stemmer,"stemmer-it"),e.it.stopWordFilter=e.generateStopWordFilter("a abbia abbiamo abbiano abbiate ad agl agli ai al all alla alle allo anche avemmo avendo avesse avessero avessi avessimo aveste avesti avete aveva avevamo avevano avevate avevi avevo avrai avranno avrebbe avrebbero avrei avremmo avremo avreste avresti avrete avrà avrò avuta avute avuti avuto c che chi ci coi col come con contro cui da dagl dagli dai dal dall dalla dalle dallo degl degli dei del dell della delle dello di dov dove e ebbe ebbero ebbi ed era erano eravamo eravate eri ero essendo faccia facciamo facciano facciate faccio facemmo facendo facesse facessero facessi facessimo faceste facesti faceva facevamo facevano facevate facevi facevo fai fanno farai faranno farebbe farebbero farei faremmo faremo fareste faresti farete farà farò fece fecero feci fosse fossero fossi fossimo foste fosti fu fui fummo furono gli ha hai hanno ho i il in io l la le lei li lo loro lui ma mi mia mie miei mio ne negl negli nei nel nell nella nelle nello noi non nostra nostre nostri nostro o per perché più quale quanta quante quanti quanto quella quelle quelli quello questa queste questi questo sarai saranno sarebbe sarebbero sarei saremmo saremo sareste saresti sarete sarà sarò se sei si sia siamo siano siate siete sono sta stai stando stanno starai staranno starebbe starebbero starei staremmo staremo stareste staresti starete starà starò stava stavamo stavano stavate stavi stavo stemmo stesse stessero stessi stessimo steste stesti stette stettero stetti stia stiamo stiano stiate sto su sua sue sugl sugli sui sul sull sulla sulle sullo suo suoi ti tra tu tua tue tuo tuoi tutti tutto un una uno vi voi vostra vostre vostri vostro è".split(" ")),e.Pipeline.registerFunction(e.it.stopWordFilter,"stopWordFilter-it")}});
```