fix(cli/fmt_errors): Abbreviate long data URLs in stack traces (#12127)

Co-authored-by: Mike White <mike.white@auctane.com>
This commit is contained in:
Nayeem Rahman 2021-09-18 14:40:04 +01:00 committed by GitHub
parent f840906943
commit 75ca013f07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 80 additions and 22 deletions

View file

@ -5,13 +5,40 @@ use crate::colors::italic_bold;
use crate::colors::red; use crate::colors::red;
use crate::colors::yellow; use crate::colors::yellow;
use deno_core::error::{AnyError, JsError, JsStackFrame}; use deno_core::error::{AnyError, JsError, JsStackFrame};
use deno_core::url::Url;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::ops::Deref; use std::ops::Deref;
const SOURCE_ABBREV_THRESHOLD: usize = 150; const SOURCE_ABBREV_THRESHOLD: usize = 150;
const DATA_URL_ABBREV_THRESHOLD: usize = 150;
// Keep in sync with `runtime/js/40_error_stack.js`. pub fn format_file_name(file_name: &str) -> String {
if file_name.len() > DATA_URL_ABBREV_THRESHOLD {
if let Ok(url) = Url::parse(file_name) {
if url.scheme() == "data" {
let data_path = url.path();
if let Some(data_pieces) = data_path.split_once(',') {
let data_length = data_pieces.1.len();
if let Some(data_start) = data_pieces.1.get(0..20) {
if let Some(data_end) = data_pieces.1.get(data_length - 20..) {
return format!(
"{}:{},{}......{}",
url.scheme(),
data_pieces.0,
data_start,
data_end
);
}
}
}
}
}
}
file_name.to_string()
}
// Keep in sync with `/core/error.js`.
pub fn format_location(frame: &JsStackFrame) -> String { pub fn format_location(frame: &JsStackFrame) -> String {
let _internal = frame let _internal = frame
.file_name .file_name
@ -22,7 +49,7 @@ pub fn format_location(frame: &JsStackFrame) -> String {
} }
let mut result = String::new(); let mut result = String::new();
if let Some(file_name) = &frame.file_name { if let Some(file_name) = &frame.file_name {
result += &cyan(&file_name).to_string(); result += &cyan(&format_file_name(file_name)).to_string();
} else { } else {
if frame.is_eval { if frame.is_eval {
result += result +=

View file

@ -1,6 +1,7 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use crate::diagnostics::Diagnostics; use crate::diagnostics::Diagnostics;
use crate::fmt_errors::format_file_name;
use crate::program_state::ProgramState; use crate::program_state::ProgramState;
use crate::source_maps::get_orig_position; use crate::source_maps::get_orig_position;
use crate::source_maps::CachedMaps; use crate::source_maps::CachedMaps;
@ -16,6 +17,7 @@ use std::sync::Arc;
pub fn init(rt: &mut deno_core::JsRuntime) { pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_sync(rt, "op_apply_source_map", op_apply_source_map); super::reg_sync(rt, "op_apply_source_map", op_apply_source_map);
super::reg_sync(rt, "op_format_diagnostic", op_format_diagnostic); super::reg_sync(rt, "op_format_diagnostic", op_format_diagnostic);
super::reg_sync(rt, "op_format_file_name", op_format_file_name);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -60,3 +62,11 @@ fn op_format_diagnostic(
let diagnostic: Diagnostics = serde_json::from_value(args)?; let diagnostic: Diagnostics = serde_json::from_value(args)?;
Ok(json!(diagnostic.to_string())) Ok(json!(diagnostic.to_string()))
} }
fn op_format_file_name(
_state: &mut OpState,
file_name: String,
_: (),
) -> Result<String, AnyError> {
Ok(format_file_name(&file_name))
}

View file

@ -1885,3 +1885,9 @@ itest!(dom_exception_formatting {
output: "dom_exception_formatting.ts.out", output: "dom_exception_formatting.ts.out",
exit_code: 1, exit_code: 1,
}); });
itest!(long_data_url_formatting {
args: "run long_data_url_formatting.ts",
output: "long_data_url_formatting.ts.out",
exit_code: 1,
});

View file

@ -1,6 +1,6 @@
[WILDCARD]error: Uncaught Error: Hello 2 [WILDCARD]error: Uncaught Error: Hello 2
throw new Error(`Hello ${A.C}`); throw new Error(`Hello ${A.C}`);
^ ^
at a (data:application/typescript;base64,ZW51bSBBIHsKICBBLAogIEIsCiAgQywKIH0KIAogZXhwb3J0IGZ1bmN0aW9uIGEoKSB7CiAgIHRocm93IG5ldyBFcnJvcihgSGVsbG8gJHtBLkN9YCk7CiB9CiA=:8:10) at a (data:application/typescript;base64,ZW51bSBBIHsKICBBLAog......JHtBLkN9YCk7CiB9CiA=:8:10)
at file:///[WILDCARD]/import_data_url_error_stack.ts:3:1 at file:///[WILDCARD]/import_data_url_error_stack.ts:3:1
[WILDCARD] [WILDCARD]

View file

@ -0,0 +1,3 @@
await import(
'data:application/typescript,console.trace("foo"); const error = new Error("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); console.log(error.stack); throw error;'
);

View file

@ -0,0 +1,8 @@
[WILDCARD]Trace: foo
at data:application/typescript,console.trace("foo")......stack); throw error;:1:9
Error: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
at data:application/typescript,console.trace("foo")......stack); throw error;:1:37
error: Uncaught (in promise) Error: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
console.trace("foo"); const error = new Error("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); console.log(error.stack); throw error;
^
at data:application/typescript,console.trace("foo")......stack); throw error;:1:37

View file

@ -70,7 +70,7 @@
} }
// Keep in sync with `cli/fmt_errors.rs`. // Keep in sync with `cli/fmt_errors.rs`.
function formatLocation(callSite) { function formatLocation(callSite, formatFileNameFn) {
if (callSite.isNative()) { if (callSite.isNative()) {
return "native"; return "native";
} }
@ -80,7 +80,7 @@
const fileName = callSite.getFileName(); const fileName = callSite.getFileName();
if (fileName) { if (fileName) {
result += fileName; result += formatFileNameFn(fileName);
} else { } else {
if (callSite.isEval()) { if (callSite.isEval()) {
const evalOrigin = callSite.getEvalOrigin(); const evalOrigin = callSite.getEvalOrigin();
@ -106,7 +106,7 @@
} }
// Keep in sync with `cli/fmt_errors.rs`. // Keep in sync with `cli/fmt_errors.rs`.
function formatCallSite(callSite) { function formatCallSite(callSite, formatFileNameFn) {
let result = ""; let result = "";
const functionName = callSite.getFunctionName(); const functionName = callSite.getFunctionName();
@ -159,11 +159,11 @@
} else if (functionName) { } else if (functionName) {
result += functionName; result += functionName;
} else { } else {
result += formatLocation(callSite); result += formatLocation(callSite, formatFileNameFn);
return result; return result;
} }
result += ` (${formatLocation(callSite)})`; result += ` (${formatLocation(callSite, formatFileNameFn)})`;
return result; return result;
} }
@ -205,7 +205,7 @@
* columnNumber: number * columnNumber: number
* }} sourceMappingFn * }} sourceMappingFn
*/ */
function createPrepareStackTrace(sourceMappingFn) { function createPrepareStackTrace(sourceMappingFn, formatFileNameFn) {
return function prepareStackTrace( return function prepareStackTrace(
error, error,
callSites, callSites,
@ -235,7 +235,10 @@
const formattedCallSites = []; const formattedCallSites = [];
for (const callSite of mappedCallSites) { for (const callSite of mappedCallSites) {
ArrayPrototypePush(error.__callSiteEvals, evaluateCallSite(callSite)); ArrayPrototypePush(error.__callSiteEvals, evaluateCallSite(callSite));
ArrayPrototypePush(formattedCallSites, formatCallSite(callSite)); ArrayPrototypePush(
formattedCallSites,
formatCallSite(callSite, formatFileNameFn),
);
} }
const message = error.message !== undefined ? error.message : ""; const message = error.message !== undefined ? error.message : "";
const name = error.name !== undefined ? error.name : "Error"; const name = error.name !== undefined ? error.name : "Error";

View file

@ -8,6 +8,10 @@
return core.opSync("op_format_diagnostic", diagnostics); return core.opSync("op_format_diagnostic", diagnostics);
} }
function opFormatFileName(location) {
return core.opSync("op_format_file_name", location);
}
function opApplySourceMap(location) { function opApplySourceMap(location) {
const res = core.opSync("op_apply_source_map", location); const res = core.opSync("op_apply_source_map", location);
return { return {
@ -18,7 +22,8 @@
} }
window.__bootstrap.errorStack = { window.__bootstrap.errorStack = {
opApplySourceMap,
opFormatDiagnostics, opFormatDiagnostics,
opFormatFileName,
opApplySourceMap,
}; };
})(this); })(this);

View file

@ -218,17 +218,13 @@ delete Object.prototype.__proto__;
); );
build.setBuildInfo(runtimeOptions.target); build.setBuildInfo(runtimeOptions.target);
util.setLogDebug(runtimeOptions.debugFlag, source); util.setLogDebug(runtimeOptions.debugFlag, source);
const prepareStackTrace = core.createPrepareStackTrace(
// TODO(bartlomieju): a very crude way to disable // TODO(bartlomieju): a very crude way to disable
// source mapping of errors. This condition is true // source mapping of errors. This condition is true
// only for compiled standalone binaries. // only for compiled standalone binaries.
let prepareStackTrace; runtimeOptions.applySourceMaps ? errorStack.opApplySourceMap : undefined,
if (runtimeOptions.applySourceMaps) { errorStack.opFormatFileName,
prepareStackTrace = core.createPrepareStackTrace(
errorStack.opApplySourceMap,
); );
} else {
prepareStackTrace = core.createPrepareStackTrace();
}
// deno-lint-ignore prefer-primordials // deno-lint-ignore prefer-primordials
Error.prepareStackTrace = prepareStackTrace; Error.prepareStackTrace = prepareStackTrace;
} }