mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
fix: use inline source maps when present in js (#8995)
This commit is contained in:
parent
8d1ee3bfaf
commit
39bbbbce70
17 changed files with 157 additions and 48 deletions
|
@ -21,6 +21,7 @@
|
||||||
"cli/dts/lib.webworker*.d.ts",
|
"cli/dts/lib.webworker*.d.ts",
|
||||||
"cli/dts/typescript.d.ts",
|
"cli/dts/typescript.d.ts",
|
||||||
"cli/tests/encoding",
|
"cli/tests/encoding",
|
||||||
|
"cli/tests/inline_js_source_map*",
|
||||||
"cli/tsc/*typescript.js",
|
"cli/tsc/*typescript.js",
|
||||||
"test_util/wpt",
|
"test_util/wpt",
|
||||||
"gh-pages",
|
"gh-pages",
|
||||||
|
|
|
@ -37,11 +37,12 @@ fn op_apply_source_map(
|
||||||
let mut mappings_map: CachedMaps = HashMap::new();
|
let mut mappings_map: CachedMaps = HashMap::new();
|
||||||
let program_state = state.borrow::<Arc<ProgramState>>().clone();
|
let program_state = state.borrow::<Arc<ProgramState>>().clone();
|
||||||
|
|
||||||
let (orig_file_name, orig_line_number, orig_column_number) =
|
let (orig_file_name, orig_line_number, orig_column_number, _) =
|
||||||
get_orig_position(
|
get_orig_position(
|
||||||
args.file_name,
|
args.file_name,
|
||||||
args.line_number.into(),
|
args.line_number.into(),
|
||||||
args.column_number.into(),
|
args.column_number.into(),
|
||||||
|
None,
|
||||||
&mut mappings_map,
|
&mut mappings_map,
|
||||||
program_state,
|
program_state,
|
||||||
);
|
);
|
||||||
|
|
|
@ -300,24 +300,10 @@ impl SourceMapGetter for ProgramState {
|
||||||
maybe_map
|
maybe_map
|
||||||
} else {
|
} else {
|
||||||
let code = String::from_utf8(code).unwrap();
|
let code = String::from_utf8(code).unwrap();
|
||||||
let lines: Vec<&str> = code.split('\n').collect();
|
source_map_from_code(code)
|
||||||
if let Some(last_line) = lines.last() {
|
|
||||||
if last_line
|
|
||||||
.starts_with("//# sourceMappingURL=data:application/json;base64,")
|
|
||||||
{
|
|
||||||
let input = last_line.trim_start_matches(
|
|
||||||
"//# sourceMappingURL=data:application/json;base64,",
|
|
||||||
);
|
|
||||||
let decoded_map = base64::decode(input)
|
|
||||||
.expect("Unable to decode source map from emitted file.");
|
|
||||||
Some(decoded_map)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if let Ok(source) = self.load(specifier, None) {
|
||||||
|
source_map_from_code(source.code)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -345,6 +331,26 @@ impl SourceMapGetter for ProgramState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn source_map_from_code(code: String) -> Option<Vec<u8>> {
|
||||||
|
let lines: Vec<&str> = code.split('\n').collect();
|
||||||
|
if let Some(last_line) = lines.last() {
|
||||||
|
if last_line
|
||||||
|
.starts_with("//# sourceMappingURL=data:application/json;base64,")
|
||||||
|
{
|
||||||
|
let input = last_line.trim_start_matches(
|
||||||
|
"//# sourceMappingURL=data:application/json;base64,",
|
||||||
|
);
|
||||||
|
let decoded_map = base64::decode(input)
|
||||||
|
.expect("Unable to decode source map from emitted file.");
|
||||||
|
Some(decoded_map)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn thread_safe() {
|
fn thread_safe() {
|
||||||
fn f<S: Send + Sync>(_: S) {}
|
fn f<S: Send + Sync>(_: S) {}
|
||||||
|
|
|
@ -33,14 +33,15 @@ pub fn apply_source_map<G: SourceMapGetter>(
|
||||||
// prepareStackTrace().
|
// prepareStackTrace().
|
||||||
let mut mappings_map: CachedMaps = HashMap::new();
|
let mut mappings_map: CachedMaps = HashMap::new();
|
||||||
|
|
||||||
let (script_resource_name, line_number, start_column) =
|
let (script_resource_name, line_number, start_column, source_line) =
|
||||||
get_maybe_orig_position(
|
get_maybe_orig_position(
|
||||||
js_error.script_resource_name.clone(),
|
js_error.script_resource_name.clone(),
|
||||||
js_error.line_number,
|
js_error.line_number,
|
||||||
// start_column is 0-based, we need 1-based here.
|
// start_column is 0-based, we need 1-based here.
|
||||||
js_error.start_column.map(|n| n + 1),
|
js_error.start_column.map(|n| n + 1),
|
||||||
|
js_error.source_line.clone(),
|
||||||
&mut mappings_map,
|
&mut mappings_map,
|
||||||
getter.clone(),
|
getter,
|
||||||
);
|
);
|
||||||
let start_column = start_column.map(|n| n - 1);
|
let start_column = start_column.map(|n| n - 1);
|
||||||
// It is better to just move end_column to be the same distance away from
|
// It is better to just move end_column to be the same distance away from
|
||||||
|
@ -56,20 +57,6 @@ pub fn apply_source_map<G: SourceMapGetter>(
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
// if there is a source line that we might be different in the source file, we
|
|
||||||
// will go fetch it from the getter
|
|
||||||
let source_line = match line_number {
|
|
||||||
Some(ln)
|
|
||||||
if js_error.source_line.is_some() && script_resource_name.is_some() =>
|
|
||||||
{
|
|
||||||
getter.get_source_line(
|
|
||||||
&js_error.script_resource_name.clone().unwrap(),
|
|
||||||
// Getter expects 0-based line numbers, but ours are 1-based.
|
|
||||||
ln as usize - 1,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => js_error.source_line.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
JsError {
|
JsError {
|
||||||
message: js_error.message.clone(),
|
message: js_error.message.clone(),
|
||||||
|
@ -87,16 +74,29 @@ fn get_maybe_orig_position<G: SourceMapGetter>(
|
||||||
file_name: Option<String>,
|
file_name: Option<String>,
|
||||||
line_number: Option<i64>,
|
line_number: Option<i64>,
|
||||||
column_number: Option<i64>,
|
column_number: Option<i64>,
|
||||||
|
source_line: Option<String>,
|
||||||
mappings_map: &mut CachedMaps,
|
mappings_map: &mut CachedMaps,
|
||||||
getter: Arc<G>,
|
getter: Arc<G>,
|
||||||
) -> (Option<String>, Option<i64>, Option<i64>) {
|
) -> (Option<String>, Option<i64>, Option<i64>, Option<String>) {
|
||||||
match (file_name, line_number, column_number) {
|
match (file_name, line_number, column_number) {
|
||||||
(Some(file_name_v), Some(line_v), Some(column_v)) => {
|
(Some(file_name_v), Some(line_v), Some(column_v)) => {
|
||||||
let (file_name, line_number, column_number) =
|
let (file_name, line_number, column_number, source_line) =
|
||||||
get_orig_position(file_name_v, line_v, column_v, mappings_map, getter);
|
get_orig_position(
|
||||||
(Some(file_name), Some(line_number), Some(column_number))
|
file_name_v,
|
||||||
|
line_v,
|
||||||
|
column_v,
|
||||||
|
source_line,
|
||||||
|
mappings_map,
|
||||||
|
getter,
|
||||||
|
);
|
||||||
|
(
|
||||||
|
Some(file_name),
|
||||||
|
Some(line_number),
|
||||||
|
Some(column_number),
|
||||||
|
source_line,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => (None, None, None),
|
_ => (None, None, None, source_line),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,11 +104,13 @@ pub fn get_orig_position<G: SourceMapGetter>(
|
||||||
file_name: String,
|
file_name: String,
|
||||||
line_number: i64,
|
line_number: i64,
|
||||||
column_number: i64,
|
column_number: i64,
|
||||||
|
source_line: Option<String>,
|
||||||
mappings_map: &mut CachedMaps,
|
mappings_map: &mut CachedMaps,
|
||||||
getter: Arc<G>,
|
getter: Arc<G>,
|
||||||
) -> (String, i64, i64) {
|
) -> (String, i64, i64, Option<String>) {
|
||||||
let maybe_source_map = get_mappings(&file_name, mappings_map, getter);
|
let maybe_source_map = get_mappings(&file_name, mappings_map, getter.clone());
|
||||||
let default_pos = (file_name, line_number, column_number);
|
let default_pos =
|
||||||
|
(file_name, line_number, column_number, source_line.clone());
|
||||||
|
|
||||||
// Lookup expects 0-based line and column numbers, but ours are 1-based.
|
// Lookup expects 0-based line and column numbers, but ours are 1-based.
|
||||||
let line_number = line_number - 1;
|
let line_number = line_number - 1;
|
||||||
|
@ -121,11 +123,33 @@ pub fn get_orig_position<G: SourceMapGetter>(
|
||||||
None => default_pos,
|
None => default_pos,
|
||||||
Some(token) => match token.get_source() {
|
Some(token) => match token.get_source() {
|
||||||
None => default_pos,
|
None => default_pos,
|
||||||
Some(original) => (
|
Some(original) => {
|
||||||
original.to_string(),
|
let maybe_source_line =
|
||||||
i64::from(token.get_src_line()) + 1,
|
if let Some(source_view) = token.get_source_view() {
|
||||||
i64::from(token.get_src_col()) + 1,
|
source_view.get_line(token.get_src_line())
|
||||||
),
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let source_line = if let Some(source_line) = maybe_source_line {
|
||||||
|
Some(source_line.to_string())
|
||||||
|
} else if let Some(source_line) = getter.get_source_line(
|
||||||
|
original,
|
||||||
|
// Getter expects 0-based line numbers, but ours are 1-based.
|
||||||
|
token.get_src_line() as usize,
|
||||||
|
) {
|
||||||
|
Some(source_line)
|
||||||
|
} else {
|
||||||
|
source_line
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
original.to_string(),
|
||||||
|
i64::from(token.get_src_line()) + 1,
|
||||||
|
i64::from(token.get_src_col()) + 1,
|
||||||
|
source_line,
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
[WILDCARD]error: Uncaught PermissionDenied: read access to "non-existent", run again with the --allow-read flag
|
[WILDCARD]error: Uncaught PermissionDenied: read access to "non-existent", run again with the --allow-read flag
|
||||||
|
throw new ErrorClass(res.err.message);
|
||||||
|
^
|
||||||
at [WILDCARD]
|
at [WILDCARD]
|
||||||
|
|
|
@ -2,4 +2,6 @@
|
||||||
at foo ([WILDCARD])
|
at foo ([WILDCARD])
|
||||||
at [WILDCARD]
|
at [WILDCARD]
|
||||||
error: Uncaught (in promise) Error: Unhandled error event reached main worker.
|
error: Uncaught (in promise) Error: Unhandled error event reached main worker.
|
||||||
|
throw new Error("Unhandled error event reached main worker.");
|
||||||
|
^
|
||||||
at Worker.#poll ([WILDCARD])
|
at Worker.#poll ([WILDCARD])
|
||||||
|
|
|
@ -2,4 +2,6 @@
|
||||||
at foo ([WILDCARD])
|
at foo ([WILDCARD])
|
||||||
at [WILDCARD]
|
at [WILDCARD]
|
||||||
error: Uncaught (in promise) Error: Unhandled error event reached main worker.
|
error: Uncaught (in promise) Error: Unhandled error event reached main worker.
|
||||||
|
throw new Error("Unhandled error event reached main worker.");
|
||||||
|
^
|
||||||
at Worker.#poll ([WILDCARD])
|
at Worker.#poll ([WILDCARD])
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[WILDCARD]
|
[WILDCARD]
|
||||||
error: Found 2 not formatted files in [WILDCARD] files
|
error: Found 5 not formatted files in [WILDCARD] files
|
||||||
|
|
6
cli/tests/inline_js_source_map.ts
Normal file
6
cli/tests/inline_js_source_map.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
1 + 1;
|
||||||
|
interface Test {
|
||||||
|
hello: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw new Error("Hello world!" as string);
|
4
cli/tests/inline_js_source_map_2.js
Normal file
4
cli/tests/inline_js_source_map_2.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"use strict";
|
||||||
|
1 + 1;
|
||||||
|
throw new Error("Hello world!");
|
||||||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaHR0cDovL2xvY2FsaG9zdDo0NTQ1L2NsaS90ZXN0cy9pbmxpbmVfanNfc291cmNlX21hcF8yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxDQUFDLEdBQUMsQ0FBQyxDQUFDO0FBS0osTUFBTSxJQUFJLEtBQUssQ0FBQyxjQUErQixDQUFDLENBQUMifQ==
|
4
cli/tests/inline_js_source_map_2.js.out
Normal file
4
cli/tests/inline_js_source_map_2.js.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: Uncaught Error: Hello world!
|
||||||
|
throw new Error("Hello world!");
|
||||||
|
^
|
||||||
|
at http://localhost:4545/cli/tests/inline_js_source_map_2.ts:6:7
|
6
cli/tests/inline_js_source_map_2.ts
Normal file
6
cli/tests/inline_js_source_map_2.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
1 + 1;
|
||||||
|
interface Test {
|
||||||
|
hello: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Hello world!" as unknown as string);
|
4
cli/tests/inline_js_source_map_2_with_inline_contents.js
Normal file
4
cli/tests/inline_js_source_map_2_with_inline_contents.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
throw new Error("Hello world!");
|
||||||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaHR0cDovL2xvY2FsaG9zdDo0NTQ1L2NsaS90ZXN0cy9pbmxpbmVfanNfc291cmNlX21hcF8yLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIjErMTtcbmludGVyZmFjZSBUZXN0IHtcbiAgaGVsbG86IHN0cmluZztcbn1cblxudGhyb3cgbmV3IEVycm9yKFwiSGVsbG8gd29ybGQhXCIgYXMgdW5rbm93biBhcyBzdHJpbmcpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxDQUFDLEdBQUMsQ0FBQyxDQUFDO0FBS0osTUFBTSxJQUFJLEtBQUssQ0FBQyxjQUErQixDQUFDLENBQUMifQ==
|
|
@ -0,0 +1,4 @@
|
||||||
|
error: Uncaught Error: Hello world!
|
||||||
|
throw new Error("Hello world!" as unknown as string);
|
||||||
|
^
|
||||||
|
at http://localhost:4545/cli/tests/inline_js_source_map_2.ts:6:7
|
|
@ -0,0 +1,4 @@
|
||||||
|
"use strict";
|
||||||
|
import "http://localhost:4545/cli/tests/inline_js_source_map.ts";
|
||||||
|
throw new Error("Hello world!");
|
||||||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaHR0cDovL2xvY2FsaG9zdDo0NTQ1L2NsaS90ZXN0cy9pbmxpbmVfanNfc291cmNlX21hcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsQ0FBQyxHQUFDLENBQUMsQ0FBQztBQUtKLE1BQU0sSUFBSSxLQUFLLENBQUMsY0FBK0IsQ0FBQyxDQUFDIn0=
|
|
@ -0,0 +1,4 @@
|
||||||
|
error: Uncaught Error: Hello world!
|
||||||
|
// throw new Error("Hello world!" as string);
|
||||||
|
^
|
||||||
|
at http://localhost:4545/cli/tests/inline_js_source_map.ts:6:7
|
|
@ -3446,6 +3446,41 @@ itest!(local_sources_not_cached_in_memory {
|
||||||
output: "no_mem_cache.js.out",
|
output: "no_mem_cache.js.out",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This test checks that inline source map data is used. It uses a hand crafted
|
||||||
|
// source map that maps to a file that exists, but is not loaded into the module
|
||||||
|
// graph (inline_js_source_map_2.ts) (because there are no direct dependencies).
|
||||||
|
// Source line is not remapped because no inline source contents are included in
|
||||||
|
// the sourcemap and the file is not present in the dependency graph.
|
||||||
|
itest!(inline_js_source_map_2 {
|
||||||
|
args: "run --quiet inline_js_source_map_2.js",
|
||||||
|
output: "inline_js_source_map_2.js.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// This test checks that inline source map data is used. It uses a hand crafted
|
||||||
|
// source map that maps to a file that exists, but is not loaded into the module
|
||||||
|
// graph (inline_js_source_map_2.ts) (because there are no direct dependencies).
|
||||||
|
// Source line remapped using th inline source contents that are included in the
|
||||||
|
// inline source map.
|
||||||
|
itest!(inline_js_source_map_2_with_inline_contents {
|
||||||
|
args: "run --quiet inline_js_source_map_2_with_inline_contents.js",
|
||||||
|
output: "inline_js_source_map_2_with_inline_contents.js.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// This test checks that inline source map data is used. It uses a hand crafted
|
||||||
|
// source map that maps to a file that exists, and is loaded into the module
|
||||||
|
// graph because of a direct import statement (inline_js_source_map.ts). The
|
||||||
|
// source map was generated from an earlier version of this file, where the throw
|
||||||
|
// was not commented out. The source line is remapped using source contents that
|
||||||
|
// from the module graph.
|
||||||
|
itest!(inline_js_source_map_with_contents_from_graph {
|
||||||
|
args: "run --quiet inline_js_source_map_with_contents_from_graph.js",
|
||||||
|
output: "inline_js_source_map_with_contents_from_graph.js.out",
|
||||||
|
exit_code: 1,
|
||||||
|
http_server: true,
|
||||||
|
});
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cafile_env_fetch() {
|
fn cafile_env_fetch() {
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
|
|
Loading…
Reference in a new issue