pray-core 1.22.0

Core library for Prayfile, the package manager for the language placed before inference
Documentation
use super::call::{parse_call, string_from_value};
use super::decls::parse_package_decl;
use super::BlockParser;
use crate::publish_remote::ManifestPublishRemote;
use crate::{PrayError, PrayResult};

impl BlockParser<'_> {
    pub(super) fn apply_publish_statement(
        &mut self,
        remotes: &mut Vec<ManifestPublishRemote>,
        rest: &str,
    ) -> PrayResult<()> {
        let is_block = rest.trim_end().ends_with(" do");
        let header = rest.trim_end().strip_suffix(" do").unwrap_or(rest).trim();
        let mut remote = parse_publish_header(header)?;
        if is_block {
            self.parse_publish_block(&mut remote)?;
        }
        remotes.push(remote);
        Ok(())
    }

    fn parse_publish_block(&mut self, remote: &mut ManifestPublishRemote) -> PrayResult<()> {
        while let Some(statement) = self.next_statement()? {
            if statement == "end" {
                return Ok(());
            }
            let Some(pray_rest) = statement
                .strip_prefix("pray ")
                .or_else(|| statement.strip_prefix("use "))
                .or_else(|| statement.strip_prefix("include "))
                .or_else(|| statement.strip_prefix("agent "))
                .or_else(|| statement.strip_prefix("package "))
            else {
                return Err(PrayError::Parse {
                    kind: "manifest",
                    message: format!("publish blocks only support pray package names: {statement}"),
                });
            };
            let package = parse_package_decl(pray_rest)?;
            if remote.packages.iter().any(|name| name == &package.name) {
                return Err(PrayError::Parse {
                    kind: "manifest",
                    message: format!(
                        "duplicate package {} in publish \"{}\"",
                        package.name, remote.name
                    ),
                });
            }
            remote.packages.push(package.name);
        }
        Err(PrayError::Parse {
            kind: "manifest",
            message: "missing 'end' for publish block".to_string(),
        })
    }
}

pub(super) fn parse_publish_header(rest: &str) -> PrayResult<ManifestPublishRemote> {
    let (values, keywords) = parse_call(rest)?;
    if values.is_empty() {
        return Err(PrayError::Parse {
            kind: "manifest",
            message: "publish requires a name".to_string(),
        });
    }
    let name = string_from_value(&values[0])?;
    let path = keywords.get("path").map(string_from_value).transpose()?;
    let url = if let Some(value) = values.get(1) {
        Some(string_from_value(value)?)
    } else {
        None
    };
    if keywords.contains_key("git")
        || keywords.contains_key("source")
        || keywords.contains_key("signing_key")
        || keywords.contains_key("token")
    {
        return Err(PrayError::Parse {
            kind: "manifest",
            message: format!(
                "publish \"{name}\" does not take git:, source:, signing_key:, or token:"
            ),
        });
    }
    Ok(ManifestPublishRemote {
        name,
        path,
        url,
        packages: Vec::new(),
    })
}