fhttp-core 2.1.0

core library for the fhttp tool
Documentation
use std::hash::Hash;
use std::marker::PhantomData;
use std::path::Path;
#[cfg(test)]
use std::path::PathBuf;

use crate::parsers::{parse_gql_str, parse_str};
use crate::path_utils::{canonicalize, CanonicalizedPathBuf, RelativePath};
use crate::preprocessing::dependant::{request_dependencies, Dependant};
use crate::request_sources::request_dependency_eval::RequestDependencyEval;
use crate::request_sources::request_wrapper::RequestWrapper;
use crate::request_sources::structured_request_source::{
    parse_request_from_json, parse_request_from_yaml,
};
use crate::{Config, Profile, ResponseStore};
use anyhow::Result;
use file_includes::load_file_recursively;
use variable_support::replace_evals;

pub mod file_includes;
pub mod request_dependency_eval;
pub mod request_wrapper;
pub mod structured_request_source;
pub mod variable_support;

#[derive(Debug, Eq, PartialEq)]
pub struct Raw;
#[derive(Debug, Eq, PartialEq)]
pub struct Preprocessed;

#[derive(Debug, Eq)]
pub struct RequestSource<State = Raw> {
    state: PhantomData<State>,
    pub source_path: CanonicalizedPathBuf,
    pub text: String,
    pub dependency: bool,
}

impl<State> RequestSource<State> {
    pub fn from_file<P: AsRef<Path>>(path: P, dependency: bool) -> Result<Self> {
        let path = canonicalize(path.as_ref())?;
        let content = load_file_recursively(&path)?;

        Self::_new(path, content, dependency)
    }

    #[cfg(test)]
    pub fn new<P: Into<PathBuf>, T: Into<String>>(path: P, text: T) -> Result<Self> {
        let path = canonicalize(&path.into())?;
        RequestSource::_new(path, text, false)
    }

    fn _new<S: Into<String>>(
        path: CanonicalizedPathBuf,
        text: S,
        dependency: bool,
    ) -> Result<Self> {
        let ret = RequestSource {
            state: PhantomData,
            source_path: path,
            text: text.into(),
            dependency,
        };

        Ok(ret)
    }

    pub fn unescaped_dependency_paths(&self) -> Result<Vec<CanonicalizedPathBuf>> {
        self.unescaped_dependencies()?
            .into_iter()
            .map(|dep| self.get_dependency_path(dep.path))
            .collect()
    }
}

impl RequestSource<Raw> {
    pub fn replace_variables(
        self,
        profile: &Profile,
        config: &Config,
        response_store: &ResponseStore,
    ) -> Result<RequestSource<Preprocessed>> {
        let new_text = replace_evals(
            self.text,
            &self.source_path,
            self.dependency,
            profile,
            config,
            response_store,
        )?;

        Ok(RequestSource {
            text: new_text,
            state: PhantomData,
            source_path: self.source_path,
            dependency: self.dependency,
        })
    }
}

impl RequestSource<Preprocessed> {
    pub fn parse(self) -> Result<RequestWrapper> {
        let path = self.source_path.to_str().to_lowercase();
        let request = if path.ends_with(".gql.http") || path.ends_with(".graphql.http") {
            parse_gql_str(&self.text)?
        } else if path.ends_with(".json") {
            parse_request_from_json(&self.source_path, &self.text)?
        } else if path.ends_with(".yaml") || path.ends_with(".yml") {
            parse_request_from_yaml(&self.source_path, &self.text)?
        } else {
            parse_str(&self.source_path, &self.text)?
        };

        Ok(RequestWrapper {
            source_path: self.source_path,
            request,
        })
    }
}

impl<T> Dependant for RequestSource<T> {
    fn dependencies(&self) -> Result<Vec<RequestDependencyEval>> {
        request_dependencies(&self.text)
    }
}

impl<T> AsRef<Path> for RequestSource<T> {
    fn as_ref(&self) -> &Path {
        self.source_path.as_ref()
    }
}

impl<T> PartialEq for RequestSource<T> {
    fn eq(&self, other: &Self) -> bool {
        self.source_path == other.source_path
    }
}

impl Hash for RequestSource {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.source_path.hash(state);
    }
}