java-functional-lsp 0.9.9__tar.gz → 0.9.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.
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/PKG-INFO +1 -1
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/pyproject.toml +1 -1
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/__init__.py +1 -1
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/proxy.py +84 -38
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/server.py +1 -1
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_proxy.py +113 -4
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.claude-plugin/plugin.json +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.githooks/pre-commit +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.githooks/pre-push +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/CODEOWNERS +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/SECURITY.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/dependabot.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/workflows/publish.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/workflows/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/workflows/stale.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/workflows/test.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/workflows/update-homebrew.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/workflows/vscode-ext.yml +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.gitignore +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/CONTRIBUTING.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/LICENSE +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/README.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/SKILL.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/commands/lint-java.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/intellij/README.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/intellij/lsp4ij-template.json +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/vscode/.vscodeignore +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/vscode/README.md +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/vscode/package-lock.json +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/vscode/package.json +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/vscode/src/extension.ts +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/editors/vscode/tsconfig.json +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/hooks/hooks.json +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/hooks/java_linter_reminder.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/scripts/ensure-lsp.sh +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/scripts/generate-formula.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/__main__.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/analyzers/__init__.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/analyzers/base.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/cli.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/fixes.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/merkle.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/__init__.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/conftest.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_base.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_cli.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_config.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_e2e.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_e2e_jdtls.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_exception_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_fixes.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_functional_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_merkle.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_merkle_proxy.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_mutation_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_null_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_server.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_spring_checker.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/tests/test_suppress.py +0 -0
- {java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/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.10
|
|
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.10"
|
|
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" }
|
|
@@ -28,6 +28,7 @@ _INITIALIZE_TIMEOUT = 120.0 # seconds — module-scoped init can still be slow
|
|
|
28
28
|
_START_RETRY_COOLDOWN = 300.0 # seconds — retry jdtls startup after transient failure
|
|
29
29
|
DEFAULT_JVM_MAX_HEAP = "4g"
|
|
30
30
|
_STDERR_LINE_MAX = 1000
|
|
31
|
+
_MAX_EXPANDED_GROUPS: int = 5 # hard cap on concurrent Maven group workspace folders (prevents jdtls OOM)
|
|
31
32
|
|
|
32
33
|
#: Minimum Java major version required by jdtls 1.57+. Anything below this
|
|
33
34
|
#: is rejected by the jdtls Python launcher with ``"jdtls requires at least
|
|
@@ -374,6 +375,10 @@ class ModuleRegistry:
|
|
|
374
375
|
if event is not None:
|
|
375
376
|
event.set()
|
|
376
377
|
|
|
378
|
+
def uris(self) -> list[str]:
|
|
379
|
+
"""Return all tracked module URIs (any state)."""
|
|
380
|
+
return list(self._states)
|
|
381
|
+
|
|
377
382
|
def clear(self) -> None:
|
|
378
383
|
"""Reset all state. Used by tests."""
|
|
379
384
|
self._states.clear()
|
|
@@ -445,6 +450,7 @@ def _version_key(name: str) -> tuple[int, ...]:
|
|
|
445
450
|
return tuple(parts)
|
|
446
451
|
|
|
447
452
|
|
|
453
|
+
@lru_cache(maxsize=64)
|
|
448
454
|
def _find_maven_group_root(initial_module: Path, workspace_root: Path) -> Path:
|
|
449
455
|
"""Return the tightest Maven multi-module parent of *initial_module*.
|
|
450
456
|
|
|
@@ -641,7 +647,7 @@ class JdtlsProxy:
|
|
|
641
647
|
self._initial_module_uri: str | None = None
|
|
642
648
|
self.modules = ModuleRegistry()
|
|
643
649
|
self.has_lombok = False
|
|
644
|
-
self.
|
|
650
|
+
self._expanded_groups: set[str] = set()
|
|
645
651
|
# Merkle snapshot diff: module_uri → (diff | None, current_snapshot)
|
|
646
652
|
# Populated by _kick_module_diff (background task on add_module_if_new).
|
|
647
653
|
# Consumed by server._apply_module_diff after module reaches READY.
|
|
@@ -887,33 +893,76 @@ class JdtlsProxy:
|
|
|
887
893
|
pass # result storage is _kick_module_diff's responsibility
|
|
888
894
|
|
|
889
895
|
async def add_module_if_new(self, file_uri: str) -> str | None:
|
|
890
|
-
"""Add the module
|
|
896
|
+
"""Add the module's Maven group to jdtls if not already expanded.
|
|
897
|
+
|
|
898
|
+
When the user navigates to a file in a new Maven group, we add the
|
|
899
|
+
group root (not the individual module) as a workspace folder. This
|
|
900
|
+
gives jdtls the full Maven classpath for cross-module navigation
|
|
901
|
+
within that group.
|
|
891
902
|
|
|
892
|
-
Returns the module URI if a new
|
|
893
|
-
or ``None`` if already
|
|
894
|
-
used with ``modules.wait_until_ready()`` for adaptive waiting.
|
|
903
|
+
Returns the module URI if a new group was expanded (for use with
|
|
904
|
+
``modules.wait_until_ready()``), or ``None`` if already covered.
|
|
895
905
|
|
|
896
|
-
|
|
897
|
-
duplicate add calls from concurrent coroutines.
|
|
906
|
+
Capped at ``_MAX_EXPANDED_GROUPS`` to prevent jdtls OOM.
|
|
898
907
|
"""
|
|
899
|
-
if not self._available
|
|
908
|
+
if not self._available:
|
|
900
909
|
return None
|
|
910
|
+
from pygls.uris import from_fs_path, to_fs_path
|
|
911
|
+
|
|
901
912
|
module_uri = _resolve_module_uri(file_uri)
|
|
902
913
|
if module_uri is None or self.modules.was_added(module_uri):
|
|
903
914
|
return None
|
|
915
|
+
|
|
916
|
+
# Resolve the Maven group root for this module.
|
|
917
|
+
module_path = to_fs_path(module_uri)
|
|
918
|
+
workspace_path = to_fs_path(self._original_root_uri) if self._original_root_uri else None
|
|
919
|
+
if module_path and workspace_path:
|
|
920
|
+
group_root = _find_maven_group_root(Path(module_path), Path(workspace_path))
|
|
921
|
+
group_uri = from_fs_path(str(group_root)) or module_uri
|
|
922
|
+
else:
|
|
923
|
+
group_uri = module_uri
|
|
924
|
+
|
|
925
|
+
# Already expanded this group — module is covered, nothing to do.
|
|
926
|
+
if group_uri in self._expanded_groups:
|
|
927
|
+
return None
|
|
928
|
+
|
|
929
|
+
# Hard cap: refuse expansion beyond the limit.
|
|
930
|
+
if len(self._expanded_groups) >= _MAX_EXPANDED_GROUPS:
|
|
931
|
+
logger.warning(
|
|
932
|
+
"jdtls: refusing to expand group for %s — %d groups already expanded (max %d). Restart IDE to reset.",
|
|
933
|
+
Path(module_path or module_uri).name,
|
|
934
|
+
len(self._expanded_groups),
|
|
935
|
+
_MAX_EXPANDED_GROUPS,
|
|
936
|
+
)
|
|
937
|
+
return None
|
|
938
|
+
|
|
939
|
+
# Remove individually-added child modules within this group to avoid
|
|
940
|
+
# double-indexing once the group root covers them. Must run BEFORE
|
|
941
|
+
# mark_added so we don't remove the module we're about to add.
|
|
942
|
+
group_path = Path(to_fs_path(group_uri) or group_uri)
|
|
943
|
+
removed: list[dict[str, str]] = []
|
|
944
|
+
for uri in self.modules.uris():
|
|
945
|
+
if uri == group_uri:
|
|
946
|
+
continue
|
|
947
|
+
p = Path(to_fs_path(uri) or uri)
|
|
948
|
+
if p == group_path or p.is_relative_to(group_path):
|
|
949
|
+
removed.append({"uri": uri, "name": p.name})
|
|
950
|
+
|
|
904
951
|
# Mark ADDED before await — atomic in asyncio, prevents duplicate sends.
|
|
905
952
|
self.modules.mark_added(module_uri)
|
|
906
|
-
|
|
953
|
+
self.modules.mark_added(group_uri)
|
|
954
|
+
self._expanded_groups.add(group_uri)
|
|
907
955
|
|
|
908
|
-
|
|
909
|
-
|
|
956
|
+
group_name = Path(to_fs_path(group_uri) or group_uri).name
|
|
957
|
+
logger.info(
|
|
958
|
+
"jdtls: expanding to group %s (group %d/%d)", group_name, len(self._expanded_groups), _MAX_EXPANDED_GROUPS
|
|
959
|
+
)
|
|
910
960
|
await self.send_notification(
|
|
911
961
|
_WORKSPACE_DID_CHANGE_FOLDERS,
|
|
912
|
-
{"event": {"added": [{"uri":
|
|
962
|
+
{"event": {"added": [{"uri": group_uri, "name": group_name}], "removed": removed}},
|
|
913
963
|
)
|
|
914
|
-
|
|
915
|
-
#
|
|
916
|
-
# readiness timeout (which starts ticking at mark_added above).
|
|
964
|
+
|
|
965
|
+
# Fire-and-forget: compute snapshot diff in background.
|
|
917
966
|
diff_task = asyncio.create_task(self._kick_module_diff(module_uri))
|
|
918
967
|
self._proxy_bg_tasks.add(diff_task)
|
|
919
968
|
diff_task.add_done_callback(self._proxy_bg_tasks.discard)
|
|
@@ -921,24 +970,16 @@ class JdtlsProxy:
|
|
|
921
970
|
return module_uri
|
|
922
971
|
|
|
923
972
|
async def expand_full_workspace(self) -> None:
|
|
924
|
-
"""Expand jdtls workspace to the
|
|
973
|
+
"""Expand jdtls workspace to the initial module's Maven group root.
|
|
925
974
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
``pom.xml`` declares ``<modules>`` — i.e. the tightest multi-module
|
|
930
|
-
Maven parent. This covers sibling modules (the common case for
|
|
931
|
-
cross-module navigation) without ballooning the index.
|
|
932
|
-
|
|
933
|
-
Falls back to the initial module itself when no intermediate
|
|
934
|
-
multi-module parent is found (e.g. flat modules sitting directly
|
|
935
|
-
under the workspace root), keeping the jdtls scope as tight as
|
|
936
|
-
possible.
|
|
975
|
+
Called once during lazy start. Subsequent groups are expanded
|
|
976
|
+
on-demand by ``add_module_if_new()`` as the user navigates to
|
|
977
|
+
files in other Maven groups.
|
|
937
978
|
|
|
938
979
|
Removes all individually-added module folders to avoid double-indexing
|
|
939
980
|
with the newly added group root.
|
|
940
981
|
"""
|
|
941
|
-
if
|
|
982
|
+
if not self._available or not self._original_root_uri:
|
|
942
983
|
return
|
|
943
984
|
from pygls.uris import from_fs_path, to_fs_path
|
|
944
985
|
|
|
@@ -952,26 +993,31 @@ class JdtlsProxy:
|
|
|
952
993
|
|
|
953
994
|
root_path = group_root_path
|
|
954
995
|
root_uri = from_fs_path(root_path) or self._original_root_uri
|
|
955
|
-
|
|
956
|
-
|
|
996
|
+
|
|
997
|
+
# Already expanded (e.g. initial module IS the group root, or called twice).
|
|
998
|
+
if root_uri in self._expanded_groups or self.modules.was_added(root_uri):
|
|
999
|
+
self._expanded_groups.add(root_uri)
|
|
957
1000
|
return
|
|
958
1001
|
self.modules.mark_added(root_uri)
|
|
959
1002
|
|
|
960
|
-
# Remove
|
|
961
|
-
#
|
|
962
|
-
#
|
|
1003
|
+
# Remove individually-added modules that are children of the new root.
|
|
1004
|
+
# This covers the initial scoped module and any modules added by
|
|
1005
|
+
# add_module_if_new during the ensure_started window.
|
|
1006
|
+
root_path_obj = Path(root_path)
|
|
963
1007
|
removed: list[dict[str, str]] = []
|
|
964
|
-
for uri in
|
|
965
|
-
if uri
|
|
966
|
-
|
|
967
|
-
|
|
1008
|
+
for uri in self.modules.uris():
|
|
1009
|
+
if uri == root_uri:
|
|
1010
|
+
continue
|
|
1011
|
+
p = Path(to_fs_path(uri) or uri)
|
|
1012
|
+
if p == root_path_obj or p.is_relative_to(root_path_obj):
|
|
1013
|
+
removed.append({"uri": uri, "name": p.name})
|
|
968
1014
|
|
|
969
1015
|
logger.info("jdtls: expanding workspace to module group %s", _redact_path(root_path))
|
|
970
1016
|
await self.send_notification(
|
|
971
1017
|
_WORKSPACE_DID_CHANGE_FOLDERS,
|
|
972
1018
|
{"event": {"added": [{"uri": root_uri, "name": Path(root_path).name}], "removed": removed}},
|
|
973
1019
|
)
|
|
974
|
-
self.
|
|
1020
|
+
self._expanded_groups.add(root_uri)
|
|
975
1021
|
|
|
976
1022
|
async def stop(self) -> None:
|
|
977
1023
|
"""Shutdown jdtls subprocess gracefully."""
|
|
@@ -724,7 +724,7 @@ async def _ensure_module_and_forward(
|
|
|
724
724
|
return result
|
|
725
725
|
|
|
726
726
|
# Cold path: add module if unknown, then wait for ready.
|
|
727
|
-
logger.info("jdtls: %s [cold] module=%s
|
|
727
|
+
logger.info("jdtls: %s [cold] module=%s groups=%d", method, short_mod, len(proxy._expanded_groups))
|
|
728
728
|
new_module_uri = await proxy.add_module_if_new(file_uri)
|
|
729
729
|
|
|
730
730
|
serialized = _serialize_params(params)
|
|
@@ -983,6 +983,13 @@ class TestFindModuleRoot:
|
|
|
983
983
|
class TestLazyStart:
|
|
984
984
|
"""Tests for lazy-start proxy features."""
|
|
985
985
|
|
|
986
|
+
@pytest.fixture(autouse=True)
|
|
987
|
+
def _clear_group_root_cache(self) -> None: # type: ignore[override]
|
|
988
|
+
"""Clear _find_maven_group_root lru_cache between tests."""
|
|
989
|
+
from java_functional_lsp.proxy import _find_maven_group_root
|
|
990
|
+
|
|
991
|
+
_find_maven_group_root.cache_clear()
|
|
992
|
+
|
|
986
993
|
def test_check_available_true(self) -> None:
|
|
987
994
|
from java_functional_lsp.proxy import JdtlsProxy
|
|
988
995
|
|
|
@@ -1164,7 +1171,7 @@ class TestLazyStart:
|
|
|
1164
1171
|
|
|
1165
1172
|
# No notification — module was already added and is already the tightest scope
|
|
1166
1173
|
proxy.send_notification.assert_not_called() # type: ignore[attr-defined]
|
|
1167
|
-
assert proxy.
|
|
1174
|
+
assert len(proxy._expanded_groups) > 0
|
|
1168
1175
|
|
|
1169
1176
|
async def test_expand_full_workspace_sends_notification(self) -> None:
|
|
1170
1177
|
from unittest.mock import AsyncMock
|
|
@@ -1177,7 +1184,7 @@ class TestLazyStart:
|
|
|
1177
1184
|
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1178
1185
|
await proxy.expand_full_workspace()
|
|
1179
1186
|
proxy.send_notification.assert_called_once() # type: ignore[attr-defined]
|
|
1180
|
-
assert proxy.
|
|
1187
|
+
assert len(proxy._expanded_groups) > 0
|
|
1181
1188
|
|
|
1182
1189
|
async def test_expand_full_workspace_removes_initial_module(self, tmp_path: Path) -> None:
|
|
1183
1190
|
"""All modules in _states are removed when expanding to an intermediate group root."""
|
|
@@ -1227,7 +1234,7 @@ class TestLazyStart:
|
|
|
1227
1234
|
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1228
1235
|
await proxy.expand_full_workspace()
|
|
1229
1236
|
proxy.send_notification.assert_not_called() # type: ignore[attr-defined]
|
|
1230
|
-
assert proxy.
|
|
1237
|
+
assert len(proxy._expanded_groups) == 0
|
|
1231
1238
|
|
|
1232
1239
|
async def test_expand_full_workspace_noop_when_already_added(self) -> None:
|
|
1233
1240
|
from unittest.mock import AsyncMock
|
|
@@ -1241,7 +1248,109 @@ class TestLazyStart:
|
|
|
1241
1248
|
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1242
1249
|
await proxy.expand_full_workspace()
|
|
1243
1250
|
proxy.send_notification.assert_not_called() # type: ignore[attr-defined]
|
|
1244
|
-
assert proxy.
|
|
1251
|
+
assert len(proxy._expanded_groups) > 0
|
|
1252
|
+
|
|
1253
|
+
async def test_add_module_cross_group_expands_new_group(self, tmp_path: Path) -> None:
|
|
1254
|
+
"""Navigating to a file in a different Maven group expands that group."""
|
|
1255
|
+
from unittest.mock import AsyncMock
|
|
1256
|
+
|
|
1257
|
+
from java_functional_lsp.proxy import JdtlsProxy
|
|
1258
|
+
|
|
1259
|
+
# Layout: monorepo/group-a/mod-a, monorepo/group-b/mod-b
|
|
1260
|
+
monorepo = tmp_path / "monorepo"
|
|
1261
|
+
group_a = monorepo / "group-a"
|
|
1262
|
+
mod_a = group_a / "mod-a"
|
|
1263
|
+
group_b = monorepo / "group-b"
|
|
1264
|
+
mod_b = group_b / "mod-b"
|
|
1265
|
+
for d in (mod_a, mod_b):
|
|
1266
|
+
d.mkdir(parents=True)
|
|
1267
|
+
(d / "pom.xml").write_text("<project/>")
|
|
1268
|
+
(group_a / "pom.xml").write_text("<project><modules><module>mod-a</module></modules></project>")
|
|
1269
|
+
(group_b / "pom.xml").write_text("<project><modules><module>mod-b</module></modules></project>")
|
|
1270
|
+
|
|
1271
|
+
proxy = JdtlsProxy()
|
|
1272
|
+
proxy._available = True
|
|
1273
|
+
proxy._original_root_uri = monorepo.as_uri()
|
|
1274
|
+
proxy._initial_module_uri = mod_a.as_uri()
|
|
1275
|
+
proxy._expanded_groups.add(group_a.as_uri()) # simulate initial expansion done
|
|
1276
|
+
proxy.modules.mark_added(mod_a.as_uri())
|
|
1277
|
+
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1278
|
+
|
|
1279
|
+
file_uri = (mod_b / "src" / "Foo.java").as_uri()
|
|
1280
|
+
# Create the file so _resolve_module_uri can find mod-b's pom.xml
|
|
1281
|
+
(mod_b / "src").mkdir()
|
|
1282
|
+
(mod_b / "src" / "Foo.java").touch()
|
|
1283
|
+
|
|
1284
|
+
result = await proxy.add_module_if_new(file_uri)
|
|
1285
|
+
assert result is not None # module_uri returned for wait_until_ready
|
|
1286
|
+
proxy.send_notification.assert_called_once() # type: ignore[attr-defined]
|
|
1287
|
+
call_args = proxy.send_notification.call_args[0] # type: ignore[attr-defined]
|
|
1288
|
+
event = call_args[1]["event"]
|
|
1289
|
+
assert event["added"][0]["uri"] == group_b.as_uri()
|
|
1290
|
+
assert event["removed"] == [] # no child modules to remove from new group
|
|
1291
|
+
assert group_b.as_uri() in proxy._expanded_groups
|
|
1292
|
+
assert len(proxy._expanded_groups) == 2
|
|
1293
|
+
|
|
1294
|
+
async def test_add_module_within_expanded_group_is_noop(self, tmp_path: Path) -> None:
|
|
1295
|
+
"""A file within an already-expanded group returns None."""
|
|
1296
|
+
from unittest.mock import AsyncMock
|
|
1297
|
+
|
|
1298
|
+
from java_functional_lsp.proxy import JdtlsProxy
|
|
1299
|
+
|
|
1300
|
+
monorepo = tmp_path / "monorepo"
|
|
1301
|
+
group = monorepo / "group"
|
|
1302
|
+
mod_a = group / "mod-a"
|
|
1303
|
+
mod_b = group / "mod-b"
|
|
1304
|
+
for d in (mod_a, mod_b):
|
|
1305
|
+
d.mkdir(parents=True)
|
|
1306
|
+
(d / "pom.xml").write_text("<project/>")
|
|
1307
|
+
(group / "pom.xml").write_text(
|
|
1308
|
+
"<project><modules><module>mod-a</module><module>mod-b</module></modules></project>"
|
|
1309
|
+
)
|
|
1310
|
+
|
|
1311
|
+
proxy = JdtlsProxy()
|
|
1312
|
+
proxy._available = True
|
|
1313
|
+
proxy._original_root_uri = monorepo.as_uri()
|
|
1314
|
+
proxy._expanded_groups.add(group.as_uri())
|
|
1315
|
+
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1316
|
+
|
|
1317
|
+
file_uri = (mod_b / "src" / "Bar.java").as_uri()
|
|
1318
|
+
(mod_b / "src").mkdir()
|
|
1319
|
+
(mod_b / "src" / "Bar.java").touch()
|
|
1320
|
+
|
|
1321
|
+
result = await proxy.add_module_if_new(file_uri)
|
|
1322
|
+
assert result is None
|
|
1323
|
+
proxy.send_notification.assert_not_called() # type: ignore[attr-defined]
|
|
1324
|
+
|
|
1325
|
+
async def test_add_module_at_cap_refuses_expansion(self, tmp_path: Path) -> None:
|
|
1326
|
+
"""Expansion is refused when _MAX_EXPANDED_GROUPS is reached."""
|
|
1327
|
+
from unittest.mock import AsyncMock
|
|
1328
|
+
|
|
1329
|
+
from java_functional_lsp.proxy import _MAX_EXPANDED_GROUPS, JdtlsProxy
|
|
1330
|
+
|
|
1331
|
+
monorepo = tmp_path / "monorepo"
|
|
1332
|
+
new_group = monorepo / "new-group"
|
|
1333
|
+
mod = new_group / "mod"
|
|
1334
|
+
mod.mkdir(parents=True)
|
|
1335
|
+
(mod / "pom.xml").write_text("<project/>")
|
|
1336
|
+
(new_group / "pom.xml").write_text("<project><modules><module>mod</module></modules></project>")
|
|
1337
|
+
|
|
1338
|
+
proxy = JdtlsProxy()
|
|
1339
|
+
proxy._available = True
|
|
1340
|
+
proxy._original_root_uri = monorepo.as_uri()
|
|
1341
|
+
# Fill up to the cap with dummy groups
|
|
1342
|
+
for i in range(_MAX_EXPANDED_GROUPS):
|
|
1343
|
+
proxy._expanded_groups.add(f"file:///fake/group-{i}")
|
|
1344
|
+
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1345
|
+
|
|
1346
|
+
file_uri = (mod / "src" / "Baz.java").as_uri()
|
|
1347
|
+
(mod / "src").mkdir()
|
|
1348
|
+
(mod / "src" / "Baz.java").touch()
|
|
1349
|
+
|
|
1350
|
+
result = await proxy.add_module_if_new(file_uri)
|
|
1351
|
+
assert result is None
|
|
1352
|
+
proxy.send_notification.assert_not_called() # type: ignore[attr-defined]
|
|
1353
|
+
assert len(proxy._expanded_groups) == _MAX_EXPANDED_GROUPS
|
|
1245
1354
|
|
|
1246
1355
|
async def test_ensure_started_no_build_file(self) -> None:
|
|
1247
1356
|
"""ensure_started with no build file should pass module_root_uri=None."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.github/ISSUE_TEMPLATE/bug-report.md
RENAMED
|
File without changes
|
{java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.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.9 → java_functional_lsp-0.9.10}/.github/workflows/release-drafter.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/.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.9 → java_functional_lsp-0.9.10}/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
|
{java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/src/java_functional_lsp/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.9 → java_functional_lsp-0.9.10}/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
|