mirror of
https://github.com/danbulant/oxc
synced 2026-05-23 06:08:47 +00:00
feat(transform_conformance): handle deserialization errors (#2980)
This commit is contained in:
parent
627dd424cb
commit
c753c9fa74
2 changed files with 88 additions and 57 deletions
|
|
@ -1,4 +1,4 @@
|
|||
Passed: 221/408
|
||||
Passed: 213/408
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-react-jsx-source
|
||||
|
|
@ -25,7 +25,9 @@ Passed: 221/408
|
|||
* opts/optimizeConstEnums/input.ts
|
||||
* opts/rewriteImportExtensions/input.ts
|
||||
|
||||
# babel-plugin-transform-typescript (68/164)
|
||||
# babel-plugin-transform-typescript (59/164)
|
||||
* class/abstract-allowDeclareFields-false/input.ts
|
||||
* class/abstract-allowDeclareFields-true/input.ts
|
||||
* class/abstract-class-decorated/input.ts
|
||||
* class/abstract-class-decorated-method/input.ts
|
||||
* class/abstract-class-decorated-parameter/input.ts
|
||||
|
|
@ -43,6 +45,7 @@ Passed: 221/408
|
|||
* class/parameter-properties-with-super/input.ts
|
||||
* class/private-method-override-transform-private/input.ts
|
||||
* class/transform-properties-declare-wrong-order/input.ts
|
||||
* class/uninitialized-definite-babel-7/input.ts
|
||||
* class/uninitialized-definite-with-declare-disabled-babel-7/input.ts
|
||||
* declarations/erased/input.ts
|
||||
* declarations/export-declare-enum/input.ts
|
||||
|
|
@ -73,16 +76,20 @@ Passed: 221/408
|
|||
* imports/elision-rename/input.ts
|
||||
* imports/enum-id/input.ts
|
||||
* imports/enum-value/input.ts
|
||||
* imports/import-named-type/input.ts
|
||||
* imports/import-named-type-default-and-named/input.ts
|
||||
* imports/import-removed-exceptions/input.ts
|
||||
* imports/import-type/input.ts
|
||||
* imports/import-type-func-with-duplicate-name/input.ts
|
||||
* imports/import-type-not-removed/input.ts
|
||||
* imports/import=-module/input.ts
|
||||
* imports/only-remove-type-imports/input.ts
|
||||
* imports/property-signature/input.ts
|
||||
* imports/type-only-export-specifier-1/input.ts
|
||||
* imports/type-only-export-specifier-2/input.ts
|
||||
* imports/type-only-import-specifier-2/input.ts
|
||||
* imports/type-only-import-specifier-3/input.ts
|
||||
* imports/type-only-import-specifier-4/input.ts
|
||||
* namespace/alias/input.ts
|
||||
* namespace/ambient-module-nested/input.ts
|
||||
* namespace/ambient-module-nested-exported/input.ts
|
||||
|
|
@ -99,6 +106,7 @@ Passed: 221/408
|
|||
* namespace/export-type-only/input.ts
|
||||
* namespace/module-nested/input.ts
|
||||
* namespace/module-nested-export/input.ts
|
||||
* namespace/multiple/input.ts
|
||||
* namespace/mutable-fail/input.ts
|
||||
* namespace/namespace-flag/input.ts
|
||||
* namespace/namespace-nested-module/input.ts
|
||||
|
|
@ -108,6 +116,7 @@ Passed: 221/408
|
|||
* namespace/nested-shorthand/input.ts
|
||||
* namespace/nested-shorthand-export/input.ts
|
||||
* namespace/same-name/input.ts
|
||||
* namespace/undeclared/input.ts
|
||||
* optimize-const-enums/custom-values/input.ts
|
||||
* optimize-const-enums/custom-values-exported/input.ts
|
||||
* optimize-const-enums/declare/input.ts
|
||||
|
|
@ -137,7 +146,7 @@ Passed: 221/408
|
|||
* regression/another-preset-with-custom-jsx-keep-source-self/input.mjs
|
||||
* regression/runtime-classic-allow-multiple-source-self/input.mjs
|
||||
|
||||
# babel-plugin-transform-react-jsx (130/161)
|
||||
# babel-plugin-transform-react-jsx (131/161)
|
||||
* autoImport/auto-import-react-source-type-module/input.js
|
||||
* autoImport/complicated-scope-module/input.js
|
||||
* autoImport/react-defined/input.js
|
||||
|
|
@ -168,7 +177,6 @@ Passed: 221/408
|
|||
* react-automatic/should-properly-handle-keys/input.js
|
||||
* react-automatic/should-throw-when-filter-is-specified/input.js
|
||||
* runtime/defaults-to-classis-babel-7/input.js
|
||||
* runtime/invalid-runtime/input.js
|
||||
|
||||
# babel-plugin-transform-react-display-name (15/16)
|
||||
* display-name/nested/input.js
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use serde_json::Value;
|
|||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_diagnostics::Error;
|
||||
use oxc_diagnostics::{miette::miette, Error};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_semantic::SemanticBuilder;
|
||||
use oxc_span::{SourceType, VALID_EXTENSIONS};
|
||||
|
|
@ -72,40 +72,44 @@ impl TestCaseKind {
|
|||
}
|
||||
}
|
||||
|
||||
fn transform_options(options: &BabelOptions) -> TransformOptions {
|
||||
fn get_options<T: Default + DeserializeOwned>(value: Option<Value>) -> T {
|
||||
value.and_then(|v| serde_json::from_value::<T>(v).ok()).unwrap_or_default()
|
||||
fn transform_options(options: &BabelOptions) -> serde_json::Result<TransformOptions> {
|
||||
fn get_options<T: Default + DeserializeOwned>(value: Option<Value>) -> serde_json::Result<T> {
|
||||
match value {
|
||||
Some(v) => serde_json::from_value::<T>(v),
|
||||
None => Ok(T::default()),
|
||||
}
|
||||
}
|
||||
|
||||
let react = options.get_preset("react").map_or_else(
|
||||
|| {
|
||||
let jsx_plugin = options.get_plugin("transform-react-jsx");
|
||||
let has_jsx_plugin = jsx_plugin.as_ref().is_some();
|
||||
let mut react_options = jsx_plugin.map(get_options::<ReactOptions>).unwrap_or_default();
|
||||
react_options.jsx_plugin = has_jsx_plugin;
|
||||
react_options.display_name_plugin =
|
||||
options.get_plugin("transform-react-display-name").is_some();
|
||||
react_options.jsx_self_plugin =
|
||||
options.get_plugin("transform-react-jsx-self").is_some();
|
||||
react_options.jsx_source_plugin =
|
||||
options.get_plugin("transform-react-jsx-source").is_some();
|
||||
react_options
|
||||
},
|
||||
get_options::<ReactOptions>,
|
||||
);
|
||||
let react = if let Some(options) = options.get_preset("react") {
|
||||
get_options::<ReactOptions>(options)?
|
||||
} else {
|
||||
let jsx_plugin = options.get_plugin("transform-react-jsx");
|
||||
let has_jsx_plugin = jsx_plugin.as_ref().is_some();
|
||||
let mut react_options =
|
||||
jsx_plugin.map(get_options::<ReactOptions>).transpose()?.unwrap_or_default();
|
||||
react_options.jsx_plugin = has_jsx_plugin;
|
||||
react_options.display_name_plugin =
|
||||
options.get_plugin("transform-react-display-name").is_some();
|
||||
react_options.jsx_self_plugin = options.get_plugin("transform-react-jsx-self").is_some();
|
||||
react_options.jsx_source_plugin =
|
||||
options.get_plugin("transform-react-jsx-source").is_some();
|
||||
react_options
|
||||
};
|
||||
|
||||
TransformOptions {
|
||||
Ok(TransformOptions {
|
||||
assumptions: serde_json::from_value(options.assumptions.clone()).unwrap_or_default(),
|
||||
decorators: options
|
||||
.get_plugin("proposal-decorators")
|
||||
.map(get_options::<DecoratorsOptions>)
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
typescript: options
|
||||
.get_plugin("transform-typescript")
|
||||
.map(get_options::<TypeScriptOptions>)
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
react,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub trait TestCase {
|
||||
|
|
@ -113,7 +117,7 @@ pub trait TestCase {
|
|||
|
||||
fn options(&self) -> &BabelOptions;
|
||||
|
||||
fn transform_options(&self) -> &TransformOptions;
|
||||
fn transform_options(&self) -> &serde_json::Result<TransformOptions>;
|
||||
|
||||
fn test(&self, filtered: bool) -> bool;
|
||||
|
||||
|
|
@ -129,9 +133,10 @@ pub trait TestCase {
|
|||
|
||||
// Skip deprecated react options
|
||||
if options.babel_8_breaking.is_some_and(|b| b) {
|
||||
let react_options = &self.transform_options().react;
|
||||
if react_options.use_built_ins.is_some() || react_options.use_spread.is_some() {
|
||||
return true;
|
||||
if let Ok(options) = self.transform_options() {
|
||||
if options.react.use_built_ins.is_some() || options.react.use_spread.is_some() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +168,13 @@ pub trait TestCase {
|
|||
}
|
||||
|
||||
fn transform(&self, path: &Path) -> Result<String, Vec<Error>> {
|
||||
let transform_options = match self.transform_options() {
|
||||
Ok(transform_options) => transform_options,
|
||||
Err(json_err) => {
|
||||
return Err(vec![miette!(format!("{json_err:?}"))]);
|
||||
}
|
||||
};
|
||||
|
||||
let allocator = Allocator::default();
|
||||
let source_text = fs::read_to_string(path).unwrap();
|
||||
|
||||
|
|
@ -178,7 +190,7 @@ pub trait TestCase {
|
|||
|
||||
let transformed_program = allocator.alloc(ret.program);
|
||||
|
||||
let result = Transformer::new(&allocator, path, semantic, self.transform_options().clone())
|
||||
let result = Transformer::new(&allocator, path, semantic, transform_options.clone())
|
||||
.build(transformed_program);
|
||||
|
||||
result.map(|()| {
|
||||
|
|
@ -193,7 +205,7 @@ pub trait TestCase {
|
|||
pub struct ConformanceTestCase {
|
||||
path: PathBuf,
|
||||
options: BabelOptions,
|
||||
transform_options: TransformOptions,
|
||||
transform_options: serde_json::Result<TransformOptions>,
|
||||
}
|
||||
|
||||
impl TestCase for ConformanceTestCase {
|
||||
|
|
@ -207,7 +219,7 @@ impl TestCase for ConformanceTestCase {
|
|||
&self.options
|
||||
}
|
||||
|
||||
fn transform_options(&self) -> &TransformOptions {
|
||||
fn transform_options(&self) -> &serde_json::Result<TransformOptions> {
|
||||
&self.transform_options
|
||||
}
|
||||
|
||||
|
|
@ -230,8 +242,6 @@ impl TestCase for ConformanceTestCase {
|
|||
.as_ref()
|
||||
.is_some_and(|path| path.extension().and_then(std::ffi::OsStr::to_str) == Some("js"));
|
||||
|
||||
let transform_options = self.transform_options();
|
||||
|
||||
let source_type = SourceType::from_path(&self.path)
|
||||
.unwrap()
|
||||
.with_script(if self.options.source_type.is_some() {
|
||||
|
|
@ -246,32 +256,45 @@ impl TestCase for ConformanceTestCase {
|
|||
println!("output_path: {output_path:?}");
|
||||
}
|
||||
|
||||
// Transform input.js
|
||||
let ret = Parser::new(&allocator, &input, source_type).parse();
|
||||
let semantic = SemanticBuilder::new(&input, source_type)
|
||||
.with_trivias(ret.trivias)
|
||||
.build_module_record(PathBuf::new(), &ret.program)
|
||||
.build(&ret.program)
|
||||
.semantic;
|
||||
let program = allocator.alloc(ret.program);
|
||||
let transformer =
|
||||
Transformer::new(&allocator, &self.path, semantic, transform_options.clone());
|
||||
|
||||
let codegen_options = CodegenOptions::default();
|
||||
let mut transformed_code = String::new();
|
||||
let mut actual_errors = String::new();
|
||||
let result = transformer.build(program);
|
||||
if result.is_ok() {
|
||||
transformed_code = Codegen::<false>::new("", &input, codegen_options.clone())
|
||||
.build(program)
|
||||
.source_text;
|
||||
} else {
|
||||
actual_errors = result.err().unwrap().iter().map(ToString::to_string).collect();
|
||||
}
|
||||
|
||||
let transform_options = match self.transform_options() {
|
||||
Ok(transform_options) => {
|
||||
let ret = Parser::new(&allocator, &input, source_type).parse();
|
||||
let semantic = SemanticBuilder::new(&input, source_type)
|
||||
.with_trivias(ret.trivias)
|
||||
.build_module_record(PathBuf::new(), &ret.program)
|
||||
.build(&ret.program)
|
||||
.semantic;
|
||||
let program = allocator.alloc(ret.program);
|
||||
let transformer =
|
||||
Transformer::new(&allocator, &self.path, semantic, transform_options.clone());
|
||||
let result = transformer.build(program);
|
||||
if result.is_ok() {
|
||||
transformed_code = Codegen::<false>::new("", &input, codegen_options.clone())
|
||||
.build(program)
|
||||
.source_text;
|
||||
} else {
|
||||
actual_errors = result.err().unwrap().iter().map(ToString::to_string).collect();
|
||||
}
|
||||
Some(transform_options.clone())
|
||||
}
|
||||
Err(json_err) => {
|
||||
let error = format!("{json_err:?}");
|
||||
if error.contains("expected `classic` or `automatic`") {
|
||||
actual_errors.push_str(r#"Runtime must be either "classic" or "automatic"."#);
|
||||
} else {
|
||||
actual_errors.push_str(&error);
|
||||
}
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let babel_options = self.options();
|
||||
|
||||
// Get output.js by using our codeg so code comparison can match.
|
||||
// Get output.js by using our code gen so code comparison can match.
|
||||
let output = output_path.and_then(|path| fs::read_to_string(path).ok()).map_or_else(
|
||||
|| {
|
||||
if let Some(throws) = &babel_options.throws {
|
||||
|
|
@ -324,7 +347,7 @@ impl TestCase for ConformanceTestCase {
|
|||
pub struct ExecTestCase {
|
||||
path: PathBuf,
|
||||
options: BabelOptions,
|
||||
transform_options: TransformOptions,
|
||||
transform_options: serde_json::Result<TransformOptions>,
|
||||
}
|
||||
|
||||
impl ExecTestCase {
|
||||
|
|
@ -368,7 +391,7 @@ impl TestCase for ExecTestCase {
|
|||
&self.options
|
||||
}
|
||||
|
||||
fn transform_options(&self) -> &TransformOptions {
|
||||
fn transform_options(&self) -> &serde_json::Result<TransformOptions> {
|
||||
&self.transform_options
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue