feat(plugin/macros): Export new interface for getting plugin schema version (#5166)

This commit is contained in:
OJ Kwon 2022-07-10 18:44:00 -07:00 committed by GitHub
parent 793c423a24
commit f167198470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 94 additions and 10 deletions

View File

@ -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
@ -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
@ -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: |

View File

@ -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",
]

View File

@ -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",

View File

@ -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"

View File

@ -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",

View File

@ -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",
]

View File

@ -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"

View File

@ -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(

View File

@ -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"] }

View File

@ -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 {

View File

@ -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
@ -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

View File

@ -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"
@ -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",

View File

@ -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;
@ -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>,
@ -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")?,
@ -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)]

View File

@ -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"))? {

View File

@ -848,7 +848,7 @@ dependencies = [
[[package]]
name = "swc_plugin"
version = "0.74.0"
version = "0.75.0"
dependencies = [
"swc_atoms",
"swc_common",
@ -868,7 +868,7 @@ dependencies = [
[[package]]
name = "swc_plugin_proxy"
version = "0.8.0"
version = "0.9.0"
dependencies = [
"better_scoped_tls",
"bytecheck",