elm_solve_deps/lib.rs
1// SPDX-License-Identifier: MPL-2.0
2
3//! # Dependency solving for the elm ecosystem
4//!
5//! The elm-solve-deps crate provides a set of types, functions and traits
6//! to deal with dependencies in the elm ecosystem.
7//! It is based on the [pubgrub crate][pubgrub] and powers the dependency solvers
8//! of some of the tools in the elm ecosystem such as:
9//! - [elm-solve-deps]: a dedicated dependency solver executable
10//! - [elm-test-rs]: an alternative tests runner for elm
11//!
12//! [pubgrub]: https://github.com/pubgrub-rs/pubgrub
13//! [elm-solve-deps]: https://github.com/mpizenberg/elm-solve-deps
14//! [elm-test-rs]: https://github.com/mpizenberg/elm-test-rs
15//!
16//! The main objective of dependency solving is to start from
17//! a set of dependency constraints, provided for example by the `elm.json` of a package:
18//!
19//! ```json
20//! {
21//! ...,
22//! "dependencies": {
23//! "elm/core": "1.0.2 <= v < 2.0.0",
24//! "elm/http": "2.0.0 <= v < 3.0.0",
25//! "elm/json": "1.1.2 <= v < 2.0.0",
26//! },
27//! "test-dependencies": {
28//! "elm-explorations/test": "1.2.0 <= v < 2.0.0"
29//! }
30//! }
31//! ```
32//!
33//! And then find a set of package versions satisfying these constraints.
34//! In general we also want some prioritization, such as picking the newest versions compatible.
35//! In this case and at this date, without considering the test dependencies, the newest solution is:
36//!
37//! ```json
38//! {
39//! "direct": {
40//! "elm/core": "1.0.5",
41//! "elm/http": "2.0.0",
42//! "elm/json": "1.1.3"
43//! },
44//! "indirect": {
45//! "elm/bytes": "1.0.8",
46//! "elm/file": "1.0.5",
47//! "elm/time": "1.0.0"
48//! }
49//! }
50//! ```
51//!
52//! And if we also consider the tests dependencies, we get instead:
53//!
54//! ```json
55//! {
56//! "direct": {
57//! "elm/core": "1.0.5",
58//! "elm/http": "2.0.0",
59//! "elm/json": "1.1.3",
60//! "elm-explorations/test": "1.2.2"
61//! },
62//! "indirect": {
63//! "elm/bytes": "1.0.8",
64//! "elm/file": "1.0.5",
65//! "elm/html": "1.0.0",
66//! "elm/random": "1.0.0",
67//! "elm/time": "1.0.0",
68//! "elm/virtual-dom": "1.0.2"
69//! }
70//! }
71//! ```
72//!
73//! ## Simple offline dependency solver
74//!
75//! This library already provides a dependency solver ready for offline use cases.
76//! The [`solver::Offline`] struct has to be initialized with the path to `ELM_HOME`,
77//! as well as the version of elm used (concretely, this should only be `"0.19.1"` for now).
78//! Then it provides a [`solve_deps`](solver::Offline::solve_deps) function,
79//! which will either succeed and return a solution, or fail with an error.
80//!
81//! The offline solver will only ever look for packages inside `ELM_HOME` and thus
82//! should work with other "elm-compatible" ecosystems such as Lamdera.
83//! You can use it as follows.
84//!
85//! ```no_run
86//! # use elm_solve_deps::solver;
87//! # let elm_home = || "";
88//! // Define an offline solver.
89//! let offline_solver = solver::Offline::new(elm_home(), "0.19.1");
90//!
91//! // Load the project elm.json.
92//! let elm_json_str = std::fs::read_to_string("elm.json")
93//! .expect("Are you in an elm project? there was an issue loading the elm.json");
94//! let project_elm_json = serde_json::from_str(&elm_json_str)
95//! .expect("Failed to decode the elm.json");
96//!
97//! // Solve with tests dependencies.
98//! let use_test = true;
99//!
100//! // Do not add any extra additional dependency.
101//! let extras = &[];
102//!
103//! // Solve dependencies.
104//! let solution = offline_solver
105//! .solve_deps(&project_elm_json, use_test, extras)
106//! .expect("Dependency solving failed");
107//! ```
108//!
109//! Note that it is possible to provide additional package constraints,
110//! which is convenient for tooling when requiring additional packages that are not recorded
111//! directly in the original `elm.json` file.
112//!
113//! ## Online dependency solver
114//!
115//! We also provide an online solver for convenience.
116//! When initialized, it starts by updating its database of known packages.
117//! Then when solving dependencies, it works similarly than the offline solver,
118//! but with a set of packages that is the union of those existing locally,
119//! and those existing on the package server.
120//! Refer to [`solver::Online`] documentation for more info.
121//!
122//! ## Custom dependency solver
123//!
124//! Finally, if you want more control over the process of choosing dependencies,
125//! you can either use the configurable function [`solver::solve_deps_with`],
126//! or go with full customization by writing your own dependency provider
127//! and use directly the pubgrub crate.
128//!
129//! When using [`solver::solve_deps_with`], you are required to provide
130//! two functions, namely `fetch_elm_json` and `list_available_versions`,
131//! implementing the following pseudo trait bounds:
132//!
133//! ```ignore
134//! fetch_elm_json: Fn(&Pkg, SemVer) -> Result<PackageConfig, Error>
135//! list_available_versions: Fn(&Pkg) -> Result<Iterator<SemVer>, Error>
136//! ```
137//!
138//! It is up to you to figure out where to look for those config `elm.json`
139//! and how to provide the list of existing versions.
140//! Remark that the order in the versions iterator returned will correspond
141//! to the prioritization for picking versions.
142//! This means prioritizing newest or oldest versions is just a `.reverse()` on your part.
143//!
144//! ## Other helper modules
145//!
146//! In order for the different solver types to come together nicely,
147//! a bunch of helper modules are also provided by this crate.
148//!
149//! - [`project_config`]: module dealing with the serialization and deserialization of config `elm.json` files.
150//! - [`pkg_version`]: module defining the base type identifying a unique package version. It also
151//! provides a few helper types and functions to read/write to a cache in `ELM_HOME` and to fetch
152//! packages from a server following the same API than the official elm package server.
153//! - [`constraint`]: module helping with serialization and deserialization of version constraints.
154//! - [`dependency_provider`]: module with a helper implementation converting a generic dependency
155//! provider into one that is using a project `elm.json` as root.
156
157#![warn(missing_docs)]
158
159pub mod constraint;
160pub mod dependency_provider;
161pub mod pkg_version;
162pub mod project_config;
163pub mod solver;