java-functional-lsp 0.9.1__tar.gz → 0.9.2__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.1 → java_functional_lsp-0.9.2}/PKG-INFO +1 -1
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/pyproject.toml +1 -1
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/__init__.py +1 -1
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/proxy.py +59 -5
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_proxy.py +60 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.claude-plugin/plugin.json +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.githooks/pre-commit +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.githooks/pre-push +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/CODEOWNERS +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/SECURITY.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/dependabot.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/workflows/publish.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/workflows/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/workflows/stale.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/workflows/test.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/workflows/update-homebrew.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/workflows/vscode-ext.yml +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.gitignore +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/CONTRIBUTING.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/LICENSE +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/README.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/SKILL.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/commands/lint-java.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/intellij/README.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/intellij/lsp4ij-template.json +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/vscode/.vscodeignore +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/vscode/README.md +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/vscode/package-lock.json +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/vscode/package.json +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/vscode/src/extension.ts +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/editors/vscode/tsconfig.json +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/hooks/hooks.json +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/hooks/java_linter_reminder.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/scripts/ensure-lsp.sh +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/scripts/generate-formula.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/__main__.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/analyzers/__init__.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/analyzers/base.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/cli.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/fixes.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/merkle.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/src/java_functional_lsp/server.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/__init__.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/conftest.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_base.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_cli.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_config.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_e2e.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_e2e_jdtls.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_exception_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_fixes.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_functional_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_merkle.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_merkle_proxy.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_mutation_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_null_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_server.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_spring_checker.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/tests/test_suppress.py +0 -0
- {java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/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.2
|
|
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.2"
|
|
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" }
|
|
@@ -445,6 +445,42 @@ def _version_key(name: str) -> tuple[int, ...]:
|
|
|
445
445
|
return tuple(parts)
|
|
446
446
|
|
|
447
447
|
|
|
448
|
+
def _find_maven_group_root(initial_module: Path, workspace_root: Path) -> Path:
|
|
449
|
+
"""Return the tightest Maven multi-module parent of *initial_module*.
|
|
450
|
+
|
|
451
|
+
Walks up from ``initial_module.parent`` (the module itself is skipped —
|
|
452
|
+
we want its *parent* group, not the module's own pom) toward (and
|
|
453
|
+
including) ``workspace_root``, returning the first ancestor whose
|
|
454
|
+
``pom.xml`` contains a ``<modules>`` section. Falls back to
|
|
455
|
+
``workspace_root`` when no such intermediate parent exists (e.g. flat
|
|
456
|
+
single-level monorepos).
|
|
457
|
+
|
|
458
|
+
This keeps the jdtls index bounded to a module *group* (typically
|
|
459
|
+
5-20 modules) rather than the full IDE workspace (potentially 200+ modules)
|
|
460
|
+
which would cause ``OutOfMemoryError: Java heap space`` during indexing.
|
|
461
|
+
|
|
462
|
+
Both *initial_module* and *workspace_root* are resolved to real paths
|
|
463
|
+
before walking to avoid symlink-based boundary escapes.
|
|
464
|
+
"""
|
|
465
|
+
workspace_root = workspace_root.resolve()
|
|
466
|
+
current = initial_module.resolve().parent
|
|
467
|
+
# Bail immediately if the initial module is outside the workspace.
|
|
468
|
+
if not current.is_relative_to(workspace_root):
|
|
469
|
+
return workspace_root
|
|
470
|
+
while True:
|
|
471
|
+
pom = current / "pom.xml"
|
|
472
|
+
if pom.is_file():
|
|
473
|
+
try:
|
|
474
|
+
if "<modules>" in pom.read_text(encoding="utf-8", errors="ignore"):
|
|
475
|
+
return current
|
|
476
|
+
except OSError:
|
|
477
|
+
pass
|
|
478
|
+
if current in (workspace_root, current.parent):
|
|
479
|
+
break
|
|
480
|
+
current = current.parent
|
|
481
|
+
return workspace_root
|
|
482
|
+
|
|
483
|
+
|
|
448
484
|
@lru_cache(maxsize=256)
|
|
449
485
|
def _module_snapshot_path(module_uri: str) -> Path:
|
|
450
486
|
"""Return the path for the persistent snapshot file for *module_uri*.
|
|
@@ -862,16 +898,34 @@ class JdtlsProxy:
|
|
|
862
898
|
return module_uri
|
|
863
899
|
|
|
864
900
|
async def expand_full_workspace(self) -> None:
|
|
865
|
-
"""Expand jdtls workspace to the
|
|
901
|
+
"""Expand jdtls workspace to the nearest Maven module-group root.
|
|
902
|
+
|
|
903
|
+
Instead of expanding all the way to the IDE workspace root (which may
|
|
904
|
+
contain hundreds of Maven modules and cause jdtls OOM), this walks up
|
|
905
|
+
from the initial module to find the *nearest* ancestor directory whose
|
|
906
|
+
``pom.xml`` declares ``<modules>`` — i.e. the tightest multi-module
|
|
907
|
+
Maven parent. This covers sibling modules (the common case for
|
|
908
|
+
cross-module navigation) without ballooning the index.
|
|
909
|
+
|
|
910
|
+
Falls back to the full IDE workspace root when no intermediate
|
|
911
|
+
multi-module parent is found.
|
|
866
912
|
|
|
867
|
-
Removes
|
|
868
|
-
|
|
913
|
+
Removes all individually-added module folders to avoid double-indexing
|
|
914
|
+
with the newly added group root.
|
|
869
915
|
"""
|
|
870
916
|
if self._workspace_expanded or not self._available or not self._original_root_uri:
|
|
871
917
|
return
|
|
872
918
|
from pygls.uris import from_fs_path, to_fs_path
|
|
873
919
|
|
|
874
|
-
|
|
920
|
+
workspace_path = to_fs_path(self._original_root_uri) or self._original_root_uri
|
|
921
|
+
|
|
922
|
+
# Find the tightest multi-module Maven parent of the initial module.
|
|
923
|
+
group_root_path: str = workspace_path
|
|
924
|
+
if self._initial_module_uri:
|
|
925
|
+
initial_path = to_fs_path(self._initial_module_uri) or self._initial_module_uri
|
|
926
|
+
group_root_path = str(_find_maven_group_root(Path(initial_path), Path(workspace_path)))
|
|
927
|
+
|
|
928
|
+
root_path = group_root_path
|
|
875
929
|
root_uri = from_fs_path(root_path) or self._original_root_uri
|
|
876
930
|
if self.modules.was_added(root_uri):
|
|
877
931
|
self._workspace_expanded = True
|
|
@@ -887,7 +941,7 @@ class JdtlsProxy:
|
|
|
887
941
|
p = to_fs_path(uri) or uri
|
|
888
942
|
removed.append({"uri": uri, "name": Path(p).name})
|
|
889
943
|
|
|
890
|
-
logger.info("jdtls: expanding to
|
|
944
|
+
logger.info("jdtls: expanding workspace to module group %s", _redact_path(root_path))
|
|
891
945
|
await self.send_notification(
|
|
892
946
|
_WORKSPACE_DID_CHANGE_FOLDERS,
|
|
893
947
|
{"event": {"added": [{"uri": root_uri, "name": Path(root_path).name}], "removed": removed}},
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import json
|
|
7
7
|
import subprocess
|
|
8
|
+
from pathlib import Path
|
|
8
9
|
from typing import Any
|
|
9
10
|
from unittest.mock import MagicMock, patch
|
|
10
11
|
|
|
@@ -1037,6 +1038,65 @@ class TestLazyStart:
|
|
|
1037
1038
|
assert result2 is None # Already known
|
|
1038
1039
|
assert proxy.send_notification.call_count == 1 # type: ignore[attr-defined]
|
|
1039
1040
|
|
|
1041
|
+
async def test_expand_uses_maven_group_root_not_workspace_root(self, tmp_path: Path) -> None:
|
|
1042
|
+
"""expand_full_workspace expands to nearest multi-module Maven parent, not the full IDE root."""
|
|
1043
|
+
from unittest.mock import AsyncMock
|
|
1044
|
+
|
|
1045
|
+
from java_functional_lsp.proxy import JdtlsProxy
|
|
1046
|
+
|
|
1047
|
+
# Layout: workspace/group/module — group/pom.xml has <modules>
|
|
1048
|
+
workspace = tmp_path / "workspace"
|
|
1049
|
+
group = workspace / "group"
|
|
1050
|
+
module = group / "module"
|
|
1051
|
+
module.mkdir(parents=True)
|
|
1052
|
+
(group / "pom.xml").write_text("<project><modules><module>module</module></modules></project>")
|
|
1053
|
+
(workspace / "pom.xml").write_text("<project><modules><module>group</module></modules></project>")
|
|
1054
|
+
|
|
1055
|
+
module_uri = module.as_uri()
|
|
1056
|
+
workspace_uri = workspace.as_uri()
|
|
1057
|
+
|
|
1058
|
+
proxy = JdtlsProxy()
|
|
1059
|
+
proxy._available = True
|
|
1060
|
+
proxy._original_root_uri = workspace_uri
|
|
1061
|
+
proxy._initial_module_uri = module_uri
|
|
1062
|
+
proxy.modules.mark_added(module_uri)
|
|
1063
|
+
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1064
|
+
await proxy.expand_full_workspace()
|
|
1065
|
+
|
|
1066
|
+
call_args = proxy.send_notification.call_args[0] # type: ignore[attr-defined]
|
|
1067
|
+
event = call_args[1]["event"]
|
|
1068
|
+
# Should expand to group/, NOT workspace/
|
|
1069
|
+
assert event["added"][0]["uri"] == group.as_uri()
|
|
1070
|
+
assert event["added"][0]["uri"] != workspace_uri
|
|
1071
|
+
|
|
1072
|
+
async def test_expand_falls_back_to_workspace_root_when_no_group_pom(self, tmp_path: Path) -> None:
|
|
1073
|
+
"""Falls back to the IDE workspace root when no intermediate multi-module parent exists."""
|
|
1074
|
+
from unittest.mock import AsyncMock
|
|
1075
|
+
|
|
1076
|
+
from java_functional_lsp.proxy import JdtlsProxy
|
|
1077
|
+
|
|
1078
|
+
# Flat layout: workspace/module — no intermediate pom.xml
|
|
1079
|
+
workspace = tmp_path / "workspace"
|
|
1080
|
+
module = workspace / "module"
|
|
1081
|
+
module.mkdir(parents=True)
|
|
1082
|
+
# workspace/pom.xml has <modules>, but there's nothing in between
|
|
1083
|
+
(workspace / "pom.xml").write_text("<project><modules><module>module</module></modules></project>")
|
|
1084
|
+
|
|
1085
|
+
module_uri = module.as_uri()
|
|
1086
|
+
workspace_uri = workspace.as_uri()
|
|
1087
|
+
|
|
1088
|
+
proxy = JdtlsProxy()
|
|
1089
|
+
proxy._available = True
|
|
1090
|
+
proxy._original_root_uri = workspace_uri
|
|
1091
|
+
proxy._initial_module_uri = module_uri
|
|
1092
|
+
proxy.modules.mark_added(module_uri)
|
|
1093
|
+
proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1094
|
+
await proxy.expand_full_workspace()
|
|
1095
|
+
|
|
1096
|
+
call_args = proxy.send_notification.call_args[0] # type: ignore[attr-defined]
|
|
1097
|
+
event = call_args[1]["event"]
|
|
1098
|
+
assert event["added"][0]["uri"] == workspace_uri
|
|
1099
|
+
|
|
1040
1100
|
async def test_expand_full_workspace_sends_notification(self) -> None:
|
|
1041
1101
|
from unittest.mock import AsyncMock
|
|
1042
1102
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.github/ISSUE_TEMPLATE/bug-report.md
RENAMED
|
File without changes
|
{java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.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.1 → java_functional_lsp-0.9.2}/.github/workflows/release-drafter.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.1 → java_functional_lsp-0.9.2}/.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.1 → java_functional_lsp-0.9.2}/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.1 → java_functional_lsp-0.9.2}/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
|