Skip to content

Commit

Permalink
Rework get_diagnostics function
Browse files Browse the repository at this point in the history
- Now accepts a list of errors instead of running parse/template directly
  • Loading branch information
kyleect committed Jan 12, 2025
1 parent 0887579 commit 8465451
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 134 deletions.
74 changes: 32 additions & 42 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use clap::{crate_authors, crate_description, crate_version, Arg, ArgMatches, Com
use reqlang::{parse, ParseResult};
use std::{collections::HashMap, fs, process::exit};

use reqlang::{diagnostics::Diagnoser, export, template, Format, ReqlangError, Spanned};
use reqlang::{diagnostics::get_diagnostics, export, template, Format};

use std::error::Error;

Expand All @@ -29,16 +29,6 @@ where
Ok((key, value))
}

fn map_errs(errs: &[Spanned<ReqlangError>]) -> String {
let err = errs
.iter()
.map(|x| format!("{} ({:?})", x.0, x.1))
.collect::<Vec<_>>()
.join("\n- ");

format!("Errors:\n\n- {err}")
}

fn export_command(matches: &ArgMatches) {
let path = matches.get_one::<String>("path").unwrap();

Expand All @@ -62,52 +52,52 @@ fn export_command(matches: &ArgMatches) {

let contents = fs::read_to_string(path).expect("Should have been able to read the file");

let diagnostics = Diagnoser::get_diagnostics_with_env(&contents, env, &prompts, &secrets);

if !diagnostics.is_empty() {
eprintln!("Invalid request file or errors when exporting");
let json = serde_json::to_string_pretty(&diagnostics).unwrap();
println!("{json}");
exit(1);
}

let provider_values = HashMap::from([(String::from("env"), env.clone())]);

let reqfile = template(&contents, env, &prompts, &secrets, &provider_values);

let reqfile = match reqfile {
Ok(reqfile) => reqfile,
match reqfile {
Ok(reqfile) => {
let exported_request = export(&reqfile.request, format);

println!("{}", exported_request);
}
Err(errs) => {
let err = map_errs(&errs);
eprintln!("{err}");
exit(1);
let diagnostics = get_diagnostics(&errs, &contents);

if !diagnostics.is_empty() {
eprintln!("Invalid request file or errors when exporting");
let json = serde_json::to_string_pretty(&diagnostics).unwrap();
println!("{json}");
exit(1);
}
}
};

let exported_request = export(&reqfile.request, format);

println!("{}", exported_request);
}

fn parse_command(matches: &ArgMatches) {
let path = matches.get_one::<String>("path").unwrap();
let contents = fs::read_to_string(path).expect("Should have been able to read the file");

let diagnostics = Diagnoser::get_diagnostics(&contents);

if !diagnostics.is_empty() {
eprintln!("Invalid request file");
let json = serde_json::to_string_pretty(&diagnostics).unwrap();
println!("{json}");
exit(1);
}

let parsed_reqfile = parse(&contents).unwrap();
let parse_results: ParseResult = parsed_reqfile.into();
match parse(&contents) {
Ok(parsed_reqfile) => {
let parse_results: ParseResult = parsed_reqfile.into();

let json = serde_json::to_string_pretty(&parse_results).unwrap();
let json = serde_json::to_string_pretty(&parse_results).unwrap();

println!("{json}");
println!("{json}");
}
Err(errs) => {
let diagnostics = get_diagnostics(&errs, &contents);

if !diagnostics.is_empty() {
eprintln!("Invalid request file");
let json = serde_json::to_string_pretty(&diagnostics).unwrap();
println!("{json}");
exit(1);
}
}
}
}

fn main() {
Expand Down
84 changes: 27 additions & 57 deletions diagnostics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,33 @@
use std::collections::HashMap;

use codespan_reporting::diagnostic::{Diagnostic, Label};
use errors::{ParseError, ReqlangError, ResolverError};
use parser::template;
use serde::{Deserialize, Serialize};
use span::Span;
use span::{Span, Spanned};
use str_idxpos::index_to_position;

#[derive(Debug, Default)]
pub struct Diagnoser {}

impl Diagnoser {
pub fn get_diagnostics(source: &str) -> Vec<Diagnosis> {
match parser::parse(source) {
Ok(_) => vec![],
Err(errs) => {
return errs
.iter()
.map(|(err, span)| Diagnosis {
range: Diagnoser::get_range(source, span),
severity: Some(DiagnosisSeverity::ERROR),
message: err.to_string(),
})
.collect();
}
}
}

pub fn get_diagnostics_with_env(
source: &str,
env: &str,
prompts: &HashMap<String, String>,
secrets: &HashMap<String, String>,
) -> Vec<Diagnosis> {
match template(source, env, prompts, secrets, &HashMap::new()) {
Ok(_) => vec![],
Err(errs) => {
return errs
.iter()
.map(|(err, span)| Diagnosis {
range: Diagnoser::get_range(source, span),
severity: Some(DiagnosisSeverity::ERROR),
message: err.to_string(),
})
.collect();
}
}
}
/// Get a list of diagnostics from a list of errors
pub fn get_diagnostics(errs: &[Spanned<ReqlangError>], source: &str) -> Vec<Diagnosis> {
errs.iter()
.map(|(err, span)| Diagnosis {
range: get_range(source, span),
severity: Some(DiagnosisSeverity::ERROR),
message: err.to_string(),
})
.collect()
}

pub fn get_range(source: &str, span: &Span) -> DiagnosisRange {
DiagnosisRange {
start: Diagnoser::get_position(source, span.start),
end: Diagnoser::get_position(source, span.end),
}
fn get_range(source: &str, span: &Span) -> DiagnosisRange {
DiagnosisRange {
start: get_position(source, span.start),
end: get_position(source, span.end),
}
}

pub fn get_position(source: &str, idx: usize) -> DiagnosisPosition {
let (line, character) = index_to_position(source, idx);
fn get_position(source: &str, idx: usize) -> DiagnosisPosition {
let (line, character) = index_to_position(source, idx);

DiagnosisPosition {
line: line as u32,
character: character as u32,
}
DiagnosisPosition {
line: line as u32,
character: character as u32,
}
}

Expand Down Expand Up @@ -143,12 +109,16 @@ impl AsDiagnostic for ReqlangError {

#[cfg(test)]
mod tests {
use crate::{Diagnoser, Diagnosis, DiagnosisPosition, DiagnosisRange, DiagnosisSeverity};
use parser::parse;

use crate::{get_diagnostics, Diagnosis, DiagnosisPosition, DiagnosisRange, DiagnosisSeverity};

#[test]
fn it_works() {
let source = String::from("");

let errs = parse(&source).unwrap_err();

assert_eq!(
vec![Diagnosis {
range: DiagnosisRange {
Expand All @@ -164,7 +134,7 @@ mod tests {
severity: Some(DiagnosisSeverity::ERROR),
message: String::from("ParseError: Request file is an empty file")
}],
Diagnoser::get_diagnostics(&source)
get_diagnostics(&errs, &source)
);
}
}
6 changes: 3 additions & 3 deletions errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use thiserror::Error;
use types::ReferenceType;

/// Common error for parsing and templating request files
#[derive(Debug, Error, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Error, PartialEq, Serialize, Deserialize)]
pub enum ReqlangError {
#[error("ParseError: {0}")]
ParseError(ParseError),
#[error("ResolverError: {0}")]
ResolverError(ResolverError),
}

#[derive(Debug, Error, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Error, PartialEq, Serialize, Deserialize)]
pub enum ParseError {
#[error("Request file is an empty file")]
EmptyFileError,
Expand All @@ -33,7 +33,7 @@ pub enum ParseError {
ForbiddenRequestHeaderNameError(String),
}

#[derive(Debug, Error, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Error, PartialEq, Serialize, Deserialize)]
pub enum ResolverError {
#[error("Invalid env: {0}")]
InvalidEnvError(String),
Expand Down
61 changes: 30 additions & 31 deletions reqlang-lsp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use std::ops::Deref;
use anyhow::{Context, Result};
use reqlang::{
assert_response::assert_response,
diagnostics::{Diagnoser, Diagnosis, DiagnosisPosition, DiagnosisRange, DiagnosisSeverity},
diagnostics::{
get_diagnostics, Diagnosis, DiagnosisPosition, DiagnosisRange, DiagnosisSeverity,
},
export, parse, template, Fetch, Format, HttpRequestFetcher, ParseResult, ReqlangError,
RequestParamsFromClient, Spanned,
};
Expand Down Expand Up @@ -92,50 +94,47 @@ impl LanguageServer for Backend {
let mut file_texts = self.file_texts.lock().await;
file_texts.insert(uri.clone(), source.clone());

let result: Result<ParseResult, Vec<Spanned<ReqlangError>>> =
parse(&source).map(|unresolved_reqfile| {
let result: ParseResult = unresolved_reqfile.into();
let result: Result<ParseResult, _> = parse(&source).map(|reqfile| reqfile.into());

result
});
if let Err(errs) = &result {
self.client
.publish_diagnostics(
uri.clone(),
get_diagnostics(errs, &source)
.iter()
.map(|x| (LspDiagnosis((*x).clone())).into())
.collect(),
Some(params.text_document.version),
)
.await;
}

self.client
.send_notification::<ParseNotification>(ParseNotificationParams::new(
uri.clone(),
result,
))
.await;

let version = Some(params.text_document.version);
let diagnostics = Diagnoser::get_diagnostics(&source);
self.client
.publish_diagnostics(
uri.clone(),
diagnostics
.iter()
.map(|x| (LspDiagnosis((*x).clone())).into())
.collect(),
version,
)
.await;
}

async fn did_change(&self, params: DidChangeTextDocumentParams) {
let uri = params.text_document.uri;
let source = &params.content_changes.first().unwrap().text;

let version = Some(params.text_document.version);
let diagnostics = Diagnoser::get_diagnostics(source);
self.client
.publish_diagnostics(
uri,
diagnostics
.iter()
.map(|x| LspDiagnosis((*x).clone()).into())
.collect(),
version,
)
.await;
let result: Result<ParseResult, _> = parse(source).map(|reqfile| reqfile.into());

if let Err(errs) = &result {
self.client
.publish_diagnostics(
uri.clone(),
get_diagnostics(errs, source)
.iter()
.map(|x| (LspDiagnosis((*x).clone())).into())
.collect(),
Some(params.text_document.version),
)
.await;
}
}

async fn did_save(&self, params: DidSaveTextDocumentParams) {
Expand Down
2 changes: 1 addition & 1 deletion types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ impl From<Value> for RequestParamsFromClient {
/// A simplified version of a [ParsedRequestFile]
///
/// This is useful for language server clients
#[derive(Debug, Deserialize, Serialize, PartialEq, TS)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)]
#[ts(export)]
pub struct ParseResult {
pub vars: Vec<String>,
Expand Down

0 comments on commit 8465451

Please sign in to comment.