java-functional-lsp 0.9.6__tar.gz → 0.9.8__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.
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/PKG-INFO +1 -1
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/pyproject.toml +1 -1
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/__init__.py +1 -1
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/server.py +41 -9
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_server.py +28 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.claude-plugin/plugin.json +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.githooks/pre-commit +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.githooks/pre-push +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/CODEOWNERS +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/SECURITY.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/dependabot.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/publish.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/stale.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/test.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/update-homebrew.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/vscode-ext.yml +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.gitignore +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/CONTRIBUTING.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/LICENSE +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/README.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/SKILL.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/commands/lint-java.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/intellij/README.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/intellij/lsp4ij-template.json +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/vscode/.vscodeignore +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/vscode/README.md +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/vscode/package-lock.json +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/vscode/package.json +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/vscode/src/extension.ts +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/vscode/tsconfig.json +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/hooks/hooks.json +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/hooks/java_linter_reminder.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/scripts/ensure-lsp.sh +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/scripts/generate-formula.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/__main__.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/__init__.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/base.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/cli.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/fixes.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/merkle.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/proxy.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/__init__.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/conftest.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_base.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_cli.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_config.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_e2e.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_e2e_jdtls.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_exception_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_fixes.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_functional_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_merkle.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_merkle_proxy.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_mutation_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_null_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_proxy.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_spring_checker.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/tests/test_suppress.py +0 -0
- {java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: java-functional-lsp
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.8
|
|
4
4
|
Summary: Java LSP server enforcing functional programming best practices — null safety, immutability, no exceptions
|
|
5
5
|
Project-URL: Homepage, https://github.com/aviadshiber/java-functional-lsp
|
|
6
6
|
Project-URL: Repository, https://github.com/aviadshiber/java-functional-lsp
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "java-functional-lsp"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.8"
|
|
8
8
|
description = "Java LSP server enforcing functional programming best practices — null safety, immutability, no exceptions"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -660,7 +660,24 @@ async def _lazy_start_jdtls(file_uri: str) -> None:
|
|
|
660
660
|
# they only activate after jdtls starts.
|
|
661
661
|
|
|
662
662
|
|
|
663
|
-
|
|
663
|
+
# Methods that operate on a single file and succeed before cross-file indexing
|
|
664
|
+
# is complete. A successful response from these does NOT mean the module is fully
|
|
665
|
+
# indexed, so we must NOT use them to transition the module to READY — doing so
|
|
666
|
+
# would cause cross-file requests (references, callHierarchy) to skip the wait
|
|
667
|
+
# and return empty results from an under-indexed jdtls instance.
|
|
668
|
+
_LIGHTWEIGHT_METHODS: frozenset[str] = frozenset(
|
|
669
|
+
{
|
|
670
|
+
"textDocument/documentHighlight",
|
|
671
|
+
"textDocument/documentSymbol",
|
|
672
|
+
}
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
async def _ensure_module_and_forward(
|
|
677
|
+
method: str,
|
|
678
|
+
params: Any,
|
|
679
|
+
file_uri: str,
|
|
680
|
+
) -> Any | None:
|
|
664
681
|
"""Forward a request to jdtls, ensuring the file's module is loaded.
|
|
665
682
|
|
|
666
683
|
Uses ``ModuleRegistry`` for adaptive waiting:
|
|
@@ -668,28 +685,38 @@ async def _ensure_module_and_forward(method: str, params: Any, file_uri: str) ->
|
|
|
668
685
|
- **UNKNOWN**: add module, wait until ready (adaptive, not fixed sleep)
|
|
669
686
|
- **ADDED**: module sent but not confirmed — wait until ready
|
|
670
687
|
|
|
671
|
-
When a request
|
|
672
|
-
requests skip the wait entirely.
|
|
688
|
+
When a request that requires full project indexing succeeds, marks the
|
|
689
|
+
module as READY so subsequent requests skip the wait entirely.
|
|
690
|
+
Methods in ``_LIGHTWEIGHT_METHODS`` operate on a single file and succeed
|
|
691
|
+
before cross-file indexing completes — their success is never used to
|
|
692
|
+
signal readiness.
|
|
673
693
|
"""
|
|
674
694
|
proxy = server._proxy
|
|
675
695
|
if not proxy.is_available:
|
|
676
696
|
return None
|
|
677
697
|
|
|
678
698
|
module_uri = _resolve_module_uri(file_uri)
|
|
699
|
+
short_mod = Path(to_fs_path(module_uri) or module_uri).name if module_uri else "<none>"
|
|
679
700
|
|
|
680
701
|
# Hot path: module already confirmed working.
|
|
681
702
|
if module_uri and proxy.modules.is_ready(module_uri):
|
|
682
|
-
|
|
703
|
+
logger.info("jdtls: %s [hot] module=%s", method, short_mod)
|
|
704
|
+
result = await proxy.send_request(method, _serialize_params(params))
|
|
705
|
+
if result is None:
|
|
706
|
+
logger.info("jdtls: %s [hot] → null (jdtls has no result for this file_uri)", method)
|
|
707
|
+
return result
|
|
683
708
|
|
|
684
709
|
# Cold path: add module if unknown, then wait for ready.
|
|
710
|
+
logger.info("jdtls: %s [cold] module=%s expanded=%s", method, short_mod, proxy._workspace_expanded)
|
|
685
711
|
new_module_uri = await proxy.add_module_if_new(file_uri)
|
|
686
712
|
|
|
687
713
|
serialized = _serialize_params(params)
|
|
688
714
|
result = await proxy.send_request(method, serialized)
|
|
689
715
|
|
|
716
|
+
can_mark_ready = method not in _LIGHTWEIGHT_METHODS
|
|
690
717
|
if result is not None:
|
|
691
|
-
# Success — mark module as ready so future requests are instant.
|
|
692
|
-
if module_uri:
|
|
718
|
+
# Success — mark module as ready so future cross-file requests are instant.
|
|
719
|
+
if can_mark_ready and module_uri:
|
|
693
720
|
proxy.modules.mark_ready(module_uri)
|
|
694
721
|
return result
|
|
695
722
|
|
|
@@ -698,11 +725,13 @@ async def _ensure_module_and_forward(method: str, params: Any, file_uri: str) ->
|
|
|
698
725
|
# If a concurrent request succeeds, Event.set() wakes us early.
|
|
699
726
|
wait_uri = new_module_uri or module_uri
|
|
700
727
|
if wait_uri and not proxy.modules.is_ready(wait_uri):
|
|
728
|
+
logger.info("jdtls: %s [cold] waiting for module %s to become ready", method, short_mod)
|
|
701
729
|
await proxy.modules.wait_until_ready(wait_uri, timeout=5.0)
|
|
702
730
|
# Always retry once after waiting — even on timeout the module may be ready.
|
|
703
731
|
result = await proxy.send_request(method, serialized)
|
|
704
|
-
if result is not None and module_uri:
|
|
732
|
+
if result is not None and can_mark_ready and module_uri:
|
|
705
733
|
proxy.modules.mark_ready(module_uri)
|
|
734
|
+
logger.info("jdtls: %s [cold] retry → %s", method, "result" if result is not None else "null")
|
|
706
735
|
return result
|
|
707
736
|
|
|
708
737
|
|
|
@@ -782,8 +811,11 @@ async def _on_incoming_calls(
|
|
|
782
811
|
if result is None:
|
|
783
812
|
return None
|
|
784
813
|
try:
|
|
785
|
-
|
|
786
|
-
|
|
814
|
+
structured = [_converter.structure(c, lsp.CallHierarchyIncomingCall) for c in result]
|
|
815
|
+
logger.info("jdtls: incomingCalls → %d callers", len(structured))
|
|
816
|
+
return structured
|
|
817
|
+
except Exception as e:
|
|
818
|
+
logger.warning("jdtls: incomingCalls structuring failed: %s (raw=%r)", e, result)
|
|
787
819
|
return None
|
|
788
820
|
|
|
789
821
|
|
|
@@ -581,6 +581,34 @@ class TestServerInternals:
|
|
|
581
581
|
finally:
|
|
582
582
|
srv._proxy.modules.clear()
|
|
583
583
|
|
|
584
|
+
async def test_ensure_module_and_forward_lightweight_methods_skip_transition(self) -> None:
|
|
585
|
+
"""Methods in _LIGHTWEIGHT_METHODS do not transition module to READY."""
|
|
586
|
+
from unittest.mock import AsyncMock, patch
|
|
587
|
+
|
|
588
|
+
from java_functional_lsp.proxy import ModuleState
|
|
589
|
+
from java_functional_lsp.server import _LIGHTWEIGHT_METHODS, _ensure_module_and_forward
|
|
590
|
+
from java_functional_lsp.server import server as srv
|
|
591
|
+
|
|
592
|
+
mock_add = AsyncMock(return_value="file:///mod")
|
|
593
|
+
raw_result = [{"range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 3}}}]
|
|
594
|
+
mock_send = AsyncMock(return_value=raw_result)
|
|
595
|
+
try:
|
|
596
|
+
for lightweight_method in _LIGHTWEIGHT_METHODS:
|
|
597
|
+
srv._proxy.modules.clear()
|
|
598
|
+
with (
|
|
599
|
+
patch.object(srv._proxy, "add_module_if_new", mock_add),
|
|
600
|
+
patch.object(srv._proxy, "send_request", mock_send),
|
|
601
|
+
patch.object(srv._proxy, "_available", True),
|
|
602
|
+
patch("java_functional_lsp.server._resolve_module_uri", return_value="file:///mod"),
|
|
603
|
+
):
|
|
604
|
+
await _ensure_module_and_forward(lightweight_method, {}, "file:///mod/F.java")
|
|
605
|
+
# Module should NOT be READY — lightweight op does not confirm full indexing.
|
|
606
|
+
assert srv._proxy.modules.get_state("file:///mod") != ModuleState.READY, (
|
|
607
|
+
f"{lightweight_method} should not mark module as READY"
|
|
608
|
+
)
|
|
609
|
+
finally:
|
|
610
|
+
srv._proxy.modules.clear()
|
|
611
|
+
|
|
584
612
|
async def test_on_prepare_call_hierarchy_forwards_to_jdtls(self) -> None:
|
|
585
613
|
"""_on_prepare_call_hierarchy forwards request and structures result."""
|
|
586
614
|
from unittest.mock import AsyncMock, patch
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/ISSUE_TEMPLATE/bug-report.md
RENAMED
|
File without changes
|
{java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/ISSUE_TEMPLATE/feature-request.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/release-drafter.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/.github/workflows/update-homebrew.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/editors/intellij/lsp4ij-template.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.6 → java_functional_lsp-0.9.8}/src/java_functional_lsp/analyzers/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|