java-functional-lsp 0.9.14__tar.gz → 0.9.15__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 (70) hide show
  1. java_functional_lsp-0.9.15/.claude-plugin/plugin.json +16 -0
  2. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/PKG-INFO +21 -7
  3. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/README.md +20 -6
  4. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/SKILL.md +3 -6
  5. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/pyproject.toml +1 -1
  6. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_server.py +30 -10
  7. java_functional_lsp-0.9.14/.claude-plugin/plugin.json +0 -5
  8. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.githooks/pre-commit +0 -0
  9. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.githooks/pre-push +0 -0
  10. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/CODEOWNERS +0 -0
  11. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  12. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  13. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  14. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/SECURITY.md +0 -0
  15. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/dependabot.yml +0 -0
  16. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/release-drafter.yml +0 -0
  17. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/workflows/publish.yml +0 -0
  18. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/workflows/release-drafter.yml +0 -0
  19. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/workflows/stale.yml +0 -0
  20. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/workflows/test.yml +0 -0
  21. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/workflows/update-homebrew.yml +0 -0
  22. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.github/workflows/vscode-ext.yml +0 -0
  23. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/.gitignore +0 -0
  24. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/CONTRIBUTING.md +0 -0
  25. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/LICENSE +0 -0
  26. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/commands/lint-java.md +0 -0
  27. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/intellij/README.md +0 -0
  28. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/intellij/lsp4ij-template.json +0 -0
  29. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/vscode/.vscodeignore +0 -0
  30. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/vscode/README.md +0 -0
  31. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/vscode/package-lock.json +0 -0
  32. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/vscode/package.json +0 -0
  33. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/vscode/src/extension.ts +0 -0
  34. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/editors/vscode/tsconfig.json +0 -0
  35. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/hooks/hooks.json +0 -0
  36. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/hooks/java_linter_reminder.py +0 -0
  37. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/scripts/ensure-lsp.sh +0 -0
  38. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/scripts/generate-formula.py +0 -0
  39. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/__init__.py +0 -0
  40. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/__main__.py +0 -0
  41. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/analyzers/__init__.py +0 -0
  42. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/analyzers/base.py +0 -0
  43. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
  44. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
  45. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
  46. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
  47. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
  48. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/cli.py +0 -0
  49. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/fixes.py +0 -0
  50. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/merkle.py +0 -0
  51. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/proxy.py +0 -0
  52. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/src/java_functional_lsp/server.py +0 -0
  53. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/__init__.py +0 -0
  54. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/conftest.py +0 -0
  55. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_base.py +0 -0
  56. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_cli.py +0 -0
  57. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_config.py +0 -0
  58. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_e2e.py +0 -0
  59. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_e2e_jdtls.py +0 -0
  60. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_exception_checker.py +0 -0
  61. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_fixes.py +0 -0
  62. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_functional_checker.py +0 -0
  63. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_merkle.py +0 -0
  64. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_merkle_proxy.py +0 -0
  65. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_mutation_checker.py +0 -0
  66. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_null_checker.py +0 -0
  67. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_proxy.py +0 -0
  68. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_spring_checker.py +0 -0
  69. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/tests/test_suppress.py +0 -0
  70. {java_functional_lsp-0.9.14 → java_functional_lsp-0.9.15}/uv.lock +0 -0
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "java-functional-lsp",
3
+ "description": "Java LSP with functional programming rules enforcement — null safety, immutability, no exceptions, Spring best practices. Wraps jdtls for full Java language support.",
4
+ "version": "0.4.2",
5
+ "lspServers": {
6
+ "java-functional": {
7
+ "command": "java-functional-lsp",
8
+ "extensionToLanguage": {
9
+ ".java": "java"
10
+ },
11
+ "startupTimeout": 120000,
12
+ "restartOnCrash": true,
13
+ "maxRestarts": 5
14
+ }
15
+ }
16
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: java-functional-lsp
3
- Version: 0.9.14
3
+ Version: 0.9.15
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
@@ -136,11 +136,17 @@ See [editors/intellij/README.md](editors/intellij/README.md) for detailed instru
136
136
 
137
137
  **Step 1: Enable LSP support** (required, one-time):
138
138
 
139
- Add to `~/.claude/settings.json`:
139
+ Add `lspServers` to `~/.claude/settings.json` (the plugin handles this automatically — only needed for manual setup):
140
140
  ```json
141
141
  {
142
- "env": {
143
- "ENABLE_LSP_TOOL": "1"
142
+ "lspServers": {
143
+ "java-functional": {
144
+ "command": "java-functional-lsp",
145
+ "extensionToLanguage": { ".java": "java" },
146
+ "startupTimeout": 120000,
147
+ "restartOnCrash": true,
148
+ "maxRestarts": 5
149
+ }
144
150
  }
145
151
  }
146
152
  ```
@@ -160,19 +166,27 @@ Or manually add to your Claude Code config:
160
166
  "lspServers": {
161
167
  "java-functional": {
162
168
  "command": "java-functional-lsp",
163
- "extensionToLanguage": { ".java": "java" }
169
+ "extensionToLanguage": { ".java": "java" },
170
+ "startupTimeout": 120000,
171
+ "restartOnCrash": true,
172
+ "maxRestarts": 5
164
173
  }
165
174
  }
166
175
  }
167
176
  ```
168
177
 
178
+ (`startupTimeout: 120000` accommodates jdtls cold-start; `restartOnCrash` keeps the server alive across session.)
179
+
169
180
  **Alternative: project-level `.lsp.json`** — instead of installing the plugin or editing global config, add a `.lsp.json` file at your project root:
170
181
 
171
182
  ```json
172
183
  {
173
184
  "java-functional": {
174
185
  "command": "java-functional-lsp",
175
- "extensionToLanguage": { ".java": "java" }
186
+ "extensionToLanguage": { ".java": "java" },
187
+ "startupTimeout": 120000,
188
+ "restartOnCrash": true,
189
+ "maxRestarts": 5
176
190
  }
177
191
  }
178
192
  ```
@@ -198,7 +212,7 @@ moving on. Fix any type errors or missing imports immediately.
198
212
 
199
213
  | Issue | Fix |
200
214
  |-------|-----|
201
- | No diagnostics appear | Ensure `ENABLE_LSP_TOOL=1` is set, restart Claude Code |
215
+ | No diagnostics appear | Ensure `lspServers` is configured (plugin or settings.json), restart |
202
216
  | "java-functional-lsp not found" | Run `brew install aviadshiber/tap/java-functional-lsp` |
203
217
  | Plugin not active | Run `claude plugin list` to verify, then `/reload-plugins` |
204
218
  | Diagnostics slow on first open | Normal — tree-sitter parses on first load, then incremental |
@@ -108,11 +108,17 @@ See [editors/intellij/README.md](editors/intellij/README.md) for detailed instru
108
108
 
109
109
  **Step 1: Enable LSP support** (required, one-time):
110
110
 
111
- Add to `~/.claude/settings.json`:
111
+ Add `lspServers` to `~/.claude/settings.json` (the plugin handles this automatically — only needed for manual setup):
112
112
  ```json
113
113
  {
114
- "env": {
115
- "ENABLE_LSP_TOOL": "1"
114
+ "lspServers": {
115
+ "java-functional": {
116
+ "command": "java-functional-lsp",
117
+ "extensionToLanguage": { ".java": "java" },
118
+ "startupTimeout": 120000,
119
+ "restartOnCrash": true,
120
+ "maxRestarts": 5
121
+ }
116
122
  }
117
123
  }
118
124
  ```
@@ -132,19 +138,27 @@ Or manually add to your Claude Code config:
132
138
  "lspServers": {
133
139
  "java-functional": {
134
140
  "command": "java-functional-lsp",
135
- "extensionToLanguage": { ".java": "java" }
141
+ "extensionToLanguage": { ".java": "java" },
142
+ "startupTimeout": 120000,
143
+ "restartOnCrash": true,
144
+ "maxRestarts": 5
136
145
  }
137
146
  }
138
147
  }
139
148
  ```
140
149
 
150
+ (`startupTimeout: 120000` accommodates jdtls cold-start; `restartOnCrash` keeps the server alive across session.)
151
+
141
152
  **Alternative: project-level `.lsp.json`** — instead of installing the plugin or editing global config, add a `.lsp.json` file at your project root:
142
153
 
143
154
  ```json
144
155
  {
145
156
  "java-functional": {
146
157
  "command": "java-functional-lsp",
147
- "extensionToLanguage": { ".java": "java" }
158
+ "extensionToLanguage": { ".java": "java" },
159
+ "startupTimeout": 120000,
160
+ "restartOnCrash": true,
161
+ "maxRestarts": 5
148
162
  }
149
163
  }
150
164
  ```
@@ -170,7 +184,7 @@ moving on. Fix any type errors or missing imports immediately.
170
184
 
171
185
  | Issue | Fix |
172
186
  |-------|-----|
173
- | No diagnostics appear | Ensure `ENABLE_LSP_TOOL=1` is set, restart Claude Code |
187
+ | No diagnostics appear | Ensure `lspServers` is configured (plugin or settings.json), restart |
174
188
  | "java-functional-lsp not found" | Run `brew install aviadshiber/tap/java-functional-lsp` |
175
189
  | Plugin not active | Run `claude plugin list` to verify, then `/reload-plugins` |
176
190
  | Diagnostics slow on first open | Normal — tree-sitter parses on first load, then incremental |
@@ -112,14 +112,11 @@ To release a new version:
112
112
 
113
113
  ## Enabling LSP in Claude Code
114
114
 
115
- LSP support requires `ENABLE_LSP_TOOL=1` in `~/.claude/settings.json`:
116
- ```json
117
- { "env": { "ENABLE_LSP_TOOL": "1" } }
118
- ```
115
+ Declare `lspServers` in `~/.claude/settings.json` or in `plugin.json` — Claude Code enables the LSP tool automatically when `lspServers` is configured. `ENABLE_LSP_TOOL=1` is no longer needed.
119
116
 
120
117
  For containers or CI, add a `.lsp.json` at the project root instead of installing the plugin:
121
118
  ```json
122
- { "java-functional": { "command": "java-functional-lsp", "extensionToLanguage": { ".java": "java" } } }
119
+ { "java-functional": { "command": "java-functional-lsp", "extensionToLanguage": { ".java": "java" }, "startupTimeout": 120000, "restartOnCrash": true, "maxRestarts": 5 } }
123
120
  ```
124
121
 
125
122
  To nudge Claude to act on diagnostics, add to your project's `CLAUDE.md`:
@@ -130,7 +127,7 @@ Fix any violations immediately — do not explain, just apply the fix.
130
127
 
131
128
  ## Troubleshooting
132
129
 
133
- - **No diagnostics in Claude Code**: Ensure `ENABLE_LSP_TOOL=1` is set, restart Claude Code
130
+ - **No diagnostics in Claude Code**: Ensure `lspServers` is configured (in `plugin.json` or `settings.json`), restart Claude Code
134
131
  - **"java-functional-lsp not found"**: Run `brew install aviadshiber/tap/java-functional-lsp`
135
132
  - **No completions/hover**: Install jdtls: `brew install jdtls` (requires JDK 21+)
136
133
  - **Too many warnings**: Create `.java-functional-lsp.json` with `excludes` or per-rule severity
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "java-functional-lsp"
7
- version = "0.9.14"
7
+ version = "0.9.15"
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" }
@@ -71,10 +71,15 @@ async def lsp_client(tmp_path: Any) -> LanguageClient: # type: ignore[misc]
71
71
 
72
72
  # Collect published diagnostics so tests can assert on them.
73
73
  client._published: dict[str, list[lsp.Diagnostic]] = {} # type: ignore[attr-defined]
74
+ # Per-URI events signalled by on_publish — used by _open_and_wait_for_diagnostics.
75
+ client._diag_events: dict[str, asyncio.Event] = {} # type: ignore[attr-defined]
74
76
 
75
77
  @client.feature(lsp.TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS)
76
78
  def on_publish(params: lsp.PublishDiagnosticsParams) -> None:
77
79
  client._published[params.uri] = list(params.diagnostics) # type: ignore[attr-defined]
80
+ evt = client._diag_events.get(params.uri) # type: ignore[attr-defined]
81
+ if evt is not None:
82
+ evt.set()
78
83
 
79
84
  await client.start_io(sys.executable, "-m", "java_functional_lsp")
80
85
 
@@ -121,10 +126,21 @@ async def _open_and_wait_for_diagnostics(
121
126
  ) -> list[lsp.Diagnostic]:
122
127
  """Open a document and wait until publishDiagnostics arrives for its URI.
123
128
 
124
- The server publishes diagnostics asynchronously after didOpen. We poll
125
- the client's collected notifications until the URI appears or timeout.
129
+ The server publishes diagnostics asynchronously after didOpen. We register
130
+ an asyncio.Event that on_publish signals, then await it with wait_for so the
131
+ full timeout is always respected — even when the event loop is transiently
132
+ busy (e.g. jdtls subprocess creation on a slow macOS runner).
133
+
134
+ Note: the server always emits publishDiagnostics for every opened file
135
+ (including clean ones with zero findings) synchronously inside on_did_open,
136
+ before jdtls is involved. The event is therefore guaranteed to fire on the
137
+ first — and correct — notification for each URI in this test setup.
126
138
  """
127
139
  client._published.pop(uri, None) # type: ignore[attr-defined]
140
+ # Register event before sending didOpen — no await between these two lines,
141
+ # so on_publish cannot fire and miss the registration.
142
+ event = asyncio.Event()
143
+ client._diag_events[uri] = event # type: ignore[attr-defined]
128
144
 
129
145
  client.text_document_did_open(
130
146
  lsp.DidOpenTextDocumentParams(
@@ -137,14 +153,18 @@ async def _open_and_wait_for_diagnostics(
137
153
  )
138
154
  )
139
155
 
140
- deadline = asyncio.get_running_loop().time() + timeout
141
- while asyncio.get_running_loop().time() < deadline:
142
- if uri in client._published: # type: ignore[attr-defined]
143
- return client._published[uri] # type: ignore[attr-defined]
144
- await asyncio.sleep(0.1)
156
+ try:
157
+ await asyncio.wait_for(event.wait(), timeout=timeout)
158
+ except asyncio.TimeoutError:
159
+ # pytest.fail() raises Failed (a BaseException subclass);
160
+ # the finally block below still runs before the exception propagates.
161
+ pytest.fail(f"Timed out waiting for publishDiagnostics on {uri}")
162
+ finally:
163
+ client._diag_events.pop(uri, None) # type: ignore[attr-defined]
145
164
 
146
- pytest.fail(f"Timed out waiting for publishDiagnostics on {uri}")
147
- return [] # unreachable, but satisfies type checker
165
+ # on_publish stores to _published before setting the event, so the key
166
+ # is guaranteed to exist here — use direct access to surface any violation.
167
+ return client._published[uri] # type: ignore[attr-defined]
148
168
 
149
169
 
150
170
  # --------------------------------------------------------------------------
@@ -2077,7 +2097,7 @@ class TestCacheClear:
2077
2097
  # --------------------------------------------------------------------------
2078
2098
 
2079
2099
 
2080
- @pytest.mark.timeout(30)
2100
+ @pytest.mark.timeout(60) # covers fixture setup (subprocess spawn + initialize handshake) on slow macOS runners
2081
2101
  class TestLspLifecycle:
2082
2102
  """Full LSP lifecycle tests via real stdio transport — zero mocks."""
2083
2103
 
@@ -1,5 +0,0 @@
1
- {
2
- "name": "java-functional-lsp",
3
- "description": "Java LSP with functional programming rules enforcement — null safety, immutability, no exceptions, Spring best practices. Wraps jdtls for full Java language support.",
4
- "version": "0.4.1"
5
- }