fhttp_core/request_sources/
mod.rs

1use std::hash::Hash;
2use std::marker::PhantomData;
3use std::path::Path;
4#[cfg(test)]
5use std::path::PathBuf;
6
7use crate::parsers::{parse_gql_str, parse_str};
8use crate::path_utils::{canonicalize, CanonicalizedPathBuf, RelativePath};
9use crate::preprocessing::dependant::{request_dependencies, Dependant};
10use crate::request_sources::request_dependency_eval::RequestDependencyEval;
11use crate::request_sources::request_wrapper::RequestWrapper;
12use crate::request_sources::structured_request_source::{
13    parse_request_from_json, parse_request_from_yaml,
14};
15use crate::{Config, Profile, ResponseStore};
16use anyhow::Result;
17use file_includes::load_file_recursively;
18use variable_support::replace_evals;
19
20pub mod file_includes;
21pub mod request_dependency_eval;
22pub mod request_wrapper;
23pub mod structured_request_source;
24pub mod variable_support;
25
26#[derive(Debug, Eq, PartialEq)]
27pub struct Raw;
28#[derive(Debug, Eq, PartialEq)]
29pub struct Preprocessed;
30
31#[derive(Debug, Eq)]
32pub struct RequestSource<State = Raw> {
33    state: PhantomData<State>,
34    pub source_path: CanonicalizedPathBuf,
35    pub text: String,
36    pub dependency: bool,
37}
38
39impl<State> RequestSource<State> {
40    pub fn from_file<P: AsRef<Path>>(path: P, dependency: bool) -> Result<Self> {
41        let path = canonicalize(path.as_ref())?;
42        let content = load_file_recursively(&path)?;
43
44        Self::_new(path, content, dependency)
45    }
46
47    #[cfg(test)]
48    pub fn new<P: Into<PathBuf>, T: Into<String>>(path: P, text: T) -> Result<Self> {
49        let path = canonicalize(&path.into())?;
50        RequestSource::_new(path, text, false)
51    }
52
53    fn _new<S: Into<String>>(
54        path: CanonicalizedPathBuf,
55        text: S,
56        dependency: bool,
57    ) -> Result<Self> {
58        let ret = RequestSource {
59            state: PhantomData,
60            source_path: path,
61            text: text.into(),
62            dependency,
63        };
64
65        Ok(ret)
66    }
67
68    pub fn unescaped_dependency_paths(&self) -> Result<Vec<CanonicalizedPathBuf>> {
69        self.unescaped_dependencies()?
70            .into_iter()
71            .map(|dep| self.get_dependency_path(dep.path))
72            .collect()
73    }
74}
75
76impl RequestSource<Raw> {
77    pub fn replace_variables(
78        self,
79        profile: &Profile,
80        config: &Config,
81        response_store: &ResponseStore,
82    ) -> Result<RequestSource<Preprocessed>> {
83        let new_text = replace_evals(
84            self.text,
85            &self.source_path,
86            self.dependency,
87            profile,
88            config,
89            response_store,
90        )?;
91
92        Ok(RequestSource {
93            text: new_text,
94            state: PhantomData,
95            source_path: self.source_path,
96            dependency: self.dependency,
97        })
98    }
99}
100
101impl RequestSource<Preprocessed> {
102    pub fn parse(self) -> Result<RequestWrapper> {
103        let path = self.source_path.to_str().to_lowercase();
104        let request = if path.ends_with(".gql.http") || path.ends_with(".graphql.http") {
105            parse_gql_str(&self.text)?
106        } else if path.ends_with(".json") {
107            parse_request_from_json(&self.source_path, &self.text)?
108        } else if path.ends_with(".yaml") || path.ends_with(".yml") {
109            parse_request_from_yaml(&self.source_path, &self.text)?
110        } else {
111            parse_str(&self.source_path, &self.text)?
112        };
113
114        Ok(RequestWrapper {
115            source_path: self.source_path,
116            request,
117        })
118    }
119}
120
121impl<T> Dependant for RequestSource<T> {
122    fn dependencies(&self) -> Result<Vec<RequestDependencyEval>> {
123        request_dependencies(&self.text)
124    }
125}
126
127impl<T> AsRef<Path> for RequestSource<T> {
128    fn as_ref(&self) -> &Path {
129        self.source_path.as_ref()
130    }
131}
132
133impl<T> PartialEq for RequestSource<T> {
134    fn eq(&self, other: &Self) -> bool {
135        self.source_path == other.source_path
136    }
137}
138
139impl Hash for RequestSource {
140    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
141        self.source_path.hash(state);
142    }
143}