Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
---
source: crates/oxc_codegen/tests/integration/sourcemap.rs
---
## Input
const fn = () => {
Error.stackTraceLimit = 2;
throw new Error()
};
fn()

## Output
const fn = () => {
Error.stackTraceLimit = 2;
throw new Error();
};
fn();


## Stderr
/project/input.js:3
throw new Error()
^


Error
at fn (/project/input.js:3:11)
at <anonymous> (/project/input.js:5:1)

------------------------------------------------------
## Input
const obj = {
fn() {
Error.stackTraceLimit = 2;
throw new Error()
}
}
obj.fn()

## Output
const obj = { fn() {
Error.stackTraceLimit = 2;
throw new Error();
} };
obj.fn();


## Stderr
/project/input.js:4
throw new Error()
^


Error
at Object.fn (/project/input.js:4:15)
at <anonymous> (/project/input.js:7:5)

------------------------------------------------------
## Input
const obj = {
obj2: {
fn() {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.obj2.fn()

## Output
const obj = { obj2: { fn() {
Error.stackTraceLimit = 2;
throw new Error();
} } };
obj.obj2.fn();


## Stderr
/project/input.js:5
throw new Error()
^


Error
at Object.fn (/project/input.js:5:19)
at <anonymous> (/project/input.js:9:10)

------------------------------------------------------
## Input
const obj = {
fn() {
return function fn2() {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.fn()()

## Output
const obj = { fn() {
return function fn2() {
Error.stackTraceLimit = 2;
throw new Error();
};
} };
obj.fn()();


## Stderr
/project/input.js:5
throw new Error()
^


Error
at fn2 (/project/input.js:5:19)
at <anonymous> (/project/input.js:9:5)

------------------------------------------------------
## Input
const obj = {
fn() {
return () => {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.fn([1])()

## Output
const obj = { fn() {
return () => {
Error.stackTraceLimit = 2;
throw new Error();
};
} };
obj.fn([1])();


## Stderr
/project/input.js:5
throw new Error()
^


Error
at <anonymous> (/project/input.js:5:19)
at <anonymous> (/project/input.js:9:9)

------------------------------------------------------
## Input
var a
const obj = {
fn() {
return () => {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.fn({a})()

## Output
var a;
const obj = { fn() {
return () => {
Error.stackTraceLimit = 2;
throw new Error();
};
} };
obj.fn({ a })();


## Stderr
/project/input.js:6
throw new Error()
^


Error
at <anonymous> (/project/input.js:6:19)
at <anonymous> (/project/input.js:10:9)

------------------------------------------------------
## Input
const fn = (name, cb) => {
cb()
}
fn('name', () => {
Error.stackTraceLimit = 2;
throw new Error()
})

## Output
const fn = (name, cb) => {
cb();
};
fn("name", () => {
Error.stackTraceLimit = 2;
throw new Error();
});


## Stderr
/project/input.js:6
throw new Error()
^


Error
at <anonymous> (/project/input.js:6:11)
at fn (/project/input.js:2:5)
116 changes: 115 additions & 1 deletion crates/oxc_codegen/tests/integration/sourcemap.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::{env, path::PathBuf};

use cow_utils::CowUtils;
use oxc_allocator::Allocator;
use oxc_ast::ast::{Expression, Statement};
use oxc_codegen::Codegen;
use oxc_codegen::{Codegen, CodegenOptions};
use oxc_parser::Parser;
use oxc_span::{SourceType, Span};

Expand All @@ -27,3 +30,114 @@ fn incorrect_ast() {
let ret = Codegen::new().with_options(default_options()).build(&program);
assert!(ret.map.is_some(), "sourcemap exists");
}

#[test]
fn stacktrace_is_correct() {
let cases = &[
"\
const fn = () => {
Error.stackTraceLimit = 2;
throw new Error()
};
fn()",
"\
const obj = {
fn() {
Error.stackTraceLimit = 2;
throw new Error()
}
}
obj.fn()",
"\
const obj = {
obj2: {
fn() {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.obj2.fn()",
"\
const obj = {
fn() {
return function fn2() {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.fn()()",
"\
const obj = {
fn() {
return () => {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.fn([1])()",
"\
var a
const obj = {
fn() {
return () => {
Error.stackTraceLimit = 2;
throw new Error()
}
}
}
obj.fn({a})()",
"\
const fn = (name, cb) => {
cb()
}
fn('name', () => {
Error.stackTraceLimit = 2;
throw new Error()
})",
];

insta::with_settings!({ prepend_module_to_snapshot => false, snapshot_suffix => "", omit_expression => true }, {
insta::assert_snapshot!(
"stacktrace_is_correct",
cases.iter().map(|s| {
let (output, sourcemap_url) = codegen(s);
format!("## Input\n{}\n\n## Output\n{}\n\n## Stderr\n{}", s, output, execute_with_node(&output, &sourcemap_url))
}).collect::<Vec<_>>().join("\n------------------------------------------------------\n")
);
});
}

fn codegen(code: &str) -> (String, String) {
let allocator = Allocator::default();
let ret = Parser::new(&allocator, code, SourceType::mjs()).parse();
let ret = Codegen::new()
.with_options(CodegenOptions {
source_map_path: Some(PathBuf::from("input.js")),
..Default::default()
})
.build(&ret.program);
(ret.code, ret.map.unwrap().to_data_url())
}

fn execute_with_node(code: &str, sourcemap_url: &str) -> String {
let cwd = env::current_dir().unwrap().join("input.js");
let cwd = cwd.to_str().unwrap();

let code = format!("{code}\n//# sourceMappingURL={sourcemap_url}\n");

let output = std::process::Command::new("node")
.arg("--enable-source-maps")
.args(["--input-type", "module"])
.args(["--eval", &code])
.output()
.unwrap();
String::from_utf8_lossy(&output.stderr)
.cow_replace(cwd, "/project/input.js")
.lines()
.filter(|line| !line.starts_with("Node.js v"))
.collect::<Vec<_>>()
.join("\n")
}
Loading