Skip to main content

pakx_core/lockfile/
parse.rs

1//! Parse `agents.lock` source text into a validated [`Lockfile`].
2
3use std::path::Path;
4
5use crate::errors::LockfileError;
6
7use super::schema::{is_valid_entry_key, Lockfile, LOCKFILE_VERSION};
8
9/// Parse a JSON lockfile. If `path` is supplied, it is attached to any
10/// returned error for diagnostic display.
11pub fn parse_lockfile(source: &str, path: Option<&Path>) -> Result<Lockfile, LockfileError> {
12    let lockfile: Lockfile =
13        serde_json::from_str(source).map_err(|source| LockfileError::ParseJson {
14            source,
15            path: path.map(Path::to_path_buf),
16        })?;
17
18    if lockfile.lockfile_version != LOCKFILE_VERSION {
19        return Err(LockfileError::Schema {
20            message: format!(
21                "unsupported lockfileVersion {} (this build understands {LOCKFILE_VERSION})",
22                lockfile.lockfile_version
23            ),
24            path: path.map(Path::to_path_buf),
25        });
26    }
27
28    for key in lockfile.entries.keys() {
29        if !is_valid_entry_key(key) {
30            return Err(LockfileError::Schema {
31                message: format!("invalid entry key {key:?}: must match `<type>/<id>@<version>`"),
32                path: path.map(Path::to_path_buf),
33            });
34        }
35    }
36
37    for dep_key in lockfile.entries.values().flat_map(|e| &e.dependencies) {
38        if !is_valid_entry_key(dep_key) {
39            return Err(LockfileError::Schema {
40                message: format!(
41                    "invalid transitive dependency key {dep_key:?}: must match `<type>/<id>@<version>`"
42                ),
43                path: path.map(Path::to_path_buf),
44            });
45        }
46    }
47
48    Ok(lockfile)
49}