Merge pull request 'feature/return-highlight-error' (#22) from feature/return-highlight-error into main

Reviewed-on: #22
This commit is contained in:
hendrik 2025-02-09 16:18:15 +00:00
commit 9e53289731
7 changed files with 205 additions and 70 deletions

View File

@ -3,6 +3,9 @@
use strum_macros::Display;
use thiserror::Error;
#[derive(Error, Debug, Display)]
// TODO: NonYamlError is prob wrong - i may wanna collect here eyerything that i dont know where to put otherwise
pub enum NonYamlError {
Io(#[from] std::io::Error),
ScanError(#[from] yaml_rust2::ScanError),
NoYamlFound,
}

67
src/code/highlight.rs Normal file
View File

@ -0,0 +1,67 @@
use serde::Serialize;
use wasm_bindgen::prelude::wasm_bindgen;
use crate::error::validate::ValidationError;
#[wasm_bindgen]
#[derive(Serialize, Clone, Copy)]
pub enum HighlightErrorSeverity {
Error = 1,
Warning = 2,
Information = 3,
Hint = 4,
}
#[wasm_bindgen]
pub struct HighlightError {
message: String,
start: usize,
end: usize,
severity: HighlightErrorSeverity,
}
#[wasm_bindgen]
impl HighlightError {
#[wasm_bindgen(constructor)]
pub fn new(
message: String,
start: usize,
end: usize,
severity: HighlightErrorSeverity,
) -> HighlightError {
HighlightError {
message,
start,
end,
severity,
}
}
#[wasm_bindgen(getter)]
pub fn message(&self) -> String {
self.message.clone()
}
#[wasm_bindgen(getter)]
pub fn start(&self) -> usize {
self.start
}
#[wasm_bindgen(getter)]
pub fn end(&self) -> usize {
self.end
}
#[wasm_bindgen(getter)]
pub fn severity(&self) -> HighlightErrorSeverity {
self.severity
}
}
impl From<(usize, usize, ValidationError)> for HighlightError {
fn from((start, end, error): (usize, usize, ValidationError)) -> Self {
Self {
message: error.to_string(),
start,
end,
severity: HighlightErrorSeverity::Error,
}
}
}

1
src/code/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod highlight;

View File

@ -1,6 +1,8 @@
use log::info;
use yaml_rust2::Yaml;
use crate::{
add_err::NonYamlError,
error::{validate::ValidationError, with_context::WError},
parser::{
facade::{ParLoader, YamlLoad},
@ -20,32 +22,37 @@ pub struct YamlWrapper<'a> {
yaml: Yaml,
location_map: Mark,
validation_result: Vec<WError<ValidationError>>,
marker_map: Vec<(usize, usize, ValidationError)>,
_marker_map: Vec<(usize, usize, ValidationError)>,
// TODO: needed? Since i kept the linebreaks, i could just use column and line to get the absolute position
// via let res = &self.raw_lines[line - 1][col..(col + len)]; (or first char - would be enough)
// and res.as_ptr() as usize - self.raw.as_ptr() as usize,
_removed_data: RemovedHandler,
}
impl<'a> YamlWrapper<'a> {
pub fn new(raw: &'a str) -> Self {
let ((yaml, location_map), removed_data) = Self::parse_yaml(raw);
let raw_lines = raw.lines().collect();
Self {
raw,
impl<'a> TryFrom<&'a str> for YamlWrapper<'a> {
type Error = NonYamlError;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
let ((yaml, location_map), removed_data) = Self::parse_yaml(value)?;
let raw_lines = value.lines().collect();
Ok(Self {
raw: value,
_removed_data: removed_data,
raw_lines,
yaml,
location_map,
validation_result: Vec::new(),
marker_map: Vec::new(),
}
_marker_map: Vec::new(),
})
}
}
impl<'a> YamlWrapper<'a> {
fn get_pos_in_raw(&self, line: usize, col: usize) -> usize {
let lines = &self.raw_lines;
if line > lines.len() - 1 {
return self.raw.len() - 1;
if line > lines.len() {
return self.raw.len() - 2;
}
let line_to_find_in = lines[line - 1];
@ -57,32 +64,38 @@ impl<'a> YamlWrapper<'a> {
}
}
fn parse_yaml(raw: &'a str) -> ((Yaml, Mark), RemovedHandler) {
fn parse_yaml(raw: &'a str) -> Result<((Yaml, Mark), RemovedHandler), NonYamlError> {
let mut iter_handler = IterHandler::new(raw);
let parsed_data = ParLoader::load_from_iter(iter_handler.comment_removed_iter())
.unwrap()
let parsed_data = ParLoader::load_from_iter(iter_handler.comment_removed_iter())?
.into_iter()
.next()
.unwrap();
.ok_or(NonYamlError::NoYamlFound)?;
let positions = iter_handler.removed().to_vec();
(parsed_data, positions.into())
Ok((parsed_data, positions.into()))
}
pub fn validate_yml<'b: 'a>(&mut self, context: &'b SchemaCache<'b>) {
pub fn validate_yml<'b: 'a>(
&mut self,
context: &SchemaCache<'b>,
) -> Vec<(usize, usize, ValidationError)> {
let validation_result = context.validate_yaml(&self.yaml);
if let Err(e) = validation_result {
self.validation_result = e;
}
self.construct_marker_map();
self.construct_marker_map()
}
fn get_range_for_scalar(&self, scalar: &Mark) -> (usize, usize) {
assert!(matches!(scalar, Mark::Scalar(_, _)));
let (line, col, len) = scalar.get_first_token_range();
info!(
"First token in range Line: {:?}, Col: {:?}, Len: {:?}",
line, col, len
);
let index = self.get_pos_in_raw(line, col);
(index, index + len)
(index, (index + len).min(self.raw.len()))
}
fn traverse_path<'b>(
@ -121,28 +134,35 @@ impl<'a> YamlWrapper<'a> {
}
}
fn construct_marker_map(&mut self) {
for e in self.validation_result.iter() {
let mut cloned_path = e.path().clone();
if cloned_path.empty() {
println!("highlighting first characters?");
// TODO: think of sth else
self.marker_map.push((0, 1, e.src().clone()));
continue;
}
let mut yaml = &self.yaml;
let mut marker = &self.location_map;
let mut current_segment = cloned_path.shift().unwrap();
while !cloned_path.empty() {
(_, marker, yaml) = Self::traverse_path(current_segment, yaml, marker);
current_segment = cloned_path.shift().unwrap();
}
fn construct_marker_map(&self) -> Vec<(usize, usize, ValidationError)> {
self.validation_result
.iter()
.map(|e| {
let mut cloned_path = e.path().clone();
info!("Path: {:?}; Handling: {:?}", cloned_path, e);
if cloned_path.empty() {
info!("{:?} highlighting first characters?", e);
// TODO: think of sth else
(0, 1, e.src().clone())
} else {
let mut yaml = &self.yaml;
let mut marker = &self.location_map;
let mut current_segment = cloned_path.shift().unwrap();
while !cloned_path.empty() {
(_, marker, yaml) = Self::traverse_path(current_segment, yaml, marker);
current_segment = cloned_path.shift().unwrap();
}
(marker, _, _) = Self::traverse_path(current_segment, yaml, marker);
let position = self.get_range_for_scalar(marker);
self.marker_map
.push((position.0, position.1, e.src().clone()));
}
(marker, _, _) = Self::traverse_path(current_segment, yaml, marker);
info!(
"{:?} highlighting scalar- len: {:?}",
marker,
self.raw.len()
);
let position = self.get_range_for_scalar(marker);
(position.0, position.1, e.src().clone())
}
})
.collect()
}
}

View File

@ -1,4 +1,5 @@
pub mod add_err;
pub mod code;
pub mod error;
pub mod input;
pub mod log_helper;

View File

@ -1,3 +1,4 @@
use log::info;
use yaml_rust2::{
parser::{MarkedEventReceiver, Parser},
scanner::Marker,
@ -72,6 +73,16 @@ spam:
foom
"#;
const add_kw: &str = r#"id: DEMO.administration
objectType: pageContainer
data:
variables:
tes:
type: string
value: "test"
pi: d
"#;
const COMMENT_TEST: &str = r#"
key1: \#value1
key2: "this is # not a comment"
@ -127,6 +138,45 @@ const INCOMPLETE_YAML: &str = r#"data:
type: string
value: TEST"#;
fn test_with_page_for_str(content: &str) {
let schemas_to_parse = SCHEMA_PATHS;
let schemas = schemas_to_parse
.iter()
.map(|path| {
(
file_to_name(path),
YamlLoader::load_from_str(&Reader::from_file(path).unwrap()).unwrap(),
)
})
.collect::<Vec<_>>();
let mut storage = storage::SchemaCache::new();
for (nam, yaml) in &schemas {
let n = yaml.len();
if yaml.len() != 1 {
panic!("only one document per file is allowed - found {n} in {nam}");
}
let parsed_schema: Result<Schema, _> = (&yaml[0]).try_into();
storage.add_schema(nam, parsed_schema.unwrap());
}
let mut wrapper = YamlWrapper::try_from(content).unwrap();
let error = wrapper.validate_yml(&storage);
for (st, en, err) in error {
info!("Error:({}, {}) {:?}", st, en, err);
println!(
"Pos: ({:?}..{:?}) = ({:?}: Error: {:?}",
st,
en,
&content[st..en],
err
);
}
}
pub struct EventSink {
events: Vec<(Event, Marker)>,
loader: YamlLoader,
@ -140,7 +190,8 @@ impl MarkedEventReceiver for EventSink {
pub fn do_sth() {
//com();
my_own();
//my_own();
test_with_page_for_str(add_kw);
}
fn com() {
@ -171,7 +222,7 @@ pub fn my_own() {
// panic!("stop");
let schema = SCHEMA;
let schemas_to_parse = SCHEMA_MATCH;
let mut wrapper = YamlWrapper::new(schemas_to_parse);
let mut wrapper = YamlWrapper::try_from(schemas_to_parse).unwrap();
let schema_yaml = YamlLoader::load_from_str(schema).unwrap()[0].clone();
let schema_onj = (&schema_yaml).try_into().unwrap();
let name = "page.schema.json";
@ -206,8 +257,8 @@ fn my_own5() {
let test_yaml_paths = vec![TEST[0]];
for test_yaml_path in test_yaml_paths {
let content = &Reader::from_file(test_yaml_path).unwrap();
let mut wrapper = YamlWrapper::new(content);
let content = Reader::from_file(test_yaml_path).unwrap();
let mut wrapper = YamlWrapper::try_from(content.as_str()).unwrap();
wrapper.validate_yml(&storage);
}
}

View File

@ -5,6 +5,8 @@ use wasm_bindgen::prelude::wasm_bindgen;
use yaml_rust2::{Yaml, YamlLoader};
use crate::{
code::highlight::HighlightError,
input::wrapper::YamlWrapper,
read::{file_to_name, Reader, SCHEMA_PATHS},
schema::storage::{self, SchemaCache},
};
@ -31,7 +33,7 @@ pub fn load_context() {
.map(|path| {
(
file_to_name(path),
YamlLoader::load_from_str(&Reader::from_file(path).unwrap()).unwrap(),
YamlLoader::load_from_str(&Reader::from_file_mock(path).unwrap()).unwrap(),
)
})
.collect::<Vec<_>>();
@ -50,35 +52,25 @@ pub fn load_context() {
let mut context = CONTEXT.lock().unwrap();
*context = Some(storage);
console_log("context loaded");
info!("context loaded");
}
#[wasm_bindgen]
pub fn get_highlighting(yaml: &str) {
if let Some(test_yaml) = construct_yaml(yaml) {
let context = CONTEXT.lock().unwrap();
let val_res = context.as_ref().unwrap().validate_yaml(&test_yaml);
match val_res {
Ok(_) => debug!("Valid"),
Err(e) => {
for err in e {
info!("{:?}", err);
}
}
pub fn get_highlighting(yaml: &str) -> Vec<HighlightError> {
if let Ok(mut test_yaml) = YamlWrapper::try_from(yaml) {
if CONTEXT.lock().unwrap().is_none() {
error!("Context not loaded");
load_context();
//return Vec::new();
}
}
}
fn construct_yaml(input: &str) -> Option<Yaml> {
let yaml = YamlLoader::load_from_str(input)
.inspect_err(|e| {
error!("{:?}", e);
})
.unwrap_or_default();
if yaml.is_empty() {
None
let context_guard = CONTEXT.lock().unwrap();
test_yaml
.validate_yml(context_guard.as_ref().unwrap())
.into_iter()
.map(|e| e.into())
.collect()
} else {
Some(yaml[0].clone())
Vec::new()
}
}