Skip to content

Commit

Permalink
JavaScript visitor API for custom transforms (parcel-bundler#363)
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett authored Dec 26, 2022
1 parent 87ca705 commit 0445926
Show file tree
Hide file tree
Showing 111 changed files with 16,573 additions and 841 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,15 @@ jobs:
- uses: Swatinem/rust-cache@v1
- run: cargo fmt
- run: cargo test --all-features
test-js:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 18
- uses: bahmutov/[email protected]
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v1
- run: yarn build
- run: yarn test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ dist/
.parcel-cache
node/*.flow
artifacts
npm
npm
node/ast.json
67 changes: 65 additions & 2 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ bundler = ["dashmap", "rayon"]
cli = ["clap", "serde_json", "browserslist", "jemallocator"]
grid = []
nodejs = ["dep:serde"]
serde = ["dep:serde", "smallvec/serde", "cssparser/serde"]
serde = ["dep:serde", "smallvec/serde", "cssparser/serde", "parcel_selectors/serde"]
jsonschema = ["schemars", "serde", "parcel_selectors/jsonschema"]
visitor = ["lightningcss-derive"]

[dependencies]
Expand All @@ -55,6 +56,7 @@ rayon = { version = "1.5.1", optional = true }
dashmap = { version = "5.0.0", optional = true }
serde_json = { version = "1.0.78", optional = true }
lightningcss-derive = { version = "1.0.0-alpha.35", path = "./derive", optional = true }
schemars = { version = "*", features = ["smallvec"], optional = true }

[target.'cfg(target_os = "macos")'.dependencies]
jemallocator = { version = "0.3.2", features = ["disable_initial_exec_tls"], optional = true }
Expand Down
45 changes: 36 additions & 9 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use syn::{
GenericParam, Ident, Member, Token, Type,
};

#[proc_macro_derive(Visit, attributes(visit, skip_visit, skip_type))]
#[proc_macro_derive(Visit, attributes(visit, skip_visit, skip_type, visit_types))]
pub fn derive_visit_children(input: TokenStream) -> TokenStream {
let DeriveInput {
ident,
Expand Down Expand Up @@ -52,6 +52,14 @@ pub fn derive_visit_children(input: TokenStream) -> TokenStream {
None
};

let visit_types = if let Some(attr) = attrs.iter().find(|attr| attr.path.is_ident("visit_types")) {
let types: VisitTypes = attr.parse_args().unwrap();
let types = types.types;
Some(quote! { crate::visit_types!(#(#types)|*) })
} else {
None
};

let mut seen_types = HashSet::new();
let mut child_types = Vec::new();
let mut visit = Vec::new();
Expand All @@ -66,7 +74,7 @@ pub fn derive_visit_children(input: TokenStream) -> TokenStream {
continue;
}

if !seen_types.contains(ty) && !skip_type(attrs) {
if visit_types.is_none() && !seen_types.contains(ty) && !skip_type(attrs) {
seen_types.insert(ty.clone());
child_types.push(quote! {
<#ty as Visit<#lifetime, #t, #v>>::CHILD_TYPES.bits()
Expand Down Expand Up @@ -97,7 +105,8 @@ pub fn derive_visit_children(input: TokenStream) -> TokenStream {
continue;
}

if !seen_types.contains(ty) && !skip_type(attrs) && !skip_type(&variant.attrs) {
if visit_types.is_none() && !seen_types.contains(ty) && !skip_type(attrs) && !skip_type(&variant.attrs)
{
seen_types.insert(ty.clone());
child_types.push(quote! {
<#ty as Visit<#lifetime, #t, #v>>::CHILD_TYPES.bits()
Expand Down Expand Up @@ -137,7 +146,7 @@ pub fn derive_visit_children(input: TokenStream) -> TokenStream {
_ => {}
}

if child_types.is_empty() {
if visit_types.is_none() && child_types.is_empty() {
child_types.push(quote! { crate::visitor::VisitTypes::empty().bits() });
}

Expand All @@ -146,7 +155,7 @@ pub fn derive_visit_children(input: TokenStream) -> TokenStream {

quote! {
fn visit(&mut self, visitor: &mut #v) {
if #v::TYPES.contains(crate::visitor::VisitTypes::#kind) {
if visitor.visit_types().contains(crate::visitor::VisitTypes::#kind) {
visitor.#visit(self)
} else {
self.visit_children(visitor)
Expand All @@ -160,9 +169,11 @@ pub fn derive_visit_children(input: TokenStream) -> TokenStream {
let (_, ty_generics, _) = generics.split_for_impl();
let (impl_generics, _, where_clause) = impl_generics.split_for_impl();

let child_types = quote! {
unsafe { crate::visitor::VisitTypes::from_bits_unchecked(#(#child_types)|*) }
};
let child_types = visit_types.unwrap_or_else(|| {
quote! {
unsafe { crate::visitor::VisitTypes::from_bits_unchecked(#(#child_types)|*) }
}
});

let output = quote! {
impl #impl_generics Visit<#lifetime, #t, #v> for #ident #ty_generics #where_clause {
Expand All @@ -171,7 +182,7 @@ pub fn derive_visit_children(input: TokenStream) -> TokenStream {
#self_visit

fn visit_children(&mut self, visitor: &mut #v) {
if !<Self as Visit<#lifetime, #t, #v>>::CHILD_TYPES.intersects(#v::TYPES) {
if !<Self as Visit<#lifetime, #t, #v>>::CHILD_TYPES.intersects(visitor.visit_types()) {
return
}

Expand Down Expand Up @@ -200,3 +211,19 @@ impl Parse for VisitOptions {
Ok(Self { visit, kind })
}
}

struct VisitTypes {
types: Vec<Ident>,
}

impl Parse for VisitTypes {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let first: Ident = input.parse()?;
let mut types = vec![first];
while input.parse::<Token![|]>().is_ok() {
let id: Ident = input.parse()?;
types.push(id);
}
Ok(Self { types })
}
}
8 changes: 8 additions & 0 deletions examples/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn main() {
#[cfg(feature = "jsonschema")]
{
let schema = schemars::schema_for!(lightningcss::stylesheet::StyleSheet);
let output = serde_json::to_string_pretty(&schema).unwrap();
let _ = std::fs::write("node/ast.json", output);
}
}
4 changes: 3 additions & 1 deletion node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ crate-type = ["cdylib"]
serde = { version = "1.0.123", features = ["derive"] }
serde_bytes = "0.11.5"
cssparser = "0.29.1"
lightningcss = { path = "../", features = ["nodejs"] }
lightningcss = { path = "../", features = ["nodejs", "serde", "visitor"] }
parcel_sourcemap = { version = "2.1.1", features = ["json"] }
serde-detach = "*"
smallvec = { version = "1.7.0", features = ["union"] }

[target.'cfg(target_os = "macos")'.dependencies]
jemallocator = { version = "0.3.2", features = ["disable_initial_exec_tls"] }
Expand Down
Loading

0 comments on commit 0445926

Please sign in to comment.