mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(transform_conformance): only print semantic mismatch errors when output is correct (#5589)
closes #5166 Had to rerun for mismatch errors :-/
This commit is contained in:
parent
24d6a47f8b
commit
919d17fc5c
6 changed files with 2831 additions and 4732 deletions
|
|
@ -102,7 +102,7 @@ impl BabelOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_module(&self) -> bool {
|
pub fn is_module(&self) -> bool {
|
||||||
self.source_type.as_ref().map_or(false, |s| matches!(s.as_str(), "module"))
|
self.source_type.as_ref().map_or(false, |s| s.as_str() == "module")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_unambiguous(&self) -> bool {
|
pub fn is_unambiguous(&self) -> bool {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -10,6 +10,7 @@ use oxc::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Driver {
|
pub struct Driver {
|
||||||
|
check_semantic: bool,
|
||||||
options: TransformOptions,
|
options: TransformOptions,
|
||||||
printed: String,
|
printed: String,
|
||||||
errors: Vec<OxcDiagnostic>,
|
errors: Vec<OxcDiagnostic>,
|
||||||
|
|
@ -41,6 +42,7 @@ impl CompilerInterface for Driver {
|
||||||
program: &mut Program<'_>,
|
program: &mut Program<'_>,
|
||||||
transformer_return: &mut TransformerReturn,
|
transformer_return: &mut TransformerReturn,
|
||||||
) -> ControlFlow<()> {
|
) -> ControlFlow<()> {
|
||||||
|
if self.check_semantic {
|
||||||
if let Some(errors) = check_semantic_after_transform(
|
if let Some(errors) = check_semantic_after_transform(
|
||||||
&transformer_return.symbols,
|
&transformer_return.symbols,
|
||||||
&transformer_return.scopes,
|
&transformer_return.scopes,
|
||||||
|
|
@ -48,13 +50,14 @@ impl CompilerInterface for Driver {
|
||||||
) {
|
) {
|
||||||
self.errors.extend(errors);
|
self.errors.extend(errors);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Driver {
|
impl Driver {
|
||||||
pub fn new(options: TransformOptions) -> Self {
|
pub fn new(check_semantic: bool, options: TransformOptions) -> Self {
|
||||||
Self { options, printed: String::new(), errors: vec![] }
|
Self { check_semantic, options, printed: String::new(), errors: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn errors(&mut self) -> Vec<OxcDiagnostic> {
|
pub fn errors(&mut self) -> Vec<OxcDiagnostic> {
|
||||||
|
|
|
||||||
|
|
@ -175,13 +175,13 @@ impl TestRunner {
|
||||||
let errors = test_case.errors();
|
let errors = test_case.errors();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
snapshot.push('\n');
|
snapshot.push('\n');
|
||||||
for error in test_case.errors() {
|
for error in errors {
|
||||||
snapshot.push_str(&error.message);
|
snapshot.push_str(&error.message);
|
||||||
}
|
|
||||||
snapshot.push('\n');
|
snapshot.push('\n');
|
||||||
}
|
}
|
||||||
snapshot.push('\n');
|
snapshot.push('\n');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
snapshot.push('\n');
|
snapshot.push('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,16 +172,13 @@ pub trait TestCase {
|
||||||
|
|
||||||
// Some babel test cases have a js extension, but contain typescript code.
|
// Some babel test cases have a js extension, but contain typescript code.
|
||||||
// Therefore, if the typescript plugin exists, enable typescript.
|
// Therefore, if the typescript plugin exists, enable typescript.
|
||||||
let mut source_type = SourceType::from_path(path).unwrap();
|
let source_type = SourceType::from_path(path).unwrap().with_typescript(
|
||||||
if !source_type.is_typescript()
|
self.options().get_plugin("transform-typescript").is_some()
|
||||||
&& (self.options().get_plugin("transform-typescript").is_some()
|
|| self.options().get_plugin("syntax-typescript").is_some(),
|
||||||
|| self.options().get_plugin("syntax-typescript").is_some())
|
);
|
||||||
{
|
|
||||||
source_type = source_type.with_typescript(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let driver =
|
let driver =
|
||||||
Driver::new(transform_options.clone()).execute(&source_text, source_type, path);
|
Driver::new(false, transform_options.clone()).execute(&source_text, source_type, path);
|
||||||
Ok(driver)
|
Ok(driver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -228,25 +225,27 @@ impl TestCase for ConformanceTestCase {
|
||||||
|
|
||||||
let allocator = Allocator::default();
|
let allocator = Allocator::default();
|
||||||
let input = fs::read_to_string(&self.path).unwrap();
|
let input = fs::read_to_string(&self.path).unwrap();
|
||||||
let input_is_js = self.path.extension().and_then(std::ffi::OsStr::to_str) == Some("js");
|
|
||||||
let output_is_js = output_path
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|path| path.extension().and_then(std::ffi::OsStr::to_str) == Some("js"));
|
|
||||||
|
|
||||||
|
let source_type = {
|
||||||
let mut source_type = SourceType::from_path(&self.path)
|
let mut source_type = SourceType::from_path(&self.path)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_script(if self.options.source_type.is_some() {
|
|
||||||
!self.options.is_module()
|
|
||||||
} else {
|
|
||||||
input_is_js && output_is_js
|
|
||||||
})
|
|
||||||
.with_jsx(self.options.get_plugin("syntax-jsx").is_some());
|
.with_jsx(self.options.get_plugin("syntax-jsx").is_some());
|
||||||
if !source_type.is_typescript()
|
|
||||||
&& (self.options.get_plugin("transform-typescript").is_some()
|
source_type = match self.options.source_type.as_deref() {
|
||||||
|| self.options.get_plugin("syntax-typescript").is_some())
|
Some("unambiguous") => source_type.with_unambiguous(true),
|
||||||
{
|
Some("script") => source_type.with_script(true),
|
||||||
source_type = source_type.with_typescript(true);
|
Some("module") => source_type.with_module(true),
|
||||||
}
|
Some(s) => panic!("Unexpected source type {s}"),
|
||||||
|
None => source_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
source_type = source_type.with_typescript(
|
||||||
|
self.options.get_plugin("transform-typescript").is_some()
|
||||||
|
|| self.options.get_plugin("syntax-typescript").is_some(),
|
||||||
|
);
|
||||||
|
|
||||||
|
source_type
|
||||||
|
};
|
||||||
|
|
||||||
if filtered {
|
if filtered {
|
||||||
println!("input_path: {:?}", &self.path);
|
println!("input_path: {:?}", &self.path);
|
||||||
|
|
@ -255,14 +254,18 @@ impl TestCase for ConformanceTestCase {
|
||||||
|
|
||||||
let project_root = project_root();
|
let project_root = project_root();
|
||||||
let mut transformed_code = String::new();
|
let mut transformed_code = String::new();
|
||||||
let mut actual_errors = String::new();
|
let mut actual_errors = None;
|
||||||
let mut transform_options = None;
|
let mut transform_options = None;
|
||||||
|
|
||||||
match self.transform_options() {
|
match self.transform_options() {
|
||||||
|
Err(json_err) => {
|
||||||
|
let error = json_err.iter().map(ToString::to_string).collect::<Vec<_>>().join("\n");
|
||||||
|
actual_errors.replace(get_babel_error(&error));
|
||||||
|
}
|
||||||
Ok(options) => {
|
Ok(options) => {
|
||||||
transform_options.replace(options.clone());
|
transform_options.replace(options.clone());
|
||||||
let mut driver =
|
let mut driver =
|
||||||
Driver::new(options.clone()).execute(&input, source_type, &self.path);
|
Driver::new(false, options.clone()).execute(&input, source_type, &self.path);
|
||||||
transformed_code = driver.printed();
|
transformed_code = driver.printed();
|
||||||
let errors = driver.errors();
|
let errors = driver.errors();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
|
|
@ -275,13 +278,9 @@ impl TestCase for ConformanceTestCase {
|
||||||
.map(|err| format!("{:?}", err.with_source_code(source.clone())))
|
.map(|err| format!("{:?}", err.with_source_code(source.clone())))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
actual_errors = get_babel_error(&error);
|
actual_errors.replace(get_babel_error(&error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(json_err) => {
|
|
||||||
let error = json_err.iter().map(ToString::to_string).collect::<Vec<_>>().join("\n");
|
|
||||||
actual_errors = get_babel_error(&error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let babel_options = self.options();
|
let babel_options = self.options();
|
||||||
|
|
@ -289,7 +288,8 @@ impl TestCase for ConformanceTestCase {
|
||||||
let output;
|
let output;
|
||||||
let passed = if let Some(throws) = &babel_options.throws {
|
let passed = if let Some(throws) = &babel_options.throws {
|
||||||
output = throws.to_string().replace(" (1:6)", "");
|
output = throws.to_string().replace(" (1:6)", "");
|
||||||
!output.is_empty() && actual_errors.contains(&output)
|
!output.is_empty()
|
||||||
|
&& actual_errors.as_ref().is_some_and(|errors| errors.contains(&output))
|
||||||
} else {
|
} else {
|
||||||
// Get output.js by using our code gen so code comparison can match.
|
// Get output.js by using our code gen so code comparison can match.
|
||||||
output = output_path.and_then(|path| fs::read_to_string(path).ok()).map_or_else(
|
output = output_path.and_then(|path| fs::read_to_string(path).ok()).map_or_else(
|
||||||
|
|
@ -302,10 +302,10 @@ impl TestCase for ConformanceTestCase {
|
||||||
);
|
);
|
||||||
|
|
||||||
if transformed_code == output {
|
if transformed_code == output {
|
||||||
actual_errors.is_empty()
|
actual_errors.is_none()
|
||||||
} else {
|
} else {
|
||||||
if !actual_errors.is_empty() && !transformed_code.is_empty() {
|
if actual_errors.is_none() {
|
||||||
actual_errors.insert_str(0, " x Output mismatch\n");
|
actual_errors.replace("x Output mismatch".to_string());
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -320,10 +320,12 @@ impl TestCase for ConformanceTestCase {
|
||||||
println!("Expected Errors:\n");
|
println!("Expected Errors:\n");
|
||||||
println!("{output}\n");
|
println!("{output}\n");
|
||||||
println!("Actual Errors:\n");
|
println!("Actual Errors:\n");
|
||||||
|
if let Some(actual_errors) = &actual_errors {
|
||||||
println!("{actual_errors}\n");
|
println!("{actual_errors}\n");
|
||||||
if !passed {
|
if !passed {
|
||||||
println!("Diff:\n");
|
println!("Diff:\n");
|
||||||
print_diff_in_terminal(&output, &actual_errors);
|
print_diff_in_terminal(&output, actual_errors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("Expected:\n");
|
println!("Expected:\n");
|
||||||
|
|
@ -331,7 +333,9 @@ impl TestCase for ConformanceTestCase {
|
||||||
println!("Transformed:\n");
|
println!("Transformed:\n");
|
||||||
println!("{transformed_code}");
|
println!("{transformed_code}");
|
||||||
println!("Errors:\n");
|
println!("Errors:\n");
|
||||||
|
if let Some(actual_errors) = &actual_errors {
|
||||||
println!("{actual_errors}\n");
|
println!("{actual_errors}\n");
|
||||||
|
}
|
||||||
if !passed {
|
if !passed {
|
||||||
println!("Diff:\n");
|
println!("Diff:\n");
|
||||||
print_diff_in_terminal(&output, &transformed_code);
|
print_diff_in_terminal(&output, &transformed_code);
|
||||||
|
|
@ -341,7 +345,15 @@ impl TestCase for ConformanceTestCase {
|
||||||
println!("Passed: {passed}");
|
println!("Passed: {passed}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if !passed {
|
if passed {
|
||||||
|
if let Some(options) = transform_options {
|
||||||
|
let mismatch_errors =
|
||||||
|
Driver::new(/* check transform mismatch */ true, options)
|
||||||
|
.execute(&input, source_type, &self.path)
|
||||||
|
.errors();
|
||||||
|
self.errors.extend(mismatch_errors);
|
||||||
|
}
|
||||||
|
} else if let Some(actual_errors) = actual_errors {
|
||||||
self.errors.push(OxcDiagnostic::error(actual_errors));
|
self.errors.push(OxcDiagnostic::error(actual_errors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue