Skip to content

Commit

Permalink
feat: add parser spans
Browse files Browse the repository at this point in the history
  • Loading branch information
TheEdward162 committed Jan 11, 2024
1 parent fb3cf3c commit e30df5d
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 177 deletions.
22 changes: 11 additions & 11 deletions core/comlink/src/typescript_parser/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct Diagnostic {
pub severity: DiagnosticSeverity,
pub code: u16,
pub message: String,
pub range: TextSpan,
pub span: TextSpan,
}

#[repr(u16)]
Expand All @@ -37,16 +37,16 @@ impl DiagnosticCode {
pub fn description(&self) -> &'static str {
match self {
Self::Unknown => "Unknown",
Self::GlobalTypeUnknown => "Global type is unknown",
Self::GlobalTypeInvalid => "Global type is invalid or missing",
Self::UseCaseInvalid => "Use case options are invalid or missing",
Self::UseCaseNameInvalid => "Use case name is invalid or missing",
Self::UseCaseMemberUnknown => "Use case member is unknown",
Self::UseCaseMemberInvalid => "Use case member is invalid or missing",
Self::UseCaseExamplesArrayInvalid => "Use case examples array is invalid",
Self::UseCaseExampleInvalid => "Use case example is invalid",
Self::UseCaseExampleMemberUnknown => "Use case example member is unknown",
Self::UseCaseExampleMemberInvalid => "Use case example member is invalid or missing",
Self::GlobalTypeUnknown => "Global type unknown",
Self::GlobalTypeInvalid => "Global type error",
Self::UseCaseInvalid => "Use case options error",
Self::UseCaseNameInvalid => "Use case name error",
Self::UseCaseMemberUnknown => "Use case member unknown",
Self::UseCaseMemberInvalid => "Use case member error",
Self::UseCaseExamplesArrayInvalid => "Use case examples array error",
Self::UseCaseExampleInvalid => "Use case example error",
Self::UseCaseExampleMemberUnknown => "Use case example member unknown",
Self::UseCaseExampleMemberInvalid => "Use case example member error",
}
}
}
57 changes: 50 additions & 7 deletions core/comlink/src/typescript_parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,61 @@ mod diagnostic;
mod model;
mod parser;

pub use diagnostic::{Diagnostic, DiagnosticSeverity};
pub use model::{Documentation, Profile, UseCase, UseCaseExample, UseCaseSafety};
pub use diagnostic::{Diagnostic, DiagnosticSeverity, DiagnosticCode};
pub use model::{Documentation, Profile, UseCase, UseCaseExample, UseCaseSafety, ProfileSpans};

use crate::json::{JsonValue, JsonSchema};

use self::model::TextSpan;

/// Parse a profile from source text.
///
/// Returns a best-effort Profile structure and a list of errors encountered.
/// If the list of errors is empty then the parsing was successful.
pub fn parse_profile(source: &str) -> (Profile, Vec<Diagnostic>) {
let (profile, diagnostics) = parser::ProfileParser::parse(source);
pub fn parse_profile(source: &str) -> (Profile, ProfileSpans, Vec<Diagnostic>) {
let (profile, spans, mut diagnostics) = parser::ProfileParser::parse(source);

// TODO: check examples against input, result and error schemas
// TODO: any other checks?
for (usecase, usecase_spans) in profile.usecases.iter().zip(spans.usecases.iter()) {
for (example, example_spans) in usecase.examples.iter().zip(usecase_spans.examples.iter()) {
match example {
UseCaseExample::Success { input, result, .. } => {
check_profile_examples_schemas( &usecase.input, usecase_spans.input, input, example_spans.input, &mut diagnostics);
check_profile_examples_schemas( &usecase.result, usecase_spans.result, result, example_spans.output, &mut diagnostics);
}
UseCaseExample::Failure { input, error, .. } => {
check_profile_examples_schemas( &usecase.input, usecase_spans.input, input, example_spans.input, &mut diagnostics);
check_profile_examples_schemas( &usecase.error, usecase_spans.error, error, example_spans.output, &mut diagnostics);
}
}
}
}

(profile, diagnostics)
(profile, spans, diagnostics)
}

fn check_profile_examples_schemas(schema: &JsonSchema, schema_span: TextSpan, value: &JsonValue, value_span: TextSpan, diag: &mut Vec<Diagnostic>) {
let validator = match super::json_schema_validator::JsonSchemaValidator::new(schema) {
Ok(v) => v,
Err(err) => {
diag.push(Diagnostic {
severity: DiagnosticSeverity::Error,
code: DiagnosticCode::UseCaseInvalid as u16,
message: format!("{}: Generated schema is invalid: {}", DiagnosticCode::UseCaseInvalid.description(), err),
span: schema_span
});
return;
}
};

match validator.validate(value) {
Ok(()) => (),
Err(err) => {
diag.push(Diagnostic {
severity: DiagnosticSeverity::Error,
code: DiagnosticCode::UseCaseExampleInvalid as u16,
message: format!("{}: UseCase example doesn't match the schema: {}", DiagnosticCode::UseCaseExampleInvalid.description(), err),
span: value_span
});
}
}
}
41 changes: 38 additions & 3 deletions core/comlink/src/typescript_parser/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use serde::Serialize;

use crate::json::{JsonSchema, JsonValue};

pub type TextSpan = [usize; 2];
#[derive(Debug, Clone, Copy, Default, Serialize)]
#[serde(transparent)]
pub struct TextSpan(pub [usize; 2]);

#[derive(Debug, Default, Serialize)]
pub struct Documentation {
Expand Down Expand Up @@ -75,7 +77,40 @@ pub struct UseCase {
pub examples: Vec<UseCaseExample>,
}

#[derive(Debug, Default, Serialize)]
pub struct ProfileSpans {
/// Span of the whole profile document
pub document: TextSpan
/// Span of the entire profile document
pub entire: TextSpan,
/// Spans for individual use cases, same order as [Profile::usecases] vec
pub usecases: Vec<UseCaseSpans>
}
#[derive(Debug, Default, Serialize)]
pub struct UseCaseSpans {
/// Span of the entire use case
pub entire: TextSpan,
/// Span of the name text
pub name: TextSpan,
/// Span of the safety value
pub safety: TextSpan,
/// Span of the documentation
pub documentation: TextSpan,
/// Span of the input schema value
pub input: TextSpan,
/// Span of the result schema value
pub result: TextSpan,
/// Span of the error schema value
pub error: TextSpan,
/// Spans of examples, same order as [UseCase::examples]
pub examples: Vec<UseCaseExampleSpans>
}
#[derive(Debug, Default, Serialize)]
pub struct UseCaseExampleSpans {
/// Span of the entire exmaple
pub entire: TextSpan,
/// Span of the name value
pub name: TextSpan,
/// Span of the input value
pub input: TextSpan,
/// Span of the output value
pub output: TextSpan
}
Loading

0 comments on commit e30df5d

Please sign in to comment.