Show source names in diagnostics

This commit is contained in:
2026-06-22 18:05:26 +09:00
parent cc5ab63922
commit a2a6dee025
6 changed files with 113 additions and 54 deletions
+43 -27
View File
@@ -1,7 +1,8 @@
use std::collections::BTreeMap;
use decodal_core::{
Data, Diagnostic, DiagnosticKind, EmptyLoader, Engine, LoadedSource, SourceLoader, Span,
Data, Diagnostic, DiagnosticKind, EmptyLoader, Engine, LoadedSource, SourceId, SourceLoader,
Span, format_diagnostic_with,
};
use wasm_bindgen::prelude::*;
@@ -24,11 +25,18 @@ fn encode_result(result: Result<String, String>) -> String {
fn evaluate_inner(source: &str) -> Result<String, String> {
let mut engine = Engine::new(EmptyLoader);
let module = engine
.add_root_source("playground", "playground", source)
.map_err(format_diagnostic)?;
let value = engine.eval_module(module).map_err(format_diagnostic)?;
let data = engine.materialize(&value).map_err(format_diagnostic)?;
let module = match engine.add_root_source("playground", "playground", source) {
Ok(module) => module,
Err(error) => return Err(format_diagnostic_with_root(&error, "playground")),
};
let value = match engine.eval_module(module) {
Ok(value) => value,
Err(error) => return Err(engine.format_diagnostic(&error)),
};
let data = match engine.materialize(&value) {
Ok(data) => data,
Err(error) => return Err(engine.format_diagnostic(&error)),
};
Ok(format_data(&data, 0))
}
@@ -48,11 +56,18 @@ fn evaluate_project_inner(entry: &str, files_json: &str) -> Result<String, Strin
.ok_or_else(|| format!("entry file `{entry}` was not found"))?;
let mut engine = Engine::new(VirtualLoader { files });
let module = engine
.add_root_source(entry.clone(), entry.clone(), &source)
.map_err(format_diagnostic)?;
let value = engine.eval_module(module).map_err(format_diagnostic)?;
let data = engine.materialize(&value).map_err(format_diagnostic)?;
let module = match engine.add_root_source(entry.clone(), entry.clone(), &source) {
Ok(module) => module,
Err(error) => return Err(format_diagnostic_with_root(&error, &entry)),
};
let value = match engine.eval_module(module) {
Ok(value) => value,
Err(error) => return Err(engine.format_diagnostic(&error)),
};
let data = match engine.materialize(&value) {
Ok(data) => data,
Err(error) => return Err(engine.format_diagnostic(&error)),
};
Ok(format_data(&data, 0))
}
@@ -124,22 +139,10 @@ fn normalize_path(path: &str) -> Option<String> {
}
}
fn format_diagnostic(diagnostic: decodal_core::Diagnostic) -> String {
let mut out = format!(
"{:?} at {}:{}..{}: {}",
diagnostic.kind,
diagnostic.span.source.0,
diagnostic.span.start,
diagnostic.span.end,
diagnostic.message,
);
for label in diagnostic.labels {
out.push_str(&format!(
"\nnote at {}:{}..{}: {}",
label.span.source.0, label.span.start, label.span.end, label.message,
));
}
out
fn format_diagnostic_with_root(diagnostic: &decodal_core::Diagnostic, root_name: &str) -> String {
format_diagnostic_with(diagnostic, |source| {
(source == SourceId(0)).then_some(root_name)
})
}
fn format_data(data: &Data, indent: usize) -> String {
@@ -237,4 +240,17 @@ mod tests {
let output = evaluate_project_inner("main.dcdl", files).unwrap();
assert!(output.contains("\"port\": 9443"));
}
#[test]
fn project_diagnostics_use_virtual_file_names() {
let files = r#"{
"main.dcdl":"let dep = import \"./schemas/service.dcdl\"; in dep.Service & { port = 80; }",
"schemas/service.dcdl":"Service = { port = Int & > 443 default 8443; }"
}"#;
let error = evaluate_project_inner("main.dcdl", files).unwrap_err();
assert!(error.contains("main.dcdl:"));
assert!(error.contains("schemas/service.dcdl:"));
assert!(!error.contains("source 0:"));
assert!(!error.contains("source 1:"));
}
}