From 0dd215fb10e69e2abf6ecc53813b7dffb93e6e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=B2=E5=B0=98?= Date: Mon, 30 Oct 2023 16:34:33 +0800 Subject: [PATCH 01/10] feat: support built-in loader of compilation --- crates/loader_compilation/src/lib.rs | 57 ++++++++++++++++-- crates/loader_compilation/src/options.rs | 0 .../loader_compilation/src/transform/mod.rs | 60 +++++++++++++++++++ 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 crates/loader_compilation/src/options.rs create mode 100644 crates/loader_compilation/src/transform/mod.rs diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index 34570bc..4f61f07 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -1,10 +1,21 @@ +use std::sync::Arc; use rspack_core::{rspack_sources::SourceMap, LoaderRunnerContext, Mode}; use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; use rspack_error::{ internal_error, Diagnostic, DiagnosticKind, Error, InternalError, Result, Severity, TraceableError, }; - +use swc_core::{ + base::{ + Compiler, + config::{InputSourceMap, Options}, + try_with_handler + }, + common::{FilePathMapping,GLOBALS, FileName, comments::SingleThreadedComments}, + ecma::transforms::base::pass::noop +}; +mod transform; +use transform::*; pub struct CompilationLoader { identifier: Identifier, } @@ -28,14 +39,48 @@ impl CompilationLoader { #[async_trait::async_trait] impl Loader for CompilationLoader { async fn run(&self, loader_context: &mut LoaderContext<'_, LoaderRunnerContext>) -> Result<()> { + let resource_path = loader_context.resource_path.to_path_buf(); let Some(content) = std::mem::take(&mut loader_context.content) else { return Err(internal_error!("No content found")); }; - let mut source = content.try_into_string()?; - source += r#" -window.__custom_code__ = true; -"#; - loader_context.content = Some(source.into()); + + let compiler = Compiler::new(Arc::from(swc_core::common::SourceMap::new(FilePathMapping::empty()))); + // TODO: init loader with custom options. + let mut swc_options = Options::default(); + + // TODO: merge config with built-in config. + + if let Some(pre_source_map) = std::mem::take(&mut loader_context.source_map) { + if let Ok(source_map) = pre_source_map.to_json() { + swc_options.config.input_source_map = Some(InputSourceMap:: Str(source_map)) + } + } + + GLOBALS.set(&Default::default(), || { + try_with_handler(compiler.cm.clone(), Default::default(), |handler| { + compiler.run(|| { + let content = content.try_into_string()?; + let fm = compiler.cm.new_source_file(FileName::Real(resource_path.clone()), content.clone()); + let comments = SingleThreadedComments::default(); + let transform_options = SwcPluginOptions { + keep_export: None, + remove_export: None, + }; + let out = compiler.process_js_with_custom_pass( + fm, + None, + handler, + &swc_options, + comments, |_| { + transform(transform_options) + }, + |_| noop(), + )?; + Ok(()) + }) + }) + })?; + Ok(()) } } diff --git a/crates/loader_compilation/src/options.rs b/crates/loader_compilation/src/options.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/loader_compilation/src/transform/mod.rs b/crates/loader_compilation/src/transform/mod.rs new file mode 100644 index 0000000..e0e15f8 --- /dev/null +++ b/crates/loader_compilation/src/transform/mod.rs @@ -0,0 +1,60 @@ +use either::Either; +use swc_core::common::chain; +use swc_core::ecma::{ + transforms::base::pass::noop, + visit::{as_folder, Fold, VisitMut}, + ast::Module, +}; + +macro_rules! either { + ($config:expr, $f:expr) => { + if let Some(config) = &$config { + Either::Left($f(config)) + } else { + Either::Right(noop()) + } + }; + ($config:expr, $f:expr, $enabled:expr) => { + if $enabled { + either!($config, $f) + } else { + Either::Right(noop()) + } + }; +} + +pub struct KeepExportOptions { + export_names: Vec, +} + +pub struct RemoveExport { + remove_names: Vec, +} + +pub struct SwcPluginOptions { + pub keep_export: Option, + pub remove_export: Option, +} + +pub(crate) fn transform<'a>(plugin_options: SwcPluginOptions) -> impl Fold + 'a { + chain!( + either!(plugin_options.keep_export, |_| { + keep_export() + }), + either!(plugin_options.remove_export, |_| { + keep_export() + }), + ) +} + +struct KeepExport; + +impl VisitMut for KeepExport { + fn visit_mut_module(&mut self, module: &mut Module) { + + } +} + +fn keep_export() -> impl Fold { + as_folder(KeepExport) +} \ No newline at end of file From 1cf0af4fc76a4c08d0f6f12d493761c36c2b8b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=B2=E5=B0=98?= Date: Mon, 30 Oct 2023 17:47:07 +0800 Subject: [PATCH 02/10] fix: bump rspack_core version --- Cargo.toml | 73 +- .../binding_options/src/options/js_loader.rs | 28 +- crates/binding_options/src/options/mod.rs | 6 +- crates/node_binding/src/lib.rs | 1 - crates/node_binding/src/loader.rs | 3 +- pnpm-lock.yaml | 1071 +++-------------- scripts/clone-rspack.mjs | 2 +- 7 files changed, 229 insertions(+), 955 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e8df955..3930002 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,30 +9,21 @@ members = [ resolver = "2" [workspace.dependencies] -anyhow = { version = "1.0.75" } -async-trait = { version = "0.1.71" } -better_scoped_tls = { version = "0.1.1" } -derivative = { version = "2.2.0" } -glob = { version = "0.3.1" } -# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix -napi = "2.12.2" -napi-derive = "2.12.2" -napi-build = "2.0.1" -rustc-hash = { version = "1.1.0" } -serde = { version = "1.0.171" } -serde_json = { version = "1.0.100" } -tokio = { version = "1.29.1" } -tracing = { version = "0.1.37" } +anyhow = { version = "1.0.71", features = ["backtrace"] } async-recursion = { version = "1.0.4" } async-scoped = { version = "0.7.1" } +async-trait = { version = "0.1.71" } backtrace = "0.3" +better_scoped_tls = { version = "0.1.1" } bitflags = { version = "1.3.2" } colored = { version = "2.0.4" } concat-string = "1.0.1" dashmap = { version = "5.5.0" } +derivative = { version = "2.2.0" } derive_builder = { version = "0.11.2" } futures = { version = "0.3.28" } futures-util = { version = "0.3.28" } +glob = { version = "0.3.1" } hashlink = { version = "0.8.3" } indexmap = { version = "1.9.3" } insta = { version = "1.30.0" } @@ -43,49 +34,59 @@ mimalloc-rust = { version = "0.2" } mime_guess = { version = "2.0.4" } once_cell = { version = "1.18.0" } paste = { version = "1.0" } +path-clean = { version = "1.0.1" } pathdiff = { version = "0.2.1" } preset_env_base = { version = "0.4.5" } rayon = { version = "1.7.0" } regex = { version = "1.9.1" } rkyv = { version = "0.7.42" } rspack_sources = { version = "0.2.7" } +rustc-hash = { version = "1.1.0" } schemars = { version = "0.8.12" } +serde = { version = "1.0.171" } +serde_json = { version = "1.0.100" } similar = { version = "2.2.1" } sugar_path = { version = "0.0.12" } testing_macros = { version = "0.2.11" } +tokio = { version = "1.29.1" } +tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.17" } url = { version = "2.4.0" } urlencoding = { version = "2.1.2" } ustr = { version = "0.9.0" } xxhash-rust = { version = "0.8.6" } +# Pinned +napi = { version = "=2.13.3" } +napi-build = { version = "=2.0.1" } +napi-derive = { version = "=2.13.0" } napi-sys = { version = "=2.2.3" } -styled_components = { version = "=0.72.0" } +styled_components = { version = "0.77.0" } swc_config = { version = "=0.1.7" } -swc_core = { version = "=0.83.1", default-features = false } -swc_css = { version = "=0.155.2" } -swc_ecma_minifier = { version = "=0.187.0", default-features = false } -swc_emotion = { version = "=0.42.0" } -swc_error_reporters = { version = "=0.16.1" } -swc_html = { version = "=0.131.0" } -swc_html_minifier = { version = "=0.128.0" } -swc_node_comments = { version = "=0.19.1" } +swc_core = { version = "0.86.9", default-features = false } +swc_css = { version = "0.157.1" } +swc_ecma_minifier = { version = "0.189.9", default-features = false } +swc_emotion = { version = "=0.53.0" } +swc_error_reporters = { version = "=0.17.0" } +swc_html = { version = "=0.134.10" } +swc_html_minifier = { version = "=0.131.9" } +swc_node_comments = { version = "=0.20.0" } tikv-jemallocator = { version = "=0.5.4", features = ["disable_initial_exec_tls"] } [patch.crates-io] -swc_config = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_core = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_ecma_minifier = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_error_reporters = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_html = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_html_minifier = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_node_comments = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_common = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_ecma_utils = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_ecma_ast = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_ecma_visit = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -swc_atoms = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } -preset_env_base = { git = "https://github.com/swc-project/swc.git", rev = "5c00525" } +swc_config = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_core = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_ecma_minifier = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_error_reporters = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_html = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_html_minifier = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_node_comments = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_common = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_ecma_utils = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_ecma_ast = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_ecma_visit = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +swc_atoms = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } +preset_env_base = { git = "https://github.com/swc-project/swc.git", rev = "4a1a233" } [profile.dev] debug = 2 diff --git a/crates/binding_options/src/options/js_loader.rs b/crates/binding_options/src/options/js_loader.rs index 98ee634..ae36171 100644 --- a/crates/binding_options/src/options/js_loader.rs +++ b/crates/binding_options/src/options/js_loader.rs @@ -21,6 +21,16 @@ pub async fn run_builtin_loader( let loader = get_builtin_loader(&builtin, options); let loader_item = loader.clone().into(); let list = &[loader_item]; + let additional_data = { + let mut additional_data = loader_context.additional_data_external.clone(); + if let Some(data) = loader_context + .additional_data + .map(|b| String::from_utf8_lossy(b.as_ref()).to_string()) + { + additional_data.insert(data); + } + additional_data + }; let mut cx = LoaderContext { content: loader_context @@ -30,15 +40,13 @@ pub async fn run_builtin_loader( resource_path: Path::new(&loader_context.resource_path), resource_query: loader_context.resource_query.as_deref(), resource_fragment: loader_context.resource_fragment.as_deref(), - context: loader_context.context.clone(), + context: loader_context.context_external.clone(), source_map: loader_context .source_map .map(|s| SourceMap::from_slice(s.as_ref())) .transpose() .map_err(|e| Error::from_reason(e.to_string()))?, - additional_data: loader_context - .additional_data - .map(|b| String::from_utf8_lossy(b.as_ref()).to_string()), + additional_data, cacheable: loader_context.cacheable, file_dependencies: HashSet::from_iter( loader_context @@ -69,21 +77,21 @@ pub async fn run_builtin_loader( __diagnostics: vec![], __resource_data: &ResourceData::new(Default::default(), Default::default()), __loader_items: LoaderItemList(list), - __loader_index: 0, + // This is used an hack to `builtin:swc-loader` in order to determine whether to return AST or source. + __loader_index: loader_context.loader_index_from_js.unwrap_or(0) as usize, __plugins: &[], }; if loader_context.is_pitching { - // Run pitching loader - loader - .pitch(&mut cx) - .await - .map_err(|e| Error::from_reason(e.to_string()))?; + // Builtin loaders dispatched using JS loader-runner does not support pitching. + // This phase is ignored. } else { // Run normal loader loader .run(&mut cx) .await .map_err(|e| Error::from_reason(e.to_string()))?; + // restore the hack + cx.__loader_index = 0; } JsLoaderContext::try_from(&cx).map_err(|e| Error::from_reason(e.to_string())) diff --git a/crates/binding_options/src/options/mod.rs b/crates/binding_options/src/options/mod.rs index 786396a..414bb5a 100644 --- a/crates/binding_options/src/options/mod.rs +++ b/crates/binding_options/src/options/mod.rs @@ -9,7 +9,7 @@ use rspack_binding_options::{ RawMode, RawNodeOption, RawOptimizationOptions, RawOutputOptions, RawResolveOptions, RawSnapshotOptions, RawStatsOptions, RawTarget, RawOptionsApply, RawModuleOptions, }; -use rspack_plugin_javascript::{FlagDependencyExportsPlugin, FlagDependencyUsagePlugin}; +use rspack_plugin_javascript::{FlagDependencyExportsPlugin, FlagDependencyUsagePlugin, SideEffectsFlagPlugin}; use serde::Deserialize; mod raw_module; @@ -72,6 +72,7 @@ impl RawOptionsApply for RSPackRawOptions { }, async_web_assembly: self.experiments.async_web_assembly, new_split_chunks: self.experiments.new_split_chunks, + top_level_await: self.experiments.top_level_await, rspack_future: self.experiments.rspack_future.into(), }; let optimization = IS_ENABLE_NEW_SPLIT_CHUNKS.set(&experiments.new_split_chunks, || { @@ -128,6 +129,9 @@ impl RawOptionsApply for RSPackRawOptions { plugins.push(rspack_ids::NamedChunkIdsPlugin::new(None, None).boxed()); if experiments.rspack_future.new_treeshaking { + if optimization.side_effects.is_enable() { + plugins.push(SideEffectsFlagPlugin::default().boxed()); + } if optimization.provided_exports { plugins.push(FlagDependencyExportsPlugin::default().boxed()); } diff --git a/crates/node_binding/src/lib.rs b/crates/node_binding/src/lib.rs index b3c9180..262a360 100644 --- a/crates/node_binding/src/lib.rs +++ b/crates/node_binding/src/lib.rs @@ -27,7 +27,6 @@ mod utils; use hook::*; use js_values::*; - // Napi macro registered this successfully #[allow(unused)] use loader::*; diff --git a/crates/node_binding/src/loader.rs b/crates/node_binding/src/loader.rs index 03eb3b9..cc28833 100644 --- a/crates/node_binding/src/loader.rs +++ b/crates/node_binding/src/loader.rs @@ -1,6 +1,5 @@ use napi::Result; use rspack_binding_options::JsLoaderContext; -use binding_options::run_builtin_loader as run_builtin; /// Builtin loader runner #[napi(catch_unwind)] @@ -10,5 +9,5 @@ pub async fn run_builtin_loader( options: Option, loader_context: JsLoaderContext, ) -> Result { - run_builtin(builtin, options.as_deref(), loader_context).await + binding_options::run_builtin_loader(builtin, options.as_deref(), loader_context).await } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2786b92..eccca0c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,55 +1,61 @@ -lockfileVersion: 5.4 +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false importers: .: - specifiers: - fs-extra: ^11.1.1 - git-clone: 0.2.0 - ora: ^7.0.1 - rimraf: ^5.0.5 devDependencies: - fs-extra: 11.1.1 - git-clone: 0.2.0 - ora: 7.0.1 - rimraf: 5.0.5 + fs-extra: + specifier: ^11.1.1 + version: 11.1.1 + git-clone: + specifier: 0.2.0 + version: 0.2.0 + ora: + specifier: ^7.0.1 + version: 7.0.1 + rimraf: + specifier: ^5.0.5 + version: 5.0.5 crates/node_binding: - specifiers: - '@napi-rs/cli': 3.0.0-alpha.3 - ava: ^5.1.1 - call-bind: 1.0.2 devDependencies: - '@napi-rs/cli': 3.0.0-alpha.3 - ava: 5.3.1 - call-bind: 1.0.2 + '@napi-rs/cli': + specifier: 3.0.0-alpha.3 + version: 3.0.0-alpha.3 + call-bind: + specifier: 1.0.2 + version: 1.0.2 packages: - /@isaacs/cliui/8.0.2: + /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} dependencies: string-width: 5.1.2 - string-width-cjs: /string-width/4.2.3 + string-width-cjs: /string-width@4.2.3 strip-ansi: 7.1.0 - strip-ansi-cjs: /strip-ansi/6.0.1 + strip-ansi-cjs: /strip-ansi@6.0.1 wrap-ansi: 8.1.0 - wrap-ansi-cjs: /wrap-ansi/7.0.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true - /@ljharb/through/2.3.10: + /@ljharb/through@2.3.10: resolution: {integrity: sha512-NwkQ4+jf4tMpDSlRc1wlttHnC7KfII+SjdqDEwEuQ7W0IaTK5Ab1jxCJrH6pYsLbLXiQgRn+nFQsGmKowbAKkA==} engines: {node: '>= 0.4'} dev: true - /@napi-rs/cli/3.0.0-alpha.3: + /@napi-rs/cli@3.0.0-alpha.3: resolution: {integrity: sha512-s5RHKqbqUVVfwgr/wO7S/vdqQ9shQzvIETgdz57r1Gg4bRv8kqy2Q1LfJAQJ09Y9Ddao9jKErvz4+11gHZZrWA==} engines: {node: '>= 16'} hasBin: true dependencies: '@octokit/rest': 19.0.13 - clipanion: 3.2.1 + clipanion: 3.2.1(typanion@3.14.0) colorette: 2.0.20 debug: 4.3.4 inquirer: 9.2.11 @@ -61,33 +67,12 @@ packages: - supports-color dev: true - /@nodelib/fs.scandir/2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat/2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk/1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 - dev: true - - /@octokit/auth-token/3.0.4: + /@octokit/auth-token@3.0.4: resolution: {integrity: sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==} engines: {node: '>= 14'} dev: true - /@octokit/core/4.2.4: + /@octokit/core@4.2.4: resolution: {integrity: sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==} engines: {node: '>= 14'} dependencies: @@ -102,7 +87,7 @@ packages: - encoding dev: true - /@octokit/endpoint/7.0.6: + /@octokit/endpoint@7.0.6: resolution: {integrity: sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==} engines: {node: '>= 14'} dependencies: @@ -111,7 +96,7 @@ packages: universal-user-agent: 6.0.0 dev: true - /@octokit/graphql/5.0.6: + /@octokit/graphql@5.0.6: resolution: {integrity: sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==} engines: {node: '>= 14'} dependencies: @@ -122,11 +107,11 @@ packages: - encoding dev: true - /@octokit/openapi-types/18.1.1: + /@octokit/openapi-types@18.1.1: resolution: {integrity: sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw==} dev: true - /@octokit/plugin-paginate-rest/6.1.2_@octokit+core@4.2.4: + /@octokit/plugin-paginate-rest@6.1.2(@octokit/core@4.2.4): resolution: {integrity: sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==} engines: {node: '>= 14'} peerDependencies: @@ -137,7 +122,7 @@ packages: '@octokit/types': 9.3.2 dev: true - /@octokit/plugin-request-log/1.0.4_@octokit+core@4.2.4: + /@octokit/plugin-request-log@1.0.4(@octokit/core@4.2.4): resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==} peerDependencies: '@octokit/core': '>=3' @@ -145,7 +130,7 @@ packages: '@octokit/core': 4.2.4 dev: true - /@octokit/plugin-rest-endpoint-methods/7.2.3_@octokit+core@4.2.4: + /@octokit/plugin-rest-endpoint-methods@7.2.3(@octokit/core@4.2.4): resolution: {integrity: sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==} engines: {node: '>= 14'} peerDependencies: @@ -155,7 +140,7 @@ packages: '@octokit/types': 10.0.0 dev: true - /@octokit/request-error/3.0.3: + /@octokit/request-error@3.0.3: resolution: {integrity: sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==} engines: {node: '>= 14'} dependencies: @@ -164,7 +149,7 @@ packages: once: 1.4.0 dev: true - /@octokit/request/6.2.8: + /@octokit/request@6.2.8: resolution: {integrity: sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==} engines: {node: '>= 14'} dependencies: @@ -178,197 +163,87 @@ packages: - encoding dev: true - /@octokit/rest/19.0.13: + /@octokit/rest@19.0.13: resolution: {integrity: sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==} engines: {node: '>= 14'} dependencies: '@octokit/core': 4.2.4 - '@octokit/plugin-paginate-rest': 6.1.2_@octokit+core@4.2.4 - '@octokit/plugin-request-log': 1.0.4_@octokit+core@4.2.4 - '@octokit/plugin-rest-endpoint-methods': 7.2.3_@octokit+core@4.2.4 + '@octokit/plugin-paginate-rest': 6.1.2(@octokit/core@4.2.4) + '@octokit/plugin-request-log': 1.0.4(@octokit/core@4.2.4) + '@octokit/plugin-rest-endpoint-methods': 7.2.3(@octokit/core@4.2.4) transitivePeerDependencies: - encoding dev: true - /@octokit/tsconfig/1.0.2: + /@octokit/tsconfig@1.0.2: resolution: {integrity: sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==} dev: true - /@octokit/types/10.0.0: + /@octokit/types@10.0.0: resolution: {integrity: sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==} dependencies: '@octokit/openapi-types': 18.1.1 dev: true - /@octokit/types/9.3.2: + /@octokit/types@9.3.2: resolution: {integrity: sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==} dependencies: '@octokit/openapi-types': 18.1.1 dev: true - /@pkgjs/parseargs/0.11.0: + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} requiresBuild: true dev: true optional: true - /acorn-walk/8.2.0: - resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn/8.10.0: - resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /aggregate-error/4.0.1: - resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} - engines: {node: '>=12'} - dependencies: - clean-stack: 4.2.0 - indent-string: 5.0.0 - dev: true - - /ansi-escapes/4.3.2: + /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} dependencies: type-fest: 0.21.3 dev: true - /ansi-regex/5.0.1: + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} dev: true - /ansi-regex/6.0.1: + /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} dev: true - /ansi-styles/4.3.0: + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 dev: true - /ansi-styles/6.2.1: + /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} dev: true - /anymatch/3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - - /argparse/1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - - /argparse/2.0.1: + /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /array-find-index/1.0.2: - resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} - engines: {node: '>=0.10.0'} - dev: true - - /arrgv/1.0.2: - resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} - engines: {node: '>=8.0.0'} - dev: true - - /arrify/3.0.0: - resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} - engines: {node: '>=12'} - dev: true - - /ava/5.3.1: - resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} - engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} - hasBin: true - peerDependencies: - '@ava/typescript': '*' - peerDependenciesMeta: - '@ava/typescript': - optional: true - dependencies: - acorn: 8.10.0 - acorn-walk: 8.2.0 - ansi-styles: 6.2.1 - arrgv: 1.0.2 - arrify: 3.0.0 - callsites: 4.1.0 - cbor: 8.1.0 - chalk: 5.3.0 - chokidar: 3.5.3 - chunkd: 2.0.1 - ci-info: 3.9.0 - ci-parallel-vars: 1.0.1 - clean-yaml-object: 0.1.0 - cli-truncate: 3.1.0 - code-excerpt: 4.0.0 - common-path-prefix: 3.0.0 - concordance: 5.0.4 - currently-unhandled: 0.4.1 - debug: 4.3.4 - emittery: 1.0.1 - figures: 5.0.0 - globby: 13.2.2 - ignore-by-default: 2.1.0 - indent-string: 5.0.0 - is-error: 2.2.2 - is-plain-object: 5.0.0 - is-promise: 4.0.0 - matcher: 5.0.0 - mem: 9.0.2 - ms: 2.1.3 - p-event: 5.0.1 - p-map: 5.5.0 - picomatch: 2.3.1 - pkg-conf: 4.0.0 - plur: 5.1.0 - pretty-ms: 8.0.0 - resolve-cwd: 3.0.0 - stack-utils: 2.0.6 - strip-ansi: 7.1.0 - supertap: 3.0.1 - temp-dir: 3.0.0 - write-file-atomic: 5.0.1 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - dev: true - - /balanced-match/1.0.2: + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /base64-js/1.5.1: + /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true - /before-after-hook/2.2.3: + /before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} dev: true - /binary-extensions/2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true - - /bl/4.1.0: + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: buffer: 5.7.1 @@ -376,7 +251,7 @@ packages: readable-stream: 3.6.2 dev: true - /bl/5.1.0: + /bl@5.1.0: resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} dependencies: buffer: 6.0.3 @@ -384,57 +259,34 @@ packages: readable-stream: 3.6.2 dev: true - /blueimp-md5/2.19.0: - resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} - dev: true - - /brace-expansion/2.0.1: + /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 dev: true - /braces/3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /buffer/5.7.1: + /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 dev: true - /buffer/6.0.3: + /buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 dev: true - /call-bind/1.0.2: + /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: function-bind: 1.1.1 get-intrinsic: 1.2.1 dev: true - /callsites/4.1.0: - resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} - engines: {node: '>=12.20'} - dev: true - - /cbor/8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} - dependencies: - nofilter: 3.1.0 - dev: true - - /chalk/4.1.2: + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} dependencies: @@ -442,153 +294,68 @@ packages: supports-color: 7.2.0 dev: true - /chalk/5.3.0: + /chalk@5.3.0: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true - /chardet/0.7.0: + /chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true - /chokidar/3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /chunkd/2.0.1: - resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} - dev: true - - /ci-info/3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - dev: true - - /ci-parallel-vars/1.0.1: - resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} - dev: true - - /clean-stack/4.2.0: - resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} - engines: {node: '>=12'} - dependencies: - escape-string-regexp: 5.0.0 - dev: true - - /clean-yaml-object/0.1.0: - resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} - engines: {node: '>=0.10.0'} - dev: true - - /cli-cursor/3.1.0: + /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} dependencies: restore-cursor: 3.1.0 dev: true - /cli-cursor/4.0.0: + /cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: restore-cursor: 4.0.0 dev: true - /cli-spinners/2.9.1: + /cli-spinners@2.9.1: resolution: {integrity: sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==} engines: {node: '>=6'} dev: true - /cli-truncate/3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - slice-ansi: 5.0.0 - string-width: 5.1.2 - dev: true - - /cli-width/4.1.0: + /cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} dev: true - /clipanion/3.2.1: + /clipanion@3.2.1(typanion@3.14.0): resolution: {integrity: sha512-dYFdjLb7y1ajfxQopN05mylEpK9ZX0sO1/RfMXdfmwjlIsPkbh4p7A682x++zFPLDCo1x3p82dtljHf5cW2LKA==} + peerDependencies: + typanion: '*' dependencies: typanion: 3.14.0 dev: true - /cliui/8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /clone/1.0.4: + /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} dev: true - /code-excerpt/4.0.0: - resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - convert-to-spaces: 2.0.1 - dev: true - - /color-convert/2.0.1: + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 dev: true - /color-name/1.1.4: + /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true - /colorette/2.0.20: + /colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} dev: true - /common-path-prefix/3.0.0: - resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} - dev: true - - /concordance/5.0.4: - resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} - engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} - dependencies: - date-time: 3.1.0 - esutils: 2.0.3 - fast-diff: 1.3.0 - js-string-escape: 1.0.1 - lodash: 4.17.21 - md5-hex: 3.0.1 - semver: 7.5.4 - well-known-symbols: 2.0.0 - dev: true - - /convert-to-spaces/2.0.1: - resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - - /cross-spawn/7.0.3: + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} dependencies: @@ -597,21 +364,7 @@ packages: which: 2.0.2 dev: true - /currently-unhandled/0.4.1: - resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} - engines: {node: '>=0.10.0'} - dependencies: - array-find-index: 1.0.2 - dev: true - - /date-time/3.1.0: - resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} - engines: {node: '>=6'} - dependencies: - time-zone: 1.0.0 - dev: true - - /debug/4.3.4: + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: @@ -623,71 +376,38 @@ packages: ms: 2.1.2 dev: true - /defaults/1.0.4: + /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 dev: true - /deprecation/2.3.1: + /deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} dev: true - /dir-glob/3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - - /eastasianwidth/0.2.0: + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /emittery/1.0.1: - resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} - engines: {node: '>=14.16'} - dev: true - - /emoji-regex/10.2.1: + /emoji-regex@10.2.1: resolution: {integrity: sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==} dev: true - /emoji-regex/8.0.0: + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true - /emoji-regex/9.2.2: + /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true - /escalade/3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp/2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true - - /escape-string-regexp/5.0.0: + /escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} dev: true - /esprima/4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /esutils/2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /external-editor/3.1.0: + /external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} dependencies: @@ -696,28 +416,7 @@ packages: tmp: 0.0.33 dev: true - /fast-diff/1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - dev: true - - /fast-glob/3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - - /fastq/1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} - dependencies: - reusify: 1.0.4 - dev: true - - /figures/5.0.0: + /figures@5.0.0: resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} engines: {node: '>=14'} dependencies: @@ -725,22 +424,7 @@ packages: is-unicode-supported: 1.3.0 dev: true - /fill-range/7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - - /find-up/6.3.0: - resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - dev: true - - /foreground-child/3.1.1: + /foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} dependencies: @@ -748,7 +432,7 @@ packages: signal-exit: 4.1.0 dev: true - /fs-extra/11.1.1: + /fs-extra@11.1.1: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} dependencies: @@ -757,24 +441,11 @@ packages: universalify: 2.0.0 dev: true - /fsevents/2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind/1.1.1: + /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true - /get-caller-file/2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true - - /get-intrinsic/1.2.1: + /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: function-bind: 1.1.1 @@ -783,18 +454,11 @@ packages: has-symbols: 1.0.3 dev: true - /git-clone/0.2.0: + /git-clone@0.2.0: resolution: {integrity: sha512-1UAkEPIFbyjHaddljUKvPhhLRnrKaImT71T7rdvSvWLXw95nLdhdi6Qmlx0KOWoV1qqvHGLq5lMLJEZM0JXk8A==} dev: true - /glob-parent/5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob/10.3.10: + /glob@10.3.10: resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true @@ -806,77 +470,46 @@ packages: path-scurry: 1.10.1 dev: true - /globby/13.2.2: - resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - dir-glob: 3.0.1 - fast-glob: 3.3.1 - ignore: 5.2.4 - merge2: 1.4.1 - slash: 4.0.0 - dev: true - - /graceful-fs/4.2.11: + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true - /has-flag/4.0.0: + /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} dev: true - /has-proto/1.0.1: + /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} dev: true - /has-symbols/1.0.3: + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} dev: true - /has/1.0.4: + /has@1.0.4: resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} engines: {node: '>= 0.4.0'} dev: true - /iconv-lite/0.4.24: + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 dev: true - /ieee754/1.2.1: + /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: true - /ignore-by-default/2.1.0: - resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} - engines: {node: '>=10 <11 || >=12 <13 || >=14'} - dev: true - - /ignore/5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - dev: true - - /imurmurhash/0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /indent-string/5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - dev: true - - /inherits/2.0.4: + /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true - /inquirer/9.2.11: + /inquirer@9.2.11: resolution: {integrity: sha512-B2LafrnnhbRzCWfAdOXisUzL89Kg8cVJlYmhqoi3flSiV/TveO+nsXwgKr9h9PIo+J1hz7nBSk6gegRIMBBf7g==} engines: {node: '>=14.18.0'} dependencies: @@ -897,83 +530,41 @@ packages: wrap-ansi: 6.2.0 dev: true - /irregular-plurals/3.5.0: - resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} - engines: {node: '>=8'} - dev: true - - /is-binary-path/2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.2.0 - dev: true - - /is-error/2.2.2: - resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} - dev: true - - /is-extglob/2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-fullwidth-code-point/3.0.0: + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} dev: true - /is-fullwidth-code-point/4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - dev: true - - /is-glob/4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-interactive/1.0.0: + /is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} dev: true - /is-interactive/2.0.0: + /is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} dev: true - /is-number/7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - - /is-plain-object/5.0.0: + /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} dev: true - /is-promise/4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - dev: true - - /is-unicode-supported/0.1.0: + /is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} dev: true - /is-unicode-supported/1.3.0: + /is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} dev: true - /isexe/2.0.0: + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true - /jackspeak/2.3.6: + /jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} dependencies: @@ -982,27 +573,14 @@ packages: '@pkgjs/parseargs': 0.11.0 dev: true - /js-string-escape/1.0.1: - resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} - engines: {node: '>= 0.8'} - dev: true - - /js-yaml/3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - - /js-yaml/4.1.0: + /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true dependencies: argparse: 2.0.1 dev: true - /jsonfile/6.1.0: + /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: universalify: 2.0.0 @@ -1010,27 +588,15 @@ packages: graceful-fs: 4.2.11 dev: true - /load-json-file/7.0.1: - resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - - /locate-path/7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-locate: 6.0.0 - dev: true - - /lodash-es/4.17.21: + /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} dev: true - /lodash/4.17.21: + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - /log-symbols/4.1.0: + /log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} dependencies: @@ -1038,7 +604,7 @@ packages: is-unicode-supported: 0.1.0 dev: true - /log-symbols/5.1.0: + /log-symbols@5.1.0: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} engines: {node: '>=12'} dependencies: @@ -1046,96 +612,38 @@ packages: is-unicode-supported: 1.3.0 dev: true - /lru-cache/10.0.1: + /lru-cache@10.0.1: resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} engines: {node: 14 || >=16.14} dev: true - /lru-cache/6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /map-age-cleaner/0.1.3: - resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} - engines: {node: '>=6'} - dependencies: - p-defer: 1.0.0 - dev: true - - /matcher/5.0.0: - resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - escape-string-regexp: 5.0.0 - dev: true - - /md5-hex/3.0.1: - resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} - engines: {node: '>=8'} - dependencies: - blueimp-md5: 2.19.0 - dev: true - - /mem/9.0.2: - resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} - engines: {node: '>=12.20'} - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 4.0.0 - dev: true - - /merge2/1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true - - /micromatch/4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - dev: true - - /mimic-fn/2.1.0: + /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} dev: true - /mimic-fn/4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - dev: true - - /minimatch/9.0.3: + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 dev: true - /minipass/7.0.4: + /minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} dev: true - /ms/2.1.2: + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /ms/2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /mute-stream/1.0.0: + /mute-stream@1.0.0: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true - /node-fetch/2.7.0: + /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} peerDependencies: @@ -1147,30 +655,20 @@ packages: whatwg-url: 5.0.0 dev: true - /nofilter/3.1.0: - resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} - engines: {node: '>=12.19'} - dev: true - - /normalize-path/3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /once/1.4.0: + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 dev: true - /onetime/5.1.2: + /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} dependencies: mimic-fn: 2.1.0 dev: true - /ora/5.4.1: + /ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} dependencies: @@ -1185,7 +683,7 @@ packages: wcwidth: 1.0.1 dev: true - /ora/7.0.1: + /ora@7.0.1: resolution: {integrity: sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==} engines: {node: '>=16'} dependencies: @@ -1200,65 +698,17 @@ packages: strip-ansi: 7.1.0 dev: true - /os-tmpdir/1.0.2: + /os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} dev: true - /p-defer/1.0.0: - resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} - engines: {node: '>=4'} - dev: true - - /p-event/5.0.1: - resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-timeout: 5.1.0 - dev: true - - /p-limit/4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - yocto-queue: 1.0.0 - dev: true - - /p-locate/6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-limit: 4.0.0 - dev: true - - /p-map/5.5.0: - resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} - engines: {node: '>=12'} - dependencies: - aggregate-error: 4.0.1 - dev: true - - /p-timeout/5.1.0: - resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} - engines: {node: '>=12'} - dev: true - - /parse-ms/3.0.0: - resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} - engines: {node: '>=12'} - dev: true - - /path-exists/5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - - /path-key/3.1.1: + /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} dev: true - /path-scurry/1.10.1: + /path-scurry@1.10.1: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} dependencies: @@ -1266,43 +716,7 @@ packages: minipass: 7.0.4 dev: true - /path-type/4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true - - /picomatch/2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - - /pkg-conf/4.0.0: - resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - find-up: 6.3.0 - load-json-file: 7.0.1 - dev: true - - /plur/5.1.0: - resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - irregular-plurals: 3.5.0 - dev: true - - /pretty-ms/8.0.0: - resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} - engines: {node: '>=14.16'} - dependencies: - parse-ms: 3.0.0 - dev: true - - /queue-microtask/1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - - /readable-stream/3.6.2: + /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} dependencies: @@ -1311,31 +725,7 @@ packages: util-deprecate: 1.0.2 dev: true - /readdirp/3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - dev: true - - /require-directory/2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true - - /resolve-cwd/3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - dependencies: - resolve-from: 5.0.0 - dev: true - - /resolve-from/5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true - - /restore-cursor/3.1.0: + /restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} dependencies: @@ -1343,7 +733,7 @@ packages: signal-exit: 3.0.7 dev: true - /restore-cursor/4.0.0: + /restore-cursor@4.0.0: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: @@ -1351,12 +741,7 @@ packages: signal-exit: 3.0.7 dev: true - /reusify/1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf/5.0.5: + /rimraf@5.0.5: resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} engines: {node: '>=14'} hasBin: true @@ -1364,99 +749,54 @@ packages: glob: 10.3.10 dev: true - /run-async/3.0.0: + /run-async@3.0.0: resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} engines: {node: '>=0.12.0'} dev: true - /run-parallel/1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /rxjs/7.8.1: + /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: tslib: 2.6.2 dev: true - /safe-buffer/5.2.1: + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true - /safer-buffer/2.1.2: + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true - /semver/7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /serialize-error/7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} - dependencies: - type-fest: 0.13.1 - dev: true - - /shebang-command/2.0.0: + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 dev: true - /shebang-regex/3.0.0: + /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} dev: true - /signal-exit/3.0.7: + /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true - /signal-exit/4.1.0: + /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} dev: true - /slash/4.0.0: - resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} - engines: {node: '>=12'} - dev: true - - /slice-ansi/5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} - engines: {node: '>=12'} - dependencies: - ansi-styles: 6.2.1 - is-fullwidth-code-point: 4.0.0 - dev: true - - /sprintf-js/1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true - - /stack-utils/2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - - /stdin-discarder/0.1.0: + /stdin-discarder@0.1.0: resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: bl: 5.1.0 dev: true - /string-width/4.2.3: + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} dependencies: @@ -1465,7 +805,7 @@ packages: strip-ansi: 6.0.1 dev: true - /string-width/5.1.2: + /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} dependencies: @@ -1474,7 +814,7 @@ packages: strip-ansi: 7.1.0 dev: true - /string-width/6.1.0: + /string-width@6.1.0: resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} engines: {node: '>=16'} dependencies: @@ -1483,125 +823,88 @@ packages: strip-ansi: 7.1.0 dev: true - /string_decoder/1.3.0: + /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 dev: true - /strip-ansi/6.0.1: + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 dev: true - /strip-ansi/7.1.0: + /strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 dev: true - /supertap/3.0.1: - resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - indent-string: 5.0.0 - js-yaml: 3.14.1 - serialize-error: 7.0.1 - strip-ansi: 7.1.0 - dev: true - - /supports-color/7.2.0: + /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 dev: true - /temp-dir/3.0.0: - resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} - engines: {node: '>=14.16'} - dev: true - - /time-zone/1.0.0: - resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} - engines: {node: '>=4'} - dev: true - - /tmp/0.0.33: + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} dependencies: os-tmpdir: 1.0.2 dev: true - /to-regex-range/5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - - /tr46/0.0.3: + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true - /tslib/2.6.2: + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true - /typanion/3.14.0: + /typanion@3.14.0: resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==} dev: true - /type-fest/0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - dev: true - - /type-fest/0.21.3: + /type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} dev: true - /universal-user-agent/6.0.0: + /universal-user-agent@6.0.0: resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} dev: true - /universalify/2.0.0: + /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} dev: true - /util-deprecate/1.0.2: + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true - /wcwidth/1.0.1: + /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.4 dev: true - /webidl-conversions/3.0.1: + /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: true - /well-known-symbols/2.0.0: - resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} - engines: {node: '>=6'} - dev: true - - /whatwg-url/5.0.0: + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 dev: true - /which/2.0.2: + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true @@ -1609,7 +912,7 @@ packages: isexe: 2.0.0 dev: true - /wrap-ansi/6.2.0: + /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} dependencies: @@ -1618,7 +921,7 @@ packages: strip-ansi: 6.0.1 dev: true - /wrap-ansi/7.0.0: + /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} dependencies: @@ -1627,7 +930,7 @@ packages: strip-ansi: 6.0.1 dev: true - /wrap-ansi/8.1.0: + /wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} dependencies: @@ -1636,46 +939,6 @@ packages: strip-ansi: 7.1.0 dev: true - /wrappy/1.0.2: + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - - /write-file-atomic/5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dependencies: - imurmurhash: 0.1.4 - signal-exit: 4.1.0 - dev: true - - /y18n/5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true - - /yallist/4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yargs-parser/21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true - - /yargs/17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - dependencies: - cliui: 8.0.1 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - dev: true - - /yocto-queue/1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} - engines: {node: '>=12.20'} - dev: true diff --git a/scripts/clone-rspack.mjs b/scripts/clone-rspack.mjs index cdd4d34..f4c5d9d 100644 --- a/scripts/clone-rspack.mjs +++ b/scripts/clone-rspack.mjs @@ -5,7 +5,7 @@ import fse from 'fs-extra'; const REPO = 'git@github.com:web-infra-dev/rspack.git'; const DEST = 'crates/.rspack_crates/'; -const CEHECKOUT = 'v0.3.6'; +const CEHECKOUT = 'main'; function createSpinner( text, From 0650d4da1c54e1f3ceb4ba33393515e0ea5b8f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=B2=E5=B0=98?= Date: Mon, 30 Oct 2023 18:00:50 +0800 Subject: [PATCH 03/10] chore: deprecate built in react refresh --- crates/binding_options/Cargo.toml | 1 - crates/binding_options/src/options/raw_module.rs | 5 ----- 2 files changed, 6 deletions(-) diff --git a/crates/binding_options/Cargo.toml b/crates/binding_options/Cargo.toml index 6f13b5a..d3464bc 100644 --- a/crates/binding_options/Cargo.toml +++ b/crates/binding_options/Cargo.toml @@ -10,7 +10,6 @@ rspack_core = { path = "../.rspack_crates/rspack_cor rspack_error = { path = "../.rspack_crates/rspack_error" } rspack_identifier = { path = "../.rspack_crates/rspack_identifier" } rspack_ids = { path = "../.rspack_crates/rspack_ids" } -rspack_loader_react_refresh = { path = "../.rspack_crates/rspack_loader_react_refresh" } rspack_loader_runner = { path = "../.rspack_crates/rspack_loader_runner" } rspack_loader_sass = { path = "../.rspack_crates/rspack_loader_sass" } rspack_loader_swc = { path = "../.rspack_crates/rspack_loader_swc" } diff --git a/crates/binding_options/src/options/raw_module.rs b/crates/binding_options/src/options/raw_module.rs index 4cc8e18..74ae56b 100644 --- a/crates/binding_options/src/options/raw_module.rs +++ b/crates/binding_options/src/options/raw_module.rs @@ -24,11 +24,6 @@ pub fn get_builtin_loader(builtin: &str, options: Option<&str>) -> BoxLoader { .with_identifier(builtin.into()), ); } - if builtin.starts_with(REACT_REFRESH_LOADER_IDENTIFIER) { - return Arc::new( - rspack_loader_react_refresh::ReactRefreshLoader::default().with_identifier(builtin.into()), - ); - } if builtin.starts_with(COMPILATION_LOADER_IDENTIFIER) { return Arc::new( From e0f374d4ca10f480849c0b093b070382b78cab98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=B2=E5=B0=98?= Date: Tue, 31 Oct 2023 17:27:28 +0800 Subject: [PATCH 04/10] feat: loader structure --- crates/loader_compilation/Cargo.toml | 3 + crates/loader_compilation/src/compiler.rs | 262 ++++++++++++++++++ crates/loader_compilation/src/lib.rs | 98 ++++--- .../src/transform/keep_export.rs | 0 .../src/transform/remove_export.rs | 0 5 files changed, 325 insertions(+), 38 deletions(-) create mode 100644 crates/loader_compilation/src/compiler.rs create mode 100644 crates/loader_compilation/src/transform/keep_export.rs create mode 100644 crates/loader_compilation/src/transform/remove_export.rs diff --git a/crates/loader_compilation/Cargo.toml b/crates/loader_compilation/Cargo.toml index 94e1198..7a825a6 100644 --- a/crates/loader_compilation/Cargo.toml +++ b/crates/loader_compilation/Cargo.toml @@ -8,11 +8,14 @@ edition = "2021" [dependencies] anyhow = { workspace = true } async-trait = { workspace = true } +dashmap = { workspace = true } either = "1" once_cell = { workspace = true } +rspack_ast = { path = "../.rspack_crates/rspack_ast" } rspack_core = { path = "../.rspack_crates/rspack_core" } rspack_error = { path = "../.rspack_crates/rspack_error" } rspack_loader_runner = { path = "../.rspack_crates/rspack_loader_runner" } +rspack_plugin_javascript = { path = "../.rspack_crates/rspack_plugin_javascript" } serde = { workspace = true, features = ["derive"] } serde_json = "1.0.100" swc_config = { workspace = true } diff --git a/crates/loader_compilation/src/compiler.rs b/crates/loader_compilation/src/compiler.rs new file mode 100644 index 0000000..f8a91a3 --- /dev/null +++ b/crates/loader_compilation/src/compiler.rs @@ -0,0 +1,262 @@ +use std::env; +use std::{path::PathBuf, sync::Arc}; +use anyhow::{Context, Error}; +use dashmap::DashMap; +use rspack_ast::javascript::{Ast as JsAst, Context as JsAstContext, Program as JsProgram}; +use swc_core:: { + base::{ + config::{Options, JsMinifyCommentOption, BuiltInput, IsModule}, + try_with_handler, SwcComments + }, + common::{ + Globals, SourceFile, SourceMap, GLOBALS, Mark, FileName, FilePathMapping, BytePos, + comments::{SingleThreadedComments, Comments, Comment, CommentKind}, + errors::{Handler, HANDLER}, + }, + ecma::{transforms::base::helpers::{self, Helpers}, ast::{Program, EsVersion}, visit::{Fold, FoldWith}, + parser::{parse_file_as_module, Syntax, parse_file_as_script, parse_file_as_program}}, +}; +use swc_config::config_types::BoolOr; + +fn minify_file_comments( + comments: &SingleThreadedComments, + preserve_comments: BoolOr, +) { + match preserve_comments { + BoolOr::Bool(true) | BoolOr::Data(JsMinifyCommentOption::PreserveAllComments) => {} + + BoolOr::Data(JsMinifyCommentOption::PreserveSomeComments) => { + let preserve_excl = |_: &BytePos, vc: &mut Vec| -> bool { + // Preserve license comments. + // + // See https://github.com/terser/terser/blob/798135e04baddd94fea403cfaab4ba8b22b1b524/lib/output.js#L175-L181 + vc.retain(|c: &Comment| { + c.text.contains("@lic") + || c.text.contains("@preserve") + || c.text.contains("@copyright") + || c.text.contains("@cc_on") + || (c.kind == CommentKind::Block && c.text.starts_with('!')) + }); + !vc.is_empty() + }; + let (mut l, mut t) = comments.borrow_all_mut(); + + l.retain(preserve_excl); + t.retain(preserve_excl); + } + + BoolOr::Bool(false) => { + let (mut l, mut t) = comments.borrow_all_mut(); + l.clear(); + t.clear(); + } + } +} + +pub(crate) struct SwcCompiler { + cm: Arc, + fm: Arc, + comments: SingleThreadedComments, + options: Options, + globals: Globals, + helpers: Helpers, +} + +impl SwcCompiler { + pub fn new(resource_path: PathBuf, source: String, mut options: Options) -> Result { + let cm = Arc::new(SourceMap::new(FilePathMapping::empty())); + let globals = Globals::default(); + GLOBALS.set(&globals, || { + let top_level_mark = Mark::new(); + let unresolved_mark = Mark::new(); + options.top_level_mark = Some(top_level_mark); + options.unresolved_mark = Some(unresolved_mark); + }); + // TODO: support read config of .swcrc. + let fm = cm.new_source_file(FileName::Real(resource_path), source); + let comments = SingleThreadedComments::default(); + let helpers = GLOBALS.set(&globals, || { + let external_helpers = options.config.jsc.external_helpers; + Helpers::new(external_helpers.into()) + }); + + Ok(Self { + cm, + fm, + comments, + options, + globals, + helpers, + }) + } + + pub fn run(&self, op: impl FnOnce() -> R) -> R { + GLOBALS.set(&self.globals, op) + } + + fn parse_js( + &self, + fm: Arc, + handler: &Handler, + target: EsVersion, + syntax: Syntax, + is_module: IsModule, + comments: Option<&dyn Comments>, + ) -> Result { + let mut error = false; + let mut errors = vec![]; + + let program_result = match is_module { + IsModule::Bool(true) => { + parse_file_as_module(&fm, syntax, target, comments, &mut errors).map(Program::Module) + } + IsModule::Bool(false) => { + parse_file_as_script(&fm, syntax, target, comments, &mut errors).map(Program::Script) + } + IsModule::Unknown => parse_file_as_program(&fm, syntax, target, comments, &mut errors), + }; + + for e in errors { + e.into_diagnostic(handler).emit(); + error = true; + } + + let mut res = program_result.map_err(|e| { + e.into_diagnostic(handler).emit(); + Error::msg("Syntax Error") + }); + + if error { + return Err(anyhow::anyhow!("Syntax Error")); + } + + if env::var("SWC_DEBUG").unwrap_or_default() == "1" { + res = res.with_context(|| format!("Parser config: {:?}", syntax)); + } + + res + + } + + pub fn parse<'a, P>( + &'a self, + program: Option, + before_pass: impl FnOnce(&Program) -> P + 'a, + ) -> Result, Error> + where + P: Fold + 'a, + { + let built = self.run(|| { + try_with_handler(self.cm.clone(), Default::default(), |handler| { + let built = self.options.build_as_input( + &self.cm, + &self.fm.name, + move |syntax, target, is_module| match program { + Some(v) => Ok(v), + _ => self.parse_js( + self.fm.clone(), + handler, + target, + syntax, + is_module, + Some(&self.comments), + ), + }, + self.options.output_path.as_deref(), + self.options.source_file_name.clone(), + handler, + // TODO: support config file. + Some(self.options.config.clone()), + Some(&self.comments), + before_pass, + )?; + + Ok(Some(built)) + }) + })?; + + match built { + Some(v) => Ok(v), + None => { + anyhow::bail!("cannot process file because it's ignored by .swcrc") + } + } + } + + pub fn transform(&self, config: BuiltInput) -> Result { + let program = config.program; + let mut pass = config.pass; + + let program = self.run(|| { + helpers::HELPERS.set(&self.helpers, || { + try_with_handler(self.cm.clone(), Default::default(), |handler| { + HANDLER.set(handler, || { + // Fold module + Ok(program.fold_with(&mut pass)) + }) + }) + }) + }); + if let Some(comments) = &config.comments { + minify_file_comments(comments, config.preserve_comments); + }; + + program + } + + pub fn comments(&self) -> &SingleThreadedComments { + &self.comments + } + + pub fn options(&self) -> &Options { + &self.options + } + + pub fn cm(&self) -> &Arc { + &self.cm + } +} + +pub(crate) trait IntoJsAst { + fn into_js_ast(self, program: Program) -> JsAst; +} + +impl IntoJsAst for SwcCompiler { + fn into_js_ast(self, program: Program) -> JsAst { + JsAst::default() + .with_program(JsProgram::new( + program, + Some(self.comments.into_swc_comments()), + )) + .with_context(JsAstContext { + globals: self.globals, + helpers: self.helpers, + source_map: self.cm, + top_level_mark: self + .options + .top_level_mark + .expect("`top_level_mark` should be initialized"), + unresolved_mark: self + .options + .unresolved_mark + .expect("`unresolved_mark` should be initialized"), + }) + } +} + +trait IntoSwcComments { + fn into_swc_comments(self) -> SwcComments; +} + +impl IntoSwcComments for SingleThreadedComments { + fn into_swc_comments(self) -> SwcComments { + let (l, t) = { + let (l, t) = self.take_all(); + (l.take(), t.take()) + }; + SwcComments { + leading: Arc::new(DashMap::from_iter(l.into_iter())), + trailing: Arc::new(DashMap::from_iter(t.into_iter())), + } + } +} \ No newline at end of file diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index 4f61f07..ad1f6f1 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -1,21 +1,19 @@ -use std::sync::Arc; -use rspack_core::{rspack_sources::SourceMap, LoaderRunnerContext, Mode}; +use rspack_ast::RspackAst; +use rspack_core::{rspack_sources::SourceMap, LoaderRunnerContext}; use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; use rspack_error::{ - internal_error, Diagnostic, DiagnosticKind, Error, InternalError, Result, Severity, - TraceableError, + internal_error, Result, }; -use swc_core::{ - base::{ - Compiler, - config::{InputSourceMap, Options}, - try_with_handler - }, - common::{FilePathMapping,GLOBALS, FileName, comments::SingleThreadedComments}, - ecma::transforms::base::pass::noop +use swc_core::base::config::{InputSourceMap, Options, OutputCharset}; +use rspack_plugin_javascript::{ + ast::{self, SourceMapConfig}, + TransformOutput, }; +mod compiler; mod transform; + use transform::*; +use compiler::{SwcCompiler, IntoJsAst}; pub struct CompilationLoader { identifier: Identifier, } @@ -43,8 +41,6 @@ impl Loader for CompilationLoader { let Some(content) = std::mem::take(&mut loader_context.content) else { return Err(internal_error!("No content found")); }; - - let compiler = Compiler::new(Arc::from(swc_core::common::SourceMap::new(FilePathMapping::empty()))); // TODO: init loader with custom options. let mut swc_options = Options::default(); @@ -56,31 +52,57 @@ impl Loader for CompilationLoader { } } - GLOBALS.set(&Default::default(), || { - try_with_handler(compiler.cm.clone(), Default::default(), |handler| { - compiler.run(|| { - let content = content.try_into_string()?; - let fm = compiler.cm.new_source_file(FileName::Real(resource_path.clone()), content.clone()); - let comments = SingleThreadedComments::default(); - let transform_options = SwcPluginOptions { - keep_export: None, - remove_export: None, - }; - let out = compiler.process_js_with_custom_pass( - fm, - None, - handler, - &swc_options, - comments, |_| { - transform(transform_options) - }, - |_| noop(), - )?; - Ok(()) - }) - }) + let devtool = &loader_context.context.options.devtool; + let source = content.try_into_string()?; + let compiler = SwcCompiler::new(resource_path.clone(), source.clone(), swc_options)?; + + let transform_options = SwcPluginOptions { + keep_export: None, + remove_export: None, + }; + let built = compiler.parse(None, |_| { + transform(transform_options) })?; - + + let codegen_options = ast::CodegenOptions { + target: Some(built.target), + minify: Some(built.minify), + ascii_only: built + .output + .charset + .as_ref() + .map(|v| matches!(v, OutputCharset::Ascii)), + source_map_config: SourceMapConfig { + enable: devtool.source_map(), + inline_sources_content: true, + emit_columns: !devtool.cheap(), + names: Default::default(), + }, + keep_comments: Some(true), + }; + let program = compiler.transform(built)?; + let ast = compiler.into_js_ast(program); + + // If swc-loader is the latest loader available, + // then loader produces AST, which could be used as an optimization. + if loader_context.loader_index() == 0 + && (loader_context + .current_loader() + .composed_index_by_identifier(&self.identifier) + .map(|idx| idx == 0) + .unwrap_or(true)) + { + loader_context + .additional_data + .insert(RspackAst::JavaScript(ast)); + loader_context.additional_data.insert(codegen_options); + loader_context.content = Some("".to_owned().into()) + } else { + let TransformOutput { code, map } = ast::stringify(&ast, codegen_options)?; + loader_context.content = Some(code.into()); + loader_context.source_map = map.map(|m| SourceMap::from_json(&m)).transpose()?; + } + Ok(()) } } diff --git a/crates/loader_compilation/src/transform/keep_export.rs b/crates/loader_compilation/src/transform/keep_export.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/loader_compilation/src/transform/remove_export.rs b/crates/loader_compilation/src/transform/remove_export.rs new file mode 100644 index 0000000..e69de29 From f75281009d10b012442a2bb38f4fe2f5cef882ca Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 31 Oct 2023 17:34:21 +0800 Subject: [PATCH 05/10] fix: update loader test case --- crates/loader_compilation/tests/fixtures.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/loader_compilation/tests/fixtures.rs b/crates/loader_compilation/tests/fixtures.rs index d99f90b..b6c9d18 100644 --- a/crates/loader_compilation/tests/fixtures.rs +++ b/crates/loader_compilation/tests/fixtures.rs @@ -1,14 +1,23 @@ use std::{str::FromStr,env, fs,path::{Path, PathBuf}, sync::Arc}; use loader_compilation::CompilationLoader; -use rspack_core::{run_loaders, CompilerContext, CompilerOptions, SideEffectOption}; -use rspack_loader_runner::ResourceData; +use rspack_core::{ + run_loaders, CompilerContext, CompilerOptions, Loader, LoaderRunnerContext, ResourceData, SideEffectOption, +}; +use serde_json::json; +use swc_core::base::config::{PluginConfig, Config}; async fn loader_test(actual: impl AsRef, expected: impl AsRef) { let tests_path = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"))).join("tests"); - let actual_path = tests_path.join(actual); let expected_path = tests_path.join(expected); + let actual_path = tests_path.join(actual); + let plugin_path = tests_path.join("my_first_plugin.wasm"); + let mut options = Config::default(); + options.jsc.experimental.plugins = Some(vec![PluginConfig( + plugin_path.to_string_lossy().to_string(), + json!(null), + )]); let (result, _) = run_loaders( - &[Arc::new(CompilationLoader::default())], + &[Arc::new(CompilationLoader::new(options)) as Arc>], &ResourceData::new(actual_path.to_string_lossy().to_string(), actual_path), &[], CompilerContext { @@ -71,11 +80,12 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { side_effects: SideEffectOption::False, provided_exports: Default::default(), used_exports: Default::default(), + inner_graph: Default::default(), }, profile: false, }), resolver_factory: Default::default(), - } + }, ) .await .expect("TODO:") From 408a4dae194b5ab009f5e80ad161c97cd5bdaa41 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 31 Oct 2023 17:55:03 +0800 Subject: [PATCH 06/10] fix: impl new --- crates/binding_options/src/options/raw_module.rs | 2 +- crates/loader_compilation/src/lib.rs | 6 ++---- crates/loader_compilation/tests/fixtures.rs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/binding_options/src/options/raw_module.rs b/crates/binding_options/src/options/raw_module.rs index 74ae56b..9b909d5 100644 --- a/crates/binding_options/src/options/raw_module.rs +++ b/crates/binding_options/src/options/raw_module.rs @@ -27,7 +27,7 @@ pub fn get_builtin_loader(builtin: &str, options: Option<&str>) -> BoxLoader { if builtin.starts_with(COMPILATION_LOADER_IDENTIFIER) { return Arc::new( - loader_compilation::CompilationLoader::default().with_identifier(builtin.into()), + loader_compilation::CompilationLoader::new().with_identifier(builtin.into()), ); } diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index ad1f6f1..617b2b4 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -18,15 +18,13 @@ pub struct CompilationLoader { identifier: Identifier, } -impl Default for CompilationLoader { - fn default() -> Self { +impl CompilationLoader { + pub fn new() -> Self { Self { identifier: COMPILATION_LOADER_IDENTIFIER.into(), } } -} -impl CompilationLoader { pub fn with_identifier(mut self, identifier: Identifier) -> Self { assert!(identifier.starts_with(COMPILATION_LOADER_IDENTIFIER)); self.identifier = identifier; diff --git a/crates/loader_compilation/tests/fixtures.rs b/crates/loader_compilation/tests/fixtures.rs index b6c9d18..efb3880 100644 --- a/crates/loader_compilation/tests/fixtures.rs +++ b/crates/loader_compilation/tests/fixtures.rs @@ -17,7 +17,7 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { json!(null), )]); let (result, _) = run_loaders( - &[Arc::new(CompilationLoader::new(options)) as Arc>], + &[Arc::new(CompilationLoader::new()) as Arc>], &ResourceData::new(actual_path.to_string_lossy().to_string(), actual_path), &[], CompilerContext { From 6fe41befa86241637559850c30b18eb3c84a7672 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Thu, 2 Nov 2023 15:40:45 +0800 Subject: [PATCH 07/10] feat: add tranform chain of remove exports and keep exports --- crates/loader_compilation/Cargo.toml | 1 + crates/loader_compilation/src/lib.rs | 8 +- .../src/transform/keep_export.rs | 589 ++++++++++++++++++ .../loader_compilation/src/transform/mod.rs | 38 +- .../src/transform/remove_export.rs | 586 +++++++++++++++++ crates/loader_compilation/tests/fixtures.rs | 6 +- .../tests/fixtures/basic/input.js | 7 + 7 files changed, 1206 insertions(+), 29 deletions(-) diff --git a/crates/loader_compilation/Cargo.toml b/crates/loader_compilation/Cargo.toml index 7a825a6..4e519ce 100644 --- a/crates/loader_compilation/Cargo.toml +++ b/crates/loader_compilation/Cargo.toml @@ -10,6 +10,7 @@ anyhow = { workspace = true } async-trait = { workspace = true } dashmap = { workspace = true } either = "1" +fxhash= "0.2.1" once_cell = { workspace = true } rspack_ast = { path = "../.rspack_crates/rspack_ast" } rspack_core = { path = "../.rspack_crates/rspack_core" } diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index 617b2b4..fde47b2 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -55,8 +55,12 @@ impl Loader for CompilationLoader { let compiler = SwcCompiler::new(resource_path.clone(), source.clone(), swc_options)?; let transform_options = SwcPluginOptions { - keep_export: None, - remove_export: None, + keep_export: Some(KeepExportOptions { + export_names: vec!["default".to_string()], + }), + remove_export: Some(RemoveExportOptions { + remove_names: vec!["default".to_string()], + }), }; let built = compiler.parse(None, |_| { transform(transform_options) diff --git a/crates/loader_compilation/src/transform/keep_export.rs b/crates/loader_compilation/src/transform/keep_export.rs index e69de29..1d23124 100644 --- a/crates/loader_compilation/src/transform/keep_export.rs +++ b/crates/loader_compilation/src/transform/keep_export.rs @@ -0,0 +1,589 @@ +// transform code is modified based on swc plugin of keep_export: +// https://github.com/ice-lab/swc-plugins/tree/main/packages/keep-export +use fxhash::FxHashSet; +use std::mem::take; +use swc_core::ecma::{ + ast::*, + visit::{Fold, FoldWith, noop_fold_type}, +}; +use swc_core::common::{ + DUMMY_SP, pass::{Repeat, Repeated} +}; + +/// State of the transforms. Shared by the analyzer and the transform. +#[derive(Debug, Default)] +struct State { + /// Identifiers referenced by other functions. + /// + /// Cleared before running each pass, because we drop ast nodes between the + /// passes. + refs_from_other: FxHashSet, + + /// Identifiers referenced by kept functions or derivatives. + /// + /// Preserved between runs, because we should remember derivatives of data + /// functions as the data function itself is already removed. + refs_used: FxHashSet, + + should_run_again: bool, + keep_exports: Vec, +} + +impl State { + fn should_keep_identifier(&mut self, i: &Ident) -> bool { + self.keep_exports.contains(&String::from(&*i.sym)) + } + + fn should_keep_default(&mut self) -> bool { + self.keep_exports.contains(&String::from("default")) + } +} + +struct KeepExport { + pub state: State, + in_lhs_of_var: bool, +} + +impl KeepExport { + fn should_remove(&self, id: Id) -> bool { + !self.state.refs_used.contains(&id) && !self.state.refs_from_other.contains(&id) + } + + /// Mark identifiers in `n` as a candidate for removal. + fn mark_as_candidate(&mut self, n: N) -> N + where + N: for<'a> FoldWith>, + { + // Analyzer never change `in_kept_fn` to false, so all identifiers in `n` will + // be marked as referenced from a data function. + let mut v = Analyzer { + state: &mut self.state, + in_lhs_of_var: false, + in_kept_fn: false, + }; + + let n = n.fold_with(&mut v); + self.state.should_run_again = true; + n + } +} + +impl Repeated for KeepExport { + fn changed(&self) -> bool { + self.state.should_run_again + } + + fn reset(&mut self) { + self.state.refs_from_other.clear(); + self.state.should_run_again = false; + } +} + +impl Fold for KeepExport { + // This is important for reducing binary sizes. + noop_fold_type!(); + + // Remove import expression + fn fold_import_decl(&mut self, mut i: ImportDecl) -> ImportDecl { + // Imports for side effects. + if i.specifiers.is_empty() { + return i; + } + + i.specifiers.retain(|s| match s { + ImportSpecifier::Named(ImportNamedSpecifier { local, .. }) + | ImportSpecifier::Default(ImportDefaultSpecifier { local, .. }) + | ImportSpecifier::Namespace(ImportStarAsSpecifier { local, .. }) => { + if self.should_remove(local.to_id()) { + self.state.should_run_again = true; + false + } else { + true + } + } + }); + + i + } + + fn fold_module(&mut self, mut m: Module) -> Module { + { + // Fill the state. + let mut v = Analyzer { + state: &mut self.state, + in_lhs_of_var: false, + in_kept_fn: false, + }; + m = m.fold_with(&mut v); + } + + m.fold_children_with(self) + } + + fn fold_module_items(&mut self, mut items: Vec) -> Vec { + items = items.fold_children_with(self); + + // Drop nodes. + items.retain(|s| !matches!(s, ModuleItem::Stmt(Stmt::Empty(..)))); + + // If all exports are deleted, return the empty named export. + if items.len() == 0 { + items.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport{ + span: DUMMY_SP, + specifiers: Vec::new(), + src: None, + type_only: false, + with: Default::default(), + }))); + } + + items + } + + fn fold_module_item(&mut self, i: ModuleItem) -> ModuleItem { + if let ModuleItem::ModuleDecl(ModuleDecl::Import(i)) = i { + let i = i.fold_with(self); + + if i.specifiers.is_empty() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + + return ModuleItem::ModuleDecl(ModuleDecl::Import(i)); + } + + let i = i.fold_children_with(self); + + match &i { + ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(e)) if e.specifiers.is_empty() => { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })) + } + _ => {} + } + + i + } + + fn fold_named_export(&mut self, mut n: NamedExport) -> NamedExport { + n.specifiers = n.specifiers.fold_with(self); + + n.specifiers.retain(|s| { + let preserve = match s { + ExportSpecifier::Namespace(ExportNamespaceSpecifier { + name: ModuleExportName::Ident(exported), + .. + }) + | ExportSpecifier::Default(ExportDefaultSpecifier { exported, .. }) + | ExportSpecifier::Named(ExportNamedSpecifier { + exported: Some(ModuleExportName::Ident(exported)), + .. + }) => self + .state + .should_keep_identifier(exported), + ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(orig), + .. + }) => self + .state + .should_keep_identifier(orig), + _ => false, + }; + + match preserve { + false => { + if let ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(_orig), + .. + }) = s + { + self.state.should_run_again = true; + } + + false + } + true => true, + } + }); + + n + } + + /// This methods returns [Pat::Invalid] if the pattern should be removed. + fn fold_pat(&mut self, mut p: Pat) -> Pat { + p = p.fold_children_with(self); + + if self.in_lhs_of_var { + match &mut p { + Pat::Ident(name) => { + if self.should_remove(name.id.to_id()) { + self.state.should_run_again = true; + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + Pat::Array(arr) => { + if !arr.elems.is_empty() { + arr.elems.retain(|e| !matches!(e, Some(Pat::Invalid(..)))); + + if arr.elems.is_empty() { + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + } + Pat::Object(obj) => { + if !obj.props.is_empty() { + obj.props = take(&mut obj.props) + .into_iter() + .filter_map(|prop| match prop { + ObjectPatProp::KeyValue(prop) => { + if prop.value.is_invalid() { + None + } else { + Some(ObjectPatProp::KeyValue(prop)) + } + } + ObjectPatProp::Assign(prop) => { + if self.should_remove(prop.key.to_id()) { + self.mark_as_candidate(prop.value); + + None + } else { + Some(ObjectPatProp::Assign(prop)) + } + } + ObjectPatProp::Rest(prop) => { + if prop.arg.is_invalid() { + None + } else { + Some(ObjectPatProp::Rest(prop)) + } + } + }) + .collect(); + + if obj.props.is_empty() { + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + } + Pat::Rest(rest) => { + if rest.arg.is_invalid() { + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + _ => {} + } + } + + p + } + + #[allow(clippy::single_match)] + fn fold_stmt(&mut self, mut s: Stmt) -> Stmt { + match s { + Stmt::Decl(Decl::Fn(f)) => { + if self.should_remove(f.ident.to_id()) { + self.mark_as_candidate(f.function); + return Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + } + + s = Stmt::Decl(Decl::Fn(f)); + } + Stmt::Decl(Decl::Class(c)) => { + if self.should_remove(c.ident.to_id()) { + self.mark_as_candidate(c.class); + return Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + } + + s = Stmt::Decl(Decl::Class(c)); + } + _ => {} + } + + let s = s.fold_children_with(self); + match s { + Stmt::Decl(Decl::Var(v)) if v.decls.is_empty() => { + return Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + } + _ => {} + } + + s + } + + /// This method make `name` of [VarDeclarator] to [Pat::Invalid] if it + /// should be removed. + fn fold_var_declarator(&mut self, mut d: VarDeclarator) -> VarDeclarator { + let old = self.in_lhs_of_var; + self.in_lhs_of_var = true; + let name = d.name.fold_with(self); + + self.in_lhs_of_var = false; + if name.is_invalid() { + d.init = self.mark_as_candidate(d.init); + } + let init = d.init.fold_with(self); + self.in_lhs_of_var = old; + + VarDeclarator { name, init, ..d } + } + + fn fold_var_declarators(&mut self, mut decls: Vec) -> Vec { + decls = decls.fold_children_with(self); + decls.retain(|d| !d.name.is_invalid()); + + decls + } +} + +struct Analyzer<'a> { + state: &'a mut State, + in_lhs_of_var: bool, + in_kept_fn: bool, +} + +impl Analyzer<'_> { + fn add_ref(&mut self, id: Id) { + if self.in_kept_fn { + self.state.refs_used.insert(id); + } else { + self.state.refs_from_other.insert(id); + } + } + + fn check_default>(&mut self, e: T) -> T { + if self.state.should_keep_default() { + let old_in_kept = self.in_kept_fn; + self.in_kept_fn = true; + let e = e.fold_children_with(self); + self.in_kept_fn = old_in_kept; + return e + } + + return e; + } +} + +impl Fold for Analyzer<'_> { + // This is important for reducing binary sizes. + noop_fold_type!(); + + fn fold_binding_ident(&mut self, i: BindingIdent) -> BindingIdent { + if !self.in_lhs_of_var || self.in_kept_fn { + self.add_ref(i.id.to_id()); + } + i + } + + fn fold_export_named_specifier(&mut self, s: ExportNamedSpecifier) -> ExportNamedSpecifier { + if let ModuleExportName::Ident(i) = &s.orig { + match &s.exported { + Some(exported) => { + if let ModuleExportName::Ident(e) = exported { + if self.state.should_keep_identifier(e) { + self.add_ref(i.to_id()); + } + } + } + None => { + if self.state.should_keep_identifier(i) { + self.add_ref(i.to_id()); + } + } + } + } + s + } + + fn fold_export_decl(&mut self, s: ExportDecl) -> ExportDecl { + let old_in_kept = self.in_kept_fn; + + match &s.decl { + Decl::Fn(f) => { + if self.state.should_keep_identifier(&f.ident) { + self.in_kept_fn = true; + self.add_ref(f.ident.to_id()); + } + } + + Decl::Var(d) => { + if d.decls.is_empty() { + return s; + } + if let Pat::Ident(id) = &d.decls[0].name { + if self.state.should_keep_identifier(&id.id) { + self.in_kept_fn = true; + self.add_ref(id.to_id()); + } + } + } + _ => {} + } + let e = s.fold_children_with(self); + self.in_kept_fn = old_in_kept; + e + } + + fn fold_expr(&mut self, e: Expr) -> Expr { + let e = e.fold_children_with(self); + + if let Expr::Ident(i) = &e { + self.add_ref(i.to_id()); + } + e + } + + fn fold_jsx_element(&mut self, jsx: JSXElement) -> JSXElement { + fn get_leftmost_id_member_expr(e: &JSXMemberExpr) -> Id { + match &e.obj { + JSXObject::Ident(i) => i.to_id(), + JSXObject::JSXMemberExpr(e) => get_leftmost_id_member_expr(e), + } + } + + match &jsx.opening.name { + JSXElementName::Ident(i) => { + self.add_ref(i.to_id()); + } + JSXElementName::JSXMemberExpr(e) => { + self.add_ref(get_leftmost_id_member_expr(e)); + } + _ => {} + } + + jsx.fold_children_with(self) + } + + fn fold_fn_decl(&mut self, f: FnDecl) -> FnDecl { + let f = f.fold_children_with(self); + if self.in_kept_fn { + self.add_ref(f.ident.to_id()); + } + f + } + + fn fold_fn_expr(&mut self, f: FnExpr) -> FnExpr { + let f = f.fold_children_with(self); + if let Some(id) = &f.ident { + self.add_ref(id.to_id()); + } + f + } + + /// Drops [ExportDecl] if all specifiers are removed. + fn fold_module_item(&mut self, s: ModuleItem) -> ModuleItem { + match s { + ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(e)) if !e.specifiers.is_empty() => { + let e = e.fold_with(self); + + if e.specifiers.is_empty() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + + return ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(e)); + } + + ModuleItem::Stmt(Stmt::Expr(_e)) => { + // remove top expression + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })) + } + + ModuleItem::Stmt(Stmt::If(_e)) => { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })) + } + + ModuleItem::Stmt(Stmt::DoWhile(_e)) => { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })) + } + + ModuleItem::Stmt(Stmt::Try(_e)) => { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })) + } + _ => {} + }; + + if let ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(e)) = &s { + match &e.decl { + Decl::Fn(f) => { + if self.state.should_keep_identifier(&f.ident) { + let s = s.fold_children_with(self); + return s; + } else { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + } + + Decl::Var(d) => { + if d.decls.is_empty() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + + if let Pat::Ident(id) = &d.decls[0].name { + if self.state.should_keep_identifier(&id.id) { + let s = s.fold_children_with(self); + return s; + } else { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + } + } + _ => {} + } + } + + if let ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(_e)) = &s { + if !self.state.should_keep_default() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + } + + if let ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(_e)) = &s { + if !self.state.should_keep_default() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + } + + // Visit children to ensure that all references is added to the scope. + let s = s.fold_children_with(self); + s + } + + fn fold_default_decl(&mut self, d: DefaultDecl) -> DefaultDecl { + return self.check_default(d); + } + + fn fold_export_default_expr(&mut self, e: ExportDefaultExpr) -> ExportDefaultExpr { + return self.check_default(e); + } + + fn fold_prop(&mut self, p: Prop) -> Prop { + let p = p.fold_children_with(self); + + if let Prop::Shorthand(i) = &p { + self.add_ref(i.to_id()); + } + + p + } + + fn fold_var_declarator(&mut self, mut v: VarDeclarator) -> VarDeclarator { + let old_in_lhs_of_var = self.in_lhs_of_var; + + self.in_lhs_of_var = true; + v.name = v.name.fold_with(self); + + self.in_lhs_of_var = false; + v.init = v.init.fold_with(self); + + self.in_lhs_of_var = old_in_lhs_of_var; + v + } +} + +pub fn keep_export(exports: Vec) -> impl Fold { + Repeat::new(KeepExport { + state: State { + keep_exports: exports, + ..Default::default() + }, + in_lhs_of_var: false, + }) +} \ No newline at end of file diff --git a/crates/loader_compilation/src/transform/mod.rs b/crates/loader_compilation/src/transform/mod.rs index e0e15f8..9e08e7e 100644 --- a/crates/loader_compilation/src/transform/mod.rs +++ b/crates/loader_compilation/src/transform/mod.rs @@ -2,13 +2,19 @@ use either::Either; use swc_core::common::chain; use swc_core::ecma::{ transforms::base::pass::noop, - visit::{as_folder, Fold, VisitMut}, + visit::{as_folder, Fold, VisitMut, Visit}, ast::Module, }; +mod keep_export; +mod remove_export; + +use keep_export::keep_export; +use remove_export::remove_export; + macro_rules! either { ($config:expr, $f:expr) => { - if let Some(config) = &$config { + if let Some(config) = $config { Either::Left($f(config)) } else { Either::Right(noop()) @@ -24,37 +30,25 @@ macro_rules! either { } pub struct KeepExportOptions { - export_names: Vec, + pub export_names: Vec, } -pub struct RemoveExport { - remove_names: Vec, +pub struct RemoveExportOptions { + pub remove_names: Vec, } pub struct SwcPluginOptions { pub keep_export: Option, - pub remove_export: Option, + pub remove_export: Option, } pub(crate) fn transform<'a>(plugin_options: SwcPluginOptions) -> impl Fold + 'a { chain!( - either!(plugin_options.keep_export, |_| { - keep_export() + either!(plugin_options.keep_export, |options: KeepExportOptions| { + keep_export(options.export_names) }), - either!(plugin_options.remove_export, |_| { - keep_export() + either!(plugin_options.remove_export, |options: RemoveExportOptions| { + remove_export(options.remove_names) }), ) -} - -struct KeepExport; - -impl VisitMut for KeepExport { - fn visit_mut_module(&mut self, module: &mut Module) { - - } -} - -fn keep_export() -> impl Fold { - as_folder(KeepExport) } \ No newline at end of file diff --git a/crates/loader_compilation/src/transform/remove_export.rs b/crates/loader_compilation/src/transform/remove_export.rs index e69de29..f58b3c1 100644 --- a/crates/loader_compilation/src/transform/remove_export.rs +++ b/crates/loader_compilation/src/transform/remove_export.rs @@ -0,0 +1,586 @@ +// transform code is modified based on swc plugin of remove_export: +// https://github.com/ice-lab/swc-plugins/tree/main/packages/remove-export +use fxhash::FxHashSet; +use std::mem::take; +use swc_core::ecma::{ + ast::*, + visit::{Fold, FoldWith, noop_fold_type}, +}; +use rspack_error::Error; +use swc_core::common::{ + DUMMY_SP, pass::{Repeat, Repeated} +}; + +/// State of the transforms. Shared by the analyzer and the transform. +#[derive(Debug, Default)] +struct State { + /// Identifiers referenced by non-data function codes. + /// + /// Cleared before running each pass, because we drop ast nodes between the + /// passes. + refs_from_other: FxHashSet, + + /// Identifiers referenced by data functions or derivatives. + /// + /// Preserved between runs, because we should remember derivatives of data + /// functions as the data function itself is already removed. + refs_from_data_fn: FxHashSet, + + cur_declaring: FxHashSet, + + should_run_again: bool, + remove_exports: Vec, +} + +impl State { + fn should_remove_identifier(&mut self, i: &Ident) -> Result { + Ok(self.remove_exports.contains(&String::from(&*i.sym))) + } + fn should_remove_default(&mut self) -> bool { + self.remove_exports.contains(&String::from("default")) + } +} + +struct Analyzer<'a> { + state: &'a mut State, + in_lhs_of_var: bool, + in_data_fn: bool, +} + +impl Analyzer<'_> { + fn add_ref(&mut self, id: Id) { + if self.in_data_fn { + self.state.refs_from_data_fn.insert(id); + } else { + if self.state.cur_declaring.contains(&id) { + return; + } + + self.state.refs_from_other.insert(id); + } + } + + fn check_default>(&mut self, e: T) -> T { + if self.state.should_remove_default() { + let old_in_data = self.in_data_fn; + self.in_data_fn = true; + let e = e.fold_children_with(self); + self.in_data_fn = old_in_data; + return e + } + + return e.fold_children_with(self); + } +} + +impl Fold for Analyzer<'_> { + // This is important for reducing binary sizes. + noop_fold_type!(); + + fn fold_binding_ident(&mut self, i: BindingIdent) -> BindingIdent { + if !self.in_lhs_of_var || self.in_data_fn { + self.add_ref(i.id.to_id()); + } + + i + } + + fn fold_export_named_specifier(&mut self, s: ExportNamedSpecifier) -> ExportNamedSpecifier { + if let ModuleExportName::Ident(id) = &s.orig { + if !self.state.remove_exports.contains(&String::from(&*id.sym)) { + self.add_ref(id.to_id()); + } + } + + s + } + + fn fold_export_decl(&mut self, s: ExportDecl) -> ExportDecl { + let old_in_data = self.in_data_fn; + + match &s.decl { + Decl::Fn(f) => { + if let Ok(should_remove_identifier) = self.state.should_remove_identifier(&f.ident) { + if should_remove_identifier { + self.in_data_fn = true; + self.add_ref(f.ident.to_id()); + } + } + } + + Decl::Var(d) => { + if d.decls.is_empty() { + return s; + } + if let Pat::Ident(id) = &d.decls[0].name { + if self.state.remove_exports.contains(&String::from(&*id.id.sym)) { + self.in_data_fn = true; + self.add_ref(id.to_id()); + } + } + } + _ => {} + } + + let e = s.fold_children_with(self); + + self.in_data_fn = old_in_data; + + return e; + } + + fn fold_expr(&mut self, e: Expr) -> Expr { + let e = e.fold_children_with(self); + + if let Expr::Ident(i) = &e { + self.add_ref(i.to_id()); + } + + e + } + + fn fold_jsx_element(&mut self, jsx: JSXElement) -> JSXElement { + fn get_leftmost_id_member_expr(e: &JSXMemberExpr) -> Id { + match &e.obj { + JSXObject::Ident(i) => i.to_id(), + JSXObject::JSXMemberExpr(e) => get_leftmost_id_member_expr(e), + } + } + + match &jsx.opening.name { + JSXElementName::Ident(i) => { + self.add_ref(i.to_id()); + } + JSXElementName::JSXMemberExpr(e) => { + self.add_ref(get_leftmost_id_member_expr(e)); + } + _ => {} + } + + jsx.fold_children_with(self) + } + + fn fold_fn_decl(&mut self, f: FnDecl) -> FnDecl { + let f = f.fold_children_with(self); + if self.in_data_fn { + self.add_ref(f.ident.to_id()); + } + + f + } + + fn fold_fn_expr(&mut self, f: FnExpr) -> FnExpr { + let f = f.fold_children_with(self); + if let Some(id) = &f.ident { + self.add_ref(id.to_id()); + } + + f + } + + /// Drops [ExportDecl] if all specifiers are removed. + fn fold_module_item(&mut self, s: ModuleItem) -> ModuleItem { + match s { + ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(e)) if !e.specifiers.is_empty() => { + let e = e.fold_with(self); + + if e.specifiers.is_empty() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + + return ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(e)); + } + _ => {} + }; + + // Visit children to ensure that all references is added to the scope. + let s = s.fold_children_with(self); + + if let ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(e)) = &s { + match &e.decl { + Decl::Fn(f) => { + if let Ok(should_remove_identifier) = self.state.should_remove_identifier(&f.ident) { + if should_remove_identifier { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + } else { + return s; + } + } + + Decl::Var(d) => { + if d.decls.is_empty() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + } + _ => {} + } + } + + s + } + + fn fold_named_export(&mut self, mut n: NamedExport) -> NamedExport { + if n.src.is_some() { + n.specifiers = n.specifiers.fold_with(self); + } + + n + } + + fn fold_default_decl(&mut self, d: DefaultDecl) -> DefaultDecl { + return self.check_default(d); + } + + fn fold_export_default_expr(&mut self, e: ExportDefaultExpr) -> ExportDefaultExpr { + return self.check_default(e); + } + + fn fold_prop(&mut self, p: Prop) -> Prop { + let p = p.fold_children_with(self); + if let Prop::Shorthand(i) = &p { + self.add_ref(i.to_id()); + } + p + } + + fn fold_var_declarator(&mut self, mut v: VarDeclarator) -> VarDeclarator { + let old_in_lhs_of_var = self.in_lhs_of_var; + + self.in_lhs_of_var = true; + v.name = v.name.fold_with(self); + + self.in_lhs_of_var = false; + v.init = v.init.fold_with(self); + + self.in_lhs_of_var = old_in_lhs_of_var; + v + } +} + +struct RemoveExport { + pub state: State, + in_lhs_of_var: bool, +} + +impl RemoveExport { + fn should_remove(&self, id: Id) -> bool { + self.state.refs_from_data_fn.contains(&id) && !self.state.refs_from_other.contains(&id) + } + + /// Mark identifiers in `n` as a candidate for removal. + fn mark_as_candidate(&mut self, n: N) -> N + where + N: for<'a> FoldWith>, + { + // Analyzer never change `in_data_fn` to false, so all identifiers in `n` will + // be marked as referenced from a data function. + let mut v = Analyzer { + state: &mut self.state, + in_lhs_of_var: false, + in_data_fn: true, + }; + + let n = n.fold_with(&mut v); + self.state.should_run_again = true; + n + } + + fn create_empty_fn(&mut self) -> FnExpr { + return FnExpr { + ident: None, + function: Box::new(Function { + params: vec![], + body: Some(BlockStmt { + span: DUMMY_SP, + stmts: vec![] + }), + span: DUMMY_SP, + is_generator: false, + is_async: false, + decorators: vec![], + return_type: None, + type_params: None, + }) + }; + } +} + +impl Repeated for RemoveExport { + fn changed(&self) -> bool { + self.state.should_run_again + } + + fn reset(&mut self) { + self.state.refs_from_other.clear(); + self.state.cur_declaring.clear(); + self.state.should_run_again = false; + } +} + +impl Fold for RemoveExport { + // This is important for reducing binary sizes. + noop_fold_type!(); + + // Remove import expression + fn fold_import_decl(&mut self, mut i: ImportDecl) -> ImportDecl { + // Imports for side effects. + if i.specifiers.is_empty() { + return i; + } + + i.specifiers.retain(|s| match s { + ImportSpecifier::Named(ImportNamedSpecifier { local, .. }) + | ImportSpecifier::Default(ImportDefaultSpecifier { local, .. }) + | ImportSpecifier::Namespace(ImportStarAsSpecifier { local, .. }) => { + if self.should_remove(local.to_id()) { + self.state.should_run_again = true; + false + } else { + true + } + } + }); + + i + } + + fn fold_module(&mut self, mut m: Module) -> Module { + { + // Fill the state. + let mut v = Analyzer { + state: &mut self.state, + in_lhs_of_var: false, + in_data_fn: false, + }; + m = m.fold_with(&mut v); + } + + m.fold_children_with(self) + } + + fn fold_module_items(&mut self, mut items: Vec) -> Vec { + items = items.fold_children_with(self); + // Drop nodes. + items.retain(|s| !matches!(s, ModuleItem::Stmt(Stmt::Empty(..)))); + items + } + + fn fold_module_item(&mut self, i: ModuleItem) -> ModuleItem { + if let ModuleItem::ModuleDecl(ModuleDecl::Import(i)) = i { + let is_for_side_effect = i.specifiers.is_empty(); + let i = i.fold_with(self); + + if !is_for_side_effect && i.specifiers.is_empty() { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + return ModuleItem::ModuleDecl(ModuleDecl::Import(i)); + } + + let i = i.fold_children_with(self); + + match &i { + ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(e)) if e.specifiers.is_empty() => { + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })) + } + _ => {} + } + + i + } + + fn fold_named_export(&mut self, mut n: NamedExport) -> NamedExport { + n.specifiers = n.specifiers.fold_with(self); + + n.specifiers.retain(|s| { + let preserve = match s { + ExportSpecifier::Namespace(ExportNamespaceSpecifier { + name: ModuleExportName::Ident(exported), + .. + }) + | ExportSpecifier::Default(ExportDefaultSpecifier { exported, .. }) + | ExportSpecifier::Named(ExportNamedSpecifier { + exported: Some(ModuleExportName::Ident(exported)), + .. + }) => self + .state + .should_remove_identifier(exported) + .map(|should_remove_identifier| !should_remove_identifier), + ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(orig), + .. + }) => self + .state + .should_remove_identifier(orig) + .map(|should_remove_identifier| !should_remove_identifier), + _ => Ok(true), + }; + + match preserve { + Ok(false) => { + if let ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(orig), + .. + }) = s + { + self.state.should_run_again = true; + self.state.refs_from_data_fn.insert(orig.to_id()); + } + + false + } + Ok(true) => true, + Err(_) => false, + } + }); + + n + } + + fn fold_default_decl(&mut self, d: DefaultDecl) -> DefaultDecl { + if self.state.should_remove_default() { + // Replace with an empty function + return DefaultDecl::Fn(self.create_empty_fn()) + } + d + } + + fn fold_export_default_expr(&mut self, n: ExportDefaultExpr) -> ExportDefaultExpr { + if self.state.should_remove_default() { + // Replace with an empty function + return ExportDefaultExpr { + span: DUMMY_SP, + expr: Box::new(Expr::Fn(self.create_empty_fn())) + }; + } + n + } + + /// This methods returns [Pat::Invalid] if the pattern should be removed. + fn fold_pat(&mut self, mut p: Pat) -> Pat { + p = p.fold_children_with(self); + + if self.in_lhs_of_var { + match &mut p { + Pat::Ident(name) => { + if self.should_remove(name.id.to_id()) { + self.state.should_run_again = true; + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + Pat::Array(arr) => { + if !arr.elems.is_empty() { + arr.elems.retain(|e| !matches!(e, Some(Pat::Invalid(..)))); + + if arr.elems.is_empty() { + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + } + Pat::Object(obj) => { + if !obj.props.is_empty() { + obj.props = take(&mut obj.props) + .into_iter() + .filter_map(|prop| match prop { + ObjectPatProp::KeyValue(prop) => { + if prop.value.is_invalid() { + None + } else { + Some(ObjectPatProp::KeyValue(prop)) + } + } + ObjectPatProp::Assign(prop) => { + if self.should_remove(prop.key.to_id()) { + self.mark_as_candidate(prop.value); + + None + } else { + Some(ObjectPatProp::Assign(prop)) + } + } + ObjectPatProp::Rest(prop) => { + if prop.arg.is_invalid() { + None + } else { + Some(ObjectPatProp::Rest(prop)) + } + } + }) + .collect(); + + if obj.props.is_empty() { + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + } + Pat::Rest(rest) => { + if rest.arg.is_invalid() { + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + _ => {} + } + } + + p + } + + #[allow(clippy::single_match)] + fn fold_stmt(&mut self, mut s: Stmt) -> Stmt { + match s { + Stmt::Decl(Decl::Fn(f)) => { + if self.should_remove(f.ident.to_id()) { + self.mark_as_candidate(f.function); + return Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + } + + s = Stmt::Decl(Decl::Fn(f)); + } + _ => {} + } + + let s = s.fold_children_with(self); + match s { + Stmt::Decl(Decl::Var(v)) if v.decls.is_empty() => { + return Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + } + _ => {} + } + + s + } + + /// This method make `name` of [VarDeclarator] to [Pat::Invalid] if it + /// should be removed. + fn fold_var_declarator(&mut self, mut d: VarDeclarator) -> VarDeclarator { + let old = self.in_lhs_of_var; + self.in_lhs_of_var = true; + let name = d.name.fold_with(self); + + self.in_lhs_of_var = false; + if name.is_invalid() { + d.init = self.mark_as_candidate(d.init); + } + let init = d.init.fold_with(self); + self.in_lhs_of_var = old; + + VarDeclarator { name, init, ..d } + } + + fn fold_var_declarators(&mut self, mut decls: Vec) -> Vec { + decls = decls.fold_children_with(self); + decls.retain(|d| !d.name.is_invalid()); + + decls + } +} + +pub fn remove_export(exports: Vec) -> impl Fold { + Repeat::new(RemoveExport { + state: State { + remove_exports: exports, + ..Default::default() + }, + in_lhs_of_var: false, + }) +} \ No newline at end of file diff --git a/crates/loader_compilation/tests/fixtures.rs b/crates/loader_compilation/tests/fixtures.rs index efb3880..3b78fdb 100644 --- a/crates/loader_compilation/tests/fixtures.rs +++ b/crates/loader_compilation/tests/fixtures.rs @@ -10,12 +10,8 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { let tests_path = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"))).join("tests"); let expected_path = tests_path.join(expected); let actual_path = tests_path.join(actual); - let plugin_path = tests_path.join("my_first_plugin.wasm"); + let mut options = Config::default(); - options.jsc.experimental.plugins = Some(vec![PluginConfig( - plugin_path.to_string_lossy().to_string(), - json!(null), - )]); let (result, _) = run_loaders( &[Arc::new(CompilationLoader::new()) as Arc>], &ResourceData::new(actual_path.to_string_lossy().to_string(), actual_path), diff --git a/crates/loader_compilation/tests/fixtures/basic/input.js b/crates/loader_compilation/tests/fixtures/basic/input.js index 54b82a0..f11cfe5 100644 --- a/crates/loader_compilation/tests/fixtures/basic/input.js +++ b/crates/loader_compilation/tests/fixtures/basic/input.js @@ -1 +1,8 @@ const a = 1; +const b = 2; + +export const dataLoader = { + b, +}; + +export default a; \ No newline at end of file From 8a3631bc0b4a737529d7d14c1b2bd4c761e8e6ca Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Thu, 23 Nov 2023 15:06:04 +0800 Subject: [PATCH 08/10] feat: support loader options (#8) * feat: support swc options * feat: support transform rule of remove export and keep export * fix: optimize code * chore: remove comments --- .../binding_options/src/options/raw_module.rs | 6 +- crates/loader_compilation/Cargo.toml | 4 +- crates/loader_compilation/src/compiler.rs | 12 -- crates/loader_compilation/src/lib.rs | 116 ++++++++++++++---- crates/loader_compilation/src/options.rs | 0 .../loader_compilation/src/transform/mod.rs | 91 ++++++++++++-- crates/loader_compilation/tests/fixtures.rs | 11 +- .../fixtures/basic/.ice/route-manifest.json | 22 ++++ 8 files changed, 210 insertions(+), 52 deletions(-) delete mode 100644 crates/loader_compilation/src/options.rs create mode 100644 crates/loader_compilation/tests/fixtures/basic/.ice/route-manifest.json diff --git a/crates/binding_options/src/options/raw_module.rs b/crates/binding_options/src/options/raw_module.rs index 9b909d5..2b550d5 100644 --- a/crates/binding_options/src/options/raw_module.rs +++ b/crates/binding_options/src/options/raw_module.rs @@ -27,7 +27,11 @@ pub fn get_builtin_loader(builtin: &str, options: Option<&str>) -> BoxLoader { if builtin.starts_with(COMPILATION_LOADER_IDENTIFIER) { return Arc::new( - loader_compilation::CompilationLoader::new().with_identifier(builtin.into()), + loader_compilation::CompilationLoader::new( + serde_json::from_str(options.unwrap_or("{}")).unwrap_or_else(|e| { + panic!("Could not parse builtin:compilation-loader options:{options:?},error: {e:?}") + }), + ).with_identifier(builtin.into()), ); } diff --git a/crates/loader_compilation/Cargo.toml b/crates/loader_compilation/Cargo.toml index 4e519ce..c252936 100644 --- a/crates/loader_compilation/Cargo.toml +++ b/crates/loader_compilation/Cargo.toml @@ -10,13 +10,15 @@ anyhow = { workspace = true } async-trait = { workspace = true } dashmap = { workspace = true } either = "1" -fxhash= "0.2.1" +fxhash = "0.2.1" +lazy_static = "1.4.0" once_cell = { workspace = true } rspack_ast = { path = "../.rspack_crates/rspack_ast" } rspack_core = { path = "../.rspack_crates/rspack_core" } rspack_error = { path = "../.rspack_crates/rspack_error" } rspack_loader_runner = { path = "../.rspack_crates/rspack_loader_runner" } rspack_plugin_javascript = { path = "../.rspack_crates/rspack_plugin_javascript" } +regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = "1.0.100" swc_config = { workspace = true } diff --git a/crates/loader_compilation/src/compiler.rs b/crates/loader_compilation/src/compiler.rs index f8a91a3..040d40a 100644 --- a/crates/loader_compilation/src/compiler.rs +++ b/crates/loader_compilation/src/compiler.rs @@ -203,18 +203,6 @@ impl SwcCompiler { program } - - pub fn comments(&self) -> &SingleThreadedComments { - &self.comments - } - - pub fn options(&self) -> &Options { - &self.options - } - - pub fn cm(&self) -> &Arc { - &self.cm - } } pub(crate) trait IntoJsAst { diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index fde47b2..29729c9 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -1,10 +1,12 @@ +use std::{path::Path, collections::HashMap, sync::Mutex}; +use lazy_static::lazy_static; use rspack_ast::RspackAst; -use rspack_core::{rspack_sources::SourceMap, LoaderRunnerContext}; +use rspack_core::{rspack_sources::SourceMap, LoaderRunnerContext, Mode}; use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; use rspack_error::{ - internal_error, Result, + internal_error, Result, Diagnostic, }; -use swc_core::base::config::{InputSourceMap, Options, OutputCharset}; +use swc_core::{base::config::{InputSourceMap, Options, OutputCharset, Config, TransformConfig}, ecma::transforms::react::Runtime}; use rspack_plugin_javascript::{ ast::{self, SourceMapConfig}, TransformOutput, @@ -14,14 +16,41 @@ mod transform; use transform::*; use compiler::{SwcCompiler, IntoJsAst}; + +pub struct LoaderOptions { + pub swc_options: Config, + pub transform_features: TransformFeatureOptions, +} + +pub struct CompilationOptions { + swc_options: Options, + transform_features: TransformFeatureOptions, +} pub struct CompilationLoader { identifier: Identifier, + loader_options: CompilationOptions, +} + +pub const COMPILATION_LOADER_IDENTIFIER: &str = "builtin:compilation-loader"; + +impl From for CompilationOptions { + fn from(value: LoaderOptions) -> Self { + let transform_features = TransformFeatureOptions::default(); + CompilationOptions { + swc_options: Options { + config: value.swc_options, + ..Default::default() + }, + transform_features, + } + } } impl CompilationLoader { - pub fn new() -> Self { + pub fn new(options: LoaderOptions) -> Self { Self { identifier: COMPILATION_LOADER_IDENTIFIER.into(), + loader_options: options.into(), } } @@ -32,6 +61,11 @@ impl CompilationLoader { } } +lazy_static! { + static ref GLOBAL_FILE_ACCESS: Mutex> = Mutex::new(HashMap::new()); + static ref GLOBAL_ROUTES_CONFIG: Mutex>> = Mutex::new(None); +} + #[async_trait::async_trait] impl Loader for CompilationLoader { async fn run(&self, loader_context: &mut LoaderContext<'_, LoaderRunnerContext>) -> Result<()> { @@ -39,31 +73,69 @@ impl Loader for CompilationLoader { let Some(content) = std::mem::take(&mut loader_context.content) else { return Err(internal_error!("No content found")); }; - // TODO: init loader with custom options. - let mut swc_options = Options::default(); - // TODO: merge config with built-in config. + let swc_options = { + let mut swc_options = self.loader_options.swc_options.clone(); + if swc_options.config.jsc.transform.as_ref().is_some() { + let mut transform = TransformConfig::default(); + let default_development = matches!(loader_context.context.options.mode, Mode::Development); + transform.react.development = Some(default_development); + transform.react.runtime = Some(Runtime::Automatic); + } - if let Some(pre_source_map) = std::mem::take(&mut loader_context.source_map) { - if let Ok(source_map) = pre_source_map.to_json() { - swc_options.config.input_source_map = Some(InputSourceMap:: Str(source_map)) + if let Some(pre_source_map) = std::mem::take(&mut loader_context.source_map) { + if let Ok(source_map) = pre_source_map.to_json() { + swc_options.config.input_source_map = Some(InputSourceMap:: Str(source_map)) + } + } + + if swc_options.config.jsc.experimental.plugins.is_some() { + loader_context.emit_diagnostic(Diagnostic::warn( + COMPILATION_LOADER_IDENTIFIER.to_string(), + "Experimental plugins are not currently supported.".to_string(), + 0, + 0, + )); } - } + if swc_options.config.jsc.target.is_some() && swc_options.config.env.is_some() { + loader_context.emit_diagnostic(Diagnostic::warn( + COMPILATION_LOADER_IDENTIFIER.to_string(), + "`env` and `jsc.target` cannot be used together".to_string(), + 0, + 0, + )); + } + swc_options + }; let devtool = &loader_context.context.options.devtool; let source = content.try_into_string()?; let compiler = SwcCompiler::new(resource_path.clone(), source.clone(), swc_options)?; - let transform_options = SwcPluginOptions { - keep_export: Some(KeepExportOptions { - export_names: vec!["default".to_string()], - }), - remove_export: Some(RemoveExportOptions { - remove_names: vec!["default".to_string()], - }), - }; + let transform_options = &self.loader_options.transform_features; + let compiler_context:&str = loader_context.context.options.context.as_ref(); + let mut file_access = GLOBAL_FILE_ACCESS.lock().unwrap(); + let mut routes_config = GLOBAL_ROUTES_CONFIG.lock().unwrap(); + let file_accessed = file_access.contains_key(&resource_path.to_string_lossy().to_string()); + + if routes_config.is_none() || file_accessed { + // Load routes config for transform. + let routes_config_path: std::path::PathBuf = Path::new(compiler_context).join(".ice/route-manifest.json"); + *routes_config = Some(load_routes_config(&routes_config_path).unwrap()); + + if file_accessed { + // If file accessed, then we need to clear the map for the current compilation. + file_access.clear(); + } + } + file_access.insert(resource_path.to_string_lossy().to_string(), true); + let built = compiler.parse(None, |_| { - transform(transform_options) + transform( + &resource_path, + routes_config.as_ref().unwrap(), + transform_options + ) })?; let codegen_options = ast::CodegenOptions { @@ -87,7 +159,7 @@ impl Loader for CompilationLoader { // If swc-loader is the latest loader available, // then loader produces AST, which could be used as an optimization. - if loader_context.loader_index() == 0 + if loader_context.loader_index() == 1 && (loader_context .current_loader() .composed_index_by_identifier(&self.identifier) @@ -109,8 +181,6 @@ impl Loader for CompilationLoader { } } -pub const COMPILATION_LOADER_IDENTIFIER: &str = "builtin:compilation-loader"; - impl Identifiable for CompilationLoader { fn identifier(&self) -> Identifier { self.identifier diff --git a/crates/loader_compilation/src/options.rs b/crates/loader_compilation/src/options.rs deleted file mode 100644 index e69de29..0000000 diff --git a/crates/loader_compilation/src/transform/mod.rs b/crates/loader_compilation/src/transform/mod.rs index 9e08e7e..589a9d4 100644 --- a/crates/loader_compilation/src/transform/mod.rs +++ b/crates/loader_compilation/src/transform/mod.rs @@ -1,9 +1,10 @@ +use std::path::Path; +use anyhow::{Error, Context}; use either::Either; +use serde::Deserialize; use swc_core::common::chain; use swc_core::ecma::{ - transforms::base::pass::noop, - visit::{as_folder, Fold, VisitMut, Visit}, - ast::Module, + transforms::base::pass::noop, visit::Fold, }; mod keep_export; @@ -14,14 +15,14 @@ use remove_export::remove_export; macro_rules! either { ($config:expr, $f:expr) => { - if let Some(config) = $config { + if let Some(config) = &$config { Either::Left($f(config)) } else { Either::Right(noop()) } }; ($config:expr, $f:expr, $enabled:expr) => { - if $enabled { + if $enabled() { either!($config, $f) } else { Either::Right(noop()) @@ -29,26 +30,94 @@ macro_rules! either { }; } +// Only define the stuct which is used in the following function. +#[derive(Deserialize, Debug)] +struct NestedRoutesManifest { + file: String, + children: Option>, +} + +fn get_routes_file(routes: Vec) -> Vec { + let mut result: Vec = vec![]; + for route in routes { + // Add default prefix of src/pages/ to the route file. + let mut path_str = String::from("src/pages/"); + path_str.push_str(&route.file); + + result.push(path_str.to_string()); + + if let Some(children) = route.children { + result.append(&mut get_routes_file(children)); + } + } + result +} + +fn parse_routes_config(c: String) -> Result, Error> { + let routes = serde_json::from_str(&c)?; + Ok(get_routes_file(routes)) +} + +pub(crate) fn load_routes_config(path: &Path) -> Result, Error> { + let content = std::fs::read_to_string(path).context("failed to read routes config")?; + parse_routes_config(content) +} + +fn match_route_entry(resource_path: &Path, routes: &Vec) -> bool { + let resource_path_str = resource_path.to_str().unwrap(); + for route in routes { + if resource_path_str.ends_with(&route.to_string()) { + return true; + } + } + false +} + +fn match_app_entry(resource_path: &Path) -> bool { + let resource_path_str = resource_path.to_str().unwrap(); + // File path ends with src/app.(ts|tsx|js|jsx) + let regex_for_app = regex::Regex::new(r"src/app\.(ts|tsx|js|jsx)$").unwrap(); + regex_for_app.is_match(resource_path_str) +} + +#[derive(Default, Debug, Clone)] pub struct KeepExportOptions { pub export_names: Vec, } +#[derive(Default, Debug, Clone)] pub struct RemoveExportOptions { pub remove_names: Vec, } -pub struct SwcPluginOptions { +#[derive(Default, Debug)] +pub struct TransformFeatureOptions { pub keep_export: Option, pub remove_export: Option, } -pub(crate) fn transform<'a>(plugin_options: SwcPluginOptions) -> impl Fold + 'a { +pub(crate) fn transform<'a>( + resource_path: &'a Path, + routes_config: &Vec, + feature_options: &TransformFeatureOptions, +) -> impl Fold + 'a { chain!( - either!(plugin_options.keep_export, |options: KeepExportOptions| { - keep_export(options.export_names) + either!(feature_options.keep_export, |options: &KeepExportOptions| { + let mut exports_name = options.export_names.clone(); + // Special case for app entry. + // When keep pageConfig, we should also keep the default export of app entry. + if match_app_entry(resource_path) && exports_name.contains(&String::from("pageConfig")) { + exports_name.push(String::from("default")); + } + keep_export(exports_name) + }, || { + match_app_entry(resource_path) || match_route_entry(resource_path, routes_config) }), - either!(plugin_options.remove_export, |options: RemoveExportOptions| { - remove_export(options.remove_names) + either!(feature_options.remove_export, |options: &RemoveExportOptions| { + remove_export(options.remove_names.clone()) + }, || { + // Remove export only work for app entry and route entry. + match_app_entry(resource_path) || match_route_entry(resource_path, routes_config) }), ) } \ No newline at end of file diff --git a/crates/loader_compilation/tests/fixtures.rs b/crates/loader_compilation/tests/fixtures.rs index 3b78fdb..2a4597a 100644 --- a/crates/loader_compilation/tests/fixtures.rs +++ b/crates/loader_compilation/tests/fixtures.rs @@ -1,24 +1,27 @@ use std::{str::FromStr,env, fs,path::{Path, PathBuf}, sync::Arc}; -use loader_compilation::CompilationLoader; +use loader_compilation::{CompilationLoader, LoaderOptions}; use rspack_core::{ run_loaders, CompilerContext, CompilerOptions, Loader, LoaderRunnerContext, ResourceData, SideEffectOption, }; -use serde_json::json; use swc_core::base::config::{PluginConfig, Config}; async fn loader_test(actual: impl AsRef, expected: impl AsRef) { let tests_path = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"))).join("tests"); let expected_path = tests_path.join(expected); let actual_path = tests_path.join(actual); + let parent_path = actual_path.parent().unwrap().to_path_buf(); let mut options = Config::default(); let (result, _) = run_loaders( - &[Arc::new(CompilationLoader::new()) as Arc>], + &[Arc::new(CompilationLoader::new(LoaderOptions { + swc_options: options, + transform_features: Default::default(), + })) as Arc>], &ResourceData::new(actual_path.to_string_lossy().to_string(), actual_path), &[], CompilerContext { options: std::sync::Arc::new(CompilerOptions { - context: rspack_core::Context::default(), + context: rspack_core::Context::new(parent_path.to_string_lossy().to_string()), dev_server: rspack_core::DevServerOptions::default(), devtool: rspack_core::Devtool::from("source-map".to_string()), mode: rspack_core::Mode::None, diff --git a/crates/loader_compilation/tests/fixtures/basic/.ice/route-manifest.json b/crates/loader_compilation/tests/fixtures/basic/.ice/route-manifest.json new file mode 100644 index 0000000..cfcf422 --- /dev/null +++ b/crates/loader_compilation/tests/fixtures/basic/.ice/route-manifest.json @@ -0,0 +1,22 @@ +[ + { + "path": "error", + "id": "error", + "file": "error.tsx", + "componentName": "error", + "layout": false, + "exports": [ + "default" + ] + }, + { + "index": true, + "id": "/", + "file": "index.tsx", + "componentName": "index", + "layout": false, + "exports": [ + "default" + ] + } +] \ No newline at end of file From 78e8b832aea7ae46fc0b32e8d742258e710efe3c Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 28 Nov 2023 13:59:16 +0800 Subject: [PATCH 09/10] fix: loader index --- crates/loader_compilation/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index 2ad1e23..ff2e4ce 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -163,7 +163,7 @@ impl Loader for CompilationLoader { // If swc-loader is the latest loader available, // then loader produces AST, which could be used as an optimization. - if loader_context.loader_index() == 1 + if loader_context.loader_index() == 0 && (loader_context .current_loader() .composed_index_by_identifier(&self.identifier) From 746b8d2efd57b3a554f82d3f0a96f59d84d7f9b5 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Wed, 29 Nov 2023 15:30:55 +0800 Subject: [PATCH 10/10] fix: simplify loader config (#15) * fix: simplify loader config * chore: fix test case * fix: built-in options --- Cargo.lock | 1 + crates/loader_compilation/Cargo.toml | 1 + crates/loader_compilation/src/lib.rs | 46 +++++++++++++++++-- .../loader_compilation/src/transform/mod.rs | 25 +++------- crates/loader_compilation/tests/fixtures.rs | 5 +- 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6133446..ba40dc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1483,6 +1483,7 @@ dependencies = [ "rspack_error", "rspack_loader_runner", "rspack_plugin_javascript", + "rspack_regex", "rspack_testing", "serde", "serde_json", diff --git a/crates/loader_compilation/Cargo.toml b/crates/loader_compilation/Cargo.toml index c252936..46e8ced 100644 --- a/crates/loader_compilation/Cargo.toml +++ b/crates/loader_compilation/Cargo.toml @@ -18,6 +18,7 @@ rspack_core = { path = "../.rspack_crates/rspack_core" } rspack_error = { path = "../.rspack_crates/rspack_error" } rspack_loader_runner = { path = "../.rspack_crates/rspack_loader_runner" } rspack_plugin_javascript = { path = "../.rspack_crates/rspack_plugin_javascript" } +rspack_regex = { path = "../.rspack_crates/rspack_regex" } regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = "1.0.100" diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index ff2e4ce..5bcb3c9 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -6,12 +6,18 @@ use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; use rspack_error::{ internal_error, Result, Diagnostic, }; -use swc_core::{base::config::{InputSourceMap, Options, OutputCharset, Config, TransformConfig}, ecma::transforms::react::Runtime}; +use swc_core::{ + base::config::{InputSourceMap, Options, OutputCharset, Config, TransformConfig}, + ecma::parser::{Syntax, TsConfig}, +}; + +use swc_config::{config_types::MergingOption, merge::Merge}; use rspack_plugin_javascript::{ ast::{self, SourceMapConfig}, TransformOutput, }; use serde::Deserialize; +use rspack_regex::RspackRegex; mod compiler; mod transform; @@ -19,16 +25,25 @@ mod transform; use transform::*; use compiler::{SwcCompiler, IntoJsAst}; +#[derive(Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", default)] +pub struct CompileRules { + // Built-in rules to exclude files from compilation, such as react, react-dom, etc. + exclude: Option>, +} + #[derive(Debug, Default, Deserialize)] #[serde(rename_all = "camelCase", default)] pub struct LoaderOptions { pub swc_options: Config, pub transform_features: TransformFeatureOptions, + pub compile_rules: CompileRules, } pub struct CompilationOptions { swc_options: Options, transform_features: TransformFeatureOptions, + compile_rules: CompileRules, } pub struct CompilationLoader { identifier: Identifier, @@ -39,13 +54,15 @@ pub const COMPILATION_LOADER_IDENTIFIER: &str = "builtin:compilation-loader"; impl From for CompilationOptions { fn from(value: LoaderOptions) -> Self { - let transform_features = TransformFeatureOptions::default(); + let transform_features = value.transform_features; + let compile_rules = value.compile_rules; CompilationOptions { swc_options: Options { config: value.swc_options, ..Default::default() }, transform_features, + compile_rules, } } } @@ -74,6 +91,17 @@ lazy_static! { impl Loader for CompilationLoader { async fn run(&self, loader_context: &mut LoaderContext<'_, LoaderRunnerContext>) -> Result<()> { let resource_path = loader_context.resource_path.to_path_buf(); + + if self.loader_options.compile_rules.exclude.is_some() { + let exclude = self.loader_options.compile_rules.exclude.as_ref().unwrap(); + for pattern in exclude { + let pattern = RspackRegex::new(pattern).unwrap(); + if pattern.test(&resource_path.to_string_lossy()) { + return Ok(()); + } + } + } + let Some(content) = std::mem::take(&mut loader_context.content) else { return Err(internal_error!("No content found")); }; @@ -84,7 +112,17 @@ impl Loader for CompilationLoader { let mut transform = TransformConfig::default(); let default_development = matches!(loader_context.context.options.mode, Mode::Development); transform.react.development = Some(default_development); - transform.react.runtime = Some(Runtime::Automatic); + swc_options + .config + .jsc + .transform + .merge(MergingOption::from(Some(transform))); + } + + let file_extension = resource_path.extension().unwrap(); + let ts_extensions = vec!["tsx", "ts", "mts"]; + if ts_extensions.iter().any(|ext| ext == &file_extension) { + swc_options.config.jsc.syntax = Some(Syntax::Typescript(TsConfig { tsx: true, decorators: true, ..Default::default() })); } if let Some(pre_source_map) = std::mem::take(&mut loader_context.source_map) { @@ -133,7 +171,7 @@ impl Loader for CompilationLoader { } } file_access.insert(resource_path.to_string_lossy().to_string(), true); - + let built = compiler.parse(None, |_| { transform( &resource_path, diff --git a/crates/loader_compilation/src/transform/mod.rs b/crates/loader_compilation/src/transform/mod.rs index ff2a10b..9bc09dd 100644 --- a/crates/loader_compilation/src/transform/mod.rs +++ b/crates/loader_compilation/src/transform/mod.rs @@ -80,24 +80,11 @@ fn match_app_entry(resource_path: &Path) -> bool { regex_for_app.is_match(resource_path_str) } -#[derive(Default, Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase", default)] -pub struct KeepExportOptions { - pub export_names: Vec, -} - -#[derive(Default, Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase", default)] -pub struct RemoveExportOptions { - pub remove_names: Vec, -} - - #[derive(Debug, Default, Deserialize)] #[serde(rename_all = "camelCase", default)] pub struct TransformFeatureOptions { - pub keep_export: Option, - pub remove_export: Option, + pub keep_export: Option>, + pub remove_export: Option>, } pub(crate) fn transform<'a>( @@ -106,8 +93,8 @@ pub(crate) fn transform<'a>( feature_options: &TransformFeatureOptions, ) -> impl Fold + 'a { chain!( - either!(feature_options.keep_export, |options: &KeepExportOptions| { - let mut exports_name = options.export_names.clone(); + either!(feature_options.keep_export, |options: &Vec| { + let mut exports_name = options.clone(); // Special case for app entry. // When keep pageConfig, we should also keep the default export of app entry. if match_app_entry(resource_path) && exports_name.contains(&String::from("pageConfig")) { @@ -117,8 +104,8 @@ pub(crate) fn transform<'a>( }, || { match_app_entry(resource_path) || match_route_entry(resource_path, routes_config) }), - either!(feature_options.remove_export, |options: &RemoveExportOptions| { - remove_export(options.remove_names.clone()) + either!(feature_options.remove_export, |options: &Vec| { + remove_export(options.clone()) }, || { // Remove export only work for app entry and route entry. match_app_entry(resource_path) || match_route_entry(resource_path, routes_config) diff --git a/crates/loader_compilation/tests/fixtures.rs b/crates/loader_compilation/tests/fixtures.rs index 2a4597a..ae7386a 100644 --- a/crates/loader_compilation/tests/fixtures.rs +++ b/crates/loader_compilation/tests/fixtures.rs @@ -3,7 +3,7 @@ use loader_compilation::{CompilationLoader, LoaderOptions}; use rspack_core::{ run_loaders, CompilerContext, CompilerOptions, Loader, LoaderRunnerContext, ResourceData, SideEffectOption, }; -use swc_core::base::config::{PluginConfig, Config}; +use swc_core::base::config::Config; async fn loader_test(actual: impl AsRef, expected: impl AsRef) { let tests_path = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"))).join("tests"); @@ -16,10 +16,13 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { &[Arc::new(CompilationLoader::new(LoaderOptions { swc_options: options, transform_features: Default::default(), + compile_rules: Default::default(), })) as Arc>], &ResourceData::new(actual_path.to_string_lossy().to_string(), actual_path), &[], CompilerContext { + module: None, + module_context: None, options: std::sync::Arc::new(CompilerOptions { context: rspack_core::Context::new(parent_path.to_string_lossy().to_string()), dev_server: rspack_core::DevServerOptions::default(),