deps-core 1.2.0

Core abstractions for deps-lsp: caching, errors, and traits
Documentation

deps-core

Crates.io docs.rs CI codecov License: MIT

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

This crate provides the shared infrastructure used by all ecosystem-specific crates in the deps-lsp workspace. Every ecosystem crate depends on deps-core and implements its Ecosystem trait.

What this crate provides

  • Ecosystem trait — Unified interface for all package ecosystems (parse, registry, format)
  • EcosystemId enum — Exhaustive, typed identifier for every registered ecosystem, with Display/FromStr interop with Ecosystem::id(). Downstream code should match on this instead of the raw id string so a new ecosystem forces every relevant match to be updated at compile time
  • PackageName/VersionReq newtypes — Distinguish a manifest package name from a version requirement string at the type level, threaded through Registry, Ecosystem, and EcosystemFormatter so the two cannot be swapped at a call site
  • Registry trait — Abstraction over package registries with version lookup
  • freshness module — Release-freshness signal (PublishTime, FreshnessSettings, is_within_cooldown) flagging a "latest" version still inside its cooldown window, mirroring GitHub Dependabot's default 3-day package cooldown
  • LockFileProvider trait — Abstract lock file parsing for resolved versions
  • Generic LSP handlers — generate_inlay_hints, generate_hover, generate_code_actions, generate_diagnostics_from_cache, generate_code_lenses, taking a bundled VersionData (cached + resolved version maps) to avoid swapping same-typed arguments at call sites
  • collect_update_all_edits — batch TextEdits bringing every safely-editable outdated dependency to latest, shared across all ecosystems; guards against rewriting a version_range that isn't actually the version literal (property references, DSL variables, catalog aliases, synthesized range bounds)
  • HttpCache — ETag/Last-Modified caching for registry HTTP requests, with a streaming 32 MiB response-size cap
  • osv::OsvClient — batches dependency versions against the OSV.dev vulnerability database (POST /v1/querybatch), resolves matching advisories, and caches both queries and records independently of HttpCache (OSV sends no cache validators). EcosystemId::osv_ecosystem() and EcosystemFormatter::osv_package_name() provide the per-ecosystem mapping
  • check_toml_nesting_depth — single-pass structural guard rejecting pathologically nested TOML (bracket depth and dotted-key/header segment count) before it reaches the recursive-descent toml_span parser
  • check_yaml_nesting_depth — single-pass structural guard rejecting pathologically nested YAML (flow bracket depth and block-style indentation/dash-chain nesting) before it reaches the recursive-descent yaml-rust2 parser
  • check_yaml_expansion — streaming pre-pass over yaml-rust2's own parser event stream rejecting YAML whose anchor/alias references would expand to an excessive number of allocated bytes (billion-laughs-style), independent of nesting depth
  • lockfile::read_lockfile_content — shared read-and-error-wrap helper for lock file parsers
  • deps_dev::DepsDevClient — supply-chain trust signal client for the deps.dev API, resolving a dependency's linked source repository, OpenSSF Scorecard score, and SLSA/attestation provenance status (SupplyChainTrustSignal, ScorecardSummary, ProvenanceStatus)
  • licenses::LicensePolicy — SPDX allow/deny-list evaluation shared by every ecosystem's license_policy diagnostic, plus Ecosystem::fetch_license/license_source() sealed-trait hooks for tier-3 ecosystems whose license isn't already present in the hot-path registry response
  • diagnostic::Diagnostic/RelatedInformation — sanitize and cap their message/code text at construction (control characters, bidi/invisible-character overrides, unbounded length), exposed only through message()/code() getters so no caller can bypass the sanitization after the fact
  • net_policy::redact_parse_error_for_log — redacts credential-shaped substrings from a parser error before it reaches logs or an LSP-visible diagnostic
  • rate_limit::RateLimitGate — process-lifetime cooldown gate shared by ecosystem registry clients to stop hammering an upstream once it has rate-limited or auth-rejected a request
  • Error types — Unified error handling with thiserror

Installation

[dependencies]
deps-core = "1.2"

[!IMPORTANT] Requires Rust 1.98 or later.

Implementing a new ecosystem

use deps_core::{Ecosystem, Registry, ParseResult};

pub struct MyEcosystem {
    registry: Arc<MyRegistry>,
}

impl Ecosystem for MyEcosystem {
    fn ecosystem_id(&self) -> deps_core::EcosystemId { deps_core::EcosystemId::Cargo }
    fn display_name(&self) -> &'static str { "My Ecosystem" }

    fn matches_uri(&self, uri: &Uri) -> bool {
        uri.path().ends_with("my-manifest.json")
    }

    async fn parse_manifest(&self, content: &str, uri: &Uri) -> Result<ParseResult> {
        // Parse the manifest and return dependencies with source positions
        todo!()
    }
}

Versioning

deps-core's public trait signatures (Ecosystem, Dependency, ParseResult, EcosystemFormatter) — and its public lsp_helpers / completion helper functions — are typed directly against tower_lsp_server::ls_types types. tower-lsp-server is pinned pre-1.0, so a tower-lsp-server minor bump (e.g. 0.23 → 0.24) is not an implementation detail deps-core can absorb silently — it forces a breaking release of deps-core: a minor version bump while deps-core itself remains pre-1.0, a major version bump once deps-core reaches 1.0.

If you implement Ecosystem outside this workspace, depend on the exact matching tower-lsp-server version via deps_core::tower_lsp_server rather than adding your own separate direct dependency on tower-lsp-server, to avoid it drifting out of sync with the version deps-core was built against.

License

MIT