Skip to content

Commit f167198

Browse files
authored
feat(plugin/macros): Export new interface for getting plugin schema version (#5166)
1 parent 793c423 commit f167198

File tree

15 files changed

+94
-10
lines changed

15 files changed

+94
-10
lines changed

.github/workflows/cargo.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ jobs:
115115
- crate: swc
116116
os: ubuntu-latest
117117
check: |
118-
cargo hack check --feature-powerset --no-dev-deps --exclude-features debug --exclude-features plugin
118+
cargo hack check --feature-powerset --no-dev-deps --exclude-features debug --exclude-features plugin --exclude-features plugin-transform-schema-v1
119119
- crate: swc
120120
os: windows-latest
121121
- crate: swc_atoms
@@ -136,7 +136,7 @@ jobs:
136136
- crate: swc_common
137137
os: ubuntu-latest
138138
check: |
139-
cargo hack check --feature-powerset --no-dev-deps
139+
cargo hack check --feature-powerset --no-dev-deps --exclude-features plugin-transform-schema-vtest
140140
- crate: swc_common
141141
os: windows-latest
142142
- crate: swc_config
@@ -398,9 +398,15 @@ jobs:
398398
swc-exec-cache-${{ matrix.settings.crate }}-${{ runner.os }}
399399
400400
- name: Run cargo test
401+
if: matrix.settings.crate != 'swc_plugin_runner'
401402
run: |
402403
cargo test --color always -p ${{ matrix.settings.crate }}
403404
405+
- name: Run cargo test (plugin)
406+
if: matrix.settings.crate == 'swc_plugin_runner'
407+
run: |
408+
cargo test --color always -p swc_plugin_runner --features plugin-transform-schema-v1
409+
404410
- name: Run cargo test (all features)
405411
if: matrix.settings.crate == 'swc_ecma_parser' || matrix.settings.crate == 'swc_ecma_loader' || matrix.settings.crate == 'swc_ecma_transforms'
406412
run: |

crates/binding_core_node/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ crate-type = ["cdylib"]
1616
default = ["swc_v1", "plugin"]
1717
plugin = [
1818
"swc/plugin",
19+
"swc/plugin-transform-schema-v1",
20+
"swc_common/plugin-transform-schema-v1",
1921
"swc_plugin_runner/default",
22+
"swc_plugin_runner/plugin-transform-schema-v1",
2023
"wasmer/default",
2124
"wasmer-wasi/default",
2225
]

crates/binding_core_wasm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ swc_v2 = []
2020
plugin = [
2121
"swc/plugin",
2222
"swc_plugin_runner/memory_cache",
23+
"swc_plugin_runner/plugin-transform-schema-v1",
2324
"wasmer",
2425
"wasmer-wasi",
2526
"wasmer/js-default",

crates/swc/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ default = ["es3"]
2222
es3 = []
2323
node = ["napi", "napi-derive"]
2424
plugin = ["swc_plugin_runner", "swc_plugin_proxy/plugin-rt"]
25+
plugin-transform-schema-v1 = [
26+
"swc_common/plugin-transform-schema-v1",
27+
"swc_plugin_runner/plugin-transform-schema-v1"
28+
]
2529

2630
[dependencies]
2731
ahash = "0.7.4"

crates/swc/src/plugin.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ impl RustPlugins {
127127
&self.source_map,
128128
)?;
129129

130+
if !transform_plugin_executor.is_transform_schema_compatible()? {
131+
anyhow::bail!("Cannot execute incompatible plugin {}", &p.0);
132+
}
133+
130134
let span = tracing::span!(
131135
tracing::Level::INFO,
132136
"serialize_context",

crates/swc_cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ default = []
1818
plugin = [
1919
"swc/plugin",
2020
"swc_plugin_runner/filesystem_cache",
21+
"swc_plugin_runner/plugin-transform-schema-v1",
2122
"wasmer/default",
2223
"wasmer-wasi/default",
2324
]

crates/swc_common/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ plugin-mode = ["plugin-base"]
2626
plugin-rt = ["plugin-base"]
2727
rkyv-impl = ["rkyv", "bytecheck"]
2828
tty-emitter = ["atty", "termcolor"]
29+
plugin-transform-schema-v1 = []
30+
plugin-transform-schema-vtest = []
2931

3032
[dependencies]
3133
ahash = "0.7.4"

crates/swc_common/src/plugin.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,28 @@ use rkyv::{with::AsBox, Archive, Deserialize, Serialize};
1212

1313
use crate::{syntax_pos::Mark, SyntaxContext};
1414

15+
/**
16+
* Compile-time version constant for the AST struct schema's version.
17+
*
18+
* NOTE: this is for PARTIAL compatibility only, supporting if AST struct
19+
* adds new properties without changing / removing existing properties.
20+
*
21+
* - When adding a new properties to the AST struct:
22+
* 1. Create a new feature flag in cargo.toml
23+
* 2. Create a new schema version with new feature flag.
24+
* 3. Create a new AST struct with compile time feature flag with newly
25+
* added properties. Previous struct should remain with existing feature
26+
* flag, or add previous latest feature flag.
27+
*
28+
* - When removing, or changing existing properties in the AST struct: TBD
29+
*/
30+
#[cfg(feature = "plugin-transform-schema-v1")]
31+
pub const PLUGIN_TRANSFORM_AST_SCHEMA_VERSION: u32 = 1;
32+
33+
// Reserved for the testing purpose.
34+
#[cfg(feature = "plugin-transform-schema-vtest")]
35+
pub const PLUGIN_TRANSFORM_AST_SCHEMA_VERSION: u32 = u32::MAX - 1;
36+
1537
#[derive(Debug, Clone, PartialEq, Eq)]
1638
#[non_exhaustive]
1739
#[cfg_attr(

crates/swc_plugin/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ quote = ["swc_ecma_quote"]
2222
swc_atoms = { version = "0.2.0", path = "../swc_atoms" }
2323
swc_common = { version = "0.23.0", path = "../swc_common", features = [
2424
"plugin-mode",
25+
"plugin-transform-schema-v1"
2526
] }
2627
swc_ecma_quote = { version = "0.25.0", path = "../swc_ecma_quote", optional = true }
2728
swc_ecmascript = { version = "0.179.0", path = "../swc_ecmascript", features = ["utils", "visit", "rkyv-impl"] }

crates/swc_plugin/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
// Reexports
44
pub use swc_common::{
55
chain,
6-
plugin::{deserialize_from_ptr, PluginError, PluginSerializedBytes, VersionedSerializable},
6+
plugin::{
7+
deserialize_from_ptr, PluginError, PluginSerializedBytes, VersionedSerializable,
8+
PLUGIN_TRANSFORM_AST_SCHEMA_VERSION,
9+
},
710
};
811

912
pub mod comments {

crates/swc_plugin_macro/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ fn handle_func(func: ItemFn) -> TokenStream {
2121
let ident = func.sig.ident.clone();
2222
let transform_process_impl_ident =
2323
Ident::new("__transform_plugin_process_impl", Span::call_site());
24+
let transform_schema_version_ident =
25+
Ident::new("__get_transform_plugin_schema_version", Span::call_site());
2426

2527
let ret = quote! {
2628
#func
@@ -55,6 +57,11 @@ fn handle_func(func: ItemFn) -> TokenStream {
5557
1
5658
}
5759

60+
#[no_mangle]
61+
pub fn #transform_schema_version_ident() -> u32 {
62+
swc_plugin::PLUGIN_TRANSFORM_AST_SCHEMA_VERSION
63+
}
64+
5865
// Macro to allow compose plugin's transform function without manual pointer operation.
5966
// Internally it wraps pointer operation also bubbles up error in forms of PluginError.
6067
// There are some cases error won't be wrapped up however - for example, we expect

crates/swc_plugin_runner/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ filesystem_cache = ["wasmer-cache"]
1919
# Supports a cache allow to store wasm module in-memory. This avoids recompilation
2020
# to the same module in a single procress lifecycle.
2121
memory_cache = []
22+
plugin-transform-schema-v1 = [
23+
"swc_common/plugin-transform-schema-v1"
24+
]
2225

2326
[dependencies]
2427
anyhow = "1.0.42"
@@ -28,7 +31,7 @@ serde = { version = "1.0.126", features = ["derive"] }
2831
serde_json = "1.0.64"
2932
swc_common = { version = "0.23.0", path = "../swc_common", features = [
3033
"plugin-rt",
31-
"concurrent",
34+
"concurrent"
3235
] }
3336
swc_ecma_ast = { version = "0.84.0", path = "../swc_ecma_ast", features = [
3437
"rkyv-impl",

crates/swc_plugin_runner/src/transform_executor.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33
use anyhow::{anyhow, Error};
44
use parking_lot::Mutex;
55
use swc_common::{
6-
plugin::{PluginError, PluginSerializedBytes},
6+
plugin::{PluginError, PluginSerializedBytes, PLUGIN_TRANSFORM_AST_SCHEMA_VERSION},
77
SourceMap,
88
};
99
use wasmer::Instance;
@@ -14,6 +14,8 @@ use crate::memory_interop::write_into_memory_view;
1414
pub struct TransformExecutor {
1515
// Main transform interface plugin exports
1616
exported_plugin_transform: wasmer::NativeFunc<(i32, i32, i32, i32, i32, i32, i32), i32>,
17+
// Schema version interface exports
18+
exported_plugin_transform_schema_version: wasmer::NativeFunc<(), u32>,
1719
// `__free` function automatically exported via swc_plugin sdk to allow deallocation in guest
1820
// memory space
1921
exported_plugin_free: wasmer::NativeFunc<(i32, i32), i32>,
@@ -42,6 +44,9 @@ impl TransformExecutor {
4244
.get_native_function::<(i32, i32, i32, i32, i32, i32, i32), i32>(
4345
"__transform_plugin_process_impl",
4446
)?,
47+
exported_plugin_transform_schema_version: instance
48+
.exports
49+
.get_native_function::<(), u32>("__get_transform_plugin_schema_version")?,
4550
exported_plugin_free: instance
4651
.exports
4752
.get_native_function::<(i32, i32), i32>("__free")?,
@@ -103,14 +108,28 @@ impl TransformExecutor {
103108
}
104109

105110
/**
106-
* Check compile-time versions of AST schema between the plugin and
111+
* Check compile-time version of AST schema between the plugin and
107112
* the host. Returns true if it's compatible, false otherwise.
108113
*
109114
* Host should appropriately handle if plugin is not compatible to the
110115
* current runtime.
111116
*/
112-
pub fn is_transform_schema_compatible(&self) -> bool {
113-
todo!("Not supported yet");
117+
pub fn is_transform_schema_compatible(&self) -> Result<bool, Error> {
118+
let plugin_schema_version = self.exported_plugin_transform_schema_version.call();
119+
120+
match plugin_schema_version {
121+
Ok(plugin_schema_version) => {
122+
let host_schema_version = PLUGIN_TRANSFORM_AST_SCHEMA_VERSION;
123+
124+
// TODO: this is incomplete
125+
if plugin_schema_version == host_schema_version {
126+
Ok(true)
127+
} else {
128+
Ok(false)
129+
}
130+
}
131+
Err(e) => Err(anyhow!("Failed to call plugin's schema version: {}", e)),
132+
}
114133
}
115134

116135
#[tracing::instrument(level = "info", skip_all)]

crates/swc_plugin_runner/tests/integration.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ fn build_plugin(dir: &Path) -> Result<PathBuf, Error> {
2424
cmd.args(["build", "--target=wasm32-wasi"])
2525
.stderr(Stdio::inherit());
2626
cmd.output()?;
27+
28+
if !cmd
29+
.status()
30+
.expect("Exit code should be available")
31+
.success()
32+
{
33+
return Err(anyhow!("Failed to build plugin"));
34+
}
2735
}
2836

2937
for entry in fs::read_dir(&dir.join("target").join("wasm32-wasi").join("debug"))? {

tests/rust-plugins/swc_internal_plugin/Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)