Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(swc/plugin_macro): export new interface for getting plugin schema version (#5060: Part 5) #5166

Merged
merged 3 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/cargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ jobs:
- crate: swc
os: ubuntu-latest
check: |
cargo hack check --feature-powerset --no-dev-deps --exclude-features debug --exclude-features plugin
cargo hack check --feature-powerset --no-dev-deps --exclude-features debug --exclude-features plugin --exclude-features plugin-transform-schema-v1
- crate: swc
os: windows-latest
- crate: swc_atoms
Expand All @@ -136,7 +136,7 @@ jobs:
- crate: swc_common
os: ubuntu-latest
check: |
cargo hack check --feature-powerset --no-dev-deps
cargo hack check --feature-powerset --no-dev-deps --exclude-features plugin-transform-schema-vtest
- crate: swc_common
os: windows-latest
- crate: swc_config
Expand Down Expand Up @@ -398,9 +398,15 @@ jobs:
swc-exec-cache-${{ matrix.settings.crate }}-${{ runner.os }}

- name: Run cargo test
if: matrix.settings.crate != 'swc_plugin_runner'
run: |
cargo test --color always -p ${{ matrix.settings.crate }}

- name: Run cargo test (plugin)
if: matrix.settings.crate == 'swc_plugin_runner'
run: |
cargo test --color always -p swc_plugin_runner --features plugin-transform-schema-v1

- name: Run cargo test (all features)
if: matrix.settings.crate == 'swc_ecma_parser' || matrix.settings.crate == 'swc_ecma_loader' || matrix.settings.crate == 'swc_ecma_transforms'
run: |
Expand Down
3 changes: 3 additions & 0 deletions crates/binding_core_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ crate-type = ["cdylib"]
default = ["swc_v1", "plugin"]
plugin = [
"swc/plugin",
"swc/plugin-transform-schema-v1",
"swc_common/plugin-transform-schema-v1",
"swc_plugin_runner/default",
"swc_plugin_runner/plugin-transform-schema-v1",
"wasmer/default",
"wasmer-wasi/default",
]
Expand Down
1 change: 1 addition & 0 deletions crates/binding_core_wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ swc_v2 = []
plugin = [
"swc/plugin",
"swc_plugin_runner/memory_cache",
"swc_plugin_runner/plugin-transform-schema-v1",
"wasmer",
"wasmer-wasi",
"wasmer/js-default",
Expand Down
4 changes: 4 additions & 0 deletions crates/swc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ default = ["es3"]
es3 = []
node = ["napi", "napi-derive"]
plugin = ["swc_plugin_runner", "swc_plugin_proxy/plugin-rt"]
plugin-transform-schema-v1 = [
"swc_common/plugin-transform-schema-v1",
"swc_plugin_runner/plugin-transform-schema-v1"
]

[dependencies]
ahash = "0.7.4"
Expand Down
4 changes: 4 additions & 0 deletions crates/swc/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ impl RustPlugins {
&self.source_map,
)?;

if !transform_plugin_executor.is_transform_schema_compatible()? {
anyhow::bail!("Cannot execute incompatible plugin {}", &p.0);
}

let span = tracing::span!(
tracing::Level::INFO,
"serialize_context",
Expand Down
1 change: 1 addition & 0 deletions crates/swc_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ default = []
plugin = [
"swc/plugin",
"swc_plugin_runner/filesystem_cache",
"swc_plugin_runner/plugin-transform-schema-v1",
"wasmer/default",
"wasmer-wasi/default",
]
Expand Down
2 changes: 2 additions & 0 deletions crates/swc_common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ plugin-mode = ["plugin-base"]
plugin-rt = ["plugin-base"]
rkyv-impl = ["rkyv", "bytecheck"]
tty-emitter = ["atty", "termcolor"]
plugin-transform-schema-v1 = []
plugin-transform-schema-vtest = []

[dependencies]
ahash = "0.7.4"
Expand Down
22 changes: 22 additions & 0 deletions crates/swc_common/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ use rkyv::{with::AsBox, Archive, Deserialize, Serialize};

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

/**
* Compile-time version constant for the AST struct schema's version.
*
* NOTE: this is for PARTIAL compatibility only, supporting if AST struct
* adds new properties without changing / removing existing properties.
*
* - When adding a new properties to the AST struct:
* 1. Create a new feature flag in cargo.toml
* 2. Create a new schema version with new feature flag.
* 3. Create a new AST struct with compile time feature flag with newly
* added properties. Previous struct should remain with existing feature
* flag, or add previous latest feature flag.
*
* - When removing, or changing existing properties in the AST struct: TBD
*/
#[cfg(feature = "plugin-transform-schema-v1")]
pub const PLUGIN_TRANSFORM_AST_SCHEMA_VERSION: u32 = 1;

// Reserved for the testing purpose.
#[cfg(feature = "plugin-transform-schema-vtest")]
pub const PLUGIN_TRANSFORM_AST_SCHEMA_VERSION: u32 = u32::MAX - 1;

#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
#[cfg_attr(
Expand Down
1 change: 1 addition & 0 deletions crates/swc_plugin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ quote = ["swc_ecma_quote"]
swc_atoms = { version = "0.2.0", path = "../swc_atoms" }
swc_common = { version = "0.23.0", path = "../swc_common", features = [
"plugin-mode",
"plugin-transform-schema-v1"
] }
swc_ecma_quote = { version = "0.25.0", path = "../swc_ecma_quote", optional = true }
swc_ecmascript = { version = "0.179.0", path = "../swc_ecmascript", features = ["utils", "visit", "rkyv-impl"] }
Expand Down
5 changes: 4 additions & 1 deletion crates/swc_plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
// Reexports
pub use swc_common::{
chain,
plugin::{deserialize_from_ptr, PluginError, PluginSerializedBytes, VersionedSerializable},
plugin::{
deserialize_from_ptr, PluginError, PluginSerializedBytes, VersionedSerializable,
PLUGIN_TRANSFORM_AST_SCHEMA_VERSION,
},
};

pub mod comments {
Expand Down
7 changes: 7 additions & 0 deletions crates/swc_plugin_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ 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_schema_version_ident =
Ident::new("__get_transform_plugin_schema_version", Span::call_site());

let ret = quote! {
#func
Expand Down Expand Up @@ -55,6 +57,11 @@ fn handle_func(func: ItemFn) -> TokenStream {
1
}

#[no_mangle]
pub fn #transform_schema_version_ident() -> u32 {
swc_plugin::PLUGIN_TRANSFORM_AST_SCHEMA_VERSION
}

// Macro to allow compose plugin's transform function without manual pointer operation.
// Internally it wraps pointer operation also bubbles up error in forms of PluginError.
// There are some cases error won't be wrapped up however - for example, we expect
Expand Down
5 changes: 4 additions & 1 deletion crates/swc_plugin_runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ filesystem_cache = ["wasmer-cache"]
# Supports a cache allow to store wasm module in-memory. This avoids recompilation
# to the same module in a single procress lifecycle.
memory_cache = []
plugin-transform-schema-v1 = [
"swc_common/plugin-transform-schema-v1"
]

[dependencies]
anyhow = "1.0.42"
Expand All @@ -28,7 +31,7 @@ serde = { version = "1.0.126", features = ["derive"] }
serde_json = "1.0.64"
swc_common = { version = "0.23.0", path = "../swc_common", features = [
"plugin-rt",
"concurrent",
"concurrent"
] }
swc_ecma_ast = { version = "0.84.0", path = "../swc_ecma_ast", features = [
"rkyv-impl",
Expand Down
27 changes: 23 additions & 4 deletions crates/swc_plugin_runner/src/transform_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;
use anyhow::{anyhow, Error};
use parking_lot::Mutex;
use swc_common::{
plugin::{PluginError, PluginSerializedBytes},
plugin::{PluginError, PluginSerializedBytes, PLUGIN_TRANSFORM_AST_SCHEMA_VERSION},
SourceMap,
};
use wasmer::Instance;
Expand All @@ -14,6 +14,8 @@ use crate::memory_interop::write_into_memory_view;
pub struct TransformExecutor {
// Main transform interface plugin exports
exported_plugin_transform: wasmer::NativeFunc<(i32, i32, i32, i32, i32, i32, i32), i32>,
// Schema version interface exports
exported_plugin_transform_schema_version: wasmer::NativeFunc<(), u32>,
// `__free` function automatically exported via swc_plugin sdk to allow deallocation in guest
// memory space
exported_plugin_free: wasmer::NativeFunc<(i32, i32), i32>,
Expand Down Expand Up @@ -42,6 +44,9 @@ impl TransformExecutor {
.get_native_function::<(i32, i32, i32, i32, i32, i32, i32), i32>(
"__transform_plugin_process_impl",
)?,
exported_plugin_transform_schema_version: instance
.exports
.get_native_function::<(), u32>("__get_transform_plugin_schema_version")?,
exported_plugin_free: instance
.exports
.get_native_function::<(i32, i32), i32>("__free")?,
Expand Down Expand Up @@ -103,14 +108,28 @@ impl TransformExecutor {
}

/**
* Check compile-time versions of AST schema between the plugin and
* Check compile-time version of AST schema between the plugin and
* the host. Returns true if it's compatible, false otherwise.
*
* Host should appropriately handle if plugin is not compatible to the
* current runtime.
*/
pub fn is_transform_schema_compatible(&self) -> bool {
todo!("Not supported yet");
pub fn is_transform_schema_compatible(&self) -> Result<bool, Error> {
let plugin_schema_version = self.exported_plugin_transform_schema_version.call();

match plugin_schema_version {
Ok(plugin_schema_version) => {
let host_schema_version = PLUGIN_TRANSFORM_AST_SCHEMA_VERSION;

// TODO: this is incomplete
if plugin_schema_version == host_schema_version {
Ok(true)
} else {
Ok(false)
}
}
Err(e) => Err(anyhow!("Failed to call plugin's schema version: {}", e)),
}
}

#[tracing::instrument(level = "info", skip_all)]
Expand Down
8 changes: 8 additions & 0 deletions crates/swc_plugin_runner/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ fn build_plugin(dir: &Path) -> Result<PathBuf, Error> {
cmd.args(["build", "--target=wasm32-wasi"])
.stderr(Stdio::inherit());
cmd.output()?;

if !cmd
.status()
.expect("Exit code should be available")
.success()
{
return Err(anyhow!("Failed to build plugin"));
}
}

for entry in fs::read_dir(&dir.join("target").join("wasm32-wasi").join("debug"))? {
Expand Down
4 changes: 2 additions & 2 deletions tests/rust-plugins/swc_internal_plugin/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.