java-functional-lsp 0.9.0__tar.gz → 0.9.1__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.
Files changed (69) hide show
  1. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/PKG-INFO +1 -1
  2. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/pyproject.toml +1 -1
  3. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/__init__.py +1 -1
  4. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/proxy.py +13 -5
  5. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/server.py +12 -3
  6. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_proxy.py +7 -3
  7. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.claude-plugin/plugin.json +0 -0
  8. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.githooks/pre-commit +0 -0
  9. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.githooks/pre-push +0 -0
  10. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/CODEOWNERS +0 -0
  11. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  12. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  13. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  14. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/SECURITY.md +0 -0
  15. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/dependabot.yml +0 -0
  16. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/release-drafter.yml +0 -0
  17. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/workflows/publish.yml +0 -0
  18. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/workflows/release-drafter.yml +0 -0
  19. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/workflows/stale.yml +0 -0
  20. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/workflows/test.yml +0 -0
  21. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/workflows/update-homebrew.yml +0 -0
  22. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.github/workflows/vscode-ext.yml +0 -0
  23. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/.gitignore +0 -0
  24. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/CONTRIBUTING.md +0 -0
  25. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/LICENSE +0 -0
  26. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/README.md +0 -0
  27. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/SKILL.md +0 -0
  28. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/commands/lint-java.md +0 -0
  29. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/intellij/README.md +0 -0
  30. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/intellij/lsp4ij-template.json +0 -0
  31. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/vscode/.vscodeignore +0 -0
  32. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/vscode/README.md +0 -0
  33. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/vscode/package-lock.json +0 -0
  34. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/vscode/package.json +0 -0
  35. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/vscode/src/extension.ts +0 -0
  36. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/editors/vscode/tsconfig.json +0 -0
  37. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/hooks/hooks.json +0 -0
  38. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/hooks/java_linter_reminder.py +0 -0
  39. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/scripts/ensure-lsp.sh +0 -0
  40. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/scripts/generate-formula.py +0 -0
  41. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/__main__.py +0 -0
  42. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/analyzers/__init__.py +0 -0
  43. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/analyzers/base.py +0 -0
  44. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
  45. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
  46. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
  47. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
  48. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
  49. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/cli.py +0 -0
  50. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/fixes.py +0 -0
  51. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/src/java_functional_lsp/merkle.py +0 -0
  52. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/__init__.py +0 -0
  53. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/conftest.py +0 -0
  54. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_base.py +0 -0
  55. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_cli.py +0 -0
  56. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_config.py +0 -0
  57. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_e2e.py +0 -0
  58. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_e2e_jdtls.py +0 -0
  59. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_exception_checker.py +0 -0
  60. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_fixes.py +0 -0
  61. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_functional_checker.py +0 -0
  62. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_merkle.py +0 -0
  63. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_merkle_proxy.py +0 -0
  64. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_mutation_checker.py +0 -0
  65. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_null_checker.py +0 -0
  66. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_server.py +0 -0
  67. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_spring_checker.py +0 -0
  68. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/tests/test_suppress.py +0 -0
  69. {java_functional_lsp-0.9.0 → java_functional_lsp-0.9.1}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: java-functional-lsp
3
- Version: 0.9.0
3
+ Version: 0.9.1
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.0"
7
+ version = "0.9.1"
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" }
@@ -1,3 +1,3 @@
1
1
  """java-functional-lsp: A Java LSP server enforcing functional programming best practices."""
2
2
 
3
- __version__ = "0.9.0"
3
+ __version__ = "0.9.1"
@@ -777,6 +777,11 @@ class JdtlsProxy:
777
777
  Uses a ``deque(maxlen=200)`` so oldest entries are dropped in O(1)
778
778
  when the queue overflows during long jdtls startup.
779
779
  """
780
+ if len(self._queued_notifications) >= _MAX_QUEUED_NOTIFICATIONS:
781
+ logger.warning(
782
+ "jdtls: notification queue full (%d cap) — oldest entry dropped; some didOpen events may be missed",
783
+ _MAX_QUEUED_NOTIFICATIONS,
784
+ )
780
785
  self._queued_notifications.append((method, params))
781
786
 
782
787
  async def flush_queued_notifications(self) -> None:
@@ -832,7 +837,7 @@ class JdtlsProxy:
832
837
  Calls ``modules.mark_added()`` before any ``await`` to prevent
833
838
  duplicate add calls from concurrent coroutines.
834
839
  """
835
- if not self._available:
840
+ if not self._available or self._workspace_expanded:
836
841
  return None
837
842
  module_uri = _resolve_module_uri(file_uri)
838
843
  if module_uri is None or self.modules.was_added(module_uri):
@@ -873,11 +878,14 @@ class JdtlsProxy:
873
878
  return
874
879
  self.modules.mark_added(root_uri)
875
880
 
876
- # Remove initial module folder to avoid double-indexing.
881
+ # Remove ALL individually-added modules to prevent double-indexing with
882
+ # the full root. This covers both the initial scoped module and any
883
+ # modules added by add_module_if_new during the ensure_started window.
877
884
  removed: list[dict[str, str]] = []
878
- if self._initial_module_uri and self._initial_module_uri != root_uri:
879
- ini_path = to_fs_path(self._initial_module_uri) or self._initial_module_uri
880
- removed.append({"uri": self._initial_module_uri, "name": Path(ini_path).name})
885
+ for uri in list(self.modules._states):
886
+ if uri != root_uri:
887
+ p = to_fs_path(uri) or uri
888
+ removed.append({"uri": uri, "name": Path(p).name})
881
889
 
882
890
  logger.info("jdtls: expanding to full workspace %s", _redact_path(root_path))
883
891
  await self.send_notification(
@@ -98,6 +98,8 @@ class JavaFunctionalLspServer(LanguageServer):
98
98
  _fire_and_forget(_apply_module_diff(self._proxy, module_uri))
99
99
  try:
100
100
  _analyze_and_publish(uri)
101
+ except FileNotFoundError:
102
+ pass # Virtual jdtls file (e.g., decompiled source in jdtls-data); skip silently.
101
103
  except Exception as e:
102
104
  logger.error("Error re-publishing diagnostics for %s: %s", uri, e)
103
105
 
@@ -602,14 +604,21 @@ async def _lazy_start_jdtls(file_uri: str) -> None:
602
604
  """Background task: start jdtls scoped to the module containing *file_uri*.
603
605
 
604
606
  Runs in the background so ``on_did_open`` returns immediately with custom
605
- diagnostics. After jdtls initializes, registers capabilities and flushes
606
- queued notifications. Workspace expansion is NOT done eagerly — modules
607
- are loaded on-demand via ``add_module_if_new()`` as files are opened.
607
+ diagnostics. After jdtls initializes, the workspace is immediately expanded
608
+ to the full IDE workspace root (inside-out) so jdtls discovers all sibling
609
+ modules before any queued ``didOpen`` notifications are flushed. This means
610
+ ``add_module_if_new`` is a no-op for all subsequent file opens — jdtls
611
+ already covers the whole project.
608
612
  """
609
613
  try:
610
614
  started = await server._proxy.ensure_started(server._init_params, file_uri, config=server._config)
611
615
  if started:
612
616
  logger.info("jdtls proxy active — full Java language support enabled")
617
+ # Expand to full workspace BEFORE flushing queued notifications so
618
+ # all files are processed in the full-workspace context (inside-out).
619
+ # expand_full_workspace is a no-op for standalone projects where
620
+ # the workspace root equals the initial module.
621
+ await server._proxy.expand_full_workspace()
613
622
  if server._skip_jdtls_registration:
614
623
  logger.info("Skipping dynamic capability registration (no-register mode)")
615
624
  else:
@@ -1051,7 +1051,7 @@ class TestLazyStart:
1051
1051
  assert proxy._workspace_expanded is True
1052
1052
 
1053
1053
  async def test_expand_full_workspace_removes_initial_module(self) -> None:
1054
- """When _initial_module_uri differs from root, it should be in the removed list."""
1054
+ """All modules in _states (not just _initial_module_uri) are removed on expansion."""
1055
1055
  from unittest.mock import AsyncMock
1056
1056
 
1057
1057
  from java_functional_lsp.proxy import JdtlsProxy
@@ -1060,13 +1060,17 @@ class TestLazyStart:
1060
1060
  proxy._available = True
1061
1061
  proxy._original_root_uri = "file:///workspace/monorepo"
1062
1062
  proxy._initial_module_uri = "file:///workspace/monorepo/module-a"
1063
+ # Simulate that module-a was mark_added during start() and module-b via add_module_if_new
1064
+ proxy.modules.mark_added("file:///workspace/monorepo/module-a")
1065
+ proxy.modules.mark_added("file:///workspace/monorepo/module-b")
1063
1066
  proxy.send_notification = AsyncMock() # type: ignore[assignment]
1064
1067
  await proxy.expand_full_workspace()
1065
1068
  proxy.send_notification.assert_called_once() # type: ignore[attr-defined]
1066
1069
  call_args = proxy.send_notification.call_args[0] # type: ignore[attr-defined]
1067
1070
  event = call_args[1]["event"]
1068
- assert len(event["removed"]) == 1
1069
- assert event["removed"][0]["uri"] == "file:///workspace/monorepo/module-a"
1071
+ removed_uris = {e["uri"] for e in event["removed"]}
1072
+ assert "file:///workspace/monorepo/module-a" in removed_uris
1073
+ assert "file:///workspace/monorepo/module-b" in removed_uris
1070
1074
  assert event["added"][0]["uri"] == "file:///workspace/monorepo"
1071
1075
 
1072
1076
  async def test_expand_full_workspace_noop_when_not_available(self) -> None: