mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
fix: add suggestion how to fix importing CJS module (#21764)
``` $ cat exports_error.js Object.defineProperty(exports, "__esModule", { value: true }); $ deno exports_error.js error: Uncaught (in promise) ReferenceError: exports is not defined Object.defineProperty(exports, "__esModule", { value: true }); ^ at file:///exports_error.js:1:23 info: Deno doesn't support CommonJS modules without `.cjs` extension. hint: Rewrite this module to ESM or change the file extension to `.cjs`. ```
This commit is contained in:
parent
dda6328745
commit
794d347ec6
7 changed files with 111 additions and 5 deletions
23
cli/main.rs
23
cli/main.rs
|
@ -46,7 +46,8 @@ use deno_core::error::JsError;
|
|||
use deno_core::futures::FutureExt;
|
||||
use deno_core::unsync::JoinHandle;
|
||||
use deno_npm::resolution::SnapshotFromLockfileError;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use deno_runtime::fmt_errors::format_js_error_with_suggestions;
|
||||
use deno_runtime::fmt_errors::FixSuggestion;
|
||||
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
|
||||
use deno_terminal::colors;
|
||||
use factory::CliFactory;
|
||||
|
@ -336,12 +337,30 @@ fn exit_with_message(message: &str, code: i32) -> ! {
|
|||
std::process::exit(code);
|
||||
}
|
||||
|
||||
fn get_suggestions_for_commonjs_error(e: &JsError) -> Vec<FixSuggestion> {
|
||||
if e.name.as_deref() == Some("ReferenceError") {
|
||||
if let Some(msg) = &e.message {
|
||||
if msg.contains("module is not defined")
|
||||
|| msg.contains("exports is not defined")
|
||||
{
|
||||
return vec![
|
||||
FixSuggestion::info("Deno does not support CommonJS modules without `.cjs` extension."),
|
||||
FixSuggestion::hint("Rewrite this module to ESM or change the file extension to `.cjs`."),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn exit_for_error(error: AnyError) -> ! {
|
||||
let mut error_string = format!("{error:?}");
|
||||
let mut error_code = 1;
|
||||
|
||||
if let Some(e) = error.downcast_ref::<JsError>() {
|
||||
error_string = format_js_error(e);
|
||||
let suggestions = get_suggestions_for_commonjs_error(e);
|
||||
error_string = format_js_error_with_suggestions(e, suggestions);
|
||||
} else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) =
|
||||
error.downcast_ref::<SnapshotFromLockfileError>()
|
||||
{
|
||||
|
|
|
@ -20,6 +20,34 @@ struct IndexedErrorReference<'a> {
|
|||
index: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum FixSuggestionKind {
|
||||
Info,
|
||||
Hint,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FixSuggestion<'a> {
|
||||
kind: FixSuggestionKind,
|
||||
message: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> FixSuggestion<'a> {
|
||||
pub fn info(message: &'a str) -> Self {
|
||||
Self {
|
||||
kind: FixSuggestionKind::Info,
|
||||
message,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hint(message: &'a str) -> Self {
|
||||
Self {
|
||||
kind: FixSuggestionKind::Hint,
|
||||
message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AnsiColors;
|
||||
|
||||
impl deno_core::error::ErrorFormat for AnsiColors {
|
||||
|
@ -129,6 +157,7 @@ fn format_aggregated_error(
|
|||
index: nested_circular_reference_index,
|
||||
}),
|
||||
false,
|
||||
vec![],
|
||||
);
|
||||
|
||||
for line in error_string.trim_start_matches("Uncaught ").lines() {
|
||||
|
@ -143,6 +172,7 @@ fn format_js_error_inner(
|
|||
js_error: &JsError,
|
||||
circular: Option<IndexedErrorReference>,
|
||||
include_source_code: bool,
|
||||
suggestions: Vec<FixSuggestion>,
|
||||
) -> String {
|
||||
let mut s = String::new();
|
||||
|
||||
|
@ -190,7 +220,7 @@ fn format_js_error_inner(
|
|||
let error_string = if is_caused_by_circular {
|
||||
cyan(format!("[Circular *{}]", circular.unwrap().index)).to_string()
|
||||
} else {
|
||||
format_js_error_inner(cause, circular, false)
|
||||
format_js_error_inner(cause, circular, false, vec![])
|
||||
};
|
||||
|
||||
write!(
|
||||
|
@ -200,6 +230,21 @@ fn format_js_error_inner(
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
if !suggestions.is_empty() {
|
||||
write!(s, "\n\n").unwrap();
|
||||
for (index, suggestion) in suggestions.iter().enumerate() {
|
||||
write!(s, " ").unwrap();
|
||||
match suggestion.kind {
|
||||
FixSuggestionKind::Hint => write!(s, "{} ", cyan("hint:")).unwrap(),
|
||||
FixSuggestionKind::Info => write!(s, "{} ", yellow("info:")).unwrap(),
|
||||
};
|
||||
write!(s, "{}", suggestion.message).unwrap();
|
||||
if index != (suggestions.len() - 1) {
|
||||
writeln!(s).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
|
@ -211,7 +256,21 @@ pub fn format_js_error(js_error: &JsError) -> String {
|
|||
index: 1,
|
||||
});
|
||||
|
||||
format_js_error_inner(js_error, circular, true)
|
||||
format_js_error_inner(js_error, circular, true, vec![])
|
||||
}
|
||||
|
||||
/// Format a [`JsError`] for terminal output, printing additional suggestions.
|
||||
pub fn format_js_error_with_suggestions(
|
||||
js_error: &JsError,
|
||||
suggestions: Vec<FixSuggestion>,
|
||||
) -> String {
|
||||
let circular =
|
||||
find_recursive_cause(js_error).map(|reference| IndexedErrorReference {
|
||||
reference,
|
||||
index: 1,
|
||||
});
|
||||
|
||||
format_js_error_inner(js_error, circular, true, suggestions)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
{
|
||||
"steps": [
|
||||
{ "args": "run -R index.cjs", "output": "index.out" },
|
||||
{ "args": "run -R main.ts", "output": "main.out" }
|
||||
{ "args": "run -R main.ts", "output": "main.out" },
|
||||
{
|
||||
"args": "run module_error.js",
|
||||
"output": "module_error.out",
|
||||
"exitCode": 1
|
||||
},
|
||||
{
|
||||
"args": "run exports_error.js",
|
||||
"output": "exports_error.out",
|
||||
"exitCode": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
1
tests/specs/run/import_common_js/exports_error.js
Normal file
1
tests/specs/run/import_common_js/exports_error.js
Normal file
|
@ -0,0 +1 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
7
tests/specs/run/import_common_js/exports_error.out
Normal file
7
tests/specs/run/import_common_js/exports_error.out
Normal file
|
@ -0,0 +1,7 @@
|
|||
error: Uncaught (in promise) ReferenceError: exports is not defined
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
^
|
||||
at [WILDCARD]exports_error.js:1:23
|
||||
|
||||
info: Deno does not support CommonJS modules without `.cjs` extension.
|
||||
hint: Rewrite this module to ESM or change the file extension to `.cjs`.
|
3
tests/specs/run/import_common_js/module_error.js
Normal file
3
tests/specs/run/import_common_js/module_error.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
foobar: "foobar",
|
||||
};
|
7
tests/specs/run/import_common_js/module_error.out
Normal file
7
tests/specs/run/import_common_js/module_error.out
Normal file
|
@ -0,0 +1,7 @@
|
|||
error: Uncaught (in promise) ReferenceError: module is not defined
|
||||
module.exports = {
|
||||
^
|
||||
at [WILDCARD]module_error.js:1:1
|
||||
|
||||
info: Deno does not support CommonJS modules without `.cjs` extension.
|
||||
hint: Rewrite this module to ESM or change the file extension to `.cjs`.
|
Loading…
Reference in a new issue