java-functional-lsp 0.9.15__tar.gz → 0.9.16__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.15 → java_functional_lsp-0.9.16}/PKG-INFO +1 -1
  2. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/intellij/README.md +1 -1
  3. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/pyproject.toml +1 -1
  4. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/__init__.py +1 -1
  5. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/cli.py +34 -25
  6. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_cli.py +27 -1
  7. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_server.py +7 -2
  8. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.claude-plugin/plugin.json +0 -0
  9. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.githooks/pre-commit +0 -0
  10. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.githooks/pre-push +0 -0
  11. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/CODEOWNERS +0 -0
  12. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  13. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  14. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  15. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/SECURITY.md +0 -0
  16. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/dependabot.yml +0 -0
  17. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/release-drafter.yml +0 -0
  18. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/workflows/publish.yml +0 -0
  19. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/workflows/release-drafter.yml +0 -0
  20. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/workflows/stale.yml +0 -0
  21. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/workflows/test.yml +0 -0
  22. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/workflows/update-homebrew.yml +0 -0
  23. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.github/workflows/vscode-ext.yml +0 -0
  24. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/.gitignore +0 -0
  25. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/CONTRIBUTING.md +0 -0
  26. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/LICENSE +0 -0
  27. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/README.md +0 -0
  28. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/SKILL.md +0 -0
  29. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/commands/lint-java.md +0 -0
  30. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/intellij/lsp4ij-template.json +0 -0
  31. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/vscode/.vscodeignore +0 -0
  32. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/vscode/README.md +0 -0
  33. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/vscode/package-lock.json +0 -0
  34. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/vscode/package.json +0 -0
  35. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/vscode/src/extension.ts +0 -0
  36. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/editors/vscode/tsconfig.json +0 -0
  37. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/hooks/hooks.json +0 -0
  38. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/hooks/java_linter_reminder.py +0 -0
  39. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/scripts/ensure-lsp.sh +0 -0
  40. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/scripts/generate-formula.py +0 -0
  41. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/__main__.py +0 -0
  42. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/analyzers/__init__.py +0 -0
  43. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/analyzers/base.py +0 -0
  44. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/analyzers/exception_checker.py +0 -0
  45. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/analyzers/functional_checker.py +0 -0
  46. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/analyzers/mutation_checker.py +0 -0
  47. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/analyzers/null_checker.py +0 -0
  48. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/analyzers/spring_checker.py +0 -0
  49. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/fixes.py +0 -0
  50. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/merkle.py +0 -0
  51. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/proxy.py +0 -0
  52. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/src/java_functional_lsp/server.py +0 -0
  53. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/__init__.py +0 -0
  54. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/conftest.py +0 -0
  55. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_base.py +0 -0
  56. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_config.py +0 -0
  57. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_e2e.py +0 -0
  58. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_e2e_jdtls.py +0 -0
  59. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_exception_checker.py +0 -0
  60. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_fixes.py +0 -0
  61. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_functional_checker.py +0 -0
  62. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_merkle.py +0 -0
  63. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_merkle_proxy.py +0 -0
  64. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_mutation_checker.py +0 -0
  65. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_null_checker.py +0 -0
  66. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_proxy.py +0 -0
  67. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_spring_checker.py +0 -0
  68. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/tests/test_suppress.py +0 -0
  69. {java_functional_lsp-0.9.15 → java_functional_lsp-0.9.16}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: java-functional-lsp
3
- Version: 0.9.15
3
+ Version: 0.9.16
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
@@ -84,7 +84,7 @@ The server automatically detects JetBrains IDEs and disables the jdtls proxy —
84
84
  ### No diagnostics appear
85
85
  - Ensure the file mapping is set to Language: `Java`, Language ID: `java`
86
86
  - Check that `.java-functional-lsp.json` doesn't have rules set to `"off"`
87
- - Try restarting the language server: **Tools** → **Language Servers** → **Restart**
87
+ - Try restarting the language server: **Language Servers** (search it in intellij Actions [Double Shift on keyboard]) → click on java-functional-lsp → **Restart**
88
88
  - If diagnostics worked before but stopped, the jdtls proxy may be interfering. Set `JAVA_FUNCTIONAL_LSP_JDTLS=off` in the server command environment to force-disable jdtls. The server auto-detects JetBrains IDEs and disables jdtls by default (since IntelliJ provides native Java support), but this can be overridden with `JAVA_FUNCTIONAL_LSP_JDTLS=on`.
89
89
 
90
90
  ### PATH not found
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "java-functional-lsp"
7
- version = "0.9.15"
7
+ version = "0.9.16"
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.14"
3
+ __version__ = "0.9.16"
@@ -66,14 +66,41 @@ def format_diagnostic(path: Path, d: Diagnostic) -> str:
66
66
  return f"{path}:{d.line + 1}:{d.col}: [{sym}] {d.code}: {d.message}"
67
67
 
68
68
 
69
+ _USAGE = """\
70
+ Usage: java-functional-lsp check <file.java> [file2.java ...]
71
+ java-functional-lsp check --dir <directory>
72
+ java-functional-lsp (start LSP server on stdio)"""
73
+
74
+
75
+ def _collect_files(args: list[str]) -> list[Path]:
76
+ """Resolve CLI args to a list of .java paths."""
77
+ files: list[Path] = []
78
+ if args and args[0] == "--dir":
79
+ if len(args) < 2:
80
+ print("Error: --dir requires a directory path", file=sys.stderr)
81
+ sys.exit(1)
82
+ directory = Path(args[1])
83
+ if not directory.is_dir():
84
+ print(f"Error: {directory} is not a directory", file=sys.stderr)
85
+ sys.exit(1)
86
+ return sorted(directory.rglob("*.java"))
87
+ for arg in args:
88
+ p = Path(arg)
89
+ if p.is_file():
90
+ files.append(p)
91
+ elif p.is_dir():
92
+ files.extend(sorted(p.rglob("*.java")))
93
+ else:
94
+ print(f"Warning: {arg} not found, skipping", file=sys.stderr)
95
+ return files
96
+
97
+
69
98
  def main() -> None:
70
99
  """CLI entry point: java-functional-lsp check <files...>"""
71
100
  args = sys.argv[1:]
72
101
 
73
102
  if args and args[0] in ("-h", "--help"):
74
- print("Usage: java-functional-lsp check <file.java> [file2.java ...]")
75
- print(" java-functional-lsp check --dir <directory>")
76
- print(" java-functional-lsp (start LSP server on stdio)")
103
+ print(_USAGE)
77
104
  sys.exit(0)
78
105
 
79
106
  if not args or args[0] != "check":
@@ -85,34 +112,16 @@ def main() -> None:
85
112
 
86
113
  args = args[1:] # skip "check"
87
114
 
88
- # Collect files
89
- files: list[Path] = []
90
- if args and args[0] == "--dir":
91
- if len(args) < 2:
92
- print("Error: --dir requires a directory path", file=sys.stderr)
93
- sys.exit(1)
94
- directory = Path(args[1])
95
- if not directory.is_dir():
96
- print(f"Error: {directory} is not a directory", file=sys.stderr)
97
- sys.exit(1)
98
- files = sorted(directory.rglob("*.java"))
99
- else:
100
- for arg in args:
101
- p = Path(arg)
102
- if p.is_file():
103
- files.append(p)
104
- elif p.is_dir():
105
- files.extend(sorted(p.rglob("*.java")))
106
- else:
107
- print(f"Warning: {arg} not found, skipping", file=sys.stderr)
115
+ if args and args[0] in ("-h", "--help"):
116
+ print(_USAGE)
117
+ sys.exit(0)
108
118
 
119
+ files = _collect_files(args)
109
120
  if not files:
110
121
  print("No .java files found", file=sys.stderr)
111
122
  sys.exit(1)
112
123
 
113
- # Load config from first file's directory
114
124
  config = load_config(files[0])
115
-
116
125
  total_diags = 0
117
126
  excludes: list[str] = config.get("excludes", [])
118
127
  for path in files:
@@ -4,8 +4,11 @@ from __future__ import annotations
4
4
 
5
5
  from pathlib import Path
6
6
  from typing import Any
7
+ from unittest.mock import patch
7
8
 
8
- from java_functional_lsp.cli import check_file, format_diagnostic, load_config
9
+ import pytest
10
+
11
+ from java_functional_lsp.cli import check_file, format_diagnostic, load_config, main
9
12
 
10
13
 
11
14
  class TestCheckFile:
@@ -53,3 +56,26 @@ class TestLoadConfig:
53
56
  def test_missing_config(self, tmp_path: Path) -> None:
54
57
  config = load_config(tmp_path / "Test.java")
55
58
  assert config == {}
59
+
60
+
61
+ class TestHelp:
62
+ def test_top_level_help(self, capsys: pytest.CaptureFixture[str]) -> None:
63
+ with patch("sys.argv", ["java-functional-lsp", "--help"]):
64
+ with pytest.raises(SystemExit) as exc:
65
+ main()
66
+ assert exc.value.code == 0
67
+ assert "check" in capsys.readouterr().out
68
+
69
+ def test_check_subcommand_help(self, capsys: pytest.CaptureFixture[str]) -> None:
70
+ with patch("sys.argv", ["java-functional-lsp", "check", "--help"]):
71
+ with pytest.raises(SystemExit) as exc:
72
+ main()
73
+ assert exc.value.code == 0
74
+ assert "check" in capsys.readouterr().out
75
+
76
+ def test_check_short_help(self, capsys: pytest.CaptureFixture[str]) -> None:
77
+ with patch("sys.argv", ["java-functional-lsp", "check", "-h"]):
78
+ with pytest.raises(SystemExit) as exc:
79
+ main()
80
+ assert exc.value.code == 0
81
+ assert "check" in capsys.readouterr().out
@@ -109,12 +109,17 @@ async def lsp_client(tmp_path: Any) -> LanguageClient: # type: ignore[misc]
109
109
  try:
110
110
  yield client
111
111
  finally:
112
+ # Teardown with timeouts: the server subprocess may be mid-jdtls-startup
113
+ # on a slow CI runner, causing shutdown_async or stop to hang indefinitely.
112
114
  try:
113
- await client.shutdown_async(None)
115
+ await asyncio.wait_for(client.shutdown_async(None), timeout=5.0)
114
116
  client.exit(None)
115
117
  except Exception:
116
118
  pass
117
- await client.stop()
119
+ try:
120
+ await asyncio.wait_for(client.stop(), timeout=5.0)
121
+ except Exception:
122
+ pass
118
123
 
119
124
 
120
125
  async def _open_and_wait_for_diagnostics(