mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +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:
|
# All Passed:
|
||||||
* babel-plugin-transform-react-jsx-source
|
* babel-plugin-transform-react-jsx-source
|
||||||
|
|
@ -25,7 +25,9 @@ Passed: 221/408
|
||||||
* opts/optimizeConstEnums/input.ts
|
* opts/optimizeConstEnums/input.ts
|
||||||
* opts/rewriteImportExtensions/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/input.ts
|
||||||
* class/abstract-class-decorated-method/input.ts
|
* class/abstract-class-decorated-method/input.ts
|
||||||
* class/abstract-class-decorated-parameter/input.ts
|
* class/abstract-class-decorated-parameter/input.ts
|
||||||
|
|
@ -43,6 +45,7 @@ Passed: 221/408
|
||||||
* class/parameter-properties-with-super/input.ts
|
* class/parameter-properties-with-super/input.ts
|
||||||
* class/private-method-override-transform-private/input.ts
|
* class/private-method-override-transform-private/input.ts
|
||||||
* class/transform-properties-declare-wrong-order/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
|
* class/uninitialized-definite-with-declare-disabled-babel-7/input.ts
|
||||||
* declarations/erased/input.ts
|
* declarations/erased/input.ts
|
||||||
* declarations/export-declare-enum/input.ts
|
* declarations/export-declare-enum/input.ts
|
||||||
|
|
@ -73,16 +76,20 @@ Passed: 221/408
|
||||||
* imports/elision-rename/input.ts
|
* imports/elision-rename/input.ts
|
||||||
* imports/enum-id/input.ts
|
* imports/enum-id/input.ts
|
||||||
* imports/enum-value/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-removed-exceptions/input.ts
|
||||||
* imports/import-type/input.ts
|
* imports/import-type/input.ts
|
||||||
* imports/import-type-func-with-duplicate-name/input.ts
|
* imports/import-type-func-with-duplicate-name/input.ts
|
||||||
* imports/import-type-not-removed/input.ts
|
* imports/import-type-not-removed/input.ts
|
||||||
* imports/import=-module/input.ts
|
* imports/import=-module/input.ts
|
||||||
|
* imports/only-remove-type-imports/input.ts
|
||||||
* imports/property-signature/input.ts
|
* imports/property-signature/input.ts
|
||||||
* imports/type-only-export-specifier-1/input.ts
|
* imports/type-only-export-specifier-1/input.ts
|
||||||
* imports/type-only-export-specifier-2/input.ts
|
* imports/type-only-export-specifier-2/input.ts
|
||||||
* imports/type-only-import-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-3/input.ts
|
||||||
|
* imports/type-only-import-specifier-4/input.ts
|
||||||
* namespace/alias/input.ts
|
* namespace/alias/input.ts
|
||||||
* namespace/ambient-module-nested/input.ts
|
* namespace/ambient-module-nested/input.ts
|
||||||
* namespace/ambient-module-nested-exported/input.ts
|
* namespace/ambient-module-nested-exported/input.ts
|
||||||
|
|
@ -99,6 +106,7 @@ Passed: 221/408
|
||||||
* namespace/export-type-only/input.ts
|
* namespace/export-type-only/input.ts
|
||||||
* namespace/module-nested/input.ts
|
* namespace/module-nested/input.ts
|
||||||
* namespace/module-nested-export/input.ts
|
* namespace/module-nested-export/input.ts
|
||||||
|
* namespace/multiple/input.ts
|
||||||
* namespace/mutable-fail/input.ts
|
* namespace/mutable-fail/input.ts
|
||||||
* namespace/namespace-flag/input.ts
|
* namespace/namespace-flag/input.ts
|
||||||
* namespace/namespace-nested-module/input.ts
|
* namespace/namespace-nested-module/input.ts
|
||||||
|
|
@ -108,6 +116,7 @@ Passed: 221/408
|
||||||
* namespace/nested-shorthand/input.ts
|
* namespace/nested-shorthand/input.ts
|
||||||
* namespace/nested-shorthand-export/input.ts
|
* namespace/nested-shorthand-export/input.ts
|
||||||
* namespace/same-name/input.ts
|
* namespace/same-name/input.ts
|
||||||
|
* namespace/undeclared/input.ts
|
||||||
* optimize-const-enums/custom-values/input.ts
|
* optimize-const-enums/custom-values/input.ts
|
||||||
* optimize-const-enums/custom-values-exported/input.ts
|
* optimize-const-enums/custom-values-exported/input.ts
|
||||||
* optimize-const-enums/declare/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/another-preset-with-custom-jsx-keep-source-self/input.mjs
|
||||||
* regression/runtime-classic-allow-multiple-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/auto-import-react-source-type-module/input.js
|
||||||
* autoImport/complicated-scope-module/input.js
|
* autoImport/complicated-scope-module/input.js
|
||||||
* autoImport/react-defined/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-properly-handle-keys/input.js
|
||||||
* react-automatic/should-throw-when-filter-is-specified/input.js
|
* react-automatic/should-throw-when-filter-is-specified/input.js
|
||||||
* runtime/defaults-to-classis-babel-7/input.js
|
* runtime/defaults-to-classis-babel-7/input.js
|
||||||
* runtime/invalid-runtime/input.js
|
|
||||||
|
|
||||||
# babel-plugin-transform-react-display-name (15/16)
|
# babel-plugin-transform-react-display-name (15/16)
|
||||||
* display-name/nested/input.js
|
* display-name/nested/input.js
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use serde_json::Value;
|
||||||
|
|
||||||
use oxc_allocator::Allocator;
|
use oxc_allocator::Allocator;
|
||||||
use oxc_codegen::{Codegen, CodegenOptions};
|
use oxc_codegen::{Codegen, CodegenOptions};
|
||||||
use oxc_diagnostics::Error;
|
use oxc_diagnostics::{miette::miette, Error};
|
||||||
use oxc_parser::Parser;
|
use oxc_parser::Parser;
|
||||||
use oxc_semantic::SemanticBuilder;
|
use oxc_semantic::SemanticBuilder;
|
||||||
use oxc_span::{SourceType, VALID_EXTENSIONS};
|
use oxc_span::{SourceType, VALID_EXTENSIONS};
|
||||||
|
|
@ -72,40 +72,44 @@ impl TestCaseKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_options(options: &BabelOptions) -> TransformOptions {
|
fn transform_options(options: &BabelOptions) -> serde_json::Result<TransformOptions> {
|
||||||
fn get_options<T: Default + DeserializeOwned>(value: Option<Value>) -> T {
|
fn get_options<T: Default + DeserializeOwned>(value: Option<Value>) -> serde_json::Result<T> {
|
||||||
value.and_then(|v| serde_json::from_value::<T>(v).ok()).unwrap_or_default()
|
match value {
|
||||||
|
Some(v) => serde_json::from_value::<T>(v),
|
||||||
|
None => Ok(T::default()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let react = options.get_preset("react").map_or_else(
|
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 jsx_plugin = options.get_plugin("transform-react-jsx");
|
||||||
let has_jsx_plugin = jsx_plugin.as_ref().is_some();
|
let has_jsx_plugin = jsx_plugin.as_ref().is_some();
|
||||||
let mut react_options = jsx_plugin.map(get_options::<ReactOptions>).unwrap_or_default();
|
let mut react_options =
|
||||||
|
jsx_plugin.map(get_options::<ReactOptions>).transpose()?.unwrap_or_default();
|
||||||
react_options.jsx_plugin = has_jsx_plugin;
|
react_options.jsx_plugin = has_jsx_plugin;
|
||||||
react_options.display_name_plugin =
|
react_options.display_name_plugin =
|
||||||
options.get_plugin("transform-react-display-name").is_some();
|
options.get_plugin("transform-react-display-name").is_some();
|
||||||
react_options.jsx_self_plugin =
|
react_options.jsx_self_plugin = options.get_plugin("transform-react-jsx-self").is_some();
|
||||||
options.get_plugin("transform-react-jsx-self").is_some();
|
|
||||||
react_options.jsx_source_plugin =
|
react_options.jsx_source_plugin =
|
||||||
options.get_plugin("transform-react-jsx-source").is_some();
|
options.get_plugin("transform-react-jsx-source").is_some();
|
||||||
react_options
|
react_options
|
||||||
},
|
};
|
||||||
get_options::<ReactOptions>,
|
|
||||||
);
|
|
||||||
|
|
||||||
TransformOptions {
|
Ok(TransformOptions {
|
||||||
assumptions: serde_json::from_value(options.assumptions.clone()).unwrap_or_default(),
|
assumptions: serde_json::from_value(options.assumptions.clone()).unwrap_or_default(),
|
||||||
decorators: options
|
decorators: options
|
||||||
.get_plugin("proposal-decorators")
|
.get_plugin("proposal-decorators")
|
||||||
.map(get_options::<DecoratorsOptions>)
|
.map(get_options::<DecoratorsOptions>)
|
||||||
|
.transpose()?
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
typescript: options
|
typescript: options
|
||||||
.get_plugin("transform-typescript")
|
.get_plugin("transform-typescript")
|
||||||
.map(get_options::<TypeScriptOptions>)
|
.map(get_options::<TypeScriptOptions>)
|
||||||
|
.transpose()?
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
react,
|
react,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TestCase {
|
pub trait TestCase {
|
||||||
|
|
@ -113,7 +117,7 @@ pub trait TestCase {
|
||||||
|
|
||||||
fn options(&self) -> &BabelOptions;
|
fn options(&self) -> &BabelOptions;
|
||||||
|
|
||||||
fn transform_options(&self) -> &TransformOptions;
|
fn transform_options(&self) -> &serde_json::Result<TransformOptions>;
|
||||||
|
|
||||||
fn test(&self, filtered: bool) -> bool;
|
fn test(&self, filtered: bool) -> bool;
|
||||||
|
|
||||||
|
|
@ -129,11 +133,12 @@ pub trait TestCase {
|
||||||
|
|
||||||
// Skip deprecated react options
|
// Skip deprecated react options
|
||||||
if options.babel_8_breaking.is_some_and(|b| b) {
|
if options.babel_8_breaking.is_some_and(|b| b) {
|
||||||
let react_options = &self.transform_options().react;
|
if let Ok(options) = self.transform_options() {
|
||||||
if react_options.use_built_ins.is_some() || react_options.use_spread.is_some() {
|
if options.react.use_built_ins.is_some() || options.react.use_spread.is_some() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Legacy decorators is not supported by the parser
|
// Legacy decorators is not supported by the parser
|
||||||
if options
|
if options
|
||||||
|
|
@ -163,6 +168,13 @@ pub trait TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform(&self, path: &Path) -> Result<String, Vec<Error>> {
|
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 allocator = Allocator::default();
|
||||||
let source_text = fs::read_to_string(path).unwrap();
|
let source_text = fs::read_to_string(path).unwrap();
|
||||||
|
|
||||||
|
|
@ -178,7 +190,7 @@ pub trait TestCase {
|
||||||
|
|
||||||
let transformed_program = allocator.alloc(ret.program);
|
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);
|
.build(transformed_program);
|
||||||
|
|
||||||
result.map(|()| {
|
result.map(|()| {
|
||||||
|
|
@ -193,7 +205,7 @@ pub trait TestCase {
|
||||||
pub struct ConformanceTestCase {
|
pub struct ConformanceTestCase {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
options: BabelOptions,
|
options: BabelOptions,
|
||||||
transform_options: TransformOptions,
|
transform_options: serde_json::Result<TransformOptions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestCase for ConformanceTestCase {
|
impl TestCase for ConformanceTestCase {
|
||||||
|
|
@ -207,7 +219,7 @@ impl TestCase for ConformanceTestCase {
|
||||||
&self.options
|
&self.options
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_options(&self) -> &TransformOptions {
|
fn transform_options(&self) -> &serde_json::Result<TransformOptions> {
|
||||||
&self.transform_options
|
&self.transform_options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,8 +242,6 @@ impl TestCase for ConformanceTestCase {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|path| path.extension().and_then(std::ffi::OsStr::to_str) == Some("js"));
|
.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)
|
let source_type = SourceType::from_path(&self.path)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_script(if self.options.source_type.is_some() {
|
.with_script(if self.options.source_type.is_some() {
|
||||||
|
|
@ -246,7 +256,12 @@ impl TestCase for ConformanceTestCase {
|
||||||
println!("output_path: {output_path:?}");
|
println!("output_path: {output_path:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform input.js
|
let codegen_options = CodegenOptions::default();
|
||||||
|
let mut transformed_code = String::new();
|
||||||
|
let mut actual_errors = String::new();
|
||||||
|
|
||||||
|
let transform_options = match self.transform_options() {
|
||||||
|
Ok(transform_options) => {
|
||||||
let ret = Parser::new(&allocator, &input, source_type).parse();
|
let ret = Parser::new(&allocator, &input, source_type).parse();
|
||||||
let semantic = SemanticBuilder::new(&input, source_type)
|
let semantic = SemanticBuilder::new(&input, source_type)
|
||||||
.with_trivias(ret.trivias)
|
.with_trivias(ret.trivias)
|
||||||
|
|
@ -256,10 +271,6 @@ impl TestCase for ConformanceTestCase {
|
||||||
let program = allocator.alloc(ret.program);
|
let program = allocator.alloc(ret.program);
|
||||||
let transformer =
|
let transformer =
|
||||||
Transformer::new(&allocator, &self.path, semantic, transform_options.clone());
|
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);
|
let result = transformer.build(program);
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
transformed_code = Codegen::<false>::new("", &input, codegen_options.clone())
|
transformed_code = Codegen::<false>::new("", &input, codegen_options.clone())
|
||||||
|
|
@ -268,10 +279,22 @@ impl TestCase for ConformanceTestCase {
|
||||||
} else {
|
} else {
|
||||||
actual_errors = result.err().unwrap().iter().map(ToString::to_string).collect();
|
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();
|
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(
|
let output = output_path.and_then(|path| fs::read_to_string(path).ok()).map_or_else(
|
||||||
|| {
|
|| {
|
||||||
if let Some(throws) = &babel_options.throws {
|
if let Some(throws) = &babel_options.throws {
|
||||||
|
|
@ -324,7 +347,7 @@ impl TestCase for ConformanceTestCase {
|
||||||
pub struct ExecTestCase {
|
pub struct ExecTestCase {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
options: BabelOptions,
|
options: BabelOptions,
|
||||||
transform_options: TransformOptions,
|
transform_options: serde_json::Result<TransformOptions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecTestCase {
|
impl ExecTestCase {
|
||||||
|
|
@ -368,7 +391,7 @@ impl TestCase for ExecTestCase {
|
||||||
&self.options
|
&self.options
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_options(&self) -> &TransformOptions {
|
fn transform_options(&self) -> &serde_json::Result<TransformOptions> {
|
||||||
&self.transform_options
|
&self.transform_options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue