diff --git a/crates/oxc_transformer/src/jsx/options.rs b/crates/oxc_transformer/src/jsx/options.rs index a7c0bf6b0..dac670dfd 100644 --- a/crates/oxc_transformer/src/jsx/options.rs +++ b/crates/oxc_transformer/src/jsx/options.rs @@ -109,6 +109,20 @@ pub struct JsxOptions { impl Default for JsxOptions { fn default() -> Self { + Self::enable() + } +} + +impl JsxOptions { + pub fn conform(&mut self) { + if self.development { + self.jsx_plugin = true; + self.jsx_self_plugin = true; + self.jsx_source_plugin = true; + } + } + + pub fn enable() -> Self { Self { jsx_plugin: true, display_name_plugin: true, @@ -126,14 +140,23 @@ impl Default for JsxOptions { refresh: None, } } -} -impl JsxOptions { - pub fn conform(&mut self) { - if self.development { - self.jsx_plugin = true; - self.jsx_self_plugin = true; - self.jsx_source_plugin = true; + pub fn disable() -> Self { + Self { + jsx_plugin: false, + display_name_plugin: false, + jsx_self_plugin: false, + jsx_source_plugin: false, + runtime: JsxRuntime::default(), + development: false, + throw_if_namespace: false, + pure: false, + import_source: None, + pragma: None, + pragma_frag: None, + use_built_ins: None, + use_spread: None, + refresh: None, } } } diff --git a/napi/transform/index.d.ts b/napi/transform/index.d.ts index a40af6a82..492ba4810 100644 --- a/napi/transform/index.d.ts +++ b/napi/transform/index.d.ts @@ -259,7 +259,7 @@ export interface TransformOptions { /** Configure how TypeScript is transformed. */ typescript?: TypeScriptOptions /** Configure how TSX and JSX are transformed. */ - jsx?: JsxOptions + jsx?: 'preserve' | JsxOptions /** * Sets the target environment for the generated JavaScript. * diff --git a/napi/transform/src/transformer.rs b/napi/transform/src/transformer.rs index 1ce05e297..800914f37 100644 --- a/napi/transform/src/transformer.rs +++ b/napi/transform/src/transformer.rs @@ -106,7 +106,8 @@ pub struct TransformOptions { pub typescript: Option, /// Configure how TSX and JSX are transformed. - pub jsx: Option, + #[napi(ts_type = "'preserve' | JsxOptions")] + pub jsx: Option>, /// Sets the target environment for the generated JavaScript. /// @@ -150,7 +151,17 @@ impl TryFrom for oxc::transformer::TransformOptions { .typescript .map(oxc::transformer::TypeScriptOptions::from) .unwrap_or_default(), - jsx: options.jsx.map(Into::into).unwrap_or_default(), + jsx: match options.jsx { + Some(Either::A(s)) => { + if s == "preserve" { + oxc::transformer::JsxOptions::disable() + } else { + return Err(format!("Invalid jsx option: `{s}`.")); + } + } + Some(Either::B(options)) => oxc::transformer::JsxOptions::from(options), + None => oxc::transformer::JsxOptions::enable(), + }, env, helper_loader: options .helpers diff --git a/napi/transform/test/transform.test.ts b/napi/transform/test/transform.test.ts index f1acbfe78..a271a27e4 100644 --- a/napi/transform/test/transform.test.ts +++ b/napi/transform/test/transform.test.ts @@ -140,6 +140,31 @@ import bar = require('bar') }); }); +describe('jsx', () => { + const code = `const foo: Foo =
`; + + it('enables jsx transform by default', () => { + const ret = transform('test.tsx', code); + expect(ret.code).toEqual('import { jsx as _jsx } from "react/jsx-runtime";\nconst foo = _jsx("div", {});\n'); + }); + + it('configures jsx', () => { + const ret = transform('test.tsx', code, { + jsx: { + importSource: 'xxx', + }, + }); + expect(ret.code).toEqual('import { jsx as _jsx } from "xxx/jsx-runtime";\nconst foo = _jsx("div", {});\n'); + }); + + it('can preserve jsx transform', () => { + const ret = transform('test.tsx', code, { + jsx: 'preserve', + }); + expect(ret.code).toEqual('const foo =
;\n'); + }); +}); + describe('react refresh plugin', () => { const code = `import { useState } from "react"; export const App = () => {