fhttp_core/request_sources/
mod.rs1use 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}