feat(plugin): Implement PoC of comments api (#4206)

This commit is contained in:
OJ Kwon 2022-03-31 01:45:08 -07:00 committed by GitHub
parent be9017dfe1
commit 536a190dc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 877 additions and 663 deletions

3
.gitignore vendored
View File

@ -55,4 +55,5 @@ pkg/
/lab
*.mm_profdata
.tsbuildinfo
.tsbuildinfo
.swc/

20
Cargo.lock generated
View File

@ -2345,9 +2345,9 @@ checksum = "11000e6ba5020e53e7cc26f73b91ae7d5496b4977851479edb66b694c0675c21"
[[package]]
name = "rkyv"
version = "0.7.35"
version = "0.7.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cdcf5caf69bcc87b1e3f5427b4f21a32fdd53c2847687bdf9861abb1cdaa0d8"
checksum = "5230ae2981a885590b0dc84e0b24c0ed23ad24f7adc0eb824b26cafa961f7c36"
dependencies = [
"bytecheck",
"hashbrown 0.12.0",
@ -2359,9 +2359,9 @@ dependencies = [
[[package]]
name = "rkyv_derive"
version = "0.7.35"
version = "0.7.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cf557da1f81b8c7e889c59c9c3abaf6978f7feb156b9579e4f8bf6d7a2bada"
checksum = "0fc752d5925dbcb324522f3a4c93193d17f107b2e11810913aa3ad352fa01480"
dependencies = [
"proc-macro2",
"quote",
@ -2856,6 +2856,7 @@ dependencies = [
"swc_error_reporters",
"swc_node_base",
"swc_node_comments",
"swc_plugin_comments",
"swc_plugin_runner",
"swc_visit",
"testing",
@ -3774,9 +3775,19 @@ dependencies = [
"swc_ecma_ast",
"swc_ecma_quote",
"swc_ecma_visit",
"swc_plugin_comments",
"swc_plugin_macro",
]
[[package]]
name = "swc_plugin_comments"
version = "0.1.0"
dependencies = [
"better_scoped_tls",
"rkyv",
"swc_common",
]
[[package]]
name = "swc_plugin_macro"
version = "0.3.1"
@ -3801,6 +3812,7 @@ dependencies = [
"swc_ecma_loader",
"swc_ecma_parser",
"swc_ecma_visit",
"swc_plugin_comments",
"testing",
"tracing",
"wasmer",

View File

@ -14,6 +14,7 @@ members = [
"crates/swc_plugin_macro",
"crates/swc_plugin_runner",
"crates/swc_plugin_testing",
"crates/swc_plugin_comments",
"crates/swc_timer",
"crates/swc_webpack_ast",
"crates/wasm",

View File

@ -27,7 +27,7 @@ concurrent = [
]
debug = ["swc_ecma_visit/debug"]
node = ["napi", "napi-derive"]
plugin = ["swc_plugin_runner"]
plugin = ["swc_plugin_runner", "swc_plugin_comments/plugin-rt"]
[dependencies]
ahash = "0.7.4"
@ -80,6 +80,7 @@ swc_ecmascript = { version = "0.140.0", path = "../swc_ecmascript" }
swc_error_reporters = { version = "0.1.0", path = "../swc_error_reporters" }
swc_node_comments = { version = "0.4.0", path = "../swc_node_comments" }
swc_plugin_runner = { version = "0.48.0", path = "../swc_plugin_runner", optional = true, default-features = false }
swc_plugin_comments = { version = "0.1.0", path = "../swc_plugin_comments", optional = true }
swc_visit = { version = "0.3.0", path = "../swc_visit" }
tracing = "0.1.32"

View File

@ -466,7 +466,13 @@ impl Options {
swc_plugin_runner::cache::init_plugin_module_cache_once(&experimental.cache_root);
}
crate::plugin::plugins(Some(plugin_resolver), experimental, plugin_context)
let comments = comments.cloned();
crate::plugin::plugins(
Some(plugin_resolver),
comments,
experimental,
plugin_context,
)
};
// Native runtime plugin target, based on assumption we have
@ -487,7 +493,8 @@ impl Options {
};
swc_plugin_runner::cache::init_plugin_module_cache_once();
crate::plugin::plugins(None, experimental, plugin_context)
let comments = comments.cloned();
crate::plugin::plugins(None, comments, experimental, plugin_context)
};
#[cfg(not(feature = "plugin"))]

View File

@ -44,12 +44,14 @@ pub struct PluginContext {
#[cfg(feature = "plugin")]
pub fn plugins(
resolver: Option<CachingResolver<NodeModulesResolver>>,
comments: Option<swc_common::comments::SingleThreadedComments>,
config: crate::config::JscExperimental,
plugin_context: PluginContext,
) -> impl Fold {
{
RustPlugins {
resolver,
comments,
plugins: config.plugins,
plugin_context,
}
@ -63,6 +65,7 @@ pub fn plugins() -> impl Fold {
struct RustPlugins {
resolver: Option<CachingResolver<NodeModulesResolver>>,
comments: Option<swc_common::comments::SingleThreadedComments>,
plugins: Option<Vec<PluginConfig>>,
plugin_context: PluginContext,
}
@ -77,65 +80,77 @@ impl RustPlugins {
use swc_common::{plugin::Serialized, FileName};
use swc_ecma_loader::resolve::Resolve;
let mut serialized = Serialized::serialize(&n)?;
// swc_plugin_macro will not inject proxy to the comments if comments is empty
let should_enable_comments_proxy = self.comments.is_some();
// Run plugin transformation against current program.
// We do not serialize / deserialize between each plugin execution but
// copies raw transformed bytes directly into plugin's memory space.
// Note: This doesn't mean plugin won't perform any se/deserialization: it
// still have to construct from raw bytes internally to perform actual
// transform.
if let Some(plugins) = &self.plugins {
for p in plugins {
let span = tracing::span!(
tracing::Level::INFO,
"serialize_context",
plugin_module = p.0.as_str()
);
let context_span_guard = span.enter();
// Set comments once per whole plugin transform execution.
swc_plugin_comments::COMMENTS.set(
&swc_plugin_comments::HostCommentsStorage {
inner: self.comments.clone(),
},
|| {
let mut serialized = Serialized::serialize(&n)?;
let config_json = serde_json::to_string(&p.1)
.context("Failed to serialize plugin config as json")
.and_then(|value| Serialized::serialize(&value))?;
// Run plugin transformation against current program.
// We do not serialize / deserialize between each plugin execution but
// copies raw transformed bytes directly into plugin's memory space.
// Note: This doesn't mean plugin won't perform any se/deserialization: it
// still have to construct from raw bytes internally to perform actual
// transform.
if let Some(plugins) = &self.plugins {
for p in plugins {
let span = tracing::span!(
tracing::Level::INFO,
"serialize_context",
plugin_module = p.0.as_str()
);
let context_span_guard = span.enter();
let context_json = serde_json::to_string(&self.plugin_context)
.context("Failed to serialize plugin context as json")
.and_then(|value| Serialized::serialize(&value))?;
let config_json = serde_json::to_string(&p.1)
.context("Failed to serialize plugin config as json")
.and_then(|value| Serialized::serialize(&value))?;
let resolved_path = self
.resolver
.as_ref()
.expect("filesystem_cache should provide resolver")
.resolve(&FileName::Real(PathBuf::from(&p.0)), &p.0)?;
let context_json = serde_json::to_string(&self.plugin_context)
.context("Failed to serialize plugin context as json")
.and_then(|value| Serialized::serialize(&value))?;
let path = if let FileName::Real(value) = resolved_path {
Arc::new(value)
} else {
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
};
drop(context_span_guard);
let resolved_path = self
.resolver
.as_ref()
.expect("filesystem_cache should provide resolver")
.resolve(&FileName::Real(PathBuf::from(&p.0)), &p.0)?;
let span = tracing::span!(
tracing::Level::INFO,
"execute_plugin_runner",
plugin_module = p.0.as_str()
);
let transform_span_guard = span.enter();
serialized = swc_plugin_runner::apply_transform_plugin(
&p.0,
&path,
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
serialized,
config_json,
context_json,
)?;
drop(transform_span_guard);
}
}
let path = if let FileName::Real(value) = resolved_path {
Arc::new(value)
} else {
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
};
drop(context_span_guard);
// Plugin transformation is done. Deserialize transformed bytes back
// into Program
Serialized::deserialize(&serialized)
let span = tracing::span!(
tracing::Level::INFO,
"execute_plugin_runner",
plugin_module = p.0.as_str()
);
let transform_span_guard = span.enter();
serialized = swc_plugin_runner::apply_transform_plugin(
&p.0,
&path,
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
serialized,
config_json,
context_json,
should_enable_comments_proxy,
)?;
drop(transform_span_guard);
}
}
// Plugin transformation is done. Deserialize transformed bytes back
// into Program
Serialized::deserialize(&serialized)
},
)
}
#[cfg(all(feature = "plugin", target_arch = "wasm32"))]
@ -146,30 +161,40 @@ impl RustPlugins {
use swc_common::{plugin::Serialized, FileName};
use swc_ecma_loader::resolve::Resolve;
let mut serialized = Serialized::serialize(&n)?;
let should_enable_comments_proxy = self.comments.is_some();
if let Some(plugins) = &self.plugins {
for p in plugins {
let config_json = serde_json::to_string(&p.1)
.context("Failed to serialize plugin config as json")
.and_then(|value| Serialized::serialize(&value))?;
swc_plugin_comments::COMMENTS.set(
&swc_plugin_comments::HostCommentsStorage {
inner: self.comments.clone(),
},
|| {
let mut serialized = Serialized::serialize(&n)?;
let context_json = serde_json::to_string(&self.plugin_context)
.context("Failed to serialize plugin context as json")
.and_then(|value| Serialized::serialize(&value))?;
if let Some(plugins) = &self.plugins {
for p in plugins {
let config_json = serde_json::to_string(&p.1)
.context("Failed to serialize plugin config as json")
.and_then(|value| Serialized::serialize(&value))?;
serialized = swc_plugin_runner::apply_transform_plugin(
&p.0,
&PathBuf::from(&p.0),
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
serialized,
config_json,
context_json,
)?;
}
}
let context_json = serde_json::to_string(&self.plugin_context)
.context("Failed to serialize plugin context as json")
.and_then(|value| Serialized::serialize(&value))?;
Serialized::deserialize(&serialized)
serialized = swc_plugin_runner::apply_transform_plugin(
&p.0,
&PathBuf::from(&p.0),
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
serialized,
config_json,
context_json,
should_enable_comments_proxy,
)?;
}
}
Serialized::deserialize(&serialized)
},
)
}
}

View File

@ -537,6 +537,10 @@ impl SingleThreadedComments {
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
pub struct Comment {
pub kind: CommentKind,
pub span: Span,
@ -550,6 +554,10 @@ impl Spanned for Comment {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
pub enum CommentKind {
Line,
Block,

View File

@ -27,7 +27,7 @@ pub enum PluginError {
/// plugin_macro, noramlly plugin author should not raise this manually.
SizeInteropFailure(String),
/// Occurs when failed to reconstruct a struct from `Serialized`.
Deserialize((String, Vec<u8>)),
Deserialize(String),
/// Occurs when failed to serialize a struct into `Serialized`.
/// Unlike deserialize error, this error cannot forward any context for the
/// raw bytes: when serialze failed, there's nothing we can pass between
@ -94,4 +94,27 @@ impl Serialized {
.deserialize(&mut rkyv::Infallible)
.with_context(|| format!("failed to deserialize `{}`", type_name::<W>()))
}
/// Convinient wrapper to Serialized::* to construct actual struct from raw
/// ptr. This is common workflow on both of runtime (host / plugin) to
/// deserialize struct from allocated / copied ptr.
///
/// # Safety
/// This is naturally unsafe by constructing bytes slice from raw ptr.
pub unsafe fn deserialize_from_ptr<W>(
raw_allocated_ptr: *const u8,
raw_allocated_ptr_len: i32,
) -> Result<W, Error>
where
W: rkyv::Archive,
W::Archived: rkyv::Deserialize<W, rkyv::Infallible>,
{
// Create serialized bytes slice from ptr
let raw_ptr_bytes = unsafe {
std::slice::from_raw_parts(raw_allocated_ptr, raw_allocated_ptr_len.try_into()?)
};
let serialized = Serialized::new_for_plugin(raw_ptr_bytes, raw_allocated_ptr_len);
Serialized::deserialize(&serialized)
}
}

View File

@ -91,9 +91,6 @@ extern "C" {
fn __mark_is_descendant_of_proxy(self_mark: u32, ancestor: u32, allocated_ptr: i32);
fn __mark_least_ancestor(a: u32, b: u32, allocated_ptr: i32);
fn __syntax_context_remove_mark_proxy(self_mark: u32, allocated_ptr: i32);
fn __alloc(size: usize) -> *mut u8;
fn __free(ptr: *mut u8, size: usize) -> i32;
}
impl Mark {
@ -176,8 +173,9 @@ impl Mark {
// In here, preallocate memory for the context.
let serialized = crate::plugin::Serialized::serialize(&MutableMarkContext(0, 0, 0))
.expect("Should be serializable");
let len = serialized.as_ref().len();
let ptr = unsafe { __alloc(len) };
let serialized_ref = serialized.as_ref();
let ptr = serialized_ref.as_ptr();
let len = serialized_ref.len();
// Calling host proxy fn. Inside of host proxy, host will
// write the result into allocated context in the guest memory space.
@ -186,18 +184,15 @@ impl Mark {
}
// Deserialize result, assign / return values as needed.
let raw_result_bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
let result =
crate::plugin::Serialized::new_for_plugin(raw_result_bytes, len.try_into().expect(""));
let context: MutableMarkContext =
crate::plugin::Serialized::deserialize(&result).expect("Should be deserializable");
let context: MutableMarkContext = unsafe {
crate::plugin::Serialized::deserialize_from_ptr(
ptr,
len.try_into().expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize")
};
self = Mark::from_u32(context.0);
unsafe {
__free(ptr, len);
}
return context.2 != 0;
}
@ -219,26 +214,24 @@ impl Mark {
pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark {
let serialized = crate::plugin::Serialized::serialize(&MutableMarkContext(0, 0, 0))
.expect("Should be serializable");
let len = serialized.as_ref().len();
let ptr = unsafe { __alloc(len) };
let serialized_ref = serialized.as_ref();
let ptr = serialized_ref.as_ptr();
let len = serialized_ref.len();
unsafe {
__mark_least_ancestor(a.0, b.0, ptr as _);
}
let raw_result_bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
let result =
crate::plugin::Serialized::new_for_plugin(raw_result_bytes, len.try_into().expect(""));
let context: MutableMarkContext =
crate::plugin::Serialized::deserialize(&result).expect("Should be deserializable");
let context: MutableMarkContext = unsafe {
crate::plugin::Serialized::deserialize_from_ptr(
ptr,
len.try_into().expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize")
};
a = Mark::from_u32(context.0);
b = Mark::from_u32(context.1);
unsafe {
__free(ptr, len);
}
return Mark(context.2);
}
@ -387,25 +380,24 @@ impl SyntaxContext {
let context = MutableMarkContext(0, 0, 0);
let serialized =
crate::plugin::Serialized::serialize(&context).expect("Should be serializable");
let len = serialized.as_ref().len();
let ptr = unsafe { __alloc(len) };
let serialized_ref = serialized.as_ref();
let ptr = serialized_ref.as_ptr();
let len = serialized_ref.len();
unsafe {
__syntax_context_remove_mark_proxy(self.0, ptr as _);
}
let raw_result_bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
let result =
crate::plugin::Serialized::new_for_plugin(raw_result_bytes, len.try_into().expect(""));
let context: MutableMarkContext =
crate::plugin::Serialized::deserialize(&result).expect("Should be deserializable");
let context: MutableMarkContext = unsafe {
crate::plugin::Serialized::deserialize_from_ptr(
ptr,
len.try_into().expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize")
};
*self = SyntaxContext(context.0);
unsafe {
__free(ptr, len);
}
return Mark::from_u32(context.2);
}

View File

@ -20,6 +20,9 @@ swc_atoms = { version = "0.2.0", path = "../swc_atoms" }
swc_common = { version = "0.17.0", path = "../swc_common", features = [
"plugin-mode",
] }
swc_plugin_comments = { version = "0.1.0", path = "../swc_plugin_comments", features = [
"plugin-mode",
] }
swc_ecma_ast = { version = "0.73.0", path = "../swc_ecma_ast", features = [
"rkyv-impl",
] }

View File

@ -1,31 +0,0 @@
use swc_common::plugin::Serialized;
#[cfg(target_arch = "wasm32")] // Allow testing
extern "C" {
fn __emit_diagnostics(bytes_ptr: i32, bytes_ptr_len: i32);
fn __free(bytes_ptr: i32, size: i32) -> i32;
}
/// An emitter for the Diagnostic in plugin's context by borrowing host's
/// environment context.
///
/// It is not expected to call this directly inside of plugin transform.
/// Instead, it is encouraged to use global HANDLER.
pub struct PluginDiagnosticsEmitter {}
impl swc_common::errors::Emitter for PluginDiagnosticsEmitter {
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
fn emit(&mut self, db: &swc_common::errors::DiagnosticBuilder<'_>) {
let diag =
Serialized::serialize(&*db.diagnostic).expect("Should able to serialize Diagnostic");
let diag_ref = diag.as_ref();
let ptr = diag_ref.as_ptr() as i32;
let len = diag_ref.len() as i32;
#[cfg(target_arch = "wasm32")] // Allow testing
unsafe {
__emit_diagnostics(ptr, len);
}
}
}

View File

@ -1,34 +1,37 @@
use swc_common::sync::OnceCell;
use swc_common::{plugin::Serialized, sync::OnceCell};
/// Simple substitution for scoped_thread_local with limited interface parity.
/// The only available fn in this struct is `with`, which is being used for the
/// consumers when they need to access global scope handler (HANDLER.with()).
/// Any other interfaces to support thread local is not available.
pub struct PseudoScopedKey {
// As we can't use scoped_thread_local for the global HANDLER, it is challenging
// to set its inner handler for each plugin scope's diagnostic emitter.
// Via lazy init OnceCell we keep static HANDLER as immutable, also allows to set
// plugin specific values when proc_macro expands plugin's transform helper.
pub inner: OnceCell<swc_common::errors::Handler>,
use crate::pseudo_scoped_key::PseudoScopedKey;
#[cfg(target_arch = "wasm32")] // Allow testing
extern "C" {
fn __emit_diagnostics(bytes_ptr: i32, bytes_ptr_len: i32);
fn __free(bytes_ptr: i32, size: i32) -> i32;
}
impl PseudoScopedKey {
pub fn with<F, R>(&self, f: F) -> R
where
F: FnOnce(&swc_common::errors::Handler) -> R,
{
f(self.inner.get().expect("Should set handler before call"))
/// An emitter for the Diagnostic in plugin's context by borrowing host's
/// environment context.
///
/// It is not expected to call this directly inside of plugin transform.
/// Instead, it is encouraged to use global HANDLER.
pub struct PluginDiagnosticsEmitter;
impl swc_common::errors::Emitter for PluginDiagnosticsEmitter {
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
fn emit(&mut self, db: &swc_common::errors::DiagnosticBuilder<'_>) {
let diag =
Serialized::serialize(&*db.diagnostic).expect("Should able to serialize Diagnostic");
let diag_ref = diag.as_ref();
let ptr = diag_ref.as_ptr() as i32;
let len = diag_ref.len() as i32;
#[cfg(target_arch = "wasm32")] // Allow testing
unsafe {
__emit_diagnostics(ptr, len);
}
}
}
// This is to conform some of swc_common::errors::Handler's thread-safety
// required properties.
//
// NOTE: This only works cause we know each plugin transform doesn't need any
// thread safety. However, if wasm gets thread support and if we're going to
// support it this should be revisited.
unsafe impl std::marker::Sync for PseudoScopedKey {}
/// global context HANDLER in plugin's transform function.
pub static HANDLER: PseudoScopedKey = PseudoScopedKey {
inner: OnceCell::new(),

View File

@ -6,6 +6,11 @@ pub use swc_common::{
plugin::{PluginError, Serialized},
};
pub mod comments {
pub use swc_common::comments::Comments;
pub use swc_plugin_comments::PluginCommentsProxy;
}
pub mod util {
pub use swc_common::util::take;
#[cfg(feature = "swc_ecma_quote")]
@ -30,10 +35,10 @@ pub mod errors {
pub use crate::handler::HANDLER;
}
mod context;
pub mod environment {
pub use crate::context::*;
pub use crate::handler::*;
}
use swc_plugin_comments::PluginCommentsProxy;
// We don't set target cfg as it'll block macro expansions
// in ide (i.e rust-analyzer) or non-wasm target `cargo check`
pub use swc_plugin_macro::plugin_transform;
@ -43,3 +48,24 @@ mod allocation;
pub mod memory {
pub use crate::allocation::*;
}
mod pseudo_scoped_key;
/// An arbitary metadata for given Program to run transform in plugin.
/// These are information not directly attached to Program's AST structures
/// but required for certain transforms.
#[derive(Debug)]
pub struct TransformPluginProgramMetadata {
/// Proxy to the comments for the Program passed into plugin.
/// This is a proxy to the actual data lives in the host. Only when plugin
/// attempts to read these it'll ask to the host to get values.
pub comments: Option<PluginCommentsProxy>,
/// Stringified JSON value for given plugin's configuration.
/// This is readonly. Changing value in plugin doesn't affect host's
/// behavior.
pub plugin_config: String,
/// Stringified JSON value for relative context while running transform,
/// like filenames.
/// /// This is readonly. Changing value in plugin doesn't affect host's
/// behavior.
pub transform_context: String,
}

View File

@ -0,0 +1,28 @@
/// Simple substitution for scoped_thread_local with limited interface parity.
/// The only available fn in this struct is `with`, which is being used for the
/// consumers when they need to access global scope handler (HANDLER.with()).
/// Any other interfaces to support thread local is not available.
pub struct PseudoScopedKey {
// As we can't use scoped_thread_local for the global HANDLER, it is challenging
// to set its inner handler for each plugin scope's diagnostic emitter.
// Via lazy init OnceCell we keep static HANDLER as immutable, also allows to set
// plugin specific values when proc_macro expands plugin's transform helper.
pub inner: swc_common::sync::OnceCell<swc_common::errors::Handler>,
}
impl PseudoScopedKey {
pub fn with<F, R>(&self, f: F) -> R
where
F: FnOnce(&swc_common::errors::Handler) -> R,
{
f(self.inner.get().expect("Should set handler before call"))
}
}
// This is to conform some of swc_common::errors::Handler's thread-safety
// required properties.
//
// NOTE: This only works cause we know each plugin transform doesn't need any
// thread safety. However, if wasm gets thread support and if we're going to
// support it this should be revisited.
unsafe impl std::marker::Sync for PseudoScopedKey {}

View File

@ -0,0 +1,22 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>", "OJ Kwon <kwon.ohjoong@gmail.com>"]
description = "Internal sharable storage for the comments between host to the plugin"
name = "swc_plugin_comments"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/swc-project/swc.git"
[features]
# swc/core, which runs plugin
plugin-rt = []
# actual wasm plugin binary
plugin-mode = []
[dependencies]
better_scoped_tls = { version = "0.1.0", path = "../better_scoped_tls" }
rkyv = "0.7.36"
swc_common = { version = "0.17.0", path = "../swc_common", features = [
"plugin-base",
] }

View File

@ -0,0 +1,21 @@
/// A struct to internally store current file's comments for the
/// transform plugins.
///
/// This storage is introduced to conform with existing design to the comments,
/// specifically `SingleThreadedComments`. It doesn't support thread-safety
/// which does not allow to be passed into wasmerEnv (HostEnvironment). A scoped
/// tls holds inner comments as global, per each transform execution. Refer
/// `swc::RustPlugins::apply_transform_plugin` for the responsibility to manage
/// actual data.
///
/// Should never attempt to use this other than plugin_runner.
// TODO: This storage does not support mutable yet
#[cfg(feature = "plugin-rt")]
pub struct HostCommentsStorage {
pub inner: Option<swc_common::comments::SingleThreadedComments>,
}
#[cfg(feature = "plugin-rt")]
better_scoped_tls::scoped_tls!(
pub static COMMENTS: HostCommentsStorage
);

View File

@ -0,0 +1,8 @@
mod host_comments_storage;
#[cfg(feature = "plugin-rt")]
pub use host_comments_storage::{HostCommentsStorage, COMMENTS};
mod plugin_comments_proxy;
pub use plugin_comments_proxy::CommentsVecPtr;
#[cfg(feature = "plugin-mode")]
pub use plugin_comments_proxy::PluginCommentsProxy;

View File

@ -0,0 +1,134 @@
#[cfg(feature = "plugin-mode")]
use swc_common::plugin::Serialized;
#[cfg(feature = "plugin-mode")]
use swc_common::{
comments::{Comment, Comments},
BytePos,
};
#[cfg(target = "wasm32")]
extern "C" {
fn __get_leading_comments_proxy(byte_pos: u32, allocated_ret_ptr: i32) -> i32;
}
/// A struct to exchance allocated Vec<Comment> between memory spaces.
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct CommentsVecPtr(pub i32, pub i32);
/// A struct implements `swc_common::comments::Comments` for the plugin.
/// This is a proxy to the host's comments reference while plugin transform
/// runs, does not contain actual data but lazily requests to the host for each
/// interfaces.
///
/// This _does not_ derives serialization / deserialization for the
/// Serialized::de/serialize interface. Instead, swc_plugin_macro injects an
/// instance in plugin's runtime directly.
#[cfg(feature = "plugin-mode")]
#[derive(Debug)]
pub struct PluginCommentsProxy;
#[cfg(feature = "plugin-mode")]
impl Comments for PluginCommentsProxy {
fn add_leading(&self, pos: BytePos, cmt: Comment) {
unimplemented!("not implemented yet");
}
fn add_leading_comments(&self, pos: BytePos, comments: Vec<Comment>) {
unimplemented!("not implemented yet");
}
fn has_leading(&self, pos: BytePos) -> bool {
unimplemented!("not implemented yet");
}
fn move_leading(&self, from: BytePos, to: BytePos) {
unimplemented!("not implemented yet");
}
fn take_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
unimplemented!("not implemented yet");
}
fn get_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
// Allocate CommentsVecPtr to get return value from the host
let comments_vec_ptr = CommentsVecPtr(0, 0);
let serialized_comments_vec_ptr = Serialized::serialize(&comments_vec_ptr)
.expect("Should able to serialize CommentsVecPtr");
let serialized_comments_vec_ptr_ref = serialized_comments_vec_ptr.as_ref();
let serialized_comments_vec_ptr_raw_ptr = serialized_comments_vec_ptr_ref.as_ptr();
let serialized_comments_vec_ptr_raw_len = serialized_comments_vec_ptr_ref.len();
#[cfg(target = "wasm32")]
{
let ret = unsafe {
__get_leading_comments_proxy(pos.0, serialized_comments_vec_ptr_raw_ptr as _)
};
if ret == 0 {
return None;
}
}
// First, reconstruct CommentsVecPtr to reveal ptr to the allocated
// Vec<Comments>
let comments_vec_ptr: CommentsVecPtr = unsafe {
Serialized::deserialize_from_ptr(
serialized_comments_vec_ptr_raw_ptr,
serialized_comments_vec_ptr_raw_len
.try_into()
.expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize CommentsVecPtr")
};
// Using CommentsVecPtr's value, reconstruct actual Vec<Comments>
Some(unsafe {
Serialized::deserialize_from_ptr(comments_vec_ptr.0 as _, comments_vec_ptr.1)
.expect("Returned comments should be serializable")
})
}
fn add_trailing(&self, pos: BytePos, cmt: Comment) {
unimplemented!("not implemented yet");
}
fn add_trailing_comments(&self, pos: BytePos, comments: Vec<Comment>) {
unimplemented!("not implemented yet");
}
fn has_trailing(&self, pos: BytePos) -> bool {
unimplemented!("not implemented yet");
}
fn move_trailing(&self, from: BytePos, to: BytePos) {
unimplemented!("not implemented yet");
}
fn take_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
unimplemented!("not implemented yet");
}
fn get_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
unimplemented!("not implemented yet");
}
fn add_pure_comment(&self, pos: BytePos) {
unimplemented!("not implemented yet");
}
fn with_leading<F, Ret>(&self, pos: BytePos, f: F) -> Ret
where
Self: Sized,
F: FnOnce(&[Comment]) -> Ret,
{
unimplemented!("not implemented yet");
}
fn with_trailing<F, Ret>(&self, pos: BytePos, f: F) -> Ret
where
Self: Sized,
F: FnOnce(&[Comment]) -> Ret,
{
unimplemented!("not implemented yet");
}
}

View File

@ -58,68 +58,28 @@ fn handle_func(func: ItemFn) -> TokenStream {
// There are some cases error won't be wrapped up however - for example, we expect
// serialization of PluginError itself should succeed.
#[no_mangle]
pub fn #process_impl_ident(ast_ptr: *const u8, ast_ptr_len: i32, config_str_ptr: *const u8, config_str_ptr_len: i32, context_str_ptr: *const u8, context_str_ptr_len: i32) -> i32 {
let ast_ptr_len_usize: Result<usize, std::num::TryFromIntError> = std::convert::TryInto::try_into(ast_ptr_len);
let config_str_ptr_len_usize: Result<usize, std::num::TryFromIntError> = std::convert::TryInto::try_into(config_str_ptr_len);
let context_str_ptr_len_usize: Result<usize, std::num::TryFromIntError> = std::convert::TryInto::try_into(context_str_ptr_len);
if ast_ptr_len_usize.is_err() {
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of AST pointer".to_string());
return construct_error_ptr(err);
}
if config_str_ptr_len_usize.is_err() {
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of plugin config string pointer".to_string());
return construct_error_ptr(err);
}
if context_str_ptr_len_usize.is_err() {
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of context string pointer".to_string());
return construct_error_ptr(err);
}
// Read raw serialized bytes from wasm's memory space. Host (SWC) should
// allocate memory, copy bytes and pass ptr to plugin.
let raw_ast_serialized_bytes =
unsafe { std::slice::from_raw_parts(ast_ptr, ast_ptr_len_usize.unwrap()) };
let raw_config_serialized_bytes =
unsafe { std::slice::from_raw_parts(config_str_ptr, config_str_ptr_len_usize.unwrap()) };
let raw_context_serialized_bytes =
unsafe { std::slice::from_raw_parts(context_str_ptr, context_str_ptr_len_usize.unwrap()) };
// Reconstruct SerializedProgram from raw bytes
let serialized_program = swc_plugin::Serialized::new_for_plugin(raw_ast_serialized_bytes, ast_ptr_len);
let serialized_config = swc_plugin::Serialized::new_for_plugin(raw_config_serialized_bytes, config_str_ptr_len);
let serialized_context = swc_plugin::Serialized::new_for_plugin(raw_context_serialized_bytes, context_str_ptr_len);
pub fn #process_impl_ident(ast_ptr: *const u8, ast_ptr_len: i32, config_str_ptr: *const u8, config_str_ptr_len: i32, context_str_ptr: *const u8, context_str_ptr_len: i32, should_enable_comments_proxy: i32) -> i32 {
// Reconstruct `Program` & config string from serialized program
let program = swc_plugin::Serialized::deserialize(&serialized_program);
let config = swc_plugin::Serialized::deserialize(&serialized_config);
let context = swc_plugin::Serialized::deserialize(&serialized_context);
// Host (SWC) should allocate memory, copy bytes and pass ptr to plugin.
let program = unsafe { swc_plugin::Serialized::deserialize_from_ptr(ast_ptr, ast_ptr_len) };
if program.is_err() {
let err = swc_plugin::PluginError::Deserialize(
("Failed to deserialize program received from host".to_string(),
raw_ast_serialized_bytes.to_vec())
);
let err = swc_plugin::PluginError::Deserialize("Failed to deserialize program received from host".to_string());
return construct_error_ptr(err);
}
let program: Program = program.expect("Should be a program");
let config = unsafe { swc_plugin::Serialized::deserialize_from_ptr(config_str_ptr, config_str_ptr_len) };
if config.is_err() {
let err = swc_plugin::PluginError::Deserialize(
("Failed to deserialize config string received from host".to_string(),
raw_config_serialized_bytes.to_vec())
"Failed to deserialize config string received from host".to_string()
);
return construct_error_ptr(err);
}
let config: String = config.expect("Should be a string");
let context = unsafe { swc_plugin::Serialized::deserialize_from_ptr(context_str_ptr, context_str_ptr_len) };
if context.is_err() {
let err = swc_plugin::PluginError::Deserialize(
("Failed to deserialize context string received from host".to_string(),
raw_context_serialized_bytes.to_vec())
);
let err = swc_plugin::PluginError::Deserialize("Failed to deserialize context string received from host".to_string());
return construct_error_ptr(err);
}
let context: String = context.expect("Should be a string");
@ -128,7 +88,7 @@ fn handle_func(func: ItemFn) -> TokenStream {
let handler = swc_plugin::errors::Handler::with_emitter(
true,
false,
Box::new(swc_plugin::environment::PluginDiagnosticsEmitter {})
Box::new(swc_plugin::environment::PluginDiagnosticsEmitter)
);
let handler_set_result = swc_plugin::errors::HANDLER.inner.set(handler);
@ -139,8 +99,16 @@ fn handle_func(func: ItemFn) -> TokenStream {
return construct_error_ptr(err);
}
// Construct metadata to the `Program` for the transform plugin.
let plugin_comments_proxy = if should_enable_comments_proxy == 1 { Some(swc_plugin::comments::PluginCommentsProxy) } else { None };
let mut metadata = swc_plugin::TransformPluginProgramMetadata {
comments: plugin_comments_proxy,
plugin_config: config,
transform_context: context
};
// Take original plugin fn ident, then call it with interop'ed args
let transformed_program = #ident(program, config, context);
let transformed_program = #ident(program, metadata);
// Serialize transformed result, return back to the host.
let serialized_result = swc_plugin::Serialized::serialize(&transformed_program);

View File

@ -27,6 +27,9 @@ swc_common = { version = "0.17.0", path = "../swc_common", features = [
"plugin-rt",
"concurrent",
] }
swc_plugin_comments = { version = "0.1.0", path = "../swc_plugin_comments", features = [
"plugin-rt",
] }
swc_ecma_ast = { version = "0.73.0", path = "../swc_ecma_ast", features = [
"rkyv-impl",
] }

View File

@ -1,15 +0,0 @@
use std::sync::Arc;
use parking_lot::Mutex;
use wasmer::Memory;
#[derive(wasmer::WasmerEnv, Clone)]
/// An external enviornment state imported (declared in host, injected into
/// guest) fn can access. This'll allow host access updated state via plugin's
/// transform.
/// ref: https://docs.wasmer.io/integrations/examples/host-functions#declaring-the-data
pub struct HostEnvironment {
#[wasmer(export)]
pub memory: wasmer::LazyInit<Memory>,
pub transform_result: Arc<Mutex<Vec<u8>>>,
}

View File

@ -0,0 +1,29 @@
use std::sync::Arc;
use parking_lot::Mutex;
use wasmer::{LazyInit, Memory, NativeFunc};
#[derive(wasmer::WasmerEnv, Clone)]
/// An external enviornment state imported (declared in host, injected into
/// guest) fn can access. This'll allow host access updated state via plugin's
/// transform.
/// ref: https://docs.wasmer.io/integrations/examples/host-functions#declaring-the-data
pub struct HostEnvironment {
#[wasmer(export)]
pub memory: wasmer::LazyInit<Memory>,
pub transform_result: Arc<Mutex<Vec<u8>>>,
/// Attached imported fn `__alloc` to the hostenvironment to allow any other
/// imported fn can allocate guest's memory space from host runtime.
#[wasmer(export(name = "__alloc"))]
pub alloc_guest_memory: LazyInit<NativeFunc<u32, i32>>,
}
impl HostEnvironment {
pub fn new(transform_result: &Arc<Mutex<Vec<u8>>>) -> HostEnvironment {
HostEnvironment {
memory: LazyInit::default(),
transform_result: transform_result.clone(),
alloc_guest_memory: LazyInit::default(),
}
}
}

View File

@ -0,0 +1,72 @@
use swc_common::{comments::Comments, plugin::Serialized, BytePos};
use swc_plugin_comments::{CommentsVecPtr, HostCommentsStorage, COMMENTS};
use crate::{host_environment::HostEnvironment, memory_interop::write_into_memory_view};
/// Ask to get leading_comments from currently scoped comments held by
/// HostCommentsStorage.
///
/// Returns 1 if operation success with Some(Vec<Comments>), 0 otherwise.
/// Allocated results should be read through CommentsPtr.
pub fn get_leading_comments_proxy(
env: &HostEnvironment,
byte_pos: u32,
allocated_ret_ptr: i32,
) -> i32 {
if let Some(memory) = env.memory_ref() {
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
if !COMMENTS.is_set() {
return 0;
}
return COMMENTS.with(|storage: &HostCommentsStorage| {
if let Some(comments) = &storage.inner {
let leading_comments = comments.get_leading(BytePos(byte_pos));
if let Some(leading_comments) = leading_comments {
let serialized_leading_comments_vec_bytes =
Serialized::serialize(&leading_comments)
.expect("Should be serializable");
let serialized_bytes_len =
serialized_leading_comments_vec_bytes.as_ref().len();
let (allocated_ptr, allocated_ptr_len) = write_into_memory_view(
memory,
&serialized_leading_comments_vec_bytes,
|_| {
// In most cases our host-plugin tranmpoline works in a way that
// plugin pre-allocates
// memory before calling host imported fn. But in case of
// comments return value is Vec<Comments> which
// guest cannot predetermine size to allocate, intead
// let host allocate by calling guest's alloc via attached
// hostenvironment.
alloc_guest_memory
.call(
serialized_bytes_len
.try_into()
.expect("Should be able to convert size"),
)
.expect("Should able to allocate memory in the plugin")
},
);
// Retuning (allocated_ptr, len) into caller (plugin)
let comment_ptr_serialized = Serialized::serialize(&CommentsVecPtr(
allocated_ptr,
allocated_ptr_len,
))
.expect("Should be serializable");
write_into_memory_view(memory, &comment_ptr_serialized, |_| {
allocated_ret_ptr
});
return 1;
}
}
0
});
}
}
0
}

View File

@ -0,0 +1,23 @@
use swc_common::{
errors::{Diagnostic, HANDLER},
plugin::Serialized,
};
use crate::{host_environment::HostEnvironment, memory_interop::copy_bytes_into_host};
pub fn emit_diagnostics(env: &HostEnvironment, bytes_ptr: i32, bytes_ptr_len: i32) {
if let Some(memory) = env.memory_ref() {
if HANDLER.is_set() {
HANDLER.with(|handler| {
let diagnostics_bytes = copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
let serialized = Serialized::new_for_plugin(&diagnostics_bytes[..], bytes_ptr_len);
let diagnostic = Serialized::deserialize::<Diagnostic>(&serialized)
.expect("Should able to be deserialized into diagnsotic");
let mut builder =
swc_common::errors::DiagnosticBuilder::new_diagnostic(handler, diagnostic);
builder.emit();
})
}
}
}

View File

@ -1,46 +1,6 @@
//! Functions imported into the guests (plugin) runtime allows interop between
//! host's state to plugin.
//! All of these fn is being called inside of guest's memory space, which calls
//! appropriate host fn as needed.
use swc_common::{hygiene::MutableMarkContext, plugin::Serialized, Mark, SyntaxContext};
use swc_common::{
errors::{Diagnostic, HANDLER},
hygiene::MutableMarkContext,
plugin::Serialized,
Mark, SyntaxContext,
};
use crate::{
context::HostEnvironment,
memory_interop::{copy_bytes_into_host, write_into_memory_view},
};
/// Set plugin's transformed result into host's enviroment.
/// This is an `imported` fn - when we instantiate plugin module, we inject this
/// fn into pluging's export space. Once transform completes, plugin will call
/// this to set its result back to host.
pub fn set_transform_result(env: &HostEnvironment, bytes_ptr: i32, bytes_ptr_len: i32) {
if let Some(memory) = env.memory_ref() {
(*env.transform_result.lock()) = copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
}
}
pub fn emit_diagnostics(env: &HostEnvironment, bytes_ptr: i32, bytes_ptr_len: i32) {
if let Some(memory) = env.memory_ref() {
if HANDLER.is_set() {
HANDLER.with(|handler| {
let diagnostics_bytes = copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
let serialized = Serialized::new_for_plugin(&diagnostics_bytes[..], bytes_ptr_len);
let diagnostic = Serialized::deserialize::<Diagnostic>(&serialized)
.expect("Should able to be deserialized into diagnsotic");
let mut builder =
swc_common::errors::DiagnosticBuilder::new_diagnostic(handler, diagnostic);
builder.emit();
})
}
}
}
use crate::{host_environment::HostEnvironment, memory_interop::write_into_memory_view};
/// A proxy to Mark::fresh() that can be used in plugin.
/// This it not direcly called by plugin, instead `impl Mark` will selectively

View File

@ -0,0 +1,136 @@
//! Functions for syntax_pos::hygiene imported into the guests (plugin) runtime
//! allows interop between host's state to plugin. When guest calls these fn,
//! it'll be executed in host's memory space.
/*
* Below diagram shows one reference example how guest does trampoline between
* host's memory space.
*
*Host (SWC/core) Plugin (wasm)
*
* COMMENTS.with()
* PluginCommentsProxy
*
*
* get_leading_comments_proxy()get_leading()
*
*
* CommentsVecPtr(ptr, len)
*
*
*
*
* Vec<Comments>
*
*
*
*
*
* 1. Plugin calls `PluginCommentsProxy::get_leading()`. PluginCommentsProxy is
* a struct constructed in plugin's memory space.
* 2. `get_leading()` internally calls `__get_leading_comments_proxy`, which is
* imported fn `get_leading_comments_proxy` exists in the host.
* 3. Host access necessary values in its memory space (COMMENTS)
* 4. Host copies value to be returned into plguin's memory space. Memory
* allocation for the value should be manually performed.
* 5. Host completes imported fn, `PluginCommentsProxy::get_leading()` now can
* read, deserialize memory host wrote.
* - In case of `get_leading`, returned value is non-deterministic vec
* (`Vec<Comments>`) guest cannot preallocate with specific length. Instead,
* guest passes a fixed size struct (CommentsVecPtr), once host allocates
* actual vec into guest it'll write pointer to the vec into the struct.
*/
use std::sync::Arc;
use parking_lot::Mutex;
use wasmer::{imports, Function, ImportObject, Module};
use crate::{host_environment::HostEnvironment, imported_fn::comments::get_leading_comments_proxy};
mod comments;
mod handler;
mod hygiene;
mod set_transform_result;
use handler::*;
use hygiene::*;
use set_transform_result::*;
/// Create an ImportObject includes functions to be imported from host to the
/// plugins.
pub(crate) fn build_import_object(
module: &Module,
transform_result: &Arc<Mutex<Vec<u8>>>,
) -> ImportObject {
let wasmer_store = module.store();
// transfrom_result
let set_transform_result_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment::new(transform_result),
set_transform_result,
);
// handler
let emit_diagnostics_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment::new(transform_result),
emit_diagnostics,
);
// hygiene
let mark_fresh_fn_decl = Function::new_native(wasmer_store, mark_fresh_proxy);
let mark_parent_fn_decl = Function::new_native(wasmer_store, mark_parent_proxy);
let mark_is_builtin_fn_decl = Function::new_native(wasmer_store, mark_is_builtin_proxy);
let mark_set_builtin_fn_decl = Function::new_native(wasmer_store, mark_set_builtin_proxy);
let mark_is_descendant_of_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment::new(transform_result),
mark_is_descendant_of_proxy,
);
let mark_least_ancestor_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment::new(transform_result),
mark_least_ancestor_proxy,
);
let syntax_context_apply_mark_fn_decl =
Function::new_native(wasmer_store, syntax_context_apply_mark_proxy);
let syntax_context_remove_mark_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment::new(transform_result),
syntax_context_remove_mark_proxy,
);
let syntax_context_outer_fn_decl =
Function::new_native(wasmer_store, syntax_context_outer_proxy);
// comments
let get_leading_comments_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment::new(transform_result),
get_leading_comments_proxy,
);
imports! {
"env" => {
// transform
"__set_transform_result" => set_transform_result_fn_decl,
// handler
"__emit_diagnostics" => emit_diagnostics_fn_decl,
// hygiene
"__mark_fresh_proxy" => mark_fresh_fn_decl,
"__mark_parent_proxy" => mark_parent_fn_decl,
"__mark_is_builtin_proxy" => mark_is_builtin_fn_decl,
"__mark_set_builtin_proxy" => mark_set_builtin_fn_decl,
"__mark_is_descendant_of_proxy" => mark_is_descendant_of_fn_decl,
"__mark_least_ancestor" => mark_least_ancestor_fn_decl,
"__syntax_context_apply_mark_proxy" => syntax_context_apply_mark_fn_decl,
"__syntax_context_remove_mark_proxy" => syntax_context_remove_mark_fn_decl,
"__syntax_context_outer_proxy" => syntax_context_outer_fn_decl,
// comments
"__get_leading_comments_proxy" => get_leading_comments_fn_decl,
}
}
}

View File

@ -0,0 +1,11 @@
use crate::{host_environment::HostEnvironment, memory_interop::copy_bytes_into_host};
/// Set plugin's transformed result into host's enviroment.
/// This is an `imported` fn - when we instantiate plugin module, we inject this
/// fn into pluging's export space. Once transform completes, plugin will call
/// this to set its result back to host.
pub fn set_transform_result(env: &HostEnvironment, bytes_ptr: i32, bytes_ptr_len: i32) {
if let Some(memory) = env.memory_ref() {
(*env.transform_result.lock()) = copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
}
}

View File

@ -6,7 +6,7 @@ use swc_common::plugin::Serialized;
use transform_executor::TransformExecutor;
pub mod cache;
mod context;
mod host_environment;
mod imported_fn;
mod load_plugin;
mod memory_interop;
@ -20,11 +20,17 @@ pub fn apply_transform_plugin(
program: Serialized,
config_json: Serialized,
context_json: Serialized,
should_enable_comments_proxy: bool,
) -> Result<Serialized, Error> {
(|| -> Result<_, Error> {
let mut transform_tracker = TransformExecutor::new(path, cache)?;
transform_tracker.transform(&program, &config_json, &context_json)
let should_enable_comments_proxy = if should_enable_comments_proxy { 1 } else { 0 };
transform_tracker.transform(
&program,
&config_json,
&context_json,
should_enable_comments_proxy,
)
})()
.with_context(|| {
format!(

View File

@ -2,18 +2,10 @@ use std::sync::Arc;
use anyhow::{Context, Error};
use parking_lot::Mutex;
use wasmer::{imports, ChainableNamedResolver, Function, Instance, LazyInit};
use wasmer::{ChainableNamedResolver, Instance};
use wasmer_wasi::{is_wasi_module, WasiState};
use crate::{
context::HostEnvironment,
imported_fn::{
emit_diagnostics, mark_fresh_proxy, mark_is_builtin_proxy, mark_is_descendant_of_proxy,
mark_least_ancestor_proxy, mark_parent_proxy, mark_set_builtin_proxy, set_transform_result,
syntax_context_apply_mark_proxy, syntax_context_outer_proxy,
syntax_context_remove_mark_proxy,
},
};
use crate::imported_fn::build_import_object;
#[tracing::instrument(level = "info", skip_all)]
pub fn load_plugin(
@ -24,77 +16,8 @@ pub fn load_plugin(
return match module {
Ok(module) => {
let wasmer_store = module.store();
let transform_result: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(vec![]));
let set_transform_result_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment {
memory: LazyInit::default(),
transform_result: transform_result.clone(),
},
set_transform_result,
);
let emit_diagnostics_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment {
memory: LazyInit::default(),
transform_result: transform_result.clone(),
},
emit_diagnostics,
);
let mark_fresh_fn_decl = Function::new_native(wasmer_store, mark_fresh_proxy);
let mark_parent_fn_decl = Function::new_native(wasmer_store, mark_parent_proxy);
let mark_is_builtin_fn_decl = Function::new_native(wasmer_store, mark_is_builtin_proxy);
let mark_set_builtin_fn_decl =
Function::new_native(wasmer_store, mark_set_builtin_proxy);
let mark_is_descendant_of_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment {
memory: LazyInit::default(),
transform_result: transform_result.clone(),
},
mark_is_descendant_of_proxy,
);
let mark_least_ancestor_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment {
memory: LazyInit::default(),
transform_result: transform_result.clone(),
},
mark_least_ancestor_proxy,
);
let syntax_context_apply_mark_fn_decl =
Function::new_native(wasmer_store, syntax_context_apply_mark_proxy);
let syntax_context_remove_mark_fn_decl = Function::new_native_with_env(
wasmer_store,
HostEnvironment {
memory: LazyInit::default(),
transform_result: transform_result.clone(),
},
syntax_context_remove_mark_proxy,
);
let syntax_context_outer_fn_decl =
Function::new_native(wasmer_store, syntax_context_outer_proxy);
let import_object = imports! {
"env" => {
"__set_transform_result" => set_transform_result_fn_decl,
"__emit_diagnostics" => emit_diagnostics_fn_decl,
"__mark_fresh_proxy" => mark_fresh_fn_decl,
"__mark_parent_proxy" => mark_parent_fn_decl,
"__mark_is_builtin_proxy" => mark_is_builtin_fn_decl,
"__mark_set_builtin_proxy" => mark_set_builtin_fn_decl,
"__mark_is_descendant_of_proxy" => mark_is_descendant_of_fn_decl,
"__mark_least_ancestor" => mark_least_ancestor_fn_decl,
"__syntax_context_apply_mark_proxy" => syntax_context_apply_mark_fn_decl,
"__syntax_context_remove_mark_proxy" => syntax_context_remove_mark_fn_decl,
"__syntax_context_outer_proxy" => syntax_context_outer_fn_decl
}
};
let import_object = build_import_object(&module, &transform_result);
// Plugin binary can be either wasm32-wasi or wasm32-unknown-unknown.
// Wasi specific env need to be initialized if given module targets wasm32-wasi.

View File

@ -10,7 +10,7 @@ use crate::memory_interop::write_into_memory_view;
/// A struct encapsule executing a plugin's transform interop to its teardown
pub struct TransformExecutor {
// Main transform interface plugin exports
exported_plugin_transform: wasmer::NativeFunc<(i32, i32, i32, i32, i32, i32), i32>,
exported_plugin_transform: wasmer::NativeFunc<(i32, i32, i32, i32, i32, i32, i32), i32>,
// `__free` function automatically exported via swc_plugin sdk to allow deallocation in guest
// memory space
exported_plugin_free: wasmer::NativeFunc<(i32, i32), i32>,
@ -34,7 +34,7 @@ impl TransformExecutor {
let tracker = TransformExecutor {
exported_plugin_transform: instance
.exports
.get_native_function::<(i32, i32, i32, i32, i32, i32), i32>(
.get_native_function::<(i32, i32, i32, i32, i32, i32, i32), i32>(
"__plugin_process_impl",
)?,
exported_plugin_free: instance
@ -85,7 +85,7 @@ impl TransformExecutor {
"Failed to convert pointer size to calculate: {}",
msg
)),
PluginError::Deserialize((msg, ..)) | PluginError::Serialize(msg) => {
PluginError::Deserialize(msg) | PluginError::Serialize(msg) => {
Err(anyhow!("{}", msg))
}
_ => Err(anyhow!(
@ -101,6 +101,7 @@ impl TransformExecutor {
program: &Serialized,
config: &Serialized,
context: &Serialized,
should_enable_comments_proxy: i32,
) -> Result<Serialized, Error> {
let guest_program_ptr = self.write_bytes_into_guest(program)?;
let config_str_ptr = self.write_bytes_into_guest(config)?;
@ -113,6 +114,7 @@ impl TransformExecutor {
config_str_ptr.1,
context_str_ptr.0,
context_str_ptr.1,
should_enable_comments_proxy,
)?;
self.read_bytes_from_guest(result)

View File

@ -94,6 +94,7 @@ fn internal() -> Result<(), Error> {
program,
config,
context,
false,
)
.expect("Plugin should apply transform");
@ -142,6 +143,7 @@ fn internal() -> Result<(), Error> {
program,
config,
context,
false,
)
.expect("Plugin should apply transform")
});
@ -176,6 +178,7 @@ fn internal() -> Result<(), Error> {
Serialized::serialize(&"{}".to_string()).expect("Should serializable"),
Serialized::serialize(&"{sourceFileName: 'multiple_plugin_test'}".to_string())
.expect("Should serializable"),
false,
)
.expect("Plugin should apply transform");
@ -188,6 +191,7 @@ fn internal() -> Result<(), Error> {
Serialized::serialize(&"{}".to_string()).expect("Should serializable"),
Serialized::serialize(&"{sourceFileName: 'multiple_plugin_test2'}".to_string())
.expect("Should serializable"),
false,
)
.expect("Plugin should apply transform");

View File

@ -18,7 +18,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom 0.2.3",
"getrandom",
"once_cell",
"version_check",
]
@ -63,6 +63,15 @@ dependencies = [
"scoped-tls",
]
[[package]]
name = "better_scoped_tls"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b73e8ecdec39e98aa3b19e8cd0b8ed8f77ccb86a6b0b2dc7cd86d105438a2123"
dependencies = [
"scoped-tls",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -90,27 +99,12 @@ dependencies = [
"syn",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloudabi"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
dependencies = [
"bitflags",
]
[[package]]
name = "darling"
version = "0.13.1"
@ -161,16 +155,6 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "enum_kind"
version = "0.2.1"
dependencies = [
"pmutil",
"proc-macro2",
"swc_macros_common",
"syn",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -197,33 +181,22 @@ dependencies = [
"syn",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
dependencies = [
"ahash",
]
@ -245,25 +218,6 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "is-macro"
version = "0.2.0"
@ -283,79 +237,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lexical"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccd3e434c16f0164124ade12dcdee324fcc3dafb1cad0c7f1d8c2451a1aa6886"
dependencies = [
"lexical-core",
]
[[package]]
name = "lexical-core"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92912c4af2e7d9075be3e5e3122c4d7263855fa6cce34fbece4dd08e5884624d"
dependencies = [
"lexical-parse-float",
"lexical-parse-integer",
"lexical-util",
"lexical-write-float",
"lexical-write-integer",
]
[[package]]
name = "lexical-parse-float"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f518eed87c3be6debe6d26b855c97358d8a11bf05acec137e5f53080f5ad2dd8"
dependencies = [
"lexical-parse-integer",
"lexical-util",
"static_assertions",
]
[[package]]
name = "lexical-parse-integer"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc852ec67c6538bbb2b9911116a385b24510e879a69ab516e6a151b15a79168"
dependencies = [
"lexical-util",
"static_assertions",
]
[[package]]
name = "lexical-util"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c72a9d52c5c4e62fa2cdc2cb6c694a39ae1382d9c2a17a466f18e272a0930eb1"
dependencies = [
"static_assertions",
]
[[package]]
name = "lexical-write-float"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26f6202bff3d35ede41a6200227837468bb92e4ecdd437328b1055ed218fb855"
dependencies = [
"lexical-util",
"lexical-write-integer",
"static_assertions",
]
[[package]]
name = "lexical-write-integer"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "094060bd2a7c2ff3a16d5304a6ae82727cb3cc9d1c70f813cc73f744c319337e"
dependencies = [
"lexical-util",
"static_assertions",
]
[[package]]
name = "libc"
version = "0.2.112"
@ -364,9 +245,9 @@ checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "lock_api"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
dependencies = [
"scopeguard",
]
@ -428,28 +309,25 @@ checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "parking_lot"
version = "0.11.1"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954"
dependencies = [
"cfg-if 0.1.10",
"cloudabi",
"instant",
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"winapi",
"windows-sys",
]
[[package]]
@ -460,23 +338,14 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "phf_generator"
version = "0.8.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
"phf_shared 0.8.0",
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
dependencies = [
"siphasher",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
@ -555,23 +424,20 @@ dependencies = [
[[package]]
name = "rand"
version = "0.7.3"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
"rand_pcg",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
@ -579,36 +445,21 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.5.1"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core",
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
@ -638,9 +489,9 @@ dependencies = [
[[package]]
name = "rkyv"
version = "0.7.29"
version = "0.7.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49a37de5dfc60bae2d94961dacd03c7b80e426b66a99fa1b17799570dbdd8f96"
checksum = "5230ae2981a885590b0dc84e0b24c0ed23ad24f7adc0eb824b26cafa961f7c36"
dependencies = [
"bytecheck",
"hashbrown",
@ -652,9 +503,9 @@ dependencies = [
[[package]]
name = "rkyv_derive"
version = "0.7.29"
version = "0.7.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719d447dd0e84b23cee6cb5b32d97e21efb112a3e3c636c8da36647b938475a1"
checksum = "0fc752d5925dbcb324522f3a4c93193d17f107b2e11810913aa3ad352fa01480"
dependencies = [
"proc-macro2",
"quote",
@ -717,34 +568,28 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "string_cache"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26"
checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"once_cell",
"parking_lot",
"phf_shared 0.10.0",
"phf_shared",
"precomputed-hash",
"serde",
]
[[package]]
name = "string_cache_codegen"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
dependencies = [
"phf_generator",
"phf_shared 0.8.0",
"phf_shared",
"proc-macro2",
"quote",
]
@ -768,7 +613,7 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "swc_atoms"
version = "0.2.10"
version = "0.2.11"
dependencies = [
"string_cache",
"string_cache_codegen",
@ -781,8 +626,8 @@ dependencies = [
"ahash",
"anyhow",
"ast_node",
"better_scoped_tls",
"cfg-if 1.0.0",
"better_scoped_tls 0.1.0",
"cfg-if",
"debug_unreachable",
"either",
"from_variant",
@ -814,64 +659,6 @@ dependencies = [
"unicode-id",
]
[[package]]
name = "swc_ecma_parser"
version = "0.97.2"
dependencies = [
"either",
"enum_kind",
"lexical",
"num-bigint",
"serde",
"smallvec",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"tracing",
"typed-arena",
"unicode-id",
]
[[package]]
name = "swc_ecma_quote"
version = "0.8.0"
dependencies = [
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_quote_macros",
"swc_ecma_utils",
]
[[package]]
name = "swc_ecma_quote_macros"
version = "0.7.0"
dependencies = [
"anyhow",
"pmutil",
"proc-macro2",
"quote",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_parser",
"swc_macros_common",
"syn",
]
[[package]]
name = "swc_ecma_utils"
version = "0.76.0"
dependencies = [
"indexmap",
"once_cell",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_visit",
"tracing",
]
[[package]]
name = "swc_ecma_visit"
version = "0.59.0"
@ -914,16 +701,25 @@ dependencies = [
[[package]]
name = "swc_plugin"
version = "0.37.0"
version = "0.39.0"
dependencies = [
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_quote",
"swc_ecma_visit",
"swc_plugin_comments",
"swc_plugin_macro",
]
[[package]]
name = "swc_plugin_comments"
version = "0.1.0"
dependencies = [
"better_scoped_tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rkyv",
"swc_common",
]
[[package]]
name = "swc_plugin_macro"
version = "0.3.1"
@ -985,7 +781,7 @@ version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@ -1011,12 +807,6 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "typed-arena"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
[[package]]
name = "unicode-bidi"
version = "0.3.7"
@ -1083,12 +873,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
@ -1096,23 +880,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "winapi"
version = "0.3.9"
name = "windows-sys"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
name = "windows_aarch64_msvc"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
name = "windows_i686_gnu"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
[[package]]
name = "windows_i686_msvc"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
[[package]]
name = "windows_x86_64_gnu"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"

View File

@ -1,4 +1,6 @@
use swc_plugin::{ast::*, errors::HANDLER, plugin_transform, syntax_pos::DUMMY_SP};
use swc_plugin::{
ast::*, errors::HANDLER, plugin_transform, syntax_pos::DUMMY_SP, TransformPluginProgramMetadata,
};
struct ConsoleOutputReplacer;
@ -33,7 +35,8 @@ impl VisitMut for ConsoleOutputReplacer {
/// config_str_ptr: *const u8,
/// config_str_ptr_len: i32,
/// context_str_ptr: *const u8,
/// context_str_ptr_len: i32) ->
/// context_str_ptr_len: i32,
/// should_enable_comments: i32) ->
/// i32 /* 0 for success, fail otherwise.
/// Note this is only for internal pointer interop result,
/// not actual transform result */
@ -42,7 +45,7 @@ impl VisitMut for ConsoleOutputReplacer {
/// important steps manually need to be performed like sending transformed
/// results back to host. Refer swc_plugin_macro how does it work internally.
#[plugin_transform]
pub fn process(program: Program, _plugin_config: String, _context: String) -> Program {
pub fn process(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
HANDLER.with(|handler| {
handler
.struct_span_err(DUMMY_SP, "Test diagnostics from plugin")