diff --git a/Cargo.lock b/Cargo.lock index be91c15e833..b54f7c32d38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.53" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" +checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" [[package]] name = "arbitrary" @@ -643,6 +643,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "dashmap" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", + "parking_lot 0.12.0", +] + [[package]] name = "debug_unreachable" version = "0.1.1" @@ -1139,7 +1150,7 @@ name = "jsdoc" version = "0.60.0" dependencies = [ "anyhow", - "dashmap", + "dashmap 4.0.2", "nom 5.1.2", "serde", "swc_atoms", @@ -1917,7 +1928,7 @@ dependencies = [ "ahash", "anyhow", "browserslist-rs", - "dashmap", + "dashmap 4.0.2", "from_variant", "once_cell", "semver 1.0.4", @@ -2459,16 +2470,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_regex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" -dependencies = [ - "regex", - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.0" @@ -2702,7 +2703,7 @@ dependencies = [ "ahash", "anyhow", "base64 0.13.0", - "dashmap", + "dashmap 4.0.2", "either", "indexmap", "lru", @@ -2717,6 +2718,7 @@ dependencies = [ "serde_json", "sourcemap", "swc_atoms", + "swc_cached", "swc_common", "swc_ecma_ast", "swc_ecma_codegen", @@ -2757,7 +2759,7 @@ dependencies = [ "ahash", "anyhow", "crc", - "dashmap", + "dashmap 4.0.2", "hex", "indexmap", "is-macro", @@ -2794,6 +2796,19 @@ dependencies = [ "url", ] +[[package]] +name = "swc_cached" +version = "0.1.0" +dependencies = [ + "ahash", + "anyhow", + "dashmap 5.1.0", + "once_cell", + "regex", + "serde", + "swc_atoms", +] + [[package]] name = "swc_cli" version = "0.13.0" @@ -3040,7 +3055,7 @@ version = "0.19.1" dependencies = [ "ahash", "auto_impl", - "dashmap", + "dashmap 4.0.2", "parking_lot 0.12.0", "rayon", "regex", @@ -3062,15 +3077,15 @@ version = "0.28.0" dependencies = [ "ahash", "anyhow", - "dashmap", + "dashmap 4.0.2", "lru", "normpath", "once_cell", "parking_lot 0.12.0", "path-clean", - "regex", "serde", "serde_json", + "swc_cached", "swc_common", "tracing", ] @@ -3092,8 +3107,8 @@ dependencies = [ "retain_mut", "serde", "serde_json", - "serde_regex", "swc_atoms", + "swc_cached", "swc_common", "swc_ecma_ast", "swc_ecma_codegen", @@ -3139,7 +3154,7 @@ version = "0.98.0" dependencies = [ "ahash", "anyhow", - "dashmap", + "dashmap 4.0.2", "indexmap", "once_cell", "preset_env_base", @@ -3316,7 +3331,7 @@ name = "swc_ecma_transforms_optimization" version = "0.94.1" dependencies = [ "ahash", - "dashmap", + "dashmap 4.0.2", "indexmap", "once_cell", "rayon", @@ -3368,7 +3383,7 @@ version = "0.86.2" dependencies = [ "ahash", "base64 0.13.0", - "dashmap", + "dashmap 4.0.2", "indexmap", "once_cell", "regex", @@ -3563,7 +3578,7 @@ name = "swc_node_bundler" version = "0.0.0" dependencies = [ "anyhow", - "dashmap", + "dashmap 4.0.2", "is-macro", "once_cell", "pretty_assertions", @@ -3592,7 +3607,7 @@ name = "swc_node_comments" version = "0.4.0" dependencies = [ "ahash", - "dashmap", + "dashmap 4.0.2", "swc_common", ] diff --git a/crates/swc/Cargo.toml b/crates/swc/Cargo.toml index 32d7b501dc7..aadc403c2a5 100644 --- a/crates/swc/Cargo.toml +++ b/crates/swc/Cargo.toml @@ -40,12 +40,14 @@ either = "1" indexmap = {version = "1", features = ["serde"]} lru = "0.7.1" once_cell = "1.9.0" +parking_lot = "0.12.0" pathdiff = "0.2.0" regex = "1" serde = {version = "1", features = ["derive"]} serde_json = "1" sourcemap = "6" swc_atoms = {version = "0.2", path = "../swc_atoms"} +swc_cached = {version = "0.1.0", path = "../swc_cached"} swc_common = {version = "0.17.0", path = "../swc_common", features = ["sourcemap", "concurrent", "parking_lot"]} swc_ecma_ast = {version = "0.68.0", path = "../swc_ecma_ast"} swc_ecma_codegen = {version = "0.93.0", path = "../swc_ecma_codegen"} @@ -73,7 +75,6 @@ swc_node_comments = {version = "0.4.0", path = "../swc_node_comments"} swc_plugin_runner = {version = "0.38.0", path = "../swc_plugin_runner", optional = true} swc_visit = {version = "0.3.0", path = "../swc_visit"} tracing = "0.1.31" -parking_lot = "0.12.0" [dependencies.napi-derive] default-features = false diff --git a/crates/swc/src/config/mod.rs b/crates/swc/src/config/mod.rs index ca0281b377d..a453bbe05f7 100644 --- a/crates/swc/src/config/mod.rs +++ b/crates/swc/src/config/mod.rs @@ -9,17 +9,17 @@ use std::{ usize, }; -use anyhow::{bail, Context, Error}; +use anyhow::{bail, Error}; use dashmap::DashMap; use either::Either; use indexmap::IndexMap; use once_cell::sync::Lazy; -use regex::Regex; use serde::{ de::{Unexpected, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use swc_atoms::JsWord; +use swc_cached::regex::CachedRegex; pub use swc_common::chain; use swc_common::{ collections::{AHashMap, AHashSet}, @@ -891,34 +891,23 @@ impl Config { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum FileMatcher { - Regex(String), + None, + Regex(CachedRegex), Multi(Vec), } impl Default for FileMatcher { fn default() -> Self { - Self::Regex(String::from("")) + Self::None } } impl FileMatcher { pub fn matches(&self, filename: &Path) -> Result { - static CACHE: Lazy> = - Lazy::new(Default::default); - match self { - FileMatcher::Regex(ref s) => { - if s.is_empty() { - return Ok(false); - } - - if !CACHE.contains_key(&*s) { - let re = Regex::new(s).with_context(|| format!("invalid regex: {}", s))?; - CACHE.insert(s.clone(), re); - } - - let re = CACHE.get(&*s).unwrap(); + FileMatcher::None => Ok(false), + FileMatcher::Regex(re) => { let filename = if cfg!(target_os = "windows") { filename.to_string_lossy().replace('\\', "/") } else { diff --git a/crates/swc_cached/Cargo.toml b/crates/swc_cached/Cargo.toml new file mode 100644 index 00000000000..8b6b35391fd --- /dev/null +++ b/crates/swc_cached/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["강동윤 "] +description = "Cached types for swc" +documentation = "https://rustdoc.swc.rs/swc_cached/" +edition = "2021" +include = ["Cargo.toml", "src/**/*.rs"] +license = "Apache-2.0" +name = "swc_cached" +repository = "https://github.com/swc-project/swc.git" +version = "0.1.0" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ahash = "0.7.6" +anyhow = "1.0.55" +dashmap = "5.1.0" +once_cell = "1.9.0" +regex = "1.5.4" +serde = "1.0.136" +swc_atoms = {version = "0.2.9", path = "../swc_atoms"} diff --git a/crates/swc_cached/src/lib.rs b/crates/swc_cached/src/lib.rs new file mode 100644 index 00000000000..8b3e7759993 --- /dev/null +++ b/crates/swc_cached/src/lib.rs @@ -0,0 +1,3 @@ +#![deny(warnings)] + +pub mod regex; diff --git a/crates/swc_cached/src/regex.rs b/crates/swc_cached/src/regex.rs new file mode 100644 index 00000000000..cb460f01ac1 --- /dev/null +++ b/crates/swc_cached/src/regex.rs @@ -0,0 +1,72 @@ +use std::{ops::Deref, sync::Arc}; + +use anyhow::{Context, Result}; +use dashmap::DashMap; +use once_cell::sync::Lazy; +use regex::Regex; +use serde::{de::Error, Deserialize, Serialize}; + +/// A regex which can be used as a configuration. +/// +/// While deserializing, this will be converted to a string and cached based on +/// the pattern. +#[derive(Debug, Clone)] +pub struct CachedRegex { + regex: Arc, +} + +impl Deref for CachedRegex { + type Target = Regex; + + fn deref(&self) -> &Self::Target { + &self.regex + } +} + +impl CachedRegex { + pub fn new(input: &str) -> Result { + static CACHE: Lazy, ahash::RandomState>> = + Lazy::new(Default::default); + + if let Some(cache) = CACHE.get(input).as_deref().cloned() { + return Ok(Self { regex: cache }); + } + + let regex = + Regex::new(input).with_context(|| format!("failed to parse `{}` as regex", input))?; + let regex = Arc::new(regex); + + CACHE.insert(input.to_owned(), regex.clone()); + + Ok(CachedRegex { regex }) + } +} + +impl<'de> Deserialize<'de> for CachedRegex { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + + Self::new(&s).map_err(|err| D::Error::custom(err.to_string())) + } +} + +impl Serialize for CachedRegex { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let s = self.regex.as_str(); + + serializer.serialize_str(s) + } +} + +/// This will panic for wrong patterns. +impl From<&'_ str> for CachedRegex { + fn from(s: &'_ str) -> Self { + Self::new(s).unwrap() + } +} diff --git a/crates/swc_ecma_loader/Cargo.toml b/crates/swc_ecma_loader/Cargo.toml index c0af300885e..5b144eb3238 100644 --- a/crates/swc_ecma_loader/Cargo.toml +++ b/crates/swc_ecma_loader/Cargo.toml @@ -19,7 +19,7 @@ cache = ["lru", "parking_lot"] # Enable node js resolver node = ["normpath", "serde_json", "dashmap", "once_cell", "path-clean"] # Enable support for `paths` of tsconfig.json -tsc = ["dashmap", "once_cell", "regex"] +tsc = ["dashmap", "once_cell", "swc_cached"] [dependencies] ahash = "0.7.4" @@ -29,9 +29,9 @@ lru = {version = "0.7.1", optional = true} once_cell = {version = "1.9.0", optional = true} parking_lot = {version = "0.12.0", optional = true} path-clean = {version = "=0.1.0", optional = true} -regex = {version = "1", optional = true} serde = {version = "1", features = ["derive"]} serde_json = {version = "1.0.64", optional = true} +swc_cached = {version = "0.1.0", optional = true, path = "../swc_cached"} swc_common = {version = "0.17.0", path = "../swc_common"} tracing = "0.1.31" diff --git a/crates/swc_ecma_loader/src/resolvers/tsc.rs b/crates/swc_ecma_loader/src/resolvers/tsc.rs index ff9c71fcb6d..277ee96c1f5 100644 --- a/crates/swc_ecma_loader/src/resolvers/tsc.rs +++ b/crates/swc_ecma_loader/src/resolvers/tsc.rs @@ -1,16 +1,14 @@ use std::path::{Component, PathBuf}; use anyhow::{bail, Context, Error}; -use dashmap::DashMap; -use once_cell::sync::Lazy; -use regex::Regex; +use swc_cached::regex::CachedRegex; use swc_common::FileName; use crate::resolve::Resolve; #[derive(Debug)] enum Pattern { - Regex(Regex), + Regex(CachedRegex), /// No wildcard. Exact(String), } @@ -193,19 +191,6 @@ where } } -fn compile_regex(src: String) -> Regex { - static CACHE: Lazy> = Lazy::new(Default::default); - - if !CACHE.contains_key(&*src) { - // Create capture group - let regex_pat = src.replace('*', "(.*)"); - let re = Regex::new(®ex_pat).unwrap_or_else(|err| { - panic!("failed to compile `{}` as a pattern: {:?}", regex_pat, err) - }); - CACHE.insert(src.clone(), re); - } - - let re = CACHE.get(&*src).unwrap(); - - (*re).clone() +fn compile_regex(src: String) -> CachedRegex { + CachedRegex::new(&src.replace('*', "(.*)")).unwrap() } diff --git a/crates/swc_ecma_minifier/Cargo.toml b/crates/swc_ecma_minifier/Cargo.toml index 059ae2b92d2..8fccca3b755 100644 --- a/crates/swc_ecma_minifier/Cargo.toml +++ b/crates/swc_ecma_minifier/Cargo.toml @@ -28,8 +28,8 @@ regex = "1.5.3" retain_mut = "0.1.2" serde = {version = "1.0.118", features = ["derive"]} serde_json = "1.0.61" -serde_regex = "1.1.0" swc_atoms = {version = "0.2", path = "../swc_atoms"} +swc_cached = {version = "0.1.0", path = "../swc_cached"} swc_common = {version = "0.17.0", path = "../swc_common"} swc_ecma_ast = {version = "0.68.0", path = "../swc_ecma_ast"} swc_ecma_codegen = {version = "0.93.0", path = "../swc_ecma_codegen"} diff --git a/crates/swc_ecma_minifier/src/option/mod.rs b/crates/swc_ecma_minifier/src/option/mod.rs index fbfe566c6e3..b2633619f60 100644 --- a/crates/swc_ecma_minifier/src/option/mod.rs +++ b/crates/swc_ecma_minifier/src/option/mod.rs @@ -1,6 +1,6 @@ -use regex::Regex; use serde::{Deserialize, Serialize}; use swc_atoms::JsWord; +use swc_cached::regex::CachedRegex; use swc_common::{collections::AHashMap, Mark}; use swc_ecma_ast::{EsVersion, Expr}; @@ -72,8 +72,8 @@ pub struct ManglePropertiesOptions { pub reserved: Vec, #[serde(default, alias = "undeclared")] pub undeclared: bool, - #[serde(default, with = "serde_regex")] - pub regex: Option, + #[serde(default)] + pub regex: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/crates/swc_stylis/tests/prefixer.rs b/crates/swc_stylis/tests/prefixer.rs index 52c7f14fadc..7dba239d3cc 100644 --- a/crates/swc_stylis/tests/prefixer.rs +++ b/crates/swc_stylis/tests/prefixer.rs @@ -2,15 +2,13 @@ //! //! License is MIT, which is original license at the time of copying. //! Original test authors have copyright for their work. +#![deny(warnings)] #![allow(clippy::needless_update)] use std::path::PathBuf; use swc_common::{FileName, DUMMY_SP}; -use swc_css_ast::{ - ComponentValue, DeclarationOrAtRule, QualifiedRule, SimpleBlock, Stylesheet, Token, - TokenAndSpan, -}; +use swc_css_ast::{ComponentValue, DeclarationOrAtRule, QualifiedRule, SimpleBlock, Stylesheet}; use swc_css_codegen::{ writer::basic::{BasicCssWriter, BasicCssWriterConfig}, CodegenConfig, Emit, @@ -537,10 +535,10 @@ fn t(src: &str, expected: &str) { wr.push_str(&s); - let need_semi = match p { - ComponentValue::DeclarationOrAtRule(DeclarationOrAtRule::Invalid(_)) => false, - _ => true, - }; + let need_semi = !matches!( + p, + ComponentValue::DeclarationOrAtRule(DeclarationOrAtRule::Invalid(_)) + ); if need_semi { wr.push(';');