kodit 0.3.8__tar.gz → 0.3.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kodit might be problematic. Click here for more details.
- {kodit-0.3.8 → kodit-0.3.10}/PKG-INFO +1 -1
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/_version.py +2 -2
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/services/index_service.py +19 -9
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/slicing/slicer.py +46 -21
- kodit-0.3.10/tests/kodit/domain/services/index_service_test.py +320 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/slicer_test.py +250 -126
- kodit-0.3.8/tests/kodit/domain/services/index_service_test.py +0 -162
- {kodit-0.3.8 → kodit-0.3.10}/.claude/commands/debug.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.claude/commands/new-requirement.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.claude/commands/refactor.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.claude/commands/update-docs.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.claude/settings.json +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.cursor/rules/kodit.mdc +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.cursor/rules/style.mdc +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.dockerignore +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/CODE_OF_CONDUCT.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/CONTRIBUTING.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/dependabot.yml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/workflows/docker.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/workflows/docs.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/workflows/pull_request.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/workflows/pypi-test.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/workflows/pypi.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.github/workflows/test.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.gitignore +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.python-version +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.vscode/launch.json +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/.vscode/settings.json +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/CLAUDE.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/Dockerfile +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/LICENSE +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/README.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/alembic.ini +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/_index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/demos/_index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/demos/go-simple-microservice/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/demos/knock-knock-auth/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/developer/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/getting-started/_index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/getting-started/installation/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/getting-started/integration/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/getting-started/quick-start/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/_index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/configuration/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/deployment/docker-compose.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/deployment/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/deployment/kubernetes.yaml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/indexing/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/mcp/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/sync/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/docs/reference/telemetry/index.md +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/pyproject.toml +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/.gitignore +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/app.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/application/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/application/factories/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/application/factories/code_indexing_factory.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/application/services/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/application/services/code_indexing_application_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/application/services/sync_scheduler.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/cli.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/config.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/database.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/entities.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/errors.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/interfaces.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/protocols.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/services/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/services/bm25_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/services/embedding_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/services/enrichment_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/services/index_query_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/domain/value_objects.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/bm25/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/bm25/bm25_factory.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/bm25/local_bm25_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/bm25/vectorchord_bm25_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/cloning/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/cloning/git/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/cloning/git/working_copy.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/cloning/metadata.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/embedding_factory.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/embedding_providers/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/embedding_providers/batching.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/embedding_providers/local_embedding_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/embedding_providers/openai_embedding_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/local_vector_search_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/enrichment/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/enrichment/enrichment_factory.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/enrichment/local_enrichment_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/enrichment/null_enrichment_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/enrichment/openai_enrichment_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/git/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/git/git_utils.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/ignore/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/ignore/ignore_pattern_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/indexing/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/indexing/auto_indexing_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/indexing/fusion_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/mappers/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/mappers/index_mapper.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/slicing/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/slicing/language_detection_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/sqlalchemy/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/sqlalchemy/embedding_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/sqlalchemy/entities.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/sqlalchemy/index_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/ui/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/ui/progress.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/infrastructure/ui/spinner.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/log.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/mcp.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/middleware.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/README +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/env.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/script.py.mako +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/versions/4073b33f9436_add_file_processing_flag.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/versions/4552eb3f23ce_add_summary.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/versions/7c3bbc2ab32b_add_embeddings_table.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/versions/85155663351e_initial.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/versions/9e53ea8bb3b0_add_authors.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/versions/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/reporting.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/utils/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/src/kodit/utils/path_utils.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/conftest.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/docker-smoke.sh +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/experiments/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/experiments/cline_prompt_tests/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/experiments/cline_prompt_tests/cline_prompt.txt +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/experiments/cline_prompt_tests/cline_prompt_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/application/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/application/services/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/application/services/test_sync_scheduler.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/application/test_code_indexing_application_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/cli_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/config_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/bm25_domain_service_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/enrichment_domain_service_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/entities_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/services/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/test_embedding_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/test_language_mapping.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/domain/test_multi_search_result.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/e2e.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/bm25/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/bm25/local_bm25_repository_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/bm25/vectorchord_bm25_repository_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/cloning/git_cloning/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/cloning/git_cloning/working_copy_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/embedding_factory_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/embedding_provider/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/embedding_provider/test_hash_embedding_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/embedding_provider/test_local_embedding_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/embedding_provider/test_openai_embedding_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/test_batching.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/test_embedding_integration.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/test_local_vector_search_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/embedding/test_vectorchord_vector_search_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/enrichment/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/enrichment/enrichment_provider/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/enrichment/enrichment_provider/test_local_enrichment_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/enrichment/enrichment_provider/test_null_enrichment_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/enrichment/enrichment_provider/test_openai_enrichment_provider.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/enrichment/test_enrichment_factory.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/indexing/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/indexing/test_auto_indexing_service.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/mappers/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/mappers/test_index_mapper.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/c/main.c +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/c/models.c +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/c/models.h +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/c/utils.c +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/c/utils.h +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/cpp/main.cpp +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/cpp/models.cpp +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/cpp/models.hpp +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/cpp/utils.cpp +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/cpp/utils.hpp +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/csharp/Main.cs +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/csharp/Models.cs +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/csharp/Utils.cs +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/css/components.css +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/css/main.css +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/css/utilities.css +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/go/main.go +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/go/models.go +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/go/utils.go +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/html/components.html +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/html/forms.html +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/html/main.html +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/java/Main.java +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/java/Models.java +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/java/Utils.java +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/javascript/main.js +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/javascript/models.js +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/javascript/utils.js +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/python/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/python/main.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/python/models.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/python/utils.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/rust/main.rs +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/rust/models.rs +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/slicing/data/rust/utils.rs +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/snippets/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/snippets/csharp.cs +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/snippets/golang.go +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/snippets/javascript.js +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/snippets/knock_knock_server.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/snippets/python.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/snippets/typescript.tsx +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/sqlalchemy/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/infrastructure/sqlalchemy/test_embedding_repository.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/log_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/mcp_stdio_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/kodit/mcp_test.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/performance/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/performance/similarity.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/smoke.sh +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/utils/__init__.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/utils/test_path_utils.py +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/tests/vectorchord-smoke.sh +0 -0
- {kodit-0.3.8 → kodit-0.3.10}/uv.lock +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Pure domain service for Index aggregate operations."""
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
+
from collections import defaultdict
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
import structlog
|
|
@@ -104,30 +105,39 @@ class IndexDomainService:
|
|
|
104
105
|
|
|
105
106
|
# Create a set of languages to extract snippets for
|
|
106
107
|
extensions = {file.extension() for file in files}
|
|
107
|
-
|
|
108
|
+
lang_files_map: dict[str, list[domain_entities.File]] = defaultdict(list)
|
|
108
109
|
for ext in extensions:
|
|
109
110
|
try:
|
|
110
|
-
|
|
111
|
+
lang = LanguageMapping.get_language_for_extension(ext)
|
|
112
|
+
lang_files_map[lang].extend(
|
|
113
|
+
file for file in files if file.extension() == ext
|
|
114
|
+
)
|
|
111
115
|
except ValueError as e:
|
|
112
|
-
self.log.
|
|
116
|
+
self.log.debug("Skipping", error=str(e))
|
|
113
117
|
continue
|
|
114
118
|
|
|
119
|
+
self.log.info(
|
|
120
|
+
"Languages to process",
|
|
121
|
+
languages=lang_files_map.keys(),
|
|
122
|
+
)
|
|
123
|
+
|
|
115
124
|
reporter = Reporter(self.log, progress_callback)
|
|
116
125
|
await reporter.start(
|
|
117
126
|
"extract_snippets",
|
|
118
|
-
len(
|
|
127
|
+
len(lang_files_map.keys()),
|
|
119
128
|
"Extracting code snippets...",
|
|
120
129
|
)
|
|
130
|
+
|
|
121
131
|
# Calculate snippets for each language
|
|
122
132
|
slicer = Slicer()
|
|
123
|
-
for i,
|
|
133
|
+
for i, (lang, lang_files) in enumerate(lang_files_map.items()):
|
|
124
134
|
await reporter.step(
|
|
125
135
|
"extract_snippets",
|
|
126
|
-
|
|
127
|
-
len(
|
|
128
|
-
"Extracting code snippets...",
|
|
136
|
+
i,
|
|
137
|
+
len(lang_files_map.keys()),
|
|
138
|
+
f"Extracting code snippets for {lang}...",
|
|
129
139
|
)
|
|
130
|
-
s = slicer.extract_snippets(
|
|
140
|
+
s = slicer.extract_snippets(lang_files, language=lang)
|
|
131
141
|
index.snippets.extend(s)
|
|
132
142
|
|
|
133
143
|
await reporter.done("extract_snippets")
|
|
@@ -10,10 +10,12 @@ from dataclasses import dataclass, field
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any, ClassVar
|
|
12
12
|
|
|
13
|
+
import structlog
|
|
13
14
|
from tree_sitter import Node, Parser, Tree
|
|
14
15
|
from tree_sitter_language_pack import get_language
|
|
15
16
|
|
|
16
17
|
from kodit.domain.entities import File, Snippet
|
|
18
|
+
from kodit.domain.value_objects import LanguageMapping
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
@dataclass
|
|
@@ -145,8 +147,9 @@ class Slicer:
|
|
|
145
147
|
|
|
146
148
|
def __init__(self) -> None:
|
|
147
149
|
"""Initialize an empty slicer."""
|
|
150
|
+
self.log = structlog.get_logger(__name__)
|
|
148
151
|
|
|
149
|
-
def extract_snippets(
|
|
152
|
+
def extract_snippets( # noqa: C901
|
|
150
153
|
self, files: list[File], language: str = "python"
|
|
151
154
|
) -> list[Snippet]:
|
|
152
155
|
"""Extract code snippets from a list of files.
|
|
@@ -170,6 +173,7 @@ class Slicer:
|
|
|
170
173
|
|
|
171
174
|
# Get language configuration
|
|
172
175
|
if language not in LanguageConfig.CONFIGS:
|
|
176
|
+
self.log.debug("Skipping", language=language)
|
|
173
177
|
return []
|
|
174
178
|
|
|
175
179
|
config = LanguageConfig.CONFIGS[language]
|
|
@@ -185,16 +189,20 @@ class Slicer:
|
|
|
185
189
|
# Create mapping from Paths to File objects and extract paths
|
|
186
190
|
path_to_file_map: dict[Path, File] = {}
|
|
187
191
|
file_paths: list[Path] = []
|
|
188
|
-
|
|
189
192
|
for file in files:
|
|
190
193
|
file_path = file.as_path()
|
|
191
|
-
|
|
192
|
-
|
|
194
|
+
|
|
195
|
+
# Validate file matches language
|
|
196
|
+
if not self._file_matches_language(file_path.suffix, language):
|
|
197
|
+
raise ValueError(f"File {file_path} does not match language {language}")
|
|
193
198
|
|
|
194
199
|
# Validate file exists
|
|
195
200
|
if not file_path.exists():
|
|
196
201
|
raise FileNotFoundError(f"File not found: {file_path}")
|
|
197
202
|
|
|
203
|
+
path_to_file_map[file_path] = file
|
|
204
|
+
file_paths.append(file_path)
|
|
205
|
+
|
|
198
206
|
# Initialize state
|
|
199
207
|
state = AnalyzerState(parser=parser)
|
|
200
208
|
state.files = file_paths
|
|
@@ -209,7 +217,7 @@ class Slicer:
|
|
|
209
217
|
state.asts[file_path] = tree
|
|
210
218
|
except OSError:
|
|
211
219
|
# Skip files that can't be parsed
|
|
212
|
-
|
|
220
|
+
continue
|
|
213
221
|
|
|
214
222
|
# Build indexes
|
|
215
223
|
self._build_definition_and_import_indexes(state, config, language)
|
|
@@ -233,6 +241,19 @@ class Slicer:
|
|
|
233
241
|
|
|
234
242
|
return snippets
|
|
235
243
|
|
|
244
|
+
def _file_matches_language(self, file_extension: str, language: str) -> bool:
|
|
245
|
+
"""Check if a file extension matches the current language."""
|
|
246
|
+
if language not in LanguageConfig.CONFIGS:
|
|
247
|
+
return False
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
return (
|
|
251
|
+
language == LanguageMapping.get_language_for_extension(file_extension)
|
|
252
|
+
)
|
|
253
|
+
except ValueError:
|
|
254
|
+
# Extension not supported, so it doesn't match any language
|
|
255
|
+
return False
|
|
256
|
+
|
|
236
257
|
def _get_tree_sitter_language_name(self, language: str) -> str:
|
|
237
258
|
"""Map user language names to tree-sitter language names."""
|
|
238
259
|
mapping = {
|
|
@@ -247,9 +268,9 @@ class Slicer:
|
|
|
247
268
|
"typescript": "typescript",
|
|
248
269
|
"js": "javascript",
|
|
249
270
|
"ts": "typescript",
|
|
250
|
-
"csharp": "
|
|
251
|
-
"c#": "
|
|
252
|
-
"cs": "
|
|
271
|
+
"csharp": "csharp",
|
|
272
|
+
"c#": "csharp",
|
|
273
|
+
"cs": "csharp",
|
|
253
274
|
"html": "html",
|
|
254
275
|
"css": "css",
|
|
255
276
|
}
|
|
@@ -299,19 +320,23 @@ class Slicer:
|
|
|
299
320
|
|
|
300
321
|
def _walk_tree(self, node: Node) -> Generator[Node, None, None]:
|
|
301
322
|
"""Walk the AST tree, yielding all nodes."""
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
323
|
+
# Use a simple queue-based approach to avoid recursion issues
|
|
324
|
+
queue = [node]
|
|
325
|
+
visited: set[int] = set() # Track by node id (memory address)
|
|
326
|
+
|
|
327
|
+
while queue:
|
|
328
|
+
current = queue.pop(0)
|
|
329
|
+
|
|
330
|
+
# Use node id (memory address) as unique identifier to avoid infinite loops
|
|
331
|
+
node_id = id(current)
|
|
332
|
+
if node_id in visited:
|
|
333
|
+
continue
|
|
334
|
+
visited.add(node_id)
|
|
335
|
+
|
|
336
|
+
yield current
|
|
337
|
+
|
|
338
|
+
# Add children to queue
|
|
339
|
+
queue.extend(current.children)
|
|
315
340
|
|
|
316
341
|
def _is_function_definition(self, node: Node, config: dict[str, Any]) -> bool:
|
|
317
342
|
"""Check if node is a function definition."""
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""Unit tests for IndexDomainService."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from unittest.mock import AsyncMock, Mock
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from pydantic import AnyUrl
|
|
8
|
+
|
|
9
|
+
from kodit.domain.entities import Index, Snippet, Source, SourceType, WorkingCopy
|
|
10
|
+
from kodit.domain.services.enrichment_service import EnrichmentDomainService
|
|
11
|
+
from kodit.domain.services.index_service import (
|
|
12
|
+
IndexDomainService,
|
|
13
|
+
LanguageDetectionService,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MockLanguageDetectionService(LanguageDetectionService):
|
|
18
|
+
"""Mock language detection service."""
|
|
19
|
+
|
|
20
|
+
async def detect_language(self, file_path: Path) -> str:
|
|
21
|
+
"""Return a mock language based on file extension."""
|
|
22
|
+
if file_path.suffix == ".py":
|
|
23
|
+
return "python"
|
|
24
|
+
return "unknown"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def mock_enrichment_service() -> EnrichmentDomainService:
|
|
29
|
+
"""Create a mock enrichment service."""
|
|
30
|
+
service = Mock(spec=EnrichmentDomainService)
|
|
31
|
+
service.enrich_documents = AsyncMock()
|
|
32
|
+
return service
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def index_domain_service(
|
|
37
|
+
mock_enrichment_service: EnrichmentDomainService,
|
|
38
|
+
tmp_path: Path,
|
|
39
|
+
) -> IndexDomainService:
|
|
40
|
+
"""Create an IndexDomainService for testing."""
|
|
41
|
+
return IndexDomainService(
|
|
42
|
+
language_detector=MockLanguageDetectionService(),
|
|
43
|
+
enrichment_service=mock_enrichment_service,
|
|
44
|
+
clone_dir=tmp_path / "clones",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.asyncio
|
|
49
|
+
async def test_prepare_index_creates_working_copy(
|
|
50
|
+
index_domain_service: IndexDomainService, tmp_path: Path
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Test that prepare_index creates a working copy without repository calls."""
|
|
53
|
+
# Create a test file
|
|
54
|
+
test_file = tmp_path / "test.py"
|
|
55
|
+
test_file.write_text("def hello(): pass")
|
|
56
|
+
|
|
57
|
+
# Prepare index (this only creates the working copy structure, no files scanned yet)
|
|
58
|
+
working_copy = await index_domain_service.prepare_index(str(tmp_path))
|
|
59
|
+
|
|
60
|
+
# Verify the working copy was created
|
|
61
|
+
assert isinstance(working_copy, WorkingCopy)
|
|
62
|
+
assert isinstance(working_copy.remote_uri, AnyUrl)
|
|
63
|
+
assert working_copy.source_type == SourceType.FOLDER
|
|
64
|
+
|
|
65
|
+
# In the new flow, files are not scanned during prepare_index
|
|
66
|
+
# They are scanned during refresh_working_copy
|
|
67
|
+
assert len(working_copy.files) == 0
|
|
68
|
+
|
|
69
|
+
# Now refresh to actually scan the files
|
|
70
|
+
refreshed_working_copy = await index_domain_service.refresh_working_copy(
|
|
71
|
+
working_copy
|
|
72
|
+
)
|
|
73
|
+
assert len(refreshed_working_copy.files) == 1
|
|
74
|
+
assert refreshed_working_copy.files[0].uri.path.endswith("test.py") # type: ignore[union-attr]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.mark.asyncio
|
|
78
|
+
async def test_extract_snippets_from_index_returns_snippets(
|
|
79
|
+
index_domain_service: IndexDomainService, tmp_path: Path
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Test that extract_snippets_from_index returns snippets without persistence."""
|
|
82
|
+
# Create a mock index with files
|
|
83
|
+
test_file = tmp_path / "test.py"
|
|
84
|
+
test_file.write_text("def hello(): pass")
|
|
85
|
+
|
|
86
|
+
# Prepare working copy first
|
|
87
|
+
working_copy = await index_domain_service.prepare_index(str(tmp_path))
|
|
88
|
+
|
|
89
|
+
# Now refresh to scan the files
|
|
90
|
+
working_copy = await index_domain_service.refresh_working_copy(working_copy)
|
|
91
|
+
|
|
92
|
+
from datetime import UTC, datetime
|
|
93
|
+
|
|
94
|
+
# Create a mock index
|
|
95
|
+
source = Source(
|
|
96
|
+
id=1,
|
|
97
|
+
working_copy=working_copy,
|
|
98
|
+
)
|
|
99
|
+
index = Index(
|
|
100
|
+
id=1,
|
|
101
|
+
source=source,
|
|
102
|
+
snippets=[],
|
|
103
|
+
created_at=datetime.now(UTC),
|
|
104
|
+
updated_at=datetime.now(UTC),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Extract snippets - this method returns the updated Index, not just snippets
|
|
108
|
+
updated_index = await index_domain_service.extract_snippets_from_index(
|
|
109
|
+
index=index,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Verify snippets were extracted
|
|
113
|
+
assert len(updated_index.snippets) > 0
|
|
114
|
+
assert isinstance(updated_index.snippets[0], Snippet)
|
|
115
|
+
# The actual Slicer is used now, so we should check for the actual function
|
|
116
|
+
assert "def hello" in updated_index.snippets[0].original_text()
|
|
117
|
+
assert "pass" in updated_index.snippets[0].original_text()
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@pytest.mark.asyncio
|
|
121
|
+
async def test_enrich_snippets_in_index_returns_enriched_snippets(
|
|
122
|
+
tmp_path: Path,
|
|
123
|
+
) -> None:
|
|
124
|
+
"""Test enrich_snippets_in_index returns enriched snippets without persistence."""
|
|
125
|
+
from kodit.domain.services.enrichment_service import EnrichmentDomainService
|
|
126
|
+
from kodit.infrastructure.enrichment.null_enrichment_provider import (
|
|
127
|
+
NullEnrichmentProvider,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Create real enrichment service with null provider (fast)
|
|
131
|
+
enrichment_service = EnrichmentDomainService(
|
|
132
|
+
enrichment_provider=NullEnrichmentProvider()
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Create domain service with real enrichment service
|
|
136
|
+
domain_service = IndexDomainService(
|
|
137
|
+
language_detector=MockLanguageDetectionService(),
|
|
138
|
+
enrichment_service=enrichment_service,
|
|
139
|
+
clone_dir=tmp_path / "clones",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Create mock snippets
|
|
143
|
+
snippet = Snippet(derives_from=[])
|
|
144
|
+
snippet.id = 1
|
|
145
|
+
snippet.add_original_content("def test(): pass", "python")
|
|
146
|
+
snippets = [snippet]
|
|
147
|
+
|
|
148
|
+
# Enrich snippets
|
|
149
|
+
enriched_snippets = await domain_service.enrich_snippets_in_index(snippets=snippets)
|
|
150
|
+
|
|
151
|
+
# Verify snippets were returned (null provider doesn't actually enrich)
|
|
152
|
+
assert len(enriched_snippets) == 1
|
|
153
|
+
assert enriched_snippets[0].id == 1
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@pytest.mark.asyncio
|
|
157
|
+
async def test_enrich_snippets_with_empty_list_returns_empty_list(
|
|
158
|
+
index_domain_service: IndexDomainService,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Test that enriching an empty list returns an empty list."""
|
|
161
|
+
enriched_snippets = await index_domain_service.enrich_snippets_in_index(snippets=[])
|
|
162
|
+
assert enriched_snippets == []
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@pytest.mark.asyncio
|
|
166
|
+
async def test_extract_snippets_only_processes_relevant_files(
|
|
167
|
+
index_domain_service: IndexDomainService, tmp_path: Path
|
|
168
|
+
) -> None:
|
|
169
|
+
"""Test that extract_snippets only processes files relevant to their language."""
|
|
170
|
+
# Create files of different types
|
|
171
|
+
py_file = tmp_path / "test.py"
|
|
172
|
+
py_file.write_text("def hello(): pass")
|
|
173
|
+
|
|
174
|
+
js_file = tmp_path / "test.js"
|
|
175
|
+
js_file.write_text("function hello() {}")
|
|
176
|
+
|
|
177
|
+
png_file = tmp_path / "image.png"
|
|
178
|
+
png_file.write_bytes(b"fake png data")
|
|
179
|
+
|
|
180
|
+
txt_file = tmp_path / "readme.txt"
|
|
181
|
+
txt_file.write_text("This is just text")
|
|
182
|
+
|
|
183
|
+
# Prepare working copy
|
|
184
|
+
working_copy = await index_domain_service.prepare_index(str(tmp_path))
|
|
185
|
+
working_copy = await index_domain_service.refresh_working_copy(working_copy)
|
|
186
|
+
|
|
187
|
+
# Verify all files were discovered
|
|
188
|
+
assert len(working_copy.files) == 4
|
|
189
|
+
|
|
190
|
+
from datetime import UTC, datetime
|
|
191
|
+
|
|
192
|
+
from kodit.domain.entities import Index, Source
|
|
193
|
+
|
|
194
|
+
# Create a mock index
|
|
195
|
+
source = Source(id=1, working_copy=working_copy)
|
|
196
|
+
index = Index(
|
|
197
|
+
id=1,
|
|
198
|
+
source=source,
|
|
199
|
+
snippets=[],
|
|
200
|
+
created_at=datetime.now(UTC),
|
|
201
|
+
updated_at=datetime.now(UTC),
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Extract snippets - should process all supported languages found in files
|
|
205
|
+
updated_index = await index_domain_service.extract_snippets_from_index(index)
|
|
206
|
+
|
|
207
|
+
# Should have snippets from both Python and JavaScript files (2 supported languages)
|
|
208
|
+
# PNG and TXT files should be ignored as they're not supported
|
|
209
|
+
assert len(updated_index.snippets) == 2 # Python and JavaScript files
|
|
210
|
+
|
|
211
|
+
# Get snippet texts
|
|
212
|
+
snippet_texts = [s.original_text() for s in updated_index.snippets]
|
|
213
|
+
|
|
214
|
+
# Should contain content from both supported languages
|
|
215
|
+
assert any("def hello" in text for text in snippet_texts) # Python file
|
|
216
|
+
assert any("function hello" in text for text in snippet_texts) # JavaScript file
|
|
217
|
+
|
|
218
|
+
# Verify the snippets derive from the correct files
|
|
219
|
+
source_files = [s.derives_from[0].uri.path for s in updated_index.snippets]
|
|
220
|
+
assert any(path.endswith("test.py") for path in source_files) # type: ignore[union-attr]
|
|
221
|
+
assert any(path.endswith("test.js") for path in source_files) # type: ignore[union-attr]
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
@pytest.mark.asyncio
|
|
225
|
+
async def test_extract_snippets_filters_by_language_mapping(
|
|
226
|
+
index_domain_service: IndexDomainService, tmp_path: Path
|
|
227
|
+
) -> None:
|
|
228
|
+
"""Test that extract_snippets correctly filters files by language mapping."""
|
|
229
|
+
# Create files for different languages
|
|
230
|
+
py_file = tmp_path / "script.py"
|
|
231
|
+
py_file.write_text("def python_func(): return 'python'")
|
|
232
|
+
|
|
233
|
+
js_file = tmp_path / "script.js"
|
|
234
|
+
js_file.write_text("function jsFunc() { return 'javascript'; }")
|
|
235
|
+
|
|
236
|
+
java_file = tmp_path / "Script.java"
|
|
237
|
+
java_file.write_text("public class Script { public void javaMethod() {} }")
|
|
238
|
+
|
|
239
|
+
# Create unsupported file type
|
|
240
|
+
unknown_file = tmp_path / "script.unknown"
|
|
241
|
+
unknown_file.write_text("some unknown content")
|
|
242
|
+
|
|
243
|
+
# Prepare working copy
|
|
244
|
+
working_copy = await index_domain_service.prepare_index(str(tmp_path))
|
|
245
|
+
working_copy = await index_domain_service.refresh_working_copy(working_copy)
|
|
246
|
+
|
|
247
|
+
# Should discover all files
|
|
248
|
+
assert len(working_copy.files) == 4
|
|
249
|
+
|
|
250
|
+
from datetime import UTC, datetime
|
|
251
|
+
|
|
252
|
+
from kodit.domain.entities import Index, Source
|
|
253
|
+
|
|
254
|
+
# Create a mock index
|
|
255
|
+
source = Source(id=1, working_copy=working_copy)
|
|
256
|
+
index = Index(
|
|
257
|
+
id=1,
|
|
258
|
+
source=source,
|
|
259
|
+
snippets=[],
|
|
260
|
+
created_at=datetime.now(UTC),
|
|
261
|
+
updated_at=datetime.now(UTC),
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Extract snippets - should process supported languages only
|
|
265
|
+
updated_index = await index_domain_service.extract_snippets_from_index(index)
|
|
266
|
+
|
|
267
|
+
# Should have snippets from Python, JavaScript, and Java files
|
|
268
|
+
# (unknown file should be ignored)
|
|
269
|
+
assert len(updated_index.snippets) == 3
|
|
270
|
+
|
|
271
|
+
# Get the snippet texts
|
|
272
|
+
snippet_texts = [s.original_text() for s in updated_index.snippets]
|
|
273
|
+
|
|
274
|
+
# Should contain content from all supported languages
|
|
275
|
+
assert any("def python_func" in text for text in snippet_texts)
|
|
276
|
+
assert any("function jsFunc" in text for text in snippet_texts)
|
|
277
|
+
assert any("javaMethod" in text for text in snippet_texts)
|
|
278
|
+
|
|
279
|
+
# Should not contain content from unsupported file
|
|
280
|
+
assert not any("unknown content" in text for text in snippet_texts)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@pytest.mark.asyncio
|
|
284
|
+
async def test_extract_snippets_handles_no_matching_files(
|
|
285
|
+
index_domain_service: IndexDomainService, tmp_path: Path
|
|
286
|
+
) -> None:
|
|
287
|
+
"""Test extract_snippets handles case where no files match supported languages."""
|
|
288
|
+
# Create only unsupported file types
|
|
289
|
+
img_file = tmp_path / "image.png"
|
|
290
|
+
img_file.write_bytes(b"fake image data")
|
|
291
|
+
|
|
292
|
+
doc_file = tmp_path / "document.pdf"
|
|
293
|
+
doc_file.write_bytes(b"fake pdf data")
|
|
294
|
+
|
|
295
|
+
# Prepare working copy
|
|
296
|
+
working_copy = await index_domain_service.prepare_index(str(tmp_path))
|
|
297
|
+
working_copy = await index_domain_service.refresh_working_copy(working_copy)
|
|
298
|
+
|
|
299
|
+
# Should discover files
|
|
300
|
+
assert len(working_copy.files) == 2
|
|
301
|
+
|
|
302
|
+
from datetime import UTC, datetime
|
|
303
|
+
|
|
304
|
+
from kodit.domain.entities import Index, Source
|
|
305
|
+
|
|
306
|
+
# Create a mock index
|
|
307
|
+
source = Source(id=1, working_copy=working_copy)
|
|
308
|
+
index = Index(
|
|
309
|
+
id=1,
|
|
310
|
+
source=source,
|
|
311
|
+
snippets=[],
|
|
312
|
+
created_at=datetime.now(UTC),
|
|
313
|
+
updated_at=datetime.now(UTC),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
# Extract snippets - should return empty list since no supported files
|
|
317
|
+
updated_index = await index_domain_service.extract_snippets_from_index(index)
|
|
318
|
+
|
|
319
|
+
# Should have no snippets
|
|
320
|
+
assert len(updated_index.snippets) == 0
|