1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{Item as SynItem, ItemFn};
#[proc_macro_attribute]
pub fn plugin_transform(
_args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let token = proc_macro2::TokenStream::from(input);
let parsed_results = syn::parse2::<SynItem>(token).expect("Failed to parse tokens");
match parsed_results {
SynItem::Fn(func) => handle_func(func),
_ => panic!("Please confirm if plugin macro is specified for the function"),
}
}
fn handle_func(func: ItemFn) -> TokenStream {
let ident = func.sig.ident.clone();
let transform_process_impl_ident =
Ident::new("__transform_plugin_process_impl", Span::call_site());
let transform_core_pkg_diag_ident =
Ident::new("__get_transform_plugin_core_pkg_diag", Span::call_site());
let ret = quote! {
#func
#[cfg(target_arch = "wasm32")] extern "C" {
fn __set_transform_result(bytes_ptr: u32, bytes_ptr_len: u32);
fn __set_transform_plugin_core_pkg_diagnostics(bytes_ptr: u32, bytes_ptr_len: u32);
fn __emit_diagnostics(bytes_ptr: u32, bytes_ptr_len: u32);
}
pub struct PluginDiagnosticsEmitter;
impl swc_core::common::errors::Emitter for PluginDiagnosticsEmitter {
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
fn emit(&mut self, db: &swc_core::common::errors::DiagnosticBuilder<'_>) {
let diag = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(&*db.diagnostic)
.expect("Should able to serialize Diagnostic");
let (ptr, len) = diag.as_ptr();
#[cfg(target_arch = "wasm32")] unsafe {
__emit_diagnostics(ptr as u32, len as u32);
}
}
}
fn send_transform_result_to_host(bytes_ptr: u32, bytes_ptr_len: u32) {
#[cfg(target_arch = "wasm32")] unsafe {
__set_transform_result(bytes_ptr, bytes_ptr_len);
}
}
fn construct_error_ptr(plugin_error: swc_core::common::plugin::serialized::PluginError) -> u32 {
let ret = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(&plugin_error).expect("Should able to serialize PluginError");
let (ptr, len) = ret.as_ptr();
send_transform_result_to_host(
ptr as _,
len as u32
);
1
}
#[no_mangle]
pub fn #transform_core_pkg_diag_ident() -> u32 {
let schema_version = swc_core::common::plugin::PLUGIN_TRANSFORM_AST_SCHEMA_VERSION;
let core_pkg_diag = swc_core::diagnostics::get_core_engine_diagnostics();
let result = swc_core::common::plugin::diagnostics::PluginCorePkgDiagnostics {
ast_schema_version: schema_version,
pkg_version: core_pkg_diag.package_semver,
git_sha: core_pkg_diag.git_sha,
cargo_features: core_pkg_diag.cargo_features,
};
let serialized_result = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(
&result
).expect("Diagnostics should be always serializable");
let (serialized_result_ptr, serialized_result_ptr_len) = serialized_result.as_ptr();
#[cfg(target_arch = "wasm32")] unsafe {
__set_transform_plugin_core_pkg_diagnostics(serialized_result_ptr as _, serialized_result_ptr_len as u32);
}
0
}
#[no_mangle]
pub fn #transform_process_impl_ident(
ast_ptr: *const u8, ast_ptr_len: u32,
unresolved_mark: u32, should_enable_comments_proxy: i32) -> u32 {
let program = unsafe { swc_core::common::plugin::serialized::deserialize_from_ptr(ast_ptr, ast_ptr_len) };
if program.is_err() {
let err = swc_core::common::plugin::serialized::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 handler = swc_core::common::errors::Handler::with_emitter(
true,
false,
Box::new(PluginDiagnosticsEmitter)
);
let handler_set_result = swc_core::plugin::errors::HANDLER.inner.set(handler);
if handler_set_result.is_err() {
let err = swc_core::common::plugin::serialized::PluginError::Serialize(
"Failed to set handler for plugin".to_string()
);
return construct_error_ptr(err);
}
let plugin_comments_proxy = if should_enable_comments_proxy == 1 { Some(swc_core::plugin::proxies::PluginCommentsProxy) } else { None };
let mut metadata = swc_core::plugin::metadata::TransformPluginProgramMetadata {
comments: plugin_comments_proxy,
source_map: swc_core::plugin::proxies::PluginSourceMapProxy { source_file: swc_core::common::sync::OnceCell::new() },
unresolved_mark: swc_core::common::Mark::from_u32(unresolved_mark as u32),
};
let transformed_program = #ident(program, metadata);
let serialized_result = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(
&transformed_program
);
if serialized_result.is_err() {
let err = swc_core::common::plugin::serialized::PluginError::Serialize("Failed to serialize transformed program".to_string());
return construct_error_ptr(err);
}
let serialized_result = serialized_result.expect("Should be a realized transformed program");
let (serialized_result_ptr, serialized_result_ptr_len) = serialized_result.as_ptr();
send_transform_result_to_host(serialized_result_ptr as _, serialized_result_ptr_len as u32);
0
}
};
ret.into()
}