fix(#10761): graph errors reported as diagnostics for Deno.emit() (#10767)

Fixes #10761
This commit is contained in:
Kitson Kelly 2021-06-22 07:27:32 +10:00 committed by GitHub
parent 281c4cd8fc
commit a5eb2dfc93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 7 deletions

View File

@ -6,7 +6,9 @@ use deno_core::serde::Deserialize;
use deno_core::serde::Deserializer;
use deno_core::serde::Serialize;
use deno_core::serde::Serializer;
use deno_core::ModuleSpecifier;
use regex::Regex;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
@ -233,13 +235,14 @@ impl Diagnostic {
_ => "",
};
let code = if self.code >= 900001 {
"".to_string()
} else {
colors::bold(format!("TS{} ", self.code)).to_string()
};
if !category.is_empty() {
write!(
f,
"{} [{}]: ",
colors::bold(&format!("TS{}", self.code)),
category
)
write!(f, "{}[{}]: ", code, category)
} else {
Ok(())
}
@ -359,6 +362,24 @@ impl Diagnostics {
Diagnostics(diagnostics)
}
pub fn extend_graph_errors(
&mut self,
errors: HashMap<ModuleSpecifier, String>,
) {
self.0.extend(errors.into_iter().map(|(s, e)| Diagnostic {
category: DiagnosticCategory::Error,
code: 900001,
start: None,
end: None,
message_text: Some(e),
message_chain: None,
source: None,
source_line: None,
file_name: Some(s.to_string()),
related_information: None,
}));
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}

View File

@ -1273,6 +1273,18 @@ impl Graph {
Ok(())
}
/// Retrieve the first module loading error from the graph and return it.
pub fn get_errors(&self) -> HashMap<ModuleSpecifier, String> {
self
.modules
.iter()
.filter_map(|(s, sl)| match sl {
ModuleSlot::Err(err) => Some((s.clone(), err.to_string())),
_ => None,
})
.collect()
}
/// Retrieve a map that contains a representation of each module in the graph
/// which can be used to provide code to a module loader without holding all
/// the state to be able to operate on the graph.

View File

@ -118,12 +118,14 @@ async fn op_emit(
};
let graph = builder.get_graph();
let debug = program_state.flags.log_level == Some(log::Level::Debug);
let (files, result_info) = graph.emit(EmitOptions {
let graph_errors = graph.get_errors();
let (files, mut result_info) = graph.emit(EmitOptions {
bundle_type,
check: args.check.unwrap_or(true),
debug,
maybe_user_config: args.compiler_options,
})?;
result_info.diagnostics.extend_graph_errors(graph_errors);
Ok(json!({
"diagnostics": result_info.diagnostics,

View File

@ -456,3 +456,49 @@ Deno.test({
assert(files["deno:///bundle.js.map"]);
},
});
Deno.test({
name: `Deno.emit() - graph errors as diagnostics`,
ignore: Deno.build.os === "windows",
async fn() {
const { diagnostics } = await Deno.emit("/a.ts", {
sources: {
"/a.ts": `import { b } from "./b.ts";
console.log(b);`,
},
});
assert(diagnostics);
assertEquals(diagnostics, [
{
category: 1,
code: 2305,
start: { line: 0, character: 9 },
end: { line: 0, character: 10 },
messageText:
`Module '"deno:///missing_dependency.d.ts"' has no exported member 'b'.`,
messageChain: null,
source: null,
sourceLine: 'import { b } from "./b.ts";',
fileName: "file:///a.ts",
relatedInformation: null,
},
{
category: 1,
code: 900001,
start: null,
end: null,
messageText: "Unable to find specifier in sources: file:///b.ts",
messageChain: null,
source: null,
sourceLine: null,
fileName: "file:///b.ts",
relatedInformation: null,
},
]);
assert(
Deno.formatDiagnostics(diagnostics).includes(
"Unable to find specifier in sources: file:///b.ts",
),
);
},
});