Skip to content

Commit

Permalink
Add error report feature to cynic-parser (#833)
Browse files Browse the repository at this point in the history
It's not perfect but it is a start
  • Loading branch information
obmarg authored Jan 21, 2024
1 parent f699ef2 commit 7388e4a
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 3 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion cynic-parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ publish = false
[features]
default = []
print = ["pretty"]
report = ["ariadne"]

[dependencies]
indexmap = "2"
lalrpop-util = "0.20.0"
logos = "0.13"

ariadne = { version = "0.4", optional = true }
pretty = { version = "0.12", optional = true }

[dev-dependencies]
Expand All @@ -23,7 +26,7 @@ insta = "1.29"
similar-asserts = "1.5"

# Tests need the `print` functionality so enable it here
cynic-parser = { path = ".", features = ["print"] }
cynic-parser = { path = ".", features = ["print", "report"] }

[build-dependencies]
# Commenting this out as parser-generator does this.
Expand Down
4 changes: 2 additions & 2 deletions cynic-parser/src/ast/span.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Span {
start: usize,
end: usize,
pub start: usize,
pub end: usize,
}

impl Span {
Expand Down
6 changes: 6 additions & 0 deletions cynic-parser/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#[cfg(feature = "report")]
mod report;

use std::fmt;

#[cfg(feature = "report")]
pub use report::Report;

use crate::{
lexer::{self, LexicalError},
Span,
Expand Down
86 changes: 86 additions & 0 deletions cynic-parser/src/errors/report.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use core::fmt;

use ariadne::{Config, Label, ReportKind, Source};

use crate::Error;

pub struct Report<'doc> {
inner: ariadne::Report<'static>,
document: &'doc str,
}

impl Error {
pub fn to_report<'a>(&self, document: &'a str) -> Report<'a> {
let (message, label, note) = self.components();

let mut builder = ariadne::Report::build(ReportKind::Error, (), 0)
.with_code(3)
.with_message(message)
.with_label(label)
.with_config(Config::default().with_color(false));

if let Some(note) = note {
builder.set_note(note)
}

let inner = builder.finish();

Report { inner, document }
}

fn components(&self) -> (String, Label, Option<String>) {
match self {
Error::InvalidToken { location } => (
"invalid token".into(),
Label::new(*location..*location).with_message("could not understand this token"),
None,
),
Error::UnrecognizedEof { location, expected } => (
"unexpected eof".into(),
Label::new(*location..*location).with_message("expected another token here"),
Some(format!("expected one of {}", expected.join(", "))),
),
Error::UnrecognizedToken {
token: (start, token, end),
expected,
} => (
format!("unexpected {}", token),
Label::new(*start..*end).with_message("didn't expect to see this"),
Some(format!("expected one of {}", expected.join(", "))),
),
Error::ExtraToken {
token: (start, token, end),
} => (
format!("extra {}", token),
Label::new(*start..*end).with_message("we expected the document to end here"),
None,
),
Error::User { error } => {
let span = error.span();
(
"invalid token".into(),
Label::new(span.start..span.end).with_message("could not parse a token here"),
None,
)
}
}
}
}

impl fmt::Display for Report<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut output = Vec::<u8>::new();
self.inner
.write(Source::from(self.document), &mut output)
.unwrap();
let s = String::from_utf8_lossy(&output);

write!(f, "{s}")
}
}

impl fmt::Debug for Report<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
22 changes: 22 additions & 0 deletions cynic-parser/tests/report.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use cynic_parser::Error;

#[test]
fn test_report() {
let document = "type Blah {}";
let report = cynic_parser::parse_type_system_document(document)
.map(|_| ())
.unwrap_err()
.to_report(document);

insta::assert_display_snapshot!(report, @r###"
[03] Error: unexpected closing brace ('}')
╭─[<unknown>:1:1]
1 │ type Blah {}
│ ┬
│ ╰── didn't expect to see this
│ Note: expected one of "enum", BlockStringLiteral, RawIdent, StringLiteral, directive, extend, false, implements, input, interface, mutation, null, on, query, repeatable, scalar, schema, subscription, true, ty, union
───╯
"###);
}

0 comments on commit 7388e4a

Please sign in to comment.