diff --git a/rust/src/core.rs b/rust/src/core.rs index 15474fe6..1a61a631 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -21,6 +21,28 @@ use crate::{enums, options, outputs}; const VERSION: &'static str = "0.2.0"; +pub fn parse<'local>(code: String, options: options::ParseOptions) -> Result { + let parse_params = ParseParams { + specifier: options.specifier, + text_info: SourceTextInfo::from_string(code), + media_type: options.media_type, + capture_tokens: options.capture_tokens, + maybe_syntax: None, + scope_analysis: options.scope_analysis, + }; + let result = match options.parse_mode { + enums::ParseMode::Script => parse_script(parse_params), + _ => parse_module(parse_params), + }; + match result { + Ok(parsed_source) => Ok(outputs::ParseOutput { + module: parsed_source.is_module(), + script: parsed_source.is_script(), + }), + Err(e) => Err(e.to_string()), + } +} + pub fn transpile<'local>(code: String, options: options::TranspileOptions) -> Result { let parse_params = ParseParams { specifier: options.specifier, diff --git a/rust/src/error.rs b/rust/src/error.rs index 56480c2f..b6998150 100644 --- a/rust/src/error.rs +++ b/rust/src/error.rs @@ -17,59 +17,113 @@ use jni::objects::{GlobalRef, JStaticMethodID, JThrowable}; use jni::signature::ReturnType; -use jni::sys::{jvalue}; +use jni::sys::jvalue; use jni::JNIEnv; use crate::converter; -struct JniCalls { - pub jclass_core_exception: GlobalRef, - pub jmethod_id_core_exception_transpile_error: JStaticMethodID, +struct JavaCoreException { + pub class: GlobalRef, + pub method_parse_error: JStaticMethodID, + pub method_transpile_error: JStaticMethodID, } -unsafe impl Send for JniCalls {} -unsafe impl Sync for JniCalls {} +unsafe impl Send for JavaCoreException {} +unsafe impl Sync for JavaCoreException {} -static mut JNI_CALLS: Option = None; +impl JavaCoreException { + pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { + let class = env + .find_class("com/caoccao/javet/swc4j/exceptions/Swc4jCoreException") + .expect("Couldn't find class Swc4jCoreException"); + let class = env + .new_global_ref(class) + .expect("Couldn't globalize class Swc4jCoreException"); + let method_parse_error = env + .get_static_method_id( + &class, + "parseError", + "(Ljava/lang/String;)Lcom/caoccao/javet/swc4j/exceptions/Swc4jCoreException;", + ) + .expect("Couldn't find static method Swc4jCoreException.parseError"); + let method_transpile_error = env + .get_static_method_id( + &class, + "transpileError", + "(Ljava/lang/String;)Lcom/caoccao/javet/swc4j/exceptions/Swc4jCoreException;", + ) + .expect("Couldn't find static method Swc4jCoreException.transpileError"); + JavaCoreException { + class, + method_parse_error, + method_transpile_error, + } + } + + pub fn throw_parse_error<'local, 'a>(&self, env: &mut JNIEnv<'local>, message: &'a str) { + let message = jvalue { + l: converter::string_to_jstring(env, message).as_raw(), + }; + let exception = unsafe { + JThrowable::from_raw( + env + .call_static_method_unchecked( + &self.class, + &self.method_parse_error, + ReturnType::Object, + &[message], + ) + .expect("Couldn't create parse error") + .as_jni() + .l, + ) + }; + let _ = env.throw(exception); + } + + pub fn throw_transpile_error<'local, 'a>(&self, env: &mut JNIEnv<'local>, message: &'a str) { + let message = jvalue { + l: converter::string_to_jstring(env, message).as_raw(), + }; + let exception = unsafe { + JThrowable::from_raw( + env + .call_static_method_unchecked( + &self.class, + &self.method_transpile_error, + ReturnType::Object, + &[message], + ) + .expect("Couldn't create transpile error") + .as_jni() + .l, + ) + }; + let _ = env.throw(exception); + } +} + +static mut JAVA_CORE_EXCEPTION: Option = None; pub fn init<'local>(env: &mut JNIEnv<'local>) { - let jclass_core_exception = env - .find_class("com/caoccao/javet/swc4j/exceptions/Swc4jCoreException") - .expect("Couldn't find class Swc4jCoreException"); - let jclass_core_exception = env - .new_global_ref(jclass_core_exception) - .expect("Couldn't globalize class Swc4jCoreException"); - let jmethod_id_core_exception_transpile_error = env - .get_static_method_id( - &jclass_core_exception, - "transpileError", - "(Ljava/lang/String;)Lcom/caoccao/javet/swc4j/exceptions/Swc4jCoreException;", - ) - .expect("Couldn't find static method Swc4jCoreException.transpileError"); unsafe { - JNI_CALLS = Some(JniCalls { - jclass_core_exception, - jmethod_id_core_exception_transpile_error, - }); + JAVA_CORE_EXCEPTION = Some(JavaCoreException::new(env)); + } +} + +pub fn throw_parse_error<'local, 'a>(env: &mut JNIEnv<'local>, message: &'a str) { + unsafe { + JAVA_CORE_EXCEPTION + .as_ref() + .unwrap() + .throw_parse_error(env, message); } } pub fn throw_transpile_error<'local, 'a>(env: &mut JNIEnv<'local>, message: &'a str) { - let message = jvalue { - l: converter::string_to_jstring(env, message).as_raw(), - }; - let exception = unsafe { - JThrowable::from_raw( - env - .call_static_method_unchecked( - &JNI_CALLS.as_ref().unwrap().jclass_core_exception, - &JNI_CALLS.as_ref().unwrap().jmethod_id_core_exception_transpile_error, - ReturnType::Object, - &[message], - ) - .expect("Couldn't create transpile error") - .as_jni() - .l, - ) - }; - let _ = env.throw(exception); + unsafe { + JAVA_CORE_EXCEPTION + .as_ref() + .unwrap() + .throw_transpile_error(env, message); + } } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index e15cfd2d..a04610c6 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -53,13 +53,20 @@ pub extern "system" fn Java_com_caoccao_javet_swc4j_Swc4jNative_coreGetVersion<' #[no_mangle] pub extern "system" fn Java_com_caoccao_javet_swc4j_Swc4jNative_coreParse<'local>( - _: JNIEnv<'local>, + mut env: JNIEnv<'local>, _: JClass<'local>, - _: jstring, - _: jobject, + code: jstring, + options: jobject, ) -> jobject { - // TODO - null_mut() + let code = converter::jstring_to_string(&mut env, code); + let options = options::ParseOptions::from_jni_type(&mut env, options); + match core::parse(code, options) { + Ok(output) => output.to_jni_type(&mut env).as_raw(), + Err(message) => { + error::throw_parse_error(&mut env, message.as_str()); + null_mut() + } + } } #[no_mangle] diff --git a/rust/src/options.rs b/rust/src/options.rs index 6f2c27c9..63179eae 100644 --- a/rust/src/options.rs +++ b/rust/src/options.rs @@ -132,6 +132,80 @@ impl JavaParseMode { } } +struct JavaParseOptions { + #[allow(dead_code)] + class: GlobalRef, + method_get_media_type: JMethodID, + method_get_parse_mode: JMethodID, + method_get_specifier: JMethodID, + method_is_capture_tokens: JMethodID, + method_is_scope_analysis: JMethodID, +} +unsafe impl Send for JavaParseOptions {} +unsafe impl Sync for JavaParseOptions {} + +impl JavaParseOptions { + pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { + let class = env + .find_class("com/caoccao/javet/swc4j/options/Swc4jParseOptions") + .expect("Couldn't find class Swc4jParseOptions"); + let class = env + .new_global_ref(class) + .expect("Couldn't globalize class Swc4jParseOptions"); + let method_get_media_type = env + .get_method_id( + &class, + "getMediaType", + "()Lcom/caoccao/javet/swc4j/enums/Swc4jMediaType;", + ) + .expect("Couldn't find method Swc4jTranspileOptions.getMediaType"); + let method_get_parse_mode = env + .get_method_id( + &class, + "getParseMode", + "()Lcom/caoccao/javet/swc4j/enums/Swc4jParseMode;", + ) + .expect("Couldn't find method Swc4jTranspileOptions.getParseMode"); + let method_get_specifier = env + .get_method_id(&class, "getSpecifier", "()Ljava/lang/String;") + .expect("Couldn't find method Swc4jTranspileOptions.getSpecifier"); + let method_is_capture_tokens = env + .get_method_id(&class, "isCaptureTokens", "()Z") + .expect("Couldn't find method Swc4jTranspileOptions.isCaptureTokens"); + let method_is_scope_analysis = env + .get_method_id(&class, "isScopeAnalysis", "()Z") + .expect("Couldn't find method Swc4jTranspileOptions.isScopeAnalysis"); + JavaParseOptions { + class, + method_get_media_type, + method_get_parse_mode, + method_get_specifier, + method_is_capture_tokens, + method_is_scope_analysis, + } + } + + pub fn get_media_type<'local, 'a, 'b>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> JObject<'b> { + jni_utils::get_as_jobject(env, obj, self.method_get_media_type) + } + + pub fn get_parse_mode<'local, 'a, 'b>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> JObject<'b> { + jni_utils::get_as_jobject(env, obj, self.method_get_parse_mode) + } + + pub fn get_specifier<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> String { + jni_utils::get_as_string(env, obj, self.method_get_specifier) + } + + pub fn is_capture_tokens<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> bool { + jni_utils::get_as_boolean(env, obj, self.method_is_capture_tokens) + } + + pub fn is_scope_analysis<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> bool { + jni_utils::get_as_boolean(env, obj, self.method_is_scope_analysis) + } +} + struct JavaTranspileOptions { #[allow(dead_code)] class: GlobalRef, @@ -334,14 +408,16 @@ impl JavaTranspileOptions { static mut JAVA_IMPORTS_NOT_USED_AS_VALUES: Option = None; static mut JAVA_MEDIA_TYPE: Option = None; static mut JAVA_PARSE_MODE: Option = None; -static mut JAVA_TRANSPILER_OPTIONS: Option = None; +static mut JAVA_PARSE_OPTIONS: Option = None; +static mut JAVA_TRANSPILE_OPTIONS: Option = None; pub fn init<'local>(env: &mut JNIEnv<'local>) { unsafe { JAVA_IMPORTS_NOT_USED_AS_VALUES = Some(JavaImportsNotUsedAsValues::new(env)); JAVA_MEDIA_TYPE = Some(JavaMediaType::new(env)); JAVA_PARSE_MODE = Some(JavaParseMode::new(env)); - JAVA_TRANSPILER_OPTIONS = Some(JavaTranspileOptions::new(env)); + JAVA_PARSE_OPTIONS = Some(JavaParseOptions::new(env)); + JAVA_TRANSPILE_OPTIONS = Some(JavaTranspileOptions::new(env)); } } @@ -349,6 +425,58 @@ pub trait FromJniType { fn from_jni_type<'local>(env: &mut JNIEnv<'local>, o: jobject) -> Self; } +#[derive(Debug)] +pub struct ParseOptions { + /// Whether to capture tokens or not. + pub capture_tokens: bool, + /// Media type of the source text. + pub media_type: MediaType, + /// Should the code to be parsed as Module or Script, + pub parse_mode: enums::ParseMode, + /// Whether to apply swc's scope analysis. + pub scope_analysis: bool, + /// Specifier of the source text. + pub specifier: String, +} + +impl Default for ParseOptions { + fn default() -> Self { + ParseOptions { + capture_tokens: false, + media_type: MediaType::TypeScript, + parse_mode: enums::ParseMode::Module, + scope_analysis: false, + specifier: "file:///main.js".to_owned(), + } + } +} + +impl FromJniType for ParseOptions { + fn from_jni_type<'local>(env: &mut JNIEnv<'local>, obj: jobject) -> ParseOptions { + let obj = unsafe { JObject::from_raw(obj) }; + let obj = obj.as_ref(); + let java_media_type = unsafe { JAVA_MEDIA_TYPE.as_ref().unwrap() }; + let java_parse_mode = unsafe { JAVA_PARSE_MODE.as_ref().unwrap() }; + let java_parse_options = unsafe { JAVA_PARSE_OPTIONS.as_ref().unwrap() }; + let capture_tokens = java_parse_options.is_capture_tokens(env, obj); + let media_type = java_parse_options.get_media_type(env, obj); + let media_type = media_type.as_ref(); + let media_type = java_media_type.get_media_type(env, media_type); + let scope_analysis = java_parse_options.is_scope_analysis(env, obj); + let specifier = java_parse_options.get_specifier(env, obj); + let parse_mode = java_parse_options.get_parse_mode(env, obj); + let parse_mode = parse_mode.as_ref(); + let parse_mode = java_parse_mode.get_parse_mode(env, parse_mode); + ParseOptions { + capture_tokens, + media_type, + parse_mode, + scope_analysis, + specifier, + } + } +} + #[derive(Debug)] pub struct TranspileOptions { /// Whether to capture tokens or not. @@ -384,6 +512,12 @@ pub struct TranspileOptions { pub jsx_import_source: Option, /// Media type of the source text. pub media_type: MediaType, + /// Should the code to be parsed as Module or Script, + pub parse_mode: enums::ParseMode, + /// Should JSX be precompiled into static strings that need to be concatenated + /// with dynamic content. Defaults to `false`, mutually exclusive with + /// `transform_jsx`. + pub precompile_jsx: bool, /// Whether to apply swc's scope analysis. pub scope_analysis: bool, /// Should a corresponding .map file be created for the output. This should be @@ -393,12 +527,6 @@ pub struct TranspileOptions { pub specifier: String, /// Should JSX be transformed. Defaults to `true`. pub transform_jsx: bool, - /// Should the code to be parsed as Module or Script, - pub parse_mode: enums::ParseMode, - /// Should JSX be precompiled into static strings that need to be concatenated - /// with dynamic content. Defaults to `false`, mutually exclusive with - /// `transform_jsx`. - pub precompile_jsx: bool, /// Should import declarations be transformed to variable declarations using /// a dynamic import. This is useful for import & export declaration support /// in script contexts such as the Deno REPL. Defaults to `false`. @@ -437,7 +565,7 @@ impl FromJniType for TranspileOptions { let java_imports_not_used_as_values = unsafe { JAVA_IMPORTS_NOT_USED_AS_VALUES.as_ref().unwrap() }; let java_media_type = unsafe { JAVA_MEDIA_TYPE.as_ref().unwrap() }; let java_parse_mode = unsafe { JAVA_PARSE_MODE.as_ref().unwrap() }; - let java_transpiler_options = unsafe { JAVA_TRANSPILER_OPTIONS.as_ref().unwrap() }; + let java_transpiler_options = unsafe { JAVA_TRANSPILE_OPTIONS.as_ref().unwrap() }; let capture_tokens = java_transpiler_options.is_capture_tokens(env, obj); let emit_metadata = java_transpiler_options.is_emit_metadata(env, obj); let imports_not_used_as_values = java_transpiler_options.get_imports_not_used_as_values(env, obj); @@ -454,14 +582,14 @@ impl FromJniType for TranspileOptions { let media_type = java_transpiler_options.get_media_type(env, obj); let media_type = media_type.as_ref(); let media_type = java_media_type.get_media_type(env, media_type); - let scope_analysis = java_transpiler_options.is_scope_analysis(env, obj); - let source_map = java_transpiler_options.is_source_map(env, obj); - let specifier = java_transpiler_options.get_specifier(env, obj); - let transform_jsx = java_transpiler_options.is_transform_jsx(env, obj); let parse_mode = java_transpiler_options.get_parse_mode(env, obj); let parse_mode = parse_mode.as_ref(); let parse_mode = java_parse_mode.get_parse_mode(env, parse_mode); let precompile_jsx = java_transpiler_options.is_precompile_jsx(env, obj); + let scope_analysis = java_transpiler_options.is_scope_analysis(env, obj); + let source_map = java_transpiler_options.is_source_map(env, obj); + let specifier = java_transpiler_options.get_specifier(env, obj); + let transform_jsx = java_transpiler_options.is_transform_jsx(env, obj); let var_decl_imports = java_transpiler_options.is_var_decl_imports(env, obj); TranspileOptions { capture_tokens, @@ -475,12 +603,12 @@ impl FromJniType for TranspileOptions { jsx_fragment_factory, jsx_import_source, media_type, + parse_mode, + precompile_jsx, scope_analysis, source_map, specifier, transform_jsx, - parse_mode, - precompile_jsx, var_decl_imports, } } diff --git a/rust/src/outputs.rs b/rust/src/outputs.rs index b3689570..727a547c 100644 --- a/rust/src/outputs.rs +++ b/rust/src/outputs.rs @@ -23,6 +23,42 @@ use std::ptr::null_mut; use crate::converter; +struct JavaParseOutput { + class: GlobalRef, + method_constructor: JMethodID, +} +unsafe impl Send for JavaParseOutput {} +unsafe impl Sync for JavaParseOutput {} + +impl JavaParseOutput { + pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { + let class = env + .find_class("com/caoccao/javet/swc4j/outputs/Swc4jParseOutput") + .expect("Couldn't find class Swc4jParseOutput"); + let class = env + .new_global_ref(class) + .expect("Couldn't globalize class Swc4jParseOutput"); + let method_constructor = env + .get_method_id(&class, "", "(ZZ)V") + .expect("Couldn't find method Swc4jParseOutput.Swc4jParseOutput"); + JavaParseOutput { + class, + method_constructor, + } + } + + pub fn create<'local, 'a>(&self, env: &mut JNIEnv<'local>, module: jvalue, script: jvalue) -> JObject<'a> + where + 'local: 'a, + { + unsafe { + env + .new_object_unchecked(&self.class, self.method_constructor, &[module, script]) + .expect("Couldn't create Swc4jParseOutput") + } + } +} + struct JavaTranspileOutput { class: GlobalRef, method_constructor: JMethodID, @@ -60,16 +96,22 @@ impl JavaTranspileOutput { { unsafe { env - .new_object_unchecked(&self.class, self.method_constructor, &[code, module, script, source_map]) + .new_object_unchecked( + &self.class, + self.method_constructor, + &[code, module, script, source_map], + ) .expect("Couldn't create Swc4jTranspileOutput") } } } +static mut JAVA_PARSE_OUTPUT: Option = None; static mut JAVA_TRANSPILE_OUTPUT: Option = None; pub fn init<'local>(env: &mut JNIEnv<'local>) { unsafe { + JAVA_PARSE_OUTPUT = Some(JavaParseOutput::new(env)); JAVA_TRANSPILE_OUTPUT = Some(JavaTranspileOutput::new(env)); } } @@ -80,6 +122,27 @@ pub trait ToJniType { 'local: 'a; } +#[derive(Debug)] +pub struct ParseOutput { + pub module: bool, + pub script: bool, +} + +impl ToJniType for ParseOutput { + fn to_jni_type<'local, 'a>(&self, env: &mut JNIEnv<'local>) -> JObject<'a> + where + 'local: 'a, + { + let module = jvalue { + z: if self.module { 1u8 } else { 0u8 }, + }; + let script = jvalue { + z: if self.script { 1u8 } else { 0u8 }, + }; + unsafe { JAVA_PARSE_OUTPUT.as_ref().unwrap() }.create(env, module, script) + } +} + #[derive(Debug)] pub struct TranspileOutput { pub code: String, diff --git a/rust/tests/test_core.rs b/rust/tests/test_core.rs index 27594b2b..3b18f482 100644 --- a/rust/tests/test_core.rs +++ b/rust/tests/test_core.rs @@ -24,6 +24,44 @@ fn test_get_version() { assert_eq!(core::get_version(), "0.2.0"); } +#[test] +fn test_parse_jsx_with_default_options() { + let code = String::from("import React from 'react';\n") + + "import './App.css';\n" + + "function App() {\n" + + " return (\n" + + "

Hello World!

\n" + + " );\n" + + "}\n" + + "export default App;"; + let options = options::ParseOptions { + media_type: MediaType::Jsx, + ..Default::default() + }; + let output = core::parse(code.to_owned(), options); + assert!(output.is_ok()); + let output = output.unwrap(); + assert!(output.module); + assert!(!output.script); +} + +#[test] +fn test_parse_wrong_media_type() { + let code = "function add(a:number, b:number) { return a+b; }"; + let expected_error = String::from("Expected ',', got ':' at file:///main.js:1:15\n") + + "\n" + + " function add(a:number, b:number) { return a+b; }\n" + + " ~"; + let options = options::ParseOptions { + media_type: MediaType::JavaScript, + ..Default::default() + }; + let output = core::parse(code.to_owned(), options); + assert!(output.is_err()); + let output_error = output.err().unwrap(); + assert_eq!(expected_error, output_error); +} + #[test] fn test_transpile_jsx_with_custom_jsx_factory() { let code = String::from("import React from 'react';\n") @@ -50,6 +88,7 @@ fn test_transpile_jsx_with_custom_jsx_factory() { assert!(output.is_ok()); let output = output.unwrap(); assert!(output.module); + assert!(!output.script); let output_code = output.code; assert_eq!(expected_code, &output_code[0..expected_code.len()]); assert!(output_code[expected_code.len()..].starts_with(expected_source_map_prefix)); @@ -80,6 +119,7 @@ fn test_transpile_jsx_with_default_options() { assert!(output.is_ok()); let output = output.unwrap(); assert!(output.module); + assert!(!output.script); let output_code = output.code; assert_eq!(expected_code, &output_code[0..expected_code.len()]); assert!(output_code[expected_code.len()..].starts_with(expected_source_map_prefix)); @@ -95,6 +135,7 @@ fn test_transpile_type_script_with_inline_source_map() { assert!(output.is_ok()); let output = output.unwrap(); assert!(output.module); + assert!(!output.script); let output_code = output.code; assert_eq!(expected_code, &output_code[0..expected_code.len()]); assert!(output_code[expected_code.len()..].starts_with(expected_source_map_prefix)); diff --git a/src/main/java/com/caoccao/javet/swc4j/exceptions/Swc4jCoreException.java b/src/main/java/com/caoccao/javet/swc4j/exceptions/Swc4jCoreException.java index 8073d7fa..29051d71 100644 --- a/src/main/java/com/caoccao/javet/swc4j/exceptions/Swc4jCoreException.java +++ b/src/main/java/com/caoccao/javet/swc4j/exceptions/Swc4jCoreException.java @@ -43,6 +43,17 @@ public static Swc4jCoreException featureNotSupported(String feature) { return new Swc4jCoreException(MessageFormat.format("Feature {0} is not supported", feature)); } + /** + * Parse error. + * + * @param message the message + * @return the swc4j core exception + * @since 0.1.0 + */ + public static Swc4jCoreException parseError(String message) { + return new Swc4jCoreException(message); + } + /** * Transpile error. * diff --git a/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java b/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java index a24f5811..746985de 100644 --- a/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java +++ b/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java @@ -19,7 +19,9 @@ import com.caoccao.javet.swc4j.enums.Swc4jMediaType; import com.caoccao.javet.swc4j.enums.Swc4jParseMode; import com.caoccao.javet.swc4j.exceptions.Swc4jCoreException; +import com.caoccao.javet.swc4j.options.Swc4jParseOptions; import com.caoccao.javet.swc4j.options.Swc4jTranspileOptions; +import com.caoccao.javet.swc4j.outputs.Swc4jParseOutput; import com.caoccao.javet.swc4j.outputs.Swc4jTranspileOutput; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -42,7 +44,41 @@ public void testGetVersion() { } @Test - public void testTranspileJSXWithCustomJsxFactory() throws Swc4jCoreException { + public void testParseJsxWithDefaultOptions() throws Swc4jCoreException { + String code = "import React from 'react';\n" + + "import './App.css';\n" + + "function App() {\n" + + " return (\n" + + "

Hello World!

\n" + + " );\n" + + "}\n" + + "export default App;"; + Swc4jParseOptions options = new Swc4jParseOptions() + .setMediaType(Swc4jMediaType.Jsx); + Swc4jParseOutput output = swc4j.parse(code, options); + assertNotNull(output); + assertTrue(output.isModule()); + assertFalse(output.isScript()); + } + + @Test + public void testParseWrongMediaType() { + String code = "function add(a:number, b:number) { return a+b; }"; + Swc4jParseOptions options = new Swc4jParseOptions() + .setMediaType(Swc4jMediaType.JavaScript); + assertEquals( + "Expected ',', got ':' at file:///main.js:1:15\n" + + "\n" + + " function add(a:number, b:number) { return a+b; }\n" + + " ~", + assertThrows( + Swc4jCoreException.class, + () -> swc4j.parse(code, options)) + .getMessage()); + } + + @Test + public void testTranspileJsxWithCustomJsxFactory() throws Swc4jCoreException { String code = "import React from 'react';\n" + "import './App.css';\n" + "function App() {\n" + @@ -65,6 +101,7 @@ public void testTranspileJSXWithCustomJsxFactory() throws Swc4jCoreException { assertNotNull(output); assertEquals(expectedCode, output.getCode().substring(0, expectedCode.length())); assertTrue(output.isModule()); + assertFalse(output.isScript()); assertEquals( expectedSourceMapPrefix, output.getCode().substring( @@ -74,7 +111,7 @@ public void testTranspileJSXWithCustomJsxFactory() throws Swc4jCoreException { } @Test - public void testTranspileJSXWithDefaultOptions() throws Swc4jCoreException { + public void testTranspileJsxWithDefaultOptions() throws Swc4jCoreException { String code = "import React from 'react';\n" + "import './App.css';\n" + "function App() {\n" + @@ -96,6 +133,7 @@ public void testTranspileJSXWithDefaultOptions() throws Swc4jCoreException { assertNotNull(output); assertEquals(expectedCode, output.getCode().substring(0, expectedCode.length())); assertTrue(output.isModule()); + assertFalse(output.isScript()); assertEquals( expectedSourceMapPrefix, output.getCode().substring( @@ -117,6 +155,7 @@ public void testTranspileTypeScriptWithInlineSourceMap() throws Swc4jCoreExcepti assertNotNull(output); assertEquals(expectedCode, output.getCode().substring(0, expectedCode.length())); assertTrue(output.isModule()); + assertFalse(output.isScript()); assertEquals( expectedSourceMapPrefix, output.getCode().substring(