deps-core 1.0.0

Core abstractions for deps-lsp: caching, errors, and traits
Documentation
// This crate defines the `Registry`/`Ecosystem` boxed-future trait signatures (and the
// `impl_dependency!`/`impl_version!` macros generating their `Send`-bound futures) that every
// ecosystem crate's `get_latest_matching`-style implementation coerces into; rustc's default
// recursion limit has proven occasionally insufficient to prove that bound for several such
// implementations, downgrading a previously-silent trait-solver retry into
// `recursion_depth_exceeding_limit`, which the fuzz CI job's `-D warnings` nightly build turns
// into a hard error (rust-lang/rust#159228). Same class of fix as deps-cargo (#745),
// deps-nuget (#696), deps-swift (#673), deps-composer.
#![recursion_limit = "256"]

//! Core abstractions for deps-lsp.
//!
//! This crate provides the foundational traits and utilities used across
//! all ecosystem-specific implementations (Cargo, npm, PyPI, etc.).
//!
//! # Architecture
//!
//! deps-core defines:
//! - **Traits**: `Registry`, `Version`, `Metadata`, `Ecosystem`, `ParseResult`
//! - **HTTP Cache**: Shared caching layer with ETag/Last-Modified validation
//! - **Error Types**: Unified error handling across all ecosystems
//!
//! # API stability (issue #769)
//!
//! Most public structs and enums here are `#[non_exhaustive]` so a new field or variant
//! never breaks a downstream ecosystem crate's exhaustive match or struct literal. This is a
//! per-kind decision, not one policy for both: on a **struct** with no `pub` fields,
//! `#[non_exhaustive]` is a semantic no-op (an external crate can't literal-construct or
//! destructure it either way), so such structs are deliberately left exhaustive instead. On
//! an **enum**, `#[non_exhaustive]` always forces a downstream `match` to carry a wildcard
//! arm, regardless of any variant's field visibility — each enum opts in when that forced
//! wildcard is wanted and stays exhaustive when a future variant should instead be a
//! compile error downstream; see the individual enum's own doc comment for which applies.
//!
//! A few pre-1.0 dependency types remain visible in public signatures as a deliberate
//! semver commitment rather than an oversight:
//! - [`error::SanitizedRegistryError`] implements `From<reqwest::Error>` — a `reqwest`
//!   major bump that reshapes `Error` is a breaking change for this crate too.
//! - [`parser::yaml_scalar_string`] takes `&yaml_rust2::Yaml`; `yaml_rust2` is re-exported
//!   from the crate root so callers can name the type without their own direct dependency,
//!   and a `yaml-rust2` major bump is likewise a breaking change here.
//! - `deps-gitlab-ci`'s `gitlab_version_req` (`crates/deps-gitlab-ci/src/component.rs`)
//!   returns `semver::VersionReq` directly — low risk since `semver` is unusually stable
//!   pre-1.0, but the same commitment applies.
//!
//! ## LSP type stability (issue #832)
//!
//! The `Ecosystem`, `Dependency`, `ParseResult`, and `EcosystemFormatter` trait signatures
//! — and the public `lsp_helpers` / `completion` helper functions — are typed directly
//! against `tower_lsp_server::ls_types` types (`Hover`, `Diagnostic`, `CodeAction`, and so
//! on). `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 this crate 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.
//!
//! Downstream consumers implementing [`ecosystem::Ecosystem`] should depend on the exact
//! matching `tower-lsp-server` version through the [`tower_lsp_server`] re-export rather than
//! adding their own separate direct dependency, which could otherwise drift out of sync with
//! the version `deps-core` was built against.

// #673: re-enable the three cast-safety pedantic lints the workspace allows by default
// (`Cargo.toml`'s `[workspace.lints.clippy]`), specifically for this crate — deps-core
// computes LSP offset/length/position math from parsed, attacker-influenceable input,
// where a silent truncation/sign-loss/precision-loss cast is exactly the class of bug
// this issue is about. Sites confirmed safe are individually `#[allow]`ed with a
// one-line justification, not blanket-allowed.
#![warn(
    clippy::cast_possible_truncation,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss
)]
/// HTTP response cache with `ETag`/`Last-Modified` conditional-request validation.
pub mod cache;
/// Bounded-`DashMap` capacity policies shared by [`cache`], [`github`], [`deps_dev`], and
/// [`osv`].
pub(crate) mod cache_policy;
pub mod completion;
/// Shared `#[macro_export]`ed conformance-test scaffolding (#758).
///
/// Ecosystem crates invoke these macros instead of hand-copying the same test family. Gated
/// identically to [`test_util`].
#[cfg(any(test, feature = "test-util"))]
pub mod conformance;
/// Per-document ceiling on tracked dependencies, enforced by
/// [`ecosystem::parse_manifest_blocking`] for all 14 ecosystems (#796).
pub mod dependency_cap;
pub mod deps_dev;
/// The [`ecosystem::Ecosystem`] trait: the sealed extension point every package
/// ecosystem crate implements to plug into the LSP server.
pub mod ecosystem;
/// Routes a manifest path to its owning [`ecosystem::Ecosystem`] implementation.
pub mod ecosystem_registry;
/// Unified error types (`DepsError`, `FetchFailure`) shared across ecosystems.
pub mod error;
pub mod fallback_completion;
pub mod freshness;
pub mod fs_probe;
pub mod github;
/// Shared bracket-interval version-range grammar (`[1.0,2.0)`-shaped), used by
/// `deps-maven`, `deps-gradle`, and `deps-nuget` (#821).
pub mod interval;
pub mod json_ast;
pub mod json_helpers;
pub mod licenses;
pub mod lockfile;
pub mod lsp_helpers;
pub mod macros;
pub mod mtime_cache;
pub mod net_policy;
pub mod osv;
pub mod package;
pub mod pagination;
/// Shared manifest-parsing helpers: bounded JSON/TOML/YAML nesting checks and
/// depth-limited parsing used by every ecosystem's manifest parser.
pub mod parser;
/// The [`registry::Registry`] trait: version lookup and search that every
/// ecosystem's registry client implements.
pub mod registry;
pub mod secret;
#[cfg(any(test, feature = "test-util"))]
pub mod test_util;
pub mod version_matcher;
pub mod xml_bounds;
pub mod yaml_anchor;
pub mod yaml_walk;

/// Re-export of the LSP protocol types that appear in this crate's public trait
/// signatures. `deps-core`'s version tracks `tower-lsp-server`'s: a
/// `tower-lsp-server` bump is a breaking change here, by construction. See the
/// "LSP type stability" section of this module's docs for detail.
pub use tower_lsp_server;

// Re-export commonly used types
pub use cache::{BodyLimit, CachedResponse, HttpCache};
pub use dependency_cap::{DependencyBudget, MAX_DEPENDENCIES_PER_DOCUMENT};
pub use deps_dev::{DepsDevClient, ProvenanceStatus, ScorecardSummary, SupplyChainTrustSignal};
pub use ecosystem::{
    BlockedRegistryOccurrence, BlockedSourceClass, Dependency, Ecosystem, EcosystemConfig,
    EcosystemId, LicenseSource, ParseResult, parse_manifest_blocking,
};
pub use ecosystem_registry::EcosystemRegistry;
pub use error::{DepsError, FetchFailure, Result};
pub use freshness::{
    DEFAULT_COOLDOWN_SECS, FreshnessSettings, PublishTime, format_relative_age, is_within_cooldown,
};
pub use json_ast::{JsonAst, JsonSection, find_last_prop};
pub use json_helpers::string_valued_entries;
pub use licenses::{
    LicensePolicy, LicenseViolation, MAX_POM_LICENSE_NAME_RAW_CHARS, ViolationReason,
    evaluate as evaluate_license_policy, resolve_license_entries,
};
pub use lockfile::{
    LockFileProvider, ResolvedPackage, ResolvedPackages, ResolvedSource, read_and_parse_lockfile,
    read_lockfile_content,
};
pub use lsp_helpers::{
    DependencyOutcome, DependencyOutcomes, DiagnosticMessages, DiagnosticPolicy,
    DiagnosticSeverities, EcosystemFormatter, HOVER_RECENT_VERSIONS,
    LICENSE_POLICY_VIOLATION_DIAGNOSTIC_CODE, LineOffsetTable, OsvNaming, PackageNaming,
    PackageRendering, PackageVersions, RequirementMatcher, RequirementResolution,
    RequirementStatus, SourcePolicy, UNSATISFIABLE_DIAGNOSTIC_CODE, VersionData,
    collect_update_all_edits, generate_code_actions as lsp_generate_code_actions,
    generate_code_lenses as lsp_generate_code_lenses, generate_hover as lsp_generate_hover,
    generate_inlay_hints as lsp_generate_inlay_hints, is_dot_segment,
    is_safe_maven_coordinate_segment, is_safe_package_name, is_safe_registry_url,
    is_safe_version_string, is_same_major_minor, maven_coordinate_path, position_in_range,
    requirement_is_unsatisfiable, warn_rejected_value,
};
pub use mtime_cache::{DEFAULT_MAX_CACHED_FILES, MAX_CACHED_FILE_BYTES, MtimeFileCache};
pub use package::{ConcreteVersion, InvalidPackageName, PackageName, VersionReq};
pub use parser::{
    DependencySource, LoadingState, MAX_JSON_NESTING_DEPTH, MAX_TOML_NESTING_DEPTH,
    MAX_YAML_EXPANDED_BYTES, MAX_YAML_NESTING_DEPTH, check_json_nesting_depth,
    check_toml_nesting_depth, check_yaml_expansion, check_yaml_nesting_depth,
    json_depth_error_message, parse_json_checked, yaml_scalar_string,
};
pub use registry::{
    Deprecation, Metadata, Registry, RemovalStatus, Version, classify_default_registry_url,
    existence_wildcard_req, find_latest_stable, has_default_prerelease_marker, hash_routing_key,
    is_existence_wildcard, is_existence_wildcard_str, not_found_or, select_latest_for_existence,
};
pub use version_matcher::{
    Pep440Matcher, SemverMatcher, VersionRequirementMatcher, extract_pypi_min_version,
    normalize_and_parse_version, normalize_operator_spacing,
};

/// Re-exported so a caller of [`yaml_scalar_string`] can name `yaml_rust2::Yaml` without
/// depending on `yaml-rust2` directly — see the "API stability" section above for the
/// semver implication of this pre-1.0 dependency coupling.
pub use yaml_rust2;

/// Re-exported so a caller of [`error::SanitizedRegistryError`]'s `From<reqwest::Error>`
/// impl can name `reqwest::Error` without depending on `reqwest` directly — see the "API
/// stability" section above for the semver implication of this pre-1.0 dependency coupling.
pub use reqwest;