mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 13:51:19 +03:00
feat(cli): Add a command for scaffolding a new plugin (#3536)
This commit is contained in:
parent
90d080c16b
commit
6ed089e1cf
230
Cargo.lock
generated
230
Cargo.lock
generated
@ -60,9 +60,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.52"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
@ -263,6 +263,28 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||
|
||||
[[package]]
|
||||
name = "cargo-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2bf633f7ad4e022f63c4197085047af9606a08a3df17badbb7bd3644dc7faeb"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"core-foundation",
|
||||
"crypto-hash",
|
||||
"filetime",
|
||||
"hex 0.4.3",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"same-file",
|
||||
"shell-escape",
|
||||
"tempfile",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
@ -298,17 +320,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
version = "3.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim 0.8.0",
|
||||
"clap_derive",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"os_str_bytes",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a1132dc3944b31c20dd8b906b3a9f0a5d0243e092d59171414969657ac6aa85"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -320,6 +358,24 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "commoncrypto"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
|
||||
dependencies = [
|
||||
"commoncrypto-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "commoncrypto-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
@ -524,6 +580,18 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-hash"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a77162240fd97248d19a564a565eb563a3f592b386e4136fb300909e67dddca"
|
||||
dependencies = [
|
||||
"commoncrypto",
|
||||
"hex 0.3.2",
|
||||
"openssl",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.21"
|
||||
@ -719,6 +787,18 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall 0.2.10",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.2.0"
|
||||
@ -908,12 +988,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
@ -924,6 +1001,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
@ -1085,6 +1168,15 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.55"
|
||||
@ -1625,6 +1717,15 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.2"
|
||||
@ -1681,33 +1782,6 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||
|
||||
[[package]]
|
||||
name = "paw"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9"
|
||||
dependencies = [
|
||||
"paw-attributes",
|
||||
"paw-raw",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paw-attributes"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paw-raw"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
@ -2393,6 +2467,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-escape"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.9"
|
||||
@ -2567,12 +2647,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.9.3"
|
||||
@ -2585,31 +2659,6 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"lazy_static",
|
||||
"paw",
|
||||
"structopt-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc"
|
||||
version = "0.123.6"
|
||||
@ -2672,7 +2721,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"crc",
|
||||
"dashmap",
|
||||
"hex",
|
||||
"hex 0.4.3",
|
||||
"indexmap",
|
||||
"is-macro",
|
||||
"ntest",
|
||||
@ -2712,8 +2761,9 @@ dependencies = [
|
||||
name = "swc_cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"paw",
|
||||
"structopt",
|
||||
"anyhow",
|
||||
"cargo-util",
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3250,7 +3300,7 @@ version = "0.60.0"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"anyhow",
|
||||
"hex",
|
||||
"hex 0.4.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha-1",
|
||||
@ -3602,6 +3652,16 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testing"
|
||||
version = "0.18.1"
|
||||
@ -3634,11 +3694,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3891,12 +3951,6 @@ dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
@ -3936,12 +3990,6 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
@ -4107,7 +4155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e75c10d11f4a62c5e152170db7831d6f81155b4524fbf0a4f5c78c1d8f7e51db"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"hex",
|
||||
"hex 0.4.3",
|
||||
"thiserror",
|
||||
"wasmer",
|
||||
]
|
||||
|
@ -1,5 +1,6 @@
|
||||
[package]
|
||||
description = "Commandline for swc"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>", "OJ Kwon <kwon.ohjoong@gmail.com>"]
|
||||
description = "Commandline for SWC"
|
||||
edition = "2021"
|
||||
include = ["Cargo.toml", "src/**/*.rs"]
|
||||
license = "Apache-2.0"
|
||||
@ -12,5 +13,8 @@ name = "swc"
|
||||
path = "./src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
paw = "1.0"
|
||||
structopt = {version = "0.3.25", features = ["paw"]}
|
||||
anyhow = "1.0.53"
|
||||
cargo-util = "0.1.1"
|
||||
clap = { version = "3.0.14", features = ["derive", "wrap_help"] }
|
||||
|
||||
[features]
|
||||
|
@ -1,36 +0,0 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// Transform, compile files.
|
||||
#[derive(Debug, StructOpt)]
|
||||
pub struct CompileCommand {
|
||||
///Filename to use when reading from stdin - this will be used in
|
||||
/// source-maps, errors etc
|
||||
#[structopt(short = "f", long = "filename")]
|
||||
file_name: String,
|
||||
/// Path to a .swcrc file to use
|
||||
#[structopt(parse(from_os_str), long = "config-file")]
|
||||
config_file: PathBuf,
|
||||
/// The name of the 'env' to use when loading configs and plugins.
|
||||
/// Defaults to the value of SWC_ENV, or else NODE_ENV, or else
|
||||
/// 'development'.
|
||||
///
|
||||
/// DEPRECATED: use --env flag instead.
|
||||
#[structopt(long = "env-name")]
|
||||
env_name: String,
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(about = "Speedy Web Compiler")]
|
||||
pub enum SwcCommand {
|
||||
Compile(CompileCommand),
|
||||
}
|
||||
|
||||
impl SwcCommand {
|
||||
pub fn execute(self) {
|
||||
match self {
|
||||
SwcCommand::Compile(..) => {}
|
||||
};
|
||||
}
|
||||
}
|
5
crates/swc_cli/src/commands/compile.rs
Normal file
5
crates/swc_cli/src/commands/compile.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
pub struct CompileOptions {}
|
30
crates/swc_cli/src/commands/mod.rs
Normal file
30
crates/swc_cli/src/commands/mod.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use clap::{AppSettings, Parser, Subcommand};
|
||||
|
||||
mod compile;
|
||||
mod plugin;
|
||||
|
||||
pub use compile::*;
|
||||
pub use plugin::{PluginScaffoldOptions, PluginSubcommand};
|
||||
|
||||
// Set of subcommands supported by the `swc` command.
|
||||
#[derive(Subcommand)]
|
||||
pub enum Command {
|
||||
/// Commandline utilities for creating, building plugins.
|
||||
#[clap(subcommand)]
|
||||
Plugin(PluginSubcommand),
|
||||
/// Run SWC's transformer.
|
||||
Compile(CompileOptions),
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(name = "SWC", version)]
|
||||
#[clap(global_setting(AppSettings::PropagateVersion))]
|
||||
#[clap(global_setting(AppSettings::UseLongFormatForHelpSubcommand))]
|
||||
pub struct SwcCliOptions {
|
||||
#[clap(subcommand)]
|
||||
pub command: Command,
|
||||
}
|
||||
|
||||
pub trait CommandRunner {
|
||||
fn execute(&self) -> anyhow::Result<()>;
|
||||
}
|
234
crates/swc_cli/src/commands/plugin.rs
Normal file
234
crates/swc_cli/src/commands/plugin.rs
Normal file
@ -0,0 +1,234 @@
|
||||
use std::{
|
||||
io::{BufRead, BufReader, ErrorKind},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use cargo_util::paths::{self, create_dir_all};
|
||||
use clap::{ArgEnum, Parser, Subcommand};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, ArgEnum)]
|
||||
pub enum PluginTargetType {
|
||||
/// wasm32-unknown-unknown target.
|
||||
Wasm32UnknownUnknown,
|
||||
/// wasm32-wasi target.
|
||||
Wasm32Wasi,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct PluginScaffoldOptions {
|
||||
/// Set the resulting plugin name, defaults to the directory name
|
||||
#[clap(long)]
|
||||
pub name: Option<String>,
|
||||
|
||||
/// Sets default build target type of the plugin.
|
||||
///
|
||||
/// "wasm32-wasi" enables wasi (https://github.com/WebAssembly/WASI) support for the generated
|
||||
/// binary which allows to use macros like 'println!' or 'dbg!' and other
|
||||
/// system-related calls.
|
||||
///
|
||||
/// "wasm32-unknown-unknown" will makes those calls as no-op, instead
|
||||
/// generates slightly smaller binaries.
|
||||
#[clap(long, arg_enum)]
|
||||
pub target_type: PluginTargetType,
|
||||
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
/// Infer package name of the plugin if not specified via cli options.
|
||||
fn get_name(option: &PluginScaffoldOptions) -> Result<&str> {
|
||||
if let Some(ref name) = option.name {
|
||||
return Ok(name);
|
||||
}
|
||||
|
||||
let file_name = option.path.file_name().ok_or_else(|| {
|
||||
anyhow::format_err!(
|
||||
"cannot auto-detect package name from path {:?} ; use --name to override",
|
||||
option.path.as_os_str()
|
||||
)
|
||||
})?;
|
||||
|
||||
file_name.to_str().ok_or_else(|| {
|
||||
anyhow::format_err!(
|
||||
"cannot create package with a non-unicode name: {:?}",
|
||||
file_name
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Generate ignore file for the project.
|
||||
///
|
||||
/// Note: this is slim implementation does not support different vcs other than
|
||||
/// git at the moment.
|
||||
fn write_ignore_file(base_path: &Path) -> Result<()> {
|
||||
let ignore_list: Vec<String> = vec!["/target", "^target/", "target"]
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect();
|
||||
|
||||
let ignore_file_path = base_path.join(".gitignore");
|
||||
|
||||
let ignore: String = match paths::open(&ignore_file_path) {
|
||||
Err(err) => match err.downcast_ref::<std::io::Error>() {
|
||||
Some(io_err) if io_err.kind() == ErrorKind::NotFound => ignore_list.join("\n") + "\n",
|
||||
_ => return Err(err),
|
||||
},
|
||||
Ok(file) => {
|
||||
let existing = BufReader::new(file);
|
||||
|
||||
let existing_items = existing.lines().collect::<Result<Vec<_>, _>>().unwrap();
|
||||
let mut out = String::new();
|
||||
|
||||
out.push_str("\n\n# Added by swc\n");
|
||||
if ignore_list.iter().any(|item| existing_items.contains(item)) {
|
||||
out.push_str("#\n# already existing elements were commented out\n");
|
||||
}
|
||||
out.push('\n');
|
||||
|
||||
for item in &ignore_list {
|
||||
if existing_items.contains(item) {
|
||||
out.push('#');
|
||||
}
|
||||
out.push_str(item);
|
||||
out.push('\n');
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
};
|
||||
|
||||
paths::append(&ignore_file_path, ignore.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl super::CommandRunner for PluginScaffoldOptions {
|
||||
/// Create a rust project for the plugin from template.
|
||||
/// This largely mimic https://github.com/rust-lang/cargo/blob/master/src/cargo/ops/cargo_new.rs,
|
||||
/// but also thinner implementation based on some assumptions like skipping
|
||||
/// to support non-git based vcs.
|
||||
fn execute(&self) -> Result<()> {
|
||||
let path = &self.path;
|
||||
if path.exists() {
|
||||
anyhow::bail!("destination `{}` already exists", path.display())
|
||||
}
|
||||
|
||||
let name = get_name(self)?;
|
||||
|
||||
// Choose to rely on system's git binary instead of depends on git lib for now
|
||||
// to avoid bring in large / heavy dependencies into cli binaries.
|
||||
// Depends on our usecase grows, we can revisit this.
|
||||
let mut base_git_cmd = if cfg!(target_os = "windows") {
|
||||
let mut c = std::process::Command::new("cmd");
|
||||
c.arg("/C").arg("git");
|
||||
c
|
||||
} else {
|
||||
std::process::Command::new("git")
|
||||
};
|
||||
|
||||
// init git repo
|
||||
base_git_cmd
|
||||
.args(["init", name])
|
||||
.output()
|
||||
.context("failed to create dir for the plugin")?;
|
||||
|
||||
// generate .gitignore
|
||||
write_ignore_file(path)?;
|
||||
|
||||
// Create `Cargo.toml` file with necessary sections
|
||||
paths::write(
|
||||
&path.join("Cargo.toml"),
|
||||
format!(
|
||||
r#"[package]
|
||||
name = "{}"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
# Workaround for https://github.com/Amanieu/parking_lot/issues/269
|
||||
# (swc_atoms -> string_cache -> parking_lot)
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
parking_lot_core = "=0.8.0"
|
||||
|
||||
[dependencies]
|
||||
serde = "1"
|
||||
swc_plugin = "*""#,
|
||||
name
|
||||
)
|
||||
.as_bytes(),
|
||||
)?;
|
||||
|
||||
let build_target = match self.target_type {
|
||||
PluginTargetType::Wasm32UnknownUnknown => "wasm32-unknown-unknown",
|
||||
PluginTargetType::Wasm32Wasi => "wasm32-wasi",
|
||||
};
|
||||
|
||||
// Create cargo config for build target
|
||||
let cargo_config_path = path.join(".cargo");
|
||||
create_dir_all(&cargo_config_path)?;
|
||||
paths::write(
|
||||
&cargo_config_path.join("config"),
|
||||
format!(
|
||||
r#"[build]
|
||||
target = "{}""#,
|
||||
build_target
|
||||
)
|
||||
.as_bytes(),
|
||||
)?;
|
||||
|
||||
// Create entrypoint src file
|
||||
let src_path = path.join("src");
|
||||
create_dir_all(&src_path)?;
|
||||
paths::write(
|
||||
&src_path.join("lib.rs"),
|
||||
r#"use swc_plugin::{ast::*, plugin_transform};
|
||||
|
||||
pub struct TransformVisitor;
|
||||
|
||||
impl VisitMut for TransformVisitor {
|
||||
// Implement necessary visit_mut_* methods for actual custom transform.
|
||||
}
|
||||
|
||||
/// An entrypoint to the SWC's transform plugin.
|
||||
/// `plugin_transform` macro handles necessary interop to communicate with the host,
|
||||
/// and entrypoint function name (`process_transform`) can be anything else.
|
||||
///
|
||||
/// If plugin need to handle low-level ptr directly,
|
||||
/// it is possible to opt out from macro by writing transform fn manually via raw interface
|
||||
///
|
||||
/// `__plugin_process_impl(
|
||||
/// ast_ptr: *const u8,
|
||||
/// ast_ptr_len: i32,
|
||||
/// config_str_ptr: *const u8,
|
||||
/// config_str_ptr_len: i32) ->
|
||||
/// i32 /* 0 for success, fail otherwise.
|
||||
/// Note this is only for internal pointer interop result,
|
||||
/// not actual transform result */
|
||||
///
|
||||
/// However, this means plugin author need to handle all of serialization/deserialization
|
||||
/// steps with communicating with host. Refer `swc_plugin_macro` for more details.
|
||||
#[plugin_transform]
|
||||
pub fn process_transform(program: Program, _plugin_config: String) -> Program {
|
||||
program.fold_with(&mut as_folder(TransformVisitor))
|
||||
}
|
||||
"#
|
||||
.as_bytes(),
|
||||
)?;
|
||||
|
||||
println!(
|
||||
r#"Successfully created {}.
|
||||
If you haven't, please ensure to add target via "rustup target add {}" "#,
|
||||
path.display(),
|
||||
build_target
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Set of subcommands for the plugin subcommand.
|
||||
#[derive(Subcommand)]
|
||||
pub enum PluginSubcommand {
|
||||
/// Create a new plugin project with minimal scaffolding template.
|
||||
New(PluginScaffoldOptions),
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
#![allow(dead_code)]
|
||||
use clap::Parser;
|
||||
use commands::{Command, CommandRunner, PluginSubcommand, SwcCliOptions};
|
||||
|
||||
mod cli;
|
||||
use cli::SwcCommand;
|
||||
mod commands;
|
||||
|
||||
#[paw::main]
|
||||
fn main(_args: SwcCommand) {
|
||||
unimplemented!("Not yet implemented");
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let command = SwcCliOptions::parse().command;
|
||||
|
||||
match &command {
|
||||
Command::Plugin(PluginSubcommand::New(options)) => options.execute(),
|
||||
Command::Compile(..) => anyhow::bail!("Compile command is not yet implemented"),
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,24 @@
|
||||
# swc_plugin
|
||||
# SWC Plugin
|
||||
|
||||
Base runtime for SWC plugins, written in rust.
|
||||
This crate provides necessary types and macros for creating a custom plugin for SWC (https://swc.rs/), which are WebAssembly modules that may be used to modify behavior of SWC. Currently only `trasnform` (https://swc.rs/docs/usage/core#transform) is supported.
|
||||
|
||||
**Disclaimer: currently SWC plugin support is experimental, there may be possible breaking changes or unexpected behaviors. Please provide issues, feedbacks to https://github.com/swc-project/swc/discussions .**
|
||||
|
||||
## Writing a plugin
|
||||
|
||||
All plugin require adding crate-type = ['cdylib'] to the Cargo.toml. For a quick setup, SWC provides a simple commandline to create project for the plugin.
|
||||
|
||||
```
|
||||
// if you haven't, add build targets for webassembly
|
||||
rustup target add wasm32-wasi wasm32-unknown-unknown
|
||||
|
||||
cargo install swc
|
||||
|
||||
swc plugin new ${plugin_name} --target-type wasm32-wasi
|
||||
```
|
||||
|
||||
When create a new project cli require to specify target type between `wasm32-wasi` or `wasm32-unknown-unknown`. `wasm32-unknown-unknown` will generate slighly smaller binary, but it doesn't support system interfaces as well as macros like `printn!()`.
|
||||
|
||||
Generated project will contain a fn with macro `#[plugin_transform]` which internally does necessary interop for communication between host to the plugin.
|
||||
|
||||
There are few references like SWC's [jest transform](https://github.com/swc-project/swc/blob/90d080c16b41b73f34151c1f5ecbcbf0b5d8e236/crates/swc_ecma_ext_transforms/src/jest.rs) for writing actual `VisitMut`.
|
@ -3,6 +3,11 @@ pub use swc_common::{
|
||||
chain,
|
||||
plugin::{PluginError, Serialized},
|
||||
};
|
||||
|
||||
pub mod util {
|
||||
pub use swc_common::util::take;
|
||||
}
|
||||
|
||||
pub mod ast {
|
||||
pub use swc_atoms::*;
|
||||
pub use swc_ecma_ast::*;
|
||||
@ -26,7 +31,7 @@ pub mod environment {
|
||||
}
|
||||
// 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_module;
|
||||
pub use swc_plugin_macro::plugin_transform;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod allocation;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
@ -5,7 +5,7 @@ use quote::quote;
|
||||
use syn::{Item as SynItem, ItemFn};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn plugin_module(
|
||||
pub fn plugin_transform(
|
||||
_args: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
@ -47,7 +47,10 @@ fn handle_func(func: ItemFn) -> TokenStream {
|
||||
let ret = swc_plugin::Serialized::serialize(&plugin_error).expect("Should able to serialize PluginError");
|
||||
let ret_ref = ret.as_ref();
|
||||
|
||||
set_transform_result_volatile(ret_ref.as_ptr() as _, ret_ref.len().try_into().expect("Should able to convert size of PluginError"));
|
||||
set_transform_result_volatile(
|
||||
ret_ref.as_ptr() as _,
|
||||
std::convert::TryInto::try_into(ret_ref.len()).expect("Should able to convert size of PluginError")
|
||||
);
|
||||
1
|
||||
}
|
||||
|
||||
@ -57,8 +60,8 @@ fn handle_func(func: ItemFn) -> TokenStream {
|
||||
// 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) -> i32 {
|
||||
let ast_ptr_len_usize: Result<usize, std::num::TryFromIntError> = ast_ptr_len.try_into();
|
||||
let config_str_ptr_len_usize: Result<usize, std::num::TryFromIntError> = config_str_ptr_len.try_into();
|
||||
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);
|
||||
|
||||
if ast_ptr_len_usize.is_err() {
|
||||
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of AST pointer".to_string());
|
||||
@ -134,7 +137,7 @@ fn handle_func(func: ItemFn) -> TokenStream {
|
||||
let serialized_result = serialized_result.expect("Should be a realized transformed program");
|
||||
let serialized_result = serialized_result.as_ref();
|
||||
|
||||
let serialized_result_len: Result<i32, std::num::TryFromIntError> = serialized_result.len().try_into();
|
||||
let serialized_result_len: Result<i32, std::num::TryFromIntError> = std::convert::TryInto::try_into(serialized_result.len());
|
||||
|
||||
if serialized_result_len.is_err() {
|
||||
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of transformed AST pointer".to_string());
|
||||
|
@ -676,7 +676,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_common"
|
||||
version = "0.17.4"
|
||||
version = "0.17.5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
|
@ -1,9 +1,4 @@
|
||||
use swc_plugin::{
|
||||
ast::*,
|
||||
errors::HANDLER,
|
||||
plugin_module,
|
||||
syntax_pos::{DUMMY_SP},
|
||||
};
|
||||
use swc_plugin::{ast::*, errors::HANDLER, plugin_transform, syntax_pos::DUMMY_SP};
|
||||
|
||||
struct ConsoleOutputReplacer;
|
||||
|
||||
@ -29,8 +24,8 @@ impl VisitMut for ConsoleOutputReplacer {
|
||||
}
|
||||
|
||||
/// An example plugin function with macro support.
|
||||
/// `plugin_module` macro interop pointers into deserialized structs, as well as
|
||||
/// returning ptr back to host.
|
||||
/// `plugin_transform` macro interop pointers into deserialized structs, as well
|
||||
/// as returning ptr back to host.
|
||||
///
|
||||
/// It is possible to opt out from macro by writing transform fn manually via
|
||||
/// `__plugin_process_impl(
|
||||
@ -45,7 +40,7 @@ impl VisitMut for ConsoleOutputReplacer {
|
||||
/// if plugin need to handle low-level ptr directly. However, there are
|
||||
/// important steps manually need to be performed like sending transformed
|
||||
/// results back to host. Refer swc_plugin_macro how does it work internally.
|
||||
#[plugin_module]
|
||||
#[plugin_transform]
|
||||
pub fn process(program: Program, _plugin_config: String) -> Program {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
|
Loading…
Reference in New Issue
Block a user