mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-26 00:22:10 +03:00
Refacto on lint error display in hurlfmt.
This commit is contained in:
parent
497e9cae0f
commit
b58bdca4e9
@ -20,7 +20,7 @@ def test(hurl_file):
|
||||
cmd = ["hurlfmt", "--check", hurl_file]
|
||||
print(" ".join(cmd))
|
||||
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if result.returncode != 1:
|
||||
if result.returncode != 3:
|
||||
print(f"return code => expected: 1 actual {result.returncode}")
|
||||
sys.exit(1)
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
warning: Unnecessary space
|
||||
--> tests_error_lint/sections.hurl:4:1
|
||||
|
|
||||
4 | [QueryStringParams]
|
||||
| ^ Remove space
|
||||
|
|
||||
|
@ -1,4 +1,4 @@
|
||||
warning: One space
|
||||
warning: One space
|
||||
--> tests_error_lint/spaces.hurl:1:4
|
||||
|
|
||||
1 | GET http://localhost:8000/hello
|
||||
|
@ -15,16 +15,12 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use std::path::PathBuf;
|
||||
|
||||
use hurl_core::error::{DisplaySourceError, OutputFormat};
|
||||
use hurl_core::text::{Format, Style, StyledString};
|
||||
|
||||
use crate::linter;
|
||||
|
||||
/// A simple logger to log app related event (start, high levels error, etc...).
|
||||
pub struct Logger {
|
||||
/// Format of the messaeg in the terminal: ANSI or plain.
|
||||
/// Format of the message in the terminal: ANSI or plain.
|
||||
format: Format,
|
||||
}
|
||||
|
||||
@ -44,13 +40,8 @@ impl Logger {
|
||||
eprintln!("{}", s.to_string(self.format));
|
||||
}
|
||||
|
||||
/// Display a Hurl parsing error.
|
||||
pub fn error_parsing_rich<E: DisplaySourceError>(
|
||||
&mut self,
|
||||
content: &str,
|
||||
filename: &str,
|
||||
error: &E,
|
||||
) {
|
||||
/// Displays a Hurl parsing error.
|
||||
pub fn error_parsing<E: DisplaySourceError>(&self, content: &str, filename: &str, error: &E) {
|
||||
// FIXME: peut-être qu'on devrait faire rentrer le prefix `error:` qui est
|
||||
// fournit par `self.error_rich` dans la méthode `error.to_string`
|
||||
let message = error.to_string(
|
||||
@ -67,30 +58,21 @@ impl Logger {
|
||||
s.push("\n");
|
||||
eprintln!("{}", s.to_string(self.format));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_logger_linter_error(
|
||||
lines: Vec<String>,
|
||||
color: bool,
|
||||
filename: Option<PathBuf>,
|
||||
) -> impl Fn(&linter::Error, bool) {
|
||||
move |error: &linter::Error, warning: bool| {
|
||||
let filename = match &filename {
|
||||
None => "-".to_string(),
|
||||
Some(value) => value.display().to_string(),
|
||||
};
|
||||
let content = lines.join("\n");
|
||||
let message = error.to_string(&filename, &content, None, OutputFormat::Terminal(color));
|
||||
eprintln!("{}: {}\n", get_prefix(warning, color), message);
|
||||
/// Displays a lint warning.
|
||||
pub fn warn_lint<E: DisplaySourceError>(&self, content: &str, filename: &str, error: &E) {
|
||||
let message = error.to_string(
|
||||
filename,
|
||||
content,
|
||||
None,
|
||||
OutputFormat::Terminal(self.format == Format::Ansi),
|
||||
);
|
||||
|
||||
let mut s = StyledString::new();
|
||||
s.push_with("warning", Style::new().yellow().bold());
|
||||
s.push(": ");
|
||||
s.push(&message);
|
||||
s.push("\n");
|
||||
eprintln!("{}", s.to_string(self.format));
|
||||
}
|
||||
}
|
||||
fn get_prefix(warning: bool, color: bool) -> String {
|
||||
let mut message = StyledString::new();
|
||||
if warning {
|
||||
message.push_with("warning", Style::new().yellow().bold());
|
||||
} else {
|
||||
message.push_with("error", Style::new().red());
|
||||
};
|
||||
let fmt = if color { Format::Ansi } else { Format::Plain };
|
||||
message.to_string(fmt)
|
||||
}
|
||||
|
@ -15,9 +15,8 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
pub use self::fs::read_to_string;
|
||||
pub use self::logger::{make_logger_linter_error, Logger};
|
||||
pub use self::logger::Logger;
|
||||
|
||||
mod fs;
|
||||
mod logger;
|
||||
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Hurl (https://hurl.dev)
|
||||
* Copyright (C) 2024 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;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Error {
|
||||
pub source_info: SourceInfo,
|
||||
pub inner: LinterError,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum LinterError {
|
||||
UnnecessarySpace,
|
||||
UnnecessaryJsonEncoding,
|
||||
OneSpace,
|
||||
}
|
@ -18,36 +18,46 @@
|
||||
use hurl_core::ast::SourceInfo;
|
||||
use hurl_core::error;
|
||||
use hurl_core::error::DisplaySourceError;
|
||||
use hurl_core::text::StyledString;
|
||||
use hurl_core::text::{Style, StyledString};
|
||||
|
||||
use crate::linter;
|
||||
use crate::linter::LinterError;
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct LinterError {
|
||||
pub source_info: SourceInfo,
|
||||
pub kind: LinterErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum LinterErrorKind {
|
||||
UnnecessarySpace,
|
||||
UnnecessaryJsonEncoding,
|
||||
OneSpace,
|
||||
}
|
||||
|
||||
///
|
||||
/// Textual Output for linter errors
|
||||
///
|
||||
impl DisplaySourceError for linter::Error {
|
||||
impl DisplaySourceError for LinterError {
|
||||
fn source_info(&self) -> SourceInfo {
|
||||
self.source_info
|
||||
}
|
||||
|
||||
fn description(&self) -> String {
|
||||
match self.inner {
|
||||
LinterError::UnnecessarySpace => "Unnecessary space".to_string(),
|
||||
LinterError::UnnecessaryJsonEncoding => "Unnecessary json encoding".to_string(),
|
||||
LinterError::OneSpace => "One space ".to_string(),
|
||||
match self.kind {
|
||||
LinterErrorKind::UnnecessarySpace => "Unnecessary space".to_string(),
|
||||
LinterErrorKind::UnnecessaryJsonEncoding => "Unnecessary json encoding".to_string(),
|
||||
LinterErrorKind::OneSpace => "One space".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn fixme(&self, content: &[&str]) -> StyledString {
|
||||
let message = match self.inner {
|
||||
LinterError::UnnecessarySpace => "Remove space".to_string(),
|
||||
LinterError::UnnecessaryJsonEncoding => "Use Simple String".to_string(),
|
||||
LinterError::OneSpace => "Use only one space".to_string(),
|
||||
let message = match self.kind {
|
||||
LinterErrorKind::UnnecessarySpace => "Remove space".to_string(),
|
||||
LinterErrorKind::UnnecessaryJsonEncoding => "Use Simple String".to_string(),
|
||||
LinterErrorKind::OneSpace => "Use only one space".to_string(),
|
||||
};
|
||||
let mut s = StyledString::new();
|
||||
let message = error::add_carets(&message, self.source_info(), content);
|
||||
s.push(&message);
|
||||
s.push_with(&message, Style::new().cyan());
|
||||
s
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
*/
|
||||
pub use rules::{check_hurl_file, lint_hurl_file};
|
||||
|
||||
pub use self::core::{Error, LinterError};
|
||||
mod core;
|
||||
pub use self::error::{LinterError, LinterErrorKind};
|
||||
mod error;
|
||||
mod rules;
|
||||
|
@ -15,13 +15,12 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use crate::linter::{LinterError, LinterErrorKind};
|
||||
use hurl_core::ast::*;
|
||||
use hurl_core::reader::Pos;
|
||||
|
||||
use crate::linter::core::{Error, LinterError};
|
||||
|
||||
/// Returns lint errors for the `hurl_file`.
|
||||
pub fn check_hurl_file(hurl_file: &HurlFile) -> Vec<Error> {
|
||||
pub fn check_hurl_file(hurl_file: &HurlFile) -> Vec<LinterError> {
|
||||
hurl_file.entries.iter().flat_map(check_entry).collect()
|
||||
}
|
||||
|
||||
@ -33,7 +32,7 @@ pub fn lint_hurl_file(hurl_file: &HurlFile) -> HurlFile {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_entry(entry: &Entry) -> Vec<Error> {
|
||||
fn check_entry(entry: &Entry) -> Vec<LinterError> {
|
||||
let mut errors = vec![];
|
||||
errors.append(&mut check_request(&entry.request));
|
||||
match &entry.response {
|
||||
@ -49,23 +48,24 @@ fn lint_entry(entry: &Entry) -> Entry {
|
||||
Entry { request, response }
|
||||
}
|
||||
|
||||
fn check_request(request: &Request) -> Vec<Error> {
|
||||
fn check_request(request: &Request) -> Vec<LinterError> {
|
||||
let mut errors = vec![];
|
||||
if !request.space0.value.is_empty() {
|
||||
errors.push(Error {
|
||||
errors.push(LinterError {
|
||||
source_info: request.space0.source_info,
|
||||
inner: LinterError::UnnecessarySpace,
|
||||
kind: LinterErrorKind::UnnecessarySpace,
|
||||
});
|
||||
}
|
||||
if request.space1.value != " " {
|
||||
errors.push(Error {
|
||||
errors.push(LinterError {
|
||||
source_info: request.space1.source_info,
|
||||
inner: LinterError::OneSpace,
|
||||
kind: LinterErrorKind::OneSpace,
|
||||
});
|
||||
}
|
||||
for error in check_line_terminator(&request.line_terminator0) {
|
||||
errors.push(error);
|
||||
}
|
||||
errors.extend(request.sections.iter().flat_map(check_section));
|
||||
errors
|
||||
}
|
||||
|
||||
@ -97,14 +97,15 @@ fn lint_request(request: &Request) -> Request {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_response(response: &Response) -> Vec<Error> {
|
||||
fn check_response(response: &Response) -> Vec<LinterError> {
|
||||
let mut errors = vec![];
|
||||
if !response.space0.value.is_empty() {
|
||||
errors.push(Error {
|
||||
errors.push(LinterError {
|
||||
source_info: response.space0.source_info,
|
||||
inner: LinterError::UnnecessarySpace,
|
||||
kind: LinterErrorKind::UnnecessarySpace,
|
||||
});
|
||||
}
|
||||
errors.extend(response.sections.iter().flat_map(check_section));
|
||||
errors
|
||||
}
|
||||
|
||||
@ -134,6 +135,20 @@ fn lint_response(response: &Response) -> Response {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_section(section: &Section) -> Vec<LinterError> {
|
||||
let mut errors = vec![];
|
||||
if !section.space0.value.is_empty() {
|
||||
errors.push(LinterError {
|
||||
source_info: section.space0.source_info,
|
||||
kind: LinterErrorKind::UnnecessarySpace,
|
||||
});
|
||||
}
|
||||
for error in check_line_terminator(§ion.line_terminator0) {
|
||||
errors.push(error);
|
||||
}
|
||||
errors
|
||||
}
|
||||
|
||||
fn lint_section(section: &Section) -> Section {
|
||||
let line_terminators = section.line_terminators.clone();
|
||||
let line_terminator0 = section.line_terminator0.clone();
|
||||
@ -568,15 +583,15 @@ fn one_whitespace() -> Whitespace {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_line_terminator(line_terminator: &LineTerminator) -> Vec<Error> {
|
||||
fn check_line_terminator(line_terminator: &LineTerminator) -> Vec<LinterError> {
|
||||
let mut errors = vec![];
|
||||
match &line_terminator.comment {
|
||||
Some(_) => {}
|
||||
None => {
|
||||
if !line_terminator.space0.value.is_empty() {
|
||||
errors.push(Error {
|
||||
errors.push(LinterError {
|
||||
source_info: line_terminator.space0.source_info,
|
||||
inner: LinterError::UnnecessarySpace,
|
||||
kind: LinterErrorKind::UnnecessarySpace,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use hurlfmt::{cli, curl, format, linter};
|
||||
const EXIT_OK: i32 = 0;
|
||||
const EXIT_ERROR: i32 = 1;
|
||||
const EXIT_INVALID_INPUT: i32 = 2;
|
||||
const EXIT_LINT_ISSUE: i32 = 3;
|
||||
|
||||
/// Executes `hurlfmt` entry point.
|
||||
fn main() {
|
||||
@ -46,7 +47,7 @@ fn main() {
|
||||
},
|
||||
};
|
||||
|
||||
let mut logger = Logger::new(opts.color);
|
||||
let logger = Logger::new(opts.color);
|
||||
let mut output_all = String::new();
|
||||
|
||||
for input_file in &opts.input_files {
|
||||
@ -63,26 +64,23 @@ fn main() {
|
||||
}
|
||||
},
|
||||
};
|
||||
let input_path = Path::new(input_file).to_path_buf();
|
||||
let lines: Vec<&str> = regex::Regex::new(r"\n|\r\n")
|
||||
.unwrap()
|
||||
.split(&input)
|
||||
.collect();
|
||||
let lines: Vec<String> = lines.iter().map(|s| (*s).to_string()).collect();
|
||||
let log_linter_error =
|
||||
cli::make_logger_linter_error(lines, opts.color, Some(input_path));
|
||||
|
||||
match parser::parse_hurl_file(&input) {
|
||||
Err(e) => {
|
||||
logger.error_parsing_rich(&content, input_file, &e);
|
||||
logger.error_parsing(&content, input_file, &e);
|
||||
process::exit(EXIT_INVALID_INPUT);
|
||||
}
|
||||
Ok(hurl_file) => {
|
||||
if opts.check {
|
||||
for e in linter::check_hurl_file(&hurl_file).iter() {
|
||||
log_linter_error(e, true);
|
||||
let lints = linter::check_hurl_file(&hurl_file);
|
||||
for e in lints.iter() {
|
||||
logger.warn_lint(&content, input_file, e);
|
||||
}
|
||||
if lints.is_empty() {
|
||||
process::exit(EXIT_OK);
|
||||
} else {
|
||||
process::exit(EXIT_LINT_ISSUE);
|
||||
}
|
||||
process::exit(1);
|
||||
} else {
|
||||
let output = match opts.output_format {
|
||||
OutputFormat::Hurl => {
|
||||
|
Loading…
Reference in New Issue
Block a user