diff --git a/rust/src/enums.rs b/rust/src/enums.rs index d84f1add..7d873d8f 100644 --- a/rust/src/enums.rs +++ b/rust/src/enums.rs @@ -15,23 +15,58 @@ * limitations under the License. */ +use jni::objects::{GlobalRef, JMethodID, JObject, JStaticMethodID}; +use jni::signature::ReturnType; +use jni::sys::jvalue; +use jni::JNIEnv; + pub use deno_ast::{ImportsNotUsedAsValues, MediaType}; -pub trait ParseById { +use crate::jni_utils; + +pub trait IdentifiableEnum { + fn get_id(&self) -> i32; fn parse_by_id(id: i32) -> T; } -impl ParseById for ImportsNotUsedAsValues { +impl IdentifiableEnum for ImportsNotUsedAsValues { + fn get_id(&self) -> i32 { + match self { + ImportsNotUsedAsValues::Remove => 0, + ImportsNotUsedAsValues::Preserve => 1, + ImportsNotUsedAsValues::Error => 2, + } + } fn parse_by_id(id: i32) -> ImportsNotUsedAsValues { match id { - 1 => ImportsNotUsedAsValues::Remove, - 2 => ImportsNotUsedAsValues::Preserve, + 0 => ImportsNotUsedAsValues::Remove, + 1 => ImportsNotUsedAsValues::Preserve, _ => ImportsNotUsedAsValues::Error, } } } -impl ParseById for MediaType { +impl IdentifiableEnum for MediaType { + fn get_id(&self) -> i32 { + match self { + MediaType::JavaScript => 0, + MediaType::Jsx => 1, + MediaType::Mjs => 2, + MediaType::Cjs => 3, + MediaType::TypeScript => 4, + MediaType::Mts => 5, + MediaType::Cts => 6, + MediaType::Dts => 7, + MediaType::Dmts => 8, + MediaType::Dcts => 9, + MediaType::Tsx => 10, + MediaType::Json => 11, + MediaType::Wasm => 12, + MediaType::TsBuildInfo => 13, + MediaType::SourceMap => 14, + MediaType::Unknown => 15, + } + } fn parse_by_id(id: i32) -> MediaType { match id { 0 => MediaType::JavaScript, @@ -60,11 +95,138 @@ pub enum ParseMode { Script, } -impl ParseById for ParseMode { +impl IdentifiableEnum for ParseMode { + fn get_id(&self) -> i32 { + match self { + ParseMode::Module => 0, + ParseMode::Script => 1, + } + } fn parse_by_id(id: i32) -> ParseMode { match id { - 1 => ParseMode::Script, - _ => ParseMode::Module, + 0 => ParseMode::Module, + _ => ParseMode::Script, } } } + +pub struct JavaImportsNotUsedAsValues { + #[allow(dead_code)] + class: GlobalRef, + method_get_id: JMethodID, +} +unsafe impl Send for JavaImportsNotUsedAsValues {} +unsafe impl Sync for JavaImportsNotUsedAsValues {} + +impl JavaImportsNotUsedAsValues { + pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { + let class = env + .find_class("com/caoccao/javet/swc4j/enums/Swc4jImportsNotUsedAsValues") + .expect("Couldn't find class Swc4jImportsNotUsedAsValues"); + let class = env + .new_global_ref(class) + .expect("Couldn't globalize class Swc4jImportsNotUsedAsValues"); + let method_get_id = env + .get_method_id(&class, "getId", "()I") + .expect("Couldn't find method Swc4jImportsNotUsedAsValues.getId"); + JavaImportsNotUsedAsValues { class, method_get_id } + } + + pub fn get_imports_not_used_as_values<'local, 'a>( + &self, + env: &mut JNIEnv<'local>, + obj: &JObject<'a>, + ) -> ImportsNotUsedAsValues { + let id = jni_utils::get_as_int(env, obj.as_ref(), self.method_get_id); + ImportsNotUsedAsValues::parse_by_id(id) + } +} + +pub struct JavaMediaType { + #[allow(dead_code)] + class: GlobalRef, + method_get_id: JMethodID, + method_parse: JStaticMethodID, +} +unsafe impl Send for JavaMediaType {} +unsafe impl Sync for JavaMediaType {} + +impl JavaMediaType { + pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { + let class = env + .find_class("com/caoccao/javet/swc4j/enums/Swc4jMediaType") + .expect("Couldn't find class Swc4jMediaType"); + let class = env + .new_global_ref(class) + .expect("Couldn't globalize class Swc4jMediaType"); + let method_get_id = env + .get_method_id(&class, "getId", "()I") + .expect("Couldn't find method Swc4jMediaType.getId"); + let method_parse = env + .get_static_method_id(&class, "parse", "(I)Lcom/caoccao/javet/swc4j/enums/Swc4jMediaType;") + .expect("Couldn't find method Swc4jMediaType.parse"); + JavaMediaType { + class, + method_get_id, + method_parse, + } + } + + pub fn get_media_type<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> MediaType { + let id = jni_utils::get_as_int(env, obj.as_ref(), self.method_get_id); + MediaType::parse_by_id(id) + } + + pub fn parse<'local, 'a>(&self, env: &mut JNIEnv<'local>, id: i32) -> JObject<'a> { + let id = jvalue { i: id }; + unsafe { + JObject::from_raw( + env + .call_static_method_unchecked(&self.class, self.method_parse, ReturnType::Object, &[id]) + .expect("Object is expected") + .as_jni() + .l, + ) + } + } +} + +pub struct JavaParseMode { + #[allow(dead_code)] + class: GlobalRef, + method_get_id: JMethodID, +} +unsafe impl Send for JavaParseMode {} +unsafe impl Sync for JavaParseMode {} + +impl JavaParseMode { + pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { + let class = env + .find_class("com/caoccao/javet/swc4j/enums/Swc4jParseMode") + .expect("Couldn't find class Swc4jParseMode"); + let class = env + .new_global_ref(class) + .expect("Couldn't globalize class Swc4jParseMode"); + let method_get_id = env + .get_method_id(&class, "getId", "()I") + .expect("Couldn't find method Swc4jParseMode.getId"); + JavaParseMode { class, method_get_id } + } + + pub fn get_parse_mode<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> ParseMode { + let id = jni_utils::get_as_int(env, obj.as_ref(), self.method_get_id); + ParseMode::parse_by_id(id) + } +} + +pub static mut JAVA_IMPORTS_NOT_USED_AS_VALUES: Option = None; +pub static mut JAVA_MEDIA_TYPE: Option = None; +pub static mut JAVA_PARSE_MODE: 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)); + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index a04610c6..12ef7aa9 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -37,6 +37,7 @@ pub mod outputs; pub extern "system" fn JNI_OnLoad<'local>(java_vm: JavaVM, _: c_void) -> jint { debug_println!("JNI_OnLoad()"); let mut env = java_vm.get_env().expect("Cannot get JNI env"); + enums::init(&mut env); error::init(&mut env); options::init(&mut env); outputs::init(&mut env); diff --git a/rust/src/options.rs b/rust/src/options.rs index 558a5804..34e1662a 100644 --- a/rust/src/options.rs +++ b/rust/src/options.rs @@ -19,95 +19,8 @@ use jni::objects::{GlobalRef, JMethodID, JObject}; use jni::sys::jobject; use jni::JNIEnv; -use crate::{enums::*, jni_utils}; - -struct JavaImportsNotUsedAsValues { - #[allow(dead_code)] - class: GlobalRef, - method_get_id: JMethodID, -} -unsafe impl Send for JavaImportsNotUsedAsValues {} -unsafe impl Sync for JavaImportsNotUsedAsValues {} - -impl JavaImportsNotUsedAsValues { - pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { - let class = env - .find_class("com/caoccao/javet/swc4j/enums/Swc4jImportsNotUsedAsValues") - .expect("Couldn't find class Swc4jImportsNotUsedAsValues"); - let class = env - .new_global_ref(class) - .expect("Couldn't globalize class Swc4jImportsNotUsedAsValues"); - let method_get_id = env - .get_method_id(&class, "getId", "()I") - .expect("Couldn't find method Swc4jImportsNotUsedAsValues.getId"); - JavaImportsNotUsedAsValues { class, method_get_id } - } - - pub fn get_imports_not_used_as_values<'local, 'a>( - &self, - env: &mut JNIEnv<'local>, - obj: &JObject<'a>, - ) -> ImportsNotUsedAsValues { - let id = jni_utils::get_as_int(env, obj.as_ref(), self.method_get_id); - ImportsNotUsedAsValues::parse_by_id(id) - } -} - -struct JavaMediaType { - #[allow(dead_code)] - class: GlobalRef, - method_get_id: JMethodID, -} -unsafe impl Send for JavaMediaType {} -unsafe impl Sync for JavaMediaType {} - -impl JavaMediaType { - pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { - let class = env - .find_class("com/caoccao/javet/swc4j/enums/Swc4jMediaType") - .expect("Couldn't find class Swc4jMediaType"); - let class = env - .new_global_ref(class) - .expect("Couldn't globalize class Swc4jMediaType"); - let method_get_id = env - .get_method_id(&class, "getId", "()I") - .expect("Couldn't find method Swc4jMediaType.getId"); - JavaMediaType { class, method_get_id } - } - - pub fn get_media_type<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> MediaType { - let id = jni_utils::get_as_int(env, obj.as_ref(), self.method_get_id); - MediaType::parse_by_id(id) - } -} - -struct JavaParseMode { - #[allow(dead_code)] - class: GlobalRef, - method_get_id: JMethodID, -} -unsafe impl Send for JavaParseMode {} -unsafe impl Sync for JavaParseMode {} - -impl JavaParseMode { - pub fn new<'local>(env: &mut JNIEnv<'local>) -> Self { - let class = env - .find_class("com/caoccao/javet/swc4j/enums/Swc4jParseMode") - .expect("Couldn't find class Swc4jParseMode"); - let class = env - .new_global_ref(class) - .expect("Couldn't globalize class Swc4jParseMode"); - let method_get_id = env - .get_method_id(&class, "getId", "()I") - .expect("Couldn't find method Swc4jParseMode.getId"); - JavaParseMode { class, method_get_id } - } - - pub fn get_parse_mode<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> ParseMode { - let id = jni_utils::get_as_int(env, obj.as_ref(), self.method_get_id); - ParseMode::parse_by_id(id) - } -} +use crate::enums::*; +use crate::jni_utils; struct JavaParseOptions { #[allow(dead_code)] @@ -382,17 +295,11 @@ 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_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_PARSE_OPTIONS = Some(JavaParseOptions::new(env)); JAVA_TRANSPILE_OPTIONS = Some(JavaTranspileOptions::new(env)); } diff --git a/rust/src/outputs.rs b/rust/src/outputs.rs index ad4658a0..bd26f659 100644 --- a/rust/src/outputs.rs +++ b/rust/src/outputs.rs @@ -25,6 +25,7 @@ use deno_ast::{ParsedSource, TranspiledSource}; use std::ptr::null_mut; use crate::converter; +use crate::enums::*; use crate::options::*; struct JavaParseOutput { @@ -43,7 +44,11 @@ impl JavaParseOutput { .new_global_ref(class) .expect("Couldn't globalize class Swc4jParseOutput"); let method_constructor = env - .get_method_id(&class, "", "(ZZLjava/lang/String;)V") + .get_method_id( + &class, + "", + "(Lcom/caoccao/javet/swc4j/enums/Swc4jMediaType;ZZLjava/lang/String;)V", + ) .expect("Couldn't find method Swc4jParseOutput.Swc4jParseOutput"); JavaParseOutput { class, @@ -54,6 +59,7 @@ impl JavaParseOutput { pub fn create<'local, 'a>( &self, env: &mut JNIEnv<'local>, + media_type: jvalue, module: jvalue, script: jvalue, source_map: jvalue, @@ -63,7 +69,11 @@ impl JavaParseOutput { { unsafe { env - .new_object_unchecked(&self.class, self.method_constructor, &[module, script, source_map]) + .new_object_unchecked( + &self.class, + self.method_constructor, + &[media_type, module, script, source_map], + ) .expect("Couldn't create Swc4jParseOutput") } } @@ -88,7 +98,7 @@ impl JavaTranspileOutput { .get_method_id( &class, "", - "(Ljava/lang/String;ZZLjava/lang/String;Ljava/lang/String;)V", + "(Ljava/lang/String;Lcom/caoccao/javet/swc4j/enums/Swc4jMediaType;ZZLjava/lang/String;Ljava/lang/String;)V", ) .expect("Couldn't find method Swc4jTranspileOutput.Swc4jTranspileOutput"); JavaTranspileOutput { @@ -101,6 +111,7 @@ impl JavaTranspileOutput { &self, env: &mut JNIEnv<'local>, code: jvalue, + media_type: jvalue, module: jvalue, script: jvalue, source_map: jvalue, @@ -114,7 +125,7 @@ impl JavaTranspileOutput { .new_object_unchecked( &self.class, self.method_constructor, - &[code, module, script, source_map, source_text], + &[code, media_type, module, script, source_map, source_text], ) .expect("Couldn't create Swc4jTranspileOutput") } @@ -139,6 +150,7 @@ pub trait ToJniType { #[derive(Debug)] pub struct ParseOutput { + pub media_type: MediaType, pub module: bool, pub script: bool, pub source_text: String, @@ -147,6 +159,7 @@ pub struct ParseOutput { impl ParseOutput { pub fn new(parse_options: &ParseOptions, parsed_source: &ParsedSource) -> ParseOutput { + let media_type = parsed_source.media_type(); let module = parsed_source.is_module(); let script = parsed_source.is_script(); let source_text = parsed_source.text_info().text().to_string(); @@ -156,6 +169,7 @@ impl ParseOutput { None }; ParseOutput { + media_type, module, script, source_text, @@ -169,6 +183,10 @@ impl ToJniType for ParseOutput { where 'local: 'a, { + let java_media_type = unsafe { JAVA_MEDIA_TYPE.as_ref().unwrap() }; + let media_type = jvalue { + l: java_media_type.parse(env, self.media_type.get_id()).as_raw(), + }; let module = jvalue { z: if self.module { 1u8 } else { 0u8 }, }; @@ -178,13 +196,14 @@ impl ToJniType for ParseOutput { let source_text = jvalue { l: converter::string_to_jstring(env, &self.source_text).as_raw(), }; - unsafe { JAVA_PARSE_OUTPUT.as_ref().unwrap() }.create(env, module, script, source_text) + unsafe { JAVA_PARSE_OUTPUT.as_ref().unwrap() }.create(env, media_type, module, script, source_text) } } #[derive(Debug)] pub struct TranspileOutput { pub code: String, + pub media_type: MediaType, pub module: bool, pub script: bool, pub source_map: Option, @@ -192,14 +211,20 @@ pub struct TranspileOutput { } impl TranspileOutput { - pub fn new(_: &TranspileOptions, parsed_source: &ParsedSource, transpiled_source: &TranspiledSource) -> TranspileOutput { + pub fn new( + _: &TranspileOptions, + parsed_source: &ParsedSource, + transpiled_source: &TranspiledSource, + ) -> TranspileOutput { let code = transpiled_source.text.to_owned(); + let media_type = parsed_source.media_type(); let module = parsed_source.is_module(); let script = parsed_source.is_script(); let source_map = transpiled_source.source_map.to_owned(); let source_text = parsed_source.text_info().text().to_string(); TranspileOutput { code, + media_type, module, script, source_map, @@ -216,6 +241,10 @@ impl ToJniType for TranspileOutput { let code = jvalue { l: converter::string_to_jstring(env, &self.code).as_raw(), }; + let java_media_type = unsafe { JAVA_MEDIA_TYPE.as_ref().unwrap() }; + let media_type = jvalue { + l: java_media_type.parse(env, self.media_type.get_id()).as_raw(), + }; let module = jvalue { z: if self.module { 1u8 } else { 0u8 }, }; @@ -231,6 +260,14 @@ impl ToJniType for TranspileOutput { let source_text = jvalue { l: converter::string_to_jstring(env, &self.source_text).as_raw(), }; - unsafe { JAVA_TRANSPILE_OUTPUT.as_ref().unwrap() }.create(env, code, module, script, source_map, source_text) + unsafe { JAVA_TRANSPILE_OUTPUT.as_ref().unwrap() }.create( + env, + code, + media_type, + module, + script, + source_map, + source_text, + ) } } diff --git a/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jParseOutput.java b/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jParseOutput.java index de060a8a..9b48b381 100644 --- a/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jParseOutput.java +++ b/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jParseOutput.java @@ -16,12 +16,21 @@ package com.caoccao.javet.swc4j.outputs; +import com.caoccao.javet.swc4j.enums.Swc4jMediaType; +import com.caoccao.javet.swc4j.utils.AssertionUtils; + /** * The type Swc4j parse output. * * @since 0.2.0 */ public class Swc4jParseOutput { + /** + * The Media type. + * + * @since 0.2.0 + */ + protected Swc4jMediaType mediaType; /** * The Module. * @@ -49,12 +58,23 @@ public class Swc4jParseOutput { * @param sourceText the source text * @since 0.2.0 */ - public Swc4jParseOutput(boolean module, boolean script, String sourceText) { + public Swc4jParseOutput(Swc4jMediaType mediaType, boolean module, boolean script, String sourceText) { + setMediaType(mediaType); setModule(module); setScript(script); setSourceText(sourceText); } + /** + * Gets media type. + * + * @return the media type + * @since 0.2.0 + */ + public Swc4jMediaType getMediaType() { + return mediaType; + } + /** * Gets source text. * @@ -85,6 +105,18 @@ public boolean isScript() { return script; } + /** + * Sets media type. + * + * @param mediaType the media type + * @return the media type + * @since 0.2.0 + */ + public Swc4jParseOutput setMediaType(Swc4jMediaType mediaType) { + this.mediaType = AssertionUtils.notNull(mediaType, "Media type"); + return this; + } + /** * Sets module. * diff --git a/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jTranspileOutput.java b/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jTranspileOutput.java index 54fed4b7..e3b54a9b 100644 --- a/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jTranspileOutput.java +++ b/src/main/java/com/caoccao/javet/swc4j/outputs/Swc4jTranspileOutput.java @@ -16,6 +16,8 @@ package com.caoccao.javet.swc4j.outputs; +import com.caoccao.javet.swc4j.enums.Swc4jMediaType; + /** * The type Swc4j transpile output. * @@ -35,37 +37,25 @@ public class Swc4jTranspileOutput extends Swc4jParseOutput { */ protected String sourceMap; - /** - * Instantiates a new Swc4j transpile output. - * - * @since 0.1.0 - */ - public Swc4jTranspileOutput() { - this(null); - } - - /** - * Instantiates a new Swc4j transpile output. - * - * @param code the code - * @since 0.1.0 - */ - public Swc4jTranspileOutput(String code) { - this(code, false, false, null, null); - } - /** * Instantiates a new Swc4j transpile output. * * @param code the code + * @param mediaType the media type * @param module the module * @param script the script * @param sourceMap the source map * @param sourceText the source text * @since 0.1.0 */ - public Swc4jTranspileOutput(String code, boolean module, boolean script, String sourceMap, String sourceText) { - super(module, script, sourceText); + public Swc4jTranspileOutput( + String code, + Swc4jMediaType mediaType, + boolean module, + boolean script, + String sourceMap, + String sourceText) { + super(mediaType, module, script, sourceText); setCode(code); setSourceMap(sourceMap); } @@ -102,6 +92,12 @@ public Swc4jTranspileOutput setCode(String code) { return this; } + @Override + public Swc4jTranspileOutput setMediaType(Swc4jMediaType mediaType) { + super.setMediaType(mediaType); + return this; + } + @Override public Swc4jTranspileOutput setModule(boolean module) { super.setModule(module); diff --git a/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java b/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java index 8c5cc217..8e6cbc53 100644 --- a/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java +++ b/src/test/java/com/caoccao/javet/swc4j/TestSwc4j.java @@ -60,6 +60,7 @@ public void testParseJsxWithDefaultOptions() throws Swc4jCoreException { assertTrue(output.isModule()); assertFalse(output.isScript()); assertEquals(code, output.getSourceText()); + assertEquals(Swc4jMediaType.Jsx, output.getMediaType()); } @Test @@ -136,6 +137,7 @@ public void testTranspileJsxWithDefaultOptions() throws Swc4jCoreException { assertEquals(expectedCode, output.getCode().substring(0, expectedCode.length())); assertTrue(output.isModule()); assertFalse(output.isScript()); + assertEquals(Swc4jMediaType.Jsx, output.getMediaType()); assertEquals( expectedSourceMapPrefix, output.getCode().substring(