java-functional-lsp 0.9.8__tar.gz → 0.9.9__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.8 → java_functional_lsp-0.9.9}/PKG-INFO +1 -1
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/pyproject.toml +1 -1
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/__init__.py +1 -1
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/server.py +25 -8
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_server.py +49 -1
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.claude-plugin/plugin.json +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.githooks/pre-commit +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.githooks/pre-push +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/CODEOWNERS +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/SECURITY.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/dependabot.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/workflows/publish.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/workflows/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/workflows/stale.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/workflows/test.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/workflows/update-homebrew.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/workflows/vscode-ext.yml +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.gitignore +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/CONTRIBUTING.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/LICENSE +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/README.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/SKILL.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/commands/lint-java.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/intellij/README.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/intellij/lsp4ij-template.json +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/vscode/.vscodeignore +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/vscode/README.md +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/vscode/package-lock.json +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/vscode/package.json +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/vscode/src/extension.ts +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/editors/vscode/tsconfig.json +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/hooks/hooks.json +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/hooks/java_linter_reminder.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/scripts/ensure-lsp.sh +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/scripts/generate-formula.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/__main__.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/analyzers/__init__.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/analyzers/base.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/cli.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/fixes.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/merkle.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/src/java_functional_lsp/proxy.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/__init__.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/conftest.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_base.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_cli.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_config.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_e2e.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_e2e_jdtls.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_exception_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_fixes.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_functional_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_merkle.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_merkle_proxy.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_mutation_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_null_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_proxy.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_spring_checker.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/tests/test_suppress.py +0 -0
- {java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/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.9
|
|
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.9"
|
|
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" }
|
|
@@ -76,13 +76,18 @@ class JavaFunctionalLspServer(LanguageServer):
|
|
|
76
76
|
self._skip_jdtls_registration: bool = False
|
|
77
77
|
self._init_generation: int = 0
|
|
78
78
|
|
|
79
|
-
def _on_jdtls_diagnostics(self, uri: str,
|
|
79
|
+
def _on_jdtls_diagnostics(self, uri: str, diagnostics: list[Any]) -> None:
|
|
80
80
|
"""Called when jdtls publishes diagnostics — merge with custom and re-publish.
|
|
81
81
|
|
|
82
82
|
Also marks the file's module as READY, since receiving diagnostics from
|
|
83
83
|
jdtls is a reliable signal that the module has been indexed (more reliable
|
|
84
84
|
than a first non-None response which may be semantically empty).
|
|
85
85
|
|
|
86
|
+
Exception: if any diagnostic carries ``_JDTLS_NON_PROJECT_CODE`` (code 16),
|
|
87
|
+
jdtls has opened the file but hasn't resolved its Maven project yet — only
|
|
88
|
+
syntax errors are available. We skip the READY transition and wait for the
|
|
89
|
+
follow-up publish (after Maven import completes) that arrives without code 16.
|
|
90
|
+
|
|
86
91
|
When a module transitions to READY, fires ``_apply_module_diff`` to
|
|
87
92
|
notify jdtls about any externally changed files (e.g., after git pull).
|
|
88
93
|
"""
|
|
@@ -90,12 +95,18 @@ class JavaFunctionalLspServer(LanguageServer):
|
|
|
90
95
|
return
|
|
91
96
|
module_uri = _resolve_module_uri(uri)
|
|
92
97
|
if module_uri:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
is_non_project = any(
|
|
99
|
+
str(d.get("code", "")) == _JDTLS_NON_PROJECT_CODE for d in diagnostics if isinstance(d, dict)
|
|
100
|
+
)
|
|
101
|
+
if is_non_project:
|
|
102
|
+
logger.info("jdtls: skipping READY for %s (non-project file, Maven import pending)", Path(uri).name)
|
|
103
|
+
else:
|
|
104
|
+
already_ready = self._proxy.modules.is_ready(module_uri)
|
|
105
|
+
self._proxy.modules.mark_ready(module_uri)
|
|
106
|
+
if not already_ready:
|
|
107
|
+
# First READY transition only — subsequent diagnostics for the same
|
|
108
|
+
# module are no-ops to avoid spawning O(files) redundant tasks.
|
|
109
|
+
_fire_and_forget(_apply_module_diff(self._proxy, module_uri))
|
|
99
110
|
try:
|
|
100
111
|
_analyze_and_publish(uri)
|
|
101
112
|
except FileNotFoundError:
|
|
@@ -419,7 +430,7 @@ def on_initialize(params: lsp.InitializeParams) -> lsp.InitializeResult:
|
|
|
419
430
|
|
|
420
431
|
|
|
421
432
|
@server.feature(lsp.INITIALIZED)
|
|
422
|
-
async def on_initialized(
|
|
433
|
+
async def on_initialized(_: lsp.InitializedParams) -> None:
|
|
423
434
|
"""Check jdtls availability; actual start deferred to first didOpen."""
|
|
424
435
|
logger.info(
|
|
425
436
|
"java-functional-lsp initialized (rules: %s)",
|
|
@@ -672,6 +683,12 @@ _LIGHTWEIGHT_METHODS: frozenset[str] = frozenset(
|
|
|
672
683
|
}
|
|
673
684
|
)
|
|
674
685
|
|
|
686
|
+
# jdtls diagnostic code for files it opened but hasn't resolved into a Maven project yet.
|
|
687
|
+
# When this appears in a publishDiagnostics batch, jdtls has syntax info only — no classpath,
|
|
688
|
+
# no cross-file resolution. We must NOT mark the module READY yet; wait for a re-publish
|
|
689
|
+
# without code 16 (after Maven project import finishes).
|
|
690
|
+
_JDTLS_NON_PROJECT_CODE: str = "16"
|
|
691
|
+
|
|
675
692
|
|
|
676
693
|
async def _ensure_module_and_forward(
|
|
677
694
|
method: str,
|
|
@@ -290,6 +290,54 @@ class TestServerInternals:
|
|
|
290
290
|
finally:
|
|
291
291
|
server.workspace.remove_text_document(uri)
|
|
292
292
|
|
|
293
|
+
def test_on_jdtls_diagnostics_non_project_skips_ready(self) -> None:
|
|
294
|
+
"""A publishDiagnostics batch with code-16 must NOT mark the module READY."""
|
|
295
|
+
from unittest.mock import patch
|
|
296
|
+
|
|
297
|
+
from java_functional_lsp.proxy import ModuleState
|
|
298
|
+
from java_functional_lsp.server import server
|
|
299
|
+
|
|
300
|
+
server._proxy.modules.clear()
|
|
301
|
+
uri = "file:///mod/Foo.java"
|
|
302
|
+
non_project_diag = {
|
|
303
|
+
"code": "16",
|
|
304
|
+
"message": "Foo.java is a non-project file, only syntax errors are reported",
|
|
305
|
+
"source": "Java",
|
|
306
|
+
"severity": 2,
|
|
307
|
+
"range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 1}},
|
|
308
|
+
}
|
|
309
|
+
with (
|
|
310
|
+
patch("java_functional_lsp.server._resolve_module_uri", return_value="file:///mod"),
|
|
311
|
+
patch("java_functional_lsp.server._analyze_and_publish"),
|
|
312
|
+
):
|
|
313
|
+
server._on_jdtls_diagnostics(uri, [non_project_diag])
|
|
314
|
+
assert server._proxy.modules.get_state("file:///mod") != ModuleState.READY
|
|
315
|
+
|
|
316
|
+
def test_on_jdtls_diagnostics_project_file_marks_ready(self) -> None:
|
|
317
|
+
"""A publishDiagnostics batch without code-16 MUST mark the module READY."""
|
|
318
|
+
from unittest.mock import patch
|
|
319
|
+
|
|
320
|
+
from java_functional_lsp.proxy import ModuleState
|
|
321
|
+
from java_functional_lsp.server import server
|
|
322
|
+
|
|
323
|
+
server._proxy.modules.clear()
|
|
324
|
+
uri = "file:///mod/Pr.java"
|
|
325
|
+
real_diag = {
|
|
326
|
+
"code": "268435844",
|
|
327
|
+
"message": "Some unused import",
|
|
328
|
+
"source": "Java",
|
|
329
|
+
"severity": 2,
|
|
330
|
+
"range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 1}},
|
|
331
|
+
}
|
|
332
|
+
with (
|
|
333
|
+
patch("java_functional_lsp.server._resolve_module_uri", return_value="file:///mod"),
|
|
334
|
+
patch("java_functional_lsp.server._analyze_and_publish"),
|
|
335
|
+
patch("java_functional_lsp.server._fire_and_forget"),
|
|
336
|
+
):
|
|
337
|
+
server._on_jdtls_diagnostics(uri, [real_diag])
|
|
338
|
+
assert server._proxy.modules.get_state("file:///mod") == ModuleState.READY
|
|
339
|
+
server._proxy.modules.clear()
|
|
340
|
+
|
|
293
341
|
def test_init_capabilities_exclude_jdtls_features(self) -> None:
|
|
294
342
|
"""Static capabilities must NOT include hover/definition/references/completion/documentSymbol.
|
|
295
343
|
|
|
@@ -541,7 +589,7 @@ class TestServerInternals:
|
|
|
541
589
|
mock_add = AsyncMock(return_value="file:///mod")
|
|
542
590
|
mock_send = AsyncMock(side_effect=[None, {"result": "ok"}])
|
|
543
591
|
|
|
544
|
-
async def mock_wait(uri: str, timeout: float = 30.0) -> bool: #
|
|
592
|
+
async def mock_wait(uri: str, timeout: float = 30.0) -> bool: # type: ignore[reportUnusedParameter]
|
|
545
593
|
srv._proxy.modules.mark_ready(uri)
|
|
546
594
|
return True
|
|
547
595
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.github/ISSUE_TEMPLATE/bug-report.md
RENAMED
|
File without changes
|
{java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.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.8 → java_functional_lsp-0.9.9}/.github/workflows/release-drafter.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.8 → java_functional_lsp-0.9.9}/.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.8 → java_functional_lsp-0.9.9}/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.8 → java_functional_lsp-0.9.9}/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
|