#[cfg(feature = "rspc")]
use rspc::Type;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::model::PartialRequest;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "rspc", derive(Type))]
#[derive(Error, Debug, PartialEq, Eq, Clone)]
pub enum ParseError {
#[error("Could not read the file: '{0}'.")]
CouldNotReadRequestFile(PathBuf),
#[error("Invalid comment start characters: '{0}', comments before the request url should start with '//', '#' or '###'.")]
InvalidCommentStart(String),
#[error("Invalid request URL found: '{0}'. The URL should either be in the form of an URL using host with optional schemes 'http://', 'https://' or it should be a relative url starting with a slash and the 'Host:' header defined.")]
InvalidRequestUrl(String),
#[error("The HTTP version: '{0}' is not valid. A valid HTTP version requires format: 'HTTP/\\d+.\\d+' or 'HTTP/\\d+'.\nFor example 'HTTP/2.1'. You can also omit the version and only specify the url target of the request or the HTTP method and the url target.")]
InvalidHttpVersion(String),
#[error("Expected either a prerequest script within '{{% %}}' blocks or a filepath to a pre-request script after matching '<' character.")]
MissingPreRequestScript,
#[error("A pre-request script should be ended with '%}}' characters but none were found.")]
MissingPreRequestScriptClose,
#[error("Missing request target line.")]
MissingRequestTargetLine,
#[error("The request target line containing the url for the request contains too many elements. There should only be a method, the URL and HTTP version. You have additional elements: {0}")]
TooManyElementsOnRequestLine(String),
#[error("Expected header in the form of '<Key>: <Value>'. Found line: {0}")]
InvalidHeaderField(String),
#[error("Missing multipart boundary in 'Content-Type' for 'multipart/form-data'. Using default boundary '{0}' instead.")]
MissingMultipartHeaderBoundaryDefinition(String),
#[error("Within multipart body expected either a new boundary starting with '{next_boundary}' or finishing a multipart with '{end_boundary}' but none were found.")]
MissingMultipartBoundary {
next_boundary: String,
end_boundary: String,
},
#[error("Multipart requires a first starting boundary before any content.")]
MissingMultipartStartingBoundary,
#[error("Could not parse the headers of the given part of a multipart body. Error during parsing: {error_msg}.")]
InvalidSingleMultipartHeaders {
header_parse_err: Box<ParseError>,
error_msg: String,
},
#[error("Missing 'Content-Disposition' header of the multipart part.")]
MissingSingleMultipartContentDispositionHeader,
#[error("First header of a multipart part should be the 'Content-Disposition' header, found '{0}' instead.")]
WrongMultipartContentDispositionHeader(String),
#[error("Multipart Content-Disposition should have type 'form-data', found: {0}.")]
InvalidMultipartContentDispositionFormData(String),
#[error("Expected content disposition values in form <key>=<value> or <key>=\"<value>\" but found: '{0}'")]
MalformedContentDispositionEntries(String),
#[error("Requires empty line in single multipart after Content-Disposition and other headers before the body begins!")]
SingleMultipartMissingEmptyLine,
#[error("Multipart should be ended with boundary '{0}'. End of file encountered instead.")]
MultipartShouldBeEndedWithBoundary(String),
#[error("Boundary within multipart content type is required to be 1-70 characters long.")]
InvalidMultipartBoundaryLength,
#[error("Invalid character: '{0}' found in multipart boundary.")]
InvalidMultipartBoundaryCharacter(String),
#[error("Content disposition header of a multipart (multipart/formdata) requires a name field, found only {0}")]
SingleMultipartNameMissing(String),
#[error("Expected closing '%}}' characters for response handler when opened with '{{%', response handler script is malformed.")]
MissingResponseHandlerClose,
#[error("Missing filepath for response after redirecting file using '>>', or '>>!'")]
MissingResponseOutputPath,
#[error("Could not import collection")]
ImportCollectionError,
#[error("unknown parse error")]
Unknown,
}
#[derive(Debug, PartialEq, Clone)]
pub struct ParseErrorDetails {
pub error: ParseError,
pub details: Option<String>,
pub start_pos: Option<usize>,
pub end_pos: Option<usize>,
}
impl Default for ParseErrorDetails {
fn default() -> Self {
ParseErrorDetails {
error: ParseError::Unknown,
details: None,
start_pos: None,
end_pos: None,
}
}
}
impl ParseErrorDetails {
pub fn new_with_position(error: ParseError, position: (usize, Option<usize>)) -> Self {
ParseErrorDetails {
error,
details: None,
start_pos: Some(position.0),
end_pos: position.1,
}
}
}
impl From<ParseError> for ParseErrorDetails {
fn from(parse_error: ParseError) -> Self {
ParseErrorDetails {
error: parse_error,
..Default::default()
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Error, Debug, PartialEq, Eq)]
pub enum SerializeError {
#[error("IoError occurred during serialization: {0}")]
IoError(String),
}
#[derive(Debug, PartialEq)]
pub struct ErrorWithPartial {
pub partial_request: PartialRequest,
pub details: Vec<ParseErrorDetails>,
}