diff --git a/.travis.yml b/.travis.yml index 4c9c0e9c4..b842378b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ jobs: os: linux dist: bionic before_script: - - export VERSION=$(grep '^version' Cargo.toml | cut -f2 -d'"') + - export VERSION=$(grep '^version' packages/hurl/Cargo.toml | cut -f2 -d'"') - sudo apt install -y libcurl4-openssl-dev script: - ci/man.sh @@ -39,7 +39,7 @@ jobs: os: osx before_script: - brew install jq - - export VERSION=$(grep '^version' Cargo.toml | cut -f2 -d'"') + - export VERSION=$(grep '^version' packages/hurl/Cargo.toml | cut -f2 -d'"') script: - ci/man.sh - ci/release.sh diff --git a/packages/hurlfmt/src/format/color.rs b/packages/hurl/src/cli/color.rs similarity index 99% rename from packages/hurlfmt/src/format/color.rs rename to packages/hurl/src/cli/color.rs index 79b70cf29..25ac7da7b 100644 --- a/packages/hurlfmt/src/format/color.rs +++ b/packages/hurl/src/cli/color.rs @@ -15,6 +15,8 @@ * limitations under the License. * */ + +#[allow(unused)] pub enum TerminalColor { Black, Red, diff --git a/packages/hurl/src/cli/logger.rs b/packages/hurl/src/cli/logger.rs index 73ef3e28d..e4a0da0a5 100644 --- a/packages/hurl/src/cli/logger.rs +++ b/packages/hurl/src/cli/logger.rs @@ -16,9 +16,11 @@ * */ -use super::error::Error; -use crate::format::TerminalColor; use crate::runner; + +use super::color::TerminalColor; + +use hurl_core::error::Error; use hurl_core::parser; pub fn make_logger_verbose(verbose: bool) -> impl Fn(&str) { diff --git a/packages/hurl/src/cli/mod.rs b/packages/hurl/src/cli/mod.rs index 7c5abacc2..17d586bdd 100644 --- a/packages/hurl/src/cli/mod.rs +++ b/packages/hurl/src/cli/mod.rs @@ -16,14 +16,10 @@ * */ -pub use self::error::Error; pub use self::logger::{ log_info, make_logger_error_message, make_logger_parser_error, make_logger_runner_error, make_logger_verbose, }; -pub use self::options::cookies_output_file; -pub use self::options::CLIError; -mod error; +mod color; mod logger; -mod options; diff --git a/packages/hurl/src/cli/options.rs b/packages/hurl/src/cli/options.rs deleted file mode 100644 index 8079a7825..000000000 --- a/packages/hurl/src/cli/options.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -pub struct CLIError { - pub message: String, -} - -pub fn cookies_output_file(filename: String, n: usize) -> Result { - if n > 1 { - Err(CLIError { - message: "Only save cookies for a unique session".to_string(), - }) - } else { - let path = std::path::Path::new(&filename); - Ok(path.to_path_buf()) - } -} diff --git a/packages/hurl/src/format/html.rs b/packages/hurl/src/format/html.rs deleted file mode 100644 index 3719c3a81..000000000 --- a/packages/hurl/src/format/html.rs +++ /dev/null @@ -1,571 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -use hurl_core::ast::*; - -pub trait Htmlable { - fn to_html(&self) -> String; -} - -pub fn format_standalone(hurl_file: HurlFile) -> String { - let css = include_str!("hurl.css"); - - let mut buffer = String::from(""); - buffer.push_str("\n"); - buffer.push_str(""); - buffer.push_str(""); - buffer.push_str("Hurl File"); - buffer.push_str(""); - buffer.push_str(""); - buffer.push_str("\n"); - buffer.push_str(hurl_file.to_html().as_str()); - buffer.push_str("\n"); - buffer.push_str(""); - buffer -} - -pub fn format(hurl_file: HurlFile, standalone: bool) -> String { - if standalone { - format_standalone(hurl_file) - } else { - hurl_file.to_html() - } -} - -impl Htmlable for HurlFile { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str("
"); - for entry in self.clone().entries { - buffer.push_str(entry.to_html().as_str()); - } - for line_terminator in self.line_terminators.clone() { - buffer.push_str(line_terminator.to_html().as_str()); - } - buffer.push_str("
"); - buffer - } -} - -impl Htmlable for Entry { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str("
"); - buffer.push_str(self.request.to_html().as_str()); - if let Some(response) = self.clone().response { - buffer.push_str(response.to_html().as_str()); - } - buffer.push_str("
"); - buffer - } -} - -impl Htmlable for Request { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str("
"); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.method.to_html().as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer.push_str(self.url.to_html().as_str()); - buffer.push_str(self.line_terminator0.to_html().as_str()); - buffer.push_str(""); - buffer.push_str("
"); - for header in self.headers.clone() { - buffer.push_str(header.to_html().as_str()); - } - for section in self.sections.clone() { - buffer.push_str(section.to_html().as_str()); - } - buffer - } -} - -impl Htmlable for Response { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str("
"); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.version.to_html().as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer.push_str(self.status.to_html().as_str()); - buffer.push_str(""); - for section in self.sections.clone() { - buffer.push_str(section.to_html().as_str()); - } - buffer.push_str("
"); - buffer - } -} - -impl Htmlable for Method { - fn to_html(&self) -> String { - return format!("{}", self.as_str()); - } -} - -impl Htmlable for Version { - fn to_html(&self) -> String { - return format!( - "HTTP/{}", - self.value.as_str() - ); - } -} - -impl Htmlable for Status { - fn to_html(&self) -> String { - format!("{}", self.value.to_string()) - } -} - -impl Htmlable for Section { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(self.space0.to_html().as_str()); - - buffer - .push_str(format!("[{}]", self.name()).as_str()); - buffer.push_str(""); - buffer.push_str(self.value.to_html().as_str()); - buffer - } -} - -impl Htmlable for SectionValue { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - match self { - SectionValue::Asserts(items) => { - for item in items { - buffer.push_str(item.to_html().as_str()) - } - } - SectionValue::QueryParams(items) => { - for item in items { - buffer.push_str(item.to_html().as_str()) - } - } - SectionValue::FormParams(items) => { - for item in items { - buffer.push_str(item.to_html().as_str()) - } - } - SectionValue::MultipartFormData(items) => { - for item in items { - buffer.push_str(item.to_html().as_str()) - } - } - SectionValue::Cookies(items) => { - for item in items { - buffer.push_str(item.to_html().as_str()) - } - } - SectionValue::Captures(items) => { - for item in items { - buffer.push_str(item.to_html().as_str()) - } - } - } - buffer - } -} - -impl Htmlable for KeyValue { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.key.to_html().as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer.push_str(":"); - buffer.push_str(self.space2.to_html().as_str()); - buffer.push_str(self.value.to_html().as_str()); - buffer.push_str(self.line_terminator0.to_html().as_str()); - buffer.push_str(""); - buffer - } -} - -impl Htmlable for MultipartParam { - fn to_html(&self) -> String { - match self { - MultipartParam::Param(keyvalue) => keyvalue.to_html(), - MultipartParam::FileParam(file_param) => file_param.to_html(), - } - } -} - -impl Htmlable for FileParam { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.key.to_html().as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer.push_str(":"); - buffer.push_str(self.space2.to_html().as_str()); - buffer.push_str(self.value.to_html().as_str()); - buffer.push_str(self.line_terminator0.to_html().as_str()); - buffer.push_str(""); - buffer - } -} - -impl Htmlable for FileValue { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer - } -} - -impl Htmlable for Cookie { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.name.value.as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer.push_str(":"); - buffer.push_str(self.space2.to_html().as_str()); - buffer.push_str(self.value.to_html().as_str()); - buffer.push_str(self.line_terminator0.to_html().as_str()); - buffer.push_str(""); - buffer - } -} - -impl Htmlable for CookieValue { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str(self.value.as_str()); - buffer - } -} - -impl Htmlable for Capture { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.name.value.as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer.push_str(":"); - buffer.push_str(self.space2.to_html().as_str()); - buffer.push_str(self.query.to_html().as_str()); - buffer.push_str(self.line_terminator0.to_html().as_str()); - buffer.push_str(""); - buffer - } -} - -impl Htmlable for Query { - fn to_html(&self) -> String { - self.value.to_html() - } -} - -impl Htmlable for QueryValue { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - match self { - QueryValue::Status {} => { - buffer.push_str("status"); - } - QueryValue::Header { space0, name } => { - buffer.push_str("header"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(name.to_html().as_str()); - } - QueryValue::Cookie { space0, expr } => { - buffer.push_str("cookie"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(expr.to_html().as_str()); - } - QueryValue::Body {} => { - buffer.push_str("status"); - } - QueryValue::Xpath { space0, expr } => { - buffer.push_str("xpath"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(expr.to_html().as_str()); - } - QueryValue::Jsonpath { space0, expr } => { - buffer.push_str("jsonpath"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(expr.to_html().as_str()); - } - QueryValue::Regex { space0, expr } => { - buffer.push_str("regex"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(expr.to_html().as_str()); - } - QueryValue::Variable { space0, name } => { - buffer.push_str("variable"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(name.to_html().as_str()); - } - } - - buffer - } -} - -impl Htmlable for CookiePath { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str(self.name.to_html().as_str()); - if let Some(attribute) = self.attribute.clone() { - buffer.push_str(attribute.to_html().as_str()); - } - buffer - } -} - -impl Htmlable for CookieAttribute { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.name.value().as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer - } -} - -impl Htmlable for Assert { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - add_line_terminators(&mut buffer, self.line_terminators.clone()); - buffer.push_str(""); - buffer.push_str(self.space0.to_html().as_str()); - buffer.push_str(self.query.to_html().as_str()); - buffer.push_str(self.space1.to_html().as_str()); - buffer.push_str(self.predicate.to_html().as_str()); - buffer.push_str(""); - buffer.push_str(self.line_terminator0.to_html().as_str()); - buffer - } -} - -impl Htmlable for Predicate { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - if self.not { - buffer.push_str("not"); - buffer.push_str(self.space0.to_html().as_str()); - } - buffer.push_str(self.predicate_func.to_html().as_str()); - buffer - } -} - -impl Htmlable for PredicateFunc { - fn to_html(&self) -> String { - self.value.to_html() - } -} - -impl Htmlable for PredicateFuncValue { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - match self { - PredicateFuncValue::CountEqual { space0, value } => { - buffer.push_str("equals"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(format!("{}", value).as_str()); - } - PredicateFuncValue::EqualString { space0, value } => { - buffer.push_str("equals"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str( - format!("{}", value.to_html()).as_str(), - ); - } - PredicateFuncValue::EqualInt { space0, value } => { - buffer.push_str("equals"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(format!("{}", value).as_str()); - } - PredicateFuncValue::EqualFloat { space0, value } => { - buffer.push_str("equals"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str( - format!("{}", value.to_string()).as_str(), - ); - } - PredicateFuncValue::EqualExpression { space0, value } => { - buffer.push_str("equals"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(value.to_html().as_str()); - } - PredicateFuncValue::StartWith { space0, value } => { - buffer.push_str("startsWith"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str( - format!("{}", value.to_html()).as_str(), - ); - } - PredicateFuncValue::Contain { space0, value } => { - buffer.push_str("contains"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str( - format!("{}", value.to_html()).as_str(), - ); - } - PredicateFuncValue::IncludeString { space0, value } => { - buffer.push_str("includes"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str( - format!("{}", value.to_html()).as_str(), - ); - } - PredicateFuncValue::IncludeInt { space0, value } => { - buffer.push_str("includes"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(format!("{}", value).as_str()); - } - PredicateFuncValue::IncludeNull { space0 } => { - buffer.push_str("includes"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str("null"); - } - PredicateFuncValue::IncludeBool { space0, value } => { - buffer.push_str("includes"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(format!("{}", value).as_str()); - } - PredicateFuncValue::IncludeFloat { space0, value } => { - buffer.push_str("includes"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str( - format!("{}", value.to_string()).as_str(), - ); - } - PredicateFuncValue::IncludeExpression { space0, value } => { - buffer.push_str("includes"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(value.to_html().as_str()); - } - PredicateFuncValue::Match { space0, value } => { - buffer.push_str("matches"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str( - format!("{}", value.to_html()).as_str(), - ); - } - PredicateFuncValue::EqualNull { space0 } => { - buffer.push_str("equals"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str("null"); - } - PredicateFuncValue::EqualBool { space0, value } => { - buffer.push_str("equals"); - buffer.push_str(space0.to_html().as_str()); - buffer.push_str(format!("{}", value).as_str()); - } - PredicateFuncValue::Exist {} => { - buffer.push_str("exists"); - } - } - buffer - } -} - -impl Htmlable for Whitespace { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - let Whitespace { value, .. } = self; - if !value.is_empty() { - buffer.push_str(self.value.as_str()); - }; - buffer - } -} - -impl Htmlable for LineTerminator { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - buffer.push_str(self.space0.to_html().as_str()); - if let Some(v) = self.clone().comment { - buffer.push_str(""); - buffer.push_str(format!("#{}", v.value.as_str()).as_str()); - buffer.push_str(""); - } - buffer - } -} - -impl Htmlable for EncodedString { - fn to_html(&self) -> String { - format!("\"{}\"", self.encoded) - } -} - -impl Htmlable for Template { - fn to_html(&self) -> String { - let mut buffer = String::from(""); - for element in self.elements.clone() { - buffer.push_str(element.to_html().as_str()); - } - buffer - } -} - -impl Htmlable for TemplateElement { - fn to_html(&self) -> String { - match self { - TemplateElement::String { encoded, .. } => { - format!("{}", encoded) - } - TemplateElement::Expression(value) => value.to_html(), - /* space0: _, variable: _, space1: _ } => { - let mut buffer = String::from(""); - buffer.push_str("{{"); - buffer.push_str("}}"); - return buffer; - }*/ - } - } -} - -impl Htmlable for Expr { - fn to_html(&self) -> String { - format!("{}", self.variable.name) - } -} - -fn to_line(v: String) -> String { - format!("{}", v) -} - -fn add_line_terminators(buffer: &mut String, line_terminators: Vec) { - for line_terminator in line_terminators.clone() { - buffer.push_str(to_line(line_terminator.to_html()).as_str()); - } -} diff --git a/packages/hurl/src/format/hurl.css b/packages/hurl/src/format/hurl.css deleted file mode 100644 index 4d004184a..000000000 --- a/packages/hurl/src/format/hurl.css +++ /dev/null @@ -1,51 +0,0 @@ - -dy { - counter-reset: line; - font-family: monospace; -} - -span.line { - display: block; - line-height: 1.2rem; -} - -span.line:before { - counter-increment: line; - content: counter(line); - display: inline-block; - border-right: 1px solid #ddd; - padding: 0 1em; - margin-right: .5em; - color: #888; - width: 2.5em; - text-align: right; -} - -.method { - color: black; -} - -.version { - color: black; -} - -.section-header { - color: darkmagenta; -} - -.query-type { - color: teal; -} - -.predicate-type { - color: darkblue; -} - -.string { - color: darkgreen; -} - -.comment { - color: dimgray; -} - diff --git a/packages/hurl/src/format/mod.rs b/packages/hurl/src/format/mod.rs deleted file mode 100644 index 9b7ae22a5..000000000 --- a/packages/hurl/src/format/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -pub use self::color::TerminalColor; -pub use self::html::format as format_html; -pub use self::text::format as format_text; -pub use self::token::{Token, Tokenizable}; - -mod color; -mod html; -mod text; -mod token; diff --git a/packages/hurl/src/format/text.rs b/packages/hurl/src/format/text.rs deleted file mode 100644 index 4bb96c8a3..000000000 --- a/packages/hurl/src/format/text.rs +++ /dev/null @@ -1,117 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -use hurl_core::ast::*; - -use super::color::TerminalColor; -use super::token::*; - -pub fn format(hurl_file: HurlFile, color: bool) -> String { - let mut buffer = String::from(""); - for token in hurl_file.tokenize() { - buffer.push_str(format_token(token, color).as_str()); - } - buffer -} - -fn format_token(token: Token, color: bool) -> String { - match token { - Token::Whitespace(value) => value, - Token::Method(value) => { - if color { - TerminalColor::LightYellow.format(value) - } else { - value - } - } - Token::Version(value) => value, - Token::Status(value) => value, - Token::SectionHeader(value) => { - if color { - TerminalColor::Magenta.format(value) - } else { - value - } - } - Token::Comment(value) => { - if color { - TerminalColor::LightBlack.format(value) - } else { - value - } - } - Token::Value(value) => value, - Token::Colon(value) => value, - Token::QueryType(value) => { - if color { - TerminalColor::LightCyan.format(value) - } else { - value - } - } - Token::PredicateType(value) => { - if color { - TerminalColor::LightYellow.format(value) - } else { - value - } - } - Token::Not(value) => { - if color { - TerminalColor::LightYellow.format(value) - } else { - value - } - } - Token::Boolean(value) | Token::Number(value) => { - if color { - TerminalColor::Cyan.format(value) - } else { - value - } - } - Token::String(value) => { - if color { - TerminalColor::Green.format(value) - } else { - value - } - } - Token::Quote(value) => { - if color { - TerminalColor::Green.format(value) - } else { - value - } - } - Token::CodeDelimiter(value) => { - if color { - TerminalColor::Green.format(value) - } else { - value - } - } - Token::CodeVariable(value) => { - if color { - TerminalColor::Green.format(value) - } else { - value - } - } - Token::Keyword(value) => value, - } -} diff --git a/packages/hurl/src/format/token.rs b/packages/hurl/src/format/token.rs deleted file mode 100644 index d45c3c190..000000000 --- a/packages/hurl/src/format/token.rs +++ /dev/null @@ -1,785 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -use hurl_core::ast::*; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Token { - Method(String), - Version(String), - Status(String), - SectionHeader(String), - QueryType(String), - PredicateType(String), - Not(String), - Keyword(String), - - // Primitives - Whitespace(String), - Comment(String), - Value(String), - Colon(String), - Quote(String), - Boolean(String), - Number(String), - String(String), - CodeDelimiter(String), - CodeVariable(String), -} - -pub trait Tokenizable { - fn tokenize(&self) -> Vec; -} - -fn add_tokens(tokens1: &mut Vec, tokens2: Vec) { - for token in tokens2 { - tokens1.push(token); - } -} - -impl Tokenizable for HurlFile { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.entries.iter().flat_map(|e| e.tokenize()).collect(), - ); - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - tokens - } -} - -impl Tokenizable for Entry { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens(&mut tokens, self.request.tokenize()); - if let Some(response) = self.clone().response { - add_tokens(&mut tokens, response.tokenize()) - } - tokens - } -} - -impl Tokenizable for Request { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - tokens.push(Token::Method(self.method.as_str().to_string())); - add_tokens(&mut tokens, self.space1.tokenize()); - add_tokens(&mut tokens, self.url.tokenize()); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - add_tokens( - &mut tokens, - self.headers.iter().flat_map(|e| e.tokenize()).collect(), - ); - add_tokens( - &mut tokens, - self.sections.iter().flat_map(|e| e.tokenize()).collect(), - ); - if let Some(body) = self.clone().body { - add_tokens(&mut tokens, body.tokenize()) - } - tokens - } -} - -impl Tokenizable for Response { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - add_tokens(&mut tokens, self.version.tokenize()); - add_tokens(&mut tokens, self.space1.tokenize()); - tokens.push(Token::Status(self.status.value.to_string())); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - add_tokens( - &mut tokens, - self.headers.iter().flat_map(|e| e.tokenize()).collect(), - ); - add_tokens( - &mut tokens, - self.sections.iter().flat_map(|e| e.tokenize()).collect(), - ); - if let Some(body) = self.clone().body { - add_tokens(&mut tokens, body.tokenize()) - } - tokens - } -} - -impl Tokenizable for Version { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::Version(format!( - "HTTP/{}", - match self.value { - VersionValue::Version1 => String::from("1.0"), - VersionValue::Version11 => String::from("1.1"), - VersionValue::Version2 => String::from("2"), - VersionValue::VersionAny => String::from("*"), - } - ))); - tokens - } -} - -impl Tokenizable for Body { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - add_tokens(&mut tokens, self.value.tokenize()); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - tokens - } -} - -impl Tokenizable for Bytes { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - match self { - Bytes::Json { value } => tokens.append(&mut value.tokenize()), - Bytes::Xml { value } => { - tokens.push(Token::String(value.to_string())); - } - // Bytes::MultilineString { value: _ } => {} - Bytes::RawString { newline0, value } => { - tokens.push(Token::Keyword(String::from("```"))); - add_tokens(&mut tokens, newline0.tokenize()); - tokens.append(&mut value.tokenize()); - tokens.push(Token::Keyword(String::from("```"))); - } - Bytes::Base64 { - space0, - encoded, - space1, - .. - } => { - tokens.push(Token::Keyword(String::from("base64,"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::String(encoded.to_string())); - add_tokens(&mut tokens, space1.tokenize()); - tokens.push(Token::Keyword(String::from(";"))); - } - Bytes::File { - space0, - filename, - space1, - } => { - tokens.push(Token::Keyword(String::from("file,"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, filename.tokenize()); - //tokens.push(Token::String(filename.to_string())); - add_tokens(&mut tokens, space1.tokenize()); - tokens.push(Token::Keyword(String::from(";"))); - } - } - tokens - } -} - -impl Tokenizable for Section { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - tokens.push(Token::SectionHeader(format!("[{}]", self.name()))); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - add_tokens(&mut tokens, self.value.tokenize()); - // add_tokens(&mut tokens, self.space0.tokenize()); - // tokens.push(Token::SectionHeader(format!("[{}]", self.name))); - tokens - } -} - -impl Tokenizable for SectionValue { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - match self { - SectionValue::Asserts(items) => { - add_tokens( - &mut tokens, - items.iter().flat_map(|e| e.tokenize()).collect(), - ); - } - SectionValue::QueryParams(items) => { - add_tokens( - &mut tokens, - items.iter().flat_map(|e| e.tokenize()).collect(), - ); - } - SectionValue::FormParams(items) => { - add_tokens( - &mut tokens, - items.iter().flat_map(|e| e.tokenize()).collect(), - ); - } - SectionValue::MultipartFormData(items) => { - add_tokens( - &mut tokens, - items.iter().flat_map(|e| e.tokenize()).collect(), - ); - } - SectionValue::Cookies(items) => { - add_tokens( - &mut tokens, - items.iter().flat_map(|e| e.tokenize()).collect(), - ); - } - SectionValue::Captures(items) => { - add_tokens( - &mut tokens, - items.iter().flat_map(|e| e.tokenize()).collect(), - ); - } - } - tokens - } -} - -impl Tokenizable for KeyValue { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - add_tokens(&mut tokens, self.key.tokenize()); - add_tokens(&mut tokens, self.space1.tokenize()); - tokens.push(Token::Colon(String::from(":"))); - add_tokens(&mut tokens, self.space2.tokenize()); - add_tokens(&mut tokens, self.value.tokenize()); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - tokens - } -} - -impl Tokenizable for MultipartParam { - fn tokenize(&self) -> Vec { - match self { - MultipartParam::Param(key_value) => key_value.tokenize(), - MultipartParam::FileParam(file_param) => file_param.tokenize(), - } - } -} - -impl Tokenizable for FileParam { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens(&mut tokens, self.space0.tokenize()); - add_tokens(&mut tokens, self.key.tokenize()); - add_tokens(&mut tokens, self.space1.tokenize()); - tokens.push(Token::Colon(String::from(":"))); - add_tokens(&mut tokens, self.space2.tokenize()); - tokens.append(&mut self.value.tokenize()); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - tokens - } -} - -impl Tokenizable for FileValue { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::Keyword("file,".to_string())); - tokens.append(&mut self.space0.tokenize()); - tokens.append(&mut self.filename.tokenize()); - tokens.append(&mut self.space1.tokenize()); - tokens.push(Token::Keyword(";".to_string())); - tokens.append(&mut self.space2.tokenize()); - if let Some(content_type) = self.content_type.clone() { - tokens.push(Token::String(content_type)); - } - tokens - } -} - -impl Tokenizable for Cookie { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - add_tokens(&mut tokens, self.name.tokenize()); - add_tokens(&mut tokens, self.space1.tokenize()); - tokens.push(Token::Colon(String::from(":"))); - add_tokens(&mut tokens, self.space2.tokenize()); - add_tokens(&mut tokens, self.value.tokenize()); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - tokens - } -} - -impl Tokenizable for CookieValue { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::Value(self.clone().value)); - tokens - } -} - -impl Tokenizable for Capture { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - add_tokens(&mut tokens, self.name.tokenize()); - add_tokens(&mut tokens, self.space1.tokenize()); - tokens.push(Token::Colon(String::from(":"))); - add_tokens(&mut tokens, self.space2.tokenize()); - add_tokens(&mut tokens, self.query.tokenize()); - add_tokens(&mut tokens, self.space3.tokenize()); - if let Some(subquery) = self.clone().subquery { - add_tokens(&mut tokens, subquery.tokenize()) - } - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - tokens - } -} - -impl Tokenizable for Assert { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens( - &mut tokens, - self.line_terminators - .iter() - .flat_map(|e| e.tokenize()) - .collect(), - ); - add_tokens(&mut tokens, self.space0.tokenize()); - add_tokens(&mut tokens, self.query.tokenize()); - add_tokens(&mut tokens, self.space1.tokenize()); - // TODO reconvert back your first predicate for jsonpath - // so that you can use your firstX predicate for other query - add_tokens(&mut tokens, self.predicate.tokenize()); - add_tokens(&mut tokens, self.line_terminator0.tokenize()); - tokens - } -} - -impl Tokenizable for Query { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - match self.value.clone() { - QueryValue::Status {} => tokens.push(Token::QueryType(String::from("status"))), - QueryValue::Header { space0, name } => { - tokens.push(Token::QueryType(String::from("header"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, name.tokenize()); - } - QueryValue::Cookie { space0, expr } => { - tokens.push(Token::QueryType(String::from("cookie"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::CodeDelimiter("\"".to_string())); - add_tokens(&mut tokens, expr.tokenize()); - tokens.push(Token::CodeDelimiter("\"".to_string())); - } - QueryValue::Body {} => tokens.push(Token::QueryType(String::from("body"))), - QueryValue::Xpath { space0, expr } => { - tokens.push(Token::QueryType(String::from("xpath"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, expr.tokenize()); - } - QueryValue::Jsonpath { space0, expr } => { - tokens.push(Token::QueryType(String::from("jsonpath"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, expr.tokenize()); - } - QueryValue::Regex { space0, expr } => { - tokens.push(Token::QueryType(String::from("regex"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, expr.tokenize()); - } - QueryValue::Variable { space0, name } => { - tokens.push(Token::QueryType(String::from("variable"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, name.tokenize()); - } - } - tokens - } -} - -impl Tokenizable for CookiePath { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens(&mut tokens, self.name.tokenize()); - if let Some(attribute) = self.attribute.clone() { - add_tokens(&mut tokens, attribute.tokenize()); - } - tokens - } -} - -impl Tokenizable for CookieAttribute { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::CodeDelimiter("[".to_string())); - add_tokens(&mut tokens, self.space0.tokenize()); - tokens.push(Token::String(self.name.value())); - add_tokens(&mut tokens, self.space1.tokenize()); - tokens.push(Token::CodeDelimiter("]".to_string())); - tokens - } -} - -impl Tokenizable for Subquery { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - match self.value.clone() { - SubqueryValue::Regex { space0, expr } => { - tokens.push(Token::QueryType(String::from("regex"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, expr.tokenize()); - } - } - tokens - } -} - -impl Tokenizable for Predicate { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - if self.not { - tokens.push(Token::Not(String::from("not"))); - add_tokens(&mut tokens, self.space0.tokenize()); - } - add_tokens(&mut tokens, self.predicate_func.tokenize()); - tokens - } -} - -impl Tokenizable for PredicateFunc { - fn tokenize(&self) -> Vec { - self.value.tokenize() - } -} - -impl Tokenizable for PredicateFuncValue { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - match self { - PredicateFuncValue::EqualNull { space0 } => { - tokens.push(Token::PredicateType(String::from("equals"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Keyword("null".to_string())); - } - PredicateFuncValue::EqualBool { space0, value } => { - tokens.push(Token::PredicateType(String::from("equals"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Boolean(value.to_string())); - } - PredicateFuncValue::EqualString { space0, value } => { - tokens.push(Token::PredicateType(String::from("equals"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, value.tokenize()); - } - PredicateFuncValue::EqualInt { space0, value } => { - tokens.push(Token::PredicateType(String::from("equals"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Number(value.to_string())); - } - PredicateFuncValue::EqualFloat { space0, value } => { - tokens.push(Token::PredicateType(String::from("equals"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Number(value.to_string())); - } - PredicateFuncValue::EqualExpression { space0, value } => { - tokens.push(Token::PredicateType(String::from("equals"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.append(&mut value.tokenize()); - } - PredicateFuncValue::CountEqual { space0, value } => { - tokens.push(Token::PredicateType(String::from("countEquals"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Boolean(value.to_string())); - } - PredicateFuncValue::StartWith { space0, value } => { - tokens.push(Token::PredicateType(String::from("startsWith"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, value.tokenize()); - } - PredicateFuncValue::Contain { space0, value } => { - tokens.push(Token::PredicateType(String::from("contains"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, value.tokenize()); - } - PredicateFuncValue::IncludeString { space0, value } => { - tokens.push(Token::PredicateType(String::from("includes"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, value.tokenize()); - } - PredicateFuncValue::IncludeInt { space0, value } => { - tokens.push(Token::PredicateType(String::from("includes"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Number(value.to_string())); - } - PredicateFuncValue::IncludeFloat { space0, value } => { - tokens.push(Token::PredicateType(String::from("includes"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Number(value.to_string())); - } - PredicateFuncValue::IncludeNull { space0 } => { - tokens.push(Token::PredicateType(String::from("includes"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Keyword("null".to_string())); - } - PredicateFuncValue::IncludeBool { space0, value } => { - tokens.push(Token::PredicateType(String::from("includes"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.push(Token::Boolean(value.to_string())); - } - PredicateFuncValue::IncludeExpression { space0, value } => { - tokens.push(Token::PredicateType(String::from("includes"))); - add_tokens(&mut tokens, space0.tokenize()); - tokens.append(&mut value.tokenize()); - } - PredicateFuncValue::Match { space0, value } => { - tokens.push(Token::PredicateType(String::from("matches"))); - add_tokens(&mut tokens, space0.tokenize()); - add_tokens(&mut tokens, value.tokenize()); - } - PredicateFuncValue::Exist {} => { - tokens.push(Token::PredicateType(String::from("exists"))); - } - } - tokens - } -} - -impl Tokenizable for EncodedString { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - if self.quotes { - tokens.push(Token::Quote( - if self.clone().quotes { "\"" } else { "" }.to_string(), - )); - } - tokens.push(Token::String(self.encoded.clone())); - - if self.quotes { - tokens.push(Token::Quote( - if self.clone().quotes { "\"" } else { "" }.to_string(), - )); - } - tokens - } -} - -impl Tokenizable for Template { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - if self.quotes { - tokens.push(Token::Quote( - if self.clone().quotes { "\"" } else { "" }.to_string(), - )); - } - for element in self.elements.clone() { - add_tokens(&mut tokens, element.tokenize()); - } - - if self.quotes { - tokens.push(Token::Quote( - if self.clone().quotes { "\"" } else { "" }.to_string(), - )); - } - tokens - } -} - -impl Tokenizable for TemplateElement { - fn tokenize(&self) -> Vec { - match self { - TemplateElement::String { encoded, .. } => { - let mut tokens: Vec = vec![]; - tokens.push(Token::String(encoded.to_string())); - tokens - } - TemplateElement::Expression(value) => { - let mut tokens: Vec = vec![]; - add_tokens(&mut tokens, value.tokenize()); - tokens - } - } - } -} - -impl Tokenizable for Expr { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::CodeDelimiter(String::from("{{"))); - add_tokens(&mut tokens, self.space0.tokenize()); - tokens.push(Token::CodeVariable(self.variable.name.clone())); - add_tokens(&mut tokens, self.space1.tokenize()); - tokens.push(Token::CodeDelimiter(String::from("}}"))); - tokens - } -} - -impl Tokenizable for LineTerminator { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - add_tokens(&mut tokens, self.space0.tokenize()); - if let Some(comment) = self.clone().comment { - add_tokens(&mut tokens, comment.tokenize()); - } - add_tokens(&mut tokens, self.newline.tokenize()); - tokens - } -} - -impl Tokenizable for Whitespace { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - if self.value != "" { - tokens.push(Token::Whitespace(self.clone().value)); - } - tokens - } -} - -impl Tokenizable for Comment { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::Comment(format!("#{}", self.clone().value))); - tokens - } -} - -impl Tokenizable for Filename { - fn tokenize(&self) -> Vec { - return vec![Token::String(self.clone().value)]; - } -} - -impl Tokenizable for JsonValue { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - match self { - JsonValue::String(s) => { - //tokens.push(Token::CodeDelimiter("\"".to_string())); - tokens.append(&mut s.tokenize()); - //tokens.push(Token::CodeDelimiter("\"".to_string())); - } - JsonValue::Number(value) => { - tokens.push(Token::Number(value.clone())); - } - JsonValue::Boolean(value) => { - tokens.push(Token::Number(value.to_string())); - } - JsonValue::List { space0, elements } => { - tokens.push(Token::CodeDelimiter("[".to_string())); - tokens.push(Token::Whitespace(space0.clone())); - for (i, element) in elements.iter().enumerate() { - if i > 0 { - tokens.push(Token::CodeDelimiter(",".to_string())); - } - tokens.append(&mut element.tokenize()); - } - tokens.push(Token::CodeDelimiter("]".to_string())); - } - JsonValue::Object { space0, elements } => { - tokens.push(Token::CodeDelimiter("{".to_string())); - tokens.push(Token::Whitespace(space0.clone())); - for (i, element) in elements.iter().enumerate() { - if i > 0 { - tokens.push(Token::CodeDelimiter(",".to_string())); - } - tokens.append(&mut element.tokenize()); - } - tokens.push(Token::CodeDelimiter("}".to_string())); - } - JsonValue::Null {} => { - tokens.push(Token::Keyword("null".to_string())); - } - } - tokens - } -} - -impl Tokenizable for JsonListElement { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::Whitespace(self.space0.clone())); - tokens.append(&mut self.value.tokenize()); - tokens.push(Token::Whitespace(self.space1.clone())); - tokens - } -} - -impl Tokenizable for JsonObjectElement { - fn tokenize(&self) -> Vec { - let mut tokens: Vec = vec![]; - tokens.push(Token::Whitespace(self.space0.clone())); - tokens.push(Token::Quote("\"".to_string())); - tokens.push(Token::String(self.name.clone())); - tokens.push(Token::Quote("\"".to_string())); - tokens.push(Token::Whitespace(self.space1.clone())); - tokens.push(Token::CodeDelimiter(":".to_string())); - tokens.push(Token::Whitespace(self.space2.clone())); - tokens.append(&mut self.value.tokenize()); - tokens.push(Token::Whitespace(self.space3.clone())); - tokens - } -} diff --git a/packages/hurl/src/lib.rs b/packages/hurl/src/lib.rs index 73680def7..687ab871d 100644 --- a/packages/hurl/src/lib.rs +++ b/packages/hurl/src/lib.rs @@ -21,7 +21,6 @@ extern crate float_cmp; pub mod cli; -pub mod format; pub mod html; pub mod http; pub mod jsonpath; diff --git a/packages/hurl/src/main.rs b/packages/hurl/src/main.rs index c21f3493e..303f4f8da 100644 --- a/packages/hurl/src/main.rs +++ b/packages/hurl/src/main.rs @@ -29,12 +29,12 @@ use chrono::{DateTime, Local}; use clap::{AppSettings, ArgMatches}; use hurl::cli; -use hurl::cli::Error; use hurl::html; use hurl::http; use hurl::runner; use hurl::runner::{HurlResult, RunnerOptions}; use hurl_core::ast::{Pos, SourceInfo}; +use hurl_core::error::Error; use hurl_core::parser; #[derive(Clone, Debug, PartialEq, Eq)] @@ -56,6 +56,10 @@ pub struct CLIOptions { pub user: Option, } +pub struct CLIError { + pub message: String, +} + fn execute( filename: &str, contents: String, @@ -75,10 +79,12 @@ fn execute( } else { Some(filename.to_string()) }; + let log_parser_error = cli::make_logger_parser_error(lines.clone(), cli_options.color, optional_filename.clone()); let log_runner_error = cli::make_logger_runner_error(lines, cli_options.color, optional_filename); + match parser::parse_hurl_file(contents.as_str()) { Err(e) => { log_parser_error(&e, false); @@ -89,7 +95,7 @@ fn execute( log_verbose(format!("insecure: {}", cli_options.insecure).as_str()); log_verbose(format!("follow redirect: {}", cli_options.follow_location).as_str()); if let Some(n) = cli_options.max_redirect { - log_verbose(format!("max redirect: {}", n).as_str()); + log_verbose(format!("max redirect: {}", n.to_string()).as_str()); } if let Some(proxy) = cli_options.proxy.clone() { log_verbose(format!("proxy: {}", proxy).as_str()); @@ -108,7 +114,7 @@ fn execute( format!( "executing {}/{} entries", to_entry.to_string(), - hurl_file.entries.len() + hurl_file.entries.len().to_string() ) .as_str(), ); @@ -190,11 +196,11 @@ fn output_color(matches: ArgMatches) -> bool { } } -fn to_entry(matches: ArgMatches) -> Result, cli::CLIError> { +fn to_entry(matches: ArgMatches) -> Result, CLIError> { match matches.value_of("to_entry") { Some(value) => match value.parse() { Ok(v) => Ok(Some(v)), - Err(_) => Err(cli::CLIError { + Err(_) => Err(CLIError { message: "Invalid value for option --to-entry - must be a positive integer!" .to_string(), }), @@ -206,7 +212,7 @@ fn to_entry(matches: ArgMatches) -> Result, cli::CLIError> { fn json_file( matches: ArgMatches, log_verbose: impl Fn(&str), -) -> Result<(Vec, Option), cli::CLIError> { +) -> Result<(Vec, Option), CLIError> { if let Some(filename) = matches.value_of("json") { let path = Path::new(filename); @@ -217,14 +223,14 @@ fn json_file( let v: serde_json::Value = match serde_json::from_str(data.as_str()) { Ok(val) => val, Err(_) => { - return Err(cli::CLIError { + return Err(CLIError { message: format!("The file {} is not a valid json file", path.display()), }); } }; match runner::deserialize_results(v) { Err(msg) => { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Existing Hurl json can not be parsed! - {}", msg), }); } @@ -240,7 +246,7 @@ fn json_file( } } -fn html_report(matches: ArgMatches) -> Result, cli::CLIError> { +fn html_report(matches: ArgMatches) -> Result, CLIError> { if let Some(dir) = matches.value_of("html_report") { let path = Path::new(dir); if std::path::Path::new(&path).exists() { @@ -249,7 +255,7 @@ fn html_report(matches: ArgMatches) -> Result, cli::C .map(|mut i| i.next().is_none()) .unwrap_or(false) { - return Err(cli::CLIError { + return Err(CLIError { message: format!( "Html dir {} already exists and is not empty", path.display() @@ -259,7 +265,7 @@ fn html_report(matches: ArgMatches) -> Result, cli::C Ok(Some(path.to_path_buf())) } else { match std::fs::create_dir(path) { - Err(_) => Err(cli::CLIError { + Err(_) => Err(CLIError { message: format!("Html dir {} can not be created", path.display()), }), Ok(_) => Ok(Some(path.to_path_buf())), @@ -270,21 +276,21 @@ fn html_report(matches: ArgMatches) -> Result, cli::C } } -fn variables(matches: ArgMatches) -> Result, cli::CLIError> { +fn variables(matches: ArgMatches) -> Result, CLIError> { let mut variables = HashMap::new(); if matches.is_present("variable") { let input: Vec<_> = matches.values_of("variable").unwrap().collect(); for s in input { match s.find('=') { None => { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Missing variable value for {}!", s), }); } Some(index) => { let (name, value) = s.split_at(index); if variables.contains_key(name) { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Variable {} defined twice!", name), }); } @@ -466,7 +472,7 @@ fn app() -> clap::App<'static, 'static> { pub fn unwrap_or_exit( log_error_message: &impl Fn(bool, &str), - result: Result, + result: Result, ) -> T { match result { Ok(v) => v, @@ -477,7 +483,7 @@ pub fn unwrap_or_exit( } } -fn parse_options(matches: ArgMatches) -> Result { +fn parse_options(matches: ArgMatches) -> Result { let verbose = matches.is_present("verbose"); let color = output_color(matches.clone()); let fail_fast = !matches.is_present("fail_at_end"); @@ -494,7 +500,7 @@ fn parse_options(matches: ArgMatches) -> Result { Some(s) => match s.parse::() { Ok(x) => Some(x), Err(_) => { - return Err(cli::CLIError { + return Err(CLIError { message: "max_redirs option can not be parsed".to_string(), }); } @@ -506,7 +512,7 @@ fn parse_options(matches: ArgMatches) -> Result { Some(s) => match s.parse::() { Ok(n) => Duration::from_secs(n), Err(_) => { - return Err(cli::CLIError { + return Err(CLIError { message: "max_time option can not be parsed".to_string(), }); } @@ -518,7 +524,7 @@ fn parse_options(matches: ArgMatches) -> Result { Some(s) => match s.parse::() { Ok(n) => Duration::from_secs(n), Err(_) => { - return Err(cli::CLIError { + return Err(CLIError { message: "connect-timeout option can not be parsed".to_string(), }); } @@ -586,7 +592,7 @@ fn main() { Some(filename) => { let filename = unwrap_or_exit( &log_error_message, - cli::cookies_output_file(filename.to_string(), filenames.len()), + cookies_output_file(filename.to_string(), filenames.len()), ); Some(filename) } @@ -753,7 +759,7 @@ fn exit_code(hurl_results: Vec) -> i32 { } } -fn write_output(bytes: Vec, filename: Option<&str>) -> Result<(), cli::CLIError> { +fn write_output(bytes: Vec, filename: Option<&str>) -> Result<(), CLIError> { match filename { None => { let stdout = io::stdout(); @@ -768,7 +774,7 @@ fn write_output(bytes: Vec, filename: Option<&str>) -> Result<(), cli::CLIEr let path = Path::new(filename); let mut file = match std::fs::File::create(&path) { Err(why) => { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Issue writing to {}: {:?}", path.display(), why), }); } @@ -781,13 +787,21 @@ fn write_output(bytes: Vec, filename: Option<&str>) -> Result<(), cli::CLIEr } } -fn write_cookies_file( - file_path: PathBuf, - hurl_results: Vec, -) -> Result<(), cli::CLIError> { +pub fn cookies_output_file(filename: String, n: usize) -> Result { + if n > 1 { + Err(CLIError { + message: "Only save cookies for a unique session".to_string(), + }) + } else { + let path = std::path::Path::new(&filename); + Ok(path.to_path_buf()) + } +} + +fn write_cookies_file(file_path: PathBuf, hurl_results: Vec) -> Result<(), CLIError> { let mut file = match std::fs::File::create(&file_path) { Err(why) => { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } @@ -800,7 +814,7 @@ fn write_cookies_file( .to_string(); match hurl_results.first() { None => { - return Err(cli::CLIError { + return Err(CLIError { message: "Issue fetching results".to_string(), }); } @@ -813,17 +827,14 @@ fn write_cookies_file( } if let Err(why) = file.write_all(s.as_bytes()) { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } Ok(()) } -fn write_html_report( - dir_path: PathBuf, - hurl_results: Vec, -) -> Result<(), cli::CLIError> { +fn write_html_report(dir_path: PathBuf, hurl_results: Vec) -> Result<(), CLIError> { //let now: DateTime = Utc::now(); let now: DateTime = Local::now(); let html = create_html_index(now.to_rfc2822(), hurl_results); @@ -832,14 +843,14 @@ fn write_html_report( let file_path = dir_path.join("index.html"); let mut file = match std::fs::File::create(&file_path) { Err(why) => { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } Ok(file) => file, }; if let Err(why) = file.write_all(s.as_bytes()) { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } @@ -847,14 +858,14 @@ fn write_html_report( let file_path = dir_path.join("report.css"); let mut file = match std::fs::File::create(&file_path) { Err(why) => { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } Ok(file) => file, }; if let Err(why) = file.write_all(include_bytes!("report.css")) { - return Err(cli::CLIError { + return Err(CLIError { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } diff --git a/packages/hurl/src/cli/error.rs b/packages/hurl/src/runner/error.rs similarity index 65% rename from packages/hurl/src/cli/error.rs rename to packages/hurl/src/runner/error.rs index 04e5900e0..edcd193f4 100644 --- a/packages/hurl/src/cli/error.rs +++ b/packages/hurl/src/runner/error.rs @@ -1,83 +1,7 @@ use crate::runner; use crate::runner::RunnerError; use hurl_core::ast::SourceInfo; -use hurl_core::parser; -use hurl_core::parser::ParseError; - -pub trait Error { - fn source_info(&self) -> SourceInfo; - fn description(&self) -> String; - fn fixme(&self) -> String; -} - -/// -/// Textual Output for parser errors -/// - -impl Error for parser::Error { - fn source_info(&self) -> SourceInfo { - SourceInfo { - start: self.pos.clone(), - end: self.pos.clone(), - } - } - - fn description(&self) -> String { - match self.clone().inner { - ParseError::Method { .. } => "Parsing Method".to_string(), - ParseError::Version { .. } => "Parsing Version".to_string(), - ParseError::Status { .. } => "Parsing Status".to_string(), - ParseError::Filename { .. } => "Parsing Filename".to_string(), - ParseError::Expecting { .. } => "Parsing literal".to_string(), - ParseError::Space { .. } => "Parsing space".to_string(), - ParseError::SectionName { .. } => "Parsing section name".to_string(), - ParseError::JsonpathExpr { .. } => "Parsing jsonpath expression".to_string(), - ParseError::XPathExpr { .. } => "Parsing xpath expression".to_string(), - ParseError::TemplateVariable { .. } => "Parsing template variable".to_string(), - ParseError::Json { .. } => "Parsing json".to_string(), - ParseError::Predicate { .. } => "Parsing predicate".to_string(), - ParseError::PredicateValue { .. } => "Parsing predicate value".to_string(), - ParseError::RegexExpr { .. } => "Parsing regex".to_string(), - ParseError::DuplicateSection { .. } => "Parsing section".to_string(), - ParseError::RequestSection { .. } => "Parsing section".to_string(), - ParseError::ResponseSection { .. } => "Parsing section".to_string(), - ParseError::EscapeChar { .. } => "Parsing escape character".to_string(), - ParseError::InvalidCookieAttribute { .. } => "Parsing cookie attribute".to_string(), - _ => format!("{:?}", self), - } - } - - fn fixme(&self) -> String { - match self.inner.clone() { - ParseError::Method { .. } => "Available HTTP Method GET, POST, ...".to_string(), - ParseError::Version { .. } => "The http version must be 1.0, 1.1, 2 or *".to_string(), - ParseError::Status { .. } => "The http status is not valid".to_string(), - ParseError::Filename { .. } => "expecting a filename".to_string(), - ParseError::Expecting { value } => format!("expecting '{}'", value), - ParseError::Space { .. } => "expecting a space".to_string(), - ParseError::SectionName { name } => format!("the section {} is not valid", name), - ParseError::JsonpathExpr { .. } => "expecting a jsonpath expression".to_string(), - ParseError::XPathExpr { .. } => "expecting a xpath expression".to_string(), - ParseError::TemplateVariable { .. } => "expecting a variable".to_string(), - ParseError::Json { .. } => "json error".to_string(), - ParseError::Predicate { .. } => "expecting a predicate".to_string(), - ParseError::PredicateValue { .. } => "invalid predicate value".to_string(), - ParseError::RegexExpr { .. } => "Invalid Regex expression".to_string(), - ParseError::DuplicateSection { .. } => "The section is already defined".to_string(), - ParseError::RequestSection { .. } => { - "This is not a valid section for a request".to_string() - } - ParseError::ResponseSection { .. } => { - "This is not a valid section for a response".to_string() - } - ParseError::EscapeChar { .. } => "The escaping sequence is not valid".to_string(), - ParseError::InvalidCookieAttribute { .. } => { - "The cookie attribute is not valid".to_string() - } - _ => format!("{:?}", self), - } - } -} +use hurl_core::error::Error; /// /// Textual Output for runner errors diff --git a/packages/hurl/src/runner/mod.rs b/packages/hurl/src/runner/mod.rs index 366c35913..d6a427267 100644 --- a/packages/hurl/src/runner/mod.rs +++ b/packages/hurl/src/runner/mod.rs @@ -34,6 +34,7 @@ mod content_decoding; mod cookie; mod core; mod entry; +mod error; mod expr; mod http_response; mod hurl_file; diff --git a/packages/hurl_core/Cargo.toml b/packages/hurl_core/Cargo.toml index 097714a52..fc7afdb93 100644 --- a/packages/hurl_core/Cargo.toml +++ b/packages/hurl_core/Cargo.toml @@ -15,6 +15,3 @@ float-cmp = "0.6.0" sxd-document = "0.3.2" - - - diff --git a/packages/hurlfmt/src/cli/error.rs b/packages/hurl_core/src/error/mod.rs similarity index 79% rename from packages/hurlfmt/src/cli/error.rs rename to packages/hurl_core/src/error/mod.rs index 994680958..7a0a8308b 100644 --- a/packages/hurlfmt/src/cli/error.rs +++ b/packages/hurl_core/src/error/mod.rs @@ -1,9 +1,23 @@ -use hurl_core::ast::SourceInfo; -use hurl_core::parser; -use hurl_core::parser::ParseError; - -use crate::linter; -use crate::linter::LinterError; +/* + * hurl (https://hurl.dev) + * Copyright (C) 2020 Orange + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +use super::ast::SourceInfo; +use super::parser; +use super::parser::ParseError; pub trait Error { fn source_info(&self) -> SourceInfo; @@ -11,10 +25,6 @@ pub trait Error { fn fixme(&self) -> String; } -/// -/// Textual Output for parser errors -/// - impl Error for parser::Error { fn source_info(&self) -> SourceInfo { SourceInfo { @@ -79,29 +89,3 @@ impl Error for parser::Error { } } } - -/// -/// Textual Output for linter errors -/// -/// -impl Error for linter::Error { - fn source_info(&self) -> SourceInfo { - self.clone().source_info - } - - fn description(&self) -> String { - match self.inner { - LinterError::UnneccessarySpace { .. } => "Unnecessary space".to_string(), - LinterError::UnneccessaryJsonEncoding {} => "Unnecessary json encoding".to_string(), - LinterError::OneSpace {} => "One space ".to_string(), - } - } - - fn fixme(&self) -> String { - match self.inner { - LinterError::UnneccessarySpace { .. } => "Remove space".to_string(), - LinterError::UnneccessaryJsonEncoding {} => "Use Simple String".to_string(), - LinterError::OneSpace {} => "Use only one space".to_string(), - } - } -} diff --git a/packages/hurl_core/src/lib.rs b/packages/hurl_core/src/lib.rs index 71b5fed56..ccc723b20 100644 --- a/packages/hurl_core/src/lib.rs +++ b/packages/hurl_core/src/lib.rs @@ -20,4 +20,5 @@ extern crate float_cmp; pub mod ast; +pub mod error; pub mod parser; diff --git a/packages/hurl/src/format/color.rs b/packages/hurlfmt/src/cli/color.rs similarity index 100% rename from packages/hurl/src/format/color.rs rename to packages/hurlfmt/src/cli/color.rs diff --git a/packages/hurlfmt/src/cli/logger.rs b/packages/hurlfmt/src/cli/logger.rs index a2c177a2e..9658f96da 100644 --- a/packages/hurlfmt/src/cli/logger.rs +++ b/packages/hurlfmt/src/cli/logger.rs @@ -16,9 +16,9 @@ * */ -use super::error::Error; -use crate::format::TerminalColor; +use super::color::TerminalColor; use crate::linter; +use hurl_core::error::Error; use hurl_core::parser; pub fn make_logger_verbose(verbose: bool) -> impl Fn(&str) { diff --git a/packages/hurlfmt/src/cli/mod.rs b/packages/hurlfmt/src/cli/mod.rs index 247553082..b4a5f788a 100644 --- a/packages/hurlfmt/src/cli/mod.rs +++ b/packages/hurlfmt/src/cli/mod.rs @@ -16,14 +16,12 @@ * */ -pub use self::error::Error; pub use self::logger::{ log_info, make_logger_error_message, make_logger_linter_error, make_logger_parser_error, make_logger_verbose, }; -pub use self::options::cookies_output_file; -pub use self::options::CLIError; -mod error; +pub use self::color::TerminalColor; + +mod color; mod logger; -mod options; diff --git a/packages/hurlfmt/src/cli/options.rs b/packages/hurlfmt/src/cli/options.rs deleted file mode 100644 index 8079a7825..000000000 --- a/packages/hurlfmt/src/cli/options.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -pub struct CLIError { - pub message: String, -} - -pub fn cookies_output_file(filename: String, n: usize) -> Result { - if n > 1 { - Err(CLIError { - message: "Only save cookies for a unique session".to_string(), - }) - } else { - let path = std::path::Path::new(&filename); - Ok(path.to_path_buf()) - } -} diff --git a/packages/hurlfmt/src/format/mod.rs b/packages/hurlfmt/src/format/mod.rs index 9b7ae22a5..a1613dcf8 100644 --- a/packages/hurlfmt/src/format/mod.rs +++ b/packages/hurlfmt/src/format/mod.rs @@ -16,12 +16,10 @@ * */ -pub use self::color::TerminalColor; pub use self::html::format as format_html; pub use self::text::format as format_text; pub use self::token::{Token, Tokenizable}; -mod color; mod html; mod text; mod token; diff --git a/packages/hurlfmt/src/format/text.rs b/packages/hurlfmt/src/format/text.rs index 4bb96c8a3..33dd80a81 100644 --- a/packages/hurlfmt/src/format/text.rs +++ b/packages/hurlfmt/src/format/text.rs @@ -17,8 +17,8 @@ */ use hurl_core::ast::*; -use super::color::TerminalColor; use super::token::*; +use crate::cli::TerminalColor; pub fn format(hurl_file: HurlFile, color: bool) -> String { let mut buffer = String::from(""); diff --git a/packages/hurlfmt/src/html/ast.rs b/packages/hurlfmt/src/html/ast.rs deleted file mode 100644 index 1eac3d5ce..000000000 --- a/packages/hurlfmt/src/html/ast.rs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Html { - pub head: Head, - pub body: Body, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Head { - pub title: String, - pub stylesheet: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Body { - pub children: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Element { - TextElement(String), - NodeElement { - name: String, - attributes: Vec, - children: Vec, - }, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Attribute { - Class(String), - Id(String), -} diff --git a/packages/hurlfmt/src/html/mod.rs b/packages/hurlfmt/src/html/mod.rs deleted file mode 100644 index 6c61c8d7c..000000000 --- a/packages/hurlfmt/src/html/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -pub use self::ast::{Attribute, Body, Element, Head, Html}; - -mod ast; -mod render; diff --git a/packages/hurlfmt/src/html/render.rs b/packages/hurlfmt/src/html/render.rs deleted file mode 100644 index 694a626af..000000000 --- a/packages/hurlfmt/src/html/render.rs +++ /dev/null @@ -1,131 +0,0 @@ -/* - * hurl (https://hurl.dev) - * Copyright (C) 2020 Orange - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -use super::ast::*; - -impl Html { - pub fn render(self) -> String { - format!( - "\n{}{}", - self.head.render(), - self.body.render() - ) - } -} - -impl Head { - fn render(self) -> String { - let mut s = "".to_string(); - s.push_str(format!("{}", self.title).as_str()); - if let Some(filename) = self.stylesheet { - s.push_str( - format!( - "", - filename - ) - .as_str(), - ); - } - format!("{}", s) - } -} - -impl Body { - fn render(self) -> String { - let children: Vec = self.children.iter().map(|e| e.clone().render()).collect(); - format!("{}", children.join("")) - } -} - -impl Element { - fn render(self) -> String { - match self { - Element::NodeElement { - name, - children, - attributes, - } => { - let attributes = if attributes.is_empty() { - "".to_string() - } else { - format!( - " {}", - attributes - .iter() - .map(|a| a.clone().render()) - .collect::>() - .join("") - ) - }; - let children: Vec = children.iter().map(|e| e.clone().render()).collect(); - format!("<{}{}>{}", name, attributes, children.join(""), name) - } - Element::TextElement(s) => s, - } - } -} - -impl Attribute { - fn render(self) -> String { - match self { - Attribute::Class(s) => format!("class=\"{}\"", s), - Attribute::Id(s) => format!("id=\"{}\"", s), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - pub fn sample_html() -> Html { - Html { - head: Head { - title: "This is a title".to_string(), - stylesheet: None, - }, - body: Body { - children: vec![Element::NodeElement { - name: "p".to_string(), - attributes: vec![], - children: vec![Element::TextElement("Hello world!".to_string())], - }], - }, - } - } - - #[test] - fn test_render_html() { - assert_eq!(sample_html().render(), "\nThis is a title

Hello world!

"); - } - - pub fn sample_div() -> Element { - Element::NodeElement { - name: "div".to_string(), - attributes: vec![Attribute::Class("request".to_string())], - children: vec![], - } - } - - #[test] - fn test_render_div() { - assert_eq!( - sample_div().render(), - "
".to_string() - ); - } -} diff --git a/packages/hurlfmt/src/lib.rs b/packages/hurlfmt/src/lib.rs index 4906e516e..ebd79f795 100644 --- a/packages/hurlfmt/src/lib.rs +++ b/packages/hurlfmt/src/lib.rs @@ -19,5 +19,4 @@ pub mod cli; pub mod format; -pub mod html; pub mod linter; diff --git a/packages/hurlfmt/src/linter/error.rs b/packages/hurlfmt/src/linter/error.rs new file mode 100644 index 000000000..2905d26f8 --- /dev/null +++ b/packages/hurlfmt/src/linter/error.rs @@ -0,0 +1,49 @@ +/* + * hurl (https://hurl.dev) + * Copyright (C) 2020 Orange + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +use hurl_core::ast::SourceInfo; +use hurl_core::error::Error; + +use crate::linter; +use crate::linter::LinterError; + +/// +/// Textual Output for linter errors +/// +/// +impl Error for linter::Error { + fn source_info(&self) -> SourceInfo { + self.clone().source_info + } + + fn description(&self) -> String { + match self.inner { + LinterError::UnneccessarySpace { .. } => "Unnecessary space".to_string(), + LinterError::UnneccessaryJsonEncoding {} => "Unnecessary json encoding".to_string(), + LinterError::OneSpace {} => "One space ".to_string(), + } + } + + fn fixme(&self) -> String { + match self.inner { + LinterError::UnneccessarySpace { .. } => "Remove space".to_string(), + LinterError::UnneccessaryJsonEncoding {} => "Use Simple String".to_string(), + LinterError::OneSpace {} => "Use only one space".to_string(), + } + } +} diff --git a/packages/hurlfmt/src/linter/mod.rs b/packages/hurlfmt/src/linter/mod.rs index b9037a313..d59431e00 100644 --- a/packages/hurlfmt/src/linter/mod.rs +++ b/packages/hurlfmt/src/linter/mod.rs @@ -19,4 +19,5 @@ pub use self::core::{Error, Lintable, LinterError}; mod core; +mod error; mod rules; diff --git a/packages/hurlfmt/src/main.rs b/packages/hurlfmt/src/main.rs index eb2dd3f3a..306f0d4f9 100644 --- a/packages/hurlfmt/src/main.rs +++ b/packages/hurlfmt/src/main.rs @@ -30,6 +30,10 @@ use hurlfmt::cli; use hurlfmt::format; use hurlfmt::linter::Lintable; +pub struct CLIError { + pub message: String, +} + fn main() { // // Do we have a git hash? // // (Yes, if ripgrep was built on a machine with `git` installed.)