java-functional-lsp 0.9.11__tar.gz → 0.9.12__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.11 → java_functional_lsp-0.9.12}/PKG-INFO +32 -2
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/README.md +31 -1
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/pyproject.toml +1 -1
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/__init__.py +1 -1
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/server.py +19 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_server.py +44 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.claude-plugin/plugin.json +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.githooks/pre-commit +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.githooks/pre-push +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/CODEOWNERS +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/SECURITY.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/dependabot.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/workflows/publish.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/workflows/release-drafter.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/workflows/stale.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/workflows/test.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/workflows/update-homebrew.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/workflows/vscode-ext.yml +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.gitignore +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/CONTRIBUTING.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/LICENSE +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/SKILL.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/commands/lint-java.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/intellij/README.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/intellij/lsp4ij-template.json +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/vscode/.vscodeignore +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/vscode/README.md +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/vscode/package-lock.json +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/vscode/package.json +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/vscode/src/extension.ts +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/editors/vscode/tsconfig.json +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/hooks/hooks.json +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/hooks/java_linter_reminder.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/scripts/ensure-lsp.sh +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/scripts/generate-formula.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/__main__.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/analyzers/__init__.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/analyzers/base.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/cli.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/fixes.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/merkle.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/proxy.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/__init__.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/conftest.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_base.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_cli.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_config.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_e2e.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_e2e_jdtls.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_exception_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_fixes.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_functional_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_merkle.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_merkle_proxy.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_mutation_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_null_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_proxy.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_spring_checker.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/tests/test_suppress.py +0 -0
- {java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/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.12
|
|
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
|
|
@@ -270,7 +270,37 @@ The server auto-discovers `lombok.jar` from these locations (first match wins):
|
|
|
270
270
|
3. **Maven cache** — auto-discovered from `~/.m2/repository/org/projectlombok/lombok/`
|
|
271
271
|
4. **Dedicated directory** — `~/.jdtls-libs/lombok.jar`
|
|
272
272
|
|
|
273
|
-
If Lombok is used in your project but the jar isn't found, the server logs a warning.
|
|
273
|
+
If Lombok is used in your project but the jar isn't found, the server logs a warning.
|
|
274
|
+
|
|
275
|
+
### jdtls settings
|
|
276
|
+
|
|
277
|
+
The server sends Maven/Gradle settings to jdtls at startup via `initializationOptions.settings`. Defaults are optimized for Maven monorepos (Maven enabled, Gradle disabled, build artifact exclusions). Override via `.java-functional-lsp.json`:
|
|
278
|
+
|
|
279
|
+
```json
|
|
280
|
+
{
|
|
281
|
+
"jdtls": {
|
|
282
|
+
"settings": {
|
|
283
|
+
"java": {
|
|
284
|
+
"import": {
|
|
285
|
+
"maven": { "enabled": true },
|
|
286
|
+
"gradle": { "enabled": true },
|
|
287
|
+
"exclusions": ["**/node_modules/**", "**/target/**"]
|
|
288
|
+
},
|
|
289
|
+
"configuration": { "updateBuildConfiguration": "automatic" },
|
|
290
|
+
"maven": { "downloadSources": true }
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Custom settings fully replace the defaults (no merge). See the [jdtls Preferences reference](https://github.com/eclipse-jdtls/eclipse.jdt.ls/blob/main/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java) for all available keys.
|
|
298
|
+
|
|
299
|
+
### jdtls cache
|
|
300
|
+
|
|
301
|
+
The jdtls Eclipse workspace index is cached in `~/.cache/jdtls-data/`. Warm starts (~10-20s) reuse this cache; cold starts (60-120s) rebuild from scratch. The cache is automatically invalidated when jdtls or Java is upgraded, but **not** when java-functional-lsp is upgraded — our Python code changes don't affect the Eclipse index.
|
|
302
|
+
|
|
303
|
+
To force a clean rebuild: `rm -rf ~/.cache/jdtls-data/`
|
|
274
304
|
|
|
275
305
|
### Suppressing jdtls diagnostics
|
|
276
306
|
|
|
@@ -242,7 +242,37 @@ The server auto-discovers `lombok.jar` from these locations (first match wins):
|
|
|
242
242
|
3. **Maven cache** — auto-discovered from `~/.m2/repository/org/projectlombok/lombok/`
|
|
243
243
|
4. **Dedicated directory** — `~/.jdtls-libs/lombok.jar`
|
|
244
244
|
|
|
245
|
-
If Lombok is used in your project but the jar isn't found, the server logs a warning.
|
|
245
|
+
If Lombok is used in your project but the jar isn't found, the server logs a warning.
|
|
246
|
+
|
|
247
|
+
### jdtls settings
|
|
248
|
+
|
|
249
|
+
The server sends Maven/Gradle settings to jdtls at startup via `initializationOptions.settings`. Defaults are optimized for Maven monorepos (Maven enabled, Gradle disabled, build artifact exclusions). Override via `.java-functional-lsp.json`:
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"jdtls": {
|
|
254
|
+
"settings": {
|
|
255
|
+
"java": {
|
|
256
|
+
"import": {
|
|
257
|
+
"maven": { "enabled": true },
|
|
258
|
+
"gradle": { "enabled": true },
|
|
259
|
+
"exclusions": ["**/node_modules/**", "**/target/**"]
|
|
260
|
+
},
|
|
261
|
+
"configuration": { "updateBuildConfiguration": "automatic" },
|
|
262
|
+
"maven": { "downloadSources": true }
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Custom settings fully replace the defaults (no merge). See the [jdtls Preferences reference](https://github.com/eclipse-jdtls/eclipse.jdt.ls/blob/main/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java) for all available keys.
|
|
270
|
+
|
|
271
|
+
### jdtls cache
|
|
272
|
+
|
|
273
|
+
The jdtls Eclipse workspace index is cached in `~/.cache/jdtls-data/`. Warm starts (~10-20s) reuse this cache; cold starts (60-120s) rebuild from scratch. The cache is automatically invalidated when jdtls or Java is upgraded, but **not** when java-functional-lsp is upgraded — our Python code changes don't affect the Eclipse index.
|
|
274
|
+
|
|
275
|
+
To force a clean rebuild: `rm -rf ~/.cache/jdtls-data/`
|
|
246
276
|
|
|
247
277
|
### Suppressing jdtls diagnostics
|
|
248
278
|
|
|
@@ -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.12"
|
|
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" }
|
|
@@ -12,6 +12,7 @@ import logging
|
|
|
12
12
|
import os
|
|
13
13
|
import re
|
|
14
14
|
import sys
|
|
15
|
+
import time
|
|
15
16
|
from collections.abc import Coroutine
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
from typing import Any
|
|
@@ -635,6 +636,24 @@ async def on_did_close(params: lsp.DidCloseTextDocumentParams) -> None:
|
|
|
635
636
|
_forward_or_queue("textDocument/didClose", _serialize_params(params))
|
|
636
637
|
|
|
637
638
|
|
|
639
|
+
_DIDCHANGE_CONFIG_COOLDOWN = 30.0 # seconds — rate-limit didChangeConfiguration forwarding
|
|
640
|
+
_last_config_forward: float = 0.0
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
@server.feature(lsp.WORKSPACE_DID_CHANGE_CONFIGURATION)
|
|
644
|
+
def on_did_change_configuration(params: lsp.DidChangeConfigurationParams) -> None:
|
|
645
|
+
"""Forward IDE configuration changes to jdtls (rate-limited)."""
|
|
646
|
+
global _last_config_forward
|
|
647
|
+
if not server._proxy.is_available:
|
|
648
|
+
return
|
|
649
|
+
now = time.monotonic()
|
|
650
|
+
if now - _last_config_forward < _DIDCHANGE_CONFIG_COOLDOWN:
|
|
651
|
+
logger.debug("jdtls: throttling didChangeConfiguration (%.0fs cooldown)", _DIDCHANGE_CONFIG_COOLDOWN)
|
|
652
|
+
return
|
|
653
|
+
_last_config_forward = now
|
|
654
|
+
_fire_and_forget(server._proxy.send_notification("workspace/didChangeConfiguration", _serialize_params(params)))
|
|
655
|
+
|
|
656
|
+
|
|
638
657
|
async def _lazy_start_jdtls(file_uri: str) -> None:
|
|
639
658
|
"""Background task: start jdtls scoped to the module containing *file_uri*.
|
|
640
659
|
|
|
@@ -1547,6 +1547,50 @@ class TestFindLombokJar:
|
|
|
1547
1547
|
assert any("does not exist" in r.getMessage() for r in caplog.records)
|
|
1548
1548
|
|
|
1549
1549
|
|
|
1550
|
+
class TestDidChangeConfiguration:
|
|
1551
|
+
"""Tests for workspace/didChangeConfiguration forwarding."""
|
|
1552
|
+
|
|
1553
|
+
def test_forwards_to_jdtls_when_available(self) -> None:
|
|
1554
|
+
from unittest.mock import AsyncMock, patch
|
|
1555
|
+
|
|
1556
|
+
import java_functional_lsp.server as srv_mod
|
|
1557
|
+
from java_functional_lsp.server import on_did_change_configuration, server
|
|
1558
|
+
|
|
1559
|
+
srv_mod._last_config_forward = 0.0 # reset cooldown
|
|
1560
|
+
server._proxy._available = True
|
|
1561
|
+
server._proxy.send_notification = AsyncMock() # type: ignore[assignment]
|
|
1562
|
+
params = lsp.DidChangeConfigurationParams(settings={"java": {"autobuild": {"enabled": True}}})
|
|
1563
|
+
with patch("java_functional_lsp.server._fire_and_forget") as mock_faf:
|
|
1564
|
+
on_did_change_configuration(params)
|
|
1565
|
+
mock_faf.assert_called_once()
|
|
1566
|
+
|
|
1567
|
+
def test_throttled_within_cooldown(self) -> None:
|
|
1568
|
+
from unittest.mock import patch
|
|
1569
|
+
|
|
1570
|
+
import java_functional_lsp.server as srv_mod
|
|
1571
|
+
from java_functional_lsp.server import on_did_change_configuration, server
|
|
1572
|
+
|
|
1573
|
+
server._proxy._available = True
|
|
1574
|
+
import time
|
|
1575
|
+
|
|
1576
|
+
srv_mod._last_config_forward = time.monotonic() # just sent
|
|
1577
|
+
params = lsp.DidChangeConfigurationParams(settings={})
|
|
1578
|
+
with patch("java_functional_lsp.server._fire_and_forget") as mock_faf:
|
|
1579
|
+
on_did_change_configuration(params)
|
|
1580
|
+
mock_faf.assert_not_called()
|
|
1581
|
+
|
|
1582
|
+
def test_skipped_when_proxy_unavailable(self) -> None:
|
|
1583
|
+
from unittest.mock import patch
|
|
1584
|
+
|
|
1585
|
+
from java_functional_lsp.server import on_did_change_configuration, server
|
|
1586
|
+
|
|
1587
|
+
server._proxy._available = False
|
|
1588
|
+
params = lsp.DidChangeConfigurationParams(settings={})
|
|
1589
|
+
with patch("java_functional_lsp.server._fire_and_forget") as mock_faf:
|
|
1590
|
+
on_did_change_configuration(params)
|
|
1591
|
+
mock_faf.assert_not_called()
|
|
1592
|
+
|
|
1593
|
+
|
|
1550
1594
|
class TestCacheClear:
|
|
1551
1595
|
"""Tests for _clear_cache_on_version_change() and _compute_cache_marker()."""
|
|
1552
1596
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.github/ISSUE_TEMPLATE/bug-report.md
RENAMED
|
File without changes
|
{java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.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.11 → java_functional_lsp-0.9.12}/.github/workflows/release-drafter.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/.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
|
{java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/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.11 → java_functional_lsp-0.9.12}/src/java_functional_lsp/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{java_functional_lsp-0.9.11 → java_functional_lsp-0.9.12}/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
|