napi: Fix access to diagnostics

Invoking the diagnostics getter would throw an exception because the JsDiagnostic type has no constructor.

There's however no constructor that would allow for the previous
laziness, so instead this PR bites the bullet:

- When diagnostics are requested, we convert them all in one go into proper JavaScript objects.
- The vector returned by line_column is replaced with more idiomatic column and lineNumber properties
This commit is contained in:
Simon Hausmann 2023-08-07 16:13:15 +02:00 committed by Simon Hausmann
parent 4679bb6c38
commit 5d102bc838
2 changed files with 35 additions and 33 deletions

View file

@ -196,3 +196,20 @@ test('globalCallbacks ComponentDefinition', (t) => {
t.is(callbacks![0], "first-callback");
t.is(callbacks![1], "second-callback");
})
test('compiler diagnostics', (t) => {
let compiler = new ComponentCompiler;
t.is(compiler.buildFromSource(`export component App {
garbage
}`, "testsource.slint"), null);
const diags = compiler.diagnostics;
t.is(diags.length, 1);
t.deepEqual(diags[0], {
level: 0,
message: 'Parse error',
lineNumber: 2,
column: 12,
sourceFile: 'testsource.slint'
});
})

View file

@ -19,42 +19,27 @@ impl From<DiagnosticLevel> for JsDiagnosticLevel {
}
}
#[napi(js_name = "Diagnostic")]
#[napi(object, js_name = "Diagnostic")]
pub struct JsDiagnostic {
internal: Diagnostic,
}
#[napi]
impl JsDiagnostic {
#[napi]
pub fn level(&self) -> JsDiagnosticLevel {
self.internal.level().into()
}
#[napi]
pub fn message(&self) -> String {
self.internal.message().into()
}
#[napi]
pub fn line_column(&self) -> Vec<i32> {
let (start, column) = self.internal.line_column();
vec![start as i32, column as i32]
}
#[napi]
pub fn source_file(&self) -> Option<String> {
if let Some(source_file) = self.internal.source_file() {
if let Some(source_file) = source_file.to_str() {
return Some(source_file.into());
}
}
None
}
pub level: JsDiagnosticLevel,
pub message: String,
pub line_number: u32,
pub column: u32,
pub source_file: Option<String>,
}
impl From<Diagnostic> for JsDiagnostic {
fn from(diagnostic: Diagnostic) -> Self {
Self { internal: diagnostic }
fn from(internal_diagnostic: Diagnostic) -> Self {
let (line_number, column) = internal_diagnostic.line_column();
Self {
level: internal_diagnostic.level().into(),
message: internal_diagnostic.message().into(),
line_number: line_number as u32,
column: column as u32,
source_file: internal_diagnostic
.source_file()
.and_then(|path| path.to_str())
.map(|str| str.into()),
}
}
}