From 1e2edc87897784dc6a3ee6239fb5018c7edec45f Mon Sep 17 00:00:00 2001 From: Sam Cao Date: Sun, 10 Mar 2024 11:53:50 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20Add=20importsNotUsedAsValue?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rust/Cargo.lock | 1 - rust/Cargo.toml | 1 - rust/src/converter.rs | 12 +++- rust/src/options.rs | 71 ++++++++++++++++++- .../enums/Swc4jImportsNotUsedAsValues.java | 66 +++++++++++++++++ .../swc4j/options/Swc4jTranspileOptions.java | 27 +++++++ 6 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/caoccao/javet/swc4j/enums/Swc4jImportsNotUsedAsValues.java diff --git a/rust/Cargo.lock b/rust/Cargo.lock index f5f74b0b..2d38b8eb 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -818,7 +818,6 @@ version = "0.1.0" dependencies = [ "debug_print", "deno_ast", - "deno_media_type", "jni", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 79243d09..ca09af21 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,5 +11,4 @@ crate_type = ["cdylib", "rlib"] [dependencies] debug_print = "1.0.0" deno_ast = { version = "1.0.1", features = ["module_specifier", "transpiling", "transforms"] } -deno_media_type = "0.1.2" jni = "0.21.1" diff --git a/rust/src/converter.rs b/rust/src/converter.rs index 0994af06..f40d1aa3 100644 --- a/rust/src/converter.rs +++ b/rust/src/converter.rs @@ -19,7 +19,17 @@ use jni::objects::JString; use jni::sys::{jboolean, jstring}; use jni::JNIEnv; -use deno_media_type::MediaType; +use deno_ast::{ImportsNotUsedAsValues, MediaType}; + +pub fn imports_not_used_as_values_id_to_imports_not_used_as_values( + imports_not_used_as_values_id: i32, +) -> ImportsNotUsedAsValues { + match imports_not_used_as_values_id { + 1 => ImportsNotUsedAsValues::Remove, + 2 => ImportsNotUsedAsValues::Preserve, + _ => ImportsNotUsedAsValues::Error, + } +} pub fn jboolean_to_bool(b: jboolean) -> bool { b != 0 diff --git a/rust/src/options.rs b/rust/src/options.rs index bdfec5bd..d2693e1d 100644 --- a/rust/src/options.rs +++ b/rust/src/options.rs @@ -19,10 +19,45 @@ use jni::objects::{GlobalRef, JMethodID, JObject}; use jni::sys::jobject; use jni::JNIEnv; -use deno_ast::MediaType; +use deno_ast::{ImportsNotUsedAsValues, MediaType}; use crate::{converter, 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 { + converter::imports_not_used_as_values_id_to_imports_not_used_as_values(jni_utils::get_as_int( + env, + obj.as_ref(), + self.method_get_id, + )) + } +} + struct JavaMediaType { #[allow(dead_code)] class: GlobalRef, @@ -53,6 +88,7 @@ impl JavaMediaType { struct JavaTranspileOptions { #[allow(dead_code)] class: GlobalRef, + method_get_imports_not_used_as_values: JMethodID, method_get_media_type: JMethodID, method_get_specifier: JMethodID, method_get_jsx_factory: JMethodID, @@ -79,6 +115,13 @@ impl JavaTranspileOptions { let class = env .new_global_ref(class) .expect("Couldn't globalize class Swc4jTranspileOptions"); + let method_get_imports_not_used_as_values = env + .get_method_id( + &class, + "getImportsNotUsedAsValues", + "()Lcom/caoccao/javet/swc4j/enums/Swc4jImportsNotUsedAsValues;", + ) + .expect("Couldn't find method Swc4jTranspileOptions.getImportsNotUsedAsValues"); let method_get_media_type = env .get_method_id( &class, @@ -127,6 +170,7 @@ impl JavaTranspileOptions { .expect("Couldn't find method Swc4jTranspileOptions.isVarDeclImports"); JavaTranspileOptions { class, + method_get_imports_not_used_as_values, method_get_media_type, method_get_specifier, method_get_jsx_factory, @@ -144,6 +188,14 @@ impl JavaTranspileOptions { } } + pub fn get_imports_not_used_as_values<'local, 'a, 'b>( + &self, + env: &mut JNIEnv<'local>, + obj: &JObject<'a>, + ) -> JObject<'b> { + jni_utils::get_as_jobject(env, obj, self.method_get_imports_not_used_as_values) + } + pub fn get_jsx_factory<'local, 'a>(&self, env: &mut JNIEnv<'local>, obj: &JObject<'a>) -> String { jni_utils::get_as_string(env, obj, self.method_get_jsx_factory) } @@ -201,11 +253,13 @@ impl JavaTranspileOptions { } } +static mut JAVA_IMPORTS_NOT_USED_AS_VALUES: Option = None; static mut JAVA_MEDIA_TYPE: Option = None; static mut JAVA_TRANSPILER_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_TRANSPILER_OPTIONS = Some(JavaTranspileOptions::new(env)); } @@ -220,6 +274,10 @@ pub struct TranspileOptions { /// When emitting a legacy decorator, also emit experimental decorator meta /// data. Defaults to `false`. pub emit_metadata: bool, + /// What to do with import statements that only import types i.e. whether to + /// remove them (`Remove`), keep them as side-effect imports (`Preserve`) + /// or error (`Error`). Defaults to `Remove`. + pub imports_not_used_as_values: ImportsNotUsedAsValues, /// Should the source map be inlined in the emitted code file, or provided /// as a separate file. Defaults to `true`. pub inline_source_map: bool, @@ -265,6 +323,7 @@ impl Default for TranspileOptions { fn default() -> Self { TranspileOptions { emit_metadata: false, + imports_not_used_as_values: ImportsNotUsedAsValues::Remove, inline_source_map: true, inline_sources: true, jsx_automatic: false, @@ -286,8 +345,14 @@ impl FromJniType for TranspileOptions { fn from_jni_type<'local>(env: &mut JNIEnv<'local>, obj: jobject) -> TranspileOptions { let obj = unsafe { JObject::from_raw(obj) }; let obj = obj.as_ref(); + 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_transpiler_options = unsafe { JAVA_TRANSPILER_OPTIONS.as_ref().unwrap() }; 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); + let imports_not_used_as_values = imports_not_used_as_values.as_ref(); + let imports_not_used_as_values = + java_imports_not_used_as_values.get_imports_not_used_as_values(env, imports_not_used_as_values); let inline_source_map = java_transpiler_options.is_inline_source_map(env, obj); let inline_sources = java_transpiler_options.is_inline_sources(env, obj); let jsx_automatic = java_transpiler_options.is_jsx_automatic(env, obj); @@ -297,15 +362,15 @@ impl FromJniType for TranspileOptions { let jsx_import_source = java_transpiler_options.get_jsx_import_source(env, obj); let media_type = java_transpiler_options.get_media_type(env, obj); let media_type = media_type.as_ref(); - let java_media_type = unsafe { JAVA_MEDIA_TYPE.as_ref().unwrap() }; let media_type = java_media_type.get_media_type(env, media_type); 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 precompile_jsx = java_transpiler_options.is_precompile_jsx(env, obj); - let var_decl_imports =java_transpiler_options.is_var_decl_imports(env, obj); + let var_decl_imports = java_transpiler_options.is_var_decl_imports(env, obj); TranspileOptions { emit_metadata, + imports_not_used_as_values, inline_source_map, inline_sources, jsx_automatic, diff --git a/src/main/java/com/caoccao/javet/swc4j/enums/Swc4jImportsNotUsedAsValues.java b/src/main/java/com/caoccao/javet/swc4j/enums/Swc4jImportsNotUsedAsValues.java new file mode 100644 index 00000000..5d3423c9 --- /dev/null +++ b/src/main/java/com/caoccao/javet/swc4j/enums/Swc4jImportsNotUsedAsValues.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.caoccao.javet.swc4j.enums; + +import java.util.stream.Stream; + +/** + * What to do with import statements that only import types i.e. whether to + * remove them (`Remove`), keep them as side-effect imports (`Preserve`) + * or error (`Error`). Defaults to `Remove`. + * + * @since 0.1.0 + */ +public enum Swc4jImportsNotUsedAsValues { + Remove(0), + Preserve(1), + Error(2); + + private static final int LENGTH = 3; + private static final Swc4jImportsNotUsedAsValues[] TYPES = new Swc4jImportsNotUsedAsValues[LENGTH]; + + static { + Stream.of(values()).forEach(v -> TYPES[v.getId()] = v); + } + + private final int id; + + Swc4jImportsNotUsedAsValues(int id) { + this.id = id; + } + + /** + * Parse swc4j imports not used as values. + * + * @param id the id + * @return the swc4j media type + * @since 0.1.0 + */ + public static Swc4jImportsNotUsedAsValues parse(int id) { + return id >= 0 && id < LENGTH ? TYPES[id] : Remove; + } + + /** + * Gets id. + * + * @return the id + * @since 0.1.0 + */ + public int getId() { + return id; + } +} diff --git a/src/main/java/com/caoccao/javet/swc4j/options/Swc4jTranspileOptions.java b/src/main/java/com/caoccao/javet/swc4j/options/Swc4jTranspileOptions.java index 330324bc..ed69b0fb 100644 --- a/src/main/java/com/caoccao/javet/swc4j/options/Swc4jTranspileOptions.java +++ b/src/main/java/com/caoccao/javet/swc4j/options/Swc4jTranspileOptions.java @@ -16,6 +16,7 @@ package com.caoccao.javet.swc4j.options; +import com.caoccao.javet.swc4j.enums.Swc4jImportsNotUsedAsValues; import com.caoccao.javet.swc4j.enums.Swc4jMediaType; import com.caoccao.javet.swc4j.utils.AssertionUtils; @@ -44,6 +45,7 @@ public final class Swc4jTranspileOptions { */ public static final String DEFAULT_JSX_FRAGMENT_FACTORY = "React.Fragment"; private boolean emitMetadata; + private Swc4jImportsNotUsedAsValues importsNotUsedAsValues; private boolean inlineSourceMap; private boolean inlineSources; private boolean jsxAutomatic; @@ -65,6 +67,7 @@ public final class Swc4jTranspileOptions { */ public Swc4jTranspileOptions() { setEmitMetadata(false); + setImportsNotUsedAsValues(Swc4jImportsNotUsedAsValues.Remove); setJsxAutomatic(false); setJsxDevelopment(false); setJsxFactory(DEFAULT_JSX_FACTORY); @@ -80,6 +83,18 @@ public Swc4jTranspileOptions() { setVarDeclImports(false); } + /** + * What to do with import statements that only import types i.e. whether to + * remove them (`Remove`), keep them as side-effect imports (`Preserve`) + * or error (`Error`). Defaults to `Remove`. + * + * @return the imports not used as values + * @since 0.1.0 + */ + public Swc4jImportsNotUsedAsValues getImportsNotUsedAsValues() { + return importsNotUsedAsValues; + } + /** * When transforming JSX, what value should be used for the JSX factory. * Defaults to `React.createElement`. @@ -242,6 +257,18 @@ public Swc4jTranspileOptions setEmitMetadata(boolean emitMetadata) { return this; } + /** + * Sets imports not used as values. + * + * @param importsNotUsedAsValues the imports not used as values + * @return the self + * @since 0.1.0 + */ + public Swc4jTranspileOptions setImportsNotUsedAsValues(Swc4jImportsNotUsedAsValues importsNotUsedAsValues) { + this.importsNotUsedAsValues = AssertionUtils.notNull(importsNotUsedAsValues, "Imports not used as values"); + return this; + } + /** * Sets inline source map. *