Skip to content

Commit eaaa13a

Browse files
authored
feat(go): Add Go ecosystem support - Complete (Phases 1-4) (#40)
* feat(go): implement Phase 1 - core types and parser Add Go ecosystem support for deps-lsp. This phase implements: Core Types (types.rs): - GoDependency with module_path, version, directive, indirect - GoDirective enum (Require, Replace, Exclude, Retract) - GoVersion with pseudo-version and retracted tracking - GoMetadata with pkg.go.dev documentation URL go.mod Parser (parser.rs): - LineOffsetTable for O(log n) position lookups - UTF-16 character position calculation for LSP - Support for require, replace, exclude directives - Multi-line block parsing with state machine - Inline comment handling (including URL-aware // stripping) - Indirect dependency marker extraction Version Utilities (version.rs): - Module path escaping (uppercase → !lowercase) - Pseudo-version detection and base version extraction - Semantic version comparison with +incompatible handling Error Handling (error.rs): - 10 error variants with thiserror integration - Bidirectional deps_core::DepsError conversion - Helper factory methods for common errors Tests: 41 unit tests, all passing Coverage: ~85% across all modules Snapshots: insta snapshot tests for parser output * feat(go): implement Phase 2 - registry client Add GoRegistry for proxy.golang.org integration: - HTTP client with HttpCache for ETag/Last-Modified caching - get_versions() - fetch all available versions for a module - get_version_info() - get metadata for specific version - get_latest() - fetch latest stable version - get_go_mod() - retrieve go.mod content for a version - Module path escaping (uppercase to !lowercase) - deps_core::Registry trait implementation Security hardening: - Module path length validation (max 500 chars) - Version string validation (no path traversal, valid chars) - Input sanitization before URL construction Performance optimizations: - Zero-copy parsing with std::str::from_utf8 - Synchronous parse functions (no async overhead) - Efficient module path escaping with encode_utf8() 62 tests passing with comprehensive coverage. * feat(go): implement Phase 3 - LSP features integration Add full LSP support for Go modules (go.mod files): GoFormatter (formatter.rs): - Unquoted version format for go.mod - Package URLs to pkg.go.dev - Version matching with boundary checking - URL encoding for special characters GoEcosystem (ecosystem.rs): - Ecosystem trait implementation for LSP handlers - Inlay hints, hover, code actions, diagnostics - Version completion from proxy.golang.org - Retracted version filtering LSP Integration (state.rs): - Go variant in Ecosystem enum with go.mod detection - UnifiedDependency::Go and UnifiedVersion::Go - GoEcosystem registration in ServerState Performance optimizations: - Single-pass version completion (no double iteration) - Parser Vec pre-allocation 690 tests passing. * test(go): implement Phase 4 - comprehensive test coverage Add 25 new tests to address critical coverage gaps: Ecosystem Tests (ecosystem.rs): - Inlay hint generation (up-to-date, needs update, no cache) - Hover generation for module paths - Code action generation - Completion context detection (package name, version) - Parse manifest error handling State Integration Tests (state.rs): - Ecosystem detection from filenames (go.mod) - Ecosystem detection from URIs - UnifiedDependency::Go variant methods - UnifiedVersion::Go variant methods - DocumentState Go ecosystem support Coverage improvements: - ecosystem.rs: 73% -> 83% - state.rs: Go variants fully covered 713 tests passing (9 ignored for network access). * docs: update READMEs and CI for Go ecosystem support README updates: - Add Go Modules to supported ecosystems table - Add go.sum to lock file support list - Add deps-go to project structure - Create deps-go README with usage examples - Update deps-core to mention deps-go CI updates: - Add deps-go to per-crate coverage generation - Add codecov upload step for deps-go coverage Other: - Add **/snapshots/ to .gitignore * feat(go): add go.sum lockfile parser Implement LockFileProvider for Go ecosystem: - Parse go.sum format (module_path version h1:hash) - Skip /go.mod entries (module file checksums) - Validate h1: prefix for checksums - First occurrence wins (Go's MVS algorithm) - Async file operations with staleness detection - Workspace search (up to 5 levels) Integration: - GoEcosystem::lockfile_provider() returns GoSumParser - Resolved versions now available for inlay hints 22 lockfile tests, 97.66% coverage. * refactor(go): replace insta snapshot with assertions - Rewrite test_parse_complex_go_mod to use regular assertions - Remove insta dev-dependency from deps-go
1 parent 69485a6 commit eaaa13a

File tree

20 files changed

+3854
-4
lines changed

20 files changed

+3854
-4
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ jobs:
215215
- name: Generate per-crate coverage
216216
run: |
217217
# Generate coverage for each crate separately
218-
for crate in deps-core deps-cargo deps-npm deps-pypi deps-lsp; do
218+
for crate in deps-core deps-cargo deps-npm deps-pypi deps-go deps-lsp; do
219219
echo "Generating coverage for $crate..."
220220
cargo llvm-cov --all-features --package "$crate" --lcov \
221221
--output-path "lcov-$crate.info" nextest 2>/dev/null || true
@@ -261,6 +261,14 @@ jobs:
261261
flags: deps-pypi
262262
fail_ci_if_error: false
263263

264+
- name: Upload deps-go coverage
265+
uses: codecov/codecov-action@v5
266+
with:
267+
token: ${{ secrets.CODECOV_TOKEN }}
268+
files: lcov-deps-go.info
269+
flags: deps-go
270+
fail_ci_if_error: false
271+
264272
- name: Upload deps-lsp coverage
265273
uses: codecov/codecov-action@v5
266274
with:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ target
1414

1515
# Testing
1616
.snapshots/
17+
**/snapshots/
1718

1819
# Local development
1920
.local/

Cargo.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ deps-core = { version = "0.4.1", path = "crates/deps-core" }
1919
deps-cargo = { version = "0.4.1", path = "crates/deps-cargo" }
2020
deps-npm = { version = "0.4.1", path = "crates/deps-npm" }
2121
deps-pypi = { version = "0.4.1", path = "crates/deps-pypi" }
22+
deps-go = { version = "0.4.1", path = "crates/deps-go" }
2223
deps-lsp = { version = "0.4.1", path = "crates/deps-lsp" }
2324
futures = "0.3"
2425
insta = "1"
@@ -28,6 +29,7 @@ once_cell = "1.20"
2829
pep440_rs = "0.7"
2930
pep508_rs = "0.9"
3031
bytes = "1"
32+
regex = "1"
3133
reqwest = { version = "0.12", default-features = false }
3234
semver = "1"
3335
serde = "1"

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ A universal Language Server Protocol (LSP) server for dependency management acro
1414

1515
- **Intelligent Autocomplete** — Package names, versions, and feature flags
1616
- **Version Hints** — Inlay hints showing latest available versions
17-
- **Lock File Support** — Reads resolved versions from Cargo.lock, package-lock.json, poetry.lock, uv.lock
17+
- **Lock File Support** — Reads resolved versions from Cargo.lock, package-lock.json, poetry.lock, uv.lock, go.sum
1818
- **Diagnostics** — Warnings for outdated, unknown, or yanked dependencies
1919
- **Hover Information** — Package descriptions with resolved version from lock file
2020
- **Code Actions** — Quick fixes to update dependencies
@@ -43,10 +43,14 @@ deps-lsp is optimized for responsiveness:
4343
| Rust/Cargo | `Cargo.toml` | ✅ Supported |
4444
| npm | `package.json` | ✅ Supported |
4545
| Python/PyPI | `pyproject.toml` | ✅ Supported |
46+
| Go Modules | `go.mod` | ✅ Supported |
4647

4748
> [!NOTE]
4849
> PyPI support includes PEP 621, PEP 735 (dependency-groups), and Poetry formats.
4950
51+
> [!NOTE]
52+
> Go support includes require, replace, and exclude directives with pseudo-version handling.
53+
5054
## Installation
5155

5256
### From crates.io
@@ -185,6 +189,7 @@ deps-lsp/
185189
│ ├── deps-cargo/ # Cargo.toml parser + crates.io registry
186190
│ ├── deps-npm/ # package.json parser + npm registry
187191
│ ├── deps-pypi/ # pyproject.toml parser + PyPI registry
192+
│ ├── deps-go/ # go.mod parser + proxy.golang.org
188193
│ ├── deps-lsp/ # Main LSP server
189194
│ └── deps-zed/ # Zed extension (WASM)
190195
├── .config/ # nextest configuration

crates/deps-core/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
Core abstractions for deps-lsp: traits, caching, and generic LSP handlers.
99

10-
This crate provides the shared infrastructure used by ecosystem-specific crates (`deps-cargo`, `deps-npm`, `deps-pypi`).
10+
This crate provides the shared infrastructure used by ecosystem-specific crates (`deps-cargo`, `deps-npm`, `deps-pypi`, `deps-go`).
1111

1212
## Features
1313

crates/deps-go/Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "deps-go"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
authors.workspace = true
7+
license.workspace = true
8+
repository.workspace = true
9+
description = "Go module support for deps-lsp"
10+
11+
[dependencies]
12+
deps-core = { workspace = true }
13+
async-trait.workspace = true
14+
serde.workspace = true
15+
serde_json.workspace = true
16+
thiserror.workspace = true
17+
tokio.workspace = true
18+
tower-lsp-server.workspace = true
19+
tracing.workspace = true
20+
regex.workspace = true
21+
once_cell.workspace = true
22+
semver.workspace = true
23+
24+
[dev-dependencies]
25+
tokio = { workspace = true, features = ["macros", "rt"] }
26+
tokio-test.workspace = true
27+
tempfile.workspace = true

crates/deps-go/README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# deps-go
2+
3+
[![Crates.io](https://img.shields.io/crates/v/deps-go)](https://crates.io/crates/deps-go)
4+
[![docs.rs](https://img.shields.io/docsrs/deps-go)](https://docs.rs/deps-go)
5+
[![codecov](https://codecov.io/gh/bug-ops/deps-lsp/graph/badge.svg?token=S71PTINTGQ&flag=deps-go)](https://codecov.io/gh/bug-ops/deps-lsp)
6+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../../LICENSE)
7+
8+
Go modules support for deps-lsp.
9+
10+
This crate provides parsing and registry integration for Go's module ecosystem.
11+
12+
## Features
13+
14+
- **go.mod Parsing** — Parse `go.mod` with position tracking for all directives
15+
- **Directive Support** — Handle `require`, `replace`, `exclude`, and `retract` directives
16+
- **Indirect Dependencies** — Detect and mark indirect dependencies (`// indirect`)
17+
- **Pseudo-versions** — Parse and validate Go pseudo-version format
18+
- **proxy.golang.org** — Fetch module versions from Go module proxy
19+
- **Module Path Escaping** — Proper URL encoding for uppercase characters
20+
- **EcosystemHandler** — Implements `deps_core::EcosystemHandler` trait
21+
22+
## Usage
23+
24+
```toml
25+
[dependencies]
26+
deps-go = "0.4"
27+
```
28+
29+
```rust
30+
use deps_go::{parse_go_mod, GoRegistry};
31+
32+
let dependencies = parse_go_mod(content, &uri)?;
33+
let registry = GoRegistry::new(cache);
34+
let versions = registry.get_versions("github.com/gin-gonic/gin").await?;
35+
```
36+
37+
## Supported Directives
38+
39+
### require
40+
41+
```go
42+
require github.com/gin-gonic/gin v1.9.1
43+
require (
44+
github.com/stretchr/testify v1.8.4
45+
golang.org/x/sync v0.5.0 // indirect
46+
)
47+
```
48+
49+
### replace
50+
51+
```go
52+
replace github.com/old/module => github.com/new/module v1.0.0
53+
replace github.com/local/module => ../local/module
54+
```
55+
56+
### exclude
57+
58+
```go
59+
exclude github.com/pkg/module v1.2.3
60+
```
61+
62+
## Pseudo-version Support
63+
64+
Handles Go's pseudo-version format for unreleased commits:
65+
66+
```
67+
v0.0.0-20191109021931-daa7c04131f5
68+
```
69+
70+
Extracts base version and timestamp for display.
71+
72+
## License
73+
74+
[MIT](../../LICENSE)

0 commit comments

Comments
 (0)