mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 20:29:11 +00:00
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:
parent
f840906943
commit
75ca013f07
9 changed files with 80 additions and 22 deletions
|
@ -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 +=
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
});
|
||||||
|
|
|
@ -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]
|
||||||
|
|
3
cli/tests/testdata/long_data_url_formatting.ts
vendored
Normal file
3
cli/tests/testdata/long_data_url_formatting.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
await import(
|
||||||
|
'data:application/typescript,console.trace("foo"); const error = new Error("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); console.log(error.stack); throw error;'
|
||||||
|
);
|
8
cli/tests/testdata/long_data_url_formatting.ts.out
vendored
Normal file
8
cli/tests/testdata/long_data_url_formatting.ts.out
vendored
Normal 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
|
|
@ -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";
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
// TODO(bartlomieju): a very crude way to disable
|
const prepareStackTrace = core.createPrepareStackTrace(
|
||||||
// source mapping of errors. This condition is true
|
// TODO(bartlomieju): a very crude way to disable
|
||||||
// only for compiled standalone binaries.
|
// source mapping of errors. This condition is true
|
||||||
let prepareStackTrace;
|
// only for compiled standalone binaries.
|
||||||
if (runtimeOptions.applySourceMaps) {
|
runtimeOptions.applySourceMaps ? errorStack.opApplySourceMap : undefined,
|
||||||
prepareStackTrace = core.createPrepareStackTrace(
|
errorStack.opFormatFileName,
|
||||||
errorStack.opApplySourceMap,
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
prepareStackTrace = core.createPrepareStackTrace();
|
|
||||||
}
|
|
||||||
// deno-lint-ignore prefer-primordials
|
// deno-lint-ignore prefer-primordials
|
||||||
Error.prepareStackTrace = prepareStackTrace;
|
Error.prepareStackTrace = prepareStackTrace;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue