From e7c2d1e932928a497c826f568af0e69c6002f825 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 14 Jun 2022 10:48:25 +0200 Subject: [PATCH 001/672] add initial dev-server and next-dev cli --- packages/next-swc/crates/next-dev/Cargo.toml | 29 +++++++++++ packages/next-swc/crates/next-dev/build.rs | 5 ++ packages/next-swc/crates/next-dev/src/main.rs | 52 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 packages/next-swc/crates/next-dev/Cargo.toml create mode 100644 packages/next-swc/crates/next-dev/build.rs create mode 100644 packages/next-swc/crates/next-dev/src/main.rs diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml new file mode 100644 index 00000000000000..191414e5da0215 --- /dev/null +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "next-dev" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "next-dev" +path = "src/main.rs" +bench = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +"clap" = { version = "3.1.3", features = ["derive"] } +"turbo-tasks" = { path = "../turbo-tasks" } +"turbo-tasks-memory" = { path = "../turbo-tasks-memory" } +"turbo-tasks-rocksdb" = { path = "../turbo-tasks-rocksdb" } +"turbo-tasks-fs" = { path = "../turbo-tasks-fs" } +"turbopack" = { path = "../turbopack" } +"turbopack-core" = { path = "../turbopack-core" } +"turbopack-dev-server" = { path = "../turbopack-dev-server" } +anyhow = "1.0.47" +tokio = { version = "1.11.0", features = ["full", "tracing"] } +json = "0.12.4" +serde = "1.0.136" +console-subscriber = "0.1.6" + +[build-dependencies] +"turbo-tasks-build" = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-dev/build.rs b/packages/next-swc/crates/next-dev/build.rs new file mode 100644 index 00000000000000..1673efed59cce6 --- /dev/null +++ b/packages/next-swc/crates/next-dev/build.rs @@ -0,0 +1,5 @@ +use turbo_tasks_build::generate_register; + +fn main() { + generate_register(); +} diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs new file mode 100644 index 00000000000000..fa905838a5d6f7 --- /dev/null +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -0,0 +1,52 @@ +use std::env::current_dir; + +use anyhow::anyhow; +use turbo_tasks::TurboTasks; +use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; +use turbo_tasks_memory::MemoryBackend; +use turbopack::{ecmascript::target::CompileTarget, GraphOptionsVc, ModuleAssetContextVc}; +use turbopack_core::{context::AssetContextVc, source_asset::SourceAssetVc}; +use turbopack_dev_server::DevServerVc; + +#[tokio::main] +async fn main() { + #[cfg(debug_assertions)] + console_subscriber::init(); + register(); + + let dir = current_dir() + .unwrap() + .to_str() + .ok_or_else(|| anyhow!("current directory contains invalid characters")) + .unwrap() + .to_string(); + + let tt = TurboTasks::new(MemoryBackend::new()); + let server = tt + .run_once(async move { + let fs = DiskFileSystemVc::new("project".to_string(), dir).into(); + let root = FileSystemPathVc::new(fs, "demo"); + let source_asset = + SourceAssetVc::new(FileSystemPathVc::new(fs, "demo/index.js")).into(); + let context: AssetContextVc = ModuleAssetContextVc::new( + root, + GraphOptionsVc::new(true, false, CompileTarget::Current.into()), + ) + .into(); + let module = context.process(source_asset); + + let server = DevServerVc::new(root, module); + server.listen().await + }) + .await + .unwrap(); + server.future.await.unwrap() +} + +fn register() { + turbo_tasks::register(); + turbo_tasks_fs::register(); + turbopack_dev_server::register(); + turbopack::register(); + include!(concat!(env!("OUT_DIR"), "/register.rs")); +} From b3df7a862e9212017ebce27791e9181428eec06f Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 14 Jun 2022 12:40:31 +0200 Subject: [PATCH 002/672] abstract lazy graph into Asset decorator enable watching for dev server --- packages/next-swc/crates/next-dev/src/main.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index fa905838a5d6f7..afecdb0c8cadd6 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -5,7 +5,7 @@ use turbo_tasks::TurboTasks; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::MemoryBackend; use turbopack::{ecmascript::target::CompileTarget, GraphOptionsVc, ModuleAssetContextVc}; -use turbopack_core::{context::AssetContextVc, source_asset::SourceAssetVc}; +use turbopack_core::{context::AssetContextVc, lazy::LazyAssetVc, source_asset::SourceAssetVc}; use turbopack_dev_server::DevServerVc; #[tokio::main] @@ -24,18 +24,21 @@ async fn main() { let tt = TurboTasks::new(MemoryBackend::new()); let server = tt .run_once(async move { - let fs = DiskFileSystemVc::new("project".to_string(), dir).into(); + let disk_fs = DiskFileSystemVc::new("project".to_string(), dir); + let fs = disk_fs.into(); let root = FileSystemPathVc::new(fs, "demo"); let source_asset = SourceAssetVc::new(FileSystemPathVc::new(fs, "demo/index.js")).into(); let context: AssetContextVc = ModuleAssetContextVc::new( root, - GraphOptionsVc::new(true, false, CompileTarget::Current.into()), + GraphOptionsVc::new(false, false, CompileTarget::Current.into()), ) .into(); let module = context.process(source_asset); + let lazy_asset = LazyAssetVc::new(module).into(); - let server = DevServerVc::new(root, module); + let server = DevServerVc::new(root, lazy_asset); + disk_fs.await?.start_watching()?; server.listen().await }) .await From 54985ab83dc2152bc0f72e52629c3a309514fffd Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 28 Jun 2022 10:21:04 +0200 Subject: [PATCH 003/672] chunking and bugfixes --- packages/next-swc/crates/next-dev/src/main.rs | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index afecdb0c8cadd6..dc785f9a3df438 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -5,8 +5,16 @@ use turbo_tasks::TurboTasks; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::MemoryBackend; use turbopack::{ecmascript::target::CompileTarget, GraphOptionsVc, ModuleAssetContextVc}; -use turbopack_core::{context::AssetContextVc, lazy::LazyAssetVc, source_asset::SourceAssetVc}; -use turbopack_dev_server::DevServerVc; +use turbopack_core::{ + chunk::{ + dev::{DevChunkingContext, DevChunkingContextVc}, + ChunkableAssetVc, + }, + context::AssetContextVc, + lazy::LazyAssetVc, + source_asset::SourceAssetVc, +}; +use turbopack_dev_server::{fs::DevServerFileSystemVc, html::DevHtmlAsset, DevServerVc}; #[tokio::main] async fn main() { @@ -35,9 +43,23 @@ async fn main() { ) .into(); let module = context.process(source_asset); - let lazy_asset = LazyAssetVc::new(module).into(); + let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); + let chunking_context: DevChunkingContextVc = DevChunkingContext { + context_path: root, + root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), + } + .into(); + let chunk_group = chunking_context + .as_chunking_context() + .as_chunk_group(ChunkableAssetVc::cast_from(module)); + let html = DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_group, + } + .into(); + let lazy_asset = LazyAssetVc::new(html).into(); - let server = DevServerVc::new(root, lazy_asset); + let server = DevServerVc::new(FileSystemPathVc::new(dev_server_fs, ""), lazy_asset); disk_fs.await?.start_watching()?; server.listen().await }) From db41ef8432f65058b8a5335c2ff65a9f9bf58543 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 29 Jun 2022 09:40:11 +0200 Subject: [PATCH 004/672] place the persistent cache behind a feature flag --- packages/next-swc/crates/next-dev/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 191414e5da0215..82c7ecf07237b8 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -14,7 +14,6 @@ bench = false "clap" = { version = "3.1.3", features = ["derive"] } "turbo-tasks" = { path = "../turbo-tasks" } "turbo-tasks-memory" = { path = "../turbo-tasks-memory" } -"turbo-tasks-rocksdb" = { path = "../turbo-tasks-rocksdb" } "turbo-tasks-fs" = { path = "../turbo-tasks-fs" } "turbopack" = { path = "../turbopack" } "turbopack-core" = { path = "../turbopack-core" } From 667507c5caa6f6443f415b242e358ed4c52a6f31 Mon Sep 17 00:00:00 2001 From: Leah Date: Wed, 29 Jun 2022 17:34:15 +0200 Subject: [PATCH 005/672] don't like these quoted names lol --- packages/next-swc/crates/next-dev/Cargo.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 82c7ecf07237b8..37b44aecd97971 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -11,13 +11,13 @@ bench = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -"clap" = { version = "3.1.3", features = ["derive"] } -"turbo-tasks" = { path = "../turbo-tasks" } -"turbo-tasks-memory" = { path = "../turbo-tasks-memory" } -"turbo-tasks-fs" = { path = "../turbo-tasks-fs" } -"turbopack" = { path = "../turbopack" } -"turbopack-core" = { path = "../turbopack-core" } -"turbopack-dev-server" = { path = "../turbopack-dev-server" } +clap = { version = "3.1.3", features = ["derive"] } +turbo-tasks = { path = "../turbo-tasks" } +turbo-tasks-memory = { path = "../turbo-tasks-memory" } +turbo-tasks-fs = { path = "../turbo-tasks-fs" } +turbopack = { path = "../turbopack" } +turbopack-core = { path = "../turbopack-core" } +turbopack-dev-server = { path = "../turbopack-dev-server" } anyhow = "1.0.47" tokio = { version = "1.11.0", features = ["full", "tracing"] } json = "0.12.4" @@ -25,4 +25,4 @@ serde = "1.0.136" console-subscriber = "0.1.6" [build-dependencies] -"turbo-tasks-build" = { path = "../turbo-tasks-build" } +turbo-tasks-build = { path = "../turbo-tasks-build" } From 89f6ad1151e00c8d499d5648f978f56ed6647603 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 30 Jun 2022 13:54:04 +0200 Subject: [PATCH 006/672] cleanup and documentation --- packages/next-swc/crates/next-dev/src/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index dc785f9a3df438..b16c74b86c2bb1 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -8,7 +8,7 @@ use turbopack::{ecmascript::target::CompileTarget, GraphOptionsVc, ModuleAssetCo use turbopack_core::{ chunk::{ dev::{DevChunkingContext, DevChunkingContextVc}, - ChunkableAssetVc, + ChunkGroupVc, ChunkableAssetVc, }, context::AssetContextVc, lazy::LazyAssetVc, @@ -49,9 +49,10 @@ async fn main() { root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), } .into(); - let chunk_group = chunking_context - .as_chunking_context() - .as_chunk_group(ChunkableAssetVc::cast_from(module)); + let chunk_group = ChunkGroupVc::from_asset( + ChunkableAssetVc::cast_from(module), + chunking_context.into(), + ); let html = DevHtmlAsset { path: FileSystemPathVc::new(dev_server_fs, "index.html"), chunk_group, From 878dd09578bd6a90e71a56772a5829e24a6733f3 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 7 Jul 2022 14:27:15 +0200 Subject: [PATCH 007/672] improve visualization make TransientValue functional make console-subscriber an optional feature avoid cloning when calling a function capture timings of task executions fix LazyAsset expose graph from dev server --- packages/next-swc/crates/next-dev/Cargo.toml | 7 ++-- packages/next-swc/crates/next-dev/src/main.rs | 36 +++++++++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 37b44aecd97971..5aa089b301f005 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -10,6 +10,9 @@ bench = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +tokio_console = ["dep:console-subscriber", "tokio/tracing", "turbo-tasks/tokio_tracing"] + [dependencies] clap = { version = "3.1.3", features = ["derive"] } turbo-tasks = { path = "../turbo-tasks" } @@ -19,10 +22,10 @@ turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } anyhow = "1.0.47" -tokio = { version = "1.11.0", features = ["full", "tracing"] } +tokio = { version = "1.11.0", features = ["full"] } json = "0.12.4" serde = "1.0.136" -console-subscriber = "0.1.6" +console-subscriber = { version = "0.1.6", optional = true } [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index b16c74b86c2bb1..609785e3419f9e 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -1,9 +1,10 @@ -use std::env::current_dir; +use std::{env::current_dir, sync::Arc}; use anyhow::anyhow; -use turbo_tasks::TurboTasks; +use clap::Parser; +use turbo_tasks::{TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; -use turbo_tasks_memory::MemoryBackend; +use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; use turbopack::{ecmascript::target::CompileTarget, GraphOptionsVc, ModuleAssetContextVc}; use turbopack_core::{ chunk::{ @@ -16,12 +17,18 @@ use turbopack_core::{ }; use turbopack_dev_server::{fs::DevServerFileSystemVc, html::DevHtmlAsset, DevServerVc}; +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args {} + #[tokio::main] async fn main() { - #[cfg(debug_assertions)] + #[cfg(feature = "tokio_console")] console_subscriber::init(); register(); + let Args {} = Args::parse(); + let dir = current_dir() .unwrap() .to_str() @@ -31,6 +38,7 @@ async fn main() { let tt = TurboTasks::new(MemoryBackend::new()); let server = tt + .clone() .run_once(async move { let disk_fs = DiskFileSystemVc::new("project".to_string(), dir); let fs = disk_fs.into(); @@ -60,13 +68,29 @@ async fn main() { .into(); let lazy_asset = LazyAssetVc::new(html).into(); - let server = DevServerVc::new(FileSystemPathVc::new(dev_server_fs, ""), lazy_asset); + let server = DevServerVc::new( + FileSystemPathVc::new(dev_server_fs, ""), + lazy_asset, + TransientValue::new(Arc::new(move |path| { + if path == "/__turbo_tasks_graph__" { + let mut stats = Stats::new(); + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + stats.add_id(b, task); + }); + let tree = stats.treeify(); + let graph = viz::visualize_stats_tree(tree); + return Some(viz::wrap_html(&graph)); + } + None + })), + ); disk_fs.await?.start_watching()?; server.listen().await }) .await .unwrap(); - server.future.await.unwrap() + server.future.await.unwrap(); } fn register() { From 99e015c41f3f7843f902d867de7ee17dd6d5a0d8 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 8 Jul 2022 11:40:55 +0200 Subject: [PATCH 008/672] complete strongly consistent read performance improvements --- packages/next-swc/crates/next-dev/src/main.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 609785e3419f9e..2637699a967a11 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -1,4 +1,7 @@ -use std::{env::current_dir, sync::Arc}; +#![feature(future_join)] +#![feature(future_poll_fn)] + +use std::{env::current_dir, future::join, sync::Arc, time::Instant}; use anyhow::anyhow; use clap::Parser; @@ -29,6 +32,8 @@ async fn main() { let Args {} = Args::parse(); + let start = Instant::now(); + let dir = current_dir() .unwrap() .to_str() @@ -37,6 +42,7 @@ async fn main() { .to_string(); let tt = TurboTasks::new(MemoryBackend::new()); + let tt_clone = tt.clone(); let server = tt .clone() .run_once(async move { @@ -90,7 +96,16 @@ async fn main() { }) .await .unwrap(); - server.future.await.unwrap(); + join! { + async move { + tt_clone.wait_done().await; + println!("initial request prepared in {} ms", start.elapsed().as_millis()); + }, + async { + server.future.await.unwrap() + } + } + .await; } fn register() { From cd647d7fc4ed3d188e1a45b7914dc8d532753eaf Mon Sep 17 00:00:00 2001 From: Leah Date: Tue, 12 Jul 2022 17:09:16 +0200 Subject: [PATCH 009/672] match `next dev` args --- packages/next-swc/crates/next-dev/src/main.rs | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 2637699a967a11..a06813d24816a0 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -1,7 +1,7 @@ #![feature(future_join)] #![feature(future_poll_fn)] -use std::{env::current_dir, future::join, sync::Arc, time::Instant}; +use std::{env::current_dir, future::join, net::IpAddr, path::PathBuf, sync::Arc, time::Instant}; use anyhow::anyhow; use clap::Parser; @@ -22,7 +22,20 @@ use turbopack_dev_server::{fs::DevServerFileSystemVc, html::DevHtmlAsset, DevSer #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] -struct Args {} +struct Cli { + /// The directory of the Next.js application. + /// If no directory is provided, the current directory will be used. + #[clap(value_parser)] + dir: Option, + + /// The port number on which to start the application + #[clap(short, long, value_parser, default_value_t = 3000)] + port: u16, + + /// Hostname on which to start the application + #[clap(short = 'H', long, value_parser, default_value = "127.0.0.1")] + hostname: IpAddr, +} #[tokio::main] async fn main() { @@ -30,12 +43,13 @@ async fn main() { console_subscriber::init(); register(); - let Args {} = Args::parse(); + let args = Cli::parse(); let start = Instant::now(); - let dir = current_dir() - .unwrap() + let dir = args + .dir + .unwrap_or_else(|| current_dir().unwrap()) .to_str() .ok_or_else(|| anyhow!("current directory contains invalid characters")) .unwrap() @@ -48,9 +62,9 @@ async fn main() { .run_once(async move { let disk_fs = DiskFileSystemVc::new("project".to_string(), dir); let fs = disk_fs.into(); - let root = FileSystemPathVc::new(fs, "demo"); + let root = FileSystemPathVc::new(fs, "src"); let source_asset = - SourceAssetVc::new(FileSystemPathVc::new(fs, "demo/index.js")).into(); + SourceAssetVc::new(FileSystemPathVc::new(fs, "src/index.js")).into(); let context: AssetContextVc = ModuleAssetContextVc::new( root, GraphOptionsVc::new(false, false, CompileTarget::Current.into()), @@ -77,6 +91,7 @@ async fn main() { let server = DevServerVc::new( FileSystemPathVc::new(dev_server_fs, ""), lazy_asset, + TransientValue::new((args.hostname, args.port).into()), TransientValue::new(Arc::new(move |path| { if path == "/__turbo_tasks_graph__" { let mut stats = Stats::new(); From 2909fd07caa2243d27705295243321a334cee3af Mon Sep 17 00:00:00 2001 From: Leah Date: Tue, 12 Jul 2022 17:17:23 +0200 Subject: [PATCH 010/672] fmt --- packages/next-swc/crates/next-dev/src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index a06813d24816a0..34ce29cb63f766 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -63,8 +63,7 @@ async fn main() { let disk_fs = DiskFileSystemVc::new("project".to_string(), dir); let fs = disk_fs.into(); let root = FileSystemPathVc::new(fs, "src"); - let source_asset = - SourceAssetVc::new(FileSystemPathVc::new(fs, "src/index.js")).into(); + let source_asset = SourceAssetVc::new(FileSystemPathVc::new(fs, "src/index.js")).into(); let context: AssetContextVc = ModuleAssetContextVc::new( root, GraphOptionsVc::new(false, false, CompileTarget::Current.into()), From 85ae4b5036b85bf14216de31d110de73f7a8089b Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 12 Jul 2022 16:31:13 +0200 Subject: [PATCH 011/672] add bootstrap logic for chunks --- packages/next-swc/crates/next-dev/src/main.rs | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 34ce29cb63f766..bba7b431f783e6 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -8,7 +8,10 @@ use clap::Parser; use turbo_tasks::{TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; -use turbopack::{ecmascript::target::CompileTarget, GraphOptionsVc, ModuleAssetContextVc}; +use turbopack::{ + ecmascript::{target::CompileTarget, ModuleAssetVc as EcmascriptModuleAssetVc}, + GraphOptionsVc, ModuleAssetContextVc, +}; use turbopack_core::{ chunk::{ dev::{DevChunkingContext, DevChunkingContextVc}, @@ -76,16 +79,31 @@ async fn main() { root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), } .into(); - let chunk_group = ChunkGroupVc::from_asset( - ChunkableAssetVc::cast_from(module), - chunking_context.into(), - ); - let html = DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_group, - } - .into(); - let lazy_asset = LazyAssetVc::new(html).into(); + let entry_asset = + if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { + let chunk = ecmascript.as_evaluated_chunk(chunking_context.into()); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_group, + } + .into() + } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { + let chunk = chunkable.as_chunk(chunking_context.into()); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_group, + } + .into() + } else { + // TODO convert into a serve-able asset + return Err(anyhow!( + "Entry module is not chunkable, so it can't be used to bootstrap the \ + application" + )); + }; + let lazy_asset = LazyAssetVc::new(entry_asset).into(); let server = DevServerVc::new( FileSystemPathVc::new(dev_server_fs, ""), From f134e1104c0fdf4d50e41bb5abed92ff8feaabe0 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 18 Jul 2022 18:11:13 +0200 Subject: [PATCH 012/672] fixup paths --- packages/next-swc/crates/next-dev/src/main.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index bba7b431f783e6..154c1ace1525e9 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -65,7 +65,7 @@ async fn main() { .run_once(async move { let disk_fs = DiskFileSystemVc::new("project".to_string(), dir); let fs = disk_fs.into(); - let root = FileSystemPathVc::new(fs, "src"); + let root = FileSystemPathVc::new(fs, ""); let source_asset = SourceAssetVc::new(FileSystemPathVc::new(fs, "src/index.js")).into(); let context: AssetContextVc = ModuleAssetContextVc::new( root, @@ -76,7 +76,8 @@ async fn main() { let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let chunking_context: DevChunkingContextVc = DevChunkingContext { context_path: root, - root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), + chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), + asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static"), } .into(); let entry_asset = From aa640550551b2f646ce1122eb4cf6ba94aae1abe Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 18 Jul 2022 20:26:10 +0200 Subject: [PATCH 013/672] add util for formating durations --- packages/next-swc/crates/next-dev/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 154c1ace1525e9..b877704b295ebe 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -5,7 +5,7 @@ use std::{env::current_dir, future::join, net::IpAddr, path::PathBuf, sync::Arc, use anyhow::anyhow; use clap::Parser; -use turbo_tasks::{TransientValue, TurboTasks}; +use turbo_tasks::{util::FormatDuration, TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; use turbopack::{ @@ -132,7 +132,7 @@ async fn main() { join! { async move { tt_clone.wait_done().await; - println!("initial request prepared in {} ms", start.elapsed().as_millis()); + println!("initial request prepared in {}", FormatDuration(start.elapsed())); }, async { server.future.await.unwrap() From 099e5c7c4b0e8c169394aecbc3fcf27697968e0d Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Mon, 18 Jul 2022 17:56:26 -0400 Subject: [PATCH 014/672] next-dev: Fix watching relative directories Fixes vercel/turbo#107 --- packages/next-swc/crates/next-dev/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index b877704b295ebe..4037ac50ccf709 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -52,7 +52,9 @@ async fn main() { let dir = args .dir - .unwrap_or_else(|| current_dir().unwrap()) + .map(|dir| dir.canonicalize()) + .unwrap_or_else(|| current_dir()) + .unwrap() .to_str() .ok_or_else(|| anyhow!("current directory contains invalid characters")) .unwrap() From a12541a06adc3239f6e4d78b6dd45f577f9d3a64 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 19 Jul 2022 10:53:47 +0200 Subject: [PATCH 015/672] add performance table --- packages/next-swc/crates/next-dev/src/main.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 4037ac50ccf709..26e448c11798db 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -120,8 +120,18 @@ async fn main() { stats.add_id(b, task); }); let tree = stats.treeify(); - let graph = viz::visualize_stats_tree(tree); - return Some(viz::wrap_html(&graph)); + let graph = viz::graph::visualize_stats_tree(tree); + return Some(viz::graph::wrap_html(&graph)); + } + if path == "/__turbo_tasks_table__" { + let mut stats = Stats::new(); + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + stats.add_id(b, task); + }); + let tree = stats.treeify(); + let table = viz::table::create_table(tree); + return Some(viz::table::wrap_html(&table)); } None })), From fb1bc5a55ff5bacb009164ba970efaee1a8d42b6 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 20 Jul 2022 19:49:27 +0200 Subject: [PATCH 016/672] make websocket task special as it never completes aggregate timings before displaying --- packages/next-swc/crates/next-dev/src/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 26e448c11798db..8460fcf195c4e5 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -1,7 +1,14 @@ #![feature(future_join)] #![feature(future_poll_fn)] -use std::{env::current_dir, future::join, net::IpAddr, path::PathBuf, sync::Arc, time::Instant}; +use std::{ + env::current_dir, + future::join, + net::IpAddr, + path::PathBuf, + sync::Arc, + time::{Duration, Instant}, +}; use anyhow::anyhow; use clap::Parser; @@ -145,6 +152,10 @@ async fn main() { async move { tt_clone.wait_done().await; println!("initial request prepared in {}", FormatDuration(start.elapsed())); + loop { + let (elapsed, count) = tt_clone.wait_next_done(Duration::from_millis(100)).await; + println!("updated {} tasks in {}", count, FormatDuration(elapsed)); + } }, async { server.future.await.unwrap() From 144e95bc4e1e8e93e6585ee2544c7398e82f7a5e Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 21 Jul 2022 13:22:23 +0200 Subject: [PATCH 017/672] allow to switch to eager compiling --- packages/next-swc/crates/next-dev/src/main.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 8460fcf195c4e5..4b5d16a03bf1ff 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -45,6 +45,11 @@ struct Cli { /// Hostname on which to start the application #[clap(short = 'H', long, value_parser, default_value = "127.0.0.1")] hostname: IpAddr, + + /// Compile all, instead of only compiling referenced assets when their + /// parent asset is requested + #[clap(long)] + eager_compile: bool, } #[tokio::main] @@ -113,11 +118,15 @@ async fn main() { application" )); }; - let lazy_asset = LazyAssetVc::new(entry_asset).into(); + + let mut served_asset = entry_asset; + if !args.eager_compile { + served_asset = LazyAssetVc::new(served_asset).into(); + } let server = DevServerVc::new( FileSystemPathVc::new(dev_server_fs, ""), - lazy_asset, + served_asset, TransientValue::new((args.hostname, args.port).into()), TransientValue::new(Arc::new(move |path| { if path == "/__turbo_tasks_graph__" { From a55a831b398dde470c850bc1c901dc92ca18fb37 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Fri, 22 Jul 2022 18:36:08 +0800 Subject: [PATCH 018/672] Node Module Trace webpack plugin (vercel/turbo#140) * Initialize Node.js/TypeScript workspace * node-module-trace Webpack plugin * Add new fmt checks to pipeline * Popup unwind error * Implement --exact flag * Yarn 3.2.2 * Reformat toml files * Fix socket io test, 100ms timeout is too long * remove unnecessary CI cache config * regenerate lockfile from old lockfile, align the dependencies version * Run nmt tests in system tmp dir * Apply code review suggestions * allow to wait for task completion and propagate errors and panics * revert method addition * spawn_root_task should be sync Co-authored-by: Tobias Koppers --- packages/next-swc/crates/next-dev/Cargo.toml | 18 +++++++++++------- packages/next-swc/crates/next-dev/src/main.rs | 13 +++++++------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 5aa089b301f005..e44127d085d083 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -11,21 +11,25 @@ bench = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -tokio_console = ["dep:console-subscriber", "tokio/tracing", "turbo-tasks/tokio_tracing"] +tokio_console = [ + "dep:console-subscriber", + "tokio/tracing", + "turbo-tasks/tokio_tracing", +] [dependencies] +anyhow = "1.0.47" clap = { version = "3.1.3", features = ["derive"] } +console-subscriber = { version = "0.1.6", optional = true } +json = "0.12.4" +serde = "1.0.136" +tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } -turbo-tasks-memory = { path = "../turbo-tasks-memory" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } +turbo-tasks-memory = { path = "../turbo-tasks-memory" } turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } -anyhow = "1.0.47" -tokio = { version = "1.11.0", features = ["full"] } -json = "0.12.4" -serde = "1.0.136" -console-subscriber = { version = "0.1.6", optional = true } [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 4b5d16a03bf1ff..e811ea63e1f980 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -54,14 +54,14 @@ struct Cli { #[tokio::main] async fn main() { + let start = Instant::now(); + #[cfg(feature = "tokio_console")] console_subscriber::init(); register(); let args = Cli::parse(); - let start = Instant::now(); - let dir = args .dir .map(|dir| dir.canonicalize()) @@ -159,11 +159,12 @@ async fn main() { .unwrap(); join! { async move { - tt_clone.wait_done().await; - println!("initial request prepared in {}", FormatDuration(start.elapsed())); + let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; + println!("initial compilation {} ({} task execution, {} tasks)", FormatDuration(start.elapsed()), FormatDuration(elapsed), count); + loop { - let (elapsed, count) = tt_clone.wait_next_done(Duration::from_millis(100)).await; - println!("updated {} tasks in {}", count, FormatDuration(elapsed)); + let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::from_millis(100)).await; + println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); } }, async { From d4a50bfd0c2ae1604f5996994fad1212e55f2032 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 27 Jul 2022 10:13:29 +0200 Subject: [PATCH 019/672] reduce number of clippy warnings (vercel/turbo#164) --- packages/next-swc/crates/next-dev/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index e811ea63e1f980..6f287e07327b39 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -65,7 +65,7 @@ async fn main() { let dir = args .dir .map(|dir| dir.canonicalize()) - .unwrap_or_else(|| current_dir()) + .unwrap_or_else(current_dir) .unwrap() .to_str() .ok_or_else(|| anyhow!("current directory contains invalid characters")) From eb417b1e2572cd78a058efd7e6ada563961ae50d Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 27 Jul 2022 11:36:10 +0200 Subject: [PATCH 020/672] cleanup compile target (vercel/turbo#157) --- packages/next-swc/crates/next-dev/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 6f287e07327b39..a05addb09bcc13 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -16,7 +16,7 @@ use turbo_tasks::{util::FormatDuration, TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; use turbopack::{ - ecmascript::{target::CompileTarget, ModuleAssetVc as EcmascriptModuleAssetVc}, + ecmascript::{target::CompileTargetVc, ModuleAssetVc as EcmascriptModuleAssetVc}, GraphOptionsVc, ModuleAssetContextVc, }; use turbopack_core::{ @@ -83,7 +83,7 @@ async fn main() { let source_asset = SourceAssetVc::new(FileSystemPathVc::new(fs, "src/index.js")).into(); let context: AssetContextVc = ModuleAssetContextVc::new( root, - GraphOptionsVc::new(false, false, CompileTarget::Current.into()), + GraphOptionsVc::new(false, false, CompileTargetVc::current()), ) .into(); let module = context.process(source_asset); From 45b409393dab73a4a09d3abbd2a96e68f04d5b42 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 27 Jul 2022 12:09:11 -0700 Subject: [PATCH 021/672] Move browser opening to next-dev cli (vercel/turbo#169) Cherry-picking this from my work on the next-dev test runner. This moves browser opening from the turbopack-dev-server crate into the next-dev crate, which has the cli entrypoint that runs the dev server. It looks like the dev server package is meant to be used as a library (it's only a library crate), and having this external side effect feels unexpected and makes it difficult to use this crate in situations like a test runner for next-dev, where we should test with a headless web browser. Alternatively, opening the browser could be an option passed when creating the dev server, but this feels a bit cleaner to me. Test Plan: `cargo run -p next-dev` and verify the browser still opens and successfully connects to the dev server. --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/src/main.rs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index e44127d085d083..4a73dbfa3b1b2c 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -30,6 +30,7 @@ turbo-tasks-memory = { path = "../turbo-tasks-memory" } turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } +webbrowser = "0.7.1" [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index a05addb09bcc13..3a839402878fd3 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -157,6 +157,17 @@ async fn main() { }) .await .unwrap(); + + { + let index_uri = if server.addr.ip().is_loopback() { + format!("http://localhost:{}", server.addr.port()) + } else { + format!("http://{}", server.addr) + }; + println!("server listening on: {uri}", uri = index_uri); + let _ = webbrowser::open(&index_uri); + } + join! { async move { let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; From 52557b1c4d0dded98825e63d5c88129f2d3163d9 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 28 Jul 2022 00:33:14 +0200 Subject: [PATCH 022/672] introduce an Environment and track that for the graph and Assets (vercel/turbo#167) --- packages/next-swc/crates/next-dev/src/main.rs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 3a839402878fd3..fff628564f76fc 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -12,19 +12,17 @@ use std::{ use anyhow::anyhow; use clap::Parser; -use turbo_tasks::{util::FormatDuration, TransientValue, TurboTasks}; +use turbo_tasks::{util::FormatDuration, TransientValue, TurboTasks, Value}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; -use turbopack::{ - ecmascript::{target::CompileTargetVc, ModuleAssetVc as EcmascriptModuleAssetVc}, - GraphOptionsVc, ModuleAssetContextVc, -}; +use turbopack::{ecmascript::ModuleAssetVc as EcmascriptModuleAssetVc, ModuleAssetContextVc}; use turbopack_core::{ chunk::{ dev::{DevChunkingContext, DevChunkingContextVc}, ChunkGroupVc, ChunkableAssetVc, }, context::AssetContextVc, + environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, lazy::LazyAssetVc, source_asset::SourceAssetVc, }; @@ -83,7 +81,18 @@ async fn main() { let source_asset = SourceAssetVc::new(FileSystemPathVc::new(fs, "src/index.js")).into(); let context: AssetContextVc = ModuleAssetContextVc::new( root, - GraphOptionsVc::new(false, false, CompileTargetVc::current()), + EnvironmentVc::new( + Value::new(ExecutionEnvironment::Browser( + BrowserEnvironment { + dom: true, + web_worker: false, + service_worker: false, + browser_version: 0, + } + .into(), + )), + Value::new(EnvironmentIntention::Client), + ), ) .into(); let module = context.process(source_asset); From 41c2dfd2de9f6ff876cb14d1ba567acbc122076a Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 1 Aug 2022 09:02:53 +0200 Subject: [PATCH 023/672] introduce ContentSource as source for the dev server (vercel/turbo#185) and potentially a next build in future --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/src/main.rs | 56 ++++++++--------- .../crates/next-dev/src/turbo_tasks_viz.rs | 62 +++++++++++++++++++ 3 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 4a73dbfa3b1b2c..63db15b749493c 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -22,6 +22,7 @@ anyhow = "1.0.47" clap = { version = "3.1.3", features = ["derive"] } console-subscriber = { version = "0.1.6", optional = true } json = "0.12.4" +mime = "0.3.16" serde = "1.0.136" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index fff628564f76fc..5022d4e3bcd129 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -1,12 +1,14 @@ #![feature(future_join)] #![feature(future_poll_fn)] +#![feature(min_specialization)] + +mod turbo_tasks_viz; use std::{ env::current_dir, future::join, net::IpAddr, path::PathBuf, - sync::Arc, time::{Duration, Instant}, }; @@ -14,7 +16,7 @@ use anyhow::anyhow; use clap::Parser; use turbo_tasks::{util::FormatDuration, TransientValue, TurboTasks, Value}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; -use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; +use turbo_tasks_memory::MemoryBackend; use turbopack::{ecmascript::ModuleAssetVc as EcmascriptModuleAssetVc, ModuleAssetContextVc}; use turbopack_core::{ chunk::{ @@ -26,7 +28,14 @@ use turbopack_core::{ lazy::LazyAssetVc, source_asset::SourceAssetVc, }; -use turbopack_dev_server::{fs::DevServerFileSystemVc, html::DevHtmlAsset, DevServerVc}; +use turbopack_dev_server::{ + fs::DevServerFileSystemVc, + html::DevHtmlAsset, + source::{asset_graph::AssetGraphContentSource, router::RouterContentSource}, + DevServerVc, +}; + +use self::turbo_tasks_viz::TurboTasksSource; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] @@ -133,33 +142,24 @@ async fn main() { served_asset = LazyAssetVc::new(served_asset).into(); } + let graph = AssetGraphContentSource { + root_asset: served_asset, + root_path: FileSystemPathVc::new(dev_server_fs, ""), + } + .into(); + let viz = TurboTasksSource { + turbo_tasks: tt.clone(), + } + .into(); + let source = RouterContentSource { + routes: vec![("__turbo_tasks__/".to_string(), viz)], + fallback: graph, + } + .into(); + let server = DevServerVc::new( - FileSystemPathVc::new(dev_server_fs, ""), - served_asset, + source, TransientValue::new((args.hostname, args.port).into()), - TransientValue::new(Arc::new(move |path| { - if path == "/__turbo_tasks_graph__" { - let mut stats = Stats::new(); - let b = tt.backend(); - b.with_all_cached_tasks(|task| { - stats.add_id(b, task); - }); - let tree = stats.treeify(); - let graph = viz::graph::visualize_stats_tree(tree); - return Some(viz::graph::wrap_html(&graph)); - } - if path == "/__turbo_tasks_table__" { - let mut stats = Stats::new(); - let b = tt.backend(); - b.with_all_cached_tasks(|task| { - stats.add_id(b, task); - }); - let tree = stats.treeify(); - let table = viz::table::create_table(tree); - return Some(viz::table::wrap_html(&table)); - } - None - })), ); disk_fs.await?.start_watching()?; server.listen().await diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs new file mode 100644 index 00000000000000..2396ba40a8e2a5 --- /dev/null +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -0,0 +1,62 @@ +use std::{str::FromStr, sync::Arc}; + +use anyhow::Result; +use mime::Mime; +use turbo_tasks::TurboTasks; +use turbo_tasks_fs::{File, FileContent, FileContentVc}; +use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; +use turbopack_dev_server::source::{ContentSource, ContentSourceVc}; + +#[turbo_tasks::value(ContentSource, serialization: none, eq: manual, cell: new, into: new)] +pub struct TurboTasksSource { + #[trace_ignore] + pub turbo_tasks: Arc>, +} + +impl TurboTasksSourceVc { + pub fn new(turbo_tasks: Arc>) -> Self { + Self::cell(TurboTasksSource { turbo_tasks }) + } +} + +#[turbo_tasks::value_impl] +impl ContentSource for TurboTasksSource { + #[turbo_tasks::function] + fn get(&self, path: &str) -> Result { + let tt = &self.turbo_tasks; + if path == "graph" { + let mut stats = Stats::new(); + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + stats.add_id(b, task); + }); + let tree = stats.treeify(); + let graph = viz::graph::visualize_stats_tree(tree); + return Ok(FileContent::Content( + File::from_source(viz::graph::wrap_html(&graph)) + .with_content_type(Mime::from_str("text/html")?), + ) + .into()); + } + if path == "table" { + let mut stats = Stats::new(); + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + stats.add_id(b, task); + }); + let tree = stats.treeify(); + let table = viz::table::create_table(tree); + return Ok(FileContent::Content( + File::from_source(viz::table::wrap_html(&table)) + .with_content_type(Mime::from_str("text/html")?), + ) + .into()); + } + Ok(FileContent::NotFound.into()) + } + + #[turbo_tasks::function] + fn get_by_id(&self, _id: &str) -> FileContentVc { + FileContent::NotFound.into() + } +} From 12d720ff48c4443b56b417549e348b8beb818b50 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 1 Aug 2022 09:53:09 +0200 Subject: [PATCH 024/672] refactor lazy asset to lazy graph content source (vercel/turbo#186) --- packages/next-swc/crates/next-dev/src/main.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 5022d4e3bcd129..6d24bab84359f0 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -25,13 +25,12 @@ use turbopack_core::{ }, context::AssetContextVc, environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, - lazy::LazyAssetVc, source_asset::SourceAssetVc, }; use turbopack_dev_server::{ fs::DevServerFileSystemVc, html::DevHtmlAsset, - source::{asset_graph::AssetGraphContentSource, router::RouterContentSource}, + source::{asset_graph::AssetGraphContentSourceVc, router::RouterContentSource}, DevServerVc, }; @@ -137,14 +136,11 @@ async fn main() { )); }; - let mut served_asset = entry_asset; - if !args.eager_compile { - served_asset = LazyAssetVc::new(served_asset).into(); - } - - let graph = AssetGraphContentSource { - root_asset: served_asset, - root_path: FileSystemPathVc::new(dev_server_fs, ""), + let root_path = FileSystemPathVc::new(dev_server_fs, ""); + let graph = if args.eager_compile { + AssetGraphContentSourceVc::new_eager(root_path, entry_asset) + } else { + AssetGraphContentSourceVc::new_lazy(root_path, entry_asset) } .into(); let viz = TurboTasksSource { From 8fad8a68819cc7dcf9369d0151efda19b6e3ac7b Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 2 Aug 2022 19:36:48 +0200 Subject: [PATCH 025/672] Custom debug implementation for Vcs (vercel/turbo#193) This PR builds our own `Debug`-like derive-macro machinery for formatting structs, relying on `std::fmt::Formatter` for the actual formatting. ### Usage A new `ValueDebug` trait is automatically implemented for all `#[turbo_tasks::value]`s, which has a single `.dbg()` method which resolves to a debug representation that can then be printed to the screen. `#[turbo_tasks::value_trait]` also implement the `.dbg()` method directly. ```rust dbg!(any_vc.dbg().await?); ``` If you have a `#[turbo_tasks::value]` struct with a field that doesn't implement `Debug`, you'll want to declare that field as `#[debug_ignore]`. For instance: ```rust #[turbo_tasks::value(ContentSource, serialization: none, eq: manual, cell: new, into: new)] pub struct TurboTasksSource { #[debug_ignore] #[trace_ignore] pub turbo_tasks: Arc>, } ``` ### Why not use `Debug` directly? We can't use `Debug` because our values are resolved asynchronously and can nest `Vc`s arbitrarily. I tried using `futures::executor::block_on` to resolve them synchronously in a `Debug` implementation but that causes deadlocks. --- packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 2396ba40a8e2a5..bb6cb94062d34e 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -9,6 +9,7 @@ use turbopack_dev_server::source::{ContentSource, ContentSourceVc}; #[turbo_tasks::value(ContentSource, serialization: none, eq: manual, cell: new, into: new)] pub struct TurboTasksSource { + #[debug_ignore] #[trace_ignore] pub turbo_tasks: Arc>, } From 01a7e41834725480ef028c44713a1e2236ee275c Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Tue, 2 Aug 2022 16:28:11 -0700 Subject: [PATCH 026/672] Extract server creation into own function and module (vercel/turbo#191) * Extract server creation into fn * Use builder pattern and anyhow context --- packages/next-swc/crates/next-dev/Cargo.toml | 2 + packages/next-swc/crates/next-dev/src/lib.rs | 196 ++++++++++++++++++ packages/next-swc/crates/next-dev/src/main.rs | 145 ++----------- 3 files changed, 221 insertions(+), 122 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/src/lib.rs diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 63db15b749493c..eda86226cfc80a 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -8,6 +8,8 @@ name = "next-dev" path = "src/main.rs" bench = false +[lib] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs new file mode 100644 index 00000000000000..310f1bb4824105 --- /dev/null +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -0,0 +1,196 @@ +#![feature(future_join)] +#![feature(future_poll_fn)] +#![feature(min_specialization)] + +use std::{net::IpAddr, sync::Arc}; + +use anyhow::{anyhow, Context, Result}; +use turbo_tasks::{TransientValue, TurboTasks, Value}; +use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; +use turbo_tasks_memory::MemoryBackend; +use turbopack::{ecmascript::ModuleAssetVc as EcmascriptModuleAssetVc, ModuleAssetContextVc}; +use turbopack_core::{ + chunk::{ + dev::{DevChunkingContext, DevChunkingContextVc}, + ChunkGroupVc, ChunkableAssetVc, + }, + context::AssetContextVc, + environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, + source_asset::SourceAssetVc, +}; +use turbopack_dev_server::{ + fs::DevServerFileSystemVc, + html::DevHtmlAsset, + source::{asset_graph::AssetGraphContentSourceVc, router::RouterContentSource}, + DevServerListening, DevServerVc, +}; + +mod turbo_tasks_viz; + +pub struct NextDevServerBuilder { + turbo_tasks: Option>>, + project_dir: Option, + entry_asset_path: Option, + eager_compile: bool, + hostname: Option, + port: Option, +} + +impl Default for NextDevServerBuilder { + fn default() -> Self { + NextDevServerBuilder::new() + } +} + +impl NextDevServerBuilder { + pub fn new() -> NextDevServerBuilder { + NextDevServerBuilder { + turbo_tasks: None, + project_dir: None, + entry_asset_path: None, + eager_compile: false, + hostname: None, + port: None, + } + } + + pub fn turbo_tasks(mut self, tt: Arc>) -> NextDevServerBuilder { + self.turbo_tasks = Some(tt); + self + } + + pub fn project_dir(mut self, project_dir: String) -> NextDevServerBuilder { + self.project_dir = Some(project_dir); + self + } + + pub fn entry_asset_path(mut self, entry_asset_path: String) -> NextDevServerBuilder { + self.entry_asset_path = Some(entry_asset_path); + self + } + + pub fn eager_compile(mut self, eager_compile: bool) -> NextDevServerBuilder { + self.eager_compile = eager_compile; + self + } + + pub fn hostname(mut self, hostname: IpAddr) -> NextDevServerBuilder { + self.hostname = Some(hostname); + self + } + + pub fn port(mut self, port: u16) -> NextDevServerBuilder { + self.port = Some(port); + self + } + + pub async fn build(self) -> Result { + let turbo_tasks = self.turbo_tasks.context("turbo_tasks must be set")?; + + turbo_tasks + .clone() + .run_once(async move { + let disk_fs = DiskFileSystemVc::new( + "project".to_string(), + self.project_dir.context("project_dir must be set")?, + ); + let fs = disk_fs.into(); + let root = FileSystemPathVc::new(fs, ""); + let source_asset = SourceAssetVc::new(FileSystemPathVc::new( + fs, + &self + .entry_asset_path + .context("entry_asset_path must be set")?, + )) + .into(); + let context: AssetContextVc = ModuleAssetContextVc::new( + root, + EnvironmentVc::new( + Value::new(ExecutionEnvironment::Browser( + BrowserEnvironment { + dom: true, + web_worker: false, + service_worker: false, + browser_version: 0, + } + .into(), + )), + Value::new(EnvironmentIntention::Client), + ), + ) + .into(); + let module = context.process(source_asset); + let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); + let chunking_context: DevChunkingContextVc = DevChunkingContext { + context_path: root, + chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), + asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static"), + } + .into(); + let entry_asset = if let Some(ecmascript) = + EcmascriptModuleAssetVc::resolve_from(module).await? + { + let chunk = ecmascript.as_evaluated_chunk(chunking_context.into()); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_group, + } + .into() + } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { + let chunk = chunkable.as_chunk(chunking_context.into()); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_group, + } + .into() + } else { + // TODO convert into a serve-able asset + return Err(anyhow!( + "Entry module is not chunkable, so it can't be used to bootstrap the \ + application" + )); + }; + + let root_path = FileSystemPathVc::new(dev_server_fs, ""); + let graph = if self.eager_compile { + AssetGraphContentSourceVc::new_eager(root_path, entry_asset) + } else { + AssetGraphContentSourceVc::new_lazy(root_path, entry_asset) + } + .into(); + let viz = turbo_tasks_viz::TurboTasksSource { + turbo_tasks: turbo_tasks.clone(), + } + .into(); + let source = RouterContentSource { + routes: vec![("__turbo_tasks__/".to_string(), viz)], + fallback: graph, + } + .into(); + + let server = DevServerVc::new( + source, + TransientValue::new( + ( + self.hostname.context("hostname must be set")?, + self.port.context("port must be set")?, + ) + .into(), + ), + ); + disk_fs.await?.start_watching()?; + server.listen().await + }) + .await + } +} + +pub fn register() { + turbo_tasks::register(); + turbo_tasks_fs::register(); + turbopack_dev_server::register(); + turbopack::register(); + include!(concat!(env!("OUT_DIR"), "/register.rs")); +} diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 6d24bab84359f0..1548d9188746ff 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -2,8 +2,6 @@ #![feature(future_poll_fn)] #![feature(min_specialization)] -mod turbo_tasks_viz; - use std::{ env::current_dir, future::join, @@ -12,29 +10,11 @@ use std::{ time::{Duration, Instant}, }; -use anyhow::anyhow; +use anyhow::Context; use clap::Parser; -use turbo_tasks::{util::FormatDuration, TransientValue, TurboTasks, Value}; -use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; +use next_dev::{register, NextDevServerBuilder}; +use turbo_tasks::{util::FormatDuration, TurboTasks}; use turbo_tasks_memory::MemoryBackend; -use turbopack::{ecmascript::ModuleAssetVc as EcmascriptModuleAssetVc, ModuleAssetContextVc}; -use turbopack_core::{ - chunk::{ - dev::{DevChunkingContext, DevChunkingContextVc}, - ChunkGroupVc, ChunkableAssetVc, - }, - context::AssetContextVc, - environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, - source_asset::SourceAssetVc, -}; -use turbopack_dev_server::{ - fs::DevServerFileSystemVc, - html::DevHtmlAsset, - source::{asset_graph::AssetGraphContentSourceVc, router::RouterContentSource}, - DevServerVc, -}; - -use self::turbo_tasks_viz::TurboTasksSource; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] @@ -74,92 +54,21 @@ async fn main() { .unwrap_or_else(current_dir) .unwrap() .to_str() - .ok_or_else(|| anyhow!("current directory contains invalid characters")) + .context("current directory contains invalid characters") .unwrap() .to_string(); let tt = TurboTasks::new(MemoryBackend::new()); let tt_clone = tt.clone(); - let server = tt - .clone() - .run_once(async move { - let disk_fs = DiskFileSystemVc::new("project".to_string(), dir); - let fs = disk_fs.into(); - let root = FileSystemPathVc::new(fs, ""); - let source_asset = SourceAssetVc::new(FileSystemPathVc::new(fs, "src/index.js")).into(); - let context: AssetContextVc = ModuleAssetContextVc::new( - root, - EnvironmentVc::new( - Value::new(ExecutionEnvironment::Browser( - BrowserEnvironment { - dom: true, - web_worker: false, - service_worker: false, - browser_version: 0, - } - .into(), - )), - Value::new(EnvironmentIntention::Client), - ), - ) - .into(); - let module = context.process(source_asset); - let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); - let chunking_context: DevChunkingContextVc = DevChunkingContext { - context_path: root, - chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), - asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static"), - } - .into(); - let entry_asset = - if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { - let chunk = ecmascript.as_evaluated_chunk(chunking_context.into()); - let chunk_group = ChunkGroupVc::from_chunk(chunk); - DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_group, - } - .into() - } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { - let chunk = chunkable.as_chunk(chunking_context.into()); - let chunk_group = ChunkGroupVc::from_chunk(chunk); - DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_group, - } - .into() - } else { - // TODO convert into a serve-able asset - return Err(anyhow!( - "Entry module is not chunkable, so it can't be used to bootstrap the \ - application" - )); - }; - let root_path = FileSystemPathVc::new(dev_server_fs, ""); - let graph = if args.eager_compile { - AssetGraphContentSourceVc::new_eager(root_path, entry_asset) - } else { - AssetGraphContentSourceVc::new_lazy(root_path, entry_asset) - } - .into(); - let viz = TurboTasksSource { - turbo_tasks: tt.clone(), - } - .into(); - let source = RouterContentSource { - routes: vec![("__turbo_tasks__/".to_string(), viz)], - fallback: graph, - } - .into(); - - let server = DevServerVc::new( - source, - TransientValue::new((args.hostname, args.port).into()), - ); - disk_fs.await?.start_watching()?; - server.listen().await - }) + let server = NextDevServerBuilder::new() + .turbo_tasks(tt) + .project_dir(dir) + .entry_asset_path("src/index.js".into()) + .eager_compile(args.eager_compile) + .hostname(args.hostname) + .port(args.port) + .build() .await .unwrap(); @@ -174,26 +83,18 @@ async fn main() { } join! { - async move { - let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; - println!("initial compilation {} ({} task execution, {} tasks)", FormatDuration(start.elapsed()), FormatDuration(elapsed), count); - - loop { - let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::from_millis(100)).await; - println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); + async move { + let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; + println!("initial compilation {} ({} task execution, {} tasks)", + FormatDuration(start.elapsed()), FormatDuration(elapsed), count); + + loop { + let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::from_millis(100)).await; + println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); } + }, + async { + server.future.await.unwrap() } - }, - async { - server.future.await.unwrap() } - } .await; } - -fn register() { - turbo_tasks::register(); - turbo_tasks_fs::register(); - turbopack_dev_server::register(); - turbopack::register(); - include!(concat!(env!("OUT_DIR"), "/register.rs")); -} From 1d4821382b38fcb0c87f6fc4da17222527ad6364 Mon Sep 17 00:00:00 2001 From: Leah Date: Wed, 3 Aug 2022 05:37:56 +0200 Subject: [PATCH 027/672] fix css layer import (vercel/turbo#195) kdy1 fixes this upstream --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index eda86226cfc80a..8be152fe4b12b5 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -9,6 +9,7 @@ path = "src/main.rs" bench = false [lib] +bench = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 796f6053012437c77dec1446daa22cb50043501e Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 4 Aug 2022 23:14:09 +0200 Subject: [PATCH 028/672] track processing path for issues (vercel/turbo#205) allow to attach context at any point show processing path in output move cli issue display into separate crate --- packages/next-swc/crates/next-dev/src/lib.rs | 100 ++++-------------- .../crates/next-dev/src/web_entry_source.rs | 84 +++++++++++++++ 2 files changed, 103 insertions(+), 81 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/src/web_entry_source.rs diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 310f1bb4824105..bc39801f6423d0 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -4,28 +4,19 @@ use std::{net::IpAddr, sync::Arc}; -use anyhow::{anyhow, Context, Result}; -use turbo_tasks::{TransientValue, TurboTasks, Value}; +use anyhow::{Context, Result}; +use turbo_tasks::{TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::MemoryBackend; -use turbopack::{ecmascript::ModuleAssetVc as EcmascriptModuleAssetVc, ModuleAssetContextVc}; -use turbopack_core::{ - chunk::{ - dev::{DevChunkingContext, DevChunkingContextVc}, - ChunkGroupVc, ChunkableAssetVc, - }, - context::AssetContextVc, - environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, - source_asset::SourceAssetVc, -}; +use turbopack::ecmascript::ModuleAssetVc as EcmascriptModuleAssetVc; use turbopack_dev_server::{ - fs::DevServerFileSystemVc, - html::DevHtmlAsset, - source::{asset_graph::AssetGraphContentSourceVc, router::RouterContentSource}, - DevServerListening, DevServerVc, + fs::DevServerFileSystemVc, source::router::RouterContentSource, DevServerListening, DevServerVc, }; +use self::web_entry_source::create_web_entry_source; + mod turbo_tasks_viz; +mod web_entry_source; pub struct NextDevServerBuilder { turbo_tasks: Option>>, @@ -95,78 +86,25 @@ impl NextDevServerBuilder { self.project_dir.context("project_dir must be set")?, ); let fs = disk_fs.into(); - let root = FileSystemPathVc::new(fs, ""); - let source_asset = SourceAssetVc::new(FileSystemPathVc::new( - fs, - &self - .entry_asset_path - .context("entry_asset_path must be set")?, - )) - .into(); - let context: AssetContextVc = ModuleAssetContextVc::new( - root, - EnvironmentVc::new( - Value::new(ExecutionEnvironment::Browser( - BrowserEnvironment { - dom: true, - web_worker: false, - service_worker: false, - browser_version: 0, - } - .into(), - )), - Value::new(EnvironmentIntention::Client), - ), - ) - .into(); - let module = context.process(source_asset); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); - let chunking_context: DevChunkingContextVc = DevChunkingContext { - context_path: root, - chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), - asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static"), - } - .into(); - let entry_asset = if let Some(ecmascript) = - EcmascriptModuleAssetVc::resolve_from(module).await? - { - let chunk = ecmascript.as_evaluated_chunk(chunking_context.into()); - let chunk_group = ChunkGroupVc::from_chunk(chunk); - DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_group, - } - .into() - } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { - let chunk = chunkable.as_chunk(chunking_context.into()); - let chunk_group = ChunkGroupVc::from_chunk(chunk); - DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_group, - } - .into() - } else { - // TODO convert into a serve-able asset - return Err(anyhow!( - "Entry module is not chunkable, so it can't be used to bootstrap the \ - application" - )); - }; - - let root_path = FileSystemPathVc::new(dev_server_fs, ""); - let graph = if self.eager_compile { - AssetGraphContentSourceVc::new_eager(root_path, entry_asset) - } else { - AssetGraphContentSourceVc::new_lazy(root_path, entry_asset) - } - .into(); + let main_source = create_web_entry_source( + FileSystemPathVc::new(fs, ""), + FileSystemPathVc::new( + fs, + &self + .entry_asset_path + .context("entry_asset_path must be set")?, + ), + dev_server_fs, + self.eager_compile, + ); let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.clone(), } .into(); let source = RouterContentSource { routes: vec![("__turbo_tasks__/".to_string(), viz)], - fallback: graph, + fallback: main_source, } .into(); diff --git a/packages/next-swc/crates/next-dev/src/web_entry_source.rs b/packages/next-swc/crates/next-dev/src/web_entry_source.rs new file mode 100644 index 00000000000000..8d43cb79ce3dbe --- /dev/null +++ b/packages/next-swc/crates/next-dev/src/web_entry_source.rs @@ -0,0 +1,84 @@ +use anyhow::{anyhow, Result}; +use turbo_tasks::Value; +use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; +use turbopack::ModuleAssetContextVc; +use turbopack_core::{ + chunk::{ + dev::{DevChunkingContext, DevChunkingContextVc}, + ChunkGroupVc, ChunkableAssetVc, + }, + context::AssetContextVc, + environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, + source_asset::SourceAssetVc, +}; +use turbopack_dev_server::{ + html::DevHtmlAsset, + source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, +}; + +use crate::EcmascriptModuleAssetVc; + +#[turbo_tasks::function] +pub async fn create_web_entry_source( + root: FileSystemPathVc, + entry_path: FileSystemPathVc, + dev_server_fs: FileSystemVc, + eager_compile: bool, +) -> Result { + let source_asset = SourceAssetVc::new(entry_path).into(); + let context: AssetContextVc = ModuleAssetContextVc::new( + root, + EnvironmentVc::new( + Value::new(ExecutionEnvironment::Browser( + BrowserEnvironment { + dom: true, + web_worker: false, + service_worker: false, + browser_version: 0, + } + .into(), + )), + Value::new(EnvironmentIntention::Client), + ), + ) + .into(); + let module = context.process(source_asset); + let chunking_context: DevChunkingContextVc = DevChunkingContext { + context_path: root, + chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), + asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static"), + } + .into(); + let entry_asset = + if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { + let chunk = ecmascript.as_evaluated_chunk(chunking_context.into()); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_group, + } + .into() + } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { + let chunk = chunkable.as_chunk(chunking_context.into()); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_group, + } + .into() + } else { + // TODO convert into a serve-able asset + return Err(anyhow!( + "Entry module is not chunkable, so it can't be used to bootstrap the application" + )); + }; + + let root_path = FileSystemPathVc::new(dev_server_fs, ""); + let graph = if eager_compile { + AssetGraphContentSourceVc::new_eager(root_path, entry_asset) + } else { + AssetGraphContentSourceVc::new_lazy(root_path, entry_asset) + } + .into(); + Ok(graph) +} From 64bb520332b083600996616604870d198cbd0058 Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 4 Aug 2022 23:58:19 +0200 Subject: [PATCH 029/672] add `open-browser` option (vercel/turbo#199) Fixes https://github.com/vercel/turbo-tooling/issues/171 --- packages/next-swc/crates/next-dev/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 1548d9188746ff..28c4b323d3fc8f 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -36,6 +36,10 @@ struct Cli { /// parent asset is requested #[clap(long)] eager_compile: bool, + + /// Don't open the browser automatically when the dev server has started. + #[clap(long)] + no_open: bool, } #[tokio::main] @@ -79,7 +83,9 @@ async fn main() { format!("http://{}", server.addr) }; println!("server listening on: {uri}", uri = index_uri); - let _ = webbrowser::open(&index_uri); + if !args.no_open { + let _ = webbrowser::open(&index_uri); + } } join! { From 71429b9beb2ab3e81abe4f78aa364b1513f248cc Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 4 Aug 2022 23:58:32 +0200 Subject: [PATCH 030/672] simplify `turbo_tasks::value` (vercel/turbo#196) Removes the trait arguments and registers them separately --- packages/next-swc/crates/next-dev/src/lib.rs | 2 ++ packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 2 +- packages/next-swc/crates/next-dev/src/web_entry_source.rs | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index bc39801f6423d0..782fefa5a3dba8 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -101,11 +101,13 @@ impl NextDevServerBuilder { let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.clone(), } + .cell() .into(); let source = RouterContentSource { routes: vec![("__turbo_tasks__/".to_string(), viz)], fallback: main_source, } + .cell() .into(); let server = DevServerVc::new( diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index bb6cb94062d34e..38b4e84fe31b19 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -7,7 +7,7 @@ use turbo_tasks_fs::{File, FileContent, FileContentVc}; use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; use turbopack_dev_server::source::{ContentSource, ContentSourceVc}; -#[turbo_tasks::value(ContentSource, serialization: none, eq: manual, cell: new, into: new)] +#[turbo_tasks::value(serialization: none, eq: manual, cell: new, into: new)] pub struct TurboTasksSource { #[debug_ignore] #[trace_ignore] diff --git a/packages/next-swc/crates/next-dev/src/web_entry_source.rs b/packages/next-swc/crates/next-dev/src/web_entry_source.rs index 8d43cb79ce3dbe..a3541066902f45 100644 --- a/packages/next-swc/crates/next-dev/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-dev/src/web_entry_source.rs @@ -57,6 +57,7 @@ pub async fn create_web_entry_source( path: FileSystemPathVc::new(dev_server_fs, "index.html"), chunk_group, } + .cell() .into() } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { let chunk = chunkable.as_chunk(chunking_context.into()); @@ -65,6 +66,7 @@ pub async fn create_web_entry_source( path: FileSystemPathVc::new(dev_server_fs, "index.html"), chunk_group, } + .cell() .into() } else { // TODO convert into a serve-able asset From 5e4ba91c7c15fc28385a8495c37aaf17208e0f36 Mon Sep 17 00:00:00 2001 From: Leah Date: Fri, 5 Aug 2022 08:20:42 +0200 Subject: [PATCH 031/672] rename `ModuleAsset` (vercel/turbo#206) --- packages/next-swc/crates/next-dev/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 782fefa5a3dba8..63018c66a0c36b 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -8,7 +8,7 @@ use anyhow::{Context, Result}; use turbo_tasks::{TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::MemoryBackend; -use turbopack::ecmascript::ModuleAssetVc as EcmascriptModuleAssetVc; +use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_dev_server::{ fs::DevServerFileSystemVc, source::router::RouterContentSource, DevServerListening, DevServerVc, }; From 1277c36e35cf57330c0293fb588f9ee32511394f Mon Sep 17 00:00:00 2001 From: Leah Date: Fri, 5 Aug 2022 08:26:22 +0200 Subject: [PATCH 032/672] refactor `turbo-tasks-macros` (vercel/turbo#198) Changes attribute/argument parsing to the more usual `field = "value"` / `turbo_tasks(trace_ignore)` --- packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 38b4e84fe31b19..c093249353f779 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -7,10 +7,9 @@ use turbo_tasks_fs::{File, FileContent, FileContentVc}; use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; use turbopack_dev_server::source::{ContentSource, ContentSourceVc}; -#[turbo_tasks::value(serialization: none, eq: manual, cell: new, into: new)] +#[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new", into = "new")] pub struct TurboTasksSource { - #[debug_ignore] - #[trace_ignore] + #[turbo_tasks(debug_ignore, trace_ignore)] pub turbo_tasks: Arc>, } From 659a5fd83db8721e159aa2896f797d97b333ad82 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 8 Aug 2022 09:39:52 +0200 Subject: [PATCH 033/672] add issue reporting to next dev (vercel/turbo#208) --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/src/lib.rs | 30 +++++++++++++++++-- packages/next-swc/crates/next-dev/src/main.rs | 23 +++++++------- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 8be152fe4b12b5..08d92dbc8595a9 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -32,6 +32,7 @@ turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } turbo-tasks-memory = { path = "../turbo-tasks-memory" } turbopack = { path = "../turbopack" } +turbopack-cli-utils = { path = "../turbopack-cli-utils" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } webbrowser = "0.7.1" diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 63018c66a0c36b..f31647b95b9f57 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -4,11 +4,13 @@ use std::{net::IpAddr, sync::Arc}; -use anyhow::{Context, Result}; -use turbo_tasks::{TransientValue, TurboTasks}; +use anyhow::{anyhow, Context, Result}; +use turbo_tasks::{CollectiblesSource, TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::MemoryBackend; use turbopack::ecmascript::EcmascriptModuleAssetVc; +use turbopack_cli_utils::issue::issue_to_styled_string; +use turbopack_core::issue::{IssueSeverity, IssueVc}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, source::router::RouterContentSource, DevServerListening, DevServerVc, }; @@ -78,6 +80,24 @@ impl NextDevServerBuilder { pub async fn build(self) -> Result { let turbo_tasks = self.turbo_tasks.context("turbo_tasks must be set")?; + async fn handle_issues(source: T) -> Result<()> { + let issues = IssueVc::peek_issues_with_path(source).await?; + let issues = issues.await?; + let mut fatal = false; + for (issue, path) in issues.iter_with_shortest_path() { + println!("{}\n", &*issue_to_styled_string(issue, path).await?); + if *issue.severity().await? >= IssueSeverity::Fatal { + fatal = true; + } + } + + if fatal { + Err(anyhow!("Fatal issue(s) occurred")) + } else { + Ok(()) + } + } + turbo_tasks .clone() .run_once(async move { @@ -120,6 +140,12 @@ impl NextDevServerBuilder { .into(), ), ); + + handle_issues(disk_fs).await?; + handle_issues(dev_server_fs).await?; + handle_issues(main_source).await?; + handle_issues(server).await?; + disk_fs.await?.start_watching()?; server.listen().await }) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 28c4b323d3fc8f..5ef28f59ba5085 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -89,18 +89,19 @@ async fn main() { } join! { - async move { - let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; - println!("initial compilation {} ({} task execution, {} tasks)", - FormatDuration(start.elapsed()), FormatDuration(elapsed), count); - - loop { - let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::from_millis(100)).await; - println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); } - }, - async { - server.future.await.unwrap() + async move { + let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; + println!("initial compilation {} ({} task execution, {} tasks)", + FormatDuration(start.elapsed()), FormatDuration(elapsed), count); + + loop { + let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::from_millis(100)).await; + println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); } + }, + async { + server.future.await.unwrap() } + } .await; } From 7bd5321b0952d6ce242dda059b6737ec16530a74 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Tue, 9 Aug 2022 09:20:30 -0700 Subject: [PATCH 034/672] next-dev test runner (vercel/turbo#172) This is a very early version of the next-dev test runner. I'm opening this early to get thoughts from folks re: the direction of the design and implementation. Fixes vercel/turbo#204 Currently it: * Discovers integration test fixtures from the filesystem. Right now these are expected to be single files that get bundled and will eventually include assertions. This is powered by the test-generator crate, which allows us not to have to manually enumerate each case. We could consider using this for the node-file-trace tests as well. * Starts the dev server on a free port and opens a headless browser to its root. The browser control is implemented with the https://crates.io/crates/chromiumoxide crate, which expects Chrome or Chromium to already be available. Eventually it will: * [x] Implement a minimal test environment loaded in the browser so that assertions can be run there from bundled code. * [x] Report back the results of these assertions to rust, where we can pass/fail cargo tests with those results. In the future it could: * Possibly include snapshot-style tests to assert on transformed results. This could be in the form of fixture directories instead of files cc @jridgewell * Support expressing special configuration of turbopack in a fixture, possibly as another file in the fixture directory. * [x] ~Possibly support distributing tests to a pool of open browsers instead of opening and closing for each test.~ Test Plan: See next PRs --- packages/next-swc/crates/next-dev/Cargo.toml | 9 ++ packages/next-swc/crates/next-dev/src/lib.rs | 18 ++- packages/next-swc/crates/next-dev/src/main.rs | 2 +- .../crates/next-dev/src/web_entry_source.rs | 46 +++--- .../next-swc/crates/next-dev/tests/harness.js | 7 + .../crates/next-dev/tests/integration.rs | 136 ++++++++++++++++++ .../turbopack/basic/simple/index.js | 19 +++ .../crates/next-dev/tests/package.json | 10 ++ 8 files changed, 213 insertions(+), 34 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/tests/harness.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration.rs create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/package.json diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 08d92dbc8595a9..9ec1284742e759 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -24,6 +24,7 @@ tokio_console = [ anyhow = "1.0.47" clap = { version = "3.1.3", features = ["derive"] } console-subscriber = { version = "0.1.6", optional = true } +futures = "0.3.21" json = "0.12.4" mime = "0.3.16" serde = "1.0.136" @@ -37,5 +38,13 @@ turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } webbrowser = "0.7.1" +[dev-dependencies] +chromiumoxide = { version = "0.3.5", features = [ + "tokio-runtime", +], default-features = false } +lazy_static = "1.4.0" +portpicker = "0.1.1" +test-generator = "0.3.0" + [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index f31647b95b9f57..76a49a8906dffd 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -23,7 +23,7 @@ mod web_entry_source; pub struct NextDevServerBuilder { turbo_tasks: Option>>, project_dir: Option, - entry_asset_path: Option, + entry_assets: Vec, eager_compile: bool, hostname: Option, port: Option, @@ -40,7 +40,7 @@ impl NextDevServerBuilder { NextDevServerBuilder { turbo_tasks: None, project_dir: None, - entry_asset_path: None, + entry_assets: vec![], eager_compile: false, hostname: None, port: None, @@ -57,8 +57,8 @@ impl NextDevServerBuilder { self } - pub fn entry_asset_path(mut self, entry_asset_path: String) -> NextDevServerBuilder { - self.entry_asset_path = Some(entry_asset_path); + pub fn entry_asset(mut self, entry_asset_path: String) -> NextDevServerBuilder { + self.entry_assets.push(entry_asset_path); self } @@ -109,12 +109,10 @@ impl NextDevServerBuilder { let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let main_source = create_web_entry_source( FileSystemPathVc::new(fs, ""), - FileSystemPathVc::new( - fs, - &self - .entry_asset_path - .context("entry_asset_path must be set")?, - ), + self.entry_assets + .iter() + .map(|a| FileSystemPathVc::new(fs, a)) + .collect(), dev_server_fs, self.eager_compile, ); diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 5ef28f59ba5085..947bb33dc59b3f 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -68,7 +68,7 @@ async fn main() { let server = NextDevServerBuilder::new() .turbo_tasks(tt) .project_dir(dir) - .entry_asset_path("src/index.js".into()) + .entry_asset("src/index.js".into()) .eager_compile(args.eager_compile) .hostname(args.hostname) .port(args.port) diff --git a/packages/next-swc/crates/next-dev/src/web_entry_source.rs b/packages/next-swc/crates/next-dev/src/web_entry_source.rs index a3541066902f45..c10cd5b05ed592 100644 --- a/packages/next-swc/crates/next-dev/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-dev/src/web_entry_source.rs @@ -1,4 +1,5 @@ use anyhow::{anyhow, Result}; +use futures::future::try_join_all; use turbo_tasks::Value; use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; use turbopack::ModuleAssetContextVc; @@ -21,11 +22,10 @@ use crate::EcmascriptModuleAssetVc; #[turbo_tasks::function] pub async fn create_web_entry_source( root: FileSystemPathVc, - entry_path: FileSystemPathVc, + entry_paths: Vec, dev_server_fs: FileSystemVc, eager_compile: bool, ) -> Result { - let source_asset = SourceAssetVc::new(entry_path).into(); let context: AssetContextVc = ModuleAssetContextVc::new( root, EnvironmentVc::new( @@ -42,38 +42,38 @@ pub async fn create_web_entry_source( ), ) .into(); - let module = context.process(source_asset); + let chunking_context: DevChunkingContextVc = DevChunkingContext { context_path: root, chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static"), } .into(); - let entry_asset = + + let modules = entry_paths + .into_iter() + .map(|p| context.process(SourceAssetVc::new(p).into())); + let chunks = try_join_all(modules.map(|module| async move { if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { - let chunk = ecmascript.as_evaluated_chunk(chunking_context.into()); - let chunk_group = ChunkGroupVc::from_chunk(chunk); - DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_group, - } - .cell() - .into() + Ok(ecmascript.as_evaluated_chunk(chunking_context.into())) } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { - let chunk = chunkable.as_chunk(chunking_context.into()); - let chunk_group = ChunkGroupVc::from_chunk(chunk); - DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_group, - } - .cell() - .into() + Ok(chunkable.as_chunk(chunking_context.into())) } else { // TODO convert into a serve-able asset - return Err(anyhow!( + Err(anyhow!( "Entry module is not chunkable, so it can't be used to bootstrap the application" - )); - }; + )) + } + // ChunkGroupVc::from_chunk(m) + })) + .await?; + + let entry_asset = DevHtmlAsset { + path: FileSystemPathVc::new(dev_server_fs, "index.html"), + chunk_groups: chunks.into_iter().map(ChunkGroupVc::from_chunk).collect(), + } + .cell() + .into(); let root_path = FileSystemPathVc::new(dev_server_fs, ""); let graph = if eager_compile { diff --git a/packages/next-swc/crates/next-dev/tests/harness.js b/packages/next-swc/crates/next-dev/tests/harness.js new file mode 100644 index 00000000000000..64c95d3959baeb --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/harness.js @@ -0,0 +1,7 @@ +import * as jest from 'jest-circus-browser/dist/umd/jest-circus.js' +import expect from 'expect/build-es5/index.js' + +globalThis.__jest__ = jest +globalThis.expect = expect +globalThis.describe = jest.describe +globalThis.it = jest.it diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs new file mode 100644 index 00000000000000..bcbd690913773f --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -0,0 +1,136 @@ +#![cfg(test)] +extern crate test_generator; + +use std::{net::SocketAddr, path::Path}; + +use chromiumoxide::browser::{Browser, BrowserConfig}; +use futures::StreamExt; +use next_dev::{register, NextDevServerBuilder}; +use serde::Deserialize; +use test_generator::test_resources; +use turbo_tasks::TurboTasks; +use turbo_tasks_memory::MemoryBackend; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct JestRunResult { + test_results: Vec, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct JestTestResult { + test_path: Vec, + errors: Vec, +} + +#[test_resources("crates/next-dev/tests/integration/*/*/*")] +#[tokio::main] +async fn test(resource: &str) { + register(); + let path = Path::new(resource) + // test_resources matches and returns relative paths from the workspace root, + // but pwd in cargo tests is the crate under test. + .strip_prefix("crates/next-dev") + .unwrap(); + assert!(path.exists(), "{} does not exist", resource); + + assert!( + path.is_dir(), + "{} is not a directory. Integration tests must be directories.", + path.to_str().unwrap() + ); + + if path.ends_with("__skipped__") { + // "Skip" directories named `__skipped__`, which include test directories to + // skip. These tests are not considered truly skipped by `cargo test`, but they + // are not run. + return; + } + + let test_entry = path.join("index.js"); + assert!( + test_entry.exists(), + "Test entry {} must exist.", + test_entry.to_str().unwrap() + ); + + let server = NextDevServerBuilder::new() + .turbo_tasks(TurboTasks::new(MemoryBackend::new())) + .project_dir("tests".into()) + .entry_asset("harness.js".into()) + .entry_asset( + test_entry + .strip_prefix("tests") + .unwrap() + .to_str() + .unwrap() + .replace('\\', "/"), + ) + .eager_compile(false) + .hostname("127.0.0.1".parse().unwrap()) + .port(portpicker::pick_unused_port().unwrap()) + .build() + .await + .unwrap(); + + println!("server started at http://{}", server.addr); + + tokio::select! { + r = run_browser_test(server.addr) => r.unwrap(), + r = server.future => r.unwrap(), + }; +} + +async fn create_browser() -> Result> { + let (browser, mut handler) = Browser::launch(BrowserConfig::builder().build()?).await?; + // See https://crates.io/crates/chromiumoxide + tokio::task::spawn(async move { + loop { + let _ = handler.next().await.unwrap(); + } + }); + + Ok(browser) +} + +async fn run_browser_test(addr: SocketAddr) -> Result<(), Box> { + let browser = create_browser().await?; + + let page = browser.new_page(format!("http://{}", addr)).await?; + + let run_result: JestRunResult = page + .evaluate("__jest__.run()") + .await + .unwrap() + .into_value() + .unwrap(); + + assert!( + !run_result.test_results.is_empty(), + "Expected one or more tests to run." + ); + + let mut messages = vec![]; + for test_result in run_result.test_results { + // It's possible to fail multiple tests across these tests, + // so collect them and fail the respective test in Rust with + // an aggregate message. + if !test_result.errors.is_empty() { + messages.push(format!( + "\"{}\":\n{}", + test_result.test_path[1..].join(" > "), + test_result.errors.join("\n") + )); + } + } + + if !messages.is_empty() { + panic!( + "Failed with error(s) in the following test(s):\n\n{}", + messages.join("\n\n--\n") + ) + } + + Ok(()) +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js new file mode 100644 index 00000000000000..64dbc0d26757fc --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js @@ -0,0 +1,19 @@ +it('runs sync tests', () => { + expect(true).toBe(true) +}) + +it('runs async tests', async () => { + await Promise.resolve() + expect(true).toBe(true) +}) + +describe('nested describe', () => { + it('runs sync tests', () => { + expect(true).toBe(true) + }) + + it('runs async tests', async () => { + await Promise.resolve() + expect(true).toBe(true) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json new file mode 100644 index 00000000000000..8c4ae087a410d7 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -0,0 +1,10 @@ +{ + "private": true, + "devDependencies": { + "expect": "^24.5.0", + "jest-circus-browser": "^1.0.7" + }, + "installConfig": { + "hoistingLimits": "workspaces" + } +} From 1a5d175d8d08e81cf8f079aa87d656b2cac90c3f Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 9 Aug 2022 19:38:05 +0200 Subject: [PATCH 035/672] Update toolchain to 2022-08-02 (vercel/turbo#215) * Update toolchain to 2022-08-02 * Fix warnings --- packages/next-swc/crates/next-dev/src/lib.rs | 1 - packages/next-swc/crates/next-dev/src/main.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 76a49a8906dffd..b9a3d9c8c17a05 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -1,5 +1,4 @@ #![feature(future_join)] -#![feature(future_poll_fn)] #![feature(min_specialization)] use std::{net::IpAddr, sync::Arc}; diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 947bb33dc59b3f..8b269beac9c5e4 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -1,5 +1,4 @@ #![feature(future_join)] -#![feature(future_poll_fn)] #![feature(min_specialization)] use std::{ From 51c69f20f87a9c4d9dc7e677d514f09aec4696b0 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 10 Aug 2022 03:14:01 -0700 Subject: [PATCH 036/672] next-dev test runner: Implement manual debug mode (vercel/turbo#211) This implements a manual debug mode for next-dev tests, enabled by setting the environment variable TURBOPACK_DEBUG_BROWSER to any value. It launches the test browser in non-headless mode and holds it open ~~indefinitely~~ until the user closes it, so it can be inspected. Test Plan: `TURBOPACK_DEBUG_BROWSER=1 cargo test -p next-dev -- test_crates_next_dev_tests_integration_chunks_circular_correctness --nocapture` and verify the browser is opened non-headless and is held open --- packages/next-swc/crates/next-dev/Cargo.toml | 2 + .../crates/next-dev/tests/integration.rs | 84 +++++++++++++++---- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 9ec1284742e759..7fd4a964b91aa4 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -39,6 +39,8 @@ turbopack-dev-server = { path = "../turbopack-dev-server" } webbrowser = "0.7.1" [dev-dependencies] +tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in +# sync with chromiumoxide's tungstenite requirement. chromiumoxide = { version = "0.3.5", features = [ "tokio-runtime", ], default-features = false } diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index bcbd690913773f..c17ae8c4699023 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -1,13 +1,19 @@ #![cfg(test)] extern crate test_generator; -use std::{net::SocketAddr, path::Path}; +use std::{env, net::SocketAddr, path::Path}; -use chromiumoxide::browser::{Browser, BrowserConfig}; +use chromiumoxide::{ + browser::{Browser, BrowserConfig}, + error::CdpError::Ws, +}; use futures::StreamExt; +use lazy_static::lazy_static; use next_dev::{register, NextDevServerBuilder}; use serde::Deserialize; use test_generator::test_resources; +use tokio::task::JoinHandle; +use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; use turbo_tasks::TurboTasks; use turbo_tasks_memory::MemoryBackend; @@ -24,6 +30,12 @@ struct JestTestResult { errors: Vec, } +lazy_static! { + // Allows for interactive manual debugging of a test case in a browser with: + // `TURBOPACK_DEBUG_BROWSER=1 cargo test -p next-dev -- test_my_pattern --nocapture` + static ref DEBUG_BROWSER: bool = env::var("TURBOPACK_DEBUG_BROWSER").is_ok(); +} + #[test_resources("crates/next-dev/tests/integration/*/*/*")] #[tokio::main] async fn test(resource: &str) { @@ -77,34 +89,70 @@ async fn test(resource: &str) { println!("server started at http://{}", server.addr); tokio::select! { - r = run_browser_test(server.addr) => r.unwrap(), + r = run_browser(server.addr) => r.unwrap(), r = server.future => r.unwrap(), }; } -async fn create_browser() -> Result> { - let (browser, mut handler) = Browser::launch(BrowserConfig::builder().build()?).await?; +async fn create_browser( + is_debugging: bool, +) -> Result<(Browser, JoinHandle<()>), Box> { + let mut config_builder = BrowserConfig::builder(); + if is_debugging { + config_builder = config_builder + .with_head() + .args(vec!["--auto-open-devtools-for-tabs"]); + } + + let (browser, mut handler) = Browser::launch(config_builder.build()?).await?; // See https://crates.io/crates/chromiumoxide - tokio::task::spawn(async move { + let thread_handle = tokio::task::spawn(async move { loop { - let _ = handler.next().await.unwrap(); + if let Err(Ws(Protocol(ResetWithoutClosingHandshake))) = handler.next().await.unwrap() { + // The user has most likely closed the browser. End gracefully. + break; + } } }); - Ok(browser) + Ok((browser, thread_handle)) } -async fn run_browser_test(addr: SocketAddr) -> Result<(), Box> { - let browser = create_browser().await?; +async fn run_browser(addr: SocketAddr) -> Result<(), Box> { + if *DEBUG_BROWSER { + run_debug_browser(addr).await?; + } + + run_test_browser(addr).await?; + Ok(()) +} + +async fn run_debug_browser(addr: SocketAddr) -> Result<(), Box> { + let (browser, handle) = create_browser(true).await?; let page = browser.new_page(format!("http://{}", addr)).await?; - let run_result: JestRunResult = page - .evaluate("__jest__.run()") - .await - .unwrap() - .into_value() - .unwrap(); + let run_tests_msg = + "Entering debug mode. Run `await __jest__.run()` in the browser console to run tests."; + println!("\n\n{}", run_tests_msg); + page.evaluate(format!( + r#"console.info("%cTurbopack tests:", "font-weight: bold;", "{}");"#, + run_tests_msg + )) + .await?; + + // Wait for the user to close the browser + handle.await?; + + Ok(()) +} + +async fn run_test_browser(addr: SocketAddr) -> Result> { + let (browser, _) = create_browser(false).await?; + let page = browser.new_page(format!("http://{}", addr)).await?; + page.wait_for_navigation().await?; + + let run_result: JestRunResult = page.evaluate("__jest__.run()").await?.into_value()?; assert!( !run_result.test_results.is_empty(), @@ -112,7 +160,7 @@ async fn run_browser_test(addr: SocketAddr) -> Result<(), Box Result<(), Box Date: Thu, 11 Aug 2022 10:03:38 +0200 Subject: [PATCH 037/672] Introduce FileContent, Versioned, and refactor dev server updates (vercel/turbo#209) This prepares the way for HMR (vercel/turbo#160) by letting us diff assets between versions. 1. Add `Asset::versioned_content` which returns a `VersionedContentVc`. 2. `VersionedContent`s have a built-in versioning mechanism as they must implement `version() -> VersionVc`. `Version` is a trait, so `VersionVc` can contain a specific version implementation by asset type. This is particularly important because... 3. A `VersionedContentVc` can be diffed with a `VersionVc` from the same underlying `VersionedContent` type with `content.update(from: version)`. This returns an `UpdateVc` which describes the steps necessary to update from one verson to the next. In the case of ES chunks, this will be a map of added, and modified module IDs, with their respective factories, and a set of deleted module IDs. 4. Implement diffing for ES chunks. --- packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index c093249353f779..f8fb8fe000e8a6 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -3,8 +3,9 @@ use std::{str::FromStr, sync::Arc}; use anyhow::Result; use mime::Mime; use turbo_tasks::TurboTasks; -use turbo_tasks_fs::{File, FileContent, FileContentVc}; +use turbo_tasks_fs::{File, FileContent}; use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; +use turbopack_core::version::VersionedContentVc; use turbopack_dev_server::source::{ContentSource, ContentSourceVc}; #[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new", into = "new")] @@ -22,7 +23,7 @@ impl TurboTasksSourceVc { #[turbo_tasks::value_impl] impl ContentSource for TurboTasksSource { #[turbo_tasks::function] - fn get(&self, path: &str) -> Result { + fn get(&self, path: &str) -> Result { let tt = &self.turbo_tasks; if path == "graph" { let mut stats = Stats::new(); @@ -56,7 +57,7 @@ impl ContentSource for TurboTasksSource { } #[turbo_tasks::function] - fn get_by_id(&self, _id: &str) -> FileContentVc { + fn get_by_id(&self, _id: &str) -> VersionedContentVc { FileContent::NotFound.into() } } From 47782703059e945fdaf10f319fa76148cd866b61 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 11 Aug 2022 09:33:25 -0700 Subject: [PATCH 038/672] next-dev test runner: Check in and use webpack's chunk test cases (vercel/turbo#212) This commits webpack's chunk tests (test/cases/chunks) and skips those that do not pass yet. Test Plan: `cargo test -p next-dev -- --nocapture` and verify the non-skipped tests run. --- .../tests/integration/webpack/LICENSE-webpack | 20 ++ .../__skipped__/context-weak/dir/four.js | 1 + .../chunks/__skipped__/context-weak/index.js | 29 +++ .../chunks/__skipped__/context-weak/three.js | 1 + .../chunks/__skipped__/context-weak/two.js | 1 + .../chunks/__skipped__/context/index.js | 9 + .../webpack/chunks/__skipped__/context/two.js | 1 + .../chunks/__skipped__/import-circle/index.js | 11 + .../__skipped__/import-circle/leftHelix.js | 6 + .../import-circle/leftHelixPrime.js | 9 + .../__skipped__/import-circle/rightHelix.js | 6 + .../import-circle/rightHelixPrime.js | 9 + .../initialModule.js | 1 + .../initialModule2.js | 1 + .../dir-initial/initialModule.js | 1 + .../import-context-exist-chunk/index.js | 21 ++ .../__skipped__/import-context/dir/one.js | 1 + .../__skipped__/import-context/dir/three.js | 1 + .../__skipped__/import-context/dir/two.js | 1 + .../__skipped__/import-context/dir2/one.js | 1 + .../__skipped__/import-context/dir2/three.js | 1 + .../__skipped__/import-context/dir2/two.js | 1 + .../__skipped__/import-context/index.js | 42 ++++ .../chunks/__skipped__/import/index.js | 14 ++ .../webpack/chunks/__skipped__/import/two.js | 1 + .../__skipped__/inline-options/dir1/a.js | 1 + .../__skipped__/inline-options/dir1/b.js | 1 + .../__skipped__/inline-options/dir1/c.js | 1 + .../__skipped__/inline-options/dir1/d.js | 1 + .../__skipped__/inline-options/dir10/a.js | 1 + .../__skipped__/inline-options/dir11/a.js | 1 + .../__skipped__/inline-options/dir12/a.js | 9 + .../__skipped__/inline-options/dir13/a.js | 7 + .../__skipped__/inline-options/dir13/b.js | 7 + .../__skipped__/inline-options/dir2/a.js | 1 + .../__skipped__/inline-options/dir2/b.js | 1 + .../__skipped__/inline-options/dir2/c.js | 1 + .../__skipped__/inline-options/dir2/d.js | 1 + .../__skipped__/inline-options/dir3/a.js | 1 + .../__skipped__/inline-options/dir3/b.js | 1 + .../__skipped__/inline-options/dir3/c.js | 1 + .../__skipped__/inline-options/dir3/d.js | 1 + .../__skipped__/inline-options/dir4/a.js | 1 + .../__skipped__/inline-options/dir4/b.js | 1 + .../__skipped__/inline-options/dir4/c.js | 1 + .../__skipped__/inline-options/dir4/d.js | 1 + .../__skipped__/inline-options/dir5/a.js | 1 + .../__skipped__/inline-options/dir5/b.js | 1 + .../__skipped__/inline-options/dir5/c.js | 1 + .../__skipped__/inline-options/dir5/d.js | 1 + .../__skipped__/inline-options/dir6/a.js | 1 + .../__skipped__/inline-options/dir6/b.js | 1 + .../__skipped__/inline-options/dir6/c.js | 1 + .../__skipped__/inline-options/dir6/d.js | 1 + .../__skipped__/inline-options/dir7/a.js | 1 + .../__skipped__/inline-options/dir7/b.js | 1 + .../__skipped__/inline-options/dir7/c.js | 1 + .../__skipped__/inline-options/dir7/d.js | 1 + .../__skipped__/inline-options/dir8/a.js | 1 + .../__skipped__/inline-options/dir8/b.js | 1 + .../__skipped__/inline-options/dir8/c.js | 1 + .../__skipped__/inline-options/dir9/a.js | 1 + .../__skipped__/inline-options/dir9/b.js | 1 + .../__skipped__/inline-options/dir9/c.js | 1 + .../__skipped__/inline-options/index.js | 226 ++++++++++++++++++ .../__skipped__/issue-2443/dir/one/file.js | 1 + .../__skipped__/issue-2443/dir/three/file.js | 1 + .../__skipped__/issue-2443/dir/two/file.js | 1 + .../chunks/__skipped__/issue-2443/index.js | 26 ++ .../chunks/__skipped__/issue-5153/index.js | 7 + .../chunks/__skipped__/issue-5153/module.js | 1 + .../chunks/__skipped__/named-chunks/empty.js | 0 .../chunks/__skipped__/named-chunks/empty2.js | 0 .../chunks/__skipped__/named-chunks/empty3.js | 0 .../chunks/__skipped__/named-chunks/empty4.js | 0 .../chunks/__skipped__/named-chunks/index.js | 177 ++++++++++++++ .../chunks/__skipped__/nested-in-empty/a.js | 0 .../chunks/__skipped__/nested-in-empty/b.js | 1 + .../__skipped__/nested-in-empty/index.js | 13 + .../chunks/__skipped__/parsing/empty.js | 0 .../chunks/__skipped__/parsing/index.js | 49 ++++ .../__skipped__/parsing/require.include.js | 1 + .../webpack/chunks/__skipped__/runtime/a.js | 1 + .../chunks/__skipped__/runtime/acircular.js | 3 + .../chunks/__skipped__/runtime/acircular2.js | 3 + .../webpack/chunks/__skipped__/runtime/b.js | 1 + .../chunks/__skipped__/runtime/duplicate.js | 3 + .../chunks/__skipped__/runtime/duplicate2.js | 3 + .../chunks/__skipped__/runtime/empty.js | 0 .../chunks/__skipped__/runtime/index.js | 54 +++++ .../chunks/__skipped__/runtime/test.filter.js | 4 + .../var-inject-error-handler/empty.js | 0 .../var-inject-error-handler/index.js | 12 + .../weak-dependencies-context/a.js | 0 .../weak-dependencies-context/b.js | 0 .../weak-dependencies-context/c.js | 0 .../weak-dependencies-context/index.js | 24 ++ .../chunks/__skipped__/weak-dependencies/a.js | 0 .../chunks/__skipped__/weak-dependencies/b.js | 0 .../chunks/__skipped__/weak-dependencies/c.js | 0 .../chunks/__skipped__/weak-dependencies/d.js | 0 .../__skipped__/weak-dependencies/index.js | 13 + .../chunks/circular-correctness/index.js | 16 ++ .../chunks/circular-correctness/module-a.js | 3 + .../chunks/circular-correctness/module-a2.js | 1 + .../chunks/circular-correctness/module-b.js | 5 + .../chunks/circular-correctness/module-b2.js | 1 + .../chunks/circular-correctness/module-c.js | 9 + .../chunks/circular-correctness/module-x.js | 1 + .../chunks/weird-reference-to-entry/errors.js | 5 + .../chunks/weird-reference-to-entry/index.js | 10 + .../weird-reference-to-entry/module-a.js | 1 + 112 files changed, 926 insertions(+) create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/LICENSE-webpack create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty2.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty3.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty4.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/empty.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/empty.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/empty.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/d.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/LICENSE-webpack b/packages/next-swc/crates/next-dev/tests/integration/webpack/LICENSE-webpack new file mode 100644 index 00000000000000..8c11fc7289b754 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/LICENSE-webpack @@ -0,0 +1,20 @@ +Copyright JS Foundation and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js new file mode 100644 index 00000000000000..11f8e7e4030768 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js @@ -0,0 +1 @@ +module.exports = 4 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js new file mode 100644 index 00000000000000..ae7870d4766ba4 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js @@ -0,0 +1,29 @@ +it("should not bundle context requires with asyncMode === 'weak'", function () { + var contextRequire = require.context('.', false, /two/, 'weak') + expect(function () { + contextRequire('./two') + }).toThrowError(/not available/) +}) + +it("should not bundle context requires with asyncMode === 'weak' using import.meta.webpackContext", function () { + const contextRequire = import.meta.webpackContext('.', { + recursive: false, + regExp: /two/, + mode: 'weak', + }) + expect(function () { + contextRequire('./two') + }).toThrowError(/not available/) +}) + +it("should find module with asyncMode === 'weak' when required elsewhere", function () { + var contextRequire = require.context('.', false, /.+/, 'weak') + expect(contextRequire('./three')).toBe(3) + require('./three') // in a real app would be served as a separate chunk +}) + +it("should find module with asyncMode === 'weak' when required elsewhere (recursive)", function () { + var contextRequire = require.context('.', true, /.+/, 'weak') + expect(contextRequire('./dir/four')).toBe(4) + require('./dir/four') // in a real app would be served as a separate chunk +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js new file mode 100644 index 00000000000000..6887896a4640a8 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js @@ -0,0 +1 @@ +module.exports = 3 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js new file mode 100644 index 00000000000000..4afe2ededa2763 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js @@ -0,0 +1 @@ +module.exports = 2 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js new file mode 100644 index 00000000000000..663649f4dea3b1 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js @@ -0,0 +1,9 @@ +it('should also work in a chunk', function (done) { + require.ensure([], function (require) { + var contextRequire = require.context('.', false, /two/) + expect(contextRequire('./two')).toBe(2) + var tw = 'tw' + expect(require('.' + '/' + tw + 'o')).toBe(2) + done() + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js new file mode 100644 index 00000000000000..4afe2ededa2763 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js @@ -0,0 +1 @@ +module.exports = 2 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js new file mode 100644 index 00000000000000..cd992f62acbe05 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js @@ -0,0 +1,11 @@ +import leftHelix from './leftHelix' +import rightHelix from './rightHelix' + +it('should import generate ensure function for this', () => { + return Promise.all([leftHelix.run(), rightHelix.run()]) +}) + +export default { + leftHelix, + rightHelix, +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js new file mode 100644 index 00000000000000..620445f512afb7 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js @@ -0,0 +1,6 @@ +import leftHelixPrime, { run } from './leftHelixPrime' + +export default { + leftHelixPrime, + run, +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js new file mode 100644 index 00000000000000..f330e942e5a7db --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js @@ -0,0 +1,9 @@ +import rightHelixPrime from './rightHelixPrime' + +export function run() { + return import(/* webpackChunkName: "left" */ './leftHelix') +} + +export default { + rightHelixPrime: () => rightHelixPrime, +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js new file mode 100644 index 00000000000000..8836f2f9d4d33c --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js @@ -0,0 +1,6 @@ +import rightHelixPrime, { run } from './rightHelixPrime' + +export default { + rightHelixPrime, + run, +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js new file mode 100644 index 00000000000000..123e3723a17ad0 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js @@ -0,0 +1,9 @@ +import leftHelixPrime from './leftHelixPrime' + +export function run() { + return import(/* webpackChunkName: "right" */ './rightHelix') +} + +export default { + leftHelixPrime: () => leftHelixPrime, +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js new file mode 100644 index 00000000000000..31f025c1266247 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js @@ -0,0 +1 @@ +export default 'initialModuleDefault' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js new file mode 100644 index 00000000000000..65f212bcf1317e --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js @@ -0,0 +1 @@ +exports.default = 'other' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js new file mode 100644 index 00000000000000..31f025c1266247 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js @@ -0,0 +1 @@ +export default 'initialModuleDefault' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js new file mode 100644 index 00000000000000..0baa2ceaf64b03 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js @@ -0,0 +1,21 @@ +it('should resolve when import existed chunk (#8626)', function (done) { + require.context('./dir-initial/') + const fileName = 'initialModule' + import(`./dir-initial/${fileName}`) + .then(({ default: m }) => { + expect(m).toBe('initialModuleDefault') + done() + }) + .catch(done) +}) + +it('should resolve when import existed chunk with fake maps', function (done) { + require.context('./dir-initial-with-fake-map/') + const fileName = 'initialModule' + import(`./dir-initial-with-fake-map/${fileName}`) + .then(({ default: m }) => { + expect(m).toBe('initialModuleDefault') + done() + }) + .catch(done) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js new file mode 100644 index 00000000000000..e8f7328d6ee564 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js @@ -0,0 +1 @@ +module.exports = 1 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js new file mode 100644 index 00000000000000..6887896a4640a8 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js @@ -0,0 +1 @@ +module.exports = 3 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js new file mode 100644 index 00000000000000..4afe2ededa2763 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js @@ -0,0 +1 @@ +module.exports = 2 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js new file mode 100644 index 00000000000000..e8f7328d6ee564 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js @@ -0,0 +1 @@ +module.exports = 1 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js new file mode 100644 index 00000000000000..6887896a4640a8 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js @@ -0,0 +1 @@ +module.exports = 3 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js new file mode 100644 index 00000000000000..4afe2ededa2763 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js @@ -0,0 +1 @@ +module.exports = 2 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js new file mode 100644 index 00000000000000..feaea8796f91a3 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js @@ -0,0 +1,42 @@ +function testCase(load, done) { + load('two', 2, function () { + var sync = true + load('one', 1, function () { + expect(sync).toBe(false) + load('three', 3, function () { + var sync = true + load('two', 2, function () { + expect(sync).toBe(true) + done() + }) + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () { + sync = false + }) + }) + }) + Promise.resolve().then(function () { + sync = false + }) + }) +} + +it('should be able to use expressions in import', function (done) { + function load(name, expected, callback) { + import('./dir/' + name) + .then(function (result) { + expect(result).toEqual( + nsObj({ + default: expected, + }), + ) + callback() + }) + .catch(function (err) { + done(err) + }) + } + testCase(load, done) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js new file mode 100644 index 00000000000000..6825a7d22f67cd --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js @@ -0,0 +1,14 @@ +it('should be able to use import', function (done) { + import('./two') + .then(function (two) { + expect(two).toEqual( + nsObj({ + default: 2, + }), + ) + done() + }) + .catch(function (err) { + done(err) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js new file mode 100644 index 00000000000000..4afe2ededa2763 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js @@ -0,0 +1 @@ +module.exports = 2 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js new file mode 100644 index 00000000000000..5b54497ffd4a67 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js @@ -0,0 +1 @@ +export default 'd' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js new file mode 100644 index 00000000000000..e76b95092fa037 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js @@ -0,0 +1,9 @@ +export const c = 'c' + +export const d = 'd' + +export const longnameforexport = 'longnameforexport' + +export default 'default2' + +export const usedExports = __webpack_exports_info__.usedExports diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js new file mode 100644 index 00000000000000..ad25fc156cf77f --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js @@ -0,0 +1,7 @@ +export const c = 'c' + +export const d = 'd' + +export default 'default2' + +export const usedExports = __webpack_exports_info__.usedExports diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js new file mode 100644 index 00000000000000..550822fd68d778 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js @@ -0,0 +1,7 @@ +export const a = 'a' + +export const b = 'b' + +export default 'default' + +export const usedExports = __webpack_exports_info__.usedExports diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js new file mode 100644 index 00000000000000..5b54497ffd4a67 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js @@ -0,0 +1 @@ +export default 'd' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js new file mode 100644 index 00000000000000..5b54497ffd4a67 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js @@ -0,0 +1 @@ +export default 'd' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js new file mode 100644 index 00000000000000..5b54497ffd4a67 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js @@ -0,0 +1 @@ +export default 'd' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js new file mode 100644 index 00000000000000..5b54497ffd4a67 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js @@ -0,0 +1 @@ +export default 'd' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js new file mode 100644 index 00000000000000..5b54497ffd4a67 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js @@ -0,0 +1 @@ +export default 'd' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js new file mode 100644 index 00000000000000..5b54497ffd4a67 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js @@ -0,0 +1 @@ +export default 'd' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js new file mode 100644 index 00000000000000..90bd54cd7f2e6d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js @@ -0,0 +1 @@ +export default 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js new file mode 100644 index 00000000000000..a3bb49043e4bab --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js @@ -0,0 +1 @@ +export default 'b' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js new file mode 100644 index 00000000000000..da4b0edae9cc2b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js @@ -0,0 +1 @@ +export default 'c' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js new file mode 100644 index 00000000000000..7e4e66cba60e6b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js @@ -0,0 +1,226 @@ +it('should be able to use eager mode', function () { + function load(name) { + return import(/* webpackMode: "eager" */ './dir1/' + name) + } + return testChunkLoading(load, true, true) +}) + +it('should be able to use lazy-once mode', function () { + function load(name) { + return import(/* webpackMode: "lazy-once" */ './dir2/' + name) + } + return testChunkLoading(load, false, true) +}) + +it('should be able to use lazy-once mode with name', function () { + function load(name) { + return import( + /* webpackMode: "lazy-once", webpackChunkName: "name-lazy-once" */ './dir3/' + + name + ) + } + return testChunkLoading(load, false, true) +}) + +it('should be able to use lazy mode', function () { + function load(name) { + return import(/* webpackMode: "lazy" */ './dir4/' + name) + } + return testChunkLoading(load, false, false) +}) + +it('should be able to use lazy mode with name', function () { + function load(name) { + return import( + /* webpackMode: "lazy", webpackChunkName: "name-lazy" */ './dir5/' + name + ) + } + return testChunkLoading(load, false, false) +}) + +it('should be able to use lazy mode with name and placeholder', function () { + function load(name) { + return import( + /* webpackMode: "lazy", webpackChunkName: "name-lazy-[request]" */ './dir6/' + + name + ) + } + return testChunkLoading(load, false, false) +}) + +it('should be able to combine chunks by name', function () { + function load(name) { + switch (name) { + case 'a': + return import(/* webpackMode: "eager" */ './dir7/a') + case 'b': + return import(/* webpackChunkName: "name-3" */ './dir7/b') + case 'c': + return import(/* webpackChunkName: "name-3" */ './dir7/c') + case 'd': + return import(/* webpackChunkName: "name-3" */ './dir7/d') + default: + throw new Error('Unexpected test data') + } + } + return testChunkLoading(load, false, true) +}) + +it('should be able to use weak mode', function () { + function load(name) { + return import(/* webpackMode: "weak" */ './dir8/' + name) + } + require('./dir8/a') // chunks served manually by the user + require('./dir8/b') + require('./dir8/c') + return testChunkLoading(load, true, true) +}) + +it('should be able to use weak mode (without context)', function () { + function load(name) { + switch (name) { + case 'a': + return import(/* webpackMode: "weak" */ './dir9/a') + case 'b': + return import(/* webpackMode: "weak" */ './dir9/b') + case 'c': + return import(/* webpackMode: "weak" */ './dir9/c') + default: + throw new Error('Unexpected test data') + } + } + require('./dir9/a') // chunks served manually by the user + require('./dir9/b') + require('./dir9/c') + return testChunkLoading(load, true, true) +}) + +it('should not find module when mode is weak and chunk not served elsewhere', function () { + var name = 'a' + return import(/* webpackMode: "weak" */ './dir10/' + name).catch(function ( + e, + ) { + expect(e).toMatchObject({ + message: /not available/, + code: /MODULE_NOT_FOUND/, + }) + }) +}) + +it('should not find module when mode is weak and chunk not served elsewhere (without context)', function () { + return import(/* webpackMode: "weak" */ './dir11/a').catch(function (e) { + expect(e).toMatchObject({ + message: /not available/, + code: /MODULE_NOT_FOUND/, + }) + }) +}) + +if (process.env.NODE_ENV === 'production') { + it('should contain only one export from webpackExports from module', function () { + return import(/* webpackExports: "usedExports" */ './dir12/a?1').then( + (module) => { + expect(module.usedExports).toEqual(['usedExports']) + }, + ) + }) + + it('should contain only webpackExports from module', function () { + return import( + /* webpackExports: ["a", "usedExports", "b"] */ './dir12/a?2' + ).then((module) => { + expect(module.usedExports).toEqual(['a', 'b', 'usedExports']) + }) + }) + + it('should contain only webpackExports from module in eager mode', function () { + return import( + /* + webpackMode: "eager", + webpackExports: ["a", "usedExports", "b"] + */ './dir12/a?3' + ).then((module) => { + expect(module.usedExports).toEqual(['a', 'b', 'usedExports']) + }) + }) + + it('should contain webpackExports from module in weak mode', function () { + require.resolve('./dir12/a?4') + return import( + /* + webpackMode: "weak", + webpackExports: ["a", "usedExports", "b"] + */ './dir12/a?4' + ).then((module) => { + expect(module.usedExports).toEqual(['a', 'b', 'usedExports']) + }) + }) + + it('should not mangle webpackExports from module', function () { + return import(/* webpackExports: "longnameforexport" */ './dir12/a?5').then( + (module) => { + expect(module).toHaveProperty('longnameforexport') + }, + ) + }) + + it('should not mangle default webpackExports from module', function () { + return import(/* webpackExports: "default" */ './dir12/a?6').then( + (module) => { + expect(module).toHaveProperty('default') + }, + ) + }) + + it('should contain only webpackExports from module in context mode', function () { + const x = 'b' + return import(/* webpackExports: "usedExports" */ `./dir13/${x}`).then( + (module) => { + expect(module.usedExports).toEqual(['usedExports']) + }, + ) + }) +} + +function testChunkLoading(load, expectedSyncInitial, expectedSyncRequested) { + var sync = false + var syncInitial = true + var p = Promise.all([load('a'), load('b')]).then(function () { + expect(syncInitial).toBe(expectedSyncInitial) + sync = true + var p = Promise.all([ + load('a').then(function (a) { + expect(a).toEqual( + nsObj({ + default: 'a', + }), + ) + expect(sync).toBe(true) + }), + load('c').then(function (c) { + expect(c).toEqual( + nsObj({ + default: 'c', + }), + ) + expect(sync).toBe(expectedSyncRequested) + }), + ]) + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () {}) + .then(function () { + sync = false + }) + return p + }) + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () {}) + .then(function () { + syncInitial = false + }) + return p +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js new file mode 100644 index 00000000000000..e8f7328d6ee564 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js @@ -0,0 +1 @@ +module.exports = 1 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js new file mode 100644 index 00000000000000..6887896a4640a8 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js @@ -0,0 +1 @@ +module.exports = 3 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js new file mode 100644 index 00000000000000..4afe2ededa2763 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js @@ -0,0 +1 @@ +module.exports = 2 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js new file mode 100644 index 00000000000000..8216ef4ff32bbd --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js @@ -0,0 +1,26 @@ +it('should be able to use expressions in import (directory)', function (done) { + function load(name, expected, callback) { + import('./dir/' + name + '/file.js') + .then(function (result) { + expect(result).toEqual( + nsObj({ + default: expected, + }), + ) + callback() + }) + .catch(function (err) { + done(err) + }) + } + if (Math.random() < 0) require('./dir/three/file') + load('one', 1, function () { + load('two', 2, function () { + load('three', 3, function () { + load('two', 2, function () { + done() + }) + }) + }) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js new file mode 100644 index 00000000000000..62fbb104f22099 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js @@ -0,0 +1,7 @@ +import x from './module' + +it('should export the same binding', () => { + return import('./module').then((ns) => { + expect(x).toBe(ns.default) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js new file mode 100644 index 00000000000000..b1c6ea436a5400 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js @@ -0,0 +1 @@ +export default {} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty2.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty3.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty3.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty4.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/empty4.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js new file mode 100644 index 00000000000000..abb59fc3305a23 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js @@ -0,0 +1,177 @@ +it('should handle named chunks', function (done) { + var sync = false + require.ensure( + [], + function (require) { + require('./empty?a') + require('./empty?b') + testLoad() + sync = true + process.nextTick(function () { + sync = false + }) + }, + 'named-chunk', + ) + function testLoad() { + require.ensure( + [], + function (require) { + require('./empty?c') + require('./empty?d') + expect(sync).toBeTruthy() + done() + }, + 'named-chunk', + ) + } +}) + +it('should handle empty named chunks', function (done) { + var sync = false + require.ensure( + [], + function (require) { + expect(sync).toBeTruthy() + }, + 'empty-named-chunk', + ) + require.ensure( + [], + function (require) { + expect(sync).toBeTruthy() + done() + }, + 'empty-named-chunk', + ) + sync = true + setImmediate(function () { + sync = false + }) +}) + +it('should handle named chunks when there is an error callback', function (done) { + var sync = false + require.ensure( + [], + function (require) { + require('./empty?e') + require('./empty?f') + testLoad() + sync = true + process.nextTick(function () { + sync = false + }) + }, + function (error) {}, + 'named-chunk-for-error-callback', + ) + function testLoad() { + require.ensure( + [], + function (require) { + require('./empty?g') + require('./empty?h') + expect(sync).toBeTruthy() + done() + }, + function (error) {}, + 'named-chunk-for-error-callback', + ) + } +}) + +it('should handle empty named chunks when there is an error callback', function (done) { + var sync = false + require.ensure( + [], + function (require) { + expect(sync).toBeTruthy() + }, + function (error) {}, + 'empty-named-chunk-for-error-callback', + ) + require.ensure( + [], + function (require) { + expect(sync).toBeTruthy() + done() + }, + function (error) {}, + 'empty-named-chunk-for-error-callback', + ) + sync = true + setImmediate(function () { + sync = false + }) +}) + +it('should be able to use named chunks in import()', function (done) { + var sync = false + import( + './empty?import1-in-chunk1' /* webpackChunkName: "import-named-chunk-1" */ + ).then(function (result) { + var i = 0 + import( + './empty?import2-in-chunk1' /* webpackChunkName: "import-named-chunk-1" */ + ) + .then(function (result) { + expect(sync).toBeTruthy() + if (i++ > 0) done() + }) + .catch(function (err) { + done(err) + }) + import( + './empty?import3-in-chunk2' /* webpackChunkName: "import-named-chunk-2" */ + ) + .then(function (result) { + expect(sync).toBeFalsy() + if (i++ > 0) done() + }) + .catch(function (err) { + done(err) + }) + sync = true + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () { + sync = false + }) + }) +}) + +it('should be able to use named chunk in context import()', function (done) { + // cspell:ignore mpty + var mpty = 'mpty' + var sync = false + import('./e' + mpty + '2' /* webpackChunkName: "context-named-chunk" */).then( + function (result) { + var i = 0 + import('./e' + mpty + '3' /* webpackChunkName: "context-named-chunk" */) + .then(function (result) { + expect(sync).toBeTruthy() + if (i++ > 0) done() + }) + .catch(function (err) { + done(err) + }) + import('./e' + mpty + '4' /* webpackChunkName: "context-named-chunk-2" */) + .then(function (result) { + expect(sync).toBeFalsy() + if (i++ > 0) done() + }) + .catch(function (err) { + done(err) + }) + sync = true + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () { + sync = false + }) + }, + ) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/a.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js new file mode 100644 index 00000000000000..a8653a9c9264ca --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js @@ -0,0 +1 @@ +module.exports = 42 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js new file mode 100644 index 00000000000000..529dea49dfd414 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js @@ -0,0 +1,13 @@ +it('should include a chunk nested in an empty chunk', (done) => { + require.ensure(['./a'], () => { + require.ensure([], () => { + require.ensure(['./a'], () => { + require.ensure([], () => { + const b = require('./b') + expect(b).toBe(42) + done() + }) + }) + }) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/empty.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/empty.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js new file mode 100644 index 00000000000000..d629ab1d37fa8d --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js @@ -0,0 +1,49 @@ +it('should handle bound function expressions', function (done) { + require.ensure( + [], + function (require) { + expect(this).toEqual({ test: true }) + require('./empty?test') + expect(process.nextTick).toBeTypeOf('function') // check if injection still works + require.ensure( + [], + function (require) { + expect(this).toEqual({ test: true }) + done() + }.bind(this), + ) + }.bind({ test: true }), + ) +}) + +it('should handle require.ensure without function expression', function (done) { + function f() { + done() + } + require.ensure([], f) +}) + +it("should parse expression in require.ensure, which isn't a function expression", function (done) { + require.ensure( + [], + (function () { + expect(require('./empty?require.ensure:test')).toEqual({}) + return function f() { + done() + } + })(), + ) +}) + +it('should accept an already included module', function (done) { + if (Math.random() < 0) require('./require.include') + var value = null + require.ensure([], function (require) { + value = require('./require.include') + }) + setImmediate(function () { + expect(value).toBe('require.include') + expect(value).toBe('require.include') + done() + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js new file mode 100644 index 00000000000000..2a3e53cff08921 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js @@ -0,0 +1 @@ +module.exports = 'require.include' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js new file mode 100644 index 00000000000000..67606e3f86ef08 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js @@ -0,0 +1 @@ +module.exports = 'a' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js new file mode 100644 index 00000000000000..dc7913891e6a38 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js @@ -0,0 +1,3 @@ +require.ensure(['./acircular2'], function (require) { + require('./acircular2') +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js new file mode 100644 index 00000000000000..91cc6f271ac6be --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js @@ -0,0 +1,3 @@ +require.ensure(['./acircular'], function (require) { + require('./acircular') +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js new file mode 100644 index 00000000000000..0df40b2a802d5f --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js @@ -0,0 +1 @@ +module.exports = require('./a') diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js new file mode 100644 index 00000000000000..1830a4e6eaf811 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js @@ -0,0 +1,3 @@ +require.ensure(['./a'], function (require) { + expect(require('./a')).toBe('a') +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js new file mode 100644 index 00000000000000..cf892b8dd66513 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js @@ -0,0 +1,3 @@ +require.ensure(['./b'], function (require) { + expect(require('./b')).toBe('a') +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/empty.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/empty.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js new file mode 100644 index 00000000000000..ac44d739b7caae --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js @@ -0,0 +1,54 @@ +/* globals it */ +it('should handle duplicate chunks', function (done) { + var firstOne = false, + secondOne = false + require.ensure([], function (require) { + require('./acircular') + require('./duplicate') + require('./duplicate2') + firstOne = true + if (secondOne) done() + }) + require.ensure([], function (require) { + require('./acircular2') + require('./duplicate') + require('./duplicate2') + secondOne = true + if (firstOne) done() + }) +}) + +it('should not load a chunk which is included in a already loaded one', function (done) { + var asyncFlag = false + require.ensure(['./empty?x', './empty?y', './empty?z'], function (require) { + try { + expect(asyncFlag).toBe(true) + loadChunk() + } catch (e) { + done(e) + } + }) + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () { + asyncFlag = true + }) + function loadChunk() { + var sync = true + require.ensure(['./empty?x', './empty?y'], function (require) { + try { + expect(sync).toBe(true) + done() + } catch (e) { + done(e) + } + }) + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () { + sync = false + }) + } +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js new file mode 100644 index 00000000000000..a530e6222da5b7 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js @@ -0,0 +1,4 @@ +module.exports = function (config) { + // This test can't run in development mode as it depends on the flagIncludedChunks optimization + return config.mode !== 'development' +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/empty.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/empty.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js new file mode 100644 index 00000000000000..fb000bb0f3214c --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js @@ -0,0 +1,12 @@ +it('should handle var injection in require.ensure with error callback', function (done) { + require.ensure( + [], + function (require) { + require('./empty') + var x = module.x + done() + }, + function (error) {}, + 'chunk-with-var-inject', + ) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/a.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/b.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/c.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js new file mode 100644 index 00000000000000..0677b49aba0006 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js @@ -0,0 +1,24 @@ +it('should not include a module with a weak dependency using context', function () { + var fileA = 'a' + var fileB = 'b' + var fileC = 'c' + + var resolveWeakA = require.resolveWeak('./' + fileA) + var resolveWeakB = require.resolveWeak('./' + fileB) + var resolveWeakC = require.resolveWeak('./' + fileC) + + var a = !!__webpack_modules__[resolveWeakA] + var b = !!__webpack_modules__[resolveWeakB] + var c = !!__webpack_modules__[resolveWeakC] + + require(['./b']) + require('./c') + + expect(resolveWeakA).toBeDefined() + expect(resolveWeakB).toBeDefined() + expect(resolveWeakC).toBeDefined() + + expect(a).toBe(false) + expect(b).toBe(false) + expect(c).toBe(true) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/a.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/b.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/c.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/d.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js new file mode 100644 index 00000000000000..57cc29d985da6a --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js @@ -0,0 +1,13 @@ +it('should not include a module with a weak dependency', function () { + var a = !!__webpack_modules__[require.resolveWeak('./a')] + var b = !!__webpack_modules__[require.resolve('./b')] + var c = !!__webpack_modules__[require.resolveWeak('./c')] + var d = !!__webpack_modules__[require.resolveWeak('./d')] + require(['./c']) + require('./d') + + expect(a).toBe(false) + expect(b).toBe(true) + expect(c).toBe(false) + expect(d).toBe(true) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js new file mode 100644 index 00000000000000..aeb0fa01602b30 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js @@ -0,0 +1,16 @@ +it('should handle circular chunks correctly', function (done) { + import(/* webpackChunkName: "a" */ './module-a') + .then(function (result) { + return result.default() + }) + .then(function (result2) { + expect(result2.default()).toBe('x') + done() + }) + .catch(function (e) { + done(e) + }) + const couldBe = function () { + return import(/* webpackChunkName: "b" */ './module-b') + } +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js new file mode 100644 index 00000000000000..28186c7d058d78 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js @@ -0,0 +1,3 @@ +export default function () { + return import(/* webpackChunkName: "c" */ './module-c') +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js new file mode 100644 index 00000000000000..11657bc4d6f874 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js @@ -0,0 +1 @@ +export default 'a2' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js new file mode 100644 index 00000000000000..6988115c8dfacc --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js @@ -0,0 +1,5 @@ +import './module-x' + +export default function () { + return import(/* webpackChunkName: "c" */ './module-c') +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js new file mode 100644 index 00000000000000..6ada853c4fcb7c --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js @@ -0,0 +1 @@ +export default 'b2' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js new file mode 100644 index 00000000000000..e1589931fec458 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js @@ -0,0 +1,9 @@ +import x from './module-x' + +export default function () { + if (Math.random() < -1) { + import(/* webpackChunkName: "a" */ './module-a') + import(/* webpackChunkName: "b" */ './module-b') + } + return x +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js new file mode 100644 index 00000000000000..064e9982a8b4d1 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js @@ -0,0 +1 @@ +export default 'x' diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js new file mode 100644 index 00000000000000..b143ed5890b4d2 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js @@ -0,0 +1,5 @@ +module.exports = [ + [ + /It's not allowed to load an initial chunk on demand\. The chunk name "main" is already used by an entrypoint\./, + ], +] diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js new file mode 100644 index 00000000000000..7bad2ad04f4dae --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js @@ -0,0 +1,10 @@ +it('should handle reference to entry chunk correctly', function (done) { + import(/* webpackChunkName: "main" */ './module-a') + .then(function (result) { + expect(result.default).toBe('ok') + done() + }) + .catch(function (e) { + done(e) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js new file mode 100644 index 00000000000000..60c71f346d9a3e --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js @@ -0,0 +1 @@ +export default 'ok' From c2fb81dd37691973cbc2e04aab8a8a0c2df7140d Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 11 Aug 2022 09:39:32 -0700 Subject: [PATCH 039/672] next-dev test runner: Ensure skipped tests fail (vercel/turbo#216) This adds test runs for integration tests in `__skipped__` directories, ensuring that they fail, otherwise they should probably be unskipped. Test Plan: Temporarily moved a succeeding test into a `__skipped__` directory and ensured that cargo test began failing that test. --- .../crates/next-dev/tests/integration.rs | 103 +++++++++++------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index c17ae8c4699023..ccd9568767b87c 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -39,6 +39,62 @@ lazy_static! { #[test_resources("crates/next-dev/tests/integration/*/*/*")] #[tokio::main] async fn test(resource: &str) { + if resource.ends_with("__skipped__") { + // "Skip" directories named `__skipped__`, which include test directories to + // skip. These tests are not considered truly skipped by `cargo test`, but they + // are not run. + return; + } + + let run_result = run_test(resource).await; + + assert!( + !run_result.test_results.is_empty(), + "Expected one or more tests to run." + ); + + let mut messages = vec![]; + for test_result in run_result.test_results { + // It's possible to fail multiple tests across these tests, + // so collect them and fail the respective test in Rust with + // an aggregate message. + if !test_result.errors.is_empty() { + messages.push(format!( + "\"{}\":\n{}", + test_result.test_path[1..].join(" > "), + test_result.errors.join("\n") + )); + } + } + + if !messages.is_empty() { + panic!( + "Failed with error(s) in the following test(s):\n\n{}", + messages.join("\n\n--\n") + ) + }; +} + +#[test_resources("crates/next-dev/tests/integration/*/*/__skipped__/*")] +#[should_panic] +#[tokio::main] +async fn test_skipped_fails(resource: &str) { + let run_result = run_test(resource).await; + + // Assert that this skipped test itself has at least one browser test which + // fails. + assert!( + // Skipped tests sometimes have errors (e.g. unsupported syntax) that prevent tests from + // running at all. Allow them to have empty results. + run_result.test_results.is_empty() + || run_result + .test_results + .into_iter() + .any(|r| !r.errors.is_empty()), + ); +} + +async fn run_test(resource: &str) -> JestRunResult { register(); let path = Path::new(resource) // test_resources matches and returns relative paths from the workspace root, @@ -53,13 +109,6 @@ async fn test(resource: &str) { path.to_str().unwrap() ); - if path.ends_with("__skipped__") { - // "Skip" directories named `__skipped__`, which include test directories to - // skip. These tests are not considered truly skipped by `cargo test`, but they - // are not run. - return; - } - let test_entry = path.join("index.js"); assert!( test_entry.exists(), @@ -90,8 +139,8 @@ async fn test(resource: &str) { tokio::select! { r = run_browser(server.addr) => r.unwrap(), - r = server.future => r.unwrap(), - }; + _ = server.future => panic!("Never resolves"), + } } async fn create_browser( @@ -118,14 +167,12 @@ async fn create_browser( Ok((browser, thread_handle)) } -async fn run_browser(addr: SocketAddr) -> Result<(), Box> { +async fn run_browser(addr: SocketAddr) -> Result> { if *DEBUG_BROWSER { run_debug_browser(addr).await?; } - run_test_browser(addr).await?; - - Ok(()) + run_test_browser(addr).await } async fn run_debug_browser(addr: SocketAddr) -> Result<(), Box> { @@ -152,33 +199,5 @@ async fn run_test_browser(addr: SocketAddr) -> Result "), - test_result.errors.join("\n") - )); - } - } - - if !messages.is_empty() { - panic!( - "Failed with error(s) in the following test(s):\n\n{}", - messages.join("\n\n--\n") - ) - } - - Ok(run_result) + Ok(page.evaluate("__jest__.run()").await?.into_value()?) } From 935e46f995b59b49a31b1e69542eb04e833b1de4 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Fri, 12 Aug 2022 14:21:21 -0700 Subject: [PATCH 040/672] next-dev test runner: ask os for free port (vercel/turbo#238) These integration tests have been flaky, failing when a "free" port turns out to be in use. Since nextest parallelizes test runs and portpicker guesses and checks free ports [0], I'm guessing that there's a collision occurring. Instead, ask the operating system for a free port by binding to port 0 and read the port back from the resulting address. Test Plan: Tried local runs with nextest, but those succeeded before as well. I'll probably retry things on CI a few times. [0] https://github.com/Dentosal/portpicker-rs/blob/912f913ac325278a564d8828d550070db1d79373/src/lib.rs#L53 --- packages/next-swc/crates/next-dev/Cargo.toml | 1 - .../next-swc/crates/next-dev/tests/integration.rs | 13 ++++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 7fd4a964b91aa4..fedeffc6f23bdb 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -45,7 +45,6 @@ chromiumoxide = { version = "0.3.5", features = [ "tokio-runtime", ], default-features = false } lazy_static = "1.4.0" -portpicker = "0.1.1" test-generator = "0.3.0" [build-dependencies] diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index ccd9568767b87c..0e40dd36c6f7f5 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -12,7 +12,7 @@ use lazy_static::lazy_static; use next_dev::{register, NextDevServerBuilder}; use serde::Deserialize; use test_generator::test_resources; -use tokio::task::JoinHandle; +use tokio::{net::TcpSocket, task::JoinHandle}; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; use turbo_tasks::TurboTasks; use turbo_tasks_memory::MemoryBackend; @@ -116,6 +116,7 @@ async fn run_test(resource: &str) -> JestRunResult { test_entry.to_str().unwrap() ); + let requested_addr = get_free_local_addr().unwrap(); let server = NextDevServerBuilder::new() .turbo_tasks(TurboTasks::new(MemoryBackend::new())) .project_dir("tests".into()) @@ -129,8 +130,8 @@ async fn run_test(resource: &str) -> JestRunResult { .replace('\\', "/"), ) .eager_compile(false) - .hostname("127.0.0.1".parse().unwrap()) - .port(portpicker::pick_unused_port().unwrap()) + .hostname(requested_addr.ip()) + .port(requested_addr.port()) .build() .await .unwrap(); @@ -201,3 +202,9 @@ async fn run_test_browser(addr: SocketAddr) -> Result Result { + let socket = TcpSocket::new_v4()?; + socket.bind("127.0.0.1:0".parse().unwrap())?; + socket.local_addr() +} From eab61f3c652a627f5d0a4e183521dd8592db16cf Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 15 Aug 2022 19:26:37 +0200 Subject: [PATCH 041/672] add basic next pages support (vercel/turbo#223) Server Rendering: * This adds an additional ContentSource to next-dev which takes care of handling the `pages` directory. * The content source creates a ServerRenderedAsset from each file in the `src/pages` or `pages` directory and a AssetGraphContentSource for that. * The ServerRenderedAsset will reference an underlying asset for the node.js context which will be passed to the node executable for rendering. It uses a WrapperAsset to add additional communication logic. Client Transition: * When annotating `import`s with `transition: "next-client"` the NextClientTransition is used * This transition changes the environment to browser * It wraps the referenced asset with a next-hyrdation wrapper asset * It leaves a little module in the previous context which exports a list of URLs for chunks needed. * The NextClientTransition takes a client_chunking_context as argument which specifies how the client code is chunked. --- packages/next-swc/crates/next-core/Cargo.toml | 25 ++ packages/next-swc/crates/next-core/build.rs | 5 + packages/next-swc/crates/next-core/src/lib.rs | 17 + .../crates/next-core/src/next_client/mod.rs | 62 +++ .../src/next_client/next_hydrater.js | 5 + .../next-core/src/server_render/asset.rs | 353 ++++++++++++++++++ .../next-core/src/server_render/issue.rs | 40 ++ .../crates/next-core/src/server_render/mod.rs | 4 + .../src/server_render/nodejs_bootstrap.rs | 52 +++ .../src/server_render/nodejs_pool.rs | 203 ++++++++++ .../src/server_render/server_renderer.js | 78 ++++ .../next-core/src/server_rendered_source.rs | 182 +++++++++ .../src/web_entry_source.rs | 12 +- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/src/lib.rs | 47 ++- 15 files changed, 1064 insertions(+), 22 deletions(-) create mode 100644 packages/next-swc/crates/next-core/Cargo.toml create mode 100644 packages/next-swc/crates/next-core/build.rs create mode 100644 packages/next-swc/crates/next-core/src/lib.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client/next_hydrater.js create mode 100644 packages/next-swc/crates/next-core/src/server_render/asset.rs create mode 100644 packages/next-swc/crates/next-core/src/server_render/issue.rs create mode 100644 packages/next-swc/crates/next-core/src/server_render/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs create mode 100644 packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs create mode 100644 packages/next-swc/crates/next-core/src/server_render/server_renderer.js create mode 100644 packages/next-swc/crates/next-core/src/server_rendered_source.rs rename packages/next-swc/crates/{next-dev => next-core}/src/web_entry_source.rs (92%) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml new file mode 100644 index 00000000000000..4cf03f21f368e9 --- /dev/null +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "next-core" +version = "0.1.0" +edition = "2021" + +[lib] +bench = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.47" +futures = "0.3.21" +json = "0.12.4" +mime = "0.3.16" +serde = "1.0.136" +tokio = { version = "1.11.0", features = ["full"] } +turbo-tasks = { path = "../turbo-tasks" } +turbo-tasks-fs = { path = "../turbo-tasks-fs" } +turbopack = { path = "../turbopack" } +turbopack-core = { path = "../turbopack-core" } +turbopack-dev-server = { path = "../turbopack-dev-server" } + +[build-dependencies] +turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-core/build.rs b/packages/next-swc/crates/next-core/build.rs new file mode 100644 index 00000000000000..1673efed59cce6 --- /dev/null +++ b/packages/next-swc/crates/next-core/build.rs @@ -0,0 +1,5 @@ +use turbo_tasks_build::generate_register; + +fn main() { + generate_register(); +} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs new file mode 100644 index 00000000000000..6d5bcfa8d08c32 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -0,0 +1,17 @@ +#![feature(min_specialization)] + +pub mod next_client; +mod server_render; +mod server_rendered_source; +mod web_entry_source; + +pub use server_rendered_source::create_server_rendered_source; +pub use web_entry_source::create_web_entry_source; + +pub fn register() { + turbo_tasks::register(); + turbo_tasks_fs::register(); + turbopack_dev_server::register(); + turbopack::register(); + include!(concat!(env!("OUT_DIR"), "/register.rs")); +} diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs new file mode 100644 index 00000000000000..9379ab847ca7b3 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -0,0 +1,62 @@ +use anyhow::{anyhow, Result}; +use turbo_tasks::ValueToString; +use turbo_tasks_fs::{File, FileContent, FileContentVc, FileSystemPathVc}; +use turbopack::ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset; +use turbopack_core::{ + asset::AssetVc, + chunk::{ChunkableAssetVc, ChunkingContextVc}, + environment::EnvironmentVc, + transition::{Transition, TransitionVc}, + wrapper_asset::WrapperAssetVc, +}; + +#[turbo_tasks::function] +fn get_next_hydrater() -> FileContentVc { + FileContent::Content(File::from_source( + include_str!("next_hydrater.js").to_string(), + )) + .cell() +} + +/// Makes a transition into a next.js client context. +/// +/// It wraps the target asset with client bootstrapping hydration. It changes +/// the environment to be inside of the browser. It offers a module to the +/// importer that exports an array of chunk urls. +#[turbo_tasks::value(shared)] +pub struct NextClientTransition { + pub client_environment: EnvironmentVc, + pub client_chunking_context: ChunkingContextVc, + pub server_root: FileSystemPathVc, +} + +#[turbo_tasks::value_impl] +impl Transition for NextClientTransition { + #[turbo_tasks::function] + fn process_source(&self, asset: AssetVc) -> AssetVc { + WrapperAssetVc::new(asset, "next-hydrate.js", get_next_hydrater()).into() + } + + #[turbo_tasks::function] + fn process_environment(&self, _environment: EnvironmentVc) -> EnvironmentVc { + self.client_environment + } + + #[turbo_tasks::function] + async fn process_module(&self, asset: AssetVc) -> Result { + if let Some(chunkable_asset) = ChunkableAssetVc::resolve_from(asset).await? { + Ok(ChunkGroupFilesAsset { + asset: chunkable_asset, + chunking_context: self.client_chunking_context, + base_path: self.server_root, + } + .cell() + .into()) + } else { + Err(anyhow!( + "asset {} is not chunkable", + asset.path().to_string().await? + )) + } + } +} diff --git a/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js b/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js new file mode 100644 index 00000000000000..ff38c450f0d520 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js @@ -0,0 +1,5 @@ +import Component from '.' +import { hydrateRoot } from 'react-dom/client' + +const data = JSON.parse(document.getElementById('__NEXT_DATA__').textContent) +hydrateRoot(document.getElementById('__next'), ) diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs new file mode 100644 index 00000000000000..5d5e18d5cf4fc9 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -0,0 +1,353 @@ +use std::{ + collections::{HashMap, HashSet}, + path::PathBuf, +}; + +use anyhow::{anyhow, Result}; +use futures::{stream::FuturesUnordered, TryStreamExt}; +use mime::TEXT_HTML_UTF_8; +use turbo_tasks::{ + primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, Value, ValueToString, +}; +use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileContentVc, FileSystemPathVc}; +use turbopack::ecmascript::{ + EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetVc, ModuleAssetType, +}; +use turbopack_core::{ + asset::{Asset, AssetVc}, + chunk::{ + dev::{DevChunkingContext, DevChunkingContextVc}, + ChunkGroupVc, + }, + context::AssetContextVc, + reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, + resolve::{ResolveResult, ResolveResultVc}, + wrapper_asset::WrapperAssetVc, +}; + +use super::{ + nodejs_bootstrap::NodeJsBootstrapAsset, + nodejs_pool::{NodeJsPool, NodeJsPoolVc}, +}; +use crate::server_render::issue::RenderingIssue; + +/// This is an asset which content is determined by running +/// `React.renderToString` on the default export of [entry_asset] in a Node.js +/// context. +/// +/// For that the [entry_asset] is bundled and emitted into +/// [intermediate_output_path] and a pool of Node.js processes is used to run +/// that. [request_data] is passed to the [entry_asset] component as props. When +/// only [path] and [request_data] differs multiple [ServerRenderedAsset]s will +/// share the Node.js worker pool. +#[turbo_tasks::value] +pub struct ServerRenderedAsset { + path: FileSystemPathVc, + context: AssetContextVc, + entry_asset: AssetVc, + context_path: FileSystemPathVc, + intermediate_output_path: FileSystemPathVc, + request_data: String, +} + +#[turbo_tasks::value_impl] +impl ServerRenderedAssetVc { + #[turbo_tasks::function] + pub fn new( + path: FileSystemPathVc, + context: AssetContextVc, + entry_asset: AssetVc, + context_path: FileSystemPathVc, + intermediate_output_path: FileSystemPathVc, + request_data: String, + ) -> Self { + ServerRenderedAsset { + path, + context, + entry_asset, + context_path, + intermediate_output_path, + request_data, + } + .cell() + } +} + +#[turbo_tasks::value_impl] +impl Asset for ServerRenderedAsset { + #[turbo_tasks::function] + fn path(&self) -> FileSystemPathVc { + self.path + } + + #[turbo_tasks::function] + fn content(&self) -> FileContentVc { + render( + self.path, + get_renderer_pool( + get_intermediate_asset( + self.context, + self.entry_asset, + self.context_path, + self.intermediate_output_path, + ), + self.intermediate_output_path, + ), + &self.request_data, + ) + } + + #[turbo_tasks::function] + async fn references(&self) -> Result { + Ok(AssetReferencesVc::cell( + separate_assets( + get_intermediate_asset( + self.context, + self.entry_asset, + self.context_path, + self.intermediate_output_path, + ), + self.intermediate_output_path, + ) + .await? + .external_asset_entrypoints + .iter() + .map(|a| { + ServerRenderedClientAssetReference { asset: *a } + .cell() + .into() + }) + .collect(), + )) + } +} + +#[turbo_tasks::value] +pub struct ServerRenderedClientAssetReference { + asset: AssetVc, +} + +#[turbo_tasks::value_impl] +impl AssetReference for ServerRenderedClientAssetReference { + #[turbo_tasks::function] + fn resolve_reference(&self) -> ResolveResultVc { + ResolveResult::Single(self.asset, Vec::new()).into() + } + + #[turbo_tasks::function] + async fn description(&self) -> Result { + Ok(StringVc::cell(format!( + "client asset {}", + self.asset.path().to_string().await? + ))) + } +} + +#[turbo_tasks::function] +fn get_server_renderer() -> FileContentVc { + FileContent::Content(File::from_source( + include_str!("server_renderer.js").to_string(), + )) + .cell() +} + +#[turbo_tasks::function] +async fn get_intermediate_asset( + context: AssetContextVc, + entry_asset: AssetVc, + context_path: FileSystemPathVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + let chunking_context: DevChunkingContextVc = DevChunkingContext { + context_path, + chunk_root_path: intermediate_output_path.join("chunks"), + asset_root_path: intermediate_output_path.join("assets"), + } + .into(); + let module = EcmascriptModuleAssetVc::new( + WrapperAssetVc::new(entry_asset, "server-renderer.js", get_server_renderer()).into(), + context.with_context_path(entry_asset.path()), + Value::new(ModuleAssetType::Ecmascript), + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::JSX]), + context.environment(), + ); + let chunk = module.as_evaluated_chunk(chunking_context.into()); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + Ok(NodeJsBootstrapAsset { + path: intermediate_output_path.join("index.js"), + chunk_group, + } + .cell() + .into()) +} + +#[turbo_tasks::function] +async fn emit( + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + Ok(CompletionsVc::cell( + separate_assets(intermediate_asset, intermediate_output_path) + .await? + .internal_assets + .iter() + .map(|a| a.path().write(a.content())) + .collect(), + ) + .all()) +} + +#[turbo_tasks::value] +struct SeparatedAssets { + internal_assets: HashSet, + external_asset_entrypoints: HashSet, +} + +#[turbo_tasks::function] +async fn separate_assets( + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + enum Type { + Internal(AssetVc, Vec), + External(AssetVc), + } + let intermediate_output_path = intermediate_output_path.await?; + let mut queue = FuturesUnordered::new(); + let process_asset = |asset: AssetVc| { + let intermediate_output_path = &intermediate_output_path; + async move { + if asset.path().await?.is_inside(intermediate_output_path) { + let mut assets = Vec::new(); + for reference in asset.references().await?.iter() { + for asset in reference.resolve_reference().primary_assets().await?.iter() { + assets.push(*asset); + } + } + Ok::<_, anyhow::Error>(Type::Internal(asset, assets)) + } else { + Ok(Type::External(asset)) + } + } + }; + queue.push(process_asset(intermediate_asset)); + let mut processed = HashSet::new(); + let mut internal_assets = HashSet::new(); + let mut external_asset_entrypoints = HashSet::new(); + while let Some(item) = queue.try_next().await? { + match item { + Type::Internal(asset, assets) => { + internal_assets.insert(asset); + for asset in assets { + if processed.insert(asset) { + queue.push(process_asset(asset)); + } + } + } + Type::External(asset) => { + // external + external_asset_entrypoints.insert(asset); + } + } + } + Ok(SeparatedAssets { + internal_assets, + external_asset_entrypoints, + } + .cell()) +} + +#[turbo_tasks::function] +async fn get_renderer_pool( + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + emit(intermediate_asset, intermediate_output_path).await?; + let output = intermediate_output_path.await?; + if let Some(disk) = DiskFileSystemVc::resolve_from(output.fs).await? { + let dir = PathBuf::from(&disk.await?.root).join(&output.path); + let entrypoint = dir.join("index.js"); + let pool = NodeJsPool::new(dir, entrypoint, HashMap::new(), 4); + Ok(pool.cell()) + } else { + Err(anyhow!("can only render from a disk filesystem")) + } +} + +#[turbo_tasks::function] +async fn render( + path: FileSystemPathVc, + renderer_pool: NodeJsPoolVc, + request_data: &str, +) -> Result { + fn into_result(content: String) -> Result { + Ok( + FileContent::Content(File::from_source(content).with_content_type(TEXT_HTML_UTF_8)) + .cell(), + ) + } + let pool = renderer_pool.await?; + let mut op = pool.run(request_data.as_bytes()).await?; + let lines = spawn_blocking(move || { + let lines = op.read_lines()?; + drop(op); + Ok::<_, anyhow::Error>(lines) + }) + .await?; + let issue = if let Some(last_line) = lines.last() { + if let Some(data) = last_line.strip_prefix("RESULT=") { + let data = json::parse(data)?; + if let Some(s) = data.as_str() { + return into_result(s.to_string()); + } else { + RenderingIssue { + context: path, + message: StringVc::cell( + "Result provided by Node.js rendering process was not a string".to_string(), + ), + logging: StringVc::cell(lines.join("\n")), + } + } + } else if let Some(data) = last_line.strip_prefix("ERROR=") { + let data = json::parse(data)?; + if let Some(s) = data.as_str() { + RenderingIssue { + context: path, + message: StringVc::cell(s.to_string()), + logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), + } + } else { + RenderingIssue { + context: path, + message: StringVc::cell(data.to_string()), + logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), + } + } + } else { + RenderingIssue { + context: path, + message: StringVc::cell("No result provided by Node.js process".to_string()), + logging: StringVc::cell(lines.join("\n")), + } + } + } else { + RenderingIssue { + context: path, + message: StringVc::cell("No content received from Node.js process.".to_string()), + logging: StringVc::cell("".to_string()), + } + }; + + // Show error page + // TODO This need to include HMR handler to allow auto refresh + let result = into_result(format!( + "Error during rendering:\n{}\n\n{}", + issue.message.await?, + issue.logging.await? + )); + + // Emit an issue for error reporting + issue.cell().as_issue().emit(); + + result +} diff --git a/packages/next-swc/crates/next-core/src/server_render/issue.rs b/packages/next-swc/crates/next-core/src/server_render/issue.rs new file mode 100644 index 00000000000000..8b2c4027f29185 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/server_render/issue.rs @@ -0,0 +1,40 @@ +use anyhow::Result; +use turbo_tasks::{primitives::StringVc, ValueToString}; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_core::issue::{Issue, IssueVc}; + +#[turbo_tasks::value(shared)] +pub struct RenderingIssue { + pub context: FileSystemPathVc, + pub message: StringVc, + pub logging: StringVc, +} + +#[turbo_tasks::value_impl] +impl Issue for RenderingIssue { + #[turbo_tasks::function] + async fn title(&self) -> Result { + Ok(StringVc::cell(format!( + "error during rendering of {}", + self.context.to_string().await?, + ))) + } + + #[turbo_tasks::function] + fn category(&self) -> StringVc { + StringVc::cell("rendering".to_string()) + } + + #[turbo_tasks::function] + fn context(&self) -> FileSystemPathVc { + self.context + } + + #[turbo_tasks::function] + fn description(&self) -> StringVc { + self.message + } + + // TODO add sub_issue for logging data + // TODO parse stack trace +} diff --git a/packages/next-swc/crates/next-core/src/server_render/mod.rs b/packages/next-swc/crates/next-core/src/server_render/mod.rs new file mode 100644 index 00000000000000..d0d15de63bbf70 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/server_render/mod.rs @@ -0,0 +1,4 @@ +pub mod asset; +pub(crate) mod issue; +pub mod nodejs_bootstrap; +pub mod nodejs_pool; diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs b/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs new file mode 100644 index 00000000000000..afd2f3e118690e --- /dev/null +++ b/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs @@ -0,0 +1,52 @@ +use std::fmt::Write; + +use anyhow::Result; +use turbo_tasks_fs::{File, FileContent, FileContentVc, FileSystemPathVc}; +use turbopack::ecmascript::utils::stringify_str; +use turbopack_core::{ + asset::{Asset, AssetVc}, + chunk::{ChunkGroupVc, ChunkReferenceVc}, + reference::AssetReferencesVc, +}; + +#[turbo_tasks::value(shared)] +pub struct NodeJsBootstrapAsset { + pub path: FileSystemPathVc, + pub chunk_group: ChunkGroupVc, +} + +#[turbo_tasks::value_impl] +impl Asset for NodeJsBootstrapAsset { + #[turbo_tasks::function] + fn path(&self) -> FileSystemPathVc { + self.path + } + + #[turbo_tasks::function] + async fn content(&self) -> Result { + let context_path = self.path.parent().await?; + + // TODO(sokra) We need to have a chunk format for node.js + // but until then this is a simple hack to make it work for now + let mut output = "global.self = global;\n".to_string(); + + for chunk in self.chunk_group.chunks().await?.iter() { + let path = &*chunk.path().await?; + if let Some(p) = context_path.get_relative_path_to(path) { + writeln!(&mut output, "require({});", stringify_str(&p))?; + } + } + + Ok(FileContent::Content(File::from_source(output)).into()) + } + + #[turbo_tasks::function] + async fn references(&self) -> Result { + let chunks = self.chunk_group.chunks().await?; + let mut references = Vec::new(); + for chunk in chunks.iter() { + references.push(ChunkReferenceVc::new(*chunk).into()); + } + Ok(AssetReferencesVc::cell(references)) + } +} diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs b/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs new file mode 100644 index 00000000000000..f027fae7d73684 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs @@ -0,0 +1,203 @@ +use std::{ + collections::HashMap, + io::{BufRead, BufReader, Write}, + mem::transmute, + path::{Path, PathBuf}, + process::{Child, ChildStdin, ChildStdout, Command, Stdio}, + sync::{Arc, Mutex}, +}; + +use anyhow::{bail, Result}; +use tokio::sync::{OwnedSemaphorePermit, Semaphore}; +use turbo_tasks::spawn_blocking; + +const END_OF_OPERATION: &str = + "END_OF_OPERATION 4329g8b57hnz349bo58tzuasgnhv9o8e4zo6gvj END_OF_OPERATION\n"; + +struct NodeJsPoolProcess { + child: Child, + stdin: ChildStdin, + stdout: BufReader, +} + +impl Drop for NodeJsPoolProcess { + fn drop(&mut self) { + let _ = self.child.kill(); + let _ = self.child.wait(); + } +} + +impl NodeJsPoolProcess { + fn prepare(cwd: &Path, env: &HashMap, entrypoint: &Path) -> Command { + let mut cmd = Command::new("node"); + cmd.current_dir(cwd); + cmd.arg(entrypoint); + cmd.arg(&END_OF_OPERATION[..END_OF_OPERATION.len() - 1]); + cmd.env_clear(); + cmd.envs(env); + cmd.stdin(Stdio::piped()); + cmd.stdout(Stdio::piped()); + cmd + } + + fn start(mut cmd: Command) -> Result { + let mut child = cmd.spawn()?; + let stdin = child.stdin.take().unwrap(); + let mut stdout = BufReader::new(child.stdout.take().unwrap()); + let mut bootstrap_log = Vec::new(); + loop { + let mut buf = String::new(); + if stdout.read_line(&mut buf)? == 0 { + bail!("process closed unexpectedly\n{}", bootstrap_log.join("\n")); + } + if buf == "READY\n" { + break; + } + bootstrap_log.push(buf); + } + Ok(NodeJsPoolProcess { + child, + stdin, + stdout, + }) + } + + fn read_line(&mut self, buf: &mut String) -> std::io::Result { + self.stdout.read_line(buf) + } + + pub fn write(&mut self, buf: &[u8]) -> std::io::Result<()> { + self.stdin.write_all(buf) + } +} + +/// A pool of Node.js workers operating on [entrypoint] with specific [cwd] and +/// [env]. +/// +/// The pool will spawn processes when needed and reuses old ones. It will never +/// spawn more then a certain number of concurrent processes. This is specified +/// with the `concurrency` argument in the constructor. +/// +/// The worker will *not* use the env of the parent process by default. All env +/// vars need to be provided to make the execution as pure as possible. +#[turbo_tasks::value(into = "new", cell = "new", serialization = "none", eq = "manual")] +pub struct NodeJsPool { + cwd: PathBuf, + entrypoint: PathBuf, + env: HashMap, + #[turbo_tasks(trace_ignore, debug_ignore)] + processes: Arc>>, + #[turbo_tasks(trace_ignore, debug_ignore)] + semaphore: Arc, +} + +impl NodeJsPool { + pub fn new( + cwd: PathBuf, + entrypoint: PathBuf, + env: HashMap, + concurrency: usize, + ) -> Self { + Self { + cwd, + entrypoint, + env, + processes: Arc::new(Mutex::new(Vec::new())), + semaphore: Arc::new(Semaphore::new(concurrency)), + } + } + + async fn acquire_child(&self) -> Result<(NodeJsPoolProcess, OwnedSemaphorePermit)> { + let permit = self.semaphore.clone().acquire_owned().await?; + let popped = { + let mut processes = self.processes.lock().unwrap(); + processes.pop() + }; + Ok(if let Some(child) = popped { + (child, permit) + } else { + let cmd = NodeJsPoolProcess::prepare( + self.cwd.as_path(), + &self.env, + self.entrypoint.as_path(), + ); + let fresh = spawn_blocking(move || NodeJsPoolProcess::start(cmd)).await?; + (fresh, permit) + }) + } + + pub async fn run(&self, input: &[u8]) -> Result { + let (mut child, permit) = self.acquire_child().await?; + // SAFETY we await spawn blocking so we stay within the lifetime of input + let static_input: &'static [u8] = unsafe { transmute(input) }; + let child = spawn_blocking(move || { + child.write(static_input)?; + Ok::<_, anyhow::Error>(child) + }) + .await?; + + Ok(NodeJsOperationResult { + child: Some(child), + child_ended: false, + permit, + processes: self.processes.clone(), + }) + } +} + +pub struct NodeJsOperationResult { + child_ended: bool, + child: Option, + // This is used for drop + #[allow(dead_code)] + permit: OwnedSemaphorePermit, + processes: Arc>>, +} + +impl NodeJsOperationResult { + pub fn stdin(&mut self) -> Option<&mut ChildStdin> { + self.child.as_mut().map(|c| &mut c.stdin) + } + + pub fn read_line(&mut self, buf: &mut String) -> Result { + if let Some(ref mut child) = self.child { + if self.child_ended { + return Ok(0); + } + let len = child.read_line(buf)?; + if len == 0 { + self.child = None; + return Ok(0); + } + if buf.ends_with(END_OF_OPERATION) { + buf.truncate(buf.len() - END_OF_OPERATION.len()); + self.child_ended = true; + Ok(0) + } else { + Ok(len) + } + } else { + Ok(0) + } + } + + pub fn read_lines(&mut self) -> Result, std::io::Error> { + let mut lines = Vec::new(); + loop { + let mut line = String::new(); + if self.read_line(&mut line)? == 0 { + return Ok(lines); + } + line.pop(); + lines.push(line); + } + } +} + +impl Drop for NodeJsOperationResult { + fn drop(&mut self) { + if let Some(child) = self.child.take() { + self.processes.lock().unwrap().push(child) + } + } +} diff --git a/packages/next-swc/crates/next-core/src/server_render/server_renderer.js b/packages/next-swc/crates/next-core/src/server_render/server_renderer.js new file mode 100644 index 00000000000000..3b343b81ca1e29 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/server_render/server_renderer.js @@ -0,0 +1,78 @@ +const END_OF_OPERATION = process.argv[2] + +import Component from '.' +import { renderToString, renderToStaticMarkup } from 'react-dom/server' +;('TURBOPACK { transition: next-client }') +import chunkGroup from '.' + +process.stdout.write('READY\n') + +const NEW_LINE = '\n'.charCodeAt(0) +let buffer = [] +process.stdin.on('data', (data) => { + let idx = data.indexOf(NEW_LINE) + while (idx >= 0) { + buffer.push(data.slice(0, idx)) + try { + let json = JSON.parse(Buffer.concat(buffer).toString('utf-8')) + let result = operation(json) + console.log(`RESULT=${JSON.stringify(result)}`) + } catch (e) { + console.log(`ERROR=${JSON.stringify(e.stack)}`) + } + console.log(END_OF_OPERATION) + data = data.slice(idx + 1) + idx = data.indexOf(NEW_LINE) + } + buffer.push(data) +}) + +function operation(data) { + // TODO capture meta info during rendering + const rendered = { __html: renderToString() } + const urls = chunkGroup.map((p) => `/${p}`) + const scripts = urls.filter((url) => url.endsWith('.js')) + const styles = urls.filter((url) => url.endsWith('.css')) + return renderToStaticMarkup( + + + {styles.map((url) => ( + + ))} + {scripts.map((url) => ( + + ))} + + + +
+ {scripts.map((url) => ( + + ))} + + , + ) +} + +// This utility is based on https://github.com/zertosh/htmlescape +// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE + +const ESCAPE_LOOKUP = { + '&': '\\u0026', + '>': '\\u003e', + '<': '\\u003c', + '\u2028': '\\u2028', + '\u2029': '\\u2029', +} + +const ESCAPE_REGEX = /[&><\u2028\u2029]/g + +export function htmlEscapeJsonString(str) { + return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]) +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs new file mode 100644 index 00000000000000..691c64c87e0fe6 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -0,0 +1,182 @@ +use std::collections::HashMap; + +use anyhow::Result; +use turbo_tasks::Value; +use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; +use turbopack::ModuleAssetContextVc; +use turbopack_core::{ + chunk::dev::DevChunkingContext, + context::AssetContextVc, + environment::{ + BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, + NodeJsEnvironment, + }, + source_asset::SourceAssetVc, + target::CompileTargetVc, + transition::TransitionsByNameVc, +}; +use turbopack_dev_server::source::{ + asset_graph::AssetGraphContentSourceVc, + combined::{CombinedContentSource, CombinedContentSourceVc}, + ContentSourceVc, NoContentSourceVc, +}; + +use crate::{next_client::NextClientTransition, server_render::asset::ServerRenderedAssetVc}; + +/// Create a content source serving the `pages` or `src/pages` directory as +/// Node.js pages folder. +#[turbo_tasks::function] +pub async fn create_server_rendered_source( + root_path: FileSystemPathVc, + output_path: FileSystemPathVc, + target_root: FileSystemPathVc, +) -> Result { + let pages = root_path.join("pages"); + let src_pages = root_path.join("src/pages"); + let dir = if *pages.get_type().await? == FileSystemEntryType::Directory { + pages + } else if *src_pages.get_type().await? == FileSystemEntryType::Directory { + src_pages + } else { + return Ok(NoContentSourceVc::new().into()); + }; + + let client_chunking_context = DevChunkingContext { + context_path: root_path, + chunk_root_path: target_root.join("_next/static/chunks"), + asset_root_path: target_root.join("_next/static/assets"), + } + .cell() + .into(); + let client_environment = EnvironmentVc::new( + Value::new(ExecutionEnvironment::Browser( + BrowserEnvironment { + dom: true, + web_worker: false, + service_worker: false, + browser_version: 0, + } + .into(), + )), + Value::new(EnvironmentIntention::Client), + ); + let next_client_transition = NextClientTransition { + client_chunking_context, + client_environment, + server_root: target_root, + } + .cell() + .into(); + + let mut transitions = HashMap::new(); + transitions.insert("next-client".to_string(), next_client_transition); + let context: AssetContextVc = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(transitions), + root_path, + EnvironmentVc::new( + Value::new(ExecutionEnvironment::NodeJsLambda( + NodeJsEnvironment { + compile_target: CompileTargetVc::current(), + node_version: 0, + typescript_enabled: false, + } + .into(), + )), + Value::new(EnvironmentIntention::Client), + ), + ) + .into(); + + Ok(create_server_rendered_source_for_directory( + context, + dir, + target_root, + target_root, + output_path, + ) + .into()) +} + +/// Handles a single page file in the pages directory +#[turbo_tasks::function] +async fn create_server_rendered_source_for_file( + context: AssetContextVc, + entry: FileSystemPathVc, + target_root: FileSystemPathVc, + target_path: FileSystemPathVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + let context_path = context.context_path(); + let source_asset = SourceAssetVc::new(entry).into(); + let module = context + .with_context_path(entry.parent()) + .process(source_asset); + let asset = ServerRenderedAssetVc::new( + target_path, + context, + module, + context_path, + intermediate_output_path, + "{\"props\":{}}\n".to_string(), + ); + Ok(AssetGraphContentSourceVc::new_lazy( + target_root, + asset.into(), + )) +} + +/// Handles a directory in the pages directory (or the pages directory itself). +/// Calls itself recursively for sub directories or the +/// [create_server_rendered_source_for_file] method for files. +#[turbo_tasks::function] +async fn create_server_rendered_source_for_directory( + context: AssetContextVc, + input_dir: FileSystemPathVc, + target_root: FileSystemPathVc, + target_path: FileSystemPathVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + let mut sources = Vec::new(); + if let DirectoryContent::Entries(entries) = &*input_dir.read_dir().await? { + for (name, entry) in entries.iter() { + match entry { + DirectoryEntry::File(file) => { + if let Some((name, _extension)) = name.rsplit_once('.') { + let (target_path, intermediate_output_path) = if name == "index" { + (target_path.join("index.html"), intermediate_output_path) + } else { + ( + target_path.join(name).join("index.html"), + intermediate_output_path.join(name), + ) + }; + sources.push( + create_server_rendered_source_for_file( + context, + *file, + target_root, + target_path, + intermediate_output_path, + ) + .into(), + ); + } + } + DirectoryEntry::Directory(dir) => { + sources.push( + create_server_rendered_source_for_directory( + context, + *dir, + target_root, + target_path.join(name), + intermediate_output_path.join(name), + ) + .into(), + ); + } + _ => {} + } + } + } + Ok(CombinedContentSource { sources }.cell()) +} diff --git a/packages/next-swc/crates/next-dev/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs similarity index 92% rename from packages/next-swc/crates/next-dev/src/web_entry_source.rs rename to packages/next-swc/crates/next-core/src/web_entry_source.rs index c10cd5b05ed592..086b28eab36fe5 100644 --- a/packages/next-swc/crates/next-dev/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -1,8 +1,10 @@ +use std::collections::HashMap; + use anyhow::{anyhow, Result}; use futures::future::try_join_all; use turbo_tasks::Value; use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; -use turbopack::ModuleAssetContextVc; +use turbopack::{ecmascript::EcmascriptModuleAssetVc, ModuleAssetContextVc}; use turbopack_core::{ chunk::{ dev::{DevChunkingContext, DevChunkingContextVc}, @@ -11,14 +13,13 @@ use turbopack_core::{ context::AssetContextVc, environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, source_asset::SourceAssetVc, + transition::TransitionsByNameVc, }; use turbopack_dev_server::{ html::DevHtmlAsset, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; -use crate::EcmascriptModuleAssetVc; - #[turbo_tasks::function] pub async fn create_web_entry_source( root: FileSystemPathVc, @@ -27,6 +28,7 @@ pub async fn create_web_entry_source( eager_compile: bool, ) -> Result { let context: AssetContextVc = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(HashMap::new()), root, EnvironmentVc::new( Value::new(ExecutionEnvironment::Browser( @@ -45,8 +47,8 @@ pub async fn create_web_entry_source( let chunking_context: DevChunkingContextVc = DevChunkingContext { context_path: root, - chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/chunks"), - asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static"), + chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static/chunks"), + asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static/assets"), } .into(); diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index fedeffc6f23bdb..7b177ed9226195 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -27,6 +27,7 @@ console-subscriber = { version = "0.1.6", optional = true } futures = "0.3.21" json = "0.12.4" mime = "0.3.16" +next-core = { path = "../next-core" } serde = "1.0.136" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index b9a3d9c8c17a05..36c963205d890c 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -4,20 +4,19 @@ use std::{net::IpAddr, sync::Arc}; use anyhow::{anyhow, Context, Result}; +use next_core::{create_server_rendered_source, create_web_entry_source}; use turbo_tasks::{CollectiblesSource, TransientValue, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; use turbo_tasks_memory::MemoryBackend; -use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_cli_utils::issue::issue_to_styled_string; use turbopack_core::issue::{IssueSeverity, IssueVc}; use turbopack_dev_server::{ - fs::DevServerFileSystemVc, source::router::RouterContentSource, DevServerListening, DevServerVc, + fs::DevServerFileSystemVc, + source::{combined::CombinedContentSource, router::RouterContentSource}, + DevServerListening, DevServerVc, }; -use self::web_entry_source::create_web_entry_source; - mod turbo_tasks_viz; -mod web_entry_source; pub struct NextDevServerBuilder { turbo_tasks: Option>>, @@ -100,13 +99,22 @@ impl NextDevServerBuilder { turbo_tasks .clone() .run_once(async move { - let disk_fs = DiskFileSystemVc::new( - "project".to_string(), - self.project_dir.context("project_dir must be set")?, + let project_dir = self.project_dir.context("project_dir must be set")?; + let output_disk_fs = DiskFileSystemVc::new( + "output".to_string(), + format!("{project_dir}/.next/server"), ); + handle_issues(output_disk_fs).await?; + output_disk_fs.await?.start_watching()?; + let output_fs = output_disk_fs.into(); + + let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir); + handle_issues(disk_fs).await?; + disk_fs.await?.start_watching()?; let fs = disk_fs.into(); + let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); - let main_source = create_web_entry_source( + let web_source = create_web_entry_source( FileSystemPathVc::new(fs, ""), self.entry_assets .iter() @@ -115,6 +123,11 @@ impl NextDevServerBuilder { dev_server_fs, self.eager_compile, ); + let rendered_source = create_server_rendered_source( + FileSystemPathVc::new(fs, ""), + FileSystemPathVc::new(output_fs, ""), + FileSystemPathVc::new(dev_server_fs, ""), + ); let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.clone(), } @@ -122,7 +135,11 @@ impl NextDevServerBuilder { .into(); let source = RouterContentSource { routes: vec![("__turbo_tasks__/".to_string(), viz)], - fallback: main_source, + fallback: CombinedContentSource { + sources: vec![rendered_source, web_source], + } + .cell() + .into(), } .cell() .into(); @@ -138,12 +155,11 @@ impl NextDevServerBuilder { ), ); - handle_issues(disk_fs).await?; handle_issues(dev_server_fs).await?; - handle_issues(main_source).await?; + handle_issues(web_source).await?; + handle_issues(rendered_source).await?; handle_issues(server).await?; - disk_fs.await?.start_watching()?; server.listen().await }) .await @@ -151,9 +167,6 @@ impl NextDevServerBuilder { } pub fn register() { - turbo_tasks::register(); - turbo_tasks_fs::register(); - turbopack_dev_server::register(); - turbopack::register(); + next_core::register(); include!(concat!(env!("OUT_DIR"), "/register.rs")); } From c7ff4150c8e3e3e03fd058fd10ca2c5db27e6d03 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 16 Aug 2022 15:12:09 +0200 Subject: [PATCH 042/672] fix consistency issues (vercel/turbo#224) There are a bunch or problems with invalidations: * The fs impl watches path case-insenstive. This means two paths might conflict when on a case-sensitive filesystem. It uses an array of Invalidators now * Move the next-dev bootstrapping logic out of the run_once scope (which is not updated when invalidations occur). Instead it's executed inside the request handling resp. update stream where changes can be handled. * `TransientValue` was not an Value type actually. This fixes that. * Adds a new `TransientInstance` wrapper to pass transient by reference. * `strongly_consistent` was broken when using nested TaskScopes. This fixes that. --- packages/next-swc/crates/next-dev/src/lib.rs | 200 ++++++++++--------- 1 file changed, 111 insertions(+), 89 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 36c963205d890c..0e7b782a7dc656 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -1,19 +1,19 @@ #![feature(future_join)] #![feature(min_specialization)] -use std::{net::IpAddr, sync::Arc}; +use std::{net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; use next_core::{create_server_rendered_source, create_web_entry_source}; -use turbo_tasks::{CollectiblesSource, TransientValue, TurboTasks}; -use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc}; +use turbo_tasks::{CollectiblesSource, TransientInstance, TurboTasks}; +use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::issue_to_styled_string; use turbopack_core::issue::{IssueSeverity, IssueVc}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, - source::{combined::CombinedContentSource, router::RouterContentSource}, - DevServerListening, DevServerVc, + source::{combined::CombinedContentSource, router::RouterContentSource, ContentSourceVc}, + DevServer, }; mod turbo_tasks_viz; @@ -75,97 +75,119 @@ impl NextDevServerBuilder { self } - pub async fn build(self) -> Result { + pub async fn build(self) -> Result { let turbo_tasks = self.turbo_tasks.context("turbo_tasks must be set")?; - async fn handle_issues(source: T) -> Result<()> { - let issues = IssueVc::peek_issues_with_path(source).await?; - let issues = issues.await?; - let mut fatal = false; - for (issue, path) in issues.iter_with_shortest_path() { - println!("{}\n", &*issue_to_styled_string(issue, path).await?); - if *issue.severity().await? >= IssueSeverity::Fatal { - fatal = true; - } - } - - if fatal { - Err(anyhow!("Fatal issue(s) occurred")) - } else { - Ok(()) - } + let project_dir = self.project_dir.context("project_dir must be set")?; + let entry_assets = self.entry_assets; + let eager_compile = self.eager_compile; + + let server = DevServer::listen( + turbo_tasks.clone(), + move || { + source( + project_dir.clone(), + entry_assets.clone(), + eager_compile, + turbo_tasks.clone().into(), + ) + }, + ( + self.hostname.context("hostname must be set")?, + self.port.context("port must be set")?, + ) + .into(), + ); + + Ok(server) + } +} + +async fn handle_issues(source: T) -> Result<()> { + let issues = IssueVc::peek_issues_with_path(source).await?; + let issues = issues.await?; + let mut fatal = false; + for (issue, path) in issues.iter_with_shortest_path() { + println!("{}\n", &*issue_to_styled_string(issue, path).await?); + if *issue.severity().await? >= IssueSeverity::Fatal { + fatal = true; } + } - turbo_tasks - .clone() - .run_once(async move { - let project_dir = self.project_dir.context("project_dir must be set")?; - let output_disk_fs = DiskFileSystemVc::new( - "output".to_string(), - format!("{project_dir}/.next/server"), - ); - handle_issues(output_disk_fs).await?; - output_disk_fs.await?.start_watching()?; - let output_fs = output_disk_fs.into(); - - let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir); - handle_issues(disk_fs).await?; - disk_fs.await?.start_watching()?; - let fs = disk_fs.into(); - - let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); - let web_source = create_web_entry_source( - FileSystemPathVc::new(fs, ""), - self.entry_assets - .iter() - .map(|a| FileSystemPathVc::new(fs, a)) - .collect(), - dev_server_fs, - self.eager_compile, - ); - let rendered_source = create_server_rendered_source( - FileSystemPathVc::new(fs, ""), - FileSystemPathVc::new(output_fs, ""), - FileSystemPathVc::new(dev_server_fs, ""), - ); - let viz = turbo_tasks_viz::TurboTasksSource { - turbo_tasks: turbo_tasks.clone(), - } - .cell() - .into(); - let source = RouterContentSource { - routes: vec![("__turbo_tasks__/".to_string(), viz)], - fallback: CombinedContentSource { - sources: vec![rendered_source, web_source], - } - .cell() - .into(), - } - .cell() - .into(); - - let server = DevServerVc::new( - source, - TransientValue::new( - ( - self.hostname.context("hostname must be set")?, - self.port.context("port must be set")?, - ) - .into(), - ), - ); - - handle_issues(dev_server_fs).await?; - handle_issues(web_source).await?; - handle_issues(rendered_source).await?; - handle_issues(server).await?; - - server.listen().await - }) - .await + if fatal { + Err(anyhow!("Fatal issue(s) occurred")) + } else { + Ok(()) } } +#[turbo_tasks::function] +async fn project_fs(project_dir: &str) -> Result { + let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir.to_string()); + handle_issues(disk_fs).await?; + disk_fs.await?.start_watching()?; + Ok(disk_fs.into()) +} + +#[turbo_tasks::function] +async fn output_fs(project_dir: &str) -> Result { + let disk_fs = DiskFileSystemVc::new( + "output".to_string(), + format!("{project_dir}{s}.next{s}server", s = MAIN_SEPARATOR), + ); + handle_issues(disk_fs).await?; + disk_fs.await?.start_watching()?; + Ok(disk_fs.into()) +} + +#[turbo_tasks::function] +async fn source( + project_dir: String, + entry_assets: Vec, + eager_compile: bool, + turbo_tasks: TransientInstance>, +) -> Result { + let output_fs = output_fs(&project_dir); + let fs = project_fs(&project_dir); + + let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); + let web_source = create_web_entry_source( + FileSystemPathVc::new(fs, ""), + entry_assets + .iter() + .map(|a| FileSystemPathVc::new(fs, a)) + .collect(), + dev_server_fs, + eager_compile, + ); + let rendered_source = create_server_rendered_source( + FileSystemPathVc::new(fs, ""), + FileSystemPathVc::new(output_fs, ""), + FileSystemPathVc::new(dev_server_fs, ""), + ); + let viz = turbo_tasks_viz::TurboTasksSource { + turbo_tasks: turbo_tasks.into(), + } + .cell() + .into(); + let source = RouterContentSource { + routes: vec![("__turbo_tasks__/".to_string(), viz)], + fallback: CombinedContentSource { + sources: vec![rendered_source, web_source], + } + .cell() + .into(), + } + .cell() + .into(); + + handle_issues(dev_server_fs).await?; + handle_issues(web_source).await?; + handle_issues(rendered_source).await?; + + Ok(source) +} + pub fn register() { next_core::register(); include!(concat!(env!("OUT_DIR"), "/register.rs")); From c867a32ba166a86755ee913ac8eed5c3e3ec0ad6 Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 18 Aug 2022 16:12:40 +0200 Subject: [PATCH 043/672] fix: fs errors when running `next-dev` with pages (vercel/turbo#253) --- .../crates/next-core/src/server_render/nodejs_pool.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs b/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs index f027fae7d73684..1b1f673ae0a3c0 100644 --- a/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs +++ b/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs @@ -7,7 +7,7 @@ use std::{ sync::{Arc, Mutex}, }; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use tokio::sync::{OwnedSemaphorePermit, Semaphore}; use turbo_tasks::spawn_blocking; @@ -34,6 +34,10 @@ impl NodeJsPoolProcess { cmd.arg(entrypoint); cmd.arg(&END_OF_OPERATION[..END_OF_OPERATION.len() - 1]); cmd.env_clear(); + cmd.env( + "PATH", + std::env::var("PATH").expect("PATH should always be set"), + ); cmd.envs(env); cmd.stdin(Stdio::piped()); cmd.stdout(Stdio::piped()); @@ -41,7 +45,7 @@ impl NodeJsPoolProcess { } fn start(mut cmd: Command) -> Result { - let mut child = cmd.spawn()?; + let mut child = cmd.spawn().with_context(|| format!("spawning node pool"))?; let stdin = child.stdin.take().unwrap(); let mut stdout = BufReader::new(child.stdout.take().unwrap()); let mut bootstrap_log = Vec::new(); From e16bd1b5840fb0586141c05c6e4dfcf5ce8005c8 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Mon, 22 Aug 2022 17:35:09 +0800 Subject: [PATCH 044/672] Group and prettier log messages (vercel/turbo#245) ### Default flags `cargo run --bin node-file-trace -- build --context-directory crates/turbopack/tests/node-file-trace ./crates/turbopack/tests/node-file-trace/integration/loopback.js` image ### `--show-all` `cargo run --bin node-file-trace -- build --show-all --context-directory crates/turbopack/tests/node-file-trace ./crates/turbopack/tests/node-file-trace/integration/loopback.js` image ### `--log-detail` `cargo run --bin node-file-trace -- build --log-detail --context-directory crates/turbopack/tests/node-file-trace ./crates/turbopack/tests/node-file-trace/integration/loopback.js` image Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> --- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- packages/next-swc/crates/next-dev/src/lib.rs | 67 +++++++++++++------ packages/next-swc/crates/next-dev/src/main.rs | 17 +++++ 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 7b177ed9226195..6f30e9bf67ee3a 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -22,7 +22,7 @@ tokio_console = [ [dependencies] anyhow = "1.0.47" -clap = { version = "3.1.3", features = ["derive"] } +clap = { version = "3", features = ["derive"] } console-subscriber = { version = "0.1.6", optional = true } futures = "0.3.21" json = "0.12.4" diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 0e7b782a7dc656..4963e92e00a29d 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -8,7 +8,7 @@ use next_core::{create_server_rendered_source, create_web_entry_source}; use turbo_tasks::{CollectiblesSource, TransientInstance, TurboTasks}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; -use turbopack_cli_utils::issue::issue_to_styled_string; +use turbopack_cli_utils::issue::{group_and_display_issues, LogOptions, LogOptionsVc}; use turbopack_core::issue::{IssueSeverity, IssueVc}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, @@ -25,6 +25,9 @@ pub struct NextDevServerBuilder { eager_compile: bool, hostname: Option, port: Option, + log_level: IssueSeverity, + show_all: bool, + log_detail: bool, } impl Default for NextDevServerBuilder { @@ -42,6 +45,9 @@ impl NextDevServerBuilder { eager_compile: false, hostname: None, port: None, + log_level: IssueSeverity::Error, + show_all: false, + log_detail: false, } } @@ -75,12 +81,36 @@ impl NextDevServerBuilder { self } + pub fn log_level(mut self, log_level: IssueSeverity) -> NextDevServerBuilder { + self.log_level = log_level; + self + } + + pub fn show_all(mut self, show_all: bool) -> NextDevServerBuilder { + self.show_all = show_all; + self + } + + pub fn log_detail(mut self, log_detail: bool) -> NextDevServerBuilder { + self.log_detail = log_detail; + self + } + pub async fn build(self) -> Result { let turbo_tasks = self.turbo_tasks.context("turbo_tasks must be set")?; let project_dir = self.project_dir.context("project_dir must be set")?; let entry_assets = self.entry_assets; let eager_compile = self.eager_compile; + let show_all = self.show_all; + let log_detail = self.log_detail; + let log_options = LogOptions { + project_dir: project_dir.clone(), + show_all, + log_detail, + log_level: self.log_level, + }; + let log_options_to_dev_server = log_options.clone(); let server = DevServer::listen( turbo_tasks.clone(), @@ -90,6 +120,7 @@ impl NextDevServerBuilder { entry_assets.clone(), eager_compile, turbo_tasks.clone().into(), + log_options.clone().cell(), ) }, ( @@ -97,22 +128,19 @@ impl NextDevServerBuilder { self.port.context("port must be set")?, ) .into(), + log_options_to_dev_server, ); Ok(server) } } -async fn handle_issues(source: T) -> Result<()> { +async fn handle_issues( + source: T, + options: LogOptionsVc, +) -> Result<()> { let issues = IssueVc::peek_issues_with_path(source).await?; - let issues = issues.await?; - let mut fatal = false; - for (issue, path) in issues.iter_with_shortest_path() { - println!("{}\n", &*issue_to_styled_string(issue, path).await?); - if *issue.severity().await? >= IssueSeverity::Fatal { - fatal = true; - } - } + let fatal = *group_and_display_issues(options, issues).await?; if fatal { Err(anyhow!("Fatal issue(s) occurred")) @@ -122,20 +150,20 @@ async fn handle_issues(source: T) -> Result<()> { } #[turbo_tasks::function] -async fn project_fs(project_dir: &str) -> Result { +async fn project_fs(project_dir: &str, log_options: LogOptionsVc) -> Result { let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir.to_string()); - handle_issues(disk_fs).await?; + handle_issues(disk_fs, log_options).await?; disk_fs.await?.start_watching()?; Ok(disk_fs.into()) } #[turbo_tasks::function] -async fn output_fs(project_dir: &str) -> Result { +async fn output_fs(project_dir: &str, log_options: LogOptionsVc) -> Result { let disk_fs = DiskFileSystemVc::new( "output".to_string(), format!("{project_dir}{s}.next{s}server", s = MAIN_SEPARATOR), ); - handle_issues(disk_fs).await?; + handle_issues(disk_fs, log_options).await?; disk_fs.await?.start_watching()?; Ok(disk_fs.into()) } @@ -146,9 +174,10 @@ async fn source( entry_assets: Vec, eager_compile: bool, turbo_tasks: TransientInstance>, + log_options: LogOptionsVc, ) -> Result { - let output_fs = output_fs(&project_dir); - let fs = project_fs(&project_dir); + let output_fs = output_fs(&project_dir, log_options); + let fs = project_fs(&project_dir, log_options); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let web_source = create_web_entry_source( @@ -181,9 +210,9 @@ async fn source( .cell() .into(); - handle_issues(dev_server_fs).await?; - handle_issues(web_source).await?; - handle_issues(rendered_source).await?; + handle_issues(dev_server_fs, log_options).await?; + handle_issues(web_source, log_options).await?; + handle_issues(rendered_source, log_options).await?; Ok(source) } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 8b269beac9c5e4..b657651dbc93e1 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -14,6 +14,8 @@ use clap::Parser; use next_dev::{register, NextDevServerBuilder}; use turbo_tasks::{util::FormatDuration, TurboTasks}; use turbo_tasks_memory::MemoryBackend; +use turbopack_cli_utils::issue::IssueSeverityCliOption; +use turbopack_core::issue::IssueSeverity; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] @@ -39,6 +41,18 @@ struct Cli { /// Don't open the browser automatically when the dev server has started. #[clap(long)] no_open: bool, + + #[clap(short, long)] + /// Filter by issue severity. + log_level: Option, + + #[clap(long)] + /// Show all log messages without limit. + show_all: bool, + + #[clap(long)] + /// Expand the log details. + log_detail: bool, } #[tokio::main] @@ -71,6 +85,9 @@ async fn main() { .eager_compile(args.eager_compile) .hostname(args.hostname) .port(args.port) + .log_detail(args.log_detail) + .show_all(args.show_all) + .log_level(args.log_level.map_or_else(|| IssueSeverity::Error, |l| l.0)) .build() .await .unwrap(); From 4935008b88617595cbf53dc5a134c4546c0e2556 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 22 Aug 2022 18:02:09 +0200 Subject: [PATCH 045/672] single thread for test cases (vercel/turbo#264) --- packages/next-swc/crates/next-dev/tests/integration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index 0e40dd36c6f7f5..d84c1ddd26d334 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -37,7 +37,7 @@ lazy_static! { } #[test_resources("crates/next-dev/tests/integration/*/*/*")] -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn test(resource: &str) { if resource.ends_with("__skipped__") { // "Skip" directories named `__skipped__`, which include test directories to From 078f4d81910d313672f724d13d27290068c2eab3 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 23 Aug 2022 13:47:39 +0200 Subject: [PATCH 046/672] Do not execute .css during server rendering (vercel/turbo#254) Ignore any non-code chunks for server rendering --- .../crates/next-core/src/server_render/nodejs_bootstrap.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs b/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs index afd2f3e118690e..1e8db8a6d82a88 100644 --- a/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs +++ b/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs @@ -33,7 +33,9 @@ impl Asset for NodeJsBootstrapAsset { for chunk in self.chunk_group.chunks().await?.iter() { let path = &*chunk.path().await?; if let Some(p) = context_path.get_relative_path_to(path) { - writeln!(&mut output, "require({});", stringify_str(&p))?; + if p.ends_with(".js") { + writeln!(&mut output, "require({});", stringify_str(&p))?; + } } } From 44eec9b9e0d26a752b98f11835f086c96d56e2c1 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 23 Aug 2022 15:24:25 +0200 Subject: [PATCH 047/672] only create pages for .js etc. files in pages (vercel/turbo#255) --- .../next-core/src/server_rendered_source.rs | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 691c64c87e0fe6..683519087712f8 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -141,25 +141,32 @@ async fn create_server_rendered_source_for_directory( for (name, entry) in entries.iter() { match entry { DirectoryEntry::File(file) => { - if let Some((name, _extension)) = name.rsplit_once('.') { - let (target_path, intermediate_output_path) = if name == "index" { - (target_path.join("index.html"), intermediate_output_path) - } else { - ( - target_path.join(name).join("index.html"), - intermediate_output_path.join(name), - ) - }; - sources.push( - create_server_rendered_source_for_file( - context, - *file, - target_root, - target_path, - intermediate_output_path, - ) - .into(), - ); + if let Some((name, extension)) = name.rsplit_once('.') { + match extension { + // pageExtensions option from next.js + // defaults: https://github.com/vercel/next.js/blob/611e13f5159457fedf96d850845650616a1f75dd/packages/next/server/config-shared.ts#L499 + "js" | "ts" | "jsx" | "tsx" => { + let (target_path, intermediate_output_path) = if name == "index" { + (target_path.join("index.html"), intermediate_output_path) + } else { + ( + target_path.join(name).join("index.html"), + intermediate_output_path.join(name), + ) + }; + sources.push( + create_server_rendered_source_for_file( + context, + *file, + target_root, + target_path, + intermediate_output_path, + ) + .into(), + ); + } + _ => {} + } } } DirectoryEntry::Directory(dir) => { From 77e46e2670636017155781c42df8c31b2f68e4ba Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 23 Aug 2022 12:10:38 -0400 Subject: [PATCH 048/672] Normalize Windows paths into Unix paths (vercel/turbo#251) The snapshot tests were failing because Windows paths were sneaking into the `FileSystemPathVc::path`. Reviewing, the `::new` method didn't normalize `\` into `/`, and the various `::join` methods didn't either. This came up in both the chunk ids, and the request pathnames used by the server. No path with backslash should enter the FileSystemPath APIs, they should be normalized during conversion from `Path` to `String` Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> --- packages/next-swc/crates/next-dev/tests/integration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index d84c1ddd26d334..382fb5f3a2c1d8 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -127,7 +127,7 @@ async fn run_test(resource: &str) -> JestRunResult { .unwrap() .to_str() .unwrap() - .replace('\\', "/"), + .to_string(), ) .eager_compile(false) .hostname(requested_addr.ip()) From e783ec8302b4f6efcb770a9f27a73c580af42aa1 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 24 Aug 2022 11:36:08 -0700 Subject: [PATCH 049/672] Benchmark startup time for bundling many modules (vercel/turbo#240) * Basic startup bench for dev server * fixes to benchmarking (vercel/turbo#268) * use bench profile for benchmarking * make setup and teardown not part of the measurement add support for async setup and teardown share browser between measurements * updates for changes TestApp Co-authored-by: Tobias Koppers --- packages/next-swc/crates/next-dev/Cargo.toml | 11 +- .../next-swc/crates/next-dev/benches/mod.rs | 223 ++++++++++++++++++ 2 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/benches/mod.rs diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 6f30e9bf67ee3a..fb23c7c75a5790 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -11,6 +11,10 @@ bench = false [lib] bench = false +[[bench]] +name = "mod" +harness = false + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] @@ -40,13 +44,16 @@ turbopack-dev-server = { path = "../turbopack-dev-server" } webbrowser = "0.7.1" [dev-dependencies] -tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in -# sync with chromiumoxide's tungstenite requirement. chromiumoxide = { version = "0.3.5", features = [ "tokio-runtime", ], default-features = false } +criterion = { version = "0.3.5", features = ["async_tokio"] } lazy_static = "1.4.0" +regex = "1.6.0" test-generator = "0.3.0" +# sync with chromiumoxide's tungstenite requirement. +tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in +turbopack-create-test-app = { path = "../turbopack-create-test-app" } [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs new file mode 100644 index 00000000000000..3306c914bfe679 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -0,0 +1,223 @@ +use std::{ + fs::remove_dir_all, + future::Future, + io::{BufRead, BufReader}, + path::PathBuf, + process::{Child, ChildStdout, Command, Stdio}, + time::Duration, +}; + +use chromiumoxide::{ + browser::{Browser, BrowserConfig}, + error::CdpError::Ws, + Page, +}; +use criterion::{ + async_executor::AsyncExecutor, + black_box, criterion_group, criterion_main, + measurement::{Measurement, WallTime}, + AsyncBencher, BenchmarkId, Criterion, +}; +use futures::StreamExt; +use regex::Regex; +use tokio::runtime::Runtime; +use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; +use turbopack_create_test_app::test_app_builder::TestAppBuilder; + +fn bench_startup(c: &mut Criterion) { + let mut g = c.benchmark_group("bench_startup"); + g.sample_size(10); + g.measurement_time(Duration::from_secs(80)); + + let runtime = Runtime::new().unwrap(); + let browser = &runtime.block_on(create_browser()); + + for size in [100, 1_000] { + g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { + b.to_async(&runtime).iter_batched_async( + || PreparedApp::new(s), + |mut app| async move { + app.start_server(); + let page = app.new_page(browser).await; + page.wait_for_navigation().await.unwrap(); + app.schedule_page_disposal(page); + // return the PreparedApp doesn't make dropping it part of the measurement + app + }, + |app| app.dispose(), + ) + }); + } + + g.finish(); +} +struct PreparedApp { + server: Option<(Child, String)>, + test_dir: PathBuf, + pages: Vec, +} + +impl PreparedApp { + async fn new(module_count: usize) -> Self { + let test_dir = TestAppBuilder { + module_count, + directories_count: module_count / 20, + ..Default::default() + } + .build() + .unwrap(); + + Self { + test_dir, + server: None, + pages: Vec::new(), + } + } + + fn start_server(&mut self) { + assert!(self.server.is_none(), "Server already started"); + + let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) + .args([self.test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + + let addr = wait_for_addr(proc.stdout.as_mut().unwrap()); + self.server = Some((proc, addr)); + } + + async fn new_page(&self, browser: &Browser) -> Page { + let server = self.server.as_ref().expect("Server must be started"); + browser.new_page(&server.1).await.unwrap() + } + + fn schedule_page_disposal(&mut self, page: Page) { + self.pages.push(page); + } + + async fn dispose(self) { + if let Some(mut server) = self.server { + server.0.kill().unwrap(); + } + for page in self.pages { + page.close().await.unwrap(); + } + remove_dir_all(&self.test_dir).unwrap(); + } +} + +async fn create_browser() -> Browser { + let (browser, mut handler) = Browser::launch(BrowserConfig::builder().build().unwrap()) + .await + .unwrap(); + + // See https://crates.io/crates/chromiumoxide + tokio::task::spawn(async move { + loop { + if let Err(Ws(Protocol(ResetWithoutClosingHandshake))) = handler.next().await.unwrap() { + break; + } + } + }); + + browser +} + +fn wait_for_addr(stdout: &mut ChildStdout) -> String { + // See https://docs.rs/async-process/latest/async_process/#examples + let mut line_reader = BufReader::new(stdout).lines(); + let started_regex = Regex::new("server listening on: (.*)").unwrap(); + // Wait for "server listening on" message to appear before navigating there. + let mut addr: Option = None; + while let Some(Ok(line)) = line_reader.next() { + if let Some(cap) = started_regex.captures(&line) { + addr = Some(cap.get(1).unwrap().as_str().into()); + break; + } + } + + addr.unwrap() +} + +trait AsyncBencherExtension { + fn iter_batched_async(&mut self, setup: S, routine: R, teardown: T) + where + S: Fn() -> SF, + SF: Future, + R: Fn(I) -> F, + F: Future, + T: Fn(O) -> TF, + TF: Future; +} + +impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, WallTime> { + #[inline(never)] + fn iter_batched_async(&mut self, setup: S, routine: R, teardown: T) + where + S: Fn() -> SF, + SF: Future, + R: Fn(I) -> F, + F: Future, + T: Fn(O) -> TF, + TF: Future, + { + let setup = &setup; + let routine = &routine; + let teardown = &teardown; + self.iter_custom(|iters| { + async move { + let batch_size = std::cmp::min(iters, 50); + let measurement = WallTime; + let mut value = measurement.zero(); + + if batch_size == 1 { + for _ in 0..iters { + let input = black_box(setup().await); + + let start = measurement.start(); + let output = routine(input).await; + let end = measurement.end(start); + value = measurement.add(&value, &end); + + teardown(black_box(output)).await; + } + } else { + let mut iteration_counter = 0; + + while iteration_counter < iters { + let batch_size = std::cmp::min(batch_size, iters - iteration_counter); + + let inputs = black_box({ + let mut inputs = Vec::new(); + for _ in 0..batch_size { + inputs.push(setup().await) + } + inputs + }); + let mut outputs = Vec::with_capacity(batch_size as usize); + + let start = measurement.start(); + // Can't use .extend here like the sync version does + for input in inputs { + outputs.push(routine(input).await); + } + let end = measurement.end(start); + value = measurement.add(&value, &end); + + for output in black_box(outputs) { + teardown(output).await; + } + + iteration_counter += batch_size; + } + } + + value + } + }) + } +} + +criterion_group!(benches, bench_startup); +criterion_main!(benches); From 5156dcfc2563df17bf0af96febe64cf98c5caa62 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 24 Aug 2022 20:41:16 +0200 Subject: [PATCH 050/672] add root_dir to support monorepos (vercel/turbo#260) This adds an option to pass the root dir from CLI, before it was always the current directory --- packages/next-swc/crates/next-dev/src/lib.rs | 26 +++++++++++---- packages/next-swc/crates/next-dev/src/main.rs | 32 ++++++++++++++----- .../crates/next-dev/tests/integration.rs | 1 + 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 4963e92e00a29d..b34d464577b710 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -21,6 +21,7 @@ mod turbo_tasks_viz; pub struct NextDevServerBuilder { turbo_tasks: Option>>, project_dir: Option, + root_dir: Option, entry_assets: Vec, eager_compile: bool, hostname: Option, @@ -41,6 +42,7 @@ impl NextDevServerBuilder { NextDevServerBuilder { turbo_tasks: None, project_dir: None, + root_dir: None, entry_assets: vec![], eager_compile: false, hostname: None, @@ -61,6 +63,11 @@ impl NextDevServerBuilder { self } + pub fn root_dir(mut self, root_dir: String) -> NextDevServerBuilder { + self.root_dir = Some(root_dir); + self + } + pub fn entry_asset(mut self, entry_asset_path: String) -> NextDevServerBuilder { self.entry_assets.push(entry_asset_path); self @@ -100,6 +107,7 @@ impl NextDevServerBuilder { let turbo_tasks = self.turbo_tasks.context("turbo_tasks must be set")?; let project_dir = self.project_dir.context("project_dir must be set")?; + let root_dir = self.root_dir.context("root_dir must be set")?; let entry_assets = self.entry_assets; let eager_compile = self.eager_compile; let show_all = self.show_all; @@ -116,6 +124,7 @@ impl NextDevServerBuilder { turbo_tasks.clone(), move || { source( + root_dir.clone(), project_dir.clone(), entry_assets.clone(), eager_compile, @@ -170,6 +179,7 @@ async fn output_fs(project_dir: &str, log_options: LogOptionsVc) -> Result, eager_compile: bool, @@ -177,20 +187,22 @@ async fn source( log_options: LogOptionsVc, ) -> Result { let output_fs = output_fs(&project_dir, log_options); - let fs = project_fs(&project_dir, log_options); + let fs = project_fs(&root_dir, log_options); + let project_relative = project_dir.strip_prefix(&root_dir).unwrap(); + let project_relative = project_relative + .strip_prefix(MAIN_SEPARATOR) + .unwrap_or(project_relative); + let project_path = FileSystemPathVc::new(fs, project_relative); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let web_source = create_web_entry_source( - FileSystemPathVc::new(fs, ""), - entry_assets - .iter() - .map(|a| FileSystemPathVc::new(fs, a)) - .collect(), + project_path, + entry_assets.iter().map(|a| project_path.join(a)).collect(), dev_server_fs, eager_compile, ); let rendered_source = create_server_rendered_source( - FileSystemPathVc::new(fs, ""), + project_path, FileSystemPathVc::new(output_fs, ""), FileSystemPathVc::new(dev_server_fs, ""), ); diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index b657651dbc93e1..3b65cc1aa1c540 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -9,7 +9,7 @@ use std::{ time::{Duration, Instant}, }; -use anyhow::Context; +use anyhow::{Context, Result}; use clap::Parser; use next_dev::{register, NextDevServerBuilder}; use turbo_tasks::{util::FormatDuration, TurboTasks}; @@ -25,6 +25,12 @@ struct Cli { #[clap(value_parser)] dir: Option, + /// The root directory of the project. Nothing outside of this directory can + /// be accessed. e. g. the monorepo root. + /// If no directory is provided, `dir` will be used. + #[clap(long, value_parser)] + root: Option, + /// The port number on which to start the application #[clap(short, long, value_parser, default_value_t = 3000)] port: u16, @@ -56,7 +62,7 @@ struct Cli { } #[tokio::main] -async fn main() { +async fn main() -> Result<()> { let start = Instant::now(); #[cfg(feature = "tokio_console")] @@ -68,19 +74,28 @@ async fn main() { let dir = args .dir .map(|dir| dir.canonicalize()) - .unwrap_or_else(current_dir) - .unwrap() + .unwrap_or_else(current_dir)? .to_str() - .context("current directory contains invalid characters") - .unwrap() + .context("current directory contains invalid characters")? .to_string(); + let root_dir = if let Some(root) = args.root { + root.canonicalize() + .unwrap() + .to_str() + .context("current directory contains invalid characters")? + .to_string() + } else { + dir.clone() + }; + let tt = TurboTasks::new(MemoryBackend::new()); let tt_clone = tt.clone(); let server = NextDevServerBuilder::new() .turbo_tasks(tt) .project_dir(dir) + .root_dir(root_dir) .entry_asset("src/index.js".into()) .eager_compile(args.eager_compile) .hostname(args.hostname) @@ -89,8 +104,7 @@ async fn main() { .show_all(args.show_all) .log_level(args.log_level.map_or_else(|| IssueSeverity::Error, |l| l.0)) .build() - .await - .unwrap(); + .await?; { let index_uri = if server.addr.ip().is_loopback() { @@ -120,4 +134,6 @@ async fn main() { } } .await; + + Ok(()) } diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index 382fb5f3a2c1d8..2e194a54a69c20 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -119,6 +119,7 @@ async fn run_test(resource: &str) -> JestRunResult { let requested_addr = get_free_local_addr().unwrap(); let server = NextDevServerBuilder::new() .turbo_tasks(TurboTasks::new(MemoryBackend::new())) + .root_dir("tests".into()) .project_dir("tests".into()) .entry_asset("harness.js".into()) .entry_asset( From 3148d3b67bc87acdc773377ed28e7f0c32642110 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 25 Aug 2022 17:44:11 +0200 Subject: [PATCH 051/672] fix windows path separators (vercel/turbo#281) --- packages/next-swc/crates/next-dev/tests/integration.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index 2e194a54a69c20..e942af31501567 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -15,6 +15,7 @@ use test_generator::test_resources; use tokio::{net::TcpSocket, task::JoinHandle}; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; use turbo_tasks::TurboTasks; +use turbo_tasks_fs::util::sys_to_unix; use turbo_tasks_memory::MemoryBackend; #[derive(Debug, Deserialize)] @@ -123,12 +124,7 @@ async fn run_test(resource: &str) -> JestRunResult { .project_dir("tests".into()) .entry_asset("harness.js".into()) .entry_asset( - test_entry - .strip_prefix("tests") - .unwrap() - .to_str() - .unwrap() - .to_string(), + sys_to_unix(test_entry.strip_prefix("tests").unwrap().to_str().unwrap()).to_string(), ) .eager_compile(false) .hostname(requested_addr.ip()) From 32d10a037ad9ee1616d95a3e8476c141ad048e14 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 26 Aug 2022 13:26:58 +0200 Subject: [PATCH 052/672] resolve entrypoint to allow it to select jsx automatically (vercel/turbo#278) --- .../src/server_render/nodejs_pool.rs | 2 +- .../crates/next-core/src/web_entry_source.rs | 20 +++++++++----- packages/next-swc/crates/next-dev/src/lib.rs | 26 ++++++++++++------- packages/next-swc/crates/next-dev/src/main.rs | 2 +- .../crates/next-dev/tests/integration.rs | 4 +-- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs b/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs index 1b1f673ae0a3c0..ba26f44a9a2331 100644 --- a/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs +++ b/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs @@ -45,7 +45,7 @@ impl NodeJsPoolProcess { } fn start(mut cmd: Command) -> Result { - let mut child = cmd.spawn().with_context(|| format!("spawning node pool"))?; + let mut child = cmd.spawn().context("spawning node pool")?; let stdin = child.stdin.take().unwrap(); let mut stdout = BufReader::new(child.stdout.take().unwrap()); let mut bootstrap_log = Vec::new(); diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 086b28eab36fe5..b98f47ac7af0e4 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -1,8 +1,7 @@ -use std::collections::HashMap; +use std::{collections::HashMap, future::IntoFuture}; use anyhow::{anyhow, Result}; -use futures::future::try_join_all; -use turbo_tasks::Value; +use turbo_tasks::{util::try_join_all, Value}; use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; use turbopack::{ecmascript::EcmascriptModuleAssetVc, ModuleAssetContextVc}; use turbopack_core::{ @@ -12,7 +11,7 @@ use turbopack_core::{ }, context::AssetContextVc, environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, - source_asset::SourceAssetVc, + resolve::parse::RequestVc, transition::TransitionsByNameVc, }; use turbopack_dev_server::{ @@ -23,7 +22,7 @@ use turbopack_dev_server::{ #[turbo_tasks::function] pub async fn create_web_entry_source( root: FileSystemPathVc, - entry_paths: Vec, + entry_requests: Vec, dev_server_fs: FileSystemVc, eager_compile: bool, ) -> Result { @@ -52,9 +51,16 @@ pub async fn create_web_entry_source( } .into(); - let modules = entry_paths + let modules = try_join_all(entry_requests.into_iter().map(|r| { + context + .resolve_asset(context.context_path(), r, context.resolve_options()) + .primary_assets() + .into_future() + })) + .await?; + let modules = modules .into_iter() - .map(|p| context.process(SourceAssetVc::new(p).into())); + .flat_map(|assets| assets.iter().copied().collect::>()); let chunks = try_join_all(modules.map(|module| async move { if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { Ok(ecmascript.as_evaluated_chunk(chunking_context.into())) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index b34d464577b710..98a692fdc9dc73 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -5,11 +5,14 @@ use std::{net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; use next_core::{create_server_rendered_source, create_web_entry_source}; -use turbo_tasks::{CollectiblesSource, TransientInstance, TurboTasks}; +use turbo_tasks::{CollectiblesSource, TransientInstance, TurboTasks, Value}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::{group_and_display_issues, LogOptions, LogOptionsVc}; -use turbopack_core::issue::{IssueSeverity, IssueVc}; +use turbopack_core::{ + issue::{IssueSeverity, IssueVc}, + resolve::parse::RequestVc, +}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, source::{combined::CombinedContentSource, router::RouterContentSource, ContentSourceVc}, @@ -22,7 +25,7 @@ pub struct NextDevServerBuilder { turbo_tasks: Option>>, project_dir: Option, root_dir: Option, - entry_assets: Vec, + entry_requests: Vec, eager_compile: bool, hostname: Option, port: Option, @@ -43,7 +46,7 @@ impl NextDevServerBuilder { turbo_tasks: None, project_dir: None, root_dir: None, - entry_assets: vec![], + entry_requests: vec![], eager_compile: false, hostname: None, port: None, @@ -68,8 +71,8 @@ impl NextDevServerBuilder { self } - pub fn entry_asset(mut self, entry_asset_path: String) -> NextDevServerBuilder { - self.entry_assets.push(entry_asset_path); + pub fn entry_request(mut self, entry_asset_path: String) -> NextDevServerBuilder { + self.entry_requests.push(entry_asset_path); self } @@ -108,7 +111,7 @@ impl NextDevServerBuilder { let project_dir = self.project_dir.context("project_dir must be set")?; let root_dir = self.root_dir.context("root_dir must be set")?; - let entry_assets = self.entry_assets; + let entry_requests = self.entry_requests; let eager_compile = self.eager_compile; let show_all = self.show_all; let log_detail = self.log_detail; @@ -126,7 +129,7 @@ impl NextDevServerBuilder { source( root_dir.clone(), project_dir.clone(), - entry_assets.clone(), + entry_requests.clone(), eager_compile, turbo_tasks.clone().into(), log_options.clone().cell(), @@ -181,7 +184,7 @@ async fn output_fs(project_dir: &str, log_options: LogOptionsVc) -> Result, + entry_requests: Vec, eager_compile: bool, turbo_tasks: TransientInstance>, log_options: LogOptionsVc, @@ -197,7 +200,10 @@ async fn source( let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let web_source = create_web_entry_source( project_path, - entry_assets.iter().map(|a| project_path.join(a)).collect(), + entry_requests + .iter() + .map(|a| RequestVc::relative(Value::new(a.to_string().into()), false)) + .collect(), dev_server_fs, eager_compile, ); diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 3b65cc1aa1c540..40021ddf1da8bf 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -96,7 +96,7 @@ async fn main() -> Result<()> { .turbo_tasks(tt) .project_dir(dir) .root_dir(root_dir) - .entry_asset("src/index.js".into()) + .entry_request("src/index".into()) .eager_compile(args.eager_compile) .hostname(args.hostname) .port(args.port) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index e942af31501567..3bf97fe47d9b92 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -122,8 +122,8 @@ async fn run_test(resource: &str) -> JestRunResult { .turbo_tasks(TurboTasks::new(MemoryBackend::new())) .root_dir("tests".into()) .project_dir("tests".into()) - .entry_asset("harness.js".into()) - .entry_asset( + .entry_request("harness.js".into()) + .entry_request( sys_to_unix(test_entry.strip_prefix("tests").unwrap().to_str().unwrap()).to_string(), ) .eager_compile(false) From 8f54f35e90ca143690f54796119244c3f98abb54 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Fri, 26 Aug 2022 18:30:04 +0200 Subject: [PATCH 053/672] HMR support + React Refresh (vercel/turbo#252) This PR implements HMR support with React Refresh built-in. For now, in order for React Refresh to be enabled, you'll need the `@next/react-refresh-utils` package to be resolveable: `yarn add @next/react-refresh-utils` in your app folder. * Depends on vercel/turbo#266 * Integrated both HMR-and-React-Refresh-specific logic directly into the ES chunks' runtime. Webpack has more complex setup here, but for now this makes the logic much more easy to follow since everything is in one place. I have yet to implement the "dependencies" signature for `hot.accept`/`hot.dispose`, since React Refresh does not depend on them. We'll have to see if they're even used in the wild or if we should deprecate them. * Only implemented the [module API](https://webpack.js.org/api/hot-module-replacement/#module-api), not the [management API](https://webpack.js.org/api/hot-module-replacement/#management-api). We apply all updates as soon as we receive them. * Added support for "runtime entries" to ES chunks. These are assets that will be executed *before* the main entry of an ES chunk. They'll be useful for polyfills in the future, but for now they're here to evaluate the react refresh runtime before any module is instantiated. Next steps for HMR: * Implement CSS HMR * Implement (or decide to deprecate) the [dependencies form](https://webpack.js.org/api/hot-module-replacement/#accept) of `hot.accept`/`hot.dispose` * Clean up `runtime.js` some more: switch to TypeScript, split into multiple files, etc. It'd be nice if all of this could be done at compile time, but how to achieve this is unclear at the moment. _Can we run turbopack to compile turbopack?_ --- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../crates/next-core/src/react_refresh.rs | 108 ++++++++++++++++++ .../next-core/src/server_render/asset.rs | 4 +- .../next-core/src/server_rendered_source.rs | 1 + .../crates/next-core/src/web_entry_source.rs | 53 ++++++--- packages/next-swc/crates/next-dev/src/lib.rs | 2 +- packages/next-swc/crates/next-dev/src/main.rs | 5 +- 7 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/react_refresh.rs diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 6d5bcfa8d08c32..d3e2e419d8a80b 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -1,6 +1,7 @@ #![feature(min_specialization)] pub mod next_client; +pub mod react_refresh; mod server_render; mod server_rendered_source; mod web_entry_source; diff --git a/packages/next-swc/crates/next-core/src/react_refresh.rs b/packages/next-swc/crates/next-core/src/react_refresh.rs new file mode 100644 index 00000000000000..b365103f43db45 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/react_refresh.rs @@ -0,0 +1,108 @@ +use anyhow::{anyhow, Result}; +use turbo_tasks::primitives::{BoolVc, StringVc}; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::ecmascript::{ + chunk::EcmascriptChunkPlaceableVc, + resolve::{apply_cjs_specific_options, cjs_resolve}, +}; +use turbopack_core::{ + context::AssetContextVc, + environment::EnvironmentVc, + issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, + resolve::{parse::RequestVc, ResolveResult}, +}; + +#[turbo_tasks::function] +fn react_refresh_request() -> RequestVc { + RequestVc::parse_string("@next/react-refresh-utils/dist/runtime".to_string()) +} + +/// Checks whether we can resolve the React Refresh runtime module from the +/// given path. Emits an issue if we can't. +/// +/// Differs from `resolve_react_refresh` in that we don't have access to an +/// [AssetContextVc] when we first want to check for RR. +#[turbo_tasks::function] +pub async fn assert_can_resolve_react_refresh( + path: FileSystemPathVc, + environment: EnvironmentVc, +) -> Result { + let resolve_options = apply_cjs_specific_options(turbopack::resolve_options(path, environment)); + let result = turbopack_core::resolve::resolve(path, react_refresh_request(), resolve_options); + + Ok(match &*result.await? { + ResolveResult::Single(_, _) => BoolVc::cell(true), + _ => { + ReactRefreshResolvingIssue { + path, + description: StringVc::cell( + "could not resolve the `@next/react-refresh-utils/dist/runtime` module" + .to_string(), + ), + } + .cell() + .as_issue() + .emit(); + BoolVc::cell(false) + } + }) +} + +/// Resolves the React Refresh runtime module from the given [AssetContextVc]. +#[turbo_tasks::function] +pub async fn resolve_react_refresh(context: AssetContextVc) -> Result { + match &*cjs_resolve(react_refresh_request(), context).await? { + ResolveResult::Single(asset, _) => { + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { + Ok(placeable) + } else { + Err(anyhow!("React Refresh runtime asset is not placeable")) + } + } + // The react-refresh-runtime module is not installed. + ResolveResult::Unresolveable(_) => Err(anyhow!( + "could not resolve the `@next/react-refresh-utils/dist/runtime` module" + )), + _ => Err(anyhow!("invalid React Refresh runtime asset")), + } +} + +/// An issue that occurred while resolving the React Refresh runtime module. +#[turbo_tasks::value(shared)] +pub struct ReactRefreshResolvingIssue { + path: FileSystemPathVc, + description: StringVc, +} + +#[turbo_tasks::value_impl] +impl Issue for ReactRefreshResolvingIssue { + #[turbo_tasks::function] + fn severity(&self) -> IssueSeverityVc { + IssueSeverity::Warning.into() + } + + #[turbo_tasks::function] + async fn title(&self) -> Result { + Ok(StringVc::cell( + "An issue occurred while resolving the React Refresh runtime. React Refresh will be \ + disabled.\nTo enable React Refresh, install the `react-refresh` and \ + `@next/react-refresh-utils` modules." + .to_string(), + )) + } + + #[turbo_tasks::function] + fn category(&self) -> StringVc { + StringVc::cell("other".to_string()) + } + + #[turbo_tasks::function] + fn context(&self) -> FileSystemPathVc { + self.path + } + + #[turbo_tasks::function] + fn description(&self) -> StringVc { + self.description + } +} diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index 5d5e18d5cf4fc9..ddc75b26bb2571 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -168,10 +168,10 @@ async fn get_intermediate_asset( WrapperAssetVc::new(entry_asset, "server-renderer.js", get_server_renderer()).into(), context.with_context_path(entry_asset.path()), Value::new(ModuleAssetType::Ecmascript), - EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::JSX]), + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { refresh: false }]), context.environment(), ); - let chunk = module.as_evaluated_chunk(chunking_context.into()); + let chunk = module.as_evaluated_chunk(chunking_context.into(), None); let chunk_group = ChunkGroupVc::from_chunk(chunk); Ok(NodeJsBootstrapAsset { path: intermediate_output_path.join("index.js"), diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 683519087712f8..aab60e665751df 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -84,6 +84,7 @@ pub async fn create_server_rendered_source( )), Value::new(EnvironmentIntention::Client), ), + Default::default(), ) .into(); diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index b98f47ac7af0e4..f17d3db3005635 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -3,7 +3,11 @@ use std::{collections::HashMap, future::IntoFuture}; use anyhow::{anyhow, Result}; use turbo_tasks::{util::try_join_all, Value}; use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; -use turbopack::{ecmascript::EcmascriptModuleAssetVc, ModuleAssetContextVc}; +use turbopack::{ + ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}, + module_options::ModuleOptionsContext, + ModuleAssetContextVc, +}; use turbopack_core::{ chunk::{ dev::{DevChunkingContext, DevChunkingContextVc}, @@ -19,6 +23,8 @@ use turbopack_dev_server::{ source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; +use crate::react_refresh::{assert_can_resolve_react_refresh, resolve_react_refresh}; + #[turbo_tasks::function] pub async fn create_web_entry_source( root: FileSystemPathVc, @@ -26,21 +32,32 @@ pub async fn create_web_entry_source( dev_server_fs: FileSystemVc, eager_compile: bool, ) -> Result { + let environment = EnvironmentVc::new( + Value::new(ExecutionEnvironment::Browser( + BrowserEnvironment { + dom: true, + web_worker: false, + service_worker: false, + browser_version: 0, + } + .into(), + )), + Value::new(EnvironmentIntention::Client), + ); + + let can_resolve_react_refresh = *assert_can_resolve_react_refresh(root, environment).await?; + let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), root, - EnvironmentVc::new( - Value::new(ExecutionEnvironment::Browser( - BrowserEnvironment { - dom: true, - web_worker: false, - service_worker: false, - browser_version: 0, - } - .into(), - )), - Value::new(EnvironmentIntention::Client), - ), + environment, + ModuleOptionsContext { + // We don't need to resolve React Refresh for each module. Instead, + // we try resolve it once at the root and pass down a context to all + // the modules. + enable_react_refresh: can_resolve_react_refresh, + } + .into(), ) .into(); @@ -51,6 +68,14 @@ pub async fn create_web_entry_source( } .into(); + let runtime_entries = if can_resolve_react_refresh { + Some(EcmascriptChunkPlaceablesVc::cell(vec![ + resolve_react_refresh(context), + ])) + } else { + None + }; + let modules = try_join_all(entry_requests.into_iter().map(|r| { context .resolve_asset(context.context_path(), r, context.resolve_options()) @@ -63,7 +88,7 @@ pub async fn create_web_entry_source( .flat_map(|assets| assets.iter().copied().collect::>()); let chunks = try_join_all(modules.map(|module| async move { if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { - Ok(ecmascript.as_evaluated_chunk(chunking_context.into())) + Ok(ecmascript.as_evaluated_chunk(chunking_context.into(), runtime_entries)) } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { Ok(chunkable.as_chunk(chunking_context.into())) } else { diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 98a692fdc9dc73..5da5181ae6e43d 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -50,7 +50,7 @@ impl NextDevServerBuilder { eager_compile: false, hostname: None, port: None, - log_level: IssueSeverity::Error, + log_level: IssueSeverity::Warning, show_all: false, log_detail: false, } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 40021ddf1da8bf..3ead12545a3552 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -102,7 +102,10 @@ async fn main() -> Result<()> { .port(args.port) .log_detail(args.log_detail) .show_all(args.show_all) - .log_level(args.log_level.map_or_else(|| IssueSeverity::Error, |l| l.0)) + .log_level( + args.log_level + .map_or_else(|| IssueSeverity::Warning, |l| l.0), + ) .build() .await?; From 2ee6039ad036c3d994cb07523e45da0a56c8aaa9 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 29 Aug 2022 15:41:26 -0700 Subject: [PATCH 054/672] Benchmarks: Install node_modules and reuse test directories (vercel/turbo#284) This: * Runs `npm install` in test directories to provide turbopack with modules necessary to bundle them. * Reuses test directories for iterations across the given benchmark. This prevents unnecessary file writing and `npm install` for each iteration, improving the times to run benchmarks. Currently cherry-picks vercel/turbo#278 as it's necessary along with vercel/turbo#277. Test Plan: Connected to the running devserver mid-test and confirmed no errors are thrown and the triangle is rendered correctly. --- .../next-swc/crates/next-dev/benches/mod.rs | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 3306c914bfe679..4dd84bcd7e9f8b 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -1,7 +1,7 @@ use std::{ fs::remove_dir_all, future::Future, - io::{BufRead, BufReader}, + io::{self, BufRead, BufReader, Write}, path::PathBuf, process::{Child, ChildStdout, Command, Stdio}, time::Duration, @@ -34,10 +34,11 @@ fn bench_startup(c: &mut Criterion) { for size in [100, 1_000] { g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { + let test_dir = build_test(s); b.to_async(&runtime).iter_batched_async( - || PreparedApp::new(s), - |mut app| async move { - app.start_server(); + PreparedApp::new, + |mut app| async { + app.start_server(&test_dir); let page = app.new_page(browser).await; page.wait_for_navigation().await.unwrap(); app.schedule_page_disposal(page); @@ -45,7 +46,8 @@ fn bench_startup(c: &mut Criterion) { app }, |app| app.dispose(), - ) + ); + remove_dir_all(&test_dir).unwrap(); }); } @@ -53,32 +55,22 @@ fn bench_startup(c: &mut Criterion) { } struct PreparedApp { server: Option<(Child, String)>, - test_dir: PathBuf, pages: Vec, } impl PreparedApp { - async fn new(module_count: usize) -> Self { - let test_dir = TestAppBuilder { - module_count, - directories_count: module_count / 20, - ..Default::default() - } - .build() - .unwrap(); - + async fn new() -> Self { Self { - test_dir, server: None, pages: Vec::new(), } } - fn start_server(&mut self) { + fn start_server(&mut self, test_dir: &PathBuf) { assert!(self.server.is_none(), "Server already started"); - let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) - .args([self.test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) + .args([".", "--no-open", "--port", "0"]) + .current_dir(test_dir) .stdout(Stdio::piped()) .spawn() .unwrap(); @@ -103,10 +95,34 @@ impl PreparedApp { for page in self.pages { page.close().await.unwrap(); } - remove_dir_all(&self.test_dir).unwrap(); } } +fn build_test(module_count: usize) -> PathBuf { + let test_dir = TestAppBuilder { + module_count, + directories_count: module_count / 20, + package_json: true, + ..Default::default() + } + .build() + .unwrap(); + + let npm = Command::new("npm") + .args(["install", "--prefer-offline", "--loglevel=error"]) + .current_dir(&test_dir) + .output() + .unwrap(); + + if !npm.status.success() { + io::stdout().write_all(&npm.stdout).unwrap(); + io::stderr().write_all(&npm.stderr).unwrap(); + panic!("npm install failed. See above."); + } + + test_dir +} + async fn create_browser() -> Browser { let (browser, mut handler) = Browser::launch(BrowserConfig::builder().build().unwrap()) .await From 43f25065c828e3d4e66e8bb38fed581546d2c673 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 29 Aug 2022 16:18:26 -0700 Subject: [PATCH 055/672] Benchmarks: assert that no runtime errors occur when loading pages (vercel/turbo#285) This adds an assertion that no runtime (browser) errors occurred when loading a benchmark page. Test Plan: Temporarily removed the npm install for the test app and verified the benchmark failed as the test app requires react, react-dom. Restored the npm install and verified the benchmark runs to completion. --- packages/next-swc/crates/next-dev/benches/mod.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 4dd84bcd7e9f8b..a670bb9ace8af4 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -9,6 +9,7 @@ use std::{ use chromiumoxide::{ browser::{Browser, BrowserConfig}, + cdp::js_protocol::runtime::EventExceptionThrown, error::CdpError::Ws, Page, }; @@ -18,7 +19,7 @@ use criterion::{ measurement::{Measurement, WallTime}, AsyncBencher, BenchmarkId, Criterion, }; -use futures::StreamExt; +use futures::{FutureExt, StreamExt}; use regex::Regex; use tokio::runtime::Runtime; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; @@ -81,7 +82,15 @@ impl PreparedApp { async fn new_page(&self, browser: &Browser) -> Page { let server = self.server.as_ref().expect("Server must be started"); - browser.new_page(&server.1).await.unwrap() + let page = browser.new_page("about:blank").await.unwrap(); + let mut errors = page.event_listener::().await.unwrap(); + + page.goto(&server.1).await.unwrap(); + + // Make sure no runtime errors occurred when loading the page + assert!(errors.next().now_or_never().is_none()); + + page } fn schedule_page_disposal(&mut self, page: Page) { From 1e8d63d10d3cd858b6246851811e664e96a03a24 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 30 Aug 2022 17:15:06 +0200 Subject: [PATCH 056/672] Postfix join and try_join (vercel/turbo#300) Instead of dropping back to prefix calling form in `try_join_all(iterator_of_intofutures).await?`, we now use postfix form `iterator_of_intofutures.try_join().await?`. --- .../crates/next-core/src/web_entry_source.rs | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index f17d3db3005635..93528ab10084d6 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, future::IntoFuture}; use anyhow::{anyhow, Result}; -use turbo_tasks::{util::try_join_all, Value}; +use turbo_tasks::{TryJoinIterExt, Value}; use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; use turbopack::{ ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}, @@ -76,30 +76,36 @@ pub async fn create_web_entry_source( None }; - let modules = try_join_all(entry_requests.into_iter().map(|r| { - context - .resolve_asset(context.context_path(), r, context.resolve_options()) - .primary_assets() - .into_future() - })) - .await?; + let modules = entry_requests + .into_iter() + .map(|r| { + context + .resolve_asset(context.context_path(), r, context.resolve_options()) + .primary_assets() + .into_future() + }) + .try_join() + .await?; let modules = modules .into_iter() .flat_map(|assets| assets.iter().copied().collect::>()); - let chunks = try_join_all(modules.map(|module| async move { - if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { - Ok(ecmascript.as_evaluated_chunk(chunking_context.into(), runtime_entries)) - } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { - Ok(chunkable.as_chunk(chunking_context.into())) - } else { - // TODO convert into a serve-able asset - Err(anyhow!( - "Entry module is not chunkable, so it can't be used to bootstrap the application" - )) - } - // ChunkGroupVc::from_chunk(m) - })) - .await?; + let chunks = modules + .map(|module| async move { + if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { + Ok(ecmascript.as_evaluated_chunk(chunking_context.into(), runtime_entries)) + } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { + Ok(chunkable.as_chunk(chunking_context.into())) + } else { + // TODO convert into a serve-able asset + Err(anyhow!( + "Entry module is not chunkable, so it can't be used to bootstrap the \ + application" + )) + } + // ChunkGroupVc::from_chunk(m) + }) + .try_join() + .await?; let entry_asset = DevHtmlAsset { path: FileSystemPathVc::new(dev_server_fs, "index.html"), From 42dda2f1811e00a432f33118357859a416d6cb62 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 30 Aug 2022 18:31:35 +0200 Subject: [PATCH 057/672] improve vizualization (vercel/turbo#225) --- .../crates/next-dev/src/turbo_tasks_viz.rs | 90 ++++++++++++------- 1 file changed, 59 insertions(+), 31 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index f8fb8fe000e8a6..8b62a6301782c0 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -1,10 +1,13 @@ -use std::{str::FromStr, sync::Arc}; +use std::{str::FromStr, sync::Arc, time::Duration}; use anyhow::Result; use mime::Mime; -use turbo_tasks::TurboTasks; +use turbo_tasks::{get_invalidator, TurboTasks}; use turbo_tasks_fs::{File, FileContent}; -use turbo_tasks_memory::{stats::Stats, viz, MemoryBackend}; +use turbo_tasks_memory::{ + stats::{ReferenceType, Stats}, + viz, MemoryBackend, +}; use turbopack_core::version::VersionedContentVc; use turbopack_dev_server::source::{ContentSource, ContentSourceVc}; @@ -20,40 +23,65 @@ impl TurboTasksSourceVc { } } +const INVALIDATION_INTERVAL: Duration = Duration::from_secs(3); + #[turbo_tasks::value_impl] impl ContentSource for TurboTasksSource { #[turbo_tasks::function] fn get(&self, path: &str) -> Result { let tt = &self.turbo_tasks; - if path == "graph" { - let mut stats = Stats::new(); - let b = tt.backend(); - b.with_all_cached_tasks(|task| { - stats.add_id(b, task); - }); - let tree = stats.treeify(); - let graph = viz::graph::visualize_stats_tree(tree); - return Ok(FileContent::Content( - File::from_source(viz::graph::wrap_html(&graph)) - .with_content_type(Mime::from_str("text/html")?), - ) - .into()); - } - if path == "table" { - let mut stats = Stats::new(); - let b = tt.backend(); - b.with_all_cached_tasks(|task| { - stats.add_id(b, task); - }); - let tree = stats.treeify(); - let table = viz::table::create_table(tree); - return Ok(FileContent::Content( - File::from_source(viz::table::wrap_html(&table)) - .with_content_type(Mime::from_str("text/html")?), - ) - .into()); + let invalidator = get_invalidator(); + tokio::spawn({ + async move { + tokio::time::sleep(INVALIDATION_INTERVAL).await; + invalidator.invalidate(); + } + }); + match path { + "graph" => { + let mut stats = Stats::new(); + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + stats.add_id(b, task); + }); + let tree = stats.treeify(ReferenceType::Dependency); + let graph = viz::graph::visualize_stats_tree(tree, ReferenceType::Dependency); + Ok(FileContent::Content( + File::from_source(viz::graph::wrap_html(&graph)) + .with_content_type(Mime::from_str("text/html")?), + ) + .into()) + } + "call-graph" => { + let mut stats = Stats::new(); + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + stats.add_id(b, task); + }); + let tree = stats.treeify(ReferenceType::Child); + let graph = viz::graph::visualize_stats_tree(tree, ReferenceType::Child); + Ok(FileContent::Content( + File::from_source(viz::graph::wrap_html(&graph)) + .with_content_type(Mime::from_str("text/html")?), + ) + .into()) + } + "table" => { + let mut stats = Stats::new(); + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + stats.add_id(b, task); + }); + let tree = stats.treeify(ReferenceType::Dependency); + let table = viz::table::create_table(tree); + Ok(FileContent::Content( + File::from_source(viz::table::wrap_html(&table)) + .with_content_type(Mime::from_str("text/html")?), + ) + .into()) + } + _ => Ok(FileContent::NotFound.into()), } - Ok(FileContent::NotFound.into()) } #[turbo_tasks::function] From e55a098efdff40a63f69172f1fcc2b5f1c8dbdca Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Sat, 3 Sep 2022 13:38:14 +0200 Subject: [PATCH 058/672] CSS HMR (vercel/turbo#296) Implements HMR for CSS chunks and paves the way for accepting HMR updates for the HTML entry point as well. --- .../next-swc/crates/next-core/src/web_entry_source.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 93528ab10084d6..55708d1bcca83a 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -107,10 +107,10 @@ pub async fn create_web_entry_source( .try_join() .await?; - let entry_asset = DevHtmlAsset { - path: FileSystemPathVc::new(dev_server_fs, "index.html"), - chunk_groups: chunks.into_iter().map(ChunkGroupVc::from_chunk).collect(), - } + let entry_asset = DevHtmlAsset::new( + FileSystemPathVc::new(dev_server_fs, "index.html"), + chunks.into_iter().map(ChunkGroupVc::from_chunk).collect(), + ) .cell() .into(); From d78084a0b482f6994c7e4500c820ccc529cbb293 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 6 Sep 2022 08:48:01 +0200 Subject: [PATCH 059/672] Test benchmark cases in separate job (vercel/turbo#311) Move benchmark test into separate job and run them for windows and macOS too --- packages/next-swc/crates/next-dev/benches/mod.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index a670bb9ace8af4..c9b89b51e86dfd 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -100,6 +100,7 @@ impl PreparedApp { async fn dispose(self) { if let Some(mut server) = self.server { server.0.kill().unwrap(); + server.0.wait().unwrap(); } for page in self.pages { page.close().await.unwrap(); @@ -107,6 +108,16 @@ impl PreparedApp { } } +fn command(bin: &str) -> Command { + if cfg!(windows) { + let mut command = Command::new("cmd.exe"); + command.args(["/C", bin]); + command + } else { + Command::new(bin) + } +} + fn build_test(module_count: usize) -> PathBuf { let test_dir = TestAppBuilder { module_count, @@ -117,7 +128,7 @@ fn build_test(module_count: usize) -> PathBuf { .build() .unwrap(); - let npm = Command::new("npm") + let npm = command("npm") .args(["install", "--prefer-offline", "--loglevel=error"]) .current_dir(&test_dir) .output() From 80d0a86655b27ac90cd022eefa849c4a476bb3ee Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Tue, 6 Sep 2022 00:34:25 -0700 Subject: [PATCH 060/672] Basic change bench for dev server (vercel/turbo#297) This builds on vercel/turbo#240, starting up a server and then benchmarking the response to a small file change. This change does not introduce nor remove any dependencies. A followup benchmark should do so. Test Plan: cargo bench -p next-dev Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> --- packages/next-swc/crates/next-dev/Cargo.toml | 2 + .../next-swc/crates/next-dev/benches/mod.rs | 105 ++++++++++++++++-- 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index fb23c7c75a5790..2595b76716bc95 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -48,8 +48,10 @@ chromiumoxide = { version = "0.3.5", features = [ "tokio-runtime", ], default-features = false } criterion = { version = "0.3.5", features = ["async_tokio"] } +fs_extra = "1.2.0" lazy_static = "1.4.0" regex = "1.6.0" +tempfile = "3.3.0" test-generator = "0.3.0" # sync with chromiumoxide's tungstenite requirement. tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index c9b89b51e86dfd..514d2bd909ac62 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -1,5 +1,5 @@ use std::{ - fs::remove_dir_all, + fs::{self, remove_dir_all}, future::Future, io::{self, BufRead, BufReader, Write}, path::PathBuf, @@ -25,6 +25,8 @@ use tokio::runtime::Runtime; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; use turbopack_create_test_app::test_app_builder::TestAppBuilder; +static MODULE_COUNTS: &[usize] = &[100, 1_000]; + fn bench_startup(c: &mut Criterion) { let mut g = c.benchmark_group("bench_startup"); g.sample_size(10); @@ -33,13 +35,13 @@ fn bench_startup(c: &mut Criterion) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for size in [100, 1_000] { + for size in MODULE_COUNTS { g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { - let test_dir = build_test(s); + let template_dir = build_test(*s); b.to_async(&runtime).iter_batched_async( - PreparedApp::new, + || async { PreparedApp::new(template_dir.clone()).await }, |mut app| async { - app.start_server(&test_dir); + app.start_server(); let page = app.new_page(browser).await; page.wait_for_navigation().await.unwrap(); app.schedule_page_disposal(page); @@ -48,30 +50,107 @@ fn bench_startup(c: &mut Criterion) { }, |app| app.dispose(), ); - remove_dir_all(&test_dir).unwrap(); + remove_dir_all(&template_dir).unwrap(); }); } g.finish(); } + +fn bench_simple_file_change(c: &mut Criterion) { + let mut g = c.benchmark_group("bench_simple_file_change"); + g.sample_size(10); + g.measurement_time(Duration::from_secs(30)); + + let runtime = Runtime::new().unwrap(); + let browser = &runtime.block_on(create_browser()); + + for size in MODULE_COUNTS { + g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { + let template_dir = build_test(*s); + + b.to_async(Runtime::new().unwrap()).iter_batched_async( + || async { + let mut app = PreparedApp::new(template_dir.clone()).await; + app.start_server(); + let page = app.new_page(browser).await; + page.wait_for_navigation().await.unwrap(); + + (app, page) + }, + |(mut app, page)| async { + let index_path = app.test_dir.path().join("src/index.jsx"); + let mut contents = + String::from_utf8_lossy(&fs::read(&index_path).unwrap()).to_string(); + contents.push_str("globalThis.__updated = true;\n"); + fs::write(&index_path, &contents).unwrap(); + + // Wait for the change introduced above to be reflected at runtime. This expects + // HMR or automatic reloading to occur. + loop { + match page.evaluate("globalThis.__updated").await { + Ok(status_res) => { + if let Ok(status) = status_res.into_value::() { + assert!(status); + break; + } + } + Err(e) => { + if !e + .to_string() + // This error occurs when the page is reloading and is safe + // to ignore. + .contains("Cannot find context with specified id") + { + panic!("{:?}", e); + } + } + } + } + + app.schedule_page_disposal(page); + app + }, + |app| async { + app.dispose().await; + }, + ); + remove_dir_all(&template_dir).unwrap(); + }); + } +} + struct PreparedApp { + test_dir: tempfile::TempDir, server: Option<(Child, String)>, pages: Vec, } impl PreparedApp { - async fn new() -> Self { + async fn new(template_dir: PathBuf) -> Self { + let test_dir = tempfile::tempdir().unwrap(); + fs_extra::dir::copy( + &template_dir, + &test_dir, + &fs_extra::dir::CopyOptions { + content_only: true, + ..fs_extra::dir::CopyOptions::default() + }, + ) + .unwrap(); + Self { - server: None, pages: Vec::new(), + server: None, + test_dir, } } - fn start_server(&mut self, test_dir: &PathBuf) { + fn start_server(&mut self) { assert!(self.server.is_none(), "Server already started"); let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) .args([".", "--no-open", "--port", "0"]) - .current_dir(test_dir) + .current_dir(&self.test_dir) .stdout(Stdio::piped()) .spawn() .unwrap(); @@ -255,5 +334,9 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, } } -criterion_group!(benches, bench_startup); +criterion_group!( + name = benches; + config = Criterion::default(); + targets = bench_startup, bench_simple_file_change +); criterion_main!(benches); From 7d79ce5029a64451df688109f5411eefb9a75f6f Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Tue, 6 Sep 2022 01:30:08 -0700 Subject: [PATCH 061/672] Benchmark restart time for dev server (vercel/turbo#244) This implements a benchmark of restarting the devserver after successfully starting it and shutting it down. ## Question/TODO: Since our goal is metrics that don't scale with project size, should we assert that the small/medium benchmark results don't differ? Test Plan: `cargo bench -p next-dev` --- .../next-swc/crates/next-dev/benches/mod.rs | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 514d2bd909ac62..a863190b57016c 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -120,6 +120,44 @@ fn bench_simple_file_change(c: &mut Criterion) { } } +fn bench_restart(c: &mut Criterion) { + let mut g = c.benchmark_group("bench_restart"); + g.sample_size(10); + g.measurement_time(Duration::from_secs(30)); + + let runtime = Runtime::new().unwrap(); + let browser = &runtime.block_on(create_browser()); + + for size in [100, 1_000] { + g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { + let template_dir = build_test(s); + b.to_async(Runtime::new().unwrap()).iter_batched_async( + || async { + // Run a complete build, shut down, and test running it again + let mut app = PreparedApp::new(template_dir.clone()).await; + app.start_server(); + + let page = app.new_page(browser).await; + page.close().await.unwrap(); + + let mut proc = app.stop_server(); + proc.wait().unwrap(); + app + }, + |mut app| async { + app.start_server(); + let page = app.new_page(browser).await; + page.wait_for_navigation().await.unwrap(); + app.schedule_page_disposal(page); + app + }, + |app| app.dispose(), + ); + remove_dir_all(&template_dir).unwrap(); + }); + } +} + struct PreparedApp { test_dir: tempfile::TempDir, server: Option<(Child, String)>, @@ -185,6 +223,12 @@ impl PreparedApp { page.close().await.unwrap(); } } + + fn stop_server(&mut self) -> Child { + let mut proc = self.server.take().expect("Server never started").0; + proc.kill().unwrap(); + proc + } } fn command(bin: &str) -> Command { @@ -337,6 +381,6 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, criterion_group!( name = benches; config = Criterion::default(); - targets = bench_startup, bench_simple_file_change + targets = bench_startup, bench_simple_file_change, bench_restart ); criterion_main!(benches); From aab23b38daf005ea46f58787807e9dca6cab8ef3 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Tue, 6 Sep 2022 02:39:11 -0700 Subject: [PATCH 062/672] Parameterize devserver used in benchmarks (vercel/turbo#298) This implements the basics of parameterizing the tool/devserver used in these tests. Following PRs will implement benchmarking of Vite, bun, Parcel, etc. Test Plan: `cargo bench -p next-dev` and verify no change in performance. --- .../next-swc/crates/next-dev/benches/mod.rs | 287 +++++++++++------- 1 file changed, 169 insertions(+), 118 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index a863190b57016c..b22ffb22b8b0ef 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -2,7 +2,7 @@ use std::{ fs::{self, remove_dir_all}, future::Future, io::{self, BufRead, BufReader, Write}, - path::PathBuf, + path::{Path, PathBuf}, process::{Child, ChildStdout, Command, Stdio}, time::Duration, }; @@ -35,25 +35,32 @@ fn bench_startup(c: &mut Criterion) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for size in MODULE_COUNTS { - g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { - let template_dir = build_test(*s); - b.to_async(&runtime).iter_batched_async( - || async { PreparedApp::new(template_dir.clone()).await }, - |mut app| async { - app.start_server(); - let page = app.new_page(browser).await; - page.wait_for_navigation().await.unwrap(); - app.schedule_page_disposal(page); - // return the PreparedApp doesn't make dropping it part of the measurement - app + for bundler in get_bundlers() { + for module_count in MODULE_COUNTS { + let input = (bundler.as_ref(), module_count); + g.bench_with_input( + BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), + &input, + |b, &(bundler, module_count)| { + let template_dir = build_test(*module_count); + b.to_async(&runtime).iter_batched_async( + || async { PreparedApp::new(bundler, template_dir.clone()) }, + |mut app| async { + app.start_server(); + let page = app.new_page(browser).await; + page.wait_for_navigation().await.unwrap(); + app.schedule_page_disposal(page); + // return the PreparedApp doesn't make dropping it part of the + // measurement + app + }, + |app| app.dispose(), + ); + remove_dir_all(&template_dir).unwrap(); }, - |app| app.dispose(), ); - remove_dir_all(&template_dir).unwrap(); - }); + } } - g.finish(); } @@ -65,58 +72,68 @@ fn bench_simple_file_change(c: &mut Criterion) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for size in MODULE_COUNTS { - g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { - let template_dir = build_test(*s); - - b.to_async(Runtime::new().unwrap()).iter_batched_async( - || async { - let mut app = PreparedApp::new(template_dir.clone()).await; - app.start_server(); - let page = app.new_page(browser).await; - page.wait_for_navigation().await.unwrap(); - - (app, page) - }, - |(mut app, page)| async { - let index_path = app.test_dir.path().join("src/index.jsx"); - let mut contents = - String::from_utf8_lossy(&fs::read(&index_path).unwrap()).to_string(); - contents.push_str("globalThis.__updated = true;\n"); - fs::write(&index_path, &contents).unwrap(); - - // Wait for the change introduced above to be reflected at runtime. This expects - // HMR or automatic reloading to occur. - loop { - match page.evaluate("globalThis.__updated").await { - Ok(status_res) => { - if let Ok(status) = status_res.into_value::() { - assert!(status); - break; - } - } - Err(e) => { - if !e - .to_string() - // This error occurs when the page is reloading and is safe - // to ignore. - .contains("Cannot find context with specified id") - { - panic!("{:?}", e); + for bundler in get_bundlers() { + for module_count in MODULE_COUNTS { + let input = (bundler.as_ref(), module_count); + + g.bench_with_input( + BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), + &input, + |b, &(bundler, module_count)| { + let template_dir = build_test(*module_count); + + b.to_async(Runtime::new().unwrap()).iter_batched_async( + || async { + let mut app = PreparedApp::new(bundler, template_dir.clone()); + app.start_server(); + let page = app.new_page(browser).await; + page.wait_for_navigation().await.unwrap(); + (app, page) + }, + |(mut app, page)| async { + let index_path = &app.test_dir.path().join("src/index.jsx"); + let mut contents = + String::from_utf8_lossy(&fs::read(&index_path).unwrap()) + .to_string(); + contents.push_str("globalThis.__updated = true;\n"); + fs::write(&index_path, contents).unwrap(); + + // Wait for the change introduced above to be reflected at runtime. This + // expects HMR or automatic reloading to + // occur. + loop { + match page.evaluate("globalThis.__updated").await { + Ok(status_res) => { + if let Ok(status) = status_res.into_value::() { + assert!(status); + break; + } + } + Err(e) => { + if !e + .to_string() + // This error occurs when the page is reloading and is + // safe + // to ignore. + .contains("Cannot find context with specified id") + { + panic!("{:?}", e); + } + } } } - } - } - app.schedule_page_disposal(page); - app - }, - |app| async { - app.dispose().await; + app.schedule_page_disposal(page); + app + }, + |app| async { + app.dispose().await; + }, + ); + remove_dir_all(&template_dir).unwrap(); }, ); - remove_dir_all(&template_dir).unwrap(); - }); + } } } @@ -128,44 +145,100 @@ fn bench_restart(c: &mut Criterion) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for size in [100, 1_000] { - g.bench_with_input(BenchmarkId::new("modules", size), &size, |b, &s| { - let template_dir = build_test(s); - b.to_async(Runtime::new().unwrap()).iter_batched_async( - || async { - // Run a complete build, shut down, and test running it again - let mut app = PreparedApp::new(template_dir.clone()).await; - app.start_server(); - - let page = app.new_page(browser).await; - page.close().await.unwrap(); - - let mut proc = app.stop_server(); - proc.wait().unwrap(); - app + for bundler in get_bundlers() { + for module_count in MODULE_COUNTS { + let input = (bundler.as_ref(), module_count); + + g.bench_with_input( + BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), + &input, + |b, &(bundler, module_count)| { + let template_dir = build_test(*module_count); + b.to_async(Runtime::new().unwrap()).iter_batched_async( + || async { + // Run a complete build, shut down, and test running it again + let mut app = PreparedApp::new(bundler, template_dir.clone()); + app.start_server(); + + let page = app.new_page(browser).await; + page.close().await.unwrap(); + + let mut proc = app.stop_server(); + proc.wait().unwrap(); + app + }, + |mut app| async { + app.start_server(); + let page = app.new_page(browser).await; + page.wait_for_navigation().await.unwrap(); + app.schedule_page_disposal(page); + app + }, + |app| app.dispose(), + ); + remove_dir_all(&template_dir).unwrap(); }, - |mut app| async { - app.start_server(); - let page = app.new_page(browser).await; - page.wait_for_navigation().await.unwrap(); - app.schedule_page_disposal(page); - app - }, - |app| app.dispose(), ); - remove_dir_all(&template_dir).unwrap(); - }); + } } } -struct PreparedApp { - test_dir: tempfile::TempDir, - server: Option<(Child, String)>, +trait Bundler { + fn get_name(&self) -> &str; + fn start_server(&self, test_dir: &Path) -> (Child, String); +} + +struct Turbopack; +impl Bundler for Turbopack { + fn get_name(&self) -> &str { + "Turbopack" + } + + fn start_server(&self, test_dir: &Path) -> (Child, String) { + let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) + .args([test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + + // Wait for the devserver address to appear in stdout. + let addr = wait_for_match( + proc.stdout.as_mut().unwrap(), + Regex::new("server listening on: (.*)").unwrap(), + ); + + (proc, addr) + } +} + +fn get_bundlers() -> Vec> { + vec![Box::new(Turbopack {})] +} + +fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> String { + // See https://docs.rs/async-process/latest/async_process/#examples + let mut line_reader = BufReader::new(stdout).lines(); + // Read until the match appears in the buffer + let mut matched: Option = None; + while let Some(Ok(line)) = line_reader.next() { + if let Some(cap) = re.captures(&line) { + matched = Some(cap.get(1).unwrap().as_str().into()); + break; + } + } + + matched.unwrap() +} + +struct PreparedApp<'a> { + bundler: &'a dyn Bundler, pages: Vec, + server: Option<(Child, String)>, + test_dir: tempfile::TempDir, } -impl PreparedApp { - async fn new(template_dir: PathBuf) -> Self { +impl<'a> PreparedApp<'a> { + fn new(bundler: &'a dyn Bundler, template_dir: PathBuf) -> Self { let test_dir = tempfile::tempdir().unwrap(); fs_extra::dir::copy( &template_dir, @@ -178,6 +251,7 @@ impl PreparedApp { .unwrap(); Self { + bundler, pages: Vec::new(), server: None, test_dir, @@ -186,15 +260,8 @@ impl PreparedApp { fn start_server(&mut self) { assert!(self.server.is_none(), "Server already started"); - let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) - .args([".", "--no-open", "--port", "0"]) - .current_dir(&self.test_dir) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); - let addr = wait_for_addr(proc.stdout.as_mut().unwrap()); - self.server = Some((proc, addr)); + self.server = Some(self.bundler.start_server(self.test_dir.path())); } async fn new_page(&self, browser: &Browser) -> Page { @@ -283,22 +350,6 @@ async fn create_browser() -> Browser { browser } -fn wait_for_addr(stdout: &mut ChildStdout) -> String { - // See https://docs.rs/async-process/latest/async_process/#examples - let mut line_reader = BufReader::new(stdout).lines(); - let started_regex = Regex::new("server listening on: (.*)").unwrap(); - // Wait for "server listening on" message to appear before navigating there. - let mut addr: Option = None; - while let Some(Ok(line)) = line_reader.next() { - if let Some(cap) = started_regex.captures(&line) { - addr = Some(cap.get(1).unwrap().as_str().into()); - break; - } - } - - addr.unwrap() -} - trait AsyncBencherExtension { fn iter_batched_async(&mut self, setup: S, routine: R, teardown: T) where From 7df0c410fce3983d32a66cc32c75b2cb70ad5273 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 6 Sep 2022 16:02:07 +0200 Subject: [PATCH 063/672] improve HMR update performance (vercel/turbo#295) * avoid cloning Strings and reading/calling many functions when building ecmascript chunk content * introduce `ReadRef` to allow storing snapshot of a value in values * use snapshot trees to allow caching more function calls and reads Before: ``` updated in 35ms (18 tasks) updated in 34ms (18 tasks) updated in 37ms (18 tasks) updated in 31ms (18 tasks) updated in 40ms (19 tasks) updated in 37ms (18 tasks) updated in 37ms (18 tasks) updated in 34ms (18 tasks) updated in 35ms (18 tasks) updated in 52ms (18 tasks) ``` After: ``` updated in 6.105ms (19 tasks) updated in 5.279ms (18 tasks) updated in 10.471ms (19 tasks) updated in 6.863ms (18 tasks) updated in 4.593ms (18 tasks) updated in 4.173ms (18 tasks) updated in 5.352ms (18 tasks) updated in 10.69ms (18 tasks) updated in 5.065ms (18 tasks) updated in 6.309ms (19 tasks) ``` a 5x performance improvement --- .../crates/next-dev/src/turbo_tasks_viz.rs | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 8b62a6301782c0..b32bfc45037f9f 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -8,8 +8,9 @@ use turbo_tasks_memory::{ stats::{ReferenceType, Stats}, viz, MemoryBackend, }; -use turbopack_core::version::VersionedContentVc; -use turbopack_dev_server::source::{ContentSource, ContentSourceVc}; +use turbopack_dev_server::source::{ + ContentSource, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, +}; #[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new", into = "new")] pub struct TurboTasksSource { @@ -28,7 +29,7 @@ const INVALIDATION_INTERVAL: Duration = Duration::from_secs(3); #[turbo_tasks::value_impl] impl ContentSource for TurboTasksSource { #[turbo_tasks::function] - fn get(&self, path: &str) -> Result { + fn get(&self, path: &str) -> Result { let tt = &self.turbo_tasks; let invalidator = get_invalidator(); tokio::spawn({ @@ -37,7 +38,7 @@ impl ContentSource for TurboTasksSource { invalidator.invalidate(); } }); - match path { + let html = match path { "graph" => { let mut stats = Stats::new(); let b = tt.backend(); @@ -46,11 +47,7 @@ impl ContentSource for TurboTasksSource { }); let tree = stats.treeify(ReferenceType::Dependency); let graph = viz::graph::visualize_stats_tree(tree, ReferenceType::Dependency); - Ok(FileContent::Content( - File::from_source(viz::graph::wrap_html(&graph)) - .with_content_type(Mime::from_str("text/html")?), - ) - .into()) + viz::graph::wrap_html(&graph) } "call-graph" => { let mut stats = Stats::new(); @@ -60,11 +57,7 @@ impl ContentSource for TurboTasksSource { }); let tree = stats.treeify(ReferenceType::Child); let graph = viz::graph::visualize_stats_tree(tree, ReferenceType::Child); - Ok(FileContent::Content( - File::from_source(viz::graph::wrap_html(&graph)) - .with_content_type(Mime::from_str("text/html")?), - ) - .into()) + viz::graph::wrap_html(&graph) } "table" => { let mut stats = Stats::new(); @@ -74,18 +67,28 @@ impl ContentSource for TurboTasksSource { }); let tree = stats.treeify(ReferenceType::Dependency); let table = viz::table::create_table(tree); - Ok(FileContent::Content( - File::from_source(viz::table::wrap_html(&table)) - .with_content_type(Mime::from_str("text/html")?), - ) - .into()) + viz::table::wrap_html(&table) + } + "reset" => { + let b = tt.backend(); + b.with_all_cached_tasks(|task| { + b.with_task(task, |task| task.reset_stats()); + }); + "Done".to_string() } - _ => Ok(FileContent::NotFound.into()), - } + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + Ok(ContentSourceResult::Static( + FileContent::Content( + File::from_source(html).with_content_type(Mime::from_str("text/html")?), + ) + .into(), + ) + .cell()) } #[turbo_tasks::function] - fn get_by_id(&self, _id: &str) -> VersionedContentVc { - FileContent::NotFound.into() + fn get_by_id(&self, _id: &str) -> ContentSourceResultVc { + ContentSourceResult::NotFound.cell() } } From b78ede609996370e4c43faaf36c66c10688a8e27 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 6 Sep 2022 19:34:51 +0200 Subject: [PATCH 064/672] fix benchmark compare actions (vercel/turbo#318) The benchmark github action didn't correctly copy and use the executables used in benchmarks via CARGO_BIN_EXE_*. This adds a CARGO_BIN_EXE_* runtime override to the github action to allow to use correct executable. It will show correct results for next-dev benchmarks too, e. g. here an example of reverting vercel/turbo#295 ![image](https://user-images.githubusercontent.com/1365881/188696769-d393cd45-b08f-4fd5-ad69-2d38a54bcd92.png) --- packages/next-swc/crates/next-dev/benches/mod.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index b22ffb22b8b0ef..9d72afa2ac13f3 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -195,11 +195,14 @@ impl Bundler for Turbopack { } fn start_server(&self, test_dir: &Path) -> (Child, String) { - let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) - .args([test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); + let mut proc = Command::new( + std::env::var("CARGO_BIN_EXE_next-dev") + .unwrap_or_else(|_| std::env!("CARGO_BIN_EXE_next-dev").to_string()), + ) + .args([test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); // Wait for the devserver address to appear in stdout. let addr = wait_for_match( From 12e5f19a84682e2cbf0d97cc8d6e661dd8f70d65 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Tue, 6 Sep 2022 17:09:06 -0700 Subject: [PATCH 065/672] Benchmark against Vite (vercel/turbo#299) This adds a comparison against Vite to our benchmark suite, running the startup, change, and restart benchmarks. Test Plan: `cargo bench` Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + .../crates/next-dev/benches/bundlers.rs | 147 ++++++++++++++++++ .../next-swc/crates/next-dev/benches/mod.rs | 73 +-------- 3 files changed, 156 insertions(+), 65 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers.rs diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 2595b76716bc95..362dd6eb16feab 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -2,6 +2,7 @@ name = "next-dev" version = "0.1.0" edition = "2021" +autobenches = false [[bin]] name = "next-dev" diff --git a/packages/next-swc/crates/next-dev/benches/bundlers.rs b/packages/next-swc/crates/next-dev/benches/bundlers.rs new file mode 100644 index 00000000000000..dfac99b8afb5fb --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers.rs @@ -0,0 +1,147 @@ +use std::{ + env::{self, VarError}, + fs::File, + io::{self, BufRead, BufReader, Write}, + path::Path, + process::{Child, ChildStdout, Command, Stdio}, +}; + +use regex::Regex; +use tempfile::TempDir; + +pub trait Bundler { + fn get_name(&self) -> &str; + fn start_server(&self, test_dir: &Path) -> (Child, String); +} + +struct Turbopack; +impl Bundler for Turbopack { + fn get_name(&self) -> &str { + "Turbopack" + } + + fn start_server(&self, test_dir: &Path) -> (Child, String) { + let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) + .args([test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + + // Wait for the devserver address to appear in stdout. + let addr = wait_for_match( + proc.stdout.as_mut().unwrap(), + Regex::new("server listening on: (.*)").unwrap(), + ); + + (proc, addr) + } +} + +struct Vite { + install_dir: TempDir, +} + +impl Vite { + fn new() -> Self { + // Manage our own installation and avoid `npm exec`, `npx`, etc. to avoid their + // overhead influencing benchmarks. + let install_dir = tempfile::tempdir().unwrap(); + + let package_json = json::object! { + private: true, + version: "0.0.0", + dependencies: json::object! { + "vite": "3.0.9", + } + }; + + File::create(install_dir.path().join("package.json")) + .unwrap() + .write_all(package_json.pretty(2).as_bytes()) + .unwrap(); + + let npm = command("npm") + .args(["install", "--prefer-offline"]) + .current_dir(&install_dir) + .output() + .unwrap(); + + if !npm.status.success() { + io::stdout().write_all(&npm.stdout).unwrap(); + io::stderr().write_all(&npm.stderr).unwrap(); + panic!("npm install failed. See above."); + } + + Vite { install_dir } + } +} + +impl Bundler for Vite { + fn get_name(&self) -> &str { + "Vite" + } + + fn start_server(&self, test_dir: &Path) -> (Child, String) { + let mut proc = Command::new("node") + .args([ + &self + .install_dir + .path() + .join("node_modules") + .join("vite") + .join("bin") + .join("vite.js") + .to_str() + .unwrap(), + "--port", + "0", + ]) + .env("NO_COLOR", "1") + .current_dir(test_dir.to_str().unwrap()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .unwrap(); + + // Wait for the devserver address to appear in stdout. + let addr = wait_for_match( + proc.stdout.as_mut().unwrap(), + Regex::new("Local:\\s+(.*)").unwrap(), + ); + + (proc, addr) + } +} + +pub fn get_bundlers() -> Vec> { + if let Err(VarError::NotPresent) = env::var("TURBOPACK_BENCH_ALL") { + vec![Box::new(Turbopack {})] + } else { + vec![Box::new(Turbopack {}), Box::new(Vite::new())] + } +} + +fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> String { + // See https://docs.rs/async-process/latest/async_process/#examples + let mut line_reader = BufReader::new(stdout).lines(); + // Read until the match appears in the buffer + let mut matched: Option = None; + while let Some(Ok(line)) = line_reader.next() { + if let Some(cap) = re.captures(&line) { + matched = Some(cap.get(1).unwrap().as_str().into()); + break; + } + } + + matched.unwrap() +} + +pub fn command(bin: &str) -> Command { + if cfg!(windows) { + let mut command = Command::new("cmd.exe"); + command.args(["/C", bin]); + command + } else { + Command::new(bin) + } +} diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 9d72afa2ac13f3..0e289b2d7a800d 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -1,12 +1,13 @@ use std::{ fs::{self, remove_dir_all}, future::Future, - io::{self, BufRead, BufReader, Write}, - path::{Path, PathBuf}, - process::{Child, ChildStdout, Command, Stdio}, + io::{self, Write}, + path::PathBuf, + process::Child, time::Duration, }; +use bundlers::{command, get_bundlers, Bundler}; use chromiumoxide::{ browser::{Browser, BrowserConfig}, cdp::js_protocol::runtime::EventExceptionThrown, @@ -20,13 +21,14 @@ use criterion::{ AsyncBencher, BenchmarkId, Criterion, }; use futures::{FutureExt, StreamExt}; -use regex::Regex; use tokio::runtime::Runtime; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; use turbopack_create_test_app::test_app_builder::TestAppBuilder; static MODULE_COUNTS: &[usize] = &[100, 1_000]; +mod bundlers; + fn bench_startup(c: &mut Criterion) { let mut g = c.benchmark_group("bench_startup"); g.sample_size(10); @@ -67,7 +69,7 @@ fn bench_startup(c: &mut Criterion) { fn bench_simple_file_change(c: &mut Criterion) { let mut g = c.benchmark_group("bench_simple_file_change"); g.sample_size(10); - g.measurement_time(Duration::from_secs(30)); + g.measurement_time(Duration::from_secs(60)); let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); @@ -183,56 +185,6 @@ fn bench_restart(c: &mut Criterion) { } } -trait Bundler { - fn get_name(&self) -> &str; - fn start_server(&self, test_dir: &Path) -> (Child, String); -} - -struct Turbopack; -impl Bundler for Turbopack { - fn get_name(&self) -> &str { - "Turbopack" - } - - fn start_server(&self, test_dir: &Path) -> (Child, String) { - let mut proc = Command::new( - std::env::var("CARGO_BIN_EXE_next-dev") - .unwrap_or_else(|_| std::env!("CARGO_BIN_EXE_next-dev").to_string()), - ) - .args([test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); - - // Wait for the devserver address to appear in stdout. - let addr = wait_for_match( - proc.stdout.as_mut().unwrap(), - Regex::new("server listening on: (.*)").unwrap(), - ); - - (proc, addr) - } -} - -fn get_bundlers() -> Vec> { - vec![Box::new(Turbopack {})] -} - -fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> String { - // See https://docs.rs/async-process/latest/async_process/#examples - let mut line_reader = BufReader::new(stdout).lines(); - // Read until the match appears in the buffer - let mut matched: Option = None; - while let Some(Ok(line)) = line_reader.next() { - if let Some(cap) = re.captures(&line) { - matched = Some(cap.get(1).unwrap().as_str().into()); - break; - } - } - - matched.unwrap() -} - struct PreparedApp<'a> { bundler: &'a dyn Bundler, pages: Vec, @@ -297,20 +249,11 @@ impl<'a> PreparedApp<'a> { fn stop_server(&mut self) -> Child { let mut proc = self.server.take().expect("Server never started").0; proc.kill().unwrap(); + proc.wait().unwrap(); proc } } -fn command(bin: &str) -> Command { - if cfg!(windows) { - let mut command = Command::new("cmd.exe"); - command.args(["/C", bin]); - command - } else { - Command::new(bin) - } -} - fn build_test(module_count: usize) -> PathBuf { let test_dir = TestAppBuilder { module_count, From 512539821def893471f12852e9626d6ffb4f8556 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 7 Sep 2022 15:56:10 +0200 Subject: [PATCH 066/672] fix runtime code for server rendered content source (vercel/turbo#315) move transition into turbopack --- .../crates/next-core/src/next_client/mod.rs | 57 +++++++++++++++++-- .../src/next_client/runtime_reference.rs | 38 +++++++++++++ .../crates/next-core/src/react_refresh.rs | 2 +- .../next-core/src/server_rendered_source.rs | 52 ++++++++++++++--- .../crates/next-core/src/web_entry_source.rs | 24 ++++---- 5 files changed, 147 insertions(+), 26 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 9379ab847ca7b3..fe8e7cd3d96993 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -1,15 +1,27 @@ +pub(crate) mod runtime_reference; + use anyhow::{anyhow, Result}; -use turbo_tasks::ValueToString; +use serde::{Deserialize, Serialize}; +use turbo_tasks::{debug::ValueDebugFormat, trace::TraceRawVcs, ValueToString}; use turbo_tasks_fs::{File, FileContent, FileContentVc, FileSystemPathVc}; -use turbopack::ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset; +use turbopack::{ + ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, + module_options::ModuleOptionsContextVc, + transition::{Transition, TransitionVc}, + ModuleAssetContextVc, +}; use turbopack_core::{ asset::AssetVc, chunk::{ChunkableAssetVc, ChunkingContextVc}, + context::AssetContext, environment::EnvironmentVc, - transition::{Transition, TransitionVc}, + reference::{AssetReferenceVc, AssetReferencesVc}, + resolve::parse::RequestVc, wrapper_asset::WrapperAssetVc, }; +use self::runtime_reference::RuntimeAssetReferenceVc; + #[turbo_tasks::function] fn get_next_hydrater() -> FileContentVc { FileContent::Content(File::from_source( @@ -18,6 +30,12 @@ fn get_next_hydrater() -> FileContentVc { .cell() } +#[derive(ValueDebugFormat, PartialEq, Eq, TraceRawVcs, Serialize, Deserialize)] +pub enum RuntimeReference { + Request(RequestVc, FileSystemPathVc), + Reference(AssetReferenceVc), +} + /// Makes a transition into a next.js client context. /// /// It wraps the target asset with client bootstrapping hydration. It changes @@ -26,8 +44,10 @@ fn get_next_hydrater() -> FileContentVc { #[turbo_tasks::value(shared)] pub struct NextClientTransition { pub client_environment: EnvironmentVc, + pub client_module_options_context: ModuleOptionsContextVc, pub client_chunking_context: ChunkingContextVc, pub server_root: FileSystemPathVc, + pub runtime_references: Vec, } #[turbo_tasks::value_impl] @@ -43,12 +63,41 @@ impl Transition for NextClientTransition { } #[turbo_tasks::function] - async fn process_module(&self, asset: AssetVc) -> Result { + fn process_module_options_context( + &self, + _context: ModuleOptionsContextVc, + ) -> ModuleOptionsContextVc { + self.client_module_options_context + } + + #[turbo_tasks::function] + async fn process_module( + &self, + asset: AssetVc, + context: ModuleAssetContextVc, + ) -> Result { if let Some(chunkable_asset) = ChunkableAssetVc::resolve_from(asset).await? { + let runtime_references = self + .runtime_references + .iter() + .map(|r| match *r { + RuntimeReference::Request(r, context_path) => { + RuntimeAssetReferenceVc::new(context.with_context_path(context_path), r) + .as_asset_reference() + } + RuntimeReference::Reference(r) => r, + }) + .collect::>(); + let runtime_references = if runtime_references.is_empty() { + None + } else { + Some(AssetReferencesVc::cell(runtime_references)) + }; Ok(ChunkGroupFilesAsset { asset: chunkable_asset, chunking_context: self.client_chunking_context, base_path: self.server_root, + runtime_references, } .cell() .into()) diff --git a/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs b/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs new file mode 100644 index 00000000000000..e2410302829205 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs @@ -0,0 +1,38 @@ +use anyhow::Result; +use turbo_tasks::{primitives::StringVc, ValueToString}; +use turbopack::ecmascript::resolve::cjs_resolve; +use turbopack_core::{ + context::AssetContextVc, + reference::{AssetReference, AssetReferenceVc}, + resolve::{parse::RequestVc, ResolveResultVc}, +}; + +#[turbo_tasks::value(shared)] +pub struct RuntimeAssetReference { + pub context: AssetContextVc, + pub request: RequestVc, +} + +#[turbo_tasks::value_impl] +impl RuntimeAssetReferenceVc { + #[turbo_tasks::function] + pub fn new(context: AssetContextVc, request: RequestVc) -> Self { + Self::cell(RuntimeAssetReference { context, request }) + } +} + +#[turbo_tasks::value_impl] +impl AssetReference for RuntimeAssetReference { + #[turbo_tasks::function] + fn resolve_reference(&self) -> ResolveResultVc { + cjs_resolve(self.request, self.context) + } + + #[turbo_tasks::function] + async fn description(&self) -> Result { + Ok(StringVc::cell(format!( + "runtime {}", + self.request.to_string().await? + ))) + } +} diff --git a/packages/next-swc/crates/next-core/src/react_refresh.rs b/packages/next-swc/crates/next-core/src/react_refresh.rs index b365103f43db45..a56e2b54295cd3 100644 --- a/packages/next-swc/crates/next-core/src/react_refresh.rs +++ b/packages/next-swc/crates/next-core/src/react_refresh.rs @@ -13,7 +13,7 @@ use turbopack_core::{ }; #[turbo_tasks::function] -fn react_refresh_request() -> RequestVc { +pub fn react_refresh_request() -> RequestVc { RequestVc::parse_string("@next/react-refresh-utils/dist/runtime".to_string()) } diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index aab60e665751df..f0ea3f64bab972 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -1,9 +1,11 @@ use std::collections::HashMap; use anyhow::Result; -use turbo_tasks::Value; +use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; -use turbopack::ModuleAssetContextVc; +use turbopack::{ + module_options::ModuleOptionsContext, transition::TransitionsByNameVc, ModuleAssetContextVc, +}; use turbopack_core::{ chunk::dev::DevChunkingContext, context::AssetContextVc, @@ -11,17 +13,24 @@ use turbopack_core::{ BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment, }, + reference::SingleAssetReferenceVc, source_asset::SourceAssetVc, target::CompileTargetVc, - transition::TransitionsByNameVc, }; -use turbopack_dev_server::source::{ - asset_graph::AssetGraphContentSourceVc, - combined::{CombinedContentSource, CombinedContentSourceVc}, - ContentSourceVc, NoContentSourceVc, +use turbopack_dev_server::{ + html_runtime_asset::HtmlRuntimeAssetVc, + source::{ + asset_graph::AssetGraphContentSourceVc, + combined::{CombinedContentSource, CombinedContentSourceVc}, + ContentSourceVc, NoContentSourceVc, + }, }; -use crate::{next_client::NextClientTransition, server_render::asset::ServerRenderedAssetVc}; +use crate::{ + next_client::{NextClientTransition, RuntimeReference}, + react_refresh::{assert_can_resolve_react_refresh, react_refresh_request}, + server_render::asset::ServerRenderedAssetVc, +}; /// Create a content source serving the `pages` or `src/pages` directory as /// Node.js pages folder. @@ -60,10 +69,32 @@ pub async fn create_server_rendered_source( )), Value::new(EnvironmentIntention::Client), ); + let enable_react_refresh = + *assert_can_resolve_react_refresh(root_path, client_environment).await?; + let runtime_references = if enable_react_refresh { + vec![ + RuntimeReference::Request(react_refresh_request(), root_path), + RuntimeReference::Reference( + SingleAssetReferenceVc::new( + HtmlRuntimeAssetVc::new().into(), + StringVc::cell("html-runtime".to_string()), + ) + .into(), + ), + ] + } else { + Vec::new() + }; + let client_module_options_context = ModuleOptionsContext { + enable_react_refresh, + } + .cell(); let next_client_transition = NextClientTransition { client_chunking_context, + client_module_options_context, client_environment, server_root: target_root, + runtime_references, } .cell() .into(); @@ -84,7 +115,10 @@ pub async fn create_server_rendered_source( )), Value::new(EnvironmentIntention::Client), ), - Default::default(), + ModuleOptionsContext { + ..Default::default() + } + .cell(), ) .into(); diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 55708d1bcca83a..94a5517bd07004 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -6,6 +6,7 @@ use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; use turbopack::{ ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}, module_options::ModuleOptionsContext, + transition::TransitionsByNameVc, ModuleAssetContextVc, }; use turbopack_core::{ @@ -16,10 +17,10 @@ use turbopack_core::{ context::AssetContextVc, environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, resolve::parse::RequestVc, - transition::TransitionsByNameVc, }; use turbopack_dev_server::{ html::DevHtmlAsset, + html_runtime_asset::HtmlRuntimeAssetVc, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; @@ -45,7 +46,7 @@ pub async fn create_web_entry_source( Value::new(EnvironmentIntention::Client), ); - let can_resolve_react_refresh = *assert_can_resolve_react_refresh(root, environment).await?; + let enable_react_refresh = *assert_can_resolve_react_refresh(root, environment).await?; let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -55,7 +56,7 @@ pub async fn create_web_entry_source( // We don't need to resolve React Refresh for each module. Instead, // we try resolve it once at the root and pass down a context to all // the modules. - enable_react_refresh: can_resolve_react_refresh, + enable_react_refresh, } .into(), ) @@ -68,13 +69,11 @@ pub async fn create_web_entry_source( } .into(); - let runtime_entries = if can_resolve_react_refresh { - Some(EcmascriptChunkPlaceablesVc::cell(vec![ - resolve_react_refresh(context), - ])) - } else { - None - }; + let mut runtime_entries = vec![HtmlRuntimeAssetVc::new().as_ecmascript_chunk_placeable()]; + if enable_react_refresh { + runtime_entries.push(resolve_react_refresh(context)) + } + let runtime_entries = EcmascriptChunkPlaceablesVc::cell(runtime_entries); let modules = entry_requests .into_iter() @@ -92,8 +91,10 @@ pub async fn create_web_entry_source( let chunks = modules .map(|module| async move { if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { - Ok(ecmascript.as_evaluated_chunk(chunking_context.into(), runtime_entries)) + Ok(ecmascript.as_evaluated_chunk(chunking_context.into(), Some(runtime_entries))) } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { + // TODO this is missing runtime code, so it's probably broken and we should also + // add an ecmascript chunk with the runtime code Ok(chunkable.as_chunk(chunking_context.into())) } else { // TODO convert into a serve-able asset @@ -102,7 +103,6 @@ pub async fn create_web_entry_source( application" )) } - // ChunkGroupVc::from_chunk(m) }) .try_join() .await?; From abcdd786234998a4ae63c592c80ee793d7c78e1d Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 7 Sep 2022 22:00:32 -0700 Subject: [PATCH 067/672] Benchmark Next.js 11 and 12 (vercel/turbo#304) This implements benchmark support for Next.js 12. Next.js (the tool) expects to be able to resolve from the `next` package in the cwd, so it must be installed alongside the other node_modules in the test. `prepare` was added to the Bundler trait to handle this case. Test Plan: `TURBOPACK_BENCH_ALL=all cargo bench -p next-dev` Co-authored-by: Alex Kirszenberg <1621758+alexkirsz@users.noreply.github.com> Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> --- packages/next-swc/crates/next-dev/Cargo.toml | 2 + .../crates/next-dev/benches/bundlers.rs | 257 ++++++--- .../next-swc/crates/next-dev/benches/mod.rs | 501 ++++++++++++------ 3 files changed, 539 insertions(+), 221 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 362dd6eb16feab..b92e3985d55c98 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -33,6 +33,7 @@ futures = "0.3.21" json = "0.12.4" mime = "0.3.16" next-core = { path = "../next-core" } +portpicker = "0.1.1" serde = "1.0.136" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } @@ -42,6 +43,7 @@ turbopack = { path = "../turbopack" } turbopack-cli-utils = { path = "../turbopack-cli-utils" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } +url = "2.3.0" webbrowser = "0.7.1" [dev-dependencies] diff --git a/packages/next-swc/crates/next-dev/benches/bundlers.rs b/packages/next-swc/crates/next-dev/benches/bundlers.rs index dfac99b8afb5fb..964aa0d6adf31d 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers.rs @@ -1,39 +1,71 @@ use std::{ - env::{self, VarError}, - fs::File, + fs::{self, File}, io::{self, BufRead, BufReader, Write}, path::Path, process::{Child, ChildStdout, Command, Stdio}, }; +use anyhow::{anyhow, Context, Result}; use regex::Regex; use tempfile::TempDir; pub trait Bundler { fn get_name(&self) -> &str; - fn start_server(&self, test_dir: &Path) -> (Child, String); + fn get_path(&self) -> &str { + "/" + } + fn prepare(&self, _template_dir: &Path) -> Result<()> { + Ok(()) + } + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)>; +} + +struct Turbopack { + name: String, + path: String, +} + +impl Turbopack { + fn new(name: &str, path: &str) -> Self { + Turbopack { + name: name.to_owned(), + path: path.to_owned(), + } + } } -struct Turbopack; impl Bundler for Turbopack { fn get_name(&self) -> &str { - "Turbopack" + &self.name + } + + fn get_path(&self) -> &str { + &self.path } - fn start_server(&self, test_dir: &Path) -> (Child, String) { + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) - .args([test_dir.to_str().unwrap(), "--no-open", "--port", "0"]) + .args([ + test_dir + .to_str() + .ok_or_else(|| anyhow!("failed to convert test directory path to string"))?, + "--no-open", + "--port", + "0", + ]) .stdout(Stdio::piped()) - .spawn() - .unwrap(); + .spawn()?; // Wait for the devserver address to appear in stdout. let addr = wait_for_match( - proc.stdout.as_mut().unwrap(), - Regex::new("server listening on: (.*)").unwrap(), - ); + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("server listening on: (.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; - (proc, addr) + Ok((proc, addr)) } } @@ -42,49 +74,26 @@ struct Vite { } impl Vite { - fn new() -> Self { + fn new() -> Result { // Manage our own installation and avoid `npm exec`, `npx`, etc. to avoid their // overhead influencing benchmarks. - let install_dir = tempfile::tempdir().unwrap(); - - let package_json = json::object! { - private: true, - version: "0.0.0", - dependencies: json::object! { - "vite": "3.0.9", - } - }; + let install_dir = tempfile::tempdir()?; + install_from_npm(install_dir.path(), "vite", "3.0.9") + .context("failed to install `vite` module")?; - File::create(install_dir.path().join("package.json")) - .unwrap() - .write_all(package_json.pretty(2).as_bytes()) - .unwrap(); - - let npm = command("npm") - .args(["install", "--prefer-offline"]) - .current_dir(&install_dir) - .output() - .unwrap(); - - if !npm.status.success() { - io::stdout().write_all(&npm.stdout).unwrap(); - io::stderr().write_all(&npm.stderr).unwrap(); - panic!("npm install failed. See above."); - } - - Vite { install_dir } + Ok(Vite { install_dir }) } } impl Bundler for Vite { fn get_name(&self) -> &str { - "Vite" + "Vite CSR" } - fn start_server(&self, test_dir: &Path) -> (Child, String) { + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { let mut proc = Command::new("node") .args([ - &self + (self .install_dir .path() .join("node_modules") @@ -92,36 +101,128 @@ impl Bundler for Vite { .join("bin") .join("vite.js") .to_str() - .unwrap(), + .unwrap()), "--port", "0", ]) .env("NO_COLOR", "1") - .current_dir(test_dir.to_str().unwrap()) + .current_dir(test_dir) .stdout(Stdio::piped()) .stderr(Stdio::inherit()) .spawn() - .unwrap(); + .context("failed to run `vite` command")?; - // Wait for the devserver address to appear in stdout. let addr = wait_for_match( - proc.stdout.as_mut().unwrap(), - Regex::new("Local:\\s+(.*)").unwrap(), - ); + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("Local:\\s+(.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; - (proc, addr) + Ok((proc, addr)) } } -pub fn get_bundlers() -> Vec> { - if let Err(VarError::NotPresent) = env::var("TURBOPACK_BENCH_ALL") { - vec![Box::new(Turbopack {})] - } else { - vec![Box::new(Turbopack {}), Box::new(Vite::new())] +struct NextJs { + version: u32, + name: String, +} + +impl NextJs { + fn new(version: u32) -> Self { + Self { + version, + name: format!("Next.js {version} SSR"), + } } } -fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> String { +impl Bundler for NextJs { + fn get_name(&self) -> &str { + &self.name + } + + fn get_path(&self) -> &str { + "/page" + } + + fn prepare(&self, install_dir: &Path) -> Result<()> { + install_from_npm(install_dir, "next", &format!("^{}", self.version)) + .context("failed to install `next` module")?; + Ok(()) + } + + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { + // Using `node_modules/.bin/next` would sometimes error with `Error: Cannot find + // module '../build/output/log'` + let mut proc = Command::new("node") + .args([ + test_dir + .join("node_modules") + .join("next") + .join("dist") + .join("bin") + .join("next") + .to_str() + .unwrap(), + "dev", + "--port", + // Next.js currently has a bug where requests for port 0 are ignored and it falls + // back to the default 3000. Use portpicker instead. + &portpicker::pick_unused_port() + .ok_or_else(|| anyhow!("failed to pick unused port"))? + .to_string(), + ]) + .current_dir(test_dir) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .context("failed to run `next` command")?; + + let addr = wait_for_match( + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("started server.*url: (.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; + + Ok((proc, format!("{addr}/page"))) + } +} + +pub fn get_bundlers() -> Result>> { + let config = std::env::var("TURBOPACK_BENCH_BUNDLERS").ok(); + let mut turbopack = false; + let mut others = false; + match config.as_deref() { + Some("all") => { + turbopack = true; + others = true + } + Some("others") => others = true, + None | Some("") => { + turbopack = true; + } + _ => panic!("Invalid value for TURBOPACK_BENCH_BUNDLERS"), + } + let mut bundlers: Vec> = Vec::new(); + if turbopack { + bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/"))); + bundlers.push(Box::new(Turbopack::new("Turbopack SSR", "/page"))); + } + + if others { + bundlers.push(Box::new(Vite::new()?)); + bundlers.push(Box::new(NextJs::new(12))); + bundlers.push(Box::new(NextJs::new(11))); + } + + Ok(bundlers) +} + +fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> Option { // See https://docs.rs/async-process/latest/async_process/#examples let mut line_reader = BufReader::new(stdout).lines(); // Read until the match appears in the buffer @@ -133,7 +234,7 @@ fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> String { } } - matched.unwrap() + matched } pub fn command(bin: &str) -> Command { @@ -145,3 +246,41 @@ pub fn command(bin: &str) -> Command { Command::new(bin) } } + +fn install_from_npm( + install_dir: &Path, + package_name: &str, + package_version_expr: &str, +) -> Result<()> { + if !fs::metadata(install_dir.join("package.json")) + .map(|metadata| metadata.is_file()) + .unwrap_or(false) + { + // Create a simple package.json if one doesn't exist + + let package_json = json::object! { + private: true, + version: "0.0.0", + }; + + File::create(install_dir.join("package.json"))? + .write_all(package_json.pretty(2).as_bytes())?; + } + + let npm = command("npm") + .args([ + "install", + "--force", + &format!("{}@{}", package_name, package_version_expr), + ]) + .current_dir(install_dir) + .output()?; + + if !npm.status.success() { + io::stdout().write_all(&npm.stdout)?; + io::stderr().write_all(&npm.stderr)?; + return Err(anyhow!("npm install failed. See above.")); + } + + Ok(()) +} diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 0e289b2d7a800d..a9ae435d202e45 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -1,64 +1,179 @@ use std::{ - fs::{self, remove_dir_all}, + fs::{self}, future::Future, io::{self, Write}, - path::PathBuf, + path::{Path, PathBuf}, process::Child, time::Duration, }; +use anyhow::{anyhow, Context, Result}; use bundlers::{command, get_bundlers, Bundler}; use chromiumoxide::{ browser::{Browser, BrowserConfig}, - cdp::js_protocol::runtime::EventExceptionThrown, + cdp::js_protocol::runtime::{AddBindingParams, EventBindingCalled, EventExceptionThrown}, error::CdpError::Ws, + listeners::EventStream, Page, }; use criterion::{ async_executor::AsyncExecutor, black_box, criterion_group, criterion_main, measurement::{Measurement, WallTime}, - AsyncBencher, BenchmarkId, Criterion, + AsyncBencher, BenchmarkGroup, BenchmarkId, Criterion, }; use futures::{FutureExt, StreamExt}; -use tokio::runtime::Runtime; +use tokio::{ + runtime::Runtime, + time::{sleep, timeout}, +}; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; -use turbopack_create_test_app::test_app_builder::TestAppBuilder; - -static MODULE_COUNTS: &[usize] = &[100, 1_000]; +use turbopack_create_test_app::test_app_builder::{TestApp, TestAppBuilder}; +use url::Url; mod bundlers; +const BINDING_NAME: &str = "__turbopackBenchBinding"; +const TEST_APP_HYDRATION_DONE: &str = "Hydration done"; + +const MAX_UPDATE_TIMEOUT: Duration = Duration::from_secs(20); +const MAX_HYDRATION_TIMEOUT: Duration = Duration::from_secs(30); + +fn get_module_counts() -> &'static [usize] { + let config = std::env::var("TURBOPACK_BENCH_COUNTS").ok(); + match config.as_deref() { + Some("all") => { + static C: &[usize] = &[100, 500, 1_000, 2_000]; + C + } + Some("others") => { + static C: &[usize] = &[500, 2_000]; + C + } + None | Some("") => { + static C: &[usize] = &[100, 1_000]; + C + } + _ => panic!("Invalid value for TURBOPACK_BENCH_COUNTS"), + } +} + +fn retry(mut args: A, f: F, max_retries: usize, mut timeout: Duration) -> Result +where + F: Fn(&mut A) -> Result, +{ + let mut retries = 0usize; + loop { + match f(&mut args) { + Ok(value) => return Ok(value), + Err(e) => { + if retries >= max_retries { + return Err(e); + } + retries += 1; + std::thread::sleep(timeout); + timeout += timeout; + } + } + } +} + +fn retry_default(args: A, f: F) -> Result +where + F: Fn(&mut A) -> Result, +{ + // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total + retry(args, f, 5, Duration::from_secs(5)) +} + +async fn retry_async( + mut args: A, + f: F, + max_retries: usize, + mut timeout: Duration, +) -> Result +where + F: Fn(&mut A) -> Fut, + Fut: Future>, +{ + let mut retries = 0usize; + loop { + match f(&mut args).await { + Ok(value) => return Ok(value), + Err(e) => { + if retries >= max_retries { + return Err(e); + } + retries += 1; + tokio::time::sleep(timeout).await; + timeout += timeout; + } + } + } +} + +async fn retry_async_default(args: A, f: F) -> Result +where + F: Fn(&mut A) -> Fut, + Fut: Future>, +{ + // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total + retry_async(args, f, 5, Duration::from_secs(5)).await +} + fn bench_startup(c: &mut Criterion) { let mut g = c.benchmark_group("bench_startup"); g.sample_size(10); g.measurement_time(Duration::from_secs(80)); + bench_startup_internal(g, false); +} + +fn bench_hydration(c: &mut Criterion) { + let mut g = c.benchmark_group("bench_hydration"); + g.sample_size(10); + g.measurement_time(Duration::from_secs(80)); + + bench_startup_internal(g, true); +} + +fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: bool) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for bundler in get_bundlers() { - for module_count in MODULE_COUNTS { + for bundler in retry_default((), |_| get_bundlers()).expect("failed to get bundlers") { + for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); g.bench_with_input( BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, module_count)| { - let template_dir = build_test(*module_count); - b.to_async(&runtime).iter_batched_async( - || async { PreparedApp::new(bundler, template_dir.clone()) }, + let test_app = build_test(*module_count, bundler); + let template_dir = test_app.path(); + b.to_async(&runtime).try_iter_async( + || async { PreparedApp::new(bundler, template_dir.to_path_buf()) }, |mut app| async { - app.start_server(); - let page = app.new_page(browser).await; - page.wait_for_navigation().await.unwrap(); + app.start_server()?; + let (page, mut events) = app.new_page(browser).await?; + page.wait_for_navigation().await?; + if wait_for_hydration { + timeout( + MAX_HYDRATION_TIMEOUT, + wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + ) + .await??; + } app.schedule_page_disposal(page); // return the PreparedApp doesn't make dropping it part of the // measurement - app + Ok(app) + }, + |app| async move { + if let Err(err) = app.dispose().await { + eprintln!("error disposing app: {}", err); + } }, - |app| app.dispose(), ); - remove_dir_all(&template_dir).unwrap(); }, ); } @@ -74,111 +189,163 @@ fn bench_simple_file_change(c: &mut Criterion) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for bundler in get_bundlers() { - for module_count in MODULE_COUNTS { + for bundler in retry_default((), |_| get_bundlers()).expect("failed to get bundlers") { + for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); g.bench_with_input( BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, module_count)| { - let template_dir = build_test(*module_count); - - b.to_async(Runtime::new().unwrap()).iter_batched_async( + let test_app = build_test(*module_count, bundler); + let template_dir = test_app.path(); + fn add_code<'a>(app: &mut PreparedApp<'a>, code: &str) -> Result<()> { + let triangle_path = app.path().join("src/triangle.jsx"); + let mut contents = fs::read_to_string(&triangle_path)?; + const COMPONENT_START: &str = + "export default function Container({ style }) {\n"; + let a = contents + .find(COMPONENT_START) + .ok_or_else(|| anyhow!("unable to find component start"))?; + let b = contents + .find("\n return <>") + .ok_or_else(|| anyhow!("unable to find component start"))?; + contents.replace_range(a..b, &format!("{COMPONENT_START}{code}")); + fs::write(&triangle_path, contents)?; + Ok(()) + } + async fn make_change<'a>( + app: &mut PreparedApp<'a>, + events: &mut EventStream, + ) -> Result<()> { + let msg = format!("TURBOPACK_BENCH_CHANGE_{}", app.counter()); + add_code( + app, + &format!( + " React.useEffect(() => {{ globalThis.{BINDING_NAME}('{msg}'); \ + }});\n" + ), + )?; + + // Wait for the change introduced above to be reflected at runtime. + // This expects HMR or automatic reloading to occur. + timeout(MAX_UPDATE_TIMEOUT, wait_for_binding(events, &msg)) + .await? + .context("update was not registered by bundler")?; + + Ok(()) + } + b.to_async(Runtime::new().unwrap()).try_iter_async( || async { - let mut app = PreparedApp::new(bundler, template_dir.clone()); - app.start_server(); - let page = app.new_page(browser).await; - page.wait_for_navigation().await.unwrap(); - (app, page) + let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; + app.start_server()?; + let (page, mut events) = app.new_page(browser).await?; + + page.wait_for_navigation().await?; + timeout( + MAX_HYDRATION_TIMEOUT, + wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + ) + .await??; + // Make warmup change + make_change(&mut app, &mut events).await?; + + Ok((app, page, events)) }, - |(mut app, page)| async { - let index_path = &app.test_dir.path().join("src/index.jsx"); - let mut contents = - String::from_utf8_lossy(&fs::read(&index_path).unwrap()) - .to_string(); - contents.push_str("globalThis.__updated = true;\n"); - fs::write(&index_path, contents).unwrap(); - - // Wait for the change introduced above to be reflected at runtime. This - // expects HMR or automatic reloading to - // occur. - loop { - match page.evaluate("globalThis.__updated").await { - Ok(status_res) => { - if let Ok(status) = status_res.into_value::() { - assert!(status); - break; - } - } - Err(e) => { - if !e - .to_string() - // This error occurs when the page is reloading and is - // safe - // to ignore. - .contains("Cannot find context with specified id") - { - panic!("{:?}", e); - } - } - } - } + |(mut app, page, mut events)| async move { + make_change(&mut app, &mut events).await?; app.schedule_page_disposal(page); - app + + Ok(app) }, - |app| async { - app.dispose().await; + |app| async move { + if let Err(err) = app.dispose().await { + eprintln!("error disposing app: {}", err); + } }, ); - remove_dir_all(&template_dir).unwrap(); }, ); } } } +async fn wait_for_binding( + events: &mut EventStream, + payload: &str, +) -> Result<()> { + while let Some(event) = events.next().await { + if event.name == BINDING_NAME && event.payload == payload { + return Ok(()); + } + } + + Err(anyhow!("event stream ended before binding was called")) +} + +/// Adds benchmark-specific bindings to the page. +async fn add_binding(page: &Page) -> Result<()> { + page.execute(AddBindingParams::new(BINDING_NAME)).await?; + Ok(()) +} + fn bench_restart(c: &mut Criterion) { let mut g = c.benchmark_group("bench_restart"); g.sample_size(10); - g.measurement_time(Duration::from_secs(30)); + g.measurement_time(Duration::from_secs(60)); let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for bundler in get_bundlers() { - for module_count in MODULE_COUNTS { + for bundler in retry_default((), |_| get_bundlers()).expect("failed to get bundlers") { + for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); g.bench_with_input( BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, module_count)| { - let template_dir = build_test(*module_count); - b.to_async(Runtime::new().unwrap()).iter_batched_async( + let test_app = build_test(*module_count, bundler); + let template_dir = test_app.path(); + b.to_async(Runtime::new().unwrap()).try_iter_async( || async { // Run a complete build, shut down, and test running it again - let mut app = PreparedApp::new(bundler, template_dir.clone()); - app.start_server(); - - let page = app.new_page(browser).await; - page.close().await.unwrap(); - - let mut proc = app.stop_server(); - proc.wait().unwrap(); - app + let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; + app.start_server()?; + let (page, mut events) = app.new_page(browser).await?; + page.wait_for_navigation().await?; + timeout( + MAX_HYDRATION_TIMEOUT, + wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + ) + .await??; + page.close().await?; + + // Give it 4 seconds time to store the cache + sleep(Duration::from_secs(4)).await; + + app.stop_server()?; + Ok(app) }, |mut app| async { - app.start_server(); - let page = app.new_page(browser).await; - page.wait_for_navigation().await.unwrap(); + app.start_server()?; + let (page, mut events) = app.new_page(browser).await?; + page.wait_for_navigation().await?; + timeout( + MAX_HYDRATION_TIMEOUT, + wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + ) + .await??; app.schedule_page_disposal(page); - app + Ok(app) + }, + |app| async move { + if let Err(err) = app.dispose().await { + eprintln!("error disposing app: {}", err); + } }, - |app| app.dispose(), ); - remove_dir_all(&template_dir).unwrap(); }, ); } @@ -190,11 +357,13 @@ struct PreparedApp<'a> { pages: Vec, server: Option<(Child, String)>, test_dir: tempfile::TempDir, + counter: usize, } impl<'a> PreparedApp<'a> { - fn new(bundler: &'a dyn Bundler, template_dir: PathBuf) -> Self { - let test_dir = tempfile::tempdir().unwrap(); + fn new(bundler: &'a dyn Bundler, template_dir: PathBuf) -> Result { + let test_dir = tempfile::tempdir()?; + fs_extra::dir::copy( &template_dir, &test_dir, @@ -202,60 +371,78 @@ impl<'a> PreparedApp<'a> { content_only: true, ..fs_extra::dir::CopyOptions::default() }, - ) - .unwrap(); + )?; - Self { + Ok(Self { bundler, pages: Vec::new(), server: None, test_dir, - } + counter: 0, + }) + } + + fn counter(&mut self) -> usize { + self.counter += 1; + self.counter } - fn start_server(&mut self) { + fn start_server(&mut self) -> Result<()> { assert!(self.server.is_none(), "Server already started"); - self.server = Some(self.bundler.start_server(self.test_dir.path())); + self.server = Some(self.bundler.start_server(self.test_dir.path())?); + + Ok(()) } - async fn new_page(&self, browser: &Browser) -> Page { - let server = self.server.as_ref().expect("Server must be started"); - let page = browser.new_page("about:blank").await.unwrap(); - let mut errors = page.event_listener::().await.unwrap(); + async fn new_page(&self, browser: &Browser) -> Result<(Page, EventStream)> { + let server = self.server.as_ref().context("Server must be started")?; + let page = browser.new_page("about:blank").await?; + // Bindings survive page reloads. Set them up as early as possible. + add_binding(&page).await?; + + let mut errors = page.event_listener::().await?; + let binding_events = page.event_listener::().await?; - page.goto(&server.1).await.unwrap(); + let destination = Url::parse(&server.1)?.join(self.bundler.get_path())?; + page.goto(destination).await?; // Make sure no runtime errors occurred when loading the page assert!(errors.next().now_or_never().is_none()); - page + Ok((page, binding_events)) } fn schedule_page_disposal(&mut self, page: Page) { self.pages.push(page); } - async fn dispose(self) { + async fn dispose(self) -> Result<()> { if let Some(mut server) = self.server { - server.0.kill().unwrap(); - server.0.wait().unwrap(); + server.0.kill()?; + server.0.wait()?; } for page in self.pages { - page.close().await.unwrap(); + page.close().await?; } + Ok(()) } - fn stop_server(&mut self) -> Child { + fn stop_server(&mut self) -> Result<()> { let mut proc = self.server.take().expect("Server never started").0; - proc.kill().unwrap(); - proc.wait().unwrap(); - proc + proc.kill()?; + proc.wait()?; + + Ok(()) + } + + fn path(&self) -> &Path { + self.test_dir.path() } } -fn build_test(module_count: usize) -> PathBuf { - let test_dir = TestAppBuilder { +fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { + let test_app = TestAppBuilder { module_count, directories_count: module_count / 20, package_json: true, @@ -266,7 +453,7 @@ fn build_test(module_count: usize) -> PathBuf { let npm = command("npm") .args(["install", "--prefer-offline", "--loglevel=error"]) - .current_dir(&test_dir) + .current_dir(&test_app.path()) .output() .unwrap(); @@ -276,7 +463,9 @@ fn build_test(module_count: usize) -> PathBuf { panic!("npm install failed. See above."); } - test_dir + retry_default((), |_| bundler.prepare(test_app.path())).unwrap(); + + test_app } async fn create_browser() -> Browser { @@ -297,80 +486,68 @@ async fn create_browser() -> Browser { } trait AsyncBencherExtension { - fn iter_batched_async(&mut self, setup: S, routine: R, teardown: T) + fn try_iter_async(&mut self, setup: S, routine: R, teardown: T) where S: Fn() -> SF, - SF: Future, + SF: Future>, R: Fn(I) -> F, - F: Future, + F: Future>, T: Fn(O) -> TF, TF: Future; } impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, WallTime> { #[inline(never)] - fn iter_batched_async(&mut self, setup: S, routine: R, teardown: T) + fn try_iter_async(&mut self, setup: S, routine: R, teardown: T) where S: Fn() -> SF, - SF: Future, + SF: Future>, R: Fn(I) -> F, - F: Future, + F: Future>, T: Fn(O) -> TF, TF: Future, { let setup = &setup; let routine = &routine; let teardown = &teardown; - self.iter_custom(|iters| { - async move { - let batch_size = std::cmp::min(iters, 50); - let measurement = WallTime; - let mut value = measurement.zero(); - - if batch_size == 1 { - for _ in 0..iters { - let input = black_box(setup().await); - - let start = measurement.start(); - let output = routine(input).await; - let end = measurement.end(start); - value = measurement.add(&value, &end); - - teardown(black_box(output)).await; - } - } else { - let mut iteration_counter = 0; - - while iteration_counter < iters { - let batch_size = std::cmp::min(batch_size, iters - iteration_counter); + self.iter_custom(|iters| async move { + let measurement = WallTime; + let mut value = measurement.zero(); + + let mut iter = 0u64; + let mut failures = 0u64; + while iter < iters { + let output = loop { + let input = black_box( + retry_async_default((), |_| setup()) + .await + .expect("failed to setup"), + ); - let inputs = black_box({ - let mut inputs = Vec::new(); - for _ in 0..batch_size { - inputs.push(setup().await) - } - inputs - }); - let mut outputs = Vec::with_capacity(batch_size as usize); - - let start = measurement.start(); - // Can't use .extend here like the sync version does - for input in inputs { - outputs.push(routine(input).await); + let start = measurement.start(); + match routine(input).await { + Ok(output) => { + let duration = measurement.end(start); + value = measurement.add(&value, &duration); + iter += 1; + break output; } - let end = measurement.end(start); - value = measurement.add(&value, &end); - - for output in black_box(outputs) { - teardown(output).await; + Err(err) => { + failures += 1; + if failures > iters { + panic!("Routine failed {failures} times, aborting\n{:?}", err) + } else { + eprintln!("Routine failed, will be retried: {:?}", err); + continue; + } } - - iteration_counter += batch_size; } - } + }; - value + teardown(black_box(output)).await; } + + value }) } } @@ -378,6 +555,6 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, criterion_group!( name = benches; config = Criterion::default(); - targets = bench_startup, bench_simple_file_change, bench_restart + targets = bench_startup, bench_hydration, bench_simple_file_change, bench_restart ); criterion_main!(benches); From dd217c71b95b83ccb6fe5557346ffe544bc58125 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 8 Sep 2022 04:08:25 -0700 Subject: [PATCH 068/672] Benchmark Parcel (vercel/turbo#322) * Benchmark Parcel * add Parcel to the CI benchmarks * move some turbopack dependencies to the bundler as they conflict with other bundlers Co-authored-by: Tobias Koppers --- .../crates/next-dev/benches/bundlers.rs | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers.rs b/packages/next-swc/crates/next-dev/benches/bundlers.rs index 964aa0d6adf31d..143175be8d4fe2 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers.rs @@ -43,6 +43,14 @@ impl Bundler for Turbopack { &self.path } + fn prepare(&self, install_dir: &Path) -> Result<()> { + install_from_npm(install_dir, "react-refresh", "^0.12.0") + .context("failed to install `parcel` module")?; + install_from_npm(install_dir, "@next/react-refresh-utils", "^12.2.5") + .context("failed to install `process` module")?; + Ok(()) + } + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) .args([ @@ -69,6 +77,57 @@ impl Bundler for Turbopack { } } +struct Parcel; +impl Bundler for Parcel { + fn get_name(&self) -> &str { + "Parcel CSR" + } + + fn prepare(&self, install_dir: &Path) -> Result<()> { + install_from_npm(install_dir, "parcel", "2.7.0") + .context("failed to install `parcel` module")?; + + // `process` would otherwise be auto-installed by Parcel. Do this in advance as + // to not influence the benchmark. + install_from_npm(install_dir, "process", "^0.11.0") + .context("failed to install `process` module")?; + Ok(()) + } + + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { + let mut proc = Command::new("node") + .args([ + (test_dir + .join("node_modules") + .join("parcel") + .join("lib") + .join("bin.js") + .to_str() + .unwrap()), + "--port", + &portpicker::pick_unused_port() + .ok_or_else(|| anyhow!("failed to pick unused port"))? + .to_string(), + "index.html", + ]) + .current_dir(test_dir) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .context("failed to run `parcel` command")?; + + let addr = wait_for_match( + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("Server running at\\s+(.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; + + Ok((proc, addr)) + } +} + struct Vite { install_dir: TempDir, } @@ -214,6 +273,7 @@ pub fn get_bundlers() -> Result>> { } if others { + bundlers.push(Box::new(Parcel {})); bundlers.push(Box::new(Vite::new()?)); bundlers.push(Box::new(NextJs::new(12))); bundlers.push(Box::new(NextJs::new(11))); From 6f0fc67cab0dc1775bce7406869e51ac80eaebc2 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Thu, 8 Sep 2022 14:00:19 +0200 Subject: [PATCH 069/672] Stop processes gracefully when possible, add drop guard to pages (vercel/turbo#328) --- packages/next-swc/crates/next-dev/Cargo.toml | 3 + .../next-swc/crates/next-dev/benches/mod.rs | 162 ++++++++++++------ 2 files changed, 117 insertions(+), 48 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index b92e3985d55c98..d5a658d94a86f1 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -60,5 +60,8 @@ test-generator = "0.3.0" tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in turbopack-create-test-app = { path = "../turbopack-create-test-app" } +[target.'cfg(unix)'.dev-dependencies] +nix = "0.25.0" + [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index a9ae435d202e45..a8a273537edc06 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -154,8 +154,8 @@ fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: b || async { PreparedApp::new(bundler, template_dir.to_path_buf()) }, |mut app| async { app.start_server()?; - let (page, mut events) = app.new_page(browser).await?; - page.wait_for_navigation().await?; + let (guard, mut events) = app.new_page(browser).await?; + guard.page().wait_for_navigation().await?; if wait_for_hydration { timeout( MAX_HYDRATION_TIMEOUT, @@ -163,14 +163,13 @@ fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: b ) .await??; } - app.schedule_page_disposal(page); // return the PreparedApp doesn't make dropping it part of the // measurement - Ok(app) + Ok((app, guard)) }, - |app| async move { - if let Err(err) = app.dispose().await { - eprintln!("error disposing app: {}", err); + |(_app, guard)| async move { + if let Err(e) = guard.close_page().await { + eprintln!("failed to close page: {:?}", e); } }, ); @@ -239,29 +238,28 @@ fn bench_simple_file_change(c: &mut Criterion) { || async { let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; app.start_server()?; - let (page, mut events) = app.new_page(browser).await?; - - page.wait_for_navigation().await?; + let (guard, mut events) = app.new_page(browser).await?; + guard.page().wait_for_navigation().await?; timeout( MAX_HYDRATION_TIMEOUT, wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), ) .await??; + // Make warmup change make_change(&mut app, &mut events).await?; - Ok((app, page, events)) + Ok((app, guard, events)) }, - |(mut app, page, mut events)| async move { + |(mut app, guard, mut events)| async move { make_change(&mut app, &mut events).await?; - app.schedule_page_disposal(page); - - Ok(app) + // Defer the dropping of the app and the page guard to `teardown`. + Ok((app, guard)) }, - |app| async move { - if let Err(err) = app.dispose().await { - eprintln!("error disposing app: {}", err); + |(_app, guard)| async move { + if let Err(err) = guard.close_page().await { + eprintln!("failed to close page: {:?}", err); } }, ); @@ -313,14 +311,14 @@ fn bench_restart(c: &mut Criterion) { // Run a complete build, shut down, and test running it again let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; app.start_server()?; - let (page, mut events) = app.new_page(browser).await?; - page.wait_for_navigation().await?; + let (guard, mut events) = app.new_page(browser).await?; + guard.page().wait_for_navigation().await?; timeout( MAX_HYDRATION_TIMEOUT, wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), ) .await??; - page.close().await?; + guard.close_page().await?; // Give it 4 seconds time to store the cache sleep(Duration::from_secs(4)).await; @@ -330,19 +328,18 @@ fn bench_restart(c: &mut Criterion) { }, |mut app| async { app.start_server()?; - let (page, mut events) = app.new_page(browser).await?; - page.wait_for_navigation().await?; + let (guard, mut events) = app.new_page(browser).await?; + guard.page().wait_for_navigation().await?; timeout( MAX_HYDRATION_TIMEOUT, wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), ) .await??; - app.schedule_page_disposal(page); - Ok(app) + Ok((app, guard)) }, - |app| async move { - if let Err(err) = app.dispose().await { - eprintln!("error disposing app: {}", err); + |(_app, guard)| async move { + if let Err(err) = guard.close_page().await { + eprintln!("failed to close page: {:?}", err); } }, ); @@ -354,7 +351,6 @@ fn bench_restart(c: &mut Criterion) { struct PreparedApp<'a> { bundler: &'a dyn Bundler, - pages: Vec, server: Option<(Child, String)>, test_dir: tempfile::TempDir, counter: usize, @@ -375,7 +371,6 @@ impl<'a> PreparedApp<'a> { Ok(Self { bundler, - pages: Vec::new(), server: None, test_dir, counter: 0, @@ -395,7 +390,10 @@ impl<'a> PreparedApp<'a> { Ok(()) } - async fn new_page(&self, browser: &Browser) -> Result<(Page, EventStream)> { + async fn new_page( + &self, + browser: &Browser, + ) -> Result<(PageGuard, EventStream)> { let server = self.server.as_ref().context("Server must be started")?; let page = browser.new_page("about:blank").await?; // Bindings survive page reloads. Set them up as early as possible. @@ -410,35 +408,103 @@ impl<'a> PreparedApp<'a> { // Make sure no runtime errors occurred when loading the page assert!(errors.next().now_or_never().is_none()); - Ok((page, binding_events)) + Ok((PageGuard::new(page), binding_events)) } - fn schedule_page_disposal(&mut self, page: Page) { - self.pages.push(page); + fn stop_server(&mut self) -> Result<()> { + let mut proc = self.server.take().expect("Server never started").0; + stop_process(&mut proc)?; + Ok(()) } - async fn dispose(self) -> Result<()> { - if let Some(mut server) = self.server { - server.0.kill()?; - server.0.wait()?; - } - for page in self.pages { - page.close().await?; + fn path(&self) -> &Path { + self.test_dir.path() + } +} + +impl<'a> Drop for PreparedApp<'a> { + fn drop(&mut self) { + if let Some(mut server) = self.server.take() { + stop_process(&mut server.0).expect("failed to stop process"); } - Ok(()) } +} - fn stop_server(&mut self) -> Result<()> { - let mut proc = self.server.take().expect("Server never started").0; - proc.kill()?; - proc.wait()?; +/// Closes a browser page on Drop. +struct PageGuard(Option); + +impl PageGuard { + /// Creates a new guard for the given page. + pub fn new(page: Page) -> Self { + Self(Some(page)) + } + /// Returns a reference to the page. + pub fn page(&self) -> &Page { + self.0.as_ref().unwrap() + } + + pub async fn close_page(mut self) -> Result<()> { + // Invariant: the page is always Some while the guard is alive. + let page = self.0.take().unwrap(); + page.close().await?; Ok(()) } +} - fn path(&self) -> &Path { - self.test_dir.path() +impl Drop for PageGuard { + fn drop(&mut self) { + // The page might have been closed already in `close_page`. + if let Some(page) = self.0.take() { + // This is a way to block on a future in a destructor. It's not ideal, but for + // the purposes of this benchmark it's fine. + futures::executor::block_on(page.close()).expect("failed to close page"); + } + } +} + +#[cfg(unix)] +fn stop_process(proc: &mut Child) -> Result<()> { + use nix::{ + sys::signal::{kill, Signal}, + unistd::Pid, + }; + + const KILL_DEADLINE: Duration = Duration::from_secs(5); + const KILL_DEADLINE_CHECK_STEPS: u32 = 10; + + let pid = Pid::from_raw(proc.id() as _); + match kill(pid, Signal::SIGINT) { + Ok(()) => { + let expire = std::time::Instant::now() + KILL_DEADLINE; + while let Ok(None) = proc.try_wait() { + if std::time::Instant::now() > expire { + break; + } + std::thread::sleep(KILL_DEADLINE / KILL_DEADLINE_CHECK_STEPS); + } + if let Ok(None) = proc.try_wait() { + eprintln!("Process {} did not exit after SIGINT, sending SIGKILL", pid); + kill_process(proc)?; + } + } + Err(_) => { + eprintln!("Failed to send SIGINT to process {}, sending SIGKILL", pid); + kill_process(proc)?; + } } + Ok(()) +} + +#[cfg(not(unix))] +fn stop_process(proc: &mut Child) -> Result<()> { + kill_process(proc) +} + +fn kill_process(proc: &mut Child) -> Result<()> { + proc.kill()?; + proc.wait()?; + Ok(()) } fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { From a45572b6428c388d2b3ba15cf75e416afc9836f7 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Thu, 8 Sep 2022 15:02:48 +0200 Subject: [PATCH 070/672] Ensure pages close before app does (vercel/turbo#329) --- .../next-swc/crates/next-dev/benches/mod.rs | 153 +++++++++--------- 1 file changed, 80 insertions(+), 73 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index a8a273537edc06..f9d93dd48be3e4 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -154,24 +154,20 @@ fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: b || async { PreparedApp::new(bundler, template_dir.to_path_buf()) }, |mut app| async { app.start_server()?; - let (guard, mut events) = app.new_page(browser).await?; + let mut guard = app.with_page(browser).await?; guard.page().wait_for_navigation().await?; if wait_for_hydration { timeout( MAX_HYDRATION_TIMEOUT, - wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + guard.wait_for_binding(TEST_APP_HYDRATION_DONE), ) .await??; } - // return the PreparedApp doesn't make dropping it part of the - // measurement - Ok((app, guard)) - }, - |(_app, guard)| async move { - if let Err(e) = guard.close_page().await { - eprintln!("failed to close page: {:?}", e); - } + + // Defer the dropping of the guard to `teardown`. + Ok(guard) }, + |_guard| async move {}, ); }, ); @@ -191,15 +187,14 @@ fn bench_simple_file_change(c: &mut Criterion) { for bundler in retry_default((), |_| get_bundlers()).expect("failed to get bundlers") { for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); - g.bench_with_input( BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, module_count)| { let test_app = build_test(*module_count, bundler); let template_dir = test_app.path(); - fn add_code<'a>(app: &mut PreparedApp<'a>, code: &str) -> Result<()> { - let triangle_path = app.path().join("src/triangle.jsx"); + fn add_code(app_path: &Path, code: &str) -> Result<()> { + let triangle_path = app_path.join("src/triangle.jsx"); let mut contents = fs::read_to_string(&triangle_path)?; const COMPONENT_START: &str = "export default function Container({ style }) {\n"; @@ -213,13 +208,10 @@ fn bench_simple_file_change(c: &mut Criterion) { fs::write(&triangle_path, contents)?; Ok(()) } - async fn make_change<'a>( - app: &mut PreparedApp<'a>, - events: &mut EventStream, - ) -> Result<()> { - let msg = format!("TURBOPACK_BENCH_CHANGE_{}", app.counter()); + async fn make_change<'a>(guard: &mut PageGuard<'a>) -> Result<()> { + let msg = format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); add_code( - app, + guard.app().path(), &format!( " React.useEffect(() => {{ globalThis.{BINDING_NAME}('{msg}'); \ }});\n" @@ -228,7 +220,7 @@ fn bench_simple_file_change(c: &mut Criterion) { // Wait for the change introduced above to be reflected at runtime. // This expects HMR or automatic reloading to occur. - timeout(MAX_UPDATE_TIMEOUT, wait_for_binding(events, &msg)) + timeout(MAX_UPDATE_TIMEOUT, guard.wait_for_binding(&msg)) .await? .context("update was not registered by bundler")?; @@ -238,30 +230,26 @@ fn bench_simple_file_change(c: &mut Criterion) { || async { let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; app.start_server()?; - let (guard, mut events) = app.new_page(browser).await?; + let mut guard = app.with_page(browser).await?; guard.page().wait_for_navigation().await?; timeout( MAX_HYDRATION_TIMEOUT, - wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + guard.wait_for_binding(TEST_APP_HYDRATION_DONE), ) .await??; // Make warmup change - make_change(&mut app, &mut events).await?; + make_change(&mut guard).await?; - Ok((app, guard, events)) + Ok(guard) }, - |(mut app, guard, mut events)| async move { - make_change(&mut app, &mut events).await?; + |mut guard| async move { + make_change(&mut guard).await?; - // Defer the dropping of the app and the page guard to `teardown`. - Ok((app, guard)) - }, - |(_app, guard)| async move { - if let Err(err) = guard.close_page().await { - eprintln!("failed to close page: {:?}", err); - } + // Defer the dropping of the guard to `teardown`. + Ok(guard) }, + |_guard| async move {}, ); }, ); @@ -269,19 +257,6 @@ fn bench_simple_file_change(c: &mut Criterion) { } } -async fn wait_for_binding( - events: &mut EventStream, - payload: &str, -) -> Result<()> { - while let Some(event) = events.next().await { - if event.name == BINDING_NAME && event.payload == payload { - return Ok(()); - } - } - - Err(anyhow!("event stream ended before binding was called")) -} - /// Adds benchmark-specific bindings to the page. async fn add_binding(page: &Page) -> Result<()> { page.execute(AddBindingParams::new(BINDING_NAME)).await?; @@ -311,14 +286,14 @@ fn bench_restart(c: &mut Criterion) { // Run a complete build, shut down, and test running it again let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; app.start_server()?; - let (guard, mut events) = app.new_page(browser).await?; + let mut guard = app.with_page(browser).await?; guard.page().wait_for_navigation().await?; timeout( MAX_HYDRATION_TIMEOUT, - wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + guard.wait_for_binding(TEST_APP_HYDRATION_DONE), ) .await??; - guard.close_page().await?; + let mut app = guard.close_page().await?; // Give it 4 seconds time to store the cache sleep(Duration::from_secs(4)).await; @@ -328,20 +303,18 @@ fn bench_restart(c: &mut Criterion) { }, |mut app| async { app.start_server()?; - let (guard, mut events) = app.new_page(browser).await?; + let mut guard = app.with_page(browser).await?; guard.page().wait_for_navigation().await?; timeout( MAX_HYDRATION_TIMEOUT, - wait_for_binding(&mut events, TEST_APP_HYDRATION_DONE), + guard.wait_for_binding(TEST_APP_HYDRATION_DONE), ) .await??; - Ok((app, guard)) - }, - |(_app, guard)| async move { - if let Err(err) = guard.close_page().await { - eprintln!("failed to close page: {:?}", err); - } + + // Defer the dropping of the guard to `teardown`. + Ok(guard) }, + |_guard| async move {}, ); }, ); @@ -390,10 +363,7 @@ impl<'a> PreparedApp<'a> { Ok(()) } - async fn new_page( - &self, - browser: &Browser, - ) -> Result<(PageGuard, EventStream)> { + async fn with_page(self, browser: &Browser) -> Result> { let server = self.server.as_ref().context("Server must be started")?; let page = browser.new_page("about:blank").await?; // Bindings survive page reloads. Set them up as early as possible. @@ -408,7 +378,9 @@ impl<'a> PreparedApp<'a> { // Make sure no runtime errors occurred when loading the page assert!(errors.next().now_or_never().is_none()); - Ok((PageGuard::new(page), binding_events)) + let page_guard = PageGuard::new(page, binding_events, self); + + Ok(page_guard) } fn stop_server(&mut self) -> Result<()> { @@ -431,31 +403,66 @@ impl<'a> Drop for PreparedApp<'a> { } /// Closes a browser page on Drop. -struct PageGuard(Option); +struct PageGuard<'a> { + page: Option, + app: Option>, + events: EventStream, +} -impl PageGuard { +impl<'a> PageGuard<'a> { /// Creates a new guard for the given page. - pub fn new(page: Page) -> Self { - Self(Some(page)) + pub fn new(page: Page, events: EventStream, app: PreparedApp<'a>) -> Self { + Self { + page: Some(page), + app: Some(app), + events, + } } /// Returns a reference to the page. pub fn page(&self) -> &Page { - self.0.as_ref().unwrap() + // Invariant: page is always Some while the guard is alive. + self.page.as_ref().unwrap() + } + + /// Returns a reference to the app. + pub fn app(&self) -> &PreparedApp<'a> { + // Invariant: app is always Some while the guard is alive. + self.app.as_ref().unwrap() + } + + /// Returns a mutable reference to the app. + pub fn app_mut(&mut self) -> &mut PreparedApp<'a> { + // Invariant: app is always Some while the guard is alive. + self.app.as_mut().unwrap() } - pub async fn close_page(mut self) -> Result<()> { + /// Closes the page, returns the app. + pub async fn close_page(mut self) -> Result> { // Invariant: the page is always Some while the guard is alive. - let page = self.0.take().unwrap(); - page.close().await?; - Ok(()) + self.page.take().unwrap().close().await?; + Ok( + // Invariant: the app is always Some while the guard is alive. + self.app.take().unwrap(), + ) + } + + /// Waits until the binding is called with the given payload. + pub async fn wait_for_binding(&mut self, payload: &str) -> Result<()> { + while let Some(event) = self.events.next().await { + if event.name == BINDING_NAME && event.payload == payload { + return Ok(()); + } + } + + Err(anyhow!("event stream ended before binding was called")) } } -impl Drop for PageGuard { +impl<'a> Drop for PageGuard<'a> { fn drop(&mut self) { // The page might have been closed already in `close_page`. - if let Some(page) = self.0.take() { + if let Some(page) = self.page.take() { // This is a way to block on a future in a destructor. It's not ideal, but for // the purposes of this benchmark it's fine. futures::executor::block_on(page.close()).expect("failed to close page"); From 6f312afedcebe7d97d86cb11d60c04b97b290f07 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 8 Sep 2022 16:46:19 +0200 Subject: [PATCH 071/672] allow to pass module counts list via env var (vercel/turbo#332) add custom benchmark workflow run large counts in CI --- .../next-swc/crates/next-dev/benches/mod.rs | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index f9d93dd48be3e4..7f73ab743c58be 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -39,22 +39,16 @@ const TEST_APP_HYDRATION_DONE: &str = "Hydration done"; const MAX_UPDATE_TIMEOUT: Duration = Duration::from_secs(20); const MAX_HYDRATION_TIMEOUT: Duration = Duration::from_secs(30); -fn get_module_counts() -> &'static [usize] { +fn get_module_counts() -> Vec { let config = std::env::var("TURBOPACK_BENCH_COUNTS").ok(); match config.as_deref() { - Some("all") => { - static C: &[usize] = &[100, 500, 1_000, 2_000]; - C - } - Some("others") => { - static C: &[usize] = &[500, 2_000]; - C - } None | Some("") => { - static C: &[usize] = &[100, 1_000]; - C + vec![100, 1_000] } - _ => panic!("Invalid value for TURBOPACK_BENCH_COUNTS"), + Some(config) => config + .split(",") + .map(|s| s.parse().expect("Invalid value for TURBOPACK_BENCH_COUNTS")) + .collect(), } } @@ -148,7 +142,7 @@ fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: b BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, module_count)| { - let test_app = build_test(*module_count, bundler); + let test_app = build_test(module_count, bundler); let template_dir = test_app.path(); b.to_async(&runtime).try_iter_async( || async { PreparedApp::new(bundler, template_dir.to_path_buf()) }, @@ -191,7 +185,7 @@ fn bench_simple_file_change(c: &mut Criterion) { BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, module_count)| { - let test_app = build_test(*module_count, bundler); + let test_app = build_test(module_count, bundler); let template_dir = test_app.path(); fn add_code(app_path: &Path, code: &str) -> Result<()> { let triangle_path = app_path.join("src/triangle.jsx"); @@ -279,7 +273,7 @@ fn bench_restart(c: &mut Criterion) { BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, module_count)| { - let test_app = build_test(*module_count, bundler); + let test_app = build_test(module_count, bundler); let template_dir = test_app.path(); b.to_async(Runtime::new().unwrap()).try_iter_async( || async { From 378adc7112fd147fe67e8e8ed86d52ce3ace7f47 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 8 Sep 2022 16:54:09 +0200 Subject: [PATCH 072/672] cleanup nitpicks (vercel/turbo#330) --- packages/next-swc/crates/next-dev/benches/bundlers.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers.rs b/packages/next-swc/crates/next-dev/benches/bundlers.rs index 143175be8d4fe2..4d9fc9e63a5cb5 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers.rs @@ -45,9 +45,9 @@ impl Bundler for Turbopack { fn prepare(&self, install_dir: &Path) -> Result<()> { install_from_npm(install_dir, "react-refresh", "^0.12.0") - .context("failed to install `parcel` module")?; + .context("failed to install `react-refresh` module")?; install_from_npm(install_dir, "@next/react-refresh-utils", "^12.2.5") - .context("failed to install `process` module")?; + .context("failed to install `@next/react-refresh-utils` module")?; Ok(()) } From 0a112ccb140271986217f38a022cf8f78c04f562 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Thu, 8 Sep 2022 17:18:53 +0200 Subject: [PATCH 073/672] Fix Next.js 11 React version (vercel/turbo#333) --- .../crates/next-dev/benches/bundlers.rs | 86 +++++++++++++------ .../next-swc/crates/next-dev/benches/mod.rs | 12 +-- 2 files changed, 69 insertions(+), 29 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers.rs b/packages/next-swc/crates/next-dev/benches/bundlers.rs index 4d9fc9e63a5cb5..644caf49b8a366 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers.rs @@ -1,4 +1,5 @@ use std::{ + fmt::Display, fs::{self, File}, io::{self, BufRead, BufReader, Write}, path::Path, @@ -7,13 +8,15 @@ use std::{ use anyhow::{anyhow, Context, Result}; use regex::Regex; -use tempfile::TempDir; pub trait Bundler { fn get_name(&self) -> &str; fn get_path(&self) -> &str { "/" } + fn react_version(&self) -> &str { + "^18.2.0" + } fn prepare(&self, _template_dir: &Path) -> Result<()> { Ok(()) } @@ -128,19 +131,11 @@ impl Bundler for Parcel { } } -struct Vite { - install_dir: TempDir, -} +struct Vite {} impl Vite { - fn new() -> Result { - // Manage our own installation and avoid `npm exec`, `npx`, etc. to avoid their - // overhead influencing benchmarks. - let install_dir = tempfile::tempdir()?; - install_from_npm(install_dir.path(), "vite", "3.0.9") - .context("failed to install `vite` module")?; - - Ok(Vite { install_dir }) + fn new() -> Self { + Vite {} } } @@ -149,12 +144,16 @@ impl Bundler for Vite { "Vite CSR" } + fn prepare(&self, install_dir: &Path) -> Result<()> { + install_from_npm(install_dir, "vite", "3.0.9") + .context("failed to install `vite` module")?; + Ok(()) + } + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { let mut proc = Command::new("node") .args([ - (self - .install_dir - .path() + (test_dir .join("node_modules") .join("vite") .join("bin") @@ -183,16 +182,17 @@ impl Bundler for Vite { } } +#[derive(Debug)] struct NextJs { - version: u32, + version: NextJsVersion, name: String, } impl NextJs { - fn new(version: u32) -> Self { + fn new(version: NextJsVersion) -> Self { Self { + name: format!("{version} SSR"), version, - name: format!("Next.js {version} SSR"), } } } @@ -206,8 +206,12 @@ impl Bundler for NextJs { "/page" } + fn react_version(&self) -> &str { + self.version.react_version() + } + fn prepare(&self, install_dir: &Path) -> Result<()> { - install_from_npm(install_dir, "next", &format!("^{}", self.version)) + install_from_npm(install_dir, "next", self.version.version()) .context("failed to install `next` module")?; Ok(()) } @@ -251,7 +255,41 @@ impl Bundler for NextJs { } } -pub fn get_bundlers() -> Result>> { +#[derive(Debug)] +enum NextJsVersion { + V11, + V12, +} + +impl Display for NextJsVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NextJsVersion::V11 => write!(f, "Next.js 11"), + NextJsVersion::V12 => write!(f, "Next.js 12"), + } + } +} + +impl NextJsVersion { + /// Returns the version of Next.js to install from npm. + pub fn version(&self) -> &'static str { + match self { + NextJsVersion::V11 => "^11", + NextJsVersion::V12 => "^12", + } + } + + /// Returns the version of React to install from npm alongside this version + /// of Next.js. + pub fn react_version(&self) -> &'static str { + match self { + NextJsVersion::V11 => "^17.0.2", + NextJsVersion::V12 => "^18.2.0", + } + } +} + +pub fn get_bundlers() -> Vec> { let config = std::env::var("TURBOPACK_BENCH_BUNDLERS").ok(); let mut turbopack = false; let mut others = false; @@ -274,12 +312,12 @@ pub fn get_bundlers() -> Result>> { if others { bundlers.push(Box::new(Parcel {})); - bundlers.push(Box::new(Vite::new()?)); - bundlers.push(Box::new(NextJs::new(12))); - bundlers.push(Box::new(NextJs::new(11))); + bundlers.push(Box::new(Vite::new())); + bundlers.push(Box::new(NextJs::new(NextJsVersion::V12))); + bundlers.push(Box::new(NextJs::new(NextJsVersion::V11))); } - Ok(bundlers) + bundlers } fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> Option { diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 7f73ab743c58be..d5eb754d600950 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -28,7 +28,7 @@ use tokio::{ time::{sleep, timeout}, }; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; -use turbopack_create_test_app::test_app_builder::{TestApp, TestAppBuilder}; +use turbopack_create_test_app::test_app_builder::{PackageJsonConfig, TestApp, TestAppBuilder}; use url::Url; mod bundlers; @@ -135,7 +135,7 @@ fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: b let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for bundler in retry_default((), |_| get_bundlers()).expect("failed to get bundlers") { + for bundler in get_bundlers() { for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); g.bench_with_input( @@ -178,7 +178,7 @@ fn bench_simple_file_change(c: &mut Criterion) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for bundler in retry_default((), |_| get_bundlers()).expect("failed to get bundlers") { + for bundler in get_bundlers() { for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); g.bench_with_input( @@ -265,7 +265,7 @@ fn bench_restart(c: &mut Criterion) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); - for bundler in retry_default((), |_| get_bundlers()).expect("failed to get bundlers") { + for bundler in get_bundlers() { for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); @@ -512,7 +512,9 @@ fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { let test_app = TestAppBuilder { module_count, directories_count: module_count / 20, - package_json: true, + package_json: Some(PackageJsonConfig { + react_version: bundler.react_version().to_string(), + }), ..Default::default() } .build() From ecaf59b3e6e57c20975d7bb7dbaadb3a912b0280 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 8 Sep 2022 18:00:15 +0200 Subject: [PATCH 074/672] improve startup metric measurement (vercel/turbo#331) This fixes the `startup` benchmark metric to show the time until first render, instead of being equal to hydration. It also skips `hydration` for CSR bundlers since it's equal first render for them. It now correctly measures the initial SSR as `startup`, so CLI start until page visible: ![image](https://user-images.githubusercontent.com/1365881/189152420-396b181b-5a3e-4902-881d-7c247fa43bd8.png) --- .../crates/next-dev/benches/bundlers.rs | 21 ++++- .../next-swc/crates/next-dev/benches/mod.rs | 86 ++++++++++++------- 2 files changed, 71 insertions(+), 36 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers.rs b/packages/next-swc/crates/next-dev/benches/bundlers.rs index 644caf49b8a366..1b4f4d23c70cf3 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers.rs @@ -17,6 +17,11 @@ pub trait Bundler { fn react_version(&self) -> &str { "^18.2.0" } + /// The initial HTML is enough to render the page even without JavaScript + /// loaded + fn has_server_rendered_html(&self) -> bool { + false + } fn prepare(&self, _template_dir: &Path) -> Result<()> { Ok(()) } @@ -26,13 +31,15 @@ pub trait Bundler { struct Turbopack { name: String, path: String, + has_server_rendered_html: bool, } impl Turbopack { - fn new(name: &str, path: &str) -> Self { + fn new(name: &str, path: &str, has_server_rendered_html: bool) -> Self { Turbopack { name: name.to_owned(), path: path.to_owned(), + has_server_rendered_html, } } } @@ -46,6 +53,10 @@ impl Bundler for Turbopack { &self.path } + fn has_server_rendered_html(&self) -> bool { + self.has_server_rendered_html + } + fn prepare(&self, install_dir: &Path) -> Result<()> { install_from_npm(install_dir, "react-refresh", "^0.12.0") .context("failed to install `react-refresh` module")?; @@ -210,6 +221,10 @@ impl Bundler for NextJs { self.version.react_version() } + fn has_server_rendered_html(&self) -> bool { + true + } + fn prepare(&self, install_dir: &Path) -> Result<()> { install_from_npm(install_dir, "next", self.version.version()) .context("failed to install `next` module")?; @@ -306,8 +321,8 @@ pub fn get_bundlers() -> Vec> { } let mut bundlers: Vec> = Vec::new(); if turbopack { - bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/"))); - bundlers.push(Box::new(Turbopack::new("Turbopack SSR", "/page"))); + bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false))); + bundlers.push(Box::new(Turbopack::new("Turbopack SSR", "/page", true))); } if others { diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index d5eb754d600950..73fa33a20eaa51 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -11,7 +11,10 @@ use anyhow::{anyhow, Context, Result}; use bundlers::{command, get_bundlers, Bundler}; use chromiumoxide::{ browser::{Browser, BrowserConfig}, - cdp::js_protocol::runtime::{AddBindingParams, EventBindingCalled, EventExceptionThrown}, + cdp::{ + browser_protocol::network::EventResponseReceived, + js_protocol::runtime::{AddBindingParams, EventBindingCalled, EventExceptionThrown}, + }, error::CdpError::Ws, listeners::EventStream, Page, @@ -131,11 +134,23 @@ fn bench_hydration(c: &mut Criterion) { bench_startup_internal(g, true); } -fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: bool) { +fn bench_startup_internal(mut g: BenchmarkGroup, hydration: bool) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); for bundler in get_bundlers() { + let wait_for_hydration = if !bundler.has_server_rendered_html() { + // For bundlers without server rendered html "startup" means time to hydration + // as they only render an empty screen without hydration. Since startup and + // hydration would be the same we skip the hydration benchmark for them. + if hydration { + continue; + } else { + true + } + } else { + hydration + }; for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); g.bench_with_input( @@ -149,13 +164,8 @@ fn bench_startup_internal(mut g: BenchmarkGroup, wait_for_hydration: b |mut app| async { app.start_server()?; let mut guard = app.with_page(browser).await?; - guard.page().wait_for_navigation().await?; if wait_for_hydration { - timeout( - MAX_HYDRATION_TIMEOUT, - guard.wait_for_binding(TEST_APP_HYDRATION_DONE), - ) - .await??; + guard.wait_for_hydration().await?; } // Defer the dropping of the guard to `teardown`. @@ -225,12 +235,7 @@ fn bench_simple_file_change(c: &mut Criterion) { let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; app.start_server()?; let mut guard = app.with_page(browser).await?; - guard.page().wait_for_navigation().await?; - timeout( - MAX_HYDRATION_TIMEOUT, - guard.wait_for_binding(TEST_APP_HYDRATION_DONE), - ) - .await??; + guard.wait_for_hydration().await?; // Make warmup change make_change(&mut guard).await?; @@ -281,12 +286,8 @@ fn bench_restart(c: &mut Criterion) { let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; app.start_server()?; let mut guard = app.with_page(browser).await?; - guard.page().wait_for_navigation().await?; - timeout( - MAX_HYDRATION_TIMEOUT, - guard.wait_for_binding(TEST_APP_HYDRATION_DONE), - ) - .await??; + guard.wait_for_hydration().await?; + let mut app = guard.close_page().await?; // Give it 4 seconds time to store the cache @@ -298,12 +299,7 @@ fn bench_restart(c: &mut Criterion) { |mut app| async { app.start_server()?; let mut guard = app.with_page(browser).await?; - guard.page().wait_for_navigation().await?; - timeout( - MAX_HYDRATION_TIMEOUT, - guard.wait_for_binding(TEST_APP_HYDRATION_DONE), - ) - .await??; + guard.wait_for_hydration().await?; // Defer the dropping of the guard to `teardown`. Ok(guard) @@ -365,9 +361,29 @@ impl<'a> PreparedApp<'a> { let mut errors = page.event_listener::().await?; let binding_events = page.event_listener::().await?; + let mut network_response_events = page.event_listener::().await?; let destination = Url::parse(&server.1)?.join(self.bundler.get_path())?; - page.goto(destination).await?; + // We can't use page.goto() here since this will wait for the naviation to be + // completed. A naviation would be complete when all sync script are + // evaluated, but the page actually can rendered earlier without JavaScript + // needing to be evaluated. + // So instead we navigate via JavaScript and wait only for the HTML response to + // be completed. + page.evaluate_expression(format!("window.location='{destination}'")) + .await?; + + // Wait for HTML response completed + loop { + match network_response_events.next().await { + Some(event) => { + if event.response.url == destination.as_str() { + break; + } + } + None => return Err(anyhow!("event stream ended too early")), + } + } // Make sure no runtime errors occurred when loading the page assert!(errors.next().now_or_never().is_none()); @@ -413,12 +429,6 @@ impl<'a> PageGuard<'a> { } } - /// Returns a reference to the page. - pub fn page(&self) -> &Page { - // Invariant: page is always Some while the guard is alive. - self.page.as_ref().unwrap() - } - /// Returns a reference to the app. pub fn app(&self) -> &PreparedApp<'a> { // Invariant: app is always Some while the guard is alive. @@ -451,6 +461,16 @@ impl<'a> PageGuard<'a> { Err(anyhow!("event stream ended before binding was called")) } + + /// Waits until the page and the page JavaScript is hydrated. + pub async fn wait_for_hydration(&mut self) -> Result<()> { + timeout( + MAX_HYDRATION_TIMEOUT, + self.wait_for_binding(TEST_APP_HYDRATION_DONE), + ) + .await??; + Ok(()) + } } impl<'a> Drop for PageGuard<'a> { From 361ca5eca8b3042874ce26b354cfb6f6cfbefee0 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Fri, 9 Sep 2022 16:35:12 -0700 Subject: [PATCH 075/672] Split benchmark code into more modules (vercel/turbo#337) This splits the benchmark code into more modules. Notes: * ~Moved/left `get_bundlers()` and `get_module_counts()` to/in mod.rs. In particular, moving `get_bundlers()` to either bundle.rs or util.rs would lead to a circular dependency. These both also rely on env var configuration, so I figured this was a reasonable place for them.~ * The Bundler trait has its own module (not moved to util), since it's a top-level concern and not really a miscellaneous utility. * Each bundler has its own module file. Test Plan: `TURBOPACK_BENCH_BUNDLERS=all cargo test --benches -p next-dev -- --nocapture` and verify same output as before change. --- .../crates/next-dev/benches/bundlers.rs | 399 ---------------- .../crates/next-dev/benches/bundlers/mod.rs | 65 +++ .../next-dev/benches/bundlers/nextjs.rs | 124 +++++ .../next-dev/benches/bundlers/parcel.rs | 63 +++ .../next-dev/benches/bundlers/turbopack.rs | 75 +++ .../crates/next-dev/benches/bundlers/vite.rs | 62 +++ .../next-swc/crates/next-dev/benches/mod.rs | 450 +----------------- .../crates/next-dev/benches/util/mod.rs | 232 +++++++++ .../crates/next-dev/benches/util/npm.rs | 43 ++ .../next-dev/benches/util/page_guard.rs | 83 ++++ .../next-dev/benches/util/prepared_app.rs | 169 +++++++ 11 files changed, 932 insertions(+), 833 deletions(-) delete mode 100644 packages/next-swc/crates/next-dev/benches/bundlers.rs create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/mod.rs create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/vite.rs create mode 100644 packages/next-swc/crates/next-dev/benches/util/mod.rs create mode 100644 packages/next-swc/crates/next-dev/benches/util/npm.rs create mode 100644 packages/next-swc/crates/next-dev/benches/util/page_guard.rs create mode 100644 packages/next-swc/crates/next-dev/benches/util/prepared_app.rs diff --git a/packages/next-swc/crates/next-dev/benches/bundlers.rs b/packages/next-swc/crates/next-dev/benches/bundlers.rs deleted file mode 100644 index 1b4f4d23c70cf3..00000000000000 --- a/packages/next-swc/crates/next-dev/benches/bundlers.rs +++ /dev/null @@ -1,399 +0,0 @@ -use std::{ - fmt::Display, - fs::{self, File}, - io::{self, BufRead, BufReader, Write}, - path::Path, - process::{Child, ChildStdout, Command, Stdio}, -}; - -use anyhow::{anyhow, Context, Result}; -use regex::Regex; - -pub trait Bundler { - fn get_name(&self) -> &str; - fn get_path(&self) -> &str { - "/" - } - fn react_version(&self) -> &str { - "^18.2.0" - } - /// The initial HTML is enough to render the page even without JavaScript - /// loaded - fn has_server_rendered_html(&self) -> bool { - false - } - fn prepare(&self, _template_dir: &Path) -> Result<()> { - Ok(()) - } - fn start_server(&self, test_dir: &Path) -> Result<(Child, String)>; -} - -struct Turbopack { - name: String, - path: String, - has_server_rendered_html: bool, -} - -impl Turbopack { - fn new(name: &str, path: &str, has_server_rendered_html: bool) -> Self { - Turbopack { - name: name.to_owned(), - path: path.to_owned(), - has_server_rendered_html, - } - } -} - -impl Bundler for Turbopack { - fn get_name(&self) -> &str { - &self.name - } - - fn get_path(&self) -> &str { - &self.path - } - - fn has_server_rendered_html(&self) -> bool { - self.has_server_rendered_html - } - - fn prepare(&self, install_dir: &Path) -> Result<()> { - install_from_npm(install_dir, "react-refresh", "^0.12.0") - .context("failed to install `react-refresh` module")?; - install_from_npm(install_dir, "@next/react-refresh-utils", "^12.2.5") - .context("failed to install `@next/react-refresh-utils` module")?; - Ok(()) - } - - fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { - let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) - .args([ - test_dir - .to_str() - .ok_or_else(|| anyhow!("failed to convert test directory path to string"))?, - "--no-open", - "--port", - "0", - ]) - .stdout(Stdio::piped()) - .spawn()?; - - // Wait for the devserver address to appear in stdout. - let addr = wait_for_match( - proc.stdout - .as_mut() - .ok_or_else(|| anyhow!("missing stdout"))?, - Regex::new("server listening on: (.*)")?, - ) - .ok_or_else(|| anyhow!("failed to find devserver address"))?; - - Ok((proc, addr)) - } -} - -struct Parcel; -impl Bundler for Parcel { - fn get_name(&self) -> &str { - "Parcel CSR" - } - - fn prepare(&self, install_dir: &Path) -> Result<()> { - install_from_npm(install_dir, "parcel", "2.7.0") - .context("failed to install `parcel` module")?; - - // `process` would otherwise be auto-installed by Parcel. Do this in advance as - // to not influence the benchmark. - install_from_npm(install_dir, "process", "^0.11.0") - .context("failed to install `process` module")?; - Ok(()) - } - - fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { - let mut proc = Command::new("node") - .args([ - (test_dir - .join("node_modules") - .join("parcel") - .join("lib") - .join("bin.js") - .to_str() - .unwrap()), - "--port", - &portpicker::pick_unused_port() - .ok_or_else(|| anyhow!("failed to pick unused port"))? - .to_string(), - "index.html", - ]) - .current_dir(test_dir) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .spawn() - .context("failed to run `parcel` command")?; - - let addr = wait_for_match( - proc.stdout - .as_mut() - .ok_or_else(|| anyhow!("missing stdout"))?, - Regex::new("Server running at\\s+(.*)")?, - ) - .ok_or_else(|| anyhow!("failed to find devserver address"))?; - - Ok((proc, addr)) - } -} - -struct Vite {} - -impl Vite { - fn new() -> Self { - Vite {} - } -} - -impl Bundler for Vite { - fn get_name(&self) -> &str { - "Vite CSR" - } - - fn prepare(&self, install_dir: &Path) -> Result<()> { - install_from_npm(install_dir, "vite", "3.0.9") - .context("failed to install `vite` module")?; - Ok(()) - } - - fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { - let mut proc = Command::new("node") - .args([ - (test_dir - .join("node_modules") - .join("vite") - .join("bin") - .join("vite.js") - .to_str() - .unwrap()), - "--port", - "0", - ]) - .env("NO_COLOR", "1") - .current_dir(test_dir) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .spawn() - .context("failed to run `vite` command")?; - - let addr = wait_for_match( - proc.stdout - .as_mut() - .ok_or_else(|| anyhow!("missing stdout"))?, - Regex::new("Local:\\s+(.*)")?, - ) - .ok_or_else(|| anyhow!("failed to find devserver address"))?; - - Ok((proc, addr)) - } -} - -#[derive(Debug)] -struct NextJs { - version: NextJsVersion, - name: String, -} - -impl NextJs { - fn new(version: NextJsVersion) -> Self { - Self { - name: format!("{version} SSR"), - version, - } - } -} - -impl Bundler for NextJs { - fn get_name(&self) -> &str { - &self.name - } - - fn get_path(&self) -> &str { - "/page" - } - - fn react_version(&self) -> &str { - self.version.react_version() - } - - fn has_server_rendered_html(&self) -> bool { - true - } - - fn prepare(&self, install_dir: &Path) -> Result<()> { - install_from_npm(install_dir, "next", self.version.version()) - .context("failed to install `next` module")?; - Ok(()) - } - - fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { - // Using `node_modules/.bin/next` would sometimes error with `Error: Cannot find - // module '../build/output/log'` - let mut proc = Command::new("node") - .args([ - test_dir - .join("node_modules") - .join("next") - .join("dist") - .join("bin") - .join("next") - .to_str() - .unwrap(), - "dev", - "--port", - // Next.js currently has a bug where requests for port 0 are ignored and it falls - // back to the default 3000. Use portpicker instead. - &portpicker::pick_unused_port() - .ok_or_else(|| anyhow!("failed to pick unused port"))? - .to_string(), - ]) - .current_dir(test_dir) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .spawn() - .context("failed to run `next` command")?; - - let addr = wait_for_match( - proc.stdout - .as_mut() - .ok_or_else(|| anyhow!("missing stdout"))?, - Regex::new("started server.*url: (.*)")?, - ) - .ok_or_else(|| anyhow!("failed to find devserver address"))?; - - Ok((proc, format!("{addr}/page"))) - } -} - -#[derive(Debug)] -enum NextJsVersion { - V11, - V12, -} - -impl Display for NextJsVersion { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - NextJsVersion::V11 => write!(f, "Next.js 11"), - NextJsVersion::V12 => write!(f, "Next.js 12"), - } - } -} - -impl NextJsVersion { - /// Returns the version of Next.js to install from npm. - pub fn version(&self) -> &'static str { - match self { - NextJsVersion::V11 => "^11", - NextJsVersion::V12 => "^12", - } - } - - /// Returns the version of React to install from npm alongside this version - /// of Next.js. - pub fn react_version(&self) -> &'static str { - match self { - NextJsVersion::V11 => "^17.0.2", - NextJsVersion::V12 => "^18.2.0", - } - } -} - -pub fn get_bundlers() -> Vec> { - let config = std::env::var("TURBOPACK_BENCH_BUNDLERS").ok(); - let mut turbopack = false; - let mut others = false; - match config.as_deref() { - Some("all") => { - turbopack = true; - others = true - } - Some("others") => others = true, - None | Some("") => { - turbopack = true; - } - _ => panic!("Invalid value for TURBOPACK_BENCH_BUNDLERS"), - } - let mut bundlers: Vec> = Vec::new(); - if turbopack { - bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false))); - bundlers.push(Box::new(Turbopack::new("Turbopack SSR", "/page", true))); - } - - if others { - bundlers.push(Box::new(Parcel {})); - bundlers.push(Box::new(Vite::new())); - bundlers.push(Box::new(NextJs::new(NextJsVersion::V12))); - bundlers.push(Box::new(NextJs::new(NextJsVersion::V11))); - } - - bundlers -} - -fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> Option { - // See https://docs.rs/async-process/latest/async_process/#examples - let mut line_reader = BufReader::new(stdout).lines(); - // Read until the match appears in the buffer - let mut matched: Option = None; - while let Some(Ok(line)) = line_reader.next() { - if let Some(cap) = re.captures(&line) { - matched = Some(cap.get(1).unwrap().as_str().into()); - break; - } - } - - matched -} - -pub fn command(bin: &str) -> Command { - if cfg!(windows) { - let mut command = Command::new("cmd.exe"); - command.args(["/C", bin]); - command - } else { - Command::new(bin) - } -} - -fn install_from_npm( - install_dir: &Path, - package_name: &str, - package_version_expr: &str, -) -> Result<()> { - if !fs::metadata(install_dir.join("package.json")) - .map(|metadata| metadata.is_file()) - .unwrap_or(false) - { - // Create a simple package.json if one doesn't exist - - let package_json = json::object! { - private: true, - version: "0.0.0", - }; - - File::create(install_dir.join("package.json"))? - .write_all(package_json.pretty(2).as_bytes())?; - } - - let npm = command("npm") - .args([ - "install", - "--force", - &format!("{}@{}", package_name, package_version_expr), - ]) - .current_dir(install_dir) - .output()?; - - if !npm.status.success() { - io::stdout().write_all(&npm.stdout)?; - io::stderr().write_all(&npm.stderr)?; - return Err(anyhow!("npm install failed. See above.")); - } - - Ok(()) -} diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs new file mode 100644 index 00000000000000..cc695f409f7314 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs @@ -0,0 +1,65 @@ +use std::{path::Path, process::Child}; + +use anyhow::Result; + +use self::{ + nextjs::{NextJs, NextJsVersion}, + parcel::Parcel, + turbopack::Turbopack, + vite::Vite, +}; + +mod nextjs; +mod parcel; +mod turbopack; +mod vite; + +pub trait Bundler { + fn get_name(&self) -> &str; + fn get_path(&self) -> &str { + "/" + } + fn react_version(&self) -> &str { + "^18.2.0" + } + /// The initial HTML is enough to render the page even without JavaScript + /// loaded + fn has_server_rendered_html(&self) -> bool { + false + } + fn prepare(&self, _template_dir: &Path) -> Result<()> { + Ok(()) + } + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)>; +} + +pub fn get_bundlers() -> Vec> { + let config = std::env::var("TURBOPACK_BENCH_BUNDLERS").ok(); + let mut turbopack = false; + let mut others = false; + match config.as_deref() { + Some("all") => { + turbopack = true; + others = true + } + Some("others") => others = true, + None | Some("") => { + turbopack = true; + } + _ => panic!("Invalid value for TURBOPACK_BENCH_BUNDLERS"), + } + let mut bundlers: Vec> = Vec::new(); + if turbopack { + bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false))); + bundlers.push(Box::new(Turbopack::new("Turbopack SSR", "/page", true))); + } + + if others { + bundlers.push(Box::new(Parcel {})); + bundlers.push(Box::new(Vite::new())); + bundlers.push(Box::new(NextJs::new(NextJsVersion::V12))); + bundlers.push(Box::new(NextJs::new(NextJsVersion::V11))); + } + + bundlers +} diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs new file mode 100644 index 00000000000000..298d4b58e981a9 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs @@ -0,0 +1,124 @@ +use std::{ + fmt::Display, + path::Path, + process::{Child, Command, Stdio}, +}; + +use anyhow::{anyhow, Context, Result}; +use regex::Regex; + +use crate::{ + bundlers::Bundler, + util::{npm, wait_for_match}, +}; + +#[derive(Debug)] +pub enum NextJsVersion { + V11, + V12, +} + +#[derive(Debug)] +pub struct NextJs { + version: NextJsVersion, + name: String, +} + +impl NextJs { + pub fn new(version: NextJsVersion) -> Self { + Self { + name: format!("{version} SSR"), + version, + } + } +} + +impl Bundler for NextJs { + fn get_name(&self) -> &str { + &self.name + } + + fn get_path(&self) -> &str { + "/page" + } + + fn react_version(&self) -> &str { + self.version.react_version() + } + + fn has_server_rendered_html(&self) -> bool { + true + } + + fn prepare(&self, install_dir: &Path) -> Result<()> { + npm::install(install_dir, "next", self.version.version()) + .context("failed to install `next` module")?; + Ok(()) + } + + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { + // Using `node_modules/.bin/next` would sometimes error with `Error: Cannot find + // module '../build/output/log'` + let mut proc = Command::new("node") + .args([ + test_dir + .join("node_modules") + .join("next") + .join("dist") + .join("bin") + .join("next") + .to_str() + .unwrap(), + "dev", + "--port", + // Next.js currently has a bug where requests for port 0 are ignored and it falls + // back to the default 3000. Use portpicker instead. + &portpicker::pick_unused_port() + .ok_or_else(|| anyhow!("failed to pick unused port"))? + .to_string(), + ]) + .current_dir(test_dir) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .context("failed to run `next` command")?; + + let addr = wait_for_match( + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("started server.*url: (.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; + + Ok((proc, format!("{addr}/page"))) + } +} + +impl Display for NextJsVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NextJsVersion::V11 => write!(f, "Next.js 11"), + NextJsVersion::V12 => write!(f, "Next.js 12"), + } + } +} + +impl NextJsVersion { + /// Returns the version of Next.js to install from npm. + pub fn version(&self) -> &'static str { + match self { + NextJsVersion::V11 => "^11", + NextJsVersion::V12 => "^12", + } + } + + /// Returns the version of React to install from npm alongside this version + /// of Next.js. + pub fn react_version(&self) -> &'static str { + match self { + NextJsVersion::V11 => "^17.0.2", + NextJsVersion::V12 => "^18.2.0", + } + } +} diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs b/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs new file mode 100644 index 00000000000000..3dd4f09b9a3a8e --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs @@ -0,0 +1,63 @@ +use std::{ + path::Path, + process::{Child, Command, Stdio}, +}; + +use anyhow::{anyhow, Context, Result}; +use regex::Regex; + +use crate::{ + bundlers::Bundler, + util::{npm, wait_for_match}, +}; + +pub struct Parcel; +impl Bundler for Parcel { + fn get_name(&self) -> &str { + "Parcel CSR" + } + + fn prepare(&self, install_dir: &Path) -> Result<()> { + npm::install(install_dir, "parcel", "2.7.0") + .context("failed to install `parcel` module")?; + + // `process` would otherwise be auto-installed by Parcel. Do this in advance as + // to not influence the benchmark. + npm::install(install_dir, "process", "^0.11.0") + .context("failed to install `process` module")?; + Ok(()) + } + + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { + let mut proc = Command::new("node") + .args([ + (test_dir + .join("node_modules") + .join("parcel") + .join("lib") + .join("bin.js") + .to_str() + .unwrap()), + "--port", + &portpicker::pick_unused_port() + .ok_or_else(|| anyhow!("failed to pick unused port"))? + .to_string(), + "index.html", + ]) + .current_dir(test_dir) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .context("failed to run `parcel` command")?; + + let addr = wait_for_match( + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("Server running at\\s+(.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; + + Ok((proc, addr)) + } +} diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs new file mode 100644 index 00000000000000..603c99f95357ab --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -0,0 +1,75 @@ +use std::{ + path::Path, + process::{Child, Command, Stdio}, +}; + +use anyhow::{anyhow, Context, Result}; +use regex::Regex; + +use crate::{ + bundlers::Bundler, + util::{npm, wait_for_match}, +}; + +pub struct Turbopack { + name: String, + path: String, + has_server_rendered_html: bool, +} + +impl Turbopack { + pub fn new(name: &str, path: &str, has_server_rendered_html: bool) -> Self { + Turbopack { + name: name.to_owned(), + path: path.to_owned(), + has_server_rendered_html, + } + } +} + +impl Bundler for Turbopack { + fn get_name(&self) -> &str { + &self.name + } + + fn get_path(&self) -> &str { + &self.path + } + + fn has_server_rendered_html(&self) -> bool { + self.has_server_rendered_html + } + + fn prepare(&self, install_dir: &Path) -> Result<()> { + npm::install(install_dir, "react-refresh", "^0.12.0") + .context("failed to install `react-refresh` module")?; + npm::install(install_dir, "@next/react-refresh-utils", "^12.2.5") + .context("failed to install `@next/react-refresh-utils` module")?; + Ok(()) + } + + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { + let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) + .args([ + test_dir + .to_str() + .ok_or_else(|| anyhow!("failed to convert test directory path to string"))?, + "--no-open", + "--port", + "0", + ]) + .stdout(Stdio::piped()) + .spawn()?; + + // Wait for the devserver address to appear in stdout. + let addr = wait_for_match( + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("server listening on: (.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; + + Ok((proc, addr)) + } +} diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs b/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs new file mode 100644 index 00000000000000..0576f121c4987c --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs @@ -0,0 +1,62 @@ +use std::{ + path::Path, + process::{Child, Command, Stdio}, +}; + +use anyhow::{anyhow, Context, Result}; +use regex::Regex; + +use crate::{ + bundlers::Bundler, + util::{npm, wait_for_match}, +}; + +pub struct Vite; + +impl Vite { + pub fn new() -> Self { + Vite {} + } +} + +impl Bundler for Vite { + fn get_name(&self) -> &str { + "Vite CSR" + } + + fn prepare(&self, install_dir: &Path) -> Result<()> { + npm::install(install_dir, "vite", "3.0.9").context("failed to install `vite` module")?; + Ok(()) + } + + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { + let mut proc = Command::new("node") + .args([ + (test_dir + .join("node_modules") + .join("vite") + .join("bin") + .join("vite.js") + .to_str() + .unwrap()), + "--port", + "0", + ]) + .env("NO_COLOR", "1") + .current_dir(test_dir) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .context("failed to run `vite` command")?; + + let addr = wait_for_match( + proc.stdout + .as_mut() + .ok_or_else(|| anyhow!("missing stdout"))?, + Regex::new("Local:\\s+(.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; + + Ok((proc, addr)) + } +} diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 73fa33a20eaa51..5cebe205b200c5 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -1,122 +1,26 @@ use std::{ fs::{self}, - future::Future, - io::{self, Write}, - path::{Path, PathBuf}, - process::Child, + path::Path, time::Duration, }; use anyhow::{anyhow, Context, Result}; -use bundlers::{command, get_bundlers, Bundler}; -use chromiumoxide::{ - browser::{Browser, BrowserConfig}, - cdp::{ - browser_protocol::network::EventResponseReceived, - js_protocol::runtime::{AddBindingParams, EventBindingCalled, EventExceptionThrown}, - }, - error::CdpError::Ws, - listeners::EventStream, - Page, -}; +use bundlers::get_bundlers; use criterion::{ - async_executor::AsyncExecutor, - black_box, criterion_group, criterion_main, - measurement::{Measurement, WallTime}, - AsyncBencher, BenchmarkGroup, BenchmarkId, Criterion, + criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, BenchmarkId, Criterion, }; -use futures::{FutureExt, StreamExt}; use tokio::{ runtime::Runtime, time::{sleep, timeout}, }; -use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; -use turbopack_create_test_app::test_app_builder::{PackageJsonConfig, TestApp, TestAppBuilder}; -use url::Url; +use util::{ + build_test, create_browser, AsyncBencherExtension, PageGuard, PreparedApp, BINDING_NAME, +}; mod bundlers; - -const BINDING_NAME: &str = "__turbopackBenchBinding"; -const TEST_APP_HYDRATION_DONE: &str = "Hydration done"; +mod util; const MAX_UPDATE_TIMEOUT: Duration = Duration::from_secs(20); -const MAX_HYDRATION_TIMEOUT: Duration = Duration::from_secs(30); - -fn get_module_counts() -> Vec { - let config = std::env::var("TURBOPACK_BENCH_COUNTS").ok(); - match config.as_deref() { - None | Some("") => { - vec![100, 1_000] - } - Some(config) => config - .split(",") - .map(|s| s.parse().expect("Invalid value for TURBOPACK_BENCH_COUNTS")) - .collect(), - } -} - -fn retry(mut args: A, f: F, max_retries: usize, mut timeout: Duration) -> Result -where - F: Fn(&mut A) -> Result, -{ - let mut retries = 0usize; - loop { - match f(&mut args) { - Ok(value) => return Ok(value), - Err(e) => { - if retries >= max_retries { - return Err(e); - } - retries += 1; - std::thread::sleep(timeout); - timeout += timeout; - } - } - } -} - -fn retry_default(args: A, f: F) -> Result -where - F: Fn(&mut A) -> Result, -{ - // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total - retry(args, f, 5, Duration::from_secs(5)) -} - -async fn retry_async( - mut args: A, - f: F, - max_retries: usize, - mut timeout: Duration, -) -> Result -where - F: Fn(&mut A) -> Fut, - Fut: Future>, -{ - let mut retries = 0usize; - loop { - match f(&mut args).await { - Ok(value) => return Ok(value), - Err(e) => { - if retries >= max_retries { - return Err(e); - } - retries += 1; - tokio::time::sleep(timeout).await; - timeout += timeout; - } - } - } -} - -async fn retry_async_default(args: A, f: F) -> Result -where - F: Fn(&mut A) -> Fut, - Fut: Future>, -{ - // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total - retry_async(args, f, 5, Duration::from_secs(5)).await -} fn bench_startup(c: &mut Criterion) { let mut g = c.benchmark_group("bench_startup"); @@ -256,12 +160,6 @@ fn bench_simple_file_change(c: &mut Criterion) { } } -/// Adds benchmark-specific bindings to the page. -async fn add_binding(page: &Page) -> Result<()> { - page.execute(AddBindingParams::new(BINDING_NAME)).await?; - Ok(()) -} - fn bench_restart(c: &mut Criterion) { let mut g = c.benchmark_group("bench_restart"); g.sample_size(10); @@ -312,332 +210,16 @@ fn bench_restart(c: &mut Criterion) { } } -struct PreparedApp<'a> { - bundler: &'a dyn Bundler, - server: Option<(Child, String)>, - test_dir: tempfile::TempDir, - counter: usize, -} - -impl<'a> PreparedApp<'a> { - fn new(bundler: &'a dyn Bundler, template_dir: PathBuf) -> Result { - let test_dir = tempfile::tempdir()?; - - fs_extra::dir::copy( - &template_dir, - &test_dir, - &fs_extra::dir::CopyOptions { - content_only: true, - ..fs_extra::dir::CopyOptions::default() - }, - )?; - - Ok(Self { - bundler, - server: None, - test_dir, - counter: 0, - }) - } - - fn counter(&mut self) -> usize { - self.counter += 1; - self.counter - } - - fn start_server(&mut self) -> Result<()> { - assert!(self.server.is_none(), "Server already started"); - - self.server = Some(self.bundler.start_server(self.test_dir.path())?); - - Ok(()) - } - - async fn with_page(self, browser: &Browser) -> Result> { - let server = self.server.as_ref().context("Server must be started")?; - let page = browser.new_page("about:blank").await?; - // Bindings survive page reloads. Set them up as early as possible. - add_binding(&page).await?; - - let mut errors = page.event_listener::().await?; - let binding_events = page.event_listener::().await?; - let mut network_response_events = page.event_listener::().await?; - - let destination = Url::parse(&server.1)?.join(self.bundler.get_path())?; - // We can't use page.goto() here since this will wait for the naviation to be - // completed. A naviation would be complete when all sync script are - // evaluated, but the page actually can rendered earlier without JavaScript - // needing to be evaluated. - // So instead we navigate via JavaScript and wait only for the HTML response to - // be completed. - page.evaluate_expression(format!("window.location='{destination}'")) - .await?; - - // Wait for HTML response completed - loop { - match network_response_events.next().await { - Some(event) => { - if event.response.url == destination.as_str() { - break; - } - } - None => return Err(anyhow!("event stream ended too early")), - } - } - - // Make sure no runtime errors occurred when loading the page - assert!(errors.next().now_or_never().is_none()); - - let page_guard = PageGuard::new(page, binding_events, self); - - Ok(page_guard) - } - - fn stop_server(&mut self) -> Result<()> { - let mut proc = self.server.take().expect("Server never started").0; - stop_process(&mut proc)?; - Ok(()) - } - - fn path(&self) -> &Path { - self.test_dir.path() - } -} - -impl<'a> Drop for PreparedApp<'a> { - fn drop(&mut self) { - if let Some(mut server) = self.server.take() { - stop_process(&mut server.0).expect("failed to stop process"); - } - } -} - -/// Closes a browser page on Drop. -struct PageGuard<'a> { - page: Option, - app: Option>, - events: EventStream, -} - -impl<'a> PageGuard<'a> { - /// Creates a new guard for the given page. - pub fn new(page: Page, events: EventStream, app: PreparedApp<'a>) -> Self { - Self { - page: Some(page), - app: Some(app), - events, - } - } - - /// Returns a reference to the app. - pub fn app(&self) -> &PreparedApp<'a> { - // Invariant: app is always Some while the guard is alive. - self.app.as_ref().unwrap() - } - - /// Returns a mutable reference to the app. - pub fn app_mut(&mut self) -> &mut PreparedApp<'a> { - // Invariant: app is always Some while the guard is alive. - self.app.as_mut().unwrap() - } - - /// Closes the page, returns the app. - pub async fn close_page(mut self) -> Result> { - // Invariant: the page is always Some while the guard is alive. - self.page.take().unwrap().close().await?; - Ok( - // Invariant: the app is always Some while the guard is alive. - self.app.take().unwrap(), - ) - } - - /// Waits until the binding is called with the given payload. - pub async fn wait_for_binding(&mut self, payload: &str) -> Result<()> { - while let Some(event) = self.events.next().await { - if event.name == BINDING_NAME && event.payload == payload { - return Ok(()); - } - } - - Err(anyhow!("event stream ended before binding was called")) - } - - /// Waits until the page and the page JavaScript is hydrated. - pub async fn wait_for_hydration(&mut self) -> Result<()> { - timeout( - MAX_HYDRATION_TIMEOUT, - self.wait_for_binding(TEST_APP_HYDRATION_DONE), - ) - .await??; - Ok(()) - } -} - -impl<'a> Drop for PageGuard<'a> { - fn drop(&mut self) { - // The page might have been closed already in `close_page`. - if let Some(page) = self.page.take() { - // This is a way to block on a future in a destructor. It's not ideal, but for - // the purposes of this benchmark it's fine. - futures::executor::block_on(page.close()).expect("failed to close page"); - } - } -} - -#[cfg(unix)] -fn stop_process(proc: &mut Child) -> Result<()> { - use nix::{ - sys::signal::{kill, Signal}, - unistd::Pid, - }; - - const KILL_DEADLINE: Duration = Duration::from_secs(5); - const KILL_DEADLINE_CHECK_STEPS: u32 = 10; - - let pid = Pid::from_raw(proc.id() as _); - match kill(pid, Signal::SIGINT) { - Ok(()) => { - let expire = std::time::Instant::now() + KILL_DEADLINE; - while let Ok(None) = proc.try_wait() { - if std::time::Instant::now() > expire { - break; - } - std::thread::sleep(KILL_DEADLINE / KILL_DEADLINE_CHECK_STEPS); - } - if let Ok(None) = proc.try_wait() { - eprintln!("Process {} did not exit after SIGINT, sending SIGKILL", pid); - kill_process(proc)?; - } - } - Err(_) => { - eprintln!("Failed to send SIGINT to process {}, sending SIGKILL", pid); - kill_process(proc)?; - } - } - Ok(()) -} - -#[cfg(not(unix))] -fn stop_process(proc: &mut Child) -> Result<()> { - kill_process(proc) -} - -fn kill_process(proc: &mut Child) -> Result<()> { - proc.kill()?; - proc.wait()?; - Ok(()) -} - -fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { - let test_app = TestAppBuilder { - module_count, - directories_count: module_count / 20, - package_json: Some(PackageJsonConfig { - react_version: bundler.react_version().to_string(), - }), - ..Default::default() - } - .build() - .unwrap(); - - let npm = command("npm") - .args(["install", "--prefer-offline", "--loglevel=error"]) - .current_dir(&test_app.path()) - .output() - .unwrap(); - - if !npm.status.success() { - io::stdout().write_all(&npm.stdout).unwrap(); - io::stderr().write_all(&npm.stderr).unwrap(); - panic!("npm install failed. See above."); - } - - retry_default((), |_| bundler.prepare(test_app.path())).unwrap(); - - test_app -} - -async fn create_browser() -> Browser { - let (browser, mut handler) = Browser::launch(BrowserConfig::builder().build().unwrap()) - .await - .unwrap(); - - // See https://crates.io/crates/chromiumoxide - tokio::task::spawn(async move { - loop { - if let Err(Ws(Protocol(ResetWithoutClosingHandshake))) = handler.next().await.unwrap() { - break; - } +fn get_module_counts() -> Vec { + let config = std::env::var("TURBOPACK_BENCH_COUNTS").ok(); + match config.as_deref() { + None | Some("") => { + vec![100, 1_000] } - }); - - browser -} - -trait AsyncBencherExtension { - fn try_iter_async(&mut self, setup: S, routine: R, teardown: T) - where - S: Fn() -> SF, - SF: Future>, - R: Fn(I) -> F, - F: Future>, - T: Fn(O) -> TF, - TF: Future; -} - -impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, WallTime> { - #[inline(never)] - fn try_iter_async(&mut self, setup: S, routine: R, teardown: T) - where - S: Fn() -> SF, - SF: Future>, - R: Fn(I) -> F, - F: Future>, - T: Fn(O) -> TF, - TF: Future, - { - let setup = &setup; - let routine = &routine; - let teardown = &teardown; - self.iter_custom(|iters| async move { - let measurement = WallTime; - let mut value = measurement.zero(); - - let mut iter = 0u64; - let mut failures = 0u64; - while iter < iters { - let output = loop { - let input = black_box( - retry_async_default((), |_| setup()) - .await - .expect("failed to setup"), - ); - - let start = measurement.start(); - match routine(input).await { - Ok(output) => { - let duration = measurement.end(start); - value = measurement.add(&value, &duration); - iter += 1; - break output; - } - Err(err) => { - failures += 1; - if failures > iters { - panic!("Routine failed {failures} times, aborting\n{:?}", err) - } else { - eprintln!("Routine failed, will be retried: {:?}", err); - continue; - } - } - } - }; - - teardown(black_box(output)).await; - } - - value - }) + Some(config) => config + .split(',') + .map(|s| s.parse().expect("Invalid value for TURBOPACK_BENCH_COUNTS")) + .collect(), } } diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs new file mode 100644 index 00000000000000..46b0607d2d49a7 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -0,0 +1,232 @@ +use std::{ + io::{self, BufRead, BufReader, Write}, + process::{ChildStdout, Command}, + time::Duration, +}; + +use anyhow::Result; +use chromiumoxide::{ + browser::{Browser, BrowserConfig}, + error::CdpError::Ws, +}; +use criterion::{ + async_executor::AsyncExecutor, + black_box, + measurement::{Measurement, WallTime}, + AsyncBencher, +}; +use futures::{Future, StreamExt}; +pub use page_guard::PageGuard; +pub use prepared_app::PreparedApp; +use regex::Regex; +use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; +use turbopack_create_test_app::test_app_builder::{PackageJsonConfig, TestApp, TestAppBuilder}; + +use crate::bundlers::Bundler; + +pub mod npm; +mod page_guard; +mod prepared_app; + +pub const BINDING_NAME: &str = "__turbopackBenchBinding"; + +fn retry(mut args: A, f: F, max_retries: usize, mut timeout: Duration) -> Result +where + F: Fn(&mut A) -> Result, +{ + let mut retries = 0usize; + loop { + match f(&mut args) { + Ok(value) => return Ok(value), + Err(e) => { + if retries >= max_retries { + return Err(e); + } + retries += 1; + std::thread::sleep(timeout); + timeout += timeout; + } + } + } +} + +fn retry_default(args: A, f: F) -> Result +where + F: Fn(&mut A) -> Result, +{ + // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total + retry(args, f, 5, Duration::from_secs(5)) +} + +async fn retry_async( + mut args: A, + f: F, + max_retries: usize, + mut timeout: Duration, +) -> Result +where + F: Fn(&mut A) -> Fut, + Fut: Future>, +{ + let mut retries = 0usize; + loop { + match f(&mut args).await { + Ok(value) => return Ok(value), + Err(e) => { + if retries >= max_retries { + return Err(e); + } + retries += 1; + tokio::time::sleep(timeout).await; + timeout += timeout; + } + } + } +} + +async fn retry_async_default(args: A, f: F) -> Result +where + F: Fn(&mut A) -> Fut, + Fut: Future>, +{ + // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total + retry_async(args, f, 5, Duration::from_secs(5)).await +} + +pub fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { + let test_app = TestAppBuilder { + module_count, + directories_count: module_count / 20, + package_json: Some(PackageJsonConfig { + react_version: bundler.react_version().to_string(), + }), + ..Default::default() + } + .build() + .unwrap(); + + let npm = command("npm") + .args(["install", "--prefer-offline", "--loglevel=error"]) + .current_dir(&test_app.path()) + .output() + .unwrap(); + + if !npm.status.success() { + io::stdout().write_all(&npm.stdout).unwrap(); + io::stderr().write_all(&npm.stderr).unwrap(); + panic!("npm install failed. See above."); + } + + retry_default((), |_| bundler.prepare(test_app.path())).unwrap(); + + test_app +} + +pub async fn create_browser() -> Browser { + let (browser, mut handler) = Browser::launch(BrowserConfig::builder().build().unwrap()) + .await + .unwrap(); + + // See https://crates.io/crates/chromiumoxide + tokio::task::spawn(async move { + loop { + if let Err(Ws(Protocol(ResetWithoutClosingHandshake))) = handler.next().await.unwrap() { + break; + } + } + }); + + browser +} + +pub trait AsyncBencherExtension { + fn try_iter_async(&mut self, setup: S, routine: R, teardown: T) + where + S: Fn() -> SF, + SF: Future>, + R: Fn(I) -> F, + F: Future>, + T: Fn(O) -> TF, + TF: Future; +} + +impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, WallTime> { + #[inline(never)] + fn try_iter_async(&mut self, setup: S, routine: R, teardown: T) + where + S: Fn() -> SF, + SF: Future>, + R: Fn(I) -> F, + F: Future>, + T: Fn(O) -> TF, + TF: Future, + { + let setup = &setup; + let routine = &routine; + let teardown = &teardown; + self.iter_custom(|iters| async move { + let measurement = WallTime; + let mut value = measurement.zero(); + + let mut iter = 0u64; + let mut failures = 0u64; + while iter < iters { + let output = loop { + let input = black_box( + retry_async_default((), |_| setup()) + .await + .expect("failed to setup"), + ); + + let start = measurement.start(); + match routine(input).await { + Ok(output) => { + let duration = measurement.end(start); + value = measurement.add(&value, &duration); + iter += 1; + break output; + } + Err(err) => { + failures += 1; + if failures > iters { + panic!("Routine failed {failures} times, aborting\n{:?}", err) + } else { + eprintln!("Routine failed, will be retried: {:?}", err); + continue; + } + } + } + }; + + teardown(black_box(output)).await; + } + + value + }) + } +} + +pub fn command(bin: &str) -> Command { + if cfg!(windows) { + let mut command = Command::new("cmd.exe"); + command.args(["/C", bin]); + command + } else { + Command::new(bin) + } +} + +pub fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> Option { + // See https://docs.rs/async-process/latest/async_process/#examples + let mut line_reader = BufReader::new(stdout).lines(); + // Read until the match appears in the buffer + let mut matched: Option = None; + while let Some(Ok(line)) = line_reader.next() { + if let Some(cap) = re.captures(&line) { + matched = Some(cap.get(1).unwrap().as_str().into()); + break; + } + } + + matched +} diff --git a/packages/next-swc/crates/next-dev/benches/util/npm.rs b/packages/next-swc/crates/next-dev/benches/util/npm.rs new file mode 100644 index 00000000000000..358edd797c04b3 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/util/npm.rs @@ -0,0 +1,43 @@ +use std::{ + fs::{self, File}, + io::{self, Write}, + path::Path, +}; + +use anyhow::{anyhow, Result}; + +use crate::util::command; + +pub fn install(install_dir: &Path, package_name: &str, package_version_expr: &str) -> Result<()> { + if !fs::metadata(install_dir.join("package.json")) + .map(|metadata| metadata.is_file()) + .unwrap_or(false) + { + // Create a simple package.json if one doesn't exist + + let package_json = json::object! { + private: true, + version: "0.0.0", + }; + + File::create(install_dir.join("package.json"))? + .write_all(package_json.pretty(2).as_bytes())?; + } + + let npm = command("npm") + .args([ + "install", + "--force", + &format!("{}@{}", package_name, package_version_expr), + ]) + .current_dir(install_dir) + .output()?; + + if !npm.status.success() { + io::stdout().write_all(&npm.stdout)?; + io::stderr().write_all(&npm.stderr)?; + return Err(anyhow!("npm install failed. See above.")); + } + + Ok(()) +} diff --git a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs new file mode 100644 index 00000000000000..4733af7edd1b35 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs @@ -0,0 +1,83 @@ +use std::time::Duration; + +use anyhow::{anyhow, Result}; +use chromiumoxide::{cdp::js_protocol::runtime::EventBindingCalled, listeners::EventStream, Page}; +use futures::StreamExt; +use tokio::time::timeout; + +use crate::{PreparedApp, BINDING_NAME}; + +const MAX_HYDRATION_TIMEOUT: Duration = Duration::from_secs(30); +const TEST_APP_HYDRATION_DONE: &str = "Hydration done"; + +/// Closes a browser page on Drop. +pub struct PageGuard<'a> { + page: Option, + app: Option>, + events: EventStream, +} + +impl<'a> PageGuard<'a> { + /// Creates a new guard for the given page. + pub fn new(page: Page, events: EventStream, app: PreparedApp<'a>) -> Self { + Self { + page: Some(page), + app: Some(app), + events, + } + } + + /// Returns a reference to the app. + pub fn app(&self) -> &PreparedApp<'a> { + // Invariant: app is always Some while the guard is alive. + self.app.as_ref().unwrap() + } + + /// Returns a mutable reference to the app. + pub fn app_mut(&mut self) -> &mut PreparedApp<'a> { + // Invariant: app is always Some while the guard is alive. + self.app.as_mut().unwrap() + } + + /// Closes the page, returns the app. + pub async fn close_page(mut self) -> Result> { + // Invariant: the page is always Some while the guard is alive. + self.page.take().unwrap().close().await?; + Ok( + // Invariant: the app is always Some while the guard is alive. + self.app.take().unwrap(), + ) + } + + /// Waits until the binding is called with the given payload. + pub async fn wait_for_binding(&mut self, payload: &str) -> Result<()> { + while let Some(event) = self.events.next().await { + if event.name == BINDING_NAME && event.payload == payload { + return Ok(()); + } + } + + Err(anyhow!("event stream ended before binding was called")) + } + + /// Waits until the page and the page JavaScript is hydrated. + pub async fn wait_for_hydration(&mut self) -> Result<()> { + timeout( + MAX_HYDRATION_TIMEOUT, + self.wait_for_binding(TEST_APP_HYDRATION_DONE), + ) + .await??; + Ok(()) + } +} + +impl<'a> Drop for PageGuard<'a> { + fn drop(&mut self) { + // The page might have been closed already in `close_page`. + if let Some(page) = self.page.take() { + // This is a way to block on a future in a destructor. It's not ideal, but for + // the purposes of this benchmark it's fine. + futures::executor::block_on(page.close()).expect("failed to close page"); + } + } +} diff --git a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs new file mode 100644 index 00000000000000..2fd2273f7a9010 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs @@ -0,0 +1,169 @@ +use std::{ + path::{Path, PathBuf}, + process::Child, +}; + +use anyhow::{anyhow, Context, Result}; +use chromiumoxide::{ + cdp::{ + browser_protocol::network::EventResponseReceived, + js_protocol::runtime::{AddBindingParams, EventBindingCalled, EventExceptionThrown}, + }, + Browser, Page, +}; +use futures::{FutureExt, StreamExt}; +use url::Url; + +use crate::{bundlers::Bundler, util::PageGuard, BINDING_NAME}; + +pub struct PreparedApp<'a> { + bundler: &'a dyn Bundler, + server: Option<(Child, String)>, + test_dir: tempfile::TempDir, + counter: usize, +} + +impl<'a> PreparedApp<'a> { + pub fn new(bundler: &'a dyn Bundler, template_dir: PathBuf) -> Result { + let test_dir = tempfile::tempdir()?; + + fs_extra::dir::copy( + &template_dir, + &test_dir, + &fs_extra::dir::CopyOptions { + content_only: true, + ..fs_extra::dir::CopyOptions::default() + }, + )?; + + Ok(Self { + bundler, + server: None, + test_dir, + counter: 0, + }) + } + + pub fn counter(&mut self) -> usize { + self.counter += 1; + self.counter + } + + pub fn start_server(&mut self) -> Result<()> { + assert!(self.server.is_none(), "Server already started"); + + self.server = Some(self.bundler.start_server(self.test_dir.path())?); + + Ok(()) + } + + pub async fn with_page(self, browser: &Browser) -> Result> { + let server = self.server.as_ref().context("Server must be started")?; + let page = browser.new_page("about:blank").await?; + // Bindings survive page reloads. Set them up as early as possible. + add_binding(&page).await?; + + let mut errors = page.event_listener::().await?; + let binding_events = page.event_listener::().await?; + let mut network_response_events = page.event_listener::().await?; + + let destination = Url::parse(&server.1)?.join(self.bundler.get_path())?; + // We can't use page.goto() here since this will wait for the naviation to be + // completed. A naviation would be complete when all sync script are + // evaluated, but the page actually can rendered earlier without JavaScript + // needing to be evaluated. + // So instead we navigate via JavaScript and wait only for the HTML response to + // be completed. + page.evaluate_expression(format!("window.location='{destination}'")) + .await?; + + // Wait for HTML response completed + loop { + match network_response_events.next().await { + Some(event) => { + if event.response.url == destination.as_str() { + break; + } + } + None => return Err(anyhow!("event stream ended too early")), + } + } + + // Make sure no runtime errors occurred when loading the page + assert!(errors.next().now_or_never().is_none()); + + let page_guard = PageGuard::new(page, binding_events, self); + + Ok(page_guard) + } + + pub fn stop_server(&mut self) -> Result<()> { + let mut proc = self.server.take().expect("Server never started").0; + stop_process(&mut proc)?; + Ok(()) + } + + pub fn path(&self) -> &Path { + self.test_dir.path() + } +} + +impl<'a> Drop for PreparedApp<'a> { + fn drop(&mut self) { + if let Some(mut server) = self.server.take() { + stop_process(&mut server.0).expect("failed to stop process"); + } + } +} + +/// Adds benchmark-specific bindings to the page. +async fn add_binding(page: &Page) -> Result<()> { + page.execute(AddBindingParams::new(BINDING_NAME)).await?; + Ok(()) +} + +#[cfg(unix)] +fn stop_process(proc: &mut Child) -> Result<()> { + use std::time::Duration; + + use nix::{ + sys::signal::{kill, Signal}, + unistd::Pid, + }; + + const KILL_DEADLINE: Duration = Duration::from_secs(5); + const KILL_DEADLINE_CHECK_STEPS: u32 = 10; + + let pid = Pid::from_raw(proc.id() as _); + match kill(pid, Signal::SIGINT) { + Ok(()) => { + let expire = std::time::Instant::now() + KILL_DEADLINE; + while let Ok(None) = proc.try_wait() { + if std::time::Instant::now() > expire { + break; + } + std::thread::sleep(KILL_DEADLINE / KILL_DEADLINE_CHECK_STEPS); + } + if let Ok(None) = proc.try_wait() { + eprintln!("Process {} did not exit after SIGINT, sending SIGKILL", pid); + kill_process(proc)?; + } + } + Err(_) => { + eprintln!("Failed to send SIGINT to process {}, sending SIGKILL", pid); + kill_process(proc)?; + } + } + Ok(()) +} + +#[cfg(not(unix))] +fn stop_process(proc: &mut Child) -> Result<()> { + kill_process(proc) +} + +fn kill_process(proc: &mut Child) -> Result<()> { + proc.kill()?; + proc.wait()?; + Ok(()) +} From aaa640def6fa42c8bceeb7bde100460677487077 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 12 Sep 2022 11:09:26 -0700 Subject: [PATCH 076/672] Benchmark Webpack (vercel/turbo#338) This adds webpack 5 to the benchmark suite. Test Plan: Manually confirmed package.json updates and webpack config written to temp dir correctly. `cargo bench`. --- .../crates/next-dev/benches/bundlers/mod.rs | 7 +- .../next-dev/benches/bundlers/webpack/mod.rs | 75 +++++++++++++++++++ .../bundlers/webpack/webpack.config.js | 54 +++++++++++++ .../crates/next-dev/benches/util/mod.rs | 11 ++- 4 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs index cc695f409f7314..75eaaf99d20889 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs @@ -7,12 +7,14 @@ use self::{ parcel::Parcel, turbopack::Turbopack, vite::Vite, + webpack::Webpack, }; mod nextjs; mod parcel; mod turbopack; mod vite; +mod webpack; pub trait Bundler { fn get_name(&self) -> &str; @@ -55,10 +57,11 @@ pub fn get_bundlers() -> Vec> { } if others { - bundlers.push(Box::new(Parcel {})); - bundlers.push(Box::new(Vite::new())); bundlers.push(Box::new(NextJs::new(NextJsVersion::V12))); bundlers.push(Box::new(NextJs::new(NextJsVersion::V11))); + bundlers.push(Box::new(Parcel {})); + bundlers.push(Box::new(Vite::new())); + bundlers.push(Box::new(Webpack {})); } bundlers diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs new file mode 100644 index 00000000000000..1446005049f18e --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs @@ -0,0 +1,75 @@ +use std::{ + fs, + path::Path, + process::{Child, Command, Stdio}, +}; + +use anyhow::{anyhow, Context, Result}; +use regex::Regex; + +use crate::{ + bundlers::Bundler, + util::{npm, wait_for_match}, +}; + +pub struct Webpack; +impl Bundler for Webpack { + fn get_name(&self) -> &str { + "Webpack CSR" + } + + fn prepare(&self, install_dir: &Path) -> Result<()> { + npm::install(install_dir, "@pmmmwh/react-refresh-webpack-plugin", "0.5.7") + .context("failed to install `@pmmmwh/react-refresh-webpack-plugin` module")?; + npm::install(install_dir, "@swc/core", "1.2.249") + .context("failed to install `@swc/core` module")?; + npm::install(install_dir, "react-refresh", "0.14.0") + .context("failed to install `react-refresh` module")?; + npm::install(install_dir, "swc-loader", "0.2.3") + .context("failed to install `swc-loader` module")?; + npm::install(install_dir, "webpack", "5.74.0") + .context("failed to install `webpack` module")?; + npm::install(install_dir, "webpack-cli", "4.10.0") + .context("failed to install `webpack-cli` module")?; + npm::install(install_dir, "webpack-dev-server", "4.11.0") + .context("failed to install `webpack-dev-server` module")?; + + fs::write( + install_dir.join("webpack.config.js"), + include_bytes!("webpack.config.js"), + )?; + + Ok(()) + } + + fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { + let mut proc = Command::new("node") + .args([ + (test_dir + .join("node_modules") + .join("webpack-dev-server") + .join("bin") + .join("webpack-dev-server.js") + .to_str() + .unwrap()), + "--port", + "0", + ]) + .env("NO_COLOR", "1") + .current_dir(test_dir) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("failed to run `webpack-dev-server` command")?; + + let addr = wait_for_match( + proc.stderr + .as_mut() + .ok_or_else(|| anyhow!("missing stderr"))?, + Regex::new("\\[webpack\\-dev\\-server\\] Loopback:\\s+(.*)")?, + ) + .ok_or_else(|| anyhow!("failed to find devserver address"))?; + + Ok((proc, addr)) + } +} diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js new file mode 100644 index 00000000000000..ce2c7509d921c8 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js @@ -0,0 +1,54 @@ +const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin') + +module.exports = { + mode: 'development', + resolve: { + extensions: ['.jsx', '...'], + }, + module: { + unsafeCache: true, + rules: [ + { + test: /\.jsx$/, + loader: 'swc-loader', + options: { + jsc: { + parser: { + syntax: 'ecmascript', + jsx: true, + dynamicImport: true, + privateMethod: true, + functionBind: true, + classPrivateProperty: true, + exportDefaultFrom: true, + exportNamespaceFrom: true, + decorators: true, + decoratorsBeforeExport: true, + importMeta: true, + }, + externalHelpers: true, + transform: { + react: { + runtime: 'automatic', + refresh: true, + }, + }, + }, + }, + }, + ], + }, + devServer: { + hot: true, + }, + cache: { + type: 'filesystem', + }, + node: { + global: true, + }, + experiments: { + futureDefaults: true, + }, + plugins: [new ReactRefreshWebpackPlugin()], +} diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index 46b0607d2d49a7..535069d3a571ba 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -1,6 +1,6 @@ use std::{ - io::{self, BufRead, BufReader, Write}, - process::{ChildStdout, Command}, + io::{self, BufRead, BufReader, Read, Write}, + process::Command, time::Duration, }; @@ -216,9 +216,12 @@ pub fn command(bin: &str) -> Command { } } -pub fn wait_for_match(stdout: &mut ChildStdout, re: Regex) -> Option { +pub fn wait_for_match(readable: R, re: Regex) -> Option +where + R: Read, +{ // See https://docs.rs/async-process/latest/async_process/#examples - let mut line_reader = BufReader::new(stdout).lines(); + let mut line_reader = BufReader::new(readable).lines(); // Read until the match appears in the buffer let mut matched: Option = None; while let Some(Ok(line)) = line_reader.next() { From eb93985d95fa3f8755ad44bfd5e54f9f18d7d338 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 12 Sep 2022 12:34:26 -0700 Subject: [PATCH 077/672] Benchmarks: allow simultaneously installing multiple packages from npm (vercel/turbo#339) Previously, we ran multiple `npm install` operations in serial using multiple calls to `install_from_npm`. Instead, this allows us to express dependencies all at once as a single command to the npm cli, which should reduce the time we spend installing from npm and updating package.json. Test Plan: Manually confirmed that package.json was updated correctly. `cargo bench`. --- .../next-dev/benches/bundlers/nextjs.rs | 12 +++++-- .../next-dev/benches/bundlers/parcel.rs | 21 ++++++++---- .../next-dev/benches/bundlers/turbopack.rs | 17 +++++++--- .../crates/next-dev/benches/bundlers/vite.rs | 8 +++-- .../next-dev/benches/bundlers/webpack/mod.rs | 32 +++++++++--------- .../crates/next-dev/benches/util/npm.rs | 33 +++++++++++++++---- 6 files changed, 85 insertions(+), 38 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs index 298d4b58e981a9..d4fe15e505b64c 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs @@ -9,7 +9,10 @@ use regex::Regex; use crate::{ bundlers::Bundler, - util::{npm, wait_for_match}, + util::{ + npm::{self, NpmPackage}, + wait_for_match, + }, }; #[derive(Debug)] @@ -51,8 +54,11 @@ impl Bundler for NextJs { } fn prepare(&self, install_dir: &Path) -> Result<()> { - npm::install(install_dir, "next", self.version.version()) - .context("failed to install `next` module")?; + npm::install( + install_dir, + &[NpmPackage::new("next", self.version.version())], + ) + .context("failed to install `next` module")?; Ok(()) } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs b/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs index 3dd4f09b9a3a8e..dd35e60afcd82d 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs @@ -8,7 +8,10 @@ use regex::Regex; use crate::{ bundlers::Bundler, - util::{npm, wait_for_match}, + util::{ + npm::{self, NpmPackage}, + wait_for_match, + }, }; pub struct Parcel; @@ -18,13 +21,17 @@ impl Bundler for Parcel { } fn prepare(&self, install_dir: &Path) -> Result<()> { - npm::install(install_dir, "parcel", "2.7.0") - .context("failed to install `parcel` module")?; + npm::install( + install_dir, + &[ + NpmPackage::new("parcel", "2.7.0"), + // `process` would otherwise be auto-installed by Parcel. Do this in advance as + // to not influence the benchmark. + NpmPackage::new("process", "0.11.0"), + ], + ) + .context("failed to install from npm")?; - // `process` would otherwise be auto-installed by Parcel. Do this in advance as - // to not influence the benchmark. - npm::install(install_dir, "process", "^0.11.0") - .context("failed to install `process` module")?; Ok(()) } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index 603c99f95357ab..c83d1c6f283e3c 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -8,7 +8,10 @@ use regex::Regex; use crate::{ bundlers::Bundler, - util::{npm, wait_for_match}, + util::{ + npm::{self, NpmPackage}, + wait_for_match, + }, }; pub struct Turbopack { @@ -41,10 +44,14 @@ impl Bundler for Turbopack { } fn prepare(&self, install_dir: &Path) -> Result<()> { - npm::install(install_dir, "react-refresh", "^0.12.0") - .context("failed to install `react-refresh` module")?; - npm::install(install_dir, "@next/react-refresh-utils", "^12.2.5") - .context("failed to install `@next/react-refresh-utils` module")?; + npm::install( + install_dir, + &[ + NpmPackage::new("react-refresh", "^0.12.0"), + NpmPackage::new("@next/react-refresh-utils", "^12.2.5"), + ], + ) + .context("failed to install from npm")?; Ok(()) } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs b/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs index 0576f121c4987c..66107477f12bd0 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs @@ -8,7 +8,10 @@ use regex::Regex; use crate::{ bundlers::Bundler, - util::{npm, wait_for_match}, + util::{ + npm::{self, NpmPackage}, + wait_for_match, + }, }; pub struct Vite; @@ -25,7 +28,8 @@ impl Bundler for Vite { } fn prepare(&self, install_dir: &Path) -> Result<()> { - npm::install(install_dir, "vite", "3.0.9").context("failed to install `vite` module")?; + npm::install(install_dir, &[NpmPackage::new("vite", "3.0.9")]) + .context("failed to install from npm")?; Ok(()) } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs index 1446005049f18e..8f2c1e040e48f5 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs @@ -9,7 +9,10 @@ use regex::Regex; use crate::{ bundlers::Bundler, - util::{npm, wait_for_match}, + util::{ + npm::{self, NpmPackage}, + wait_for_match, + }, }; pub struct Webpack; @@ -19,20 +22,19 @@ impl Bundler for Webpack { } fn prepare(&self, install_dir: &Path) -> Result<()> { - npm::install(install_dir, "@pmmmwh/react-refresh-webpack-plugin", "0.5.7") - .context("failed to install `@pmmmwh/react-refresh-webpack-plugin` module")?; - npm::install(install_dir, "@swc/core", "1.2.249") - .context("failed to install `@swc/core` module")?; - npm::install(install_dir, "react-refresh", "0.14.0") - .context("failed to install `react-refresh` module")?; - npm::install(install_dir, "swc-loader", "0.2.3") - .context("failed to install `swc-loader` module")?; - npm::install(install_dir, "webpack", "5.74.0") - .context("failed to install `webpack` module")?; - npm::install(install_dir, "webpack-cli", "4.10.0") - .context("failed to install `webpack-cli` module")?; - npm::install(install_dir, "webpack-dev-server", "4.11.0") - .context("failed to install `webpack-dev-server` module")?; + npm::install( + install_dir, + &[ + NpmPackage::new("@pmmmwh/react-refresh-webpack-plugin", "0.5.7"), + NpmPackage::new("@swc/core", "1.2.249"), + NpmPackage::new("react-refresh", "0.14.0"), + NpmPackage::new("swc-loader", "0.2.3"), + NpmPackage::new("webpack", "5.74.0"), + NpmPackage::new("webpack-cli", "4.10.0"), + NpmPackage::new("webpack-dev-server", "4.11.0"), + ], + ) + .context("failed to install from npm")?; fs::write( install_dir.join("webpack.config.js"), diff --git a/packages/next-swc/crates/next-dev/benches/util/npm.rs b/packages/next-swc/crates/next-dev/benches/util/npm.rs index 358edd797c04b3..79d4ccc7fe6599 100644 --- a/packages/next-swc/crates/next-dev/benches/util/npm.rs +++ b/packages/next-swc/crates/next-dev/benches/util/npm.rs @@ -8,7 +8,24 @@ use anyhow::{anyhow, Result}; use crate::util::command; -pub fn install(install_dir: &Path, package_name: &str, package_version_expr: &str) -> Result<()> { +pub struct NpmPackage { + pub name: &'static str, + pub version: &'static str, +} + +impl NpmPackage { + pub fn new(name: &'static str, version: &'static str) -> Self { + NpmPackage { name, version } + } +} + +impl std::fmt::Display for NpmPackage { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.write_fmt(format_args!("{}@{}", self.name, self.version)) + } +} + +pub fn install(install_dir: &Path, packages: &[NpmPackage]) -> Result<()> { if !fs::metadata(install_dir.join("package.json")) .map(|metadata| metadata.is_file()) .unwrap_or(false) @@ -24,12 +41,16 @@ pub fn install(install_dir: &Path, package_name: &str, package_version_expr: &st .write_all(package_json.pretty(2).as_bytes())?; } + let mut args = vec!["install".to_owned(), "--force".to_owned()]; + args.append( + &mut packages + .iter() + .map(|p| p.to_string()) + .collect::>(), + ); + let npm = command("npm") - .args([ - "install", - "--force", - &format!("{}@{}", package_name, package_version_expr), - ]) + .args(args) .current_dir(install_dir) .output()?; From 50aa9cc2617620727232ba981ec2ef55ea6f0029 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Wed, 14 Sep 2022 23:31:14 +0200 Subject: [PATCH 078/672] Initial support for getStaticProps (vercel/turbo#345) Remaining questions: * Should we have some static analysis for `getStaticProps` instead of looking into exports at runtime? * For now, the output of `getStaticProps` (if defined) will always trump the value passed in as `data`. If we consider `data` to be the cached output of `getStaticProps` (in the future, as this is not yet implemented), this logic should be adapted. --- .../src/server_render/server_renderer.js | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/server_render/server_renderer.js b/packages/next-swc/crates/next-core/src/server_render/server_renderer.js index 3b343b81ca1e29..15c08fd8cb41e9 100644 --- a/packages/next-swc/crates/next-core/src/server_render/server_renderer.js +++ b/packages/next-swc/crates/next-core/src/server_render/server_renderer.js @@ -1,6 +1,6 @@ const END_OF_OPERATION = process.argv[2] -import Component from '.' +import Component, * as otherExports from '.' import { renderToString, renderToStaticMarkup } from 'react-dom/server' ;('TURBOPACK { transition: next-client }') import chunkGroup from '.' @@ -9,13 +9,13 @@ process.stdout.write('READY\n') const NEW_LINE = '\n'.charCodeAt(0) let buffer = [] -process.stdin.on('data', (data) => { +process.stdin.on('data', async (data) => { let idx = data.indexOf(NEW_LINE) while (idx >= 0) { buffer.push(data.slice(0, idx)) try { let json = JSON.parse(Buffer.concat(buffer).toString('utf-8')) - let result = operation(json) + let result = await operation(json) console.log(`RESULT=${JSON.stringify(result)}`) } catch (e) { console.log(`ERROR=${JSON.stringify(e.stack)}`) @@ -27,9 +27,21 @@ process.stdin.on('data', (data) => { buffer.push(data) }) -function operation(data) { +async function operation(data) { + let staticProps = data + if ('getStaticProps' in otherExports) { + // TODO(alexkirsz) Pass in `context` as defined in + // https://nextjs.org/docs/api-reference/data-fetching/get-static-props#context-parameter + staticProps = otherExports.getStaticProps({}) + if ('then' in staticProps) { + staticProps = await staticProps + } + } + // TODO capture meta info during rendering - const rendered = { __html: renderToString() } + const rendered = { + __html: renderToString(), + } const urls = chunkGroup.map((p) => `/${p}`) const scripts = urls.filter((url) => url.endsWith('.js')) const styles = urls.filter((url) => url.endsWith('.css')) @@ -48,7 +60,7 @@ function operation(data) { id="__NEXT_DATA__" type="application/json" dangerouslySetInnerHTML={{ - __html: htmlEscapeJsonString(JSON.stringify(data)), + __html: htmlEscapeJsonString(JSON.stringify(staticProps)), }} >
From 826998cf07f32af906d4326a597995ef35f3e341 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 15 Sep 2022 01:17:14 +0200 Subject: [PATCH 079/672] increase benchmark timeouts to be able to benchmark larger module counts (vercel/turbo#362) --- packages/next-swc/crates/next-dev/benches/mod.rs | 2 +- packages/next-swc/crates/next-dev/benches/util/page_guard.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 5cebe205b200c5..25b99ecc1bf310 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -20,7 +20,7 @@ use util::{ mod bundlers; mod util; -const MAX_UPDATE_TIMEOUT: Duration = Duration::from_secs(20); +const MAX_UPDATE_TIMEOUT: Duration = Duration::from_secs(60); fn bench_startup(c: &mut Criterion) { let mut g = c.benchmark_group("bench_startup"); diff --git a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs index 4733af7edd1b35..c58d04ccea04c6 100644 --- a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs +++ b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs @@ -7,7 +7,7 @@ use tokio::time::timeout; use crate::{PreparedApp, BINDING_NAME}; -const MAX_HYDRATION_TIMEOUT: Duration = Duration::from_secs(30); +const MAX_HYDRATION_TIMEOUT: Duration = Duration::from_secs(120); const TEST_APP_HYDRATION_DONE: &str = "Hydration done"; /// Closes a browser page on Drop. From d4192f4bd5496c80cad1f3d6385083279dea8ab0 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 14 Sep 2022 16:46:18 -0700 Subject: [PATCH 080/672] Implement styled-jsx with swc's styled_jsx (vercel/turbo#354) This implements support for styled-jsx in next-dev using swc's styled_jsx crate. It's only applied in next-dev, and is only applied as a transform to app code, much like the react-refresh transform. To do: * [x] The transform doesn't seem to be applied. Pass the added test. Test Plan: `cargo test -p next-dev -- test_crates_next_dev_tests_integration_turbopack_basic_styled_jsx --nocapture` --- .../next-core/src/server_rendered_source.rs | 1 + .../crates/next-core/src/web_entry_source.rs | 1 + .../turbopack/basic/styled-jsx/index.js | 25 +++++++++++++++++++ .../crates/next-dev/tests/package.json | 5 +++- 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index f0ea3f64bab972..aa3b154ffefc8e 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -87,6 +87,7 @@ pub async fn create_server_rendered_source( }; let client_module_options_context = ModuleOptionsContext { enable_react_refresh, + enable_styled_jsx: true, } .cell(); let next_client_transition = NextClientTransition { diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 94a5517bd07004..3b05d48f8ec8d2 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -57,6 +57,7 @@ pub async fn create_web_entry_source( // we try resolve it once at the root and pass down a context to all // the modules. enable_react_refresh, + enable_styled_jsx: true, } .into(), ) diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js new file mode 100644 index 00000000000000..c0691d8d98ffee --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js @@ -0,0 +1,25 @@ +import React from 'react' +import TestRenderer from 'react-test-renderer' + +describe('styled-jsx', () => { + it('compiles away + , + ) + + expect(test.toJSON()).toMatchObject({ + children: ['This should be color: red'], + props: { + className: /jsx\-[0-9a-f]+/, + }, + type: 'span', + }) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 8c4ae087a410d7..02872e5dae7a4b 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -2,7 +2,10 @@ "private": true, "devDependencies": { "expect": "^24.5.0", - "jest-circus-browser": "^1.0.7" + "jest-circus-browser": "^1.0.7", + "react": "^18.2.0", + "react-test-renderer": "^18.2.0", + "styled-jsx": "^5.0.7" }, "installConfig": { "hoistingLimits": "workspaces" From f4e28a07ef3fb5c52f9953b6ff8d3d863fe6f404 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 15 Sep 2022 02:04:49 +0200 Subject: [PATCH 081/672] enable react refresh for vite (vercel/turbo#364) It was doing a full refresh before --- .../benches/bundlers/{vite.rs => vite/mod.rs} | 17 +++++++++++++++-- .../benches/bundlers/vite/vite.config.js | 6 ++++++ 2 files changed, 21 insertions(+), 2 deletions(-) rename packages/next-swc/crates/next-dev/benches/bundlers/{vite.rs => vite/mod.rs} (78%) create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs similarity index 78% rename from packages/next-swc/crates/next-dev/benches/bundlers/vite.rs rename to packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs index 66107477f12bd0..50f070c7e4784e 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs @@ -1,4 +1,5 @@ use std::{ + fs, path::Path, process::{Child, Command, Stdio}, }; @@ -28,8 +29,20 @@ impl Bundler for Vite { } fn prepare(&self, install_dir: &Path) -> Result<()> { - npm::install(install_dir, &[NpmPackage::new("vite", "3.0.9")]) - .context("failed to install from npm")?; + npm::install( + install_dir, + &[ + NpmPackage::new("vite", "3.0.9"), + NpmPackage::new("@vitejs/plugin-react", "2.1.0"), + ], + ) + .context("failed to install from npm")?; + + fs::write( + install_dir.join("vite.config.js"), + include_bytes!("vite.config.js"), + )?; + Ok(()) } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js new file mode 100644 index 00000000000000..9ffcc675746194 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) From b6d38cd4fd331f8eb59edc65255054a5c8974254 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 14 Sep 2022 17:24:08 -0700 Subject: [PATCH 082/672] Revert "Implement styled-jsx with swc's styled_jsx" (vercel/turbo#366) Revert "Implement styled-jsx with swc's styled_jsx (vercel/turbo#354)" This reverts commit 255a38b07c98252bfe442ee363f07924da45288a. --- .../next-core/src/server_rendered_source.rs | 1 - .../crates/next-core/src/web_entry_source.rs | 1 - .../turbopack/basic/styled-jsx/index.js | 25 ------------------- .../crates/next-dev/tests/package.json | 5 +--- 4 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index aa3b154ffefc8e..f0ea3f64bab972 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -87,7 +87,6 @@ pub async fn create_server_rendered_source( }; let client_module_options_context = ModuleOptionsContext { enable_react_refresh, - enable_styled_jsx: true, } .cell(); let next_client_transition = NextClientTransition { diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 3b05d48f8ec8d2..94a5517bd07004 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -57,7 +57,6 @@ pub async fn create_web_entry_source( // we try resolve it once at the root and pass down a context to all // the modules. enable_react_refresh, - enable_styled_jsx: true, } .into(), ) diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js deleted file mode 100644 index c0691d8d98ffee..00000000000000 --- a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react' -import TestRenderer from 'react-test-renderer' - -describe('styled-jsx', () => { - it('compiles away - , - ) - - expect(test.toJSON()).toMatchObject({ - children: ['This should be color: red'], - props: { - className: /jsx\-[0-9a-f]+/, - }, - type: 'span', - }) - }) -}) diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 02872e5dae7a4b..8c4ae087a410d7 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -2,10 +2,7 @@ "private": true, "devDependencies": { "expect": "^24.5.0", - "jest-circus-browser": "^1.0.7", - "react": "^18.2.0", - "react-test-renderer": "^18.2.0", - "styled-jsx": "^5.0.7" + "jest-circus-browser": "^1.0.7" }, "installConfig": { "hoistingLimits": "workspaces" From 22e996b90cae6cbded0d7bcb0ebbc99dfb600903 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 15 Sep 2022 11:54:07 +0200 Subject: [PATCH 083/672] ensure that HMR is really happening while measuring (vercel/turbo#365) no need to test all module counts --- .../next-swc/crates/next-dev/benches/mod.rs | 17 +++++++++++++++-- .../crates/next-dev/benches/util/page_guard.rs | 6 ++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 25b99ecc1bf310..4d10ce822e606a 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -140,6 +140,10 @@ fn bench_simple_file_change(c: &mut Criterion) { app.start_server()?; let mut guard = app.with_page(browser).await?; guard.wait_for_hydration().await?; + guard + .page() + .evaluate_expression("globalThis.HMR_IS_HAPPENING = true") + .await?; // Make warmup change make_change(&mut guard).await?; @@ -152,7 +156,16 @@ fn bench_simple_file_change(c: &mut Criterion) { // Defer the dropping of the guard to `teardown`. Ok(guard) }, - |_guard| async move {}, + |guard| async move { + let hmr_is_happening = guard + .page() + .evaluate_expression("globalThis.HMR_IS_HAPPENING") + .await + .unwrap(); + // Make sure that we are really measuring HMR and not accidentically + // full refreshing the page + assert!(hmr_is_happening.value().unwrap().as_bool().unwrap()); + }, ); }, ); @@ -226,6 +239,6 @@ fn get_module_counts() -> Vec { criterion_group!( name = benches; config = Criterion::default(); - targets = bench_startup, bench_hydration, bench_simple_file_change, bench_restart + targets = bench_startup, bench_hydration, bench_restart, bench_simple_file_change ); criterion_main!(benches); diff --git a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs index c58d04ccea04c6..ffa1b6929b89ff 100644 --- a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs +++ b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs @@ -33,6 +33,12 @@ impl<'a> PageGuard<'a> { self.app.as_ref().unwrap() } + /// Returns a reference to the page. + pub fn page(&self) -> &Page { + // Invariant: page is always Some while the guard is alive. + self.page.as_ref().unwrap() + } + /// Returns a mutable reference to the app. pub fn app_mut(&mut self) -> &mut PreparedApp<'a> { // Invariant: app is always Some while the guard is alive. From cf1eadb5ac84d29899fb117f5fd890ffcd5f7d9f Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 15 Sep 2022 13:51:45 -0700 Subject: [PATCH 084/672] Implement styled-jsx with swc's styled_jsx (vercel/turbo#367) This reverts commit ccf6c112d541f0a1a9f4e691f6220363550aaf01. --- .../next-core/src/server_rendered_source.rs | 1 + .../crates/next-core/src/web_entry_source.rs | 1 + .../turbopack/basic/styled-jsx/index.js | 25 +++++++++++++++++++ .../crates/next-dev/tests/package.json | 5 +++- 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index f0ea3f64bab972..aa3b154ffefc8e 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -87,6 +87,7 @@ pub async fn create_server_rendered_source( }; let client_module_options_context = ModuleOptionsContext { enable_react_refresh, + enable_styled_jsx: true, } .cell(); let next_client_transition = NextClientTransition { diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 94a5517bd07004..3b05d48f8ec8d2 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -57,6 +57,7 @@ pub async fn create_web_entry_source( // we try resolve it once at the root and pass down a context to all // the modules. enable_react_refresh, + enable_styled_jsx: true, } .into(), ) diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js new file mode 100644 index 00000000000000..c0691d8d98ffee --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js @@ -0,0 +1,25 @@ +import React from 'react' +import TestRenderer from 'react-test-renderer' + +describe('styled-jsx', () => { + it('compiles away + , + ) + + expect(test.toJSON()).toMatchObject({ + children: ['This should be color: red'], + props: { + className: /jsx\-[0-9a-f]+/, + }, + type: 'span', + }) + }) +}) diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 8c4ae087a410d7..02872e5dae7a4b 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -2,7 +2,10 @@ "private": true, "devDependencies": { "expect": "^24.5.0", - "jest-circus-browser": "^1.0.7" + "jest-circus-browser": "^1.0.7", + "react": "^18.2.0", + "react-test-renderer": "^18.2.0", + "styled-jsx": "^5.0.7" }, "installConfig": { "hoistingLimits": "workspaces" From 86f1831b06d0f531a568b8bc0ff0db8285e2c63f Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 16 Sep 2022 08:06:54 +0200 Subject: [PATCH 085/672] fix compare action (vercel/turbo#373) --- .../next-dev/benches/bundlers/turbopack.rs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index c83d1c6f283e3c..efd94e54732394 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -56,17 +56,20 @@ impl Bundler for Turbopack { } fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { - let mut proc = Command::new(std::env!("CARGO_BIN_EXE_next-dev")) - .args([ - test_dir - .to_str() - .ok_or_else(|| anyhow!("failed to convert test directory path to string"))?, - "--no-open", - "--port", - "0", - ]) - .stdout(Stdio::piped()) - .spawn()?; + let mut proc = Command::new( + std::env::var("CARGO_BIN_EXE_next-dev") + .unwrap_or_else(|_| std::env!("CARGO_BIN_EXE_next-dev").to_string()), + ) + .args([ + test_dir + .to_str() + .ok_or_else(|| anyhow!("failed to convert test directory path to string"))?, + "--no-open", + "--port", + "0", + ]) + .stdout(Stdio::piped()) + .spawn()?; // Wait for the devserver address to appear in stdout. let addr = wait_for_match( From 7795fafdc7519771a0cd5eb411e28fc6808ac9a8 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 16 Sep 2022 11:22:37 +0200 Subject: [PATCH 086/672] add typescript support (vercel/turbo#370) picked typescript transform from https://github.com/vercel/turbo-tooling/pull/341 add resolve options context as global resolve config enable typescript only for next-dev move emulating logic from environment to resolve options context Co-authored-by: Leah <8845940+ForsakenHarmony@users.noreply.github.com> --- .../crates/next-core/src/next_client/mod.rs | 2 + .../crates/next-core/src/react_refresh.rs | 40 +++++++++++++------ .../next-core/src/server_rendered_source.rs | 27 +++++++++++-- .../crates/next-core/src/web_entry_source.rs | 17 +++++++- 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index fe8e7cd3d96993..1770c657f1ce16 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -7,6 +7,7 @@ use turbo_tasks_fs::{File, FileContent, FileContentVc, FileSystemPathVc}; use turbopack::{ ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, module_options::ModuleOptionsContextVc, + resolve_options_context::ResolveOptionsContextVc, transition::{Transition, TransitionVc}, ModuleAssetContextVc, }; @@ -45,6 +46,7 @@ pub enum RuntimeReference { pub struct NextClientTransition { pub client_environment: EnvironmentVc, pub client_module_options_context: ModuleOptionsContextVc, + pub client_resolve_options_context: ResolveOptionsContextVc, pub client_chunking_context: ChunkingContextVc, pub server_root: FileSystemPathVc, pub runtime_references: Vec, diff --git a/packages/next-swc/crates/next-core/src/react_refresh.rs b/packages/next-swc/crates/next-core/src/react_refresh.rs index a56e2b54295cd3..15bacbe1994d6b 100644 --- a/packages/next-swc/crates/next-core/src/react_refresh.rs +++ b/packages/next-swc/crates/next-core/src/react_refresh.rs @@ -1,13 +1,18 @@ use anyhow::{anyhow, Result}; -use turbo_tasks::primitives::{BoolVc, StringVc}; +use turbo_tasks::{ + debug::ValueDebug, + primitives::{BoolVc, StringVc}, +}; use turbo_tasks_fs::FileSystemPathVc; -use turbopack::ecmascript::{ - chunk::EcmascriptChunkPlaceableVc, - resolve::{apply_cjs_specific_options, cjs_resolve}, +use turbopack::{ + ecmascript::{ + chunk::EcmascriptChunkPlaceableVc, + resolve::{apply_cjs_specific_options, cjs_resolve}, + }, + resolve_options_context::ResolveOptionsContextVc, }; use turbopack_core::{ context::AssetContextVc, - environment::EnvironmentVc, issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, resolve::{parse::RequestVc, ResolveResult}, }; @@ -25,20 +30,22 @@ pub fn react_refresh_request() -> RequestVc { #[turbo_tasks::function] pub async fn assert_can_resolve_react_refresh( path: FileSystemPathVc, - environment: EnvironmentVc, + resolve_options_context: ResolveOptionsContextVc, ) -> Result { - let resolve_options = apply_cjs_specific_options(turbopack::resolve_options(path, environment)); + let resolve_options = + apply_cjs_specific_options(turbopack::resolve_options(path, resolve_options_context)); let result = turbopack_core::resolve::resolve(path, react_refresh_request(), resolve_options); Ok(match &*result.await? { - ResolveResult::Single(_, _) => BoolVc::cell(true), + ResolveResult::Single(_, _) | ResolveResult::Alternatives(_, _) => BoolVc::cell(true), _ => { ReactRefreshResolvingIssue { path, - description: StringVc::cell( - "could not resolve the `@next/react-refresh-utils/dist/runtime` module" - .to_string(), - ), + description: StringVc::cell(format!( + "could not resolve the `@next/react-refresh-utils/dist/runtime` \ + module\nresolve options: {:?}", + resolve_options.dbg().await? + )), } .cell() .as_issue() @@ -59,6 +66,15 @@ pub async fn resolve_react_refresh(context: AssetContextVc) -> Result { + if let Some(placeable) = + EcmascriptChunkPlaceableVc::resolve_from(assets.iter().next().unwrap()).await? + { + Ok(placeable) + } else { + Err(anyhow!("React Refresh runtime asset is not placeable")) + } + } // The react-refresh-runtime module is not installed. ResolveResult::Unresolveable(_) => Err(anyhow!( "could not resolve the `@next/react-refresh-utils/dist/runtime` module" diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index aa3b154ffefc8e..68bee98d582cd8 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -4,7 +4,8 @@ use anyhow::Result; use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{ - module_options::ModuleOptionsContext, transition::TransitionsByNameVc, ModuleAssetContextVc, + module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext, + transition::TransitionsByNameVc, ModuleAssetContextVc, }; use turbopack_core::{ chunk::dev::DevChunkingContext, @@ -69,8 +70,16 @@ pub async fn create_server_rendered_source( )), Value::new(EnvironmentIntention::Client), ); + let client_resolve_options_context = ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + enable_node_modules: true, + custom_conditions: vec!["development".to_string()], + ..Default::default() + } + .cell(); let enable_react_refresh = - *assert_can_resolve_react_refresh(root_path, client_environment).await?; + *assert_can_resolve_react_refresh(root_path, client_resolve_options_context).await?; let runtime_references = if enable_react_refresh { vec![ RuntimeReference::Request(react_refresh_request(), root_path), @@ -88,11 +97,14 @@ pub async fn create_server_rendered_source( let client_module_options_context = ModuleOptionsContext { enable_react_refresh, enable_styled_jsx: true, + enable_typescript_transform: true, + ..Default::default() } .cell(); let next_client_transition = NextClientTransition { client_chunking_context, client_module_options_context, + client_resolve_options_context, client_environment, server_root: target_root, runtime_references, @@ -110,13 +122,22 @@ pub async fn create_server_rendered_source( NodeJsEnvironment { compile_target: CompileTargetVc::current(), node_version: 0, - typescript_enabled: false, } .into(), )), Value::new(EnvironmentIntention::Client), ), ModuleOptionsContext { + enable_typescript_transform: true, + ..Default::default() + } + .cell(), + ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + enable_node_modules: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string()], ..Default::default() } .cell(), diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 3b05d48f8ec8d2..473c27e43b5693 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -6,6 +6,7 @@ use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; use turbopack::{ ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}, module_options::ModuleOptionsContext, + resolve_options_context::ResolveOptionsContext, transition::TransitionsByNameVc, ModuleAssetContextVc, }; @@ -46,7 +47,16 @@ pub async fn create_web_entry_source( Value::new(EnvironmentIntention::Client), ); - let enable_react_refresh = *assert_can_resolve_react_refresh(root, environment).await?; + let resolve_options_context = ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + enable_node_modules: true, + custom_conditions: vec!["development".to_string()], + ..Default::default() + } + .cell(); + let enable_react_refresh = + *assert_can_resolve_react_refresh(root, resolve_options_context).await?; let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -58,8 +68,11 @@ pub async fn create_web_entry_source( // the modules. enable_react_refresh, enable_styled_jsx: true, + enable_typescript_transform: true, + ..Default::default() } - .into(), + .cell(), + resolve_options_context, ) .into(); From 36c3d2d80f119970856befae2a22c95468fc60cf Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 16 Sep 2022 17:08:00 +0200 Subject: [PATCH 087/672] SourceMap fixes and improvements (vercel/turbo#374) moves the logic of creating SourceMap assets into the asset reference. This avoids depending on the chunk items in the references() method directly. It also avoids calling CodeVc::source_map() until the source map is read avoid circular dependency in call graph It also avoids checking `has_source_map()` and just inserts potential Source Maps assets for every chunk item. Checking `has_source_map()` seems unnecessary work to do for all chunk items, when we can just send an empty source map. only expose SourceMaps for chunk items when HMR is enabled --- packages/next-swc/crates/next-core/src/server_render/asset.rs | 1 + packages/next-swc/crates/next-core/src/server_rendered_source.rs | 1 + packages/next-swc/crates/next-core/src/web_entry_source.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index ddc75b26bb2571..afefdb5cc6c54a 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -162,6 +162,7 @@ async fn get_intermediate_asset( context_path, chunk_root_path: intermediate_output_path.join("chunks"), asset_root_path: intermediate_output_path.join("assets"), + enable_hot_module_replacement: false, } .into(); let module = EcmascriptModuleAssetVc::new( diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 68bee98d582cd8..5779fe73bdc8d0 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -55,6 +55,7 @@ pub async fn create_server_rendered_source( context_path: root_path, chunk_root_path: target_root.join("_next/static/chunks"), asset_root_path: target_root.join("_next/static/assets"), + enable_hot_module_replacement: true, } .cell() .into(); diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 473c27e43b5693..5a83c3dba4c3ac 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -80,6 +80,7 @@ pub async fn create_web_entry_source( context_path: root, chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static/chunks"), asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static/assets"), + enable_hot_module_replacement: true, } .into(); From 6d1a83384ae21843c34221b37e2efb0189bf2e49 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 19 Sep 2022 11:24:55 +0200 Subject: [PATCH 088/672] Benchmark summarize script, workflow and stability (vercel/turbo#381) --- .../next-swc/crates/next-dev/benches/mod.rs | 272 +++++++++--------- .../crates/next-dev/benches/util/mod.rs | 13 + 2 files changed, 155 insertions(+), 130 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 4d10ce822e606a..67dd5e3818646b 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -1,5 +1,6 @@ use std::{ fs::{self}, + panic::AssertUnwindSafe, path::Path, time::Duration, }; @@ -17,6 +18,8 @@ use util::{ build_test, create_browser, AsyncBencherExtension, PageGuard, PreparedApp, BINDING_NAME, }; +use self::util::resume_on_error; + mod bundlers; mod util; @@ -57,28 +60,30 @@ fn bench_startup_internal(mut g: BenchmarkGroup, hydration: bool) { }; for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); - g.bench_with_input( - BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), - &input, - |b, &(bundler, module_count)| { - let test_app = build_test(module_count, bundler); - let template_dir = test_app.path(); - b.to_async(&runtime).try_iter_async( - || async { PreparedApp::new(bundler, template_dir.to_path_buf()) }, - |mut app| async { - app.start_server()?; - let mut guard = app.with_page(browser).await?; - if wait_for_hydration { - guard.wait_for_hydration().await?; - } - - // Defer the dropping of the guard to `teardown`. - Ok(guard) - }, - |_guard| async move {}, - ); - }, - ); + resume_on_error(AssertUnwindSafe(|| { + g.bench_with_input( + BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), + &input, + |b, &(bundler, module_count)| { + let test_app = build_test(module_count, bundler); + let template_dir = test_app.path(); + b.to_async(&runtime).try_iter_async( + || async { PreparedApp::new(bundler, template_dir.to_path_buf()) }, + |mut app| async { + app.start_server()?; + let mut guard = app.with_page(browser).await?; + if wait_for_hydration { + guard.wait_for_hydration().await?; + } + + // Defer the dropping of the guard to `teardown`. + Ok(guard) + }, + |_guard| async move {}, + ); + }, + ); + })); } } g.finish(); @@ -95,80 +100,84 @@ fn bench_simple_file_change(c: &mut Criterion) { for bundler in get_bundlers() { for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); - g.bench_with_input( - BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), - &input, - |b, &(bundler, module_count)| { - let test_app = build_test(module_count, bundler); - let template_dir = test_app.path(); - fn add_code(app_path: &Path, code: &str) -> Result<()> { - let triangle_path = app_path.join("src/triangle.jsx"); - let mut contents = fs::read_to_string(&triangle_path)?; - const COMPONENT_START: &str = - "export default function Container({ style }) {\n"; - let a = contents - .find(COMPONENT_START) - .ok_or_else(|| anyhow!("unable to find component start"))?; - let b = contents - .find("\n return <>") - .ok_or_else(|| anyhow!("unable to find component start"))?; - contents.replace_range(a..b, &format!("{COMPONENT_START}{code}")); - fs::write(&triangle_path, contents)?; - Ok(()) - } - async fn make_change<'a>(guard: &mut PageGuard<'a>) -> Result<()> { - let msg = format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); - add_code( - guard.app().path(), - &format!( - " React.useEffect(() => {{ globalThis.{BINDING_NAME}('{msg}'); \ - }});\n" - ), - )?; - - // Wait for the change introduced above to be reflected at runtime. - // This expects HMR or automatic reloading to occur. - timeout(MAX_UPDATE_TIMEOUT, guard.wait_for_binding(&msg)) - .await? - .context("update was not registered by bundler")?; - - Ok(()) - } - b.to_async(Runtime::new().unwrap()).try_iter_async( - || async { - let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; - app.start_server()?; - let mut guard = app.with_page(browser).await?; - guard.wait_for_hydration().await?; - guard - .page() - .evaluate_expression("globalThis.HMR_IS_HAPPENING = true") - .await?; - - // Make warmup change - make_change(&mut guard).await?; - - Ok(guard) - }, - |mut guard| async move { - make_change(&mut guard).await?; - - // Defer the dropping of the guard to `teardown`. - Ok(guard) - }, - |guard| async move { - let hmr_is_happening = guard - .page() - .evaluate_expression("globalThis.HMR_IS_HAPPENING") - .await - .unwrap(); - // Make sure that we are really measuring HMR and not accidentically - // full refreshing the page - assert!(hmr_is_happening.value().unwrap().as_bool().unwrap()); - }, - ); - }, - ); + resume_on_error(AssertUnwindSafe(|| { + g.bench_with_input( + BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), + &input, + |b, &(bundler, module_count)| { + let test_app = build_test(module_count, bundler); + let template_dir = test_app.path(); + fn add_code(app_path: &Path, code: &str) -> Result<()> { + let triangle_path = app_path.join("src/triangle.jsx"); + let mut contents = fs::read_to_string(&triangle_path)?; + const COMPONENT_START: &str = + "export default function Container({ style }) {\n"; + let a = contents + .find(COMPONENT_START) + .ok_or_else(|| anyhow!("unable to find component start"))?; + let b = contents + .find("\n return <>") + .ok_or_else(|| anyhow!("unable to find component start"))?; + contents.replace_range(a..b, &format!("{COMPONENT_START}{code}")); + fs::write(&triangle_path, contents)?; + Ok(()) + } + async fn make_change<'a>(guard: &mut PageGuard<'a>) -> Result<()> { + let msg = + format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); + add_code( + guard.app().path(), + &format!( + " React.useEffect(() => {{ \ + globalThis.{BINDING_NAME}('{msg}'); }});\n" + ), + )?; + + // Wait for the change introduced above to be reflected at runtime. + // This expects HMR or automatic reloading to occur. + timeout(MAX_UPDATE_TIMEOUT, guard.wait_for_binding(&msg)) + .await? + .context("update was not registered by bundler")?; + + Ok(()) + } + b.to_async(Runtime::new().unwrap()).try_iter_async( + || async { + let mut app = + PreparedApp::new(bundler, template_dir.to_path_buf())?; + app.start_server()?; + let mut guard = app.with_page(browser).await?; + guard.wait_for_hydration().await?; + guard + .page() + .evaluate_expression("globalThis.HMR_IS_HAPPENING = true") + .await?; + + // Make warmup change + make_change(&mut guard).await?; + + Ok(guard) + }, + |mut guard| async move { + make_change(&mut guard).await?; + + // Defer the dropping of the guard to `teardown`. + Ok(guard) + }, + |guard| async move { + let hmr_is_happening = guard + .page() + .evaluate_expression("globalThis.HMR_IS_HAPPENING") + .await + .unwrap(); + // Make sure that we are really measuring HMR and not accidentically + // full refreshing the page + assert!(hmr_is_happening.value().unwrap().as_bool().unwrap()); + }, + ); + }, + ); + })); } } } @@ -185,40 +194,43 @@ fn bench_restart(c: &mut Criterion) { for module_count in get_module_counts() { let input = (bundler.as_ref(), module_count); - g.bench_with_input( - BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), - &input, - |b, &(bundler, module_count)| { - let test_app = build_test(module_count, bundler); - let template_dir = test_app.path(); - b.to_async(Runtime::new().unwrap()).try_iter_async( - || async { - // Run a complete build, shut down, and test running it again - let mut app = PreparedApp::new(bundler, template_dir.to_path_buf())?; - app.start_server()?; - let mut guard = app.with_page(browser).await?; - guard.wait_for_hydration().await?; - - let mut app = guard.close_page().await?; - - // Give it 4 seconds time to store the cache - sleep(Duration::from_secs(4)).await; - - app.stop_server()?; - Ok(app) - }, - |mut app| async { - app.start_server()?; - let mut guard = app.with_page(browser).await?; - guard.wait_for_hydration().await?; - - // Defer the dropping of the guard to `teardown`. - Ok(guard) - }, - |_guard| async move {}, - ); - }, - ); + resume_on_error(AssertUnwindSafe(|| { + g.bench_with_input( + BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), + &input, + |b, &(bundler, module_count)| { + let test_app = build_test(module_count, bundler); + let template_dir = test_app.path(); + b.to_async(Runtime::new().unwrap()).try_iter_async( + || async { + // Run a complete build, shut down, and test running it again + let mut app = + PreparedApp::new(bundler, template_dir.to_path_buf())?; + app.start_server()?; + let mut guard = app.with_page(browser).await?; + guard.wait_for_hydration().await?; + + let mut app = guard.close_page().await?; + + // Give it 4 seconds time to store the cache + sleep(Duration::from_secs(4)).await; + + app.stop_server()?; + Ok(app) + }, + |mut app| async { + app.start_server()?; + let mut guard = app.with_page(browser).await?; + guard.wait_for_hydration().await?; + + // Defer the dropping of the guard to `teardown`. + Ok(guard) + }, + |_guard| async move {}, + ); + }, + ); + })); } } } diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index 535069d3a571ba..501a3b31196862 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -1,5 +1,6 @@ use std::{ io::{self, BufRead, BufReader, Read, Write}, + panic::UnwindSafe, process::Command, time::Duration, }; @@ -139,6 +140,18 @@ pub async fn create_browser() -> Browser { browser } +pub fn resume_on_error () + UnwindSafe>(f: F) { + let runs_as_bench = std::env::args().find(|a| a == "--bench"); + + if runs_as_bench.is_some() { + use std::panic::catch_unwind; + // panics are already printed to the console, so no need to handle the result. + let _ = catch_unwind(f); + } else { + f(); + } +} + pub trait AsyncBencherExtension { fn try_iter_async(&mut self, setup: S, routine: R, teardown: T) where From 00b7a92a395c4217ecf2559eecce174e8d1a3523 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 19 Sep 2022 14:48:18 +0200 Subject: [PATCH 089/672] measure HMR to eval and HMR to commit independent from each other (vercel/turbo#382) HMR to commit include react-refresh time to apply the update in the react component tree --- .../next-swc/crates/next-dev/benches/mod.rs | 87 +++++++++++++++---- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 67dd5e3818646b..24fc292bbeb1f4 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -89,11 +89,29 @@ fn bench_startup_internal(mut g: BenchmarkGroup, hydration: bool) { g.finish(); } -fn bench_simple_file_change(c: &mut Criterion) { - let mut g = c.benchmark_group("bench_simple_file_change"); +#[derive(Copy, Clone)] +enum CodeLocation { + Effect, + Evaluation, +} + +fn bench_hmr_to_eval(c: &mut Criterion) { + let mut g = c.benchmark_group("bench_hmr_to_eval"); + g.sample_size(10); + g.measurement_time(Duration::from_secs(60)); + + bench_hmr_internal(g, CodeLocation::Evaluation); +} + +fn bench_hmr_to_commit(c: &mut Criterion) { + let mut g = c.benchmark_group("bench_hmr_to_commit"); g.sample_size(10); g.measurement_time(Duration::from_secs(60)); + bench_hmr_internal(g, CodeLocation::Effect); +} + +fn bench_hmr_internal(mut g: BenchmarkGroup, location: CodeLocation) { let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); @@ -107,30 +125,63 @@ fn bench_simple_file_change(c: &mut Criterion) { |b, &(bundler, module_count)| { let test_app = build_test(module_count, bundler); let template_dir = test_app.path(); - fn add_code(app_path: &Path, code: &str) -> Result<()> { + fn add_code( + app_path: &Path, + code: &str, + location: CodeLocation, + ) -> Result<()> { let triangle_path = app_path.join("src/triangle.jsx"); let mut contents = fs::read_to_string(&triangle_path)?; + const INSERTED_CODE_COMMENT: &str = "// Inserted Code:\n"; const COMPONENT_START: &str = "export default function Container({ style }) {\n"; - let a = contents - .find(COMPONENT_START) - .ok_or_else(|| anyhow!("unable to find component start"))?; - let b = contents - .find("\n return <>") - .ok_or_else(|| anyhow!("unable to find component start"))?; - contents.replace_range(a..b, &format!("{COMPONENT_START}{code}")); + match location { + CodeLocation::Effect => { + let a = contents + .find(COMPONENT_START) + .ok_or_else(|| anyhow!("unable to find component start"))?; + let b = contents + .find("\n return <>") + .ok_or_else(|| anyhow!("unable to find component start"))?; + contents.replace_range( + a..b, + &format!( + "{COMPONENT_START} React.useEffect(() => {{ {code} \ + }});\n" + ), + ); + } + CodeLocation::Evaluation => { + let b = contents + .find(COMPONENT_START) + .ok_or_else(|| anyhow!("unable to find component start"))?; + if let Some(a) = contents.find(INSERTED_CODE_COMMENT) { + contents.replace_range( + a..b, + &format!("{INSERTED_CODE_COMMENT}{code}\n"), + ); + } else { + contents.insert_str( + b, + &format!("{INSERTED_CODE_COMMENT}{code}\n"), + ); + } + } + } + fs::write(&triangle_path, contents)?; Ok(()) } - async fn make_change<'a>(guard: &mut PageGuard<'a>) -> Result<()> { + async fn make_change<'a>( + guard: &mut PageGuard<'a>, + location: CodeLocation, + ) -> Result<()> { let msg = format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); add_code( guard.app().path(), - &format!( - " React.useEffect(() => {{ \ - globalThis.{BINDING_NAME}('{msg}'); }});\n" - ), + &format!("globalThis.{BINDING_NAME}('{msg}');"), + location, )?; // Wait for the change introduced above to be reflected at runtime. @@ -154,12 +205,12 @@ fn bench_simple_file_change(c: &mut Criterion) { .await?; // Make warmup change - make_change(&mut guard).await?; + make_change(&mut guard, location).await?; Ok(guard) }, |mut guard| async move { - make_change(&mut guard).await?; + make_change(&mut guard, location).await?; // Defer the dropping of the guard to `teardown`. Ok(guard) @@ -251,6 +302,6 @@ fn get_module_counts() -> Vec { criterion_group!( name = benches; config = Criterion::default(); - targets = bench_startup, bench_hydration, bench_restart, bench_simple_file_change + targets = bench_startup, bench_hydration, bench_restart, bench_hmr_to_eval, bench_hmr_to_commit ); criterion_main!(benches); From e35ad2f2dccc4a222a8fd94ea2bc061cd016f5ae Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 19 Sep 2022 17:00:22 +0200 Subject: [PATCH 090/672] Use React.memo in the test/bench app (vercel/turbo#384) With React.memo: ``` bench_hmr_to_commit/Turbopack CSR/30000 modules time: [50.608 ms 51.659 ms 52.553 ms] ``` Without React.memo: ``` bench_hmr_to_commit/Turbopack CSR/30000 modules time: [853.47 ms 1.0191 s 1.1873 s] change: [+1543.4% +1872.7% +2207.8%] (p = 0.00 < 0.05) Performance has regressed. ``` Since we're only ever editing the top-level triangle in our HMR benchmarks, we're incurring the time it takes for React to re-render the whole tree, which is a function of the number of components in said tree. By using `React.memo`, we can skip updating children components during HMR. --- packages/next-swc/crates/next-dev/benches/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 24fc292bbeb1f4..616f56a71ae4de 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -133,8 +133,7 @@ fn bench_hmr_internal(mut g: BenchmarkGroup, location: CodeLocation) { let triangle_path = app_path.join("src/triangle.jsx"); let mut contents = fs::read_to_string(&triangle_path)?; const INSERTED_CODE_COMMENT: &str = "// Inserted Code:\n"; - const COMPONENT_START: &str = - "export default function Container({ style }) {\n"; + const COMPONENT_START: &str = "function Container({ style }) {\n"; match location { CodeLocation::Effect => { let a = contents From 65be8a08049b81170e58661950335b9e12e635fd Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 19 Sep 2022 17:22:05 +0200 Subject: [PATCH 091/672] handle exceptions during waiting for events (vercel/turbo#383) --- .../next-dev/benches/util/page_guard.rs | 43 +++++++++++++++---- .../next-dev/benches/util/prepared_app.rs | 2 +- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs index ffa1b6929b89ff..7c5845b1a9c83f 100644 --- a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs +++ b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs @@ -1,8 +1,12 @@ -use std::time::Duration; +use std::{sync::Arc, time::Duration}; use anyhow::{anyhow, Result}; -use chromiumoxide::{cdp::js_protocol::runtime::EventBindingCalled, listeners::EventStream, Page}; -use futures::StreamExt; +use chromiumoxide::{ + cdp::js_protocol::runtime::{EventBindingCalled, EventExceptionThrown}, + listeners::EventStream, + Page, +}; +use futures::{Stream, StreamExt}; use tokio::time::timeout; use crate::{PreparedApp, BINDING_NAME}; @@ -14,16 +18,29 @@ const TEST_APP_HYDRATION_DONE: &str = "Hydration done"; pub struct PageGuard<'a> { page: Option, app: Option>, - events: EventStream, + events: Box + Unpin>, +} + +enum Event { + EventBindingCalled(Arc), + EventExceptionThrown(Arc), } impl<'a> PageGuard<'a> { /// Creates a new guard for the given page. - pub fn new(page: Page, events: EventStream, app: PreparedApp<'a>) -> Self { + pub fn new( + page: Page, + events: EventStream, + errors: EventStream, + app: PreparedApp<'a>, + ) -> Self { Self { page: Some(page), app: Some(app), - events, + events: Box::new(futures::stream::select( + events.map(|e| Event::EventBindingCalled(e)), + errors.map(|e| Event::EventExceptionThrown(e)), + )), } } @@ -58,8 +75,18 @@ impl<'a> PageGuard<'a> { /// Waits until the binding is called with the given payload. pub async fn wait_for_binding(&mut self, payload: &str) -> Result<()> { while let Some(event) = self.events.next().await { - if event.name == BINDING_NAME && event.payload == payload { - return Ok(()); + match event { + Event::EventBindingCalled(event) => { + if event.name == BINDING_NAME && event.payload == payload { + return Ok(()); + } + } + Event::EventExceptionThrown(event) => { + return Err(anyhow!( + "Exception throw in page: {}", + event.exception_details + )); + } } } diff --git a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs index 2fd2273f7a9010..83c9cba5207dc0 100644 --- a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs +++ b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs @@ -92,7 +92,7 @@ impl<'a> PreparedApp<'a> { // Make sure no runtime errors occurred when loading the page assert!(errors.next().now_or_never().is_none()); - let page_guard = PageGuard::new(page, binding_events, self); + let page_guard = PageGuard::new(page, binding_events, errors, self); Ok(page_guard) } From 1f7df032e29eb2a328943eb16fe3394cfd03de01 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 19 Sep 2022 19:01:18 +0200 Subject: [PATCH 092/672] benchmarks need more time and skip faster when failing (vercel/turbo#393) --- packages/next-swc/crates/next-dev/benches/util/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index 501a3b31196862..5ea8a018279aa3 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -55,8 +55,8 @@ fn retry_default(args: A, f: F) -> Result where F: Fn(&mut A) -> Result, { - // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total - retry(args, f, 5, Duration::from_secs(5)) + // waits 5, 10, 20, 40 seconds = 75 seconds total + retry(args, f, 3, Duration::from_secs(5)) } async fn retry_async( @@ -90,8 +90,8 @@ where F: Fn(&mut A) -> Fut, Fut: Future>, { - // waits 5, 10, 20, 40, 80, 160 seconds = 315 seconds total - retry_async(args, f, 5, Duration::from_secs(5)).await + // waits 5, 10, 20, 40 seconds = 75 seconds total + retry_async(args, f, 3, Duration::from_secs(5)).await } pub fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { From a9b5ada56a840a15f727dfc8fdb7109bd643a5f7 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 19 Sep 2022 19:11:14 +0200 Subject: [PATCH 093/672] fail-safe bindings code for SSR (vercel/turbo#391) --- packages/next-swc/crates/next-dev/benches/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 616f56a71ae4de..90f7e5860341fb 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -179,7 +179,10 @@ fn bench_hmr_internal(mut g: BenchmarkGroup, location: CodeLocation) { format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); add_code( guard.app().path(), - &format!("globalThis.{BINDING_NAME}('{msg}');"), + &format!( + "globalThis.{BINDING_NAME} && \ + globalThis.{BINDING_NAME}('{msg}');" + ), location, )?; From b9c36e77485afb3b656ff5dcaeae0789e51b4807 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Tue, 20 Sep 2022 15:33:15 +0800 Subject: [PATCH 094/672] Align eslint and prettier rules with turborepo (vercel/turbo#397) --- .../src/next_client/next_hydrater.js | 8 +- .../src/server_render/server_renderer.js | 78 ++--- .../benches/bundlers/vite/vite.config.js | 6 +- .../bundlers/webpack/webpack.config.js | 16 +- .../next-swc/crates/next-dev/tests/harness.js | 12 +- .../turbopack/basic/simple/index.js | 32 +- .../turbopack/basic/styled-jsx/index.js | 22 +- .../__skipped__/context-weak/dir/four.js | 2 +- .../chunks/__skipped__/context-weak/index.js | 36 +-- .../chunks/__skipped__/context-weak/three.js | 2 +- .../chunks/__skipped__/context-weak/two.js | 2 +- .../chunks/__skipped__/context/index.js | 16 +- .../webpack/chunks/__skipped__/context/two.js | 2 +- .../chunks/__skipped__/import-circle/index.js | 12 +- .../__skipped__/import-circle/leftHelix.js | 4 +- .../import-circle/leftHelixPrime.js | 6 +- .../__skipped__/import-circle/rightHelix.js | 4 +- .../import-circle/rightHelixPrime.js | 6 +- .../initialModule.js | 2 +- .../initialModule2.js | 2 +- .../dir-initial/initialModule.js | 2 +- .../import-context-exist-chunk/index.js | 28 +- .../__skipped__/import-context/dir/one.js | 2 +- .../__skipped__/import-context/dir/three.js | 2 +- .../__skipped__/import-context/dir/two.js | 2 +- .../__skipped__/import-context/dir2/one.js | 2 +- .../__skipped__/import-context/dir2/three.js | 2 +- .../__skipped__/import-context/dir2/two.js | 2 +- .../__skipped__/import-context/index.js | 52 ++-- .../chunks/__skipped__/import/index.js | 16 +- .../webpack/chunks/__skipped__/import/two.js | 2 +- .../__skipped__/inline-options/dir1/a.js | 2 +- .../__skipped__/inline-options/dir1/b.js | 2 +- .../__skipped__/inline-options/dir1/c.js | 2 +- .../__skipped__/inline-options/dir1/d.js | 2 +- .../__skipped__/inline-options/dir10/a.js | 2 +- .../__skipped__/inline-options/dir11/a.js | 2 +- .../__skipped__/inline-options/dir12/a.js | 10 +- .../__skipped__/inline-options/dir13/a.js | 8 +- .../__skipped__/inline-options/dir13/b.js | 8 +- .../__skipped__/inline-options/dir2/a.js | 2 +- .../__skipped__/inline-options/dir2/b.js | 2 +- .../__skipped__/inline-options/dir2/c.js | 2 +- .../__skipped__/inline-options/dir2/d.js | 2 +- .../__skipped__/inline-options/dir3/a.js | 2 +- .../__skipped__/inline-options/dir3/b.js | 2 +- .../__skipped__/inline-options/dir3/c.js | 2 +- .../__skipped__/inline-options/dir3/d.js | 2 +- .../__skipped__/inline-options/dir4/a.js | 2 +- .../__skipped__/inline-options/dir4/b.js | 2 +- .../__skipped__/inline-options/dir4/c.js | 2 +- .../__skipped__/inline-options/dir4/d.js | 2 +- .../__skipped__/inline-options/dir5/a.js | 2 +- .../__skipped__/inline-options/dir5/b.js | 2 +- .../__skipped__/inline-options/dir5/c.js | 2 +- .../__skipped__/inline-options/dir5/d.js | 2 +- .../__skipped__/inline-options/dir6/a.js | 2 +- .../__skipped__/inline-options/dir6/b.js | 2 +- .../__skipped__/inline-options/dir6/c.js | 2 +- .../__skipped__/inline-options/dir6/d.js | 2 +- .../__skipped__/inline-options/dir7/a.js | 2 +- .../__skipped__/inline-options/dir7/b.js | 2 +- .../__skipped__/inline-options/dir7/c.js | 2 +- .../__skipped__/inline-options/dir7/d.js | 2 +- .../__skipped__/inline-options/dir8/a.js | 2 +- .../__skipped__/inline-options/dir8/b.js | 2 +- .../__skipped__/inline-options/dir8/c.js | 2 +- .../__skipped__/inline-options/dir9/a.js | 2 +- .../__skipped__/inline-options/dir9/b.js | 2 +- .../__skipped__/inline-options/dir9/c.js | 2 +- .../__skipped__/inline-options/index.js | 290 ++++++++---------- .../__skipped__/issue-2443/dir/one/file.js | 2 +- .../__skipped__/issue-2443/dir/three/file.js | 2 +- .../__skipped__/issue-2443/dir/two/file.js | 2 +- .../chunks/__skipped__/issue-2443/index.js | 36 +-- .../chunks/__skipped__/issue-5153/index.js | 12 +- .../chunks/__skipped__/issue-5153/module.js | 2 +- .../chunks/__skipped__/named-chunks/index.js | 226 +++++++------- .../chunks/__skipped__/nested-in-empty/b.js | 2 +- .../__skipped__/nested-in-empty/index.js | 22 +- .../chunks/__skipped__/parsing/index.js | 62 ++-- .../__skipped__/parsing/require.include.js | 2 +- .../webpack/chunks/__skipped__/runtime/a.js | 2 +- .../chunks/__skipped__/runtime/acircular.js | 6 +- .../chunks/__skipped__/runtime/acircular2.js | 6 +- .../webpack/chunks/__skipped__/runtime/b.js | 2 +- .../chunks/__skipped__/runtime/duplicate.js | 6 +- .../chunks/__skipped__/runtime/duplicate2.js | 6 +- .../chunks/__skipped__/runtime/index.js | 66 ++-- .../chunks/__skipped__/runtime/test.filter.js | 4 +- .../var-inject-error-handler/index.js | 14 +- .../weak-dependencies-context/index.js | 38 +-- .../__skipped__/weak-dependencies/index.js | 24 +- .../chunks/circular-correctness/index.js | 20 +- .../chunks/circular-correctness/module-a.js | 2 +- .../chunks/circular-correctness/module-a2.js | 2 +- .../chunks/circular-correctness/module-b.js | 4 +- .../chunks/circular-correctness/module-b2.js | 2 +- .../chunks/circular-correctness/module-c.js | 8 +- .../chunks/circular-correctness/module-x.js | 2 +- .../chunks/weird-reference-to-entry/errors.js | 6 +- .../chunks/weird-reference-to-entry/index.js | 14 +- .../weird-reference-to-entry/module-a.js | 2 +- 103 files changed, 673 insertions(+), 703 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js b/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js index ff38c450f0d520..0f36a56059ba17 100644 --- a/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js +++ b/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js @@ -1,5 +1,5 @@ -import Component from '.' -import { hydrateRoot } from 'react-dom/client' +import Component from "."; +import { hydrateRoot } from "react-dom/client"; -const data = JSON.parse(document.getElementById('__NEXT_DATA__').textContent) -hydrateRoot(document.getElementById('__next'), ) +const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); +hydrateRoot(document.getElementById("__next"), ); diff --git a/packages/next-swc/crates/next-core/src/server_render/server_renderer.js b/packages/next-swc/crates/next-core/src/server_render/server_renderer.js index 15c08fd8cb41e9..36f0642a5a5b04 100644 --- a/packages/next-swc/crates/next-core/src/server_render/server_renderer.js +++ b/packages/next-swc/crates/next-core/src/server_render/server_renderer.js @@ -1,50 +1,50 @@ -const END_OF_OPERATION = process.argv[2] +const END_OF_OPERATION = process.argv[2]; -import Component, * as otherExports from '.' -import { renderToString, renderToStaticMarkup } from 'react-dom/server' -;('TURBOPACK { transition: next-client }') -import chunkGroup from '.' +import Component, * as otherExports from "."; +import { renderToString, renderToStaticMarkup } from "react-dom/server"; +("TURBOPACK { transition: next-client }"); +import chunkGroup from "."; -process.stdout.write('READY\n') +process.stdout.write("READY\n"); -const NEW_LINE = '\n'.charCodeAt(0) -let buffer = [] -process.stdin.on('data', async (data) => { - let idx = data.indexOf(NEW_LINE) +const NEW_LINE = "\n".charCodeAt(0); +let buffer = []; +process.stdin.on("data", async (data) => { + let idx = data.indexOf(NEW_LINE); while (idx >= 0) { - buffer.push(data.slice(0, idx)) + buffer.push(data.slice(0, idx)); try { - let json = JSON.parse(Buffer.concat(buffer).toString('utf-8')) - let result = await operation(json) - console.log(`RESULT=${JSON.stringify(result)}`) + let json = JSON.parse(Buffer.concat(buffer).toString("utf-8")); + let result = await operation(json); + console.log(`RESULT=${JSON.stringify(result)}`); } catch (e) { - console.log(`ERROR=${JSON.stringify(e.stack)}`) + console.log(`ERROR=${JSON.stringify(e.stack)}`); } - console.log(END_OF_OPERATION) - data = data.slice(idx + 1) - idx = data.indexOf(NEW_LINE) + console.log(END_OF_OPERATION); + data = data.slice(idx + 1); + idx = data.indexOf(NEW_LINE); } - buffer.push(data) -}) + buffer.push(data); +}); async function operation(data) { - let staticProps = data - if ('getStaticProps' in otherExports) { + let staticProps = data; + if ("getStaticProps" in otherExports) { // TODO(alexkirsz) Pass in `context` as defined in // https://nextjs.org/docs/api-reference/data-fetching/get-static-props#context-parameter - staticProps = otherExports.getStaticProps({}) - if ('then' in staticProps) { - staticProps = await staticProps + staticProps = otherExports.getStaticProps({}); + if ("then" in staticProps) { + staticProps = await staticProps; } } // TODO capture meta info during rendering const rendered = { __html: renderToString(), - } - const urls = chunkGroup.map((p) => `/${p}`) - const scripts = urls.filter((url) => url.endsWith('.js')) - const styles = urls.filter((url) => url.endsWith('.css')) + }; + const urls = chunkGroup.map((p) => `/${p}`); + const scripts = urls.filter((url) => url.endsWith(".js")); + const styles = urls.filter((url) => url.endsWith(".css")); return renderToStaticMarkup( @@ -68,23 +68,23 @@ async function operation(data) { ))} - , - ) + + ); } // This utility is based on https://github.com/zertosh/htmlescape // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE const ESCAPE_LOOKUP = { - '&': '\\u0026', - '>': '\\u003e', - '<': '\\u003c', - '\u2028': '\\u2028', - '\u2029': '\\u2029', -} + "&": "\\u0026", + ">": "\\u003e", + "<": "\\u003c", + "\u2028": "\\u2028", + "\u2029": "\\u2029", +}; -const ESCAPE_REGEX = /[&><\u2028\u2029]/g +const ESCAPE_REGEX = /[&><\u2028\u2029]/g; export function htmlEscapeJsonString(str) { - return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]) + return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js index 9ffcc675746194..081c8d9f69fcb7 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.config.js @@ -1,6 +1,6 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; export default defineConfig({ plugins: [react()], -}) +}); diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js index ce2c7509d921c8..0b794b4f59ba2f 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js +++ b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/webpack.config.js @@ -1,20 +1,20 @@ -const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin') +const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); module.exports = { - mode: 'development', + mode: "development", resolve: { - extensions: ['.jsx', '...'], + extensions: [".jsx", "..."], }, module: { unsafeCache: true, rules: [ { test: /\.jsx$/, - loader: 'swc-loader', + loader: "swc-loader", options: { jsc: { parser: { - syntax: 'ecmascript', + syntax: "ecmascript", jsx: true, dynamicImport: true, privateMethod: true, @@ -29,7 +29,7 @@ module.exports = { externalHelpers: true, transform: { react: { - runtime: 'automatic', + runtime: "automatic", refresh: true, }, }, @@ -42,7 +42,7 @@ module.exports = { hot: true, }, cache: { - type: 'filesystem', + type: "filesystem", }, node: { global: true, @@ -51,4 +51,4 @@ module.exports = { futureDefaults: true, }, plugins: [new ReactRefreshWebpackPlugin()], -} +}; diff --git a/packages/next-swc/crates/next-dev/tests/harness.js b/packages/next-swc/crates/next-dev/tests/harness.js index 64c95d3959baeb..b97f97a06bf3f6 100644 --- a/packages/next-swc/crates/next-dev/tests/harness.js +++ b/packages/next-swc/crates/next-dev/tests/harness.js @@ -1,7 +1,7 @@ -import * as jest from 'jest-circus-browser/dist/umd/jest-circus.js' -import expect from 'expect/build-es5/index.js' +import * as jest from "jest-circus-browser/dist/umd/jest-circus.js"; +import expect from "expect/build-es5/index.js"; -globalThis.__jest__ = jest -globalThis.expect = expect -globalThis.describe = jest.describe -globalThis.it = jest.it +globalThis.__jest__ = jest; +globalThis.expect = expect; +globalThis.describe = jest.describe; +globalThis.it = jest.it; diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js index 64dbc0d26757fc..bf9b0f60b565a3 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/simple/index.js @@ -1,19 +1,19 @@ -it('runs sync tests', () => { - expect(true).toBe(true) -}) +it("runs sync tests", () => { + expect(true).toBe(true); +}); -it('runs async tests', async () => { - await Promise.resolve() - expect(true).toBe(true) -}) +it("runs async tests", async () => { + await Promise.resolve(); + expect(true).toBe(true); +}); -describe('nested describe', () => { - it('runs sync tests', () => { - expect(true).toBe(true) - }) +describe("nested describe", () => { + it("runs sync tests", () => { + expect(true).toBe(true); + }); - it('runs async tests', async () => { - await Promise.resolve() - expect(true).toBe(true) - }) -}) + it("runs async tests", async () => { + await Promise.resolve(); + expect(true).toBe(true); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js index c0691d8d98ffee..e8211ff59d9f53 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/styled-jsx/index.js @@ -1,8 +1,8 @@ -import React from 'react' -import TestRenderer from 'react-test-renderer' +import React from "react"; +import TestRenderer from "react-test-renderer"; -describe('styled-jsx', () => { - it('compiles away - , - ) + + ); expect(test.toJSON()).toMatchObject({ - children: ['This should be color: red'], + children: ["This should be color: red"], props: { className: /jsx\-[0-9a-f]+/, }, - type: 'span', - }) - }) -}) + type: "span", + }); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js index 11f8e7e4030768..a9bbdd80578ef6 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/dir/four.js @@ -1 +1 @@ -module.exports = 4 +module.exports = 4; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js index ae7870d4766ba4..75a66e397c3a8b 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/index.js @@ -1,29 +1,29 @@ it("should not bundle context requires with asyncMode === 'weak'", function () { - var contextRequire = require.context('.', false, /two/, 'weak') + var contextRequire = require.context(".", false, /two/, "weak"); expect(function () { - contextRequire('./two') - }).toThrowError(/not available/) -}) + contextRequire("./two"); + }).toThrowError(/not available/); +}); it("should not bundle context requires with asyncMode === 'weak' using import.meta.webpackContext", function () { - const contextRequire = import.meta.webpackContext('.', { + const contextRequire = import.meta.webpackContext(".", { recursive: false, regExp: /two/, - mode: 'weak', - }) + mode: "weak", + }); expect(function () { - contextRequire('./two') - }).toThrowError(/not available/) -}) + contextRequire("./two"); + }).toThrowError(/not available/); +}); it("should find module with asyncMode === 'weak' when required elsewhere", function () { - var contextRequire = require.context('.', false, /.+/, 'weak') - expect(contextRequire('./three')).toBe(3) - require('./three') // in a real app would be served as a separate chunk -}) + var contextRequire = require.context(".", false, /.+/, "weak"); + expect(contextRequire("./three")).toBe(3); + require("./three"); // in a real app would be served as a separate chunk +}); it("should find module with asyncMode === 'weak' when required elsewhere (recursive)", function () { - var contextRequire = require.context('.', true, /.+/, 'weak') - expect(contextRequire('./dir/four')).toBe(4) - require('./dir/four') // in a real app would be served as a separate chunk -}) + var contextRequire = require.context(".", true, /.+/, "weak"); + expect(contextRequire("./dir/four")).toBe(4); + require("./dir/four"); // in a real app would be served as a separate chunk +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js index 6887896a4640a8..690aad34a46dc9 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/three.js @@ -1 +1 @@ -module.exports = 3 +module.exports = 3; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js index 4afe2ededa2763..4bbffde1044258 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context-weak/two.js @@ -1 +1 @@ -module.exports = 2 +module.exports = 2; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js index 663649f4dea3b1..c2d5a1d9ebdb4a 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/index.js @@ -1,9 +1,9 @@ -it('should also work in a chunk', function (done) { +it("should also work in a chunk", function (done) { require.ensure([], function (require) { - var contextRequire = require.context('.', false, /two/) - expect(contextRequire('./two')).toBe(2) - var tw = 'tw' - expect(require('.' + '/' + tw + 'o')).toBe(2) - done() - }) -}) + var contextRequire = require.context(".", false, /two/); + expect(contextRequire("./two")).toBe(2); + var tw = "tw"; + expect(require("." + "/" + tw + "o")).toBe(2); + done(); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js index 4afe2ededa2763..4bbffde1044258 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/context/two.js @@ -1 +1 @@ -module.exports = 2 +module.exports = 2; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js index cd992f62acbe05..0a4107e021f825 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/index.js @@ -1,11 +1,11 @@ -import leftHelix from './leftHelix' -import rightHelix from './rightHelix' +import leftHelix from "./leftHelix"; +import rightHelix from "./rightHelix"; -it('should import generate ensure function for this', () => { - return Promise.all([leftHelix.run(), rightHelix.run()]) -}) +it("should import generate ensure function for this", () => { + return Promise.all([leftHelix.run(), rightHelix.run()]); +}); export default { leftHelix, rightHelix, -} +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js index 620445f512afb7..7a7babc0d2b404 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelix.js @@ -1,6 +1,6 @@ -import leftHelixPrime, { run } from './leftHelixPrime' +import leftHelixPrime, { run } from "./leftHelixPrime"; export default { leftHelixPrime, run, -} +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js index f330e942e5a7db..d669006b5a1011 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/leftHelixPrime.js @@ -1,9 +1,9 @@ -import rightHelixPrime from './rightHelixPrime' +import rightHelixPrime from "./rightHelixPrime"; export function run() { - return import(/* webpackChunkName: "left" */ './leftHelix') + return import(/* webpackChunkName: "left" */ "./leftHelix"); } export default { rightHelixPrime: () => rightHelixPrime, -} +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js index 8836f2f9d4d33c..9e668f76eae14a 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelix.js @@ -1,6 +1,6 @@ -import rightHelixPrime, { run } from './rightHelixPrime' +import rightHelixPrime, { run } from "./rightHelixPrime"; export default { rightHelixPrime, run, -} +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js index 123e3723a17ad0..7d590981875983 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-circle/rightHelixPrime.js @@ -1,9 +1,9 @@ -import leftHelixPrime from './leftHelixPrime' +import leftHelixPrime from "./leftHelixPrime"; export function run() { - return import(/* webpackChunkName: "right" */ './rightHelix') + return import(/* webpackChunkName: "right" */ "./rightHelix"); } export default { leftHelixPrime: () => leftHelixPrime, -} +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js index 31f025c1266247..341b43e9dfafff 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js @@ -1 +1 @@ -export default 'initialModuleDefault' +export default "initialModuleDefault"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js index 65f212bcf1317e..4c27d0e9f9a3da 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js @@ -1 +1 @@ -exports.default = 'other' +exports.default = "other"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js index 31f025c1266247..341b43e9dfafff 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/dir-initial/initialModule.js @@ -1 +1 @@ -export default 'initialModuleDefault' +export default "initialModuleDefault"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js index 0baa2ceaf64b03..877672b6c39998 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context-exist-chunk/index.js @@ -1,21 +1,21 @@ -it('should resolve when import existed chunk (#8626)', function (done) { - require.context('./dir-initial/') - const fileName = 'initialModule' +it("should resolve when import existed chunk (#8626)", function (done) { + require.context("./dir-initial/"); + const fileName = "initialModule"; import(`./dir-initial/${fileName}`) .then(({ default: m }) => { - expect(m).toBe('initialModuleDefault') - done() + expect(m).toBe("initialModuleDefault"); + done(); }) - .catch(done) -}) + .catch(done); +}); -it('should resolve when import existed chunk with fake maps', function (done) { - require.context('./dir-initial-with-fake-map/') - const fileName = 'initialModule' +it("should resolve when import existed chunk with fake maps", function (done) { + require.context("./dir-initial-with-fake-map/"); + const fileName = "initialModule"; import(`./dir-initial-with-fake-map/${fileName}`) .then(({ default: m }) => { - expect(m).toBe('initialModuleDefault') - done() + expect(m).toBe("initialModuleDefault"); + done(); }) - .catch(done) -}) + .catch(done); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js index e8f7328d6ee564..bd816eaba4ca3b 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/one.js @@ -1 +1 @@ -module.exports = 1 +module.exports = 1; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js index 6887896a4640a8..690aad34a46dc9 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/three.js @@ -1 +1 @@ -module.exports = 3 +module.exports = 3; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js index 4afe2ededa2763..4bbffde1044258 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir/two.js @@ -1 +1 @@ -module.exports = 2 +module.exports = 2; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js index e8f7328d6ee564..bd816eaba4ca3b 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/one.js @@ -1 +1 @@ -module.exports = 1 +module.exports = 1; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js index 6887896a4640a8..690aad34a46dc9 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/three.js @@ -1 +1 @@ -module.exports = 3 +module.exports = 3; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js index 4afe2ededa2763..4bbffde1044258 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/dir2/two.js @@ -1 +1 @@ -module.exports = 2 +module.exports = 2; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js index feaea8796f91a3..f204b942a5813a 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import-context/index.js @@ -1,42 +1,42 @@ function testCase(load, done) { - load('two', 2, function () { - var sync = true - load('one', 1, function () { - expect(sync).toBe(false) - load('three', 3, function () { - var sync = true - load('two', 2, function () { - expect(sync).toBe(true) - done() - }) + load("two", 2, function () { + var sync = true; + load("one", 1, function () { + expect(sync).toBe(false); + load("three", 3, function () { + var sync = true; + load("two", 2, function () { + expect(sync).toBe(true); + done(); + }); Promise.resolve() .then(function () {}) .then(function () {}) .then(function () { - sync = false - }) - }) - }) + sync = false; + }); + }); + }); Promise.resolve().then(function () { - sync = false - }) - }) + sync = false; + }); + }); } -it('should be able to use expressions in import', function (done) { +it("should be able to use expressions in import", function (done) { function load(name, expected, callback) { - import('./dir/' + name) + import("./dir/" + name) .then(function (result) { expect(result).toEqual( nsObj({ default: expected, - }), - ) - callback() + }) + ); + callback(); }) .catch(function (err) { - done(err) - }) + done(err); + }); } - testCase(load, done) -}) + testCase(load, done); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js index 6825a7d22f67cd..cdc0d14813458c 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js @@ -1,14 +1,14 @@ -it('should be able to use import', function (done) { - import('./two') +it("should be able to use import", function (done) { + import("./two") .then(function (two) { expect(two).toEqual( nsObj({ default: 2, - }), - ) - done() + }) + ); + done(); }) .catch(function (err) { - done(err) - }) -}) + done(err); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js index 4afe2ededa2763..4bbffde1044258 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js @@ -1 +1 @@ -module.exports = 2 +module.exports = 2; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js index 5b54497ffd4a67..987d6d7e401685 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir1/d.js @@ -1 +1 @@ -export default 'd' +export default "d"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir10/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir11/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js index e76b95092fa037..880c38a198818b 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir12/a.js @@ -1,9 +1,9 @@ -export const c = 'c' +export const c = "c"; -export const d = 'd' +export const d = "d"; -export const longnameforexport = 'longnameforexport' +export const longnameforexport = "longnameforexport"; -export default 'default2' +export default "default2"; -export const usedExports = __webpack_exports_info__.usedExports +export const usedExports = __webpack_exports_info__.usedExports; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js index ad25fc156cf77f..fbeecbd206543f 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/a.js @@ -1,7 +1,7 @@ -export const c = 'c' +export const c = "c"; -export const d = 'd' +export const d = "d"; -export default 'default2' +export default "default2"; -export const usedExports = __webpack_exports_info__.usedExports +export const usedExports = __webpack_exports_info__.usedExports; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js index 550822fd68d778..b73c5a615daec3 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir13/b.js @@ -1,7 +1,7 @@ -export const a = 'a' +export const a = "a"; -export const b = 'b' +export const b = "b"; -export default 'default' +export default "default"; -export const usedExports = __webpack_exports_info__.usedExports +export const usedExports = __webpack_exports_info__.usedExports; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js index 5b54497ffd4a67..987d6d7e401685 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir2/d.js @@ -1 +1 @@ -export default 'd' +export default "d"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js index 5b54497ffd4a67..987d6d7e401685 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir3/d.js @@ -1 +1 @@ -export default 'd' +export default "d"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js index 5b54497ffd4a67..987d6d7e401685 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir4/d.js @@ -1 +1 @@ -export default 'd' +export default "d"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js index 5b54497ffd4a67..987d6d7e401685 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir5/d.js @@ -1 +1 @@ -export default 'd' +export default "d"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js index 5b54497ffd4a67..987d6d7e401685 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir6/d.js @@ -1 +1 @@ -export default 'd' +export default "d"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js index 5b54497ffd4a67..987d6d7e401685 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir7/d.js @@ -1 +1 @@ -export default 'd' +export default "d"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir8/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js index 90bd54cd7f2e6d..e94fef18587e39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/a.js @@ -1 +1 @@ -export default 'a' +export default "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js index a3bb49043e4bab..eff703ff4657b7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/b.js @@ -1 +1 @@ -export default 'b' +export default "b"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js index da4b0edae9cc2b..5d50db5bc15137 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/dir9/c.js @@ -1 +1 @@ -export default 'c' +export default "c"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js index 7e4e66cba60e6b..2587a01353309d 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js @@ -1,226 +1,206 @@ -it('should be able to use eager mode', function () { +it("should be able to use eager mode", function () { function load(name) { - return import(/* webpackMode: "eager" */ './dir1/' + name) + return import(/* webpackMode: "eager" */ "./dir1/" + name); } - return testChunkLoading(load, true, true) -}) + return testChunkLoading(load, true, true); +}); -it('should be able to use lazy-once mode', function () { +it("should be able to use lazy-once mode", function () { function load(name) { - return import(/* webpackMode: "lazy-once" */ './dir2/' + name) + return import(/* webpackMode: "lazy-once" */ "./dir2/" + name); } - return testChunkLoading(load, false, true) -}) + return testChunkLoading(load, false, true); +}); -it('should be able to use lazy-once mode with name', function () { +it("should be able to use lazy-once mode with name", function () { function load(name) { - return import( - /* webpackMode: "lazy-once", webpackChunkName: "name-lazy-once" */ './dir3/' + - name - ) + return import(/* webpackMode: "lazy-once", webpackChunkName: "name-lazy-once" */ "./dir3/" + name); } - return testChunkLoading(load, false, true) -}) + return testChunkLoading(load, false, true); +}); -it('should be able to use lazy mode', function () { +it("should be able to use lazy mode", function () { function load(name) { - return import(/* webpackMode: "lazy" */ './dir4/' + name) + return import(/* webpackMode: "lazy" */ "./dir4/" + name); } - return testChunkLoading(load, false, false) -}) + return testChunkLoading(load, false, false); +}); -it('should be able to use lazy mode with name', function () { +it("should be able to use lazy mode with name", function () { function load(name) { - return import( - /* webpackMode: "lazy", webpackChunkName: "name-lazy" */ './dir5/' + name - ) + return import(/* webpackMode: "lazy", webpackChunkName: "name-lazy" */ "./dir5/" + name); } - return testChunkLoading(load, false, false) -}) + return testChunkLoading(load, false, false); +}); -it('should be able to use lazy mode with name and placeholder', function () { +it("should be able to use lazy mode with name and placeholder", function () { function load(name) { - return import( - /* webpackMode: "lazy", webpackChunkName: "name-lazy-[request]" */ './dir6/' + - name - ) + return import(/* webpackMode: "lazy", webpackChunkName: "name-lazy-[request]" */ "./dir6/" + name); } - return testChunkLoading(load, false, false) -}) + return testChunkLoading(load, false, false); +}); -it('should be able to combine chunks by name', function () { +it("should be able to combine chunks by name", function () { function load(name) { switch (name) { - case 'a': - return import(/* webpackMode: "eager" */ './dir7/a') - case 'b': - return import(/* webpackChunkName: "name-3" */ './dir7/b') - case 'c': - return import(/* webpackChunkName: "name-3" */ './dir7/c') - case 'd': - return import(/* webpackChunkName: "name-3" */ './dir7/d') + case "a": + return import(/* webpackMode: "eager" */ "./dir7/a"); + case "b": + return import(/* webpackChunkName: "name-3" */ "./dir7/b"); + case "c": + return import(/* webpackChunkName: "name-3" */ "./dir7/c"); + case "d": + return import(/* webpackChunkName: "name-3" */ "./dir7/d"); default: - throw new Error('Unexpected test data') + throw new Error("Unexpected test data"); } } - return testChunkLoading(load, false, true) -}) + return testChunkLoading(load, false, true); +}); -it('should be able to use weak mode', function () { +it("should be able to use weak mode", function () { function load(name) { - return import(/* webpackMode: "weak" */ './dir8/' + name) + return import(/* webpackMode: "weak" */ "./dir8/" + name); } - require('./dir8/a') // chunks served manually by the user - require('./dir8/b') - require('./dir8/c') - return testChunkLoading(load, true, true) -}) + require("./dir8/a"); // chunks served manually by the user + require("./dir8/b"); + require("./dir8/c"); + return testChunkLoading(load, true, true); +}); -it('should be able to use weak mode (without context)', function () { +it("should be able to use weak mode (without context)", function () { function load(name) { switch (name) { - case 'a': - return import(/* webpackMode: "weak" */ './dir9/a') - case 'b': - return import(/* webpackMode: "weak" */ './dir9/b') - case 'c': - return import(/* webpackMode: "weak" */ './dir9/c') + case "a": + return import(/* webpackMode: "weak" */ "./dir9/a"); + case "b": + return import(/* webpackMode: "weak" */ "./dir9/b"); + case "c": + return import(/* webpackMode: "weak" */ "./dir9/c"); default: - throw new Error('Unexpected test data') + throw new Error("Unexpected test data"); } } - require('./dir9/a') // chunks served manually by the user - require('./dir9/b') - require('./dir9/c') - return testChunkLoading(load, true, true) -}) - -it('should not find module when mode is weak and chunk not served elsewhere', function () { - var name = 'a' - return import(/* webpackMode: "weak" */ './dir10/' + name).catch(function ( - e, - ) { + require("./dir9/a"); // chunks served manually by the user + require("./dir9/b"); + require("./dir9/c"); + return testChunkLoading(load, true, true); +}); + +it("should not find module when mode is weak and chunk not served elsewhere", function () { + var name = "a"; + return import(/* webpackMode: "weak" */ "./dir10/" + name).catch(function (e) { expect(e).toMatchObject({ message: /not available/, code: /MODULE_NOT_FOUND/, - }) - }) -}) + }); + }); +}); -it('should not find module when mode is weak and chunk not served elsewhere (without context)', function () { - return import(/* webpackMode: "weak" */ './dir11/a').catch(function (e) { +it("should not find module when mode is weak and chunk not served elsewhere (without context)", function () { + return import(/* webpackMode: "weak" */ "./dir11/a").catch(function (e) { expect(e).toMatchObject({ message: /not available/, code: /MODULE_NOT_FOUND/, - }) - }) -}) - -if (process.env.NODE_ENV === 'production') { - it('should contain only one export from webpackExports from module', function () { - return import(/* webpackExports: "usedExports" */ './dir12/a?1').then( - (module) => { - expect(module.usedExports).toEqual(['usedExports']) - }, - ) - }) - - it('should contain only webpackExports from module', function () { - return import( - /* webpackExports: ["a", "usedExports", "b"] */ './dir12/a?2' - ).then((module) => { - expect(module.usedExports).toEqual(['a', 'b', 'usedExports']) - }) - }) - - it('should contain only webpackExports from module in eager mode', function () { + }); + }); +}); + +if (process.env.NODE_ENV === "production") { + it("should contain only one export from webpackExports from module", function () { + return import(/* webpackExports: "usedExports" */ "./dir12/a?1").then((module) => { + expect(module.usedExports).toEqual(["usedExports"]); + }); + }); + + it("should contain only webpackExports from module", function () { + return import(/* webpackExports: ["a", "usedExports", "b"] */ "./dir12/a?2").then((module) => { + expect(module.usedExports).toEqual(["a", "b", "usedExports"]); + }); + }); + + it("should contain only webpackExports from module in eager mode", function () { return import( /* webpackMode: "eager", webpackExports: ["a", "usedExports", "b"] - */ './dir12/a?3' + */ "./dir12/a?3" ).then((module) => { - expect(module.usedExports).toEqual(['a', 'b', 'usedExports']) - }) - }) + expect(module.usedExports).toEqual(["a", "b", "usedExports"]); + }); + }); - it('should contain webpackExports from module in weak mode', function () { - require.resolve('./dir12/a?4') + it("should contain webpackExports from module in weak mode", function () { + require.resolve("./dir12/a?4"); return import( /* webpackMode: "weak", webpackExports: ["a", "usedExports", "b"] - */ './dir12/a?4' + */ "./dir12/a?4" ).then((module) => { - expect(module.usedExports).toEqual(['a', 'b', 'usedExports']) - }) - }) - - it('should not mangle webpackExports from module', function () { - return import(/* webpackExports: "longnameforexport" */ './dir12/a?5').then( - (module) => { - expect(module).toHaveProperty('longnameforexport') - }, - ) - }) - - it('should not mangle default webpackExports from module', function () { - return import(/* webpackExports: "default" */ './dir12/a?6').then( - (module) => { - expect(module).toHaveProperty('default') - }, - ) - }) - - it('should contain only webpackExports from module in context mode', function () { - const x = 'b' - return import(/* webpackExports: "usedExports" */ `./dir13/${x}`).then( - (module) => { - expect(module.usedExports).toEqual(['usedExports']) - }, - ) - }) + expect(module.usedExports).toEqual(["a", "b", "usedExports"]); + }); + }); + + it("should not mangle webpackExports from module", function () { + return import(/* webpackExports: "longnameforexport" */ "./dir12/a?5").then((module) => { + expect(module).toHaveProperty("longnameforexport"); + }); + }); + + it("should not mangle default webpackExports from module", function () { + return import(/* webpackExports: "default" */ "./dir12/a?6").then((module) => { + expect(module).toHaveProperty("default"); + }); + }); + + it("should contain only webpackExports from module in context mode", function () { + const x = "b"; + return import(/* webpackExports: "usedExports" */ `./dir13/${x}`).then((module) => { + expect(module.usedExports).toEqual(["usedExports"]); + }); + }); } function testChunkLoading(load, expectedSyncInitial, expectedSyncRequested) { - var sync = false - var syncInitial = true - var p = Promise.all([load('a'), load('b')]).then(function () { - expect(syncInitial).toBe(expectedSyncInitial) - sync = true + var sync = false; + var syncInitial = true; + var p = Promise.all([load("a"), load("b")]).then(function () { + expect(syncInitial).toBe(expectedSyncInitial); + sync = true; var p = Promise.all([ - load('a').then(function (a) { + load("a").then(function (a) { expect(a).toEqual( nsObj({ - default: 'a', - }), - ) - expect(sync).toBe(true) + default: "a", + }) + ); + expect(sync).toBe(true); }), - load('c').then(function (c) { + load("c").then(function (c) { expect(c).toEqual( nsObj({ - default: 'c', - }), - ) - expect(sync).toBe(expectedSyncRequested) + default: "c", + }) + ); + expect(sync).toBe(expectedSyncRequested); }), - ]) + ]); Promise.resolve() .then(function () {}) .then(function () {}) .then(function () {}) .then(function () { - sync = false - }) - return p - }) + sync = false; + }); + return p; + }); Promise.resolve() .then(function () {}) .then(function () {}) .then(function () {}) .then(function () { - syncInitial = false - }) - return p + syncInitial = false; + }); + return p; } diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js index e8f7328d6ee564..bd816eaba4ca3b 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/one/file.js @@ -1 +1 @@ -module.exports = 1 +module.exports = 1; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js index 6887896a4640a8..690aad34a46dc9 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/three/file.js @@ -1 +1 @@ -module.exports = 3 +module.exports = 3; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js index 4afe2ededa2763..4bbffde1044258 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/dir/two/file.js @@ -1 +1 @@ -module.exports = 2 +module.exports = 2; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js index 8216ef4ff32bbd..e9af6f942e016c 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-2443/index.js @@ -1,26 +1,26 @@ -it('should be able to use expressions in import (directory)', function (done) { +it("should be able to use expressions in import (directory)", function (done) { function load(name, expected, callback) { - import('./dir/' + name + '/file.js') + import("./dir/" + name + "/file.js") .then(function (result) { expect(result).toEqual( nsObj({ default: expected, - }), - ) - callback() + }) + ); + callback(); }) .catch(function (err) { - done(err) - }) + done(err); + }); } - if (Math.random() < 0) require('./dir/three/file') - load('one', 1, function () { - load('two', 2, function () { - load('three', 3, function () { - load('two', 2, function () { - done() - }) - }) - }) - }) -}) + if (Math.random() < 0) require("./dir/three/file"); + load("one", 1, function () { + load("two", 2, function () { + load("three", 3, function () { + load("two", 2, function () { + done(); + }); + }); + }); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js index 62fbb104f22099..0afaf89cabbd51 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/index.js @@ -1,7 +1,7 @@ -import x from './module' +import x from "./module"; -it('should export the same binding', () => { - return import('./module').then((ns) => { - expect(x).toBe(ns.default) - }) -}) +it("should export the same binding", () => { + return import("./module").then((ns) => { + expect(x).toBe(ns.default); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js index b1c6ea436a5400..ff8b4c56321a33 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/issue-5153/module.js @@ -1 +1 @@ -export default {} +export default {}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js index abb59fc3305a23..5d2c2eb3738bb8 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js @@ -1,177 +1,169 @@ -it('should handle named chunks', function (done) { - var sync = false +it("should handle named chunks", function (done) { + var sync = false; require.ensure( [], function (require) { - require('./empty?a') - require('./empty?b') - testLoad() - sync = true + require("./empty?a"); + require("./empty?b"); + testLoad(); + sync = true; process.nextTick(function () { - sync = false - }) + sync = false; + }); }, - 'named-chunk', - ) + "named-chunk" + ); function testLoad() { require.ensure( [], function (require) { - require('./empty?c') - require('./empty?d') - expect(sync).toBeTruthy() - done() + require("./empty?c"); + require("./empty?d"); + expect(sync).toBeTruthy(); + done(); }, - 'named-chunk', - ) + "named-chunk" + ); } -}) +}); -it('should handle empty named chunks', function (done) { - var sync = false +it("should handle empty named chunks", function (done) { + var sync = false; require.ensure( [], function (require) { - expect(sync).toBeTruthy() + expect(sync).toBeTruthy(); }, - 'empty-named-chunk', - ) + "empty-named-chunk" + ); require.ensure( [], function (require) { - expect(sync).toBeTruthy() - done() + expect(sync).toBeTruthy(); + done(); }, - 'empty-named-chunk', - ) - sync = true + "empty-named-chunk" + ); + sync = true; setImmediate(function () { - sync = false - }) -}) + sync = false; + }); +}); -it('should handle named chunks when there is an error callback', function (done) { - var sync = false +it("should handle named chunks when there is an error callback", function (done) { + var sync = false; require.ensure( [], function (require) { - require('./empty?e') - require('./empty?f') - testLoad() - sync = true + require("./empty?e"); + require("./empty?f"); + testLoad(); + sync = true; process.nextTick(function () { - sync = false - }) + sync = false; + }); }, function (error) {}, - 'named-chunk-for-error-callback', - ) + "named-chunk-for-error-callback" + ); function testLoad() { require.ensure( [], function (require) { - require('./empty?g') - require('./empty?h') - expect(sync).toBeTruthy() - done() + require("./empty?g"); + require("./empty?h"); + expect(sync).toBeTruthy(); + done(); }, function (error) {}, - 'named-chunk-for-error-callback', - ) + "named-chunk-for-error-callback" + ); } -}) +}); -it('should handle empty named chunks when there is an error callback', function (done) { - var sync = false +it("should handle empty named chunks when there is an error callback", function (done) { + var sync = false; require.ensure( [], function (require) { - expect(sync).toBeTruthy() + expect(sync).toBeTruthy(); }, function (error) {}, - 'empty-named-chunk-for-error-callback', - ) + "empty-named-chunk-for-error-callback" + ); require.ensure( [], function (require) { - expect(sync).toBeTruthy() - done() + expect(sync).toBeTruthy(); + done(); }, function (error) {}, - 'empty-named-chunk-for-error-callback', - ) - sync = true + "empty-named-chunk-for-error-callback" + ); + sync = true; setImmediate(function () { - sync = false - }) -}) + sync = false; + }); +}); -it('should be able to use named chunks in import()', function (done) { - var sync = false - import( - './empty?import1-in-chunk1' /* webpackChunkName: "import-named-chunk-1" */ - ).then(function (result) { - var i = 0 - import( - './empty?import2-in-chunk1' /* webpackChunkName: "import-named-chunk-1" */ - ) +it("should be able to use named chunks in import()", function (done) { + var sync = false; + import("./empty?import1-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */).then(function (result) { + var i = 0; + import("./empty?import2-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */) .then(function (result) { - expect(sync).toBeTruthy() - if (i++ > 0) done() + expect(sync).toBeTruthy(); + if (i++ > 0) done(); }) .catch(function (err) { - done(err) - }) - import( - './empty?import3-in-chunk2' /* webpackChunkName: "import-named-chunk-2" */ - ) + done(err); + }); + import("./empty?import3-in-chunk2" /* webpackChunkName: "import-named-chunk-2" */) .then(function (result) { - expect(sync).toBeFalsy() - if (i++ > 0) done() + expect(sync).toBeFalsy(); + if (i++ > 0) done(); }) .catch(function (err) { - done(err) - }) - sync = true + done(err); + }); + sync = true; Promise.resolve() .then(function () {}) .then(function () {}) .then(function () { - sync = false - }) - }) -}) + sync = false; + }); + }); +}); -it('should be able to use named chunk in context import()', function (done) { +it("should be able to use named chunk in context import()", function (done) { // cspell:ignore mpty - var mpty = 'mpty' - var sync = false - import('./e' + mpty + '2' /* webpackChunkName: "context-named-chunk" */).then( - function (result) { - var i = 0 - import('./e' + mpty + '3' /* webpackChunkName: "context-named-chunk" */) - .then(function (result) { - expect(sync).toBeTruthy() - if (i++ > 0) done() - }) - .catch(function (err) { - done(err) - }) - import('./e' + mpty + '4' /* webpackChunkName: "context-named-chunk-2" */) - .then(function (result) { - expect(sync).toBeFalsy() - if (i++ > 0) done() - }) - .catch(function (err) { - done(err) - }) - sync = true - Promise.resolve() - .then(function () {}) - .then(function () {}) - .then(function () { - sync = false - }) - }, - ) -}) + var mpty = "mpty"; + var sync = false; + import("./e" + mpty + "2" /* webpackChunkName: "context-named-chunk" */).then(function (result) { + var i = 0; + import("./e" + mpty + "3" /* webpackChunkName: "context-named-chunk" */) + .then(function (result) { + expect(sync).toBeTruthy(); + if (i++ > 0) done(); + }) + .catch(function (err) { + done(err); + }); + import("./e" + mpty + "4" /* webpackChunkName: "context-named-chunk-2" */) + .then(function (result) { + expect(sync).toBeFalsy(); + if (i++ > 0) done(); + }) + .catch(function (err) { + done(err); + }); + sync = true; + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () { + sync = false; + }); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js index a8653a9c9264ca..888cae37af95c5 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/b.js @@ -1 +1 @@ -module.exports = 42 +module.exports = 42; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js index 529dea49dfd414..155e728ed41a96 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/nested-in-empty/index.js @@ -1,13 +1,13 @@ -it('should include a chunk nested in an empty chunk', (done) => { - require.ensure(['./a'], () => { +it("should include a chunk nested in an empty chunk", (done) => { + require.ensure(["./a"], () => { require.ensure([], () => { - require.ensure(['./a'], () => { + require.ensure(["./a"], () => { require.ensure([], () => { - const b = require('./b') - expect(b).toBe(42) - done() - }) - }) - }) - }) -}) + const b = require("./b"); + expect(b).toBe(42); + done(); + }); + }); + }); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js index d629ab1d37fa8d..960692c7ee48d6 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/index.js @@ -1,49 +1,49 @@ -it('should handle bound function expressions', function (done) { +it("should handle bound function expressions", function (done) { require.ensure( [], function (require) { - expect(this).toEqual({ test: true }) - require('./empty?test') - expect(process.nextTick).toBeTypeOf('function') // check if injection still works + expect(this).toEqual({ test: true }); + require("./empty?test"); + expect(process.nextTick).toBeTypeOf("function"); // check if injection still works require.ensure( [], function (require) { - expect(this).toEqual({ test: true }) - done() - }.bind(this), - ) - }.bind({ test: true }), - ) -}) + expect(this).toEqual({ test: true }); + done(); + }.bind(this) + ); + }.bind({ test: true }) + ); +}); -it('should handle require.ensure without function expression', function (done) { +it("should handle require.ensure without function expression", function (done) { function f() { - done() + done(); } - require.ensure([], f) -}) + require.ensure([], f); +}); it("should parse expression in require.ensure, which isn't a function expression", function (done) { require.ensure( [], (function () { - expect(require('./empty?require.ensure:test')).toEqual({}) + expect(require("./empty?require.ensure:test")).toEqual({}); return function f() { - done() - } - })(), - ) -}) + done(); + }; + })() + ); +}); -it('should accept an already included module', function (done) { - if (Math.random() < 0) require('./require.include') - var value = null +it("should accept an already included module", function (done) { + if (Math.random() < 0) require("./require.include"); + var value = null; require.ensure([], function (require) { - value = require('./require.include') - }) + value = require("./require.include"); + }); setImmediate(function () { - expect(value).toBe('require.include') - expect(value).toBe('require.include') - done() - }) -}) + expect(value).toBe("require.include"); + expect(value).toBe("require.include"); + done(); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js index 2a3e53cff08921..5629abd04a65dd 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/parsing/require.include.js @@ -1 +1 @@ -module.exports = 'require.include' +module.exports = "require.include"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js index 67606e3f86ef08..6cd1d0075d4032 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/a.js @@ -1 +1 @@ -module.exports = 'a' +module.exports = "a"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js index dc7913891e6a38..9d55f62ced6edf 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular.js @@ -1,3 +1,3 @@ -require.ensure(['./acircular2'], function (require) { - require('./acircular2') -}) +require.ensure(["./acircular2"], function (require) { + require("./acircular2"); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js index 91cc6f271ac6be..61ae309602dcaa 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/acircular2.js @@ -1,3 +1,3 @@ -require.ensure(['./acircular'], function (require) { - require('./acircular') -}) +require.ensure(["./acircular"], function (require) { + require("./acircular"); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js index 0df40b2a802d5f..d45a37c0b57207 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/b.js @@ -1 +1 @@ -module.exports = require('./a') +module.exports = require("./a"); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js index 1830a4e6eaf811..d0f62131699ca7 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate.js @@ -1,3 +1,3 @@ -require.ensure(['./a'], function (require) { - expect(require('./a')).toBe('a') -}) +require.ensure(["./a"], function (require) { + expect(require("./a")).toBe("a"); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js index cf892b8dd66513..e7228b2b4e8fd8 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/duplicate2.js @@ -1,3 +1,3 @@ -require.ensure(['./b'], function (require) { - expect(require('./b')).toBe('a') -}) +require.ensure(["./b"], function (require) { + expect(require("./b")).toBe("a"); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js index ac44d739b7caae..02ef9177a56a6d 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/index.js @@ -1,54 +1,54 @@ /* globals it */ -it('should handle duplicate chunks', function (done) { +it("should handle duplicate chunks", function (done) { var firstOne = false, - secondOne = false + secondOne = false; require.ensure([], function (require) { - require('./acircular') - require('./duplicate') - require('./duplicate2') - firstOne = true - if (secondOne) done() - }) + require("./acircular"); + require("./duplicate"); + require("./duplicate2"); + firstOne = true; + if (secondOne) done(); + }); require.ensure([], function (require) { - require('./acircular2') - require('./duplicate') - require('./duplicate2') - secondOne = true - if (firstOne) done() - }) -}) + require("./acircular2"); + require("./duplicate"); + require("./duplicate2"); + secondOne = true; + if (firstOne) done(); + }); +}); -it('should not load a chunk which is included in a already loaded one', function (done) { - var asyncFlag = false - require.ensure(['./empty?x', './empty?y', './empty?z'], function (require) { +it("should not load a chunk which is included in a already loaded one", function (done) { + var asyncFlag = false; + require.ensure(["./empty?x", "./empty?y", "./empty?z"], function (require) { try { - expect(asyncFlag).toBe(true) - loadChunk() + expect(asyncFlag).toBe(true); + loadChunk(); } catch (e) { - done(e) + done(e); } - }) + }); Promise.resolve() .then(function () {}) .then(function () {}) .then(function () { - asyncFlag = true - }) + asyncFlag = true; + }); function loadChunk() { - var sync = true - require.ensure(['./empty?x', './empty?y'], function (require) { + var sync = true; + require.ensure(["./empty?x", "./empty?y"], function (require) { try { - expect(sync).toBe(true) - done() + expect(sync).toBe(true); + done(); } catch (e) { - done(e) + done(e); } - }) + }); Promise.resolve() .then(function () {}) .then(function () {}) .then(function () { - sync = false - }) + sync = false; + }); } -}) +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js index a530e6222da5b7..1fb719fdd61259 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/runtime/test.filter.js @@ -1,4 +1,4 @@ module.exports = function (config) { // This test can't run in development mode as it depends on the flagIncludedChunks optimization - return config.mode !== 'development' -} + return config.mode !== "development"; +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js index fb000bb0f3214c..76777f44c40429 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/var-inject-error-handler/index.js @@ -1,12 +1,12 @@ -it('should handle var injection in require.ensure with error callback', function (done) { +it("should handle var injection in require.ensure with error callback", function (done) { require.ensure( [], function (require) { - require('./empty') - var x = module.x - done() + require("./empty"); + var x = module.x; + done(); }, function (error) {}, - 'chunk-with-var-inject', - ) -}) + "chunk-with-var-inject" + ); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js index 0677b49aba0006..ae551faeba7877 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies-context/index.js @@ -1,24 +1,24 @@ -it('should not include a module with a weak dependency using context', function () { - var fileA = 'a' - var fileB = 'b' - var fileC = 'c' +it("should not include a module with a weak dependency using context", function () { + var fileA = "a"; + var fileB = "b"; + var fileC = "c"; - var resolveWeakA = require.resolveWeak('./' + fileA) - var resolveWeakB = require.resolveWeak('./' + fileB) - var resolveWeakC = require.resolveWeak('./' + fileC) + var resolveWeakA = require.resolveWeak("./" + fileA); + var resolveWeakB = require.resolveWeak("./" + fileB); + var resolveWeakC = require.resolveWeak("./" + fileC); - var a = !!__webpack_modules__[resolveWeakA] - var b = !!__webpack_modules__[resolveWeakB] - var c = !!__webpack_modules__[resolveWeakC] + var a = !!__webpack_modules__[resolveWeakA]; + var b = !!__webpack_modules__[resolveWeakB]; + var c = !!__webpack_modules__[resolveWeakC]; - require(['./b']) - require('./c') + require(["./b"]); + require("./c"); - expect(resolveWeakA).toBeDefined() - expect(resolveWeakB).toBeDefined() - expect(resolveWeakC).toBeDefined() + expect(resolveWeakA).toBeDefined(); + expect(resolveWeakB).toBeDefined(); + expect(resolveWeakC).toBeDefined(); - expect(a).toBe(false) - expect(b).toBe(false) - expect(c).toBe(true) -}) + expect(a).toBe(false); + expect(b).toBe(false); + expect(c).toBe(true); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js index 57cc29d985da6a..11a830afeaa01c 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/weak-dependencies/index.js @@ -1,13 +1,13 @@ -it('should not include a module with a weak dependency', function () { - var a = !!__webpack_modules__[require.resolveWeak('./a')] - var b = !!__webpack_modules__[require.resolve('./b')] - var c = !!__webpack_modules__[require.resolveWeak('./c')] - var d = !!__webpack_modules__[require.resolveWeak('./d')] - require(['./c']) - require('./d') +it("should not include a module with a weak dependency", function () { + var a = !!__webpack_modules__[require.resolveWeak("./a")]; + var b = !!__webpack_modules__[require.resolve("./b")]; + var c = !!__webpack_modules__[require.resolveWeak("./c")]; + var d = !!__webpack_modules__[require.resolveWeak("./d")]; + require(["./c"]); + require("./d"); - expect(a).toBe(false) - expect(b).toBe(true) - expect(c).toBe(false) - expect(d).toBe(true) -}) + expect(a).toBe(false); + expect(b).toBe(true); + expect(c).toBe(false); + expect(d).toBe(true); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js index aeb0fa01602b30..8b2e75f1817e44 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js @@ -1,16 +1,16 @@ -it('should handle circular chunks correctly', function (done) { - import(/* webpackChunkName: "a" */ './module-a') +it("should handle circular chunks correctly", function (done) { + import(/* webpackChunkName: "a" */ "./module-a") .then(function (result) { - return result.default() + return result.default(); }) .then(function (result2) { - expect(result2.default()).toBe('x') - done() + expect(result2.default()).toBe("x"); + done(); }) .catch(function (e) { - done(e) - }) + done(e); + }); const couldBe = function () { - return import(/* webpackChunkName: "b" */ './module-b') - } -}) + return import(/* webpackChunkName: "b" */ "./module-b"); + }; +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js index 28186c7d058d78..36315c96b8a819 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js @@ -1,3 +1,3 @@ export default function () { - return import(/* webpackChunkName: "c" */ './module-c') + return import(/* webpackChunkName: "c" */ "./module-c"); } diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js index 11657bc4d6f874..ca02e52b62d10c 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js @@ -1 +1 @@ -export default 'a2' +export default "a2"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js index 6988115c8dfacc..f0b1237c622442 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js @@ -1,5 +1,5 @@ -import './module-x' +import "./module-x"; export default function () { - return import(/* webpackChunkName: "c" */ './module-c') + return import(/* webpackChunkName: "c" */ "./module-c"); } diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js index 6ada853c4fcb7c..e8a4051b1447af 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js @@ -1 +1 @@ -export default 'b2' +export default "b2"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js index e1589931fec458..9cf7d81010bae5 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js @@ -1,9 +1,9 @@ -import x from './module-x' +import x from "./module-x"; export default function () { if (Math.random() < -1) { - import(/* webpackChunkName: "a" */ './module-a') - import(/* webpackChunkName: "b" */ './module-b') + import(/* webpackChunkName: "a" */ "./module-a"); + import(/* webpackChunkName: "b" */ "./module-b"); } - return x + return x; } diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js index 064e9982a8b4d1..3fd5ecc7a40794 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js @@ -1 +1 @@ -export default 'x' +export default "x"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js index b143ed5890b4d2..22a1feccc6446b 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js @@ -1,5 +1,3 @@ module.exports = [ - [ - /It's not allowed to load an initial chunk on demand\. The chunk name "main" is already used by an entrypoint\./, - ], -] + [/It's not allowed to load an initial chunk on demand\. The chunk name "main" is already used by an entrypoint\./], +]; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js index 7bad2ad04f4dae..83704cff68716f 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/index.js @@ -1,10 +1,10 @@ -it('should handle reference to entry chunk correctly', function (done) { - import(/* webpackChunkName: "main" */ './module-a') +it("should handle reference to entry chunk correctly", function (done) { + import(/* webpackChunkName: "main" */ "./module-a") .then(function (result) { - expect(result.default).toBe('ok') - done() + expect(result.default).toBe("ok"); + done(); }) .catch(function (e) { - done(e) - }) -}) + done(e); + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js index 60c71f346d9a3e..5c6b89abfc84dc 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/module-a.js @@ -1 +1 @@ -export default 'ok' +export default "ok"; From 647a87f8f01ea3811565f0768ebdec0da667b4bd Mon Sep 17 00:00:00 2001 From: Leah Date: Tue, 20 Sep 2022 21:57:49 +0300 Subject: [PATCH 095/672] better ssr error message (vercel/turbo#387) --- packages/next-swc/crates/next-core/src/server_render/asset.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index afefdb5cc6c54a..c320d571764953 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -342,7 +342,8 @@ async fn render( // Show error page // TODO This need to include HMR handler to allow auto refresh let result = into_result(format!( - "Error during rendering:\n{}\n\n{}", + "

Error during \ + rendering

\n

Message

\n
{}
\n

Logs

\n
{}
", issue.message.await?, issue.logging.await? )); From 620a6e0aaf73df1b41395105d1f8da42818e874d Mon Sep 17 00:00:00 2001 From: Leah Date: Wed, 21 Sep 2022 17:47:23 +0200 Subject: [PATCH 096/672] small fixes / improvements (vercel/turbo#341) Many small things I found The most important is probably the typescript transform The remaining bits should hopefully be self-explanatory from the commit messages --- packages/next-swc/crates/next-dev/src/main.rs | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 3ead12545a3552..3fd4e0ede71ff2 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -121,22 +121,24 @@ async fn main() -> Result<()> { } } - join! { - async move { - let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; - println!("initial compilation {} ({} task execution, {} tasks)", - FormatDuration(start.elapsed()), FormatDuration(elapsed), count); - - loop { - let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::from_millis(100)).await; - println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); - } - }, - async { - server.future.await.unwrap() + let stats_future = async move { + let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; + println!( + "initial compilation {} ({} task execution, {} tasks)", + FormatDuration(start.elapsed()), + FormatDuration(elapsed), + count + ); + + loop { + let (elapsed, count) = tt_clone + .get_or_wait_update_info(Duration::from_millis(100)) + .await; + println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); } - } - .await; + }; + + join!(stats_future, async { server.future.await.unwrap() }).await; Ok(()) } From b7e9d4e3f0ce4cef3ac1658620275e75deb0af2b Mon Sep 17 00:00:00 2001 From: Leah Date: Wed, 21 Sep 2022 19:14:24 +0200 Subject: [PATCH 097/672] more type safe next-dev builder (vercel/turbo#388) --- packages/next-swc/crates/next-dev/src/lib.rs | 45 ++++++------------- packages/next-swc/crates/next-dev/src/main.rs | 5 +-- .../crates/next-dev/tests/integration.rs | 29 ++++++------ 3 files changed, 30 insertions(+), 49 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 5da5181ae6e43d..723553846ac195 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -22,9 +22,9 @@ use turbopack_dev_server::{ mod turbo_tasks_viz; pub struct NextDevServerBuilder { - turbo_tasks: Option>>, - project_dir: Option, - root_dir: Option, + turbo_tasks: Arc>, + project_dir: String, + root_dir: String, entry_requests: Vec, eager_compile: bool, hostname: Option, @@ -34,18 +34,16 @@ pub struct NextDevServerBuilder { log_detail: bool, } -impl Default for NextDevServerBuilder { - fn default() -> Self { - NextDevServerBuilder::new() - } -} - impl NextDevServerBuilder { - pub fn new() -> NextDevServerBuilder { + pub fn new( + turbo_tasks: Arc>, + project_dir: String, + root_dir: String, + ) -> NextDevServerBuilder { NextDevServerBuilder { - turbo_tasks: None, - project_dir: None, - root_dir: None, + turbo_tasks, + project_dir, + root_dir, entry_requests: vec![], eager_compile: false, hostname: None, @@ -56,21 +54,6 @@ impl NextDevServerBuilder { } } - pub fn turbo_tasks(mut self, tt: Arc>) -> NextDevServerBuilder { - self.turbo_tasks = Some(tt); - self - } - - pub fn project_dir(mut self, project_dir: String) -> NextDevServerBuilder { - self.project_dir = Some(project_dir); - self - } - - pub fn root_dir(mut self, root_dir: String) -> NextDevServerBuilder { - self.root_dir = Some(root_dir); - self - } - pub fn entry_request(mut self, entry_asset_path: String) -> NextDevServerBuilder { self.entry_requests.push(entry_asset_path); self @@ -107,10 +90,10 @@ impl NextDevServerBuilder { } pub async fn build(self) -> Result { - let turbo_tasks = self.turbo_tasks.context("turbo_tasks must be set")?; + let turbo_tasks = self.turbo_tasks; - let project_dir = self.project_dir.context("project_dir must be set")?; - let root_dir = self.root_dir.context("root_dir must be set")?; + let project_dir = self.project_dir; + let root_dir = self.root_dir; let entry_requests = self.entry_requests; let eager_compile = self.eager_compile; let show_all = self.show_all; diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 3fd4e0ede71ff2..272d16ddbfab18 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -92,10 +92,7 @@ async fn main() -> Result<()> { let tt = TurboTasks::new(MemoryBackend::new()); let tt_clone = tt.clone(); - let server = NextDevServerBuilder::new() - .turbo_tasks(tt) - .project_dir(dir) - .root_dir(root_dir) + let server = NextDevServerBuilder::new(tt, dir, root_dir) .entry_request("src/index".into()) .eager_compile(args.eager_compile) .hostname(args.hostname) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index 3bf97fe47d9b92..e02416fa0eaf7d 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -118,20 +118,21 @@ async fn run_test(resource: &str) -> JestRunResult { ); let requested_addr = get_free_local_addr().unwrap(); - let server = NextDevServerBuilder::new() - .turbo_tasks(TurboTasks::new(MemoryBackend::new())) - .root_dir("tests".into()) - .project_dir("tests".into()) - .entry_request("harness.js".into()) - .entry_request( - sys_to_unix(test_entry.strip_prefix("tests").unwrap().to_str().unwrap()).to_string(), - ) - .eager_compile(false) - .hostname(requested_addr.ip()) - .port(requested_addr.port()) - .build() - .await - .unwrap(); + let server = NextDevServerBuilder::new( + TurboTasks::new(MemoryBackend::new()), + "tests".into(), + "tests".into(), + ) + .entry_request("harness.js".into()) + .entry_request( + sys_to_unix(test_entry.strip_prefix("tests").unwrap().to_str().unwrap()).to_string(), + ) + .eager_compile(false) + .hostname(requested_addr.ip()) + .port(requested_addr.port()) + .build() + .await + .unwrap(); println!("server started at http://{}", server.addr); From 25ca6b2e2c227a686383e3f68e9774d6f6df5f53 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 27 Sep 2022 16:33:45 -0400 Subject: [PATCH 098/672] Implement `.env` loading (vercel/turbo#409) This implements `.env` loading by taking advantage of the [dotenvy](https://docs.rs/dotenvy/latest/dotenvy/) crate. Unfortunately, this isn't as featureful as the npm `dotenv`, lacking `FOO=${BAR:-default}` default support (this might be important), `FOO=${MAYBE_UNDEFINED:-${BAR-:default}}` nested fallbacks, and `` FOO=`backtick` `` support. This is then converted into a series of assignments for the client code. This is run before any of the user code. ```js const env = process.env; env["FOO"] = "bar"; //... ``` - - - TODO: - [x] ~~Replace `process.env.FOO`/`process.env["FOO"]` during chunk compilation~~ - using a runtime module speeds up HMR because the code doesn't need to be recompiled. - [x] I don't actually know how to test server rendering, so I assume it works but haven't verified. --- packages/next-swc/crates/next-core/Cargo.toml | 2 ++ packages/next-swc/crates/next-core/src/env.rs | 34 +++++++++++++++++++ packages/next-swc/crates/next-core/src/lib.rs | 2 ++ .../next-core/src/server_render/asset.rs | 11 +++++- .../next-core/src/server_rendered_source.rs | 31 +++++++++++++---- .../crates/next-core/src/web_entry_source.rs | 12 +++++-- packages/next-swc/crates/next-dev/src/lib.rs | 6 +++- 7 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/env.rs diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 4cf03f21f368e9..d9352b1d2f8553 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -20,6 +20,8 @@ turbo-tasks-fs = { path = "../turbo-tasks-fs" } turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } +turbopack-ecmascript = { path = "../turbopack-ecmascript" } +turbopack-env = { path = "../turbopack-env" } [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-core/src/env.rs b/packages/next-swc/crates/next-core/src/env.rs new file mode 100644 index 00000000000000..e39e9626754f92 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/env.rs @@ -0,0 +1,34 @@ +use anyhow::Result; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_env::ProcessEnvVc; + +/// Loads a series of dotenv files according to the precedence rules set by +/// https://nextjs.org/docs/basic-features/environment-variables#environment-variable-load-order +#[turbo_tasks::function] +pub async fn load_env(project_path: FileSystemPathVc) -> Result { + let node_env = std::env::var("NODE_ENV").unwrap_or_else(|_| "development".into()); + + let files = [ + Some(format!(".env.{node_env}.local")), + if node_env == "test" { + None + } else { + Some(".env.local".into()) + }, + Some(format!(".env.{node_env}")), + Some(".env".into()), + ] + .into_iter() + .flatten(); + + let env = files.fold(ProcessEnvVc::from_command_line(), |prior, f| { + let path = project_path.join(&f); + ProcessEnvVc::from_dotenv_file(path, Some(prior)) + }); + + Ok(env) +} + +pub fn filter_for_client(env: ProcessEnvVc) -> ProcessEnvVc { + ProcessEnvVc::filter(env, "NEXT_PUBLIC_".to_string()) +} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index d3e2e419d8a80b..3041c1dc3dcca7 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -1,5 +1,7 @@ +#![feature(async_closure)] #![feature(min_specialization)] +pub mod env; pub mod next_client; pub mod react_refresh; mod server_render; diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index c320d571764953..1bc07baa085903 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -24,6 +24,7 @@ use turbopack_core::{ resolve::{ResolveResult, ResolveResultVc}, wrapper_asset::WrapperAssetVc, }; +use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; use super::{ nodejs_bootstrap::NodeJsBootstrapAsset, @@ -45,6 +46,7 @@ pub struct ServerRenderedAsset { path: FileSystemPathVc, context: AssetContextVc, entry_asset: AssetVc, + runtime_entries: EcmascriptChunkPlaceablesVc, context_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, request_data: String, @@ -57,6 +59,7 @@ impl ServerRenderedAssetVc { path: FileSystemPathVc, context: AssetContextVc, entry_asset: AssetVc, + runtime_entries: EcmascriptChunkPlaceablesVc, context_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, request_data: String, @@ -65,6 +68,7 @@ impl ServerRenderedAssetVc { path, context, entry_asset, + runtime_entries, context_path, intermediate_output_path, request_data, @@ -88,6 +92,7 @@ impl Asset for ServerRenderedAsset { get_intermediate_asset( self.context, self.entry_asset, + self.runtime_entries, self.context_path, self.intermediate_output_path, ), @@ -104,6 +109,7 @@ impl Asset for ServerRenderedAsset { get_intermediate_asset( self.context, self.entry_asset, + self.runtime_entries, self.context_path, self.intermediate_output_path, ), @@ -155,6 +161,7 @@ fn get_server_renderer() -> FileContentVc { async fn get_intermediate_asset( context: AssetContextVc, entry_asset: AssetVc, + runtime_entries: EcmascriptChunkPlaceablesVc, context_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, ) -> Result { @@ -172,7 +179,9 @@ async fn get_intermediate_asset( EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { refresh: false }]), context.environment(), ); - let chunk = module.as_evaluated_chunk(chunking_context.into(), None); + + let chunk = module.as_evaluated_chunk(chunking_context.into(), Some(runtime_entries)); + let chunk_group = ChunkGroupVc::from_chunk(chunk); Ok(NodeJsBootstrapAsset { path: intermediate_output_path.join("index.js"), diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 5779fe73bdc8d0..5591a32a810e74 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -26,8 +26,11 @@ use turbopack_dev_server::{ ContentSourceVc, NoContentSourceVc, }, }; +use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; +use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; use crate::{ + env::filter_for_client, next_client::{NextClientTransition, RuntimeReference}, react_refresh::{assert_can_resolve_react_refresh, react_refresh_request}, server_render::asset::ServerRenderedAssetVc, @@ -40,6 +43,7 @@ pub async fn create_server_rendered_source( root_path: FileSystemPathVc, output_path: FileSystemPathVc, target_root: FileSystemPathVc, + env: ProcessEnvVc, ) -> Result { let pages = root_path.join("pages"); let src_pages = root_path.join("src/pages"); @@ -79,10 +83,21 @@ pub async fn create_server_rendered_source( ..Default::default() } .cell(); + + let server_runtime_entries = + vec![ProcessEnvAssetVc::new(root_path, env).as_ecmascript_chunk_placeable()]; + let mut client_runtime_references = vec![RuntimeReference::Reference( + SingleAssetReferenceVc::new( + ProcessEnvAssetVc::new(root_path, filter_for_client(env)).as_asset(), + StringVc::cell(".env".to_string()), + ) + .into(), + )]; + let enable_react_refresh = *assert_can_resolve_react_refresh(root_path, client_resolve_options_context).await?; - let runtime_references = if enable_react_refresh { - vec![ + if enable_react_refresh { + client_runtime_references.extend(vec![ RuntimeReference::Request(react_refresh_request(), root_path), RuntimeReference::Reference( SingleAssetReferenceVc::new( @@ -91,9 +106,7 @@ pub async fn create_server_rendered_source( ) .into(), ), - ] - } else { - Vec::new() + ]); }; let client_module_options_context = ModuleOptionsContext { enable_react_refresh, @@ -108,7 +121,7 @@ pub async fn create_server_rendered_source( client_resolve_options_context, client_environment, server_root: target_root, - runtime_references, + runtime_references: client_runtime_references, } .cell() .into(); @@ -148,6 +161,7 @@ pub async fn create_server_rendered_source( Ok(create_server_rendered_source_for_directory( context, dir, + EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), target_root, target_root, output_path, @@ -160,6 +174,7 @@ pub async fn create_server_rendered_source( async fn create_server_rendered_source_for_file( context: AssetContextVc, entry: FileSystemPathVc, + runtime_entries: EcmascriptChunkPlaceablesVc, target_root: FileSystemPathVc, target_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, @@ -173,6 +188,7 @@ async fn create_server_rendered_source_for_file( target_path, context, module, + runtime_entries, context_path, intermediate_output_path, "{\"props\":{}}\n".to_string(), @@ -190,6 +206,7 @@ async fn create_server_rendered_source_for_file( async fn create_server_rendered_source_for_directory( context: AssetContextVc, input_dir: FileSystemPathVc, + runtime_entries: EcmascriptChunkPlaceablesVc, target_root: FileSystemPathVc, target_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, @@ -216,6 +233,7 @@ async fn create_server_rendered_source_for_directory( create_server_rendered_source_for_file( context, *file, + runtime_entries, target_root, target_path, intermediate_output_path, @@ -232,6 +250,7 @@ async fn create_server_rendered_source_for_directory( create_server_rendered_source_for_directory( context, *dir, + runtime_entries, target_root, target_path.join(name), intermediate_output_path.join(name), diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 5a83c3dba4c3ac..a7b531ff9a8cb8 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -24,14 +24,19 @@ use turbopack_dev_server::{ html_runtime_asset::HtmlRuntimeAssetVc, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; +use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; -use crate::react_refresh::{assert_can_resolve_react_refresh, resolve_react_refresh}; +use crate::{ + env::filter_for_client, + react_refresh::{assert_can_resolve_react_refresh, resolve_react_refresh}, +}; #[turbo_tasks::function] pub async fn create_web_entry_source( root: FileSystemPathVc, entry_requests: Vec, dev_server_fs: FileSystemVc, + env: ProcessEnvVc, eager_compile: bool, ) -> Result { let environment = EnvironmentVc::new( @@ -84,7 +89,10 @@ pub async fn create_web_entry_source( } .into(); - let mut runtime_entries = vec![HtmlRuntimeAssetVc::new().as_ecmascript_chunk_placeable()]; + let mut runtime_entries = vec![ + ProcessEnvAssetVc::new(root, filter_for_client(env)).as_ecmascript_chunk_placeable(), + HtmlRuntimeAssetVc::new().as_ecmascript_chunk_placeable(), + ]; if enable_react_refresh { runtime_entries.push(resolve_react_refresh(context)) } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 723553846ac195..2cf92b5928d482 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -4,7 +4,7 @@ use std::{net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; -use next_core::{create_server_rendered_source, create_web_entry_source}; +use next_core::{create_server_rendered_source, create_web_entry_source, env::load_env}; use turbo_tasks::{CollectiblesSource, TransientInstance, TurboTasks, Value}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; @@ -180,6 +180,8 @@ async fn source( .unwrap_or(project_relative); let project_path = FileSystemPathVc::new(fs, project_relative); + let env = load_env(project_path); + let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let web_source = create_web_entry_source( project_path, @@ -188,12 +190,14 @@ async fn source( .map(|a| RequestVc::relative(Value::new(a.to_string().into()), false)) .collect(), dev_server_fs, + env, eager_compile, ); let rendered_source = create_server_rendered_source( project_path, FileSystemPathVc::new(output_fs, ""), FileSystemPathVc::new(dev_server_fs, ""), + env, ); let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.into(), From 3263f5e5e66edb843d4de56e187ab15d0a3518e8 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 28 Sep 2022 11:02:40 +0200 Subject: [PATCH 099/672] replace json with serde_json (vercel/turbo#398) get rid of `json` in favor of only `serde_json` for consistency and less dependencies --- packages/next-swc/crates/next-core/Cargo.toml | 2 +- .../crates/next-core/src/server_render/asset.rs | 5 +++-- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- packages/next-swc/crates/next-dev/benches/util/npm.rs | 11 ++++++----- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index d9352b1d2f8553..fad26ae38014b3 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -11,9 +11,9 @@ bench = false [dependencies] anyhow = "1.0.47" futures = "0.3.21" -json = "0.12.4" mime = "0.3.16" serde = "1.0.136" +serde_json = "1.0.85" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index 1bc07baa085903..b8aa8ff253f8be 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -6,6 +6,7 @@ use std::{ use anyhow::{anyhow, Result}; use futures::{stream::FuturesUnordered, TryStreamExt}; use mime::TEXT_HTML_UTF_8; +use serde_json::Value as JsonValue; use turbo_tasks::{ primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, Value, ValueToString, }; @@ -306,7 +307,7 @@ async fn render( .await?; let issue = if let Some(last_line) = lines.last() { if let Some(data) = last_line.strip_prefix("RESULT=") { - let data = json::parse(data)?; + let data: JsonValue = serde_json::from_str(data)?; if let Some(s) = data.as_str() { return into_result(s.to_string()); } else { @@ -319,7 +320,7 @@ async fn render( } } } else if let Some(data) = last_line.strip_prefix("ERROR=") { - let data = json::parse(data)?; + let data: JsonValue = serde_json::from_str(data)?; if let Some(s) = data.as_str() { RenderingIssue { context: path, diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index d5a658d94a86f1..0a38c782e3b561 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -30,11 +30,11 @@ anyhow = "1.0.47" clap = { version = "3", features = ["derive"] } console-subscriber = { version = "0.1.6", optional = true } futures = "0.3.21" -json = "0.12.4" mime = "0.3.16" next-core = { path = "../next-core" } portpicker = "0.1.1" serde = "1.0.136" +serde_json = "1.0.85" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } diff --git a/packages/next-swc/crates/next-dev/benches/util/npm.rs b/packages/next-swc/crates/next-dev/benches/util/npm.rs index 79d4ccc7fe6599..6ea2533051c3e4 100644 --- a/packages/next-swc/crates/next-dev/benches/util/npm.rs +++ b/packages/next-swc/crates/next-dev/benches/util/npm.rs @@ -5,6 +5,7 @@ use std::{ }; use anyhow::{anyhow, Result}; +use serde_json::json; use crate::util::command; @@ -32,13 +33,13 @@ pub fn install(install_dir: &Path, packages: &[NpmPackage]) -> Result<()> { { // Create a simple package.json if one doesn't exist - let package_json = json::object! { - private: true, - version: "0.0.0", - }; + let package_json = json!({ + "private": true, + "version": "0.0.0", + }); File::create(install_dir.join("package.json"))? - .write_all(package_json.pretty(2).as_bytes())?; + .write_all(format!("{:#}", package_json).as_bytes())?; } let mut args = vec!["install".to_owned(), "--force".to_owned()]; From 402c64be0039e1383207644bfcae9d895e4ab1e2 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Wed, 28 Sep 2022 22:44:32 +0800 Subject: [PATCH 100/672] Introduce AssetContent to handle symlink assets (vercel/turbo#406) * Fix DiskFileSystem::read_link * pnpm-like integration test * Introduce AssetContent to handle symlink assets * Fix read_link on Windows * Run clippy fix * Rename `path` to `target` Co-authored-by: Justin Ridgewell * Split Windows specified code * Add comments about Redirect is only represent Directory * Handle symlink while reading content * Clippy fix * Revert previous changes in FileSystemPathVc::get_type * Fix Unix read_link * cleanup * handle symlink while resolving native bindings * Make LinkContent::Link contains only target * Add LinkType to represent link type * Cleanup VersionedAsset * Cleanup LinkType * Normalize the LinkContent::target * Comments * Revert special case workaround for sharp on Windows * comments * node_native_binding follow file link * Apply CR suggestion Co-authored-by: Justin Ridgewell --- .../crates/next-core/src/next_client/mod.rs | 8 ++++---- .../next-core/src/server_render/asset.rs | 18 +++++++++--------- .../src/server_render/nodejs_bootstrap.rs | 6 +++--- .../crates/next-dev/benches/util/mod.rs | 4 ++-- .../crates/next-dev/benches/util/page_guard.rs | 4 ++-- .../crates/next-dev/src/turbo_tasks_viz.rs | 8 ++++++-- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 1770c657f1ce16..aebaaa19daa15e 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod runtime_reference; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; use turbo_tasks::{debug::ValueDebugFormat, trace::TraceRawVcs, ValueToString}; -use turbo_tasks_fs::{File, FileContent, FileContentVc, FileSystemPathVc}; +use turbo_tasks_fs::{File, FileContent, FileSystemPathVc}; use turbopack::{ ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, module_options::ModuleOptionsContextVc, @@ -12,7 +12,7 @@ use turbopack::{ ModuleAssetContextVc, }; use turbopack_core::{ - asset::AssetVc, + asset::{AssetContentVc, AssetVc}, chunk::{ChunkableAssetVc, ChunkingContextVc}, context::AssetContext, environment::EnvironmentVc, @@ -24,11 +24,11 @@ use turbopack_core::{ use self::runtime_reference::RuntimeAssetReferenceVc; #[turbo_tasks::function] -fn get_next_hydrater() -> FileContentVc { +fn get_next_hydrater() -> AssetContentVc { FileContent::Content(File::from_source( include_str!("next_hydrater.js").to_string(), )) - .cell() + .into() } #[derive(ValueDebugFormat, PartialEq, Eq, TraceRawVcs, Serialize, Deserialize)] diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index b8aa8ff253f8be..324ad8efe31bff 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -10,12 +10,12 @@ use serde_json::Value as JsonValue; use turbo_tasks::{ primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, Value, ValueToString, }; -use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileContentVc, FileSystemPathVc}; +use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::{ EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetVc, ModuleAssetType, }; use turbopack_core::{ - asset::{Asset, AssetVc}, + asset::{Asset, AssetContentVc, AssetVc}, chunk::{ dev::{DevChunkingContext, DevChunkingContextVc}, ChunkGroupVc, @@ -86,7 +86,7 @@ impl Asset for ServerRenderedAsset { } #[turbo_tasks::function] - fn content(&self) -> FileContentVc { + fn content(&self) -> AssetContentVc { render( self.path, get_renderer_pool( @@ -151,11 +151,11 @@ impl AssetReference for ServerRenderedClientAssetReference { } #[turbo_tasks::function] -fn get_server_renderer() -> FileContentVc { +fn get_server_renderer() -> AssetContentVc { FileContent::Content(File::from_source( include_str!("server_renderer.js").to_string(), )) - .cell() + .into() } #[turbo_tasks::function] @@ -202,7 +202,7 @@ async fn emit( .await? .internal_assets .iter() - .map(|a| a.path().write(a.content())) + .map(|a| a.content().write(a.path())) .collect(), ) .all()) @@ -290,11 +290,11 @@ async fn render( path: FileSystemPathVc, renderer_pool: NodeJsPoolVc, request_data: &str, -) -> Result { - fn into_result(content: String) -> Result { +) -> Result { + fn into_result(content: String) -> Result { Ok( FileContent::Content(File::from_source(content).with_content_type(TEXT_HTML_UTF_8)) - .cell(), + .into(), ) } let pool = renderer_pool.await?; diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs b/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs index 1e8db8a6d82a88..b291b5a57d9864 100644 --- a/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs +++ b/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs @@ -1,10 +1,10 @@ use std::fmt::Write; use anyhow::Result; -use turbo_tasks_fs::{File, FileContent, FileContentVc, FileSystemPathVc}; +use turbo_tasks_fs::{File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::utils::stringify_str; use turbopack_core::{ - asset::{Asset, AssetVc}, + asset::{Asset, AssetContentVc, AssetVc}, chunk::{ChunkGroupVc, ChunkReferenceVc}, reference::AssetReferencesVc, }; @@ -23,7 +23,7 @@ impl Asset for NodeJsBootstrapAsset { } #[turbo_tasks::function] - async fn content(&self) -> Result { + async fn content(&self) -> Result { let context_path = self.path.parent().await?; // TODO(sokra) We need to have a chunk format for node.js diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index 5ea8a018279aa3..cdc84491ecbccc 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -108,7 +108,7 @@ pub fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { let npm = command("npm") .args(["install", "--prefer-offline", "--loglevel=error"]) - .current_dir(&test_app.path()) + .current_dir(test_app.path()) .output() .unwrap(); @@ -140,7 +140,7 @@ pub async fn create_browser() -> Browser { browser } -pub fn resume_on_error () + UnwindSafe>(f: F) { +pub fn resume_on_error(f: F) { let runs_as_bench = std::env::args().find(|a| a == "--bench"); if runs_as_bench.is_some() { diff --git a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs index 7c5845b1a9c83f..4b6e444783b85b 100644 --- a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs +++ b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs @@ -38,8 +38,8 @@ impl<'a> PageGuard<'a> { page: Some(page), app: Some(app), events: Box::new(futures::stream::select( - events.map(|e| Event::EventBindingCalled(e)), - errors.map(|e| Event::EventExceptionThrown(e)), + events.map(Event::EventBindingCalled), + errors.map(Event::EventExceptionThrown), )), } } diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index b32bfc45037f9f..e78c897d202e36 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -8,6 +8,7 @@ use turbo_tasks_memory::{ stats::{ReferenceType, Stats}, viz, MemoryBackend, }; +use turbopack_core::asset::AssetContent; use turbopack_dev_server::source::{ ContentSource, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, }; @@ -79,8 +80,11 @@ impl ContentSource for TurboTasksSource { _ => return Ok(ContentSourceResult::NotFound.cell()), }; Ok(ContentSourceResult::Static( - FileContent::Content( - File::from_source(html).with_content_type(Mime::from_str("text/html")?), + AssetContent::File( + FileContent::Content( + File::from_source(html).with_content_type(Mime::from_str("text/html")?), + ) + .cell(), ) .into(), ) From a3dd9915d7efd3ce240d61745a9093a958db265d Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 28 Sep 2022 21:02:39 +0200 Subject: [PATCH 101/672] Use ValueToString for AssetReference instead of description() (vercel/turbo#430) (Prerequirement for `app` support) --- .../crates/next-core/src/next_client/runtime_reference.rs | 7 +++++-- .../next-swc/crates/next-core/src/server_render/asset.rs | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs b/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs index e2410302829205..4aac2c50fe67a8 100644 --- a/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs +++ b/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use turbo_tasks::{primitives::StringVc, ValueToString}; +use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc}; use turbopack::ecmascript::resolve::cjs_resolve; use turbopack_core::{ context::AssetContextVc, @@ -27,9 +27,12 @@ impl AssetReference for RuntimeAssetReference { fn resolve_reference(&self) -> ResolveResultVc { cjs_resolve(self.request, self.context) } +} +#[turbo_tasks::value_impl] +impl ValueToString for RuntimeAssetReference { #[turbo_tasks::function] - async fn description(&self) -> Result { + async fn to_string(&self) -> Result { Ok(StringVc::cell(format!( "runtime {}", self.request.to_string().await? diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index 324ad8efe31bff..e564677bb4ffc2 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -9,6 +9,7 @@ use mime::TEXT_HTML_UTF_8; use serde_json::Value as JsonValue; use turbo_tasks::{ primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, Value, ValueToString, + ValueToStringVc, }; use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::{ @@ -140,9 +141,12 @@ impl AssetReference for ServerRenderedClientAssetReference { fn resolve_reference(&self) -> ResolveResultVc { ResolveResult::Single(self.asset, Vec::new()).into() } +} +#[turbo_tasks::value_impl] +impl ValueToString for ServerRenderedClientAssetReference { #[turbo_tasks::function] - async fn description(&self) -> Result { + async fn to_string(&self) -> Result { Ok(StringVc::cell(format!( "client asset {}", self.asset.path().to_string().await? From 3ad7c517683baf95dde3545e8139094e682a6fcb Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 28 Sep 2022 21:32:09 +0200 Subject: [PATCH 102/672] use embed_file (vercel/turbo#432) --- .../crates/next-core/src/next_client/mod.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index aebaaa19daa15e..08831f11356486 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod runtime_reference; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; use turbo_tasks::{debug::ValueDebugFormat, trace::TraceRawVcs, ValueToString}; -use turbo_tasks_fs::{File, FileContent, FileSystemPathVc}; +use turbo_tasks_fs::{embed_file, FileSystemPathVc}; use turbopack::{ ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, module_options::ModuleOptionsContextVc, @@ -12,7 +12,7 @@ use turbopack::{ ModuleAssetContextVc, }; use turbopack_core::{ - asset::{AssetContentVc, AssetVc}, + asset::AssetVc, chunk::{ChunkableAssetVc, ChunkingContextVc}, context::AssetContext, environment::EnvironmentVc, @@ -23,14 +23,6 @@ use turbopack_core::{ use self::runtime_reference::RuntimeAssetReferenceVc; -#[turbo_tasks::function] -fn get_next_hydrater() -> AssetContentVc { - FileContent::Content(File::from_source( - include_str!("next_hydrater.js").to_string(), - )) - .into() -} - #[derive(ValueDebugFormat, PartialEq, Eq, TraceRawVcs, Serialize, Deserialize)] pub enum RuntimeReference { Request(RequestVc, FileSystemPathVc), @@ -56,7 +48,12 @@ pub struct NextClientTransition { impl Transition for NextClientTransition { #[turbo_tasks::function] fn process_source(&self, asset: AssetVc) -> AssetVc { - WrapperAssetVc::new(asset, "next-hydrate.js", get_next_hydrater()).into() + WrapperAssetVc::new( + asset, + "next-hydrate.js", + embed_file!("next_hydrater.js").into(), + ) + .into() } #[turbo_tasks::function] From fb76744de1885757bb999632d1922cd762207f8a Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 29 Sep 2022 19:14:15 +0200 Subject: [PATCH 103/672] fix asset paths in server rendered pages (vercel/turbo#436) Currently, when a server rendered page imports an asset (e.g. an image) there's a hydration mismatch --- .../next-core/src/server_render/asset.rs | 24 ++++++------------- .../next-core/src/server_rendered_source.rs | 15 +++++++++--- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index e564677bb4ffc2..106378a2df96d4 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -17,10 +17,7 @@ use turbopack::ecmascript::{ }; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc}, - chunk::{ - dev::{DevChunkingContext, DevChunkingContextVc}, - ChunkGroupVc, - }, + chunk::{dev::DevChunkingContextVc, ChunkGroupVc}, context::AssetContextVc, reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, resolve::{ResolveResult, ResolveResultVc}, @@ -48,8 +45,8 @@ pub struct ServerRenderedAsset { path: FileSystemPathVc, context: AssetContextVc, entry_asset: AssetVc, + chunking_context: DevChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, - context_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, request_data: String, } @@ -62,7 +59,7 @@ impl ServerRenderedAssetVc { context: AssetContextVc, entry_asset: AssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, - context_path: FileSystemPathVc, + chunking_context: DevChunkingContextVc, intermediate_output_path: FileSystemPathVc, request_data: String, ) -> Self { @@ -71,7 +68,7 @@ impl ServerRenderedAssetVc { context, entry_asset, runtime_entries, - context_path, + chunking_context, intermediate_output_path, request_data, } @@ -95,7 +92,7 @@ impl Asset for ServerRenderedAsset { self.context, self.entry_asset, self.runtime_entries, - self.context_path, + self.chunking_context, self.intermediate_output_path, ), self.intermediate_output_path, @@ -112,7 +109,7 @@ impl Asset for ServerRenderedAsset { self.context, self.entry_asset, self.runtime_entries, - self.context_path, + self.chunking_context, self.intermediate_output_path, ), self.intermediate_output_path, @@ -167,16 +164,9 @@ async fn get_intermediate_asset( context: AssetContextVc, entry_asset: AssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, - context_path: FileSystemPathVc, + chunking_context: DevChunkingContextVc, intermediate_output_path: FileSystemPathVc, ) -> Result { - let chunking_context: DevChunkingContextVc = DevChunkingContext { - context_path, - chunk_root_path: intermediate_output_path.join("chunks"), - asset_root_path: intermediate_output_path.join("assets"), - enable_hot_module_replacement: false, - } - .into(); let module = EcmascriptModuleAssetVc::new( WrapperAssetVc::new(entry_asset, "server-renderer.js", get_server_renderer()).into(), context.with_context_path(entry_asset.path()), diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 5591a32a810e74..65e7fa200bc1d9 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -181,15 +181,24 @@ async fn create_server_rendered_source_for_file( ) -> Result { let context_path = context.context_path(); let source_asset = SourceAssetVc::new(entry).into(); - let module = context + let entry_asset = context .with_context_path(entry.parent()) .process(source_asset); + + let chunking_context = DevChunkingContext { + context_path, + chunk_root_path: intermediate_output_path.join("chunks"), + asset_root_path: target_root.join("_next/static/assets"), + enable_hot_module_replacement: false, + } + .into(); + let asset = ServerRenderedAssetVc::new( target_path, context, - module, + entry_asset, runtime_entries, - context_path, + chunking_context, intermediate_output_path, "{\"props\":{}}\n".to_string(), ); From 9fd91630960eba5dce2e2ceb38b75fcf4ca6a34f Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 29 Sep 2022 23:36:48 +0200 Subject: [PATCH 104/672] use embed macro (vercel/turbo#437) --- .../crates/next-core/src/next_client/mod.rs | 9 +++------ .../{next_hydrater.js => next_hydrate.js} | 0 .../crates/next-core/src/server_render/asset.rs | 14 ++++---------- 3 files changed, 7 insertions(+), 16 deletions(-) rename packages/next-swc/crates/next-core/src/next_client/{next_hydrater.js => next_hydrate.js} (100%) diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 08831f11356486..21bbe85394bb5a 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -48,12 +48,9 @@ pub struct NextClientTransition { impl Transition for NextClientTransition { #[turbo_tasks::function] fn process_source(&self, asset: AssetVc) -> AssetVc { - WrapperAssetVc::new( - asset, - "next-hydrate.js", - embed_file!("next_hydrater.js").into(), - ) - .into() + let next_hydrate = embed_file!("next_hydrate.js").into(); + + WrapperAssetVc::new(asset, "next-hydrate.js", next_hydrate).into() } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/next_client/next_hydrater.js b/packages/next-swc/crates/next-core/src/next_client/next_hydrate.js similarity index 100% rename from packages/next-swc/crates/next-core/src/next_client/next_hydrater.js rename to packages/next-swc/crates/next-core/src/next_client/next_hydrate.js diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index 106378a2df96d4..a3c84af1dac248 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -11,7 +11,7 @@ use turbo_tasks::{ primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, Value, ValueToString, ValueToStringVc, }; -use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; +use turbo_tasks_fs::{embed_file, DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::{ EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetVc, ModuleAssetType, }; @@ -151,14 +151,6 @@ impl ValueToString for ServerRenderedClientAssetReference { } } -#[turbo_tasks::function] -fn get_server_renderer() -> AssetContentVc { - FileContent::Content(File::from_source( - include_str!("server_renderer.js").to_string(), - )) - .into() -} - #[turbo_tasks::function] async fn get_intermediate_asset( context: AssetContextVc, @@ -167,8 +159,10 @@ async fn get_intermediate_asset( chunking_context: DevChunkingContextVc, intermediate_output_path: FileSystemPathVc, ) -> Result { + let server_renderer = embed_file!("server_renderer.js").into(); + let module = EcmascriptModuleAssetVc::new( - WrapperAssetVc::new(entry_asset, "server-renderer.js", get_server_renderer()).into(), + WrapperAssetVc::new(entry_asset, "server-renderer.js", server_renderer).into(), context.with_context_path(entry_asset.path()), Value::new(ModuleAssetType::Ecmascript), EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { refresh: false }]), From 797bbc1a2f60b4fd539e98427726eb32cf802935 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 30 Sep 2022 10:13:37 +0200 Subject: [PATCH 105/672] Refactor nodejs rendering to be more isolated and reusable (vercel/turbo#428) (Prerequirement for `app` support) --- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../bootstrap.rs} | 2 +- .../src/{server_render => nodejs}/issue.rs | 0 .../crates/next-core/src/nodejs/mod.rs | 277 ++++++++++++++++++ .../nodejs_pool.rs => nodejs/pool.rs} | 1 + .../next-core/src/server_render/asset.rs | 260 ++-------------- .../crates/next-core/src/server_render/mod.rs | 3 - .../next-core/src/server_rendered_source.rs | 10 +- 8 files changed, 315 insertions(+), 239 deletions(-) rename packages/next-swc/crates/next-core/src/{server_render/nodejs_bootstrap.rs => nodejs/bootstrap.rs} (94%) rename packages/next-swc/crates/next-core/src/{server_render => nodejs}/issue.rs (100%) create mode 100644 packages/next-swc/crates/next-core/src/nodejs/mod.rs rename packages/next-swc/crates/next-core/src/{server_render/nodejs_pool.rs => nodejs/pool.rs} (99%) diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 3041c1dc3dcca7..9240bcd1f964ed 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -3,6 +3,7 @@ pub mod env; pub mod next_client; +mod nodejs; pub mod react_refresh; mod server_render; mod server_rendered_source; diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs b/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs similarity index 94% rename from packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs rename to packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs index b291b5a57d9864..6f79defa1501ff 100644 --- a/packages/next-swc/crates/next-core/src/server_render/nodejs_bootstrap.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs @@ -28,7 +28,7 @@ impl Asset for NodeJsBootstrapAsset { // TODO(sokra) We need to have a chunk format for node.js // but until then this is a simple hack to make it work for now - let mut output = "global.self = global;\n".to_string(); + let mut output = "Error.stackTraceLimit = 100;\nglobal.self = global;\n".to_string(); for chunk in self.chunk_group.chunks().await?.iter() { let path = &*chunk.path().await?; diff --git a/packages/next-swc/crates/next-core/src/server_render/issue.rs b/packages/next-swc/crates/next-core/src/nodejs/issue.rs similarity index 100% rename from packages/next-swc/crates/next-core/src/server_render/issue.rs rename to packages/next-swc/crates/next-core/src/nodejs/issue.rs diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs new file mode 100644 index 00000000000000..704067c344b5b7 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -0,0 +1,277 @@ +use std::{ + collections::{HashMap, HashSet}, + path::PathBuf, +}; + +use anyhow::{anyhow, Result}; +use futures::{stream::FuturesUnordered, TryStreamExt}; +use mime::TEXT_HTML_UTF_8; +use serde_json::Value as JsonValue; +use turbo_tasks::{ + primitives::{JsonValueVc, StringVc}, + spawn_blocking, CompletionVc, CompletionsVc, ValueToString, +}; +use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; +use turbopack::ecmascript::EcmascriptModuleAssetVc; +use turbopack_core::{ + asset::{AssetContentVc, AssetVc, AssetsSetVc}, + chunk::{dev::DevChunkingContextVc, ChunkGroupVc}, +}; +use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; + +use self::{ + bootstrap::NodeJsBootstrapAsset, + pool::{NodeJsPool, NodeJsPoolVc}, +}; +use crate::nodejs::issue::RenderingIssue; + +pub mod bootstrap; +pub(crate) mod issue; +pub mod pool; + +#[turbo_tasks::function] +async fn emit( + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + Ok(CompletionsVc::cell( + internal_assets(intermediate_asset, intermediate_output_path) + .await? + .iter() + .map(|a| a.content().write(a.path())) + .collect(), + ) + .all()) +} + +/// List of the all assets of the "internal" subgraph and a list of boundary +/// assets that are not considered "internal" ("external") +#[turbo_tasks::value] +pub struct SeparatedAssets { + pub internal_assets: AssetsSetVc, + pub external_asset_entrypoints: AssetsSetVc, +} + +/// Extracts the subgraph of "internal" assets (assets within the passes +/// directory). Also lists all boundary assets that are not part of the +/// "internal" subgraph. +#[turbo_tasks::function] +async fn internal_assets( + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + Ok( + separate_assets(intermediate_asset, intermediate_output_path) + .await? + .internal_assets, + ) +} + +/// Returns a set of "external" assets on the boundary of the "internal" +/// subgraph +#[turbo_tasks::function] +pub async fn external_asset_entrypoints( + module: EcmascriptModuleAssetVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + chunking_context: DevChunkingContextVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + Ok(separate_assets( + get_intermediate_asset( + module, + runtime_entries, + chunking_context, + intermediate_output_path, + ), + intermediate_output_path, + ) + .await? + .external_asset_entrypoints) +} + +/// Splits the asset graph into "internal" assets and boundaries to "external" +/// assets. +#[turbo_tasks::function] +async fn separate_assets( + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + enum Type { + Internal(AssetVc, Vec), + External(AssetVc), + } + let intermediate_output_path = intermediate_output_path.await?; + let mut queue = FuturesUnordered::new(); + let process_asset = |asset: AssetVc| { + let intermediate_output_path = &intermediate_output_path; + async move { + // Assets within the output directory are considered as "internal" and all + // others as "external". We follow references on "internal" assets, but do not + // look into references of "external" assets, since there are no "internal" + // assets behind "externals" + if asset.path().await?.is_inside(intermediate_output_path) { + let mut assets = Vec::new(); + for reference in asset.references().await?.iter() { + for asset in reference.resolve_reference().primary_assets().await?.iter() { + assets.push(*asset); + } + } + Ok::<_, anyhow::Error>(Type::Internal(asset, assets)) + } else { + Ok(Type::External(asset)) + } + } + }; + queue.push(process_asset(intermediate_asset)); + let mut processed = HashSet::new(); + let mut internal_assets = HashSet::new(); + let mut external_asset_entrypoints = HashSet::new(); + while let Some(item) = queue.try_next().await? { + match item { + Type::Internal(asset, assets) => { + internal_assets.insert(asset); + for asset in assets { + if processed.insert(asset) { + queue.push(process_asset(asset)); + } + } + } + Type::External(asset) => { + external_asset_entrypoints.insert(asset); + } + } + } + Ok(SeparatedAssets { + internal_assets: AssetsSetVc::cell(internal_assets), + external_asset_entrypoints: AssetsSetVc::cell(external_asset_entrypoints), + } + .cell()) +} + +/// Creates a node.js renderer pool for an entrypoint. +#[turbo_tasks::function] +pub async fn get_renderer_pool( + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + emit(intermediate_asset, intermediate_output_path).await?; + let output = intermediate_output_path.await?; + if let Some(disk) = DiskFileSystemVc::resolve_from(output.fs).await? { + let dir = PathBuf::from(&disk.await?.root).join(&output.path); + let entrypoint = dir.join("index.js"); + let pool = NodeJsPool::new(dir, entrypoint, HashMap::new(), 4); + Ok(pool.cell()) + } else { + Err(anyhow!("can only render from a disk filesystem")) + } +} + +/// Converts a module graph into node.js executable assets +#[turbo_tasks::function] +async fn get_intermediate_asset( + entry_module: EcmascriptModuleAssetVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + chunking_context: DevChunkingContextVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + let chunk = entry_module.as_evaluated_chunk(chunking_context.into(), Some(runtime_entries)); + let chunk_group = ChunkGroupVc::from_chunk(chunk); + Ok(NodeJsBootstrapAsset { + path: intermediate_output_path.join("index.js"), + chunk_group, + } + .cell() + .into()) +} + +/// Renders a module as static HTML in a node.js process. +#[turbo_tasks::function] +pub async fn render_static( + path: FileSystemPathVc, + module: EcmascriptModuleAssetVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + chunking_context: DevChunkingContextVc, + intermediate_output_path: FileSystemPathVc, + data: JsonValueVc, +) -> Result { + fn into_result(content: String) -> Result { + Ok( + FileContent::Content(File::from_source(content).with_content_type(TEXT_HTML_UTF_8)) + .into(), + ) + } + let renderer_pool = get_renderer_pool( + get_intermediate_asset( + module, + runtime_entries, + chunking_context, + intermediate_output_path, + ), + intermediate_output_path, + ); + let pool = renderer_pool.await?; + let mut op = pool.run(data.to_string().await?.as_bytes()).await?; + let lines = spawn_blocking(move || { + let lines = op.read_lines()?; + drop(op); + Ok::<_, anyhow::Error>(lines) + }) + .await?; + let issue = if let Some(last_line) = lines.last() { + if let Some(data) = last_line.strip_prefix("RESULT=") { + let data: JsonValue = serde_json::from_str(data)?; + if let Some(s) = data.as_str() { + return into_result(s.to_string()); + } else { + RenderingIssue { + context: path, + message: StringVc::cell( + "Result provided by Node.js rendering process was not a string".to_string(), + ), + logging: StringVc::cell(lines.join("\n")), + } + } + } else if let Some(data) = last_line.strip_prefix("ERROR=") { + let data: JsonValue = serde_json::from_str(data)?; + if let Some(s) = data.as_str() { + RenderingIssue { + context: path, + message: StringVc::cell(s.to_string()), + logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), + } + } else { + RenderingIssue { + context: path, + message: StringVc::cell(data.to_string()), + logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), + } + } + } else { + RenderingIssue { + context: path, + message: StringVc::cell("No result provided by Node.js process".to_string()), + logging: StringVc::cell(lines.join("\n")), + } + } + } else { + RenderingIssue { + context: path, + message: StringVc::cell("No content received from Node.js process.".to_string()), + logging: StringVc::cell("".to_string()), + } + }; + + // Show error page + // TODO This need to include HMR handler to allow auto refresh + let result = into_result(format!( + "

Error during \ + rendering

\n

Message

\n
{}
\n

Logs

\n
{}
", + issue.message.await?, + issue.logging.await? + )); + + // Emit an issue for error reporting + issue.cell().as_issue().emit(); + + result +} diff --git a/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs similarity index 99% rename from packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs rename to packages/next-swc/crates/next-core/src/nodejs/pool.rs index ba26f44a9a2331..b5b5244b358c6e 100644 --- a/packages/next-swc/crates/next-core/src/server_render/nodejs_pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -136,6 +136,7 @@ impl NodeJsPool { let static_input: &'static [u8] = unsafe { transmute(input) }; let child = spawn_blocking(move || { child.write(static_input)?; + child.write(b"\n")?; Ok::<_, anyhow::Error>(child) }) .await?; diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index a3c84af1dac248..ff89d2e0a18068 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -1,23 +1,16 @@ -use std::{ - collections::{HashMap, HashSet}, - path::PathBuf, -}; - -use anyhow::{anyhow, Result}; -use futures::{stream::FuturesUnordered, TryStreamExt}; -use mime::TEXT_HTML_UTF_8; -use serde_json::Value as JsonValue; +use anyhow::Result; use turbo_tasks::{ - primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, Value, ValueToString, - ValueToStringVc, + primitives::{JsonValueVc, StringVc}, + Value, ValueToString, ValueToStringVc, }; -use turbo_tasks_fs::{embed_file, DiskFileSystemVc, File, FileContent, FileSystemPathVc}; +use turbo_tasks_fs::{embed_file, FileSystemPathVc}; use turbopack::ecmascript::{ EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetVc, ModuleAssetType, }; use turbopack_core::{ + self, asset::{Asset, AssetContentVc, AssetVc}, - chunk::{dev::DevChunkingContextVc, ChunkGroupVc}, + chunk::dev::DevChunkingContextVc, context::AssetContextVc, reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, resolve::{ResolveResult, ResolveResultVc}, @@ -25,11 +18,7 @@ use turbopack_core::{ }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; -use super::{ - nodejs_bootstrap::NodeJsBootstrapAsset, - nodejs_pool::{NodeJsPool, NodeJsPoolVc}, -}; -use crate::server_render::issue::RenderingIssue; +use crate::nodejs::{external_asset_entrypoints, render_static}; /// This is an asset which content is determined by running /// `React.renderToString` on the default export of [entry_asset] in a Node.js @@ -48,7 +37,7 @@ pub struct ServerRenderedAsset { chunking_context: DevChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, intermediate_output_path: FileSystemPathVc, - request_data: String, + request_data: JsonValueVc, } #[turbo_tasks::value_impl] @@ -61,7 +50,7 @@ impl ServerRenderedAssetVc { runtime_entries: EcmascriptChunkPlaceablesVc, chunking_context: DevChunkingContextVc, intermediate_output_path: FileSystemPathVc, - request_data: String, + request_data: JsonValueVc, ) -> Self { ServerRenderedAsset { path, @@ -85,37 +74,26 @@ impl Asset for ServerRenderedAsset { #[turbo_tasks::function] fn content(&self) -> AssetContentVc { - render( + render_static( self.path, - get_renderer_pool( - get_intermediate_asset( - self.context, - self.entry_asset, - self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, - ), - self.intermediate_output_path, - ), - &self.request_data, + get_intermediate_module(self.context, self.entry_asset), + self.runtime_entries, + self.chunking_context, + self.intermediate_output_path, + self.request_data, ) } #[turbo_tasks::function] async fn references(&self) -> Result { Ok(AssetReferencesVc::cell( - separate_assets( - get_intermediate_asset( - self.context, - self.entry_asset, - self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, - ), + external_asset_entrypoints( + get_intermediate_module(self.context, self.entry_asset), + self.runtime_entries, + self.chunking_context, self.intermediate_output_path, ) .await? - .external_asset_entrypoints .iter() .map(|a| { ServerRenderedClientAssetReference { asset: *a } @@ -152,202 +130,20 @@ impl ValueToString for ServerRenderedClientAssetReference { } #[turbo_tasks::function] -async fn get_intermediate_asset( +fn get_intermediate_module( context: AssetContextVc, entry_asset: AssetVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: DevChunkingContextVc, - intermediate_output_path: FileSystemPathVc, -) -> Result { - let server_renderer = embed_file!("server_renderer.js").into(); - - let module = EcmascriptModuleAssetVc::new( - WrapperAssetVc::new(entry_asset, "server-renderer.js", server_renderer).into(), +) -> EcmascriptModuleAssetVc { + EcmascriptModuleAssetVc::new( + WrapperAssetVc::new( + entry_asset, + "server-renderer.js", + embed_file!("server_renderer.js").into(), + ) + .into(), context.with_context_path(entry_asset.path()), Value::new(ModuleAssetType::Ecmascript), EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { refresh: false }]), context.environment(), - ); - - let chunk = module.as_evaluated_chunk(chunking_context.into(), Some(runtime_entries)); - - let chunk_group = ChunkGroupVc::from_chunk(chunk); - Ok(NodeJsBootstrapAsset { - path: intermediate_output_path.join("index.js"), - chunk_group, - } - .cell() - .into()) -} - -#[turbo_tasks::function] -async fn emit( - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result { - Ok(CompletionsVc::cell( - separate_assets(intermediate_asset, intermediate_output_path) - .await? - .internal_assets - .iter() - .map(|a| a.content().write(a.path())) - .collect(), ) - .all()) -} - -#[turbo_tasks::value] -struct SeparatedAssets { - internal_assets: HashSet, - external_asset_entrypoints: HashSet, -} - -#[turbo_tasks::function] -async fn separate_assets( - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result { - enum Type { - Internal(AssetVc, Vec), - External(AssetVc), - } - let intermediate_output_path = intermediate_output_path.await?; - let mut queue = FuturesUnordered::new(); - let process_asset = |asset: AssetVc| { - let intermediate_output_path = &intermediate_output_path; - async move { - if asset.path().await?.is_inside(intermediate_output_path) { - let mut assets = Vec::new(); - for reference in asset.references().await?.iter() { - for asset in reference.resolve_reference().primary_assets().await?.iter() { - assets.push(*asset); - } - } - Ok::<_, anyhow::Error>(Type::Internal(asset, assets)) - } else { - Ok(Type::External(asset)) - } - } - }; - queue.push(process_asset(intermediate_asset)); - let mut processed = HashSet::new(); - let mut internal_assets = HashSet::new(); - let mut external_asset_entrypoints = HashSet::new(); - while let Some(item) = queue.try_next().await? { - match item { - Type::Internal(asset, assets) => { - internal_assets.insert(asset); - for asset in assets { - if processed.insert(asset) { - queue.push(process_asset(asset)); - } - } - } - Type::External(asset) => { - // external - external_asset_entrypoints.insert(asset); - } - } - } - Ok(SeparatedAssets { - internal_assets, - external_asset_entrypoints, - } - .cell()) -} - -#[turbo_tasks::function] -async fn get_renderer_pool( - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result { - emit(intermediate_asset, intermediate_output_path).await?; - let output = intermediate_output_path.await?; - if let Some(disk) = DiskFileSystemVc::resolve_from(output.fs).await? { - let dir = PathBuf::from(&disk.await?.root).join(&output.path); - let entrypoint = dir.join("index.js"); - let pool = NodeJsPool::new(dir, entrypoint, HashMap::new(), 4); - Ok(pool.cell()) - } else { - Err(anyhow!("can only render from a disk filesystem")) - } -} - -#[turbo_tasks::function] -async fn render( - path: FileSystemPathVc, - renderer_pool: NodeJsPoolVc, - request_data: &str, -) -> Result { - fn into_result(content: String) -> Result { - Ok( - FileContent::Content(File::from_source(content).with_content_type(TEXT_HTML_UTF_8)) - .into(), - ) - } - let pool = renderer_pool.await?; - let mut op = pool.run(request_data.as_bytes()).await?; - let lines = spawn_blocking(move || { - let lines = op.read_lines()?; - drop(op); - Ok::<_, anyhow::Error>(lines) - }) - .await?; - let issue = if let Some(last_line) = lines.last() { - if let Some(data) = last_line.strip_prefix("RESULT=") { - let data: JsonValue = serde_json::from_str(data)?; - if let Some(s) = data.as_str() { - return into_result(s.to_string()); - } else { - RenderingIssue { - context: path, - message: StringVc::cell( - "Result provided by Node.js rendering process was not a string".to_string(), - ), - logging: StringVc::cell(lines.join("\n")), - } - } - } else if let Some(data) = last_line.strip_prefix("ERROR=") { - let data: JsonValue = serde_json::from_str(data)?; - if let Some(s) = data.as_str() { - RenderingIssue { - context: path, - message: StringVc::cell(s.to_string()), - logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), - } - } else { - RenderingIssue { - context: path, - message: StringVc::cell(data.to_string()), - logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), - } - } - } else { - RenderingIssue { - context: path, - message: StringVc::cell("No result provided by Node.js process".to_string()), - logging: StringVc::cell(lines.join("\n")), - } - } - } else { - RenderingIssue { - context: path, - message: StringVc::cell("No content received from Node.js process.".to_string()), - logging: StringVc::cell("".to_string()), - } - }; - - // Show error page - // TODO This need to include HMR handler to allow auto refresh - let result = into_result(format!( - "

Error during \ - rendering

\n

Message

\n
{}
\n

Logs

\n
{}
", - issue.message.await?, - issue.logging.await? - )); - - // Emit an issue for error reporting - issue.cell().as_issue().emit(); - - result } diff --git a/packages/next-swc/crates/next-core/src/server_render/mod.rs b/packages/next-swc/crates/next-core/src/server_render/mod.rs index d0d15de63bbf70..64cdb62cc39ba8 100644 --- a/packages/next-swc/crates/next-core/src/server_render/mod.rs +++ b/packages/next-swc/crates/next-core/src/server_render/mod.rs @@ -1,4 +1 @@ pub mod asset; -pub(crate) mod issue; -pub mod nodejs_bootstrap; -pub mod nodejs_pool; diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 65e7fa200bc1d9..e2a59e2b8ab225 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -1,7 +1,11 @@ use std::collections::HashMap; use anyhow::Result; -use turbo_tasks::{primitives::StringVc, Value}; +use serde_json::json; +use turbo_tasks::{ + primitives::{JsonValueVc, StringVc}, + Value, +}; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{ module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext, @@ -37,7 +41,7 @@ use crate::{ }; /// Create a content source serving the `pages` or `src/pages` directory as -/// Node.js pages folder. +/// Next.js pages folder. #[turbo_tasks::function] pub async fn create_server_rendered_source( root_path: FileSystemPathVc, @@ -200,7 +204,7 @@ async fn create_server_rendered_source_for_file( runtime_entries, chunking_context, intermediate_output_path, - "{\"props\":{}}\n".to_string(), + JsonValueVc::cell(json!({ "props": {} })), ); Ok(AssetGraphContentSourceVc::new_lazy( target_root, From 1a5f27bd88818953522cc59065c1d72e7977677b Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 30 Sep 2022 13:52:36 +0200 Subject: [PATCH 106/672] fixes some nitpicks (vercel/turbo#448) --- packages/next-swc/crates/next-core/src/nodejs/mod.rs | 8 ++++---- .../next-swc/crates/next-core/src/server_render/asset.rs | 6 +++--- .../crates/next-core/src/server_rendered_source.rs | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 704067c344b5b7..66220c8a1fb408 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -15,7 +15,7 @@ use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ asset::{AssetContentVc, AssetVc, AssetsSetVc}, - chunk::{dev::DevChunkingContextVc, ChunkGroupVc}, + chunk::{ChunkGroupVc, ChunkingContextVc}, }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; @@ -73,7 +73,7 @@ async fn internal_assets( pub async fn external_asset_entrypoints( module: EcmascriptModuleAssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: DevChunkingContextVc, + chunking_context: ChunkingContextVc, intermediate_output_path: FileSystemPathVc, ) -> Result { Ok(separate_assets( @@ -171,7 +171,7 @@ pub async fn get_renderer_pool( async fn get_intermediate_asset( entry_module: EcmascriptModuleAssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: DevChunkingContextVc, + chunking_context: ChunkingContextVc, intermediate_output_path: FileSystemPathVc, ) -> Result { let chunk = entry_module.as_evaluated_chunk(chunking_context.into(), Some(runtime_entries)); @@ -190,7 +190,7 @@ pub async fn render_static( path: FileSystemPathVc, module: EcmascriptModuleAssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: DevChunkingContextVc, + chunking_context: ChunkingContextVc, intermediate_output_path: FileSystemPathVc, data: JsonValueVc, ) -> Result { diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index ff89d2e0a18068..dc5e03ce8162a4 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -10,7 +10,7 @@ use turbopack::ecmascript::{ use turbopack_core::{ self, asset::{Asset, AssetContentVc, AssetVc}, - chunk::dev::DevChunkingContextVc, + chunk::ChunkingContextVc, context::AssetContextVc, reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, resolve::{ResolveResult, ResolveResultVc}, @@ -34,7 +34,7 @@ pub struct ServerRenderedAsset { path: FileSystemPathVc, context: AssetContextVc, entry_asset: AssetVc, - chunking_context: DevChunkingContextVc, + chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, intermediate_output_path: FileSystemPathVc, request_data: JsonValueVc, @@ -48,7 +48,7 @@ impl ServerRenderedAssetVc { context: AssetContextVc, entry_asset: AssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: DevChunkingContextVc, + chunking_context: ChunkingContextVc, intermediate_output_path: FileSystemPathVc, request_data: JsonValueVc, ) -> Self { diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index e2a59e2b8ab225..b9d5cbfe4c4ae7 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -195,6 +195,7 @@ async fn create_server_rendered_source_for_file( asset_root_path: target_root.join("_next/static/assets"), enable_hot_module_replacement: false, } + .cell() .into(); let asset = ServerRenderedAssetVc::new( From b9638d91d57abcb424ed1d71ba0ad5f3c01ec1df Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 30 Sep 2022 13:58:35 +0200 Subject: [PATCH 107/672] change WrapperAsset to some more general purpose VirtualAsset (vercel/turbo#447) Wrapper is a bit of a weird name since it's not actually wrapping the existing asset. Actually it's just a virtual asset with a path below the existing path. --- packages/next-swc/crates/next-core/src/next_client/mod.rs | 4 ++-- .../next-swc/crates/next-core/src/server_render/asset.rs | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 21bbe85394bb5a..15fec92e9268dc 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -18,7 +18,7 @@ use turbopack_core::{ environment::EnvironmentVc, reference::{AssetReferenceVc, AssetReferencesVc}, resolve::parse::RequestVc, - wrapper_asset::WrapperAssetVc, + virtual_asset::VirtualAssetVc, }; use self::runtime_reference::RuntimeAssetReferenceVc; @@ -50,7 +50,7 @@ impl Transition for NextClientTransition { fn process_source(&self, asset: AssetVc) -> AssetVc { let next_hydrate = embed_file!("next_hydrate.js").into(); - WrapperAssetVc::new(asset, "next-hydrate.js", next_hydrate).into() + VirtualAssetVc::new(asset.path().join("next-hydrate.js"), next_hydrate).into() } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index dc5e03ce8162a4..fddc0c2a60dec3 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -14,7 +14,7 @@ use turbopack_core::{ context::AssetContextVc, reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, resolve::{ResolveResult, ResolveResultVc}, - wrapper_asset::WrapperAssetVc, + virtual_asset::VirtualAssetVc, }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; @@ -135,9 +135,8 @@ fn get_intermediate_module( entry_asset: AssetVc, ) -> EcmascriptModuleAssetVc { EcmascriptModuleAssetVc::new( - WrapperAssetVc::new( - entry_asset, - "server-renderer.js", + VirtualAssetVc::new( + entry_asset.path().join("server-renderer.js"), embed_file!("server_renderer.js").into(), ) .into(), From 2ffcbe38e0b2379f334a5b2b51d08a028203c46f Mon Sep 17 00:00:00 2001 From: Leah Date: Fri, 30 Sep 2022 20:03:27 +0200 Subject: [PATCH 108/672] simpler runtime inclusion (vercel/turbo#438) --- .../next-core/src/next_client/context.rs | 141 ++++++++++++++++ .../crates/next-core/src/next_client/mod.rs | 67 +++----- .../src/next_client/runtime_entry.rs | 67 ++++++++ .../src/next_client/runtime_reference.rs | 41 ----- .../crates/next-core/src/nodejs/mod.rs | 2 +- .../next-core/src/server_rendered_source.rs | 155 ++++++------------ .../crates/next-core/src/web_entry_source.rs | 122 +++----------- packages/next-swc/crates/next-dev/src/lib.rs | 5 +- 8 files changed, 307 insertions(+), 293 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_client/context.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs delete mode 100644 packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs new file mode 100644 index 00000000000000..8c38d536a8258b --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -0,0 +1,141 @@ +use core::{default::Default, result::Result::Ok}; +use std::collections::HashMap; + +use anyhow::Result; +use turbo_tasks::Value; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{ + module_options::module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, + resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, + transition::TransitionsByNameVc, + ModuleAssetContextVc, +}; +use turbopack_core::{ + chunk::{dev::DevChunkingContext, ChunkingContextVc}, + context::AssetContextVc, + environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, +}; +use turbopack_dev_server::html_runtime_asset::HtmlRuntimeAssetVc; +use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; +use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; + +use crate::{ + env::filter_for_client, + next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, + react_refresh::{assert_can_resolve_react_refresh, react_refresh_request}, +}; + +#[turbo_tasks::function] +pub fn get_client_environment() -> EnvironmentVc { + EnvironmentVc::new( + Value::new(ExecutionEnvironment::Browser( + BrowserEnvironment { + dom: true, + web_worker: false, + service_worker: false, + browser_version: 0, + } + .into(), + )), + Value::new(EnvironmentIntention::Client), + ) +} + +#[turbo_tasks::function] +pub fn get_client_resolve_options_context() -> ResolveOptionsContextVc { + ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + enable_node_modules: true, + custom_conditions: vec!["development".to_string()], + ..Default::default() + } + .cell() +} + +#[turbo_tasks::function] +pub async fn get_client_module_options_context( + project_root: FileSystemPathVc, +) -> Result { + let resolve_options_context = get_client_resolve_options_context(); + let enable_react_refresh = + *assert_can_resolve_react_refresh(project_root, resolve_options_context).await?; + + Ok(ModuleOptionsContext { + // We don't need to resolve React Refresh for each module. Instead, + // we try resolve it once at the root and pass down a context to all + // the modules. + enable_react_refresh, + enable_styled_jsx: true, + enable_typescript_transform: true, + ..Default::default() + } + .cell()) +} + +#[turbo_tasks::function] +pub fn get_client_asset_context(project_root: FileSystemPathVc) -> AssetContextVc { + let environment = get_client_environment(); + let resolve_options_context = get_client_resolve_options_context(); + let module_options_context = get_client_module_options_context(project_root); + + let context: AssetContextVc = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(HashMap::new()), + project_root, + environment, + module_options_context, + resolve_options_context, + ) + .into(); + + context +} + +#[turbo_tasks::function] +pub fn get_client_chunking_context( + project_root: FileSystemPathVc, + server_root: FileSystemPathVc, +) -> ChunkingContextVc { + DevChunkingContext { + context_path: project_root, + chunk_root_path: server_root.join("/_next/static/chunks"), + asset_root_path: server_root.join("/_next/static/assets"), + enable_hot_module_replacement: true, + } + .cell() + .into() +} + +#[turbo_tasks::function] +pub async fn get_client_runtime_entries( + project_root: FileSystemPathVc, + env: ProcessEnvVc, +) -> Result { + let resolve_options_context = get_client_resolve_options_context(); + let enable_react_refresh = + *assert_can_resolve_react_refresh(project_root, resolve_options_context).await?; + + let mut runtime_entries = vec![ + RuntimeEntry::Ecmascript( + ProcessEnvAssetVc::new(project_root, filter_for_client(env)).into(), + ) + .cell(), + RuntimeEntry::Ecmascript(HtmlRuntimeAssetVc::new().into()).cell(), + ]; + if enable_react_refresh { + runtime_entries.push(RuntimeEntry::Request(react_refresh_request(), project_root).cell()) + }; + + Ok(RuntimeEntriesVc::cell(runtime_entries)) +} + +#[turbo_tasks::function] +pub fn get_resolved_client_runtime_entries( + project_root: FileSystemPathVc, + env: ProcessEnvVc, +) -> EcmascriptChunkPlaceablesVc { + let context = get_client_asset_context(project_root); + let entries = get_client_runtime_entries(project_root, env); + + entries.resolve_entries(context) +} diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 15fec92e9268dc..3ed19e62b70249 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -1,8 +1,8 @@ -pub(crate) mod runtime_reference; +pub(crate) mod context; +pub(crate) mod runtime_entry; -use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; -use turbo_tasks::{debug::ValueDebugFormat, trace::TraceRawVcs, ValueToString}; +use anyhow::{bail, Result}; +use turbo_tasks::ValueToString; use turbo_tasks_fs::{embed_file, FileSystemPathVc}; use turbopack::{ ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, @@ -14,20 +14,11 @@ use turbopack::{ use turbopack_core::{ asset::AssetVc, chunk::{ChunkableAssetVc, ChunkingContextVc}, - context::AssetContext, environment::EnvironmentVc, - reference::{AssetReferenceVc, AssetReferencesVc}, - resolve::parse::RequestVc, virtual_asset::VirtualAssetVc, }; -use self::runtime_reference::RuntimeAssetReferenceVc; - -#[derive(ValueDebugFormat, PartialEq, Eq, TraceRawVcs, Serialize, Deserialize)] -pub enum RuntimeReference { - Request(RequestVc, FileSystemPathVc), - Reference(AssetReferenceVc), -} +use self::runtime_entry::RuntimeEntriesVc; /// Makes a transition into a next.js client context. /// @@ -41,7 +32,7 @@ pub struct NextClientTransition { pub client_resolve_options_context: ResolveOptionsContextVc, pub client_chunking_context: ChunkingContextVc, pub server_root: FileSystemPathVc, - pub runtime_references: Vec, + pub runtime_entries: RuntimeEntriesVc, } #[turbo_tasks::value_impl] @@ -72,36 +63,20 @@ impl Transition for NextClientTransition { asset: AssetVc, context: ModuleAssetContextVc, ) -> Result { - if let Some(chunkable_asset) = ChunkableAssetVc::resolve_from(asset).await? { - let runtime_references = self - .runtime_references - .iter() - .map(|r| match *r { - RuntimeReference::Request(r, context_path) => { - RuntimeAssetReferenceVc::new(context.with_context_path(context_path), r) - .as_asset_reference() - } - RuntimeReference::Reference(r) => r, - }) - .collect::>(); - let runtime_references = if runtime_references.is_empty() { - None - } else { - Some(AssetReferencesVc::cell(runtime_references)) - }; - Ok(ChunkGroupFilesAsset { - asset: chunkable_asset, - chunking_context: self.client_chunking_context, - base_path: self.server_root, - runtime_references, - } - .cell() - .into()) - } else { - Err(anyhow!( - "asset {} is not chunkable", - asset.path().to_string().await? - )) - } + let chunkable_asset = match ChunkableAssetVc::resolve_from(asset).await? { + Some(chunkable_asset) => chunkable_asset, + None => bail!("asset {} is not chunkable", asset.path().to_string().await?), + }; + + let runtime_entries = self.runtime_entries.resolve_entries(context.into()); + + let asset = ChunkGroupFilesAsset { + asset: chunkable_asset, + chunking_context: self.client_chunking_context, + base_path: self.server_root, + runtime_entries: Some(runtime_entries), + }; + + Ok(asset.cell().into()) } } diff --git a/packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs b/packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs new file mode 100644 index 00000000000000..4d799340cc8b32 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs @@ -0,0 +1,67 @@ +use anyhow::{bail, Result}; +use turbo_tasks::ValueToString; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_core::{context::AssetContextVc, resolve::parse::RequestVc}; +use turbopack_ecmascript::{ + chunk::{EcmascriptChunkPlaceableVc, EcmascriptChunkPlaceablesVc}, + resolve::cjs_resolve, +}; + +#[turbo_tasks::value(shared)] +pub enum RuntimeEntry { + Request(RequestVc, FileSystemPathVc), + Ecmascript(EcmascriptChunkPlaceableVc), +} + +#[turbo_tasks::value_impl] +impl RuntimeEntryVc { + #[turbo_tasks::function] + pub async fn resolve_entry( + self, + context: AssetContextVc, + ) -> Result { + let (request, path) = match *self.await? { + RuntimeEntry::Ecmascript(e) => return Ok(EcmascriptChunkPlaceablesVc::cell(vec![e])), + RuntimeEntry::Request(r, path) => (r, path), + }; + + let context = context.with_context_path(path); + let assets = cjs_resolve(request, context).primary_assets().await?; + + let mut runtime_entries = Vec::with_capacity(assets.len()); + for asset in &assets { + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { + runtime_entries.push(placeable); + } else { + bail!( + "runtime reference resolved to an asset ({}) that is not placeable into an \ + ecmascript chunk", + asset.path().to_string().await? + ); + } + } + + Ok(EcmascriptChunkPlaceablesVc::cell(runtime_entries)) + } +} + +#[turbo_tasks::value(transparent)] +pub struct RuntimeEntries(Vec); + +#[turbo_tasks::value_impl] +impl RuntimeEntriesVc { + #[turbo_tasks::function] + pub async fn resolve_entries( + self, + context: AssetContextVc, + ) -> Result { + let mut runtime_entries = Vec::new(); + + for reference in &self.await? { + let resolved_entries = reference.resolve_entry(context).await?; + runtime_entries.extend(resolved_entries.into_iter()); + } + + Ok(EcmascriptChunkPlaceablesVc::cell(runtime_entries)) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs b/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs deleted file mode 100644 index 4aac2c50fe67a8..00000000000000 --- a/packages/next-swc/crates/next-core/src/next_client/runtime_reference.rs +++ /dev/null @@ -1,41 +0,0 @@ -use anyhow::Result; -use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc}; -use turbopack::ecmascript::resolve::cjs_resolve; -use turbopack_core::{ - context::AssetContextVc, - reference::{AssetReference, AssetReferenceVc}, - resolve::{parse::RequestVc, ResolveResultVc}, -}; - -#[turbo_tasks::value(shared)] -pub struct RuntimeAssetReference { - pub context: AssetContextVc, - pub request: RequestVc, -} - -#[turbo_tasks::value_impl] -impl RuntimeAssetReferenceVc { - #[turbo_tasks::function] - pub fn new(context: AssetContextVc, request: RequestVc) -> Self { - Self::cell(RuntimeAssetReference { context, request }) - } -} - -#[turbo_tasks::value_impl] -impl AssetReference for RuntimeAssetReference { - #[turbo_tasks::function] - fn resolve_reference(&self) -> ResolveResultVc { - cjs_resolve(self.request, self.context) - } -} - -#[turbo_tasks::value_impl] -impl ValueToString for RuntimeAssetReference { - #[turbo_tasks::function] - async fn to_string(&self) -> Result { - Ok(StringVc::cell(format!( - "runtime {}", - self.request.to_string().await? - ))) - } -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 66220c8a1fb408..d371cbf5ee1009 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -174,7 +174,7 @@ async fn get_intermediate_asset( chunking_context: ChunkingContextVc, intermediate_output_path: FileSystemPathVc, ) -> Result { - let chunk = entry_module.as_evaluated_chunk(chunking_context.into(), Some(runtime_entries)); + let chunk = entry_module.as_evaluated_chunk(chunking_context, Some(runtime_entries)); let chunk_group = ChunkGroupVc::from_chunk(chunk); Ok(NodeJsBootstrapAsset { path: intermediate_output_path.join("index.js"), diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index b9d5cbfe4c4ae7..bb909ccafe7a00 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -2,10 +2,7 @@ use std::collections::HashMap; use anyhow::Result; use serde_json::json; -use turbo_tasks::{ - primitives::{JsonValueVc, StringVc}, - Value, -}; +use turbo_tasks::{primitives::JsonValueVc, Value}; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{ module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext, @@ -14,29 +11,26 @@ use turbopack::{ use turbopack_core::{ chunk::dev::DevChunkingContext, context::AssetContextVc, - environment::{ - BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, - NodeJsEnvironment, - }, - reference::SingleAssetReferenceVc, + environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, source_asset::SourceAssetVc, target::CompileTargetVc, }; -use turbopack_dev_server::{ - html_runtime_asset::HtmlRuntimeAssetVc, - source::{ - asset_graph::AssetGraphContentSourceVc, - combined::{CombinedContentSource, CombinedContentSourceVc}, - ContentSourceVc, NoContentSourceVc, - }, +use turbopack_dev_server::source::{ + asset_graph::AssetGraphContentSourceVc, + combined::{CombinedContentSource, CombinedContentSourceVc}, + ContentSourceVc, NoContentSourceVc, }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; use crate::{ - env::filter_for_client, - next_client::{NextClientTransition, RuntimeReference}, - react_refresh::{assert_can_resolve_react_refresh, react_refresh_request}, + next_client::{ + context::{ + get_client_chunking_context, get_client_environment, get_client_module_options_context, + get_client_resolve_options_context, get_client_runtime_entries, + }, + NextClientTransition, + }, server_render::asset::ServerRenderedAssetVc, }; @@ -44,14 +38,14 @@ use crate::{ /// Next.js pages folder. #[turbo_tasks::function] pub async fn create_server_rendered_source( - root_path: FileSystemPathVc, + project_path: FileSystemPathVc, output_path: FileSystemPathVc, - target_root: FileSystemPathVc, + server_root: FileSystemPathVc, env: ProcessEnvVc, ) -> Result { - let pages = root_path.join("pages"); - let src_pages = root_path.join("src/pages"); - let dir = if *pages.get_type().await? == FileSystemEntryType::Directory { + let pages = project_path.join("pages"); + let src_pages = project_path.join("src/pages"); + let pages_dir = if *pages.get_type().await? == FileSystemEntryType::Directory { pages } else if *src_pages.get_type().await? == FileSystemEntryType::Directory { src_pages @@ -59,73 +53,20 @@ pub async fn create_server_rendered_source( return Ok(NoContentSourceVc::new().into()); }; - let client_chunking_context = DevChunkingContext { - context_path: root_path, - chunk_root_path: target_root.join("_next/static/chunks"), - asset_root_path: target_root.join("_next/static/assets"), - enable_hot_module_replacement: true, - } - .cell() - .into(); - let client_environment = EnvironmentVc::new( - Value::new(ExecutionEnvironment::Browser( - BrowserEnvironment { - dom: true, - web_worker: false, - service_worker: false, - browser_version: 0, - } - .into(), - )), - Value::new(EnvironmentIntention::Client), - ); - let client_resolve_options_context = ResolveOptionsContext { - enable_typescript: true, - enable_react: true, - enable_node_modules: true, - custom_conditions: vec!["development".to_string()], - ..Default::default() - } - .cell(); + let client_chunking_context = get_client_chunking_context(project_path, server_root); + let client_module_options_context = get_client_module_options_context(project_path); + let client_resolve_options_context = get_client_resolve_options_context(); + let client_environment = get_client_environment(); - let server_runtime_entries = - vec![ProcessEnvAssetVc::new(root_path, env).as_ecmascript_chunk_placeable()]; - let mut client_runtime_references = vec![RuntimeReference::Reference( - SingleAssetReferenceVc::new( - ProcessEnvAssetVc::new(root_path, filter_for_client(env)).as_asset(), - StringVc::cell(".env".to_string()), - ) - .into(), - )]; + let client_runtime_entries = get_client_runtime_entries(project_path, env); - let enable_react_refresh = - *assert_can_resolve_react_refresh(root_path, client_resolve_options_context).await?; - if enable_react_refresh { - client_runtime_references.extend(vec![ - RuntimeReference::Request(react_refresh_request(), root_path), - RuntimeReference::Reference( - SingleAssetReferenceVc::new( - HtmlRuntimeAssetVc::new().into(), - StringVc::cell("html-runtime".to_string()), - ) - .into(), - ), - ]); - }; - let client_module_options_context = ModuleOptionsContext { - enable_react_refresh, - enable_styled_jsx: true, - enable_typescript_transform: true, - ..Default::default() - } - .cell(); let next_client_transition = NextClientTransition { client_chunking_context, client_module_options_context, client_resolve_options_context, client_environment, - server_root: target_root, - runtime_references: client_runtime_references, + server_root, + runtime_entries: client_runtime_entries, } .cell() .into(); @@ -134,7 +75,7 @@ pub async fn create_server_rendered_source( transitions.insert("next-client".to_string(), next_client_transition); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), - root_path, + project_path, EnvironmentVc::new( Value::new(ExecutionEnvironment::NodeJsLambda( NodeJsEnvironment { @@ -162,12 +103,15 @@ pub async fn create_server_rendered_source( ) .into(); + let server_runtime_entries = + vec![ProcessEnvAssetVc::new(project_path, env).as_ecmascript_chunk_placeable()]; + Ok(create_server_rendered_source_for_directory( context, - dir, + pages_dir, EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), - target_root, - target_root, + server_root, + server_root, output_path, ) .into()) @@ -177,29 +121,29 @@ pub async fn create_server_rendered_source( #[turbo_tasks::function] async fn create_server_rendered_source_for_file( context: AssetContextVc, - entry: FileSystemPathVc, + page_file: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, - target_root: FileSystemPathVc, - target_path: FileSystemPathVc, + server_root: FileSystemPathVc, + server_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, ) -> Result { let context_path = context.context_path(); - let source_asset = SourceAssetVc::new(entry).into(); + let source_asset = SourceAssetVc::new(page_file).into(); let entry_asset = context - .with_context_path(entry.parent()) + .with_context_path(page_file.parent()) .process(source_asset); let chunking_context = DevChunkingContext { context_path, chunk_root_path: intermediate_output_path.join("chunks"), - asset_root_path: target_root.join("_next/static/assets"), + asset_root_path: server_root.join("_next/static/assets"), enable_hot_module_replacement: false, } .cell() .into(); let asset = ServerRenderedAssetVc::new( - target_path, + server_path, context, entry_asset, runtime_entries, @@ -208,7 +152,7 @@ async fn create_server_rendered_source_for_file( JsonValueVc::cell(json!({ "props": {} })), ); Ok(AssetGraphContentSourceVc::new_lazy( - target_root, + server_root, asset.into(), )) } @@ -221,8 +165,8 @@ async fn create_server_rendered_source_for_directory( context: AssetContextVc, input_dir: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, - target_root: FileSystemPathVc, - target_path: FileSystemPathVc, + server_root: FileSystemPathVc, + server_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, ) -> Result { let mut sources = Vec::new(); @@ -235,11 +179,12 @@ async fn create_server_rendered_source_for_directory( // pageExtensions option from next.js // defaults: https://github.com/vercel/next.js/blob/611e13f5159457fedf96d850845650616a1f75dd/packages/next/server/config-shared.ts#L499 "js" | "ts" | "jsx" | "tsx" => { - let (target_path, intermediate_output_path) = if name == "index" { - (target_path.join("index.html"), intermediate_output_path) + let (dev_server_path, intermediate_output_path) = if name == "index" + { + (server_path.join("index.html"), intermediate_output_path) } else { ( - target_path.join(name).join("index.html"), + server_path.join(name).join("index.html"), intermediate_output_path.join(name), ) }; @@ -248,8 +193,8 @@ async fn create_server_rendered_source_for_directory( context, *file, runtime_entries, - target_root, - target_path, + server_root, + dev_server_path, intermediate_output_path, ) .into(), @@ -265,8 +210,8 @@ async fn create_server_rendered_source_for_directory( context, *dir, runtime_entries, - target_root, - target_path.join(name), + server_root, + server_path.join(name), intermediate_output_path.join(name), ) .into(), diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index a7b531ff9a8cb8..e05beaaa79f071 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -1,124 +1,51 @@ -use std::{collections::HashMap, future::IntoFuture}; +use std::future::IntoFuture; use anyhow::{anyhow, Result}; -use turbo_tasks::{TryJoinIterExt, Value}; -use turbo_tasks_fs::{FileSystemPathVc, FileSystemVc}; -use turbopack::{ - ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}, - module_options::ModuleOptionsContext, - resolve_options_context::ResolveOptionsContext, - transition::TransitionsByNameVc, - ModuleAssetContextVc, -}; +use futures::{prelude::*, stream}; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ - chunk::{ - dev::{DevChunkingContext, DevChunkingContextVc}, - ChunkGroupVc, ChunkableAssetVc, - }, - context::AssetContextVc, - environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, + chunk::{ChunkGroupVc, ChunkableAssetVc}, resolve::parse::RequestVc, }; use turbopack_dev_server::{ html::DevHtmlAsset, - html_runtime_asset::HtmlRuntimeAssetVc, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; -use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; +use turbopack_env::ProcessEnvVc; -use crate::{ - env::filter_for_client, - react_refresh::{assert_can_resolve_react_refresh, resolve_react_refresh}, +use crate::next_client::context::{ + get_client_asset_context, get_client_chunking_context, get_resolved_client_runtime_entries, }; #[turbo_tasks::function] pub async fn create_web_entry_source( - root: FileSystemPathVc, + project_root: FileSystemPathVc, entry_requests: Vec, - dev_server_fs: FileSystemVc, + server_root: FileSystemPathVc, env: ProcessEnvVc, eager_compile: bool, ) -> Result { - let environment = EnvironmentVc::new( - Value::new(ExecutionEnvironment::Browser( - BrowserEnvironment { - dom: true, - web_worker: false, - service_worker: false, - browser_version: 0, - } - .into(), - )), - Value::new(EnvironmentIntention::Client), - ); - - let resolve_options_context = ResolveOptionsContext { - enable_typescript: true, - enable_react: true, - enable_node_modules: true, - custom_conditions: vec!["development".to_string()], - ..Default::default() - } - .cell(); - let enable_react_refresh = - *assert_can_resolve_react_refresh(root, resolve_options_context).await?; - - let context: AssetContextVc = ModuleAssetContextVc::new( - TransitionsByNameVc::cell(HashMap::new()), - root, - environment, - ModuleOptionsContext { - // We don't need to resolve React Refresh for each module. Instead, - // we try resolve it once at the root and pass down a context to all - // the modules. - enable_react_refresh, - enable_styled_jsx: true, - enable_typescript_transform: true, - ..Default::default() - } - .cell(), - resolve_options_context, - ) - .into(); + let context = get_client_asset_context(project_root); + let chunking_context = get_client_chunking_context(project_root, server_root); + let runtime_entries = get_resolved_client_runtime_entries(project_root, env); - let chunking_context: DevChunkingContextVc = DevChunkingContext { - context_path: root, - chunk_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static/chunks"), - asset_root_path: FileSystemPathVc::new(dev_server_fs, "/_next/static/assets"), - enable_hot_module_replacement: true, - } - .into(); - - let mut runtime_entries = vec![ - ProcessEnvAssetVc::new(root, filter_for_client(env)).as_ecmascript_chunk_placeable(), - HtmlRuntimeAssetVc::new().as_ecmascript_chunk_placeable(), - ]; - if enable_react_refresh { - runtime_entries.push(resolve_react_refresh(context)) - } - let runtime_entries = EcmascriptChunkPlaceablesVc::cell(runtime_entries); - - let modules = entry_requests - .into_iter() - .map(|r| { + let chunks: Vec<_> = stream::iter(entry_requests) + .then(|r| { context .resolve_asset(context.context_path(), r, context.resolve_options()) .primary_assets() .into_future() }) - .try_join() - .await?; - let modules = modules - .into_iter() - .flat_map(|assets| assets.iter().copied().collect::>()); - let chunks = modules - .map(|module| async move { + .map_ok(|assets| stream::iter(assets.clone()).map(Ok)) + .try_flatten() + .and_then(|module| async move { if let Some(ecmascript) = EcmascriptModuleAssetVc::resolve_from(module).await? { - Ok(ecmascript.as_evaluated_chunk(chunking_context.into(), Some(runtime_entries))) + Ok(ecmascript.as_evaluated_chunk(chunking_context, Some(runtime_entries))) } else if let Some(chunkable) = ChunkableAssetVc::resolve_from(module).await? { // TODO this is missing runtime code, so it's probably broken and we should also // add an ecmascript chunk with the runtime code - Ok(chunkable.as_chunk(chunking_context.into())) + Ok(chunkable.as_chunk(chunking_context)) } else { // TODO convert into a serve-able asset Err(anyhow!( @@ -127,21 +54,20 @@ pub async fn create_web_entry_source( )) } }) - .try_join() + .try_collect() .await?; let entry_asset = DevHtmlAsset::new( - FileSystemPathVc::new(dev_server_fs, "index.html"), + server_root.join("index.html"), chunks.into_iter().map(ChunkGroupVc::from_chunk).collect(), ) .cell() .into(); - let root_path = FileSystemPathVc::new(dev_server_fs, ""); let graph = if eager_compile { - AssetGraphContentSourceVc::new_eager(root_path, entry_asset) + AssetGraphContentSourceVc::new_eager(server_root, entry_asset) } else { - AssetGraphContentSourceVc::new_lazy(root_path, entry_asset) + AssetGraphContentSourceVc::new_lazy(server_root, entry_asset) } .into(); Ok(graph) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 2cf92b5928d482..a18833aa34634e 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -183,20 +183,21 @@ async fn source( let env = load_env(project_path); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); + let dev_server_root = FileSystemPathVc::new(dev_server_fs, ""); let web_source = create_web_entry_source( project_path, entry_requests .iter() .map(|a| RequestVc::relative(Value::new(a.to_string().into()), false)) .collect(), - dev_server_fs, + dev_server_root, env, eager_compile, ); let rendered_source = create_server_rendered_source( project_path, FileSystemPathVc::new(output_fs, ""), - FileSystemPathVc::new(dev_server_fs, ""), + dev_server_root, env, ); let viz = turbo_tasks_viz::TurboTasksSource { From a8b0fd4f4bb784acd15680ee4b17edafe7308ec9 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Sun, 2 Oct 2022 08:30:57 +0200 Subject: [PATCH 109/672] add layer to ChunkingContext and include that in module id and chunk paths (vercel/turbo#449) this allows multiple versions of modules to co-exist in one chunking context e. g. RSC layer and SSR layer --- .../next-core/src/next_client/context.rs | 20 +++++++++++-------- .../next-core/src/server_rendered_source.rs | 18 ++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 8c38d536a8258b..7b0a8de62d8ce4 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -11,7 +11,7 @@ use turbopack::{ ModuleAssetContextVc, }; use turbopack_core::{ - chunk::{dev::DevChunkingContext, ChunkingContextVc}, + chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, context::AssetContextVc, environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, }; @@ -96,16 +96,20 @@ pub fn get_client_chunking_context( project_root: FileSystemPathVc, server_root: FileSystemPathVc, ) -> ChunkingContextVc { - DevChunkingContext { - context_path: project_root, - chunk_root_path: server_root.join("/_next/static/chunks"), - asset_root_path: server_root.join("/_next/static/assets"), - enable_hot_module_replacement: true, - } - .cell() + DevChunkingContextVc::new( + project_root, + server_root.join("/_next/static/chunks"), + get_client_assets_path(server_root), + true, + ) .into() } +#[turbo_tasks::function] +pub fn get_client_assets_path(server_root: FileSystemPathVc) -> FileSystemPathVc { + server_root.join("/_next/static/assets") +} + #[turbo_tasks::function] pub async fn get_client_runtime_entries( project_root: FileSystemPathVc, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index bb909ccafe7a00..a3f02a174efcb5 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -9,7 +9,7 @@ use turbopack::{ transition::TransitionsByNameVc, ModuleAssetContextVc, }; use turbopack_core::{ - chunk::dev::DevChunkingContext, + chunk::dev::DevChunkingContextVc, context::AssetContextVc, environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, source_asset::SourceAssetVc, @@ -26,8 +26,9 @@ use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; use crate::{ next_client::{ context::{ - get_client_chunking_context, get_client_environment, get_client_module_options_context, - get_client_resolve_options_context, get_client_runtime_entries, + get_client_assets_path, get_client_chunking_context, get_client_environment, + get_client_module_options_context, get_client_resolve_options_context, + get_client_runtime_entries, }, NextClientTransition, }, @@ -133,13 +134,12 @@ async fn create_server_rendered_source_for_file( .with_context_path(page_file.parent()) .process(source_asset); - let chunking_context = DevChunkingContext { + let chunking_context = DevChunkingContextVc::new( context_path, - chunk_root_path: intermediate_output_path.join("chunks"), - asset_root_path: server_root.join("_next/static/assets"), - enable_hot_module_replacement: false, - } - .cell() + intermediate_output_path.join("chunks"), + get_client_assets_path(server_root), + false, + ) .into(); let asset = ServerRenderedAssetVc::new( From 8c80ba4f784c39f3b0ffafbeda792b49854e9a54 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 6 Oct 2022 00:42:55 +0800 Subject: [PATCH 110/672] Migrate to pnpm (vercel/turbo#336) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### turbo tracing in pnpm projects How pnpm link packages: ![image](https://user-images.githubusercontent.com/3468483/191022172-962af095-9b44-4b69-8e2f-1e8d440d1c31.png) After turbo tracing: ``` dist ├── crates │ └── turbopack │ └── tests │ └── node-file-trace │ ├── integration │ └── node_modules │ └── better-sqlite3 -> ../../../../../node_modules/.pnpm/better-sqlite3@7.6.2/node_modules/better-sqlite3 └── node_modules └── .pnpm ├── better-sqlite3@7.6.2 │ └── node_modules │ ├── better-sqlite3 │ │ ├── build │ │ │ └── Release │ │ └── lib │ │ └── methods │ └── bindings -> ../../bindings@1.5.0/node_modules/bindings ├── bindings@1.5.0 │ └── node_modules │ ├── bindings │ └── file-uri-to-path -> ../../file-uri-to-path@1.0.0/node_modules/file-uri-to-path └── file-uri-to-path@1.0.0 └── node_modules └── file-uri-to-path ``` No more **global .pnpm store**. The directory link will follow the original path created by pnpm. --- .../next-swc/crates/next-dev/tests/integration.rs | 15 +++++++++++---- .../next-swc/crates/next-dev/tests/package.json | 3 --- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index e02416fa0eaf7d..771554253f007d 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -1,7 +1,11 @@ #![cfg(test)] extern crate test_generator; -use std::{env, net::SocketAddr, path::Path}; +use std::{ + env, + net::SocketAddr, + path::{Path, PathBuf}, +}; use chromiumoxide::{ browser::{Browser, BrowserConfig}, @@ -116,12 +120,15 @@ async fn run_test(resource: &str) -> JestRunResult { "Test entry {} must exist.", test_entry.to_str().unwrap() ); - + let package_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let workspace_root = package_root.parent().unwrap().parent().unwrap(); + let project_dir = workspace_root.join("crates/next-dev/tests"); + let workspace_root = workspace_root.to_string_lossy().to_string(); let requested_addr = get_free_local_addr().unwrap(); let server = NextDevServerBuilder::new( TurboTasks::new(MemoryBackend::new()), - "tests".into(), - "tests".into(), + project_dir.to_string_lossy().to_string(), + workspace_root, ) .entry_request("harness.js".into()) .entry_request( diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 02872e5dae7a4b..07f5af2f2594d8 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -6,8 +6,5 @@ "react": "^18.2.0", "react-test-renderer": "^18.2.0", "styled-jsx": "^5.0.7" - }, - "installConfig": { - "hoistingLimits": "workspaces" } } From d49a9c3b9deaffe5003f954c4f7f19d0caad207e Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 6 Oct 2022 20:36:36 +0200 Subject: [PATCH 111/672] move ProcessEnv into turbo-tasks-env (vercel/turbo#462) make ProcessEnv a trait to allow other implemenetations of it --- packages/next-swc/crates/next-core/Cargo.toml | 1 + packages/next-swc/crates/next-core/src/env.rs | 13 ++++++++----- .../crates/next-core/src/next_client/context.rs | 3 ++- .../crates/next-core/src/server_rendered_source.rs | 3 ++- .../crates/next-core/src/web_entry_source.rs | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index fad26ae38014b3..89a951c125942c 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -16,6 +16,7 @@ serde = "1.0.136" serde_json = "1.0.85" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } +turbo-tasks-env = { path = "../turbo-tasks-env" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } diff --git a/packages/next-swc/crates/next-core/src/env.rs b/packages/next-swc/crates/next-core/src/env.rs index e39e9626754f92..3e9b4fed1d74a7 100644 --- a/packages/next-swc/crates/next-core/src/env.rs +++ b/packages/next-swc/crates/next-core/src/env.rs @@ -1,12 +1,15 @@ use anyhow::Result; +use turbo_tasks_env::{CommandLineProcessEnvVc, FilterProcessEnvVc, ProcessEnvVc}; use turbo_tasks_fs::FileSystemPathVc; -use turbopack_env::ProcessEnvVc; +use turbopack_env::TryDotenvProcessEnvVc; /// Loads a series of dotenv files according to the precedence rules set by /// https://nextjs.org/docs/basic-features/environment-variables#environment-variable-load-order #[turbo_tasks::function] pub async fn load_env(project_path: FileSystemPathVc) -> Result { - let node_env = std::env::var("NODE_ENV").unwrap_or_else(|_| "development".into()); + let env = CommandLineProcessEnvVc::new().as_process_env(); + let node_env = env.read("NODE_ENV").await?; + let node_env = node_env.as_deref().unwrap_or("development"); let files = [ Some(format!(".env.{node_env}.local")), @@ -21,14 +24,14 @@ pub async fn load_env(project_path: FileSystemPathVc) -> Result { .into_iter() .flatten(); - let env = files.fold(ProcessEnvVc::from_command_line(), |prior, f| { + let env = files.fold(env, |prior, f| { let path = project_path.join(&f); - ProcessEnvVc::from_dotenv_file(path, Some(prior)) + TryDotenvProcessEnvVc::new(prior, path).as_process_env() }); Ok(env) } pub fn filter_for_client(env: ProcessEnvVc) -> ProcessEnvVc { - ProcessEnvVc::filter(env, "NEXT_PUBLIC_".to_string()) + FilterProcessEnvVc::new(env, "NEXT_PUBLIC_".to_string()).into() } diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 7b0a8de62d8ce4..bf2034bfb8d826 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use anyhow::Result; use turbo_tasks::Value; +use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ module_options::module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, @@ -17,7 +18,7 @@ use turbopack_core::{ }; use turbopack_dev_server::html_runtime_asset::HtmlRuntimeAssetVc; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; -use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; +use turbopack_env::ProcessEnvAssetVc; use crate::{ env::filter_for_client, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index a3f02a174efcb5..c034a11a5477df 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use anyhow::Result; use serde_json::json; use turbo_tasks::{primitives::JsonValueVc, Value}; +use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{ module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext, @@ -21,7 +22,7 @@ use turbopack_dev_server::source::{ ContentSourceVc, NoContentSourceVc, }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; -use turbopack_env::{ProcessEnvAssetVc, ProcessEnvVc}; +use turbopack_env::ProcessEnvAssetVc; use crate::{ next_client::{ diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index e05beaaa79f071..236936b0cd80d5 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -2,6 +2,7 @@ use std::future::IntoFuture; use anyhow::{anyhow, Result}; use futures::{prelude::*, stream}; +use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ @@ -12,7 +13,6 @@ use turbopack_dev_server::{ html::DevHtmlAsset, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; -use turbopack_env::ProcessEnvVc; use crate::next_client::context::{ get_client_asset_context, get_client_chunking_context, get_resolved_client_runtime_entries, From e4f92b72061e915f392a0ae11921536eaca8c06d Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 6 Oct 2022 23:54:21 -0700 Subject: [PATCH 112/672] Automatic downleveling to browser targets using swc_preset_env (vercel/turbo#380) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes vercel/turbo#440 This uses swc's preset_env to automatically downlevel code according to the environment's browser targets, and sets next-dev to use a limited, modern target. To do: * [x] Add snapshot test * [x] turbotrace test failures — looks like this has something to do with the Buffer module? Hitting swc's "multiple constructors" not implemented: https://github.com/swc-project/swc/blob/f655488cfa252e68d8d2c0c01b398d84acc73191/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs#L545 * [x] ~Benchmark downleveling node_modules (probably on front) and make a decision re: downleveling everything vs. just workspaces~ Filed as vercel/turbo#457 --- .../next-core/src/next_client/context.rs | 28 +++++++++++-------- .../next-core/src/server_rendered_source.rs | 6 ++-- .../crates/next-core/src/web_entry_source.rs | 6 ++-- .../next-dev/benches/bundlers/turbopack.rs | 3 ++ packages/next-swc/crates/next-dev/src/lib.rs | 14 ++++++++++ 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index bf2034bfb8d826..fa234c78cb03c8 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -27,19 +27,19 @@ use crate::{ }; #[turbo_tasks::function] -pub fn get_client_environment() -> EnvironmentVc { - EnvironmentVc::new( +pub fn get_client_environment(browserslist_query: &str) -> Result { + Ok(EnvironmentVc::new( Value::new(ExecutionEnvironment::Browser( BrowserEnvironment { dom: true, web_worker: false, service_worker: false, - browser_version: 0, + browserslist_query: browserslist_query.to_owned(), } .into(), )), Value::new(EnvironmentIntention::Client), - ) + )) } #[turbo_tasks::function] @@ -57,6 +57,7 @@ pub fn get_client_resolve_options_context() -> ResolveOptionsContextVc { #[turbo_tasks::function] pub async fn get_client_module_options_context( project_root: FileSystemPathVc, + env: EnvironmentVc, ) -> Result { let resolve_options_context = get_client_resolve_options_context(); let enable_react_refresh = @@ -69,16 +70,20 @@ pub async fn get_client_module_options_context( enable_react_refresh, enable_styled_jsx: true, enable_typescript_transform: true, + preset_env_versions: Some(env), ..Default::default() } .cell()) } #[turbo_tasks::function] -pub fn get_client_asset_context(project_root: FileSystemPathVc) -> AssetContextVc { - let environment = get_client_environment(); +pub fn get_client_asset_context( + project_root: FileSystemPathVc, + browserslist_query: &str, +) -> Result { + let environment = get_client_environment(browserslist_query); let resolve_options_context = get_client_resolve_options_context(); - let module_options_context = get_client_module_options_context(project_root); + let module_options_context = get_client_module_options_context(project_root, environment); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -89,7 +94,7 @@ pub fn get_client_asset_context(project_root: FileSystemPathVc) -> AssetContextV ) .into(); - context + Ok(context) } #[turbo_tasks::function] @@ -138,9 +143,10 @@ pub async fn get_client_runtime_entries( pub fn get_resolved_client_runtime_entries( project_root: FileSystemPathVc, env: ProcessEnvVc, -) -> EcmascriptChunkPlaceablesVc { - let context = get_client_asset_context(project_root); + browserslist_query: &str, +) -> Result { + let context = get_client_asset_context(project_root, browserslist_query); let entries = get_client_runtime_entries(project_root, env); - entries.resolve_entries(context) + Ok(entries.resolve_entries(context)) } diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index c034a11a5477df..7719e40661387d 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -44,6 +44,7 @@ pub async fn create_server_rendered_source( output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, + browserslist_query: &str, ) -> Result { let pages = project_path.join("pages"); let src_pages = project_path.join("src/pages"); @@ -56,9 +57,10 @@ pub async fn create_server_rendered_source( }; let client_chunking_context = get_client_chunking_context(project_path, server_root); - let client_module_options_context = get_client_module_options_context(project_path); + let client_environment = get_client_environment(browserslist_query); + let client_module_options_context = + get_client_module_options_context(project_path, client_environment); let client_resolve_options_context = get_client_resolve_options_context(); - let client_environment = get_client_environment(); let client_runtime_entries = get_client_runtime_entries(project_path, env); diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 236936b0cd80d5..c84c07a32c9934 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -25,10 +25,12 @@ pub async fn create_web_entry_source( server_root: FileSystemPathVc, env: ProcessEnvVc, eager_compile: bool, + browserslist_query: &str, ) -> Result { - let context = get_client_asset_context(project_root); + let context = get_client_asset_context(project_root, browserslist_query); let chunking_context = get_client_chunking_context(project_root, server_root); - let runtime_entries = get_resolved_client_runtime_entries(project_root, env); + let runtime_entries = + get_resolved_client_runtime_entries(project_root, env, browserslist_query); let chunks: Vec<_> = stream::iter(entry_requests) .then(|r| { diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index efd94e54732394..d13a2fcae73f03 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -49,6 +49,9 @@ impl Bundler for Turbopack { &[ NpmPackage::new("react-refresh", "^0.12.0"), NpmPackage::new("@next/react-refresh-utils", "^12.2.5"), + // Dependencies on these are inserted by swc's preset_env + NpmPackage::new("@swc/helpers", "^0.4.11"), + NpmPackage::new("core-js", "^3.25.3"), ], ) .context("failed to install from npm")?; diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index a18833aa34634e..082451d0d0e571 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -29,6 +29,7 @@ pub struct NextDevServerBuilder { eager_compile: bool, hostname: Option, port: Option, + browserslist_query: String, log_level: IssueSeverity, show_all: bool, log_detail: bool, @@ -48,6 +49,9 @@ impl NextDevServerBuilder { eager_compile: false, hostname: None, port: None, + browserslist_query: "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \ + versions, last 1 Edge versions" + .to_owned(), log_level: IssueSeverity::Warning, show_all: false, log_detail: false, @@ -74,6 +78,11 @@ impl NextDevServerBuilder { self } + pub fn browserslist_query(mut self, browserslist_query: String) -> NextDevServerBuilder { + self.browserslist_query = browserslist_query; + self + } + pub fn log_level(mut self, log_level: IssueSeverity) -> NextDevServerBuilder { self.log_level = log_level; self @@ -98,6 +107,7 @@ impl NextDevServerBuilder { let eager_compile = self.eager_compile; let show_all = self.show_all; let log_detail = self.log_detail; + let browserslist_query = self.browserslist_query; let log_options = LogOptions { project_dir: project_dir.clone(), show_all, @@ -116,6 +126,7 @@ impl NextDevServerBuilder { eager_compile, turbo_tasks.clone().into(), log_options.clone().cell(), + browserslist_query.clone(), ) }, ( @@ -171,6 +182,7 @@ async fn source( eager_compile: bool, turbo_tasks: TransientInstance>, log_options: LogOptionsVc, + browserslist_query: String, ) -> Result { let output_fs = output_fs(&project_dir, log_options); let fs = project_fs(&root_dir, log_options); @@ -193,12 +205,14 @@ async fn source( dev_server_root, env, eager_compile, + &browserslist_query, ); let rendered_source = create_server_rendered_source( project_path, FileSystemPathVc::new(output_fs, ""), dev_server_root, env, + &browserslist_query, ); let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.into(), From e8359f796456e243a280fba12b69d07f518d27ab Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 7 Oct 2022 13:34:31 +0200 Subject: [PATCH 113/672] refactor AssetContext (vercel/turbo#465) remove context_path from AssetContext remove most with_* methods from AssetContext add ResolveOrigin trait use ResolveOrigin to pass along context path and context for resolving ecmascript and css module assets implement ResolveOrigin Noteable change: Many places use `origin_path` instead of `context_path` which means it points to the issuer module path instead of the issuer module directory. --- .../crates/next-core/src/next_client/context.rs | 4 ++-- .../crates/next-core/src/next_client/runtime_entry.rs | 10 +++++++--- .../next-swc/crates/next-core/src/react_refresh.rs | 7 +++---- .../crates/next-core/src/server_render/asset.rs | 2 +- .../crates/next-core/src/server_rendered_source.rs | 11 ++++++----- .../next-swc/crates/next-core/src/web_entry_source.rs | 7 ++++--- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index fa234c78cb03c8..09cb0c687db369 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -87,7 +87,6 @@ pub fn get_client_asset_context( let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), - project_root, environment, module_options_context, resolve_options_context, @@ -133,7 +132,8 @@ pub async fn get_client_runtime_entries( RuntimeEntry::Ecmascript(HtmlRuntimeAssetVc::new().into()).cell(), ]; if enable_react_refresh { - runtime_entries.push(RuntimeEntry::Request(react_refresh_request(), project_root).cell()) + runtime_entries + .push(RuntimeEntry::Request(react_refresh_request(), project_root.join("_")).cell()) }; Ok(RuntimeEntriesVc::cell(runtime_entries)) diff --git a/packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs b/packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs index 4d799340cc8b32..f133f76fb5250f 100644 --- a/packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_client/runtime_entry.rs @@ -1,7 +1,10 @@ use anyhow::{bail, Result}; use turbo_tasks::ValueToString; use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::{context::AssetContextVc, resolve::parse::RequestVc}; +use turbopack_core::{ + context::AssetContextVc, + resolve::{origin::PlainResolveOriginVc, parse::RequestVc}, +}; use turbopack_ecmascript::{ chunk::{EcmascriptChunkPlaceableVc, EcmascriptChunkPlaceablesVc}, resolve::cjs_resolve, @@ -25,8 +28,9 @@ impl RuntimeEntryVc { RuntimeEntry::Request(r, path) => (r, path), }; - let context = context.with_context_path(path); - let assets = cjs_resolve(request, context).primary_assets().await?; + let assets = cjs_resolve(PlainResolveOriginVc::new(context, path).into(), request) + .primary_assets() + .await?; let mut runtime_entries = Vec::with_capacity(assets.len()); for asset in &assets { diff --git a/packages/next-swc/crates/next-core/src/react_refresh.rs b/packages/next-swc/crates/next-core/src/react_refresh.rs index 15bacbe1994d6b..f6b7a2c60baa0e 100644 --- a/packages/next-swc/crates/next-core/src/react_refresh.rs +++ b/packages/next-swc/crates/next-core/src/react_refresh.rs @@ -12,9 +12,8 @@ use turbopack::{ resolve_options_context::ResolveOptionsContextVc, }; use turbopack_core::{ - context::AssetContextVc, issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, - resolve::{parse::RequestVc, ResolveResult}, + resolve::{origin::ResolveOriginVc, parse::RequestVc, ResolveResult}, }; #[turbo_tasks::function] @@ -57,8 +56,8 @@ pub async fn assert_can_resolve_react_refresh( /// Resolves the React Refresh runtime module from the given [AssetContextVc]. #[turbo_tasks::function] -pub async fn resolve_react_refresh(context: AssetContextVc) -> Result { - match &*cjs_resolve(react_refresh_request(), context).await? { +pub async fn resolve_react_refresh(origin: ResolveOriginVc) -> Result { + match &*cjs_resolve(origin, react_refresh_request()).await? { ResolveResult::Single(asset, _) => { if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { Ok(placeable) diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index fddc0c2a60dec3..a55c6b74f56e32 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -140,7 +140,7 @@ fn get_intermediate_module( embed_file!("server_renderer.js").into(), ) .into(), - context.with_context_path(entry_asset.path()), + context, Value::new(ModuleAssetType::Ecmascript), EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { refresh: false }]), context.environment(), diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 7719e40661387d..8cd1c173d6fdb2 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -79,7 +79,6 @@ pub async fn create_server_rendered_source( transitions.insert("next-client".to_string(), next_client_transition); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), - project_path, EnvironmentVc::new( Value::new(ExecutionEnvironment::NodeJsLambda( NodeJsEnvironment { @@ -111,6 +110,7 @@ pub async fn create_server_rendered_source( vec![ProcessEnvAssetVc::new(project_path, env).as_ecmascript_chunk_placeable()]; Ok(create_server_rendered_source_for_directory( + project_path, context, pages_dir, EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), @@ -124,6 +124,7 @@ pub async fn create_server_rendered_source( /// Handles a single page file in the pages directory #[turbo_tasks::function] async fn create_server_rendered_source_for_file( + context_path: FileSystemPathVc, context: AssetContextVc, page_file: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, @@ -131,11 +132,8 @@ async fn create_server_rendered_source_for_file( server_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, ) -> Result { - let context_path = context.context_path(); let source_asset = SourceAssetVc::new(page_file).into(); - let entry_asset = context - .with_context_path(page_file.parent()) - .process(source_asset); + let entry_asset = context.process(source_asset); let chunking_context = DevChunkingContextVc::new( context_path, @@ -165,6 +163,7 @@ async fn create_server_rendered_source_for_file( /// [create_server_rendered_source_for_file] method for files. #[turbo_tasks::function] async fn create_server_rendered_source_for_directory( + context_path: FileSystemPathVc, context: AssetContextVc, input_dir: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, @@ -193,6 +192,7 @@ async fn create_server_rendered_source_for_directory( }; sources.push( create_server_rendered_source_for_file( + context_path, context, *file, runtime_entries, @@ -210,6 +210,7 @@ async fn create_server_rendered_source_for_directory( DirectoryEntry::Directory(dir) => { sources.push( create_server_rendered_source_for_directory( + context_path, context, *dir, runtime_entries, diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index c84c07a32c9934..a6cbc19d7bad79 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -7,7 +7,7 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ chunk::{ChunkGroupVc, ChunkableAssetVc}, - resolve::parse::RequestVc, + resolve::{origin::PlainResolveOriginVc, parse::RequestVc}, }; use turbopack_dev_server::{ html::DevHtmlAsset, @@ -32,10 +32,11 @@ pub async fn create_web_entry_source( let runtime_entries = get_resolved_client_runtime_entries(project_root, env, browserslist_query); + let origin = PlainResolveOriginVc::new(context, project_root.join("_")).as_resolve_origin(); let chunks: Vec<_> = stream::iter(entry_requests) .then(|r| { - context - .resolve_asset(context.context_path(), r, context.resolve_options()) + origin + .resolve_asset(r, origin.resolve_options()) .primary_assets() .into_future() }) From 39663ebc78414cefe690385428ae3730a6f79c37 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 7 Oct 2022 13:35:35 +0200 Subject: [PATCH 114/672] pass request info to content source (vercel/turbo#458) allow the ContentSource to declare which info is required --- packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index e78c897d202e36..e2fbecc7fb69d3 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -2,7 +2,7 @@ use std::{str::FromStr, sync::Arc, time::Duration}; use anyhow::Result; use mime::Mime; -use turbo_tasks::{get_invalidator, TurboTasks}; +use turbo_tasks::{get_invalidator, TurboTasks, Value}; use turbo_tasks_fs::{File, FileContent}; use turbo_tasks_memory::{ stats::{ReferenceType, Stats}, @@ -10,7 +10,7 @@ use turbo_tasks_memory::{ }; use turbopack_core::asset::AssetContent; use turbopack_dev_server::source::{ - ContentSource, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, + ContentSource, ContentSourceData, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, }; #[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new", into = "new")] @@ -30,7 +30,7 @@ const INVALIDATION_INTERVAL: Duration = Duration::from_secs(3); #[turbo_tasks::value_impl] impl ContentSource for TurboTasksSource { #[turbo_tasks::function] - fn get(&self, path: &str) -> Result { + fn get(&self, path: &str, _data: Value) -> Result { let tt = &self.turbo_tasks; let invalidator = get_invalidator(); tokio::spawn({ From 839b55ff063e60951ec53b637fb62862cfbe5628 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Fri, 7 Oct 2022 13:36:44 +0200 Subject: [PATCH 115/672] Add support for pages/_app (vercel/turbo#442) This adds preliminary support for pages/_app. There's still some work to do here to support things like `App. getInitialProps`, etc., but that will come in later PRs. I've created issues for these for now. One issue remaining is that renaming `pages/_app.js` does not switch to the default _app asset. The server needs to be restarted for this to happen. Similarly, adding an _app.js file does not switch from the default asset to it. I'm guessing there's something wrong with the way I set up the import mappings, and they aren't being invalidated properly? fixes vercel/turbo#424 --- .../crates/next-core/src/embed_next.rs | 10 +++++ packages/next-swc/crates/next-core/src/lib.rs | 2 + .../crates/next-core/src/next_client/mod.rs | 5 ++- .../next-core/src/next_client/next_hydrate.js | 5 --- .../crates/next-core/src/next_import_map.rs | 40 +++++++++++++++++++ .../src/next_js/internal/next-hydrate.js | 9 +++++ .../internal/server-renderer.js} | 3 +- .../next-core/src/next_js/pages/_app.js | 6 +++ .../next-core/src/server_render/asset.rs | 9 +++-- .../next-core/src/server_rendered_source.rs | 6 +++ 10 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/embed_next.rs delete mode 100644 packages/next-swc/crates/next-core/src/next_client/next_hydrate.js create mode 100644 packages/next-swc/crates/next-core/src/next_import_map.rs create mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js rename packages/next-swc/crates/next-core/src/{server_render/server_renderer.js => next_js/internal/server-renderer.js} (95%) create mode 100644 packages/next-swc/crates/next-core/src/next_js/pages/_app.js diff --git a/packages/next-swc/crates/next-core/src/embed_next.rs b/packages/next-swc/crates/next-core/src/embed_next.rs new file mode 100644 index 00000000000000..c5e9dc0b329280 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/embed_next.rs @@ -0,0 +1,10 @@ +#[macro_export] +macro_rules! embed_next_file { + ($path:expr) => { + turbo_tasks_fs::embed_file!(concat!( + env!("CARGO_WORKSPACE_DIR"), + "crates/next-core/src/next_js/", + $path + )) + }; +} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 9240bcd1f964ed..fe7b78467970c8 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -1,8 +1,10 @@ #![feature(async_closure)] #![feature(min_specialization)] +mod embed_next; pub mod env; pub mod next_client; +mod next_import_map; mod nodejs; pub mod react_refresh; mod server_render; diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 3ed19e62b70249..56c9390216c3b1 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod runtime_entry; use anyhow::{bail, Result}; use turbo_tasks::ValueToString; -use turbo_tasks_fs::{embed_file, FileSystemPathVc}; +use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, module_options::ModuleOptionsContextVc, @@ -19,6 +19,7 @@ use turbopack_core::{ }; use self::runtime_entry::RuntimeEntriesVc; +use crate::embed_next_file; /// Makes a transition into a next.js client context. /// @@ -39,7 +40,7 @@ pub struct NextClientTransition { impl Transition for NextClientTransition { #[turbo_tasks::function] fn process_source(&self, asset: AssetVc) -> AssetVc { - let next_hydrate = embed_file!("next_hydrate.js").into(); + let next_hydrate = embed_next_file!("internal/next-hydrate.js").into(); VirtualAssetVc::new(asset.path().join("next-hydrate.js"), next_hydrate).into() } diff --git a/packages/next-swc/crates/next-core/src/next_client/next_hydrate.js b/packages/next-swc/crates/next-core/src/next_client/next_hydrate.js deleted file mode 100644 index 0f36a56059ba17..00000000000000 --- a/packages/next-swc/crates/next-core/src/next_client/next_hydrate.js +++ /dev/null @@ -1,5 +0,0 @@ -import Component from "."; -import { hydrateRoot } from "react-dom/client"; - -const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); -hydrateRoot(document.getElementById("__next"), ); diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs new file mode 100644 index 00000000000000..6ea07ba6c95005 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -0,0 +1,40 @@ +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_core::{ + resolve::{ + options::{ImportMap, ImportMapVc, ImportMapping}, + AliasPattern, ResolveResult, + }, + virtual_asset::VirtualAssetVc, +}; + +use crate::embed_next_file; + +/// Aliases [next_pages_app] to either an existing `pages/_app` asset, or a +/// default asset. +#[turbo_tasks::function] +pub fn get_next_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { + let mut import_map = ImportMap::empty(); + import_map.insert_alias( + AliasPattern::Exact("@vercel/turbopack-next/pages/_app".to_string()), + ImportMapping::Alternatives(vec![ + ImportMapping::PrimaryAlternative("./_app".to_string(), Some(pages_dir)).into(), + ImportMapping::Direct( + ResolveResult::Single( + VirtualAssetVc::new( + // TODO(alexkirsz) We should make sure these paths are unique, + // otherwise we can run into conflicts with + // user paths. + pages_dir.root().join("next_js/pages/_app.js"), + embed_next_file!("pages/_app.js").into(), + ) + .into(), + vec![], + ) + .into(), + ) + .into(), + ]) + .into(), + ); + import_map.cell() +} diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js new file mode 100644 index 00000000000000..8f6ef4f00a2fa0 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js @@ -0,0 +1,9 @@ +import App from "@vercel/turbopack-next/pages/_app"; +// TODO(alexkirsz) We might need yet another transition that makes sure "." and +// its dependencies cannot use the next-alias transition, by removing it from +// the transition map. +import Component from "."; +import { hydrateRoot } from "react-dom/client"; + +const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); +hydrateRoot(document.getElementById("__next"), ); diff --git a/packages/next-swc/crates/next-core/src/server_render/server_renderer.js b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js similarity index 95% rename from packages/next-swc/crates/next-core/src/server_render/server_renderer.js rename to packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js index 36f0642a5a5b04..9f7eb7fc1a604b 100644 --- a/packages/next-swc/crates/next-core/src/server_render/server_renderer.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js @@ -1,5 +1,6 @@ const END_OF_OPERATION = process.argv[2]; +import App from "@vercel/turbopack-next/pages/_app"; import Component, * as otherExports from "."; import { renderToString, renderToStaticMarkup } from "react-dom/server"; ("TURBOPACK { transition: next-client }"); @@ -40,7 +41,7 @@ async function operation(data) { // TODO capture meta info during rendering const rendered = { - __html: renderToString(), + __html: renderToString(), }; const urls = chunkGroup.map((p) => `/${p}`); const scripts = urls.filter((url) => url.endsWith(".js")); diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_app.js b/packages/next-swc/crates/next-core/src/next_js/pages/_app.js new file mode 100644 index 00000000000000..f144bc36e87b5c --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_js/pages/_app.js @@ -0,0 +1,6 @@ +// The full definition of the default _app.js file is in +// https://github.com/vercel/next.js/blob/canary/packages/next/pages/_app.tsx + +export default function App({ Component, pageProps }) { + return ; +} diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index a55c6b74f56e32..7dafb4f7d9f3dc 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -3,7 +3,7 @@ use turbo_tasks::{ primitives::{JsonValueVc, StringVc}, Value, ValueToString, ValueToStringVc, }; -use turbo_tasks_fs::{embed_file, FileSystemPathVc}; +use turbo_tasks_fs::FileSystemPathVc; use turbopack::ecmascript::{ EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetVc, ModuleAssetType, }; @@ -18,7 +18,10 @@ use turbopack_core::{ }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; -use crate::nodejs::{external_asset_entrypoints, render_static}; +use crate::{ + embed_next_file, + nodejs::{external_asset_entrypoints, render_static}, +}; /// This is an asset which content is determined by running /// `React.renderToString` on the default export of [entry_asset] in a Node.js @@ -137,7 +140,7 @@ fn get_intermediate_module( EcmascriptModuleAssetVc::new( VirtualAssetVc::new( entry_asset.path().join("server-renderer.js"), - embed_file!("server_renderer.js").into(), + embed_next_file!("internal/server-renderer.js").into(), ) .into(), context, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 8cd1c173d6fdb2..2ce295e993a3ce 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -33,6 +33,7 @@ use crate::{ }, NextClientTransition, }, + next_import_map::get_next_import_map, server_render::asset::ServerRenderedAssetVc, }; @@ -62,6 +63,10 @@ pub async fn create_server_rendered_source( get_client_module_options_context(project_path, client_environment); let client_resolve_options_context = get_client_resolve_options_context(); + let next_import_map = get_next_import_map(pages_dir); + let client_resolve_options_context = + client_resolve_options_context.with_extended_import_map(next_import_map); + let client_runtime_entries = get_client_runtime_entries(project_path, env); let next_client_transition = NextClientTransition { @@ -100,6 +105,7 @@ pub async fn create_server_rendered_source( enable_node_modules: true, enable_node_native_modules: true, custom_conditions: vec!["development".to_string()], + import_map: Some(next_import_map), ..Default::default() } .cell(), From c3b6b0f790b69f83960cc1c891ac9b29e80cbe42 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Fri, 7 Oct 2022 14:49:09 +0200 Subject: [PATCH 116/672] Add support for pages/_document (vercel/turbo#456) This adds preliminary support for pages/_document. The API is more complex than pages/_app, so this required a few more things in order to work. Right now, our `next/document` shim does much, much less than the original. We will eventually have to figure out whether we should distribute our own module, or find a way to reuse Next.js' internals. There's *a lot* of stuff in there so the second option is probably best. --- .../crates/next-core/src/next_import_map.rs | 100 ++++++++++++++---- .../src/next_js/internal/html-context.js | 6 ++ .../src/next_js/internal/next-hydrate.js | 3 - .../src/next_js/internal/server-renderer.js | 85 +++++++-------- .../next-core/src/next_js/pages/_document.js | 79 ++++++++++++++ 5 files changed, 203 insertions(+), 70 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/html-context.js create mode 100644 packages/next-swc/crates/next-core/src/next_js/pages/_document.js diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 6ea07ba6c95005..dd084c2c2e6b2e 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -1,7 +1,8 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::{ + asset::AssetVc, resolve::{ - options::{ImportMap, ImportMapVc, ImportMapping}, + options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}, AliasPattern, ResolveResult, }, virtual_asset::VirtualAssetVc, @@ -14,27 +15,84 @@ use crate::embed_next_file; #[turbo_tasks::function] pub fn get_next_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { let mut import_map = ImportMap::empty(); - import_map.insert_alias( - AliasPattern::Exact("@vercel/turbopack-next/pages/_app".to_string()), - ImportMapping::Alternatives(vec![ - ImportMapping::PrimaryAlternative("./_app".to_string(), Some(pages_dir)).into(), - ImportMapping::Direct( - ResolveResult::Single( - VirtualAssetVc::new( - // TODO(alexkirsz) We should make sure these paths are unique, - // otherwise we can run into conflicts with - // user paths. - pages_dir.root().join("next_js/pages/_app.js"), - embed_next_file!("pages/_app.js").into(), - ) - .into(), - vec![], - ) - .into(), - ) - .into(), - ]) + + let pages_app_asset_import_mapping = asset_to_import_mapping( + VirtualAssetVc::new( + // TODO(alexkirsz) We should make sure these paths are unique, + // otherwise we can run into conflicts with + // user paths. + pages_dir.root().join("next_js/pages/_app.js"), + embed_next_file!("pages/_app.js").into(), + ) + .into(), + ); + let pages_document_asset_import_mapping = asset_to_import_mapping( + VirtualAssetVc::new( + pages_dir.root().join("next_js/pages/_document.js"), + embed_next_file!("pages/_document.js").into(), + ) + .into(), + ); + let internal_html_context_import_mapping = asset_to_import_mapping( + VirtualAssetVc::new( + pages_dir.root().join("next_js/internal/html-context.js"), + embed_next_file!("internal/html-context.js").into(), + ) .into(), ); + + insert_alias_to_alternatives( + &mut import_map, + "@vercel/turbopack-next/pages/_app", + request_to_import_mapping(pages_dir, "./_app"), + pages_app_asset_import_mapping, + ); + insert_alias_to_alternatives( + &mut import_map, + "@vercel/turbopack-next/pages/_document", + request_to_import_mapping(pages_dir, "./_document"), + pages_document_asset_import_mapping, + ); + + insert_alias( + &mut import_map, + "@vercel/turbopack-next/internal/html-context", + internal_html_context_import_mapping, + ); + insert_alias( + &mut import_map, + "next/document", + pages_document_asset_import_mapping, + ); + import_map.cell() } + +/// Inserts an alias to an alternative of import mappings into an import map. +pub fn insert_alias_to_alternatives( + import_map: &mut ImportMap, + alias: &str, + alt1: ImportMappingVc, + alt2: ImportMappingVc, +) { + import_map.insert_alias( + AliasPattern::Exact(alias.to_string()), + ImportMapping::Alternatives(vec![alt1, alt2]).into(), + ); +} + +/// Inserts an alias to an import mapping into an import map. +pub fn insert_alias(import_map: &mut ImportMap, alias: &str, mapping: ImportMappingVc) { + import_map.insert_alias(AliasPattern::Exact(alias.to_string()), mapping); +} + +/// Creates a direct import mapping to the result of resolving a request +/// in a context. +pub fn request_to_import_mapping(context_path: FileSystemPathVc, request: &str) -> ImportMappingVc { + ImportMapping::PrimaryAlternative(request.to_string(), Some(context_path)).into() +} + +/// Creates a direct import mapping to a single asset. +pub fn asset_to_import_mapping(asset: AssetVc) -> ImportMappingVc { + ImportMapping::Direct(ResolveResult::Single(asset, vec![]).into()).into() +} diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/html-context.js b/packages/next-swc/crates/next-core/src/next_js/internal/html-context.js new file mode 100644 index 00000000000000..7197e6fce47c86 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_js/internal/html-context.js @@ -0,0 +1,6 @@ +// This is a Next-internal file that must not be exposed to end-users. +// Adapted from https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/html-context.ts + +import { createContext } from "react"; + +export const HtmlContext = createContext(null); diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js index 8f6ef4f00a2fa0..3413125f6a68d3 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js @@ -1,7 +1,4 @@ import App from "@vercel/turbopack-next/pages/_app"; -// TODO(alexkirsz) We might need yet another transition that makes sure "." and -// its dependencies cannot use the next-alias transition, by removing it from -// the transition map. import Component from "."; import { hydrateRoot } from "react-dom/client"; diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js index 9f7eb7fc1a604b..5f7c6beac2a21b 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js @@ -1,6 +1,8 @@ const END_OF_OPERATION = process.argv[2]; import App from "@vercel/turbopack-next/pages/_app"; +import Document from "@vercel/turbopack-next/pages/_document"; +import { HtmlContext } from "@vercel/turbopack-next/internal/html-context"; import Component, * as otherExports from "."; import { renderToString, renderToStaticMarkup } from "react-dom/server"; ("TURBOPACK { transition: next-client }"); @@ -28,64 +30,55 @@ process.stdin.on("data", async (data) => { buffer.push(data); }); +const DOCTYPE = ""; + +function Body({ children }) { + return
{children}
; +} + async function operation(data) { - let staticProps = data; if ("getStaticProps" in otherExports) { // TODO(alexkirsz) Pass in `context` as defined in // https://nextjs.org/docs/api-reference/data-fetching/get-static-props#context-parameter - staticProps = otherExports.getStaticProps({}); - if ("then" in staticProps) { - staticProps = await staticProps; + data = otherExports.getStaticProps({}); + if ("then" in data) { + data = await data; } } - // TODO capture meta info during rendering - const rendered = { - __html: renderToString(), - }; const urls = chunkGroup.map((p) => `/${p}`); const scripts = urls.filter((url) => url.endsWith(".js")); const styles = urls.filter((url) => url.endsWith(".css")); - return renderToStaticMarkup( - - - {styles.map((url) => ( - - ))} - {scripts.map((url) => ( - - ))} - - - -
- {scripts.map((url) => ( - - ))} - - + const documentHTML = renderToStaticMarkup( + + + ); -} -// This utility is based on https://github.com/zertosh/htmlescape -// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE - -const ESCAPE_LOOKUP = { - "&": "\\u0026", - ">": "\\u003e", - "<": "\\u003c", - "\u2028": "\\u2028", - "\u2029": "\\u2029", -}; + const [renderTargetPrefix, renderTargetSuffix] = documentHTML.split( + "" + ); -const ESCAPE_REGEX = /[&><\u2028\u2029]/g; + const result = []; + if (!documentHTML.startsWith(DOCTYPE)) { + result.push(DOCTYPE); + } + result.push(renderTargetPrefix); + // TODO capture meta info during rendering + result.push( + renderToString( + + + + ) + ); + result.push(renderTargetSuffix); -export function htmlEscapeJsonString(str) { - return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); + return result.join(""); } diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js new file mode 100644 index 00000000000000..a5ca0530b7ae43 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js @@ -0,0 +1,79 @@ +// The full definition of the default _document.js file is in +// https://github.com/vercel/next.js/blob/canary/packages/next/pages/_document.tsx + +import React from "react"; +import { HtmlContext } from "@vercel/turbopack-next/internal/html-context"; + +export function Html(props) { + return ; +} + +export function Head({ children, ...props }) { + const { styles, scripts } = React.useContext(HtmlContext); + + return ( + + {children} + {styles.map((url) => ( + + ))} + {scripts.map((url) => ( + + ))} + + ); +} + +// This utility is based on https://github.com/zertosh/htmlescape +// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE + +const ESCAPE_LOOKUP = { + "&": "\\u0026", + ">": "\\u003e", + "<": "\\u003c", + "\u2028": "\\u2028", + "\u2029": "\\u2029", +}; + +const ESCAPE_REGEX = /[&><\u2028\u2029]/g; + +export function htmlEscapeJsonString(str) { + return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); +} + +export function NextScript() { + const { scripts, data } = React.useContext(HtmlContext); + + return ( + <> + + {scripts.map((url) => ( + + ))} + + ); +} + +export function Main() { + // This element will be search-and-replaced with the actual page content once + // rendered to static markup. + return ; +} + +export default function Document() { + return ( + + + +
+ + + + ); +} From 9427514d69a819fd3493a089e6ec8ea7be37d614 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Sun, 9 Oct 2022 13:47:33 +0200 Subject: [PATCH 117/672] prepare css for different types and transforms (vercel/turbo#477) following the design of ecmascript parse and modules fix a few nitpicks --- .../next-swc/crates/next-core/src/server_render/asset.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs index 7dafb4f7d9f3dc..af7c3f424eb856 100644 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ b/packages/next-swc/crates/next-core/src/server_render/asset.rs @@ -5,7 +5,8 @@ use turbo_tasks::{ }; use turbo_tasks_fs::FileSystemPathVc; use turbopack::ecmascript::{ - EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetVc, ModuleAssetType, + EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, + EcmascriptModuleAssetVc, }; use turbopack_core::{ self, @@ -144,7 +145,7 @@ fn get_intermediate_module( ) .into(), context, - Value::new(ModuleAssetType::Ecmascript), + Value::new(EcmascriptModuleAssetType::Ecmascript), EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { refresh: false }]), context.environment(), ) From 4851e09ca8bd3fac8f4d3a0210902571a0175904 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Mon, 10 Oct 2022 02:24:54 -0400 Subject: [PATCH 118/672] Revamp errors and logging (vercel/turbo#467) This updates all of our Issues to have a consistent display, and changes the way we display source code and debug-level details. In particular, this makes the following changes: 1. Cleans up the title/description of existing issues - We were filling the `title` field with too much information, because the `desccription` field wasn't always shown. 1. Always displays the `description` - This used to be hidden behind the `--detail` flag 1. Always displays the code frame of the issue, if it exists - This used to be hidden behind the `--detail` flag 1. Fixes the `context` (file path) to display the relative path to the file - It was hardcoded to the FS string used by turbotrace 1. Creates a new `detail` function which can provide debug-level information about the internal Rust state - This is not shown by default, user must pass `--detail` flag The format for a rendered issue roughly matches: ``` ${SEVERITY} [${CATEGORY}] ${CONTEXT} ${TITLE} ${CODE FRAME} ${DESCRIPTION} ${DETAIL} ``` Where - `SEVERITY` is error/warning/etc - `CATEGORY` is a self-defined string for the phase of the compiler (eg, "parsing", "running") - `CONTEXT` is a file path to the offending file - `TITLE` is a short (single-line) title - `CODE_FRAME` is an optional position that generated the issue, which will display a few context lines and highlight the offending span of code - `DESCRIPTION` is a longer (multi-line) message that describes the issue, and what to do about it - `DETAIL` is a (by default not shown) fully detailed, debug-level, message providing insights into the internal state of Rust --- .../crates/next-core/src/nodejs/issue.rs | 17 ++++++------ .../crates/next-core/src/react_refresh.rs | 27 ++++++++++--------- packages/next-swc/crates/next-dev/src/lib.rs | 4 +-- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/issue.rs b/packages/next-swc/crates/next-core/src/nodejs/issue.rs index 8b2c4027f29185..9baa6d0fed71b1 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/issue.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/issue.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use turbo_tasks::{primitives::StringVc, ValueToString}; +use turbo_tasks::primitives::StringVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::issue::{Issue, IssueVc}; @@ -13,11 +13,8 @@ pub struct RenderingIssue { #[turbo_tasks::value_impl] impl Issue for RenderingIssue { #[turbo_tasks::function] - async fn title(&self) -> Result { - Ok(StringVc::cell(format!( - "error during rendering of {}", - self.context.to_string().await?, - ))) + fn title(&self) -> StringVc { + StringVc::cell("Error during SSR Rendering".to_string()) } #[turbo_tasks::function] @@ -35,6 +32,10 @@ impl Issue for RenderingIssue { self.message } - // TODO add sub_issue for logging data - // TODO parse stack trace + #[turbo_tasks::function] + fn detail(&self) -> StringVc { + self.logging + } + + // TODO parse stack trace into source location } diff --git a/packages/next-swc/crates/next-core/src/react_refresh.rs b/packages/next-swc/crates/next-core/src/react_refresh.rs index f6b7a2c60baa0e..6678ee0130b2d4 100644 --- a/packages/next-swc/crates/next-core/src/react_refresh.rs +++ b/packages/next-swc/crates/next-core/src/react_refresh.rs @@ -40,9 +40,8 @@ pub async fn assert_can_resolve_react_refresh( _ => { ReactRefreshResolvingIssue { path, - description: StringVc::cell(format!( - "could not resolve the `@next/react-refresh-utils/dist/runtime` \ - module\nresolve options: {:?}", + detail: StringVc::cell(format!( + "resolve options: {:?}", resolve_options.dbg().await? )), } @@ -86,7 +85,7 @@ pub async fn resolve_react_refresh(origin: ResolveOriginVc) -> Result Result { - Ok(StringVc::cell( - "An issue occurred while resolving the React Refresh runtime. React Refresh will be \ - disabled.\nTo enable React Refresh, install the `react-refresh` and \ - `@next/react-refresh-utils` modules." - .to_string(), - )) + fn title(&self) -> StringVc { + StringVc::cell("Could not resolve React Refresh runtime".to_string()) } #[turbo_tasks::function] @@ -118,6 +112,15 @@ impl Issue for ReactRefreshResolvingIssue { #[turbo_tasks::function] fn description(&self) -> StringVc { - self.description + StringVc::cell( + "React Refresh will be disabled.\nTo enable React Refresh, install the \ + `react-refresh` and `@next/react-refresh-utils` modules." + .to_string(), + ) + } + + #[turbo_tasks::function] + fn detail(&self) -> StringVc { + self.detail } } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 082451d0d0e571..472e5dd6d751be 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -1,7 +1,7 @@ #![feature(future_join)] #![feature(min_specialization)] -use std::{net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; +use std::{env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; use next_core::{create_server_rendered_source, create_web_entry_source, env::load_env}; @@ -109,7 +109,7 @@ impl NextDevServerBuilder { let log_detail = self.log_detail; let browserslist_query = self.browserslist_query; let log_options = LogOptions { - project_dir: project_dir.clone(), + current_dir: current_dir().unwrap(), show_all, log_detail, log_level: self.log_level, From ed769521f9d940d43bb8c2c329fb6969cf203a9d Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 10 Oct 2022 11:03:25 +0200 Subject: [PATCH 119/672] Support for App.getInitialProps/Page.getInitialProps (vercel/turbo#464) This is a very simplified version of what Next.js does. It adds support for `App` and page components defining `getInitialProps`. fixes vercel/web-tooling-internal#38 --- .../crates/next-core/src/next_import_map.rs | 13 +++++++++ .../src/next_js/internal/next-hydrate.js | 2 +- .../src/next_js/internal/server-renderer.js | 27 ++++++++++++------- .../src/next_js/internal/shared-utils.js | 15 +++++++++++ .../next-core/src/next_js/pages/_app.js | 9 +++++++ .../next-core/src/next_js/pages/_document.js | 4 +-- 6 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index dd084c2c2e6b2e..a27e1ba73a4cfe 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -40,6 +40,13 @@ pub fn get_next_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { ) .into(), ); + let internal_shared_utils_import_mapping = asset_to_import_mapping( + VirtualAssetVc::new( + pages_dir.root().join("next_js/internal/shared-utils.js"), + embed_next_file!("internal/shared-utils.js").into(), + ) + .into(), + ); insert_alias_to_alternatives( &mut import_map, @@ -59,6 +66,12 @@ pub fn get_next_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { "@vercel/turbopack-next/internal/html-context", internal_html_context_import_mapping, ); + insert_alias( + &mut import_map, + "@vercel/turbopack-next/internal/shared-utils", + internal_shared_utils_import_mapping, + ); + insert_alias(&mut import_map, "next/app", pages_app_asset_import_mapping); insert_alias( &mut import_map, "next/document", diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js index 3413125f6a68d3..a6f0eef958dc6d 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js @@ -3,4 +3,4 @@ import Component from "."; import { hydrateRoot } from "react-dom/client"; const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); -hydrateRoot(document.getElementById("__next"), ); +hydrateRoot(document.getElementById("__next"), ); diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js index 5f7c6beac2a21b..5276c05e96bc25 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js @@ -3,6 +3,7 @@ const END_OF_OPERATION = process.argv[2]; import App from "@vercel/turbopack-next/pages/_app"; import Document from "@vercel/turbopack-next/pages/_document"; import { HtmlContext } from "@vercel/turbopack-next/internal/html-context"; +import { loadGetInitialProps } from "@vercel/turbopack-next/internal/shared-utils"; import Component, * as otherExports from "."; import { renderToString, renderToStaticMarkup } from "react-dom/server"; ("TURBOPACK { transition: next-client }"); @@ -46,17 +47,24 @@ async function operation(data) { } } + const initialProps = await loadGetInitialProps(App, { + Component, + // TODO(alexkirsz) Pass in `context` + ctx: {}, + }); + const props = { ...initialProps, ...data.props, pageProps: { ...initialProps.pageProps, ...data.props } }; + const urls = chunkGroup.map((p) => `/${p}`); const scripts = urls.filter((url) => url.endsWith(".js")); const styles = urls.filter((url) => url.endsWith(".css")); + const htmlProps = { + scripts, + styles, + __NEXT_DATA__: { props }, + }; + const documentHTML = renderToStaticMarkup( - + ); @@ -70,11 +78,12 @@ async function operation(data) { result.push(DOCTYPE); } result.push(renderTargetPrefix); - // TODO capture meta info during rendering + result.push( + // TODO capture meta info during rendering renderToString( - + ) ); diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js b/packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js new file mode 100644 index 00000000000000..90900949f57abe --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js @@ -0,0 +1,15 @@ +// Originally defined in https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/utils.ts +export async function loadGetInitialProps(App, ctx) { + if (!App.getInitialProps) { + if (ctx.ctx && ctx.Component) { + return { + pageProps: await loadGetInitialProps(ctx.Component, ctx.ctx), + }; + } + return {}; + } + + const props = await App.getInitialProps(ctx); + + return props; +} diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_app.js b/packages/next-swc/crates/next-core/src/next_js/pages/_app.js index f144bc36e87b5c..51ad064b7e0e93 100644 --- a/packages/next-swc/crates/next-core/src/next_js/pages/_app.js +++ b/packages/next-swc/crates/next-core/src/next_js/pages/_app.js @@ -1,6 +1,15 @@ // The full definition of the default _app.js file is in // https://github.com/vercel/next.js/blob/canary/packages/next/pages/_app.tsx +import { loadGetInitialProps } from "@vercel/turbopack-next/internal/shared-utils"; + export default function App({ Component, pageProps }) { return ; } + +async function appGetInitialProps({ Component, ctx }) { + const pageProps = await loadGetInitialProps(Component, ctx); + return { pageProps }; +} + +App.getInitialProps = appGetInitialProps; diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js index a5ca0530b7ae43..740f3b06569ef6 100644 --- a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js +++ b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js @@ -42,7 +42,7 @@ export function htmlEscapeJsonString(str) { } export function NextScript() { - const { scripts, data } = React.useContext(HtmlContext); + const { scripts, __NEXT_DATA__ } = React.useContext(HtmlContext); return ( <> @@ -50,7 +50,7 @@ export function NextScript() { id="__NEXT_DATA__" type="application/json" dangerouslySetInnerHTML={{ - __html: htmlEscapeJsonString(JSON.stringify(data)), + __html: htmlEscapeJsonString(JSON.stringify(__NEXT_DATA__)), }} > {scripts.map((url) => ( From 9bc858fdddf779324ca0bdec8823374295838f80 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 10 Oct 2022 05:46:36 -0700 Subject: [PATCH 120/672] preset_env followup [1/2] (vercel/turbo#478) Addresses some feedback from vercel/turbo#380. Together with a following PR to use swc_core (currently blocked on https://github.com/swc-project/swc/pull/6083 and a subsequent publish), will address vercel/turbo#474. * Remove unnecessary Result type * Remove unnecessary @swc/helpers --- .../crates/next-core/src/next_client/context.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 09cb0c687db369..59cdfcf5b56742 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -27,8 +27,8 @@ use crate::{ }; #[turbo_tasks::function] -pub fn get_client_environment(browserslist_query: &str) -> Result { - Ok(EnvironmentVc::new( +pub fn get_client_environment(browserslist_query: &str) -> EnvironmentVc { + EnvironmentVc::new( Value::new(ExecutionEnvironment::Browser( BrowserEnvironment { dom: true, @@ -39,7 +39,7 @@ pub fn get_client_environment(browserslist_query: &str) -> Result .into(), )), Value::new(EnvironmentIntention::Client), - )) + ) } #[turbo_tasks::function] @@ -80,7 +80,7 @@ pub async fn get_client_module_options_context( pub fn get_client_asset_context( project_root: FileSystemPathVc, browserslist_query: &str, -) -> Result { +) -> AssetContextVc { let environment = get_client_environment(browserslist_query); let resolve_options_context = get_client_resolve_options_context(); let module_options_context = get_client_module_options_context(project_root, environment); @@ -93,7 +93,7 @@ pub fn get_client_asset_context( ) .into(); - Ok(context) + context } #[turbo_tasks::function] @@ -144,9 +144,9 @@ pub fn get_resolved_client_runtime_entries( project_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, -) -> Result { +) -> EcmascriptChunkPlaceablesVc { let context = get_client_asset_context(project_root, browserslist_query); let entries = get_client_runtime_entries(project_root, env); - Ok(entries.resolve_entries(context)) + entries.resolve_entries(context) } From 7ebb64846cc76e4685d29cf10ee5a8729ca3766f Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 10 Oct 2022 15:35:42 +0200 Subject: [PATCH 121/672] Make embed_file relative to package instead of invoker file (vercel/turbo#484) This makes the argument to `embed_file!` relative to the package it is invoked from, instead of relative to the file it is invoked from. The latter is closer to how `include_*!` works, but it has a couple of issues: * Since `file!` returns a path relative to the workspace, it requires knowing the full path to the workspace. However, this is undefined when the package is compiled from outside of the workspace (e.g. as a dependency of another package). * Procedural macros don't have access to the path of the file where they were originally invoked [(although we could get it with #[feature(proc_macro_span)])](https://doc.rust-lang.org/proc_macro/struct.Span.html), which means that an `embed_dir` macro would not be able to be relative to the invoker file anyway. So this makes things more consistent for such a (to be implemented) macro. --- packages/next-swc/crates/next-core/src/embed_next.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/embed_next.rs b/packages/next-swc/crates/next-core/src/embed_next.rs index c5e9dc0b329280..02099c46b8555a 100644 --- a/packages/next-swc/crates/next-core/src/embed_next.rs +++ b/packages/next-swc/crates/next-core/src/embed_next.rs @@ -1,10 +1,6 @@ #[macro_export] macro_rules! embed_next_file { ($path:expr) => { - turbo_tasks_fs::embed_file!(concat!( - env!("CARGO_WORKSPACE_DIR"), - "crates/next-core/src/next_js/", - $path - )) + turbo_tasks_fs::embed_file!(concat!("src/next_js/", $path)) }; } From 3a05f60d3ce282883ddffa034d7cbf789206eaee Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 10 Oct 2022 15:44:42 +0200 Subject: [PATCH 122/672] fix many root sources crated (vercel/turbo#485) It's important to not create a `cell` outside of the root `source` method as this will create a new cell for each call, which means each `source` will create a separate task, and this bubbles for each cell created in `source`... --- packages/next-swc/crates/next-dev/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 472e5dd6d751be..11b2d757266a2c 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -108,12 +108,12 @@ impl NextDevServerBuilder { let show_all = self.show_all; let log_detail = self.log_detail; let browserslist_query = self.browserslist_query; - let log_options = LogOptions { + let log_options = Arc::new(LogOptions { current_dir: current_dir().unwrap(), show_all, log_detail, log_level: self.log_level, - }; + }); let log_options_to_dev_server = log_options.clone(); let server = DevServer::listen( @@ -125,7 +125,7 @@ impl NextDevServerBuilder { entry_requests.clone(), eager_compile, turbo_tasks.clone().into(), - log_options.clone().cell(), + log_options.clone().into(), browserslist_query.clone(), ) }, @@ -181,9 +181,10 @@ async fn source( entry_requests: Vec, eager_compile: bool, turbo_tasks: TransientInstance>, - log_options: LogOptionsVc, + log_options: TransientInstance, browserslist_query: String, ) -> Result { + let log_options = (*log_options).clone().cell(); let output_fs = output_fs(&project_dir, log_options); let fs = project_fs(&root_dir, log_options); let project_relative = project_dir.strip_prefix(&root_dir).unwrap(); From 5e1922d3973d3d10e57db3bd822d3f2772209b1e Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 11 Oct 2022 00:21:30 +0200 Subject: [PATCH 123/672] move node.js rendering to a content source (vercel/turbo#486) add getServerSideProps and dynamic segments fixes vercel/web-tooling-internal#37 fixes vercel/turbo#444 --- packages/next-swc/crates/next-core/Cargo.toml | 3 + packages/next-swc/crates/next-core/src/lib.rs | 1 - .../src/next_js/internal/server-renderer.js | 21 ++- .../crates/next-core/src/nodejs/bootstrap.rs | 6 +- .../crates/next-core/src/nodejs/issue.rs | 8 +- .../crates/next-core/src/nodejs/mod.rs | 44 +++-- .../src/nodejs/node_rendered_source.rs | 176 ++++++++++++++++++ .../crates/next-core/src/nodejs/pool.rs | 18 +- .../next-core/src/server_render/asset.rs | 152 --------------- .../crates/next-core/src/server_render/mod.rs | 1 - .../next-core/src/server_rendered_source.rs | 138 ++++++++++---- 11 files changed, 346 insertions(+), 222 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs delete mode 100644 packages/next-swc/crates/next-core/src/server_render/asset.rs delete mode 100644 packages/next-swc/crates/next-core/src/server_render/mod.rs diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 89a951c125942c..599290e3159f04 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -11,9 +11,12 @@ bench = false [dependencies] anyhow = "1.0.47" futures = "0.3.21" +indexmap = { workspace = true, features = ["serde"] } mime = "0.3.16" +regex = "1.6.0" serde = "1.0.136" serde_json = "1.0.85" +serde_qs = "0.10.1" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-env = { path = "../turbo-tasks-env" } diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index fe7b78467970c8..5ac39ab9dc43f1 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -7,7 +7,6 @@ pub mod next_client; mod next_import_map; mod nodejs; pub mod react_refresh; -mod server_render; mod server_rendered_source; mod web_entry_source; diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js index 5276c05e96bc25..f12fc2d5ee5775 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js @@ -19,6 +19,7 @@ process.stdin.on("data", async (data) => { buffer.push(data.slice(0, idx)); try { let json = JSON.parse(Buffer.concat(buffer).toString("utf-8")); + buffer.length = 0; let result = await operation(json); console.log(`RESULT=${JSON.stringify(result)}`); } catch (e) { @@ -37,14 +38,30 @@ function Body({ children }) { return
{children}
; } -async function operation(data) { +async function operation(renderData) { + let data; if ("getStaticProps" in otherExports) { // TODO(alexkirsz) Pass in `context` as defined in // https://nextjs.org/docs/api-reference/data-fetching/get-static-props#context-parameter - data = otherExports.getStaticProps({}); + data = otherExports.getStaticProps({ + params: renderData.params, + }); if ("then" in data) { data = await data; } + } else if ("getServerSideProps" in otherExports) { + data = otherExports.getServerSideProps({ + params: renderData.params, + query: { ...renderData.query, ...renderData.params }, + req: { + headers: renderData.headers, + // TODO add `cookies` field + }, + method: renderData.method, + url: renderData.url, + }); + } else { + data = { props: {} }; } const initialProps = await loadGetInitialProps(App, { diff --git a/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs b/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs index 6f79defa1501ff..420994aa831bfd 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs @@ -10,9 +10,9 @@ use turbopack_core::{ }; #[turbo_tasks::value(shared)] -pub struct NodeJsBootstrapAsset { - pub path: FileSystemPathVc, - pub chunk_group: ChunkGroupVc, +pub(super) struct NodeJsBootstrapAsset { + pub(super) path: FileSystemPathVc, + pub(super) chunk_group: ChunkGroupVc, } #[turbo_tasks::value_impl] diff --git a/packages/next-swc/crates/next-core/src/nodejs/issue.rs b/packages/next-swc/crates/next-core/src/nodejs/issue.rs index 9baa6d0fed71b1..1e07cbd350c8f0 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/issue.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/issue.rs @@ -4,10 +4,10 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::issue::{Issue, IssueVc}; #[turbo_tasks::value(shared)] -pub struct RenderingIssue { - pub context: FileSystemPathVc, - pub message: StringVc, - pub logging: StringVc, +pub(super) struct RenderingIssue { + pub(super) context: FileSystemPathVc, + pub(super) message: StringVc, + pub(super) logging: StringVc, } #[turbo_tasks::value_impl] diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index d371cbf5ee1009..9aef96418ecdf3 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -1,33 +1,34 @@ use std::{ - collections::{HashMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet}, path::PathBuf, }; use anyhow::{anyhow, Result}; use futures::{stream::FuturesUnordered, TryStreamExt}; +use indexmap::IndexMap; use mime::TEXT_HTML_UTF_8; +pub use node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}; use serde_json::Value as JsonValue; -use turbo_tasks::{ - primitives::{JsonValueVc, StringVc}, - spawn_blocking, CompletionVc, CompletionsVc, ValueToString, -}; +use turbo_tasks::{primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc}; use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ asset::{AssetContentVc, AssetVc, AssetsSetVc}, chunk::{ChunkGroupVc, ChunkingContextVc}, }; +use turbopack_dev_server::source::{query::Query, HeaderValue}; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; use self::{ bootstrap::NodeJsBootstrapAsset, + issue::RenderingIssue, pool::{NodeJsPool, NodeJsPoolVc}, }; -use crate::nodejs::issue::RenderingIssue; -pub mod bootstrap; +pub(crate) mod bootstrap; pub(crate) mod issue; -pub mod pool; +pub(crate) mod node_rendered_source; +pub(crate) mod pool; #[turbo_tasks::function] async fn emit( @@ -47,9 +48,9 @@ async fn emit( /// List of the all assets of the "internal" subgraph and a list of boundary /// assets that are not considered "internal" ("external") #[turbo_tasks::value] -pub struct SeparatedAssets { - pub internal_assets: AssetsSetVc, - pub external_asset_entrypoints: AssetsSetVc, +struct SeparatedAssets { + internal_assets: AssetsSetVc, + external_asset_entrypoints: AssetsSetVc, } /// Extracts the subgraph of "internal" assets (assets within the passes @@ -70,7 +71,7 @@ async fn internal_assets( /// Returns a set of "external" assets on the boundary of the "internal" /// subgraph #[turbo_tasks::function] -pub async fn external_asset_entrypoints( +async fn external_asset_entrypoints( module: EcmascriptModuleAssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, chunking_context: ChunkingContextVc, @@ -150,7 +151,7 @@ async fn separate_assets( /// Creates a node.js renderer pool for an entrypoint. #[turbo_tasks::function] -pub async fn get_renderer_pool( +async fn get_renderer_pool( intermediate_asset: AssetVc, intermediate_output_path: FileSystemPathVc, ) -> Result { @@ -184,15 +185,24 @@ async fn get_intermediate_asset( .into()) } +#[turbo_tasks::value(shared)] +pub(super) struct RenderData { + params: IndexMap, + method: String, + url: String, + query: Query, + headers: BTreeMap, +} + /// Renders a module as static HTML in a node.js process. #[turbo_tasks::function] -pub async fn render_static( +async fn render_static( path: FileSystemPathVc, module: EcmascriptModuleAssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, chunking_context: ChunkingContextVc, intermediate_output_path: FileSystemPathVc, - data: JsonValueVc, + data: RenderDataVc, ) -> Result { fn into_result(content: String) -> Result { Ok( @@ -210,7 +220,9 @@ pub async fn render_static( intermediate_output_path, ); let pool = renderer_pool.await?; - let mut op = pool.run(data.to_string().await?.as_bytes()).await?; + let mut op = pool + .run(serde_json::to_string(&*data.await?)?.as_bytes()) + .await?; let lines = spawn_blocking(move || { let lines = op.read_lines()?; drop(op); diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs new file mode 100644 index 00000000000000..41879249f40258 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -0,0 +1,176 @@ +use anyhow::{anyhow, Result}; +use indexmap::IndexMap; +use turbo_tasks::primitives::RegexVc; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_core::chunk::ChunkingContextVc; +use turbopack_dev_server::source::{ + asset_graph::AssetGraphContentSourceVc, + combined::CombinedContentSource, + conditional::ConditionalContentSourceVc, + lazy_instatiated::{GetContentSource, GetContentSourceVc, LazyInstantiatedContentSource}, + ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, + ContentSourceDataVaryVc, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, +}; +use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; + +use super::{external_asset_entrypoints, render_static, RenderData}; + +/// Trait that allows to get the entry module for rendering something in Node.js +#[turbo_tasks::value_trait] +pub trait NodeRenderer { + fn module(&self) -> EcmascriptModuleAssetVc; +} + +/// Creates a content source that renders something in Node.js with the passed +/// `renderer` when it matches a `regular_expression`. Once rendered it serves +/// all assets referenced by the `renderer` that are within the `server_root`. +/// It needs a temporary directory (`intermediate_output_path`) to place file +/// for Node.js execution during rendering. The `chunking_context` should emit +/// to this directory. +#[turbo_tasks::function] +pub fn create_node_rendered_source( + server_root: FileSystemPathVc, + regular_expression: RegexVc, + renderer: NodeRendererVc, + chunking_context: ChunkingContextVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + intermediate_output_path: FileSystemPathVc, +) -> ContentSourceVc { + let source = NodeRenderContentSource { + server_root, + regular_expression, + renderer, + chunking_context, + runtime_entries, + intermediate_output_path, + } + .cell(); + ConditionalContentSourceVc::new( + source.into(), + LazyInstantiatedContentSource { + get_source: source.into(), + } + .cell() + .into(), + ) + .into() +} + +/// see [create_node_rendered_source] +#[turbo_tasks::value] +struct NodeRenderContentSource { + server_root: FileSystemPathVc, + regular_expression: RegexVc, + renderer: NodeRendererVc, + chunking_context: ChunkingContextVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + intermediate_output_path: FileSystemPathVc, +} + +impl NodeRenderContentSource { + /// Checks if a path matches the regular expression + async fn is_matching_path(&self, path: &str) -> Result { + Ok(self.regular_expression.await?.is_match(path)) + } + + /// Matches a path with the regular expression and returns a JSON object + /// with the named captures + async fn get_matches(&self, path: &str) -> Result>> { + let regexp = self.regular_expression.await?; + Ok(regexp.captures(path).map(|capture| { + regexp + .capture_names() + .flatten() + .filter_map(|name| { + let value = capture.name(name)?; + Some((name.to_string(), value.as_str().to_string())) + }) + .collect() + })) + } +} + +#[turbo_tasks::value_impl] +impl GetContentSource for NodeRenderContentSource { + /// Returns the [ContentSource] that the serves all referenced external + /// assets. This is wrapped into [LazyInstantiatedContentSource]. + #[turbo_tasks::function] + async fn content_source(&self) -> Result { + Ok(CombinedContentSource { + sources: external_asset_entrypoints( + self.renderer.module(), + self.runtime_entries, + self.chunking_context, + self.intermediate_output_path, + ) + .await? + .iter() + .map(|asset| AssetGraphContentSourceVc::new_lazy(self.server_root, *asset).into()) + .collect(), + } + .cell() + .into()) + } +} + +#[turbo_tasks::value_impl] +impl ContentSource for NodeRenderContentSource { + #[turbo_tasks::function] + async fn vary(&self, path: &str) -> Result { + Ok(if self.is_matching_path(path).await? { + ContentSourceDataVary { + method: true, + url: true, + headers: Some(ContentSourceDataFilter::All), + query: Some(ContentSourceDataFilter::All), + ..Default::default() + } + .cell() + } else { + ContentSourceDataVary::default().cell() + }) + } + + #[turbo_tasks::function] + async fn get( + &self, + path: &str, + data: turbo_tasks::Value, + ) -> Result { + Ok(if let Some(params) = self.get_matches(path).await? { + ContentSourceResult::Static( + render_static( + self.server_root.join(path), + self.renderer.module(), + self.runtime_entries, + self.chunking_context, + self.intermediate_output_path, + RenderData { + params, + method: data + .method + .clone() + .ok_or_else(|| anyhow!("method need to be provided"))?, + url: data + .url + .clone() + .ok_or_else(|| anyhow!("url need to be provided"))?, + query: data.query.clone(), + headers: data.headers.clone(), + } + .cell(), + ) + .into(), + ) + .cell() + } else { + ContentSourceResult::NotFound.cell() + }) + } + + #[turbo_tasks::function] + fn get_by_id(&self, _id: &str) -> ContentSourceResultVc { + // TODO allow to subscribe to the content + ContentSourceResult::NotFound.cell() + } +} diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index b5b5244b358c6e..2689736e897ec8 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -70,7 +70,7 @@ impl NodeJsPoolProcess { self.stdout.read_line(buf) } - pub fn write(&mut self, buf: &[u8]) -> std::io::Result<()> { + pub(super) fn write(&mut self, buf: &[u8]) -> std::io::Result<()> { self.stdin.write_all(buf) } } @@ -85,7 +85,7 @@ impl NodeJsPoolProcess { /// The worker will *not* use the env of the parent process by default. All env /// vars need to be provided to make the execution as pure as possible. #[turbo_tasks::value(into = "new", cell = "new", serialization = "none", eq = "manual")] -pub struct NodeJsPool { +pub(super) struct NodeJsPool { cwd: PathBuf, entrypoint: PathBuf, env: HashMap, @@ -96,7 +96,7 @@ pub struct NodeJsPool { } impl NodeJsPool { - pub fn new( + pub(super) fn new( cwd: PathBuf, entrypoint: PathBuf, env: HashMap, @@ -130,7 +130,7 @@ impl NodeJsPool { }) } - pub async fn run(&self, input: &[u8]) -> Result { + pub(super) async fn run(&self, input: &[u8]) -> Result { let (mut child, permit) = self.acquire_child().await?; // SAFETY we await spawn blocking so we stay within the lifetime of input let static_input: &'static [u8] = unsafe { transmute(input) }; @@ -150,7 +150,7 @@ impl NodeJsPool { } } -pub struct NodeJsOperationResult { +pub(super) struct NodeJsOperationResult { child_ended: bool, child: Option, // This is used for drop @@ -160,11 +160,7 @@ pub struct NodeJsOperationResult { } impl NodeJsOperationResult { - pub fn stdin(&mut self) -> Option<&mut ChildStdin> { - self.child.as_mut().map(|c| &mut c.stdin) - } - - pub fn read_line(&mut self, buf: &mut String) -> Result { + pub(super) fn read_line(&mut self, buf: &mut String) -> Result { if let Some(ref mut child) = self.child { if self.child_ended { return Ok(0); @@ -186,7 +182,7 @@ impl NodeJsOperationResult { } } - pub fn read_lines(&mut self) -> Result, std::io::Error> { + pub(super) fn read_lines(&mut self) -> Result, std::io::Error> { let mut lines = Vec::new(); loop { let mut line = String::new(); diff --git a/packages/next-swc/crates/next-core/src/server_render/asset.rs b/packages/next-swc/crates/next-core/src/server_render/asset.rs deleted file mode 100644 index af7c3f424eb856..00000000000000 --- a/packages/next-swc/crates/next-core/src/server_render/asset.rs +++ /dev/null @@ -1,152 +0,0 @@ -use anyhow::Result; -use turbo_tasks::{ - primitives::{JsonValueVc, StringVc}, - Value, ValueToString, ValueToStringVc, -}; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack::ecmascript::{ - EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, - EcmascriptModuleAssetVc, -}; -use turbopack_core::{ - self, - asset::{Asset, AssetContentVc, AssetVc}, - chunk::ChunkingContextVc, - context::AssetContextVc, - reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, - resolve::{ResolveResult, ResolveResultVc}, - virtual_asset::VirtualAssetVc, -}; -use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; - -use crate::{ - embed_next_file, - nodejs::{external_asset_entrypoints, render_static}, -}; - -/// This is an asset which content is determined by running -/// `React.renderToString` on the default export of [entry_asset] in a Node.js -/// context. -/// -/// For that the [entry_asset] is bundled and emitted into -/// [intermediate_output_path] and a pool of Node.js processes is used to run -/// that. [request_data] is passed to the [entry_asset] component as props. When -/// only [path] and [request_data] differs multiple [ServerRenderedAsset]s will -/// share the Node.js worker pool. -#[turbo_tasks::value] -pub struct ServerRenderedAsset { - path: FileSystemPathVc, - context: AssetContextVc, - entry_asset: AssetVc, - chunking_context: ChunkingContextVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - intermediate_output_path: FileSystemPathVc, - request_data: JsonValueVc, -} - -#[turbo_tasks::value_impl] -impl ServerRenderedAssetVc { - #[turbo_tasks::function] - pub fn new( - path: FileSystemPathVc, - context: AssetContextVc, - entry_asset: AssetVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: ChunkingContextVc, - intermediate_output_path: FileSystemPathVc, - request_data: JsonValueVc, - ) -> Self { - ServerRenderedAsset { - path, - context, - entry_asset, - runtime_entries, - chunking_context, - intermediate_output_path, - request_data, - } - .cell() - } -} - -#[turbo_tasks::value_impl] -impl Asset for ServerRenderedAsset { - #[turbo_tasks::function] - fn path(&self) -> FileSystemPathVc { - self.path - } - - #[turbo_tasks::function] - fn content(&self) -> AssetContentVc { - render_static( - self.path, - get_intermediate_module(self.context, self.entry_asset), - self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, - self.request_data, - ) - } - - #[turbo_tasks::function] - async fn references(&self) -> Result { - Ok(AssetReferencesVc::cell( - external_asset_entrypoints( - get_intermediate_module(self.context, self.entry_asset), - self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, - ) - .await? - .iter() - .map(|a| { - ServerRenderedClientAssetReference { asset: *a } - .cell() - .into() - }) - .collect(), - )) - } -} - -#[turbo_tasks::value] -pub struct ServerRenderedClientAssetReference { - asset: AssetVc, -} - -#[turbo_tasks::value_impl] -impl AssetReference for ServerRenderedClientAssetReference { - #[turbo_tasks::function] - fn resolve_reference(&self) -> ResolveResultVc { - ResolveResult::Single(self.asset, Vec::new()).into() - } -} - -#[turbo_tasks::value_impl] -impl ValueToString for ServerRenderedClientAssetReference { - #[turbo_tasks::function] - async fn to_string(&self) -> Result { - Ok(StringVc::cell(format!( - "client asset {}", - self.asset.path().to_string().await? - ))) - } -} - -#[turbo_tasks::function] -fn get_intermediate_module( - context: AssetContextVc, - entry_asset: AssetVc, -) -> EcmascriptModuleAssetVc { - EcmascriptModuleAssetVc::new( - VirtualAssetVc::new( - entry_asset.path().join("server-renderer.js"), - embed_next_file!("internal/server-renderer.js").into(), - ) - .into(), - context, - Value::new(EcmascriptModuleAssetType::Ecmascript), - EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { refresh: false }]), - context.environment(), - ) -} diff --git a/packages/next-swc/crates/next-core/src/server_render/mod.rs b/packages/next-swc/crates/next-core/src/server_render/mod.rs deleted file mode 100644 index 64cdb62cc39ba8..00000000000000 --- a/packages/next-swc/crates/next-core/src/server_render/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod asset; diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 2ce295e993a3ce..ca118ab431ef58 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -1,8 +1,8 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fmt::Write}; -use anyhow::Result; -use serde_json::json; -use turbo_tasks::{primitives::JsonValueVc, Value}; +use anyhow::{anyhow, bail, Result}; +use regex::Regex; +use turbo_tasks::{primitives::RegexVc, Value, ValueToString}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{ @@ -10,21 +10,26 @@ use turbopack::{ transition::TransitionsByNameVc, ModuleAssetContextVc, }; use turbopack_core::{ + asset::AssetVc, chunk::dev::DevChunkingContextVc, context::AssetContextVc, environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, source_asset::SourceAssetVc, target::CompileTargetVc, + virtual_asset::VirtualAssetVc, }; use turbopack_dev_server::source::{ - asset_graph::AssetGraphContentSourceVc, combined::{CombinedContentSource, CombinedContentSourceVc}, ContentSourceVc, NoContentSourceVc, }; -use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; +use turbopack_ecmascript::{ + chunk::EcmascriptChunkPlaceablesVc, EcmascriptInputTransform, EcmascriptInputTransformsVc, + EcmascriptModuleAssetType, EcmascriptModuleAssetVc, +}; use turbopack_env::ProcessEnvAssetVc; use crate::{ + embed_next_file, next_client::{ context::{ get_client_assets_path, get_client_chunking_context, get_client_environment, @@ -34,7 +39,7 @@ use crate::{ NextClientTransition, }, next_import_map::get_next_import_map, - server_render::asset::ServerRenderedAssetVc, + nodejs::node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, }; /// Create a content source serving the `pages` or `src/pages` directory as @@ -127,9 +132,54 @@ pub async fn create_server_rendered_source( .into()) } +/// Converts a filename within the server root to a regular expression with +/// named capture groups for every dynamic segment. +#[turbo_tasks::function] +async fn regular_expression_for_path( + server_root: FileSystemPathVc, + server_path: FileSystemPathVc, +) -> Result { + let server_path_value = &*server_path.await?; + let path = if let Some(path) = server_root.await?.get_path_to(server_path_value) { + path + } else { + bail!( + "server_path ({}) is not in server_root ({})", + server_path.to_string().await?, + server_root.to_string().await? + ) + }; + let (path, _) = path + .rsplit_once('.') + .ok_or_else(|| anyhow!("path ({}) has no extension", path))?; + let path = path.strip_suffix("/index").unwrap_or(path); + let mut reg_exp_source = "^".to_string(); + for segment in path.split('/') { + if reg_exp_source.len() > 1 { + reg_exp_source += "/"; + } + if let Some(segment) = segment.strip_prefix('[') { + if let Some((placeholder, rem)) = segment.split_once(']') { + if let Some(placeholder) = placeholder.strip_prefix("...") { + write!(reg_exp_source, "(?P<{placeholder}>[^?]+)")?; + } else { + write!(reg_exp_source, "(?P<{placeholder}>[^?/]+)")?; + } + reg_exp_source += ®ex::escape(rem); + } else { + bail!("path ({}) contains '[' without matching ']'", path); + } + } else { + reg_exp_source += ®ex::escape(segment); + } + } + reg_exp_source += "$"; + Ok(RegexVc::cell(Regex::new(®_exp_source)?)) +} + /// Handles a single page file in the pages directory #[turbo_tasks::function] -async fn create_server_rendered_source_for_file( +fn create_server_rendered_source_for_file( context_path: FileSystemPathVc, context: AssetContextVc, page_file: FileSystemPathVc, @@ -137,7 +187,7 @@ async fn create_server_rendered_source_for_file( server_root: FileSystemPathVc, server_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, -) -> Result { +) -> ContentSourceVc { let source_asset = SourceAssetVc::new(page_file).into(); let entry_asset = context.process(source_asset); @@ -149,19 +199,19 @@ async fn create_server_rendered_source_for_file( ) .into(); - let asset = ServerRenderedAssetVc::new( - server_path, - context, - entry_asset, - runtime_entries, + create_node_rendered_source( + server_root, + regular_expression_for_path(server_root, server_path), + SsrRenderer { + context, + entry_asset, + } + .cell() + .into(), chunking_context, + runtime_entries, intermediate_output_path, - JsonValueVc::cell(json!({ "props": {} })), - ); - Ok(AssetGraphContentSourceVc::new_lazy( - server_root, - asset.into(), - )) + ) } /// Handles a directory in the pages directory (or the pages directory itself). @@ -196,18 +246,15 @@ async fn create_server_rendered_source_for_directory( intermediate_output_path.join(name), ) }; - sources.push( - create_server_rendered_source_for_file( - context_path, - context, - *file, - runtime_entries, - server_root, - dev_server_path, - intermediate_output_path, - ) - .into(), - ); + sources.push(create_server_rendered_source_for_file( + context_path, + context, + *file, + runtime_entries, + server_root, + dev_server_path, + intermediate_output_path, + )); } _ => {} } @@ -233,3 +280,30 @@ async fn create_server_rendered_source_for_directory( } Ok(CombinedContentSource { sources }.cell()) } + +/// The node.js renderer for SSR of pages. +#[turbo_tasks::value] +struct SsrRenderer { + context: AssetContextVc, + entry_asset: AssetVc, +} + +#[turbo_tasks::value_impl] +impl NodeRenderer for SsrRenderer { + #[turbo_tasks::function] + fn module(&self) -> EcmascriptModuleAssetVc { + EcmascriptModuleAssetVc::new( + VirtualAssetVc::new( + self.entry_asset.path().join("server-renderer.js"), + embed_next_file!("internal/server-renderer.js").into(), + ) + .into(), + self.context, + Value::new(EcmascriptModuleAssetType::Ecmascript), + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::React { + refresh: false, + }]), + self.context.environment(), + ) + } +} From fb1629c54294f182bf391c84b48f09c2025d3a79 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 11 Oct 2022 11:47:43 +0200 Subject: [PATCH 124/672] continue preparations for `.module.css` (vercel/turbo#494) split global css and module css into separate assets --- .../next-swc/crates/next-core/src/next_js/pages/_document.js | 2 +- .../crates/next-core/src/nodejs/node_rendered_source.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js index 740f3b06569ef6..5c42def9bd96c4 100644 --- a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js +++ b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js @@ -15,7 +15,7 @@ export function Head({ children, ...props }) { {children} {styles.map((url) => ( - + ))} {scripts.map((url) => ( diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 41879249f40258..75b1fc77fe81b5 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -150,11 +150,11 @@ impl ContentSource for NodeRenderContentSource { method: data .method .clone() - .ok_or_else(|| anyhow!("method need to be provided"))?, + .ok_or_else(|| anyhow!("method needs to be provided"))?, url: data .url .clone() - .ok_or_else(|| anyhow!("url need to be provided"))?, + .ok_or_else(|| anyhow!("url needs to be provided"))?, query: data.query.clone(), headers: data.headers.clone(), } From 8589c15b954c6c74aa7c6c192bbae7f15bd4d7dd Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 11 Oct 2022 12:23:00 +0200 Subject: [PATCH 125/672] avoid creating too many content sources (vercel/turbo#496) --- .../src/nodejs/node_rendered_source.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 75b1fc77fe81b5..22cba08af8f40d 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -5,7 +5,6 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::chunk::ChunkingContextVc; use turbopack_dev_server::source::{ asset_graph::AssetGraphContentSourceVc, - combined::CombinedContentSource, conditional::ConditionalContentSourceVc, lazy_instatiated::{GetContentSource, GetContentSourceVc, LazyInstantiatedContentSource}, ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, @@ -95,21 +94,17 @@ impl GetContentSource for NodeRenderContentSource { /// Returns the [ContentSource] that the serves all referenced external /// assets. This is wrapped into [LazyInstantiatedContentSource]. #[turbo_tasks::function] - async fn content_source(&self) -> Result { - Ok(CombinedContentSource { - sources: external_asset_entrypoints( + fn content_source(&self) -> ContentSourceVc { + AssetGraphContentSourceVc::new_lazy_multiple( + self.server_root, + external_asset_entrypoints( self.renderer.module(), self.runtime_entries, self.chunking_context, self.intermediate_output_path, - ) - .await? - .iter() - .map(|asset| AssetGraphContentSourceVc::new_lazy(self.server_root, *asset).into()) - .collect(), - } - .cell() - .into()) + ), + ) + .into() } } From d5ed7e394018b1212710bd71ca868f64a6f7fe9e Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 11 Oct 2022 12:23:10 +0200 Subject: [PATCH 126/672] routing bugfixes (vercel/turbo#495) --- .../next-core/src/server_rendered_source.rs | 96 ++++++++++++++++--- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index ca118ab431ef58..04d6344353f62f 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -155,21 +155,80 @@ async fn regular_expression_for_path( let path = path.strip_suffix("/index").unwrap_or(path); let mut reg_exp_source = "^".to_string(); for segment in path.split('/') { - if reg_exp_source.len() > 1 { - reg_exp_source += "/"; + /// Writes regex for handling an optional catch all placeholder. + fn write_optional_catch_all( + reg_exp_source: &mut String, + segment: &str, + include_slash: bool, + path: &str, + ) -> Result<()> { + if let Some((placeholder, rem)) = segment.split_once("]]") { + if include_slash { + write!(*reg_exp_source, "(/?P<{placeholder}>[^?]+)?")?; + } else { + write!(*reg_exp_source, "(?P<{placeholder}>[^?]+)?")?; + } + *reg_exp_source += ®ex::escape(rem); + Ok(()) + } else { + bail!( + "path ({}) contains '[[' without matching ']]' at '[[...{}'", + path, + segment + ); + } } - if let Some(segment) = segment.strip_prefix('[') { + /// Writes regex for handling a required catch all placeholder. + fn write_catch_all(reg_exp_source: &mut String, segment: &str, path: &str) -> Result<()> { if let Some((placeholder, rem)) = segment.split_once(']') { - if let Some(placeholder) = placeholder.strip_prefix("...") { - write!(reg_exp_source, "(?P<{placeholder}>[^?]+)")?; + write!(*reg_exp_source, "(?P<{placeholder}>[^?]+)")?; + *reg_exp_source += ®ex::escape(rem); + Ok(()) + } else { + bail!( + "path ({}) contains '[' without matching ']' at '[...{}'", + path, + segment + ); + } + } + /// Writes regex for handling a normal placeholder. + fn write_dynamic_segment( + reg_exp_source: &mut String, + segment: &str, + path: &str, + ) -> Result<()> { + if let Some((placeholder, rem)) = segment.split_once(']') { + write!(*reg_exp_source, "(?P<{placeholder}>[^?/]+)")?; + *reg_exp_source += ®ex::escape(rem); + Ok(()) + } else { + bail!( + "path ({}) contains '[' without matching ']' at '[{}'", + path, + segment + ); + } + } + + let include_slash = reg_exp_source.len() > 1; + if let Some(segment) = segment.strip_prefix('[') { + if let Some(segment) = segment.strip_prefix("[...") { + write_optional_catch_all(&mut reg_exp_source, segment, include_slash, path)?; + } else { + if include_slash { + reg_exp_source += "/"; + } + if let Some(segment) = segment.strip_prefix("...") { + write_catch_all(&mut reg_exp_source, segment, path)?; } else { - write!(reg_exp_source, "(?P<{placeholder}>[^?/]+)")?; + write_dynamic_segment(&mut reg_exp_source, segment, path)?; } - reg_exp_source += ®ex::escape(rem); - } else { - bail!("path ({}) contains '[' without matching ']'", path); } } else { + if include_slash { + reg_exp_source += "/"; + } reg_exp_source += ®ex::escape(segment); } } @@ -227,9 +286,18 @@ async fn create_server_rendered_source_for_directory( server_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, ) -> Result { - let mut sources = Vec::new(); + let mut predefined_sources = vec![]; + let mut named_placeholder_sources = vec![]; + let mut catch_all_sources = vec![]; if let DirectoryContent::Entries(entries) = &*input_dir.read_dir().await? { for (name, entry) in entries.iter() { + let sources = if name.starts_with("[[") || name.starts_with("[...") { + &mut catch_all_sources + } else if name.starts_with('[') { + &mut named_placeholder_sources + } else { + &mut predefined_sources + }; match entry { DirectoryEntry::File(file) => { if let Some((name, extension)) = name.rsplit_once('.') { @@ -278,7 +346,13 @@ async fn create_server_rendered_source_for_directory( } } } - Ok(CombinedContentSource { sources }.cell()) + let mut ordered_sources = predefined_sources; + ordered_sources.append(&mut named_placeholder_sources); + ordered_sources.append(&mut catch_all_sources); + Ok(CombinedContentSource { + sources: ordered_sources, + } + .cell()) } /// The node.js renderer for SSR of pages. From a28aead85b68f348a5ed3eff259990ef4e0eb9b8 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 12 Oct 2022 11:07:40 +0200 Subject: [PATCH 127/672] use react-refresh-utils bundled with next when available (vercel/turbo#509) --- .../next-core/src/next_client/context.rs | 15 ++-- .../crates/next-core/src/react_refresh.rs | 68 +++++++++++++------ 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 59cdfcf5b56742..511da33aff1517 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -23,7 +23,7 @@ use turbopack_env::ProcessEnvAssetVc; use crate::{ env::filter_for_client, next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, - react_refresh::{assert_can_resolve_react_refresh, react_refresh_request}, + react_refresh::assert_can_resolve_react_refresh, }; #[turbo_tasks::function] @@ -61,7 +61,9 @@ pub async fn get_client_module_options_context( ) -> Result { let resolve_options_context = get_client_resolve_options_context(); let enable_react_refresh = - *assert_can_resolve_react_refresh(project_root, resolve_options_context).await?; + assert_can_resolve_react_refresh(project_root, resolve_options_context) + .await? + .is_found(); Ok(ModuleOptionsContext { // We don't need to resolve React Refresh for each module. Instead, @@ -122,7 +124,9 @@ pub async fn get_client_runtime_entries( ) -> Result { let resolve_options_context = get_client_resolve_options_context(); let enable_react_refresh = - *assert_can_resolve_react_refresh(project_root, resolve_options_context).await?; + assert_can_resolve_react_refresh(project_root, resolve_options_context) + .await? + .as_request(); let mut runtime_entries = vec![ RuntimeEntry::Ecmascript( @@ -131,9 +135,8 @@ pub async fn get_client_runtime_entries( .cell(), RuntimeEntry::Ecmascript(HtmlRuntimeAssetVc::new().into()).cell(), ]; - if enable_react_refresh { - runtime_entries - .push(RuntimeEntry::Request(react_refresh_request(), project_root.join("_")).cell()) + if let Some(request) = enable_react_refresh { + runtime_entries.push(RuntimeEntry::Request(request, project_root.join("_")).cell()) }; Ok(RuntimeEntriesVc::cell(runtime_entries)) diff --git a/packages/next-swc/crates/next-core/src/react_refresh.rs b/packages/next-swc/crates/next-core/src/react_refresh.rs index 6678ee0130b2d4..21b4743359b2df 100644 --- a/packages/next-swc/crates/next-core/src/react_refresh.rs +++ b/packages/next-swc/crates/next-core/src/react_refresh.rs @@ -1,8 +1,5 @@ use anyhow::{anyhow, Result}; -use turbo_tasks::{ - debug::ValueDebug, - primitives::{BoolVc, StringVc}, -}; +use turbo_tasks::{debug::ValueDebug, primitives::StringVc}; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ ecmascript::{ @@ -17,10 +14,36 @@ use turbopack_core::{ }; #[turbo_tasks::function] -pub fn react_refresh_request() -> RequestVc { +fn react_refresh_request() -> RequestVc { RequestVc::parse_string("@next/react-refresh-utils/dist/runtime".to_string()) } +#[turbo_tasks::function] +fn react_refresh_request_in_next() -> RequestVc { + RequestVc::parse_string("next/dist/compiled/@next/react-refresh-utils/dist/runtime".to_string()) +} + +#[turbo_tasks::value] +pub enum AssertReactRefreshResult { + NotFound, + Found(RequestVc), +} + +impl AssertReactRefreshResult { + pub fn as_request(&self) -> Option { + match self { + AssertReactRefreshResult::NotFound => None, + AssertReactRefreshResult::Found(r) => Some(*r), + } + } + pub fn is_found(&self) -> bool { + match self { + AssertReactRefreshResult::NotFound => false, + AssertReactRefreshResult::Found(_) => true, + } + } +} + /// Checks whether we can resolve the React Refresh runtime module from the /// given path. Emits an issue if we can't. /// @@ -30,27 +53,30 @@ pub fn react_refresh_request() -> RequestVc { pub async fn assert_can_resolve_react_refresh( path: FileSystemPathVc, resolve_options_context: ResolveOptionsContextVc, -) -> Result { +) -> Result { let resolve_options = apply_cjs_specific_options(turbopack::resolve_options(path, resolve_options_context)); - let result = turbopack_core::resolve::resolve(path, react_refresh_request(), resolve_options); + for request in [react_refresh_request_in_next(), react_refresh_request()] { + let result = turbopack_core::resolve::resolve(path, request, resolve_options); - Ok(match &*result.await? { - ResolveResult::Single(_, _) | ResolveResult::Alternatives(_, _) => BoolVc::cell(true), - _ => { - ReactRefreshResolvingIssue { - path, - detail: StringVc::cell(format!( - "resolve options: {:?}", - resolve_options.dbg().await? - )), + match &*result.await? { + ResolveResult::Single(_, _) | ResolveResult::Alternatives(_, _) => { + return Ok(AssertReactRefreshResult::Found(request).cell()) } - .cell() - .as_issue() - .emit(); - BoolVc::cell(false) + _ => {} } - }) + } + ReactRefreshResolvingIssue { + path, + detail: StringVc::cell(format!( + "resolve options: {:?}", + resolve_options.dbg().await? + )), + } + .cell() + .as_issue() + .emit(); + Ok(AssertReactRefreshResult::NotFound.cell()) } /// Resolves the React Refresh runtime module from the given [AssetContextVc]. From 1d46acd4d4a766992336bcfe13a6fc142dc55d55 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Wed, 12 Oct 2022 11:46:18 +0200 Subject: [PATCH 128/672] Introduce PathRegex for patch matching with named parameters (vercel/turbo#511) This is another attempt at fixing https://github.com/vercel/turbo-tooling/pull/507. It also handles the root index page properly ("pages/index.js"). --- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../src/nodejs/node_rendered_source.rs | 24 +--- .../crates/next-core/src/path_regex.rs | 127 ++++++++++++++++++ .../next-core/src/server_rendered_source.rs | 106 +++++---------- 4 files changed, 168 insertions(+), 90 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/path_regex.rs diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 5ac39ab9dc43f1..a53d0bd00b3a27 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -6,6 +6,7 @@ pub mod env; pub mod next_client; mod next_import_map; mod nodejs; +mod path_regex; pub mod react_refresh; mod server_rendered_source; mod web_entry_source; diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 22cba08af8f40d..8018d746a13042 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -1,6 +1,5 @@ use anyhow::{anyhow, Result}; use indexmap::IndexMap; -use turbo_tasks::primitives::RegexVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::chunk::ChunkingContextVc; use turbopack_dev_server::source::{ @@ -13,6 +12,7 @@ use turbopack_dev_server::source::{ use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; use super::{external_asset_entrypoints, render_static, RenderData}; +use crate::path_regex::PathRegexVc; /// Trait that allows to get the entry module for rendering something in Node.js #[turbo_tasks::value_trait] @@ -21,7 +21,7 @@ pub trait NodeRenderer { } /// Creates a content source that renders something in Node.js with the passed -/// `renderer` when it matches a `regular_expression`. Once rendered it serves +/// `renderer` when it matches a `path_regex`. Once rendered it serves /// all assets referenced by the `renderer` that are within the `server_root`. /// It needs a temporary directory (`intermediate_output_path`) to place file /// for Node.js execution during rendering. The `chunking_context` should emit @@ -29,7 +29,7 @@ pub trait NodeRenderer { #[turbo_tasks::function] pub fn create_node_rendered_source( server_root: FileSystemPathVc, - regular_expression: RegexVc, + path_regex: PathRegexVc, renderer: NodeRendererVc, chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, @@ -37,7 +37,7 @@ pub fn create_node_rendered_source( ) -> ContentSourceVc { let source = NodeRenderContentSource { server_root, - regular_expression, + path_regex, renderer, chunking_context, runtime_entries, @@ -59,7 +59,7 @@ pub fn create_node_rendered_source( #[turbo_tasks::value] struct NodeRenderContentSource { server_root: FileSystemPathVc, - regular_expression: RegexVc, + path_regex: PathRegexVc, renderer: NodeRendererVc, chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, @@ -69,23 +69,13 @@ struct NodeRenderContentSource { impl NodeRenderContentSource { /// Checks if a path matches the regular expression async fn is_matching_path(&self, path: &str) -> Result { - Ok(self.regular_expression.await?.is_match(path)) + Ok(self.path_regex.await?.is_match(path)) } /// Matches a path with the regular expression and returns a JSON object /// with the named captures async fn get_matches(&self, path: &str) -> Result>> { - let regexp = self.regular_expression.await?; - Ok(regexp.captures(path).map(|capture| { - regexp - .capture_names() - .flatten() - .filter_map(|name| { - let value = capture.name(name)?; - Some((name.to_string(), value.as_str().to_string())) - }) - .collect() - })) + Ok(self.path_regex.await?.get_matches(path)) } } diff --git a/packages/next-swc/crates/next-core/src/path_regex.rs b/packages/next-swc/crates/next-core/src/path_regex.rs new file mode 100644 index 00000000000000..abdcc2c04d6eb1 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/path_regex.rs @@ -0,0 +1,127 @@ +use anyhow::{Context, Result}; +use indexmap::IndexMap; +use turbo_tasks::primitives::Regex; + +/// A regular expression that matches a path, with named capture groups for the +/// dynamic parts of the path. +#[turbo_tasks::value(shared)] +#[derive(Debug)] +pub struct PathRegex { + regex: Regex, + named_params: Vec, +} + +impl PathRegex { + /// Returns true if the given path matches the regular expression. + pub fn is_match(&self, path: &str) -> bool { + self.regex.is_match(path) + } + + /// Matches a path with the regular expression and returns a map with the + /// named captures. + pub fn get_matches(&self, path: &str) -> Option> { + self.regex.captures(path).map(|capture| { + self.named_params + .iter() + .enumerate() + .filter_map(|(idx, name)| { + let value = capture.get(idx + 1)?; + Some((name.to_string(), value.as_str().to_string())) + }) + .collect() + }) + } +} + +/// Builder for [PathRegex]. +pub struct PathRegexBuilder { + regex_str: String, + named_params: Vec, +} + +impl PathRegexBuilder { + /// Creates a new [PathRegexBuilder]. + pub fn new() -> Self { + Self { + regex_str: "^".to_string(), + named_params: Default::default(), + } + } + + fn include_slash(&self) -> bool { + self.regex_str.len() > 1 + } + + fn push_str(&mut self, str: &str) { + self.regex_str.push_str(str); + } + + /// Pushes an optional catch all segment to the regex. + pub fn push_optional_catch_all(&mut self, name: N, rem: R) + where + N: Into, + R: AsRef, + { + self.push_str(if self.include_slash() { + "(/[^?]+)?" + } else { + "([^?]+)?" + }); + self.push_str(®ex::escape(rem.as_ref())); + self.named_params.push(name.into()); + } + + /// Pushes a catch all segment to the regex. + pub fn push_catch_all(&mut self, name: N, rem: R) + where + N: Into, + R: AsRef, + { + if self.include_slash() { + self.push_str("/"); + } + self.push_str("([^?]+)"); + self.push_str(®ex::escape(rem.as_ref())); + self.named_params.push(name.into()); + } + + /// Pushes a dynamic segment to the regex. + pub fn push_dynamic_segment(&mut self, name: N, rem: R) + where + N: Into, + R: AsRef, + { + if self.include_slash() { + self.push_str("/"); + } + self.push_str("([^?/]+)"); + self.push_str(®ex::escape(rem.as_ref())); + self.named_params.push(name.into()); + } + + /// Pushes a static segment to the regex. + pub fn push_static_segment(&mut self, segment: S) + where + S: AsRef, + { + if self.include_slash() { + self.push_str("/"); + } + self.push_str(®ex::escape(segment.as_ref())); + } + + /// Builds and returns the [PathRegex]. + pub fn build(mut self) -> Result { + self.regex_str += "$"; + Ok(PathRegex { + regex: Regex(regex::Regex::new(&self.regex_str).with_context(|| "invalid path regex")?), + named_params: self.named_params, + }) + } +} + +impl Default for PathRegexBuilder { + fn default() -> Self { + Self::new() + } +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 04d6344353f62f..68b954d40af3bc 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -1,8 +1,7 @@ -use std::{collections::HashMap, fmt::Write}; +use std::collections::HashMap; use anyhow::{anyhow, bail, Result}; -use regex::Regex; -use turbo_tasks::{primitives::RegexVc, Value, ValueToString}; +use turbo_tasks::{Value, ValueToString}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{ @@ -40,6 +39,7 @@ use crate::{ }, next_import_map::get_next_import_map, nodejs::node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, + path_regex::{PathRegexBuilder, PathRegexVc}, }; /// Create a content source serving the `pages` or `src/pages` directory as @@ -138,7 +138,7 @@ pub async fn create_server_rendered_source( async fn regular_expression_for_path( server_root: FileSystemPathVc, server_path: FileSystemPathVc, -) -> Result { +) -> Result { let server_path_value = &*server_path.await?; let path = if let Some(path) = server_root.await?.get_path_to(server_path_value) { path @@ -152,56 +152,36 @@ async fn regular_expression_for_path( let (path, _) = path .rsplit_once('.') .ok_or_else(|| anyhow!("path ({}) has no extension", path))?; - let path = path.strip_suffix("/index").unwrap_or(path); - let mut reg_exp_source = "^".to_string(); + let path = if path == "index" { + "" + } else { + path.strip_suffix("/index").unwrap_or(path) + }; + let mut path_regex = PathRegexBuilder::new(); for segment in path.split('/') { - /// Writes regex for handling an optional catch all placeholder. - fn write_optional_catch_all( - reg_exp_source: &mut String, - segment: &str, - include_slash: bool, - path: &str, - ) -> Result<()> { - if let Some((placeholder, rem)) = segment.split_once("]]") { - if include_slash { - write!(*reg_exp_source, "(/?P<{placeholder}>[^?]+)?")?; + if let Some(segment) = segment.strip_prefix('[') { + if let Some(segment) = segment.strip_prefix("[...") { + if let Some((placeholder, rem)) = segment.split_once("]]") { + path_regex.push_optional_catch_all(placeholder, rem); } else { - write!(*reg_exp_source, "(?P<{placeholder}>[^?]+)?")?; + bail!( + "path ({}) contains '[[' without matching ']]' at '[[...{}'", + path, + segment + ); } - *reg_exp_source += ®ex::escape(rem); - Ok(()) - } else { - bail!( - "path ({}) contains '[[' without matching ']]' at '[[...{}'", - path, - segment - ); - } - } - /// Writes regex for handling a required catch all placeholder. - fn write_catch_all(reg_exp_source: &mut String, segment: &str, path: &str) -> Result<()> { - if let Some((placeholder, rem)) = segment.split_once(']') { - write!(*reg_exp_source, "(?P<{placeholder}>[^?]+)")?; - *reg_exp_source += ®ex::escape(rem); - Ok(()) - } else { - bail!( - "path ({}) contains '[' without matching ']' at '[...{}'", - path, - segment - ); - } - } - /// Writes regex for handling a normal placeholder. - fn write_dynamic_segment( - reg_exp_source: &mut String, - segment: &str, - path: &str, - ) -> Result<()> { - if let Some((placeholder, rem)) = segment.split_once(']') { - write!(*reg_exp_source, "(?P<{placeholder}>[^?/]+)")?; - *reg_exp_source += ®ex::escape(rem); - Ok(()) + } else if let Some(segment) = segment.strip_prefix("...") { + if let Some((placeholder, rem)) = segment.split_once(']') { + path_regex.push_catch_all(placeholder, rem); + } else { + bail!( + "path ({}) contains '[' without matching ']' at '[...{}'", + path, + segment + ); + } + } else if let Some((placeholder, rem)) = segment.split_once(']') { + path_regex.push_dynamic_segment(placeholder, rem); } else { bail!( "path ({}) contains '[' without matching ']' at '[{}'", @@ -209,31 +189,11 @@ async fn regular_expression_for_path( segment ); } - } - - let include_slash = reg_exp_source.len() > 1; - if let Some(segment) = segment.strip_prefix('[') { - if let Some(segment) = segment.strip_prefix("[...") { - write_optional_catch_all(&mut reg_exp_source, segment, include_slash, path)?; - } else { - if include_slash { - reg_exp_source += "/"; - } - if let Some(segment) = segment.strip_prefix("...") { - write_catch_all(&mut reg_exp_source, segment, path)?; - } else { - write_dynamic_segment(&mut reg_exp_source, segment, path)?; - } - } } else { - if include_slash { - reg_exp_source += "/"; - } - reg_exp_source += ®ex::escape(segment); + path_regex.push_static_segment(segment); } } - reg_exp_source += "$"; - Ok(RegexVc::cell(Regex::new(®_exp_source)?)) + Ok(PathRegexVc::cell(path_regex.build()?)) } /// Handles a single page file in the pages directory From 0527d3966520c5a45f5fcef3cde8bbc614a8efce Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Wed, 12 Oct 2022 12:18:01 +0200 Subject: [PATCH 129/672] Turn the default Document component into a class component (vercel/turbo#512) Some code in userland can expect Document to be a class, and as such try to extend it. Extending a function will result in an invalid React component, so it must be a class component. e.g. https://nextjs.org/docs/advanced-features/custom-document#typescript --- .../src/next_js/internal/server-renderer.js | 7 ++++- .../next-core/src/next_js/pages/_document.js | 29 ++++++++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js index f12fc2d5ee5775..a6cf79e635dcc8 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js @@ -67,7 +67,12 @@ async function operation(renderData) { const initialProps = await loadGetInitialProps(App, { Component, // TODO(alexkirsz) Pass in `context` - ctx: {}, + ctx: { + // This is necessary for the default Document.getInitialProps to work. + defaultGetInitialProps: async (docCtx, options = {}) => { + return {}; + }, + }, }); const props = { ...initialProps, ...data.props, pageProps: { ...initialProps.pageProps, ...data.props } }; diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js index 5c42def9bd96c4..63b651b4397c3f 100644 --- a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js +++ b/packages/next-swc/crates/next-core/src/next_js/pages/_document.js @@ -8,6 +8,7 @@ export function Html(props) { return ; } +// TODO(alexkirsz) This should be a class component. export function Head({ children, ...props }) { const { styles, scripts } = React.useContext(HtmlContext); @@ -41,6 +42,7 @@ export function htmlEscapeJsonString(str) { return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); } +// TODO(alexkirsz) This should be a class component. export function NextScript() { const { scripts, __NEXT_DATA__ } = React.useContext(HtmlContext); @@ -66,14 +68,21 @@ export function Main() { return ; } -export default function Document() { - return ( - - - -
- - - - ); +// This *must* be a class component, because it can be extended in user code. +export default class Document extends React.Component { + static getInitialProps(ctx) { + return ctx.defaultGetInitialProps(ctx); + } + + render() { + return ( + + + +
+ + + + ); + } } From 4760f0dbfd68e9ce787293a5d3b0a2f91592ef28 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 13 Oct 2022 16:38:49 +0200 Subject: [PATCH 130/672] improve startup error messages (vercel/turbo#524) --- packages/next-swc/crates/next-dev/src/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 272d16ddbfab18..06fdc77bca3d89 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -74,16 +74,17 @@ async fn main() -> Result<()> { let dir = args .dir .map(|dir| dir.canonicalize()) - .unwrap_or_else(current_dir)? + .unwrap_or_else(current_dir) + .context("project directory can't be found")? .to_str() - .context("current directory contains invalid characters")? + .context("project directory contains invalid characters")? .to_string(); let root_dir = if let Some(root) = args.root { root.canonicalize() - .unwrap() + .context("root directory can't be found")? .to_str() - .context("current directory contains invalid characters")? + .context("root directory contains invalid characters")? .to_string() } else { dir.clone() From 79ea25f4915b526b4887c10c30ba13c4c7295310 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 13 Oct 2022 15:50:01 +0200 Subject: [PATCH 131/672] make less things to rely on HashSet and HashMap order --- .../crates/next-core/src/nodejs/mod.rs | 8 ++- .../next-core/src/server_rendered_source.rs | 61 +++++++++++-------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 9aef96418ecdf3..aa538b41f64c1c 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -5,7 +5,7 @@ use std::{ use anyhow::{anyhow, Result}; use futures::{stream::FuturesUnordered, TryStreamExt}; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use mime::TEXT_HTML_UTF_8; pub use node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}; use serde_json::Value as JsonValue; @@ -125,8 +125,10 @@ async fn separate_assets( }; queue.push(process_asset(intermediate_asset)); let mut processed = HashSet::new(); - let mut internal_assets = HashSet::new(); - let mut external_asset_entrypoints = HashSet::new(); + let mut internal_assets = IndexSet::new(); + let mut external_asset_entrypoints = IndexSet::new(); + // TODO(sokra) This is not deterministic, since it's using FuturesUnordered. + // This need to be fixed! while let Some(item) = queue.try_next().await? { match item { Type::Internal(asset, assets) => { diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 68b954d40af3bc..fab02aff708948 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -249,7 +249,8 @@ async fn create_server_rendered_source_for_directory( let mut predefined_sources = vec![]; let mut named_placeholder_sources = vec![]; let mut catch_all_sources = vec![]; - if let DirectoryContent::Entries(entries) = &*input_dir.read_dir().await? { + let dir_content = input_dir.read_dir().await?; + if let DirectoryContent::Entries(entries) = &*dir_content { for (name, entry) in entries.iter() { let sources = if name.starts_with("[[") || name.starts_with("[...") { &mut catch_all_sources @@ -260,28 +261,31 @@ async fn create_server_rendered_source_for_directory( }; match entry { DirectoryEntry::File(file) => { - if let Some((name, extension)) = name.rsplit_once('.') { + if let Some((basename, extension)) = name.rsplit_once('.') { match extension { // pageExtensions option from next.js // defaults: https://github.com/vercel/next.js/blob/611e13f5159457fedf96d850845650616a1f75dd/packages/next/server/config-shared.ts#L499 "js" | "ts" | "jsx" | "tsx" => { - let (dev_server_path, intermediate_output_path) = if name == "index" - { - (server_path.join("index.html"), intermediate_output_path) - } else { - ( - server_path.join(name).join("index.html"), - intermediate_output_path.join(name), - ) - }; - sources.push(create_server_rendered_source_for_file( - context_path, - context, - *file, - runtime_entries, - server_root, - dev_server_path, - intermediate_output_path, + let (dev_server_path, intermediate_output_path) = + if basename == "index" { + (server_path.join("index.html"), intermediate_output_path) + } else { + ( + server_path.join(basename).join("index.html"), + intermediate_output_path.join(basename), + ) + }; + sources.push(( + name, + create_server_rendered_source_for_file( + context_path, + context, + *file, + runtime_entries, + server_root, + dev_server_path, + intermediate_output_path, + ), )); } _ => {} @@ -289,7 +293,8 @@ async fn create_server_rendered_source_for_directory( } } DirectoryEntry::Directory(dir) => { - sources.push( + sources.push(( + name, create_server_rendered_source_for_directory( context_path, context, @@ -300,17 +305,23 @@ async fn create_server_rendered_source_for_directory( intermediate_output_path.join(name), ) .into(), - ); + )); } _ => {} } } } - let mut ordered_sources = predefined_sources; - ordered_sources.append(&mut named_placeholder_sources); - ordered_sources.append(&mut catch_all_sources); + predefined_sources.sort_by_key(|(k, _)| *k); + named_placeholder_sources.sort_by_key(|(k, _)| *k); + catch_all_sources.sort_by_key(|(k, _)| *k); + Ok(CombinedContentSource { - sources: ordered_sources, + sources: predefined_sources + .into_iter() + .chain(named_placeholder_sources.into_iter()) + .chain(catch_all_sources.into_iter()) + .map(|(_, v)| v) + .collect(), } .cell()) } From 8cab8aa1d6326a7b0b63828d7bc557384e519360 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 14 Oct 2022 00:45:39 +0200 Subject: [PATCH 132/672] windows needs magic SystemRoot env var to allow to make http requests from node.js (vercel/turbo#22) --- packages/next-swc/crates/next-core/src/nodejs/pool.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index 2689736e897ec8..a5081f077b07c9 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -38,6 +38,11 @@ impl NodeJsPoolProcess { "PATH", std::env::var("PATH").expect("PATH should always be set"), ); + #[cfg(target_family = "windows")] + cmd.env( + "SystemRoot", + std::env::var("SystemRoot").expect("SystemRoot should always be set"), + ); cmd.envs(env); cmd.stdin(Stdio::piped()); cmd.stdout(Stdio::piped()); From 280e90913102024bef9638cd9c6d94ef4a7856bc Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 14 Oct 2022 17:52:59 +0200 Subject: [PATCH 133/672] Deduplicate issues for logging (vercel/turbo#27) see https://github.com/vercel/turbo-tooling/pull/523 Co-authored-by: Justin Ridgewell --- packages/next-swc/crates/next-dev/src/lib.rs | 54 +++++++++----------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 11b2d757266a2c..67a5ea79fccfe6 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -5,14 +5,11 @@ use std::{env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; use next_core::{create_server_rendered_source, create_web_entry_source, env::load_env}; -use turbo_tasks::{CollectiblesSource, TransientInstance, TurboTasks, Value}; +use turbo_tasks::{RawVc, TransientInstance, TransientValue, TurboTasks, Value}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; -use turbopack_cli_utils::issue::{group_and_display_issues, LogOptions, LogOptionsVc}; -use turbopack_core::{ - issue::{IssueSeverity, IssueVc}, - resolve::parse::RequestVc, -}; +use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; +use turbopack_core::{issue::IssueSeverity, resolve::parse::RequestVc}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, source::{combined::CombinedContentSource, router::RouterContentSource, ContentSourceVc}, @@ -108,13 +105,14 @@ impl NextDevServerBuilder { let show_all = self.show_all; let log_detail = self.log_detail; let browserslist_query = self.browserslist_query; - let log_options = Arc::new(LogOptions { + let log_options = LogOptions { current_dir: current_dir().unwrap(), show_all, log_detail, log_level: self.log_level, - }); - let log_options_to_dev_server = log_options.clone(); + }; + let console_ui = Arc::new(ConsoleUi::new(log_options)); + let console_ui_to_dev_server = console_ui.clone(); let server = DevServer::listen( turbo_tasks.clone(), @@ -125,7 +123,7 @@ impl NextDevServerBuilder { entry_requests.clone(), eager_compile, turbo_tasks.clone().into(), - log_options.clone().into(), + console_ui.clone().into(), browserslist_query.clone(), ) }, @@ -134,21 +132,19 @@ impl NextDevServerBuilder { self.port.context("port must be set")?, ) .into(), - log_options_to_dev_server, + console_ui_to_dev_server, ); Ok(server) } } -async fn handle_issues( - source: T, - options: LogOptionsVc, -) -> Result<()> { - let issues = IssueVc::peek_issues_with_path(source).await?; - let fatal = *group_and_display_issues(options, issues).await?; +async fn handle_issues>(source: T, console_ui: ConsoleUiVc) -> Result<()> { + let state = console_ui + .group_and_display_issues(TransientValue::new(source.into())) + .await?; - if fatal { + if state.has_fatal { Err(anyhow!("Fatal issue(s) occurred")) } else { Ok(()) @@ -156,20 +152,20 @@ async fn handle_issues( } #[turbo_tasks::function] -async fn project_fs(project_dir: &str, log_options: LogOptionsVc) -> Result { +async fn project_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result { let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir.to_string()); - handle_issues(disk_fs, log_options).await?; + handle_issues(disk_fs, console_ui).await?; disk_fs.await?.start_watching()?; Ok(disk_fs.into()) } #[turbo_tasks::function] -async fn output_fs(project_dir: &str, log_options: LogOptionsVc) -> Result { +async fn output_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result { let disk_fs = DiskFileSystemVc::new( "output".to_string(), format!("{project_dir}{s}.next{s}server", s = MAIN_SEPARATOR), ); - handle_issues(disk_fs, log_options).await?; + handle_issues(disk_fs, console_ui).await?; disk_fs.await?.start_watching()?; Ok(disk_fs.into()) } @@ -181,12 +177,12 @@ async fn source( entry_requests: Vec, eager_compile: bool, turbo_tasks: TransientInstance>, - log_options: TransientInstance, + console_ui: TransientInstance, browserslist_query: String, ) -> Result { - let log_options = (*log_options).clone().cell(); - let output_fs = output_fs(&project_dir, log_options); - let fs = project_fs(&root_dir, log_options); + let console_ui = (*console_ui).clone().cell(); + let output_fs = output_fs(&project_dir, console_ui); + let fs = project_fs(&root_dir, console_ui); let project_relative = project_dir.strip_prefix(&root_dir).unwrap(); let project_relative = project_relative .strip_prefix(MAIN_SEPARATOR) @@ -231,9 +227,9 @@ async fn source( .cell() .into(); - handle_issues(dev_server_fs, log_options).await?; - handle_issues(web_source, log_options).await?; - handle_issues(rendered_source, log_options).await?; + handle_issues(dev_server_fs, console_ui).await?; + handle_issues(web_source, console_ui).await?; + handle_issues(rendered_source, console_ui).await?; Ok(source) } From 003a1ed013b3b946b5c332e48ce4213a40fd1bea Mon Sep 17 00:00:00 2001 From: Leah Date: Sat, 15 Oct 2022 18:40:02 +0200 Subject: [PATCH 134/672] add `FileSystem::root()` function to replace `FileSystemPathVc::new(fs, path)` (vercel/turbo#34) transferred from https://github.com/vercel/turbo-tooling/pull/518 --- packages/next-swc/crates/next-dev/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 67a5ea79fccfe6..9122c84886d4b4 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -6,7 +6,7 @@ use std::{env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; use next_core::{create_server_rendered_source, create_web_entry_source, env::load_env}; use turbo_tasks::{RawVc, TransientInstance, TransientValue, TurboTasks, Value}; -use turbo_tasks_fs::{DiskFileSystemVc, FileSystemPathVc, FileSystemVc}; +use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; use turbopack_core::{issue::IssueSeverity, resolve::parse::RequestVc}; @@ -187,12 +187,12 @@ async fn source( let project_relative = project_relative .strip_prefix(MAIN_SEPARATOR) .unwrap_or(project_relative); - let project_path = FileSystemPathVc::new(fs, project_relative); + let project_path = fs.root().join(project_relative); let env = load_env(project_path); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); - let dev_server_root = FileSystemPathVc::new(dev_server_fs, ""); + let dev_server_root = dev_server_fs.root(); let web_source = create_web_entry_source( project_path, entry_requests @@ -206,7 +206,7 @@ async fn source( ); let rendered_source = create_server_rendered_source( project_path, - FileSystemPathVc::new(output_fs, ""), + output_fs.root(), dev_server_root, env, &browserslist_query, From f39152cef642fc4e8be673babf8e290ce532a6d1 Mon Sep 17 00:00:00 2001 From: Leah Date: Sat, 15 Oct 2022 18:42:14 +0200 Subject: [PATCH 135/672] add `From` impl for `File` (vercel/turbo#35) transferred from https://github.com/vercel/turbo-tooling/pull/519 --- .../crates/next-core/src/nodejs/bootstrap.rs | 4 ++-- .../next-swc/crates/next-core/src/nodejs/mod.rs | 9 ++++----- .../next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 13 ++++--------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs b/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs index 420994aa831bfd..cecfa962e4c65c 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs @@ -1,7 +1,7 @@ use std::fmt::Write; use anyhow::Result; -use turbo_tasks_fs::{File, FileContent, FileSystemPathVc}; +use turbo_tasks_fs::{File, FileSystemPathVc}; use turbopack::ecmascript::utils::stringify_str; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc}, @@ -39,7 +39,7 @@ impl Asset for NodeJsBootstrapAsset { } } - Ok(FileContent::Content(File::from_source(output)).into()) + Ok(File::from(output).into()) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index aa538b41f64c1c..adb38e03d86953 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -10,7 +10,7 @@ use mime::TEXT_HTML_UTF_8; pub use node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}; use serde_json::Value as JsonValue; use turbo_tasks::{primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc}; -use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; +use turbo_tasks_fs::{DiskFileSystemVc, File, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ asset::{AssetContentVc, AssetVc, AssetsSetVc}, @@ -207,10 +207,9 @@ async fn render_static( data: RenderDataVc, ) -> Result { fn into_result(content: String) -> Result { - Ok( - FileContent::Content(File::from_source(content).with_content_type(TEXT_HTML_UTF_8)) - .into(), - ) + Ok(File::from(content) + .with_content_type(TEXT_HTML_UTF_8) + .into()) } let renderer_pool = get_renderer_pool( get_intermediate_asset( diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index e2fbecc7fb69d3..29ffcb3435c252 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -3,12 +3,12 @@ use std::{str::FromStr, sync::Arc, time::Duration}; use anyhow::Result; use mime::Mime; use turbo_tasks::{get_invalidator, TurboTasks, Value}; -use turbo_tasks_fs::{File, FileContent}; +use turbo_tasks_fs::File; use turbo_tasks_memory::{ stats::{ReferenceType, Stats}, viz, MemoryBackend, }; -use turbopack_core::asset::AssetContent; +use turbopack_core::asset::AssetContentVc; use turbopack_dev_server::source::{ ContentSource, ContentSourceData, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, }; @@ -80,13 +80,8 @@ impl ContentSource for TurboTasksSource { _ => return Ok(ContentSourceResult::NotFound.cell()), }; Ok(ContentSourceResult::Static( - AssetContent::File( - FileContent::Content( - File::from_source(html).with_content_type(Mime::from_str("text/html")?), - ) - .cell(), - ) - .into(), + AssetContentVc::from(File::from(html).with_content_type(Mime::from_str("text/html")?)) + .into(), ) .cell()) } From cabb72fa53d395e6fbf2ef252d33e6e31e408d9a Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Sun, 16 Oct 2022 10:39:18 +0200 Subject: [PATCH 136/672] avoid emitting source maps for node.js (vercel/turbo#30) --- .../next-swc/crates/next-core/src/nodejs/mod.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index adb38e03d86953..044d2f211e45e9 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -9,7 +9,9 @@ use indexmap::{IndexMap, IndexSet}; use mime::TEXT_HTML_UTF_8; pub use node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}; use serde_json::Value as JsonValue; -use turbo_tasks::{primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc}; +use turbo_tasks::{ + primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, TryJoinIterExt, +}; use turbo_tasks_fs::{DiskFileSystemVc, File, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ @@ -39,7 +41,17 @@ async fn emit( internal_assets(intermediate_asset, intermediate_output_path) .await? .iter() - .map(|a| a.content().write(a.path())) + .map(|a| async { + Ok(if *a.path().extension().await? != "map" { + Some(a.content().write(a.path())) + } else { + None + }) + }) + .try_join() + .await? + .into_iter() + .flatten() .collect(), ) .all()) From 3c821767ce99df152237af7c40b0a55fd51a3dfe Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 17 Oct 2022 08:36:30 +0200 Subject: [PATCH 137/672] use browser field for the browser (vercel/turbo#26) add module field --- .../next-swc/crates/next-core/src/next_client/context.rs | 2 ++ packages/next-swc/crates/next-core/src/next_client/mod.rs | 8 ++++++++ .../crates/next-core/src/server_rendered_source.rs | 1 + 3 files changed, 11 insertions(+) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 511da33aff1517..3227140592b1d7 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -49,6 +49,8 @@ pub fn get_client_resolve_options_context() -> ResolveOptionsContextVc { enable_react: true, enable_node_modules: true, custom_conditions: vec!["development".to_string()], + browser: true, + module: true, ..Default::default() } .cell() diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 56c9390216c3b1..c5b0408203007e 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -58,6 +58,14 @@ impl Transition for NextClientTransition { self.client_module_options_context } + #[turbo_tasks::function] + fn process_resolve_options_context( + &self, + _context: ResolveOptionsContextVc, + ) -> ResolveOptionsContextVc { + self.client_resolve_options_context + } + #[turbo_tasks::function] async fn process_module( &self, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index fab02aff708948..3ab835d11c28b1 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -111,6 +111,7 @@ pub async fn create_server_rendered_source( enable_node_native_modules: true, custom_conditions: vec!["development".to_string()], import_map: Some(next_import_map), + module: true, ..Default::default() } .cell(), From 2f3edac20c481dc9d64ed93b5fd112ad67796efa Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 17 Oct 2022 17:19:29 +0200 Subject: [PATCH 138/672] add introspection for assets and content sources (vercel/turbo#47) add very simple explorer to introspect the graph via `/__turbopack__/` Allows to "walk" through the content sources and asset graph. Some assets allows to access inner assets, e. g. from the ecmascript chunk you can access the entry module asset, so you can go a level deeper. It works by a `Introspectable` trait which can be implemented by anything we want to allow the user to inspect. In future the in browser UI should offer a nice UI to explore your application. In future we probably also want to add some `metrics` to the `Introspectable` trait, e. g. to report size of an asset. This UI is very basic currently, but that works for debugging: ![image](https://user-images.githubusercontent.com/1365881/196007862-2fb2a0e9-19ba-45c5-8a82-926418e0d479.png) --- .../crates/next-core/src/nodejs/mod.rs | 2 +- .../src/nodejs/node_rendered_source.rs | 49 ++++++++++++++++++- .../crates/next-core/src/path_regex.rs | 13 ++++- packages/next-swc/crates/next-dev/src/lib.rs | 23 ++++++--- 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 044d2f211e45e9..158e0ed349ec5f 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -183,7 +183,7 @@ async fn get_renderer_pool( /// Converts a module graph into node.js executable assets #[turbo_tasks::function] -async fn get_intermediate_asset( +pub async fn get_intermediate_asset( entry_module: EcmascriptModuleAssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, chunking_context: ChunkingContextVc, diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 8018d746a13042..b281abd8172b56 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -1,7 +1,15 @@ +use std::collections::HashSet; + use anyhow::{anyhow, Result}; use indexmap::IndexMap; +use turbo_tasks::{primitives::StringVc, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::chunk::ChunkingContextVc; +use turbopack_core::{ + chunk::ChunkingContextVc, + introspect::{ + asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, + }, +}; use turbopack_dev_server::source::{ asset_graph::AssetGraphContentSourceVc, conditional::ConditionalContentSourceVc, @@ -11,7 +19,7 @@ use turbopack_dev_server::source::{ }; use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; -use super::{external_asset_entrypoints, render_static, RenderData}; +use super::{external_asset_entrypoints, get_intermediate_asset, render_static, RenderData}; use crate::path_regex::PathRegexVc; /// Trait that allows to get the entry module for rendering something in Node.js @@ -159,3 +167,40 @@ impl ContentSource for NodeRenderContentSource { ContentSourceResult::NotFound.cell() } } + +#[turbo_tasks::function] +fn introspectable_type() -> StringVc { + StringVc::cell("node render content source".to_string()) +} + +#[turbo_tasks::value_impl] +impl Introspectable for NodeRenderContentSource { + #[turbo_tasks::function] + fn ty(&self) -> StringVc { + introspectable_type() + } + + #[turbo_tasks::function] + fn title(&self) -> StringVc { + self.path_regex.to_string() + } + + #[turbo_tasks::function] + fn children(&self) -> IntrospectableChildrenVc { + IntrospectableChildrenVc::cell(HashSet::from([ + ( + StringVc::cell("module".to_string()), + IntrospectableAssetVc::new(self.renderer.module().into()), + ), + ( + StringVc::cell("intermediate asset".to_string()), + IntrospectableAssetVc::new(get_intermediate_asset( + self.renderer.module(), + self.runtime_entries, + self.chunking_context, + self.intermediate_output_path, + )), + ), + ])) + } +} diff --git a/packages/next-swc/crates/next-core/src/path_regex.rs b/packages/next-swc/crates/next-core/src/path_regex.rs index abdcc2c04d6eb1..53dccb11b985c4 100644 --- a/packages/next-swc/crates/next-core/src/path_regex.rs +++ b/packages/next-swc/crates/next-core/src/path_regex.rs @@ -1,6 +1,9 @@ use anyhow::{Context, Result}; use indexmap::IndexMap; -use turbo_tasks::primitives::Regex; +use turbo_tasks::{ + primitives::{Regex, StringVc}, + ValueToString, ValueToStringVc, +}; /// A regular expression that matches a path, with named capture groups for the /// dynamic parts of the path. @@ -33,6 +36,14 @@ impl PathRegex { } } +#[turbo_tasks::value_impl] +impl ValueToString for PathRegex { + #[turbo_tasks::function] + fn to_string(&self) -> StringVc { + StringVc::cell(self.regex.as_str().to_string()) + } +} + /// Builder for [PathRegex]. pub struct PathRegexBuilder { regex_str: String, diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 9122c84886d4b4..f2588bc105cee5 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -1,7 +1,7 @@ #![feature(future_join)] #![feature(min_specialization)] -use std::{env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; +use std::{collections::HashSet, env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; use next_core::{create_server_rendered_source, create_web_entry_source, env::load_env}; @@ -12,6 +12,7 @@ use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; use turbopack_core::{issue::IssueSeverity, resolve::parse::RequestVc}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, + introspect::IntrospectionSource, source::{combined::CombinedContentSource, router::RouterContentSource, ContentSourceVc}, DevServer, }; @@ -216,13 +217,21 @@ async fn source( } .cell() .into(); + let main_source = CombinedContentSource { + sources: vec![rendered_source, web_source], + } + .cell(); + let introspect = IntrospectionSource { + roots: HashSet::from([main_source.into()]), + } + .cell() + .into(); let source = RouterContentSource { - routes: vec![("__turbo_tasks__/".to_string(), viz)], - fallback: CombinedContentSource { - sources: vec![rendered_source, web_source], - } - .cell() - .into(), + routes: vec![ + ("__turbopack__/".to_string(), introspect), + ("__turbo_tasks__/".to_string(), viz), + ], + fallback: main_source.into(), } .cell() .into(); From 44c2e1f5708ec04e3b1763327bbe7cdeb71176b0 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 17 Oct 2022 19:54:19 +0200 Subject: [PATCH 139/672] Optimize Next.js SSR (vercel/turbo#48) This PR also includes the changes in vercel/turbo#12 This optimizes Next.js SSR by marking `react[/*]` and `next[/*]` imports as externals in Node.js, which means that they will be `require`d directly instead of bundled. This optimization reduces the number of modules to analyze on the server for a single component app from ~1000 (Next.js SSR imports a lot of modules, including amp-optimizer which includes more) to <10. Co-authored-by: Tobias Koppers --- .../crates/next-core/src/next_client/mod.rs | 2 +- .../crates/next-core/src/next_import_map.rs | 119 ++++---- .../src/next_js/internal/html-context.js | 6 - .../src/next_js/internal/next-hydrate.js | 28 +- .../src/next_js/internal/server-renderer.js | 263 +++++++++++++----- .../src/next_js/internal/shared-utils.js | 15 - .../next-core/src/next_js/internal/shims.js | 17 ++ .../crates/next-core/src/nodejs/mod.rs | 1 + .../src/nodejs/node_rendered_source.rs | 75 +++-- .../next-core/src/server_rendered_source.rs | 9 +- .../next-dev/benches/bundlers/turbopack.rs | 3 +- 11 files changed, 350 insertions(+), 188 deletions(-) delete mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/html-context.js delete mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js create mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/shims.js diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index c5b0408203007e..38e579058672ae 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -82,7 +82,7 @@ impl Transition for NextClientTransition { let asset = ChunkGroupFilesAsset { asset: chunkable_asset, chunking_context: self.client_chunking_context, - base_path: self.server_root, + base_path: self.server_root.join("_next"), runtime_entries: Some(runtime_entries), }; diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index a27e1ba73a4cfe..80b8a233ee3e35 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -10,79 +10,87 @@ use turbopack_core::{ use crate::embed_next_file; -/// Aliases [next_pages_app] to either an existing `pages/_app` asset, or a -/// default asset. +/// Computes the Next-specific client import map. #[turbo_tasks::function] -pub fn get_next_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { +pub fn get_next_client_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { let mut import_map = ImportMap::empty(); - let pages_app_asset_import_mapping = asset_to_import_mapping( - VirtualAssetVc::new( - // TODO(alexkirsz) We should make sure these paths are unique, - // otherwise we can run into conflicts with - // user paths. - pages_dir.root().join("next_js/pages/_app.js"), - embed_next_file!("pages/_app.js").into(), - ) - .into(), - ); - let pages_document_asset_import_mapping = asset_to_import_mapping( - VirtualAssetVc::new( - pages_dir.root().join("next_js/pages/_document.js"), - embed_next_file!("pages/_document.js").into(), - ) - .into(), - ); - let internal_html_context_import_mapping = asset_to_import_mapping( - VirtualAssetVc::new( - pages_dir.root().join("next_js/internal/html-context.js"), - embed_next_file!("internal/html-context.js").into(), - ) - .into(), - ); - let internal_shared_utils_import_mapping = asset_to_import_mapping( - VirtualAssetVc::new( - pages_dir.root().join("next_js/internal/shared-utils.js"), - embed_next_file!("internal/shared-utils.js").into(), - ) - .into(), - ); + insert_next_shared_aliases(&mut import_map, pages_dir); insert_alias_to_alternatives( &mut import_map, "@vercel/turbopack-next/pages/_app", request_to_import_mapping(pages_dir, "./_app"), - pages_app_asset_import_mapping, + request_to_import_mapping(pages_dir, "next/app"), ); insert_alias_to_alternatives( &mut import_map, "@vercel/turbopack-next/pages/_document", request_to_import_mapping(pages_dir, "./_document"), - pages_document_asset_import_mapping, + request_to_import_mapping(pages_dir, "next/document"), ); - insert_alias( + import_map.cell() +} + +/// Computes the Next-specific server-side import map. +#[turbo_tasks::function] +pub fn get_next_server_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { + let mut import_map = ImportMap::empty(); + + insert_next_shared_aliases(&mut import_map, pages_dir); + + insert_alias_to_alternatives( &mut import_map, - "@vercel/turbopack-next/internal/html-context", - internal_html_context_import_mapping, + "@vercel/turbopack-next/pages/_app", + request_to_import_mapping(pages_dir, "./_app"), + external_request_to_import_mapping("next/app"), ); - insert_alias( + insert_alias_to_alternatives( &mut import_map, - "@vercel/turbopack-next/internal/shared-utils", - internal_shared_utils_import_mapping, + "@vercel/turbopack-next/pages/_document", + request_to_import_mapping(pages_dir, "./_document"), + external_request_to_import_mapping("next/document"), ); - insert_alias(&mut import_map, "next/app", pages_app_asset_import_mapping); - insert_alias( - &mut import_map, - "next/document", - pages_document_asset_import_mapping, + + import_map.insert_alias( + AliasPattern::exact("next"), + ImportMapping::External(None).into(), + ); + import_map.insert_alias( + AliasPattern::wildcard("next/", ""), + ImportMapping::External(None).into(), + ); + import_map.insert_alias( + AliasPattern::exact("react"), + ImportMapping::External(None).into(), + ); + import_map.insert_alias( + AliasPattern::wildcard("react/", ""), + ImportMapping::External(None).into(), ); import_map.cell() } +fn insert_next_shared_aliases(import_map: &mut ImportMap, pages_dir: FileSystemPathVc) { + import_map.insert_alias( + AliasPattern::exact("@vercel/turbopack-next/internal/shims"), + asset_to_import_mapping(get_internal_shims_asset(pages_dir)), + ); +} + +#[turbo_tasks::function] +fn get_internal_shims_asset(pages_dir: FileSystemPathVc) -> AssetVc { + VirtualAssetVc::new( + pages_dir.root().join("next_js/internal/shims.js"), + embed_next_file!("internal/shims.js").into(), + ) + .into() +} + /// Inserts an alias to an alternative of import mappings into an import map. -pub fn insert_alias_to_alternatives( +fn insert_alias_to_alternatives( import_map: &mut ImportMap, alias: &str, alt1: ImportMappingVc, @@ -94,18 +102,19 @@ pub fn insert_alias_to_alternatives( ); } -/// Inserts an alias to an import mapping into an import map. -pub fn insert_alias(import_map: &mut ImportMap, alias: &str, mapping: ImportMappingVc) { - import_map.insert_alias(AliasPattern::Exact(alias.to_string()), mapping); -} - /// Creates a direct import mapping to the result of resolving a request /// in a context. -pub fn request_to_import_mapping(context_path: FileSystemPathVc, request: &str) -> ImportMappingVc { +fn request_to_import_mapping(context_path: FileSystemPathVc, request: &str) -> ImportMappingVc { ImportMapping::PrimaryAlternative(request.to_string(), Some(context_path)).into() } +/// Creates a direct import mapping to the result of resolving an external +/// request. +fn external_request_to_import_mapping(request: &str) -> ImportMappingVc { + ImportMapping::External(Some(request.to_string())).into() +} + /// Creates a direct import mapping to a single asset. -pub fn asset_to_import_mapping(asset: AssetVc) -> ImportMappingVc { +fn asset_to_import_mapping(asset: AssetVc) -> ImportMappingVc { ImportMapping::Direct(ResolveResult::Single(asset, vec![]).into()).into() } diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/html-context.js b/packages/next-swc/crates/next-core/src/next_js/internal/html-context.js deleted file mode 100644 index 7197e6fce47c86..00000000000000 --- a/packages/next-swc/crates/next-core/src/next_js/internal/html-context.js +++ /dev/null @@ -1,6 +0,0 @@ -// This is a Next-internal file that must not be exposed to end-users. -// Adapted from https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/html-context.ts - -import { createContext } from "react"; - -export const HtmlContext = createContext(null); diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js index a6f0eef958dc6d..98f9da45f3f4cc 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js @@ -1,6 +1,24 @@ -import App from "@vercel/turbopack-next/pages/_app"; -import Component from "."; -import { hydrateRoot } from "react-dom/client"; +import "@vercel/turbopack-next/internal/shims"; +import { initialize, hydrate } from "next/dist/client"; +import * as _app from "@vercel/turbopack-next/pages/_app"; +import * as page from "."; -const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); -hydrateRoot(document.getElementById("__next"), ); +(async () => { + console.debug("Initializing Next.js"); + + await initialize({ + webpackHMR: { + // Expected when `process.env.NODE_ENV === 'development'` + onUnrecoverableError() {}, + }, + }); + + __NEXT_P.push(["/_app", () => _app]); + __NEXT_P.push([window.__NEXT_DATA__.page, () => page]); + + console.debug("Hydrating the page"); + + await hydrate(); + + console.debug("The page has been hydrated"); +})().catch((err) => console.error(err)); diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js index a6cf79e635dcc8..83eb6392c3d15f 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js +++ b/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js @@ -1,11 +1,9 @@ const END_OF_OPERATION = process.argv[2]; +import { renderToHTML } from "next/dist/server/render"; import App from "@vercel/turbopack-next/pages/_app"; import Document from "@vercel/turbopack-next/pages/_document"; -import { HtmlContext } from "@vercel/turbopack-next/internal/html-context"; -import { loadGetInitialProps } from "@vercel/turbopack-next/internal/shared-utils"; import Component, * as otherExports from "."; -import { renderToString, renderToStaticMarkup } from "react-dom/server"; ("TURBOPACK { transition: next-client }"); import chunkGroup from "."; @@ -32,84 +30,207 @@ process.stdin.on("data", async (data) => { buffer.push(data); }); -const DOCTYPE = ""; +/** + * Shim for Node.js's http.ServerResponse + */ +class ServerResponse { + headersSent = false; + #headers = new Map(); -function Body({ children }) { - return
{children}
; + constructor(req) { + this.req = req; + } + + setHeader(name, value) { + this.#headers.set(name.toLowerCase(), value); + return this; + } + + getHeader(name) { + return this.#headers.get(name.toLowerCase()); + } + + getHeaderNames() { + return Array.from(this.#headers.keys()); + } + + getHeaders() { + return Object.fromEntries(this.#headers); + } + + hasHeader(name) { + return this.#headers.has(name.toLowerCase()); + } + + removeHeader(name) { + this.#headers.delete(name.toLowerCase()); + } + + get statusCode() { + throw new Error("statusCode is not implemented"); + } + + set statusCode(code) { + throw new Error("set statusCode is not implemented"); + } + + get statusMessage() { + throw new Error("statusMessage is not implemented"); + } + + set statusMessage(message) { + throw new Error("set statusMessage is not implemented"); + } + + get socket() { + throw new Error("socket is not implemented"); + } + + get sendDate() { + throw new Error("sendDate is not implemented"); + } + + flushHeaders() { + throw new Error("flushHeaders is not implemented"); + } + + end() { + throw new Error("end is not implemented"); + } + + cork() { + throw new Error("cork is not implemented"); + } + + uncork() { + throw new Error("uncork is not implemented"); + } + + addTrailers() { + throw new Error("addTrailers is not implemented"); + } + + setTimeout(_msecs, _callback) { + throw new Error("setTimeout is not implemented"); + } + + get writableEnded() { + throw new Error("writableEnded is not implemented"); + } + + get writableFinished() { + throw new Error("writableFinished is not implemented"); + } + + write(_chunk, _encoding, _callback) { + throw new Error("write is not implemented"); + } + + writeContinue() { + throw new Error("writeContinue is not implemented"); + } + + writeHead(_statusCode, _statusMessage, _headers) { + throw new Error("writeHead is not implemented"); + } + + writeProcessing() { + throw new Error("writeProcessing is not implemented"); + } } async function operation(renderData) { - let data; - if ("getStaticProps" in otherExports) { - // TODO(alexkirsz) Pass in `context` as defined in - // https://nextjs.org/docs/api-reference/data-fetching/get-static-props#context-parameter - data = otherExports.getStaticProps({ - params: renderData.params, - }); - if ("then" in data) { - data = await data; - } - } else if ("getServerSideProps" in otherExports) { - data = otherExports.getServerSideProps({ - params: renderData.params, - query: { ...renderData.query, ...renderData.params }, - req: { - headers: renderData.headers, - // TODO add `cookies` field - }, - method: renderData.method, - url: renderData.url, - }); - } else { - data = { props: {} }; - } - - const initialProps = await loadGetInitialProps(App, { - Component, - // TODO(alexkirsz) Pass in `context` - ctx: { - // This is necessary for the default Document.getInitialProps to work. - defaultGetInitialProps: async (docCtx, options = {}) => { - return {}; - }, + // TODO(alexkirsz) This is missing *a lot* of data, but it's enough to get a + // basic render working. + + /* BuildManifest */ + const buildManifest = { + pages: { + // TODO(alexkirsz) We should separate _app and page chunks. Right now, we + // computing the chunk items of `next-hydrate.js`, so they contain both + // _app and page chunks. + "/_app": [], + [renderData.path]: chunkGroup, }, - }); - const props = { ...initialProps, ...data.props, pageProps: { ...initialProps.pageProps, ...data.props } }; - - const urls = chunkGroup.map((p) => `/${p}`); - const scripts = urls.filter((url) => url.endsWith(".js")); - const styles = urls.filter((url) => url.endsWith(".css")); - const htmlProps = { - scripts, - styles, - __NEXT_DATA__: { props }, + + devFiles: [], + ampDevFiles: [], + polyfillFiles: [], + lowPriorityFiles: [], + rootMainFiles: [], + ampFirstPages: [], }; - const documentHTML = renderToStaticMarkup( - - - - ); + const renderOpts = { + /* LoadComponentsReturnType */ + Component, + App, + Document, + pageConfig: {}, + buildManifest, + reactLoadableManifest: {}, + ComponentMod: { + default: Component, + ...otherExports, + }, + pathname: renderData.path, + buildId: "", - const [renderTargetPrefix, renderTargetSuffix] = documentHTML.split( - "" - ); + /* RenderOptsPartial */ + assetPrefix: "", + canonicalBase: "", + previewProps: { + previewModeId: "", + previewModeEncryptionKey: "", + previewModeSigningKey: "", + }, + basePath: "", + optimizeFonts: false, + optimizeCss: false, + nextScriptWorkers: false, + images: { + deviceSizes: [], + imageSizes: [], + loader: "default", + path: "", + domains: [], + disableStaticImages: false, + minimumCacheTTL: 0, + formats: [], + dangerouslyAllowSVG: false, + contentSecurityPolicy: "", + remotePatterns: [], + unoptimized: true, + }, + }; - const result = []; - if (!documentHTML.startsWith(DOCTYPE)) { - result.push(DOCTYPE); + if ("getStaticProps" in otherExports) { + renderOpts.getStaticProps = otherExports.getStaticProps; + } + if ("getServerSideProps" in otherExports) { + renderOpts.getServerSideProps = otherExports.getServerSideProps; } - result.push(renderTargetPrefix); - result.push( - // TODO capture meta info during rendering - renderToString( - - - - ) - ); - result.push(renderTargetSuffix); + const req = { + url: renderData.url, + method: "GET", + headers: renderData.headers, + }; + const res = new ServerResponse(req); + const query = { ...renderData.query, ...renderData.params }; - return result.join(""); + return ( + await renderToHTML( + /* req: IncomingMessage */ + req, + /* res: ServerResponse */ + res, + /* pathname: string */ + renderData.path, + /* query: ParsedUrlQuery */ + query, + /* renderOpts: RenderOpts */ + renderOpts + ) + ).toUnchunkedString(); } diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js b/packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js deleted file mode 100644 index 90900949f57abe..00000000000000 --- a/packages/next-swc/crates/next-core/src/next_js/internal/shared-utils.js +++ /dev/null @@ -1,15 +0,0 @@ -// Originally defined in https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/utils.ts -export async function loadGetInitialProps(App, ctx) { - if (!App.getInitialProps) { - if (ctx.ctx && ctx.Component) { - return { - pageProps: await loadGetInitialProps(ctx.Component, ctx.ctx), - }; - } - return {}; - } - - const props = await App.getInitialProps(ctx); - - return props; -} diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/shims.js b/packages/next-swc/crates/next-core/src/next_js/internal/shims.js new file mode 100644 index 00000000000000..8a4cf41236ec3e --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_js/internal/shims.js @@ -0,0 +1,17 @@ +// Necessary for Next.js to accept and handle the `webpackHMR` option properly +// in next-hydrate.js. +process.env.NODE_ENV = "development"; + +// This is a fix for web-vitals.js not being linked properly. +globalThis.__dirname = ""; + +// Next uses __webpack_require__ extensively. +globalThis.__webpack_require__ = (name) => { + console.error(`__webpack_require__ is not implemented (when requiring ${name})`); +}; + +// initialize() needs `__webpack_public_path__` to be defined. +globalThis.__webpack_public_path__ = undefined; + +// Avoids Next loading _next/static/[buildId]/_devMiddlewareManifest.json +globalThis.__DEV_MIDDLEWARE_MATCHERS = []; diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 158e0ed349ec5f..e4fe3d4c157b47 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -206,6 +206,7 @@ pub(super) struct RenderData { url: String, query: Query, headers: BTreeMap, + path: String, } /// Renders a module as static HTML in a node.js process. diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index b281abd8172b56..1cbd2a36ce783c 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -55,7 +55,7 @@ pub fn create_node_rendered_source( ConditionalContentSourceVc::new( source.into(), LazyInstantiatedContentSource { - get_source: source.into(), + get_source: source.as_get_content_source(), } .cell() .into(), @@ -77,19 +77,27 @@ struct NodeRenderContentSource { impl NodeRenderContentSource { /// Checks if a path matches the regular expression async fn is_matching_path(&self, path: &str) -> Result { + // TODO(alexkirsz) This should probably not happen here. + if path.starts_with("_") { + return Ok(false); + } Ok(self.path_regex.await?.is_match(path)) } /// Matches a path with the regular expression and returns a JSON object /// with the named captures async fn get_matches(&self, path: &str) -> Result>> { + // TODO(alexkirsz) This should probably not happen here. + if path.starts_with("_") { + return Ok(None); + } Ok(self.path_regex.await?.get_matches(path)) } } #[turbo_tasks::value_impl] impl GetContentSource for NodeRenderContentSource { - /// Returns the [ContentSource] that the serves all referenced external + /// Returns the [ContentSource] that serves all referenced external /// assets. This is wrapped into [LazyInstantiatedContentSource]. #[turbo_tasks::function] fn content_source(&self) -> ContentSourceVc { @@ -130,35 +138,42 @@ impl ContentSource for NodeRenderContentSource { path: &str, data: turbo_tasks::Value, ) -> Result { - Ok(if let Some(params) = self.get_matches(path).await? { - ContentSourceResult::Static( - render_static( - self.server_root.join(path), - self.renderer.module(), - self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, - RenderData { - params, - method: data - .method - .clone() - .ok_or_else(|| anyhow!("method needs to be provided"))?, - url: data - .url - .clone() - .ok_or_else(|| anyhow!("url needs to be provided"))?, - query: data.query.clone(), - headers: data.headers.clone(), - } - .cell(), + if let Some(params) = self.get_matches(path).await? { + if data + .headers + .get("accept") + .map(|value| value.contains("html")) + .unwrap_or_default() + { + return Ok(ContentSourceResult::Static( + render_static( + self.server_root.join(path), + self.renderer.module(), + self.runtime_entries, + self.chunking_context, + self.intermediate_output_path, + RenderData { + params, + method: data + .method + .clone() + .ok_or_else(|| anyhow!("method needs to be provided"))?, + url: data + .url + .clone() + .ok_or_else(|| anyhow!("url needs to be provided"))?, + query: data.query.clone(), + headers: data.headers.clone(), + path: format!("/{path}"), + } + .cell(), + ) + .into(), ) - .into(), - ) - .cell() - } else { - ContentSourceResult::NotFound.cell() - }) + .cell()); + } + } + Ok(ContentSourceResult::NotFound.cell()) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 3ab835d11c28b1..2e9f7f1de8ac49 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -37,7 +37,7 @@ use crate::{ }, NextClientTransition, }, - next_import_map::get_next_import_map, + next_import_map::{get_next_client_import_map, get_next_server_import_map}, nodejs::node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, path_regex::{PathRegexBuilder, PathRegexVc}, }; @@ -68,9 +68,10 @@ pub async fn create_server_rendered_source( get_client_module_options_context(project_path, client_environment); let client_resolve_options_context = get_client_resolve_options_context(); - let next_import_map = get_next_import_map(pages_dir); + let next_server_import_map = get_next_server_import_map(pages_dir); + let next_client_import_map = get_next_client_import_map(pages_dir); let client_resolve_options_context = - client_resolve_options_context.with_extended_import_map(next_import_map); + client_resolve_options_context.with_extended_import_map(next_client_import_map); let client_runtime_entries = get_client_runtime_entries(project_path, env); @@ -110,7 +111,7 @@ pub async fn create_server_rendered_source( enable_node_modules: true, enable_node_native_modules: true, custom_conditions: vec!["development".to_string()], - import_map: Some(next_import_map), + import_map: Some(next_server_import_map), module: true, ..Default::default() } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index d13a2fcae73f03..348727475d1ede 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -48,7 +48,8 @@ impl Bundler for Turbopack { install_dir, &[ NpmPackage::new("react-refresh", "^0.12.0"), - NpmPackage::new("@next/react-refresh-utils", "^12.2.5"), + NpmPackage::new("next", "^12.3.1"), + NpmPackage::new("@next/react-refresh-utils", "^12.3.1"), // Dependencies on these are inserted by swc's preset_env NpmPackage::new("@swc/helpers", "^0.4.11"), NpmPackage::new("core-js", "^3.25.3"), From fcc806e1e52f26b44822afcf2e06515ea0560956 Mon Sep 17 00:00:00 2001 From: Leah Date: Mon, 17 Oct 2022 23:33:25 +0200 Subject: [PATCH 140/672] embedded next.js package (vercel/turbo#37) --- .../internal => js/entry}/next-hydrate.js | 0 .../internal => js/entry}/server-renderer.js | 0 .../{src/next_js => js}/internal/shims.js | 4 +- .../{src/next_js => js}/pages/_app.js | 0 .../{src/next_js => js}/pages/_document.js | 0 .../next-swc/crates/next-core/package.json | 11 ++ .../next-swc/crates/next-core/src/embed_js.rs | 32 +++++ .../crates/next-core/src/embed_next.rs | 6 - packages/next-swc/crates/next-core/src/lib.rs | 2 +- .../crates/next-core/src/next_client/mod.rs | 10 +- .../crates/next-core/src/next_import_map.rs | 120 ++++++++---------- .../src/nodejs/node_rendered_source.rs | 4 +- .../next-core/src/server_rendered_source.rs | 10 +- 13 files changed, 115 insertions(+), 84 deletions(-) rename packages/next-swc/crates/next-core/{src/next_js/internal => js/entry}/next-hydrate.js (100%) rename packages/next-swc/crates/next-core/{src/next_js/internal => js/entry}/server-renderer.js (100%) rename packages/next-swc/crates/next-core/{src/next_js => js}/internal/shims.js (85%) rename packages/next-swc/crates/next-core/{src/next_js => js}/pages/_app.js (100%) rename packages/next-swc/crates/next-core/{src/next_js => js}/pages/_document.js (100%) create mode 100644 packages/next-swc/crates/next-core/package.json create mode 100644 packages/next-swc/crates/next-core/src/embed_js.rs delete mode 100644 packages/next-swc/crates/next-core/src/embed_next.rs diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js b/packages/next-swc/crates/next-core/js/entry/next-hydrate.js similarity index 100% rename from packages/next-swc/crates/next-core/src/next_js/internal/next-hydrate.js rename to packages/next-swc/crates/next-core/js/entry/next-hydrate.js diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js b/packages/next-swc/crates/next-core/js/entry/server-renderer.js similarity index 100% rename from packages/next-swc/crates/next-core/src/next_js/internal/server-renderer.js rename to packages/next-swc/crates/next-core/js/entry/server-renderer.js diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/shims.js b/packages/next-swc/crates/next-core/js/internal/shims.js similarity index 85% rename from packages/next-swc/crates/next-core/src/next_js/internal/shims.js rename to packages/next-swc/crates/next-core/js/internal/shims.js index 8a4cf41236ec3e..bce89cab9f107c 100644 --- a/packages/next-swc/crates/next-core/src/next_js/internal/shims.js +++ b/packages/next-swc/crates/next-core/js/internal/shims.js @@ -7,7 +7,9 @@ globalThis.__dirname = ""; // Next uses __webpack_require__ extensively. globalThis.__webpack_require__ = (name) => { - console.error(`__webpack_require__ is not implemented (when requiring ${name})`); + console.error( + `__webpack_require__ is not implemented (when requiring ${name})` + ); }; // initialize() needs `__webpack_public_path__` to be defined. diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_app.js b/packages/next-swc/crates/next-core/js/pages/_app.js similarity index 100% rename from packages/next-swc/crates/next-core/src/next_js/pages/_app.js rename to packages/next-swc/crates/next-core/js/pages/_app.js diff --git a/packages/next-swc/crates/next-core/src/next_js/pages/_document.js b/packages/next-swc/crates/next-core/js/pages/_document.js similarity index 100% rename from packages/next-swc/crates/next-core/src/next_js/pages/_document.js rename to packages/next-swc/crates/next-core/js/pages/_document.js diff --git a/packages/next-swc/crates/next-core/package.json b/packages/next-swc/crates/next-core/package.json new file mode 100644 index 00000000000000..1e50e77b16d1fe --- /dev/null +++ b/packages/next-swc/crates/next-core/package.json @@ -0,0 +1,11 @@ +{ + "name": "@vercel/turbopack-next", + "version": "0.0.0", + "description": "turbopack next runtime", + "license": "UNLICENSED", + "private": true, + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + } +} diff --git a/packages/next-swc/crates/next-core/src/embed_js.rs b/packages/next-swc/crates/next-core/src/embed_js.rs new file mode 100644 index 00000000000000..7ae5aa523cdd7a --- /dev/null +++ b/packages/next-swc/crates/next-core/src/embed_js.rs @@ -0,0 +1,32 @@ +use anyhow::Result; +use turbo_tasks_fs::{ + attach::AttachedFileSystemVc, embed_directory, FileContentVc, FileSystemPathVc, FileSystemVc, +}; + +pub const VIRTUAL_PACKAGE_NAME: &str = "@vercel/turbopack-next"; + +#[turbo_tasks::function] +pub(crate) fn next_js_fs() -> FileSystemVc { + embed_directory!("next", "$CARGO_MANIFEST_DIR/js") +} + +#[turbo_tasks::function] +pub(crate) fn next_js_file(path: &str) -> FileContentVc { + next_js_fs().root().join(path).read() +} + +#[turbo_tasks::function] +pub(crate) async fn attached_next_js_package_path( + project_path: FileSystemPathVc, +) -> FileSystemPathVc { + project_path.join(&format!("[embedded_modules]/{}", VIRTUAL_PACKAGE_NAME)) +} + +#[turbo_tasks::function] +pub(crate) async fn wrap_with_next_js_fs( + project_path: FileSystemPathVc, +) -> Result { + let attached_path = attached_next_js_package_path(project_path); + let fs = AttachedFileSystemVc::new(attached_path, next_js_fs()); + Ok(fs.convert_path(project_path)) +} diff --git a/packages/next-swc/crates/next-core/src/embed_next.rs b/packages/next-swc/crates/next-core/src/embed_next.rs deleted file mode 100644 index 02099c46b8555a..00000000000000 --- a/packages/next-swc/crates/next-core/src/embed_next.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[macro_export] -macro_rules! embed_next_file { - ($path:expr) => { - turbo_tasks_fs::embed_file!(concat!("src/next_js/", $path)) - }; -} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index a53d0bd00b3a27..915fd66d1ee779 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -1,7 +1,7 @@ #![feature(async_closure)] #![feature(min_specialization)] -mod embed_next; +mod embed_js; pub mod env; pub mod next_client; mod next_import_map; diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index 38e579058672ae..497c5d01693bee 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -19,7 +19,7 @@ use turbopack_core::{ }; use self::runtime_entry::RuntimeEntriesVc; -use crate::embed_next_file; +use crate::embed_js::next_js_file; /// Makes a transition into a next.js client context. /// @@ -40,9 +40,11 @@ pub struct NextClientTransition { impl Transition for NextClientTransition { #[turbo_tasks::function] fn process_source(&self, asset: AssetVc) -> AssetVc { - let next_hydrate = embed_next_file!("internal/next-hydrate.js").into(); - - VirtualAssetVc::new(asset.path().join("next-hydrate.js"), next_hydrate).into() + VirtualAssetVc::new( + asset.path().join("next-hydrate.js"), + next_js_file("entry/next-hydrate.js").into(), + ) + .into() } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 80b8a233ee3e35..3cd34920d9309a 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -1,33 +1,34 @@ use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::{ - asset::AssetVc, - resolve::{ - options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}, - AliasPattern, ResolveResult, - }, - virtual_asset::VirtualAssetVc, -}; +use turbopack_core::resolve::options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}; -use crate::embed_next_file; +use crate::embed_js::{attached_next_js_package_path, VIRTUAL_PACKAGE_NAME}; /// Computes the Next-specific client import map. #[turbo_tasks::function] -pub fn get_next_client_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { +pub fn get_next_client_import_map( + project_path: FileSystemPathVc, + pages_dir: FileSystemPathVc, +) -> ImportMapVc { let mut import_map = ImportMap::empty(); + let package_root = attached_next_js_package_path(project_path); - insert_next_shared_aliases(&mut import_map, pages_dir); + insert_next_shared_aliases(&mut import_map, package_root); insert_alias_to_alternatives( &mut import_map, - "@vercel/turbopack-next/pages/_app", - request_to_import_mapping(pages_dir, "./_app"), - request_to_import_mapping(pages_dir, "next/app"), + format!("{VIRTUAL_PACKAGE_NAME}/pages/_app"), + vec![ + request_to_import_mapping(pages_dir, "./_app"), + request_to_import_mapping(pages_dir, "next/app"), + ], ); insert_alias_to_alternatives( &mut import_map, - "@vercel/turbopack-next/pages/_document", - request_to_import_mapping(pages_dir, "./_document"), - request_to_import_mapping(pages_dir, "next/document"), + format!("{VIRTUAL_PACKAGE_NAME}/pages/_document"), + vec![ + request_to_import_mapping(pages_dir, "./_document"), + request_to_import_mapping(pages_dir, "next/document"), + ], ); import_map.cell() @@ -35,77 +36,69 @@ pub fn get_next_client_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { /// Computes the Next-specific server-side import map. #[turbo_tasks::function] -pub fn get_next_server_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { +pub fn get_next_server_import_map( + project_path: FileSystemPathVc, + pages_dir: FileSystemPathVc, +) -> ImportMapVc { let mut import_map = ImportMap::empty(); + let package_root = attached_next_js_package_path(project_path); - insert_next_shared_aliases(&mut import_map, pages_dir); + insert_next_shared_aliases(&mut import_map, package_root); insert_alias_to_alternatives( &mut import_map, - "@vercel/turbopack-next/pages/_app", - request_to_import_mapping(pages_dir, "./_app"), - external_request_to_import_mapping("next/app"), + format!("{VIRTUAL_PACKAGE_NAME}/pages/_app"), + vec![ + request_to_import_mapping(pages_dir, "./_app"), + external_request_to_import_mapping("next/app"), + ], ); insert_alias_to_alternatives( &mut import_map, - "@vercel/turbopack-next/pages/_document", - request_to_import_mapping(pages_dir, "./_document"), - external_request_to_import_mapping("next/document"), + format!("{VIRTUAL_PACKAGE_NAME}/pages/_document"), + vec![ + request_to_import_mapping(pages_dir, "./_document"), + external_request_to_import_mapping("next/document"), + ], ); - import_map.insert_alias( - AliasPattern::exact("next"), - ImportMapping::External(None).into(), - ); - import_map.insert_alias( - AliasPattern::wildcard("next/", ""), - ImportMapping::External(None).into(), - ); - import_map.insert_alias( - AliasPattern::exact("react"), - ImportMapping::External(None).into(), - ); - import_map.insert_alias( - AliasPattern::wildcard("react/", ""), - ImportMapping::External(None).into(), - ); + import_map.insert_exact_alias("next", ImportMapping::External(None).into()); + import_map.insert_wildcard_alias("next/", ImportMapping::External(None).into()); + import_map.insert_exact_alias("react", ImportMapping::External(None).into()); + import_map.insert_wildcard_alias("react/", ImportMapping::External(None).into()); import_map.cell() } -fn insert_next_shared_aliases(import_map: &mut ImportMap, pages_dir: FileSystemPathVc) { - import_map.insert_alias( - AliasPattern::exact("@vercel/turbopack-next/internal/shims"), - asset_to_import_mapping(get_internal_shims_asset(pages_dir)), +fn insert_next_shared_aliases(import_map: &mut ImportMap, package_root: FileSystemPathVc) { + insert_package_alias( + import_map, + &format!("{VIRTUAL_PACKAGE_NAME}/"), + package_root, ); } -#[turbo_tasks::function] -fn get_internal_shims_asset(pages_dir: FileSystemPathVc) -> AssetVc { - VirtualAssetVc::new( - pages_dir.root().join("next_js/internal/shims.js"), - embed_next_file!("internal/shims.js").into(), - ) - .into() -} - /// Inserts an alias to an alternative of import mappings into an import map. fn insert_alias_to_alternatives( import_map: &mut ImportMap, - alias: &str, - alt1: ImportMappingVc, - alt2: ImportMappingVc, + alias: impl ToString, + alternatives: Vec, ) { - import_map.insert_alias( - AliasPattern::Exact(alias.to_string()), - ImportMapping::Alternatives(vec![alt1, alt2]).into(), + import_map.insert_exact_alias(alias, ImportMapping::Alternatives(alternatives).into()); +} + +/// Inserts an alias to an import mapping into an import map. +fn insert_package_alias(import_map: &mut ImportMap, prefix: &str, package_root: FileSystemPathVc) { + import_map.insert_wildcard_alias( + prefix, + ImportMapping::PrimaryAlternative("./*".to_string(), Some(package_root)).cell(), ); } /// Creates a direct import mapping to the result of resolving a request /// in a context. fn request_to_import_mapping(context_path: FileSystemPathVc, request: &str) -> ImportMappingVc { - ImportMapping::PrimaryAlternative(request.to_string(), Some(context_path)).into() + ImportMapping::PrimaryAlternative(request.to_string(), Some(context_path)).cell() } /// Creates a direct import mapping to the result of resolving an external @@ -113,8 +106,3 @@ fn request_to_import_mapping(context_path: FileSystemPathVc, request: &str) -> I fn external_request_to_import_mapping(request: &str) -> ImportMappingVc { ImportMapping::External(Some(request.to_string())).into() } - -/// Creates a direct import mapping to a single asset. -fn asset_to_import_mapping(asset: AssetVc) -> ImportMappingVc { - ImportMapping::Direct(ResolveResult::Single(asset, vec![]).into()).into() -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 1cbd2a36ce783c..85bf627288f09c 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -78,7 +78,7 @@ impl NodeRenderContentSource { /// Checks if a path matches the regular expression async fn is_matching_path(&self, path: &str) -> Result { // TODO(alexkirsz) This should probably not happen here. - if path.starts_with("_") { + if path.starts_with('_') { return Ok(false); } Ok(self.path_regex.await?.is_match(path)) @@ -88,7 +88,7 @@ impl NodeRenderContentSource { /// with the named captures async fn get_matches(&self, path: &str) -> Result>> { // TODO(alexkirsz) This should probably not happen here. - if path.starts_with("_") { + if path.starts_with('_') { return Ok(None); } Ok(self.path_regex.await?.get_matches(path)) diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 2e9f7f1de8ac49..ce9d544ea1d7f5 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -28,7 +28,7 @@ use turbopack_ecmascript::{ use turbopack_env::ProcessEnvAssetVc; use crate::{ - embed_next_file, + embed_js::{next_js_file, wrap_with_next_js_fs}, next_client::{ context::{ get_client_assets_path, get_client_chunking_context, get_client_environment, @@ -52,6 +52,8 @@ pub async fn create_server_rendered_source( env: ProcessEnvVc, browserslist_query: &str, ) -> Result { + let project_path = wrap_with_next_js_fs(project_path); + let pages = project_path.join("pages"); let src_pages = project_path.join("src/pages"); let pages_dir = if *pages.get_type().await? == FileSystemEntryType::Directory { @@ -68,8 +70,8 @@ pub async fn create_server_rendered_source( get_client_module_options_context(project_path, client_environment); let client_resolve_options_context = get_client_resolve_options_context(); - let next_server_import_map = get_next_server_import_map(pages_dir); - let next_client_import_map = get_next_client_import_map(pages_dir); + let next_server_import_map = get_next_server_import_map(project_path, pages_dir); + let next_client_import_map = get_next_client_import_map(project_path, pages_dir); let client_resolve_options_context = client_resolve_options_context.with_extended_import_map(next_client_import_map); @@ -342,7 +344,7 @@ impl NodeRenderer for SsrRenderer { EcmascriptModuleAssetVc::new( VirtualAssetVc::new( self.entry_asset.path().join("server-renderer.js"), - embed_next_file!("internal/server-renderer.js").into(), + next_js_file("entry/server-renderer.js").into(), ) .into(), self.context, From aed7fa4d0bb3a8285466e11ca580a166294aa551 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 18 Oct 2022 03:17:06 +0200 Subject: [PATCH 141/672] add basic support for browser alias field (vercel/turbo#56) --- .../turbopack/basic/browser-alias-field/browser.js | 1 + .../turbopack/basic/browser-alias-field/dir/indirect.js | 1 + .../turbopack/basic/browser-alias-field/index.js | 7 +++++++ .../turbopack/basic/browser-alias-field/node.js | 1 + .../turbopack/basic/browser-alias-field/package.json | 5 +++++ 5 files changed, 15 insertions(+) create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/browser.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/package.json diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/browser.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/browser.js new file mode 100644 index 00000000000000..7a4e8a723a4072 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/browser.js @@ -0,0 +1 @@ +export default 42; diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js new file mode 100644 index 00000000000000..52ecf59ebfba2a --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js @@ -0,0 +1 @@ +export { default } from "../node.js" diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/index.js new file mode 100644 index 00000000000000..4541c046f90ac7 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/index.js @@ -0,0 +1,7 @@ +import value from "./node.js"; +import indirect from "./dir/indirect.js"; + +it("should alias with browser field", () => { + expect(value).toBe(42); + expect(indirect).toBe(42); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js new file mode 100644 index 00000000000000..15f511ba7da062 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js @@ -0,0 +1 @@ +throw new Error("This is node.js only") diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/package.json b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/package.json new file mode 100644 index 00000000000000..732e444fe0c15e --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/package.json @@ -0,0 +1,5 @@ +{ + "browser": { + "./node.js": "./browser.js" + } +} From 5c1d113f1ec9a99716ac99a28a9a8c86a1eb6789 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 18 Oct 2022 09:56:24 +0200 Subject: [PATCH 142/672] node.js needs a fetch polyfill (vercel/turbo#58) --- packages/next-swc/crates/next-core/js/entry/server-renderer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-core/js/entry/server-renderer.js b/packages/next-swc/crates/next-core/js/entry/server-renderer.js index 83eb6392c3d15f..a7c5886ad7acc7 100644 --- a/packages/next-swc/crates/next-core/js/entry/server-renderer.js +++ b/packages/next-swc/crates/next-core/js/entry/server-renderer.js @@ -1,5 +1,6 @@ const END_OF_OPERATION = process.argv[2]; +import "next/dist/server/node-polyfill-fetch.js"; import { renderToHTML } from "next/dist/server/render"; import App from "@vercel/turbopack-next/pages/_app"; import Document from "@vercel/turbopack-next/pages/_document"; From feb8c9ac39e7a81364e6bf20007a37c2455fa456 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 18 Oct 2022 04:05:37 -0400 Subject: [PATCH 143/672] Implement support for static assets directory (vercel/turbo#73) Fixes https://github.com/vercel/web-tooling-internal/issues/7 Co-authored-by: Tobias Koppers --- packages/next-swc/crates/next-dev/src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index f2588bc105cee5..811daf665798f6 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -13,7 +13,10 @@ use turbopack_core::{issue::IssueSeverity, resolve::parse::RequestVc}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, introspect::IntrospectionSource, - source::{combined::CombinedContentSource, router::RouterContentSource, ContentSourceVc}, + source::{ + combined::CombinedContentSource, router::RouterContentSource, + static_assets::StaticAssetsContentSourceVc, ContentSourceVc, + }, DevServer, }; @@ -217,8 +220,10 @@ async fn source( } .cell() .into(); + let static_source = + StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into(); let main_source = CombinedContentSource { - sources: vec![rendered_source, web_source], + sources: vec![static_source, rendered_source, web_source], } .cell(); let introspect = IntrospectionSource { From 105ff16578ef80c8037cd7588ef3d6d1c848d39c Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 18 Oct 2022 13:00:10 +0200 Subject: [PATCH 144/672] remove ContentSource::vary to avoid many tasks (vercel/turbo#71) --- .../src/nodejs/node_rendered_source.rs | 114 ++++++++++-------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 85bf627288f09c..f7cfe0eea20f4f 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -15,7 +15,7 @@ use turbopack_dev_server::source::{ conditional::ConditionalContentSourceVc, lazy_instatiated::{GetContentSource, GetContentSourceVc, LazyInstantiatedContentSource}, ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, - ContentSourceDataVaryVc, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, + ContentSourceResult, ContentSourceResultVc, ContentSourceVc, }; use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; @@ -116,61 +116,75 @@ impl GetContentSource for NodeRenderContentSource { #[turbo_tasks::value_impl] impl ContentSource for NodeRenderContentSource { - #[turbo_tasks::function] - async fn vary(&self, path: &str) -> Result { - Ok(if self.is_matching_path(path).await? { - ContentSourceDataVary { - method: true, - url: true, - headers: Some(ContentSourceDataFilter::All), - query: Some(ContentSourceDataFilter::All), - ..Default::default() - } - .cell() - } else { - ContentSourceDataVary::default().cell() - }) - } - #[turbo_tasks::function] async fn get( - &self, + self_vc: NodeRenderContentSourceVc, path: &str, data: turbo_tasks::Value, ) -> Result { - if let Some(params) = self.get_matches(path).await? { - if data - .headers - .get("accept") - .map(|value| value.contains("html")) - .unwrap_or_default() - { - return Ok(ContentSourceResult::Static( - render_static( - self.server_root.join(path), - self.renderer.module(), - self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, - RenderData { - params, - method: data - .method - .clone() - .ok_or_else(|| anyhow!("method needs to be provided"))?, - url: data - .url - .clone() - .ok_or_else(|| anyhow!("url needs to be provided"))?, - query: data.query.clone(), - headers: data.headers.clone(), - path: format!("/{path}"), + let this = self_vc.await?; + if this.is_matching_path(path).await? { + if let Some(params) = this.get_matches(path).await? { + if let Some(headers) = &data.headers { + if headers + .get("accept") + .map(|value| value.contains("html")) + .unwrap_or_default() + { + if data.method.is_some() && data.url.is_some() { + if let Some(query) = &data.query { + return Ok(ContentSourceResult::Static( + render_static( + this.server_root.join(path), + this.renderer.module(), + this.runtime_entries, + this.chunking_context, + this.intermediate_output_path, + RenderData { + params, + method: data.method.clone().ok_or_else(|| { + anyhow!("method needs to be provided") + })?, + url: data.url.clone().ok_or_else(|| { + anyhow!("url needs to be provided") + })?, + query: query.clone(), + headers: headers.clone(), + path: format!("/{path}"), + } + .cell(), + ) + .into(), + ) + .cell()); + } + } + return Ok(ContentSourceResult::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + method: true, + url: true, + headers: Some(ContentSourceDataFilter::All), + query: Some(ContentSourceDataFilter::All), + ..Default::default() + }, } - .cell(), - ) - .into(), - ) - .cell()); + .cell()); + } + } else { + return Ok(ContentSourceResult::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + headers: Some(ContentSourceDataFilter::Subset(HashSet::from([ + "accept".to_string(), + ]))), + ..Default::default() + }, + } + .cell()); + } } } Ok(ContentSourceResult::NotFound.cell()) From 59b7290933bd9f0f23277a1ea590c2f0be1ed9d8 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 18 Oct 2022 14:53:01 +0200 Subject: [PATCH 145/672] Remove unused pages/_app and pages/_document (vercel/turbo#78) These are no longer used, as we are now using Next.js' own components instead. --- .../crates/next-core/js/pages/_app.js | 15 ---- .../crates/next-core/js/pages/_document.js | 88 ------------------- 2 files changed, 103 deletions(-) delete mode 100644 packages/next-swc/crates/next-core/js/pages/_app.js delete mode 100644 packages/next-swc/crates/next-core/js/pages/_document.js diff --git a/packages/next-swc/crates/next-core/js/pages/_app.js b/packages/next-swc/crates/next-core/js/pages/_app.js deleted file mode 100644 index 51ad064b7e0e93..00000000000000 --- a/packages/next-swc/crates/next-core/js/pages/_app.js +++ /dev/null @@ -1,15 +0,0 @@ -// The full definition of the default _app.js file is in -// https://github.com/vercel/next.js/blob/canary/packages/next/pages/_app.tsx - -import { loadGetInitialProps } from "@vercel/turbopack-next/internal/shared-utils"; - -export default function App({ Component, pageProps }) { - return ; -} - -async function appGetInitialProps({ Component, ctx }) { - const pageProps = await loadGetInitialProps(Component, ctx); - return { pageProps }; -} - -App.getInitialProps = appGetInitialProps; diff --git a/packages/next-swc/crates/next-core/js/pages/_document.js b/packages/next-swc/crates/next-core/js/pages/_document.js deleted file mode 100644 index 63b651b4397c3f..00000000000000 --- a/packages/next-swc/crates/next-core/js/pages/_document.js +++ /dev/null @@ -1,88 +0,0 @@ -// The full definition of the default _document.js file is in -// https://github.com/vercel/next.js/blob/canary/packages/next/pages/_document.tsx - -import React from "react"; -import { HtmlContext } from "@vercel/turbopack-next/internal/html-context"; - -export function Html(props) { - return ; -} - -// TODO(alexkirsz) This should be a class component. -export function Head({ children, ...props }) { - const { styles, scripts } = React.useContext(HtmlContext); - - return ( - - {children} - {styles.map((url) => ( - - ))} - {scripts.map((url) => ( - - ))} - - ); -} - -// This utility is based on https://github.com/zertosh/htmlescape -// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE - -const ESCAPE_LOOKUP = { - "&": "\\u0026", - ">": "\\u003e", - "<": "\\u003c", - "\u2028": "\\u2028", - "\u2029": "\\u2029", -}; - -const ESCAPE_REGEX = /[&><\u2028\u2029]/g; - -export function htmlEscapeJsonString(str) { - return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); -} - -// TODO(alexkirsz) This should be a class component. -export function NextScript() { - const { scripts, __NEXT_DATA__ } = React.useContext(HtmlContext); - - return ( - <> - - {scripts.map((url) => ( - - ))} - - ); -} - -export function Main() { - // This element will be search-and-replaced with the actual page content once - // rendered to static markup. - return ; -} - -// This *must* be a class component, because it can be extended in user code. -export default class Document extends React.Component { - static getInitialProps(ctx) { - return ctx.defaultGetInitialProps(ctx); - } - - render() { - return ( - - - -
- - - - ); - } -} From 9062ad91f41971cc3edce4a347f1e03b91bb79d5 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 18 Oct 2022 19:30:07 +0200 Subject: [PATCH 146/672] Add polyfills to Node.js externals on the client-side (vercel/turbo#89) We can't use the normal `ImportMap` because we stop resolving if looking up a request within yields a result. However, for module polyfills, we only need to look up the request when normal resolving fails. Hence the dichotomy between the `import_map` and the `fallback_import_map`. In a more modular architecture, we would model this as a stack of three resolvers: 1. ImportMapResolver 2. DefaultResolver 3. FallbackImportMapResolver I'm guessing this is what we'll have in the future, but this requires a bigger refactoring than what I'm comfortable with implementing for now. --- .../crates/next-core/src/next_import_map.rs | 39 +++++++++++++++++++ .../next-core/src/server_rendered_source.rs | 11 ++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 3cd34920d9309a..dee23939a364c2 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -34,6 +34,19 @@ pub fn get_next_client_import_map( import_map.cell() } +/// Computes the Next-specific client fallback import map, which provides +/// polyfills to Node.js externals. +#[turbo_tasks::function] +pub fn get_next_client_fallback_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { + let mut import_map = ImportMap::empty(); + + for (original, alias) in NEXT_ALIASES { + import_map.insert_exact_alias(original, request_to_import_mapping(pages_dir, alias)); + } + + import_map.cell() +} + /// Computes the Next-specific server-side import map. #[turbo_tasks::function] pub fn get_next_server_import_map( @@ -70,6 +83,32 @@ pub fn get_next_server_import_map( import_map.cell() } +static NEXT_ALIASES: [(&str, &str); 23] = [ + ("asset", "next/dist/compiled/assert"), + ("buffer", "next/dist/compiled/buffer/"), + ("constants", "next/dist/compiled/constants-browserify"), + ("crypto", "next/dist/compiled/crypto-browserify"), + ("domain", "next/dist/compiled/domain-browser"), + ("http", "next/dist/compiled/stream-http"), + ("https", "next/dist/compiled/https-browserify"), + ("os", "next/dist/compiled/os-browserify"), + ("path", "next/dist/compiled/path-browserify"), + ("punycode", "next/dist/compiled/punycode"), + ("process", "next/dist/build/polyfills/process"), + ("querystring", "next/dist/compiled/querystring-es3"), + ("stream", "next/dist/compiled/stream-browserify"), + ("string_decoder", "next/dist/compiled/string_decoder"), + ("sys", "next/dist/compiled/util/"), + ("timers", "next/dist/compiled/timers-browserify"), + ("tty", "next/dist/compiled/tty-browserify"), + ("url", "next/dist/compiled/native-url"), + ("util", "next/dist/compiled/util/"), + ("vm", "next/dist/compiled/vm-browserify"), + ("zlib", "next/dist/compiled/browserify-zlib"), + ("events", "next/dist/compiled/events/"), + ("setImmediate", "next/dist/compiled/setimmediate"), +]; + fn insert_next_shared_aliases(import_map: &mut ImportMap, package_root: FileSystemPathVc) { insert_package_alias( import_map, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index ce9d544ea1d7f5..bda685de941dd9 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -37,7 +37,9 @@ use crate::{ }, NextClientTransition, }, - next_import_map::{get_next_client_import_map, get_next_server_import_map}, + next_import_map::{ + get_next_client_fallback_import_map, get_next_client_import_map, get_next_server_import_map, + }, nodejs::node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, path_regex::{PathRegexBuilder, PathRegexVc}, }; @@ -72,8 +74,10 @@ pub async fn create_server_rendered_source( let next_server_import_map = get_next_server_import_map(project_path, pages_dir); let next_client_import_map = get_next_client_import_map(project_path, pages_dir); - let client_resolve_options_context = - client_resolve_options_context.with_extended_import_map(next_client_import_map); + let next_client_fallback_import_map = get_next_client_fallback_import_map(pages_dir); + let client_resolve_options_context = client_resolve_options_context + .with_extended_import_map(next_client_import_map) + .with_extended_fallback_import_map(next_client_fallback_import_map); let client_runtime_entries = get_client_runtime_entries(project_path, env); @@ -112,6 +116,7 @@ pub async fn create_server_rendered_source( enable_react: true, enable_node_modules: true, enable_node_native_modules: true, + enable_node_externals: true, custom_conditions: vec!["development".to_string()], import_map: Some(next_server_import_map), module: true, From 7bf4a27e6abdf51ae8e179c743acc358d8ba623e Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 18 Oct 2022 19:30:46 +0200 Subject: [PATCH 147/672] Ensure Next.js uses React 18 APIs, enable styled_jsx transform in SSR (vercel/turbo#90) This will remove the warning about using `hydrate` instead of `hydrateRoot`, and fix a mismatch between SSR and CSR when using styled-jsx (` + ); +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx new file mode 100644 index 00000000000000..9a542219e47c20 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx @@ -0,0 +1,31 @@ +import * as React from "react"; + +import { styles as codeFrame } from "../components/CodeFrame/styles"; +import { styles as dialog } from "../components/Dialog"; +import { styles as leftRightDialogHeader } from "../components/LeftRightDialogHeader/styles"; +import { styles as overlay } from "../components/Overlay/styles"; +import { styles as terminal } from "../components/Terminal/styles"; +import { styles as toast } from "../components/Toast"; +import { styles as buildErrorStyles } from "../container/BuildError"; +import { styles as containerErrorStyles } from "../container/Errors"; +import { styles as containerRuntimeErrorStyles } from "../container/RuntimeError"; +import { noop as css } from "../helpers/noop-template"; + +export function ComponentStyles() { + return ( + + ); +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/CssReset.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/CssReset.tsx new file mode 100644 index 00000000000000..3eb3394d33e1d2 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/CssReset.tsx @@ -0,0 +1,362 @@ +import * as React from "react"; +import { noop as css } from "../helpers/noop-template"; + +export function CssReset() { + return ( + + ); +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/middleware.ts b/packages/next-swc/crates/next-core/js/src/overlay/middleware.ts new file mode 100644 index 00000000000000..a591c4ac0efebd --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/middleware.ts @@ -0,0 +1,6 @@ +import { StackFrame } from "@vercel/turbopack-next/compiled/stacktrace-parser"; + +export type OriginalStackFrameResponse = { + originalStackFrame: StackFrame; + originalCodeFrame: string | null; +}; diff --git a/packages/next-swc/crates/next-core/js/tsconfig.json b/packages/next-swc/crates/next-core/js/tsconfig.json index f67d3adb6e3afd..73eb366965c929 100644 --- a/packages/next-swc/crates/next-core/js/tsconfig.json +++ b/packages/next-swc/crates/next-core/js/tsconfig.json @@ -11,7 +11,7 @@ // js support "allowJs": true, - "checkJs": true, + "checkJs": false, // environment "jsx": "react-jsx", diff --git a/packages/next-swc/crates/next-core/js/types/compiled.d.ts b/packages/next-swc/crates/next-core/js/types/compiled.d.ts new file mode 100644 index 00000000000000..78c71c368d18b5 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/types/compiled.d.ts @@ -0,0 +1,28 @@ +/* GENERATED FILE, DO NOT EDIT */ + +declare module "@vercel/turbopack-next/compiled/anser" { + import m from "anser"; + export = m; +} + +declare module "@vercel/turbopack-next/compiled/css.escape" { + export = CSS.escape; +} + +declare module "@vercel/turbopack-next/compiled/platform" { + import m from "platform"; + export = m; +} + +declare module "@vercel/turbopack-next/compiled/source-map" { + export * from "source-map"; +} + +declare module "@vercel/turbopack-next/compiled/stacktrace-parser" { + export * from "stacktrace-parser"; +} + +declare module "@vercel/turbopack-next/compiled/strip-ansi" { + import m from "strip-ansi"; + export = m; +} diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 811dfe6dc14ecb..e2e77eaa04d417 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -89,7 +89,7 @@ pub fn get_next_server_import_map( static NEXT_ALIASES: [(&str, &str); 23] = [ ("asset", "next/dist/compiled/assert"), - ("buffer", "next/dist/compiled/buffer/"), + ("buffer", "next/dist/compiled/buffer"), ("constants", "next/dist/compiled/constants-browserify"), ("crypto", "next/dist/compiled/crypto-browserify"), ("domain", "next/dist/compiled/domain-browser"), @@ -102,18 +102,25 @@ static NEXT_ALIASES: [(&str, &str); 23] = [ ("querystring", "next/dist/compiled/querystring-es3"), ("stream", "next/dist/compiled/stream-browserify"), ("string_decoder", "next/dist/compiled/string_decoder"), - ("sys", "next/dist/compiled/util/"), + ("sys", "next/dist/compiled/util"), ("timers", "next/dist/compiled/timers-browserify"), ("tty", "next/dist/compiled/tty-browserify"), ("url", "next/dist/compiled/native-url"), - ("util", "next/dist/compiled/util/"), + ("util", "next/dist/compiled/util"), ("vm", "next/dist/compiled/vm-browserify"), ("zlib", "next/dist/compiled/browserify-zlib"), - ("events", "next/dist/compiled/events/"), + ("events", "next/dist/compiled/events"), ("setImmediate", "next/dist/compiled/setimmediate"), ]; fn insert_next_shared_aliases(import_map: &mut ImportMap, package_root: FileSystemPathVc) { + // we use the next.js hydration code, so we replace the error overlay with our + // own + import_map.insert_exact_alias( + "next/dist/compiled/@next/react-dev-overlay/dist/client", + request_to_import_mapping(package_root, "./overlay/client"), + ); + insert_package_alias( import_map, &format!("{VIRTUAL_PACKAGE_NAME}/"), From 3ca2fe4fd5e9b2595cd136981bafe98d8990f24e Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 20 Oct 2022 18:49:12 +0200 Subject: [PATCH 156/672] adds support for app directory (vercel/turbo#125) This can be tested with https://github.com/vercel/layouts-playground But since tailwind is not supported you need to add: ``` html ``` into `` in `app/layout.tsx` --- .../next-swc/crates/next-core/js/package.json | 7 +- .../next-core/js/src/entry/app-renderer.tsx | 196 ++++++++ .../next-core/js/src/entry/app/hydrate.tsx | 147 ++++++ .../next-core/js/src/entry/app/index.d.ts | 7 + .../js/src/entry/app/layout-entry.tsx | 10 + .../js/src/entry/app/server-to-client.tsx | 9 + .../js/src/entry/server-renderer.tsx | 136 +----- .../crates/next-core/js/src/internal/http.ts | 113 +++++ .../crates/next-core/js/types/globals.d.ts | 9 + .../crates/next-core/js/types/modules.d.ts | 4 + .../crates/next-core/js/types/turbopack.d.ts | 8 + .../crates/next-core/src/app_render/mod.rs | 12 + .../next_layout_entry_transition.rs | 77 ++++ .../crates/next-core/src/app_source.rs | 423 ++++++++++++++++++ packages/next-swc/crates/next-core/src/lib.rs | 6 + .../next-core/src/next_client/context.rs | 58 ++- .../crates/next-core/src/next_client/mod.rs | 19 +- .../client_chunks_transition.rs | 66 +++ .../in_chunking_context_asset.rs | 101 +++++ .../src/next_client_component/mod.rs | 6 + .../server_to_client_transition.rs | 19 + .../ssr_client_module_transition.rs | 62 +++ .../src/next_client_component/with_chunks.rs | 187 ++++++++ .../with_client_chunks.rs | 196 ++++++++ .../crates/next-core/src/next_import_map.rs | 165 +++++-- .../next_js/internal/next_client_component.js | 5 + .../crates/next-core/src/next_server/mod.rs | 98 ++++ .../crates/next-core/src/nodejs/mod.rs | 53 ++- .../src/nodejs/node_rendered_source.rs | 2 + .../next-core/src/server_rendered_source.rs | 150 ++----- .../next-swc/crates/next-core/src/util.rs | 74 +++ .../crates/next-core/src/web_entry_source.rs | 19 +- packages/next-swc/crates/next-dev/src/lib.rs | 18 +- .../crates/next-dev/src/turbo_tasks_viz.rs | 45 +- 34 files changed, 2152 insertions(+), 355 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/entry/app/index.d.ts create mode 100644 packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/internal/http.ts create mode 100644 packages/next-swc/crates/next-core/js/types/modules.d.ts create mode 100644 packages/next-swc/crates/next-core/js/types/turbopack.d.ts create mode 100644 packages/next-swc/crates/next-core/src/app_render/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs create mode 100644 packages/next-swc/crates/next-core/src/app_source.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client_component/client_chunks_transition.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client_component/in_chunking_context_asset.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client_component/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client_component/ssr_client_module_transition.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs create mode 100644 packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs create mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js create mode 100644 packages/next-swc/crates/next-core/src/next_server/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/util.rs diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index 728c05d166f60f..3662317db64c47 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -9,13 +9,14 @@ "build:compiled": "node build.mjs" }, "dependencies": { - "@vercel/turbopack-runtime": "workspace:*", + "@next/react-refresh-utils": "^12.2.5", + "@vercel/turbopack-runtime": "latest", "anser": "2.1.1", "css.escape": "1.5.1", - "next": "^12.3.1", + "next": "12.3.2-canary.32", "platform": "1.3.6", - "react": "^18.2.0", "react-dom": "^18.2.0", + "react": "^18.2.0", "source-map": "0.8.0-beta.0", "stacktrace-parser": "0.1.10", "strip-ansi": "6.0.1" diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx new file mode 100644 index 00000000000000..f30ce96496ca73 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -0,0 +1,196 @@ +// Provided by the rust generate code +declare global { + // an array of all layouts and the page + const LAYOUT_INFO: { segment: string; module: any; chunks: string[] }[]; + // array of chunks for the bootstrap script + const BOOTSTRAP: string[]; +} + +const END_OF_OPERATION = process.argv[2]; + +import type { IncomingMessage, ServerResponse } from "node:http"; +import type { FlightManifest } from "next/dist/build/webpack/plugins/flight-manifest-plugin"; +import type { RenderData } from "types/turbopack"; + +import "next/dist/server/node-polyfill-fetch"; +import "next/dist/server/node-polyfill-web-streams"; +import { RenderOpts, renderToHTMLOrFlight } from "next/dist/server/app-render"; +import { PassThrough } from "stream"; +import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; +import { ParsedUrlQuery } from "node:querystring"; + +globalThis.__next_require__ = (data) => { + const [ssr_id] = JSON.parse(data); + return __turbopack_require__(ssr_id); +}; +globalThis.__next_chunk_load__ = () => Promise.resolve(); + +process.env.__NEXT_NEW_LINK_BEHAVIOR = "true"; + +process.stdout.write("READY\n"); + +const NEW_LINE = "\n".charCodeAt(0); +const buffer: Buffer[] = []; +process.stdin.on("data", async (data) => { + let idx = data.indexOf(NEW_LINE); + while (idx >= 0) { + buffer.push(data.slice(0, idx)); + const str = Buffer.concat(buffer).toString("utf-8"); + buffer.length = 0; + let json: any; + try { + json = JSON.parse(str); + buffer.length = 0; + } catch (e: any) { + const input = + str.length > 100 ? `${str.slice(0, 30)}...${str.slice(-30)}` : str; + e.message += `\nduring processing input ${input}`; + console.log(`ERROR=${JSON.stringify(e.stack)}`); + } + try { + const result = await operation(json); + console.log(`RESULT=${JSON.stringify(result)}`); + } catch (e: any) { + console.log(`ERROR=${JSON.stringify(e.stack)}`); + } + console.log(END_OF_OPERATION); + data = data.slice(idx + 1); + idx = data.indexOf(NEW_LINE); + } + buffer.push(data); +}); + +type LayoutTree = [ + string, + { children?: LayoutTree }, + { page: () => any } | { layout: () => any } +]; + +type ServerComponentsManifest = { + [id: string]: ServerComponentsManifestModule; +}; +type ServerComponentsManifestModule = { + [exportName: string]: { id: string; chunks: string[]; name: string }; +}; + +async function operation(renderData: RenderData) { + const pageModule = LAYOUT_INFO[LAYOUT_INFO.length - 1].module; + const Page = pageModule.default; + let tree: LayoutTree = ["", {}, { page: () => Page }]; + for (let i = LAYOUT_INFO.length - 2; i >= 0; i--) { + const info = LAYOUT_INFO[i]; + const Layout = info.module.default; + tree = [info.segment, { children: tree }, { layout: () => Layout }]; + } + + const proxyMethodsForModule = ( + id: string + ): ProxyHandler => ({ + get(target, name, receiver) { + return { + id, + chunks: JSON.parse(id)[2], + name, + }; + }, + }); + const proxyMethods: ProxyHandler = { + get(target, name, receiver) { + if (name === "__ssr_module_mapping__") { + return manifest; + } + return new Proxy({}, proxyMethodsForModule(name as string)); + }, + }; + const manifest: FlightManifest = new Proxy({} as any, proxyMethods); + const req: IncomingMessage = { + url: renderData.url, + method: renderData.method, + headers: renderData.headers, + } as any; + const res: ServerResponse = new ServerResponseShim(req) as any; + const renderOpt: Omit< + RenderOpts, + "App" | "Document" | "Component" | "pathname" + > & { params: ParsedUrlQuery } = { + params: renderData.params, + supportsDynamicHTML: true, + dev: true, + buildManifest: { + polyfillFiles: [], + rootMainFiles: LAYOUT_INFO.flatMap(({ chunks }) => chunks).concat( + BOOTSTRAP + ), + devFiles: [], + ampDevFiles: [], + lowPriorityFiles: [], + pages: { + "/_app": [], + }, + ampFirstPages: [], + }, + ComponentMod: { + ...pageModule, + default: undefined, + tree, + pages: [], + }, + serverComponentManifest: manifest, + serverCSSManifest: {}, + runtime: "nodejs", + serverComponents: true, + assetPrefix: "", + pageConfig: pageModule.config, + reactLoadableManifest: {}, + }; + const result = await renderToHTMLOrFlight( + req, + res, + renderData.path, + { + ...renderData.query, + ...renderData.params, + }, + renderOpt as any as RenderOpts + ); + + if (!result) throw new Error("rendering was not successful"); + + let body; + if (result.isDynamic()) { + const stream = new PassThrough(); + result.pipe(stream); + + const chunks = []; + for await (const chunk of stream) { + chunks.push(chunk); + } + body = Buffer.concat(chunks).toString(); + } else { + body = result.toUnchunkedString(); + } + return { + contentType: result.contentType(), + body, + }; +} + +// This utility is based on https://github.com/zertosh/htmlescape +// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE + +const ESCAPE_LOOKUP = { + "&": "\\u0026", + ">": "\\u003e", + "<": "\\u003c", + "\u2028": "\\u2028", + "\u2029": "\\u2029", +}; + +const ESCAPE_REGEX = /[&><\u2028\u2029]/g; + +export function htmlEscapeJsonString(str: string) { + return str.replace( + ESCAPE_REGEX, + (match) => ESCAPE_LOOKUP[match as keyof typeof ESCAPE_LOOKUP] + ); +} diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx new file mode 100644 index 00000000000000..50059fb25b4c05 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx @@ -0,0 +1,147 @@ +import ReactDOMClient from "react-dom/client"; +import React, { experimental_use as use } from "react"; +import type { ReactElement } from "react"; +import { createFromReadableStream } from "next/dist/compiled/react-server-dom-webpack"; + +import { HeadManagerContext } from "next/dist/shared/lib/head-manager-context"; + +globalThis.__next_require__ = (data) => { + const [, client_id] = JSON.parse(data); + return __turbopack_require__(client_id); +}; +globalThis.__next_chunk_load__ = __turbopack_load__; + +process.env.__NEXT_NEW_LINK_BEHAVIOR = true; + +const appElement = document; + +const getCacheKey = () => { + const { pathname, search } = location; + return pathname + search; +}; + +const encoder = new TextEncoder(); +let initialServerDataBuffer: string[] | undefined = undefined; +let initialServerDataWriter: ReadableStreamDefaultController | undefined = + undefined; +let initialServerDataLoaded = false; +let initialServerDataFlushed = false; + +function nextServerDataCallback( + seg: [isBootStrap: 0] | [isNotBootstrap: 1, responsePartial: string] +): number { + if (seg[0] === 0) { + initialServerDataBuffer = []; + } else { + if (!initialServerDataBuffer) + throw new Error("Unexpected server data: missing bootstrap script."); + + if (initialServerDataWriter) { + initialServerDataWriter.enqueue(encoder.encode(seg[1])); + } else { + initialServerDataBuffer.push(seg[1]); + } + } + return 0; +} + +function nextServerDataRegisterWriter(ctr) { + if (initialServerDataBuffer) { + initialServerDataBuffer.forEach((val) => { + ctr.enqueue(encoder.encode(val)); + }); + if (initialServerDataLoaded && !initialServerDataFlushed) { + ctr.close(); + initialServerDataFlushed = true; + initialServerDataBuffer = undefined; + } + } + + initialServerDataWriter = ctr; +} + +// When `DOMContentLoaded`, we can close all pending writers to finish hydration. +const DOMContentLoaded = function () { + if (initialServerDataWriter && !initialServerDataFlushed) { + initialServerDataWriter.close(); + initialServerDataFlushed = true; + initialServerDataBuffer = undefined; + } + initialServerDataLoaded = true; +}; +// It's possible that the DOM is already loaded. +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", DOMContentLoaded, false); +} else { + DOMContentLoaded(); +} + +const nextServerDataLoadingGlobal = (self.__next_f = self.__next_f || []); +nextServerDataLoadingGlobal.forEach(nextServerDataCallback); +nextServerDataLoadingGlobal.push = nextServerDataCallback; + +function createResponseCache() { + return new Map(); +} +const rscCache = createResponseCache(); + +function useInitialServerResponse(cacheKey: string) { + const response = rscCache.get(cacheKey); + if (response) return response; + + const readable = new ReadableStream({ + start(controller) { + nextServerDataRegisterWriter(controller); + }, + }); + + const newResponse = createFromReadableStream(readable); + + rscCache.set(cacheKey, newResponse); + return newResponse; +} + +function ServerRoot({ cacheKey }: { cacheKey: string }) { + React.useEffect(() => { + rscCache.delete(cacheKey); + }); + const response = useInitialServerResponse(cacheKey); + const root = use(response) as ReactElement; + return root; +} + +function RSCComponent() { + const cacheKey = getCacheKey(); + return ; +} + +function hydrate() { + const reactEl = ( + + + + + + ); + + const isError = document.documentElement.id === "__next_error__"; + if (isError) { + const reactRoot = ReactDOMClient.createRoot(appElement); + reactRoot.render(reactEl); + } else { + React.startTransition(() => { + ReactDOMClient.hydrateRoot(appElement, reactEl); + }); + } +} + +window.next = { + version: "turbo", + appDir: true, +}; + +hydrate(); diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/index.d.ts b/packages/next-swc/crates/next-core/js/src/entry/app/index.d.ts new file mode 100644 index 00000000000000..df1093e038400d --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/app/index.d.ts @@ -0,0 +1,7 @@ +// this file is just here to make typescript happy about the wrapped/virtual assets (import ".") + +declare var Anything: any; +export = Anything; + +export const __turbopack_module_id__: string | number; +export const chunks: string[]; diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx new file mode 100644 index 00000000000000..c5c5dd57d3a455 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx @@ -0,0 +1,10 @@ +export { default as AppRouter } from "next/dist/client/components/app-router.js"; +export { default as LayoutRouter } from "next/dist/client/components/layout-router.js"; +export { default as RenderFromTemplateContext } from "next/dist/client/components/render-from-template-context.js"; +export { staticGenerationAsyncStorage } from "next/dist/esm/client/components/static-generation-async-storage.js"; +export { requestAsyncStorage } from "next/dist/esm/client/components/request-async-storage.js"; +import * as serverHooks from "next/dist/esm/client/components/hooks-server-context.js"; +export { serverHooks }; +export { renderToReadableStream } from "next/dist/compiled/react-server-dom-webpack/writer.browser.server"; + +export { default } from "."; diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx new file mode 100644 index 00000000000000..46d48673124f87 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx @@ -0,0 +1,9 @@ +import { createProxy } from "next/dist/build/webpack/loaders/next-flight-loader/module-proxy"; + +("TURBOPACK { transition: next-ssr-client-module; chunking-type: parallel }"); +import { __turbopack_module_id__ as id } from "."; + +("TURBOPACK { transition: next-client-chunks }"); +import client_id, { chunks } from "."; + +export default createProxy(JSON.stringify([id, client_id, chunks])); diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 8bea5885aa8d0a..2b79d91855d2a7 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -1,10 +1,11 @@ import type { IncomingMessage, ServerResponse } from "node:http"; import "@vercel/turbopack-next/internal/shims"; -import "next/dist/server/node-polyfill-fetch"; - -import { RenderOpts, renderToHTML } from "next/dist/server/render"; -import { NextParsedUrlQuery } from "next/dist/server/request-meta"; +import "next/dist/server/node-polyfill-fetch.js"; +import { renderToHTML } from "next/dist/server/render"; +import type { RenderOpts } from "next/dist/server/render"; +import type { RenderData } from "types/turbopack"; +import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; import App from "@vercel/turbopack-next/pages/_app"; import Document from "@vercel/turbopack-next/pages/_document"; @@ -12,8 +13,8 @@ import Document from "@vercel/turbopack-next/pages/_document"; import Component, * as otherExports from "."; ("TURBOPACK { transition: next-client }"); import chunkGroup from "."; -import { BuildManifest } from "next/dist/server/get-page-files"; -import { ChunkGroup } from "types/next"; +import type { BuildManifest } from "next/dist/server/get-page-files"; +import type { ChunkGroup } from "types/next"; const END_OF_OPERATION = process.argv[2]; const NEW_LINE = "\n".charCodeAt(0); @@ -40,118 +41,6 @@ process.stdin.on("data", async (data) => { buffer.push(data); }); -/** - * Shim for Node.js's http.ServerResponse - * - * @type {ServerResponse} - */ -class ServerResponseShim { - headersSent = false; - #headers: Map> = new Map(); - req: IncomingMessage; - - constructor(req: IncomingMessage) { - this.req = req; - } - - setHeader(name: string, value: number | string | ReadonlyArray) { - this.#headers.set(name.toLowerCase(), value); - return this; - } - - getHeader(name: string) { - return this.#headers.get(name.toLowerCase()); - } - - getHeaderNames() { - return Array.from(this.#headers.keys()); - } - - getHeaders() { - return Object.fromEntries(this.#headers); - } - - hasHeader(name: string) { - return this.#headers.has(name.toLowerCase()); - } - - removeHeader(name: string) { - this.#headers.delete(name.toLowerCase()); - } - - get statusCode() { - throw new Error("statusCode is not implemented"); - } - - set statusCode(code) { - throw new Error("set statusCode is not implemented"); - } - - get statusMessage() { - throw new Error("statusMessage is not implemented"); - } - - set statusMessage(message) { - throw new Error("set statusMessage is not implemented"); - } - - get socket() { - throw new Error("socket is not implemented"); - } - - get sendDate() { - throw new Error("sendDate is not implemented"); - } - - flushHeaders() { - throw new Error("flushHeaders is not implemented"); - } - - end() { - throw new Error("end is not implemented"); - } - - cork() { - throw new Error("cork is not implemented"); - } - - uncork() { - throw new Error("uncork is not implemented"); - } - - addTrailers() { - throw new Error("addTrailers is not implemented"); - } - - setTimeout(_msecs: any, _callback: any) { - throw new Error("setTimeout is not implemented"); - } - - get writableEnded() { - throw new Error("writableEnded is not implemented"); - } - - get writableFinished() { - throw new Error("writableFinished is not implemented"); - } - - write(_chunk: any, _encoding: any, _callback: any) { - throw new Error("write is not implemented"); - } - - writeContinue() { - throw new Error("writeContinue is not implemented"); - } - - writeHead(_statusCode: any, _statusMessage: any, _headers: any) { - throw new Error("writeHead is not implemented"); - } - - writeProcessing() { - throw new Error("writeProcessing is not implemented"); - } -} - type QueryValue = string | QueryValue[] | Query; interface Query { [key: string]: QueryValue; @@ -159,15 +48,6 @@ interface Query { type HeaderValue = string | string[]; -type RenderData = { - params: Record; - method: string; - url: string; - path: string; - query: NextParsedUrlQuery; - headers: Record; -}; - async function operation(renderData: RenderData) { // TODO(alexkirsz) This is missing *a lot* of data, but it's enough to get a // basic render working. @@ -179,7 +59,7 @@ async function operation(renderData: RenderData) { // computing the chunk items of `next-hydrate.js`, so they contain both // _app and page chunks. "/_app": [], - [renderData.path]: group.map((chunk) => chunk.path), + [renderData.path]: group, }, devFiles: [], diff --git a/packages/next-swc/crates/next-core/js/src/internal/http.ts b/packages/next-swc/crates/next-core/js/src/internal/http.ts new file mode 100644 index 00000000000000..292b80874d7511 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/internal/http.ts @@ -0,0 +1,113 @@ +import type { IncomingMessage, ServerResponse } from "node:http"; + +/** + * Shim for Node.js's http.ServerResponse + * + * @type {ServerResponse} + */ +export class ServerResponseShim { + headersSent = false; + #headers: Map> = new Map(); + req: IncomingMessage; + + constructor(req: IncomingMessage) { + this.req = req; + } + + setHeader(name: string, value: number | string | ReadonlyArray) { + this.#headers.set(name.toLowerCase(), value); + return this; + } + + getHeader(name: string) { + return this.#headers.get(name.toLowerCase()); + } + + getHeaderNames() { + return Array.from(this.#headers.keys()); + } + + getHeaders() { + return Object.fromEntries(this.#headers); + } + + hasHeader(name: string) { + return this.#headers.has(name.toLowerCase()); + } + + removeHeader(name: string) { + this.#headers.delete(name.toLowerCase()); + } + + get statusCode() { + throw new Error("statusCode is not implemented"); + } + + set statusCode(code) { + throw new Error("set statusCode is not implemented"); + } + + get statusMessage() { + throw new Error("statusMessage is not implemented"); + } + + set statusMessage(message) { + throw new Error("set statusMessage is not implemented"); + } + + get socket() { + throw new Error("socket is not implemented"); + } + + get sendDate() { + throw new Error("sendDate is not implemented"); + } + + flushHeaders() { + throw new Error("flushHeaders is not implemented"); + } + + end() { + throw new Error("end is not implemented"); + } + + cork() { + throw new Error("cork is not implemented"); + } + + uncork() { + throw new Error("uncork is not implemented"); + } + + addTrailers() { + throw new Error("addTrailers is not implemented"); + } + + setTimeout(_msecs: any, _callback: any) { + throw new Error("setTimeout is not implemented"); + } + + get writableEnded() { + throw new Error("writableEnded is not implemented"); + } + + get writableFinished() { + throw new Error("writableFinished is not implemented"); + } + + write(_chunk: any, _encoding: any, _callback: any) { + throw new Error("write is not implemented"); + } + + writeContinue() { + throw new Error("writeContinue is not implemented"); + } + + writeHead(_statusCode: any, _statusMessage: any, _headers: any) { + throw new Error("writeHead is not implemented"); + } + + writeProcessing() { + throw new Error("writeProcessing is not implemented"); + } +} diff --git a/packages/next-swc/crates/next-core/js/types/globals.d.ts b/packages/next-swc/crates/next-core/js/types/globals.d.ts index 0ab345f1d8c1eb..4a40ad0a49015a 100644 --- a/packages/next-swc/crates/next-core/js/types/globals.d.ts +++ b/packages/next-swc/crates/next-core/js/types/globals.d.ts @@ -1,7 +1,16 @@ declare global { + function __turbopack_require__(name: any): any; + function __turbopack_load__(path: string): any; function __webpack_require__(name: any): any; var __webpack_public_path__: string | undefined; var __DEV_MIDDLEWARE_MATCHERS: any[]; + + var __next_require__: (id: string) => any; + var __next_chunk_load__: (id: string) => Promise; + var __next_f: ( + | [isBootStrap: 0] + | [isNotBootstrap: 1, responsePartial: string] + )[]; } export {}; diff --git a/packages/next-swc/crates/next-core/js/types/modules.d.ts b/packages/next-swc/crates/next-core/js/types/modules.d.ts new file mode 100644 index 00000000000000..1996418b14e702 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/types/modules.d.ts @@ -0,0 +1,4 @@ +declare module "next/dist/esm/client/components/static-generation-async-storage.js"; +declare module "next/dist/esm/client/components/request-async-storage.js"; +declare module "next/dist/esm/client/components/hooks-server-context.js"; +declare module "next/dist/compiled/react-server-dom-webpack/writer.browser.server"; diff --git a/packages/next-swc/crates/next-core/js/types/turbopack.d.ts b/packages/next-swc/crates/next-core/js/types/turbopack.d.ts new file mode 100644 index 00000000000000..c5db917ff38787 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/types/turbopack.d.ts @@ -0,0 +1,8 @@ +export type RenderData = { + params: Record; + method: string; + url: string; + path: string; + query: NextParsedUrlQuery; + headers: Record; +}; diff --git a/packages/next-swc/crates/next-core/src/app_render/mod.rs b/packages/next-swc/crates/next-core/src/app_render/mod.rs new file mode 100644 index 00000000000000..d02da5ff88008f --- /dev/null +++ b/packages/next-swc/crates/next-core/src/app_render/mod.rs @@ -0,0 +1,12 @@ +use turbo_tasks_fs::FileSystemPathVc; + +pub mod next_layout_entry_transition; + +#[turbo_tasks::value(shared)] +pub struct LayoutSegment { + pub file: FileSystemPathVc, + pub target: FileSystemPathVc, +} + +#[turbo_tasks::value(transparent)] +pub struct LayoutSegments(Vec); diff --git a/packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs b/packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs new file mode 100644 index 00000000000000..0155daa8b52b30 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs @@ -0,0 +1,77 @@ +use anyhow::Result; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{ + self, + module_options::ModuleOptionsContextVc, + resolve_options_context::ResolveOptionsContextVc, + transition::{Transition, TransitionVc}, + ModuleAssetContextVc, +}; +use turbopack_core::{asset::AssetVc, environment::EnvironmentVc, virtual_asset::VirtualAssetVc}; +use turbopack_ecmascript::chunk::EcmascriptChunkPlaceableVc; + +use crate::{ + embed_js::next_js_file, next_client_component::with_client_chunks::WithClientChunksAsset, +}; + +#[turbo_tasks::value(shared)] +pub struct NextLayoutEntryTransition { + pub rsc_environment: EnvironmentVc, + pub rsc_module_options_context: ModuleOptionsContextVc, + pub rsc_resolve_options_context: ResolveOptionsContextVc, + pub server_root: FileSystemPathVc, +} + +#[turbo_tasks::value_impl] +impl Transition for NextLayoutEntryTransition { + #[turbo_tasks::function] + fn process_source(&self, asset: AssetVc) -> AssetVc { + VirtualAssetVc::new( + asset.path().join("layout-entry.tsx"), + next_js_file("entry/app/layout-entry.tsx").into(), + ) + .into() + } + + #[turbo_tasks::function] + fn process_environment(&self, _environment: EnvironmentVc) -> EnvironmentVc { + self.rsc_environment + } + + #[turbo_tasks::function] + fn process_module_options_context( + &self, + _context: ModuleOptionsContextVc, + ) -> ModuleOptionsContextVc { + self.rsc_module_options_context + } + + #[turbo_tasks::function] + fn process_resolve_options_context( + &self, + _context: ResolveOptionsContextVc, + ) -> ResolveOptionsContextVc { + self.rsc_resolve_options_context + } + + #[turbo_tasks::function] + async fn process_module( + &self, + asset: AssetVc, + _context: ModuleAssetContextVc, + ) -> Result { + Ok( + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { + WithClientChunksAsset { + asset: placeable, + // next.js code already adds _next prefix + server_root: self.server_root.join("_next"), + } + .cell() + .into() + } else { + asset + }, + ) + } +} diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs new file mode 100644 index 00000000000000..5f4b6fb802e12a --- /dev/null +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -0,0 +1,423 @@ +use std::{collections::HashMap, fmt::Write}; + +use anyhow::{anyhow, Result}; +use turbo_tasks::{TryJoinIterExt, Value, ValueToString}; +use turbo_tasks_env::ProcessEnvVc; +use turbo_tasks_fs::{ + DirectoryContent, DirectoryEntry, File, FileContent, FileSystemEntryType, FileSystemPathVc, +}; +use turbopack::{ + ecmascript::EcmascriptInputTransform, + transition::{TransitionVc, TransitionsByNameVc}, + ModuleAssetContextVc, +}; +use turbopack_core::{ + chunk::dev::DevChunkingContextVc, context::AssetContextVc, virtual_asset::VirtualAssetVc, +}; +use turbopack_dev_server::source::{ + combined::{CombinedContentSource, CombinedContentSourceVc}, + ContentSourceVc, NoContentSourceVc, +}; +use turbopack_ecmascript::{ + chunk::EcmascriptChunkPlaceablesVc, magic_identifier, utils::stringify_str, + EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, +}; +use turbopack_env::ProcessEnvAssetVc; + +use crate::{ + app_render::{ + next_layout_entry_transition::NextLayoutEntryTransition, LayoutSegment, LayoutSegmentsVc, + }, + embed_js::{next_js_file, wrap_with_next_js_fs}, + next_client::{ + context::{ + get_client_chunking_context, get_client_environment, get_client_module_options_context, + get_client_resolve_options_context, get_client_runtime_entries, ContextType, + }, + NextClientTransition, + }, + next_client_component::{ + client_chunks_transition::NextClientChunksTransition, + server_to_client_transition::NextServerToClientTransition, + ssr_client_module_transition::NextSSRClientModuleTransition, + }, + next_server::{ + get_server_environment, get_server_module_options_context, + get_server_resolve_options_context, ServerContextType, + }, + nodejs::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, + util::regular_expression_for_path, +}; + +#[turbo_tasks::function] +fn next_client_chunks_transition( + project_root: FileSystemPathVc, + app_dir: FileSystemPathVc, + server_root: FileSystemPathVc, + browserslist_query: &str, +) -> TransitionVc { + let ty = Value::new(ContextType::App { app_dir }); + let client_chunking_context = get_client_chunking_context(project_root, server_root, ty); + let client_environment = get_client_environment(browserslist_query); + + let client_module_options_context = + get_client_module_options_context(project_root, client_environment, ty); + NextClientChunksTransition { + client_chunking_context, + client_module_options_context, + client_resolve_options_context: get_client_resolve_options_context(project_root, ty), + client_environment, + server_root, + } + .cell() + .into() +} + +#[turbo_tasks::function] +async fn next_client_transition( + project_root: FileSystemPathVc, + server_root: FileSystemPathVc, + app_dir: FileSystemPathVc, + env: ProcessEnvVc, + browserslist_query: &str, +) -> Result { + let ty = Value::new(ContextType::App { app_dir }); + let client_chunking_context = get_client_chunking_context(project_root, server_root, ty); + let client_environment = get_client_environment(browserslist_query); + let client_module_options_context = + get_client_module_options_context(project_root, client_environment, ty); + let client_runtime_entries = get_client_runtime_entries(project_root, env, ty); + let client_resolve_options_context = get_client_resolve_options_context(project_root, ty); + + Ok(NextClientTransition { + is_app: true, + server_root, + client_chunking_context, + client_module_options_context, + client_resolve_options_context, + client_environment, + runtime_entries: client_runtime_entries, + } + .cell() + .into()) +} + +#[turbo_tasks::function] +fn next_ssr_client_module_transition( + project_path: FileSystemPathVc, + app_dir: FileSystemPathVc, +) -> TransitionVc { + let ty = Value::new(ServerContextType::AppSSR { app_dir }); + NextSSRClientModuleTransition { + ssr_module_options_context: get_server_module_options_context(ty), + ssr_resolve_options_context: get_server_resolve_options_context(project_path, ty), + ssr_environment: get_server_environment(ty), + } + .cell() + .into() +} + +#[turbo_tasks::function] +fn next_layout_entry_transition( + project_root: FileSystemPathVc, + app_dir: FileSystemPathVc, + server_root: FileSystemPathVc, +) -> TransitionVc { + let ty = Value::new(ServerContextType::AppRSC { app_dir }); + let rsc_environment = get_server_environment(ty); + let rsc_resolve_options_context = get_server_resolve_options_context(project_root, ty); + let rsc_module_options_context = get_server_module_options_context(ty); + + NextLayoutEntryTransition { + rsc_environment, + rsc_module_options_context, + rsc_resolve_options_context, + server_root, + } + .cell() + .into() +} + +/// Create a content source serving the `app` or `src/app` directory as +/// Next.js app folder. +#[turbo_tasks::function] +pub async fn create_app_source( + project_root: FileSystemPathVc, + output_path: FileSystemPathVc, + server_root: FileSystemPathVc, + env: ProcessEnvVc, + browserslist_query: &str, +) -> Result { + let project_root = wrap_with_next_js_fs(project_root); + + let app = project_root.join("app"); + let src_app = project_root.join("src/app"); + let app_dir = if *app.get_type().await? == FileSystemEntryType::Directory { + app + } else if *src_app.get_type().await? == FileSystemEntryType::Directory { + src_app + } else { + return Ok(NoContentSourceVc::new().into()); + }; + + let next_server_to_client_transition = NextServerToClientTransition {}.cell().into(); + + let mut transitions = HashMap::new(); + transitions.insert( + "next-layout-entry".to_string(), + next_layout_entry_transition(project_root, app_dir, server_root), + ); + transitions.insert( + "server-to-client".to_string(), + next_server_to_client_transition, + ); + transitions.insert( + "next-client".to_string(), + next_client_transition(project_root, server_root, app_dir, env, browserslist_query), + ); + transitions.insert( + "next-client-chunks".to_string(), + next_client_chunks_transition(project_root, app_dir, server_root, browserslist_query), + ); + transitions.insert( + "next-ssr-client-module".to_string(), + next_ssr_client_module_transition(project_root, app_dir), + ); + + let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir }); + let context: AssetContextVc = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(transitions), + get_server_environment(ssr_ty), + get_server_module_options_context(ssr_ty), + get_server_resolve_options_context(project_root, ssr_ty), + ) + .into(); + + let server_runtime_entries = + vec![ProcessEnvAssetVc::new(project_root, env).as_ecmascript_chunk_placeable()]; + + Ok(create_app_source_for_directory( + context, + project_root, + app_dir, + server_root, + EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), + server_root, + LayoutSegmentsVc::cell(Vec::new()), + output_path, + ) + .into()) +} + +#[turbo_tasks::function] +async fn create_app_source_for_directory( + context: AssetContextVc, + project_root: FileSystemPathVc, + input_dir: FileSystemPathVc, + server_root: FileSystemPathVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + target: FileSystemPathVc, + layouts: LayoutSegmentsVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + let mut layouts = layouts; + let mut sources = Vec::new(); + let mut page = None; + let mut layout = None; + if let DirectoryContent::Entries(entries) = &*input_dir.read_dir().await? { + for (name, entry) in entries.iter() { + if let DirectoryEntry::File(file) = entry { + if let Some((name, _)) = name.rsplit_once('.') { + match name { + "page" => { + page = Some(file); + } + "layout" => { + layout = Some(file); + } + "error" => { /* TODO */ } + "loading" => { /* TODO */ } + _ => { + // Any other file is ignored + } + } + } + } + } + if let Some(file) = layout.copied() { + let mut list = layouts.await?.clone_value(); + list.push(LayoutSegment { file, target }.cell()); + layouts = LayoutSegmentsVc::cell(list); + } + if let Some(file) = page.copied() { + let mut list = layouts.await?.clone_value(); + list.push(LayoutSegment { file, target }.cell()); + let layout_path = LayoutSegmentsVc::cell(list); + + let chunking_context = DevChunkingContextVc::new_with_layer( + project_root, + intermediate_output_path, + intermediate_output_path.join("chunks"), + server_root.join("_next/static/assets"), + false, + "ssr", + ) + .into(); + + sources.push(create_node_rendered_source( + server_root, + regular_expression_for_path(server_root, target, false), + AppRenderer { + context, + server_root, + layout_path, + } + .cell() + .into(), + chunking_context, + runtime_entries, + intermediate_output_path, + )); + } + for (name, entry) in entries.iter() { + if let DirectoryEntry::Directory(dir) = entry { + let intermediate_output_path = intermediate_output_path.join(name); + let new_target = if name.starts_with('(') && name.ends_with(')') { + // This doesn't affect the url + target + } else { + // This adds to the url + target.join(name) + }; + sources.push( + create_app_source_for_directory( + context, + project_root, + *dir, + server_root, + runtime_entries, + new_target, + layouts, + intermediate_output_path, + ) + .into(), + ); + } + } + } + Ok(CombinedContentSource { sources }.cell()) +} + +#[turbo_tasks::value] +struct AppRenderer { + context: AssetContextVc, + server_root: FileSystemPathVc, + layout_path: LayoutSegmentsVc, +} + +#[turbo_tasks::value_impl] +impl NodeRenderer for AppRenderer { + #[turbo_tasks::function] + async fn module(&self) -> Result { + let layout_path = self.layout_path.await?; + let page = layout_path + .last() + .ok_or_else(|| anyhow!("layout path must not be empty"))?; + let path = page.await?.file.parent(); + let path_value = &*path.await?; + let segments = layout_path + .iter() + .copied() + .try_join() + .await? + .into_iter() + .fold( + (self.server_root, Vec::new()), + |(last_path, mut futures), segment| { + (segment.target, { + futures.push(async move { + let file_str = segment.file.to_string().await?; + let target = &*segment.target.await?; + let segment_path = + last_path.await?.get_path_to(target).unwrap_or_default(); + let identifier = magic_identifier::encode(&format!( + "imported namespace {}", + file_str + )); + let chunks_identifier = magic_identifier::encode(&format!( + "client chunks for {}", + file_str + )); + if let Some(p) = path_value.get_relative_path_to(&*segment.file.await?) + { + Ok(( + p, + stringify_str(segment_path), + identifier, + chunks_identifier, + )) + } else { + Err(anyhow!( + "Unable to generate import as there is no relative path to \ + the layout module {} from context path {}", + file_str, + path.to_string().await? + )) + } + }); + futures + }) + }, + ) + .1 + .into_iter() + .try_join() + .await?; + let mut result = String::new(); + for (p, _, identifier, chunks_identifier) in segments.iter() { + writeln!( + result, + r#"("TURBOPACK {{ transition: next-layout-entry; chunking-type: parallel }}"); +import {}, {{ chunks as {} }} from {}; +"#, + identifier, + chunks_identifier, + stringify_str(p) + )? + } + if let Some(page) = path_value.get_relative_path_to(&*page.await?.file.await?) { + writeln!( + result, + r#"("TURBOPACK {{ transition: next-client }}"); +import BOOTSTRAP from {}; +"#, + stringify_str(&page) + )?; + } + result.push_str("const LAYOUT_INFO = ["); + for (_, segment_str_lit, identifier, chunks_identifier) in segments.iter() { + writeln!( + result, + " {{ segment: {segment_str_lit}, module: {identifier}, chunks: \ + {chunks_identifier} }},", + )? + } + result.push_str("];\n\n"); + let base_code = next_js_file("entry/app-renderer.tsx"); + let mut file = File::from(result); + if let FileContent::Content(base_file) = &*base_code.await? { + file.push_content(base_file.content()); + } + let asset = VirtualAssetVc::new(path.join("entry"), FileContent::Content(file).into()); + Ok(EcmascriptModuleAssetVc::new( + asset.into(), + self.context, + Value::new(EcmascriptModuleAssetType::Typescript), + EcmascriptInputTransformsVc::cell(vec![ + EcmascriptInputTransform::React { refresh: false }, + EcmascriptInputTransform::TypeScript, + ]), + self.context.environment(), + )) + } +} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 915fd66d1ee779..038f20a6e6d828 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -1,16 +1,22 @@ #![feature(async_closure)] #![feature(min_specialization)] +mod app_render; +mod app_source; mod embed_js; pub mod env; pub mod next_client; +mod next_client_component; mod next_import_map; +pub mod next_server; mod nodejs; mod path_regex; pub mod react_refresh; mod server_rendered_source; +mod util; mod web_entry_source; +pub use app_source::create_app_source; pub use server_rendered_source::create_server_rendered_source; pub use web_entry_source::create_web_entry_source; diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 793b18472f649f..adf6984cc6cdae 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -20,9 +20,10 @@ use turbopack_core::{ use turbopack_env::ProcessEnvAssetVc; use crate::{ - embed_js::next_js_fs, + embed_js::attached_next_js_package_path, env::filter_for_client, next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, + next_import_map::{get_next_client_fallback_import_map, get_next_client_import_map}, react_refresh::assert_can_resolve_react_refresh, }; @@ -42,13 +43,28 @@ pub fn get_client_environment(browserslist_query: &str) -> EnvironmentVc { ) } +#[turbo_tasks::value(serialization = "auto_for_input")] +#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] +pub enum ContextType { + Pages { pages_dir: FileSystemPathVc }, + App { app_dir: FileSystemPathVc }, + Other, +} + #[turbo_tasks::function] -pub fn get_client_resolve_options_context() -> ResolveOptionsContextVc { +pub fn get_client_resolve_options_context( + project_root: FileSystemPathVc, + ty: Value, +) -> ResolveOptionsContextVc { + let next_client_import_map = get_next_client_import_map(project_root, ty); + let next_client_fallback_import_map = get_next_client_fallback_import_map(ty); ResolveOptionsContext { enable_typescript: true, enable_react: true, enable_node_modules: true, custom_conditions: vec!["development".to_string()], + import_map: Some(next_client_import_map), + fallback_import_map: Some(next_client_fallback_import_map), browser: true, module: true, ..Default::default() @@ -60,8 +76,9 @@ pub fn get_client_resolve_options_context() -> ResolveOptionsContextVc { pub async fn get_client_module_options_context( project_root: FileSystemPathVc, env: EnvironmentVc, + ty: Value, ) -> Result { - let resolve_options_context = get_client_resolve_options_context(); + let resolve_options_context = get_client_resolve_options_context(project_root, ty); let enable_react_refresh = assert_can_resolve_react_refresh(project_root, resolve_options_context) .await? @@ -84,10 +101,11 @@ pub async fn get_client_module_options_context( pub fn get_client_asset_context( project_root: FileSystemPathVc, browserslist_query: &str, + ty: Value, ) -> AssetContextVc { let environment = get_client_environment(browserslist_query); - let resolve_options_context = get_client_resolve_options_context(); - let module_options_context = get_client_module_options_context(project_root, environment); + let resolve_options_context = get_client_resolve_options_context(project_root, ty); + let module_options_context = get_client_module_options_context(project_root, environment, ty); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -104,29 +122,43 @@ pub fn get_client_asset_context( pub fn get_client_chunking_context( project_root: FileSystemPathVc, server_root: FileSystemPathVc, + ty: Value, ) -> ChunkingContextVc { DevChunkingContextVc::new( project_root, server_root, - server_root.join("/_next/static/chunks"), - get_client_assets_path(server_root), + match ty.into_value() { + ContextType::Pages { .. } | ContextType::App { .. } => { + server_root.join("/_next/static/chunks") + } + ContextType::Other => server_root.join("/_chunks"), + }, + get_client_assets_path(server_root, ty), true, ) .into() } #[turbo_tasks::function] -pub fn get_client_assets_path(server_root: FileSystemPathVc) -> FileSystemPathVc { - server_root.join("/_next/static/assets") +pub fn get_client_assets_path( + server_root: FileSystemPathVc, + ty: Value, +) -> FileSystemPathVc { + match ty.into_value() { + ContextType::Pages { .. } | ContextType::App { .. } => { + server_root.join("/_next/static/assets") + } + ContextType::Other => server_root.join("/_assets"), + } } #[turbo_tasks::function] pub async fn get_client_runtime_entries( project_root: FileSystemPathVc, env: ProcessEnvVc, - bootstrap_dev_client: bool, + ty: Value, ) -> Result { - let resolve_options_context = get_client_resolve_options_context(); + let resolve_options_context = get_client_resolve_options_context(project_root, ty); let enable_react_refresh = assert_can_resolve_react_refresh(project_root, resolve_options_context) .await? @@ -136,13 +168,13 @@ pub async fn get_client_runtime_entries( ProcessEnvAssetVc::new(project_root, filter_for_client(env)).into(), ) .cell()]; - if bootstrap_dev_client { + if matches!(ty.into_value(), ContextType::Other) { runtime_entries.push( RuntimeEntry::Request( RequestVc::parse(Value::new(Pattern::Constant( "./dev/bootstrap.ts".to_string(), ))), - next_js_fs().root(), + attached_next_js_package_path(project_root).join("_"), ) .cell(), ); diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index d7b572fe916443..c6f54dbe6ef0bb 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -28,6 +28,7 @@ use crate::embed_js::next_js_file; /// importer that exports an array of chunk urls. #[turbo_tasks::value(shared)] pub struct NextClientTransition { + pub is_app: bool, pub client_environment: EnvironmentVc, pub client_module_options_context: ModuleOptionsContextVc, pub client_resolve_options_context: ResolveOptionsContextVc, @@ -40,11 +41,19 @@ pub struct NextClientTransition { impl Transition for NextClientTransition { #[turbo_tasks::function] fn process_source(&self, asset: AssetVc) -> AssetVc { - VirtualAssetVc::new( - asset.path().join("next-hydrate.tsx"), - next_js_file("entry/next-hydrate.tsx").into(), - ) - .into() + if self.is_app { + VirtualAssetVc::new( + asset.path().join("next-app-hydrate.tsx"), + next_js_file("entry/app/hydrate.tsx").into(), + ) + .into() + } else { + VirtualAssetVc::new( + asset.path().join("next-hydrate.tsx"), + next_js_file("entry/next-hydrate.tsx").into(), + ) + .into() + } } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/next_client_component/client_chunks_transition.rs b/packages/next-swc/crates/next-core/src/next_client_component/client_chunks_transition.rs new file mode 100644 index 00000000000000..5e272081a3c877 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client_component/client_chunks_transition.rs @@ -0,0 +1,66 @@ +use anyhow::Result; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{ + ecmascript::chunk::EcmascriptChunkPlaceableVc, + module_options::ModuleOptionsContextVc, + resolve_options_context::ResolveOptionsContextVc, + transition::{Transition, TransitionVc}, + ModuleAssetContextVc, +}; +use turbopack_core::{asset::AssetVc, chunk::ChunkingContextVc, environment::EnvironmentVc}; + +use super::with_chunks::WithChunksAsset; + +#[turbo_tasks::value(shared)] +pub struct NextClientChunksTransition { + pub client_environment: EnvironmentVc, + pub client_module_options_context: ModuleOptionsContextVc, + pub client_resolve_options_context: ResolveOptionsContextVc, + pub client_chunking_context: ChunkingContextVc, + pub server_root: FileSystemPathVc, +} + +#[turbo_tasks::value_impl] +impl Transition for NextClientChunksTransition { + #[turbo_tasks::function] + fn process_environment(&self, _environment: EnvironmentVc) -> EnvironmentVc { + self.client_environment + } + + #[turbo_tasks::function] + fn process_module_options_context( + &self, + _context: ModuleOptionsContextVc, + ) -> ModuleOptionsContextVc { + self.client_module_options_context + } + + #[turbo_tasks::function] + fn process_resolve_options_context( + &self, + _context: ResolveOptionsContextVc, + ) -> ResolveOptionsContextVc { + self.client_resolve_options_context + } + + #[turbo_tasks::function] + async fn process_module( + &self, + asset: AssetVc, + _context: ModuleAssetContextVc, + ) -> Result { + Ok( + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { + WithChunksAsset { + asset: placeable, + server_root: self.server_root, + chunking_context: self.client_chunking_context, + } + .cell() + .into() + } else { + asset + }, + ) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_client_component/in_chunking_context_asset.rs b/packages/next-swc/crates/next-core/src/next_client_component/in_chunking_context_asset.rs new file mode 100644 index 00000000000000..66fe227995a5a7 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client_component/in_chunking_context_asset.rs @@ -0,0 +1,101 @@ +use anyhow::Result; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::ecmascript::chunk::{ + EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkVc, + EcmascriptExportsVc, +}; +use turbopack_core::{ + asset::{Asset, AssetContentVc, AssetVc}, + chunk::{ChunkVc, ChunkableAsset, ChunkableAssetVc, ChunkingContextVc}, + reference::AssetReferencesVc, +}; + +#[turbo_tasks::value(shared)] +pub struct InChunkingContextAsset { + pub asset: EcmascriptChunkPlaceableVc, + pub chunking_context: ChunkingContextVc, +} + +#[turbo_tasks::value_impl] +impl Asset for InChunkingContextAsset { + #[turbo_tasks::function] + fn path(&self) -> FileSystemPathVc { + self.asset.path() + } + + #[turbo_tasks::function] + fn content(&self) -> AssetContentVc { + self.asset.content() + } + + #[turbo_tasks::function] + fn references(&self) -> AssetReferencesVc { + self.asset.references() + } +} + +#[turbo_tasks::value_impl] +impl ChunkableAsset for InChunkingContextAsset { + #[turbo_tasks::function] + fn as_chunk(&self, _context: ChunkingContextVc) -> ChunkVc { + EcmascriptChunkVc::new(self.chunking_context, self.asset).into() + } +} + +#[turbo_tasks::value_impl] +impl EcmascriptChunkPlaceable for InChunkingContextAsset { + #[turbo_tasks::function] + fn as_chunk_item(&self, _context: ChunkingContextVc) -> EcmascriptChunkItemVc { + self.asset.as_chunk_item(self.chunking_context) + } + + #[turbo_tasks::function] + fn get_exports(&self) -> EcmascriptExportsVc { + self.asset.get_exports() + } +} + +#[turbo_tasks::value(shared)] +pub struct WithChunkingContextScopeAsset { + pub asset: EcmascriptChunkPlaceableVc, + pub layer: String, +} + +#[turbo_tasks::value_impl] +impl Asset for WithChunkingContextScopeAsset { + #[turbo_tasks::function] + fn path(&self) -> FileSystemPathVc { + self.asset.path() + } + + #[turbo_tasks::function] + fn content(&self) -> AssetContentVc { + self.asset.content() + } + + #[turbo_tasks::function] + fn references(&self) -> AssetReferencesVc { + self.asset.references() + } +} + +#[turbo_tasks::value_impl] +impl ChunkableAsset for WithChunkingContextScopeAsset { + #[turbo_tasks::function] + fn as_chunk(&self, context: ChunkingContextVc) -> ChunkVc { + EcmascriptChunkVc::new(context.with_layer(&self.layer), self.asset).into() + } +} + +#[turbo_tasks::value_impl] +impl EcmascriptChunkPlaceable for WithChunkingContextScopeAsset { + #[turbo_tasks::function] + fn as_chunk_item(&self, context: ChunkingContextVc) -> EcmascriptChunkItemVc { + self.asset.as_chunk_item(context.with_layer(&self.layer)) + } + + #[turbo_tasks::function] + fn get_exports(&self) -> EcmascriptExportsVc { + self.asset.get_exports() + } +} diff --git a/packages/next-swc/crates/next-core/src/next_client_component/mod.rs b/packages/next-swc/crates/next-core/src/next_client_component/mod.rs new file mode 100644 index 00000000000000..b606dbf335857e --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client_component/mod.rs @@ -0,0 +1,6 @@ +pub mod client_chunks_transition; +pub mod in_chunking_context_asset; +pub mod server_to_client_transition; +pub mod ssr_client_module_transition; +pub mod with_chunks; +pub mod with_client_chunks; diff --git a/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs b/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs new file mode 100644 index 00000000000000..953d69a8a9c2ac --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs @@ -0,0 +1,19 @@ +use turbopack::transition::{Transition, TransitionVc}; +use turbopack_core::{asset::AssetVc, virtual_asset::VirtualAssetVc}; + +use crate::embed_js::next_js_file; + +#[turbo_tasks::value(shared)] +pub struct NextServerToClientTransition {} + +#[turbo_tasks::value_impl] +impl Transition for NextServerToClientTransition { + #[turbo_tasks::function] + fn process_source(&self, asset: AssetVc) -> AssetVc { + VirtualAssetVc::new( + asset.path().join("client-proxy.tsx"), + next_js_file("entry/app/server-to-client.tsx").into(), + ) + .into() + } +} diff --git a/packages/next-swc/crates/next-core/src/next_client_component/ssr_client_module_transition.rs b/packages/next-swc/crates/next-core/src/next_client_component/ssr_client_module_transition.rs new file mode 100644 index 00000000000000..c090b70d1a5416 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client_component/ssr_client_module_transition.rs @@ -0,0 +1,62 @@ +use anyhow::Result; +use turbopack::{ + ecmascript::chunk::EcmascriptChunkPlaceableVc, + module_options::ModuleOptionsContextVc, + resolve_options_context::ResolveOptionsContextVc, + transition::{Transition, TransitionVc}, + ModuleAssetContextVc, +}; +use turbopack_core::{asset::AssetVc, environment::EnvironmentVc}; + +use super::in_chunking_context_asset::WithChunkingContextScopeAsset; + +#[turbo_tasks::value(shared)] +pub struct NextSSRClientModuleTransition { + pub ssr_environment: EnvironmentVc, + pub ssr_module_options_context: ModuleOptionsContextVc, + pub ssr_resolve_options_context: ResolveOptionsContextVc, +} + +#[turbo_tasks::value_impl] +impl Transition for NextSSRClientModuleTransition { + #[turbo_tasks::function] + fn process_environment(&self, _environment: EnvironmentVc) -> EnvironmentVc { + self.ssr_environment + } + + #[turbo_tasks::function] + fn process_module_options_context( + &self, + _context: ModuleOptionsContextVc, + ) -> ModuleOptionsContextVc { + self.ssr_module_options_context + } + + #[turbo_tasks::function] + fn process_resolve_options_context( + &self, + _context: ResolveOptionsContextVc, + ) -> ResolveOptionsContextVc { + self.ssr_resolve_options_context + } + + #[turbo_tasks::function] + async fn process_module( + &self, + asset: AssetVc, + _context: ModuleAssetContextVc, + ) -> Result { + Ok( + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { + WithChunkingContextScopeAsset { + asset: placeable, + layer: "ssr".to_string(), + } + .cell() + .into() + } else { + asset + }, + ) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs new file mode 100644 index 00000000000000..0ed0e646f1057c --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs @@ -0,0 +1,187 @@ +use anyhow::Result; +use serde_json::Value; +use turbo_tasks::{primitives::StringVc, TryJoinIterExt, ValueToString, ValueToStringVc}; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::ecmascript::{ + chunk::{ + EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, + EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, + EcmascriptChunkVc, EcmascriptExports, EcmascriptExportsVc, + }, + utils::stringify_module_id, +}; +use turbopack_core::{ + asset::{Asset, AssetContentVc, AssetVc}, + chunk::{ + ChunkGroupVc, ChunkItem, ChunkItemVc, ChunkVc, ChunkableAsset, ChunkableAssetReference, + ChunkableAssetReferenceVc, ChunkableAssetVc, ChunkingContextVc, ChunkingType, + ChunkingTypeOptionVc, + }, + reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, + resolve::{ResolveResult, ResolveResultVc}, +}; + +use crate::next_client_component::in_chunking_context_asset::InChunkingContextAsset; + +#[turbo_tasks::value(shared)] +pub struct WithChunksAsset { + pub asset: EcmascriptChunkPlaceableVc, + pub server_root: FileSystemPathVc, + pub chunking_context: ChunkingContextVc, +} + +#[turbo_tasks::value_impl] +impl Asset for WithChunksAsset { + #[turbo_tasks::function] + fn path(&self) -> FileSystemPathVc { + self.asset.path().join("with-chunks.js") + } + + #[turbo_tasks::function] + fn content(&self) -> AssetContentVc { + unimplemented!() + } + + #[turbo_tasks::function] + fn references(&self) -> AssetReferencesVc { + unimplemented!() + } +} + +#[turbo_tasks::value_impl] +impl ChunkableAsset for WithChunksAsset { + #[turbo_tasks::function] + fn as_chunk(self_vc: WithChunksAssetVc, context: ChunkingContextVc) -> ChunkVc { + EcmascriptChunkVc::new(context, self_vc.as_ecmascript_chunk_placeable()).into() + } +} + +#[turbo_tasks::value_impl] +impl EcmascriptChunkPlaceable for WithChunksAsset { + #[turbo_tasks::function] + async fn as_chunk_item( + self_vc: WithChunksAssetVc, + context: ChunkingContextVc, + ) -> Result { + let this = self_vc.await?; + Ok(WithChunksChunkItem { + context, + inner_context: this.chunking_context, + inner: self_vc, + } + .cell() + .into()) + } + + #[turbo_tasks::function] + fn get_exports(&self) -> EcmascriptExportsVc { + // TODO This should be EsmExports + EcmascriptExports::Value.cell() + } +} + +#[turbo_tasks::value] +struct WithChunksChunkItem { + context: ChunkingContextVc, + inner_context: ChunkingContextVc, + inner: WithChunksAssetVc, +} + +#[turbo_tasks::value_impl] +impl ValueToString for WithChunksChunkItem { + #[turbo_tasks::function] + async fn to_string(&self) -> Result { + Ok(StringVc::cell(format!( + "{}/with-chunks.js", + self.inner.await?.asset.path().to_string().await? + ))) + } +} + +#[turbo_tasks::value_impl] +impl EcmascriptChunkItem for WithChunksChunkItem { + #[turbo_tasks::function] + fn chunking_context(&self) -> ChunkingContextVc { + self.context + } + + #[turbo_tasks::function] + async fn content(&self) -> Result { + let inner = self.inner.await?; + let group = ChunkGroupVc::from_asset(inner.asset.into(), self.inner_context); + let chunks = group.chunks().await?; + let server_root = inner.server_root.await?; + let mut client_chunks = Vec::new(); + for chunk_path in chunks.iter().map(|c| c.path()).try_join().await? { + if let Some(path) = server_root.get_path_to(&chunk_path) { + client_chunks.push(Value::String(path.to_string())); + } + } + let module_id = + stringify_module_id(&*inner.asset.as_chunk_item(self.inner_context).id().await?); + Ok(EcmascriptChunkItemContent { + inner_code: format!( + "__turbopack_esm__({{ + default: () => {}, + chunks: () => chunks +}}); +const chunks = {}; +", + module_id, + Value::Array(client_chunks) + ), + ..Default::default() + } + .cell()) + } +} + +#[turbo_tasks::value_impl] +impl ChunkItem for WithChunksChunkItem { + #[turbo_tasks::function] + async fn references(&self) -> Result { + let inner = self.inner.await?; + Ok(AssetReferencesVc::cell(vec![WithChunksAssetReference { + asset: InChunkingContextAsset { + asset: inner.asset, + chunking_context: self.inner_context, + } + .cell() + .into(), + } + .cell() + .into()])) + } +} + +#[turbo_tasks::value] +struct WithChunksAssetReference { + asset: AssetVc, +} + +#[turbo_tasks::value_impl] +impl ValueToString for WithChunksAssetReference { + #[turbo_tasks::function] + async fn to_string(&self) -> Result { + Ok(StringVc::cell(format!( + "referenced asset {}", + self.asset.path().to_string().await? + ))) + } +} + +#[turbo_tasks::value_impl] +impl AssetReference for WithChunksAssetReference { + #[turbo_tasks::function] + fn resolve_reference(&self) -> ResolveResultVc { + ResolveResult::Single(self.asset, Vec::new()).cell() + } +} + +#[turbo_tasks::value_impl] +impl ChunkableAssetReference for WithChunksAssetReference { + #[turbo_tasks::function] + fn chunking_type(&self, _context: ChunkingContextVc) -> ChunkingTypeOptionVc { + ChunkingTypeOptionVc::cell(Some(ChunkingType::Separate)) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs new file mode 100644 index 00000000000000..7490cc856ec538 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs @@ -0,0 +1,196 @@ +use anyhow::Result; +use serde_json::Value; +use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc}; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::ecmascript::{ + chunk::{ + EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, + EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, + EcmascriptChunkVc, EcmascriptExports, EcmascriptExportsVc, + }, + utils::stringify_module_id, +}; +use turbopack_core::{ + asset::{Asset, AssetContentVc, AssetVc}, + chunk::{ + ChunkGroupVc, ChunkItem, ChunkItemVc, ChunkVc, ChunkableAsset, ChunkableAssetReference, + ChunkableAssetReferenceVc, ChunkableAssetVc, ChunkingContextVc, ChunkingType, + ChunkingTypeOptionVc, + }, + reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, + resolve::{ResolveResult, ResolveResultVc}, +}; + +use crate::next_client_component::in_chunking_context_asset::InChunkingContextAsset; + +#[turbo_tasks::value(shared)] +pub struct WithClientChunksAsset { + pub asset: EcmascriptChunkPlaceableVc, + pub server_root: FileSystemPathVc, +} + +#[turbo_tasks::value_impl] +impl Asset for WithClientChunksAsset { + #[turbo_tasks::function] + fn path(&self) -> FileSystemPathVc { + self.asset.path().join("with-client-chunks.js") + } + + #[turbo_tasks::function] + fn content(&self) -> AssetContentVc { + unimplemented!() + } + + #[turbo_tasks::function] + fn references(&self) -> AssetReferencesVc { + unimplemented!() + } +} + +#[turbo_tasks::value_impl] +impl ChunkableAsset for WithClientChunksAsset { + #[turbo_tasks::function] + fn as_chunk(self_vc: WithClientChunksAssetVc, context: ChunkingContextVc) -> ChunkVc { + EcmascriptChunkVc::new( + context.with_layer("rsc"), + self_vc.as_ecmascript_chunk_placeable(), + ) + .into() + } +} + +#[turbo_tasks::value_impl] +impl EcmascriptChunkPlaceable for WithClientChunksAsset { + #[turbo_tasks::function] + fn as_chunk_item( + self_vc: WithClientChunksAssetVc, + context: ChunkingContextVc, + ) -> EcmascriptChunkItemVc { + WithClientChunksChunkItem { + context: context.with_layer("rsc"), + inner: self_vc, + } + .cell() + .into() + } + + #[turbo_tasks::function] + fn get_exports(&self) -> EcmascriptExportsVc { + // TODO This should be EsmExports + EcmascriptExports::Value.cell() + } +} + +#[turbo_tasks::value] +struct WithClientChunksChunkItem { + context: ChunkingContextVc, + inner: WithClientChunksAssetVc, +} + +#[turbo_tasks::value_impl] +impl ValueToString for WithClientChunksChunkItem { + #[turbo_tasks::function] + async fn to_string(&self) -> Result { + Ok(StringVc::cell(format!( + "{}/with-client-chunks.js", + self.inner.await?.asset.path().to_string().await? + ))) + } +} + +#[turbo_tasks::value_impl] +impl EcmascriptChunkItem for WithClientChunksChunkItem { + #[turbo_tasks::function] + fn chunking_context(&self) -> ChunkingContextVc { + self.context + } + + #[turbo_tasks::function] + async fn content(&self) -> Result { + let inner = self.inner.await?; + let group = ChunkGroupVc::from_asset(inner.asset.into(), self.context); + let chunks = group.chunks().await?; + let server_root = inner.server_root.await?; + let mut client_chunks = Vec::new(); + for chunk in chunks.iter() { + for reference in chunk.references().await?.iter() { + let assets = &*reference.resolve_reference().primary_assets().await?; + for asset in assets.iter() { + let path = &*asset.path().await?; + + // only client chunks have an path from the server root + if let Some(path) = server_root.get_path_to(path) { + client_chunks.push(Value::String(path.to_string())); + } + } + } + } + let module_id = stringify_module_id(&*inner.asset.as_chunk_item(self.context).id().await?); + Ok(EcmascriptChunkItemContent { + inner_code: format!( + "__turbopack_esm__({{ + default: () => __turbopack_import__({}), + chunks: () => chunks +}}); +const chunks = {}; +", + module_id, + Value::Array(client_chunks) + ), + ..Default::default() + } + .cell()) + } +} + +#[turbo_tasks::value_impl] +impl ChunkItem for WithClientChunksChunkItem { + #[turbo_tasks::function] + async fn references(&self) -> Result { + let inner = self.inner.await?; + Ok(AssetReferencesVc::cell(vec![ + WithClientChunksAssetReference { + asset: InChunkingContextAsset { + asset: inner.asset, + chunking_context: self.context, + } + .cell() + .into(), + } + .cell() + .into(), + ])) + } +} + +#[turbo_tasks::value] +struct WithClientChunksAssetReference { + asset: AssetVc, +} + +#[turbo_tasks::value_impl] +impl ValueToString for WithClientChunksAssetReference { + #[turbo_tasks::function] + async fn to_string(&self) -> Result { + Ok(StringVc::cell(format!( + "local asset {}", + self.asset.path().to_string().await? + ))) + } +} + +#[turbo_tasks::value_impl] +impl AssetReference for WithClientChunksAssetReference { + #[turbo_tasks::function] + fn resolve_reference(&self) -> ResolveResultVc { + ResolveResult::Single(self.asset, Vec::new()).cell() + } +} + +#[turbo_tasks::value_impl] +impl ChunkableAssetReference for WithClientChunksAssetReference { + #[turbo_tasks::function] + fn chunking_type(&self, _context: ChunkingContextVc) -> ChunkingTypeOptionVc { + ChunkingTypeOptionVc::cell(Some(ChunkingType::PlacedOrParallel)) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index e2e77eaa04d417..37f99849355f23 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -1,51 +1,89 @@ +use turbo_tasks::Value; use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::resolve::options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}; -use crate::embed_js::{attached_next_js_package_path, VIRTUAL_PACKAGE_NAME}; +use crate::{ + embed_js::{attached_next_js_package_path, next_js_fs, VIRTUAL_PACKAGE_NAME}, + next_client::context::ContextType, + next_server::ServerContextType, +}; /// Computes the Next-specific client import map. #[turbo_tasks::function] pub fn get_next_client_import_map( project_path: FileSystemPathVc, - pages_dir: FileSystemPathVc, + ty: Value, ) -> ImportMapVc { let mut import_map = ImportMap::empty(); let package_root = attached_next_js_package_path(project_path); insert_next_shared_aliases(&mut import_map, package_root); - insert_alias_to_alternatives( - &mut import_map, - format!("{VIRTUAL_PACKAGE_NAME}/pages/_app"), - vec![ - request_to_import_mapping(pages_dir, "./_app"), - request_to_import_mapping(pages_dir, "next/app"), - ], - ); - insert_alias_to_alternatives( - &mut import_map, - format!("{VIRTUAL_PACKAGE_NAME}/pages/_document"), - vec![ - request_to_import_mapping(pages_dir, "./_document"), - request_to_import_mapping(pages_dir, "next/document"), - ], - ); - + match ty.into_value() { + ContextType::Pages { pages_dir } => { + insert_alias_to_alternatives( + &mut import_map, + format!("{VIRTUAL_PACKAGE_NAME}/pages/_app"), + vec![ + request_to_import_mapping(pages_dir, "./_app"), + request_to_import_mapping(pages_dir, "next/app"), + ], + ); + insert_alias_to_alternatives( + &mut import_map, + format!("{VIRTUAL_PACKAGE_NAME}/pages/_document"), + vec![ + request_to_import_mapping(pages_dir, "./_document"), + request_to_import_mapping(pages_dir, "next/document"), + ], + ); + } + ContextType::App { app_dir } => { + import_map.insert_exact_alias( + "react", + request_to_import_mapping(app_dir, "next/dist/compiled/react"), + ); + import_map.insert_wildcard_alias( + "react/", + request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), + ); + import_map.insert_exact_alias( + "react-dom", + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom"), + ); + import_map.insert_wildcard_alias( + "react-dom/", + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), + ); + } + ContextType::Other => {} + } import_map.cell() } /// Computes the Next-specific client fallback import map, which provides /// polyfills to Node.js externals. #[turbo_tasks::function] -pub fn get_next_client_fallback_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc { +pub fn get_next_client_fallback_import_map(ty: Value) -> ImportMapVc { let mut import_map = ImportMap::empty(); - for (original, alias) in NEXT_ALIASES { - import_map.insert_exact_alias(original, request_to_import_mapping(pages_dir, alias)); - import_map.insert_exact_alias( - format!("node:{original}"), - request_to_import_mapping(pages_dir, alias), - ); + match ty.into_value() { + ContextType::Pages { + pages_dir: context_dir, + } + | ContextType::App { + app_dir: context_dir, + } => { + for (original, alias) in NEXT_ALIASES { + import_map + .insert_exact_alias(original, request_to_import_mapping(context_dir, alias)); + import_map.insert_exact_alias( + format!("node:{original}"), + request_to_import_mapping(context_dir, alias), + ); + } + } + ContextType::Other => {} } import_map.cell() @@ -55,34 +93,65 @@ pub fn get_next_client_fallback_import_map(pages_dir: FileSystemPathVc) -> Impor #[turbo_tasks::function] pub fn get_next_server_import_map( project_path: FileSystemPathVc, - pages_dir: FileSystemPathVc, + ty: Value, ) -> ImportMapVc { let mut import_map = ImportMap::empty(); let package_root = attached_next_js_package_path(project_path); insert_next_shared_aliases(&mut import_map, package_root); - insert_alias_to_alternatives( - &mut import_map, - format!("{VIRTUAL_PACKAGE_NAME}/pages/_app"), - vec![ - request_to_import_mapping(pages_dir, "./_app"), - external_request_to_import_mapping("next/app"), - ], - ); - insert_alias_to_alternatives( - &mut import_map, - format!("{VIRTUAL_PACKAGE_NAME}/pages/_document"), - vec![ - request_to_import_mapping(pages_dir, "./_document"), - external_request_to_import_mapping("next/document"), - ], - ); - - import_map.insert_exact_alias("next", ImportMapping::External(None).into()); - import_map.insert_wildcard_alias("next/", ImportMapping::External(None).into()); - import_map.insert_exact_alias("react", ImportMapping::External(None).into()); - import_map.insert_wildcard_alias("react/", ImportMapping::External(None).into()); + match ty.into_value() { + ServerContextType::Pages { pages_dir } => { + insert_alias_to_alternatives( + &mut import_map, + format!("{VIRTUAL_PACKAGE_NAME}/pages/_app"), + vec![ + request_to_import_mapping(pages_dir, "./_app"), + external_request_to_import_mapping("next/app"), + ], + ); + insert_alias_to_alternatives( + &mut import_map, + format!("{VIRTUAL_PACKAGE_NAME}/pages/_document"), + vec![ + request_to_import_mapping(pages_dir, "./_document"), + external_request_to_import_mapping("next/document"), + ], + ); + + import_map.insert_wildcard_alias( + format!("{VIRTUAL_PACKAGE_NAME}/"), + ImportMapping::PrimaryAlternative("./*".to_string(), Some(next_js_fs().root())) + .cell(), + ); + + import_map.insert_exact_alias("next", ImportMapping::External(None).into()); + import_map.insert_wildcard_alias("next/", ImportMapping::External(None).into()); + import_map.insert_exact_alias("react", ImportMapping::External(None).into()); + import_map.insert_wildcard_alias("react/", ImportMapping::External(None).into()); + } + ServerContextType::AppSSR { app_dir } | ServerContextType::AppRSC { app_dir } => { + import_map.insert_exact_alias( + "react", + request_to_import_mapping(app_dir, "next/dist/compiled/react"), + ); + import_map.insert_wildcard_alias( + "react/", + request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), + ); + import_map.insert_exact_alias( + "react-dom", + request_to_import_mapping( + app_dir, + "next/dist/compiled/react-dom/server-rendering-stub.js", + ), + ); + import_map.insert_wildcard_alias( + "react-dom/", + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), + ); + } + } import_map.cell() } diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js b/packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js new file mode 100644 index 00000000000000..0f36a56059ba17 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js @@ -0,0 +1,5 @@ +import Component from "."; +import { hydrateRoot } from "react-dom/client"; + +const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); +hydrateRoot(document.getElementById("__next"), ); diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs new file mode 100644 index 00000000000000..e3699ddd327869 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -0,0 +1,98 @@ +use turbo_tasks::{primitives::StringVc, Value}; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{ + module_options::{ModuleOptionsContext, ModuleOptionsContextVc}, + resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, +}; +use turbopack_core::{ + environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, + target::CompileTargetVc, +}; +use turbopack_ecmascript::EcmascriptInputTransform; + +use crate::next_import_map::get_next_server_import_map; + +#[turbo_tasks::value(serialization = "auto_for_input")] +#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] +pub enum ServerContextType { + Pages { pages_dir: FileSystemPathVc }, + AppSSR { app_dir: FileSystemPathVc }, + AppRSC { app_dir: FileSystemPathVc }, +} + +#[turbo_tasks::function] +pub fn get_server_resolve_options_context( + project_path: FileSystemPathVc, + ty: Value, +) -> ResolveOptionsContextVc { + let next_server_import_map = get_next_server_import_map(project_path, ty); + match ty.into_value() { + ServerContextType::Pages { .. } | ServerContextType::AppSSR { .. } => { + ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + enable_node_modules: true, + enable_node_externals: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string()], + import_map: Some(next_server_import_map), + module: true, + ..Default::default() + } + } + ServerContextType::AppRSC { .. } => ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + enable_node_modules: true, + enable_node_externals: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string(), "react-server".to_string()], + import_map: Some(next_server_import_map), + module: true, + ..Default::default() + }, + } + .cell() +} + +#[turbo_tasks::function] +pub fn get_server_environment(ty: Value) -> EnvironmentVc { + EnvironmentVc::new( + Value::new(ExecutionEnvironment::NodeJsLambda( + NodeJsEnvironment { + compile_target: CompileTargetVc::current(), + node_version: 0, + } + .cell(), + )), + match ty.into_value() { + ServerContextType::Pages { .. } => Value::new(EnvironmentIntention::ServerRendering), + ServerContextType::AppSSR { .. } => Value::new(EnvironmentIntention::Prerendering), + ServerContextType::AppRSC { .. } => Value::new(EnvironmentIntention::ServerRendering), + }, + ) +} + +#[turbo_tasks::function] +pub fn get_server_module_options_context(ty: Value) -> ModuleOptionsContextVc { + match ty.into_value() { + ServerContextType::Pages { .. } => ModuleOptionsContext { + enable_typescript_transform: true, + enable_styled_jsx: true, + ..Default::default() + }, + ServerContextType::AppSSR { .. } => ModuleOptionsContext { + enable_styled_jsx: true, + enable_typescript_transform: true, + ..Default::default() + }, + ServerContextType::AppRSC { .. } => ModuleOptionsContext { + enable_typescript_transform: true, + custom_ecmascript_transforms: vec![EcmascriptInputTransform::ClientDirective( + StringVc::cell("server-to-client".to_string()), + )], + ..Default::default() + }, + } + .cell() +} diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index e4fe3d4c157b47..02cf96855bceaa 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -8,11 +8,12 @@ use futures::{stream::FuturesUnordered, TryStreamExt}; use indexmap::{IndexMap, IndexSet}; use mime::TEXT_HTML_UTF_8; pub use node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}; +use serde::Deserialize; use serde_json::Value as JsonValue; use turbo_tasks::{ primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, TryJoinIterExt, }; -use turbo_tasks_fs::{DiskFileSystemVc, File, FileSystemPathVc}; +use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ asset::{AssetContentVc, AssetVc, AssetsSetVc}, @@ -209,6 +210,17 @@ pub(super) struct RenderData { path: String, } +#[derive(Deserialize)] +#[serde(untagged)] +pub enum RenderResult { + Simple(String), + Advanced { + body: String, + #[serde(rename = "contentType")] + content_type: Option, + }, +} + /// Renders a module as static HTML in a node.js process. #[turbo_tasks::function] async fn render_static( @@ -219,11 +231,6 @@ async fn render_static( intermediate_output_path: FileSystemPathVc, data: RenderDataVc, ) -> Result { - fn into_result(content: String) -> Result { - Ok(File::from(content) - .with_content_type(TEXT_HTML_UTF_8) - .into()) - } let renderer_pool = get_renderer_pool( get_intermediate_asset( module, @@ -245,17 +252,27 @@ async fn render_static( .await?; let issue = if let Some(last_line) = lines.last() { if let Some(data) = last_line.strip_prefix("RESULT=") { - let data: JsonValue = serde_json::from_str(data)?; - if let Some(s) = data.as_str() { - return into_result(s.to_string()); - } else { - RenderingIssue { + let result: serde_json::Result = serde_json::from_str(data); + match result { + Ok(RenderResult::Simple(body)) => { + return Ok(FileContent::Content( + File::from(body).with_content_type(TEXT_HTML_UTF_8), + ) + .into()); + } + Ok(RenderResult::Advanced { body, content_type }) => { + return Ok(FileContent::Content(File::from(body).with_content_type( + content_type.map_or(Ok(TEXT_HTML_UTF_8), |c| c.parse())?, + )) + .into()); + } + Err(err) => RenderingIssue { context: path, - message: StringVc::cell( - "Result provided by Node.js rendering process was not a string".to_string(), - ), + message: StringVc::cell(format!( + "Unexpected result provided by Node.js rendering process: {err}" + )), logging: StringVc::cell(lines.join("\n")), - } + }, } } else if let Some(data) = last_line.strip_prefix("ERROR=") { let data: JsonValue = serde_json::from_str(data)?; @@ -287,9 +304,13 @@ async fn render_static( } }; + fn into_error_document(content: String) -> Result { + Ok(FileContent::Content(File::from(content).with_content_type(TEXT_HTML_UTF_8)).into()) + } + // Show error page // TODO This need to include HMR handler to allow auto refresh - let result = into_result(format!( + let result = into_error_document(format!( "

Error during \ rendering

\n

Message

\n
{}
\n

Logs

\n
{}
", issue.message.await?, diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 8dcccf17ad06ec..17a06acfcfaa6f 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -130,6 +130,7 @@ impl ContentSource for NodeRenderContentSource { .get("accept") .map(|value| value.contains("html")) .unwrap_or_default() + || headers.contains_key("__rsc__") { if data.method.is_some() && data.url.is_some() { if let Some(query) = &data.query { @@ -179,6 +180,7 @@ impl ContentSource for NodeRenderContentSource { vary: ContentSourceDataVary { headers: Some(ContentSourceDataFilter::Subset(HashSet::from([ "accept".to_string(), + "__rsc__".to_string(), ]))), ..Default::default() }, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 237d3d4dbb2062..1cf4948a48c3fa 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -1,21 +1,13 @@ use std::collections::HashMap; -use anyhow::{anyhow, bail, Result}; -use turbo_tasks::{Value, ValueToString}; +use anyhow::Result; +use turbo_tasks::Value; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; -use turbopack::{ - module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext, - transition::TransitionsByNameVc, ModuleAssetContextVc, -}; +use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; use turbopack_core::{ - asset::AssetVc, - chunk::dev::DevChunkingContextVc, - context::AssetContextVc, - environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, - source_asset::SourceAssetVc, - target::CompileTargetVc, - virtual_asset::VirtualAssetVc, + asset::AssetVc, chunk::dev::DevChunkingContextVc, context::AssetContextVc, + source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, }; use turbopack_dev_server::source::{ combined::{CombinedContentSource, CombinedContentSourceVc}, @@ -33,15 +25,16 @@ use crate::{ context::{ get_client_assets_path, get_client_chunking_context, get_client_environment, get_client_module_options_context, get_client_resolve_options_context, - get_client_runtime_entries, + get_client_runtime_entries, ContextType, }, NextClientTransition, }, - next_import_map::{ - get_next_client_fallback_import_map, get_next_client_import_map, get_next_server_import_map, + next_server::{ + get_server_environment, get_server_module_options_context, + get_server_resolve_options_context, ServerContextType, }, nodejs::node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, - path_regex::{PathRegexBuilder, PathRegexVc}, + util::regular_expression_for_path, }; /// Create a content source serving the `pages` or `src/pages` directory as @@ -66,22 +59,19 @@ pub async fn create_server_rendered_source( return Ok(NoContentSourceVc::new().into()); }; - let client_chunking_context = get_client_chunking_context(project_path, server_root); + let ty = Value::new(ContextType::Pages { pages_dir }); + let server_ty = Value::new(ServerContextType::Pages { pages_dir }); + + let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); let client_module_options_context = - get_client_module_options_context(project_path, client_environment); - let client_resolve_options_context = get_client_resolve_options_context(); - - let next_server_import_map = get_next_server_import_map(project_path, pages_dir); - let next_client_import_map = get_next_client_import_map(project_path, pages_dir); - let next_client_fallback_import_map = get_next_client_fallback_import_map(pages_dir); - let client_resolve_options_context = client_resolve_options_context - .with_extended_import_map(next_client_import_map) - .with_extended_fallback_import_map(next_client_fallback_import_map); + get_client_module_options_context(project_path, client_environment, ty); + let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); - let client_runtime_entries = get_client_runtime_entries(project_path, env, false); + let client_runtime_entries = get_client_runtime_entries(project_path, env, ty); let next_client_transition = NextClientTransition { + is_app: false, client_chunking_context, client_module_options_context, client_resolve_options_context, @@ -96,34 +86,9 @@ pub async fn create_server_rendered_source( transitions.insert("next-client".to_string(), next_client_transition); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), - EnvironmentVc::new( - Value::new(ExecutionEnvironment::NodeJsLambda( - NodeJsEnvironment { - compile_target: CompileTargetVc::current(), - node_version: 0, - } - .into(), - )), - Value::new(EnvironmentIntention::Client), - ), - ModuleOptionsContext { - enable_typescript_transform: true, - enable_styled_jsx: true, - ..Default::default() - } - .cell(), - ResolveOptionsContext { - enable_typescript: true, - enable_react: true, - enable_node_modules: true, - enable_node_native_modules: true, - enable_node_externals: true, - custom_conditions: vec!["development".to_string()], - import_map: Some(next_server_import_map), - module: true, - ..Default::default() - } - .cell(), + get_server_environment(server_ty), + get_server_module_options_context(server_ty), + get_server_resolve_options_context(project_path, server_ty), ) .into(); @@ -134,6 +99,7 @@ pub async fn create_server_rendered_source( project_path, context, pages_dir, + pages_dir, EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), server_root, server_root, @@ -142,75 +108,12 @@ pub async fn create_server_rendered_source( .into()) } -/// Converts a filename within the server root to a regular expression with -/// named capture groups for every dynamic segment. -#[turbo_tasks::function] -async fn regular_expression_for_path( - server_root: FileSystemPathVc, - server_path: FileSystemPathVc, -) -> Result { - let server_path_value = &*server_path.await?; - let path = if let Some(path) = server_root.await?.get_path_to(server_path_value) { - path - } else { - bail!( - "server_path ({}) is not in server_root ({})", - server_path.to_string().await?, - server_root.to_string().await? - ) - }; - let (path, _) = path - .rsplit_once('.') - .ok_or_else(|| anyhow!("path ({}) has no extension", path))?; - let path = if path == "index" { - "" - } else { - path.strip_suffix("/index").unwrap_or(path) - }; - let mut path_regex = PathRegexBuilder::new(); - for segment in path.split('/') { - if let Some(segment) = segment.strip_prefix('[') { - if let Some(segment) = segment.strip_prefix("[...") { - if let Some((placeholder, rem)) = segment.split_once("]]") { - path_regex.push_optional_catch_all(placeholder, rem); - } else { - bail!( - "path ({}) contains '[[' without matching ']]' at '[[...{}'", - path, - segment - ); - } - } else if let Some(segment) = segment.strip_prefix("...") { - if let Some((placeholder, rem)) = segment.split_once(']') { - path_regex.push_catch_all(placeholder, rem); - } else { - bail!( - "path ({}) contains '[' without matching ']' at '[...{}'", - path, - segment - ); - } - } else if let Some((placeholder, rem)) = segment.split_once(']') { - path_regex.push_dynamic_segment(placeholder, rem); - } else { - bail!( - "path ({}) contains '[' without matching ']' at '[{}'", - path, - segment - ); - } - } else { - path_regex.push_static_segment(segment); - } - } - Ok(PathRegexVc::cell(path_regex.build()?)) -} - /// Handles a single page file in the pages directory #[turbo_tasks::function] fn create_server_rendered_source_for_file( context_path: FileSystemPathVc, context: AssetContextVc, + pages_dir: FileSystemPathVc, page_file: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, server_root: FileSystemPathVc, @@ -224,14 +127,14 @@ fn create_server_rendered_source_for_file( context_path, intermediate_output_path, intermediate_output_path.join("chunks"), - get_client_assets_path(server_root), + get_client_assets_path(server_root, Value::new(ContextType::Pages { pages_dir })), false, ) .into(); create_node_rendered_source( server_root, - regular_expression_for_path(server_root, server_path), + regular_expression_for_path(server_root, server_path, true), SsrRenderer { context, entry_asset, @@ -251,6 +154,7 @@ fn create_server_rendered_source_for_file( async fn create_server_rendered_source_for_directory( context_path: FileSystemPathVc, context: AssetContextVc, + pages_dir: FileSystemPathVc, input_dir: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, server_root: FileSystemPathVc, @@ -291,6 +195,7 @@ async fn create_server_rendered_source_for_directory( create_server_rendered_source_for_file( context_path, context, + pages_dir, *file, runtime_entries, server_root, @@ -309,6 +214,7 @@ async fn create_server_rendered_source_for_directory( create_server_rendered_source_for_directory( context_path, context, + pages_dir, *dir, runtime_entries, server_root, diff --git a/packages/next-swc/crates/next-core/src/util.rs b/packages/next-swc/crates/next-core/src/util.rs new file mode 100644 index 00000000000000..0b62982a011238 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/util.rs @@ -0,0 +1,74 @@ +use anyhow::{anyhow, bail, Result}; +use turbo_tasks::ValueToString; +use turbo_tasks_fs::FileSystemPathVc; + +use crate::path_regex::{PathRegexBuilder, PathRegexVc}; + +/// Converts a filename within the server root to a regular expression with +/// named capture groups for every dynamic segment. +#[turbo_tasks::function] +pub async fn regular_expression_for_path( + server_root: FileSystemPathVc, + server_path: FileSystemPathVc, + has_extension: bool, +) -> Result { + let server_path_value = &*server_path.await?; + let path = if let Some(path) = server_root.await?.get_path_to(server_path_value) { + path + } else { + bail!( + "server_path ({}) is not in server_root ({})", + server_path.to_string().await?, + server_root.to_string().await? + ) + }; + let path = if has_extension { + path.rsplit_once('.') + .ok_or_else(|| anyhow!("path ({}) has no extension", path))? + .0 + } else { + path + }; + let path = if path == "index" { + "" + } else { + path.strip_suffix("/index").unwrap_or(path) + }; + let mut path_regex = PathRegexBuilder::new(); + for segment in path.split('/') { + if let Some(segment) = segment.strip_prefix('[') { + if let Some(segment) = segment.strip_prefix("[...") { + if let Some((placeholder, rem)) = segment.split_once("]]") { + path_regex.push_optional_catch_all(placeholder, rem); + } else { + bail!( + "path ({}) contains '[[' without matching ']]' at '[[...{}'", + path, + segment + ); + } + } else if let Some(segment) = segment.strip_prefix("...") { + if let Some((placeholder, rem)) = segment.split_once(']') { + path_regex.push_catch_all(placeholder, rem); + } else { + bail!( + "path ({}) contains '[' without matching ']' at '[...{}'", + path, + segment + ); + } + } else if let Some((placeholder, rem)) = segment.split_once(']') { + path_regex.push_dynamic_segment(placeholder, rem); + } else { + bail!( + "path ({}) contains '[' without matching ']' at '[{}'", + path, + segment + ); + } + } else { + path_regex.push_static_segment(segment); + } + } + Ok(PathRegexVc::cell(path_regex.build()?)) +} diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 682716414f7a5e..328f72399e62c8 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use turbo_tasks::TryJoinIterExt; +use turbo_tasks::{TryJoinIterExt, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::ecmascript::EcmascriptModuleAssetVc; @@ -12,8 +12,12 @@ use turbopack_dev_server::{ source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; -use crate::next_client::context::{ - get_client_asset_context, get_client_chunking_context, get_client_runtime_entries, +use crate::{ + embed_js::wrap_with_next_js_fs, + next_client::context::{ + get_client_asset_context, get_client_chunking_context, get_client_runtime_entries, + ContextType, + }, }; #[turbo_tasks::function] @@ -25,9 +29,12 @@ pub async fn create_web_entry_source( eager_compile: bool, browserslist_query: &str, ) -> Result { - let context = get_client_asset_context(project_root, browserslist_query); - let chunking_context = get_client_chunking_context(project_root, server_root); - let entries = get_client_runtime_entries(project_root, env, true); + let project_root = wrap_with_next_js_fs(project_root); + + let ty = Value::new(ContextType::Other); + let context = get_client_asset_context(project_root, browserslist_query, ty); + let chunking_context = get_client_chunking_context(project_root, server_root, ty); + let entries = get_client_runtime_entries(project_root, env, ty); let runtime_entries = entries.resolve_entries(context); diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 811daf665798f6..b32e62cb7ab869 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -4,7 +4,9 @@ use std::{collections::HashSet, env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; -use next_core::{create_server_rendered_source, create_web_entry_source, env::load_env}; +use next_core::{ + create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, +}; use turbo_tasks::{RawVc, TransientInstance, TransientValue, TurboTasks, Value}; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; @@ -195,8 +197,11 @@ async fn source( let env = load_env(project_path); + let output_root = output_fs.root(); + let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let dev_server_root = dev_server_fs.root(); + let web_source = create_web_entry_source( project_path, entry_requests @@ -210,7 +215,14 @@ async fn source( ); let rendered_source = create_server_rendered_source( project_path, - output_fs.root(), + output_root.join("pages"), + dev_server_root, + env, + &browserslist_query, + ); + let app_source = create_app_source( + project_path, + output_root.join("app"), dev_server_root, env, &browserslist_query, @@ -223,7 +235,7 @@ async fn source( let static_source = StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into(); let main_source = CombinedContentSource { - sources: vec![static_source, rendered_source, web_source], + sources: vec![static_source, app_source, rendered_source, web_source], } .cell(); let introspect = IntrospectionSource { diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 52faa15ae93043..436518fa62556b 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -10,7 +10,8 @@ use turbo_tasks_memory::{ }; use turbopack_core::asset::AssetContentVc; use turbopack_dev_server::source::{ - ContentSource, ContentSourceData, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, + ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, + ContentSourceResult, ContentSourceResultVc, ContentSourceVc, }; #[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new", into = "new")] @@ -30,8 +31,13 @@ const INVALIDATION_INTERVAL: Duration = Duration::from_secs(3); #[turbo_tasks::value_impl] impl ContentSource for TurboTasksSource { #[turbo_tasks::function] - fn get(&self, path: &str, _data: Value) -> Result { - let tt = &self.turbo_tasks; + async fn get( + self_vc: TurboTasksSourceVc, + path: &str, + data: Value, + ) -> Result { + let this = self_vc.await?; + let tt = &this.turbo_tasks; let invalidator = get_invalidator(); tokio::spawn({ async move { @@ -61,14 +67,31 @@ impl ContentSource for TurboTasksSource { viz::graph::wrap_html(&graph) } "table" => { - let mut stats = Stats::new(); - let b = tt.backend(); - b.with_all_cached_tasks(|task| { - stats.add_id(b, task); - }); - let tree = stats.treeify(ReferenceType::Dependency); - let table = viz::table::create_table(tree); - viz::table::wrap_html(&table) + if let Some(query) = &data.query { + let mut stats = Stats::new(); + let b = tt.backend(); + let active_only = query.contains_key("active"); + b.with_all_cached_tasks(|task| { + stats.add_id_conditional(b, task, |_, info| { + info.executions > 0 && (!active_only || info.active) + }); + }); + let tree = stats.treeify(ReferenceType::Dependency); + let table = viz::table::create_table(tree); + viz::table::wrap_html(&table) + } else { + return Ok(ContentSourceResult::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + query: Some(ContentSourceDataFilter::Subset( + ["active".to_string()].into(), + )), + ..Default::default() + }, + } + .cell()); + } } "reset" => { let b = tt.backend(); From 2eae9f180c7699043884296d16d350ed1250e3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florentin=20/=20=E7=8F=9E=E8=BE=B0?= Date: Thu, 20 Oct 2022 18:53:27 +0200 Subject: [PATCH 157/672] add unimplemented warning for next/babel configs (vercel/turbo#124) PR for: - https://github.com/vercel/web-tooling-internal/issues/56 - https://github.com/vercel/web-tooling-internal/issues/55 Screenshot: CleanShot 2022-10-20 at 11 12 13@2x Co-authored-by: Tobias Koppers --- .../next-swc/crates/next-dev/src/issue.rs | 34 ++++++++++++++++++ packages/next-swc/crates/next-dev/src/lib.rs | 36 ++++++++++++++++--- 2 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/src/issue.rs diff --git a/packages/next-swc/crates/next-dev/src/issue.rs b/packages/next-swc/crates/next-dev/src/issue.rs new file mode 100644 index 00000000000000..64ae142d743428 --- /dev/null +++ b/packages/next-swc/crates/next-dev/src/issue.rs @@ -0,0 +1,34 @@ +use anyhow::Result; +use turbo_tasks::primitives::StringVc; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_core::issue::{Issue, IssueVc}; + +/// An issue that occurred upon detecting a file that is unimplemented. +#[turbo_tasks::value(shared)] +pub struct UnimplementedFileIssue { + pub path: FileSystemPathVc, + pub description: StringVc, +} + +#[turbo_tasks::value_impl] +impl Issue for UnimplementedFileIssue { + #[turbo_tasks::function] + fn title(&self) -> StringVc { + StringVc::cell("Feature not yet supported".to_string()) + } + + #[turbo_tasks::function] + fn category(&self) -> StringVc { + StringVc::cell("unimplemented".to_string()) + } + + #[turbo_tasks::function] + fn context(&self) -> FileSystemPathVc { + self.path + } + + #[turbo_tasks::function] + fn description(&self) -> StringVc { + self.description + } +} diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index b32e62cb7ab869..728618254b9fa0 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -1,14 +1,20 @@ #![feature(future_join)] #![feature(min_specialization)] +mod issue; +mod turbo_tasks_viz; + use std::{collections::HashSet, env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; +use issue::UnimplementedFileIssue; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, }; -use turbo_tasks::{RawVc, TransientInstance, TransientValue, TurboTasks, Value}; -use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; +use turbo_tasks::{ + primitives::StringVc, RawVc, TransientInstance, TransientValue, TurboTasks, Value, +}; +use turbo_tasks_fs::{DiskFileSystemVc, FileSystemEntryType, FileSystemPathVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; use turbopack_core::{issue::IssueSeverity, resolve::parse::RequestVc}; @@ -22,8 +28,6 @@ use turbopack_dev_server::{ DevServer, }; -mod turbo_tasks_viz; - pub struct NextDevServerBuilder { turbo_tasks: Arc>, project_dir: String, @@ -157,6 +161,28 @@ async fn handle_issues>(source: T, console_ui: ConsoleUiVc) -> Re } } +async fn handle_unimplemented_files(project_path: &FileSystemPathVc) -> Result<()> { + const UNIMPLEMENTED_FILES: [&str; 3] = ["next.config.js", "babel.config.js", ".babelrc.js"]; + for file in UNIMPLEMENTED_FILES { + let file_path = project_path.join(file); + let file_type = file_path.get_type().await?; + + if *file_type == FileSystemEntryType::File { + UnimplementedFileIssue { + path: file_path, + description: StringVc::cell(format!( + "Handling the file `{}` is currently unimplemented", + file + )), + } + .cell() + .as_issue() + .emit(); + } + } + Ok(()) +} + #[turbo_tasks::function] async fn project_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result { let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir.to_string()); @@ -195,6 +221,8 @@ async fn source( .unwrap_or(project_relative); let project_path = fs.root().join(project_relative); + handle_unimplemented_files(&project_path).await?; + let env = load_env(project_path); let output_root = output_fs.root(); From 12d723059b11f2d53381683c4109cc7da791ba23 Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 20 Oct 2022 19:49:35 +0200 Subject: [PATCH 158/672] prepare crates for publishing (vercel/turbo#29) --- packages/next-swc/crates/next-core/Cargo.toml | 4 ++-- packages/next-swc/crates/next-dev/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 599290e3159f04..57cb27277e972f 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "next-core" version = "0.1.0" +description = "TBD" +license = "MPL-2.0" edition = "2021" [lib] bench = false -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] anyhow = "1.0.47" futures = "0.3.21" diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index ec3c19404fb374..3e8f5a77cb5275 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "next-dev" version = "0.1.0" +description = "TBD" +license = "MPL-2.0" edition = "2021" autobenches = false @@ -16,8 +18,6 @@ bench = false name = "mod" harness = false -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [features] tokio_console = [ "dep:console-subscriber", From ca98d275cf73a0df8d594d9fee3a49c826abb27c Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 20 Oct 2022 22:26:53 +0200 Subject: [PATCH 159/672] fallback page (vercel/turbo#69) --- .../crates/next-core/js/src/dev/hmr-client.ts | 1 - .../crates/next-core/js/src/dev/websocket.ts | 2 + .../next-core/js/src/entry/fallback.tsx | 26 +++++++ .../crates/next-core/src/app_source.rs | 20 ++++-- .../next-swc/crates/next-core/src/fallback.rs | 68 +++++++++++++++++++ packages/next-swc/crates/next-core/src/lib.rs | 2 + .../crates/next-core/src/next_import_map.rs | 2 +- .../next_js/internal/next_client_component.js | 5 -- .../crates/next-core/src/nodejs/issue.rs | 9 +-- .../crates/next-core/src/nodejs/mod.rs | 46 +++++++------ .../src/nodejs/node_rendered_source.rs | 19 ++++-- .../crates/next-core/src/react_refresh.rs | 4 +- .../next-swc/crates/next-core/src/runtime.rs | 36 ++++++++++ .../next-core/src/server_rendered_source.rs | 34 ++++++++-- .../crates/next-core/src/web_entry_source.rs | 5 +- 15 files changed, 224 insertions(+), 55 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/entry/fallback.tsx create mode 100644 packages/next-swc/crates/next-core/src/fallback.rs delete mode 100644 packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js create mode 100644 packages/next-swc/crates/next-core/src/runtime.rs diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 40a3a628f62c7e..08bb8c4bdc7f6d 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -195,7 +195,6 @@ function handleIssues(msg: ServerMessage): boolean { function handleSocketMessage(msg: ServerMessage) { const hasErrors = handleIssues(msg); const aggregatedMsg = aggregateUpdates(msg, hasErrors); - console.dir(aggregatedMsg); if (hasErrors) return; diff --git a/packages/next-swc/crates/next-core/js/src/dev/websocket.ts b/packages/next-swc/crates/next-core/js/src/dev/websocket.ts index b747974613f96e..f65fb55b804013 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/websocket.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/websocket.ts @@ -48,6 +48,8 @@ export function connectHMR(options: HMROptions) { function init() { if (source) source.close(); + console.log("[HMR] connecting..."); + function handleOnline() { eventCallbacks.forEach((cb) => { cb({ diff --git a/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx b/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx new file mode 100644 index 00000000000000..e7eb5d2f822790 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx @@ -0,0 +1,26 @@ +import "@vercel/turbopack-next/internal/shims-client"; + +import { createRoot } from "react-dom/client"; + +import { + initializeHMR, + ReactDevOverlay, +} from "@vercel/turbopack-next/dev/client"; +import { onChunkUpdate } from "@vercel/turbopack-next/dev/hmr-client"; + +const pageChunkPath = location.pathname.slice(1); + +onChunkUpdate(pageChunkPath, (update) => { + if (update.type === "restart") { + location.reload(); + } +}); + +initializeHMR({ + assetPrefix: "", +}); + +const el = document.getElementById("__next")!; +el.innerText = ""; + +createRoot(el).render(); diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 5f4b6fb802e12a..0d0337b071f16b 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -14,9 +14,12 @@ use turbopack::{ use turbopack_core::{ chunk::dev::DevChunkingContextVc, context::AssetContextVc, virtual_asset::VirtualAssetVc, }; -use turbopack_dev_server::source::{ - combined::{CombinedContentSource, CombinedContentSourceVc}, - ContentSourceVc, NoContentSourceVc, +use turbopack_dev_server::{ + html::DevHtmlAssetVc, + source::{ + combined::{CombinedContentSource, CombinedContentSourceVc}, + ContentSourceVc, NoContentSourceVc, + }, }; use turbopack_ecmascript::{ chunk::EcmascriptChunkPlaceablesVc, magic_identifier, utils::stringify_str, @@ -29,6 +32,7 @@ use crate::{ next_layout_entry_transition::NextLayoutEntryTransition, LayoutSegment, LayoutSegmentsVc, }, embed_js::{next_js_file, wrap_with_next_js_fs}, + fallback::get_fallback_page, next_client::{ context::{ get_client_chunking_context, get_client_environment, get_client_module_options_context, @@ -142,13 +146,13 @@ fn next_layout_entry_transition( /// Next.js app folder. #[turbo_tasks::function] pub async fn create_app_source( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, ) -> Result { - let project_root = wrap_with_next_js_fs(project_root); + let project_root = wrap_with_next_js_fs(project_path); let app = project_root.join("app"); let src_app = project_root.join("src/app"); @@ -196,12 +200,15 @@ pub async fn create_app_source( let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_root, env).as_ecmascript_chunk_placeable()]; + let fallback_page = get_fallback_page(project_path, server_root, browserslist_query); + Ok(create_app_source_for_directory( context, project_root, app_dir, server_root, EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), + fallback_page, server_root, LayoutSegmentsVc::cell(Vec::new()), output_path, @@ -216,6 +223,7 @@ async fn create_app_source_for_directory( input_dir: FileSystemPathVc, server_root: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, + fallback_page: DevHtmlAssetVc, target: FileSystemPathVc, layouts: LayoutSegmentsVc, intermediate_output_path: FileSystemPathVc, @@ -276,6 +284,7 @@ async fn create_app_source_for_directory( .into(), chunking_context, runtime_entries, + fallback_page, intermediate_output_path, )); } @@ -296,6 +305,7 @@ async fn create_app_source_for_directory( *dir, server_root, runtime_entries, + fallback_page, new_target, layouts, intermediate_output_path, diff --git a/packages/next-swc/crates/next-core/src/fallback.rs b/packages/next-swc/crates/next-core/src/fallback.rs new file mode 100644 index 00000000000000..ec8dc487bf4dda --- /dev/null +++ b/packages/next-swc/crates/next-core/src/fallback.rs @@ -0,0 +1,68 @@ +use std::collections::HashMap; + +use anyhow::{bail, Result}; +use turbo_tasks::Value; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{ + ecmascript::EcmascriptModuleAssetVc, transition::TransitionsByNameVc, ModuleAssetContextVc, +}; +use turbopack_core::{ + chunk::ChunkGroupVc, + context::AssetContextVc, + resolve::{options::ImportMap, origin::PlainResolveOriginVc}, +}; +use turbopack_dev_server::html::DevHtmlAssetVc; + +use crate::{ + embed_js::attached_next_js_package_path, + next_client::context::{ + get_client_chunking_context, get_client_environment, get_client_module_options_context, + get_client_resolve_options_context, ContextType, + }, + next_import_map::insert_next_shared_aliases, + runtime::resolve_runtime_request, +}; + +#[turbo_tasks::function] +pub async fn get_fallback_page( + project_root: FileSystemPathVc, + dev_server_root: FileSystemPathVc, + browserslist_query: &str, +) -> Result { + let ty = Value::new(ContextType::Other); + let environment = get_client_environment(browserslist_query); + let resolve_options_context = get_client_resolve_options_context(project_root, ty); + let module_options_context = get_client_module_options_context(project_root, environment, ty); + let chunking_context = get_client_chunking_context(project_root, dev_server_root, ty); + + let mut import_map = ImportMap::empty(); + insert_next_shared_aliases(&mut import_map, attached_next_js_package_path(project_root)); + + let context: AssetContextVc = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(HashMap::new()), + environment, + module_options_context, + resolve_options_context.with_extended_import_map(import_map.cell()), + ) + .into(); + + let fallback_chunk = resolve_runtime_request( + PlainResolveOriginVc::new(context, project_root).into(), + "entry/fallback", + ); + + let module = if let Some(module) = + EcmascriptModuleAssetVc::resolve_from(fallback_chunk.as_asset()).await? + { + module + } else { + bail!("fallback runtime entry is not an ecmascript module"); + }; + + let chunk = module.as_evaluated_chunk(chunking_context, None); + + Ok(DevHtmlAssetVc::new( + dev_server_root.join("fallback.html"), + vec![ChunkGroupVc::from_chunk(chunk)], + )) +} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 038f20a6e6d828..8c5b87811b96a5 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -5,6 +5,7 @@ mod app_render; mod app_source; mod embed_js; pub mod env; +mod fallback; pub mod next_client; mod next_client_component; mod next_import_map; @@ -12,6 +13,7 @@ pub mod next_server; mod nodejs; mod path_regex; pub mod react_refresh; +mod runtime; mod server_rendered_source; mod util; mod web_entry_source; diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 37f99849355f23..69d899aad89a47 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -182,7 +182,7 @@ static NEXT_ALIASES: [(&str, &str); 23] = [ ("setImmediate", "next/dist/compiled/setimmediate"), ]; -fn insert_next_shared_aliases(import_map: &mut ImportMap, package_root: FileSystemPathVc) { +pub fn insert_next_shared_aliases(import_map: &mut ImportMap, package_root: FileSystemPathVc) { // we use the next.js hydration code, so we replace the error overlay with our // own import_map.insert_exact_alias( diff --git a/packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js b/packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js deleted file mode 100644 index 0f36a56059ba17..00000000000000 --- a/packages/next-swc/crates/next-core/src/next_js/internal/next_client_component.js +++ /dev/null @@ -1,5 +0,0 @@ -import Component from "."; -import { hydrateRoot } from "react-dom/client"; - -const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); -hydrateRoot(document.getElementById("__next"), ); diff --git a/packages/next-swc/crates/next-core/src/nodejs/issue.rs b/packages/next-swc/crates/next-core/src/nodejs/issue.rs index 1e07cbd350c8f0..ae41c64585d84e 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/issue.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/issue.rs @@ -4,10 +4,11 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::issue::{Issue, IssueVc}; #[turbo_tasks::value(shared)] +#[derive(Copy, Clone)] pub(super) struct RenderingIssue { - pub(super) context: FileSystemPathVc, - pub(super) message: StringVc, - pub(super) logging: StringVc, + pub context: FileSystemPathVc, + pub message: StringVc, + pub logs: StringVc, } #[turbo_tasks::value_impl] @@ -34,7 +35,7 @@ impl Issue for RenderingIssue { #[turbo_tasks::function] fn detail(&self) -> StringVc { - self.logging + self.logs } // TODO parse stack trace into source location diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 02cf96855bceaa..58c7a451007990 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -16,10 +16,13 @@ use turbo_tasks::{ use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ - asset::{AssetContentVc, AssetVc, AssetsSetVc}, + asset::{Asset, AssetContentVc, AssetVc, AssetsSetVc}, chunk::{ChunkGroupVc, ChunkingContextVc}, }; -use turbopack_dev_server::source::{query::Query, HeaderValue}; +use turbopack_dev_server::{ + html::DevHtmlAssetVc, + source::{query::Query, HeaderValue}, +}; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; use self::{ @@ -227,6 +230,7 @@ async fn render_static( path: FileSystemPathVc, module: EcmascriptModuleAssetVc, runtime_entries: EcmascriptChunkPlaceablesVc, + fallback_page: DevHtmlAssetVc, chunking_context: ChunkingContextVc, intermediate_output_path: FileSystemPathVc, data: RenderDataVc, @@ -271,7 +275,7 @@ async fn render_static( message: StringVc::cell(format!( "Unexpected result provided by Node.js rendering process: {err}" )), - logging: StringVc::cell(lines.join("\n")), + logs: StringVc::cell(lines.join("\n")), }, } } else if let Some(data) = last_line.strip_prefix("ERROR=") { @@ -280,45 +284,47 @@ async fn render_static( RenderingIssue { context: path, message: StringVc::cell(s.to_string()), - logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), + logs: StringVc::cell(lines[..lines.len() - 1].join("\n")), } } else { RenderingIssue { context: path, message: StringVc::cell(data.to_string()), - logging: StringVc::cell(lines[..lines.len() - 1].join("\n")), + logs: StringVc::cell(lines[..lines.len() - 1].join("\n")), } } } else { RenderingIssue { context: path, message: StringVc::cell("No result provided by Node.js process".to_string()), - logging: StringVc::cell(lines.join("\n")), + logs: StringVc::cell(lines.join("\n")), } } } else { RenderingIssue { context: path, message: StringVc::cell("No content received from Node.js process.".to_string()), - logging: StringVc::cell("".to_string()), + logs: StringVc::cell("".to_string()), } }; - fn into_error_document(content: String) -> Result { - Ok(FileContent::Content(File::from(content).with_content_type(TEXT_HTML_UTF_8)).into()) - } + // Emit an issue for error reporting + issue.cell().as_issue().emit(); - // Show error page - // TODO This need to include HMR handler to allow auto refresh - let result = into_error_document(format!( - "

Error during \ - rendering

\n

Message

\n
{}
\n

Logs

\n
{}
", + let body = format!( + " +
+

Error rendering page

+

Message

+
{}
+

Logs

+
{}
+
", issue.message.await?, - issue.logging.await? - )); + issue.logs.await?, + ); - // Emit an issue for error reporting - issue.cell().as_issue().emit(); + let html = fallback_page.with_body(body); - result + Ok(html.content()) } diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 17a06acfcfaa6f..54be0081c879ea 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -10,12 +10,15 @@ use turbopack_core::{ asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, }, }; -use turbopack_dev_server::source::{ - asset_graph::AssetGraphContentSourceVc, - conditional::ConditionalContentSourceVc, - lazy_instatiated::{GetContentSource, GetContentSourceVc, LazyInstantiatedContentSource}, - ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, - ContentSourceResult, ContentSourceResultVc, ContentSourceVc, +use turbopack_dev_server::{ + html::DevHtmlAssetVc, + source::{ + asset_graph::AssetGraphContentSourceVc, + conditional::ConditionalContentSourceVc, + lazy_instatiated::{GetContentSource, GetContentSourceVc, LazyInstantiatedContentSource}, + ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, + ContentSourceResult, ContentSourceResultVc, ContentSourceVc, + }, }; use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; @@ -41,6 +44,7 @@ pub fn create_node_rendered_source( renderer: NodeRendererVc, chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, + fallback_page: DevHtmlAssetVc, intermediate_output_path: FileSystemPathVc, ) -> ContentSourceVc { let source = NodeRenderContentSource { @@ -49,6 +53,7 @@ pub fn create_node_rendered_source( renderer, chunking_context, runtime_entries, + fallback_page, intermediate_output_path, } .cell(); @@ -71,6 +76,7 @@ struct NodeRenderContentSource { renderer: NodeRendererVc, chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, + fallback_page: DevHtmlAssetVc, intermediate_output_path: FileSystemPathVc, } @@ -139,6 +145,7 @@ impl ContentSource for NodeRenderContentSource { this.server_root.join(path), this.renderer.module(), this.runtime_entries, + this.fallback_page, this.chunking_context, this.intermediate_output_path, RenderData { diff --git a/packages/next-swc/crates/next-core/src/react_refresh.rs b/packages/next-swc/crates/next-core/src/react_refresh.rs index 21b4743359b2df..6c74dfb156efaf 100644 --- a/packages/next-swc/crates/next-core/src/react_refresh.rs +++ b/packages/next-swc/crates/next-core/src/react_refresh.rs @@ -91,9 +91,7 @@ pub async fn resolve_react_refresh(origin: ResolveOriginVc) -> Result { - if let Some(placeable) = - EcmascriptChunkPlaceableVc::resolve_from(assets.iter().next().unwrap()).await? - { + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(assets[0]).await? { Ok(placeable) } else { Err(anyhow!("React Refresh runtime asset is not placeable")) diff --git a/packages/next-swc/crates/next-core/src/runtime.rs b/packages/next-swc/crates/next-core/src/runtime.rs new file mode 100644 index 00000000000000..039ed5c99c5e8d --- /dev/null +++ b/packages/next-swc/crates/next-core/src/runtime.rs @@ -0,0 +1,36 @@ +use anyhow::{anyhow, Result}; +use turbopack::ecmascript::{chunk::EcmascriptChunkPlaceableVc, resolve::cjs_resolve}; +use turbopack_core::resolve::{origin::ResolveOriginVc, parse::RequestVc, ResolveResult}; + +/// Resolves the turbopack runtime module from the given [AssetContextVc]. +#[turbo_tasks::function] +pub async fn resolve_runtime_request( + origin: ResolveOriginVc, + path: &str, +) -> Result { + let runtime_request_path = format!("@vercel/turbopack-next/{}", path); + let request = RequestVc::parse_string(runtime_request_path.clone()); + + match &*cjs_resolve(origin, request).await? { + ResolveResult::Single(asset, _) => { + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { + Ok(placeable) + } else { + Err(anyhow!("turbopack runtime asset is not placeable")) + } + } + ResolveResult::Alternatives(assets, _) if !assets.is_empty() => { + if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(assets[0]).await? { + Ok(placeable) + } else { + Err(anyhow!("turbopack runtime asset is not placeable")) + } + } + // The @vercel/turbopack-runtime module is not installed. + ResolveResult::Unresolveable(_) => Err(anyhow!( + "could not resolve the `{}` module", + runtime_request_path + )), + _ => Err(anyhow!("invalid turbopack runtime asset")), + } +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 1cf4948a48c3fa..3934b08fae5955 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -9,9 +9,13 @@ use turbopack_core::{ asset::AssetVc, chunk::dev::DevChunkingContextVc, context::AssetContextVc, source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, }; -use turbopack_dev_server::source::{ - combined::{CombinedContentSource, CombinedContentSourceVc}, - ContentSourceVc, NoContentSourceVc, +use turbopack_dev_server::{ + html::DevHtmlAssetVc, + source::{ + asset_graph::AssetGraphContentSourceVc, + combined::{CombinedContentSource, CombinedContentSourceVc}, + ContentSourceVc, NoContentSourceVc, + }, }; use turbopack_ecmascript::{ chunk::EcmascriptChunkPlaceablesVc, EcmascriptInputTransform, EcmascriptInputTransformsVc, @@ -21,6 +25,7 @@ use turbopack_env::ProcessEnvAssetVc; use crate::{ embed_js::{next_js_file, wrap_with_next_js_fs}, + fallback::get_fallback_page, next_client::{ context::{ get_client_assets_path, get_client_chunking_context, get_client_environment, @@ -41,13 +46,13 @@ use crate::{ /// Next.js pages folder. #[turbo_tasks::function] pub async fn create_server_rendered_source( - project_path: FileSystemPathVc, + project_root: FileSystemPathVc, output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, ) -> Result { - let project_path = wrap_with_next_js_fs(project_path); + let project_path = wrap_with_next_js_fs(project_root); let pages = project_path.join("pages"); let src_pages = project_path.join("src/pages"); @@ -95,16 +100,26 @@ pub async fn create_server_rendered_source( let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_path, env).as_ecmascript_chunk_placeable()]; - Ok(create_server_rendered_source_for_directory( + let fallback_page = get_fallback_page(project_path, server_root, browserslist_query); + + let server_rendered_source = create_server_rendered_source_for_directory( project_path, context, pages_dir, pages_dir, EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), + fallback_page, server_root, server_root, output_path, - ) + ); + let fallback_source = + AssetGraphContentSourceVc::new_eager(server_root, fallback_page.as_asset()); + + Ok(CombinedContentSource { + sources: vec![server_rendered_source.into(), fallback_source.into()], + } + .cell() .into()) } @@ -116,6 +131,7 @@ fn create_server_rendered_source_for_file( pages_dir: FileSystemPathVc, page_file: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, + fallback_page: DevHtmlAssetVc, server_root: FileSystemPathVc, server_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, @@ -143,6 +159,7 @@ fn create_server_rendered_source_for_file( .into(), chunking_context, runtime_entries, + fallback_page, intermediate_output_path, ) } @@ -157,6 +174,7 @@ async fn create_server_rendered_source_for_directory( pages_dir: FileSystemPathVc, input_dir: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, + fallback_page: DevHtmlAssetVc, server_root: FileSystemPathVc, server_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, @@ -198,6 +216,7 @@ async fn create_server_rendered_source_for_directory( pages_dir, *file, runtime_entries, + fallback_page, server_root, dev_server_path, intermediate_output_path, @@ -217,6 +236,7 @@ async fn create_server_rendered_source_for_directory( pages_dir, *dir, runtime_entries, + fallback_page, server_root, server_path.join(name), intermediate_output_path.join(name), diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 328f72399e62c8..e103c00b688420 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -8,7 +8,7 @@ use turbopack_core::{ resolve::{origin::PlainResolveOriginVc, parse::RequestVc}, }; use turbopack_dev_server::{ - html::DevHtmlAsset, + html::DevHtmlAssetVc, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; @@ -74,11 +74,10 @@ pub async fn create_web_entry_source( .try_join() .await?; - let entry_asset = DevHtmlAsset::new( + let entry_asset = DevHtmlAssetVc::new( server_root.join("index.html"), chunks.into_iter().map(ChunkGroupVc::from_chunk).collect(), ) - .cell() .into(); let graph = if eager_compile { From 3cb06901df892008f118954e43b48c5d7dabe77a Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 20 Oct 2022 14:46:47 -0700 Subject: [PATCH 160/672] Derive a runtime version from NodeJsEnvironment's node_version (vercel/turbo#15) Ported from https://github.com/vercel/turbo-tooling/pull/452. To do: * [x] Read and use node version from PATH Test Plan: Temporarily lowered the default version and verified core-js was resolved when /page is visited. Co-authored-by: Justin Ridgewell --- .../next-swc/crates/next-core/src/app_source.rs | 12 +++++++----- .../crates/next-core/src/next_server/mod.rs | 17 ++++++++--------- .../next-core/src/server_rendered_source.rs | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 0d0337b071f16b..427c963d9a381c 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -110,12 +110,13 @@ async fn next_client_transition( fn next_ssr_client_module_transition( project_path: FileSystemPathVc, app_dir: FileSystemPathVc, + process_env: ProcessEnvVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppSSR { app_dir }); NextSSRClientModuleTransition { ssr_module_options_context: get_server_module_options_context(ty), ssr_resolve_options_context: get_server_resolve_options_context(project_path, ty), - ssr_environment: get_server_environment(ty), + ssr_environment: get_server_environment(ty, process_env), } .cell() .into() @@ -126,9 +127,10 @@ fn next_layout_entry_transition( project_root: FileSystemPathVc, app_dir: FileSystemPathVc, server_root: FileSystemPathVc, + process_env: ProcessEnvVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppRSC { app_dir }); - let rsc_environment = get_server_environment(ty); + let rsc_environment = get_server_environment(ty, process_env); let rsc_resolve_options_context = get_server_resolve_options_context(project_root, ty); let rsc_module_options_context = get_server_module_options_context(ty); @@ -169,7 +171,7 @@ pub async fn create_app_source( let mut transitions = HashMap::new(); transitions.insert( "next-layout-entry".to_string(), - next_layout_entry_transition(project_root, app_dir, server_root), + next_layout_entry_transition(project_root, app_dir, server_root, env), ); transitions.insert( "server-to-client".to_string(), @@ -185,13 +187,13 @@ pub async fn create_app_source( ); transitions.insert( "next-ssr-client-module".to_string(), - next_ssr_client_module_transition(project_root, app_dir), + next_ssr_client_module_transition(project_root, app_dir, env), ); let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir }); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), - get_server_environment(ssr_ty), + get_server_environment(ssr_ty, env), get_server_module_options_context(ssr_ty), get_server_resolve_options_context(project_root, ssr_ty), ) diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index e3699ddd327869..c2aec827a82b3f 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -1,12 +1,12 @@ use turbo_tasks::{primitives::StringVc, Value}; +use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ module_options::{ModuleOptionsContext, ModuleOptionsContextVc}, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, }; -use turbopack_core::{ - environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, - target::CompileTargetVc, +use turbopack_core::environment::{ + EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc, }; use turbopack_ecmascript::EcmascriptInputTransform; @@ -56,14 +56,13 @@ pub fn get_server_resolve_options_context( } #[turbo_tasks::function] -pub fn get_server_environment(ty: Value) -> EnvironmentVc { +pub fn get_server_environment( + ty: Value, + process_env: ProcessEnvVc, +) -> EnvironmentVc { EnvironmentVc::new( Value::new(ExecutionEnvironment::NodeJsLambda( - NodeJsEnvironment { - compile_target: CompileTargetVc::current(), - node_version: 0, - } - .cell(), + NodeJsEnvironmentVc::current(process_env), )), match ty.into_value() { ServerContextType::Pages { .. } => Value::new(EnvironmentIntention::ServerRendering), diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 3934b08fae5955..75f083ba97cf51 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -91,7 +91,7 @@ pub async fn create_server_rendered_source( transitions.insert("next-client".to_string(), next_client_transition); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), - get_server_environment(server_ty), + get_server_environment(server_ty, env), get_server_module_options_context(server_ty), get_server_resolve_options_context(project_path, server_ty), ) From d87b96bb49831088f069054ed8cdb1ec13df0985 Mon Sep 17 00:00:00 2001 From: Chris Olszewski Date: Thu, 20 Oct 2022 16:03:17 -0700 Subject: [PATCH 161/672] add postcss and tailwindcss to unimplemented files (vercel/turbo#137) Note that this doesn't completely close out [vercel/turbo#54](https://github.com/vercel/web-tooling-internal/issues/54) as the [tailwindcss config is optional](https://tailwindcss.com/docs/configuration). I'm digging deeper at additional ways to detect tailwind, but putting this up since it's a strict improvement. ``` olszewski@chriss-mbp next-dev % cargo run -p next-dev -- /tmp/with-tailwindcss-app Compiling next-dev v0.1.0 (/Users/olszewski/code/vercel/the-three-body/crates/next-dev) Finished dev [unoptimized + debuginfo] target(s) in 11.61s Running `/Users/olszewski/code/vercel/the-three-body/target/debug/next-dev /tmp/with-tailwindcss-app` server listening on: http://localhost:3000 error [unimplemented] /private/tmp/with-tailwindcss-app/next.config.js Feature not yet supported Handling the file `next.config.js` is currently unimplemented /private/tmp/with-tailwindcss-app/postcss.config.js Feature not yet supported Handling the file `postcss.config.js` is currently unimplemented /private/tmp/with-tailwindcss-app/tailwind.config.js Feature not yet supported Handling the file `tailwind.config.js` is currently unimplemented [200] / (3045ms) initial compilation 3468ms (3044ms task execution, 48380 tasks) updated in 874ms (8990 tasks) ``` --- packages/next-swc/crates/next-dev/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 728618254b9fa0..983e4b07808627 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -162,7 +162,13 @@ async fn handle_issues>(source: T, console_ui: ConsoleUiVc) -> Re } async fn handle_unimplemented_files(project_path: &FileSystemPathVc) -> Result<()> { - const UNIMPLEMENTED_FILES: [&str; 3] = ["next.config.js", "babel.config.js", ".babelrc.js"]; + const UNIMPLEMENTED_FILES: [&str; 5] = [ + "next.config.js", + "babel.config.js", + ".babelrc.js", + "postcss.config.js", + "tailwind.config.js", + ]; for file in UNIMPLEMENTED_FILES { let file_path = project_path.join(file); let file_type = file_path.get_type().await?; From 276c844152526189244ed029d27003d3a8c63ef9 Mon Sep 17 00:00:00 2001 From: Leah Date: Fri, 21 Oct 2022 01:46:26 +0200 Subject: [PATCH 162/672] prettier fixes (vercel/turbo#41) --- .../basic/browser-alias-field/dir/indirect.js | 2 +- .../basic/browser-alias-field/node.js | 2 +- .../__skipped__/inline-options/index.js | 54 ++++++++++----- .../chunks/__skipped__/named-chunks/index.js | 66 +++++++++++-------- .../chunks/weird-reference-to-entry/errors.js | 4 +- 5 files changed, 79 insertions(+), 49 deletions(-) diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js index 52ecf59ebfba2a..cebd5bd1ad5d16 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/dir/indirect.js @@ -1 +1 @@ -export { default } from "../node.js" +export { default } from "../node.js"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js index 15f511ba7da062..e52ea80b0d8c39 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/browser-alias-field/node.js @@ -1 +1 @@ -throw new Error("This is node.js only") +throw new Error("This is node.js only"); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js index 2587a01353309d..2bea28ba321756 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/inline-options/index.js @@ -14,7 +14,10 @@ it("should be able to use lazy-once mode", function () { it("should be able to use lazy-once mode with name", function () { function load(name) { - return import(/* webpackMode: "lazy-once", webpackChunkName: "name-lazy-once" */ "./dir3/" + name); + return import( + /* webpackMode: "lazy-once", webpackChunkName: "name-lazy-once" */ "./dir3/" + + name + ); } return testChunkLoading(load, false, true); }); @@ -28,14 +31,19 @@ it("should be able to use lazy mode", function () { it("should be able to use lazy mode with name", function () { function load(name) { - return import(/* webpackMode: "lazy", webpackChunkName: "name-lazy" */ "./dir5/" + name); + return import( + /* webpackMode: "lazy", webpackChunkName: "name-lazy" */ "./dir5/" + name + ); } return testChunkLoading(load, false, false); }); it("should be able to use lazy mode with name and placeholder", function () { function load(name) { - return import(/* webpackMode: "lazy", webpackChunkName: "name-lazy-[request]" */ "./dir6/" + name); + return import( + /* webpackMode: "lazy", webpackChunkName: "name-lazy-[request]" */ "./dir6/" + + name + ); } return testChunkLoading(load, false, false); }); @@ -89,7 +97,9 @@ it("should be able to use weak mode (without context)", function () { it("should not find module when mode is weak and chunk not served elsewhere", function () { var name = "a"; - return import(/* webpackMode: "weak" */ "./dir10/" + name).catch(function (e) { + return import(/* webpackMode: "weak" */ "./dir10/" + name).catch(function ( + e + ) { expect(e).toMatchObject({ message: /not available/, code: /MODULE_NOT_FOUND/, @@ -108,13 +118,17 @@ it("should not find module when mode is weak and chunk not served elsewhere (wit if (process.env.NODE_ENV === "production") { it("should contain only one export from webpackExports from module", function () { - return import(/* webpackExports: "usedExports" */ "./dir12/a?1").then((module) => { - expect(module.usedExports).toEqual(["usedExports"]); - }); + return import(/* webpackExports: "usedExports" */ "./dir12/a?1").then( + (module) => { + expect(module.usedExports).toEqual(["usedExports"]); + } + ); }); it("should contain only webpackExports from module", function () { - return import(/* webpackExports: ["a", "usedExports", "b"] */ "./dir12/a?2").then((module) => { + return import( + /* webpackExports: ["a", "usedExports", "b"] */ "./dir12/a?2" + ).then((module) => { expect(module.usedExports).toEqual(["a", "b", "usedExports"]); }); }); @@ -143,22 +157,28 @@ if (process.env.NODE_ENV === "production") { }); it("should not mangle webpackExports from module", function () { - return import(/* webpackExports: "longnameforexport" */ "./dir12/a?5").then((module) => { - expect(module).toHaveProperty("longnameforexport"); - }); + return import(/* webpackExports: "longnameforexport" */ "./dir12/a?5").then( + (module) => { + expect(module).toHaveProperty("longnameforexport"); + } + ); }); it("should not mangle default webpackExports from module", function () { - return import(/* webpackExports: "default" */ "./dir12/a?6").then((module) => { - expect(module).toHaveProperty("default"); - }); + return import(/* webpackExports: "default" */ "./dir12/a?6").then( + (module) => { + expect(module).toHaveProperty("default"); + } + ); }); it("should contain only webpackExports from module in context mode", function () { const x = "b"; - return import(/* webpackExports: "usedExports" */ `./dir13/${x}`).then((module) => { - expect(module.usedExports).toEqual(["usedExports"]); - }); + return import(/* webpackExports: "usedExports" */ `./dir13/${x}`).then( + (module) => { + expect(module.usedExports).toEqual(["usedExports"]); + } + ); }); } diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js index 5d2c2eb3738bb8..10f5161687127f 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/named-chunks/index.js @@ -108,9 +108,13 @@ it("should handle empty named chunks when there is an error callback", function it("should be able to use named chunks in import()", function (done) { var sync = false; - import("./empty?import1-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */).then(function (result) { + import( + "./empty?import1-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */ + ).then(function (result) { var i = 0; - import("./empty?import2-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */) + import( + "./empty?import2-in-chunk1" /* webpackChunkName: "import-named-chunk-1" */ + ) .then(function (result) { expect(sync).toBeTruthy(); if (i++ > 0) done(); @@ -118,7 +122,9 @@ it("should be able to use named chunks in import()", function (done) { .catch(function (err) { done(err); }); - import("./empty?import3-in-chunk2" /* webpackChunkName: "import-named-chunk-2" */) + import( + "./empty?import3-in-chunk2" /* webpackChunkName: "import-named-chunk-2" */ + ) .then(function (result) { expect(sync).toBeFalsy(); if (i++ > 0) done(); @@ -140,30 +146,32 @@ it("should be able to use named chunk in context import()", function (done) { // cspell:ignore mpty var mpty = "mpty"; var sync = false; - import("./e" + mpty + "2" /* webpackChunkName: "context-named-chunk" */).then(function (result) { - var i = 0; - import("./e" + mpty + "3" /* webpackChunkName: "context-named-chunk" */) - .then(function (result) { - expect(sync).toBeTruthy(); - if (i++ > 0) done(); - }) - .catch(function (err) { - done(err); - }); - import("./e" + mpty + "4" /* webpackChunkName: "context-named-chunk-2" */) - .then(function (result) { - expect(sync).toBeFalsy(); - if (i++ > 0) done(); - }) - .catch(function (err) { - done(err); - }); - sync = true; - Promise.resolve() - .then(function () {}) - .then(function () {}) - .then(function () { - sync = false; - }); - }); + import("./e" + mpty + "2" /* webpackChunkName: "context-named-chunk" */).then( + function (result) { + var i = 0; + import("./e" + mpty + "3" /* webpackChunkName: "context-named-chunk" */) + .then(function (result) { + expect(sync).toBeTruthy(); + if (i++ > 0) done(); + }) + .catch(function (err) { + done(err); + }); + import("./e" + mpty + "4" /* webpackChunkName: "context-named-chunk-2" */) + .then(function (result) { + expect(sync).toBeFalsy(); + if (i++ > 0) done(); + }) + .catch(function (err) { + done(err); + }); + sync = true; + Promise.resolve() + .then(function () {}) + .then(function () {}) + .then(function () { + sync = false; + }); + } + ); }); diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js index 22a1feccc6446b..a2434db4ca2b4e 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js +++ b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/weird-reference-to-entry/errors.js @@ -1,3 +1,5 @@ module.exports = [ - [/It's not allowed to load an initial chunk on demand\. The chunk name "main" is already used by an entrypoint\./], + [ + /It's not allowed to load an initial chunk on demand\. The chunk name "main" is already used by an entrypoint\./, + ], ]; From 88d0a40a9693a85aa23a71b1aa7a540fefd88669 Mon Sep 17 00:00:00 2001 From: Leah Date: Fri, 21 Oct 2022 02:28:46 +0200 Subject: [PATCH 163/672] fix tests (vercel/turbo#143) --- packages/next-swc/crates/next-dev/tests/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 07f5af2f2594d8..0d75d04132eeca 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -4,7 +4,8 @@ "expect": "^24.5.0", "jest-circus-browser": "^1.0.7", "react": "^18.2.0", + "react-dom": "^18.2.0", "react-test-renderer": "^18.2.0", - "styled-jsx": "^5.0.7" + "styled-jsx": "^5.1.0" } } From ff5f95fd475ec860a9fef5d0e3e42e58770db148 Mon Sep 17 00:00:00 2001 From: Maia Teegarden Date: Thu, 20 Oct 2022 22:27:27 -0700 Subject: [PATCH 164/672] Match Next.js server startup message (vercel/turbo#148) ![Screen Shot 2022-10-20 at 8 13 41 PM](https://user-images.githubusercontent.com/2865858/197102924-5970972b-7177-4c30-b7b2-35932d2c66fb.png) --- packages/next-swc/crates/next-dev/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 06fdc77bca3d89..8972d16e47917c 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -113,7 +113,11 @@ async fn main() -> Result<()> { } else { format!("http://{}", server.addr) }; - println!("server listening on: {uri}", uri = index_uri); + println!( + "started server on 0.0.0.0:{}, url: {}", + server.addr.port(), + index_uri + ); if !args.no_open { let _ = webbrowser::open(&index_uri); } From a442eab26ee925857bd06316f6cc92d5e0dda9dd Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 21 Oct 2022 02:01:54 -0400 Subject: [PATCH 165/672] Update default server IP to 0.0.0.0 (vercel/turbo#150) Small nit, but if we want to listen on 0.0.0.0, then we should set that to the default. The difference is that other computers can connect when we listen on 0.0.0.0, while only this computer can connect if we listen on 127.0.0.1. --- packages/next-swc/crates/next-dev/src/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 8972d16e47917c..e6169db4611139 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -36,7 +36,7 @@ struct Cli { port: u16, /// Hostname on which to start the application - #[clap(short = 'H', long, value_parser, default_value = "127.0.0.1")] + #[clap(short = 'H', long, value_parser, default_value = "0.0.0.0")] hostname: IpAddr, /// Compile all, instead of only compiling referenced assets when their @@ -108,13 +108,14 @@ async fn main() -> Result<()> { .await?; { - let index_uri = if server.addr.ip().is_loopback() { + let index_uri = if server.addr.ip().is_loopback() || server.addr.ip().is_unspecified() { format!("http://localhost:{}", server.addr.port()) } else { format!("http://{}", server.addr) }; println!( - "started server on 0.0.0.0:{}, url: {}", + "started server on {}:{}, url: {}", + server.addr.ip(), server.addr.port(), index_uri ); From b1caa9ec34c919295a31feb2a48fbb3e8d87c005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florentin=20/=20=E7=8F=9E=E8=BE=B0?= Date: Fri, 21 Oct 2022 11:50:37 +0200 Subject: [PATCH 166/672] terminal improvements (vercel/turbo#133) * Adds next-like event type styling * No tasks in logs Closes: - https://github.com/vercel/web-tooling-internal/issues/58 Screenshot: ![CleanShot 2022-10-20 at 17 59 45@2x](https://user-images.githubusercontent.com/8146736/196999636-dcf3757d-6c5f-4c52-9257-86caabf6a5d6.png) Co-authored-by: Maia Teegarden Co-authored-by: Justin Ridgewell Co-authored-by: Tobias Koppers --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + .../next-dev/benches/util/prepared_app.rs | 13 ++++++++++-- packages/next-swc/crates/next-dev/src/main.rs | 20 +++++++++++-------- .../crates/next-dev/tests/integration.rs | 7 ++++++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 3e8f5a77cb5275..a6d1a75d1b6c87 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -32,6 +32,7 @@ console-subscriber = { version = "0.1.6", optional = true } futures = "0.3.21" mime = "0.3.16" next-core = { path = "../next-core" } +owo-colors = "3" portpicker = "0.1.1" serde = "1.0.136" serde_json = "1.0.85" diff --git a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs index c3d40a27dc1097..3fd5bf2e31357d 100644 --- a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs +++ b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs @@ -14,6 +14,7 @@ use chromiumoxide::{ Browser, Page, }; use futures::{FutureExt, StreamExt}; +use owo_colors::OwoColorize; use tokio::task::spawn_blocking; use url::Url; @@ -181,12 +182,20 @@ fn stop_process(proc: &mut Child) -> Result<()> { std::thread::sleep(KILL_DEADLINE / KILL_DEADLINE_CHECK_STEPS); } if let Ok(None) = proc.try_wait() { - eprintln!("Process {} did not exit after SIGINT, sending SIGKILL", pid); + eprintln!( + "{event_type} - process {pid} did not exit after SIGINT, sending SIGKILL", + event_type = "error".red(), + pid = pid + ); kill_process(proc)?; } } Err(_) => { - eprintln!("Failed to send SIGINT to process {}, sending SIGKILL", pid); + eprintln!( + "{event_type} - failed to send SIGINT to process {pid}, sending SIGKILL", + event_type = "error".red(), + pid = pid + ); kill_process(proc)?; } } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index e6169db4611139..c3237186205be9 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -12,6 +12,7 @@ use std::{ use anyhow::{Context, Result}; use clap::Parser; use next_dev::{register, NextDevServerBuilder}; +use owo_colors::OwoColorize; use turbo_tasks::{util::FormatDuration, TurboTasks}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::IssueSeverityCliOption; @@ -114,7 +115,8 @@ async fn main() -> Result<()> { format!("http://{}", server.addr) }; println!( - "started server on {}:{}, url: {}", + "{event_type} - started server on {}:{}, url: {}", + event_type = "ready".green(), server.addr.ip(), server.addr.port(), index_uri @@ -125,19 +127,21 @@ async fn main() -> Result<()> { } let stats_future = async move { - let (elapsed, count) = tt_clone.get_or_wait_update_info(Duration::ZERO).await; println!( - "initial compilation {} ({} task execution, {} tasks)", - FormatDuration(start.elapsed()), - FormatDuration(elapsed), - count + "{event_type} - initial compilation {start}", + event_type = "event".purple(), + start = FormatDuration(start.elapsed()), ); loop { - let (elapsed, count) = tt_clone + let (elapsed, _count) = tt_clone .get_or_wait_update_info(Duration::from_millis(100)) .await; - println!("updated in {} ({} tasks)", FormatDuration(elapsed), count); + println!( + "{event_type} - updated in {elapsed}", + event_type = "event".purple(), + elapsed = FormatDuration(elapsed), + ); } }; diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index 771554253f007d..1911e1134fb4cc 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -14,6 +14,7 @@ use chromiumoxide::{ use futures::StreamExt; use lazy_static::lazy_static; use next_dev::{register, NextDevServerBuilder}; +use owo_colors::OwoColorize; use serde::Deserialize; use test_generator::test_resources; use tokio::{net::TcpSocket, task::JoinHandle}; @@ -141,7 +142,11 @@ async fn run_test(resource: &str) -> JestRunResult { .await .unwrap(); - println!("server started at http://{}", server.addr); + println!( + "{event_type} - server started at http://{address}", + event_type = "ready".green(), + address = server.addr + ); tokio::select! { r = run_browser(server.addr) => r.unwrap(), From d1db10cd3796e700c675a37a601bc747c6e2e0b4 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 21 Oct 2022 12:44:40 +0200 Subject: [PATCH 167/672] Bugfixes for merged PRs (vercel/turbo#155) --- .../next-swc/crates/next-dev/benches/bundlers/turbopack.rs | 2 +- packages/next-swc/crates/next-dev/benches/mod.rs | 6 ++++-- .../next-swc/crates/next-dev/benches/util/prepared_app.rs | 2 +- packages/next-swc/crates/next-dev/src/main.rs | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index a29ac40ca1252d..6f60abea7cb7e0 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -79,7 +79,7 @@ impl Bundler for Turbopack { proc.stdout .as_mut() .ok_or_else(|| anyhow!("missing stdout"))?, - Regex::new("server listening on: (.*)")?, + Regex::new("started server on .+, url: (.*)")?, ) .ok_or_else(|| anyhow!("failed to find devserver address"))?; diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index edd1b06fa3b8eb..7f4d08682f7ce3 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -212,13 +212,15 @@ fn bench_hmr_internal(mut g: BenchmarkGroup, location: CodeLocation) { .await?; // Make warmup change - for _ in 0..MAX_UPDATE_TIMEOUT.as_secs() / 5 { + for i in (0..MAX_UPDATE_TIMEOUT.as_secs() / 5).rev() { match make_change(&mut guard, location, Duration::from_secs(5)) .await { Ok(_) => break, Err(err) => { - if err.to_string().contains(CHANGE_TIMEOUT_MESSAGE) { + if i != 0 + && err.to_string().contains(CHANGE_TIMEOUT_MESSAGE) + { continue; } return Err(err); diff --git a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs index 3fd5bf2e31357d..35ac6b95a7f5b3 100644 --- a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs +++ b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs @@ -14,7 +14,6 @@ use chromiumoxide::{ Browser, Page, }; use futures::{FutureExt, StreamExt}; -use owo_colors::OwoColorize; use tokio::task::spawn_blocking; use url::Url; @@ -167,6 +166,7 @@ fn stop_process(proc: &mut Child) -> Result<()> { sys::signal::{kill, Signal}, unistd::Pid, }; + use owo_colors::OwoColorize; const KILL_DEADLINE: Duration = Duration::from_secs(5); const KILL_DEADLINE_CHECK_STEPS: u32 = 10; diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index c3237186205be9..1b15cc8503efb4 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -115,8 +115,8 @@ async fn main() -> Result<()> { format!("http://{}", server.addr) }; println!( - "{event_type} - started server on {}:{}, url: {}", - event_type = "ready".green(), + "{} - started server on {}:{}, url: {}", + "ready".green(), server.addr.ip(), server.addr.port(), index_uri From 790ff6c05cd4476def47f210f8a3b977db9d2cb1 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 21 Oct 2022 14:23:49 +0200 Subject: [PATCH 168/672] add some strongly consistent reads into nodejs source (vercel/turbo#154) to improve performance It doesn't fix the performance completely but makes it less bad --- packages/next-swc/crates/next-core/src/nodejs/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 58c7a451007990..0b2b3ea23e0785 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -79,6 +79,7 @@ async fn internal_assets( ) -> Result { Ok( separate_assets(intermediate_asset, intermediate_output_path) + .strongly_consistent() .await? .internal_assets, ) @@ -99,9 +100,12 @@ async fn external_asset_entrypoints( runtime_entries, chunking_context, intermediate_output_path, - ), + ) + .resolve() + .await?, intermediate_output_path, ) + .strongly_consistent() .await? .external_asset_entrypoints) } @@ -244,7 +248,9 @@ async fn render_static( ), intermediate_output_path, ); - let pool = renderer_pool.await?; + // Read this strongly consistent, since we don't want to run inconsistent + // node.js code. + let pool = renderer_pool.strongly_consistent().await?; let mut op = pool .run(serde_json::to_string(&*data.await?)?.as_bytes()) .await?; From 451dccdeb815fdfbf1615ad4a0d028296fb8df74 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 21 Oct 2022 16:11:25 +0200 Subject: [PATCH 169/672] fix startup benchmarks for CSR bundlers (vercel/turbo#152) --- packages/next-swc/crates/next-dev/benches/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 7f4d08682f7ce3..29cab269077728 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -283,6 +283,18 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup, hydration: boo let browser = &runtime.block_on(create_browser()); for bundler in get_bundlers() { + let wait_for_hydration = if !bundler.has_server_rendered_html() { + // For bundlers without server rendered html "startup" means time to hydration + // as they only render an empty screen without hydration. Since startup and + // hydration would be the same we skip the hydration benchmark for them. + if hydration { + continue; + } else { + true + } + } else { + hydration + }; for module_count in get_module_counts() { let test_app = Lazy::new(|| build_test(module_count, bundler.as_ref())); let input = (bundler.as_ref(), &test_app); From 7d8d351d5e9d1afa4e33543c3699711adb078445 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 21 Oct 2022 16:29:52 +0200 Subject: [PATCH 170/672] fix hydration bench again (vercel/turbo#162) --- packages/next-swc/crates/next-dev/benches/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 29cab269077728..588b71bbdde454 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -325,7 +325,7 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup, hydration: boo |mut app| async { app.start_server()?; let mut guard = app.with_page(browser).await?; - if hydration { + if wait_for_hydration { guard.wait_for_hydration().await?; } From 7b4f51f8fba197711b7f03452ab6dcc09c9177c4 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Fri, 21 Oct 2022 08:38:56 -0700 Subject: [PATCH 171/672] Create a package.json with type: "commonjs" in .next/server (vercel/turbo#145) Closes vercel/turbo#109 Note a difference between this and stable Next.js: at turbopack this file is placed in .next/server/package.json, while Next.js currently creates this file at .next/package.json. Test Plan: Verified that the `hello-world-esm` no longer fails to SSR (it's now blocked by vercel/turbo#111). Co-authored-by: Tobias Koppers --- .../crates/next-core/src/nodejs/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 0b2b3ea23e0785..216639665fddcc 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -18,6 +18,7 @@ use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc, AssetsSetVc}, chunk::{ChunkGroupVc, ChunkingContextVc}, + virtual_asset::VirtualAssetVc, }; use turbopack_dev_server::{ html::DevHtmlAssetVc, @@ -177,7 +178,24 @@ async fn get_renderer_pool( intermediate_asset: AssetVc, intermediate_output_path: FileSystemPathVc, ) -> Result { + // Emit a basic package.json that sets the type of the package to commonjs. + // Currently code generated for Node is CommonJS, while authored code may be + // ESM, for example. + // + // Note that this is placed at .next/server/package.json, while Next.js + // currently creates this file at .next/package.json. + emit( + VirtualAssetVc::new( + intermediate_output_path.join("package.json"), + FileContent::Content(File::from("{\"type\": \"commonjs\"}")).into(), + ) + .into(), + intermediate_output_path, + ) + .await?; + emit(intermediate_asset, intermediate_output_path).await?; + let output = intermediate_output_path.await?; if let Some(disk) = DiskFileSystemVc::resolve_from(output.fs).await? { let dir = PathBuf::from(&disk.await?.root).join(&output.path); From dd7278c0e3ca80c2fcfa73157e4d2e660cc828ea Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Fri, 21 Oct 2022 09:32:39 -0700 Subject: [PATCH 172/672] Next-dev and snapshot tests: transform ecmascript with styled_components (vercel/turbo#44) To do: * [x] The transform doesn't seem to be running properly yet. Fix this. --- packages/next-swc/crates/next-core/src/next_client/context.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index adf6984cc6cdae..958d17f0b8eecc 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -89,6 +89,7 @@ pub async fn get_client_module_options_context( // we try resolve it once at the root and pass down a context to all // the modules. enable_react_refresh, + enable_styled_components: true, enable_styled_jsx: true, enable_typescript_transform: true, preset_env_versions: Some(env), From 06cc52ecbcc88eeaf868ae13e2521ebea75fd086 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 21 Oct 2022 20:44:29 +0200 Subject: [PATCH 173/672] remove fouc optimization (vercel/turbo#169) --- .../next-swc/crates/next-core/js/src/entry/next-hydrate.tsx | 3 +-- .../next-swc/crates/next-core/js/src/entry/server-renderer.tsx | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx index 3fa9d572fcc319..c5f579540f74c8 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx @@ -2,7 +2,6 @@ import "@vercel/turbopack-next/internal/shims-client"; import { initialize, hydrate } from "next/dist/client"; import { initializeHMR } from "@vercel/turbopack-next/dev/client"; -import { displayContent } from "next/dist/client/dev/fouc"; import * as _app from "@vercel/turbopack-next/pages/_app"; import * as page from "."; @@ -26,7 +25,7 @@ import * as page from "."; console.debug("Hydrating the page"); - await hydrate({ beforeRender: displayContent }); + await hydrate({}); console.debug("The page has been hydrated"); })().catch((err) => console.error(err)); diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 2b79d91855d2a7..caf4343072e9e8 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -86,7 +86,6 @@ async function operation(renderData: RenderData) { buildId: "", /* RenderOptsPartial */ - dev: true, runtimeConfig: {}, assetPrefix: "", canonicalBase: "", From 243bc9fbc04d40139b48cbb9790cf14810716c7b Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Fri, 21 Oct 2022 21:03:52 +0200 Subject: [PATCH 174/672] Add support for API routes (vercel/turbo#163) This reworks our Node.js rendering logic to allow for: * passing binary request bodies in and out of Node.js: API routes can accept request bodies in POST, and can reply with any content type. * content source results that are recomputed every time: we don't want API routes to be cached (at least not by turbopack for now). It also reworks the `END_OF_OPERATION` logic to avoid hard coding a single end of operation marker (they're now unique per pool), and allow multiple kinds of operation events (`Step`, `Success`, `Error`). This is not a particularly good implementation for this. A better implementation would proxy the request from the client to the Node.js server in a more direct manner. We also need a way to tell turbo tasks "don't bother ever caching this", as right now every single API request and result will still be cached, even if we know they will never be used again. Finally, we should communicate with Node.js processes via a better mechanism than stdout. I made some progress on a prototype for using https://github.com/servo/ipc-channel with NAPI a while back, which I'd like to pick up some time after conf. However, it seems to work well enough for now, so yay. Co-authored-by: Tobias Koppers --- packages/next-swc/crates/next-core/Cargo.toml | 2 + .../next-core/js/src/entry/server-api.tsx | 337 ++++++++++++++++++ .../js/src/entry/server-renderer.tsx | 11 +- .../crates/next-core/src/app_source.rs | 6 +- .../crates/next-core/src/nodejs/mod.rs | 152 +++++++- .../next-core/src/nodejs/node_api_source.rs | 169 +++++++++ .../crates/next-core/src/nodejs/node_entry.rs | 8 + .../src/nodejs/node_rendered_source.rs | 30 +- .../crates/next-core/src/nodejs/pool.rs | 220 +++++++++--- .../next-core/src/server_rendered_source.rs | 80 +++-- 10 files changed, 896 insertions(+), 119 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/entry/server-api.tsx create mode 100644 packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs create mode 100644 packages/next-swc/crates/next-core/src/nodejs/node_entry.rs diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 57cb27277e972f..9d843304e1fd64 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -13,6 +13,7 @@ anyhow = "1.0.47" futures = "0.3.21" indexmap = { workspace = true, features = ["serde"] } mime = "0.3.16" +rand = "0.8.5" regex = "1.6.0" serde = "1.0.136" serde_json = "1.0.85" @@ -21,6 +22,7 @@ tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-env = { path = "../turbo-tasks-env" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } +turbo-tasks-hash = { path = "../turbo-tasks-hash" } turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx new file mode 100644 index 00000000000000..5d328ab49a6a8a --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx @@ -0,0 +1,337 @@ +import type { ClientRequest, IncomingMessage, Server } from "node:http"; +import http, { ServerResponse } from "node:http"; +import type { AddressInfo, Socket } from "node:net"; +import { Buffer } from "node:buffer"; + +import "next/dist/server/node-polyfill-fetch.js"; + +import * as allExports from "."; +import { NextParsedUrlQuery } from "next/dist/server/request-meta"; +import { apiResolver } from "next/dist/server/api-utils/node"; + +const [MARKER, OPERATION_STEP, OPERATION_SUCCESS, OPERATION_ERROR] = + process.argv.slice(2, 6).map((arg) => Buffer.from(arg, "utf8")); + +const NEW_LINE = "\n".charCodeAt(0); +const OPERATION_STEP_MARKER = Buffer.concat([ + OPERATION_STEP, + Buffer.from(" ", "utf8"), + MARKER, +]); +const OPERATION_SUCCESS_MARKER = Buffer.concat([ + OPERATION_SUCCESS, + Buffer.from(" ", "utf8"), + MARKER, +]); +const OPERATION_ERROR_MARKER = Buffer.concat([ + OPERATION_ERROR, + Buffer.from(" ", "utf8"), + MARKER, +]); + +process.stdout.write("READY\n"); + +function bufferEndsWith(buffer: Buffer, suffix: Buffer): boolean { + if (buffer.length < suffix.length) { + return false; + } + + return buffer.subarray(buffer.length - suffix.length).equals(suffix); +} + +function readStep(buffer: Buffer): { data: Buffer; remaining: Buffer } | null { + let startLineIdx = 0; + let endLineIdx = buffer.indexOf(NEW_LINE); + + while (endLineIdx !== -1) { + let considering = buffer.subarray(startLineIdx, endLineIdx); + if (considering.equals(OPERATION_STEP_MARKER)) { + return { + data: buffer.subarray( + 0, + // Remove the newline character right before the marker. + startLineIdx === 0 ? 0 : startLineIdx - 1 + ), + remaining: buffer.subarray(endLineIdx + 1), + }; + } + + // Consider the next line. + startLineIdx = endLineIdx + 1; + endLineIdx = buffer.indexOf(NEW_LINE, startLineIdx); + } + + return null; +} + +type State = "headers" | "body" | "done"; +let readState: State = "headers"; +let buffer: Buffer = Buffer.from([]); +let operationPromise: Promise | null = null; + +process.stdin.on("data", async (chunk) => { + buffer = Buffer.concat([buffer, chunk]); + + let step = readStep(buffer); + while (step != null) { + switch (readState) { + case "headers": { + readState = "body"; + const renderData = JSON.parse(step.data.toString("utf-8")); + operationPromise = createOperation(renderData); + break; + } + case "body": { + readState = "headers"; + const body = step.data; + endOperation(operationPromise!, body); + break; + } + } + buffer = step.remaining; + step = readStep(step.remaining); + } +}); + +type RenderData = { + method: string; + params: Record; + path: string; + query: NextParsedUrlQuery; +}; + +type ResponseHeaders = { + status: number; + headers: string[]; +}; + +function writeEventMarker(eventMarker: Buffer) { + process.stdout.write("\n"); + process.stdout.write(eventMarker); + process.stdout.write("\n"); +} + +function writeStep(data: Buffer | string) { + process.stdout.write(data); + writeEventMarker(OPERATION_STEP_MARKER); +} + +function writeSuccess(data: Buffer | string) { + process.stdout.write(data); + writeEventMarker(OPERATION_SUCCESS_MARKER); +} + +function writeError(error: string) { + process.stdout.write(error); + writeEventMarker(OPERATION_ERROR_MARKER); +} + +type Operation = { + clientRequest: ClientRequest; + apiOperation: Promise; + server: Server; +}; + +async function createOperation(renderData: RenderData): Promise { + const server = await createServer(); + + const { + clientRequest, + clientResponsePromise, + serverRequest, + serverResponse, + } = await makeRequest(server, renderData.method, renderData.path); + + const query = { ...renderData.query, ...renderData.params }; + + clientResponsePromise.then((clientResponse) => + handleClientResponse(server, clientResponse) + ); + + return { + clientRequest, + server, + apiOperation: apiResolver( + serverRequest, + serverResponse, + query, + allExports, + { + previewModeId: "", + previewModeEncryptionKey: "", + previewModeSigningKey: "", + }, + false, + true, + renderData.path + ), + }; +} + +function handleClientResponse(server: Server, clientResponse: IncomingMessage) { + const responseData: Buffer[] = []; + let responseHeaders: ResponseHeaders = { + status: clientResponse.statusCode!, + headers: clientResponse.rawHeaders, + }; + + writeStep(JSON.stringify(responseHeaders)); + + clientResponse.on("data", (chunk) => { + responseData.push(chunk); + }); + + clientResponse.once("end", () => { + writeSuccess(Buffer.concat(responseData)); + server.close(); + }); + + clientResponse.once("error", (err) => { + // TODO(alexkirsz) We need to ensure that we haven't already written an error in `endOperation`. + writeError(err.stack ?? "an unknown error occurred"); + server.close(); + }); +} + +/** + * Ends an operation by writing the response body to the client and waiting for the Next.js API resolver to finish. + */ +async function endOperation( + operationPromise: Promise, + body: Buffer +) { + const operation = await operationPromise; + + operation.clientRequest.end(body); + + try { + await operation.apiOperation; + } catch (error) { + if ( + error instanceof Error || + (error != null && (error as any).stack != null) + ) { + const stack = (error as any).stack as string | null; + + if (stack != null) { + writeError(stack); + operation.server.close(); + } + } else { + writeError("an unknown error occurred"); + operation.server.close(); + } + + return; + } +} + +/** + * Creates a server that listens a random port. + */ +function createServer(): Promise { + return new Promise((resolve, reject) => { + const server = http.createServer(); + server.listen(0, () => { + resolve(server); + }); + }); +} + +/** + * Creates a request to a server, and returns the (req, res) pairs from both + * the client's and server's perspective. + */ +function makeRequest( + server: Server, + method: string, + path: string +): Promise<{ + clientRequest: ClientRequest; + clientResponsePromise: Promise; + serverRequest: IncomingMessage; + serverResponse: ServerResponse; +}> { + return new Promise((resolve, reject) => { + let clientRequest: ClientRequest | null = null; + let clientResponseResolve: (value: IncomingMessage) => void; + let clientResponseReject: (error: Error) => void; + let clientResponsePromise = new Promise( + (resolve, reject) => { + clientResponseResolve = resolve; + clientResponseReject = reject; + } + ); + let serverRequest: IncomingMessage | null = null; + let serverResponse: ServerResponse | null = null; + + const maybeResolve = () => { + if ( + clientRequest != null && + serverRequest != null && + serverResponse != null + ) { + cleanup(); + resolve({ + clientRequest, + clientResponsePromise, + serverRequest, + serverResponse, + }); + } + }; + + const cleanup = () => { + server.removeListener("error", errorListener); + server.removeListener("request", requestListener); + }; + + const errorListener = (err: Error) => { + cleanup(); + reject(err); + }; + + const requestListener = ( + req: IncomingMessage, + res: ServerResponse + ) => { + serverRequest = req; + serverResponse = res; + maybeResolve(); + }; + + const cleanupClientResponse = () => { + if (clientRequest != null) { + clientRequest.removeListener("response", responseListener); + clientRequest.removeListener("error", clientResponseErrorListener); + } + }; + + const clientResponseErrorListener = (err: Error) => { + cleanupClientResponse(); + clientResponseReject(err); + }; + + const responseListener = (res: IncomingMessage) => { + cleanupClientResponse(); + clientResponseResolve(res); + }; + + server.once("request", requestListener); + server.once("error", errorListener); + + const address = server.address() as AddressInfo; + + clientRequest = http.request({ + method, + path, + host: "localhost", + port: address.port, + }); + // Otherwise Node.js waits for the first chunk of data to be written before sending the request. + clientRequest.flushHeaders(); + + clientRequest.once("response", responseListener); + clientRequest.once("error", clientResponseErrorListener); + }); +} diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index caf4343072e9e8..8e025326a762a2 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -16,8 +16,15 @@ import chunkGroup from "."; import type { BuildManifest } from "next/dist/server/get-page-files"; import type { ChunkGroup } from "types/next"; -const END_OF_OPERATION = process.argv[2]; +const [MARKER, _OPERATION_STEP, OPERATION_SUCCESS, _OPERATION_ERROR] = + process.argv.slice(2, 6).map((arg) => Buffer.from(arg, "utf8")); + const NEW_LINE = "\n".charCodeAt(0); +const OPERATION_SUCCESS_MARKER = Buffer.concat([ + OPERATION_SUCCESS, + Buffer.from(" ", "utf8"), + MARKER, +]); process.stdout.write("READY\n"); @@ -34,7 +41,7 @@ process.stdin.on("data", async (data) => { } catch (e: any) { console.log(`ERROR=${JSON.stringify(e.stack)}`); } - console.log(END_OF_OPERATION); + console.log(OPERATION_SUCCESS_MARKER.toString("utf8")); data = data.slice(idx + 1); idx = data.indexOf(NEW_LINE); } diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 427c963d9a381c..027ff9b77dece6 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -49,7 +49,7 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - nodejs::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, + nodejs::{create_node_rendered_source, NodeEntry, NodeEntryVc}, util::regular_expression_for_path, }; @@ -328,9 +328,9 @@ struct AppRenderer { } #[turbo_tasks::value_impl] -impl NodeRenderer for AppRenderer { +impl NodeEntry for AppRenderer { #[turbo_tasks::function] - async fn module(&self) -> Result { + async fn entry(&self) -> Result { let layout_path = self.layout_path.await?; let page = layout_path .last() diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 216639665fddcc..7f2be446173dd9 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -1,18 +1,19 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, + io::Write, path::PathBuf, }; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use futures::{stream::FuturesUnordered, TryStreamExt}; use indexmap::{IndexMap, IndexSet}; use mime::TEXT_HTML_UTF_8; -pub use node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}; +pub use node_api_source::create_node_api_source; +pub use node_entry::{NodeEntry, NodeEntryVc}; +pub use node_rendered_source::create_node_rendered_source; use serde::Deserialize; use serde_json::Value as JsonValue; -use turbo_tasks::{ - primitives::StringVc, spawn_blocking, CompletionVc, CompletionsVc, TryJoinIterExt, -}; +use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, TryJoinIterExt}; use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ @@ -22,7 +23,7 @@ use turbopack_core::{ }; use turbopack_dev_server::{ html::DevHtmlAssetVc, - source::{query::Query, HeaderValue}, + source::{query::Query, BodyVc, HeaderValue, ProxyResult, ProxyResultVc}, }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; @@ -31,9 +32,12 @@ use self::{ issue::RenderingIssue, pool::{NodeJsPool, NodeJsPoolVc}, }; +use crate::nodejs::pool::OperationEvent; pub(crate) mod bootstrap; pub(crate) mod issue; +pub(crate) mod node_api_source; +pub(crate) mod node_entry; pub(crate) mod node_rendered_source; pub(crate) mod pool; @@ -269,15 +273,30 @@ async fn render_static( // Read this strongly consistent, since we don't want to run inconsistent // node.js code. let pool = renderer_pool.strongly_consistent().await?; - let mut op = pool - .run(serde_json::to_string(&*data.await?)?.as_bytes()) - .await?; - let lines = spawn_blocking(move || { - let lines = op.read_lines()?; - drop(op); - Ok::<_, anyhow::Error>(lines) - }) - .await?; + let mut operation = pool.operation().await?; + let data = data.await?; + + // First, write the render data to the process as a JSON string. + let data = serde_json::to_string(&*data)?; + operation.write_all(data.as_bytes())?; + operation.write_all(&[b'\n'])?; + + let mut buffer = Vec::new(); + + // Read the result headers as a UTF8 string. + let (_, event) = operation.read_event(&mut buffer)?; + let result = match event { + OperationEvent::Success => String::from_utf8(buffer)?, + event => { + bail!( + "unexpected event from Node.js rendering process: {:?}", + event + ); + } + }; + + // Parse the result. + let lines: Vec<_> = result.lines().collect(); let issue = if let Some(last_line) = lines.last() { if let Some(data) = last_line.strip_prefix("RESULT=") { let result: serde_json::Result = serde_json::from_str(data); @@ -352,3 +371,106 @@ async fn render_static( Ok(html.content()) } + +#[turbo_tasks::value(shared)] +pub(super) struct ResponseHeaders { + status: u16, + headers: Vec, +} + +/// Renders a module as static HTML in a node.js process. +#[turbo_tasks::function] +async fn render_proxy( + path: FileSystemPathVc, + module: EcmascriptModuleAssetVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + chunking_context: ChunkingContextVc, + intermediate_output_path: FileSystemPathVc, + data: RenderDataVc, + body: BodyVc, +) -> Result { + let renderer_pool = get_renderer_pool( + get_intermediate_asset( + module, + runtime_entries, + chunking_context, + intermediate_output_path, + ), + intermediate_output_path, + ); + let pool = renderer_pool.await?; + let mut operation = pool.operation().await?; + let data = data.await?; + + // First, write the render data to the process as a JSON string. + let data = serde_json::to_string(&*data)?; + operation.write_all(data.as_bytes())?; + operation.write_step()?; + + // Then, write the binary body. + for chunk in body.await?.chunks() { + operation.write_all(chunk.as_bytes())?; + } + operation.write_step()?; + + let mut buffer = Vec::new(); + + // Read the response headers as a JSON string. + let (_, event) = operation.read_event(&mut buffer)?; + let headers: ResponseHeaders = match event { + OperationEvent::Step => serde_json::from_slice(&buffer)?, + OperationEvent::Error => return proxy_error(path, buffer), + event => { + bail!( + "unexpected event from Node.js rendering process: {:?}", + event + ); + } + }; + + // Reuse the buffer. + buffer.truncate(0); + + // Read the response body as a binary blob. + let (_, event) = operation.read_event(&mut buffer)?; + let body = match event { + OperationEvent::Success => buffer, + OperationEvent::Error => return proxy_error(path, buffer), + event => { + bail!( + "unexpected event from Node.js rendering process: {:?}", + event + ); + } + }; + + Ok(ProxyResult { + status: headers.status, + headers: headers.headers, + body, + } + .cell()) +} + +fn proxy_error(path: FileSystemPathVc, buffer: Vec) -> Result { + let error_message = String::from_utf8(buffer.clone())?; + + RenderingIssue { + context: path, + message: StringVc::cell(error_message), + logs: StringVc::cell("".to_string()), + } + .cell() + .as_issue() + .emit(); + + return Ok(ProxyResult { + status: 500, + headers: vec![ + "content-type".to_string(), + "text/html; charset=utf-8".to_string(), + ], + body: buffer, + } + .cell()); +} diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs new file mode 100644 index 00000000000000..63afe4357f6acb --- /dev/null +++ b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs @@ -0,0 +1,169 @@ +use std::collections::HashSet; + +use anyhow::Result; +use indexmap::IndexMap; +use turbo_tasks::{primitives::StringVc, ValueToString}; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_core::{ + chunk::ChunkingContextVc, + introspect::{ + asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, + }, +}; +use turbopack_dev_server::source::{ + ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, + ContentSourceResult, ContentSourceResultVc, ContentSourceVc, +}; +use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; + +use super::{get_intermediate_asset, render_proxy, NodeEntryVc, RenderData}; +use crate::path_regex::PathRegexVc; + +/// Creates a [NodeApiContentSource]. +#[turbo_tasks::function] +pub fn create_node_api_source( + server_root: FileSystemPathVc, + path_regex: PathRegexVc, + entry: NodeEntryVc, + chunking_context: ChunkingContextVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + intermediate_output_path: FileSystemPathVc, +) -> ContentSourceVc { + NodeApiContentSource { + server_root, + path_regex, + entry, + chunking_context, + runtime_entries, + intermediate_output_path, + } + .cell() + .into() +} + +/// A content source that proxies API requests to one-off Node.js +/// servers running the passed `entry` when it matches a `path_regex`. +/// +/// It needs a temporary directory (`intermediate_output_path`) to place file +/// for Node.js execution during rendering. The `chunking_context` should emit +/// to this directory. +#[turbo_tasks::value] +struct NodeApiContentSource { + server_root: FileSystemPathVc, + path_regex: PathRegexVc, + entry: NodeEntryVc, + chunking_context: ChunkingContextVc, + runtime_entries: EcmascriptChunkPlaceablesVc, + intermediate_output_path: FileSystemPathVc, +} + +impl NodeApiContentSource { + /// Checks if a path matches the regular expression + async fn is_matching_path(&self, path: &str) -> Result { + Ok(self.path_regex.await?.is_match(path)) + } + + /// Matches a path with the regular expression and returns a JSON object + /// with the named captures + async fn get_matches(&self, path: &str) -> Result>> { + Ok(self.path_regex.await?.get_matches(path)) + } +} + +#[turbo_tasks::value_impl] +impl ContentSource for NodeApiContentSource { + #[turbo_tasks::function] + async fn get( + self_vc: NodeApiContentSourceVc, + path: &str, + data: turbo_tasks::Value, + ) -> Result { + let this = self_vc.await?; + if this.is_matching_path(path).await? { + if let Some(params) = this.get_matches(path).await? { + if let ContentSourceData { + headers: Some(headers), + method: Some(method), + url: Some(url), + query: Some(query), + body: Some(body), + .. + } = &*data + { + return Ok(ContentSourceResult::HttpProxy(render_proxy( + this.server_root.join(path), + this.entry.entry(), + this.runtime_entries, + this.chunking_context, + this.intermediate_output_path, + RenderData { + params, + method: method.clone(), + url: url.clone(), + query: query.clone(), + headers: headers.clone(), + path: format!("/{path}"), + } + .cell(), + *body, + )) + .cell() + .into()); + } else { + return Ok(ContentSourceResult::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + method: true, + url: true, + headers: Some(ContentSourceDataFilter::All), + query: Some(ContentSourceDataFilter::All), + body: true, + cache_buster: true, + ..Default::default() + }, + } + .cell()); + } + } + } + Ok(ContentSourceResult::NotFound.cell()) + } +} + +#[turbo_tasks::function] +fn introspectable_type() -> StringVc { + StringVc::cell("node api content source".to_string()) +} + +#[turbo_tasks::value_impl] +impl Introspectable for NodeApiContentSource { + #[turbo_tasks::function] + fn ty(&self) -> StringVc { + introspectable_type() + } + + #[turbo_tasks::function] + fn title(&self) -> StringVc { + self.path_regex.to_string() + } + + #[turbo_tasks::function] + fn children(&self) -> IntrospectableChildrenVc { + IntrospectableChildrenVc::cell(HashSet::from([ + ( + StringVc::cell("module".to_string()), + IntrospectableAssetVc::new(self.entry.entry().into()), + ), + ( + StringVc::cell("intermediate asset".to_string()), + IntrospectableAssetVc::new(get_intermediate_asset( + self.entry.entry(), + self.runtime_entries, + self.chunking_context, + self.intermediate_output_path, + )), + ), + ])) + } +} diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs b/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs new file mode 100644 index 00000000000000..91360f071ad7d8 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs @@ -0,0 +1,8 @@ +use anyhow::Result; +use turbopack_ecmascript::EcmascriptModuleAssetVc; + +/// Trait that allows to get the entry module for rendering something in Node.js +#[turbo_tasks::value_trait] +pub trait NodeEntry { + fn entry(&self) -> EcmascriptModuleAssetVc; +} diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 54be0081c879ea..76497a6a64896f 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -20,20 +20,16 @@ use turbopack_dev_server::{ ContentSourceResult, ContentSourceResultVc, ContentSourceVc, }, }; -use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; +use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; -use super::{external_asset_entrypoints, get_intermediate_asset, render_static, RenderData}; +use super::{ + external_asset_entrypoints, get_intermediate_asset, render_static, NodeEntryVc, RenderData, +}; use crate::path_regex::PathRegexVc; -/// Trait that allows to get the entry module for rendering something in Node.js -#[turbo_tasks::value_trait] -pub trait NodeRenderer { - fn module(&self) -> EcmascriptModuleAssetVc; -} - /// Creates a content source that renders something in Node.js with the passed -/// `renderer` when it matches a `path_regex`. Once rendered it serves -/// all assets referenced by the `renderer` that are within the `server_root`. +/// `entry` when it matches a `path_regex`. Once rendered it serves +/// all assets referenced by the `entry` that are within the `server_root`. /// It needs a temporary directory (`intermediate_output_path`) to place file /// for Node.js execution during rendering. The `chunking_context` should emit /// to this directory. @@ -41,7 +37,7 @@ pub trait NodeRenderer { pub fn create_node_rendered_source( server_root: FileSystemPathVc, path_regex: PathRegexVc, - renderer: NodeRendererVc, + entry: NodeEntryVc, chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, fallback_page: DevHtmlAssetVc, @@ -50,7 +46,7 @@ pub fn create_node_rendered_source( let source = NodeRenderContentSource { server_root, path_regex, - renderer, + entry, chunking_context, runtime_entries, fallback_page, @@ -73,7 +69,7 @@ pub fn create_node_rendered_source( struct NodeRenderContentSource { server_root: FileSystemPathVc, path_regex: PathRegexVc, - renderer: NodeRendererVc, + entry: NodeEntryVc, chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, fallback_page: DevHtmlAssetVc, @@ -110,7 +106,7 @@ impl GetContentSource for NodeRenderContentSource { AssetGraphContentSourceVc::new_lazy_multiple( self.server_root, external_asset_entrypoints( - self.renderer.module(), + self.entry.entry(), self.runtime_entries, self.chunking_context, self.intermediate_output_path, @@ -143,7 +139,7 @@ impl ContentSource for NodeRenderContentSource { return Ok(ContentSourceResult::Static( render_static( this.server_root.join(path), - this.renderer.module(), + this.entry.entry(), this.runtime_entries, this.fallback_page, this.chunking_context, @@ -222,12 +218,12 @@ impl Introspectable for NodeRenderContentSource { IntrospectableChildrenVc::cell(HashSet::from([ ( StringVc::cell("module".to_string()), - IntrospectableAssetVc::new(self.renderer.module().into()), + IntrospectableAssetVc::new(self.entry.entry().into()), ), ( StringVc::cell("intermediate asset".to_string()), IntrospectableAssetVc::new(get_intermediate_asset( - self.renderer.module(), + self.entry.entry(), self.runtime_entries, self.chunking_context, self.intermediate_output_path, diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index a5081f077b07c9..1d281e556c4981 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -1,23 +1,22 @@ use std::{ collections::HashMap, io::{BufRead, BufReader, Write}, - mem::transmute, path::{Path, PathBuf}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, sync::{Arc, Mutex}, }; use anyhow::{bail, Context, Result}; +use rand::Rng; use tokio::sync::{OwnedSemaphorePermit, Semaphore}; use turbo_tasks::spawn_blocking; - -const END_OF_OPERATION: &str = - "END_OF_OPERATION 4329g8b57hnz349bo58tzuasgnhv9o8e4zo6gvj END_OF_OPERATION\n"; +use turbo_tasks_hash::encode_hex_string; struct NodeJsPoolProcess { child: Child, stdin: ChildStdin, stdout: BufReader, + marker: Arc, } impl Drop for NodeJsPoolProcess { @@ -27,12 +26,96 @@ impl Drop for NodeJsPoolProcess { } } +/// A marker used to detect the limits of a single operation without the output +/// of a Node.js process. +struct OperationMarker { + marker: String, +} + +impl OperationMarker { + const STEP: &str = "OPERATION_STEP"; + const SUCCESS: &str = "OPERATION_END"; + const ERROR: &str = "OPERATION_ERROR"; + + fn new() -> Self { + Self { + marker: encode_hex_string(&rand::thread_rng().gen::<[u8; 16]>()), + } + } + + fn read_event(&self, orig_buffer: &[u8]) -> Option<(usize, OperationEvent)> { + let buffer = orig_buffer; + let buffer = buffer.strip_suffix(&[b'\n'])?; + let buffer = buffer.strip_suffix(self.marker.as_bytes())?; + let buffer = buffer.strip_suffix(&[b' '])?; + + if let Some(buffer) = buffer + .strip_suffix(Self::STEP.as_bytes()) + .and_then(|buffer| buffer.strip_suffix(&[b'\n'])) + { + Some((orig_buffer.len() - buffer.len(), OperationEvent::Step)) + } else if let Some(buffer) = buffer + .strip_suffix(Self::SUCCESS.as_bytes()) + .and_then(|buffer| buffer.strip_suffix(&[b'\n'])) + { + Some((orig_buffer.len() - buffer.len(), OperationEvent::Success)) + } else if let Some(buffer) = buffer + .strip_suffix(Self::ERROR.as_bytes()) + .and_then(|buffer| buffer.strip_suffix(&[b'\n'])) + { + Some((orig_buffer.len() - buffer.len(), OperationEvent::Error)) + } else { + None + } + } + + fn write(&self, mut writer: W, kind: &str) -> std::io::Result<()> + where + W: Write, + { + writer.write_all(&[b'\n'])?; + writer.write_all(kind.as_bytes())?; + writer.write_all(&[b' '])?; + writer.write_all(self.marker.as_bytes())?; + writer.write_all(&[b'\n'])?; + Ok(()) + } + + fn write_step(&self, writer: W) -> std::io::Result<()> + where + W: Write, + { + self.write(writer, Self::STEP) + } +} + +impl Default for OperationMarker { + fn default() -> Self { + Self::new() + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(super) enum OperationEvent { + Step, + Success, + Error, +} + impl NodeJsPoolProcess { - fn prepare(cwd: &Path, env: &HashMap, entrypoint: &Path) -> Command { + fn prepare( + cwd: &Path, + env: &HashMap, + entrypoint: &Path, + marker: &OperationMarker, + ) -> Command { let mut cmd = Command::new("node"); cmd.current_dir(cwd); cmd.arg(entrypoint); - cmd.arg(&END_OF_OPERATION[..END_OF_OPERATION.len() - 1]); + cmd.arg(&marker.marker); + cmd.arg(&OperationMarker::STEP); + cmd.arg(&OperationMarker::SUCCESS); + cmd.arg(&OperationMarker::ERROR); cmd.env_clear(); cmd.env( "PATH", @@ -49,7 +132,7 @@ impl NodeJsPoolProcess { cmd } - fn start(mut cmd: Command) -> Result { + fn start(mut cmd: Command, marker: Arc) -> Result { let mut child = cmd.spawn().context("spawning node pool")?; let stdin = child.stdin.take().unwrap(); let mut stdout = BufReader::new(child.stdout.take().unwrap()); @@ -68,15 +151,26 @@ impl NodeJsPoolProcess { child, stdin, stdout, + marker, }) } - fn read_line(&mut self, buf: &mut String) -> std::io::Result { - self.stdout.read_line(buf) + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> std::io::Result { + self.stdout.read_until(byte, buf) } - pub(super) fn write(&mut self, buf: &[u8]) -> std::io::Result<()> { - self.stdin.write_all(buf) + fn write_step(&mut self) -> std::io::Result<()> { + self.marker.write_step(&mut self.stdin) + } +} + +impl Write for NodeJsPoolProcess { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.stdin.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.stdin.flush() } } @@ -98,6 +192,8 @@ pub(super) struct NodeJsPool { processes: Arc>>, #[turbo_tasks(trace_ignore, debug_ignore)] semaphore: Arc, + #[turbo_tasks(trace_ignore, debug_ignore)] + marker: Arc, } impl NodeJsPool { @@ -113,6 +209,7 @@ impl NodeJsPool { env, processes: Arc::new(Mutex::new(Vec::new())), semaphore: Arc::new(Semaphore::new(concurrency)), + marker: Arc::new(OperationMarker::default()), } } @@ -125,38 +222,30 @@ impl NodeJsPool { Ok(if let Some(child) = popped { (child, permit) } else { + let marker = Arc::clone(&self.marker); let cmd = NodeJsPoolProcess::prepare( self.cwd.as_path(), &self.env, self.entrypoint.as_path(), + &*marker, ); - let fresh = spawn_blocking(move || NodeJsPoolProcess::start(cmd)).await?; + let fresh = spawn_blocking(move || NodeJsPoolProcess::start(cmd, marker)).await?; (fresh, permit) }) } - pub(super) async fn run(&self, input: &[u8]) -> Result { - let (mut child, permit) = self.acquire_child().await?; - // SAFETY we await spawn blocking so we stay within the lifetime of input - let static_input: &'static [u8] = unsafe { transmute(input) }; - let child = spawn_blocking(move || { - child.write(static_input)?; - child.write(b"\n")?; - Ok::<_, anyhow::Error>(child) - }) - .await?; + pub(super) async fn operation(&self) -> Result { + let (child, permit) = self.acquire_child().await?; - Ok(NodeJsOperationResult { + Ok(NodeJsOperation { child: Some(child), - child_ended: false, permit, processes: self.processes.clone(), }) } } -pub(super) struct NodeJsOperationResult { - child_ended: bool, +pub(super) struct NodeJsOperation { child: Option, // This is used for drop #[allow(dead_code)] @@ -164,46 +253,61 @@ pub(super) struct NodeJsOperationResult { processes: Arc>>, } -impl NodeJsOperationResult { - pub(super) fn read_line(&mut self, buf: &mut String) -> Result { - if let Some(ref mut child) = self.child { - if self.child_ended { - return Ok(0); - } - let len = child.read_line(buf)?; - if len == 0 { - self.child = None; - return Ok(0); - } - if buf.ends_with(END_OF_OPERATION) { - buf.truncate(buf.len() - END_OF_OPERATION.len()); - self.child_ended = true; - Ok(0) - } else { - Ok(len) - } - } else { - Ok(0) - } +impl NodeJsOperation { + fn expect_child_mut(&mut self) -> &mut NodeJsPoolProcess { + self.child + .as_mut() + .expect("child must be present while operation is live") } - pub(super) fn read_lines(&mut self) -> Result, std::io::Error> { - let mut lines = Vec::new(); + fn take_child(&mut self) -> NodeJsPoolProcess { + self.child + .take() + .expect("child must be present while operation is live") + } + + /// Writes the step event end marker to the child process. + pub(super) fn write_step(&mut self) -> std::io::Result<()> { + self.expect_child_mut().write_step() + } + + /// Reads a completed event in the child process output. Blocks while + /// waiting for more output. + pub(super) fn read_event( + &mut self, + buf: &mut Vec, + ) -> std::io::Result<(usize, OperationEvent)> { + let child = self.expect_child_mut(); + let mut total_read = 0; loop { - let mut line = String::new(); - if self.read_line(&mut line)? == 0 { - return Ok(lines); + total_read += child.read_until(b'\n', buf)?; + + match child.marker.read_event(&buf) { + Some((read, event)) => { + buf.truncate(buf.len() - read); + break Ok((total_read - read, event)); + } + None => {} } - line.pop(); - lines.push(line); } } } -impl Drop for NodeJsOperationResult { +impl Write for NodeJsOperation { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let child = self.expect_child_mut(); + child.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + let child = self.expect_child_mut(); + child.flush() + } +} + +impl Drop for NodeJsOperation { fn drop(&mut self) { - if let Some(child) = self.child.take() { - self.processes.lock().unwrap().push(child) - } + let child = self.take_child(); + self.processes.lock().unwrap().push(child); } } diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 75f083ba97cf51..3745f30fa7f728 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use anyhow::Result; -use turbo_tasks::Value; +use turbo_tasks::{primitives::BoolVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; @@ -38,7 +38,7 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - nodejs::node_rendered_source::{create_node_rendered_source, NodeRenderer, NodeRendererVc}, + nodejs::{create_node_api_source, create_node_rendered_source, NodeEntry, NodeEntryVc}, util::regular_expression_for_path, }; @@ -111,6 +111,7 @@ pub async fn create_server_rendered_source( fallback_page, server_root, server_root, + server_root.join("api"), output_path, ); let fallback_source = @@ -125,7 +126,7 @@ pub async fn create_server_rendered_source( /// Handles a single page file in the pages directory #[turbo_tasks::function] -fn create_server_rendered_source_for_file( +async fn create_server_rendered_source_for_file( context_path: FileSystemPathVc, context: AssetContextVc, pages_dir: FileSystemPathVc, @@ -134,8 +135,9 @@ fn create_server_rendered_source_for_file( fallback_page: DevHtmlAssetVc, server_root: FileSystemPathVc, server_path: FileSystemPathVc, + is_api_path: BoolVc, intermediate_output_path: FileSystemPathVc, -) -> ContentSourceVc { +) -> Result { let source_asset = SourceAssetVc::new(page_file).into(); let entry_asset = context.process(source_asset); @@ -148,20 +150,38 @@ fn create_server_rendered_source_for_file( ) .into(); - create_node_rendered_source( - server_root, - regular_expression_for_path(server_root, server_path, true), - SsrRenderer { - context, - entry_asset, - } - .cell() - .into(), - chunking_context, - runtime_entries, - fallback_page, - intermediate_output_path, - ) + Ok(if *is_api_path.await? { + create_node_api_source( + server_root, + regular_expression_for_path(server_root, server_path, true), + SsrEntry { + context, + entry_asset, + is_api_path, + } + .cell() + .into(), + chunking_context, + runtime_entries, + intermediate_output_path, + ) + } else { + create_node_rendered_source( + server_root, + regular_expression_for_path(server_root, server_path, true), + SsrEntry { + context, + entry_asset, + is_api_path, + } + .cell() + .into(), + chunking_context, + runtime_entries, + fallback_page, + intermediate_output_path, + ) + }) } /// Handles a directory in the pages directory (or the pages directory itself). @@ -177,6 +197,7 @@ async fn create_server_rendered_source_for_directory( fallback_page: DevHtmlAssetVc, server_root: FileSystemPathVc, server_path: FileSystemPathVc, + server_api_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, ) -> Result { let mut predefined_sources = vec![]; @@ -219,6 +240,7 @@ async fn create_server_rendered_source_for_directory( fallback_page, server_root, dev_server_path, + dev_server_path.is_inside(server_api_path), intermediate_output_path, ), )); @@ -239,6 +261,7 @@ async fn create_server_rendered_source_for_directory( fallback_page, server_root, server_path.join(name), + server_api_path, intermediate_output_path.join(name), ) .into(), @@ -265,21 +288,30 @@ async fn create_server_rendered_source_for_directory( /// The node.js renderer for SSR of pages. #[turbo_tasks::value] -struct SsrRenderer { +struct SsrEntry { context: AssetContextVc, entry_asset: AssetVc, + is_api_path: BoolVc, } #[turbo_tasks::value_impl] -impl NodeRenderer for SsrRenderer { +impl NodeEntry for SsrEntry { #[turbo_tasks::function] - fn module(&self) -> EcmascriptModuleAssetVc { - EcmascriptModuleAssetVc::new( + async fn entry(&self) -> Result { + let virtual_asset = if *self.is_api_path.await? { + VirtualAssetVc::new( + self.entry_asset.path().join("server-api.tsx"), + next_js_file("entry/server-api.tsx").into(), + ) + } else { VirtualAssetVc::new( self.entry_asset.path().join("server-renderer.tsx"), next_js_file("entry/server-renderer.tsx").into(), ) - .into(), + }; + + Ok(EcmascriptModuleAssetVc::new( + virtual_asset.into(), self.context, Value::new(EcmascriptModuleAssetType::Typescript), EcmascriptInputTransformsVc::cell(vec![ @@ -287,6 +319,6 @@ impl NodeRenderer for SsrRenderer { EcmascriptInputTransform::React { refresh: false }, ]), self.context.environment(), - ) + )) } } From 4569ef779d0da1b5d37763206e748edc7cd41836 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Fri, 21 Oct 2022 12:31:01 -0700 Subject: [PATCH 175/672] Transform ecmascript with emotion (vercel/turbo#170) Enabled in next-dev and snapshot tests. There are quite a few output snapshot files. Maybe we make stubs for the third-party packages to reduce the noise... Test Plan: Added new snapshot tests. Verified transformed code contains a digest, inline source map string. --- packages/next-swc/crates/next-core/src/next_client/context.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 958d17f0b8eecc..d0430235d333c4 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -88,6 +88,7 @@ pub async fn get_client_module_options_context( // We don't need to resolve React Refresh for each module. Instead, // we try resolve it once at the root and pass down a context to all // the modules. + enable_emotion: true, enable_react_refresh, enable_styled_components: true, enable_styled_jsx: true, From 722930a00610c265f1ffa7468befd435d0ed9d22 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Fri, 21 Oct 2022 19:54:24 -0700 Subject: [PATCH 176/672] feat(devserver): try to bind instead of explicit (vercel/turbo#187) This PR attempts to try to bind server and bubbles up error, instead of explicit `bind` which panics internally if it wasn't possible to bind. --- packages/next-swc/crates/next-dev/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 983e4b07808627..28cf4f9e81b840 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -145,7 +145,7 @@ impl NextDevServerBuilder { console_ui_to_dev_server, ); - Ok(server) + server } } From 8fa162d5c567bbaba510f44dfd6c374a2d7243cf Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Sat, 22 Oct 2022 19:47:59 +0200 Subject: [PATCH 177/672] fix app layouts (vercel/turbo#190) Seems like app layout was left behind while shipping features to normal SSR rendering * fixes fallback error pages (update to error fallback changes) * fixes process communication (update to api route changes) * avoid busy looping * update to next.js updates * fix resolving cycle * fix HMR of client components * add some hard coded external packages --- .../next-swc/crates/next-core/js/package.json | 3 +- .../next-core/js/src/entry/app-renderer.tsx | 15 +++-- .../next-core/js/src/entry/app/hydrate.tsx | 8 ++- .../js/src/entry/app/layout-entry.tsx | 2 +- .../crates/next-core/js/types/modules.d.ts | 2 +- .../crates/next-core/src/app_source.rs | 10 ++-- .../crates/next-core/src/next_import_map.rs | 59 ++++++++----------- .../crates/next-core/src/nodejs/pool.rs | 15 ++++- .../next-dev/benches/bundlers/turbopack.rs | 4 +- 9 files changed, 65 insertions(+), 53 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index 3662317db64c47..48e75ffb495ce5 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -9,11 +9,10 @@ "build:compiled": "node build.mjs" }, "dependencies": { - "@next/react-refresh-utils": "^12.2.5", "@vercel/turbopack-runtime": "latest", "anser": "2.1.1", "css.escape": "1.5.1", - "next": "12.3.2-canary.32", + "next": "12.3.2-canary.33", "platform": "1.3.6", "react-dom": "^18.2.0", "react": "^18.2.0", diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index f30ce96496ca73..30c940f375f336 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -6,8 +6,6 @@ declare global { const BOOTSTRAP: string[]; } -const END_OF_OPERATION = process.argv[2]; - import type { IncomingMessage, ServerResponse } from "node:http"; import type { FlightManifest } from "next/dist/build/webpack/plugins/flight-manifest-plugin"; import type { RenderData } from "types/turbopack"; @@ -27,9 +25,18 @@ globalThis.__next_chunk_load__ = () => Promise.resolve(); process.env.__NEXT_NEW_LINK_BEHAVIOR = "true"; -process.stdout.write("READY\n"); +const [MARKER, _OPERATION_STEP, OPERATION_SUCCESS, _OPERATION_ERROR] = + process.argv.slice(2, 6).map((arg) => Buffer.from(arg, "utf8")); const NEW_LINE = "\n".charCodeAt(0); +const OPERATION_SUCCESS_MARKER = Buffer.concat([ + OPERATION_SUCCESS, + Buffer.from(" ", "utf8"), + MARKER, +]); + +process.stdout.write("READY\n"); + const buffer: Buffer[] = []; process.stdin.on("data", async (data) => { let idx = data.indexOf(NEW_LINE); @@ -53,7 +60,7 @@ process.stdin.on("data", async (data) => { } catch (e: any) { console.log(`ERROR=${JSON.stringify(e.stack)}`); } - console.log(END_OF_OPERATION); + console.log(OPERATION_SUCCESS_MARKER.toString("utf8")); data = data.slice(idx + 1); idx = data.indexOf(NEW_LINE); } diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx index 50059fb25b4c05..93adeee0070247 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx @@ -1,10 +1,16 @@ import ReactDOMClient from "react-dom/client"; import React, { experimental_use as use } from "react"; import type { ReactElement } from "react"; -import { createFromReadableStream } from "next/dist/compiled/react-server-dom-webpack"; +import { createFromReadableStream } from "next/dist/compiled/react-server-dom-webpack/client"; import { HeadManagerContext } from "next/dist/shared/lib/head-manager-context"; +import { initializeHMR } from "@vercel/turbopack-next/dev/client"; + +initializeHMR({ + assetPrefix: "", +}); + globalThis.__next_require__ = (data) => { const [, client_id] = JSON.parse(data); return __turbopack_require__(client_id); diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx index c5c5dd57d3a455..ad39d203f4a5f7 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx @@ -5,6 +5,6 @@ export { staticGenerationAsyncStorage } from "next/dist/esm/client/components/st export { requestAsyncStorage } from "next/dist/esm/client/components/request-async-storage.js"; import * as serverHooks from "next/dist/esm/client/components/hooks-server-context.js"; export { serverHooks }; -export { renderToReadableStream } from "next/dist/compiled/react-server-dom-webpack/writer.browser.server"; +export { renderToReadableStream } from "next/dist/compiled/react-server-dom-webpack/server.browser"; export { default } from "."; diff --git a/packages/next-swc/crates/next-core/js/types/modules.d.ts b/packages/next-swc/crates/next-core/js/types/modules.d.ts index 1996418b14e702..6400dd185c2260 100644 --- a/packages/next-swc/crates/next-core/js/types/modules.d.ts +++ b/packages/next-swc/crates/next-core/js/types/modules.d.ts @@ -1,4 +1,4 @@ declare module "next/dist/esm/client/components/static-generation-async-storage.js"; declare module "next/dist/esm/client/components/request-async-storage.js"; declare module "next/dist/esm/client/components/hooks-server-context.js"; -declare module "next/dist/compiled/react-server-dom-webpack/writer.browser.server"; +declare module "next/dist/compiled/react-server-dom-webpack/server.browser"; diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 027ff9b77dece6..fb35ac2d7fe8f2 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -108,14 +108,14 @@ async fn next_client_transition( #[turbo_tasks::function] fn next_ssr_client_module_transition( - project_path: FileSystemPathVc, + project_root: FileSystemPathVc, app_dir: FileSystemPathVc, process_env: ProcessEnvVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppSSR { app_dir }); NextSSRClientModuleTransition { ssr_module_options_context: get_server_module_options_context(ty), - ssr_resolve_options_context: get_server_resolve_options_context(project_path, ty), + ssr_resolve_options_context: get_server_resolve_options_context(project_root, ty), ssr_environment: get_server_environment(ty, process_env), } .cell() @@ -148,13 +148,13 @@ fn next_layout_entry_transition( /// Next.js app folder. #[turbo_tasks::function] pub async fn create_app_source( - project_path: FileSystemPathVc, + project_root: FileSystemPathVc, output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, ) -> Result { - let project_root = wrap_with_next_js_fs(project_path); + let project_root = wrap_with_next_js_fs(project_root); let app = project_root.join("app"); let src_app = project_root.join("src/app"); @@ -202,7 +202,7 @@ pub async fn create_app_source( let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_root, env).as_ecmascript_chunk_placeable()]; - let fallback_page = get_fallback_page(project_path, server_root, browserslist_query); + let fallback_page = get_fallback_page(project_root, server_root, browserslist_query); Ok(create_app_source_for_directory( context, diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 69d899aad89a47..bf88c1ff16ed11 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -3,7 +3,7 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::resolve::options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}; use crate::{ - embed_js::{attached_next_js_package_path, next_js_fs, VIRTUAL_PACKAGE_NAME}, + embed_js::{attached_next_js_package_path, VIRTUAL_PACKAGE_NAME}, next_client::context::ContextType, next_server::ServerContextType, }; @@ -39,21 +39,14 @@ pub fn get_next_client_import_map( ); } ContextType::App { app_dir } => { - import_map.insert_exact_alias( - "react", - request_to_import_mapping(app_dir, "next/dist/compiled/react"), - ); - import_map.insert_wildcard_alias( - "react/", - request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), - ); - import_map.insert_exact_alias( - "react-dom", - request_to_import_mapping(app_dir, "next/dist/compiled/react-dom"), - ); + import_map.insert_exact_alias("react", request_to_import_mapping(app_dir, "react")); + import_map + .insert_wildcard_alias("react/", request_to_import_mapping(app_dir, "react/*")); + import_map + .insert_exact_alias("react-dom", request_to_import_mapping(app_dir, "react-dom")); import_map.insert_wildcard_alias( "react-dom/", - request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), + request_to_import_mapping(app_dir, "react-dom/*"), ); } ContextType::Other => {} @@ -89,6 +82,10 @@ pub fn get_next_client_fallback_import_map(ty: Value) -> ImportMapV import_map.cell() } +// TODO this should be a user configurable option +/// Temporary hard coded externals list +static HARD_CODED_EXTERNALS: &[&str] = &["prisma", "@prisma/client", "@mux/blurhash"]; + /// Computes the Next-specific server-side import map. #[turbo_tasks::function] pub fn get_next_server_import_map( @@ -119,37 +116,33 @@ pub fn get_next_server_import_map( ], ); - import_map.insert_wildcard_alias( - format!("{VIRTUAL_PACKAGE_NAME}/"), - ImportMapping::PrimaryAlternative("./*".to_string(), Some(next_js_fs().root())) - .cell(), - ); - import_map.insert_exact_alias("next", ImportMapping::External(None).into()); import_map.insert_wildcard_alias("next/", ImportMapping::External(None).into()); import_map.insert_exact_alias("react", ImportMapping::External(None).into()); import_map.insert_wildcard_alias("react/", ImportMapping::External(None).into()); + import_map.insert_exact_alias("react-dom", ImportMapping::External(None).into()); + import_map.insert_wildcard_alias("react-dom/", ImportMapping::External(None).into()); } ServerContextType::AppSSR { app_dir } | ServerContextType::AppRSC { app_dir } => { - import_map.insert_exact_alias( - "react", - request_to_import_mapping(app_dir, "next/dist/compiled/react"), - ); - import_map.insert_wildcard_alias( - "react/", - request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), - ); + import_map.insert_exact_alias("react", request_to_import_mapping(app_dir, "react")); + import_map + .insert_wildcard_alias("react/", request_to_import_mapping(app_dir, "react/*")); import_map.insert_exact_alias( "react-dom", - request_to_import_mapping( - app_dir, - "next/dist/compiled/react-dom/server-rendering-stub.js", - ), + request_to_import_mapping(app_dir, "react-dom/server-rendering-stub.js"), ); import_map.insert_wildcard_alias( "react-dom/", - request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), + request_to_import_mapping(app_dir, "react-dom/*"), ); + + for &external in HARD_CODED_EXTERNALS { + import_map.insert_exact_alias(external, ImportMapping::External(None).into()); + import_map.insert_wildcard_alias( + format!("{external}/"), + ImportMapping::External(None).into(), + ); + } } } diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index 1d281e556c4981..40f15cec6fabf6 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -1,6 +1,6 @@ use std::{ collections::HashMap, - io::{BufRead, BufReader, Write}, + io::{BufRead, BufReader, ErrorKind, Write}, path::{Path, PathBuf}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, sync::{Arc, Mutex}, @@ -280,14 +280,23 @@ impl NodeJsOperation { let child = self.expect_child_mut(); let mut total_read = 0; loop { - total_read += child.read_until(b'\n', buf)?; + let read = child.read_until(b'\n', buf)?; + total_read += read; match child.marker.read_event(&buf) { Some((read, event)) => { buf.truncate(buf.len() - read); break Ok((total_read - read, event)); } - None => {} + None => { + if read == 0 { + // we need to stop reading in this case otherwise this loop infinitely + return Err(std::io::Error::new( + ErrorKind::UnexpectedEof, + "process closed unexpectedly while waiting for an operation result", + )); + } + } } } } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index 6f60abea7cb7e0..6e5f2360f1f777 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -47,9 +47,7 @@ impl Bundler for Turbopack { npm::install( install_dir, &[ - NpmPackage::new("react-refresh", "^0.12.0"), - NpmPackage::new("next", "^12.3.1"), - NpmPackage::new("@next/react-refresh-utils", "^12.3.1"), + NpmPackage::new("next", "12.3.2-canary.33"), // Dependency on this is inserted by swc's preset_env NpmPackage::new("@swc/helpers", "^0.4.11"), ], From b0d8d364298c6968df5c8e67274b61d2f91e5f3f Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 24 Oct 2022 03:34:13 +0200 Subject: [PATCH 178/672] Add back Next's React compiled dists (vercel/turbo#209) Required to get the layout-playground demo working. --- .../next-swc/crates/next-core/js/package.json | 2 +- .../crates/next-core/src/next_import_map.rs | 37 +++++++++++++------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index 48e75ffb495ce5..5e664649922b12 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -12,7 +12,7 @@ "@vercel/turbopack-runtime": "latest", "anser": "2.1.1", "css.escape": "1.5.1", - "next": "12.3.2-canary.33", + "next": "12.3.2-canary.35", "platform": "1.3.6", "react-dom": "^18.2.0", "react": "^18.2.0", diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index bf88c1ff16ed11..9de255a3973dcd 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -39,14 +39,21 @@ pub fn get_next_client_import_map( ); } ContextType::App { app_dir } => { - import_map.insert_exact_alias("react", request_to_import_mapping(app_dir, "react")); - import_map - .insert_wildcard_alias("react/", request_to_import_mapping(app_dir, "react/*")); - import_map - .insert_exact_alias("react-dom", request_to_import_mapping(app_dir, "react-dom")); + import_map.insert_exact_alias( + "react", + request_to_import_mapping(app_dir, "next/dist/compiled/react"), + ); + import_map.insert_wildcard_alias( + "react/", + request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), + ); + import_map.insert_exact_alias( + "react-dom", + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom"), + ); import_map.insert_wildcard_alias( "react-dom/", - request_to_import_mapping(app_dir, "react-dom/*"), + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); } ContextType::Other => {} @@ -124,16 +131,24 @@ pub fn get_next_server_import_map( import_map.insert_wildcard_alias("react-dom/", ImportMapping::External(None).into()); } ServerContextType::AppSSR { app_dir } | ServerContextType::AppRSC { app_dir } => { - import_map.insert_exact_alias("react", request_to_import_mapping(app_dir, "react")); - import_map - .insert_wildcard_alias("react/", request_to_import_mapping(app_dir, "react/*")); + import_map.insert_exact_alias( + "react", + request_to_import_mapping(app_dir, "next/dist/compiled/react"), + ); + import_map.insert_wildcard_alias( + "react/", + request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), + ); import_map.insert_exact_alias( "react-dom", - request_to_import_mapping(app_dir, "react-dom/server-rendering-stub.js"), + request_to_import_mapping( + app_dir, + "next/dist/compiled/react-dom/server-rendering-stub.js", + ), ); import_map.insert_wildcard_alias( "react-dom/", - request_to_import_mapping(app_dir, "react-dom/*"), + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); for &external in HARD_CODED_EXTERNALS { From e4f6bbf6abd9a9479447d1250233b0b768b04d6b Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Mon, 24 Oct 2022 16:21:12 -0400 Subject: [PATCH 179/672] Implement source map tracing for errors (vercel/turbo#227) Fixes https://github.com/vercel/web-tooling-internal/issues/67 --- packages/next-swc/crates/next-core/Cargo.toml | 2 + .../next-core/js/src/entry/app-renderer.tsx | 13 +- .../next-core/js/src/entry/server-api.tsx | 6 +- .../js/src/entry/server-renderer.tsx | 11 +- .../overlay/internal/helpers/stack-frame.ts | 7 +- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../crates/next-core/src/nodejs/mod.rs | 133 +++++++++-- .../src/source_map/content_source.rs | 125 ++++++++++ .../crates/next-core/src/source_map/mod.rs | 7 + .../crates/next-core/src/source_map/trace.rs | 223 ++++++++++++++++++ packages/next-swc/crates/next-dev/src/lib.rs | 6 + 11 files changed, 497 insertions(+), 37 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/source_map/content_source.rs create mode 100644 packages/next-swc/crates/next-core/src/source_map/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/source_map/trace.rs diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 9d843304e1fd64..6453bf01ba4bbf 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -18,6 +18,7 @@ regex = "1.6.0" serde = "1.0.136" serde_json = "1.0.85" serde_qs = "0.10.1" +sourcemap = "6.0.1" tokio = { version = "1.11.0", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-env = { path = "../turbo-tasks-env" } @@ -28,6 +29,7 @@ turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } turbopack-ecmascript = { path = "../turbopack-ecmascript" } turbopack-env = { path = "../turbopack-env" } +url = "2.2.2" [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 30c940f375f336..95af441a0993cf 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -16,6 +16,7 @@ import { RenderOpts, renderToHTMLOrFlight } from "next/dist/server/app-render"; import { PassThrough } from "stream"; import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; import { ParsedUrlQuery } from "node:querystring"; +import { parse as parseStackTrace } from "@vercel/turbopack-next/compiled/stacktrace-parser"; globalThis.__next_require__ = (data) => { const [ssr_id] = JSON.parse(data); @@ -52,13 +53,13 @@ process.stdin.on("data", async (data) => { const input = str.length > 100 ? `${str.slice(0, 30)}...${str.slice(-30)}` : str; e.message += `\nduring processing input ${input}`; - console.log(`ERROR=${JSON.stringify(e.stack)}`); + console.log(`ERROR=${JSON.stringify(structuredError(e))}`); } try { const result = await operation(json); console.log(`RESULT=${JSON.stringify(result)}`); } catch (e: any) { - console.log(`ERROR=${JSON.stringify(e.stack)}`); + console.log(`ERROR=${JSON.stringify(structuredError(e))}`); } console.log(OPERATION_SUCCESS_MARKER.toString("utf8")); data = data.slice(idx + 1); @@ -201,3 +202,11 @@ export function htmlEscapeJsonString(str: string) { (match) => ESCAPE_LOOKUP[match as keyof typeof ESCAPE_LOOKUP] ); } + +function structuredError(e: Error) { + return { + name: e.name, + message: e.message, + stack: parseStackTrace(e.stack!), + }; +} diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx index 5d328ab49a6a8a..1beebbf39ab50c 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx @@ -44,7 +44,7 @@ function readStep(buffer: Buffer): { data: Buffer; remaining: Buffer } | null { let endLineIdx = buffer.indexOf(NEW_LINE); while (endLineIdx !== -1) { - let considering = buffer.subarray(startLineIdx, endLineIdx); + const considering = buffer.subarray(startLineIdx, endLineIdx); if (considering.equals(OPERATION_STEP_MARKER)) { return { data: buffer.subarray( @@ -170,7 +170,7 @@ async function createOperation(renderData: RenderData): Promise { function handleClientResponse(server: Server, clientResponse: IncomingMessage) { const responseData: Buffer[] = []; - let responseHeaders: ResponseHeaders = { + const responseHeaders: ResponseHeaders = { status: clientResponse.statusCode!, headers: clientResponse.rawHeaders, }; @@ -256,7 +256,7 @@ function makeRequest( let clientRequest: ClientRequest | null = null; let clientResponseResolve: (value: IncomingMessage) => void; let clientResponseReject: (error: Error) => void; - let clientResponsePromise = new Promise( + const clientResponsePromise = new Promise( (resolve, reject) => { clientResponseResolve = resolve; clientResponseReject = reject; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 8e025326a762a2..f3c94af232ce63 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -9,6 +9,7 @@ import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; import App from "@vercel/turbopack-next/pages/_app"; import Document from "@vercel/turbopack-next/pages/_document"; +import { parse as parseStackTrace } from "@vercel/turbopack-next/compiled/stacktrace-parser"; import Component, * as otherExports from "."; ("TURBOPACK { transition: next-client }"); @@ -39,7 +40,7 @@ process.stdin.on("data", async (data) => { const result = await operation(json); console.log(`RESULT=${JSON.stringify(result)}`); } catch (e: any) { - console.log(`ERROR=${JSON.stringify(e.stack)}`); + console.log(`ERROR=${JSON.stringify(structuredError(e))}`); } console.log(OPERATION_SUCCESS_MARKER.toString("utf8")); data = data.slice(idx + 1); @@ -151,3 +152,11 @@ async function operation(renderData: RenderData) { ) )?.toUnchunkedString(); } + +function structuredError(e: Error) { + return { + name: e.name, + message: e.message, + stack: parseStackTrace(e.stack!), + }; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/stack-frame.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/stack-frame.ts index 3819118f16b88b..3c7bedbc9c1fa3 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/stack-frame.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/stack-frame.ts @@ -82,12 +82,7 @@ export function getOriginalStackFrame( }; } - if ( - !( - source.file?.startsWith("webpack-internal:") || - source.file?.startsWith("file:") - ) - ) { + if (!source.file?.startsWith(location.origin)) { return Promise.resolve({ error: false, reason: null, diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 8c5b87811b96a5..51e22652598db7 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -15,6 +15,7 @@ mod path_regex; pub mod react_refresh; mod runtime; mod server_rendered_source; +pub mod source_map; mod util; mod web_entry_source; diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 7f2be446173dd9..4f0ec232b04855 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -1,7 +1,8 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, + fmt::Write as _, io::Write, - path::PathBuf, + path::{PathBuf, MAIN_SEPARATOR}, }; use anyhow::{anyhow, bail, Result}; @@ -12,7 +13,6 @@ pub use node_api_source::create_node_api_source; pub use node_entry::{NodeEntry, NodeEntryVc}; pub use node_rendered_source::create_node_rendered_source; use serde::Deserialize; -use serde_json::Value as JsonValue; use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, TryJoinIterExt}; use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; @@ -32,7 +32,10 @@ use self::{ issue::RenderingIssue, pool::{NodeJsPool, NodeJsPoolVc}, }; -use crate::nodejs::pool::OperationEvent; +use crate::{ + nodejs::pool::OperationEvent, + source_map::{SourceMapTraceVc, StackFrame, TraceResult}, +}; pub(crate) mod bootstrap; pub(crate) mod issue; @@ -261,15 +264,13 @@ async fn render_static( intermediate_output_path: FileSystemPathVc, data: RenderDataVc, ) -> Result { - let renderer_pool = get_renderer_pool( - get_intermediate_asset( - module, - runtime_entries, - chunking_context, - intermediate_output_path, - ), + let intermediate_asset = get_intermediate_asset( + module, + runtime_entries, + chunking_context, intermediate_output_path, ); + let renderer_pool = get_renderer_pool(intermediate_asset, intermediate_output_path); // Read this strongly consistent, since we don't want to run inconsistent // node.js code. let pool = renderer_pool.strongly_consistent().await?; @@ -322,19 +323,12 @@ async fn render_static( }, } } else if let Some(data) = last_line.strip_prefix("ERROR=") { - let data: JsonValue = serde_json::from_str(data)?; - if let Some(s) = data.as_str() { - RenderingIssue { - context: path, - message: StringVc::cell(s.to_string()), - logs: StringVc::cell(lines[..lines.len() - 1].join("\n")), - } - } else { - RenderingIssue { - context: path, - message: StringVc::cell(data.to_string()), - logs: StringVc::cell(lines[..lines.len() - 1].join("\n")), - } + let error: StructuredError = serde_json::from_str(data)?; + let message = trace_stack(error.cell(), intermediate_asset, intermediate_output_path); + RenderingIssue { + context: path, + message, + logs: StringVc::cell(lines[..lines.len() - 1].join("\n")), } } else { RenderingIssue { @@ -372,6 +366,95 @@ async fn render_static( Ok(html.content()) } +#[turbo_tasks::value(shared)] +struct StructuredError { + name: String, + message: String, + stack: Vec, +} + +#[turbo_tasks::function] +async fn trace_stack( + error: StructuredErrorVc, + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result { + let error = error.await?; + let fs = match DiskFileSystemVc::resolve_from(intermediate_output_path.fs()).await? { + Some(fs) => fs, + _ => bail!("couldn't extract disk fs from path"), + } + .await?; + let root = format!( + "{}{}", + fs.to_sys_path(intermediate_output_path) + .await? + .to_str() + .unwrap(), + MAIN_SEPARATOR + ); + + let assets = internal_assets(intermediate_asset, intermediate_output_path) + .await? + .iter() + .map(|a| async { + Ok(if *a.path().extension().await? == "map" { + // The path is something like "foo.js.abc123.map + let mut p = fs.to_sys_path(a.path()).await?; + p.set_extension(""); + // The next extension is the hash + debug_assert!(p.extension().is_some()); + debug_assert_ne!(p.extension().unwrap(), "js"); + p.set_extension(""); + let p = p.strip_prefix(&root).unwrap(); + Some((p.to_str().unwrap().to_string(), *a)) + } else { + None + }) + }) + .try_join() + .await? + .into_iter() + .flatten() + .collect::>(); + + let mut message = String::new(); + + macro_rules! write_frame { + ($f:ident) => { + match $f.get_pos() { + Some((l, c)) => match &$f.name { + Some(n) => writeln!(message, " at {} ({}:{}:{})", n, $f.file, l, c), + None => writeln!(message, " at {}:{}:{}", $f.file, l, c), + }, + None => writeln!(message, " at {}", $f.file), + } + }; + } + + writeln!(message, "{}: {}", error.name, error.message)?; + + for frame in &error.stack { + if let Some((line, column)) = frame.get_pos() { + if let Some(path) = frame.file.strip_prefix(&root) { + if let Some(map) = assets.get(path) { + let map_trace = + SourceMapTraceVc::new(map.content(), line, column, frame.name.clone()); + let trace = map_trace.trace().await?; + if let TraceResult::Found(f) = &*trace { + write_frame!(f)?; + continue; + } + } + } + } + + write_frame!(frame)?; + } + + Ok(StringVc::cell(message)) +} + #[turbo_tasks::value(shared)] pub(super) struct ResponseHeaders { status: u16, @@ -464,7 +547,7 @@ fn proxy_error(path: FileSystemPathVc, buffer: Vec) -> Result .as_issue() .emit(); - return Ok(ProxyResult { + Ok(ProxyResult { status: 500, headers: vec![ "content-type".to_string(), @@ -472,5 +555,5 @@ fn proxy_error(path: FileSystemPathVc, buffer: Vec) -> Result ], body: buffer, } - .cell()); + .cell()) } diff --git a/packages/next-swc/crates/next-core/src/source_map/content_source.rs b/packages/next-swc/crates/next-core/src/source_map/content_source.rs new file mode 100644 index 00000000000000..05fb3d2328dab8 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/source_map/content_source.rs @@ -0,0 +1,125 @@ +use std::collections::HashSet; + +use anyhow::Result; +use turbo_tasks::{primitives::StringVc, Value}; +use turbopack_core::introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc}; +use turbopack_dev_server::source::{ + ContentSource, ContentSourceData, ContentSourceDataVary, ContentSourceResult, + ContentSourceResultVc, ContentSourceVc, +}; +use url::Url; + +use super::{SourceMapTraceVc, StackFrame}; + +/// Responsible for performinmg source map tracging for individual error stack +/// frames. This is the API end of the client's Overlay stack-frame.ts. +#[turbo_tasks::value(shared)] +pub struct NextSourceMapTraceContentSource { + asset_source: ContentSourceVc, +} + +#[turbo_tasks::value_impl] +impl NextSourceMapTraceContentSourceVc { + #[turbo_tasks::function] + pub fn new(asset_source: ContentSourceVc) -> NextSourceMapTraceContentSourceVc { + NextSourceMapTraceContentSource { asset_source }.cell() + } +} + +#[turbo_tasks::value_impl] +impl ContentSource for NextSourceMapTraceContentSource { + #[turbo_tasks::function] + async fn get( + self_vc: NextSourceMapTraceContentSourceVc, + path: &str, + data: Value, + ) -> Result { + let url = match &data.url { + None => { + return Ok(ContentSourceResult::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + url: true, + ..Default::default() + }, + } + .cell()); + } + Some(query) => query, + }; + + // TODO: It'd be nice if the data.query value contained the unparsed query, so I + // could convert it into my struct. + let query_idx = match url.find('?') { + Some(i) => i, + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + let frame: StackFrame = match serde_qs::from_str(&url[query_idx + 1..]) { + Ok(f) => f, + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + let (line, column) = match frame.get_pos() { + Some((l, c)) => (l, c), + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + + // The file is some percent encoded `http://localhost:3000/_next/foo/bar.js` + let file = match Url::parse(&frame.file) { + Ok(u) => u, + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + + let path = match file.path().strip_prefix('/') { + Some(p) => p, + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + + // Source maps aren't stored as `foo.js.map`, but instead use a hash of the JS's + // contents: `foo.js.abc123.map`. In order to find the map, we need to + // get the JS's version id and then fetch the map. + let this = self_vc.await?; + let js_file = this + .asset_source + .get(path, Value::new(Default::default())) + .await?; + let js_file = match &*js_file { + ContentSourceResult::Static(f) => f, + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + let id = js_file.version().id().await?; + + let map = this + .asset_source + .get(&format!("{path}.{id}.map"), Value::new(Default::default())) + .await?; + let map = match &*map { + ContentSourceResult::Static(f) => f, + _ => return Ok(ContentSourceResult::NotFound.cell()), + }; + + let traced = SourceMapTraceVc::new(map.content(), line, column, frame.name); + + Ok(ContentSourceResult::Static(traced.content().into()).cell()) + } +} + +#[turbo_tasks::value_impl] +impl Introspectable for NextSourceMapTraceContentSource { + #[turbo_tasks::function] + fn ty(&self) -> StringVc { + StringVc::cell("next source map trace content source".to_string()) + } + + #[turbo_tasks::function] + fn details(&self) -> StringVc { + StringVc::cell( + "supports tracing an error stack frame to its original source location".to_string(), + ) + } + + #[turbo_tasks::function] + async fn children(&self) -> Result { + Ok(IntrospectableChildrenVc::cell(HashSet::new())) + } +} diff --git a/packages/next-swc/crates/next-core/src/source_map/mod.rs b/packages/next-swc/crates/next-core/src/source_map/mod.rs new file mode 100644 index 00000000000000..9b97d08c86105e --- /dev/null +++ b/packages/next-swc/crates/next-core/src/source_map/mod.rs @@ -0,0 +1,7 @@ +pub mod content_source; +pub mod trace; + +pub use content_source::{NextSourceMapTraceContentSource, NextSourceMapTraceContentSourceVc}; +pub use trace::{ + SourceMapTrace, SourceMapTraceVc, StackFrame, StackFrameVc, TraceResult, TraceResultVc, +}; diff --git a/packages/next-swc/crates/next-core/src/source_map/trace.rs b/packages/next-swc/crates/next-core/src/source_map/trace.rs new file mode 100644 index 00000000000000..6db12de27b805c --- /dev/null +++ b/packages/next-swc/crates/next-core/src/source_map/trace.rs @@ -0,0 +1,223 @@ +use std::{ + ops::Deref, + sync::{Arc, Mutex}, +}; + +use anyhow::{bail, Result}; +use serde_json::json; +use sourcemap::{decode as decode_source_map, DecodedMap, Token}; +use turbo_tasks_fs::{File, FileContent, FileContentVc}; +use turbopack_core::asset::{AssetContent, AssetContentVc}; + +/// An individual stack frame, as parsed by the stacktrace-parser npm module. +/// +/// Line and column can be None if the frame is anonymous. +#[turbo_tasks::value(shared)] +#[derive(Debug)] +pub struct StackFrame { + pub file: String, + #[serde(rename = "lineNumber")] + pub line: Option, + pub column: Option, + #[serde(rename = "methodName")] + pub name: Option, +} + +impl StackFrame { + pub fn get_pos(&self) -> Option<(u32, u32)> { + match (self.line, self.column) { + (Some(l), Some(c)) => Some((l, c)), + _ => None, + } + } +} + +/// Source Map Trace implmements the actual source map tracing logic, by parsing +/// the source map and calling the appropriate methods. +#[turbo_tasks::value(shared)] +#[derive(Debug)] +pub struct SourceMapTrace { + file: AssetContentVc, + line: u32, + column: u32, + name: Option, +} + +/// The result of performing a source map trace. +#[turbo_tasks::value(shared)] +#[derive(Debug)] +pub enum TraceResult { + NotFound, + Found(StackFrame), +} + +/// Wraps DecodedMap so that it can be cached in a Vc. +/// +/// DecodedMap contains a raw pointer, which isn't Send, which is required to +/// cache in a Vc. So, we have wrap it in 4 layers of cruft to do it. We don't +/// actually use the pointer, because we don't perform sources content lookup, +/// so it's fine. +struct DecodedMapWrapper(DecodedMap); +unsafe impl Send for DecodedMapWrapper {} +impl Deref for DecodedMapWrapper { + type Target = DecodedMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// DecodedSourceMap wraps sourcemap::DecodedMap in a Vc for caching. +#[turbo_tasks::value(serialization = "none", eq = "manual")] +struct DecodedSourceMap(#[turbo_tasks(debug_ignore, trace_ignore)] Arc>); +impl Deref for DecodedSourceMap { + type Target = Arc>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[turbo_tasks::value_impl] +impl DecodedSourceMapVc { + #[turbo_tasks::function] + async fn from(file: FileContentVc) -> Result { + let file_content = file.await?; + let content = match &*file_content { + FileContent::Content(c) => c, + _ => bail!("could not read file content"), + }; + + // It'd be great if we could cache this, but SM can't be stored in a Vc and I'm + // too sleepy to mess with it. + let sm = match decode_source_map(content.as_ref()) { + Ok(sm) => sm, + _ => bail!("could not decode source map"), + }; + + Ok(DecodedSourceMap(Arc::new(Mutex::new(DecodedMapWrapper(sm)))).cell()) + } +} + +impl PartialEq for DecodedSourceMap { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.0, &other.0) + } +} + +// sourcemap crate didn't implement sectioned sourcemap lookups correctly. +// :face-palm: +fn sectioned_lookup(map: &DecodedMap, line: u32, column: u32) -> Option { + if let DecodedMap::Index(idx) = map { + let len = idx.get_section_count(); + let mut low = 0; + let mut high = len; + + // A "greatest lower bound" binary search. We're looking for the closest section + // line/col <= to our line/col. + while low < high { + let mid = (low + high) / 2; + let section = idx.get_section(mid).unwrap(); + if (line, column) < section.get_offset() { + high = mid; + } else { + low = mid + 1; + } + } + if low > 0 && low <= len { + let section = idx.get_section(low - 1).unwrap(); + if let Some(map) = section.get_sourcemap() { + let (off_line, off_col) = section.get_offset(); + // We're looking for the position `l` lines into region spanned by this + // sourcemap s section. + let l = line - off_line; + // The source map starts if offset by the column only on its first line. On the + // 2nd+ line, the sourcemap spans starting at column 0. + let c = if line == off_line { + column - off_col + } else { + column + }; + return sectioned_lookup(map, l, c); + } + } + None + } else if let DecodedMap::Regular(sm) = map { + sm.lookup_token(line, column) + } else { + unimplemented!("we should only be using the standard source map types"); + } +} + +#[turbo_tasks::value_impl] +impl SourceMapTraceVc { + #[turbo_tasks::function] + pub async fn new(file: AssetContentVc, line: u32, column: u32, name: Option) -> Self { + SourceMapTrace { + file, + line, + column, + name, + } + .cell() + } + + /// Traces the line/column through the source map into its original + /// position. + /// + /// This method is god-awful slow. We're getting the content + /// of a .map file, which means we're serializing all of the individual + /// sections into a string and concatenating, taking that and + /// deserializing into a DecodedMap, and then querying it. Besides being a + /// memory hog, it'd be so much faster if we could just direclty access + /// the individual sections of the JS file's map without the + /// serialization. + #[turbo_tasks::function] + pub async fn trace(self) -> Result { + let this = self.await?; + let file = this.file.await?; + let content = match &*file { + AssetContent::File(c) => c, + _ => return Ok(TraceResult::NotFound.cell()), + }; + let decoded_map = DecodedSourceMapVc::from(*content).await?; + + let sm = decoded_map.lock().unwrap(); + let trace = match sectioned_lookup(&sm, this.line.saturating_sub(1), this.column) { + Some(t) => t, + _ => return Ok(TraceResult::NotFound.cell()), + }; + + Ok(TraceResult::Found(StackFrame { + file: trace + .get_source() + .expect("trace was unwraped already") + .to_string(), + line: Some(trace.get_src_line().saturating_add(1)), + column: Some(trace.get_src_col()), + name: trace + .get_name() + .map(|s| s.to_string()) + .or_else(|| this.name.clone()), + }) + .cell()) + } + + /// Takes the trace and generates a (possibly valid) JSON asset content. + #[turbo_tasks::function] + pub async fn content(self) -> Result { + let trace = self.trace().await?; + let result = match &*trace { + // purposefully invalid JSON (it can't be empty), so that the catch handler will default + // to the generated stack frame. + TraceResult::NotFound => "".to_string(), + TraceResult::Found(frame) => json!({ + "originalStackFrame": frame, + // TODO + "originalCodeFrame": null, + }) + .to_string(), + }; + Ok(File::from(result).into()) + } +} diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 28cf4f9e81b840..96eedcefe26cac 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -10,6 +10,7 @@ use anyhow::{anyhow, Context, Result}; use issue::UnimplementedFileIssue; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, + source_map::NextSourceMapTraceContentSourceVc, }; use turbo_tasks::{ primitives::StringVc, RawVc, TransientInstance, TransientValue, TurboTasks, Value, @@ -277,10 +278,15 @@ async fn source( } .cell() .into(); + let source_map_trace = NextSourceMapTraceContentSourceVc::new(rendered_source).into(); let source = RouterContentSource { routes: vec![ ("__turbopack__/".to_string(), introspect), ("__turbo_tasks__/".to_string(), viz), + ( + "__nextjs_original-stack-frame".to_string(), + source_map_trace, + ), ], fallback: main_source.into(), } From 09273bdab103f887ddab5013bc649b586ae19b0f Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 24 Oct 2022 13:23:00 -0700 Subject: [PATCH 180/672] Apply Next SSG transform (vercel/turbo#130) This adds the Next SSG transform. This transform does a few things, but the one we're most interested in right now is the removal of `getStaticProps`/`getServerSideProps`/etc. from page modules. HMR will be disabled if these exports are preserved. Co-authored-by: Tobias Koppers --- .../next-core/src/next_client/context.rs | 41 +++++++++++++++++-- .../next-core/src/server_rendered_source.rs | 8 ++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index d0430235d333c4..6ed8fc574792b9 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -6,7 +6,10 @@ use turbo_tasks::Value; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ - module_options::module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, + module_options::{ + module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, + ModuleRuleCondition, ModuleRuleEffect, ModuleRuleVc, + }, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, transition::TransitionsByNameVc, ModuleAssetContextVc, @@ -17,6 +20,7 @@ use turbopack_core::{ environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, resolve::{parse::RequestVc, pattern::Pattern}, }; +use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc}; use turbopack_env::ProcessEnvAssetVc; use crate::{ @@ -84,7 +88,7 @@ pub async fn get_client_module_options_context( .await? .is_found(); - Ok(ModuleOptionsContext { + let module_options_context = ModuleOptionsContext { // We don't need to resolve React Refresh for each module. Instead, // we try resolve it once at the root and pass down a context to all // the modules. @@ -95,8 +99,37 @@ pub async fn get_client_module_options_context( enable_typescript_transform: true, preset_env_versions: Some(env), ..Default::default() - } - .cell()) + }; + + Ok(module_options_context.cell()) +} + +#[turbo_tasks::function] +pub async fn add_next_transforms_to_pages( + module_options_context: ModuleOptionsContextVc, + pages_dir: FileSystemPathVc, +) -> Result { + let mut module_options_context = module_options_context.await?.clone_value(); + // Apply the Next SSG tranform to all pages. + module_options_context.custom_rules.push(ModuleRuleVc::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathInExactDirectory(pages_dir), + ModuleRuleCondition::any(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), + ]), + ]) + .cell(), + vec![ + ModuleRuleEffect::AddEcmascriptTransforms(EcmascriptInputTransformsVc::cell(vec![ + EcmascriptInputTransform::NextJs, + ])) + .cell(), + ], + )); + Ok(module_options_context.cell()) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 3745f30fa7f728..b86bba51f2160b 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -28,9 +28,9 @@ use crate::{ fallback::get_fallback_page, next_client::{ context::{ - get_client_assets_path, get_client_chunking_context, get_client_environment, - get_client_module_options_context, get_client_resolve_options_context, - get_client_runtime_entries, ContextType, + add_next_transforms_to_pages, get_client_assets_path, get_client_chunking_context, + get_client_environment, get_client_module_options_context, + get_client_resolve_options_context, get_client_runtime_entries, ContextType, }, NextClientTransition, }, @@ -71,6 +71,8 @@ pub async fn create_server_rendered_source( let client_environment = get_client_environment(browserslist_query); let client_module_options_context = get_client_module_options_context(project_path, client_environment, ty); + let client_module_options_context = + add_next_transforms_to_pages(client_module_options_context, pages_dir); let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); let client_runtime_entries = get_client_runtime_entries(project_path, env, ty); From 36f7545c3397213074bdb24e62bcf164d21efada Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Mon, 24 Oct 2022 22:23:40 +0200 Subject: [PATCH 181/672] add HMR for RSC component changes (vercel/turbo#202) --- .../next-swc/crates/next-core/js/package.json | 2 +- .../crates/next-core/js/src/dev/hmr-client.ts | 72 ++++++--- .../next-core/js/src/dev/hot-reloader.tsx | 31 ++++ .../next-core/js/src/entry/app-renderer.tsx | 4 +- .../next-core/js/src/entry/app/hydrate.tsx | 4 +- .../js/src/entry/app/server-to-client-ssr.tsx | 9 ++ .../js/src/entry/app/server-to-client.tsx | 5 +- .../crates/next-core/src/app_source.rs | 143 ++++++++++++------ .../next-core/src/next_client/context.rs | 7 +- .../server_to_client_transition.rs | 11 +- .../crates/next-core/src/next_import_map.rs | 30 +++- .../next-core/src/nodejs/node_api_source.rs | 45 +++--- .../crates/next-core/src/nodejs/node_entry.rs | 19 ++- .../src/nodejs/node_rendered_source.rs | 72 +++++---- .../next-core/src/server_rendered_source.rs | 52 ++++--- 15 files changed, 346 insertions(+), 160 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/entry/app/server-to-client-ssr.tsx diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index 5e664649922b12..716fd7c5eac2fb 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -12,7 +12,7 @@ "@vercel/turbopack-runtime": "latest", "anser": "2.1.1", "css.escape": "1.5.1", - "next": "12.3.2-canary.35", + "next": "12.3.2-canary.39", "platform": "1.3.6", "react-dom": "^18.2.0", "react": "^18.2.0", diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 08bb8c4bdc7f6d..6342ecae18520d 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -2,11 +2,12 @@ import type { ClientMessage, EcmascriptChunkUpdate, Issue, + ResourceIdentifier, ServerMessage, } from "@vercel/turbopack-runtime/types/protocol"; import type { ChunkPath, - ChunkUpdateCallback, + UpdateCallback, TurbopackGlobals, } from "@vercel/turbopack-runtime/types"; @@ -41,7 +42,7 @@ export function connect({ assetPrefix }: ClientOptions) { throw new Error("A separate HMR handler was already registered"); } globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS = { - push: ([chunkPath, callback]: [ChunkPath, ChunkUpdateCallback]) => { + push: ([chunkPath, callback]: [ChunkPath, UpdateCallback]) => { onChunkUpdate(chunkPath, callback); }, }; @@ -55,22 +56,30 @@ export function connect({ assetPrefix }: ClientOptions) { subscribeToInitialCssChunksUpdates(assetPrefix); } -const chunkUpdateCallbacks: Map = new Map(); +const updateCallbacks: Map> = new Map(); function sendJSON(message: ClientMessage) { sendMessage(JSON.stringify(message)); } -function subscribeToChunkUpdates(chunkPath: ChunkPath) { +type ResourceKey = string; +function resourceKey(resource: ResourceIdentifier): ResourceKey { + return JSON.stringify({ + path: resource.path, + headers: resource.headers || null, + }); +} + +function subscribeToUpdates(resource: ResourceIdentifier) { sendJSON({ type: "subscribe", - chunkPath, + ...resource, }); } function handleSocketConnected() { - for (const chunkPath of chunkUpdateCallbacks.keys()) { - subscribeToChunkUpdates(chunkPath); + for (const key of updateCallbacks.keys()) { + subscribeToUpdates(JSON.parse(key)); } } @@ -87,11 +96,12 @@ function aggregateUpdates( msg: ServerMessage, hasErrors: boolean ): ServerMessage { - const aggregated = chunksWithErrors.get(msg.chunkPath); + const key = resourceKey(msg.resource); + const aggregated = chunksWithErrors.get(key); if (msg.type === "issues" && aggregated != null) { if (!hasErrors) { - chunksWithErrors.delete(msg.chunkPath); + chunksWithErrors.delete(key); } return { @@ -110,7 +120,7 @@ function aggregateUpdates( if (aggregated == null) { if (hasErrors) { - chunksWithErrors.set(msg.chunkPath, { + chunksWithErrors.set(key, { added: msg.instruction.added, modified: msg.instruction.modified, deleted: new Set(msg.instruction.deleted), @@ -158,9 +168,9 @@ function aggregateUpdates( } if (!hasErrors) { - chunksWithErrors.delete(msg.chunkPath); + chunksWithErrors.delete(key); } else { - chunksWithErrors.set(msg.chunkPath, aggregated); + chunksWithErrors.set(key, aggregated); } return { @@ -203,40 +213,54 @@ function handleSocketMessage(msg: ServerMessage) { } if (aggregatedMsg.type !== "issues") { - triggerChunkUpdate(aggregatedMsg); + triggerUpdate(aggregatedMsg); if (chunksWithErrors.size === 0) { onRefresh(); } } } -export function onChunkUpdate( - chunkPath: ChunkPath, - callback: ChunkUpdateCallback +export function onChunkUpdate(chunkPath: ChunkPath, callback: UpdateCallback) { + onUpdate( + { + path: chunkPath, + }, + callback + ); +} + +export function onUpdate( + resource: ResourceIdentifier, + callback: UpdateCallback ) { - const callbacks = chunkUpdateCallbacks.get(chunkPath); + const key = resourceKey(resource); + let callbacks = updateCallbacks.get(key); if (!callbacks) { - chunkUpdateCallbacks.set(chunkPath, [callback]); + subscribeToUpdates(resource); + updateCallbacks.set(key, (callbacks = new Set([callback]))); } else { - callbacks.push(callback); + callbacks.add(callback); } - subscribeToChunkUpdates(chunkPath); + return () => { + callbacks!.delete(callback); + }; } -function triggerChunkUpdate(update: ServerMessage) { - const callbacks = chunkUpdateCallbacks.get(update.chunkPath); +function triggerUpdate(msg: ServerMessage) { + const key = resourceKey(msg.resource); + const callbacks = updateCallbacks.get(key); if (!callbacks) { return; } try { for (const callback of callbacks) { - callback(update); + callback(msg); } } catch (err) { console.error( - `An error occurred during the update of chunk \`${update.chunkPath}\``, + `An error occurred during the update of resource \`${msg.resource.path}\``, err ); location.reload(); diff --git a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx new file mode 100644 index 00000000000000..b93045658feeb6 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx @@ -0,0 +1,31 @@ +"use client"; + +import type React from "react"; +import { useRouter, usePathname } from "next/dist/client/components/navigation"; +import { useEffect } from "react"; +import { onUpdate } from "./hmr-client"; + +export default function HotReload({ + assetPrefix, + children, +}: React.PropsWithChildren<{ assetPrefix: string }>) { + const router = useRouter(); + const path = usePathname().slice(1); + useEffect(() => { + const unsubscribe = onUpdate( + { + path, + headers: { + __rsc__: "1", + }, + }, + (update) => { + if (update.type !== "issues") { + router.refresh(); + } + } + ); + return unsubscribe; + }, [router, path]); + return children; +} diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 95af441a0993cf..665ca2f1326ebb 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -19,7 +19,7 @@ import { ParsedUrlQuery } from "node:querystring"; import { parse as parseStackTrace } from "@vercel/turbopack-next/compiled/stacktrace-parser"; globalThis.__next_require__ = (data) => { - const [ssr_id] = JSON.parse(data); + const [, , ssr_id] = JSON.parse(data); return __turbopack_require__(ssr_id); }; globalThis.__next_chunk_load__ = () => Promise.resolve(); @@ -97,7 +97,7 @@ async function operation(renderData: RenderData) { get(target, name, receiver) { return { id, - chunks: JSON.parse(id)[2], + chunks: JSON.parse(id)[1], name, }; }, diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx index 93adeee0070247..5f4bd3d80ac286 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx @@ -1,5 +1,5 @@ import ReactDOMClient from "react-dom/client"; -import React, { experimental_use as use } from "react"; +import React, { use } from "react"; import type { ReactElement } from "react"; import { createFromReadableStream } from "next/dist/compiled/react-server-dom-webpack/client"; @@ -12,7 +12,7 @@ initializeHMR({ }); globalThis.__next_require__ = (data) => { - const [, client_id] = JSON.parse(data); + const [client_id] = JSON.parse(data); return __turbopack_require__(client_id); }; globalThis.__next_chunk_load__ = __turbopack_load__; diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client-ssr.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client-ssr.tsx new file mode 100644 index 00000000000000..6497c6f59a8e8e --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client-ssr.tsx @@ -0,0 +1,9 @@ +import { createProxy } from "next/dist/build/webpack/loaders/next-flight-loader/module-proxy"; + +("TURBOPACK { transition: next-ssr-client-module; chunking-type: parallel }"); +import { __turbopack_module_id__ as id } from "."; + +("TURBOPACK { transition: next-client-chunks }"); +import client_id, { chunks } from "."; + +export default createProxy(JSON.stringify([client_id, chunks, id])); diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx index 46d48673124f87..02d1539486c479 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/server-to-client.tsx @@ -1,9 +1,6 @@ import { createProxy } from "next/dist/build/webpack/loaders/next-flight-loader/module-proxy"; -("TURBOPACK { transition: next-ssr-client-module; chunking-type: parallel }"); -import { __turbopack_module_id__ as id } from "."; - ("TURBOPACK { transition: next-client-chunks }"); import client_id, { chunks } from "."; -export default createProxy(JSON.stringify([id, client_id, chunks])); +export default createProxy(JSON.stringify([client_id, chunks])); diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index fb35ac2d7fe8f2..14d566cb534430 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -18,7 +18,7 @@ use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{ combined::{CombinedContentSource, CombinedContentSourceVc}, - ContentSourceVc, NoContentSourceVc, + ContentSourceData, ContentSourceVc, NoContentSourceVc, }, }; use turbopack_ecmascript::{ @@ -49,7 +49,11 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - nodejs::{create_node_rendered_source, NodeEntry, NodeEntryVc}, + nodejs::{ + create_node_rendered_source, + node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, + NodeEntry, NodeEntryVc, + }, util::regular_expression_for_path, }; @@ -144,29 +148,16 @@ fn next_layout_entry_transition( .into() } -/// Create a content source serving the `app` or `src/app` directory as -/// Next.js app folder. #[turbo_tasks::function] -pub async fn create_app_source( +fn app_context( project_root: FileSystemPathVc, - output_path: FileSystemPathVc, server_root: FileSystemPathVc, + app_dir: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, -) -> Result { - let project_root = wrap_with_next_js_fs(project_root); - - let app = project_root.join("app"); - let src_app = project_root.join("src/app"); - let app_dir = if *app.get_type().await? == FileSystemEntryType::Directory { - app - } else if *src_app.get_type().await? == FileSystemEntryType::Directory { - src_app - } else { - return Ok(NoContentSourceVc::new().into()); - }; - - let next_server_to_client_transition = NextServerToClientTransition {}.cell().into(); + ssr: bool, +) -> AssetContextVc { + let next_server_to_client_transition = NextServerToClientTransition { ssr }.cell().into(); let mut transitions = HashMap::new(); transitions.insert( @@ -191,13 +182,53 @@ pub async fn create_app_source( ); let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir }); - let context: AssetContextVc = ModuleAssetContextVc::new( + ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), get_server_environment(ssr_ty, env), get_server_module_options_context(ssr_ty), get_server_resolve_options_context(project_root, ssr_ty), ) - .into(); + .into() +} + +/// Create a content source serving the `app` or `src/app` directory as +/// Next.js app folder. +#[turbo_tasks::function] +pub async fn create_app_source( + project_root: FileSystemPathVc, + output_path: FileSystemPathVc, + server_root: FileSystemPathVc, + env: ProcessEnvVc, + browserslist_query: &str, +) -> Result { + let project_root = wrap_with_next_js_fs(project_root); + + let app = project_root.join("app"); + let src_app = project_root.join("src/app"); + let app_dir = if *app.get_type().await? == FileSystemEntryType::Directory { + app + } else if *src_app.get_type().await? == FileSystemEntryType::Directory { + src_app + } else { + return Ok(NoContentSourceVc::new().into()); + }; + + let context_ssr = app_context( + project_root, + server_root, + app_dir, + env, + browserslist_query, + true, + ); + let context = app_context( + project_root, + server_root, + app_dir, + env, + browserslist_query, + false, + ); let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_root, env).as_ecmascript_chunk_placeable()]; @@ -205,6 +236,7 @@ pub async fn create_app_source( let fallback_page = get_fallback_page(project_root, server_root, browserslist_query); Ok(create_app_source_for_directory( + context_ssr, context, project_root, app_dir, @@ -220,6 +252,7 @@ pub async fn create_app_source( #[turbo_tasks::function] async fn create_app_source_for_directory( + context_ssr: AssetContextVc, context: AssetContextVc, project_root: FileSystemPathVc, input_dir: FileSystemPathVc, @@ -264,30 +297,21 @@ async fn create_app_source_for_directory( list.push(LayoutSegment { file, target }.cell()); let layout_path = LayoutSegmentsVc::cell(list); - let chunking_context = DevChunkingContextVc::new_with_layer( - project_root, - intermediate_output_path, - intermediate_output_path.join("chunks"), - server_root.join("_next/static/assets"), - false, - "ssr", - ) - .into(); - sources.push(create_node_rendered_source( server_root, regular_expression_for_path(server_root, target, false), AppRenderer { + context_ssr, context, server_root, layout_path, + project_root, + intermediate_output_path, } .cell() .into(), - chunking_context, runtime_entries, fallback_page, - intermediate_output_path, )); } for (name, entry) in entries.iter() { @@ -302,6 +326,7 @@ async fn create_app_source_for_directory( }; sources.push( create_app_source_for_directory( + context_ssr, context, project_root, *dir, @@ -322,15 +347,23 @@ async fn create_app_source_for_directory( #[turbo_tasks::value] struct AppRenderer { + context_ssr: AssetContextVc, context: AssetContextVc, server_root: FileSystemPathVc, layout_path: LayoutSegmentsVc, + project_root: FileSystemPathVc, + intermediate_output_path: FileSystemPathVc, } #[turbo_tasks::value_impl] impl NodeEntry for AppRenderer { #[turbo_tasks::function] - async fn entry(&self) -> Result { + async fn entry(&self, data: Value) -> Result { + let is_rsc = if let Some(headers) = data.into_value().headers { + headers.contains_key("__rsc__") + } else { + false + }; let layout_path = self.layout_path.await?; let page = layout_path .last() @@ -421,15 +454,35 @@ import BOOTSTRAP from {}; file.push_content(base_file.content()); } let asset = VirtualAssetVc::new(path.join("entry"), FileContent::Content(file).into()); - Ok(EcmascriptModuleAssetVc::new( - asset.into(), - self.context, - Value::new(EcmascriptModuleAssetType::Typescript), - EcmascriptInputTransformsVc::cell(vec![ - EcmascriptInputTransform::React { refresh: false }, - EcmascriptInputTransform::TypeScript, - ]), - self.context.environment(), - )) + let (context, intermediate_output_path) = if is_rsc { + (self.context, self.intermediate_output_path.join("__rsc__")) + } else { + (self.context_ssr, self.intermediate_output_path) + }; + + let chunking_context = DevChunkingContextVc::new_with_layer( + self.project_root, + intermediate_output_path, + intermediate_output_path.join("chunks"), + self.server_root.join("_next/static/assets"), + false, + "ssr", + ) + .into(); + Ok(NodeRenderingEntry { + module: EcmascriptModuleAssetVc::new( + asset.into(), + context, + Value::new(EcmascriptModuleAssetType::Typescript), + EcmascriptInputTransformsVc::cell(vec![ + EcmascriptInputTransform::React { refresh: false }, + EcmascriptInputTransform::TypeScript, + ]), + context.environment(), + ), + chunking_context, + intermediate_output_path, + } + .cell()) } } diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 6ed8fc574792b9..6062725d364924 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -27,7 +27,10 @@ use crate::{ embed_js::attached_next_js_package_path, env::filter_for_client, next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, - next_import_map::{get_next_client_fallback_import_map, get_next_client_import_map}, + next_import_map::{ + get_next_client_fallback_import_map, get_next_client_import_map, + get_next_client_resolved_map, + }, react_refresh::assert_can_resolve_react_refresh, }; @@ -62,6 +65,7 @@ pub fn get_client_resolve_options_context( ) -> ResolveOptionsContextVc { let next_client_import_map = get_next_client_import_map(project_root, ty); let next_client_fallback_import_map = get_next_client_fallback_import_map(ty); + let next_client_resolved_map = get_next_client_resolved_map(project_root, project_root); ResolveOptionsContext { enable_typescript: true, enable_react: true, @@ -69,6 +73,7 @@ pub fn get_client_resolve_options_context( custom_conditions: vec!["development".to_string()], import_map: Some(next_client_import_map), fallback_import_map: Some(next_client_fallback_import_map), + resolved_map: Some(next_client_resolved_map), browser: true, module: true, ..Default::default() diff --git a/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs b/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs index 953d69a8a9c2ac..95944ea88d114c 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs @@ -4,7 +4,9 @@ use turbopack_core::{asset::AssetVc, virtual_asset::VirtualAssetVc}; use crate::embed_js::next_js_file; #[turbo_tasks::value(shared)] -pub struct NextServerToClientTransition {} +pub struct NextServerToClientTransition { + pub ssr: bool, +} #[turbo_tasks::value_impl] impl Transition for NextServerToClientTransition { @@ -12,7 +14,12 @@ impl Transition for NextServerToClientTransition { fn process_source(&self, asset: AssetVc) -> AssetVc { VirtualAssetVc::new( asset.path().join("client-proxy.tsx"), - next_js_file("entry/app/server-to-client.tsx").into(), + next_js_file(if self.ssr { + "entry/app/server-to-client-ssr.tsx" + } else { + "entry/app/server-to-client.tsx" + }) + .into(), ) .into() } diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 9de255a3973dcd..28e92f64d43adc 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -1,6 +1,8 @@ use turbo_tasks::Value; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::resolve::options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}; +use turbo_tasks_fs::{glob::GlobVc, FileSystemPathVc}; +use turbopack_core::resolve::options::{ + ImportMap, ImportMapVc, ImportMapping, ImportMappingVc, ResolvedMap, ResolvedMapVc, +}; use crate::{ embed_js::{attached_next_js_package_path, VIRTUAL_PACKAGE_NAME}, @@ -164,6 +166,30 @@ pub fn get_next_server_import_map( import_map.cell() } +pub fn get_next_client_resolved_map( + context: FileSystemPathVc, + root: FileSystemPathVc, +) -> ResolvedMapVc { + let glob_mappings = vec![ + // Temporary hack to replace the hot reloader until this is passable by props in next.js + ( + context, + GlobVc::new( + "**/*/next/dist/client/components/react-dev-overlay/hot-reloader-client.js", + ), + ImportMapping::PrimaryAlternative( + "@vercel/turbopack-next/dev/hot-reloader".to_string(), + Some(root), + ) + .into(), + ), + ]; + ResolvedMap { + by_glob: glob_mappings, + } + .cell() +} + static NEXT_ALIASES: [(&str, &str); 23] = [ ("asset", "next/dist/compiled/assert"), ("buffer", "next/dist/compiled/buffer"), diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs index 63afe4357f6acb..220c62a7268900 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs @@ -4,11 +4,8 @@ use anyhow::Result; use indexmap::IndexMap; use turbo_tasks::{primitives::StringVc, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::{ - chunk::ChunkingContextVc, - introspect::{ - asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, - }, +use turbopack_core::introspect::{ + asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, }; use turbopack_dev_server::source::{ ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, @@ -25,17 +22,13 @@ pub fn create_node_api_source( server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, - chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, - intermediate_output_path: FileSystemPathVc, ) -> ContentSourceVc { NodeApiContentSource { server_root, path_regex, entry, - chunking_context, runtime_entries, - intermediate_output_path, } .cell() .into() @@ -52,9 +45,7 @@ struct NodeApiContentSource { server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, - chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, - intermediate_output_path: FileSystemPathVc, } impl NodeApiContentSource { @@ -90,12 +81,13 @@ impl ContentSource for NodeApiContentSource { .. } = &*data { + let entry = this.entry.entry(data.clone()).await?; return Ok(ContentSourceResult::HttpProxy(render_proxy( this.server_root.join(path), - this.entry.entry(), + entry.module, this.runtime_entries, - this.chunking_context, - this.intermediate_output_path, + entry.chunking_context, + entry.intermediate_output_path, RenderData { params, method: method.clone(), @@ -149,21 +141,24 @@ impl Introspectable for NodeApiContentSource { } #[turbo_tasks::function] - fn children(&self) -> IntrospectableChildrenVc { - IntrospectableChildrenVc::cell(HashSet::from([ - ( + async fn children(&self) -> Result { + let mut set = HashSet::new(); + for &entry in self.entry.entries().await?.iter() { + let entry = entry.await?; + set.insert(( StringVc::cell("module".to_string()), - IntrospectableAssetVc::new(self.entry.entry().into()), - ), - ( + IntrospectableAssetVc::new(entry.module.into()), + )); + set.insert(( StringVc::cell("intermediate asset".to_string()), IntrospectableAssetVc::new(get_intermediate_asset( - self.entry.entry(), + entry.module, self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, + entry.chunking_context, + entry.intermediate_output_path, )), - ), - ])) + )); + } + Ok(IntrospectableChildrenVc::cell(set)) } } diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs b/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs index 91360f071ad7d8..6653f4ecd3d55b 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs @@ -1,8 +1,25 @@ use anyhow::Result; +use turbo_tasks::Value; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_core::chunk::ChunkingContextVc; +use turbopack_dev_server::source::ContentSourceData; use turbopack_ecmascript::EcmascriptModuleAssetVc; +#[turbo_tasks::value(shared)] +pub struct NodeRenderingEntry { + pub module: EcmascriptModuleAssetVc, + pub chunking_context: ChunkingContextVc, + pub intermediate_output_path: FileSystemPathVc, +} + +#[turbo_tasks::value(transparent)] +pub struct NodeRenderingEntries(Vec); + /// Trait that allows to get the entry module for rendering something in Node.js #[turbo_tasks::value_trait] pub trait NodeEntry { - fn entry(&self) -> EcmascriptModuleAssetVc; + fn entry(&self, data: Value) -> NodeRenderingEntryVc; + fn entries(&self) -> NodeRenderingEntriesVc { + NodeRenderingEntriesVc::cell(vec![self.entry(Value::new(Default::default()))]) + } } diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 76497a6a64896f..5e16c10ae01a86 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -1,11 +1,11 @@ use std::collections::HashSet; use anyhow::{anyhow, Result}; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use turbo_tasks::{primitives::StringVc, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::{ - chunk::ChunkingContextVc, + asset::AssetsSetVc, introspect::{ asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, }, @@ -38,19 +38,15 @@ pub fn create_node_rendered_source( server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, - chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, fallback_page: DevHtmlAssetVc, - intermediate_output_path: FileSystemPathVc, ) -> ContentSourceVc { let source = NodeRenderContentSource { server_root, path_regex, entry, - chunking_context, runtime_entries, fallback_page, - intermediate_output_path, } .cell(); ConditionalContentSourceVc::new( @@ -70,10 +66,8 @@ struct NodeRenderContentSource { server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, - chunking_context: ChunkingContextVc, runtime_entries: EcmascriptChunkPlaceablesVc, fallback_page: DevHtmlAssetVc, - intermediate_output_path: FileSystemPathVc, } impl NodeRenderContentSource { @@ -102,17 +96,27 @@ impl GetContentSource for NodeRenderContentSource { /// Returns the [ContentSource] that serves all referenced external /// assets. This is wrapped into [LazyInstantiatedContentSource]. #[turbo_tasks::function] - fn content_source(&self) -> ContentSourceVc { - AssetGraphContentSourceVc::new_lazy_multiple( - self.server_root, - external_asset_entrypoints( - self.entry.entry(), - self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, - ), + async fn content_source(&self) -> Result { + let entries = self.entry.entries(); + let mut set = IndexSet::new(); + for &entry in entries.await?.iter() { + let entry = entry.await?; + set.extend( + external_asset_entrypoints( + entry.module, + self.runtime_entries, + entry.chunking_context, + entry.intermediate_output_path, + ) + .await? + .iter() + .copied(), + ) + } + Ok( + AssetGraphContentSourceVc::new_lazy_multiple(self.server_root, AssetsSetVc::cell(set)) + .into(), ) - .into() } } @@ -136,14 +140,15 @@ impl ContentSource for NodeRenderContentSource { { if data.method.is_some() && data.url.is_some() { if let Some(query) = &data.query { + let entry = this.entry.entry(data.clone()).await?; return Ok(ContentSourceResult::Static( render_static( this.server_root.join(path), - this.entry.entry(), + entry.module, this.runtime_entries, this.fallback_page, - this.chunking_context, - this.intermediate_output_path, + entry.chunking_context, + entry.intermediate_output_path, RenderData { params, method: data.method.clone().ok_or_else(|| { @@ -214,21 +219,24 @@ impl Introspectable for NodeRenderContentSource { } #[turbo_tasks::function] - fn children(&self) -> IntrospectableChildrenVc { - IntrospectableChildrenVc::cell(HashSet::from([ - ( + async fn children(&self) -> Result { + let mut set = HashSet::new(); + for &entry in self.entry.entries().await?.iter() { + let entry = entry.await?; + set.insert(( StringVc::cell("module".to_string()), - IntrospectableAssetVc::new(self.entry.entry().into()), - ), - ( + IntrospectableAssetVc::new(entry.module.into()), + )); + set.insert(( StringVc::cell("intermediate asset".to_string()), IntrospectableAssetVc::new(get_intermediate_asset( - self.entry.entry(), + entry.module, self.runtime_entries, - self.chunking_context, - self.intermediate_output_path, + entry.chunking_context, + entry.intermediate_output_path, )), - ), - ])) + )); + } + Ok(IntrospectableChildrenVc::cell(set)) } } diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index b86bba51f2160b..76792497b8d1ba 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -6,15 +6,18 @@ use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; use turbopack_core::{ - asset::AssetVc, chunk::dev::DevChunkingContextVc, context::AssetContextVc, - source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, + asset::AssetVc, + chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, + context::AssetContextVc, + source_asset::SourceAssetVc, + virtual_asset::VirtualAssetVc, }; use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{ asset_graph::AssetGraphContentSourceVc, combined::{CombinedContentSource, CombinedContentSourceVc}, - ContentSourceVc, NoContentSourceVc, + ContentSourceData, ContentSourceVc, NoContentSourceVc, }, }; use turbopack_ecmascript::{ @@ -38,7 +41,11 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - nodejs::{create_node_api_source, create_node_rendered_source, NodeEntry, NodeEntryVc}, + nodejs::{ + create_node_api_source, create_node_rendered_source, + node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, + NodeEntry, NodeEntryVc, + }, util::regular_expression_for_path, }; @@ -160,12 +167,12 @@ async fn create_server_rendered_source_for_file( context, entry_asset, is_api_path, + chunking_context, + intermediate_output_path, } .cell() .into(), - chunking_context, runtime_entries, - intermediate_output_path, ) } else { create_node_rendered_source( @@ -175,13 +182,13 @@ async fn create_server_rendered_source_for_file( context, entry_asset, is_api_path, + chunking_context, + intermediate_output_path, } .cell() .into(), - chunking_context, runtime_entries, fallback_page, - intermediate_output_path, ) }) } @@ -294,12 +301,14 @@ struct SsrEntry { context: AssetContextVc, entry_asset: AssetVc, is_api_path: BoolVc, + chunking_context: ChunkingContextVc, + intermediate_output_path: FileSystemPathVc, } #[turbo_tasks::value_impl] impl NodeEntry for SsrEntry { #[turbo_tasks::function] - async fn entry(&self) -> Result { + async fn entry(&self, _data: Value) -> Result { let virtual_asset = if *self.is_api_path.await? { VirtualAssetVc::new( self.entry_asset.path().join("server-api.tsx"), @@ -312,15 +321,20 @@ impl NodeEntry for SsrEntry { ) }; - Ok(EcmascriptModuleAssetVc::new( - virtual_asset.into(), - self.context, - Value::new(EcmascriptModuleAssetType::Typescript), - EcmascriptInputTransformsVc::cell(vec![ - EcmascriptInputTransform::TypeScript, - EcmascriptInputTransform::React { refresh: false }, - ]), - self.context.environment(), - )) + Ok(NodeRenderingEntry { + module: EcmascriptModuleAssetVc::new( + virtual_asset.into(), + self.context, + Value::new(EcmascriptModuleAssetType::Typescript), + EcmascriptInputTransformsVc::cell(vec![ + EcmascriptInputTransform::TypeScript, + EcmascriptInputTransform::React { refresh: false }, + ]), + self.context.environment(), + ), + chunking_context: self.chunking_context, + intermediate_output_path: self.intermediate_output_path, + } + .cell()) } } From 233b69d2036ef61a16d9729fb9c668187911446c Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 25 Oct 2022 00:27:17 +0200 Subject: [PATCH 182/672] App CSS and fixes (vercel/turbo#246) fix app layout transition add global css support --- .../next-core/js/src/entry/app-renderer.tsx | 101 ++++++++++--- .../crates/next-core/src/app_render/mod.rs | 2 +- .../crates/next-core/src/app_source.rs | 138 ++++++++++-------- .../next-core/src/next_client/context.rs | 5 +- .../next-core/src/server_rendered_source.rs | 4 +- 5 files changed, 165 insertions(+), 85 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 665ca2f1326ebb..4527124bff0e16 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -7,7 +7,10 @@ declare global { } import type { IncomingMessage, ServerResponse } from "node:http"; -import type { FlightManifest } from "next/dist/build/webpack/plugins/flight-manifest-plugin"; +import type { + FlightCSSManifest, + FlightManifest, +} from "next/dist/build/webpack/plugins/flight-manifest-plugin"; import type { RenderData } from "types/turbopack"; import "next/dist/server/node-polyfill-fetch"; @@ -68,10 +71,23 @@ process.stdin.on("data", async (data) => { buffer.push(data); }); -type LayoutTree = [ - string, - { children?: LayoutTree }, - { page: () => any } | { layout: () => any } +// TODO expose these types in next.js +type ComponentModule = () => any; +export type ComponentsType = { + readonly [componentKey in + | "layout" + | "template" + | "error" + | "loading" + | "not-found"]?: ComponentModule; +} & { + readonly layoutOrPagePath?: string; + readonly page?: ComponentModule; +}; +type LoaderTree = [ + segment: string, + parallelRoutes: { [parallelRouterKey: string]: LoaderTree }, + components: ComponentsType ]; type ServerComponentsManifest = { @@ -82,17 +98,36 @@ type ServerComponentsManifestModule = { }; async function operation(renderData: RenderData) { - const pageModule = LAYOUT_INFO[LAYOUT_INFO.length - 1].module; + const pageItem = LAYOUT_INFO[LAYOUT_INFO.length - 1]; + const pageModule = pageItem.module; const Page = pageModule.default; - let tree: LayoutTree = ["", {}, { page: () => Page }]; + let tree: LoaderTree = [ + "", + {}, + { page: () => Page, layoutOrPagePath: "page.js" }, + ]; for (let i = LAYOUT_INFO.length - 2; i >= 0; i--) { const info = LAYOUT_INFO[i]; - const Layout = info.module.default; - tree = [info.segment, { children: tree }, { layout: () => Layout }]; + const mod = info.module; + if (mod) { + const Layout = mod.default; + tree = [ + info.segment, + { children: tree }, + { layout: () => Layout, layoutOrPagePath: `layout${i}.js` }, + ]; + } else { + tree = [ + info.segment, + { children: tree }, + { layoutOrPagePath: `layout${i}.js` }, + ]; + } } const proxyMethodsForModule = ( - id: string + id: string, + css: boolean ): ProxyHandler => ({ get(target, name, receiver) { return { @@ -102,15 +137,35 @@ async function operation(renderData: RenderData) { }; }, }); - const proxyMethods: ProxyHandler = { - get(target, name, receiver) { - if (name === "__ssr_module_mapping__") { - return manifest; - } - return new Proxy({}, proxyMethodsForModule(name as string)); - }, + const proxyMethods = (css: boolean): ProxyHandler => { + return { + get(target, name, receiver) { + if (name === "__ssr_module_mapping__") { + return manifest; + } + if (name === "__client_css_manifest__") { + return {}; + } + return new Proxy({}, proxyMethodsForModule(name as string, css)); + }, + }; + }; + const manifest: FlightManifest = new Proxy({} as any, proxyMethods(false)); + const serverCSSManifest: FlightCSSManifest = {}; + serverCSSManifest.__entry_css__ = {}; + for (let i = 0; i < LAYOUT_INFO.length - 1; i++) { + const { chunks } = LAYOUT_INFO[i]; + const cssChunks = (chunks || []).filter((path) => path.endsWith(".css")); + serverCSSManifest[`layout${i}.js`] = cssChunks.map((chunk) => + JSON.stringify([chunk, [chunk]]) + ); + } + serverCSSManifest.__entry_css__ = { + page: pageItem.chunks + .filter((path) => path.endsWith(".css")) + .map((chunk) => JSON.stringify([chunk, [chunk]])), }; - const manifest: FlightManifest = new Proxy({} as any, proxyMethods); + serverCSSManifest["page.js"] = serverCSSManifest.__entry_css__.page; const req: IncomingMessage = { url: renderData.url, method: renderData.method, @@ -126,9 +181,9 @@ async function operation(renderData: RenderData) { dev: true, buildManifest: { polyfillFiles: [], - rootMainFiles: LAYOUT_INFO.flatMap(({ chunks }) => chunks).concat( - BOOTSTRAP - ), + rootMainFiles: LAYOUT_INFO.flatMap(({ chunks }) => chunks || []) + .concat(BOOTSTRAP) + .filter((path) => !path.endsWith(".css")), devFiles: [], ampDevFiles: [], lowPriorityFiles: [], @@ -141,10 +196,10 @@ async function operation(renderData: RenderData) { ...pageModule, default: undefined, tree, - pages: [], + pages: ["page.js"], }, serverComponentManifest: manifest, - serverCSSManifest: {}, + serverCSSManifest, runtime: "nodejs", serverComponents: true, assetPrefix: "", diff --git a/packages/next-swc/crates/next-core/src/app_render/mod.rs b/packages/next-swc/crates/next-core/src/app_render/mod.rs index d02da5ff88008f..5c14d6ec56529c 100644 --- a/packages/next-swc/crates/next-core/src/app_render/mod.rs +++ b/packages/next-swc/crates/next-core/src/app_render/mod.rs @@ -4,7 +4,7 @@ pub mod next_layout_entry_transition; #[turbo_tasks::value(shared)] pub struct LayoutSegment { - pub file: FileSystemPathVc, + pub file: Option, pub target: FileSystemPathVc, } diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 14d566cb534430..2a58811c4408bd 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -287,15 +287,17 @@ async fn create_app_source_for_directory( } } } - if let Some(file) = layout.copied() { - let mut list = layouts.await?.clone_value(); - list.push(LayoutSegment { file, target }.cell()); - layouts = LayoutSegmentsVc::cell(list); - } - if let Some(file) = page.copied() { - let mut list = layouts.await?.clone_value(); - list.push(LayoutSegment { file, target }.cell()); - let layout_path = LayoutSegmentsVc::cell(list); + let mut list = layouts.await?.clone_value(); + list.push( + LayoutSegment { + file: layout.copied(), + target, + } + .cell(), + ); + layouts = LayoutSegmentsVc::cell(list); + if let Some(page_path) = page.copied() { + sources.push(create_node_rendered_source( server_root, @@ -304,7 +306,9 @@ async fn create_app_source_for_directory( context_ssr, context, server_root, - layout_path, + layout_path: layouts, + page_path, + target, project_root, intermediate_output_path, } @@ -351,6 +355,8 @@ struct AppRenderer { context: AssetContextVc, server_root: FileSystemPathVc, layout_path: LayoutSegmentsVc, + page_path: FileSystemPathVc, + target: FileSystemPathVc, project_root: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, } @@ -365,48 +371,59 @@ impl NodeEntry for AppRenderer { false }; let layout_path = self.layout_path.await?; - let page = layout_path - .last() - .ok_or_else(|| anyhow!("layout path must not be empty"))?; - let path = page.await?.file.parent(); + let page = self.page_path; + let path = page.parent(); let path_value = &*path.await?; - let segments = layout_path + let layout_and_page = layout_path .iter() .copied() + .chain(std::iter::once( + LayoutSegment { + file: Some(page), + target: self.target, + } + .cell(), + )) .try_join() - .await? + .await?; + let segments: Vec<(String, Option<(String, String, String)>)> = layout_and_page .into_iter() .fold( (self.server_root, Vec::new()), |(last_path, mut futures), segment| { (segment.target, { futures.push(async move { - let file_str = segment.file.to_string().await?; let target = &*segment.target.await?; let segment_path = last_path.await?.get_path_to(target).unwrap_or_default(); - let identifier = magic_identifier::encode(&format!( - "imported namespace {}", - file_str - )); - let chunks_identifier = magic_identifier::encode(&format!( - "client chunks for {}", - file_str - )); - if let Some(p) = path_value.get_relative_path_to(&*segment.file.await?) - { - Ok(( - p, - stringify_str(segment_path), - identifier, - chunks_identifier, - )) + if let Some(file) = segment.file { + let file_str = file.to_string().await?; + let identifier = magic_identifier::encode(&format!( + "imported namespace {}", + file_str + )); + let chunks_identifier = magic_identifier::encode(&format!( + "client chunks for {}", + file_str + )); + if let Some(p) = path_value.get_relative_path_to(&*file.await?) { + Ok(( + stringify_str(segment_path), + Some((p, identifier, chunks_identifier)), + )) + } else { + Err(anyhow!( + "Unable to generate import as there + is no relative path to the layout module {} from context + path {}", + file_str, + path.to_string().await? + )) + } } else { - Err(anyhow!( - "Unable to generate import as there is no relative path to \ - the layout module {} from context path {}", - file_str, - path.to_string().await? + Ok::<(String, Option<(String, String, String)>), _>(( + stringify_str(segment_path), + None, )) } }); @@ -419,18 +436,20 @@ impl NodeEntry for AppRenderer { .try_join() .await?; let mut result = String::new(); - for (p, _, identifier, chunks_identifier) in segments.iter() { - writeln!( - result, - r#"("TURBOPACK {{ transition: next-layout-entry; chunking-type: parallel }}"); + for (_, import) in segments.iter() { + if let Some((p, identifier, chunks_identifier)) = import { + writeln!( + result, + r#"("TURBOPACK {{ transition: next-layout-entry; chunking-type: parallel }}"); import {}, {{ chunks as {} }} from {}; "#, - identifier, - chunks_identifier, - stringify_str(p) - )? + identifier, + chunks_identifier, + stringify_str(p) + )? + } } - if let Some(page) = path_value.get_relative_path_to(&*page.await?.file.await?) { + if let Some(page) = path_value.get_relative_path_to(&*page.await?) { writeln!( result, r#"("TURBOPACK {{ transition: next-client }}"); @@ -440,12 +459,16 @@ import BOOTSTRAP from {}; )?; } result.push_str("const LAYOUT_INFO = ["); - for (_, segment_str_lit, identifier, chunks_identifier) in segments.iter() { - writeln!( - result, - " {{ segment: {segment_str_lit}, module: {identifier}, chunks: \ - {chunks_identifier} }},", - )? + for (segment_str_lit, import) in segments.iter() { + if let Some((_, identifier, chunks_identifier)) = import { + writeln!( + result, + " {{ segment: {segment_str_lit}, module: {identifier}, chunks: \ + {chunks_identifier} }},", + )? + } else { + writeln!(result, " {{ segment: {segment_str_lit} }},",)? + } } result.push_str("];\n\n"); let base_code = next_js_file("entry/app-renderer.tsx"); @@ -460,15 +483,16 @@ import BOOTSTRAP from {}; (self.context_ssr, self.intermediate_output_path) }; - let chunking_context = DevChunkingContextVc::new_with_layer( + let chunking_context = DevChunkingContextVc::builder( self.project_root, intermediate_output_path, intermediate_output_path.join("chunks"), self.server_root.join("_next/static/assets"), - false, - "ssr", ) - .into(); + .layer("ssr") + .css_chunk_root_path(self.server_root.join("_next/static/chunks")) + .build(); + Ok(NodeRenderingEntry { module: EcmascriptModuleAssetVc::new( asset.into(), diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 6062725d364924..0537955af5ae69 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -164,7 +164,7 @@ pub fn get_client_chunking_context( server_root: FileSystemPathVc, ty: Value, ) -> ChunkingContextVc { - DevChunkingContextVc::new( + DevChunkingContextVc::builder( project_root, server_root, match ty.into_value() { @@ -174,8 +174,9 @@ pub fn get_client_chunking_context( ContextType::Other => server_root.join("/_chunks"), }, get_client_assets_path(server_root, ty), - true, ) + .hot_module_replacment() + .build() .into() } diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 76792497b8d1ba..e9182f05889cc9 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -150,13 +150,13 @@ async fn create_server_rendered_source_for_file( let source_asset = SourceAssetVc::new(page_file).into(); let entry_asset = context.process(source_asset); - let chunking_context = DevChunkingContextVc::new( + let chunking_context = DevChunkingContextVc::builder( context_path, intermediate_output_path, intermediate_output_path.join("chunks"), get_client_assets_path(server_root, Value::new(ContextType::Pages { pages_dir })), - false, ) + .build() .into(); Ok(if *is_api_path.await? { From dca015b121cb144cc6790f11268cdd874063bd28 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 25 Oct 2022 01:19:14 +0200 Subject: [PATCH 183/672] move feature detection to next.js (vercel/turbo#263) --- .../crates/next-core/src/app_source.rs | 25 ++++++---- .../crates/next-core/src/next_import_map.rs | 16 +++---- .../crates/next-core/src/next_server/mod.rs | 8 +++- .../next-core/src/server_rendered_source.rs | 7 ++- .../next-swc/crates/next-dev/src/issue.rs | 34 -------------- packages/next-swc/crates/next-dev/src/lib.rs | 47 +++++-------------- 6 files changed, 48 insertions(+), 89 deletions(-) delete mode 100644 packages/next-swc/crates/next-dev/src/issue.rs diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 2a58811c4408bd..212db39b37f586 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, fmt::Write}; use anyhow::{anyhow, Result}; -use turbo_tasks::{TryJoinIterExt, Value, ValueToString}; +use turbo_tasks::{primitives::StringsVc, TryJoinIterExt, Value, ValueToString}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{ DirectoryContent, DirectoryEntry, File, FileContent, FileSystemEntryType, FileSystemPathVc, @@ -115,11 +115,16 @@ fn next_ssr_client_module_transition( project_root: FileSystemPathVc, app_dir: FileSystemPathVc, process_env: ProcessEnvVc, + externals: StringsVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppSSR { app_dir }); NextSSRClientModuleTransition { ssr_module_options_context: get_server_module_options_context(ty), - ssr_resolve_options_context: get_server_resolve_options_context(project_root, ty), + ssr_resolve_options_context: get_server_resolve_options_context( + project_root, + ty, + externals, + ), ssr_environment: get_server_environment(ty, process_env), } .cell() @@ -132,10 +137,12 @@ fn next_layout_entry_transition( app_dir: FileSystemPathVc, server_root: FileSystemPathVc, process_env: ProcessEnvVc, + externals: StringsVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppRSC { app_dir }); let rsc_environment = get_server_environment(ty, process_env); - let rsc_resolve_options_context = get_server_resolve_options_context(project_root, ty); + let rsc_resolve_options_context = + get_server_resolve_options_context(project_root, ty, externals); let rsc_module_options_context = get_server_module_options_context(ty); NextLayoutEntryTransition { @@ -156,13 +163,14 @@ fn app_context( env: ProcessEnvVc, browserslist_query: &str, ssr: bool, + externals: StringsVc, ) -> AssetContextVc { let next_server_to_client_transition = NextServerToClientTransition { ssr }.cell().into(); let mut transitions = HashMap::new(); transitions.insert( "next-layout-entry".to_string(), - next_layout_entry_transition(project_root, app_dir, server_root, env), + next_layout_entry_transition(project_root, app_dir, server_root, env, externals), ); transitions.insert( "server-to-client".to_string(), @@ -178,7 +186,7 @@ fn app_context( ); transitions.insert( "next-ssr-client-module".to_string(), - next_ssr_client_module_transition(project_root, app_dir, env), + next_ssr_client_module_transition(project_root, app_dir, env, externals), ); let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir }); @@ -186,7 +194,7 @@ fn app_context( TransitionsByNameVc::cell(transitions), get_server_environment(ssr_ty, env), get_server_module_options_context(ssr_ty), - get_server_resolve_options_context(project_root, ssr_ty), + get_server_resolve_options_context(project_root, ssr_ty, externals), ) .into() } @@ -200,6 +208,7 @@ pub async fn create_app_source( server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, + externals: StringsVc, ) -> Result { let project_root = wrap_with_next_js_fs(project_root); @@ -220,6 +229,7 @@ pub async fn create_app_source( env, browserslist_query, true, + externals, ); let context = app_context( project_root, @@ -228,6 +238,7 @@ pub async fn create_app_source( env, browserslist_query, false, + externals, ); let server_runtime_entries = @@ -297,8 +308,6 @@ async fn create_app_source_for_directory( ); layouts = LayoutSegmentsVc::cell(list); if let Some(page_path) = page.copied() { - - sources.push(create_node_rendered_source( server_root, regular_expression_for_path(server_root, target, false), diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 28e92f64d43adc..b1fa94f868d1b5 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -1,4 +1,5 @@ -use turbo_tasks::Value; +use anyhow::Result; +use turbo_tasks::{primitives::StringsVc, Value}; use turbo_tasks_fs::{glob::GlobVc, FileSystemPathVc}; use turbopack_core::resolve::options::{ ImportMap, ImportMapVc, ImportMapping, ImportMappingVc, ResolvedMap, ResolvedMapVc, @@ -91,16 +92,13 @@ pub fn get_next_client_fallback_import_map(ty: Value) -> ImportMapV import_map.cell() } -// TODO this should be a user configurable option -/// Temporary hard coded externals list -static HARD_CODED_EXTERNALS: &[&str] = &["prisma", "@prisma/client", "@mux/blurhash"]; - /// Computes the Next-specific server-side import map. #[turbo_tasks::function] -pub fn get_next_server_import_map( +pub async fn get_next_server_import_map( project_path: FileSystemPathVc, ty: Value, -) -> ImportMapVc { + externals: StringsVc, +) -> Result { let mut import_map = ImportMap::empty(); let package_root = attached_next_js_package_path(project_path); @@ -153,7 +151,7 @@ pub fn get_next_server_import_map( request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); - for &external in HARD_CODED_EXTERNALS { + for external in externals.await?.iter() { import_map.insert_exact_alias(external, ImportMapping::External(None).into()); import_map.insert_wildcard_alias( format!("{external}/"), @@ -163,7 +161,7 @@ pub fn get_next_server_import_map( } } - import_map.cell() + Ok(import_map.cell()) } pub fn get_next_client_resolved_map( diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index c2aec827a82b3f..b1bce0e8ebe360 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -1,4 +1,7 @@ -use turbo_tasks::{primitives::StringVc, Value}; +use turbo_tasks::{ + primitives::{StringVc, StringsVc}, + Value, +}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ @@ -24,8 +27,9 @@ pub enum ServerContextType { pub fn get_server_resolve_options_context( project_path: FileSystemPathVc, ty: Value, + externals: StringsVc, ) -> ResolveOptionsContextVc { - let next_server_import_map = get_next_server_import_map(project_path, ty); + let next_server_import_map = get_next_server_import_map(project_path, ty, externals); match ty.into_value() { ServerContextType::Pages { .. } | ServerContextType::AppSSR { .. } => { ResolveOptionsContext { diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index e9182f05889cc9..8e72da8136bc51 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; use anyhow::Result; -use turbo_tasks::{primitives::BoolVc, Value}; +use turbo_tasks::{ + primitives::{BoolVc, StringsVc}, + Value, +}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; @@ -102,7 +105,7 @@ pub async fn create_server_rendered_source( TransitionsByNameVc::cell(transitions), get_server_environment(server_ty, env), get_server_module_options_context(server_ty), - get_server_resolve_options_context(project_path, server_ty), + get_server_resolve_options_context(project_path, server_ty, StringsVc::empty()), ) .into(); diff --git a/packages/next-swc/crates/next-dev/src/issue.rs b/packages/next-swc/crates/next-dev/src/issue.rs deleted file mode 100644 index 64ae142d743428..00000000000000 --- a/packages/next-swc/crates/next-dev/src/issue.rs +++ /dev/null @@ -1,34 +0,0 @@ -use anyhow::Result; -use turbo_tasks::primitives::StringVc; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::issue::{Issue, IssueVc}; - -/// An issue that occurred upon detecting a file that is unimplemented. -#[turbo_tasks::value(shared)] -pub struct UnimplementedFileIssue { - pub path: FileSystemPathVc, - pub description: StringVc, -} - -#[turbo_tasks::value_impl] -impl Issue for UnimplementedFileIssue { - #[turbo_tasks::function] - fn title(&self) -> StringVc { - StringVc::cell("Feature not yet supported".to_string()) - } - - #[turbo_tasks::function] - fn category(&self) -> StringVc { - StringVc::cell("unimplemented".to_string()) - } - - #[turbo_tasks::function] - fn context(&self) -> FileSystemPathVc { - self.path - } - - #[turbo_tasks::function] - fn description(&self) -> StringVc { - self.description - } -} diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 96eedcefe26cac..e07d5448a7799b 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -1,21 +1,19 @@ #![feature(future_join)] #![feature(min_specialization)] -mod issue; mod turbo_tasks_viz; use std::{collections::HashSet, env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; use anyhow::{anyhow, Context, Result}; -use issue::UnimplementedFileIssue; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, source_map::NextSourceMapTraceContentSourceVc, }; use turbo_tasks::{ - primitives::StringVc, RawVc, TransientInstance, TransientValue, TurboTasks, Value, + primitives::StringsVc, RawVc, TransientInstance, TransientValue, TurboTasks, Value, }; -use turbo_tasks_fs::{DiskFileSystemVc, FileSystemEntryType, FileSystemPathVc, FileSystemVc}; +use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; use turbopack_core::{issue::IssueSeverity, resolve::parse::RequestVc}; @@ -34,6 +32,7 @@ pub struct NextDevServerBuilder { project_dir: String, root_dir: String, entry_requests: Vec, + server_component_externals: Vec, eager_compile: bool, hostname: Option, port: Option, @@ -54,6 +53,7 @@ impl NextDevServerBuilder { project_dir, root_dir, entry_requests: vec![], + server_component_externals: vec![], eager_compile: false, hostname: None, port: None, @@ -71,6 +71,11 @@ impl NextDevServerBuilder { self } + pub fn server_component_external(mut self, external: String) -> NextDevServerBuilder { + self.server_component_externals.push(external); + self + } + pub fn eager_compile(mut self, eager_compile: bool) -> NextDevServerBuilder { self.eager_compile = eager_compile; self @@ -112,6 +117,7 @@ impl NextDevServerBuilder { let project_dir = self.project_dir; let root_dir = self.root_dir; let entry_requests = self.entry_requests; + let server_component_externals = self.server_component_externals; let eager_compile = self.eager_compile; let show_all = self.show_all; let log_detail = self.log_detail; @@ -136,6 +142,7 @@ impl NextDevServerBuilder { turbo_tasks.clone().into(), console_ui.clone().into(), browserslist_query.clone(), + server_component_externals.clone(), ) }, ( @@ -162,34 +169,6 @@ async fn handle_issues>(source: T, console_ui: ConsoleUiVc) -> Re } } -async fn handle_unimplemented_files(project_path: &FileSystemPathVc) -> Result<()> { - const UNIMPLEMENTED_FILES: [&str; 5] = [ - "next.config.js", - "babel.config.js", - ".babelrc.js", - "postcss.config.js", - "tailwind.config.js", - ]; - for file in UNIMPLEMENTED_FILES { - let file_path = project_path.join(file); - let file_type = file_path.get_type().await?; - - if *file_type == FileSystemEntryType::File { - UnimplementedFileIssue { - path: file_path, - description: StringVc::cell(format!( - "Handling the file `{}` is currently unimplemented", - file - )), - } - .cell() - .as_issue() - .emit(); - } - } - Ok(()) -} - #[turbo_tasks::function] async fn project_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result { let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir.to_string()); @@ -218,6 +197,7 @@ async fn source( turbo_tasks: TransientInstance>, console_ui: TransientInstance, browserslist_query: String, + server_component_externals: Vec, ) -> Result { let console_ui = (*console_ui).clone().cell(); let output_fs = output_fs(&project_dir, console_ui); @@ -228,8 +208,6 @@ async fn source( .unwrap_or(project_relative); let project_path = fs.root().join(project_relative); - handle_unimplemented_files(&project_path).await?; - let env = load_env(project_path); let output_root = output_fs.root(); @@ -261,6 +239,7 @@ async fn source( dev_server_root, env, &browserslist_query, + StringsVc::cell(server_component_externals), ); let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.into(), From c8067af03f46eaf8814da2ea4eda8dbe8a765d7d Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 24 Oct 2022 17:05:21 -0700 Subject: [PATCH 184/672] Fix fallback page error overlay (vercel/turbo#268) --- .../crates/next-core/js/src/entry/fallback.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx b/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx index e7eb5d2f822790..2bdd59e608e440 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx @@ -6,15 +6,23 @@ import { initializeHMR, ReactDevOverlay, } from "@vercel/turbopack-next/dev/client"; -import { onChunkUpdate } from "@vercel/turbopack-next/dev/hmr-client"; +import { onUpdate } from "@vercel/turbopack-next/dev/hmr-client"; const pageChunkPath = location.pathname.slice(1); -onChunkUpdate(pageChunkPath, (update) => { - if (update.type === "restart") { - location.reload(); +onUpdate( + { + path: pageChunkPath, + headers: { + accept: "text/html", + }, + }, + (update) => { + if (update.type === "restart") { + location.reload(); + } } -}); +); initializeHMR({ assetPrefix: "", From dc74ca31c0a8322075a277ad037e8782c25979b9 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 24 Oct 2022 17:30:04 -0700 Subject: [PATCH 185/672] Create an app root layout if app/page.{js,tsx} exists but layout does not (vercel/turbo#264) This makes turbopack automatically create `app/layout.js` if `app/page.js` exists, or `app/layout.tsx` if `app/page.tsx` exists, and neither layout file already exists. **Note that I'd prefer this issue to have info severity, but even with a higher log level of info, the issue is never shown**. Filed vercel/turbo#265 to track this. Test Plan: In a new `create-next-app`, opt into appDirectory and create `app/page.js`. Run turbopack and verify: * [x] the index page renders correctly * [x] An issue with Warning level is logged notifying the user an `app/layout.js` was created * [x] `app/layout.js` is actually created with basic root layout In a new `create-next-app`, opt into appDirectory and create `app/page.tsx`. Run turbopack and verify: * [x] the index page renders correctly * [x] An issue with Warning level is logged notifying the user an `app/layout.tsx` was created * [x] `app/layout.tsx` is actually created with basic root layout In a new `create-next-app`, opt into appDirectory and create `app/page.tsx`. Also create a basic `app/layout.js` (note js layout with tsx page). Add a custom `` to the layout. Run turbopack and verify: * [x] the index page renders correctly * [x] No issue is logged * [x] No files are modified * [x] The custom `<title>` is reflected. --- .../crates/next-core/src/app_source.rs | 95 ++++++++++++++++++- .../crates/next-core/src/assets/layout.js | 8 ++ .../crates/next-core/src/assets/layout.tsx | 12 +++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/assets/layout.js create mode 100644 packages/next-swc/crates/next-core/src/assets/layout.tsx diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 212db39b37f586..29ad761f0c7e9a 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -1,10 +1,14 @@ use std::{collections::HashMap, fmt::Write}; -use anyhow::{anyhow, Result}; -use turbo_tasks::{primitives::StringsVc, TryJoinIterExt, Value, ValueToString}; +use anyhow::{anyhow, Context, Result}; +use turbo_tasks::{ + primitives::{StringVc, StringsVc}, + TryJoinIterExt, Value, ValueToString, +}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{ - DirectoryContent, DirectoryEntry, File, FileContent, FileSystemEntryType, FileSystemPathVc, + DirectoryContent, DirectoryEntry, File, FileContent, FileContentVc, FileSystemEntryType, + FileSystemPathVc, }; use turbopack::{ ecmascript::EcmascriptInputTransform, @@ -12,7 +16,10 @@ use turbopack::{ ModuleAssetContextVc, }; use turbopack_core::{ - chunk::dev::DevChunkingContextVc, context::AssetContextVc, virtual_asset::VirtualAssetVc, + chunk::dev::DevChunkingContextVc, + context::AssetContextVc, + issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, + virtual_asset::VirtualAssetVc, }; use turbopack_dev_server::{ html::DevHtmlAssetVc, @@ -298,6 +305,49 @@ async fn create_app_source_for_directory( } } } + + let layout_js = input_dir.join("layout.js"); + let layout_tsx = input_dir.join("layout.tsx"); + + // TODO: Use let Some(page_file) = page in expression below when + // https://rust-lang.github.io/rfcs/2497-if-let-chains.html lands + if page.is_some() && layout.is_none() && target == server_root { + // If a page exists but no layout exists, create a basic root layout + // in `app/layout.js` or `app/layout.tsx`. + let page_file = page.context("page must not be none")?; + // Use the extension to determine if the page file is TypeScript. + // TODO: Use the presence of a tsconfig.json instead, like Next.js + // stable does. + let is_tsx = *page_file.extension().await? == "tsx"; + + if is_tsx { + layout.replace(&layout_tsx); + } else { + layout.replace(&layout_js); + } + let content = if is_tsx { + include_str!("assets/layout.tsx") + } else { + include_str!("assets/layout.js") + }; + + let layout = layout.context("required")?; + layout.write(FileContentVc::from(File::from(content))); + + AppSourceIssue { + severity: IssueSeverity::Warning.into(), + path: *page_file, + message: StringVc::cell(format!( + "Your page {} did not have a root layout, we created {} for you.", + page_file.await?.path, + layout.await?.path, + )), + } + .cell() + .as_issue() + .emit(); + } + let mut list = layouts.await?.clone_value(); list.push( LayoutSegment { @@ -519,3 +569,40 @@ import BOOTSTRAP from {}; .cell()) } } + +#[turbo_tasks::value(shared)] +struct AppSourceIssue { + pub severity: IssueSeverityVc, + pub path: FileSystemPathVc, + pub message: StringVc, +} + +#[turbo_tasks::value_impl] +impl Issue for AppSourceIssue { + #[turbo_tasks::function] + fn severity(&self) -> IssueSeverityVc { + self.severity + } + + #[turbo_tasks::function] + async fn title(&self) -> Result<StringVc> { + Ok(StringVc::cell( + "An issue occurred while preparing your Next.js app".to_string(), + )) + } + + #[turbo_tasks::function] + fn category(&self) -> StringVc { + StringVc::cell("next app".to_string()) + } + + #[turbo_tasks::function] + fn context(&self) -> FileSystemPathVc { + self.path + } + + #[turbo_tasks::function] + fn description(&self) -> StringVc { + self.message + } +} diff --git a/packages/next-swc/crates/next-core/src/assets/layout.js b/packages/next-swc/crates/next-core/src/assets/layout.js new file mode 100644 index 00000000000000..47a82125a0d062 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/assets/layout.js @@ -0,0 +1,8 @@ +export default function RootLayout({ children }) { + return ( + <html> + <head></head> + <body>{children}</body> + </html> + ); +} diff --git a/packages/next-swc/crates/next-core/src/assets/layout.tsx b/packages/next-swc/crates/next-core/src/assets/layout.tsx new file mode 100644 index 00000000000000..3960a29e3c686f --- /dev/null +++ b/packages/next-swc/crates/next-core/src/assets/layout.tsx @@ -0,0 +1,12 @@ +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + <html> + <head></head> + <body>{children}</body> + </html> + ); +} From 43d86a1bfa70e597605c93ad7846abafafa905f9 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 25 Oct 2022 03:38:43 +0200 Subject: [PATCH 186/672] clippy (vercel/turbo#266) --- .../crates/next-core/src/next_client/context.rs | 1 - .../crates/next-core/src/nodejs/node_api_source.rs | 3 +-- packages/next-swc/crates/next-core/src/nodejs/pool.rs | 10 +++++----- .../crates/next-core/src/server_rendered_source.rs | 3 +-- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 0537955af5ae69..2ec59af0d37ebe 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -177,7 +177,6 @@ pub fn get_client_chunking_context( ) .hot_module_replacment() .build() - .into() } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs index 220c62a7268900..b8740ed73e8ad4 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs @@ -99,8 +99,7 @@ impl ContentSource for NodeApiContentSource { .cell(), *body, )) - .cell() - .into()); + .cell()); } else { return Ok(ContentSourceResult::NeedData { source: self_vc.into(), diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index 40f15cec6fabf6..e6ed016c1300d6 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -113,9 +113,9 @@ impl NodeJsPoolProcess { cmd.current_dir(cwd); cmd.arg(entrypoint); cmd.arg(&marker.marker); - cmd.arg(&OperationMarker::STEP); - cmd.arg(&OperationMarker::SUCCESS); - cmd.arg(&OperationMarker::ERROR); + cmd.arg(OperationMarker::STEP); + cmd.arg(OperationMarker::SUCCESS); + cmd.arg(OperationMarker::ERROR); cmd.env_clear(); cmd.env( "PATH", @@ -227,7 +227,7 @@ impl NodeJsPool { self.cwd.as_path(), &self.env, self.entrypoint.as_path(), - &*marker, + &marker, ); let fresh = spawn_blocking(move || NodeJsPoolProcess::start(cmd, marker)).await?; (fresh, permit) @@ -283,7 +283,7 @@ impl NodeJsOperation { let read = child.read_until(b'\n', buf)?; total_read += read; - match child.marker.read_event(&buf) { + match child.marker.read_event(buf) { Some((read, event)) => { buf.truncate(buf.len() - read); break Ok((total_read - read, event)); diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 8e72da8136bc51..d956678374583d 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -159,8 +159,7 @@ async fn create_server_rendered_source_for_file( intermediate_output_path.join("chunks"), get_client_assets_path(server_root, Value::new(ContextType::Pages { pages_dir })), ) - .build() - .into(); + .build(); Ok(if *is_api_path.await? { create_node_api_source( From c2bb12d0bf9846e84d627af5dcdc5d7958b76029 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Mon, 24 Oct 2022 22:16:35 -0400 Subject: [PATCH 187/672] Fix tracing of node_modules files not emitted by pages (vercel/turbo#249) Because the static SSR renderer doesn't emit files that exist in `node_modules` (because we take advantage of node's native `require` resolution), any paths that traced into `node_modules` would output the full file system path. It's just verbose and annoying. Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> --- .../crates/next-core/src/nodejs/mod.rs | 38 +++++++++---------- .../crates/next-core/src/source_map/trace.rs | 4 +- packages/next-swc/crates/next-dev/src/lib.rs | 7 +--- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 4f0ec232b04855..5c5f8c2e4f9937 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -2,7 +2,6 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, fmt::Write as _, io::Write, - path::{PathBuf, MAIN_SEPARATOR}, }; use anyhow::{anyhow, bail, Result}; @@ -71,6 +70,7 @@ async fn emit( /// List of the all assets of the "internal" subgraph and a list of boundary /// assets that are not considered "internal" ("external") +#[derive(Debug)] #[turbo_tasks::value] struct SeparatedAssets { internal_assets: AssetsSetVc, @@ -203,9 +203,9 @@ async fn get_renderer_pool( emit(intermediate_asset, intermediate_output_path).await?; - let output = intermediate_output_path.await?; - if let Some(disk) = DiskFileSystemVc::resolve_from(output.fs).await? { - let dir = PathBuf::from(&disk.await?.root).join(&output.path); + if let Some(fs) = DiskFileSystemVc::resolve_from(intermediate_output_path.fs()).await? { + let disk = fs.await?; + let dir = disk.to_sys_path(intermediate_output_path).await?; let entrypoint = dir.join("index.js"); let pool = NodeJsPool::new(dir, entrypoint, HashMap::new(), 4); Ok(pool.cell()) @@ -385,16 +385,13 @@ async fn trace_stack( _ => bail!("couldn't extract disk fs from path"), } .await?; - let root = format!( - "{}{}", - fs.to_sys_path(intermediate_output_path) - .await? - .to_str() - .unwrap(), - MAIN_SEPARATOR - ); + let root = fs + .to_sys_path(intermediate_output_path.root()) + .await? + .to_string_lossy() + .to_string(); - let assets = internal_assets(intermediate_asset, intermediate_output_path) + let assets = internal_assets(intermediate_asset, intermediate_output_path.root()) .await? .iter() .map(|a| async { @@ -421,13 +418,13 @@ async fn trace_stack( let mut message = String::new(); macro_rules! write_frame { - ($f:ident) => { + ($f:ident, $path:expr) => { match $f.get_pos() { Some((l, c)) => match &$f.name { - Some(n) => writeln!(message, " at {} ({}:{}:{})", n, $f.file, l, c), - None => writeln!(message, " at {}:{}:{}", $f.file, l, c), + Some(n) => writeln!(message, " at {} ({}:{}:{})", n, $path, l, c), + None => writeln!(message, " at {}:{}:{}", $path, l, c), }, - None => writeln!(message, " at {}", $f.file), + None => writeln!(message, " at {}", $path), } }; } @@ -442,14 +439,17 @@ async fn trace_stack( SourceMapTraceVc::new(map.content(), line, column, frame.name.clone()); let trace = map_trace.trace().await?; if let TraceResult::Found(f) = &*trace { - write_frame!(f)?; + write_frame!(f, path)?; continue; } } + + write_frame!(frame, path)?; + continue; } } - write_frame!(frame)?; + write_frame!(frame, frame.file)?; } Ok(StringVc::cell(message)) diff --git a/packages/next-swc/crates/next-core/src/source_map/trace.rs b/packages/next-swc/crates/next-core/src/source_map/trace.rs index 6db12de27b805c..c036c6bdf14190 100644 --- a/packages/next-swc/crates/next-core/src/source_map/trace.rs +++ b/packages/next-swc/crates/next-core/src/source_map/trace.rs @@ -88,8 +88,6 @@ impl DecodedSourceMapVc { _ => bail!("could not read file content"), }; - // It'd be great if we could cache this, but SM can't be stored in a Vc and I'm - // too sleepy to mess with it. let sm = match decode_source_map(content.as_ref()) { Ok(sm) => sm, _ => bail!("could not decode source map"), @@ -184,7 +182,7 @@ impl SourceMapTraceVc { let sm = decoded_map.lock().unwrap(); let trace = match sectioned_lookup(&sm, this.line.saturating_sub(1), this.column) { - Some(t) => t, + Some(t) if t.has_source() => t, _ => return Ok(TraceResult::NotFound.cell()), }; diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index e07d5448a7799b..f727dfe22a0aad 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -179,10 +179,7 @@ async fn project_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result<FileSy #[turbo_tasks::function] async fn output_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result<FileSystemVc> { - let disk_fs = DiskFileSystemVc::new( - "output".to_string(), - format!("{project_dir}{s}.next{s}server", s = MAIN_SEPARATOR), - ); + let disk_fs = DiskFileSystemVc::new("output".to_string(), project_dir.to_string()); handle_issues(disk_fs, console_ui).await?; disk_fs.await?.start_watching()?; Ok(disk_fs.into()) @@ -210,7 +207,7 @@ async fn source( let env = load_env(project_path); - let output_root = output_fs.root(); + let output_root = output_fs.root().join("/.next/server"); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let dev_server_root = dev_server_fs.root(); From 150155b7419493b44a9d1a73734c1e5a669e841e Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 25 Oct 2022 04:39:47 +0200 Subject: [PATCH 188/672] expose assets from fallback page (vercel/turbo#280) --- .../next-core/src/nodejs/node_rendered_source.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index 5e16c10ae01a86..c8329a7821e779 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -5,7 +5,7 @@ use indexmap::{IndexMap, IndexSet}; use turbo_tasks::{primitives::StringVc, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::{ - asset::AssetsSetVc, + asset::{Asset, AssetsSetVc}, introspect::{ asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, }, @@ -99,6 +99,15 @@ impl GetContentSource for NodeRenderContentSource { async fn content_source(&self) -> Result<ContentSourceVc> { let entries = self.entry.entries(); let mut set = IndexSet::new(); + for reference in self.fallback_page.references().await?.iter() { + set.extend( + reference + .resolve_reference() + .primary_assets() + .await? + .copied(), + ) + } for &entry in entries.await?.iter() { let entry = entry.await?; set.extend( From 880205ef374ca01fc03facfe2201404b13bae41a Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Mon, 24 Oct 2022 19:42:55 -0700 Subject: [PATCH 189/672] Fix bad merge (vercel/turbo#281) --- .../next-swc/crates/next-core/src/nodejs/node_rendered_source.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index c8329a7821e779..eb9aded35e00aa 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -105,6 +105,7 @@ impl GetContentSource for NodeRenderContentSource { .resolve_reference() .primary_assets() .await? + .iter() .copied(), ) } From 7d6212b06423b94f347579442e65ac2ade589f6e Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Mon, 24 Oct 2022 20:31:08 -0700 Subject: [PATCH 190/672] Use a TCP connection for IPC between Node and TP (vercel/turbo#251) Instead of using stdout for communication between the Node.js process and the Turbopack instance, this PR switches to a TCP connection. Furthermore, stdout and stderr are now piped between the Node.js process and Turbopack. --- .../next-core/js/src/entry/app-renderer.tsx | 84 ++--- .../next-core/js/src/entry/server-api.tsx | 205 ++++------- .../js/src/entry/server-renderer.tsx | 89 +++-- .../crates/next-core/js/src/internal/error.ts | 18 + .../crates/next-core/js/src/internal/ipc.ts | 125 +++++++ .../crates/next-core/src/app_source.rs | 3 +- .../crates/next-core/src/nodejs/issue.rs | 12 +- .../crates/next-core/src/nodejs/mod.rs | 344 ++++++++++------- .../crates/next-core/src/nodejs/pool.rs | 345 ++++++++---------- .../crates/next-core/src/source_map/trace.rs | 2 +- 10 files changed, 670 insertions(+), 557 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/internal/error.ts create mode 100644 packages/next-swc/crates/next-core/js/src/internal/ipc.ts diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 4527124bff0e16..afe5b2219249ce 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -1,9 +1,12 @@ +import type { Ipc } from "@vercel/turbopack-next/internal/ipc"; + // Provided by the rust generate code declare global { // an array of all layouts and the page const LAYOUT_INFO: { segment: string; module: any; chunks: string[] }[]; // array of chunks for the bootstrap script const BOOTSTRAP: string[]; + const IPC: Ipc<unknown, unknown>; } import type { IncomingMessage, ServerResponse } from "node:http"; @@ -18,8 +21,8 @@ import "next/dist/server/node-polyfill-web-streams"; import { RenderOpts, renderToHTMLOrFlight } from "next/dist/server/app-render"; import { PassThrough } from "stream"; import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; +import { structuredError } from "@vercel/turbopack-next/internal/error"; import { ParsedUrlQuery } from "node:querystring"; -import { parse as parseStackTrace } from "@vercel/turbopack-next/compiled/stacktrace-parser"; globalThis.__next_require__ = (data) => { const [, , ssr_id] = JSON.parse(data); @@ -29,46 +32,47 @@ globalThis.__next_chunk_load__ = () => Promise.resolve(); process.env.__NEXT_NEW_LINK_BEHAVIOR = "true"; -const [MARKER, _OPERATION_STEP, OPERATION_SUCCESS, _OPERATION_ERROR] = - process.argv.slice(2, 6).map((arg) => Buffer.from(arg, "utf8")); +const ipc = IPC as Ipc<IpcIncomingMessage, IpcOutgoingMessage>; + +type IpcIncomingMessage = { + type: "headers"; + data: RenderData; +}; -const NEW_LINE = "\n".charCodeAt(0); -const OPERATION_SUCCESS_MARKER = Buffer.concat([ - OPERATION_SUCCESS, - Buffer.from(" ", "utf8"), - MARKER, -]); +type IpcOutgoingMessage = { + type: "result"; + result: string | { body: string; contentType?: string }; +}; -process.stdout.write("READY\n"); +(async () => { + while (true) { + const msg = await ipc.recv(); -const buffer: Buffer[] = []; -process.stdin.on("data", async (data) => { - let idx = data.indexOf(NEW_LINE); - while (idx >= 0) { - buffer.push(data.slice(0, idx)); - const str = Buffer.concat(buffer).toString("utf-8"); - buffer.length = 0; - let json: any; - try { - json = JSON.parse(str); - buffer.length = 0; - } catch (e: any) { - const input = - str.length > 100 ? `${str.slice(0, 30)}...${str.slice(-30)}` : str; - e.message += `\nduring processing input ${input}`; - console.log(`ERROR=${JSON.stringify(structuredError(e))}`); + let renderData: RenderData; + switch (msg.type) { + case "headers": { + renderData = msg.data; + break; + } + default: { + console.error("unexpected message type", msg.type); + process.exit(1); + } } - try { - const result = await operation(json); - console.log(`RESULT=${JSON.stringify(result)}`); - } catch (e: any) { - console.log(`ERROR=${JSON.stringify(structuredError(e))}`); + + let html = await runOperation(renderData); + + if (html == null) { + throw new Error("no html returned"); } - console.log(OPERATION_SUCCESS_MARKER.toString("utf8")); - data = data.slice(idx + 1); - idx = data.indexOf(NEW_LINE); + + ipc.send({ + type: "result", + result: html, + }); } - buffer.push(data); +})().catch((err) => { + ipc.sendError(err); }); // TODO expose these types in next.js @@ -97,7 +101,7 @@ type ServerComponentsManifestModule = { [exportName: string]: { id: string; chunks: string[]; name: string }; }; -async function operation(renderData: RenderData) { +async function runOperation(renderData: RenderData) { const pageItem = LAYOUT_INFO[LAYOUT_INFO.length - 1]; const pageModule = pageItem.module; const Page = pageModule.default; @@ -257,11 +261,3 @@ export function htmlEscapeJsonString(str: string) { (match) => ESCAPE_LOOKUP[match as keyof typeof ESCAPE_LOOKUP] ); } - -function structuredError(e: Error) { - return { - name: e.name, - message: e.message, - stack: parseStackTrace(e.stack!), - }; -} diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx index 1beebbf39ab50c..0252012db15334 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx @@ -1,3 +1,5 @@ +import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; + import type { ClientRequest, IncomingMessage, Server } from "node:http"; import http, { ServerResponse } from "node:http"; import type { AddressInfo, Socket } from "node:net"; @@ -9,89 +11,28 @@ import * as allExports from "."; import { NextParsedUrlQuery } from "next/dist/server/request-meta"; import { apiResolver } from "next/dist/server/api-utils/node"; -const [MARKER, OPERATION_STEP, OPERATION_SUCCESS, OPERATION_ERROR] = - process.argv.slice(2, 6).map((arg) => Buffer.from(arg, "utf8")); - -const NEW_LINE = "\n".charCodeAt(0); -const OPERATION_STEP_MARKER = Buffer.concat([ - OPERATION_STEP, - Buffer.from(" ", "utf8"), - MARKER, -]); -const OPERATION_SUCCESS_MARKER = Buffer.concat([ - OPERATION_SUCCESS, - Buffer.from(" ", "utf8"), - MARKER, -]); -const OPERATION_ERROR_MARKER = Buffer.concat([ - OPERATION_ERROR, - Buffer.from(" ", "utf8"), - MARKER, -]); - -process.stdout.write("READY\n"); - -function bufferEndsWith(buffer: Buffer, suffix: Buffer): boolean { - if (buffer.length < suffix.length) { - return false; - } - - return buffer.subarray(buffer.length - suffix.length).equals(suffix); -} +const ipc = IPC as Ipc<IpcIncomingMessage, IpcOutgoingMessage>; -function readStep(buffer: Buffer): { data: Buffer; remaining: Buffer } | null { - let startLineIdx = 0; - let endLineIdx = buffer.indexOf(NEW_LINE); - - while (endLineIdx !== -1) { - const considering = buffer.subarray(startLineIdx, endLineIdx); - if (considering.equals(OPERATION_STEP_MARKER)) { - return { - data: buffer.subarray( - 0, - // Remove the newline character right before the marker. - startLineIdx === 0 ? 0 : startLineIdx - 1 - ), - remaining: buffer.subarray(endLineIdx + 1), - }; +type IpcIncomingMessage = + | { + type: "headers"; + data: RenderData; } + | { + type: "bodyChunk"; + data: Array<number>; + } + | { type: "bodyEnd" }; - // Consider the next line. - startLineIdx = endLineIdx + 1; - endLineIdx = buffer.indexOf(NEW_LINE, startLineIdx); - } - - return null; -} - -type State = "headers" | "body" | "done"; -let readState: State = "headers"; -let buffer: Buffer = Buffer.from([]); -let operationPromise: Promise<Operation> | null = null; - -process.stdin.on("data", async (chunk) => { - buffer = Buffer.concat([buffer, chunk]); - - let step = readStep(buffer); - while (step != null) { - switch (readState) { - case "headers": { - readState = "body"; - const renderData = JSON.parse(step.data.toString("utf-8")); - operationPromise = createOperation(renderData); - break; - } - case "body": { - readState = "headers"; - const body = step.data; - endOperation(operationPromise!, body); - break; - } +type IpcOutgoingMessage = + | { + type: "headers"; + data: ResponseHeaders; } - buffer = step.remaining; - step = readStep(step.remaining); - } -}); + | { + type: "body"; + data: Array<number>; + }; type RenderData = { method: string; @@ -105,29 +46,58 @@ type ResponseHeaders = { headers: string[]; }; -function writeEventMarker(eventMarker: Buffer) { - process.stdout.write("\n"); - process.stdout.write(eventMarker); - process.stdout.write("\n"); -} +(async () => { + while (true) { + let operationPromise: Promise<Operation> | null = null; -function writeStep(data: Buffer | string) { - process.stdout.write(data); - writeEventMarker(OPERATION_STEP_MARKER); -} + const msg = await ipc.recv(); -function writeSuccess(data: Buffer | string) { - process.stdout.write(data); - writeEventMarker(OPERATION_SUCCESS_MARKER); -} + switch (msg.type) { + case "headers": { + operationPromise = createOperation(msg.data); + break; + } + default: { + console.error("unexpected message type", msg.type); + process.exit(1); + } + } -function writeError(error: string) { - process.stdout.write(error); - writeEventMarker(OPERATION_ERROR_MARKER); -} + let body = Buffer.alloc(0); + let operation: Operation; + loop: while (true) { + const msg = await ipc.recv(); + + switch (msg.type) { + case "bodyChunk": { + body = Buffer.concat([body, Buffer.from(msg.data)]); + break; + } + case "bodyEnd": { + operation = await operationPromise; + break loop; + } + default: { + console.error("unexpected message type", msg.type); + process.exit(1); + } + } + } + + await Promise.all([ + endOperation(operation, body), + operation.clientResponsePromise.then((clientResponse) => + handleClientResponse(operation.server, clientResponse) + ), + ]); + } +})().catch((err) => { + ipc.sendError(err); +}); type Operation = { clientRequest: ClientRequest; + clientResponsePromise: Promise<IncomingMessage>; apiOperation: Promise<void>; server: Server; }; @@ -144,13 +114,10 @@ async function createOperation(renderData: RenderData): Promise<Operation> { const query = { ...renderData.query, ...renderData.params }; - clientResponsePromise.then((clientResponse) => - handleClientResponse(server, clientResponse) - ); - return { clientRequest, server, + clientResponsePromise, apiOperation: apiResolver( serverRequest, serverResponse, @@ -175,51 +142,41 @@ function handleClientResponse(server: Server, clientResponse: IncomingMessage) { headers: clientResponse.rawHeaders, }; - writeStep(JSON.stringify(responseHeaders)); + ipc.send({ + type: "headers", + data: responseHeaders, + }); clientResponse.on("data", (chunk) => { responseData.push(chunk); }); clientResponse.once("end", () => { - writeSuccess(Buffer.concat(responseData)); + ipc.send({ + type: "body", + data: Buffer.concat(responseData).toJSON().data, + }); server.close(); }); clientResponse.once("error", (err) => { - // TODO(alexkirsz) We need to ensure that we haven't already written an error in `endOperation`. - writeError(err.stack ?? "an unknown error occurred"); - server.close(); + ipc.sendError(err); }); } /** * Ends an operation by writing the response body to the client and waiting for the Next.js API resolver to finish. */ -async function endOperation( - operationPromise: Promise<Operation>, - body: Buffer -) { - const operation = await operationPromise; - +async function endOperation(operation: Operation, body: Buffer) { operation.clientRequest.end(body); try { await operation.apiOperation; } catch (error) { - if ( - error instanceof Error || - (error != null && (error as any).stack != null) - ) { - const stack = (error as any).stack as string | null; - - if (stack != null) { - writeError(stack); - operation.server.close(); - } + if (error instanceof Error) { + await ipc.sendError(error); } else { - writeError("an unknown error occurred"); - operation.server.close(); + await ipc.sendError(new Error("an unknown error occurred")); } return; @@ -230,7 +187,7 @@ async function endOperation( * Creates a server that listens a random port. */ function createServer(): Promise<Server> { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { const server = http.createServer(); server.listen(0, () => { resolve(server); diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index f3c94af232ce63..3c627bc4ea8e18 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -1,3 +1,5 @@ +import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; + import type { IncomingMessage, ServerResponse } from "node:http"; import "@vercel/turbopack-next/internal/shims"; @@ -9,7 +11,6 @@ import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; import App from "@vercel/turbopack-next/pages/_app"; import Document from "@vercel/turbopack-next/pages/_document"; -import { parse as parseStackTrace } from "@vercel/turbopack-next/compiled/stacktrace-parser"; import Component, * as otherExports from "."; ("TURBOPACK { transition: next-client }"); @@ -17,46 +18,52 @@ import chunkGroup from "."; import type { BuildManifest } from "next/dist/server/get-page-files"; import type { ChunkGroup } from "types/next"; -const [MARKER, _OPERATION_STEP, OPERATION_SUCCESS, _OPERATION_ERROR] = - process.argv.slice(2, 6).map((arg) => Buffer.from(arg, "utf8")); - -const NEW_LINE = "\n".charCodeAt(0); -const OPERATION_SUCCESS_MARKER = Buffer.concat([ - OPERATION_SUCCESS, - Buffer.from(" ", "utf8"), - MARKER, -]); - -process.stdout.write("READY\n"); - -const buffer: Buffer[] = []; -process.stdin.on("data", async (data) => { - let idx = data.indexOf(NEW_LINE); - while (idx >= 0) { - buffer.push(data.slice(0, idx)); - try { - const json = JSON.parse(Buffer.concat(buffer).toString("utf-8")); - buffer.length = 0; - const result = await operation(json); - console.log(`RESULT=${JSON.stringify(result)}`); - } catch (e: any) { - console.log(`ERROR=${JSON.stringify(structuredError(e))}`); +const ipc = IPC as Ipc<IpcIncomingMessage, IpcOutgoingMessage>; + +type IpcIncomingMessage = { + type: "headers"; + data: RenderData; +}; + +type IpcOutgoingMessage = { + type: "result"; + result: string | { body: string; contentType?: string }; +}; + +(async () => { + while (true) { + const msg = await ipc.recv(); + + let renderData: RenderData; + switch (msg.type) { + case "headers": { + renderData = msg.data; + break; + } + default: { + console.error("unexpected message type", msg.type); + process.exit(1); + } } - console.log(OPERATION_SUCCESS_MARKER.toString("utf8")); - data = data.slice(idx + 1); - idx = data.indexOf(NEW_LINE); - } - buffer.push(data); -}); -type QueryValue = string | QueryValue[] | Query; -interface Query { - [key: string]: QueryValue; -} + let html = await runOperation(renderData); -type HeaderValue = string | string[]; + if (html == null) { + throw new Error("no html returned"); + } -async function operation(renderData: RenderData) { + ipc.send({ + type: "result", + result: html, + }); + } +})().catch((err) => { + ipc.sendError(err); +}); + +async function runOperation( + renderData: RenderData +): Promise<string | undefined> { // TODO(alexkirsz) This is missing *a lot* of data, but it's enough to get a // basic render working. @@ -152,11 +159,3 @@ async function operation(renderData: RenderData) { ) )?.toUnchunkedString(); } - -function structuredError(e: Error) { - return { - name: e.name, - message: e.message, - stack: parseStackTrace(e.stack!), - }; -} diff --git a/packages/next-swc/crates/next-core/js/src/internal/error.ts b/packages/next-swc/crates/next-core/js/src/internal/error.ts new file mode 100644 index 00000000000000..58b39117d2b344 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/internal/error.ts @@ -0,0 +1,18 @@ +import { + parse as parseStackTrace, + StackFrame, +} from "@vercel/turbopack-next/compiled/stacktrace-parser"; + +export type StructuredError = { + name: string; + message: string; + stack: StackFrame[]; +}; + +export function structuredError(e: Error): StructuredError { + return { + name: e.name, + message: e.message, + stack: parseStackTrace(e.stack!), + }; +} diff --git a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts new file mode 100644 index 00000000000000..bb379fa9026877 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts @@ -0,0 +1,125 @@ +import net from "node:net"; + +import { structuredError } from "@vercel/turbopack-next/internal/error"; + +type State = + | { + type: "waiting"; + } + | { + type: "packet"; + length: number; + }; + +export type Ipc<TIncoming, TOutgoing> = { + recv(): Promise<TIncoming>; + send(message: TOutgoing): Promise<void>; + sendError(error: Error): Promise<never>; +}; + +function createIpc<TIncoming, TOutgoing>( + port: number +): Ipc<TIncoming, TOutgoing> { + const socket = net.createConnection(port); + const packetQueue: Buffer[] = []; + const recvPromiseResolveQueue: Array<(message: TIncoming) => void> = []; + + function pushPacket(packet: Buffer) { + let recvPromiseResolve = recvPromiseResolveQueue.shift(); + if (recvPromiseResolve != null) { + recvPromiseResolve(JSON.parse(packet.toString("utf8")) as TIncoming); + } else { + packetQueue.push(packet); + } + } + + let state: State = { type: "waiting" }; + let buffer: Buffer = Buffer.alloc(0); + socket.once("connect", () => { + socket.on("data", (chunk) => { + buffer = Buffer.concat([buffer, chunk]); + + loop: while (true) { + switch (state.type) { + case "waiting": { + if (buffer.length >= 4) { + const length = buffer.readUInt32BE(0); + buffer = buffer.subarray(4); + state = { type: "packet", length }; + } else { + break loop; + } + break; + } + case "packet": { + if (buffer.length >= state.length) { + const packet = buffer.subarray(0, state.length); + buffer = buffer.subarray(state.length); + state = { type: "waiting" }; + pushPacket(packet); + } else { + break loop; + } + break; + } + } + } + }); + }); + + function send(message: any): Promise<void> { + const packet = Buffer.from(JSON.stringify(message), "utf8"); + const length = Buffer.alloc(4); + length.writeUInt32BE(packet.length); + socket.write(length); + + return new Promise((resolve, reject) => { + socket.write(packet, (err) => { + if (err != null) { + reject(err); + } else { + resolve(); + } + }); + }); + } + + return { + async recv() { + let packet = packetQueue.shift(); + if (packet != null) { + return JSON.parse(packet.toString("utf8")) as TIncoming; + } + + const result = await new Promise<TIncoming>((resolve) => { + recvPromiseResolveQueue.push((result) => { + resolve(result); + }); + }); + + return result; + }, + + send(message: TOutgoing) { + return send(message); + }, + + async sendError(error: Error): Promise<never> { + await send({ + type: "error", + ...structuredError(error), + }); + process.exit(1); + }, + }; +} + +const PORT = process.argv[2]; + +const IPC = createIpc<unknown, unknown>(parseInt(PORT, 10)); + +process.on("uncaughtException", (err) => { + IPC.sendError(err); +}); + +export default IPC; diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 29ad761f0c7e9a..1df2a576fb1127 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -494,7 +494,8 @@ impl NodeEntry for AppRenderer { .into_iter() .try_join() .await?; - let mut result = String::new(); + let mut result = + "import IPC, { Ipc } from \"@vercel/turbopack-next/internal/ipc\";\n".to_string(); for (_, import) in segments.iter() { if let Some((p, identifier, chunks_identifier)) = import { writeln!( diff --git a/packages/next-swc/crates/next-core/src/nodejs/issue.rs b/packages/next-swc/crates/next-core/src/nodejs/issue.rs index ae41c64585d84e..5ab99a18aa4f34 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/issue.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/issue.rs @@ -8,7 +8,7 @@ use turbopack_core::issue::{Issue, IssueVc}; pub(super) struct RenderingIssue { pub context: FileSystemPathVc, pub message: StringVc, - pub logs: StringVc, + pub status: Option<i32>, } #[turbo_tasks::value_impl] @@ -34,8 +34,14 @@ impl Issue for RenderingIssue { } #[turbo_tasks::function] - fn detail(&self) -> StringVc { - self.logs + async fn detail(&self) -> Result<StringVc> { + let mut details = vec![]; + + if let Some(status) = self.status { + details.push(format!("Node.js exit code: {status}")); + } + + Ok(StringVc::cell(details.join("\n"))) } // TODO parse stack trace into source location diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 5c5f8c2e4f9937..a74f30b2d7f949 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -1,7 +1,6 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, fmt::Write as _, - io::Write, }; use anyhow::{anyhow, bail, Result}; @@ -11,7 +10,7 @@ use mime::TEXT_HTML_UTF_8; pub use node_api_source::create_node_api_source; pub use node_entry::{NodeEntry, NodeEntryVc}; pub use node_rendered_source::create_node_rendered_source; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, TryJoinIterExt}; use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; use turbopack::ecmascript::EcmascriptModuleAssetVc; @@ -29,12 +28,9 @@ use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; use self::{ bootstrap::NodeJsBootstrapAsset, issue::RenderingIssue, - pool::{NodeJsPool, NodeJsPoolVc}, -}; -use crate::{ - nodejs::pool::OperationEvent, - source_map::{SourceMapTraceVc, StackFrame, TraceResult}, + pool::{NodeJsOperation, NodeJsPool, NodeJsPoolVc}, }; +use crate::source_map::{SourceMapTraceVc, StackFrame, TraceResult}; pub(crate) mod bootstrap; pub(crate) mod issue; @@ -253,6 +249,19 @@ pub enum RenderResult { }, } +#[derive(Serialize)] +#[serde(tag = "type", rename_all = "camelCase")] +enum RenderStaticOutgoingMessage<'a> { + Headers { data: &'a RenderData }, +} + +#[derive(Deserialize)] +#[serde(tag = "type", rename_all = "camelCase")] +enum RenderStaticIncomingMessage { + Result { result: RenderResult }, + Error(StructuredError), +} + /// Renders a module as static HTML in a node.js process. #[turbo_tasks::function] async fn render_static( @@ -274,112 +283,101 @@ async fn render_static( // Read this strongly consistent, since we don't want to run inconsistent // node.js code. let pool = renderer_pool.strongly_consistent().await?; - let mut operation = pool.operation().await?; + let mut operation = match pool.operation().await { + Ok(operation) => operation, + Err(err) => { + return Ok(static_error(path, err, None, fallback_page).await?); + } + }; + + match run_static_operation( + &mut operation, + data, + intermediate_asset, + intermediate_output_path, + ) + .await + { + Ok(asset) => Ok(asset), + Err(err) => Ok(static_error(path, err, Some(operation), fallback_page).await?), + } +} + +async fn run_static_operation( + operation: &mut NodeJsOperation, + data: RenderDataVc, + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result<AssetContentVc> { let data = data.await?; - // First, write the render data to the process as a JSON string. - let data = serde_json::to_string(&*data)?; - operation.write_all(data.as_bytes())?; - operation.write_all(&[b'\n'])?; - - let mut buffer = Vec::new(); - - // Read the result headers as a UTF8 string. - let (_, event) = operation.read_event(&mut buffer)?; - let result = match event { - OperationEvent::Success => String::from_utf8(buffer)?, - event => { - bail!( - "unexpected event from Node.js rendering process: {:?}", - event - ); + operation + .send(RenderStaticOutgoingMessage::Headers { data: &data }) + .await?; + + match operation.recv().await? { + RenderStaticIncomingMessage::Result { + result: RenderResult::Simple(body), + } => Ok(FileContent::Content(File::from(body).with_content_type(TEXT_HTML_UTF_8)).into()), + RenderStaticIncomingMessage::Result { + result: RenderResult::Advanced { body, content_type }, + } => Ok(FileContent::Content( + File::from(body) + .with_content_type(content_type.map_or(Ok(TEXT_HTML_UTF_8), |c| c.parse())?), + ) + .into()), + RenderStaticIncomingMessage::Error(error) => { + bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?) } + } +} + +async fn static_error( + path: FileSystemPathVc, + error: anyhow::Error, + operation: Option<NodeJsOperation>, + fallback_page: DevHtmlAssetVc, +) -> Result<AssetContentVc> { + let message = format!("{error:?}"); + let status = match operation { + Some(operation) => Some(operation.wait_or_kill().await?), + None => None, }; - // Parse the result. - let lines: Vec<_> = result.lines().collect(); - let issue = if let Some(last_line) = lines.last() { - if let Some(data) = last_line.strip_prefix("RESULT=") { - let result: serde_json::Result<RenderResult> = serde_json::from_str(data); - match result { - Ok(RenderResult::Simple(body)) => { - return Ok(FileContent::Content( - File::from(body).with_content_type(TEXT_HTML_UTF_8), - ) - .into()); - } - Ok(RenderResult::Advanced { body, content_type }) => { - return Ok(FileContent::Content(File::from(body).with_content_type( - content_type.map_or(Ok(TEXT_HTML_UTF_8), |c| c.parse())?, - )) - .into()); - } - Err(err) => RenderingIssue { - context: path, - message: StringVc::cell(format!( - "Unexpected result provided by Node.js rendering process: {err}" - )), - logs: StringVc::cell(lines.join("\n")), - }, - } - } else if let Some(data) = last_line.strip_prefix("ERROR=") { - let error: StructuredError = serde_json::from_str(data)?; - let message = trace_stack(error.cell(), intermediate_asset, intermediate_output_path); - RenderingIssue { - context: path, - message, - logs: StringVc::cell(lines[..lines.len() - 1].join("\n")), - } - } else { - RenderingIssue { - context: path, - message: StringVc::cell("No result provided by Node.js process".to_string()), - logs: StringVc::cell(lines.join("\n")), - } - } + let html_status = if let Some(status) = status { + format!("<h2>Exit status</h2><pre>{status}</pre>") } else { - RenderingIssue { - context: path, - message: StringVc::cell("No content received from Node.js process.".to_string()), - logs: StringVc::cell("".to_string()), - } + format!("<h3>No exit status</pre>") }; - // Emit an issue for error reporting - issue.cell().as_issue().emit(); - let body = format!( "<script id=\"__NEXT_DATA__\" type=\"application/json\">{{ \"props\": {{}} }}</script> <div id=\"__next\"> <h1>Error rendering page</h1> <h2>Message</h2> - <pre>{}</pre> - <h2>Logs</h2> - <pre>{}</pre> + <pre>{message}</pre> + {html_status} </div>", - issue.message.await?, - issue.logs.await?, ); + let issue = RenderingIssue { + context: path, + message: StringVc::cell(format!("{error:?}")), + status: status.and_then(|status| status.code()), + }; + + issue.cell().as_issue().emit(); + let html = fallback_page.with_body(body); Ok(html.content()) } -#[turbo_tasks::value(shared)] -struct StructuredError { - name: String, - message: String, - stack: Vec<StackFrame>, -} - -#[turbo_tasks::function] async fn trace_stack( - error: StructuredErrorVc, + error: StructuredError, intermediate_asset: AssetVc, intermediate_output_path: FileSystemPathVc, -) -> Result<StringVc> { - let error = error.await?; +) -> Result<String> { let fs = match DiskFileSystemVc::resolve_from(intermediate_output_path.fs()).await? { Some(fs) => fs, _ => bail!("couldn't extract disk fs from path"), @@ -452,7 +450,7 @@ async fn trace_stack( write_frame!(frame, frame.file)?; } - Ok(StringVc::cell(message)) + Ok(message) } #[turbo_tasks::value(shared)] @@ -461,6 +459,29 @@ pub(super) struct ResponseHeaders { headers: Vec<String>, } +#[derive(Serialize)] +#[serde(tag = "type", rename_all = "camelCase")] +enum RenderProxyOutgoingMessage<'a> { + Headers { data: &'a RenderData }, + BodyChunk { data: &'a [u8] }, + BodyEnd, +} + +#[derive(Deserialize)] +#[serde(tag = "type", rename_all = "camelCase")] +enum RenderProxyIncomingMessage { + Headers { data: ResponseHeaders }, + Body { data: Vec<u8> }, + Error(StructuredError), +} + +#[turbo_tasks::value(shared)] +struct StructuredError { + name: String, + message: String, + stack: Vec<StackFrame>, +} + /// Renders a module as static HTML in a node.js process. #[turbo_tasks::function] async fn render_proxy( @@ -472,76 +493,115 @@ async fn render_proxy( data: RenderDataVc, body: BodyVc, ) -> Result<ProxyResultVc> { - let renderer_pool = get_renderer_pool( - get_intermediate_asset( - module, - runtime_entries, - chunking_context, - intermediate_output_path, - ), + let intermediate_asset = get_intermediate_asset( + module, + runtime_entries, + chunking_context, intermediate_output_path, ); + let renderer_pool = get_renderer_pool(intermediate_asset, intermediate_output_path); let pool = renderer_pool.await?; - let mut operation = pool.operation().await?; - let data = data.await?; + let mut operation = match pool.operation().await { + Ok(operation) => operation, + Err(err) => { + return Ok(proxy_error(path, err, None).await?); + } + }; - // First, write the render data to the process as a JSON string. - let data = serde_json::to_string(&*data)?; - operation.write_all(data.as_bytes())?; - operation.write_step()?; + match run_proxy_operation( + &mut operation, + data, + body, + intermediate_asset, + intermediate_output_path, + ) + .await + { + Ok(proxy_result) => Ok(proxy_result.cell()), + Err(err) => Ok(proxy_error(path, err, Some(operation)).await?), + } +} - // Then, write the binary body. - for chunk in body.await?.chunks() { - operation.write_all(chunk.as_bytes())?; +async fn run_proxy_operation( + operation: &mut NodeJsOperation, + data: RenderDataVc, + body: BodyVc, + intermediate_asset: AssetVc, + intermediate_output_path: FileSystemPathVc, +) -> Result<ProxyResult> { + let data = data.await?; + // First, send the render data. + operation + .send(RenderProxyOutgoingMessage::Headers { data: &*data }) + .await?; + + let body = body.await?; + // Then, send the binary body in chunks. + for chunk in body.chunks() { + operation + .send(RenderProxyOutgoingMessage::BodyChunk { + data: chunk.as_bytes(), + }) + .await?; } - operation.write_step()?; - - let mut buffer = Vec::new(); - - // Read the response headers as a JSON string. - let (_, event) = operation.read_event(&mut buffer)?; - let headers: ResponseHeaders = match event { - OperationEvent::Step => serde_json::from_slice(&buffer)?, - OperationEvent::Error => return proxy_error(path, buffer), - event => { - bail!( - "unexpected event from Node.js rendering process: {:?}", - event - ); + + operation.send(RenderProxyOutgoingMessage::BodyEnd).await?; + + let (status, headers) = match operation.recv().await? { + RenderProxyIncomingMessage::Headers { + data: ResponseHeaders { status, headers }, + } => (status, headers), + RenderProxyIncomingMessage::Error(error) => { + bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?) + } + _ => { + bail!("unexpected response from the Node.js process while reading response headers") } }; - // Reuse the buffer. - buffer.truncate(0); - - // Read the response body as a binary blob. - let (_, event) = operation.read_event(&mut buffer)?; - let body = match event { - OperationEvent::Success => buffer, - OperationEvent::Error => return proxy_error(path, buffer), - event => { - bail!( - "unexpected event from Node.js rendering process: {:?}", - event - ); + let body = match operation.recv().await? { + RenderProxyIncomingMessage::Body { data: body } => body, + RenderProxyIncomingMessage::Error(error) => { + bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?) + } + _ => { + bail!("unexpected response from the Node.js process while reading response body") } }; Ok(ProxyResult { - status: headers.status, - headers: headers.headers, + status, + headers, body, - } - .cell()) + }) } -fn proxy_error(path: FileSystemPathVc, buffer: Vec<u8>) -> Result<ProxyResultVc> { - let error_message = String::from_utf8(buffer.clone())?; +async fn proxy_error( + path: FileSystemPathVc, + error: anyhow::Error, + operation: Option<NodeJsOperation>, +) -> Result<ProxyResultVc> { + let message = format!("{error:?}"); + + let status = match operation { + Some(operation) => Some(operation.wait_or_kill().await?), + None => None, + }; + + let mut details = vec![]; + if let Some(status) = status { + details.push(format!("status: {status}")); + } + + let body = format!( + "An error occurred while proxying a request to Node.js:\n{message}\n{}", + details.join("\n") + ); RenderingIssue { context: path, - message: StringVc::cell(error_message), - logs: StringVc::cell("".to_string()), + message: StringVc::cell(message), + status: status.and_then(|status| status.code()), } .cell() .as_issue() @@ -553,7 +613,7 @@ fn proxy_error(path: FileSystemPathVc, buffer: Vec<u8>) -> Result<ProxyResultVc> "content-type".to_string(), "text/html; charset=utf-8".to_string(), ], - body: buffer, + body: body.into_bytes(), } .cell()) } diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index e6ed016c1300d6..edad04171ec1d4 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -1,176 +1,142 @@ use std::{ collections::HashMap, - io::{BufRead, BufReader, ErrorKind, Write}, path::{Path, PathBuf}, - process::{Child, ChildStdin, ChildStdout, Command, Stdio}, + process::{ExitStatus, Stdio}, sync::{Arc, Mutex}, + time::Duration, }; use anyhow::{bail, Context, Result}; -use rand::Rng; -use tokio::sync::{OwnedSemaphorePermit, Semaphore}; -use turbo_tasks::spawn_blocking; -use turbo_tasks_hash::encode_hex_string; +use serde::{de::DeserializeOwned, Serialize}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::{TcpListener, TcpStream}, + process::{Child, Command}, + select, + sync::{OwnedSemaphorePermit, Semaphore}, + time::sleep, +}; -struct NodeJsPoolProcess { - child: Child, - stdin: ChildStdin, - stdout: BufReader<ChildStdout>, - marker: Arc<OperationMarker>, +enum NodeJsPoolProcess { + Spawned(SpawnedNodeJsPoolProcess), + Running(RunningNodeJsPoolProcess), } -impl Drop for NodeJsPoolProcess { - fn drop(&mut self) { - let _ = self.child.kill(); - let _ = self.child.wait(); - } +struct SpawnedNodeJsPoolProcess { + child: Option<Child>, + listener: TcpListener, } -/// A marker used to detect the limits of a single operation without the output -/// of a Node.js process. -struct OperationMarker { - marker: String, +struct RunningNodeJsPoolProcess { + child: Option<Child>, + connection: TcpStream, } -impl OperationMarker { - const STEP: &str = "OPERATION_STEP"; - const SUCCESS: &str = "OPERATION_END"; - const ERROR: &str = "OPERATION_ERROR"; - - fn new() -> Self { - Self { - marker: encode_hex_string(&rand::thread_rng().gen::<[u8; 16]>()), - } - } - - fn read_event(&self, orig_buffer: &[u8]) -> Option<(usize, OperationEvent)> { - let buffer = orig_buffer; - let buffer = buffer.strip_suffix(&[b'\n'])?; - let buffer = buffer.strip_suffix(self.marker.as_bytes())?; - let buffer = buffer.strip_suffix(&[b' '])?; - - if let Some(buffer) = buffer - .strip_suffix(Self::STEP.as_bytes()) - .and_then(|buffer| buffer.strip_suffix(&[b'\n'])) - { - Some((orig_buffer.len() - buffer.len(), OperationEvent::Step)) - } else if let Some(buffer) = buffer - .strip_suffix(Self::SUCCESS.as_bytes()) - .and_then(|buffer| buffer.strip_suffix(&[b'\n'])) - { - Some((orig_buffer.len() - buffer.len(), OperationEvent::Success)) - } else if let Some(buffer) = buffer - .strip_suffix(Self::ERROR.as_bytes()) - .and_then(|buffer| buffer.strip_suffix(&[b'\n'])) - { - Some((orig_buffer.len() - buffer.len(), OperationEvent::Error)) - } else { - None +impl Drop for SpawnedNodeJsPoolProcess { + fn drop(&mut self) { + if let Some(mut child) = self.child.take() { + tokio::spawn(async move { + let _ = child.kill().await; + }); } } - - fn write<W>(&self, mut writer: W, kind: &str) -> std::io::Result<()> - where - W: Write, - { - writer.write_all(&[b'\n'])?; - writer.write_all(kind.as_bytes())?; - writer.write_all(&[b' '])?; - writer.write_all(self.marker.as_bytes())?; - writer.write_all(&[b'\n'])?; - Ok(()) - } - - fn write_step<W>(&self, writer: W) -> std::io::Result<()> - where - W: Write, - { - self.write(writer, Self::STEP) - } } -impl Default for OperationMarker { - fn default() -> Self { - Self::new() +impl Drop for RunningNodeJsPoolProcess { + fn drop(&mut self) { + if let Some(mut child) = self.child.take() { + tokio::spawn(async move { + let _ = child.kill().await; + }); + } } } -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub(super) enum OperationEvent { - Step, - Success, - Error, -} +const CONNECT_TIMEOUT: Duration = Duration::from_secs(1); impl NodeJsPoolProcess { - fn prepare( - cwd: &Path, - env: &HashMap<String, String>, - entrypoint: &Path, - marker: &OperationMarker, - ) -> Command { + async fn new(cwd: &Path, env: &HashMap<String, String>, entrypoint: &Path) -> Result<Self> { + let listener = TcpListener::bind("127.0.0.1:0") + .await + .context("binding to a port")?; + let port = listener.local_addr().context("getting port")?.port(); let mut cmd = Command::new("node"); cmd.current_dir(cwd); cmd.arg(entrypoint); - cmd.arg(&marker.marker); - cmd.arg(OperationMarker::STEP); - cmd.arg(OperationMarker::SUCCESS); - cmd.arg(OperationMarker::ERROR); + cmd.arg(port.to_string()); cmd.env_clear(); cmd.env( "PATH", - std::env::var("PATH").expect("PATH should always be set"), + std::env::var("PATH").expect("the PATH environment variable should always be set"), ); #[cfg(target_family = "windows")] cmd.env( "SystemRoot", - std::env::var("SystemRoot").expect("SystemRoot should always be set"), + std::env::var("SystemRoot") + .expect("the SystemRoot environment variable should always be set"), ); cmd.envs(env); - cmd.stdin(Stdio::piped()); - cmd.stdout(Stdio::piped()); - cmd - } + cmd.stderr(Stdio::inherit()); + cmd.stdout(Stdio::inherit()); - fn start(mut cmd: Command, marker: Arc<OperationMarker>) -> Result<Self> { - let mut child = cmd.spawn().context("spawning node pool")?; - let stdin = child.stdin.take().unwrap(); - let mut stdout = BufReader::new(child.stdout.take().unwrap()); - let mut bootstrap_log = Vec::new(); - loop { - let mut buf = String::new(); - if stdout.read_line(&mut buf)? == 0 { - bail!("process closed unexpectedly\n{}", bootstrap_log.join("\n")); - } - if buf == "READY\n" { - break; - } - bootstrap_log.push(buf); - } - Ok(NodeJsPoolProcess { - child, - stdin, - stdout, - marker, - }) - } + let child = cmd.spawn().context("spawning node pooled process")?; - fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> std::io::Result<usize> { - self.stdout.read_until(byte, buf) + Ok(Self::Spawned(SpawnedNodeJsPoolProcess { + listener, + child: Some(child), + })) } - fn write_step(&mut self) -> std::io::Result<()> { - self.marker.write_step(&mut self.stdin) + async fn run(self) -> Result<RunningNodeJsPoolProcess> { + Ok(match self { + NodeJsPoolProcess::Spawned(mut spawned) => { + let (connection, _) = select! { + connection = spawned.listener.accept() => connection.context("accepting connection")?, + _ = sleep(CONNECT_TIMEOUT) => bail!("timed out waiting for the Node.js process to connect"), + }; + + RunningNodeJsPoolProcess { + child: spawned.child.take(), + connection, + } + } + NodeJsPoolProcess::Running(running) => running, + }) } } -impl Write for NodeJsPoolProcess { - fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { - self.stdin.write(buf) +impl RunningNodeJsPoolProcess { + async fn recv(&mut self) -> Result<Vec<u8>> { + let packet_len = self + .connection + .read_u32() + .await + .context("reading packet length")? + .try_into() + .context("storing packet length")?; + let mut packet_data = vec![0; packet_len]; + self.connection + .read_exact(&mut packet_data) + .await + .context("reading packet data")?; + Ok(packet_data) } - fn flush(&mut self) -> std::io::Result<()> { - self.stdin.flush() + async fn send(&mut self, packet_data: Vec<u8>) -> Result<()> { + self.connection + .write_u32( + packet_data + .len() + .try_into() + .context("packet length does not fit into u32")?, + ) + .await + .context("writing packet length")?; + self.connection + .write_all(&packet_data) + .await + .context("writing packet data")?; + Ok(()) } } @@ -192,8 +158,6 @@ pub(super) struct NodeJsPool { processes: Arc<Mutex<Vec<NodeJsPoolProcess>>>, #[turbo_tasks(trace_ignore, debug_ignore)] semaphore: Arc<Semaphore>, - #[turbo_tasks(trace_ignore, debug_ignore)] - marker: Arc<OperationMarker>, } impl NodeJsPool { @@ -209,44 +173,39 @@ impl NodeJsPool { env, processes: Arc::new(Mutex::new(Vec::new())), semaphore: Arc::new(Semaphore::new(concurrency)), - marker: Arc::new(OperationMarker::default()), } } - async fn acquire_child(&self) -> Result<(NodeJsPoolProcess, OwnedSemaphorePermit)> { + async fn acquire_process(&self) -> Result<(NodeJsPoolProcess, OwnedSemaphorePermit)> { let permit = self.semaphore.clone().acquire_owned().await?; let popped = { let mut processes = self.processes.lock().unwrap(); processes.pop() }; - Ok(if let Some(child) = popped { - (child, permit) + Ok(if let Some(process) = popped { + (process, permit) } else { - let marker = Arc::clone(&self.marker); - let cmd = NodeJsPoolProcess::prepare( - self.cwd.as_path(), - &self.env, - self.entrypoint.as_path(), - &marker, - ); - let fresh = spawn_blocking(move || NodeJsPoolProcess::start(cmd, marker)).await?; - (fresh, permit) + let process = + NodeJsPoolProcess::new(self.cwd.as_path(), &self.env, self.entrypoint.as_path()) + .await + .context("creating new process")?; + (process, permit) }) } pub(super) async fn operation(&self) -> Result<NodeJsOperation> { - let (child, permit) = self.acquire_child().await?; + let (process, permit) = self.acquire_process().await?; Ok(NodeJsOperation { - child: Some(child), + process: Some(process.run().await?), permit, processes: self.processes.clone(), }) } } -pub(super) struct NodeJsOperation { - child: Option<NodeJsPoolProcess>, +pub struct NodeJsOperation { + process: Option<RunningNodeJsPoolProcess>, // This is used for drop #[allow(dead_code)] permit: OwnedSemaphorePermit, @@ -254,69 +213,61 @@ pub(super) struct NodeJsOperation { } impl NodeJsOperation { - fn expect_child_mut(&mut self) -> &mut NodeJsPoolProcess { - self.child + fn process_mut(&mut self) -> Result<&mut RunningNodeJsPoolProcess> { + Ok(self + .process .as_mut() - .expect("child must be present while operation is live") + .context("Node.js operation already finished")?) } - fn take_child(&mut self) -> NodeJsPoolProcess { - self.child - .take() - .expect("child must be present while operation is live") + pub(super) async fn recv<M>(&mut self) -> Result<M> + where + M: DeserializeOwned, + { + let message = self + .process_mut()? + .recv() + .await + .context("receiving message")?; + Ok(serde_json::from_slice(&message).context("deserializing message")?) } - /// Writes the step event end marker to the child process. - pub(super) fn write_step(&mut self) -> std::io::Result<()> { - self.expect_child_mut().write_step() + pub(super) async fn send<M>(&mut self, message: M) -> Result<()> + where + M: Serialize, + { + Ok(self + .process_mut()? + .send(serde_json::to_vec(&message).context("serializing message")?) + .await + .context("sending message")?) } - /// Reads a completed event in the child process output. Blocks while - /// waiting for more output. - pub(super) fn read_event( - &mut self, - buf: &mut Vec<u8>, - ) -> std::io::Result<(usize, OperationEvent)> { - let child = self.expect_child_mut(); - let mut total_read = 0; - loop { - let read = child.read_until(b'\n', buf)?; - total_read += read; + pub(super) async fn wait_or_kill(mut self) -> Result<ExitStatus> { + let mut process = self + .process + .take() + .context("Node.js operation already finished")?; - match child.marker.read_event(buf) { - Some((read, event)) => { - buf.truncate(buf.len() - read); - break Ok((total_read - read, event)); - } - None => { - if read == 0 { - // we need to stop reading in this case otherwise this loop infinitely - return Err(std::io::Error::new( - ErrorKind::UnexpectedEof, - "process closed unexpectedly while waiting for an operation result", - )); - } - } - } - } - } -} + let mut child = process + .child + .take() + .context("Node.js operation already finished")?; -impl Write for NodeJsOperation { - fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { - let child = self.expect_child_mut(); - child.write(buf) - } + child.start_kill()?; + let status = child.wait().await?; - fn flush(&mut self) -> std::io::Result<()> { - let child = self.expect_child_mut(); - child.flush() + Ok(status) } } impl Drop for NodeJsOperation { fn drop(&mut self) { - let child = self.take_child(); - self.processes.lock().unwrap().push(child); + if let Some(process) = self.process.take() { + self.processes + .lock() + .unwrap() + .push(NodeJsPoolProcess::Running(process)); + } } } diff --git a/packages/next-swc/crates/next-core/src/source_map/trace.rs b/packages/next-swc/crates/next-core/src/source_map/trace.rs index c036c6bdf14190..f94cbfa75ba84d 100644 --- a/packages/next-swc/crates/next-core/src/source_map/trace.rs +++ b/packages/next-swc/crates/next-core/src/source_map/trace.rs @@ -167,7 +167,7 @@ impl SourceMapTraceVc { /// of a .map file, which means we're serializing all of the individual /// sections into a string and concatenating, taking that and /// deserializing into a DecodedMap, and then querying it. Besides being a - /// memory hog, it'd be so much faster if we could just direclty access + /// memory hog, it'd be so much faster if we could just directly access /// the individual sections of the JS file's map without the /// serialization. #[turbo_tasks::function] From 395dbc940227c0492075232416549eab82ab505a Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 25 Oct 2022 07:05:16 +0200 Subject: [PATCH 191/672] improve node.js pool process error handling (vercel/turbo#287) --- packages/next-swc/crates/next-core/src/nodejs/mod.rs | 12 ++++++++---- .../next-swc/crates/next-core/src/nodejs/pool.rs | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index a74f30b2d7f949..c72272795306f0 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -3,7 +3,7 @@ use std::{ fmt::Write as _, }; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, bail, Context, Result}; use futures::{stream::FuturesUnordered, TryStreamExt}; use indexmap::{IndexMap, IndexSet}; use mime::TEXT_HTML_UTF_8; @@ -313,9 +313,13 @@ async fn run_static_operation( operation .send(RenderStaticOutgoingMessage::Headers { data: &data }) - .await?; - - match operation.recv().await? { + .await + .context("sending headers to node.js process")?; + match operation + .recv() + .await + .context("receiving from node.js process")? + { RenderStaticIncomingMessage::Result { result: RenderResult::Simple(body), } => Ok(FileContent::Content(File::from(body).with_content_type(TEXT_HTML_UTF_8)).into()), diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index edad04171ec1d4..58d55e7d85520c 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -254,8 +254,9 @@ impl NodeJsOperation { .take() .context("Node.js operation already finished")?; - child.start_kill()?; - let status = child.wait().await?; + // Ignore error since we are not sure if the process is still alive + let _ = child.start_kill(); + let status = child.wait().await.context("waiting for process end")?; Ok(status) } From ce4a8ed6bb2e74ab3af88737c1f7856a516b95d3 Mon Sep 17 00:00:00 2001 From: LongYinan <lynweklm@gmail.com> Date: Tue, 25 Oct 2022 13:45:08 +0800 Subject: [PATCH 192/672] Fix format check (vercel/turbo#289) --- .../next-swc/crates/next-core/js/src/entry/app-renderer.tsx | 2 +- .../crates/next-core/js/src/entry/server-renderer.tsx | 2 +- packages/next-swc/crates/next-core/js/src/internal/ipc.ts | 4 ++-- packages/next-swc/crates/next-core/src/assets/layout.js | 2 ++ packages/next-swc/crates/next-core/src/assets/layout.tsx | 2 ++ 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index afe5b2219249ce..fd99d5e841b223 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -60,7 +60,7 @@ type IpcOutgoingMessage = { } } - let html = await runOperation(renderData); + const html = await runOperation(renderData); if (html == null) { throw new Error("no html returned"); diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 3c627bc4ea8e18..ac9f559c2a9936 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -46,7 +46,7 @@ type IpcOutgoingMessage = { } } - let html = await runOperation(renderData); + const html = await runOperation(renderData); if (html == null) { throw new Error("no html returned"); diff --git a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts index bb379fa9026877..a42b839bddd578 100644 --- a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts +++ b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts @@ -25,7 +25,7 @@ function createIpc<TIncoming, TOutgoing>( const recvPromiseResolveQueue: Array<(message: TIncoming) => void> = []; function pushPacket(packet: Buffer) { - let recvPromiseResolve = recvPromiseResolveQueue.shift(); + const recvPromiseResolve = recvPromiseResolveQueue.shift(); if (recvPromiseResolve != null) { recvPromiseResolve(JSON.parse(packet.toString("utf8")) as TIncoming); } else { @@ -86,7 +86,7 @@ function createIpc<TIncoming, TOutgoing>( return { async recv() { - let packet = packetQueue.shift(); + const packet = packetQueue.shift(); if (packet != null) { return JSON.parse(packet.toString("utf8")) as TIncoming; } diff --git a/packages/next-swc/crates/next-core/src/assets/layout.js b/packages/next-swc/crates/next-core/src/assets/layout.js index 47a82125a0d062..c915855555958b 100644 --- a/packages/next-swc/crates/next-core/src/assets/layout.js +++ b/packages/next-swc/crates/next-core/src/assets/layout.js @@ -1,3 +1,5 @@ +/* eslint-disable @next/next/no-head-element */ + export default function RootLayout({ children }) { return ( <html> diff --git a/packages/next-swc/crates/next-core/src/assets/layout.tsx b/packages/next-swc/crates/next-core/src/assets/layout.tsx index 3960a29e3c686f..d3737345019476 100644 --- a/packages/next-swc/crates/next-core/src/assets/layout.tsx +++ b/packages/next-swc/crates/next-core/src/assets/layout.tsx @@ -1,3 +1,5 @@ +/* eslint-disable @next/next/no-head-element */ + export default function RootLayout({ children, }: { From 2bc7c102285bcd9b009378fe203cd43b17dc9219 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 25 Oct 2022 08:33:16 +0200 Subject: [PATCH 193/672] use error overlay in app layouts (vercel/turbo#294) --- .../next-swc/crates/next-core/js/src/dev/hot-reloader.tsx | 8 +++----- .../next-swc/crates/next-core/js/src/dev/websocket.ts | 7 ------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx index b93045658feeb6..b9911765412021 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx +++ b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx @@ -4,11 +4,9 @@ import type React from "react"; import { useRouter, usePathname } from "next/dist/client/components/navigation"; import { useEffect } from "react"; import { onUpdate } from "./hmr-client"; +import { ReactDevOverlay } from "./client"; -export default function HotReload({ - assetPrefix, - children, -}: React.PropsWithChildren<{ assetPrefix: string }>) { +export default function HotReload({ assetPrefix, children }): any { const router = useRouter(); const path = usePathname().slice(1); useEffect(() => { @@ -27,5 +25,5 @@ export default function HotReload({ ); return unsubscribe; }, [router, path]); - return children; + return <ReactDevOverlay globalOverlay={true}>{children}</ReactDevOverlay>; } diff --git a/packages/next-swc/crates/next-core/js/src/dev/websocket.ts b/packages/next-swc/crates/next-core/js/src/dev/websocket.ts index f65fb55b804013..53cf2eab42a4f9 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/websocket.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/websocket.ts @@ -75,17 +75,10 @@ export function connectHMR(options: HMROptions) { // let timer: NodeJS.Timeout function handleDisconnect() { - // clearInterval(timer) source.close(); setTimeout(init, timeout); } - // timer = setInterval(function() { - // if (Date.now() - lastActivity > timeout) { - // handleDisconnect() - // } - // }, timeout / 2) - const { hostname, port } = location; const protocol = getSocketProtocol(options.assetPrefix || ""); const assetPrefix = options.assetPrefix.replace(/^\/+/, ""); From 50ca47eb8f5c4c7c80506f74c201cc25cdc10bc3 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 25 Oct 2022 09:01:03 +0200 Subject: [PATCH 194/672] fix inconsistent asset writes (vercel/turbo#296) --- packages/next-swc/crates/next-core/src/nodejs/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index c72272795306f0..8892ba2b1eec3b 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -46,6 +46,7 @@ async fn emit( ) -> Result<CompletionVc> { Ok(CompletionsVc::cell( internal_assets(intermediate_asset, intermediate_output_path) + .strongly_consistent() .await? .iter() .map(|a| async { From 9c352406eee646e1b07b401a816e104a4ef4b8e1 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 25 Oct 2022 09:15:51 +0200 Subject: [PATCH 195/672] sort errors by relevance (vercel/turbo#299) --- .../crates/next-core/js/src/dev/hmr-client.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 6342ecae18520d..0296bc024f7290 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -184,11 +184,19 @@ function aggregateUpdates( }; } +const CRITICAL = ["bug", "error", "fatal"]; + +function compareByList(list: any[], a: any, b: any) { + const aI = list.indexOf(a) + 1 || list.length; + const bI = list.indexOf(b) + 1 || list.length; + return aI - bI; +} + function handleIssues(msg: ServerMessage): boolean { let issueToReport = null; for (const issue of msg.issues) { - if (["bug", "error", "fatal"].includes(issue.severity)) { + if (CRITICAL.includes(issue.severity)) { issueToReport = issue; break; } @@ -202,7 +210,23 @@ function handleIssues(msg: ServerMessage): boolean { return issueToReport != null; } +const SEVERITY_ORDER = ["bug", "fatal", "error", "warning", "info", "log"]; +const CATEGORY_ORDER = [ + "parse", + "resolve", + "code generation", + "rendering", + "typescript", + "other", +]; + function handleSocketMessage(msg: ServerMessage) { + msg.issues.sort((a, b) => { + const first = compareByList(SEVERITY_ORDER, a.severity, b.severity); + if (first !== 0) return first; + return compareByList(CATEGORY_ORDER, a.category, b.category); + }); + const hasErrors = handleIssues(msg); const aggregatedMsg = aggregateUpdates(msg, hasErrors); From d80eb2e0a0ba7133f7c8126ce6c97ce2a8ebfa80 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 25 Oct 2022 10:19:03 +0200 Subject: [PATCH 196/672] fix node.js 18.9 (vercel/turbo#302) --- packages/next-swc/crates/next-core/js/src/internal/ipc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts index a42b839bddd578..13a74502275de7 100644 --- a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts +++ b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts @@ -20,7 +20,7 @@ export type Ipc<TIncoming, TOutgoing> = { function createIpc<TIncoming, TOutgoing>( port: number ): Ipc<TIncoming, TOutgoing> { - const socket = net.createConnection(port); + const socket = net.createConnection(port, "127.0.0.1"); const packetQueue: Buffer[] = []; const recvPromiseResolveQueue: Array<(message: TIncoming) => void> = []; From 52da74e39d5be710d02acbdc49b06eaa9dabbbe5 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Wed, 26 Oct 2022 16:22:58 -0700 Subject: [PATCH 197/672] Implement nsObj helper from webpack tests and pass basic import test (vercel/turbo#2385) --- packages/next-swc/crates/next-dev/tests/harness.js | 8 ++++++++ .../webpack/chunks/{__skipped__ => }/import/index.js | 0 .../webpack/chunks/{__skipped__ => }/import/two.js | 0 3 files changed, 8 insertions(+) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{__skipped__ => }/import/index.js (100%) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{__skipped__ => }/import/two.js (100%) diff --git a/packages/next-swc/crates/next-dev/tests/harness.js b/packages/next-swc/crates/next-dev/tests/harness.js index b97f97a06bf3f6..3a764f4ef81032 100644 --- a/packages/next-swc/crates/next-dev/tests/harness.js +++ b/packages/next-swc/crates/next-dev/tests/harness.js @@ -5,3 +5,11 @@ globalThis.__jest__ = jest; globalThis.expect = expect; globalThis.describe = jest.describe; globalThis.it = jest.it; + +// From https://github.com/webpack/webpack/blob/9fcaa243573005d6fdece9a3f8d89a0e8b399613/test/TestCases.template.js#L422 +globalThis.nsObj = function nsObj(obj) { + Object.defineProperty(obj, Symbol.toStringTag, { + value: "Module", + }); + return obj; +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/import/index.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/index.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/import/index.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/import/two.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__skipped__/import/two.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/import/two.js From 8788e1f7d1c69b79f07e124decb2fc2e191abba6 Mon Sep 17 00:00:00 2001 From: JJ Kasper <jj@jjsweb.site> Date: Thu, 27 Oct 2022 15:19:47 -0700 Subject: [PATCH 198/672] Add Next.js require hook (vercel/turbo#2434) This hook is needed to ensure we properly map compiled modules like `styled-jsx` correctly. x-ref: [slack thread](https://vercel.slack.com/archives/CGU8HUTUH/p1666824437456749?thread_ts=1666819473.031139&cid=CGU8HUTUH) --- packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx | 1 + packages/next-swc/crates/next-core/js/src/entry/server-api.tsx | 1 + .../next-swc/crates/next-core/js/src/entry/server-renderer.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index fd99d5e841b223..bc964badf43a90 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -16,6 +16,7 @@ import type { } from "next/dist/build/webpack/plugins/flight-manifest-plugin"; import type { RenderData } from "types/turbopack"; +import 'next/dist/server/initialize-require-hook' import "next/dist/server/node-polyfill-fetch"; import "next/dist/server/node-polyfill-web-streams"; import { RenderOpts, renderToHTMLOrFlight } from "next/dist/server/app-render"; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx index 0252012db15334..f9be98fdb30dfa 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx @@ -5,6 +5,7 @@ import http, { ServerResponse } from "node:http"; import type { AddressInfo, Socket } from "node:net"; import { Buffer } from "node:buffer"; +import 'next/dist/server/initialize-require-hook' import "next/dist/server/node-polyfill-fetch.js"; import * as allExports from "."; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index ac9f559c2a9936..393215c948724c 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -2,6 +2,7 @@ import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; import type { IncomingMessage, ServerResponse } from "node:http"; +import 'next/dist/server/initialize-require-hook' import "@vercel/turbopack-next/internal/shims"; import "next/dist/server/node-polyfill-fetch.js"; import { renderToHTML } from "next/dist/server/render"; From d4cb480fca439a56290ed971e41af61a3e83e350 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Fri, 28 Oct 2022 00:30:30 -0400 Subject: [PATCH 199/672] Source map tracing fixes (vercel/turbo#2402) --- .../crates/next-core/src/nodejs/mod.rs | 66 +++++++++++-------- .../crates/next-core/src/source_map/trace.rs | 21 +++--- 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 8892ba2b1eec3b..e827d31156f0f1 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -1,6 +1,8 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, + ffi::OsStr, fmt::Write as _, + path::PathBuf, }; use anyhow::{anyhow, bail, Context, Result}; @@ -12,8 +14,7 @@ pub use node_entry::{NodeEntry, NodeEntryVc}; pub use node_rendered_source::create_node_rendered_source; use serde::{Deserialize, Serialize}; use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, TryJoinIterExt}; -use turbo_tasks_fs::{DiskFileSystemVc, File, FileContent, FileSystemPathVc}; -use turbopack::ecmascript::EcmascriptModuleAssetVc; +use turbo_tasks_fs::{to_sys_path, File, FileContent, FileSystemPathVc}; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc, AssetsSetVc}, chunk::{ChunkGroupVc, ChunkingContextVc}, @@ -23,7 +24,10 @@ use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{query::Query, BodyVc, HeaderValue, ProxyResult, ProxyResultVc}, }; -use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; +use turbopack_ecmascript::{ + chunk::{source_map::EcmascriptChunkSourceMapAssetVc, EcmascriptChunkPlaceablesVc}, + EcmascriptModuleAssetVc, +}; use self::{ bootstrap::NodeJsBootstrapAsset, @@ -200,9 +204,7 @@ async fn get_renderer_pool( emit(intermediate_asset, intermediate_output_path).await?; - if let Some(fs) = DiskFileSystemVc::resolve_from(intermediate_output_path.fs()).await? { - let disk = fs.await?; - let dir = disk.to_sys_path(intermediate_output_path).await?; + if let Some(dir) = to_sys_path(intermediate_output_path).await? { let entrypoint = dir.join("index.js"); let pool = NodeJsPool::new(dir, entrypoint, HashMap::new(), 4); Ok(pool.cell()) @@ -383,34 +385,40 @@ async fn trace_stack( intermediate_asset: AssetVc, intermediate_output_path: FileSystemPathVc, ) -> Result<String> { - let fs = match DiskFileSystemVc::resolve_from(intermediate_output_path.fs()).await? { - Some(fs) => fs, + let root = match to_sys_path(intermediate_output_path.root()).await? { + Some(r) => r.to_string_lossy().to_string(), _ => bail!("couldn't extract disk fs from path"), - } - .await?; - let root = fs - .to_sys_path(intermediate_output_path.root()) - .await? - .to_string_lossy() - .to_string(); + }; + let map_ext = OsStr::new("map"); let assets = internal_assets(intermediate_asset, intermediate_output_path.root()) .await? .iter() .map(|a| async { - Ok(if *a.path().extension().await? == "map" { - // The path is something like "foo.js.abc123.map - let mut p = fs.to_sys_path(a.path()).await?; - p.set_extension(""); - // The next extension is the hash - debug_assert!(p.extension().is_some()); - debug_assert_ne!(p.extension().unwrap(), "js"); - p.set_extension(""); - let p = p.strip_prefix(&root).unwrap(); - Some((p.to_str().unwrap().to_string(), *a)) - } else { - None - }) + let mut path = match to_sys_path(a.path()).await? { + Some(p) => p, + None => PathBuf::from(&a.path().await?.path), + }; + + if path.extension() != Some(map_ext) { + return Ok(None); + } + + // Strip the .map + path.set_extension(""); + + if EcmascriptChunkSourceMapAssetVc::resolve_from(*a) + .await? + .is_some() + { + // The path was something like "foo.js.abc123.map, and the next extension is the + // hash + debug_assert!(path.extension().is_some()); + debug_assert_ne!(path.extension().unwrap(), "js"); + path.set_extension(""); + }; + let p = path.strip_prefix(&root).unwrap(); + Ok(Some((p.to_str().unwrap().to_string(), *a))) }) .try_join() .await? @@ -442,7 +450,7 @@ async fn trace_stack( SourceMapTraceVc::new(map.content(), line, column, frame.name.clone()); let trace = map_trace.trace().await?; if let TraceResult::Found(f) = &*trace { - write_frame!(f, path)?; + write_frame!(f, f.file)?; continue; } } diff --git a/packages/next-swc/crates/next-core/src/source_map/trace.rs b/packages/next-swc/crates/next-core/src/source_map/trace.rs index f94cbfa75ba84d..f046a84cc73ddb 100644 --- a/packages/next-swc/crates/next-core/src/source_map/trace.rs +++ b/packages/next-swc/crates/next-core/src/source_map/trace.rs @@ -1,7 +1,4 @@ -use std::{ - ops::Deref, - sync::{Arc, Mutex}, -}; +use std::{ops::Deref, sync::Arc}; use anyhow::{bail, Result}; use serde_json::json; @@ -59,6 +56,7 @@ pub enum TraceResult { /// so it's fine. struct DecodedMapWrapper(DecodedMap); unsafe impl Send for DecodedMapWrapper {} +unsafe impl Sync for DecodedMapWrapper {} impl Deref for DecodedMapWrapper { type Target = DecodedMap; @@ -69,9 +67,9 @@ impl Deref for DecodedMapWrapper { /// DecodedSourceMap wraps sourcemap::DecodedMap in a Vc for caching. #[turbo_tasks::value(serialization = "none", eq = "manual")] -struct DecodedSourceMap(#[turbo_tasks(debug_ignore, trace_ignore)] Arc<Mutex<DecodedMapWrapper>>); +struct DecodedSourceMap(#[turbo_tasks(debug_ignore, trace_ignore)] Arc<DecodedMapWrapper>); impl Deref for DecodedSourceMap { - type Target = Arc<Mutex<DecodedMapWrapper>>; + type Target = Arc<DecodedMapWrapper>; fn deref(&self) -> &Self::Target { &self.0 @@ -93,7 +91,7 @@ impl DecodedSourceMapVc { _ => bail!("could not decode source map"), }; - Ok(DecodedSourceMap(Arc::new(Mutex::new(DecodedMapWrapper(sm)))).cell()) + Ok(DecodedSourceMap(Arc::new(DecodedMapWrapper(sm))).cell()) } } @@ -141,7 +139,11 @@ fn sectioned_lookup(map: &DecodedMap, line: u32, column: u32) -> Option<Token> { } None } else if let DecodedMap::Regular(sm) = map { - sm.lookup_token(line, column) + match sm.lookup_token(line, column) { + // The sourcemap package incorrectly returns the last token for large lookup lines. + Some(t) if t.get_dst_line() == line => Some(t), + _ => None, + } } else { unimplemented!("we should only be using the standard source map types"); } @@ -180,8 +182,7 @@ impl SourceMapTraceVc { }; let decoded_map = DecodedSourceMapVc::from(*content).await?; - let sm = decoded_map.lock().unwrap(); - let trace = match sectioned_lookup(&sm, this.line.saturating_sub(1), this.column) { + let trace = match sectioned_lookup(&decoded_map, this.line.saturating_sub(1), this.column) { Some(t) if t.has_source() => t, _ => return Ok(TraceResult::NotFound.cell()), }; From 201259af9451433c01cb5c63c3d1e44a72de7af6 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Thu, 27 Oct 2022 21:35:30 -0700 Subject: [PATCH 200/672] More forgiving timeout when waiting for Node.js to connect (vercel/turbo#2417) * More forgiving timeout when waiting for Node.js to connect * 10ms -> 30s --- .../next-swc/crates/next-core/src/nodejs/pool.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index 58d55e7d85520c..4316ead5deca30 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -52,7 +52,7 @@ impl Drop for RunningNodeJsPoolProcess { } } -const CONNECT_TIMEOUT: Duration = Duration::from_secs(1); +const CONNECT_TIMEOUT: Duration = Duration::from_secs(30); impl NodeJsPoolProcess { async fn new(cwd: &Path, env: &HashMap<String, String>, entrypoint: &Path) -> Result<Self> { @@ -92,7 +92,17 @@ impl NodeJsPoolProcess { NodeJsPoolProcess::Spawned(mut spawned) => { let (connection, _) = select! { connection = spawned.listener.accept() => connection.context("accepting connection")?, - _ = sleep(CONNECT_TIMEOUT) => bail!("timed out waiting for the Node.js process to connect"), + status = spawned.child.as_mut().unwrap().wait() => { + match status { + Ok(status) => { + bail!("node process exited before we could connect to it with {}", status); + } + Err(err) => { + bail!("node process exited before we could connect to it: {:?}", err); + }, + } + }, + _ = sleep(CONNECT_TIMEOUT) => bail!("timed out waiting for the Node.js process to connect ({:?} timeout)", CONNECT_TIMEOUT), }; RunningNodeJsPoolProcess { From eca1e994f1edd04a9312132feefcd9f3ce0b2f44 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Thu, 27 Oct 2022 21:39:33 -0700 Subject: [PATCH 201/672] Update Next.js dependency for the TP benchmark (vercel/turbo#2435) --- packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index 6e5f2360f1f777..4f241016f37d3a 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -47,7 +47,7 @@ impl Bundler for Turbopack { npm::install( install_dir, &[ - NpmPackage::new("next", "12.3.2-canary.33"), + NpmPackage::new("next", "13.0.0"), // Dependency on this is inserted by swc's preset_env NpmPackage::new("@swc/helpers", "^0.4.11"), ], From 2e4f40ae31b7fb165b5c563315375489132e5369 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Fri, 28 Oct 2022 06:39:56 +0200 Subject: [PATCH 202/672] prettier fixes (vercel/turbo#2436) --- .../next-swc/crates/next-core/js/src/entry/app-renderer.tsx | 2 +- packages/next-swc/crates/next-core/js/src/entry/server-api.tsx | 2 +- .../next-swc/crates/next-core/js/src/entry/server-renderer.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index bc964badf43a90..6d5b7c4422016c 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -16,7 +16,7 @@ import type { } from "next/dist/build/webpack/plugins/flight-manifest-plugin"; import type { RenderData } from "types/turbopack"; -import 'next/dist/server/initialize-require-hook' +import "next/dist/server/initialize-require-hook"; import "next/dist/server/node-polyfill-fetch"; import "next/dist/server/node-polyfill-web-streams"; import { RenderOpts, renderToHTMLOrFlight } from "next/dist/server/app-render"; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx index f9be98fdb30dfa..372b566a267177 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx @@ -5,7 +5,7 @@ import http, { ServerResponse } from "node:http"; import type { AddressInfo, Socket } from "node:net"; import { Buffer } from "node:buffer"; -import 'next/dist/server/initialize-require-hook' +import "next/dist/server/initialize-require-hook"; import "next/dist/server/node-polyfill-fetch.js"; import * as allExports from "."; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 393215c948724c..6fb4fabcf2106f 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -2,7 +2,7 @@ import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; import type { IncomingMessage, ServerResponse } from "node:http"; -import 'next/dist/server/initialize-require-hook' +import "next/dist/server/initialize-require-hook"; import "@vercel/turbopack-next/internal/shims"; import "next/dist/server/node-polyfill-fetch.js"; import { renderToHTML } from "next/dist/server/render"; From b12e0d8f4689081095eae8df2826f69bc27de2e7 Mon Sep 17 00:00:00 2001 From: Allan <al@ayz.ai> Date: Fri, 28 Oct 2022 01:40:49 -0400 Subject: [PATCH 203/672] Fix unnecessary question mark warnings (vercel/turbo#2443) * Fix unused question marks warnings Fix some return types that were giving clippy warnings, mostly `needless_question_mark`. Remaining warnings are either `too_many_arguments` or `type_complexity`. * Fix unncessary let binding Co-authored-by: Justin Ridgewell <justin@ridgewell.name> --- .../crates/next-core/src/nodejs/mod.rs | 19 ++++++------- .../crates/next-core/src/nodejs/pool.rs | 27 +++++++++---------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index e827d31156f0f1..cc9baf8884682c 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -288,9 +288,7 @@ async fn render_static( let pool = renderer_pool.strongly_consistent().await?; let mut operation = match pool.operation().await { Ok(operation) => operation, - Err(err) => { - return Ok(static_error(path, err, None, fallback_page).await?); - } + Err(err) => return static_error(path, err, None, fallback_page).await, }; match run_static_operation( @@ -302,7 +300,7 @@ async fn render_static( .await { Ok(asset) => Ok(asset), - Err(err) => Ok(static_error(path, err, Some(operation), fallback_page).await?), + Err(err) => static_error(path, err, Some(operation), fallback_page).await, } } @@ -351,10 +349,9 @@ async fn static_error( None => None, }; - let html_status = if let Some(status) = status { - format!("<h2>Exit status</h2><pre>{status}</pre>") - } else { - format!("<h3>No exit status</pre>") + let html_status = match status { + Some(status) => format!("<h2>Exit status</h2><pre>{status}</pre>"), + None => "<h3>No exit status</pre>".to_owned(), }; let body = format!( @@ -387,7 +384,7 @@ async fn trace_stack( ) -> Result<String> { let root = match to_sys_path(intermediate_output_path.root()).await? { Some(r) => r.to_string_lossy().to_string(), - _ => bail!("couldn't extract disk fs from path"), + None => bail!("couldn't extract disk fs from path"), }; let map_ext = OsStr::new("map"); @@ -517,7 +514,7 @@ async fn render_proxy( let mut operation = match pool.operation().await { Ok(operation) => operation, Err(err) => { - return Ok(proxy_error(path, err, None).await?); + return proxy_error(path, err, None).await; } }; @@ -545,7 +542,7 @@ async fn run_proxy_operation( let data = data.await?; // First, send the render data. operation - .send(RenderProxyOutgoingMessage::Headers { data: &*data }) + .send(RenderProxyOutgoingMessage::Headers { data: &data }) .await?; let body = body.await?; diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs index 4316ead5deca30..9a07cfe9cfbf23 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/pool.rs @@ -188,19 +188,20 @@ impl NodeJsPool { async fn acquire_process(&self) -> Result<(NodeJsPoolProcess, OwnedSemaphorePermit)> { let permit = self.semaphore.clone().acquire_owned().await?; + let popped = { let mut processes = self.processes.lock().unwrap(); processes.pop() }; - Ok(if let Some(process) = popped { - (process, permit) - } else { - let process = + let process = match popped { + Some(process) => process, + None => { NodeJsPoolProcess::new(self.cwd.as_path(), &self.env, self.entrypoint.as_path()) .await - .context("creating new process")?; - (process, permit) - }) + .context("creating new process")? + } + }; + Ok((process, permit)) } pub(super) async fn operation(&self) -> Result<NodeJsOperation> { @@ -224,10 +225,9 @@ pub struct NodeJsOperation { impl NodeJsOperation { fn process_mut(&mut self) -> Result<&mut RunningNodeJsPoolProcess> { - Ok(self - .process + self.process .as_mut() - .context("Node.js operation already finished")?) + .context("Node.js operation already finished") } pub(super) async fn recv<M>(&mut self) -> Result<M> @@ -239,18 +239,17 @@ impl NodeJsOperation { .recv() .await .context("receiving message")?; - Ok(serde_json::from_slice(&message).context("deserializing message")?) + serde_json::from_slice(&message).context("deserializing message") } pub(super) async fn send<M>(&mut self, message: M) -> Result<()> where M: Serialize, { - Ok(self - .process_mut()? + self.process_mut()? .send(serde_json::to_vec(&message).context("serializing message")?) .await - .context("sending message")?) + .context("sending message") } pub(super) async fn wait_or_kill(mut self) -> Result<ExitStatus> { From 0d12445d6a94b34d7f94a7c3ab21c662841ff6c7 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Fri, 28 Oct 2022 08:28:04 -0700 Subject: [PATCH 204/672] refactor(next/dev): allow devserver args serializable (vercel/turbo#2446) --- packages/next-swc/crates/next-dev/Cargo.toml | 5 +- packages/next-swc/crates/next-dev/src/main.rs | 71 +++++++++++++++---- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index a6d1a75d1b6c87..cf9e23b3591405 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -19,6 +19,9 @@ name = "mod" harness = false [features] +default = ["cli"] +cli = [] +serializable = [] tokio_console = [ "dep:console-subscriber", "tokio/tracing", @@ -59,7 +62,7 @@ regex = "1.6.0" tempfile = "3.3.0" test-generator = "0.3.0" # sync with chromiumoxide's tungstenite requirement. -tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in +tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in turbopack-create-test-app = { path = "../turbopack-create-test-app" } [target.'cfg(unix)'.dev-dependencies] diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 1b15cc8503efb4..5c5f0ee4dec8a0 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -18,51 +18,96 @@ use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::IssueSeverityCliOption; use turbopack_core::issue::IssueSeverity; -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -struct Cli { +#[derive(Debug)] +#[cfg_attr(feature = "cli", derive(Parser))] +#[cfg_attr(feature = "cli", clap(author, version, about, long_about = None))] +#[cfg_attr(feature = "serializable", derive(serde::Deserialize))] +#[cfg_attr(feature = "serializable", serde(rename_all = "camelCase"))] +pub struct DevServerOptions { /// The directory of the Next.js application. /// If no directory is provided, the current directory will be used. - #[clap(value_parser)] + #[cfg_attr(feature = "cli", clap(value_parser))] + #[cfg_attr(feature = "serializable", serde(default))] dir: Option<PathBuf>, /// The root directory of the project. Nothing outside of this directory can /// be accessed. e. g. the monorepo root. /// If no directory is provided, `dir` will be used. - #[clap(long, value_parser)] + #[cfg_attr(feature = "cli", clap(long, value_parser))] + #[cfg_attr(feature = "serializable", serde(default))] root: Option<PathBuf>, /// The port number on which to start the application - #[clap(short, long, value_parser, default_value_t = 3000)] + #[cfg_attr( + feature = "cli", + clap(short, long, value_parser, default_value_t = 3000) + )] + #[cfg_attr(feature = "serializable", serde(default = "default_port"))] port: u16, /// Hostname on which to start the application - #[clap(short = 'H', long, value_parser, default_value = "0.0.0.0")] + #[cfg_attr( + feature = "cli", + clap(short = 'H', long, value_parser, default_value = "0.0.0.0") + )] + #[cfg_attr(feature = "serializable", serde(default = "default_host"))] hostname: IpAddr, /// Compile all, instead of only compiling referenced assets when their /// parent asset is requested - #[clap(long)] + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] eager_compile: bool, /// Don't open the browser automatically when the dev server has started. - #[clap(long)] + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] no_open: bool, - #[clap(short, long)] + #[cfg_attr(feature = "cli", clap(short, long))] + #[cfg_attr(feature = "serializable", serde(default))] /// Filter by issue severity. log_level: Option<IssueSeverityCliOption>, - #[clap(long)] + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] /// Show all log messages without limit. show_all: bool, - #[clap(long)] + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] /// Expand the log details. log_detail: bool, + + // Inherited options from next-dev, need revisit later. + // This is not supported by CLI yet. + #[cfg_attr(feature = "serializable", serde(default))] + allow_retry: bool, + #[cfg_attr(feature = "serializable", serde(default))] + dev: bool, + #[cfg_attr(feature = "serializable", serde(default))] + is_next_dev_command: bool, + #[cfg_attr(feature = "serializable", serde(default))] + server_components_external_packages: Vec<String>, +} + +#[cfg(feature = "serializable")] +fn default_port() -> u16 { + 3000 +} + +#[cfg(feature = "serializable")] +fn default_host() -> IpAddr { + IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)) +} + +#[cfg(not(feature = "cli"))] +fn main() -> Result<()> { + unimplemented!("Cannot run binary without CLI feature enabled"); } #[tokio::main] +#[cfg(feature = "cli")] async fn main() -> Result<()> { let start = Instant::now(); @@ -70,7 +115,7 @@ async fn main() -> Result<()> { console_subscriber::init(); register(); - let args = Cli::parse(); + let args = DevServerOptions::parse(); let dir = args .dir From f2d661c0bb53a003abcd8c7485b01cee3356e0bf Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Fri, 28 Oct 2022 08:53:13 -0700 Subject: [PATCH 205/672] Fix large regression with turning ModuleRuleCondition::matches into a tt::fun (vercel/turbo#2450) * Fix large regression with turning ModuleRuleConditionVc::matches into a tt::fun * Remove Vcs from ModuleRule altogether --- .../next-core/src/next_client/context.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 2ec59af0d37ebe..21b7a7b286e46b 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -8,7 +8,7 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ module_options::{ module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, - ModuleRuleCondition, ModuleRuleEffect, ModuleRuleVc, + ModuleRule, ModuleRuleCondition, ModuleRuleEffect, }, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, transition::TransitionsByNameVc, @@ -116,23 +116,19 @@ pub async fn add_next_transforms_to_pages( ) -> Result<ModuleOptionsContextVc> { let mut module_options_context = module_options_context.await?.clone_value(); // Apply the Next SSG tranform to all pages. - module_options_context.custom_rules.push(ModuleRuleVc::new( + module_options_context.custom_rules.push(ModuleRule::new( ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathInExactDirectory(pages_dir), + ModuleRuleCondition::ResourcePathInExactDirectory(pages_dir.await?), ModuleRuleCondition::any(vec![ ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), ]), - ]) - .cell(), - vec![ - ModuleRuleEffect::AddEcmascriptTransforms(EcmascriptInputTransformsVc::cell(vec![ - EcmascriptInputTransform::NextJs, - ])) - .cell(), - ], + ]), + vec![ModuleRuleEffect::AddEcmascriptTransforms( + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJs]), + )], )); Ok(module_options_context.cell()) } From 5f005093215410222604f78a907ea5adfa4ee2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E8=B1=AA?= <504595380@qq.com> Date: Fri, 28 Oct 2022 23:59:21 +0800 Subject: [PATCH 206/672] chore: typo (vercel/turbo#2404) * chore: typo * Remove hot_module_replacement from snapshot tests Re: vercel/turbo#2351 Co-authored-by: Justin Ridgewell <justin@ridgewell.name> --- packages/next-swc/crates/next-core/src/next_client/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 21b7a7b286e46b..a966582932950e 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -171,7 +171,7 @@ pub fn get_client_chunking_context( }, get_client_assets_path(server_root, ty), ) - .hot_module_replacment() + .hot_module_replacement() .build() } From 2af748edd45b330ab1300866ddf32fa6a5f7102e Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Fri, 28 Oct 2022 09:41:46 -0700 Subject: [PATCH 207/672] refactor(next/dev): reusable start_server (vercel/turbo#2455) --- .../crates/next-dev/src/devserver_options.rs | 88 +++++++++ packages/next-swc/crates/next-dev/src/lib.rs | 108 +++++++++- packages/next-swc/crates/next-dev/src/main.rs | 185 +----------------- 3 files changed, 198 insertions(+), 183 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/src/devserver_options.rs diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs new file mode 100644 index 00000000000000..0d6de3c9d6a47f --- /dev/null +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -0,0 +1,88 @@ +use std::{net::IpAddr, path::PathBuf}; + +#[cfg(feature = "cli")] +use clap::Parser; +use turbopack_cli_utils::issue::IssueSeverityCliOption; + +#[derive(Debug)] +#[cfg_attr(feature = "cli", derive(Parser))] +#[cfg_attr(feature = "cli", clap(author, version, about, long_about = None))] +#[cfg_attr(feature = "serializable", derive(serde::Deserialize))] +#[cfg_attr(feature = "serializable", serde(rename_all = "camelCase"))] +pub struct DevServerOptions { + /// The directory of the Next.js application. + /// If no directory is provided, the current directory will be used. + #[cfg_attr(feature = "cli", clap(value_parser))] + #[cfg_attr(feature = "serializable", serde(default))] + pub dir: Option<PathBuf>, + + /// The root directory of the project. Nothing outside of this directory can + /// be accessed. e. g. the monorepo root. + /// If no directory is provided, `dir` will be used. + #[cfg_attr(feature = "cli", clap(long, value_parser))] + #[cfg_attr(feature = "serializable", serde(default))] + pub root: Option<PathBuf>, + + /// The port number on which to start the application + #[cfg_attr( + feature = "cli", + clap(short, long, value_parser, default_value_t = 3000) + )] + #[cfg_attr(feature = "serializable", serde(default = "default_port"))] + pub port: u16, + + /// Hostname on which to start the application + #[cfg_attr( + feature = "cli", + clap(short = 'H', long, value_parser, default_value = "0.0.0.0") + )] + #[cfg_attr(feature = "serializable", serde(default = "default_host"))] + pub hostname: IpAddr, + + /// Compile all, instead of only compiling referenced assets when their + /// parent asset is requested + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] + pub eager_compile: bool, + + /// Don't open the browser automatically when the dev server has started. + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] + pub no_open: bool, + + #[cfg_attr(feature = "cli", clap(short, long))] + #[cfg_attr(feature = "serializable", serde(default))] + /// Filter by issue severity. + pub log_level: Option<IssueSeverityCliOption>, + + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] + /// Show all log messages without limit. + pub show_all: bool, + + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] + /// Expand the log details. + pub log_detail: bool, + + // Inherited options from next-dev, need revisit later. + // This is not supported by CLI yet. + #[cfg_attr(feature = "serializable", serde(default))] + pub allow_retry: bool, + #[cfg_attr(feature = "serializable", serde(default))] + pub dev: bool, + #[cfg_attr(feature = "serializable", serde(default))] + pub is_next_dev_command: bool, + #[cfg_attr(feature = "serializable", serde(default))] + pub server_components_external_packages: Vec<String>, +} + +#[cfg(feature = "serializable")] +fn default_port() -> u16 { + 3000 +} + +#[cfg(feature = "serializable")] +fn default_host() -> IpAddr { + IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)) +} diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index f727dfe22a0aad..fd64f2d9176a4b 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -1,17 +1,29 @@ #![feature(future_join)] #![feature(min_specialization)] +pub mod devserver_options; mod turbo_tasks_viz; -use std::{collections::HashSet, env::current_dir, net::IpAddr, path::MAIN_SEPARATOR, sync::Arc}; +use std::{ + collections::HashSet, + env::current_dir, + future::join, + net::IpAddr, + path::MAIN_SEPARATOR, + sync::Arc, + time::{Duration, Instant}, +}; use anyhow::{anyhow, Context, Result}; +use devserver_options::DevServerOptions; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, source_map::NextSourceMapTraceContentSourceVc, }; +use owo_colors::OwoColorize; use turbo_tasks::{ - primitives::StringsVc, RawVc, TransientInstance, TransientValue, TurboTasks, Value, + primitives::StringsVc, util::FormatDuration, RawVc, TransientInstance, TransientValue, + TurboTasks, Value, }; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; @@ -280,3 +292,95 @@ pub fn register() { next_core::register(); include!(concat!(env!("OUT_DIR"), "/register.rs")); } + +/// Start a devserver with the given options. +pub async fn start_server(options: &DevServerOptions) -> Result<()> { + let start = Instant::now(); + + #[cfg(feature = "tokio_console")] + console_subscriber::init(); + register(); + + let dir = options + .dir + .as_ref() + .map(|dir| dir.canonicalize()) + .unwrap_or_else(current_dir) + .context("project directory can't be found")? + .to_str() + .context("project directory contains invalid characters")? + .to_string(); + + let root_dir = if let Some(root) = options.root.as_ref() { + root.canonicalize() + .context("root directory can't be found")? + .to_str() + .context("root directory contains invalid characters")? + .to_string() + } else { + dir.clone() + }; + + let tt = TurboTasks::new(MemoryBackend::new()); + let tt_clone = tt.clone(); + + let mut server = NextDevServerBuilder::new(tt, dir, root_dir) + .entry_request("src/index".into()) + .eager_compile(options.eager_compile) + .hostname(options.hostname) + .port(options.port) + .log_detail(options.log_detail) + .show_all(options.show_all) + .log_level( + options + .log_level + .map_or_else(|| IssueSeverity::Warning, |l| l.0), + ); + + for package in options.server_components_external_packages.iter() { + server = server.server_component_external(package.to_string()); + } + + let server = server.build().await?; + + { + let index_uri = if server.addr.ip().is_loopback() || server.addr.ip().is_unspecified() { + format!("http://localhost:{}", server.addr.port()) + } else { + format!("http://{}", server.addr) + }; + println!( + "{} - started server on {}:{}, url: {}", + "ready".green(), + server.addr.ip(), + server.addr.port(), + index_uri + ); + if !options.no_open { + let _ = webbrowser::open(&index_uri); + } + } + + let stats_future = async move { + println!( + "{event_type} - initial compilation {start}", + event_type = "event".purple(), + start = FormatDuration(start.elapsed()), + ); + + loop { + let (elapsed, _count) = tt_clone + .get_or_wait_update_info(Duration::from_millis(100)) + .await; + println!( + "{event_type} - updated in {elapsed}", + event_type = "event".purple(), + elapsed = FormatDuration(elapsed), + ); + } + }; + + join!(stats_future, async { server.future.await.unwrap() }).await; + + Ok(()) +} diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 5c5f0ee4dec8a0..6ce46a61bb8e2d 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -1,105 +1,9 @@ #![feature(future_join)] #![feature(min_specialization)] -use std::{ - env::current_dir, - future::join, - net::IpAddr, - path::PathBuf, - time::{Duration, Instant}, -}; - -use anyhow::{Context, Result}; +use anyhow::Result; +#[cfg(feature = "cli")] use clap::Parser; -use next_dev::{register, NextDevServerBuilder}; -use owo_colors::OwoColorize; -use turbo_tasks::{util::FormatDuration, TurboTasks}; -use turbo_tasks_memory::MemoryBackend; -use turbopack_cli_utils::issue::IssueSeverityCliOption; -use turbopack_core::issue::IssueSeverity; - -#[derive(Debug)] -#[cfg_attr(feature = "cli", derive(Parser))] -#[cfg_attr(feature = "cli", clap(author, version, about, long_about = None))] -#[cfg_attr(feature = "serializable", derive(serde::Deserialize))] -#[cfg_attr(feature = "serializable", serde(rename_all = "camelCase"))] -pub struct DevServerOptions { - /// The directory of the Next.js application. - /// If no directory is provided, the current directory will be used. - #[cfg_attr(feature = "cli", clap(value_parser))] - #[cfg_attr(feature = "serializable", serde(default))] - dir: Option<PathBuf>, - - /// The root directory of the project. Nothing outside of this directory can - /// be accessed. e. g. the monorepo root. - /// If no directory is provided, `dir` will be used. - #[cfg_attr(feature = "cli", clap(long, value_parser))] - #[cfg_attr(feature = "serializable", serde(default))] - root: Option<PathBuf>, - - /// The port number on which to start the application - #[cfg_attr( - feature = "cli", - clap(short, long, value_parser, default_value_t = 3000) - )] - #[cfg_attr(feature = "serializable", serde(default = "default_port"))] - port: u16, - - /// Hostname on which to start the application - #[cfg_attr( - feature = "cli", - clap(short = 'H', long, value_parser, default_value = "0.0.0.0") - )] - #[cfg_attr(feature = "serializable", serde(default = "default_host"))] - hostname: IpAddr, - - /// Compile all, instead of only compiling referenced assets when their - /// parent asset is requested - #[cfg_attr(feature = "cli", clap(long))] - #[cfg_attr(feature = "serializable", serde(default))] - eager_compile: bool, - - /// Don't open the browser automatically when the dev server has started. - #[cfg_attr(feature = "cli", clap(long))] - #[cfg_attr(feature = "serializable", serde(default))] - no_open: bool, - - #[cfg_attr(feature = "cli", clap(short, long))] - #[cfg_attr(feature = "serializable", serde(default))] - /// Filter by issue severity. - log_level: Option<IssueSeverityCliOption>, - - #[cfg_attr(feature = "cli", clap(long))] - #[cfg_attr(feature = "serializable", serde(default))] - /// Show all log messages without limit. - show_all: bool, - - #[cfg_attr(feature = "cli", clap(long))] - #[cfg_attr(feature = "serializable", serde(default))] - /// Expand the log details. - log_detail: bool, - - // Inherited options from next-dev, need revisit later. - // This is not supported by CLI yet. - #[cfg_attr(feature = "serializable", serde(default))] - allow_retry: bool, - #[cfg_attr(feature = "serializable", serde(default))] - dev: bool, - #[cfg_attr(feature = "serializable", serde(default))] - is_next_dev_command: bool, - #[cfg_attr(feature = "serializable", serde(default))] - server_components_external_packages: Vec<String>, -} - -#[cfg(feature = "serializable")] -fn default_port() -> u16 { - 3000 -} - -#[cfg(feature = "serializable")] -fn default_host() -> IpAddr { - IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)) -} #[cfg(not(feature = "cli"))] fn main() -> Result<()> { @@ -109,88 +13,7 @@ fn main() -> Result<()> { #[tokio::main] #[cfg(feature = "cli")] async fn main() -> Result<()> { - let start = Instant::now(); - - #[cfg(feature = "tokio_console")] - console_subscriber::init(); - register(); - - let args = DevServerOptions::parse(); - - let dir = args - .dir - .map(|dir| dir.canonicalize()) - .unwrap_or_else(current_dir) - .context("project directory can't be found")? - .to_str() - .context("project directory contains invalid characters")? - .to_string(); - - let root_dir = if let Some(root) = args.root { - root.canonicalize() - .context("root directory can't be found")? - .to_str() - .context("root directory contains invalid characters")? - .to_string() - } else { - dir.clone() - }; - - let tt = TurboTasks::new(MemoryBackend::new()); - let tt_clone = tt.clone(); - - let server = NextDevServerBuilder::new(tt, dir, root_dir) - .entry_request("src/index".into()) - .eager_compile(args.eager_compile) - .hostname(args.hostname) - .port(args.port) - .log_detail(args.log_detail) - .show_all(args.show_all) - .log_level( - args.log_level - .map_or_else(|| IssueSeverity::Warning, |l| l.0), - ) - .build() - .await?; - - { - let index_uri = if server.addr.ip().is_loopback() || server.addr.ip().is_unspecified() { - format!("http://localhost:{}", server.addr.port()) - } else { - format!("http://{}", server.addr) - }; - println!( - "{} - started server on {}:{}, url: {}", - "ready".green(), - server.addr.ip(), - server.addr.port(), - index_uri - ); - if !args.no_open { - let _ = webbrowser::open(&index_uri); - } - } - - let stats_future = async move { - println!( - "{event_type} - initial compilation {start}", - event_type = "event".purple(), - start = FormatDuration(start.elapsed()), - ); - - loop { - let (elapsed, _count) = tt_clone - .get_or_wait_update_info(Duration::from_millis(100)) - .await; - println!( - "{event_type} - updated in {elapsed}", - event_type = "event".purple(), - elapsed = FormatDuration(elapsed), - ); - } - }; - - join!(stats_future, async { server.future.await.unwrap() }).await; + let options = next_dev::devserver_options::DevServerOptions::parse(); - Ok(()) + next_dev::start_server(&options).await } From 69d98a5bdefe62db9b6317126d6f2816c3067c77 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Fri, 28 Oct 2022 20:56:40 +0200 Subject: [PATCH 208/672] make sure to exit the process in case of errors during errors sending (vercel/turbo#2457) --- .../next-swc/crates/next-core/js/src/internal/ipc.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts index 13a74502275de7..4914d0b2be617f 100644 --- a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts +++ b/packages/next-swc/crates/next-core/js/src/internal/ipc.ts @@ -105,10 +105,14 @@ function createIpc<TIncoming, TOutgoing>( }, async sendError(error: Error): Promise<never> { - await send({ - type: "error", - ...structuredError(error), - }); + try { + await send({ + type: "error", + ...structuredError(error), + }); + } catch (err) { + // ignore and exit anyway + } process.exit(1); }, }; From f9fb452b32b7a49546c2b33a31053ca10cd97108 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Fri, 28 Oct 2022 21:56:33 +0200 Subject: [PATCH 209/672] improve startup and warmup of benchmarks (vercel/turbo#2463) --- .../next-swc/crates/next-dev/benches/mod.rs | 36 ++++++++++++++----- .../crates/next-dev/benches/util/mod.rs | 24 ++++++++++--- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 588b71bbdde454..f677dcf59ae20e 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -71,6 +71,7 @@ fn bench_startup_internal(mut g: BenchmarkGroup<WallTime>, hydration: bool) { || async { PreparedApp::new(bundler, test_app.path().to_path_buf()).await }, + |app| async { Ok(app) }, |mut app| async { app.start_server()?; let mut guard = app.with_page(browser).await?; @@ -211,16 +212,29 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { .evaluate_expression("globalThis.HMR_IS_HAPPENING = true") .await?; - // Make warmup change - for i in (0..MAX_UPDATE_TIMEOUT.as_secs() / 5).rev() { - match make_change(&mut guard, location, Duration::from_secs(5)) - .await - { - Ok(_) => break, + Ok(guard) + }, + |mut guard| async { + // Make 5 warmup changes + let mut last_error = Some(anyhow!("not run yet")); + let mut timeout = Duration::from_secs(1); + let mut remaining = 5; + while timeout < MAX_UPDATE_TIMEOUT * 2 { + match make_change(&mut guard, location, timeout).await { + Ok(_) => { + // Wait a second to allow background work to complete. + sleep(Duration::from_secs(1)).await; + last_error = None; + remaining -= 1; + if remaining == 0 { + break; + } + continue; + } Err(err) => { - if i != 0 - && err.to_string().contains(CHANGE_TIMEOUT_MESSAGE) - { + if err.to_string().contains(CHANGE_TIMEOUT_MESSAGE) { + last_error = Some(err); + timeout *= 2; continue; } return Err(err); @@ -228,6 +242,9 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { } } + if let Some(err) = last_error { + return Err(err); + } Ok(guard) }, |mut guard| async move { @@ -322,6 +339,7 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo app.stop_server()?; Ok(app) }, + |app| async { Ok(app) }, |mut app| async { app.start_server()?; let mut guard = app.with_page(browser).await?; diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index 6845915af7a2a2..a20bd0b2531db4 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -166,10 +166,17 @@ pub fn resume_on_error<F: FnOnce() + UnwindSafe>(f: F) { } pub trait AsyncBencherExtension { - fn try_iter_async<I, O, S, SF, R, F, T, TF>(&mut self, setup: S, routine: R, teardown: T) - where + fn try_iter_async<I, O, S, SF, W, WF, R, F, T, TF>( + &mut self, + setup: S, + warmup: W, + routine: R, + teardown: T, + ) where S: Fn() -> SF, SF: Future<Output = Result<I>>, + W: Fn(I) -> WF, + WF: Future<Output = Result<I>>, R: Fn(I) -> F, F: Future<Output = Result<O>>, T: Fn(O) -> TF, @@ -178,10 +185,17 @@ pub trait AsyncBencherExtension { impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, WallTime> { #[inline(never)] - fn try_iter_async<I, O, S, SF, R, F, T, TF>(&mut self, setup: S, routine: R, teardown: T) - where + fn try_iter_async<I, O, S, SF, W, WF, R, F, T, TF>( + &mut self, + setup: S, + warmup: W, + routine: R, + teardown: T, + ) where S: Fn() -> SF, SF: Future<Output = Result<I>>, + W: Fn(I) -> WF, + WF: Future<Output = Result<I>>, R: Fn(I) -> F, F: Future<Output = Result<O>>, T: Fn(O) -> TF, @@ -194,6 +208,7 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, ); let setup = &setup; + let warmup = &warmup; let routine = &routine; let teardown = &teardown; self.iter_custom(|iters| async move { @@ -210,6 +225,7 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, .await .expect("failed to setup"), ); + let input = black_box(warmup(input).await).expect("failed to warmup"); let start = early_start.unwrap_or_else(|| measurement.start()); match routine(input).await { From befc272a8cd0746636bdb0afc22779136c1f7953 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Sat, 29 Oct 2022 00:24:25 +0200 Subject: [PATCH 210/672] remove require hook (vercel/turbo#2473) --- packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx | 1 - packages/next-swc/crates/next-core/js/src/entry/server-api.tsx | 1 - .../next-swc/crates/next-core/js/src/entry/server-renderer.tsx | 1 - 3 files changed, 3 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 6d5b7c4422016c..fd99d5e841b223 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -16,7 +16,6 @@ import type { } from "next/dist/build/webpack/plugins/flight-manifest-plugin"; import type { RenderData } from "types/turbopack"; -import "next/dist/server/initialize-require-hook"; import "next/dist/server/node-polyfill-fetch"; import "next/dist/server/node-polyfill-web-streams"; import { RenderOpts, renderToHTMLOrFlight } from "next/dist/server/app-render"; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx index 372b566a267177..0252012db15334 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx @@ -5,7 +5,6 @@ import http, { ServerResponse } from "node:http"; import type { AddressInfo, Socket } from "node:net"; import { Buffer } from "node:buffer"; -import "next/dist/server/initialize-require-hook"; import "next/dist/server/node-polyfill-fetch.js"; import * as allExports from "."; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 6fb4fabcf2106f..ac9f559c2a9936 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -2,7 +2,6 @@ import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; import type { IncomingMessage, ServerResponse } from "node:http"; -import "next/dist/server/initialize-require-hook"; import "@vercel/turbopack-next/internal/shims"; import "next/dist/server/node-polyfill-fetch.js"; import { renderToHTML } from "next/dist/server/render"; From 9fc8c13877d57db507c8d79fd1328815cea3ee02 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Fri, 28 Oct 2022 19:16:05 -0400 Subject: [PATCH 211/672] Faster source map tracing (vercel/turbo#2426) * Store the sourcemap::SourceMap directly, instead of encoding it * Implement GenerateSourceMap trait and use it to retrieve live maps * Cleanup and comments! * Update safety comment * Rename var * Update snapshots * Update snapshots * Fix tracing errors in SSR SSR has access to `EcmascriptChunkVc`, not `EcmascriptChunkContentVc`. Client gets access only to `EcmascriptChunkContentVc` * Fix source map sources on client Because the JS is nested in dirs, the source needs to be an absolute path. Co-authored-by: Jared Palmer <jared@jaredpalmer.com> --- .../crates/next-core/src/nodejs/mod.rs | 43 ++--- .../src/source_map/content_source.rs | 24 +-- .../crates/next-core/src/source_map/trace.rs | 168 +++--------------- 3 files changed, 53 insertions(+), 182 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index cc9baf8884682c..2f4c6abf2a722c 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -1,6 +1,5 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, - ffi::OsStr, fmt::Write as _, path::PathBuf, }; @@ -18,16 +17,14 @@ use turbo_tasks_fs::{to_sys_path, File, FileContent, FileSystemPathVc}; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc, AssetsSetVc}, chunk::{ChunkGroupVc, ChunkingContextVc}, + source_map::GenerateSourceMapVc, virtual_asset::VirtualAssetVc, }; use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{query::Query, BodyVc, HeaderValue, ProxyResult, ProxyResultVc}, }; -use turbopack_ecmascript::{ - chunk::{source_map::EcmascriptChunkSourceMapAssetVc, EcmascriptChunkPlaceablesVc}, - EcmascriptModuleAssetVc, -}; +use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; use self::{ bootstrap::NodeJsBootstrapAsset, @@ -387,35 +384,25 @@ async fn trace_stack( None => bail!("couldn't extract disk fs from path"), }; - let map_ext = OsStr::new("map"); let assets = internal_assets(intermediate_asset, intermediate_output_path.root()) .await? .iter() .map(|a| async { - let mut path = match to_sys_path(a.path()).await? { + let gen = match GenerateSourceMapVc::resolve_from(*a).await? { + Some(gen) => gen, + None => return Ok(None), + }; + + let path = match to_sys_path(a.path()).await? { Some(p) => p, None => PathBuf::from(&a.path().await?.path), }; - if path.extension() != Some(map_ext) { - return Ok(None); - } - - // Strip the .map - path.set_extension(""); - - if EcmascriptChunkSourceMapAssetVc::resolve_from(*a) - .await? - .is_some() - { - // The path was something like "foo.js.abc123.map, and the next extension is the - // hash - debug_assert!(path.extension().is_some()); - debug_assert_ne!(path.extension().unwrap(), "js"); - path.set_extension(""); - }; let p = path.strip_prefix(&root).unwrap(); - Ok(Some((p.to_str().unwrap().to_string(), *a))) + Ok(Some(( + p.to_str().unwrap().to_string(), + gen.generate_source_map(), + ))) }) .try_join() .await? @@ -443,9 +430,9 @@ async fn trace_stack( if let Some((line, column)) = frame.get_pos() { if let Some(path) = frame.file.strip_prefix(&root) { if let Some(map) = assets.get(path) { - let map_trace = - SourceMapTraceVc::new(map.content(), line, column, frame.name.clone()); - let trace = map_trace.trace().await?; + let trace = SourceMapTraceVc::new(*map, line, column, frame.name.clone()) + .trace() + .await?; if let TraceResult::Found(f) = &*trace { write_frame!(f, f.file)?; continue; diff --git a/packages/next-swc/crates/next-core/src/source_map/content_source.rs b/packages/next-swc/crates/next-core/src/source_map/content_source.rs index 05fb3d2328dab8..7ecb25b8e20543 100644 --- a/packages/next-swc/crates/next-core/src/source_map/content_source.rs +++ b/packages/next-swc/crates/next-core/src/source_map/content_source.rs @@ -2,7 +2,10 @@ use std::collections::HashSet; use anyhow::Result; use turbo_tasks::{primitives::StringVc, Value}; -use turbopack_core::introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc}; +use turbopack_core::{ + introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc}, + source_map::GenerateSourceMapVc, +}; use turbopack_dev_server::source::{ ContentSource, ContentSourceData, ContentSourceDataVary, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, @@ -75,31 +78,22 @@ impl ContentSource for NextSourceMapTraceContentSource { _ => return Ok(ContentSourceResult::NotFound.cell()), }; - // Source maps aren't stored as `foo.js.map`, but instead use a hash of the JS's - // contents: `foo.js.abc123.map`. In order to find the map, we need to - // get the JS's version id and then fetch the map. let this = self_vc.await?; - let js_file = this + let file = this .asset_source .get(path, Value::new(Default::default())) .await?; - let js_file = match &*js_file { + let file = match &*file { ContentSourceResult::Static(f) => f, _ => return Ok(ContentSourceResult::NotFound.cell()), }; - let id = js_file.version().id().await?; - let map = this - .asset_source - .get(&format!("{path}.{id}.map"), Value::new(Default::default())) - .await?; - let map = match &*map { - ContentSourceResult::Static(f) => f, + let gen = match GenerateSourceMapVc::resolve_from(file).await? { + Some(f) => f, _ => return Ok(ContentSourceResult::NotFound.cell()), }; - let traced = SourceMapTraceVc::new(map.content(), line, column, frame.name); - + let traced = SourceMapTraceVc::new(gen.generate_source_map(), line, column, frame.name); Ok(ContentSourceResult::Static(traced.content().into()).cell()) } } diff --git a/packages/next-swc/crates/next-core/src/source_map/trace.rs b/packages/next-swc/crates/next-core/src/source_map/trace.rs index f046a84cc73ddb..f1cdf3e1ed193a 100644 --- a/packages/next-swc/crates/next-core/src/source_map/trace.rs +++ b/packages/next-swc/crates/next-core/src/source_map/trace.rs @@ -1,10 +1,10 @@ -use std::{ops::Deref, sync::Arc}; - -use anyhow::{bail, Result}; +use anyhow::Result; use serde_json::json; -use sourcemap::{decode as decode_source_map, DecodedMap, Token}; -use turbo_tasks_fs::{File, FileContent, FileContentVc}; -use turbopack_core::asset::{AssetContent, AssetContentVc}; +use turbo_tasks_fs::File; +use turbopack_core::{ + asset::AssetContentVc, + source_map::{SourceMapVc, Token}, +}; /// An individual stack frame, as parsed by the stacktrace-parser npm module. /// @@ -14,14 +14,14 @@ use turbopack_core::asset::{AssetContent, AssetContentVc}; pub struct StackFrame { pub file: String, #[serde(rename = "lineNumber")] - pub line: Option<u32>, - pub column: Option<u32>, + pub line: Option<usize>, + pub column: Option<usize>, #[serde(rename = "methodName")] pub name: Option<String>, } impl StackFrame { - pub fn get_pos(&self) -> Option<(u32, u32)> { + pub fn get_pos(&self) -> Option<(usize, usize)> { match (self.line, self.column) { (Some(l), Some(c)) => Some((l, c)), _ => None, @@ -29,14 +29,14 @@ impl StackFrame { } } -/// Source Map Trace implmements the actual source map tracing logic, by parsing -/// the source map and calling the appropriate methods. +/// Source Map Trace is a convenient wrapper to perform and consume a source map +/// trace's token. #[turbo_tasks::value(shared)] #[derive(Debug)] pub struct SourceMapTrace { - file: AssetContentVc, - line: u32, - column: u32, + map: SourceMapVc, + line: usize, + column: usize, name: Option<String>, } @@ -48,113 +48,12 @@ pub enum TraceResult { Found(StackFrame), } -/// Wraps DecodedMap so that it can be cached in a Vc. -/// -/// DecodedMap contains a raw pointer, which isn't Send, which is required to -/// cache in a Vc. So, we have wrap it in 4 layers of cruft to do it. We don't -/// actually use the pointer, because we don't perform sources content lookup, -/// so it's fine. -struct DecodedMapWrapper(DecodedMap); -unsafe impl Send for DecodedMapWrapper {} -unsafe impl Sync for DecodedMapWrapper {} -impl Deref for DecodedMapWrapper { - type Target = DecodedMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -/// DecodedSourceMap wraps sourcemap::DecodedMap in a Vc for caching. -#[turbo_tasks::value(serialization = "none", eq = "manual")] -struct DecodedSourceMap(#[turbo_tasks(debug_ignore, trace_ignore)] Arc<DecodedMapWrapper>); -impl Deref for DecodedSourceMap { - type Target = Arc<DecodedMapWrapper>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[turbo_tasks::value_impl] -impl DecodedSourceMapVc { - #[turbo_tasks::function] - async fn from(file: FileContentVc) -> Result<Self> { - let file_content = file.await?; - let content = match &*file_content { - FileContent::Content(c) => c, - _ => bail!("could not read file content"), - }; - - let sm = match decode_source_map(content.as_ref()) { - Ok(sm) => sm, - _ => bail!("could not decode source map"), - }; - - Ok(DecodedSourceMap(Arc::new(DecodedMapWrapper(sm))).cell()) - } -} - -impl PartialEq for DecodedSourceMap { - fn eq(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.0, &other.0) - } -} - -// sourcemap crate didn't implement sectioned sourcemap lookups correctly. -// :face-palm: -fn sectioned_lookup(map: &DecodedMap, line: u32, column: u32) -> Option<Token> { - if let DecodedMap::Index(idx) = map { - let len = idx.get_section_count(); - let mut low = 0; - let mut high = len; - - // A "greatest lower bound" binary search. We're looking for the closest section - // line/col <= to our line/col. - while low < high { - let mid = (low + high) / 2; - let section = idx.get_section(mid).unwrap(); - if (line, column) < section.get_offset() { - high = mid; - } else { - low = mid + 1; - } - } - if low > 0 && low <= len { - let section = idx.get_section(low - 1).unwrap(); - if let Some(map) = section.get_sourcemap() { - let (off_line, off_col) = section.get_offset(); - // We're looking for the position `l` lines into region spanned by this - // sourcemap s section. - let l = line - off_line; - // The source map starts if offset by the column only on its first line. On the - // 2nd+ line, the sourcemap spans starting at column 0. - let c = if line == off_line { - column - off_col - } else { - column - }; - return sectioned_lookup(map, l, c); - } - } - None - } else if let DecodedMap::Regular(sm) = map { - match sm.lookup_token(line, column) { - // The sourcemap package incorrectly returns the last token for large lookup lines. - Some(t) if t.get_dst_line() == line => Some(t), - _ => None, - } - } else { - unimplemented!("we should only be using the standard source map types"); - } -} - #[turbo_tasks::value_impl] impl SourceMapTraceVc { #[turbo_tasks::function] - pub async fn new(file: AssetContentVc, line: u32, column: u32, name: Option<String>) -> Self { + pub async fn new(map: SourceMapVc, line: usize, column: usize, name: Option<String>) -> Self { SourceMapTrace { - file, + map, line, column, name, @@ -175,31 +74,22 @@ impl SourceMapTraceVc { #[turbo_tasks::function] pub async fn trace(self) -> Result<TraceResultVc> { let this = self.await?; - let file = this.file.await?; - let content = match &*file { - AssetContent::File(c) => c, - _ => return Ok(TraceResult::NotFound.cell()), - }; - let decoded_map = DecodedSourceMapVc::from(*content).await?; - let trace = match sectioned_lookup(&decoded_map, this.line.saturating_sub(1), this.column) { - Some(t) if t.has_source() => t, - _ => return Ok(TraceResult::NotFound.cell()), + let token = this + .map + .lookup_token(this.line.saturating_sub(1), this.column) + .await?; + let result = match &*token { + Some(Token::Original(t)) => TraceResult::Found(StackFrame { + file: t.original_file.clone(), + line: Some(t.original_line.saturating_add(1)), + column: Some(t.original_column), + name: t.name.clone().or_else(|| this.name.clone()), + }), + _ => TraceResult::NotFound, }; - Ok(TraceResult::Found(StackFrame { - file: trace - .get_source() - .expect("trace was unwraped already") - .to_string(), - line: Some(trace.get_src_line().saturating_add(1)), - column: Some(trace.get_src_col()), - name: trace - .get_name() - .map(|s| s.to_string()) - .or_else(|| this.name.clone()), - }) - .cell()) + Ok(result.cell()) } /// Takes the trace and generates a (possibly valid) JSON asset content. From 9b5c2e39ea07c5742ca9cf245e105da13a3adf87 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Sat, 29 Oct 2022 00:37:52 -0700 Subject: [PATCH 212/672] Simplify benchmark warmup (vercel/turbo#2483) * Simplify benchmark warmup * Update crates/next-dev/benches/mod.rs Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> * fmt Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> --- .../next-swc/crates/next-dev/benches/mod.rs | 36 +++---------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index f677dcf59ae20e..157c9a412a1d98 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -211,39 +211,13 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { .page() .evaluate_expression("globalThis.HMR_IS_HAPPENING = true") .await?; - Ok(guard) }, - |mut guard| async { - // Make 5 warmup changes - let mut last_error = Some(anyhow!("not run yet")); - let mut timeout = Duration::from_secs(1); - let mut remaining = 5; - while timeout < MAX_UPDATE_TIMEOUT * 2 { - match make_change(&mut guard, location, timeout).await { - Ok(_) => { - // Wait a second to allow background work to complete. - sleep(Duration::from_secs(1)).await; - last_error = None; - remaining -= 1; - if remaining == 0 { - break; - } - continue; - } - Err(err) => { - if err.to_string().contains(CHANGE_TIMEOUT_MESSAGE) { - last_error = Some(err); - timeout *= 2; - continue; - } - return Err(err); - } - } - } - - if let Some(err) = last_error { - return Err(err); + |mut guard| async move { + // Make 5 changes to warm up. + for _ in 0..5 { + let _ = + make_change(&mut guard, location, MAX_UPDATE_TIMEOUT).await; } Ok(guard) }, From 091af50322b1c1d205050ef3872a600280d8ff87 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Sat, 29 Oct 2022 18:13:39 +0200 Subject: [PATCH 213/672] add TURBOPACK_BENCH_PROGRESS to show captured values during bench (vercel/turbo#2490) --- packages/next-swc/crates/next-dev/benches/util/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index a20bd0b2531db4..827565e6c0842a 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -21,6 +21,7 @@ pub use page_guard::PageGuard; pub use prepared_app::PreparedApp; use regex::Regex; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; +use turbo_tasks::util::FormatDuration; use turbopack_create_test_app::test_app_builder::{PackageJsonConfig, TestApp, TestAppBuilder}; use crate::bundlers::Bundler; @@ -206,6 +207,10 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, config.as_deref(), None | Some("") | Some("no") | Some("false") ); + let log_progress = !matches!( + std::env::var("TURBOPACK_BENCH_PROGRESS").ok().as_deref(), + None | Some("") | Some("no") | Some("false") + ); let setup = &setup; let warmup = &warmup; @@ -238,6 +243,9 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, duration = measurement.end(start); teardown(black_box(output)).await; } + if log_progress { + eprint!(" {} ", FormatDuration(duration)); + } value = measurement.add(&value, &duration); iter += 1; break; From 36daa2bf52950df44f254a221d5159a9f62657b5 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Sun, 30 Oct 2022 12:05:37 -0700 Subject: [PATCH 214/672] feat(next/dev): allow to retry bind (vercel/turbo#2480) --- packages/next-swc/crates/next-dev/src/lib.rs | 101 +++++++++++++++---- 1 file changed, 79 insertions(+), 22 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index fd64f2d9176a4b..98471a0ab5bb48 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -8,7 +8,7 @@ use std::{ collections::HashSet, env::current_dir, future::join, - net::IpAddr, + net::{IpAddr, SocketAddr}, path::MAIN_SEPARATOR, sync::Arc, time::{Duration, Instant}, @@ -52,6 +52,7 @@ pub struct NextDevServerBuilder { log_level: IssueSeverity, show_all: bool, log_detail: bool, + allow_retry: bool, } impl NextDevServerBuilder { @@ -75,6 +76,7 @@ impl NextDevServerBuilder { log_level: IssueSeverity::Warning, show_all: false, log_detail: false, + allow_retry: false, } } @@ -118,6 +120,11 @@ impl NextDevServerBuilder { self } + pub fn allow_retry(mut self, allow_retry: bool) -> NextDevServerBuilder { + self.allow_retry = allow_retry; + self + } + pub fn log_detail(mut self, log_detail: bool) -> NextDevServerBuilder { self.log_detail = log_detail; self @@ -143,29 +150,78 @@ impl NextDevServerBuilder { let console_ui = Arc::new(ConsoleUi::new(log_options)); let console_ui_to_dev_server = console_ui.clone(); - let server = DevServer::listen( - turbo_tasks.clone(), - move || { - source( - root_dir.clone(), - project_dir.clone(), - entry_requests.clone(), - eager_compile, - turbo_tasks.clone().into(), - console_ui.clone().into(), - browserslist_query.clone(), - server_component_externals.clone(), - ) - }, - ( - self.hostname.context("hostname must be set")?, - self.port.context("port must be set")?, + let start_port = self.port.context("port must be set")?; + let host = self.hostname.context("hostname must be set")?; + + let mut err: Option<anyhow::Error> = None; + + let tasks = turbo_tasks.clone(); + let source = move || { + source( + root_dir.clone(), + project_dir.clone(), + entry_requests.clone(), + eager_compile, + turbo_tasks.clone().into(), + console_ui.clone().into(), + browserslist_query.clone(), + server_component_externals.clone(), ) - .into(), - console_ui_to_dev_server, - ); + }; + + // Retry to listen on the different port if the port is already in use. + for retry_count in 0..10 { + let current_port = start_port + retry_count; + let addr = SocketAddr::new(host, current_port); + + let listen_result = DevServer::listen( + tasks.clone(), + source.clone(), + addr, + console_ui_to_dev_server.clone(), + ); + + match listen_result { + Ok(server) => { + return Ok(server); + } + Err(e) => { + let should_retry = if self.allow_retry { + // Returned error from `listen` is not `std::io::Error` but `anyhow::Error`, + // so we need to access its source to check if it is + // `std::io::ErrorKind::AddrInUse`. + e.source() + .map(|e| { + e.source() + .map(|e| { + e.downcast_ref::<std::io::Error>() + .map(|e| e.kind() == std::io::ErrorKind::AddrInUse) + == Some(true) + }) + .unwrap_or_else(|| false) + }) + .unwrap_or_else(|| false) + } else { + false + }; + + if !should_retry { + return Err(e); + } else { + println!( + "{} - Port {} is in use, trying {} instead", + "warn ".yellow(), + current_port, + current_port + 1 + ); + } + + err = Some(e); + } + } + } - server + Err(err.expect("Should have an error if we get here")) } } @@ -331,6 +387,7 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { .port(options.port) .log_detail(options.log_detail) .show_all(options.show_all) + .allow_retry(options.allow_retry) .log_level( options .log_level From beed9fb626f501460d82f9bb362cc63c1c9180b2 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 1 Nov 2022 00:08:56 +0100 Subject: [PATCH 215/672] add benchmark documentation and blog post (vercel/turbo#2492) Co-authored-by: Anthony Shew <anthony.shew@vercel.com> Co-authored-by: Jared Palmer <jared@jaredpalmer.com> Co-authored-by: Maia Teegarden <dev@padmaia.rocks> Co-authored-by: Will Binns-Smith <wbinnssmith@gmail.com> Co-authored-by: Alex Kirszenberg <alex.kirszenberg@vercel.com> Co-authored-by: Matt Pocock <mattpocockvoice@gmail.com> --- .../crates/next-dev/benches/README.md | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 packages/next-swc/crates/next-dev/benches/README.md diff --git a/packages/next-swc/crates/next-dev/benches/README.md b/packages/next-swc/crates/next-dev/benches/README.md new file mode 100644 index 00000000000000..360d56717f99d8 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/README.md @@ -0,0 +1,45 @@ +<!-- + IMPORTANT: This document is linked to from https://turbo.build + DO NOT rename this file without updating the link in docs/pages/pack/docs/benchmarks.mdx +--> + +# Benchmarking Turbopack + +The simplest way to run Turbopack's benchmark suite is with the command `cargo bench -p next-dev`. This will benchmark Turbopack's Next.js development server in a variety of scenarios and it's what we use to track Turbopack's performance over time. + +`cargo bench -p next-dev` accepts different options via environment variables. To vary the number of modules tested, set `TURBOPACK_BENCH_COUNTS`. For example, to test against an app with 5,000 modules instead of the default 1,000, run + +```sh +TURBOPACK_BENCH_COUNTS=5000 cargo bench -p next-dev +``` + +## Benchmarking Turbopack against other bundlers + +The benchmark numbers we share on [the Turbopack website](https://turbo.build/pack) are informed by running Turbopack's benchmark suite against Turbopack and other bundlers. These are run in a controlled environment prior to being published. We use the `bench_startup` and `bench_hmr_to_eval` benchmarks currently (see below). + +To run Turbopack benchmarks against other bundlers, run: + +```sh +TURBOPACK_BENCH_BUNDLERS=all cargo bench -p next-dev +``` + +and optionally filter the benchmarks run to specific bundlers, such as: + +```sh +TURBOPACK_BENCH_BUNDLERS=all cargo bench -p next-dev -- "hmr_to_eval/(Turbopack CSR|Vite)" +``` + +**Note**: The Turbopack benchmark suite includes a mix of server-side rendered and client-only rendered examples -- these are reflected in "CSR" or "SSR" in the benchmark name. Turbopack supports both, while some other bundlers only support client-rendered examples. Take that into account when comparing CSR results against SSR. + +**Hint**: These benchmarks take a long time to complete, since they try to capture at least 10 samples for every scenario. There is a `TURBOPACK_BENCH_PROGRESS=1` env var to show values while the benchmarks are running. + +## Benchmark Suite scenarios + +The benchmark suite runs Turbopack and other bundlers in a variety of scenarios. The tests use a real headless browser and perform a variety of common scenarios in web development, and wait for results to be reflected in the page. + +- **bench_startup:** Time from startup (without cache) until the app is rendered in the browser (it doesn't have to be interactive/hydrated for this.) +- **bench_hydration:** Time from startup (without cache) until the app is interactive in the browser (it needs to be hydrated for that.) This metric is not captured for CSR since the first render is interactive. +- **bench_hmr_to_eval:** Time from changing a file until the new code is evaluated in the browser. Evaluating the code does not mean the change is visible to the user yet. For instance, when a React component changes, it need to be re-rendered in the browser. This mostly measures the time spent computing the update in the bundler itself and sending it to the client. +- **bench_hmr_to_commit:** Time from changing a file until the change is reflected in the browser. We are using a `useEffect` hook within a React component to measure the time it takes for the updated React component to be committed to the DOM. This is a good measure of the end to end performance perceived by the user. +- **bench_startup_cache:** Time from startup with persistent cache until the app is rendered in the browser (it doesn't have to be interactive/hydrated for this.). Turbopack doesn't include a persistent cache yet. (This benchmark is disabled by default and can be enabled with `TURBOPACK_BENCH_CACHED=1`) +- **bench_hydration:** Time from startup with persistent cache until the app is interactive in the browser (it needs to be hydrated for that.) This metric is not captured for CSR since the first render is interactive. Turbopack doesn't include a persistent cache yet. (This benchmark is disabled by default and can be enabled with `TURBOPACK_BENCH_CACHED=1`) From e8c027ffb2f05e0fe597fbff1bcfb12c23e89978 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Thu, 3 Nov 2022 08:01:39 +0100 Subject: [PATCH 216/672] Use mimalloc in next-dev (vercel/turbo#2467) --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/src/main.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index cf9e23b3591405..e709de67a3ea53 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -40,6 +40,7 @@ portpicker = "0.1.1" serde = "1.0.136" serde_json = "1.0.85" tokio = { version = "1.11.0", features = ["full"] } +turbo-malloc = { path = "../turbo-malloc" } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } turbo-tasks-memory = { path = "../turbo-tasks-memory" } diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 6ce46a61bb8e2d..87c474cee70837 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -5,6 +5,9 @@ use anyhow::Result; #[cfg(feature = "cli")] use clap::Parser; +#[global_allocator] +static ALLOC: turbo_malloc::TurboMalloc = turbo_malloc::TurboMalloc; + #[cfg(not(feature = "cli"))] fn main() -> Result<()> { unimplemented!("Cannot run binary without CLI feature enabled"); From e08865cafda169c1be85a5a35fb412d5c333e331 Mon Sep 17 00:00:00 2001 From: LongYinan <lynweklm@gmail.com> Date: Thu, 3 Nov 2022 23:01:50 +0800 Subject: [PATCH 217/672] Merge turbo crate into cargo workspace (vercel/turbo#2577) --- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index e709de67a3ea53..d3da3407675c6a 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -30,7 +30,7 @@ tokio_console = [ [dependencies] anyhow = "1.0.47" -clap = { version = "3", features = ["derive"] } +clap = { version = "4.0.18", features = ["derive"] } console-subscriber = { version = "0.1.6", optional = true } futures = "0.3.21" mime = "0.3.16" From 196ac9717cdba6480b0c10f2ab93126e289471b1 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Thu, 3 Nov 2022 11:28:47 -0400 Subject: [PATCH 218/672] Fix React Refresh boundary finding for CSR (vercel/turbo#2574) * Fix React Refresh boundary finding We forgot to enable the transform, which means we were rendering from the root of the app instead of the changed component. * Update snapshots * Add comment Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../crates/next-core/src/next_client/context.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index a966582932950e..1fd5a83e50e6b1 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -204,6 +204,13 @@ pub async fn get_client_runtime_entries( ProcessEnvAssetVc::new(project_root, filter_for_client(env)).into(), ) .cell()]; + + // It's important that React Refresh come before the regular bootstrap file, + // because the bootstrap contains JSX which requires Refresh's global + // functions to be available. + if let Some(request) = enable_react_refresh { + runtime_entries.push(RuntimeEntry::Request(request, project_root.join("_")).cell()) + }; if matches!(ty.into_value(), ContextType::Other) { runtime_entries.push( RuntimeEntry::Request( @@ -215,9 +222,6 @@ pub async fn get_client_runtime_entries( .cell(), ); } - if let Some(request) = enable_react_refresh { - runtime_entries.push(RuntimeEntry::Request(request, project_root.join("_")).cell()) - }; Ok(RuntimeEntriesVc::cell(runtime_entries)) } From 26cfc649d6259bb99263e938b54f5fd5719fc5eb Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Thu, 3 Nov 2022 13:44:23 -0700 Subject: [PATCH 219/672] refactor(next/dev): do not expose unsupported cli options (vercel/turbo#2586) --- .../next-swc/crates/next-dev/src/devserver_options.rs | 6 +++++- packages/next-swc/crates/next-dev/src/lib.rs | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index 0d6de3c9d6a47f..826f69c492b9d8 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -66,13 +66,17 @@ pub struct DevServerOptions { pub log_detail: bool, // Inherited options from next-dev, need revisit later. - // This is not supported by CLI yet. + // These are not supported by CLI yet. + #[cfg(feature = "serializable")] #[cfg_attr(feature = "serializable", serde(default))] pub allow_retry: bool, + #[cfg(feature = "serializable")] #[cfg_attr(feature = "serializable", serde(default))] pub dev: bool, + #[cfg(feature = "serializable")] #[cfg_attr(feature = "serializable", serde(default))] pub is_next_dev_command: bool, + #[cfg(feature = "serializable")] #[cfg_attr(feature = "serializable", serde(default))] pub server_components_external_packages: Vec<String>, } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 98471a0ab5bb48..b7071313beb891 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -380,6 +380,7 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { let tt = TurboTasks::new(MemoryBackend::new()); let tt_clone = tt.clone(); + #[allow(unused_mut)] let mut server = NextDevServerBuilder::new(tt, dir, root_dir) .entry_request("src/index".into()) .eager_compile(options.eager_compile) @@ -387,15 +388,19 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { .port(options.port) .log_detail(options.log_detail) .show_all(options.show_all) - .allow_retry(options.allow_retry) .log_level( options .log_level .map_or_else(|| IssueSeverity::Warning, |l| l.0), ); - for package in options.server_components_external_packages.iter() { - server = server.server_component_external(package.to_string()); + #[cfg(feature = "serializable")] + { + server = server.allow_retry(options.allow_retry); + + for package in options.server_components_external_packages.iter() { + server = server.server_component_external(package.to_string()); + } } let server = server.build().await?; From 35ae595de5fc68ae4afa6260561d61ce5cbea87d Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Fri, 4 Nov 2022 15:42:18 -0400 Subject: [PATCH 220/672] Implement Ropes for shared string construction (vercel/turbo#2525) --- .../crates/next-core/src/app_source.rs | 31 +++++++++++-------- .../src/next_client_component/with_chunks.rs | 3 +- .../with_client_chunks.rs | 3 +- .../crates/next-core/src/nodejs/mod.rs | 4 +-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 1df2a576fb1127..91be00d48fc45b 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fmt::Write}; +use std::{collections::HashMap, io::Write}; use anyhow::{anyhow, Context, Result}; use turbo_tasks::{ @@ -7,8 +7,8 @@ use turbo_tasks::{ }; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{ - DirectoryContent, DirectoryEntry, File, FileContent, FileContentVc, FileSystemEntryType, - FileSystemPathVc, + rope::RopeBuilder, DirectoryContent, DirectoryEntry, File, FileContent, FileContentVc, + FileSystemEntryType, FileSystemPathVc, }; use turbopack::{ ecmascript::EcmascriptInputTransform, @@ -494,15 +494,17 @@ impl NodeEntry for AppRenderer { .into_iter() .try_join() .await?; - let mut result = - "import IPC, { Ipc } from \"@vercel/turbopack-next/internal/ipc\";\n".to_string(); + let mut result = RopeBuilder::from( + "import IPC, { Ipc } from \"@vercel/turbopack-next/internal/ipc\";\n", + ); + for (_, import) in segments.iter() { if let Some((p, identifier, chunks_identifier)) = import { + result += r#"("TURBOPACK {{ transition: next-layout-entry; chunking-type: parallel }}"); +"#; writeln!( result, - r#"("TURBOPACK {{ transition: next-layout-entry; chunking-type: parallel }}"); -import {}, {{ chunks as {} }} from {}; -"#, + "import {}, {{ chunks as {} }} from {};\n", identifier, chunks_identifier, stringify_str(p) @@ -518,7 +520,8 @@ import BOOTSTRAP from {}; stringify_str(&page) )?; } - result.push_str("const LAYOUT_INFO = ["); + + result += "const LAYOUT_INFO = ["; for (segment_str_lit, import) in segments.iter() { if let Some((_, identifier, chunks_identifier)) = import { writeln!( @@ -530,13 +533,15 @@ import BOOTSTRAP from {}; writeln!(result, " {{ segment: {segment_str_lit} }},",)? } } - result.push_str("];\n\n"); + result += "];\n\n"; + let base_code = next_js_file("entry/app-renderer.tsx"); - let mut file = File::from(result); if let FileContent::Content(base_file) = &*base_code.await? { - file.push_content(base_file.content()); + result += base_file.content() } - let asset = VirtualAssetVc::new(path.join("entry"), FileContent::Content(file).into()); + + let file = File::from(result.build()); + let asset = VirtualAssetVc::new(path.join("entry"), file.into()); let (context, intermediate_output_path) = if is_rsc { (self.context, self.intermediate_output_path.join("__rsc__")) } else { diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs index 0ed0e646f1057c..90a03e3b11bac3 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_chunks.rs @@ -129,7 +129,8 @@ const chunks = {}; ", module_id, Value::Array(client_chunks) - ), + ) + .into(), ..Default::default() } .cell()) diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs index 7490cc856ec538..2c624e3b14fec1 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs @@ -136,7 +136,8 @@ const chunks = {}; ", module_id, Value::Array(client_chunks) - ), + ) + .into(), ..Default::default() } .cell()) diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs index 2f4c6abf2a722c..10b7642a579760 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/mod.rs @@ -569,7 +569,7 @@ async fn run_proxy_operation( Ok(ProxyResult { status, headers, - body, + body: body.into(), }) } @@ -610,7 +610,7 @@ async fn proxy_error( "content-type".to_string(), "text/html; charset=utf-8".to_string(), ], - body: body.into_bytes(), + body: body.into(), } .cell()) } From b893baacf89d019e658e2eb740e193fc1bb42ced Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon, 7 Nov 2022 17:51:35 +0100 Subject: [PATCH 221/672] add RSC and RCC for turbopack to benchmarks (vercel/turbo#2620) * fixup ropes * add RSC and RCC for turbopack to benchmarks RSC: whole page is a server component RCC: whole page is a client component add `app` directory to test app --- .../crates/next-core/src/app_source.rs | 2 +- .../crates/next-dev/benches/bundlers/mod.rs | 25 +++++++++++-- .../next-dev/benches/bundlers/turbopack.rs | 13 ++++++- .../next-swc/crates/next-dev/benches/mod.rs | 36 +++++++++++++++++-- .../next-dev/benches/util/page_guard.rs | 3 +- .../next-dev/benches/util/prepared_app.rs | 29 +++++++++++---- 6 files changed, 93 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 91be00d48fc45b..a356b7007efa2d 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -500,7 +500,7 @@ impl NodeEntry for AppRenderer { for (_, import) in segments.iter() { if let Some((p, identifier, chunks_identifier)) = import { - result += r#"("TURBOPACK {{ transition: next-layout-entry; chunking-type: parallel }}"); + result += r#"("TURBOPACK { transition: next-layout-entry; chunking-type: parallel }"); "#; writeln!( result, diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs index fbf2b17ffb2f3a..99be70ac0e53a7 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs @@ -29,6 +29,10 @@ pub trait Bundler { fn has_server_rendered_html(&self) -> bool { false } + /// There is a hydration done event emitted by client side JavaScript + fn has_interactivity(&self) -> bool { + true + } fn prepare(&self, _template_dir: &Path) -> Result<()> { Ok(()) } @@ -55,8 +59,25 @@ pub fn get_bundlers() -> Vec<Box<dyn Bundler>> { } let mut bundlers: Vec<Box<dyn Bundler>> = Vec::new(); if turbopack { - bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false))); - bundlers.push(Box::new(Turbopack::new("Turbopack SSR", "/page", true))); + bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false, true))); + bundlers.push(Box::new(Turbopack::new( + "Turbopack SSR", + "/page", + true, + true, + ))); + bundlers.push(Box::new(Turbopack::new( + "Turbopack RSC", + "/app", + true, + false, + ))); + bundlers.push(Box::new(Turbopack::new( + "Turbopack RCC", + "/client", + true, + true, + ))); } if others { diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index 4f241016f37d3a..b38e5a7e54a050 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -18,14 +18,21 @@ pub struct Turbopack { name: String, path: String, has_server_rendered_html: bool, + has_interactivity: bool, } impl Turbopack { - pub fn new(name: &str, path: &str, has_server_rendered_html: bool) -> Self { + pub fn new( + name: &str, + path: &str, + has_server_rendered_html: bool, + has_interactivity: bool, + ) -> Self { Turbopack { name: name.to_owned(), path: path.to_owned(), has_server_rendered_html, + has_interactivity, } } } @@ -43,6 +50,10 @@ impl Bundler for Turbopack { self.has_server_rendered_html } + fn has_interactivity(&self) -> bool { + self.has_interactivity + } + fn prepare(&self, install_dir: &Path) -> Result<()> { npm::install( install_dir, diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 157c9a412a1d98..47fc029c5d04bf 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -56,6 +56,13 @@ fn bench_startup_internal(mut g: BenchmarkGroup<WallTime>, hydration: bool) { } else { true } + } else if !bundler.has_interactivity() { + // For bundlers without interactivity there is no hydration event to wait for + if hydration { + continue; + } else { + false + } } else { hydration }; @@ -119,6 +126,10 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { let browser = &runtime.block_on(create_browser()); for bundler in get_bundlers() { + // TODO HMR for RSC is broken, fix it and enable it here + if !bundler.has_interactivity() { + continue; + } for module_count in get_module_counts() { let test_app = Lazy::new(|| build_test(module_count, bundler.as_ref())); let input = (bundler.as_ref(), &test_app); @@ -206,11 +217,19 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { .await?; app.start_server()?; let mut guard = app.with_page(browser).await?; - guard.wait_for_hydration().await?; + if bundler.has_interactivity() { + guard.wait_for_hydration().await?; + } else { + guard.page().wait_for_navigation().await?; + } guard .page() .evaluate_expression("globalThis.HMR_IS_HAPPENING = true") - .await?; + .await + .context( + "Unable to evaluate JavaScript in the page for HMR check \ + flag", + )?; Ok(guard) }, |mut guard| async move { @@ -283,6 +302,13 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo } else { true } + } else if !bundler.has_interactivity() { + // For bundlers without interactivity there is no hydration event to wait for + if hydration { + continue; + } else { + false + } } else { hydration }; @@ -303,7 +329,11 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo .await?; app.start_server()?; let mut guard = app.with_page(browser).await?; - guard.wait_for_hydration().await?; + if bundler.has_interactivity() { + guard.wait_for_hydration().await?; + } else { + guard.page().wait_for_navigation().await?; + } let mut app = guard.close_page().await?; diff --git a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs index 8eabf31de43cdd..5959fd8bf79af1 100644 --- a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs +++ b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs @@ -100,7 +100,8 @@ impl<'a> PageGuard<'a> { self.wait_for_binding(TEST_APP_HYDRATION_DONE), ) .await - .context("Timeout happened while waiting for hydration")??; + .context("Timeout happened while waiting for hydration")? + .context("Error happened while waiting for hydration")?; Ok(()) } } diff --git a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs index 35ac6b95a7f5b3..8260d486c68cd4 100644 --- a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs +++ b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs @@ -95,13 +95,27 @@ impl<'a> PreparedApp<'a> { pub async fn with_page(self, browser: &Browser) -> Result<PageGuard<'a>> { let server = self.server.as_ref().context("Server must be started")?; - let page = browser.new_page("about:blank").await?; + let page = browser + .new_page("about:blank") + .await + .context("Unable to open about:blank")?; // Bindings survive page reloads. Set them up as early as possible. - add_binding(&page).await?; - - let mut errors = page.event_listener::<EventExceptionThrown>().await?; - let binding_events = page.event_listener::<EventBindingCalled>().await?; - let mut network_response_events = page.event_listener::<EventResponseReceived>().await?; + add_binding(&page) + .await + .context("Failed to add bindings to the browser tab")?; + + let mut errors = page + .event_listener::<EventExceptionThrown>() + .await + .context("Unable to listen to exception events")?; + let binding_events = page + .event_listener::<EventBindingCalled>() + .await + .context("Unable to listen to binding events")?; + let mut network_response_events = page + .event_listener::<EventResponseReceived>() + .await + .context("Unable to listen to response received events")?; let destination = Url::parse(&server.1)?.join(self.bundler.get_path())?; // We can't use page.goto() here since this will wait for the naviation to be @@ -111,7 +125,8 @@ impl<'a> PreparedApp<'a> { // So instead we navigate via JavaScript and wait only for the HTML response to // be completed. page.evaluate_expression(format!("window.location='{destination}'")) - .await?; + .await + .context("Unable to evaluate javascript to naviagate to target page")?; // Wait for HTML response completed loop { From 3d690b277801f19d36106192b02a7a4e5d63c7da Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 8 Nov 2022 17:44:57 +0100 Subject: [PATCH 222/672] order routes by specificity (vercel/turbo#2614) * bugfix source maps in app dir * add specificity static assets are preferred over dynamic matches --- .../crates/next-core/src/app_source.rs | 21 +++- .../next-core/src/nodejs/node_api_source.rs | 33 +++-- .../src/nodejs/node_rendered_source.rs | 119 +++++++++--------- .../crates/next-core/src/path_regex.rs | 3 + .../next-core/src/server_rendered_source.rs | 51 +++++--- .../src/source_map/content_source.rs | 46 +++---- packages/next-swc/crates/next-dev/src/lib.rs | 2 +- .../crates/next-dev/src/turbo_tasks_viz.rs | 42 ++++--- 8 files changed, 190 insertions(+), 127 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index a356b7007efa2d..8b1f7420e0068a 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -25,6 +25,7 @@ use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{ combined::{CombinedContentSource, CombinedContentSourceVc}, + specificity::SpecificityVc, ContentSourceData, ContentSourceVc, NoContentSourceVc, }, }; @@ -257,6 +258,8 @@ pub async fn create_app_source( context_ssr, context, project_root, + SpecificityVc::exact(), + 0, app_dir, server_root, EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), @@ -273,6 +276,8 @@ async fn create_app_source_for_directory( context_ssr: AssetContextVc, context: AssetContextVc, project_root: FileSystemPathVc, + specificity: SpecificityVc, + position: u32, input_dir: FileSystemPathVc, server_root: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, @@ -359,6 +364,7 @@ async fn create_app_source_for_directory( layouts = LayoutSegmentsVc::cell(list); if let Some(page_path) = page.copied() { sources.push(create_node_rendered_source( + specificity, server_root, regular_expression_for_path(server_root, target, false), AppRenderer { @@ -380,18 +386,27 @@ async fn create_app_source_for_directory( for (name, entry) in entries.iter() { if let DirectoryEntry::Directory(dir) = entry { let intermediate_output_path = intermediate_output_path.join(name); - let new_target = if name.starts_with('(') && name.ends_with(')') { + let specificity = if name.starts_with("[[") || name.starts_with("[...") { + specificity.with_catch_all(position) + } else if name.starts_with('[') { + specificity.with_dynamic_segment(position) + } else { + specificity + }; + let (new_target, position) = if name.starts_with('(') && name.ends_with(')') { // This doesn't affect the url - target + (target, position) } else { // This adds to the url - target.join(name) + (target.join(name), position + 1) }; sources.push( create_app_source_for_directory( context_ssr, context, project_root, + specificity, + position, *dir, server_root, runtime_entries, diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs index b8740ed73e8ad4..264a625394b9f0 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs @@ -8,8 +8,9 @@ use turbopack_core::introspect::{ asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, }; use turbopack_dev_server::source::{ - ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, - ContentSourceResult, ContentSourceResultVc, ContentSourceVc, + specificity::SpecificityVc, ContentSource, ContentSourceContent, ContentSourceData, + ContentSourceDataFilter, ContentSourceDataVary, ContentSourceResult, ContentSourceResultVc, + ContentSourceVc, }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; @@ -19,12 +20,14 @@ use crate::path_regex::PathRegexVc; /// Creates a [NodeApiContentSource]. #[turbo_tasks::function] pub fn create_node_api_source( + specificity: SpecificityVc, server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, runtime_entries: EcmascriptChunkPlaceablesVc, ) -> ContentSourceVc { NodeApiContentSource { + specificity, server_root, path_regex, entry, @@ -42,6 +45,7 @@ pub fn create_node_api_source( /// to this directory. #[turbo_tasks::value] struct NodeApiContentSource { + specificity: SpecificityVc, server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, @@ -72,7 +76,7 @@ impl ContentSource for NodeApiContentSource { let this = self_vc.await?; if this.is_matching_path(path).await? { if let Some(params) = this.get_matches(path).await? { - if let ContentSourceData { + let content = if let ContentSourceData { headers: Some(headers), method: Some(method), url: Some(url), @@ -82,7 +86,7 @@ impl ContentSource for NodeApiContentSource { } = &*data { let entry = this.entry.entry(data.clone()).await?; - return Ok(ContentSourceResult::HttpProxy(render_proxy( + ContentSourceContent::HttpProxy(render_proxy( this.server_root.join(path), entry.module, this.runtime_entries, @@ -99,9 +103,9 @@ impl ContentSource for NodeApiContentSource { .cell(), *body, )) - .cell()); + .cell() } else { - return Ok(ContentSourceResult::NeedData { + ContentSourceContent::NeedData { source: self_vc.into(), path: path.to_string(), vary: ContentSourceDataVary { @@ -114,11 +118,16 @@ impl ContentSource for NodeApiContentSource { ..Default::default() }, } - .cell()); + .cell() + }; + return Ok(ContentSourceResult { + specificity: this.specificity, + content, } + .cell()); } } - Ok(ContentSourceResult::NotFound.cell()) + Ok(ContentSourceResultVc::not_found()) } } @@ -139,6 +148,14 @@ impl Introspectable for NodeApiContentSource { self.path_regex.to_string() } + #[turbo_tasks::function] + async fn details(&self) -> Result<StringVc> { + Ok(StringVc::cell(format!( + "Specificity: {}", + self.specificity.await? + ))) + } + #[turbo_tasks::function] async fn children(&self) -> Result<IntrospectableChildrenVc> { let mut set = HashSet::new(); diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs index eb9aded35e00aa..fa248e116cb1bc 100644 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs @@ -16,8 +16,9 @@ use turbopack_dev_server::{ asset_graph::AssetGraphContentSourceVc, conditional::ConditionalContentSourceVc, lazy_instatiated::{GetContentSource, GetContentSourceVc, LazyInstantiatedContentSource}, - ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, - ContentSourceResult, ContentSourceResultVc, ContentSourceVc, + specificity::SpecificityVc, + ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter, + ContentSourceDataVary, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, }, }; use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; @@ -35,6 +36,7 @@ use crate::path_regex::PathRegexVc; /// to this directory. #[turbo_tasks::function] pub fn create_node_rendered_source( + specificity: SpecificityVc, server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, @@ -42,6 +44,7 @@ pub fn create_node_rendered_source( fallback_page: DevHtmlAssetVc, ) -> ContentSourceVc { let source = NodeRenderContentSource { + specificity, server_root, path_regex, entry, @@ -63,6 +66,7 @@ pub fn create_node_rendered_source( /// see [create_node_rendered_source] #[turbo_tasks::value] struct NodeRenderContentSource { + specificity: SpecificityVc, server_root: FileSystemPathVc, path_regex: PathRegexVc, entry: NodeEntryVc, @@ -141,73 +145,64 @@ impl ContentSource for NodeRenderContentSource { let this = self_vc.await?; if this.is_matching_path(path).await? { if let Some(params) = this.get_matches(path).await? { - if let Some(headers) = &data.headers { - if headers - .get("accept") - .map(|value| value.contains("html")) - .unwrap_or_default() - || headers.contains_key("__rsc__") - { - if data.method.is_some() && data.url.is_some() { - if let Some(query) = &data.query { - let entry = this.entry.entry(data.clone()).await?; - return Ok(ContentSourceResult::Static( - render_static( - this.server_root.join(path), - entry.module, - this.runtime_entries, - this.fallback_page, - entry.chunking_context, - entry.intermediate_output_path, - RenderData { - params, - method: data.method.clone().ok_or_else(|| { - anyhow!("method needs to be provided") - })?, - url: data.url.clone().ok_or_else(|| { - anyhow!("url needs to be provided") - })?, - query: query.clone(), - headers: headers.clone(), - path: format!("/{path}"), - } - .cell(), - ) - .into(), - ) - .cell()); - } + let content = if data.method.is_some() + && data.url.is_some() + && data.headers.is_some() + && data.query.is_some() + { + let entry = this.entry.entry(data.clone()).await?; + let asset = render_static( + this.server_root.join(path), + entry.module, + this.runtime_entries, + this.fallback_page, + entry.chunking_context, + entry.intermediate_output_path, + RenderData { + params, + method: data + .method + .clone() + .ok_or_else(|| anyhow!("method needs to be provided"))?, + url: data + .url + .clone() + .ok_or_else(|| anyhow!("url needs to be provided"))?, + query: data + .query + .clone() + .ok_or_else(|| anyhow!("query needs to be provided"))?, + headers: data + .headers + .clone() + .ok_or_else(|| anyhow!("headers needs to be provided"))?, + path: format!("/{path}"), } - return Ok(ContentSourceResult::NeedData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - method: true, - url: true, - headers: Some(ContentSourceDataFilter::All), - query: Some(ContentSourceDataFilter::All), - ..Default::default() - }, - } - .cell()); - } + .cell(), + ); + ContentSourceContent::Static(asset.into()).cell() } else { - return Ok(ContentSourceResult::NeedData { + ContentSourceContent::NeedData { source: self_vc.into(), path: path.to_string(), vary: ContentSourceDataVary { - headers: Some(ContentSourceDataFilter::Subset(HashSet::from([ - "accept".to_string(), - "__rsc__".to_string(), - ]))), + method: true, + url: true, + headers: Some(ContentSourceDataFilter::All), + query: Some(ContentSourceDataFilter::All), ..Default::default() }, } - .cell()); + .cell() + }; + return Ok(ContentSourceResult { + specificity: this.specificity, + content, } + .cell()); } } - Ok(ContentSourceResult::NotFound.cell()) + Ok(ContentSourceResultVc::not_found()) } } @@ -228,6 +223,14 @@ impl Introspectable for NodeRenderContentSource { self.path_regex.to_string() } + #[turbo_tasks::function] + async fn details(&self) -> Result<StringVc> { + Ok(StringVc::cell(format!( + "Specificity: {}", + self.specificity.await? + ))) + } + #[turbo_tasks::function] async fn children(&self) -> Result<IntrospectableChildrenVc> { let mut set = HashSet::new(); diff --git a/packages/next-swc/crates/next-core/src/path_regex.rs b/packages/next-swc/crates/next-core/src/path_regex.rs index 53dccb11b985c4..6e9aefc5141fe4 100644 --- a/packages/next-swc/crates/next-core/src/path_regex.rs +++ b/packages/next-swc/crates/next-core/src/path_regex.rs @@ -28,6 +28,9 @@ impl PathRegex { .iter() .enumerate() .filter_map(|(idx, name)| { + if name.is_empty() { + return None; + } let value = capture.get(idx + 1)?; Some((name.to_string(), value.as_str().to_string())) }) diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index d956678374583d..ff22518744a979 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -20,6 +20,7 @@ use turbopack_dev_server::{ source::{ asset_graph::AssetGraphContentSourceVc, combined::{CombinedContentSource, CombinedContentSourceVc}, + specificity::SpecificityVc, ContentSourceData, ContentSourceVc, NoContentSourceVc, }, }; @@ -118,6 +119,8 @@ pub async fn create_server_rendered_source( project_path, context, pages_dir, + SpecificityVc::exact(), + 0, pages_dir, EcmascriptChunkPlaceablesVc::cell(server_runtime_entries), fallback_page, @@ -142,6 +145,7 @@ async fn create_server_rendered_source_for_file( context_path: FileSystemPathVc, context: AssetContextVc, pages_dir: FileSystemPathVc, + specificity: SpecificityVc, page_file: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, fallback_page: DevHtmlAssetVc, @@ -163,6 +167,7 @@ async fn create_server_rendered_source_for_file( Ok(if *is_api_path.await? { create_node_api_source( + specificity, server_root, regular_expression_for_path(server_root, server_path, true), SsrEntry { @@ -178,6 +183,7 @@ async fn create_server_rendered_source_for_file( ) } else { create_node_rendered_source( + specificity, server_root, regular_expression_for_path(server_root, server_path, true), SsrEntry { @@ -203,6 +209,8 @@ async fn create_server_rendered_source_for_directory( context_path: FileSystemPathVc, context: AssetContextVc, pages_dir: FileSystemPathVc, + specificity: SpecificityVc, + position: u32, input_dir: FileSystemPathVc, runtime_entries: EcmascriptChunkPlaceablesVc, fallback_page: DevHtmlAssetVc, @@ -211,18 +219,16 @@ async fn create_server_rendered_source_for_directory( server_api_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, ) -> Result<CombinedContentSourceVc> { - let mut predefined_sources = vec![]; - let mut named_placeholder_sources = vec![]; - let mut catch_all_sources = vec![]; + let mut sources = vec![]; let dir_content = input_dir.read_dir().await?; if let DirectoryContent::Entries(entries) = &*dir_content { for (name, entry) in entries.iter() { - let sources = if name.starts_with("[[") || name.starts_with("[...") { - &mut catch_all_sources + let specificity = if name.starts_with("[[") || name.starts_with("[...") { + specificity.with_catch_all(position) } else if name.starts_with('[') { - &mut named_placeholder_sources + specificity.with_dynamic_segment(position) } else { - &mut predefined_sources + specificity }; match entry { DirectoryEntry::File(file) => { @@ -231,13 +237,24 @@ async fn create_server_rendered_source_for_directory( // pageExtensions option from next.js // defaults: https://github.com/vercel/next.js/blob/611e13f5159457fedf96d850845650616a1f75dd/packages/next/server/config-shared.ts#L499 "js" | "ts" | "jsx" | "tsx" => { - let (dev_server_path, intermediate_output_path) = + let (dev_server_path, intermediate_output_path, specificity) = if basename == "index" { - (server_path.join("index.html"), intermediate_output_path) + ( + server_path.join("index.html"), + intermediate_output_path, + specificity, + ) + } else if basename == "404" { + ( + server_path.join("[...]"), + intermediate_output_path.join(basename), + specificity.with_fallback(position), + ) } else { ( server_path.join(basename).join("index.html"), intermediate_output_path.join(basename), + specificity, ) }; sources.push(( @@ -246,6 +263,7 @@ async fn create_server_rendered_source_for_directory( context_path, context, pages_dir, + specificity, *file, runtime_entries, fallback_page, @@ -267,6 +285,8 @@ async fn create_server_rendered_source_for_directory( context_path, context, pages_dir, + specificity, + position + 1, *dir, runtime_entries, fallback_page, @@ -282,17 +302,12 @@ async fn create_server_rendered_source_for_directory( } } } - predefined_sources.sort_by_key(|(k, _)| *k); - named_placeholder_sources.sort_by_key(|(k, _)| *k); - catch_all_sources.sort_by_key(|(k, _)| *k); + + // Ensure deterministic order since read_dir is not deterministic + sources.sort_by_key(|(k, _)| *k); Ok(CombinedContentSource { - sources: predefined_sources - .into_iter() - .chain(named_placeholder_sources.into_iter()) - .chain(catch_all_sources.into_iter()) - .map(|(_, v)| v) - .collect(), + sources: sources.into_iter().map(|(_, v)| v).collect(), } .cell()) } diff --git a/packages/next-swc/crates/next-core/src/source_map/content_source.rs b/packages/next-swc/crates/next-core/src/source_map/content_source.rs index 7ecb25b8e20543..bb9e7e1ca6ac65 100644 --- a/packages/next-swc/crates/next-core/src/source_map/content_source.rs +++ b/packages/next-swc/crates/next-core/src/source_map/content_source.rs @@ -7,7 +7,7 @@ use turbopack_core::{ source_map::GenerateSourceMapVc, }; use turbopack_dev_server::source::{ - ContentSource, ContentSourceData, ContentSourceDataVary, ContentSourceResult, + ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, }; use url::Url; @@ -39,15 +39,17 @@ impl ContentSource for NextSourceMapTraceContentSource { ) -> Result<ContentSourceResultVc> { let url = match &data.url { None => { - return Ok(ContentSourceResult::NeedData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - url: true, - ..Default::default() - }, - } - .cell()); + return Ok(ContentSourceResultVc::exact( + ContentSourceContent::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + url: true, + ..Default::default() + }, + } + .cell(), + )); } Some(query) => query, }; @@ -56,45 +58,47 @@ impl ContentSource for NextSourceMapTraceContentSource { // could convert it into my struct. let query_idx = match url.find('?') { Some(i) => i, - _ => return Ok(ContentSourceResult::NotFound.cell()), + _ => return Ok(ContentSourceResultVc::not_found()), }; let frame: StackFrame = match serde_qs::from_str(&url[query_idx + 1..]) { Ok(f) => f, - _ => return Ok(ContentSourceResult::NotFound.cell()), + _ => return Ok(ContentSourceResultVc::not_found()), }; let (line, column) = match frame.get_pos() { Some((l, c)) => (l, c), - _ => return Ok(ContentSourceResult::NotFound.cell()), + _ => return Ok(ContentSourceResultVc::not_found()), }; // The file is some percent encoded `http://localhost:3000/_next/foo/bar.js` let file = match Url::parse(&frame.file) { Ok(u) => u, - _ => return Ok(ContentSourceResult::NotFound.cell()), + _ => return Ok(ContentSourceResultVc::not_found()), }; let path = match file.path().strip_prefix('/') { Some(p) => p, - _ => return Ok(ContentSourceResult::NotFound.cell()), + _ => return Ok(ContentSourceResultVc::not_found()), }; let this = self_vc.await?; - let file = this + let result = this .asset_source .get(path, Value::new(Default::default())) .await?; - let file = match &*file { - ContentSourceResult::Static(f) => f, - _ => return Ok(ContentSourceResult::NotFound.cell()), + let file = match &*result.content.await? { + ContentSourceContent::Static(f) => *f, + _ => return Ok(ContentSourceResultVc::not_found()), }; let gen = match GenerateSourceMapVc::resolve_from(file).await? { Some(f) => f, - _ => return Ok(ContentSourceResult::NotFound.cell()), + _ => return Ok(ContentSourceResultVc::not_found()), }; let traced = SourceMapTraceVc::new(gen.generate_source_map(), line, column, frame.name); - Ok(ContentSourceResult::Static(traced.content().into()).cell()) + Ok(ContentSourceResultVc::exact( + ContentSourceContent::Static(traced.content().into()).cell(), + )) } } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index b7071313beb891..7acbe14b0154ef 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -322,7 +322,7 @@ async fn source( } .cell() .into(); - let source_map_trace = NextSourceMapTraceContentSourceVc::new(rendered_source).into(); + let source_map_trace = NextSourceMapTraceContentSourceVc::new(main_source.into()).into(); let source = RouterContentSource { routes: vec![ ("__turbopack__/".to_string(), introspect), diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 436518fa62556b..f8cf2c936ec60e 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -10,8 +10,8 @@ use turbo_tasks_memory::{ }; use turbopack_core::asset::AssetContentVc; use turbopack_dev_server::source::{ - ContentSource, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, - ContentSourceResult, ContentSourceResultVc, ContentSourceVc, + ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter, + ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, }; #[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new", into = "new")] @@ -80,17 +80,19 @@ impl ContentSource for TurboTasksSource { let table = viz::table::create_table(tree); viz::table::wrap_html(&table) } else { - return Ok(ContentSourceResult::NeedData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - query: Some(ContentSourceDataFilter::Subset( - ["active".to_string()].into(), - )), - ..Default::default() - }, - } - .cell()); + return Ok(ContentSourceResultVc::exact( + ContentSourceContent::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + query: Some(ContentSourceDataFilter::Subset( + ["active".to_string()].into(), + )), + ..Default::default() + }, + } + .cell(), + )); } } "reset" => { @@ -100,12 +102,16 @@ impl ContentSource for TurboTasksSource { }); "Done".to_string() } - _ => return Ok(ContentSourceResult::NotFound.cell()), + _ => return Ok(ContentSourceResultVc::not_found()), }; - Ok(ContentSourceResult::Static( - AssetContentVc::from(File::from(html).with_content_type(Mime::from_str("text/html")?)) + Ok(ContentSourceResultVc::exact( + ContentSourceContent::Static( + AssetContentVc::from( + File::from(html).with_content_type(Mime::from_str("text/html")?), + ) .into(), - ) - .cell()) + ) + .cell(), + )) } } From 810508aed0f835409a060cf5a5a09667fa385a48 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Wed, 9 Nov 2022 21:04:57 +0100 Subject: [PATCH 223/672] add different keyed app route elements (vercel/turbo#2636) * add different keyed app route elements * update for latest next.js canary version * fix header name * setup next.js version in benchmark --- .../next-swc/crates/next-core/js/package.json | 2 +- .../next-core/js/src/dev/hot-reloader.tsx | 2 +- .../next-core/js/src/entry/app-renderer.tsx | 74 ++++++++-------- .../crates/next-core/src/app_render/mod.rs | 4 +- .../crates/next-core/src/app_source.rs | 87 +++++++++---------- .../next-dev/benches/bundlers/turbopack.rs | 2 +- 6 files changed, 80 insertions(+), 91 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index 716fd7c5eac2fb..9312acb7f064b7 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -12,7 +12,7 @@ "@vercel/turbopack-runtime": "latest", "anser": "2.1.1", "css.escape": "1.5.1", - "next": "12.3.2-canary.39", + "next": "13.0.3-canary.2", "platform": "1.3.6", "react-dom": "^18.2.0", "react": "^18.2.0", diff --git a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx index b9911765412021..a4ffc66efb1657 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx +++ b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx @@ -14,7 +14,7 @@ export default function HotReload({ assetPrefix, children }): any { { path, headers: { - __rsc__: "1", + rsc: "1", }, }, (update) => { diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index fd99d5e841b223..5a01ba7972e736 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -1,9 +1,21 @@ import type { Ipc } from "@vercel/turbopack-next/internal/ipc"; // Provided by the rust generate code +type FileType = + | "layout" + | "template" + | "error" + | "loading" + | "not-found" + | "head"; declare global { // an array of all layouts and the page - const LAYOUT_INFO: { segment: string; module: any; chunks: string[] }[]; + const LAYOUT_INFO: ({ + segment: string; + page?: { module: any; chunks: string[] }; + } & { + [componentKey in FileType]?: { module: any; chunks: string[] }; + })[]; // array of chunks for the bootstrap script const BOOTSTRAP: string[]; const IPC: Ipc<unknown, unknown>; @@ -21,7 +33,6 @@ import "next/dist/server/node-polyfill-web-streams"; import { RenderOpts, renderToHTMLOrFlight } from "next/dist/server/app-render"; import { PassThrough } from "stream"; import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; -import { structuredError } from "@vercel/turbopack-next/internal/error"; import { ParsedUrlQuery } from "node:querystring"; globalThis.__next_require__ = (data) => { @@ -77,16 +88,11 @@ type IpcOutgoingMessage = { // TODO expose these types in next.js type ComponentModule = () => any; +type ModuleReference = [componentModule: ComponentModule, filePath: string]; export type ComponentsType = { - readonly [componentKey in - | "layout" - | "template" - | "error" - | "loading" - | "not-found"]?: ComponentModule; + [componentKey in FileType]?: ModuleReference; } & { - readonly layoutOrPagePath?: string; - readonly page?: ComponentModule; + page?: ModuleReference; }; type LoaderTree = [ segment: string, @@ -102,31 +108,24 @@ type ServerComponentsManifestModule = { }; async function runOperation(renderData: RenderData) { + const layoutInfoChunks: Record<string, string[]> = {}; const pageItem = LAYOUT_INFO[LAYOUT_INFO.length - 1]; - const pageModule = pageItem.module; + const pageModule = pageItem.page!.module; const Page = pageModule.default; - let tree: LoaderTree = [ - "", - {}, - { page: () => Page, layoutOrPagePath: "page.js" }, - ]; + let tree: LoaderTree = ["", {}, { page: [() => Page, "page.js"] }]; + layoutInfoChunks["page.js"] = pageItem.page!.chunks; for (let i = LAYOUT_INFO.length - 2; i >= 0; i--) { const info = LAYOUT_INFO[i]; - const mod = info.module; - if (mod) { - const Layout = mod.default; - tree = [ - info.segment, - { children: tree }, - { layout: () => Layout, layoutOrPagePath: `layout${i}.js` }, - ]; - } else { - tree = [ - info.segment, - { children: tree }, - { layoutOrPagePath: `layout${i}.js` }, - ]; + const components: ComponentsType = {}; + for (const key of Object.keys(info)) { + if (key === "segment") { + continue; + } + const k = key as FileType; + components[k] = [() => info[k]!.module.default, `${k}${i}.js`]; + layoutInfoChunks[`${k}${i}.js`] = info[k]!.chunks; } + tree = [info.segment, { children: tree }, components]; } const proxyMethodsForModule = ( @@ -157,19 +156,15 @@ async function runOperation(renderData: RenderData) { const manifest: FlightManifest = new Proxy({} as any, proxyMethods(false)); const serverCSSManifest: FlightCSSManifest = {}; serverCSSManifest.__entry_css__ = {}; - for (let i = 0; i < LAYOUT_INFO.length - 1; i++) { - const { chunks } = LAYOUT_INFO[i]; - const cssChunks = (chunks || []).filter((path) => path.endsWith(".css")); - serverCSSManifest[`layout${i}.js`] = cssChunks.map((chunk) => + for (const [key, chunks] of Object.entries(layoutInfoChunks)) { + const cssChunks = chunks.filter((path) => path.endsWith(".css")); + serverCSSManifest[key] = cssChunks.map((chunk) => JSON.stringify([chunk, [chunk]]) ); } serverCSSManifest.__entry_css__ = { - page: pageItem.chunks - .filter((path) => path.endsWith(".css")) - .map((chunk) => JSON.stringify([chunk, [chunk]])), + page: serverCSSManifest["page.js"], }; - serverCSSManifest["page.js"] = serverCSSManifest.__entry_css__.page; const req: IncomingMessage = { url: renderData.url, method: renderData.method, @@ -185,7 +180,8 @@ async function runOperation(renderData: RenderData) { dev: true, buildManifest: { polyfillFiles: [], - rootMainFiles: LAYOUT_INFO.flatMap(({ chunks }) => chunks || []) + rootMainFiles: Object.values(layoutInfoChunks) + .flat() .concat(BOOTSTRAP) .filter((path) => !path.endsWith(".css")), devFiles: [], diff --git a/packages/next-swc/crates/next-core/src/app_render/mod.rs b/packages/next-swc/crates/next-core/src/app_render/mod.rs index 5c14d6ec56529c..b8fc4223954c39 100644 --- a/packages/next-swc/crates/next-core/src/app_render/mod.rs +++ b/packages/next-swc/crates/next-core/src/app_render/mod.rs @@ -1,10 +1,12 @@ +use std::collections::HashMap; + use turbo_tasks_fs::FileSystemPathVc; pub mod next_layout_entry_transition; #[turbo_tasks::value(shared)] pub struct LayoutSegment { - pub file: Option<FileSystemPathVc>, + pub files: HashMap<String, FileSystemPathVc>, pub target: FileSystemPathVc, } diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 8b1f7420e0068a..dbef683e124e99 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -1,4 +1,7 @@ -use std::{collections::HashMap, io::Write}; +use std::{ + collections::{BTreeMap, HashMap}, + io::Write, +}; use anyhow::{anyhow, Context, Result}; use turbo_tasks::{ @@ -289,20 +292,18 @@ async fn create_app_source_for_directory( let mut layouts = layouts; let mut sources = Vec::new(); let mut page = None; - let mut layout = None; + let mut files = HashMap::new(); if let DirectoryContent::Entries(entries) = &*input_dir.read_dir().await? { for (name, entry) in entries.iter() { - if let DirectoryEntry::File(file) = entry { + if let &DirectoryEntry::File(file) = entry { if let Some((name, _)) = name.rsplit_once('.') { match name { "page" => { page = Some(file); } - "layout" => { - layout = Some(file); + "layout" | "error" | "loading" | "template" | "not-found" | "head" => { + files.insert(name.to_string(), file); } - "error" => { /* TODO */ } - "loading" => { /* TODO */ } _ => { // Any other file is ignored } @@ -311,8 +312,7 @@ async fn create_app_source_for_directory( } } - let layout_js = input_dir.join("layout.js"); - let layout_tsx = input_dir.join("layout.tsx"); + let layout = files.get("layout"); // TODO: Use let Some(page_file) = page in expression below when // https://rust-lang.github.io/rfcs/2497-if-let-chains.html lands @@ -325,23 +325,23 @@ async fn create_app_source_for_directory( // stable does. let is_tsx = *page_file.extension().await? == "tsx"; - if is_tsx { - layout.replace(&layout_tsx); + let layout = if is_tsx { + input_dir.join("layout.tsx") } else { - layout.replace(&layout_js); - } + input_dir.join("layout.js") + }; + files.insert("layout".to_string(), layout); let content = if is_tsx { include_str!("assets/layout.tsx") } else { include_str!("assets/layout.js") }; - let layout = layout.context("required")?; layout.write(FileContentVc::from(File::from(content))); AppSourceIssue { severity: IssueSeverity::Warning.into(), - path: *page_file, + path: page_file, message: StringVc::cell(format!( "Your page {} did not have a root layout, we created {} for you.", page_file.await?.path, @@ -354,15 +354,9 @@ async fn create_app_source_for_directory( } let mut list = layouts.await?.clone_value(); - list.push( - LayoutSegment { - file: layout.copied(), - target, - } - .cell(), - ); + list.push(LayoutSegment { files, target }.cell()); layouts = LayoutSegmentsVc::cell(list); - if let Some(page_path) = page.copied() { + if let Some(page_path) = page { sources.push(create_node_rendered_source( specificity, server_root, @@ -440,7 +434,7 @@ impl NodeEntry for AppRenderer { #[turbo_tasks::function] async fn entry(&self, data: Value<ContentSourceData>) -> Result<NodeRenderingEntryVc> { let is_rsc = if let Some(headers) = data.into_value().headers { - headers.contains_key("__rsc__") + headers.contains_key("rsc") } else { false }; @@ -453,14 +447,14 @@ impl NodeEntry for AppRenderer { .copied() .chain(std::iter::once( LayoutSegment { - file: Some(page), + files: HashMap::from([("page".to_string(), page)]), target: self.target, } .cell(), )) .try_join() .await?; - let segments: Vec<(String, Option<(String, String, String)>)> = layout_and_page + let segments: Vec<(String, BTreeMap<String, (String, String, String)>)> = layout_and_page .into_iter() .fold( (self.server_root, Vec::new()), @@ -470,7 +464,8 @@ impl NodeEntry for AppRenderer { let target = &*segment.target.await?; let segment_path = last_path.await?.get_path_to(target).unwrap_or_default(); - if let Some(file) = segment.file { + let mut imports = BTreeMap::new(); + for (key, file) in segment.files.iter() { let file_str = file.to_string().await?; let identifier = magic_identifier::encode(&format!( "imported namespace {}", @@ -481,25 +476,21 @@ impl NodeEntry for AppRenderer { file_str )); if let Some(p) = path_value.get_relative_path_to(&*file.await?) { - Ok(( - stringify_str(segment_path), - Some((p, identifier, chunks_identifier)), - )) + imports.insert( + key.to_string(), + (p, identifier, chunks_identifier), + ); } else { - Err(anyhow!( + return Err(anyhow!( "Unable to generate import as there is no relative path to the layout module {} from context path {}", file_str, path.to_string().await? - )) + )); } - } else { - Ok::<(String, Option<(String, String, String)>), _>(( - stringify_str(segment_path), - None, - )) } + Ok((stringify_str(segment_path), imports)) }); futures }) @@ -513,8 +504,8 @@ impl NodeEntry for AppRenderer { "import IPC, { Ipc } from \"@vercel/turbopack-next/internal/ipc\";\n", ); - for (_, import) in segments.iter() { - if let Some((p, identifier, chunks_identifier)) = import { + for (_, imports) in segments.iter() { + for (p, identifier, chunks_identifier) in imports.values() { result += r#"("TURBOPACK { transition: next-layout-entry; chunking-type: parallel }"); "#; writeln!( @@ -537,16 +528,16 @@ import BOOTSTRAP from {}; } result += "const LAYOUT_INFO = ["; - for (segment_str_lit, import) in segments.iter() { - if let Some((_, identifier, chunks_identifier)) = import { + for (segment_str_lit, imports) in segments.iter() { + writeln!(result, " {{\n segment: {segment_str_lit},")?; + for (key, (_, identifier, chunks_identifier)) in imports { writeln!( result, - " {{ segment: {segment_str_lit}, module: {identifier}, chunks: \ - {chunks_identifier} }},", - )? - } else { - writeln!(result, " {{ segment: {segment_str_lit} }},",)? + " {key}: {{ module: {identifier}, chunks: {chunks_identifier} }},", + key = stringify_str(key), + )?; } + result += " },"; } result += "];\n\n"; @@ -558,7 +549,7 @@ import BOOTSTRAP from {}; let file = File::from(result.build()); let asset = VirtualAssetVc::new(path.join("entry"), file.into()); let (context, intermediate_output_path) = if is_rsc { - (self.context, self.intermediate_output_path.join("__rsc__")) + (self.context, self.intermediate_output_path.join("rsc")) } else { (self.context_ssr, self.intermediate_output_path) }; diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index b38e5a7e54a050..2e8603c9520eb9 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -58,7 +58,7 @@ impl Bundler for Turbopack { npm::install( install_dir, &[ - NpmPackage::new("next", "13.0.0"), + NpmPackage::new("next", "13.0.3-canary.2"), // Dependency on this is inserted by swc's preset_env NpmPackage::new("@swc/helpers", "^0.4.11"), ], From 00b15975bb4a68597385d5ada070631a2355d230 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Thu, 10 Nov 2022 10:54:31 +0100 Subject: [PATCH 224/672] clippy (vercel/turbo#2662) --- packages/next-swc/crates/next-core/src/app_source.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index dbef683e124e99..2e530f65889987 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -454,7 +454,7 @@ impl NodeEntry for AppRenderer { )) .try_join() .await?; - let segments: Vec<(String, BTreeMap<String, (String, String, String)>)> = layout_and_page + let segments: Vec<_> = layout_and_page .into_iter() .fold( (self.server_root, Vec::new()), From af6d90d2b6abf909ca6124844f809bf6088ecd42 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:42:32 -0800 Subject: [PATCH 225/672] feat(next-dev): align devserver cli options to napi bindings (vercel/turbo#2653) --- .../crates/next-dev/src/devserver_options.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index 826f69c492b9d8..ebc51eaa400417 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -66,18 +66,23 @@ pub struct DevServerOptions { pub log_detail: bool, // Inherited options from next-dev, need revisit later. - // These are not supported by CLI yet. - #[cfg(feature = "serializable")] + #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] + /// If port is not explicitly specified, use different port if it's already + /// in use. pub allow_retry: bool, - #[cfg(feature = "serializable")] + #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] + /// Internal for next.js, no specific usage yet. pub dev: bool, - #[cfg(feature = "serializable")] + #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] + /// Internal for next.js, no specific usage yet. pub is_next_dev_command: bool, - #[cfg(feature = "serializable")] + #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] + /// Specify server component external packages explicitly. This is an + /// experimental flag. pub server_components_external_packages: Vec<String>, } From 9711a7ef4ae895ed0d64056eb0cf239b87b5cc43 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Mon, 14 Nov 2022 10:26:39 +0100 Subject: [PATCH 226/672] Add profiling docs (vercel/turbo#2664) Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/src/lib.rs | 40 ++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index d3da3407675c6a..97a3af744a5560 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -27,6 +27,7 @@ tokio_console = [ "tokio/tracing", "turbo-tasks/tokio_tracing", ] +profile = [] [dependencies] anyhow = "1.0.47" diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 7acbe14b0154ef..642624c30dcad9 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -7,7 +7,7 @@ mod turbo_tasks_viz; use std::{ collections::HashSet, env::current_dir, - future::join, + future::{join, Future}, net::{IpAddr, SocketAddr}, path::MAIN_SEPARATOR, sync::Arc, @@ -431,9 +431,12 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { ); loop { - let (elapsed, _count) = tt_clone - .get_or_wait_update_info(Duration::from_millis(100)) - .await; + let update_future = profile_timeout( + tt_clone.as_ref(), + tt_clone.get_or_wait_update_info(Duration::from_millis(100)), + ); + + let (elapsed, _count) = update_future.await; println!( "{event_type} - updated in {elapsed}", event_type = "event".purple(), @@ -446,3 +449,32 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { Ok(()) } + +#[cfg(feature = "profile")] +// When profiling, exits the process when no new updates have been received for +// a given timeout and there are no more tasks in progress. +async fn profile_timeout<T>(tt: &TurboTasks<MemoryBackend>, future: impl Future<Output = T>) -> T { + /// How long to wait in between updates before force-exiting the process + /// during profiling. + const PROFILE_EXIT_TIMEOUT: Duration = Duration::from_secs(5); + + futures::pin_mut!(future); + loop { + match tokio::time::timeout(PROFILE_EXIT_TIMEOUT, &mut future).await { + Ok(res) => return res, + Err(_) => { + if tt.get_in_progress_count() == 0 { + std::process::exit(0) + } + } + } + } +} + +#[cfg(not(feature = "profile"))] +fn profile_timeout<T>( + _tt: &TurboTasks<MemoryBackend>, + future: impl Future<Output = T>, +) -> impl Future<Output = T> { + future +} From 32593ea30d468d5df28b6bae14fdbe0bd521c598 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon, 14 Nov 2022 10:35:06 +0100 Subject: [PATCH 227/672] retry CI setup steps if needed (vercel/turbo#2692) * retry setup steps if needed * retry install nextest step * retry browser launch * ignore errors from PR comment failing due to PR from fork --- .../next-swc/crates/next-dev/benches/util/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index 827565e6c0842a..ab8ef213a855ad 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -140,7 +140,17 @@ pub async fn create_browser() -> Browser { if with_devtools { builder = builder.arg("--auto-open-devtools-for-tabs"); } - let (browser, mut handler) = Browser::launch(builder.build().unwrap()).await.unwrap(); + let (browser, mut handler) = retry_async( + builder.build().unwrap(), + |c| { + let c = c.clone(); + async { Ok(Browser::launch(c).await?) } + }, + 3, + Duration::from_millis(100), + ) + .await + .expect("Launching the browser failed"); // See https://crates.io/crates/chromiumoxide tokio::task::spawn(async move { From 5320ba564f6598e929f365945af0f8357376c8e9 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon, 14 Nov 2022 11:57:59 +0100 Subject: [PATCH 228/672] update next.js to 13.0.3 (vercel/turbo#2677) --- packages/next-swc/crates/next-core/js/package.json | 2 +- packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index 9312acb7f064b7..fe205897e3e430 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -12,7 +12,7 @@ "@vercel/turbopack-runtime": "latest", "anser": "2.1.1", "css.escape": "1.5.1", - "next": "13.0.3-canary.2", + "next": "13.0.3", "platform": "1.3.6", "react-dom": "^18.2.0", "react": "^18.2.0", diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index 2e8603c9520eb9..e60114c24cf78b 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -58,7 +58,7 @@ impl Bundler for Turbopack { npm::install( install_dir, &[ - NpmPackage::new("next", "13.0.3-canary.2"), + NpmPackage::new("next", "13.0.3"), // Dependency on this is inserted by swc's preset_env NpmPackage::new("@swc/helpers", "^0.4.11"), ], From 886a86d98b4686dd63d5322c6e0e74d976760826 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon, 14 Nov 2022 15:32:54 +0100 Subject: [PATCH 229/672] retry launching browser in test suite (vercel/turbo#2695) --- packages/next-swc/crates/next-dev/Cargo.toml | 4 +- .../crates/next-dev/benches/util/mod.rs | 57 ++----------------- .../crates/next-dev/tests/integration.rs | 15 ++++- 3 files changed, 23 insertions(+), 53 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 97a3af744a5560..e19239c22c2daf 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -63,8 +63,10 @@ once_cell = "1.13.0" regex = "1.6.0" tempfile = "3.3.0" test-generator = "0.3.0" +# For matching on errors from chromiumoxide. Keep in # sync with chromiumoxide's tungstenite requirement. -tungstenite = "0.17.3" # For matching on errors from chromiumoxide. Keep in +tungstenite = "0.17.3" +turbo-tasks-testing = { path = "../turbo-tasks-testing" } turbopack-create-test-app = { path = "../turbopack-create-test-app" } [target.'cfg(unix)'.dev-dependencies] diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index ab8ef213a855ad..57a0d4cfcd6a3f 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -22,6 +22,7 @@ pub use prepared_app::PreparedApp; use regex::Regex; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; use turbo_tasks::util::FormatDuration; +use turbo_tasks_testing::retry::{retry, retry_async}; use turbopack_create_test_app::test_app_builder::{PackageJsonConfig, TestApp, TestAppBuilder}; use crate::bundlers::Bundler; @@ -32,64 +33,18 @@ mod prepared_app; pub const BINDING_NAME: &str = "__turbopackBenchBinding"; -fn retry<A, F, R>(mut args: A, f: F, max_retries: usize, mut timeout: Duration) -> Result<R> +fn retry_default<A, F, R, E>(args: A, f: F) -> Result<R, E> where - F: Fn(&mut A) -> Result<R>, -{ - let mut retries = 0usize; - loop { - match f(&mut args) { - Ok(value) => return Ok(value), - Err(e) => { - if retries >= max_retries { - return Err(e); - } - retries += 1; - std::thread::sleep(timeout); - timeout += timeout; - } - } - } -} - -fn retry_default<A, F, R>(args: A, f: F) -> Result<R> -where - F: Fn(&mut A) -> Result<R>, + F: Fn(&mut A) -> Result<R, E>, { // waits 5, 10, 20, 40 seconds = 75 seconds total retry(args, f, 3, Duration::from_secs(5)) } -async fn retry_async<A, F, Fut, R>( - mut args: A, - f: F, - max_retries: usize, - mut timeout: Duration, -) -> Result<R> -where - F: Fn(&mut A) -> Fut, - Fut: Future<Output = Result<R>>, -{ - let mut retries = 0usize; - loop { - match f(&mut args).await { - Ok(value) => return Ok(value), - Err(e) => { - if retries >= max_retries { - return Err(e); - } - retries += 1; - tokio::time::sleep(timeout).await; - timeout += timeout; - } - } - } -} - -async fn retry_async_default<A, F, Fut, R>(args: A, f: F) -> Result<R> +async fn retry_async_default<A, F, Fut, R, E>(args: A, f: F) -> Result<R, E> where F: Fn(&mut A) -> Fut, - Fut: Future<Output = Result<R>>, + Fut: Future<Output = Result<R, E>>, { // waits 5, 10, 20, 40 seconds = 75 seconds total retry_async(args, f, 3, Duration::from_secs(5)).await @@ -144,7 +99,7 @@ pub async fn create_browser() -> Browser { builder.build().unwrap(), |c| { let c = c.clone(); - async { Ok(Browser::launch(c).await?) } + Browser::launch(c) }, 3, Duration::from_millis(100), diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index 1911e1134fb4cc..ee2de8f695ede0 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -5,8 +5,10 @@ use std::{ env, net::SocketAddr, path::{Path, PathBuf}, + time::Duration, }; +use anyhow::Context; use chromiumoxide::{ browser::{Browser, BrowserConfig}, error::CdpError::Ws, @@ -22,6 +24,7 @@ use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Pro use turbo_tasks::TurboTasks; use turbo_tasks_fs::util::sys_to_unix; use turbo_tasks_memory::MemoryBackend; +use turbo_tasks_testing::retry::retry_async; #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] @@ -164,7 +167,17 @@ async fn create_browser( .args(vec!["--auto-open-devtools-for-tabs"]); } - let (browser, mut handler) = Browser::launch(config_builder.build()?).await?; + let (browser, mut handler) = retry_async( + config_builder.build()?, + |c| { + let c = c.clone(); + Browser::launch(c) + }, + 3, + Duration::from_millis(100), + ) + .await + .context("Launching browser failed")?; // See https://crates.io/crates/chromiumoxide let thread_handle = tokio::task::spawn(async move { loop { From 6225f75a065d5c7c8df39b29e0390d767386b44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florentin=20/=20=E7=8F=9E=E8=BE=B0?= <ecklf@icloud.com> Date: Mon, 14 Nov 2022 19:10:08 +0100 Subject: [PATCH 230/672] feat: polyfill `global` with `globalThis` (vercel/turbo#2666) This PR changes the ecmascript chunk logic to polyfill `global` with `globalThis`. A more complex and less performant solution (but with the benefit of us knowing the runtime environment) would be to add an effect for simple identifier expressions. --- .../tests/integration/turbopack/basic/polyfill/index.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/polyfill/index.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/polyfill/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/polyfill/index.js new file mode 100644 index 00000000000000..6e999067360b72 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/polyfill/index.js @@ -0,0 +1,3 @@ +it("polyfills `global` to `globalThis`", () => { + expect(global).toBe(globalThis); +}); From 7e2173c092e4fde45030f1d57c8ee679005e5afe Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Wed, 16 Nov 2022 15:45:11 +0100 Subject: [PATCH 231/672] use iterations feature from criterion (vercel/turbo#2708) * use iterations feature from criterion move startup, warmup and teardown out of the iteration loop to avoid tracking this time as elapsed time this allows criterion to use the measurement time correctly for the measured task prefer slope over mean when possible as it estimates the real time (excluding warmup) * remove warmup argument * stop server for next iteration * refactor * restore verbose info, exclude file read from timing * add a little bit of delay between HMR updates * make a warmup change * no need to copy template dir for HMR benchmark * add delay after warmup change * add watch benchmark * add/fix comments * fix env var in CI --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + .../next-swc/crates/next-dev/benches/mod.rs | 176 +++++++++++------- .../crates/next-dev/benches/util/mod.rs | 157 ++++++++-------- .../next-dev/benches/util/prepared_app.rs | 28 ++- 4 files changed, 216 insertions(+), 146 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index e19239c22c2daf..8c76058588092c 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -60,6 +60,7 @@ criterion = { version = "0.3.5", features = ["async_tokio"] } fs_extra = "1.2.0" lazy_static = "1.4.0" once_cell = "1.13.0" +parking_lot = "0.12.1" regex = "1.6.0" tempfile = "3.3.0" test-generator = "0.3.0" diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 47fc029c5d04bf..4b5b6eda0a94eb 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -8,18 +8,20 @@ use std::{ use anyhow::{anyhow, Context, Result}; use bundlers::get_bundlers; use criterion::{ - criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, BenchmarkId, Criterion, + criterion_group, criterion_main, + measurement::{Measurement, WallTime}, + BenchmarkGroup, BenchmarkId, Criterion, }; use once_cell::sync::Lazy; use tokio::{ runtime::Runtime, time::{sleep, timeout}, }; -use util::{ - build_test, create_browser, AsyncBencherExtension, PageGuard, PreparedApp, BINDING_NAME, -}; +use turbo_tasks::util::FormatDuration; +use util::{build_test, create_browser, AsyncBencherExtension, PreparedApp, BINDING_NAME}; use self::util::resume_on_error; +use crate::util::PageGuard; mod bundlers; mod util; @@ -74,23 +76,28 @@ fn bench_startup_internal(mut g: BenchmarkGroup<WallTime>, hydration: bool) { BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, test_app)| { - b.to_async(&runtime).try_iter_async( - || async { - PreparedApp::new(bundler, test_app.path().to_path_buf()).await - }, - |app| async { Ok(app) }, - |mut app| async { + let test_app = &**test_app; + b.to_async(&runtime).try_iter_custom(|iters, m| async move { + let mut value = m.zero(); + + for _ in 0..iters { + let mut app = + PreparedApp::new(bundler, test_app.path().to_path_buf()) + .await?; + let start = m.start(); app.start_server()?; let mut guard = app.with_page(browser).await?; if wait_for_hydration { guard.wait_for_hydration().await?; } + let duration = m.end(start); + value = m.add(&value, &duration); - // Defer the dropping of the guard to `teardown`. - Ok(guard) - }, - |_guard| async move {}, - ); + // Defer the dropping of the guard. + drop(guard); + } + Ok(value) + }); }, ); })); @@ -122,6 +129,9 @@ fn bench_hmr_to_commit(c: &mut Criterion) { } fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { + // Only capture one sample for warmup + g.warm_up_time(Duration::from_millis(1)); + let runtime = Runtime::new().unwrap(); let browser = &runtime.block_on(create_browser()); @@ -138,11 +148,12 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, test_app)| { + let test_app = &**test_app; fn add_code( app_path: &Path, code: &str, location: CodeLocation, - ) -> Result<()> { + ) -> Result<impl FnOnce() -> Result<()>> { let triangle_path = app_path.join("src/triangle.jsx"); let mut contents = fs::read_to_string(&triangle_path)?; const INSERTED_CODE_COMMENT: &str = "// Inserted Code:\n"; @@ -181,19 +192,18 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { } } - fs::write(&triangle_path, contents)?; - Ok(()) + Ok(move || Ok(fs::write(&triangle_path, contents)?)) } static CHANGE_TIMEOUT_MESSAGE: &str = "update was not registered by bundler"; - async fn make_change<'a>( - guard: &mut PageGuard<'a>, + async fn make_change( + guard: &mut PageGuard<'_>, location: CodeLocation, - timeout_duration: Duration, - ) -> Result<()> { + m: &WallTime, + ) -> Result<Duration> { let msg = format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); - add_code( + let commit = add_code( guard.app().path(), &format!( "globalThis.{BINDING_NAME} && \ @@ -202,19 +212,31 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { location, )?; - // Wait for the change introduced above to be reflected at runtime. - // This expects HMR or automatic reloading to occur. - timeout(timeout_duration, guard.wait_for_binding(&msg)) + let start = m.start(); + commit()?; + + // Wait for the change introduced above to be reflected at + // runtime. This expects HMR or automatic reloading to occur. + timeout(MAX_UPDATE_TIMEOUT, guard.wait_for_binding(&msg)) .await .context(CHANGE_TIMEOUT_MESSAGE)??; - Ok(()) + let duration = m.end(start); + + // TODO(sokra) triggering HMR updates too fast can have weird effects + tokio::time::sleep(std::cmp::max(duration, Duration::from_millis(100))) + .await; + + Ok(duration) } - b.to_async(Runtime::new().unwrap()).try_iter_async( + b.to_async(&runtime).try_iter_async( + &runtime, || async { - let mut app = - PreparedApp::new(bundler, test_app.path().to_path_buf()) - .await?; + let mut app = PreparedApp::new_without_copy( + bundler, + test_app.path().to_path_buf(), + ) + .await?; app.start_server()?; let mut guard = app.with_page(browser).await?; if bundler.has_interactivity() { @@ -230,21 +252,36 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { "Unable to evaluate JavaScript in the page for HMR check \ flag", )?; + + // TODO(alexkirsz) Turbopack takes a few ms to start listening on + // HMR, and we don't send updates retroactively, so we need to wait + // before starting to make changes. + // This should not be required. + tokio::time::sleep(Duration::from_millis(5000)).await; + + // Make a warmup change + make_change(&mut guard, location, &WallTime).await?; + Ok(guard) }, - |mut guard| async move { - // Make 5 changes to warm up. - for _ in 0..5 { - let _ = - make_change(&mut guard, location, MAX_UPDATE_TIMEOUT).await; + |mut guard, iters, m, verbose| async move { + let mut value = m.zero(); + for iter in 0..iters { + let duration = make_change(&mut guard, location, &m).await?; + value = m.add(&value, &duration); + + let i: u64 = iter + 1; + if verbose && i != iters && i.count_ones() == 1 { + eprint!( + " [{:?} {:?}/{}]", + duration, + FormatDuration(value / (i as u32)), + i + ); + } } - Ok(guard) - }, - |mut guard| async move { - make_change(&mut guard, location, MAX_UPDATE_TIMEOUT).await?; - // Defer the dropping of the guard to `teardown`. - Ok(guard) + Ok((guard, value)) }, |guard| async move { let hmr_is_happening = guard @@ -321,41 +358,44 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, test_app)| { - b.to_async(Runtime::new().unwrap()).try_iter_async( - || async { - // Run a complete build, shut down, and test running it again - let mut app = - PreparedApp::new(bundler, test_app.path().to_path_buf()) - .await?; - app.start_server()?; - let mut guard = app.with_page(browser).await?; - if bundler.has_interactivity() { - guard.wait_for_hydration().await?; - } else { - guard.page().wait_for_navigation().await?; - } + let test_app = &**test_app; + b.to_async(&runtime).try_iter_custom(|iters, m| async move { + // Run a complete build, shut down, and test running it again + let mut app = + PreparedApp::new(bundler, test_app.path().to_path_buf()).await?; + app.start_server()?; + let mut guard = app.with_page(browser).await?; + if bundler.has_interactivity() { + guard.wait_for_hydration().await?; + } else { + guard.page().wait_for_navigation().await?; + } - let mut app = guard.close_page().await?; + let mut app = guard.close_page().await?; - // Give it 4 seconds time to store the cache - sleep(Duration::from_secs(4)).await; + // Give it 4 seconds time to store the cache + sleep(Duration::from_secs(4)).await; - app.stop_server()?; - Ok(app) - }, - |app| async { Ok(app) }, - |mut app| async { + app.stop_server()?; + + let mut value = m.zero(); + for _ in 0..iters { + let start = m.start(); app.start_server()?; let mut guard = app.with_page(browser).await?; if wait_for_hydration { guard.wait_for_hydration().await?; } + let duration = m.end(start); + value = m.add(&value, &duration); - // Defer the dropping of the guard to `teardown`. - Ok(guard) - }, - |_guard| async move {}, - ); + app = guard.close_page().await?; + app.stop_server()?; + } + + drop(app); + Ok(value) + }); }, ); })); diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index 57a0d4cfcd6a3f..e8b0d408162367 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -2,7 +2,7 @@ use std::{ io::{self, BufRead, BufReader, Read, Write}, panic::UnwindSafe, process::Command, - time::Duration, + time::{Duration, Instant}, }; use anyhow::Result; @@ -10,14 +10,10 @@ use chromiumoxide::{ browser::{Browser, BrowserConfig}, error::CdpError::Ws, }; -use criterion::{ - async_executor::AsyncExecutor, - black_box, - measurement::{Measurement, WallTime}, - AsyncBencher, -}; +use criterion::{async_executor::AsyncExecutor, black_box, measurement::WallTime, AsyncBencher}; use futures::{Future, StreamExt}; pub use page_guard::PageGuard; +use parking_lot::Mutex; pub use prepared_app::PreparedApp; use regex::Regex; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; @@ -131,105 +127,118 @@ pub fn resume_on_error<F: FnOnce() + UnwindSafe>(f: F) { } } -pub trait AsyncBencherExtension { - fn try_iter_async<I, O, S, SF, W, WF, R, F, T, TF>( +pub trait AsyncBencherExtension<A: AsyncExecutor> { + fn try_iter_custom<R, F>(&mut self, routine: R) + where + R: Fn(u64, WallTime) -> F, + F: Future<Output = Result<Duration>>; + + fn try_iter_async<I, S, SF, R, F, T, TF>( &mut self, + runner: A, setup: S, - warmup: W, routine: R, teardown: T, ) where S: Fn() -> SF, SF: Future<Output = Result<I>>, - W: Fn(I) -> WF, - WF: Future<Output = Result<I>>, - R: Fn(I) -> F, - F: Future<Output = Result<O>>, - T: Fn(O) -> TF, + R: Fn(I, u64, WallTime, bool) -> F, + F: Future<Output = Result<(I, Duration)>>, + T: Fn(I) -> TF, TF: Future<Output = ()>; } -impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension for AsyncBencher<'a, 'b, A, WallTime> { - #[inline(never)] - fn try_iter_async<I, O, S, SF, W, WF, R, F, T, TF>( +impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension<A> for AsyncBencher<'a, 'b, A, WallTime> { + fn try_iter_custom<R, F>(&mut self, routine: R) + where + R: Fn(u64, WallTime) -> F, + F: Future<Output = Result<Duration>>, + { + let log_progress = !matches!( + std::env::var("TURBOPACK_BENCH_PROGRESS").ok().as_deref(), + None | Some("") | Some("no") | Some("false") + ); + + let routine = &routine; + self.iter_custom(|iters| async move { + let measurement = WallTime; + let value = routine(iters, measurement).await.expect("routine failed"); + if log_progress { + eprint!(" {:?}/{}", FormatDuration(value / (iters as u32)), iters); + } + value + }); + } + + fn try_iter_async<I, S, SF, R, F, T, TF>( &mut self, + runner: A, setup: S, - warmup: W, routine: R, teardown: T, ) where S: Fn() -> SF, SF: Future<Output = Result<I>>, - W: Fn(I) -> WF, - WF: Future<Output = Result<I>>, - R: Fn(I) -> F, - F: Future<Output = Result<O>>, - T: Fn(O) -> TF, + R: Fn(I, u64, WallTime, bool) -> F, + F: Future<Output = Result<(I, Duration)>>, + T: Fn(I) -> TF, TF: Future<Output = ()>, { - let config = std::env::var("TURBOPACK_BENCH_BENCH").ok(); - let bench_benchmark_itself = !matches!( - config.as_deref(), - None | Some("") | Some("no") | Some("false") - ); let log_progress = !matches!( std::env::var("TURBOPACK_BENCH_PROGRESS").ok().as_deref(), None | Some("") | Some("no") | Some("false") ); let setup = &setup; - let warmup = &warmup; let routine = &routine; let teardown = &teardown; + let input_mutex = &Mutex::new(Some(black_box(runner.block_on(async { + if log_progress { + eprint!(" setup..."); + } + let start = Instant::now(); + let input = retry_async_default((), |_| setup()) + .await + .expect("failed to setup"); + if log_progress { + let duration = start.elapsed(); + eprint!(" [{:?}]", FormatDuration(duration)); + } + input + })))); + self.iter_custom(|iters| async move { let measurement = WallTime; - let mut value = measurement.zero(); - - let mut iter = 0u64; - let mut failures = 0u64; - while iter < iters { - loop { - let early_start = bench_benchmark_itself.then(|| measurement.start()); - let input = black_box( - retry_async_default((), |_| setup()) - .await - .expect("failed to setup"), - ); - let input = black_box(warmup(input).await).expect("failed to warmup"); - - let start = early_start.unwrap_or_else(|| measurement.start()); - match routine(input).await { - Ok(output) => { - let duration; - if bench_benchmark_itself { - teardown(black_box(output)).await; - duration = measurement.end(start); - } else { - duration = measurement.end(start); - teardown(black_box(output)).await; - } - if log_progress { - eprint!(" {} ", FormatDuration(duration)); - } - value = measurement.add(&value, &duration); - iter += 1; - break; - } - Err(err) => { - failures += 1; - if failures > iters { - panic!("Routine failed {failures} times, aborting\n{:?}", err) - } else { - eprintln!("Routine failed, will be retried: {:?}", err); - continue; - } - } - } - } + + let input = input_mutex + .lock() + .take() + .expect("iter_custom only executes its closure once"); + + let (output, value) = routine(input, iters, measurement, log_progress) + .await + .expect("Routine failed"); + let output = black_box(output); + + if log_progress { + eprint!(" {:?}/{}", FormatDuration(value / (iters as u32)), iters); } + input_mutex.lock().replace(output); + value - }) + }); + + let input = input_mutex.lock().take().unwrap(); + if log_progress { + eprint!(" teardown..."); + } + let start = Instant::now(); + runner.block_on(teardown(input)); + let duration = start.elapsed(); + if log_progress { + eprintln!(" [{:?}]", FormatDuration(duration)); + } } } diff --git a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs index 8260d486c68cd4..3d6b6d8df57fa0 100644 --- a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs +++ b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs @@ -58,10 +58,15 @@ async fn copy_dir(from: PathBuf, to: PathBuf) -> anyhow::Result<()> { Ok(()) } +enum PreparedDir { + TempDir(tempfile::TempDir), + Path(PathBuf), +} + pub struct PreparedApp<'a> { bundler: &'a dyn Bundler, server: Option<(Child, String)>, - test_dir: tempfile::TempDir, + test_dir: PreparedDir, counter: usize, } @@ -75,7 +80,19 @@ impl<'a> PreparedApp<'a> { Ok(Self { bundler, server: None, - test_dir, + test_dir: PreparedDir::TempDir(test_dir), + counter: 0, + }) + } + + pub async fn new_without_copy( + bundler: &'a dyn Bundler, + template_dir: PathBuf, + ) -> Result<PreparedApp<'a>> { + Ok(Self { + bundler, + server: None, + test_dir: PreparedDir::Path(template_dir), counter: 0, }) } @@ -88,7 +105,7 @@ impl<'a> PreparedApp<'a> { pub fn start_server(&mut self) -> Result<()> { assert!(self.server.is_none(), "Server already started"); - self.server = Some(self.bundler.start_server(self.test_dir.path())?); + self.server = Some(self.bundler.start_server(self.path())?); Ok(()) } @@ -155,7 +172,10 @@ impl<'a> PreparedApp<'a> { } pub fn path(&self) -> &Path { - self.test_dir.path() + match self.test_dir { + PreparedDir::TempDir(ref dir) => dir.path(), + PreparedDir::Path(ref path) => path, + } } } From 3c8bf5cb332dfeae2cfdfb128477745d67427956 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Wed, 16 Nov 2022 16:14:46 +0100 Subject: [PATCH 232/672] use latest version for parcel and webpack too (vercel/turbo#2678) --- .../crates/next-dev/benches/bundlers/parcel.rs | 4 ++-- .../crates/next-dev/benches/bundlers/vite/mod.rs | 4 ++-- .../next-dev/benches/bundlers/webpack/mod.rs | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs b/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs index dd35e60afcd82d..d6ce56ab3ef5d0 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/parcel.rs @@ -24,10 +24,10 @@ impl Bundler for Parcel { npm::install( install_dir, &[ - NpmPackage::new("parcel", "2.7.0"), + NpmPackage::new("parcel", "^2.8.0"), // `process` would otherwise be auto-installed by Parcel. Do this in advance as // to not influence the benchmark. - NpmPackage::new("process", "0.11.0"), + NpmPackage::new("process", "^0.11.10"), ], ) .context("failed to install from npm")?; diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs index 50f070c7e4784e..14a0f0fb3803c1 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs @@ -32,8 +32,8 @@ impl Bundler for Vite { npm::install( install_dir, &[ - NpmPackage::new("vite", "3.0.9"), - NpmPackage::new("@vitejs/plugin-react", "2.1.0"), + NpmPackage::new("vite", "^3.2.4"), + NpmPackage::new("@vitejs/plugin-react", "^2.2.0"), ], ) .context("failed to install from npm")?; diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs index 8f2c1e040e48f5..1fe7add999217b 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs @@ -25,13 +25,13 @@ impl Bundler for Webpack { npm::install( install_dir, &[ - NpmPackage::new("@pmmmwh/react-refresh-webpack-plugin", "0.5.7"), - NpmPackage::new("@swc/core", "1.2.249"), - NpmPackage::new("react-refresh", "0.14.0"), - NpmPackage::new("swc-loader", "0.2.3"), - NpmPackage::new("webpack", "5.74.0"), - NpmPackage::new("webpack-cli", "4.10.0"), - NpmPackage::new("webpack-dev-server", "4.11.0"), + NpmPackage::new("@pmmmwh/react-refresh-webpack-plugin", "^0.5.7"), + NpmPackage::new("@swc/core", "^1.2.249"), + NpmPackage::new("react-refresh", "^0.14.0"), + NpmPackage::new("swc-loader", "^0.2.3"), + NpmPackage::new("webpack", "^5.75.0"), + NpmPackage::new("webpack-cli", "^4.10.0"), + NpmPackage::new("webpack-dev-server", "^4.11.0"), ], ) .context("failed to install from npm")?; From 16e27669da1f1e66ad2af1cf0061cac178a15e38 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Wed, 16 Nov 2022 18:59:09 +0100 Subject: [PATCH 233/672] fix HMR for RSC benchmarking (vercel/turbo#2698) measure hmr_to_commit with detector component add Next.js 13 to benchmarks with RSC and RCC measurements this tests RSC HMR make HMR warmup faster make browser launch lazy test benchmarks for other bundlers on CI too # Conflicts: # .github/workflows/test.yml # crates/next-dev/benches/mod.rs --- .../crates/next-dev/benches/bundlers/mod.rs | 75 +++++++-- .../bundlers/{nextjs.rs => nextjs/mod.rs} | 40 +++-- .../benches/bundlers/nextjs/next.config.js | 5 + .../next-dev/benches/bundlers/turbopack.rs | 22 +-- .../next-swc/crates/next-dev/benches/mod.rs | 156 +++++++++++------- .../crates/next-dev/benches/util/mod.rs | 8 +- 6 files changed, 193 insertions(+), 113 deletions(-) rename packages/next-swc/crates/next-dev/benches/bundlers/{nextjs.rs => nextjs/mod.rs} (81%) create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/nextjs/next.config.js diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs index 99be70ac0e53a7..2a2212a9229af5 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs @@ -16,6 +16,20 @@ mod turbopack; mod vite; mod webpack; +#[derive(Debug, Clone, Copy)] +pub enum RenderType { + /// App is completely rendered on client side, the initial HTML is empty. + ClientSideRendered, + /// App is intially rendered on server side, then hydrated on client side. + ServerSidePrerendered, + /// App is rendered on server side, but additional client side javascript + /// emits events on hydration and changes + ServerSideRenderedWithEvents, + /// App is rendered on server side, without any client side events. + #[allow(dead_code)] + ServerSideRenderedWithoutInteractivity, +} + pub trait Bundler { fn get_name(&self) -> &str; fn get_path(&self) -> &str { @@ -24,15 +38,17 @@ pub trait Bundler { fn react_version(&self) -> &str { "^18.2.0" } - /// The initial HTML is enough to render the page even without JavaScript - /// loaded - fn has_server_rendered_html(&self) -> bool { - false + fn render_type(&self) -> RenderType { + RenderType::ClientSideRendered } /// There is a hydration done event emitted by client side JavaScript - fn has_interactivity(&self) -> bool { - true + fn has_hydration_event(&self) -> bool { + !matches!( + self.render_type(), + RenderType::ServerSideRenderedWithoutInteractivity + ) } + fn prepare(&self, _template_dir: &Path) -> Result<()> { Ok(()) } @@ -59,30 +75,59 @@ pub fn get_bundlers() -> Vec<Box<dyn Bundler>> { } let mut bundlers: Vec<Box<dyn Bundler>> = Vec::new(); if turbopack { - bundlers.push(Box::new(Turbopack::new("Turbopack CSR", "/", false, true))); + bundlers.push(Box::new(Turbopack::new( + "Turbopack CSR", + "/", + RenderType::ClientSideRendered, + ))); bundlers.push(Box::new(Turbopack::new( "Turbopack SSR", "/page", - true, - true, + RenderType::ServerSidePrerendered, ))); bundlers.push(Box::new(Turbopack::new( "Turbopack RSC", "/app", - true, - false, + RenderType::ServerSideRenderedWithEvents, ))); bundlers.push(Box::new(Turbopack::new( "Turbopack RCC", "/client", - true, - true, + RenderType::ServerSidePrerendered, ))); } if others { - bundlers.push(Box::new(NextJs::new(NextJsVersion::V12))); - bundlers.push(Box::new(NextJs::new(NextJsVersion::V11))); + bundlers.push(Box::new(NextJs::new( + NextJsVersion::V13, + "Next.js 13 SSR", + "/page", + RenderType::ServerSidePrerendered, + ))); + bundlers.push(Box::new(NextJs::new( + NextJsVersion::V13, + "Next.js 13 RSC", + "/app", + RenderType::ServerSideRenderedWithEvents, + ))); + bundlers.push(Box::new(NextJs::new( + NextJsVersion::V13, + "Next.js 13 RCC", + "/client", + RenderType::ServerSidePrerendered, + ))); + bundlers.push(Box::new(NextJs::new( + NextJsVersion::V12, + "Next.js 12 SSR", + "/page", + RenderType::ServerSidePrerendered, + ))); + bundlers.push(Box::new(NextJs::new( + NextJsVersion::V11, + "Next.js 11 SSR", + "/page", + RenderType::ServerSidePrerendered, + ))); bundlers.push(Box::new(Parcel {})); bundlers.push(Box::new(Vite::new())); bundlers.push(Box::new(Webpack {})); diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs/mod.rs similarity index 81% rename from packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs rename to packages/next-swc/crates/next-dev/benches/bundlers/nextjs/mod.rs index d4fe15e505b64c..0d732d09b25fc4 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/nextjs.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs/mod.rs @@ -1,5 +1,5 @@ use std::{ - fmt::Display, + fs, path::Path, process::{Child, Command, Stdio}, }; @@ -7,6 +7,7 @@ use std::{ use anyhow::{anyhow, Context, Result}; use regex::Regex; +use super::RenderType; use crate::{ bundlers::Bundler, util::{ @@ -19,18 +20,23 @@ use crate::{ pub enum NextJsVersion { V11, V12, + V13, } #[derive(Debug)] pub struct NextJs { version: NextJsVersion, name: String, + path: String, + render_type: RenderType, } impl NextJs { - pub fn new(version: NextJsVersion) -> Self { + pub fn new(version: NextJsVersion, name: &str, path: &str, render_type: RenderType) -> Self { Self { - name: format!("{version} SSR"), + name: name.to_owned(), + path: path.to_owned(), + render_type, version, } } @@ -42,15 +48,15 @@ impl Bundler for NextJs { } fn get_path(&self) -> &str { - "/page" + &self.path } - fn react_version(&self) -> &str { - self.version.react_version() + fn render_type(&self) -> RenderType { + self.render_type } - fn has_server_rendered_html(&self) -> bool { - true + fn react_version(&self) -> &str { + self.version.react_version() } fn prepare(&self, install_dir: &Path) -> Result<()> { @@ -59,6 +65,13 @@ impl Bundler for NextJs { &[NpmPackage::new("next", self.version.version())], ) .context("failed to install `next` module")?; + + if matches!(self.version, NextJsVersion::V13) { + fs::write( + install_dir.join("next.config.js"), + include_bytes!("next.config.js"), + )?; + } Ok(()) } @@ -101,21 +114,13 @@ impl Bundler for NextJs { } } -impl Display for NextJsVersion { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - NextJsVersion::V11 => write!(f, "Next.js 11"), - NextJsVersion::V12 => write!(f, "Next.js 12"), - } - } -} - impl NextJsVersion { /// Returns the version of Next.js to install from npm. pub fn version(&self) -> &'static str { match self { NextJsVersion::V11 => "^11", NextJsVersion::V12 => "^12", + NextJsVersion::V13 => "^13", } } @@ -125,6 +130,7 @@ impl NextJsVersion { match self { NextJsVersion::V11 => "^17.0.2", NextJsVersion::V12 => "^18.2.0", + NextJsVersion::V13 => "^18.2.0", } } } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/nextjs/next.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs/next.config.js new file mode 100644 index 00000000000000..ed0e87891f9e83 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/nextjs/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + experimental: { + appDir: true, + }, +}; diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs index e60114c24cf78b..ec15749b2dd18d 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs @@ -6,6 +6,7 @@ use std::{ use anyhow::{anyhow, Context, Result}; use regex::Regex; +use super::RenderType; use crate::{ bundlers::Bundler, util::{ @@ -17,22 +18,15 @@ use crate::{ pub struct Turbopack { name: String, path: String, - has_server_rendered_html: bool, - has_interactivity: bool, + render_type: RenderType, } impl Turbopack { - pub fn new( - name: &str, - path: &str, - has_server_rendered_html: bool, - has_interactivity: bool, - ) -> Self { + pub fn new(name: &str, path: &str, render_type: RenderType) -> Self { Turbopack { name: name.to_owned(), path: path.to_owned(), - has_server_rendered_html, - has_interactivity, + render_type, } } } @@ -46,12 +40,8 @@ impl Bundler for Turbopack { &self.path } - fn has_server_rendered_html(&self) -> bool { - self.has_server_rendered_html - } - - fn has_interactivity(&self) -> bool { - self.has_interactivity + fn render_type(&self) -> RenderType { + self.render_type } fn prepare(&self, install_dir: &Path) -> Result<()> { diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index 4b5b6eda0a94eb..ae060159ff893c 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -20,8 +20,8 @@ use tokio::{ use turbo_tasks::util::FormatDuration; use util::{build_test, create_browser, AsyncBencherExtension, PreparedApp, BINDING_NAME}; -use self::util::resume_on_error; -use crate::util::PageGuard; +use self::{bundlers::RenderType, util::resume_on_error}; +use crate::{bundlers::Bundler, util::PageGuard}; mod bundlers; mod util; @@ -46,27 +46,30 @@ fn bench_hydration(c: &mut Criterion) { fn bench_startup_internal(mut g: BenchmarkGroup<WallTime>, hydration: bool) { let runtime = Runtime::new().unwrap(); - let browser = &runtime.block_on(create_browser()); + let browser = Lazy::new(|| runtime.block_on(create_browser())); for bundler in get_bundlers() { - let wait_for_hydration = if !bundler.has_server_rendered_html() { - // For bundlers without server rendered html "startup" means time to hydration - // as they only render an empty screen without hydration. Since startup and - // hydration would be the same we skip the hydration benchmark for them. - if hydration { - continue; - } else { - true + let wait_for_hydration = match bundler.render_type() { + RenderType::ClientSideRendered => { + // For bundlers without server rendered html "startup" means time to hydration + // as they only render an empty screen without hydration. Since startup and + // hydration would be the same we skip the hydration benchmark for them. + if hydration { + continue; + } else { + true + } } - } else if !bundler.has_interactivity() { - // For bundlers without interactivity there is no hydration event to wait for - if hydration { - continue; - } else { - false + RenderType::ServerSidePrerendered => hydration, + RenderType::ServerSideRenderedWithEvents => hydration, + RenderType::ServerSideRenderedWithoutInteractivity => { + // For bundlers without interactivity there is no hydration event to wait for + if hydration { + continue; + } else { + false + } } - } else { - hydration }; for module_count in get_module_counts() { let test_app = Lazy::new(|| build_test(module_count, bundler.as_ref())); @@ -77,6 +80,7 @@ fn bench_startup_internal(mut g: BenchmarkGroup<WallTime>, hydration: bool) { &input, |b, &(bundler, test_app)| { let test_app = &**test_app; + let browser = &*browser; b.to_async(&runtime).try_iter_custom(|iters, m| async move { let mut value = m.zero(); @@ -133,11 +137,17 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { g.warm_up_time(Duration::from_millis(1)); let runtime = Runtime::new().unwrap(); - let browser = &runtime.block_on(create_browser()); + let browser = Lazy::new(|| runtime.block_on(create_browser())); for bundler in get_bundlers() { - // TODO HMR for RSC is broken, fix it and enable it here - if !bundler.has_interactivity() { + if matches!( + bundler.render_type(), + RenderType::ServerSideRenderedWithEvents + | RenderType::ServerSideRenderedWithoutInteractivity + ) && matches!(location, CodeLocation::Evaluation) + { + // We can't measure evaluation time for these bundlers since it's not evaluated + // in the browser continue; } for module_count in get_module_counts() { @@ -149,35 +159,44 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { &input, |b, &(bundler, test_app)| { let test_app = &**test_app; + let browser = &*browser; fn add_code( + bundler: &dyn Bundler, app_path: &Path, - code: &str, + msg: &str, location: CodeLocation, ) -> Result<impl FnOnce() -> Result<()>> { let triangle_path = app_path.join("src/triangle.jsx"); let mut contents = fs::read_to_string(&triangle_path)?; const INSERTED_CODE_COMMENT: &str = "// Inserted Code:\n"; const COMPONENT_START: &str = "function Container({ style }) {\n"; - match location { - CodeLocation::Effect => { + const DETECTOR_START: &str = "<Detector "; + const DETECTOR_END: &str = "/>"; + match (location, bundler.render_type()) { + (CodeLocation::Effect, _) => { let a = contents - .find(COMPONENT_START) - .ok_or_else(|| anyhow!("unable to find component start"))?; - let b = contents - .find("\n return <>") - .ok_or_else(|| anyhow!("unable to find component start"))?; + .find(DETECTOR_START) + .ok_or_else(|| anyhow!("unable to find detector start"))?; + let b = a + contents[a..] + .find(DETECTOR_END) + .ok_or_else(|| anyhow!("unable to find detector end"))?; contents.replace_range( a..b, - &format!( - "{COMPONENT_START} React.useEffect(() => {{ {code} \ - }});\n" - ), + &format!("{DETECTOR_START}message=\"{msg}\" "), ); } - CodeLocation::Evaluation => { + ( + CodeLocation::Evaluation, + RenderType::ClientSideRendered + | RenderType::ServerSidePrerendered, + ) => { let b = contents .find(COMPONENT_START) .ok_or_else(|| anyhow!("unable to find component start"))?; + let code = format!( + "globalThis.{BINDING_NAME} && \ + globalThis.{BINDING_NAME}('{msg}');" + ); if let Some(a) = contents.find(INSERTED_CODE_COMMENT) { contents.replace_range( a..b, @@ -190,6 +209,16 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { ); } } + ( + CodeLocation::Evaluation, + RenderType::ServerSideRenderedWithEvents + | RenderType::ServerSideRenderedWithoutInteractivity, + ) => { + panic!( + "evaluation can't be measured for bundlers which evaluate \ + on server side" + ); + } } Ok(move || Ok(fs::write(&triangle_path, contents)?)) @@ -197,20 +226,14 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { static CHANGE_TIMEOUT_MESSAGE: &str = "update was not registered by bundler"; async fn make_change( + bundler: &dyn Bundler, guard: &mut PageGuard<'_>, location: CodeLocation, m: &WallTime, ) -> Result<Duration> { let msg = format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); - let commit = add_code( - guard.app().path(), - &format!( - "globalThis.{BINDING_NAME} && \ - globalThis.{BINDING_NAME}('{msg}');" - ), - location, - )?; + let commit = add_code(bundler, guard.app().path(), &msg, location)?; let start = m.start(); commit()?; @@ -239,7 +262,7 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { .await?; app.start_server()?; let mut guard = app.with_page(browser).await?; - if bundler.has_interactivity() { + if bundler.has_hydration_event() { guard.wait_for_hydration().await?; } else { guard.page().wait_for_navigation().await?; @@ -260,14 +283,15 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { tokio::time::sleep(Duration::from_millis(5000)).await; // Make a warmup change - make_change(&mut guard, location, &WallTime).await?; + make_change(bundler, &mut guard, location, &WallTime).await?; Ok(guard) }, |mut guard, iters, m, verbose| async move { let mut value = m.zero(); for iter in 0..iters { - let duration = make_change(&mut guard, location, &m).await?; + let duration = + make_change(bundler, &mut guard, location, &m).await?; value = m.add(&value, &duration); let i: u64 = iter + 1; @@ -327,27 +351,30 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo } let runtime = Runtime::new().unwrap(); - let browser = &runtime.block_on(create_browser()); + let browser = Lazy::new(|| runtime.block_on(create_browser())); for bundler in get_bundlers() { - let wait_for_hydration = if !bundler.has_server_rendered_html() { - // For bundlers without server rendered html "startup" means time to hydration - // as they only render an empty screen without hydration. Since startup and - // hydration would be the same we skip the hydration benchmark for them. - if hydration { - continue; - } else { - true + let wait_for_hydration = match bundler.render_type() { + RenderType::ClientSideRendered => { + // For bundlers without server rendered html "startup" means time to hydration + // as they only render an empty screen without hydration. Since startup and + // hydration would be the same we skip the hydration benchmark for them. + if hydration { + continue; + } else { + true + } } - } else if !bundler.has_interactivity() { - // For bundlers without interactivity there is no hydration event to wait for - if hydration { - continue; - } else { - false + RenderType::ServerSidePrerendered => hydration, + RenderType::ServerSideRenderedWithEvents => hydration, + RenderType::ServerSideRenderedWithoutInteractivity => { + // For bundlers without interactivity there is no hydration event to wait for + if hydration { + continue; + } else { + false + } } - } else { - hydration }; for module_count in get_module_counts() { let test_app = Lazy::new(|| build_test(module_count, bundler.as_ref())); @@ -359,13 +386,14 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo &input, |b, &(bundler, test_app)| { let test_app = &**test_app; + let browser = &*browser; b.to_async(&runtime).try_iter_custom(|iters, m| async move { // Run a complete build, shut down, and test running it again let mut app = PreparedApp::new(bundler, test_app.path().to_path_buf()).await?; app.start_server()?; let mut guard = app.with_page(browser).await?; - if bundler.has_interactivity() { + if bundler.has_hydration_event() { guard.wait_for_hydration().await?; } else { guard.page().wait_for_navigation().await?; diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index e8b0d408162367..f8d917b1370864 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -117,8 +117,14 @@ pub async fn create_browser() -> Browser { pub fn resume_on_error<F: FnOnce() + UnwindSafe>(f: F) { let runs_as_bench = std::env::args().find(|a| a == "--bench"); + let ignore_errors = !matches!( + std::env::var("TURBOPACK_BENCH_IGNORE_ERRORS") + .ok() + .as_deref(), + None | Some("") | Some("no") | Some("false") + ); - if runs_as_bench.is_some() { + if runs_as_bench.is_some() || ignore_errors { use std::panic::catch_unwind; // panics are already printed to the console, so no need to handle the result. let _ = catch_unwind(f); From fd2688b98403142ab811bcb175bf8148b10f90c5 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Thu, 17 Nov 2022 15:58:19 +0100 Subject: [PATCH 234/672] add benchmarks for Vite SSR and SWC (vercel/turbo#2751) --- .../crates/next-dev/benches/bundlers/mod.rs | 4 +- .../next-dev/benches/bundlers/vite/mod.rs | 71 +++++++++++++------ .../benches/bundlers/vite/vite.swc.config.js | 7 ++ 3 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs index 2a2212a9229af5..fef726fb5dc1c6 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs @@ -129,7 +129,9 @@ pub fn get_bundlers() -> Vec<Box<dyn Bundler>> { RenderType::ServerSidePrerendered, ))); bundlers.push(Box::new(Parcel {})); - bundlers.push(Box::new(Vite::new())); + bundlers.push(Box::new(Vite::new(false, false))); + bundlers.push(Box::new(Vite::new(true, false))); + bundlers.push(Box::new(Vite::new(false, true))); bundlers.push(Box::new(Webpack {})); } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs index 14a0f0fb3803c1..81780d218251c8 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs @@ -15,50 +15,81 @@ use crate::{ }, }; -pub struct Vite; +pub struct Vite { + swc: bool, + ssr: bool, +} impl Vite { - pub fn new() -> Self { - Vite {} + pub fn new(swc: bool, ssr: bool) -> Self { + Vite { swc, ssr } } } impl Bundler for Vite { fn get_name(&self) -> &str { - "Vite CSR" + if self.ssr { + if self.swc { + "Vite SWC SSR" + } else { + "Vite SSR" + } + } else { + if self.swc { + "Vite SWC CSR" + } else { + "Vite CSR" + } + } } fn prepare(&self, install_dir: &Path) -> Result<()> { - npm::install( - install_dir, - &[ - NpmPackage::new("vite", "^3.2.4"), - NpmPackage::new("@vitejs/plugin-react", "^2.2.0"), - ], - ) - .context("failed to install from npm")?; + let mut packages = vec![NpmPackage::new("vite", "^3.2.4")]; + if self.swc { + packages.push(NpmPackage::new("vite-plugin-swc-react-refresh", "^2.2.0")); + } else { + packages.push(NpmPackage::new("@vitejs/plugin-react", "^2.2.0")); + }; + if self.ssr { + packages.push(NpmPackage::new("express", "^4.18.2")); + } + npm::install(install_dir, &packages).context("failed to install from npm")?; fs::write( install_dir.join("vite.config.js"), - include_bytes!("vite.config.js"), + if self.swc { + include_bytes!("vite.swc.config.js") as &[u8] + } else { + include_bytes!("vite.config.js") as &[u8] + }, )?; Ok(()) } fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { - let mut proc = Command::new("node") - .args([ - (test_dir + let args = if self.ssr { + vec![test_dir + .join("vite-server.mjs") + .to_str() + .unwrap() + .to_string()] + } else { + vec![ + test_dir .join("node_modules") .join("vite") .join("bin") .join("vite.js") .to_str() - .unwrap()), - "--port", - "0", - ]) + .unwrap() + .to_string(), + "--port".to_string(), + "0".to_string(), + ] + }; + let mut proc = Command::new("node") + .args(args) .env("NO_COLOR", "1") .current_dir(test_dir) .stdout(Stdio::piped()) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js new file mode 100644 index 00000000000000..ad4d9c808f4d74 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import { swcReactRefresh } from "vite-plugin-swc-react-refresh"; + +export default defineConfig({ + plugins: [swcReactRefresh()], + esbuild: { jsx: "automatic" }, +}); From 4a05036850190d2a6438f69eab34dd2d6219d46f Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:31:31 -0800 Subject: [PATCH 235/672] feat(next-dev): support port via env variable (vercel/turbo#2770) --- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- .../next-swc/crates/next-dev/src/devserver_options.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 8c76058588092c..e3217fc83e1e02 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -31,7 +31,7 @@ profile = [] [dependencies] anyhow = "1.0.47" -clap = { version = "4.0.18", features = ["derive"] } +clap = { version = "4.0.18", features = ["derive", "env"] } console-subscriber = { version = "0.1.6", optional = true } futures = "0.3.21" mime = "0.3.16" diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index ebc51eaa400417..a409b87135e998 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -24,9 +24,12 @@ pub struct DevServerOptions { pub root: Option<PathBuf>, /// The port number on which to start the application + /// Note: setting env PORT allows to configure port without explicit cli + /// args. However, this is temporary measure to conform with existing + /// next.js devserver and can be removed in the future. #[cfg_attr( feature = "cli", - clap(short, long, value_parser, default_value_t = 3000) + clap(short, long, value_parser, default_value_t = 3000, env = "PORT") )] #[cfg_attr(feature = "serializable", serde(default = "default_port"))] pub port: u16, @@ -88,7 +91,10 @@ pub struct DevServerOptions { #[cfg(feature = "serializable")] fn default_port() -> u16 { - 3000 + std::env::var("PORT") + .ok() + .and_then(|port| port.parse().ok()) + .unwrap_or(3000) } #[cfg(feature = "serializable")] From 0b841ad61f36a8db5cff22866beb9a27b8f3ea91 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Tue, 22 Nov 2022 08:50:27 -0800 Subject: [PATCH 236/672] feat(next/dev): allow to display version (vercel/turbo#2793) --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/build.rs | 5 +++ .../crates/next-dev/src/devserver_options.rs | 5 +++ packages/next-swc/crates/next-dev/src/main.rs | 37 +++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index e3217fc83e1e02..be5aa47dc96002 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -75,3 +75,4 @@ nix = "0.25.0" [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } +vergen = { version = "7.3.2", default-features = false, features = ["cargo","git"] } \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev/build.rs b/packages/next-swc/crates/next-dev/build.rs index 1673efed59cce6..ae549614245fdf 100644 --- a/packages/next-swc/crates/next-dev/build.rs +++ b/packages/next-swc/crates/next-dev/build.rs @@ -1,5 +1,10 @@ use turbo_tasks_build::generate_register; +use vergen::{vergen, Config}; fn main() { generate_register(); + + // Attempt to collect some build time env values but will skip if there are any + // errors. + let _ = vergen(Config::default()); } diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index a409b87135e998..367d2d2c51dd80 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -48,6 +48,11 @@ pub struct DevServerOptions { #[cfg_attr(feature = "serializable", serde(default))] pub eager_compile: bool, + /// Display version of the binary. Noop if used in library mode. + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] + pub display_version: bool, + /// Don't open the browser automatically when the dev server has started. #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 87c474cee70837..7816b8ed7a2bca 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -18,5 +18,42 @@ fn main() -> Result<()> { async fn main() -> Result<()> { let options = next_dev::devserver_options::DevServerOptions::parse(); + if options.display_version { + println!( + "Build Timestamp\t\t{:#?}", + option_env!("VERGEN_BUILD_TIMESTAMP").unwrap_or_else(|| "N/A") + ); + println!( + "Build Version\t\t{:#?}", + option_env!("VERGEN_BUILD_SEMVER").unwrap_or_else(|| "N/A") + ); + println!( + "Commit SHA\t\t{:#?}", + option_env!("VERGEN_GIT_SHA").unwrap_or_else(|| "N/A") + ); + println!( + "Commit Date\t\t{:#?}", + option_env!("VERGEN_GIT_COMMIT_TIMESTAMP").unwrap_or_else(|| "N/A") + ); + println!( + "Commit Branch\t\t{:#?}", + option_env!("VERGEN_GIT_BRANCH").unwrap_or_else(|| "N/A") + ); + println!( + "Commit Message\t\t{:#?}", + option_env!("VERGEN_GIT_COMMIT_MESSAGE").unwrap_or_else(|| "N/A") + ); + println!( + "Cargo Target Triple\t{:#?}", + option_env!("VERGEN_CARGO_TARGET_TRIPLE").unwrap_or_else(|| "N/A") + ); + println!( + "Cargo Profile\t\t{:#?}", + option_env!("VERGEN_CARGO_PROFILE").unwrap_or_else(|| "N/A") + ); + + return Ok(()); + } + next_dev::start_server(&options).await } From 4a6959da430e034b6d091c6ec876b788c1e3021c Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Tue, 22 Nov 2022 19:55:56 -0800 Subject: [PATCH 237/672] fix(next-dev): disable git version info (vercel/turbo#2815) --- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- packages/next-swc/crates/next-dev/src/main.rs | 17 +---------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index be5aa47dc96002..fab465e9f07b2a 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -75,4 +75,4 @@ nix = "0.25.0" [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } -vergen = { version = "7.3.2", default-features = false, features = ["cargo","git"] } \ No newline at end of file +vergen = { version = "7.3.2", default-features = false, features = ["cargo", "build"] } \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 7816b8ed7a2bca..2cee37320b0c2f 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -19,6 +19,7 @@ async fn main() -> Result<()> { let options = next_dev::devserver_options::DevServerOptions::parse(); if options.display_version { + // Note: enabling git causes trouble with aarch64 linux builds with libz-sys println!( "Build Timestamp\t\t{:#?}", option_env!("VERGEN_BUILD_TIMESTAMP").unwrap_or_else(|| "N/A") @@ -27,22 +28,6 @@ async fn main() -> Result<()> { "Build Version\t\t{:#?}", option_env!("VERGEN_BUILD_SEMVER").unwrap_or_else(|| "N/A") ); - println!( - "Commit SHA\t\t{:#?}", - option_env!("VERGEN_GIT_SHA").unwrap_or_else(|| "N/A") - ); - println!( - "Commit Date\t\t{:#?}", - option_env!("VERGEN_GIT_COMMIT_TIMESTAMP").unwrap_or_else(|| "N/A") - ); - println!( - "Commit Branch\t\t{:#?}", - option_env!("VERGEN_GIT_BRANCH").unwrap_or_else(|| "N/A") - ); - println!( - "Commit Message\t\t{:#?}", - option_env!("VERGEN_GIT_COMMIT_MESSAGE").unwrap_or_else(|| "N/A") - ); println!( "Cargo Target Triple\t{:#?}", option_env!("VERGEN_CARGO_TARGET_TRIPLE").unwrap_or_else(|| "N/A") From 1603cd2cffef1f0642804ddbf5b9c60996a4c143 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Fri, 25 Nov 2022 17:46:40 +0100 Subject: [PATCH 238/672] fix fallback overlay (vercel/turbo#2829) --- packages/next-swc/crates/next-core/src/app_source.rs | 2 +- packages/next-swc/crates/next-core/src/fallback.rs | 11 ++++++++--- .../crates/next-core/src/next_client/context.rs | 5 +++-- .../next-swc/crates/next-core/src/next_import_map.rs | 2 ++ .../crates/next-core/src/server_rendered_source.rs | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 2e530f65889987..f4a79a1fa0e051 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -255,7 +255,7 @@ pub async fn create_app_source( let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_root, env).as_ecmascript_chunk_placeable()]; - let fallback_page = get_fallback_page(project_root, server_root, browserslist_query); + let fallback_page = get_fallback_page(project_root, server_root, env, browserslist_query); Ok(create_app_source_for_directory( context_ssr, diff --git a/packages/next-swc/crates/next-core/src/fallback.rs b/packages/next-swc/crates/next-core/src/fallback.rs index ec8dc487bf4dda..c265b12e6e90c4 100644 --- a/packages/next-swc/crates/next-core/src/fallback.rs +++ b/packages/next-swc/crates/next-core/src/fallback.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use anyhow::{bail, Result}; use turbo_tasks::Value; +use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ ecmascript::EcmascriptModuleAssetVc, transition::TransitionsByNameVc, ModuleAssetContextVc, @@ -17,7 +18,7 @@ use crate::{ embed_js::attached_next_js_package_path, next_client::context::{ get_client_chunking_context, get_client_environment, get_client_module_options_context, - get_client_resolve_options_context, ContextType, + get_client_resolve_options_context, get_client_runtime_entries, ContextType, }, next_import_map::insert_next_shared_aliases, runtime::resolve_runtime_request, @@ -27,13 +28,15 @@ use crate::{ pub async fn get_fallback_page( project_root: FileSystemPathVc, dev_server_root: FileSystemPathVc, + env: ProcessEnvVc, browserslist_query: &str, ) -> Result<DevHtmlAssetVc> { - let ty = Value::new(ContextType::Other); + let ty = Value::new(ContextType::Fallback); let environment = get_client_environment(browserslist_query); let resolve_options_context = get_client_resolve_options_context(project_root, ty); let module_options_context = get_client_module_options_context(project_root, environment, ty); let chunking_context = get_client_chunking_context(project_root, dev_server_root, ty); + let entries = get_client_runtime_entries(project_root, env, ty); let mut import_map = ImportMap::empty(); insert_next_shared_aliases(&mut import_map, attached_next_js_package_path(project_root)); @@ -46,6 +49,8 @@ pub async fn get_fallback_page( ) .into(); + let runtime_entries = entries.resolve_entries(context); + let fallback_chunk = resolve_runtime_request( PlainResolveOriginVc::new(context, project_root).into(), "entry/fallback", @@ -59,7 +64,7 @@ pub async fn get_fallback_page( bail!("fallback runtime entry is not an ecmascript module"); }; - let chunk = module.as_evaluated_chunk(chunking_context, None); + let chunk = module.as_evaluated_chunk(chunking_context, Some(runtime_entries)); Ok(DevHtmlAssetVc::new( dev_server_root.join("fallback.html"), diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 1fd5a83e50e6b1..304ad101a830ca 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -55,6 +55,7 @@ pub fn get_client_environment(browserslist_query: &str) -> EnvironmentVc { pub enum ContextType { Pages { pages_dir: FileSystemPathVc }, App { app_dir: FileSystemPathVc }, + Fallback, Other, } @@ -167,7 +168,7 @@ pub fn get_client_chunking_context( ContextType::Pages { .. } | ContextType::App { .. } => { server_root.join("/_next/static/chunks") } - ContextType::Other => server_root.join("/_chunks"), + ContextType::Fallback | ContextType::Other => server_root.join("/_chunks"), }, get_client_assets_path(server_root, ty), ) @@ -184,7 +185,7 @@ pub fn get_client_assets_path( ContextType::Pages { .. } | ContextType::App { .. } => { server_root.join("/_next/static/assets") } - ContextType::Other => server_root.join("/_assets"), + ContextType::Fallback | ContextType::Other => server_root.join("/_assets"), } } diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index b1fa94f868d1b5..e02ec301be57fe 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -59,6 +59,7 @@ pub fn get_next_client_import_map( request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); } + ContextType::Fallback => {} ContextType::Other => {} } import_map.cell() @@ -86,6 +87,7 @@ pub fn get_next_client_fallback_import_map(ty: Value<ContextType>) -> ImportMapV ); } } + ContextType::Fallback => {} ContextType::Other => {} } diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index ff22518744a979..c7098465498988 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -113,7 +113,7 @@ pub async fn create_server_rendered_source( let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_path, env).as_ecmascript_chunk_placeable()]; - let fallback_page = get_fallback_page(project_path, server_root, browserslist_query); + let fallback_page = get_fallback_page(project_path, server_root, env, browserslist_query); let server_rendered_source = create_server_rendered_source_for_directory( project_path, From c0b3e0a1c1352e09d7b0f507123f71a8a1fa57f6 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Fri, 25 Nov 2022 21:06:37 +0100 Subject: [PATCH 239/672] get upstream error overlay changes and fix typescript errors (vercel/turbo#2830) * pull upstream changes * ts fixes --- .../crates/next-core/js/src/dev/hmr-client.ts | 16 +- .../next-core/js/src/dev/hot-reloader.tsx | 10 +- .../next-core/js/src/entry/app/hydrate.tsx | 9 +- .../js/src/entry/server-renderer.tsx | 1 + .../crates/next-core/js/src/overlay/client.ts | 13 +- .../js/src/overlay/internal/ErrorBoundary.tsx | 27 ++- .../src/overlay/internal/ReactDevOverlay.tsx | 215 ++++++++++++------ .../next-core/js/src/overlay/internal/bus.ts | 3 + .../components/Overlay/maintain--tab-focus.ts | 2 +- .../next-core/js/types/compiled-next.d.ts | 1 + .../crates/next-core/js/types/globals.d.ts | 4 + .../crates/next-core/js/types/next.d.ts | 4 +- 12 files changed, 208 insertions(+), 97 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/types/compiled-next.d.ts diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 0296bc024f7290..7480e49b7f0614 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -13,7 +13,12 @@ import type { import stripAnsi from "@vercel/turbopack-next/compiled/strip-ansi"; -import { onBuildOk, onRefresh, onTurbopackError } from "../overlay/client"; +import { + onBeforeRefresh, + onBuildOk, + onRefresh, + onTurbopackError, +} from "../overlay/client"; import { addEventListener, sendMessage } from "./websocket"; import { ModuleId } from "@vercel/turbopack-runtime/types"; import { HmrUpdateEntry } from "@vercel/turbopack-runtime/types/protocol"; @@ -232,16 +237,17 @@ function handleSocketMessage(msg: ServerMessage) { if (hasErrors) return; - if (chunksWithErrors.size === 0) { - onBuildOk(); - } - if (aggregatedMsg.type !== "issues") { + onBeforeRefresh(); triggerUpdate(aggregatedMsg); if (chunksWithErrors.size === 0) { onRefresh(); } } + + if (chunksWithErrors.size === 0) { + onBuildOk(); + } } export function onChunkUpdate(chunkPath: ChunkPath, callback: UpdateCallback) { diff --git a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx index a4ffc66efb1657..9ba09f5a1cc3fe 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx +++ b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx @@ -6,9 +6,14 @@ import { useEffect } from "react"; import { onUpdate } from "./hmr-client"; import { ReactDevOverlay } from "./client"; -export default function HotReload({ assetPrefix, children }): any { +type HotReloadProps = React.PropsWithChildren<{ + assetPrefix?: string; +}>; + +export default function HotReload({ assetPrefix, children }: HotReloadProps) { const router = useRouter(); - const path = usePathname().slice(1); + const path = usePathname()!.slice(1); + useEffect(() => { const unsubscribe = onUpdate( { @@ -25,5 +30,6 @@ export default function HotReload({ assetPrefix, children }): any { ); return unsubscribe; }, [router, path]); + return <ReactDevOverlay globalOverlay={true}>{children}</ReactDevOverlay>; } diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx index 5f4bd3d80ac286..a3f23143427d31 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx @@ -17,7 +17,7 @@ globalThis.__next_require__ = (data) => { }; globalThis.__next_chunk_load__ = __turbopack_load__; -process.env.__NEXT_NEW_LINK_BEHAVIOR = true; +process.env.__NEXT_NEW_LINK_BEHAVIOR = "true"; const appElement = document; @@ -51,7 +51,7 @@ function nextServerDataCallback( return 0; } -function nextServerDataRegisterWriter(ctr) { +function nextServerDataRegisterWriter(ctr: ReadableStreamDefaultController) { if (initialServerDataBuffer) { initialServerDataBuffer.forEach((val) => { ctr.enqueue(encoder.encode(val)); @@ -136,7 +136,10 @@ function hydrate() { const isError = document.documentElement.id === "__next_error__"; if (isError) { - const reactRoot = ReactDOMClient.createRoot(appElement); + // cast necessary because of a typing bug + const reactRoot = ReactDOMClient.createRoot( + appElement as unknown as DocumentFragment + ); reactRoot.render(reactEl); } else { React.startTransition(() => { diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index ac9f559c2a9936..8498c532136344 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -118,6 +118,7 @@ async function runOperation( imageSizes: [], loader: "default", path: "", + loaderFile: "", domains: [], disableStaticImages: false, minimumCacheTTL: 0, diff --git a/packages/next-swc/crates/next-core/js/src/overlay/client.ts b/packages/next-swc/crates/next-core/js/src/overlay/client.ts index f55fabb9b3be5c..d71db90343f77f 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/client.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/client.ts @@ -89,6 +89,10 @@ function onTurbopackError(issue: Issue) { Bus.emit({ type: Bus.TYPE_TURBOPACK_ERROR, issue }); } +function onBeforeRefresh() { + Bus.emit({ type: Bus.TYPE_BEFORE_REFRESH }); +} + function onRefresh() { Bus.emit({ type: Bus.TYPE_REFRESH }); } @@ -96,4 +100,11 @@ function onRefresh() { export { getErrorByType } from "./internal/helpers/getErrorByType"; export { getServerError } from "./internal/helpers/nodeStackFrames"; export { default as ReactDevOverlay } from "./internal/ReactDevOverlay"; -export { onBuildOk, onTurbopackError, register, unregister, onRefresh }; +export { + onBuildOk, + onTurbopackError, + register, + unregister, + onBeforeRefresh, + onRefresh, +}; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/ErrorBoundary.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/ErrorBoundary.tsx index d9a012950772c8..de60f977d288c1 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/ErrorBoundary.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/ErrorBoundary.tsx @@ -33,19 +33,24 @@ class ErrorBoundary extends React.PureComponent< render() { // The component has to be unmounted or else it would continue to error - return this.state.error || - (this.props.globalOverlay && this.props.isMounted) ? ( + if ( + this.state.error || + (this.props.globalOverlay && this.props.isMounted) + ) { // When the overlay is global for the application and it wraps a component rendering `<html>` // we have to render the html shell otherwise the shadow root will not be able to attach - this.props.globalOverlay ? ( - <html> - <head></head> - <body></body> - </html> - ) : null - ) : ( - this.props.children - ); + if (this.props.globalOverlay) { + return ( + <html> + <body></body> + </html> + ); + } + + return null; + } + + return this.props.children; } } diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx index b47a28c2c635e9..be141df93f42a0 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx @@ -11,12 +11,39 @@ import { Base } from "./styles/Base"; import { ComponentStyles } from "./styles/ComponentStyles"; import { CssReset } from "./styles/CssReset"; +type RefreshState = + | { + // No refresh in progress. + type: "idle"; + } + | { + // The refresh process has been triggered, but the new code has not been + // executed yet. + type: "pending"; + errors: SupportedErrorEvent[]; + }; + type OverlayState = { nextId: number; issue: Issue | null; errors: SupportedErrorEvent[]; + + refreshState: RefreshState; }; +function pushErrorFilterDuplicates( + errors: SupportedErrorEvent[], + err: SupportedErrorEvent +): SupportedErrorEvent[] { + return [ + ...errors.filter((e) => { + // Filter out duplicate errors + return e.event.reason !== err.event.reason; + }), + err, + ]; +} + function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState { switch (ev.type) { case Bus.TYPE_BUILD_OK: { @@ -25,23 +52,56 @@ function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState { case Bus.TYPE_TURBOPACK_ERROR: { return { ...state, issue: ev.issue }; } - case Bus.TYPE_REFRESH: { - return { ...state, issue: null, errors: [] }; + case Bus.TYPE_BEFORE_REFRESH: { + return { ...state, refreshState: { type: "pending", errors: [] } }; } - case Bus.TYPE_UNHANDLED_ERROR: - case Bus.TYPE_UNHANDLED_REJECTION: { + case Bus.TYPE_REFRESH: { return { ...state, - nextId: state.nextId + 1, - errors: [ - ...state.errors.filter((err) => { - // Filter out duplicate errors - return err.event.reason !== ev.reason; - }), - { id: state.nextId, event: ev }, - ], + issue: null, + errors: + // Errors can come in during updates. In this case, UNHANDLED_ERROR + // and UNHANDLED_REJECTION events might be dispatched between the + // BEFORE_REFRESH and the REFRESH event. We want to keep those errors + // around until the next refresh. Otherwise we run into a race + // condition where those errors would be cleared on refresh completion + // before they can be displayed. + state.refreshState.type === "pending" + ? state.refreshState.errors + : [], + refreshState: { type: "idle" }, }; } + case Bus.TYPE_UNHANDLED_ERROR: + case Bus.TYPE_UNHANDLED_REJECTION: { + switch (state.refreshState.type) { + case "idle": { + return { + ...state, + nextId: state.nextId + 1, + errors: pushErrorFilterDuplicates(state.errors, { + id: state.nextId, + event: ev, + }), + }; + } + case "pending": { + return { + ...state, + nextId: state.nextId + 1, + refreshState: { + ...state.refreshState, + errors: pushErrorFilterDuplicates(state.refreshState.errors, { + id: state.nextId, + event: ev, + }), + }, + }; + } + default: + return state; + } + } default: { return state; } @@ -60,68 +120,77 @@ const shouldPreventDisplay = ( return preventType.includes(errorType); }; -const ReactDevOverlay: React.FunctionComponent = function ReactDevOverlay({ - children, - preventDisplay, - globalOverlay, -}: React.PropsWithChildren<{ - preventDisplay?: ErrorType[]; +type ReactDevOverlayProps = { globalOverlay?: boolean; -}>) { - const [state, dispatch] = React.useReducer< - React.Reducer<OverlayState, Bus.BusEvent> - >(reducer, { - nextId: 1, - issue: null, - errors: [], - }); - - React.useEffect(() => { - Bus.on(dispatch); - return function () { - Bus.off(dispatch); - }; - }, [dispatch]); - - const onComponentError = React.useCallback( - (_error: Error, _componentStack: string | null) => { - // TODO: special handling - }, - [] - ); - - const hasBuildError = state.issue != null; - const hasRuntimeErrors = Boolean(state.errors.length); - - const isMounted = hasBuildError || hasRuntimeErrors; - - return ( - <React.Fragment> - <ErrorBoundary - globalOverlay={globalOverlay} - isMounted={isMounted} - onError={onComponentError} - > - {children ?? null} - </ErrorBoundary> - {isMounted ? ( - <ShadowPortal globalOverlay={globalOverlay}> - <CssReset /> - <Base /> - <ComponentStyles /> - - {shouldPreventDisplay( - hasBuildError ? "build" : hasRuntimeErrors ? "runtime" : null, - preventDisplay - ) ? null : hasBuildError ? ( - <BuildError issue={state.issue!} /> - ) : hasRuntimeErrors ? ( - <Errors errors={state.errors} /> - ) : undefined} - </ShadowPortal> - ) : undefined} - </React.Fragment> - ); + preventDisplay?: ErrorType[]; + children?: React.ReactNode; }; +const ReactDevOverlay: React.FunctionComponent<ReactDevOverlayProps> = + function ReactDevOverlay({ children, preventDisplay, globalOverlay }) { + const [state, dispatch] = React.useReducer< + React.Reducer<OverlayState, Bus.BusEvent> + >(reducer, { + nextId: 1, + issue: null, + errors: [], + refreshState: { + type: "idle", + }, + }); + + React.useEffect(() => { + Bus.on(dispatch); + return function () { + Bus.off(dispatch); + }; + }, [dispatch]); + + const onComponentError = React.useCallback( + (_error: Error, _componentStack: string | null) => { + // TODO: special handling + }, + [] + ); + + const hasBuildError = state.issue != null; + const hasRuntimeErrors = Boolean(state.errors.length); + + const errorType = hasBuildError + ? "build" + : hasRuntimeErrors + ? "runtime" + : null; + + const isMounted = hasBuildError || hasRuntimeErrors; + + return ( + <React.Fragment> + <ErrorBoundary + globalOverlay={globalOverlay} + isMounted={isMounted} + onError={onComponentError} + > + {children ?? null} + </ErrorBoundary> + {isMounted ? ( + <ShadowPortal globalOverlay={globalOverlay}> + <CssReset /> + <Base /> + <ComponentStyles /> + + {shouldPreventDisplay( + errorType, + preventDisplay + ) ? null : hasBuildError ? ( + <BuildError issue={state.issue!} /> + ) : hasRuntimeErrors ? ( + <Errors errors={state.errors} /> + ) : undefined} + </ShadowPortal> + ) : undefined} + </React.Fragment> + ); + }; + export default ReactDevOverlay; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts index 43b441b8861453..bc6c3ca0d7dcde 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts @@ -4,6 +4,7 @@ import type { Issue } from "@vercel/turbopack-runtime/types/protocol"; export const TYPE_BUILD_OK = "build-ok"; export const TYPE_TURBOPACK_ERROR = "turbopack-error"; +export const TYPE_BEFORE_REFRESH = "before-fast-refresh"; export const TYPE_REFRESH = "fast-refresh"; export const TYPE_UNHANDLED_ERROR = "unhandled-error"; export const TYPE_UNHANDLED_REJECTION = "unhandled-rejection"; @@ -13,6 +14,7 @@ export type TurbopackError = { type: typeof TYPE_TURBOPACK_ERROR; issue: Issue; }; +export type BeforeFastRefresh = { type: typeof TYPE_BEFORE_REFRESH }; export type FastRefresh = { type: typeof TYPE_REFRESH }; export type UnhandledError = { type: typeof TYPE_UNHANDLED_ERROR; @@ -27,6 +29,7 @@ export type UnhandledRejection = { export type BusEvent = | BuildOk | TurbopackError + | BeforeFastRefresh | FastRefresh | UnhandledError | UnhandledRejection; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/maintain--tab-focus.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/maintain--tab-focus.ts index 830abf68359812..409ab5cef728c7 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/maintain--tab-focus.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/maintain--tab-focus.ts @@ -926,7 +926,7 @@ var focusSvgForeignobjectTabindex = { element.innerHTML = generate( '<foreignObject tabindex="-1"><input type="text" /></foreignObject>' ); - // Safari 8's quersSelector() can't identify foreignObject, but getElementyByTagName() can + // Safari 8's querySelector() can't identify foreignObject, but getElementsByTagName() can return ( element.querySelector("foreignObject") || element.getElementsByTagName("foreignObject")[0] diff --git a/packages/next-swc/crates/next-core/js/types/compiled-next.d.ts b/packages/next-swc/crates/next-core/js/types/compiled-next.d.ts new file mode 100644 index 00000000000000..09a815da93d9d4 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/types/compiled-next.d.ts @@ -0,0 +1 @@ +declare module "next/dist/compiled/react-server-dom-webpack/client"; diff --git a/packages/next-swc/crates/next-core/js/types/globals.d.ts b/packages/next-swc/crates/next-core/js/types/globals.d.ts index 4a40ad0a49015a..77a76a589ac9c2 100644 --- a/packages/next-swc/crates/next-core/js/types/globals.d.ts +++ b/packages/next-swc/crates/next-core/js/types/globals.d.ts @@ -11,6 +11,10 @@ declare global { | [isBootStrap: 0] | [isNotBootstrap: 1, responsePartial: string] )[]; + var next: { + version: string; + appDir: boolean; + }; } export {}; diff --git a/packages/next-swc/crates/next-core/js/types/next.d.ts b/packages/next-swc/crates/next-core/js/types/next.d.ts index a80e0b151a1903..82e53f22c3903c 100644 --- a/packages/next-swc/crates/next-core/js/types/next.d.ts +++ b/packages/next-swc/crates/next-core/js/types/next.d.ts @@ -1 +1,3 @@ -export type ChunkGroup = Array<{ path: string; chunkId: string }>; +import { ChunkPath } from "@vercel/turbopack-runtime/types"; + +export type ChunkGroup = ChunkPath[]; From e2880a14c2fb35abfc1bee7dcba7e6a8ea1b05c1 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Mon, 28 Nov 2022 16:42:32 +0100 Subject: [PATCH 240/672] Sample many modules in benchmarks + reliability fixes (vercel/turbo#2750) * Sample many modules in benchmarks + reliability fixes * Fix depth sampling to be uniform * Fix Webpack benchmark * Only use detector component for RSC * Clippy * Clippy --- packages/next-swc/crates/next-dev/Cargo.toml | 1 + .../crates/next-dev/benches/bundlers/mod.rs | 11 +- .../next-dev/benches/bundlers/vite/mod.rs | 10 +- .../next-dev/benches/bundlers/webpack/mod.rs | 1 + .../next-swc/crates/next-dev/benches/mod.rs | 304 ++++++++++-------- .../crates/next-dev/benches/util/env.rs | 47 +++ .../crates/next-dev/benches/util/mod.rs | 40 +-- .../next-dev/benches/util/module_picker.rs | 46 +++ .../next-dev/benches/util/page_guard.rs | 12 - .../next-dev/benches/util/prepared_app.rs | 8 - 10 files changed, 294 insertions(+), 186 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/benches/util/env.rs create mode 100644 packages/next-swc/crates/next-dev/benches/util/module_picker.rs diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index fab465e9f07b2a..dd592888a665be 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -61,6 +61,7 @@ fs_extra = "1.2.0" lazy_static = "1.4.0" once_cell = "1.13.0" parking_lot = "0.12.1" +rand = "0.8.5" regex = "1.6.0" tempfile = "3.3.0" test-generator = "0.3.0" diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs index fef726fb5dc1c6..8b62378bc87f19 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/mod.rs @@ -9,6 +9,7 @@ use self::{ vite::Vite, webpack::Webpack, }; +use crate::util::env::read_env; mod nextjs; mod parcel; @@ -59,16 +60,16 @@ pub trait Bundler { } pub fn get_bundlers() -> Vec<Box<dyn Bundler>> { - let config = std::env::var("TURBOPACK_BENCH_BUNDLERS").ok(); + let config: String = read_env("TURBOPACK_BENCH_BUNDLERS", String::from("turbopack")).unwrap(); let mut turbopack = false; let mut others = false; - match config.as_deref() { - Some("all") => { + match config.as_ref() { + "all" => { turbopack = true; others = true } - Some("others") => others = true, - None | Some("") => { + "others" => others = true, + "turbopack" => { turbopack = true; } _ => panic!("Invalid value for TURBOPACK_BENCH_BUNDLERS"), diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs index 81780d218251c8..4170adbd69cf4f 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs @@ -34,19 +34,17 @@ impl Bundler for Vite { } else { "Vite SSR" } + } else if self.swc { + "Vite SWC CSR" } else { - if self.swc { - "Vite SWC CSR" - } else { - "Vite CSR" - } + "Vite CSR" } } fn prepare(&self, install_dir: &Path) -> Result<()> { let mut packages = vec![NpmPackage::new("vite", "^3.2.4")]; if self.swc { - packages.push(NpmPackage::new("vite-plugin-swc-react-refresh", "^2.2.0")); + packages.push(NpmPackage::new("vite-plugin-swc-react-refresh", "^2.2.1")); } else { packages.push(NpmPackage::new("@vitejs/plugin-react", "^2.2.0")); }; diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs index 1fe7add999217b..400f4fcb1598d6 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/webpack/mod.rs @@ -27,6 +27,7 @@ impl Bundler for Webpack { &[ NpmPackage::new("@pmmmwh/react-refresh-webpack-plugin", "^0.5.7"), NpmPackage::new("@swc/core", "^1.2.249"), + NpmPackage::new("@swc/helpers", "^0.4.13"), NpmPackage::new("react-refresh", "^0.14.0"), NpmPackage::new("swc-loader", "^0.2.3"), NpmPackage::new("webpack", "^5.75.0"), diff --git a/packages/next-swc/crates/next-dev/benches/mod.rs b/packages/next-swc/crates/next-dev/benches/mod.rs index ae060159ff893c..78ac239dc07516 100644 --- a/packages/next-swc/crates/next-dev/benches/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/mod.rs @@ -2,6 +2,10 @@ use std::{ fs::{self}, panic::AssertUnwindSafe, path::Path, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, time::Duration, }; @@ -18,7 +22,12 @@ use tokio::{ time::{sleep, timeout}, }; use turbo_tasks::util::FormatDuration; -use util::{build_test, create_browser, AsyncBencherExtension, PreparedApp, BINDING_NAME}; +use util::{ + build_test, create_browser, + env::{read_env, read_env_bool, read_env_list}, + module_picker::ModulePicker, + AsyncBencherExtension, PreparedApp, BINDING_NAME, +}; use self::{bundlers::RenderType, util::resume_on_error}; use crate::{bundlers::Bundler, util::PageGuard}; @@ -138,6 +147,7 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { let runtime = Runtime::new().unwrap(); let browser = Lazy::new(|| runtime.block_on(create_browser())); + let hmr_warmup = read_env("TURBOPACK_BENCH_HMR_WARMUP", 10).unwrap(); for bundler in get_bundlers() { if matches!( @@ -153,105 +163,19 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { for module_count in get_module_counts() { let test_app = Lazy::new(|| build_test(module_count, bundler.as_ref())); let input = (bundler.as_ref(), &test_app); + let module_picker = + Lazy::new(|| Arc::new(ModulePicker::new(test_app.modules().to_vec()))); + resume_on_error(AssertUnwindSafe(|| { g.bench_with_input( BenchmarkId::new(bundler.get_name(), format!("{} modules", module_count)), &input, |b, &(bundler, test_app)| { let test_app = &**test_app; + let modules = test_app.modules(); + let module_picker = &*module_picker; let browser = &*browser; - fn add_code( - bundler: &dyn Bundler, - app_path: &Path, - msg: &str, - location: CodeLocation, - ) -> Result<impl FnOnce() -> Result<()>> { - let triangle_path = app_path.join("src/triangle.jsx"); - let mut contents = fs::read_to_string(&triangle_path)?; - const INSERTED_CODE_COMMENT: &str = "// Inserted Code:\n"; - const COMPONENT_START: &str = "function Container({ style }) {\n"; - const DETECTOR_START: &str = "<Detector "; - const DETECTOR_END: &str = "/>"; - match (location, bundler.render_type()) { - (CodeLocation::Effect, _) => { - let a = contents - .find(DETECTOR_START) - .ok_or_else(|| anyhow!("unable to find detector start"))?; - let b = a + contents[a..] - .find(DETECTOR_END) - .ok_or_else(|| anyhow!("unable to find detector end"))?; - contents.replace_range( - a..b, - &format!("{DETECTOR_START}message=\"{msg}\" "), - ); - } - ( - CodeLocation::Evaluation, - RenderType::ClientSideRendered - | RenderType::ServerSidePrerendered, - ) => { - let b = contents - .find(COMPONENT_START) - .ok_or_else(|| anyhow!("unable to find component start"))?; - let code = format!( - "globalThis.{BINDING_NAME} && \ - globalThis.{BINDING_NAME}('{msg}');" - ); - if let Some(a) = contents.find(INSERTED_CODE_COMMENT) { - contents.replace_range( - a..b, - &format!("{INSERTED_CODE_COMMENT}{code}\n"), - ); - } else { - contents.insert_str( - b, - &format!("{INSERTED_CODE_COMMENT}{code}\n"), - ); - } - } - ( - CodeLocation::Evaluation, - RenderType::ServerSideRenderedWithEvents - | RenderType::ServerSideRenderedWithoutInteractivity, - ) => { - panic!( - "evaluation can't be measured for bundlers which evaluate \ - on server side" - ); - } - } - Ok(move || Ok(fs::write(&triangle_path, contents)?)) - } - static CHANGE_TIMEOUT_MESSAGE: &str = - "update was not registered by bundler"; - async fn make_change( - bundler: &dyn Bundler, - guard: &mut PageGuard<'_>, - location: CodeLocation, - m: &WallTime, - ) -> Result<Duration> { - let msg = - format!("TURBOPACK_BENCH_CHANGE_{}", guard.app_mut().counter()); - let commit = add_code(bundler, guard.app().path(), &msg, location)?; - - let start = m.start(); - commit()?; - - // Wait for the change introduced above to be reflected at - // runtime. This expects HMR or automatic reloading to occur. - timeout(MAX_UPDATE_TIMEOUT, guard.wait_for_binding(&msg)) - .await - .context(CHANGE_TIMEOUT_MESSAGE)??; - - let duration = m.end(start); - - // TODO(sokra) triggering HMR updates too fast can have weird effects - tokio::time::sleep(std::cmp::max(duration, Duration::from_millis(100))) - .await; - - Ok(duration) - } b.to_async(&runtime).try_iter_async( &runtime, || async { @@ -276,36 +200,81 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { flag", )?; - // TODO(alexkirsz) Turbopack takes a few ms to start listening on - // HMR, and we don't send updates retroactively, so we need to wait - // before starting to make changes. - // This should not be required. - tokio::time::sleep(Duration::from_millis(5000)).await; + // There's a possible race condition between hydration and + // connection to the HMR server. We attempt to make updates with an + // exponential backoff until one succeeds. + let mut exponential_duration = Duration::from_millis(100); + loop { + match make_change( + &modules[0].0, + bundler, + &mut guard, + location, + exponential_duration, + &WallTime, + ) + .await + { + Ok(_) => { + break; + } + Err(e) => { + exponential_duration *= 2; + if exponential_duration > MAX_UPDATE_TIMEOUT { + return Err( + e.context("failed to make warmup change") + ); + } + } + } + } - // Make a warmup change - make_change(bundler, &mut guard, location, &WallTime).await?; + // Once we know the HMR server is connected, we make a few warmup + // changes. + for _ in 0..hmr_warmup { + make_change( + &modules[0].0, + bundler, + &mut guard, + location, + MAX_UPDATE_TIMEOUT, + &WallTime, + ) + .await?; + } Ok(guard) }, - |mut guard, iters, m, verbose| async move { - let mut value = m.zero(); - for iter in 0..iters { - let duration = - make_change(bundler, &mut guard, location, &m).await?; - value = m.add(&value, &duration); - - let i: u64 = iter + 1; - if verbose && i != iters && i.count_ones() == 1 { - eprint!( - " [{:?} {:?}/{}]", - duration, - FormatDuration(value / (i as u32)), - i - ); + |mut guard, iters, m, verbose| { + let module_picker = Arc::clone(module_picker); + async move { + let mut value = m.zero(); + for iter in 0..iters { + let module = module_picker.pick(); + let duration = make_change( + module, + bundler, + &mut guard, + location, + MAX_UPDATE_TIMEOUT, + &m, + ) + .await?; + value = m.add(&value, &duration); + + let i: u64 = iter + 1; + if verbose && i != iters && i.count_ones() == 1 { + eprint!( + " [{:?} {:?}/{}]", + duration, + FormatDuration(value / (i as u32)), + i + ); + } } - } - Ok((guard, value)) + Ok((guard, value)) + } }, |guard| async move { let hmr_is_happening = guard @@ -325,6 +294,92 @@ fn bench_hmr_internal(mut g: BenchmarkGroup<WallTime>, location: CodeLocation) { } } +fn insert_code( + path: &Path, + bundler: &dyn Bundler, + message: &str, + location: CodeLocation, +) -> Result<impl FnOnce() -> Result<()>> { + let mut contents = fs::read_to_string(path)?; + + const PRAGMA_EVAL_START: &str = "/* @turbopack-bench:eval-start */"; + const PRAGMA_EVAL_END: &str = "/* @turbopack-bench:eval-end */"; + + let eval_start = contents + .find(PRAGMA_EVAL_START) + .ok_or_else(|| anyhow!("unable to find effect start pragma in {}", contents))?; + let eval_end = contents + .find(PRAGMA_EVAL_END) + .ok_or_else(|| anyhow!("unable to find effect end pragma in {}", contents))?; + + match (location, bundler.render_type()) { + (CodeLocation::Effect, _) => { + contents.replace_range( + eval_start + PRAGMA_EVAL_START.len()..eval_end, + &format!("\nEFFECT_PROPS.message = \"{message}\";\n"), + ); + } + ( + CodeLocation::Evaluation, + RenderType::ClientSideRendered | RenderType::ServerSidePrerendered, + ) => { + let code = format!( + "\nglobalThis.{BINDING_NAME} && globalThis.{BINDING_NAME}(\"{message}\");\n" + ); + contents.replace_range(eval_start + PRAGMA_EVAL_START.len()..eval_end, &code); + } + ( + CodeLocation::Evaluation, + RenderType::ServerSideRenderedWithEvents + | RenderType::ServerSideRenderedWithoutInteractivity, + ) => { + panic!("evaluation can't be measured for bundlers which evaluate on server side"); + } + } + + let path = path.to_owned(); + Ok(move || Ok(fs::write(&path, contents)?)) +} + +static CHANGE_TIMEOUT_MESSAGE: &str = "update was not registered by bundler"; + +async fn make_change<'a>( + module: &Path, + bundler: &dyn Bundler, + guard: &mut PageGuard<'a>, + location: CodeLocation, + timeout_duration: Duration, + measurement: &WallTime, +) -> Result<Duration> { + static CHANGE_COUNTER: AtomicUsize = AtomicUsize::new(0); + + let msg = format!( + "TURBOPACK_BENCH_CHANGE_{}", + CHANGE_COUNTER.fetch_add(1, Ordering::Relaxed) + ); + + // Keep the IO out of the measurement. + let commit = insert_code(module, bundler, &msg, location)?; + + let start = measurement.start(); + + commit()?; + + // Wait for the change introduced above to be reflected at runtime. + // This expects HMR or automatic reloading to occur. + timeout(timeout_duration, guard.wait_for_binding(&msg)) + .await + .context(CHANGE_TIMEOUT_MESSAGE)??; + + let duration = measurement.end(start); + + if cfg!(target_os = "linux") { + // TODO(sokra) triggering HMR updates too fast can have weird effects on Linux + tokio::time::sleep(std::cmp::max(duration, Duration::from_millis(100))).await; + } + Ok(duration) +} + fn bench_startup_cached(c: &mut Criterion) { let mut g = c.benchmark_group("bench_startup_cached"); g.sample_size(10); @@ -342,11 +397,7 @@ fn bench_hydration_cached(c: &mut Criterion) { } fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: bool) { - let config = std::env::var("TURBOPACK_BENCH_CACHED").ok(); - if matches!( - config.as_deref(), - None | Some("") | Some("no") | Some("false") - ) { + if !read_env_bool("TURBOPACK_BENCH_CACHED") { return; } @@ -432,16 +483,7 @@ fn bench_startup_cached_internal(mut g: BenchmarkGroup<WallTime>, hydration: boo } fn get_module_counts() -> Vec<usize> { - let config = std::env::var("TURBOPACK_BENCH_COUNTS").ok(); - match config.as_deref() { - None | Some("") => { - vec![1_000] - } - Some(config) => config - .split(',') - .map(|s| s.parse().expect("Invalid value for TURBOPACK_BENCH_COUNTS")) - .collect(), - } + read_env_list("TURBOPACK_BENCH_COUNTS", vec![1_000usize]).unwrap() } criterion_group!( diff --git a/packages/next-swc/crates/next-dev/benches/util/env.rs b/packages/next-swc/crates/next-dev/benches/util/env.rs new file mode 100644 index 00000000000000..aa557c64cdf1ce --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/util/env.rs @@ -0,0 +1,47 @@ +use std::{error::Error, str::FromStr}; + +use anyhow::{anyhow, Context, Result}; + +/// Reads an environment variable. +pub fn read_env<T>(name: &str, default: T) -> Result<T> +where + T: FromStr, + <T as FromStr>::Err: Error + Send + Sync + 'static, +{ + let config = std::env::var(name).ok(); + match config.as_deref() { + None | Some("") => Ok(default), + Some(config) => config + .parse() + .with_context(|| anyhow!("Invalid value for {}", name)), + } +} + +/// Reads an boolean-like environment variable, where any value but "0", "no", +/// or "false" is are considered true. +pub fn read_env_bool(name: &str) -> bool { + let config = std::env::var(name).ok(); + !matches!( + config.as_deref(), + None | Some("") | Some("0") | Some("no") | Some("false") + ) +} + +/// Reads a comma-separated environment variable as a vector. +pub fn read_env_list<T>(name: &str, default: Vec<T>) -> Result<Vec<T>> +where + T: FromStr, + <T as FromStr>::Err: Error + Send + Sync + 'static, +{ + let config = std::env::var(name).ok(); + match config.as_deref() { + None | Some("") => Ok(default), + Some(config) => config + .split(',') + .map(|s| { + s.parse() + .with_context(|| anyhow!("Invalid value for {}", name)) + }) + .collect(), + } +} diff --git a/packages/next-swc/crates/next-dev/benches/util/mod.rs b/packages/next-swc/crates/next-dev/benches/util/mod.rs index f8d917b1370864..16a95bf61c65b9 100644 --- a/packages/next-swc/crates/next-dev/benches/util/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/util/mod.rs @@ -19,10 +19,15 @@ use regex::Regex; use tungstenite::{error::ProtocolError::ResetWithoutClosingHandshake, Error::Protocol}; use turbo_tasks::util::FormatDuration; use turbo_tasks_testing::retry::{retry, retry_async}; -use turbopack_create_test_app::test_app_builder::{PackageJsonConfig, TestApp, TestAppBuilder}; +use turbopack_create_test_app::test_app_builder::{ + EffectMode, PackageJsonConfig, TestApp, TestAppBuilder, +}; -use crate::bundlers::Bundler; +use self::env::read_env_bool; +use crate::bundlers::{Bundler, RenderType}; +pub mod env; +pub mod module_picker; pub mod npm; mod page_guard; mod prepared_app; @@ -53,6 +58,10 @@ pub fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { package_json: Some(PackageJsonConfig { react_version: bundler.react_version().to_string(), }), + effect_mode: match bundler.render_type() { + RenderType::ServerSideRenderedWithEvents => EffectMode::Component, + _ => EffectMode::Hook, + }, ..Default::default() } .build() @@ -76,14 +85,8 @@ pub fn build_test(module_count: usize, bundler: &dyn Bundler) -> TestApp { } pub async fn create_browser() -> Browser { - let with_head = !matches!( - std::env::var("TURBOPACK_BENCH_HEAD").ok().as_deref(), - None | Some("") | Some("no") | Some("false") - ); - let with_devtools = !matches!( - std::env::var("TURBOPACK_BENCH_DEVTOOLS").ok().as_deref(), - None | Some("") | Some("no") | Some("false") - ); + let with_head = read_env_bool("TURBOPACK_BENCH_WITH_HEAD"); + let with_devtools = read_env_bool("TURBOPACK_BENCH_DEVTOOLS"); let mut builder = BrowserConfig::builder(); if with_head { builder = builder.with_head(); @@ -117,12 +120,7 @@ pub async fn create_browser() -> Browser { pub fn resume_on_error<F: FnOnce() + UnwindSafe>(f: F) { let runs_as_bench = std::env::args().find(|a| a == "--bench"); - let ignore_errors = !matches!( - std::env::var("TURBOPACK_BENCH_IGNORE_ERRORS") - .ok() - .as_deref(), - None | Some("") | Some("no") | Some("false") - ); + let ignore_errors = read_env_bool("TURBOPACK_BENCH_IGNORE_ERRORS"); if runs_as_bench.is_some() || ignore_errors { use std::panic::catch_unwind; @@ -160,10 +158,7 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension<A> for AsyncBencher<'a, 'b, R: Fn(u64, WallTime) -> F, F: Future<Output = Result<Duration>>, { - let log_progress = !matches!( - std::env::var("TURBOPACK_BENCH_PROGRESS").ok().as_deref(), - None | Some("") | Some("no") | Some("false") - ); + let log_progress = read_env_bool("TURBOPACK_BENCH_PROGRESS"); let routine = &routine; self.iter_custom(|iters| async move { @@ -190,10 +185,7 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencherExtension<A> for AsyncBencher<'a, 'b, T: Fn(I) -> TF, TF: Future<Output = ()>, { - let log_progress = !matches!( - std::env::var("TURBOPACK_BENCH_PROGRESS").ok().as_deref(), - None | Some("") | Some("no") | Some("false") - ); + let log_progress = read_env_bool("TURBOPACK_BENCH_PROGRESS"); let setup = &setup; let routine = &routine; diff --git a/packages/next-swc/crates/next-dev/benches/util/module_picker.rs b/packages/next-swc/crates/next-dev/benches/util/module_picker.rs new file mode 100644 index 00000000000000..faaa1014026fa5 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/util/module_picker.rs @@ -0,0 +1,46 @@ +use std::{collections::HashMap, path::PathBuf}; + +use rand::{rngs::StdRng, seq::SliceRandom, SeedableRng}; + +/// Picks modules at random, but with a fixed seed so runs are somewhat +/// reproducible. +/// +/// This must be initialized outside of `bench_with_input` so we don't repeat +/// the same sequence in different samples. +pub struct ModulePicker { + depths: Vec<usize>, + modules_by_depth: HashMap<usize, Vec<PathBuf>>, + rng: parking_lot::Mutex<StdRng>, +} + +impl ModulePicker { + /// Creates a new module picker. + pub fn new(mut modules: Vec<(PathBuf, usize)>) -> Self { + let rng = StdRng::seed_from_u64(42); + + // Ensure the module order is deterministic. + modules.sort(); + + let mut modules_by_depth: HashMap<_, Vec<_>> = HashMap::new(); + for (module, depth) in modules { + modules_by_depth.entry(depth).or_default().push(module); + } + let mut depths: Vec<_> = modules_by_depth.keys().copied().collect(); + // Ensure the depth order is deterministic. + depths.sort(); + + Self { + depths, + modules_by_depth, + rng: parking_lot::Mutex::new(rng), + } + } + + /// Picks a random module with a uniform distribution over all depths. + pub fn pick(&self) -> &PathBuf { + let mut rng = self.rng.lock(); + // Sample from all depths uniformly. + let depth = self.depths.choose(&mut *rng).unwrap(); + self.modules_by_depth[depth].choose(&mut *rng).unwrap() + } +} diff --git a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs index 5959fd8bf79af1..5848d9085780ec 100644 --- a/packages/next-swc/crates/next-dev/benches/util/page_guard.rs +++ b/packages/next-swc/crates/next-dev/benches/util/page_guard.rs @@ -44,24 +44,12 @@ impl<'a> PageGuard<'a> { } } - /// Returns a reference to the app. - pub fn app(&self) -> &PreparedApp<'a> { - // Invariant: app is always Some while the guard is alive. - self.app.as_ref().unwrap() - } - /// Returns a reference to the page. pub fn page(&self) -> &Page { // Invariant: page is always Some while the guard is alive. self.page.as_ref().unwrap() } - /// Returns a mutable reference to the app. - pub fn app_mut(&mut self) -> &mut PreparedApp<'a> { - // Invariant: app is always Some while the guard is alive. - self.app.as_mut().unwrap() - } - /// Closes the page, returns the app. pub async fn close_page(mut self) -> Result<PreparedApp<'a>> { // Invariant: the page is always Some while the guard is alive. diff --git a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs index 3d6b6d8df57fa0..23a73edf82d9e8 100644 --- a/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs +++ b/packages/next-swc/crates/next-dev/benches/util/prepared_app.rs @@ -67,7 +67,6 @@ pub struct PreparedApp<'a> { bundler: &'a dyn Bundler, server: Option<(Child, String)>, test_dir: PreparedDir, - counter: usize, } impl<'a> PreparedApp<'a> { @@ -81,7 +80,6 @@ impl<'a> PreparedApp<'a> { bundler, server: None, test_dir: PreparedDir::TempDir(test_dir), - counter: 0, }) } @@ -93,15 +91,9 @@ impl<'a> PreparedApp<'a> { bundler, server: None, test_dir: PreparedDir::Path(template_dir), - counter: 0, }) } - pub fn counter(&mut self) -> usize { - self.counter += 1; - self.counter - } - pub fn start_server(&mut self) -> Result<()> { assert!(self.server.is_none(), "Server already started"); From 1f38dcdf39b17846627e6e2412e23c24431638e2 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Mon, 28 Nov 2022 09:18:46 -0800 Subject: [PATCH 241/672] build(cargo): setup next-binding package (vercel/turbo#2813) * build(cargo): setup next-binding package * build(cargo): update dependencies * style(toml): update config * ci(actions): check next-binding * feat(next-binding): reexports * build(cargo): update lockfile --- .../next-swc/crates/next-binding/Cargo.toml | 132 ++++++++++++++++++ .../next-swc/crates/next-binding/README.md | 3 + .../next-swc/crates/next-binding/src/lib.rs | 53 +++++++ 3 files changed, 188 insertions(+) create mode 100644 packages/next-swc/crates/next-binding/Cargo.toml create mode 100644 packages/next-swc/crates/next-binding/README.md create mode 100644 packages/next-swc/crates/next-binding/src/lib.rs diff --git a/packages/next-swc/crates/next-binding/Cargo.toml b/packages/next-swc/crates/next-binding/Cargo.toml new file mode 100644 index 00000000000000..9f0c206c792272 --- /dev/null +++ b/packages/next-swc/crates/next-binding/Cargo.toml @@ -0,0 +1,132 @@ +[package] +name = "next-binding" +version = "0.1.0" +edition = "2021" +license = "MPL-2.0" +autobenches = false + +[lib] +bench = false + +[features] +__swc = [] +__swc_core = [ + "__swc", +] +__swc_core_next_core = [ + "__swc_core", + "swc_core/common_concurrent", + "swc_core/ecma_ast", + "swc_core/ecma_visit", + "swc_core/ecma_loader_node", + "swc_core/ecma_loader_lru", + "swc_core/ecma_utils", + "swc_core/ecma_minifier", + "swc_core/ecma_transforms", + "swc_core/ecma_transforms_react", + "swc_core/ecma_transforms_typescript", + "swc_core/ecma_transforms_optimization", + "swc_core/ecma_parser", + "swc_core/ecma_parser_typescript", + "swc_core/cached", + "swc_core/base" +] + +__swc_core_binding_napi = [ + "__swc_core", + "swc_core/allocator_node", + "swc_core/base_concurrent", + "swc_core/base_node", + "swc_core/common_concurrent", + "swc_core/ecma_ast", + "swc_core/ecma_loader_node", + "swc_core/ecma_loader_lru", + "swc_core/bundler", + "swc_core/bundler_concurrent", + "swc_core/ecma_codegen", + "swc_core/ecma_minifier", + "swc_core/ecma_parser", + "swc_core/ecma_parser_typescript", + "swc_core/ecma_transforms", + "swc_core/ecma_transforms_optimization", + "swc_core/ecma_transforms_react", + "swc_core/ecma_transforms_typescript", + "swc_core/ecma_utils", + "swc_core/ecma_visit", +] +__swc_core_binding_napi_plugin = [ + "swc_core/plugin_transform_host_native" +] + +__swc_core_binding_wasm = [ + "__swc_core", + "swc_core/common_concurrent", + "swc_core/binding_macro_wasm", + "swc_core/ecma_codegen", + "swc_core/ecma_minifier", + "swc_core/ecma_transforms", + "swc_core/ecma_transforms_typescript", + "swc_core/ecma_transforms_optimization", + "swc_core/ecma_transforms_react", + "swc_core/ecma_parser", + "swc_core/ecma_parser_typescript", + "swc_core/ecma_utils", + "swc_core/ecma_visit" +] +__swc_core_binding_wasm_plugin = [ + "swc_core/plugin_transform_host_js" +] + +__swc_core_testing_transform = [ + "swc_core/testing_transform" +] + +__turbo = [] +__feature_next_dev_server = [ + "__turbo", + "next-dev/serializable" +] +__feature_node_file_trace = [ + "__turbo", + "node-file-trace/node-api" +] + +__features = [] +__feature_mdx_rs = [ "__features", "mdxjs/serializable"] + +__swc_custom_transform = [] +__swc_transform_styled_components = [ + "__swc", + "__swc_custom_transform", + "styled_components" +] +__swc_transform_styled_jsx = [ + "__swc", + "__swc_custom_transform", + "styled_jsx" +] +__swc_transform_emotion = [ + "__swc", + "__swc_custom_transform", + "swc_emotion" +] +__swc_transform_modularize_imports = [ + "__swc", + "__swc_custom_transform", + "modularize_imports" +] +__swc_testing = [ + "__swc", + "testing" +] + +[dependencies] +swc_core = { optional = true, workspace = true } +mdxjs = { optional = true, workspace = true } +next-dev = { optional = true, workspace = true } +node-file-trace = { optional = true, workspace = true } +styled_components = { optional = true,workspace = true } +styled_jsx = { optional = true,workspace = true} +swc_emotion = { optional = true,workspace = true} +testing = {optional = true, workspace = true} +modularize_imports = { optional = true,workspace = true} \ No newline at end of file diff --git a/packages/next-swc/crates/next-binding/README.md b/packages/next-swc/crates/next-binding/README.md new file mode 100644 index 00000000000000..b2dc22fe8d8cba --- /dev/null +++ b/packages/next-swc/crates/next-binding/README.md @@ -0,0 +1,3 @@ +### next-binding + +This is an internal package, does not provide any public interface or stability guarantees. Do not use it directly. \ No newline at end of file diff --git a/packages/next-swc/crates/next-binding/src/lib.rs b/packages/next-swc/crates/next-binding/src/lib.rs new file mode 100644 index 00000000000000..3c41271cdce504 --- /dev/null +++ b/packages/next-swc/crates/next-binding/src/lib.rs @@ -0,0 +1,53 @@ +#[cfg(feature = "__swc")] +pub mod swc { + #[cfg(feature = "__swc_core")] + pub mod core { + pub use swc_core::*; + } + + #[cfg(feature = "__swc_custom_transform")] + pub mod custom_transform { + #[cfg(feature = "__swc_transform_styled_components")] + pub mod styled_components { + pub use styled_components::*; + } + #[cfg(feature = "__swc_transform_styled_jsx")] + pub mod styled_jsx { + pub use styled_jsx::*; + } + #[cfg(feature = "__swc_transform_emotion")] + pub mod emotion { + pub use swc_emotion::*; + } + #[cfg(feature = "__swc_transform_modularize_imports")] + pub mod modularize_imports { + pub use modularize_imports::*; + } + } + + #[cfg(feature = "testing")] + pub mod testing { + pub use testing::*; + } +} + +#[cfg(feature = "__turbo")] +pub mod turbo { + #[cfg(feature = "__feature_next_dev_server")] + pub mod dev_server { + pub use next_dev::*; + } + + #[cfg(feature = "__feature_node_file_trace")] + pub mod node_file_trace { + pub use node_file_trace::*; + } +} + +#[cfg(feature = "__features")] +pub mod features { + #[cfg(feature = "__feature_mdx_rs")] + pub mod mdx { + pub use mdxjs::*; + } +} From e489b1effe34243b9ec675eb88750742a09cee4b Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Tue, 29 Nov 2022 03:03:35 +0100 Subject: [PATCH 242/672] fix and improve hanging detection (vercel/turbo#2827) Commit 1: It took me hours to figure out this unsafe problem... Commit 2: updates tokio Commit 3: improves hanging detection to allow to attach notes to event listeners --- packages/next-swc/crates/next-binding/README.md | 2 +- packages/next-swc/crates/next-core/Cargo.toml | 2 +- packages/next-swc/crates/next-dev/Cargo.toml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-binding/README.md b/packages/next-swc/crates/next-binding/README.md index b2dc22fe8d8cba..2eb6cb028ac690 100644 --- a/packages/next-swc/crates/next-binding/README.md +++ b/packages/next-swc/crates/next-binding/README.md @@ -1,3 +1,3 @@ ### next-binding -This is an internal package, does not provide any public interface or stability guarantees. Do not use it directly. \ No newline at end of file +This is an internal package, does not provide any public interface or stability guarantees. Do not use it directly. diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 6453bf01ba4bbf..ae931ddc1b953f 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -19,7 +19,7 @@ serde = "1.0.136" serde_json = "1.0.85" serde_qs = "0.10.1" sourcemap = "6.0.1" -tokio = { version = "1.11.0", features = ["full"] } +tokio = { version = "1.21.2", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-env = { path = "../turbo-tasks-env" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index dd592888a665be..9217d1f1a70029 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -32,7 +32,7 @@ profile = [] [dependencies] anyhow = "1.0.47" clap = { version = "4.0.18", features = ["derive", "env"] } -console-subscriber = { version = "0.1.6", optional = true } +console-subscriber = { version = "0.1.8", optional = true } futures = "0.3.21" mime = "0.3.16" next-core = { path = "../next-core" } @@ -40,7 +40,7 @@ owo-colors = "3" portpicker = "0.1.1" serde = "1.0.136" serde_json = "1.0.85" -tokio = { version = "1.11.0", features = ["full"] } +tokio = { version = "1.21.2", features = ["full"] } turbo-malloc = { path = "../turbo-malloc" } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } From 4ebc3894783cbb774ab249a7c671dfaba1df0031 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Tue, 29 Nov 2022 11:48:57 +0100 Subject: [PATCH 243/672] Make task stats take less memory by default (vercel/turbo#2765) * Make task stats take less memory by default * Swap order of condition operands * TaskStats -> ExportedTaskStats * Add full stats disclaimers * Clippy * Fix duplicate labels * Move stats type reporting to TurboTasks * Fix turbotrace and turbopack visualization * Store last duration and execution as SmallDurations Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> --- .../crates/next-dev/src/devserver_options.rs | 5 +++++ packages/next-swc/crates/next-dev/src/lib.rs | 11 +++++++++-- .../crates/next-dev/src/turbo_tasks_viz.rs | 19 ++++++++++++++----- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index 367d2d2c51dd80..40d33a1ef5a8e6 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -73,6 +73,11 @@ pub struct DevServerOptions { /// Expand the log details. pub log_detail: bool, + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] + /// Whether to enable full task stats recording in Turbo Engine. + pub full_stats: bool, + // Inherited options from next-dev, need revisit later. #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 642624c30dcad9..a8a66ad7c0a15e 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -22,8 +22,8 @@ use next_core::{ }; use owo_colors::OwoColorize; use turbo_tasks::{ - primitives::StringsVc, util::FormatDuration, RawVc, TransientInstance, TransientValue, - TurboTasks, Value, + primitives::StringsVc, util::FormatDuration, RawVc, StatsType, TransientInstance, + TransientValue, TurboTasks, TurboTasksBackendApi, Value, }; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; @@ -378,6 +378,13 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { }; let tt = TurboTasks::new(MemoryBackend::new()); + + let stats_type = match options.full_stats { + true => StatsType::Full, + false => StatsType::Essential, + }; + tt.set_stats_type(stats_type); + let tt_clone = tt.clone(); #[allow(unused_mut)] diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index f8cf2c936ec60e..167af8a0b7062a 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -2,7 +2,7 @@ use std::{str::FromStr, sync::Arc, time::Duration}; use anyhow::Result; use mime::Mime; -use turbo_tasks::{get_invalidator, TurboTasks, Value}; +use turbo_tasks::{get_invalidator, TurboTasks, TurboTasksBackendApi, Value}; use turbo_tasks_fs::File; use turbo_tasks_memory::{ stats::{ReferenceType, Stats}, @@ -53,7 +53,11 @@ impl ContentSource for TurboTasksSource { stats.add_id(b, task); }); let tree = stats.treeify(ReferenceType::Dependency); - let graph = viz::graph::visualize_stats_tree(tree, ReferenceType::Dependency); + let graph = viz::graph::visualize_stats_tree( + tree, + ReferenceType::Dependency, + tt.stats_type(), + ); viz::graph::wrap_html(&graph) } "call-graph" => { @@ -63,7 +67,8 @@ impl ContentSource for TurboTasksSource { stats.add_id(b, task); }); let tree = stats.treeify(ReferenceType::Child); - let graph = viz::graph::visualize_stats_tree(tree, ReferenceType::Child); + let graph = + viz::graph::visualize_stats_tree(tree, ReferenceType::Child, tt.stats_type()); viz::graph::wrap_html(&graph) } "table" => { @@ -73,11 +78,15 @@ impl ContentSource for TurboTasksSource { let active_only = query.contains_key("active"); b.with_all_cached_tasks(|task| { stats.add_id_conditional(b, task, |_, info| { - info.executions > 0 && (!active_only || info.active) + (!active_only || info.active) + && info + .executions + .map(|executions| executions > 0) + .unwrap_or(true) }); }); let tree = stats.treeify(ReferenceType::Dependency); - let table = viz::table::create_table(tree); + let table = viz::table::create_table(tree, tt.stats_type()); viz::table::wrap_html(&table) } else { return Ok(ContentSourceResultVc::exact( From b680327280157b4cce830ba9dece890a205aef94 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Tue, 29 Nov 2022 14:38:22 +0100 Subject: [PATCH 244/672] error overlay redesign (vercel/turbo#2831) * refactor exports * tabs + styles + icons --- .../src/overlay/internal/ReactDevOverlay.tsx | 137 +++---- .../components/CodeFrame/CodeFrame.tsx | 9 +- .../internal/components/CodeFrame/index.tsx | 1 + .../internal/components/CodeFrame/styles.tsx | 22 +- .../internal/components/Dialog/Dialog.tsx | 61 ++- .../internal/components/Dialog/DialogBody.tsx | 24 +- .../components/Dialog/DialogContent.tsx | 33 +- .../components/Dialog/DialogHeader.tsx | 145 ++++++- .../components/Dialog/DialogHeaderTabList.tsx | 85 +++++ .../internal/components/Dialog/index.ts | 12 +- .../internal/components/Dialog/styles.ts | 95 +---- .../LeftRightDialogHeader.tsx | 273 +++++++------- .../LeftRightDialogHeader/styles.ts | 60 ++- .../internal/components/Overlay/Overlay.tsx | 17 +- .../internal/components/Overlay/index.tsx | 1 + .../internal/components/Overlay/styles.tsx | 8 +- .../internal/components/ShadowPortal.tsx | 7 +- .../internal/components/Tabs/index.tsx | 234 ++++++++++++ .../internal/components/Terminal/Terminal.tsx | 8 +- .../internal/components/Terminal/index.tsx | 1 + .../internal/components/Terminal/styles.tsx | 14 +- .../internal/components/Toast/Toast.tsx | 13 +- .../internal/components/Toast/styles.ts | 12 +- .../overlay/internal/container/BuildError.tsx | 7 +- .../src/overlay/internal/container/Errors.tsx | 356 ++++++++---------- .../internal/container/ErrorsToast.tsx | 77 ++++ .../internal/container/RuntimeError.tsx | 235 +++++++++--- .../js/src/overlay/internal/helpers/clsx.ts | 71 ++++ .../js/src/overlay/internal/hooks/context.tsx | 56 +++ .../overlay/internal/hooks/usePagination.ts | 41 ++ .../overlay/internal/icons/AlertOctagon.tsx | 11 + .../overlay/internal/icons/AlertTriangle.tsx | 11 + .../src/overlay/internal/icons/BaseIcon.tsx | 33 ++ .../src/overlay/internal/icons/CloseIcon.tsx | 32 +- .../overlay/internal/icons/ExternalLink.tsx | 11 + .../js/src/overlay/internal/icons/LICENSE.md | 15 + .../src/overlay/internal/icons/PackageX.tsx | 13 + .../js/src/overlay/internal/icons/index.ts | 6 + .../js/src/overlay/internal/styles/Base.tsx | 63 +++- .../internal/styles/ComponentStyles.tsx | 14 +- .../src/overlay/internal/styles/CssReset.tsx | 6 +- 41 files changed, 1595 insertions(+), 735 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeaderTabList.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/container/ErrorsToast.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/clsx.ts create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/context.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/usePagination.ts create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertOctagon.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertTriangle.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/icons/BaseIcon.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/icons/ExternalLink.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/icons/LICENSE.md create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/icons/PackageX.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/icons/index.ts diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx index be141df93f42a0..775c6958b91746 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx @@ -126,71 +126,72 @@ type ReactDevOverlayProps = { children?: React.ReactNode; }; -const ReactDevOverlay: React.FunctionComponent<ReactDevOverlayProps> = - function ReactDevOverlay({ children, preventDisplay, globalOverlay }) { - const [state, dispatch] = React.useReducer< - React.Reducer<OverlayState, Bus.BusEvent> - >(reducer, { - nextId: 1, - issue: null, - errors: [], - refreshState: { - type: "idle", - }, - }); - - React.useEffect(() => { - Bus.on(dispatch); - return function () { - Bus.off(dispatch); - }; - }, [dispatch]); - - const onComponentError = React.useCallback( - (_error: Error, _componentStack: string | null) => { - // TODO: special handling - }, - [] - ); - - const hasBuildError = state.issue != null; - const hasRuntimeErrors = Boolean(state.errors.length); - - const errorType = hasBuildError - ? "build" - : hasRuntimeErrors - ? "runtime" - : null; - - const isMounted = hasBuildError || hasRuntimeErrors; - - return ( - <React.Fragment> - <ErrorBoundary - globalOverlay={globalOverlay} - isMounted={isMounted} - onError={onComponentError} - > - {children ?? null} - </ErrorBoundary> - {isMounted ? ( - <ShadowPortal globalOverlay={globalOverlay}> - <CssReset /> - <Base /> - <ComponentStyles /> - - {shouldPreventDisplay( - errorType, - preventDisplay - ) ? null : hasBuildError ? ( - <BuildError issue={state.issue!} /> - ) : hasRuntimeErrors ? ( - <Errors errors={state.errors} /> - ) : undefined} - </ShadowPortal> - ) : undefined} - </React.Fragment> - ); - }; - -export default ReactDevOverlay; +export default function ReactDevOverlay({ + children, + preventDisplay, + globalOverlay, +}: ReactDevOverlayProps) { + const [state, dispatch] = React.useReducer< + React.Reducer<OverlayState, Bus.BusEvent> + >(reducer, { + nextId: 1, + issue: null, + errors: [], + refreshState: { + type: "idle", + }, + }); + + React.useEffect(() => { + Bus.on(dispatch); + return function () { + Bus.off(dispatch); + }; + }, [dispatch]); + + const onComponentError = React.useCallback( + (_error: Error, _componentStack: string | null) => { + // TODO: special handling + }, + [] + ); + + const hasBuildError = state.issue != null; + const hasRuntimeErrors = Boolean(state.errors.length); + + const errorType = hasBuildError + ? "build" + : hasRuntimeErrors + ? "runtime" + : null; + + const isMounted = hasBuildError || hasRuntimeErrors; + + return ( + <React.Fragment> + <ErrorBoundary + globalOverlay={globalOverlay} + isMounted={isMounted} + onError={onComponentError} + > + {children ?? null} + </ErrorBoundary> + {isMounted ? ( + <ShadowPortal globalOverlay={globalOverlay}> + <CssReset /> + <Base /> + <ComponentStyles /> + + {shouldPreventDisplay( + errorType, + preventDisplay + ) ? null : hasBuildError ? ( + <BuildError issue={state.issue!} /> + ) : hasRuntimeErrors ? ( + <Errors errors={state.errors} /> + ) : null} + </ShadowPortal> + ) : null} + </React.Fragment> + ); +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/CodeFrame.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/CodeFrame.tsx index 1b41b372f33c5f..4a67f94733d612 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/CodeFrame.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/CodeFrame.tsx @@ -7,10 +7,7 @@ import { getFrameSource } from "../../helpers/stack-frame"; export type CodeFrameProps = { stackFrame: StackFrame; codeFrame: string }; -export const CodeFrame: React.FC<CodeFrameProps> = function CodeFrame({ - stackFrame, - codeFrame, -}) { +export function CodeFrame({ stackFrame, codeFrame }: CodeFrameProps) { // Strip leading spaces out of the code frame: const formattedFrame = React.useMemo<string>(() => { const lines = codeFrame.split(/\r?\n/g); @@ -67,7 +64,7 @@ export const CodeFrame: React.FC<CodeFrameProps> = function CodeFrame({ // TODO: make the caret absolute return ( - <div data-nextjs-codeframe> + <div className="codeframe"> <div> <p role="link" @@ -112,4 +109,4 @@ export const CodeFrame: React.FC<CodeFrameProps> = function CodeFrame({ </pre> </div> ); -}; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/index.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/index.tsx index 3829deb8b5d94b..1fe60975845ee3 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/index.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/index.tsx @@ -1 +1,2 @@ export { CodeFrame } from "./CodeFrame"; +export { styles } from "./styles"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/styles.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/styles.tsx index aa94d638babd21..b26ed5ff0c507b 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/styles.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/CodeFrame/styles.tsx @@ -1,49 +1,49 @@ import { noop as css } from "../../helpers/noop-template"; const styles = css` - [data-nextjs-codeframe] { + .codeframe { overflow: auto; border-radius: var(--size-gap-half); background-color: var(--color-ansi-bg); color: var(--color-ansi-fg); } - [data-nextjs-codeframe]::selection, - [data-nextjs-codeframe] *::selection { + .codeframe::selection, + .codeframe *::selection { background-color: var(--color-ansi-selection); } - [data-nextjs-codeframe] * { + .codeframe * { color: inherit; background-color: transparent; - font-family: var(--font-stack-monospace); + font-family: var(--font-mono); } - [data-nextjs-codeframe] > * { + .codeframe > * { margin: 0; padding: calc(var(--size-gap) + var(--size-gap-half)) calc(var(--size-gap-double) + var(--size-gap-half)); } - [data-nextjs-codeframe] > div { + .codeframe > div { display: inline-block; width: auto; min-width: 100%; border-bottom: 1px solid var(--color-ansi-bright-black); } - [data-nextjs-codeframe] > div > p { + .codeframe > div > p { display: flex; align-items: center; justify-content: space-between; cursor: pointer; margin: 0; } - [data-nextjs-codeframe] > div > p:hover { + .codeframe > div > p:hover { text-decoration: underline dotted; } - [data-nextjs-codeframe] div > p > svg { + .codeframe div > p > svg { width: auto; height: 1em; margin-left: 8px; } - [data-nextjs-codeframe] div > pre { + .codeframe div > pre { overflow: hidden; display: inline-block; } diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/Dialog.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/Dialog.tsx index 7bad2da0ba987a..993c956c2d1ddb 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/Dialog.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/Dialog.tsx @@ -1,20 +1,23 @@ import * as React from "react"; import { useOnClickOutside } from "../../hooks/use-on-click-outside"; +import { clsx } from "../../helpers/clsx"; +import { noop as css } from "../../helpers/noop-template"; -export type DialogProps = React.PropsWithChildren & { - type: "error" | "warning"; +export type DialogProps = { "aria-labelledby": string; "aria-describedby": string; onClose?: (e: MouseEvent | TouchEvent) => void; + className?: string; + children?: React.ReactNode | undefined; }; -const Dialog: React.FC<DialogProps> = function Dialog({ +export function Dialog({ children, - type, onClose, + className, ...props -}) { +}: DialogProps) { const [dialog, setDialog] = React.useState<HTMLDivElement | null>(null); const onDialog = React.useCallback( (node: React.SetStateAction<HTMLDivElement | null>) => { @@ -37,6 +40,7 @@ const Dialog: React.FC<DialogProps> = function Dialog({ return; } const shadowRoot = root; + function handler(e: KeyboardEvent) { const el = shadowRoot.activeElement; if ( @@ -59,17 +63,56 @@ const Dialog: React.FC<DialogProps> = function Dialog({ return ( <div ref={onDialog} - data-nextjs-dialog tabIndex={-1} role="dialog" aria-labelledby={props["aria-labelledby"]} aria-describedby={props["aria-describedby"]} aria-modal="true" + className={clsx("dialog", className)} > - <div data-nextjs-dialog-banner className={`banner-${type}`} /> {children} </div> ); -}; +} + +export const styles = css` + .dialog { + display: flex; + flex-direction: column; + width: 100%; + margin-right: auto; + margin-left: auto; + outline: none; + background: white; + border-radius: var(--size-gap); + box-shadow: 0 var(--size-gap-half) var(--size-gap-double) + rgba(0, 0, 0, 0.25); + max-height: calc(100% - 56px); + overflow-y: hidden; + } + + @media (max-height: 812px) { + .dialog-overlay { + max-height: calc(100% - 15px); + } + } -export { Dialog }; + @media (min-width: 576px) { + .dialog { + max-width: 540px; + box-shadow: 0 var(--size-gap) var(--size-gap-quad) rgba(0, 0, 0, 0.25); + } + } + + @media (min-width: 768px) { + .dialog { + max-width: 720px; + } + } + + @media (min-width: 992px) { + .dialog { + max-width: 960px; + } + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogBody.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogBody.tsx index 7b5b803024b365..39765d020e1828 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogBody.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogBody.tsx @@ -1,18 +1,24 @@ import * as React from "react"; +import { clsx } from "../../helpers/clsx"; +import { noop as css } from "../../helpers/noop-template"; -export type DialogBodyProps = React.PropsWithChildren & { +export type DialogBodyProps = { className?: string; -}; + children?: React.ReactNode; +} & React.HTMLProps<HTMLDivElement>; -const DialogBody: React.FC<DialogBodyProps> = function DialogBody({ - children, - className, -}) { +export function DialogBody({ children, className, ...rest }: DialogBodyProps) { return ( - <div data-nextjs-dialog-body className={className}> + <div className={clsx("dialog-body", className)} {...rest}> {children} </div> ); -}; +} -export { DialogBody }; +export const styles = css` + .dialog-content > .dialog-body { + position: relative; + flex: 1 1 auto; + padding: var(--size-gap-double); + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogContent.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogContent.tsx index 94ce5d442af9e0..3ed6af50709d42 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogContent.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogContent.tsx @@ -1,18 +1,35 @@ import * as React from "react"; -export type DialogContentProps = React.PropsWithChildren & { +import { clsx } from "../../helpers/clsx"; +import { noop as css } from "../../helpers/noop-template"; + +export type DialogContentProps = { className?: string; -}; + children?: React.ReactNode; +} & React.HTMLProps<HTMLDivElement>; -const DialogContent: React.FC<DialogContentProps> = function DialogContent({ - children, +export function DialogContent({ className, -}) { + children, + ...rest +}: DialogContentProps) { return ( - <div data-nextjs-dialog-content className={className}> + <div className={clsx("dialog-content", className)} {...rest}> {children} </div> ); -}; +} + +export const styles = css` + .dialog-content { + display: flex; + flex-direction: column; + + overflow-y: hidden; + border: none; + margin: 0; + padding: 0; -export { DialogContent }; + height: 100%; + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeader.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeader.tsx index cd6cdee5837fae..8d7c5c50da0374 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeader.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeader.tsx @@ -1,18 +1,151 @@ import * as React from "react"; +import { clsx } from "../../helpers/clsx"; +import { CloseIcon } from "../../icons"; +import { noop as css } from "../../helpers/noop-template"; -export type DialogHeaderProps = React.PropsWithChildren & { +export type DialogHeaderProps = { + close?: () => void; className?: string; + children: React.ReactNode; }; -const DialogHeader: React.FC<DialogHeaderProps> = function DialogHeader({ +export function DialogHeader({ children, className, -}) { + close, +}: DialogHeaderProps) { + const buttonClose = React.useRef<HTMLButtonElement | null>(null); + + React.useEffect(() => { + if (buttonClose.current == null) { + return; + } + + const root = buttonClose.current.getRootNode(); + const d = self.document; + + function handler(e: KeyboardEvent) { + if (e.key === "Escape") { + e.stopPropagation(); + if (root instanceof ShadowRoot) { + const a = root.activeElement; + if (a && a !== buttonClose.current && a instanceof HTMLElement) { + a.blur(); + return; + } + } + + if (close) { + close(); + } + } + } + + root.addEventListener("keydown", handler as EventListener); + if (root !== d) { + d.addEventListener("keydown", handler); + } + return function () { + root.removeEventListener("keydown", handler as EventListener); + if (root !== d) { + d.removeEventListener("keydown", handler); + } + }; + }, [close, buttonClose]); + return ( - <div data-nextjs-dialog-header className={className}> + <div className={clsx("dialog-header", className)}> {children} + <div className="filler"> </div> + {close ? ( + <button + ref={buttonClose} + type="button" + onClick={close} + aria-label="Close" + className="close-button" + > + <span aria-hidden="true"> + <CloseIcon /> + </span> + </button> + ) : null} </div> ); -}; +} + +export const styles = css` + .dialog-content > .dialog-header { + flex-shrink: 0; + } + + .dialog-header { + --local-padding: var(--size-gap-big); + + display: flex; + flex-direction: row; + align-content: center; + align-items: center; + justify-content: space-between; + + height: calc( + var(--size-icon) + var(--local-padding) * 2 + var(--border) * 2 + ); + + background-color: var(--color-bg-secondary); + } + + .dialog-header > * { + height: 100%; + padding: var(--local-padding); + + border-bottom: var(--border); + } + + .dialog-header > *:not(:first-child):not(.close-button) { + border-left: var(--border-half); + } + + .dialog-header + > *:not(:last-child):not(:nth-last-child(2):before(.close-button)) { + border-right: var(--border-half); + } + + .dialog-header > .filler { + display: flex; + flex: 1 0 auto; + flex-grow: 1; + align-self: stretch; + padding-left: 0; + padding-right: 0; + } + + .dialog-header > .filler > div { + display: flex; + flex: 1 0 auto; + flex-grow: 1; + align-self: stretch; + padding: var(--local-padding); + padding-left: 0; + padding-right: 0; + border-bottom: var(--border); + } + + .dialog-header > button:last-of-type { + border: none; + border-bottom: var(--border); + + background-color: transparent; + appearance: none; + } + + .dialog-header > button:last-of-type > span { + display: flex; + opacity: 0.4; + transition: opacity 0.25s ease; + } -export { DialogHeader }; + .dialog-header > button:last-of-type:hover > span { + opacity: 0.7; + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeaderTabList.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeaderTabList.tsx new file mode 100644 index 00000000000000..a9972180036ae2 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/DialogHeaderTabList.tsx @@ -0,0 +1,85 @@ +import * as React from "react"; + +import { noop as css } from "../../helpers/noop-template"; +import { clsx } from "../../helpers/clsx"; +import { TabList } from "../Tabs"; + +export type DialogHeaderTabListProps = { + className?: string; + children: React.ReactNode; +}; + +export function DialogHeaderTabList({ + className, + children, +}: DialogHeaderTabListProps) { + return ( + <TabList className={clsx("dialog-header-tab-list", className)}> + {children} + </TabList> + ); +} + +export const styles = css` + .dialog-header > .dialog-header-tab-list { + padding: 0; + border: none !important; + } + + .dialog-header-tab-list { + height: 100%; + display: flex; + justify-content: start; + align-content: center; + border-bottom: 0; + } + + .dialog-header-tab-list > .tab { + display: flex; + align-items: center; + + padding-left: calc(var(--local-padding) + var(--size-gap)); + padding-right: calc(var(--local-padding) + var(--size-gap)); + + /* slight offset for the severity top border on the tabs */ + padding-top: calc(var(--local-padding) + var(--size-border)); + padding-bottom: calc(var(--local-padding) - var(--size-border)); + + height: 100%; + min-width: 250px; + + border-top: none; + border-bottom: var(--border); + border-left: var(--border-half); + border-right: var(--border-half); + + color: var(--color-text-dim); + background-color: transparent; + } + + .dialog-header-tab-list > .tab:first-child { + border-left: none; + } + + .tab::after { + position: absolute; + left: 0; + top: 0; + right: 0; + + border-top: var(--size-border-double) solid transparent; + + content: " "; + } + + .dialog-header-tab-list > .tab:hover { + background-color: var(--color-bg-secondary-hover); + } + + .dialog-header-tab-list > .tab[aria-selected="true"] { + color: var(--color-text); + background-color: var(--color-bg); + + border-bottom-color: transparent; + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/index.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/index.ts index e855977d0339a4..a87a896cc3b875 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/index.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/index.ts @@ -1,5 +1,9 @@ -export { Dialog } from "./Dialog"; -export { DialogBody } from "./DialogBody"; -export { DialogContent } from "./DialogContent"; -export { DialogHeader } from "./DialogHeader"; +export { Dialog, DialogProps } from "./Dialog"; +export { DialogBody, DialogBodyProps } from "./DialogBody"; +export { DialogContent, DialogContentProps } from "./DialogContent"; +export { DialogHeader, DialogHeaderProps } from "./DialogHeader"; +export { + DialogHeaderTabList, + DialogHeaderTabListProps, +} from "./DialogHeaderTabList"; export { styles } from "./styles"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/styles.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/styles.ts index 0ec4aef7392369..b34ee6f70cbd60 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/styles.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Dialog/styles.ts @@ -1,91 +1,16 @@ import { noop as css } from "../../helpers/noop-template"; +import { styles as dialogStyles } from "./Dialog"; +import { styles as bodyStyles } from "./DialogBody"; +import { styles as contentStyles } from "./DialogContent"; +import { styles as headerStyles } from "./DialogHeader"; +import { styles as tabListStyles } from "./DialogHeaderTabList"; const styles = css` - [data-nextjs-dialog] { - display: flex; - flex-direction: column; - width: 100%; - margin-right: auto; - margin-left: auto; - outline: none; - background: white; - border-radius: var(--size-gap); - box-shadow: 0 var(--size-gap-half) var(--size-gap-double) - rgba(0, 0, 0, 0.25); - max-height: calc(100% - 56px); - overflow-y: hidden; - } - - @media (max-height: 812px) { - [data-nextjs-dialog-overlay] { - max-height: calc(100% - 15px); - } - } - - @media (min-width: 576px) { - [data-nextjs-dialog] { - max-width: 540px; - box-shadow: 0 var(--size-gap) var(--size-gap-quad) rgba(0, 0, 0, 0.25); - } - } - - @media (min-width: 768px) { - [data-nextjs-dialog] { - max-width: 720px; - } - } - - @media (min-width: 992px) { - [data-nextjs-dialog] { - max-width: 960px; - } - } - - [data-nextjs-dialog-banner] { - position: relative; - } - [data-nextjs-dialog-banner].banner-warning { - border-color: var(--color-ansi-yellow); - } - [data-nextjs-dialog-banner].banner-error { - border-color: var(--color-ansi-red); - } - - [data-nextjs-dialog-banner]::after { - z-index: 2; - content: ""; - position: absolute; - top: 0; - right: 0; - width: 100%; - /* banner width: */ - border-top-width: var(--size-gap-half); - border-bottom-width: 0; - border-top-style: solid; - border-bottom-style: solid; - border-top-color: inherit; - border-bottom-color: transparent; - } - - [data-nextjs-dialog-content] { - overflow-y: auto; - border: none; - margin: 0; - /* calc(padding + banner width offset) */ - padding: calc(var(--size-gap-double) + var(--size-gap-half)) - var(--size-gap-double); - height: 100%; - display: flex; - flex-direction: column; - } - [data-nextjs-dialog-content] > [data-nextjs-dialog-header] { - flex-shrink: 0; - margin-bottom: var(--size-gap-double); - } - [data-nextjs-dialog-content] > [data-nextjs-dialog-body] { - position: relative; - flex: 1 1 auto; - } + ${dialogStyles} + ${bodyStyles} + ${contentStyles} + ${headerStyles} + ${tabListStyles} `; export { styles }; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/LeftRightDialogHeader.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/LeftRightDialogHeader.tsx index 8f824a635e2a96..686ffe36d6ed88 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/LeftRightDialogHeader.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/LeftRightDialogHeader.tsx @@ -1,166 +1,149 @@ import * as React from "react"; -import { CloseIcon } from "../../icons/CloseIcon"; +import { clsx } from "../../helpers/clsx"; -export type LeftRightDialogHeaderProps = React.PropsWithChildren & { +export type LeftRightDialogHeaderProps = { + hidden?: boolean; + previous?: (() => void) | null; + next?: (() => void) | null; + severity: "warning" | "error"; className?: string; - previous: (() => void) | null; - next: (() => void) | null; - close?: () => void; + children: React.ReactNode; }; -const LeftRightDialogHeader: React.FC<LeftRightDialogHeaderProps> = - function LeftRightDialogHeader({ - children, - className, - previous, - next, - close, - }) { - const buttonLeft = React.useRef<HTMLButtonElement | null>(null); - const buttonRight = React.useRef<HTMLButtonElement | null>(null); - const buttonClose = React.useRef<HTMLButtonElement | null>(null); +export function LeftRightDialogHeader({ + hidden = false, + previous, + next, + severity, + className, + children, +}: LeftRightDialogHeaderProps) { + const buttonLeft = React.useRef<HTMLButtonElement | null>(null); + const buttonRight = React.useRef<HTMLButtonElement | null>(null); - const [nav, setNav] = React.useState<HTMLElement | null>(null); - const onNav = React.useCallback((el: HTMLElement) => { - setNav(el); - }, []); + const [nav, setNav] = React.useState<HTMLElement | null>(null); + const onNav = React.useCallback((el: HTMLElement) => { + setNav(el); + }, []); - React.useEffect(() => { - if (nav == null) { - return; - } - - const root = nav.getRootNode(); - const d = self.document; + React.useEffect(() => { + if (nav == null || hidden) { + return; + } - function handler(e: KeyboardEvent) { - if (e.key === "ArrowLeft") { - e.stopPropagation(); - if (buttonLeft.current) { - buttonLeft.current.focus(); - } - previous && previous(); - } else if (e.key === "ArrowRight") { - e.stopPropagation(); - if (buttonRight.current) { - buttonRight.current.focus(); - } - next && next(); - } else if (e.key === "Escape") { - e.stopPropagation(); - if (root instanceof ShadowRoot) { - const a = root.activeElement; - if (a && a !== buttonClose.current && a instanceof HTMLElement) { - a.blur(); - return; - } - } + const root = nav.getRootNode(); + const d = self.document; - if (close) { - close(); - } + function handler(e: KeyboardEvent) { + if (e.key === "ArrowLeft") { + e.stopPropagation(); + if (buttonLeft.current) { + buttonLeft.current.focus(); } + previous && previous(); + } else if (e.key === "ArrowRight") { + e.stopPropagation(); + if (buttonRight.current) { + buttonRight.current.focus(); + } + next && next(); } + } - root.addEventListener("keydown", handler as EventListener); + root.addEventListener("keydown", handler as EventListener); + if (root !== d) { + d.addEventListener("keydown", handler); + } + return function () { + root.removeEventListener("keydown", handler as EventListener); if (root !== d) { - d.addEventListener("keydown", handler); + d.removeEventListener("keydown", handler); } - return function () { - root.removeEventListener("keydown", handler as EventListener); - if (root !== d) { - d.removeEventListener("keydown", handler); - } - }; - }, [close, nav, next, previous]); + }; + }, [hidden, nav, next, previous]); - // Unlock focus for browsers like Firefox, that break all user focus if the - // currently focused item becomes disabled. - React.useEffect(() => { - if (nav == null) { - return; - } + // Unlock focus for browsers like Firefox, that break all user focus if the + // currently focused item becomes disabled. + React.useEffect(() => { + if (nav == null) { + return; + } - const root = nav.getRootNode(); - // Always true, but we do this for TypeScript: - if (root instanceof ShadowRoot) { - const a = root.activeElement; + const root = nav.getRootNode(); + // Always true, but we do this for TypeScript: + if (root instanceof ShadowRoot) { + const a = root.activeElement; - if (previous == null) { - if (buttonLeft.current && a === buttonLeft.current) { - buttonLeft.current.blur(); - } - } else if (next == null) { - if (buttonRight.current && a === buttonRight.current) { - buttonRight.current.blur(); - } + if (previous == null) { + if (buttonLeft.current && a === buttonLeft.current) { + buttonLeft.current.blur(); + } + } else if (next == null) { + if (buttonRight.current && a === buttonRight.current) { + buttonRight.current.blur(); } } - }, [nav, next, previous]); + } + }, [nav, next, previous]); + + return ( + <nav + ref={onNav} + data-severity={severity} + className={clsx("dialog-left-right", className)} + > + {children} +   + <button + ref={buttonLeft} + type="button" + disabled={previous == null ? true : undefined} + aria-disabled={previous == null ? true : undefined} + onClick={previous ?? undefined} + > + <ArrowLeft /> + </button> + <button + ref={buttonRight} + type="button" + disabled={next == null ? true : undefined} + aria-disabled={next == null ? true : undefined} + onClick={next ?? undefined} + > + <ArrowRight /> + </button> + </nav> + ); +} - return ( - <div data-nextjs-dialog-left-right className={className}> - <nav ref={onNav}> - <button - ref={buttonLeft} - type="button" - disabled={previous == null ? true : undefined} - aria-disabled={previous == null ? true : undefined} - onClick={previous ?? undefined} - > - <svg - viewBox="0 0 14 14" - fill="none" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.99996 1.16666L1.16663 6.99999L6.99996 12.8333M12.8333 6.99999H1.99996H12.8333Z" - stroke="currentColor" - strokeWidth="2" - strokeLinecap="round" - strokeLinejoin="round" - /> - </svg> - </button> - <button - ref={buttonRight} - type="button" - disabled={next == null ? true : undefined} - aria-disabled={next == null ? true : undefined} - onClick={next ?? undefined} - > - <svg - viewBox="0 0 14 14" - fill="none" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M6.99996 1.16666L12.8333 6.99999L6.99996 12.8333M1.16663 6.99999H12H1.16663Z" - stroke="currentColor" - strokeWidth="2" - strokeLinecap="round" - strokeLinejoin="round" - /> - </svg> - </button> -   - {children} - </nav> - {close ? ( - <button - data-nextjs-errors-dialog-left-right-close-button - ref={buttonClose} - type="button" - onClick={close} - aria-label="Close" - > - <span aria-hidden="true"> - <CloseIcon /> - </span> - </button> - ) : null} - </div> - ); - }; +function ArrowLeft() { + return ( + <svg + viewBox="0 0 14 14" + fill="none" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + xmlns="http://www.w3.org/2000/svg" + > + <path d="M6.99996 1.16666L1.16663 6.99999L6.99996 12.8333M12.8333 6.99999H1.99996H12.8333Z" /> + </svg> + ); +} -export { LeftRightDialogHeader }; +function ArrowRight() { + return ( + <svg + viewBox="0 0 14 14" + fill="none" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + xmlns="http://www.w3.org/2000/svg" + > + <path d="M6.99996 1.16666L12.8333 6.99999L6.99996 12.8333M1.16663 6.99999H12H1.16663Z" /> + </svg> + ); +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/styles.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/styles.ts index a1b22e57830f1f..34e2500de01ea4 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/styles.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/LeftRightDialogHeader/styles.ts @@ -1,14 +1,10 @@ import { noop as css } from "../../helpers/noop-template"; const styles = css` - [data-nextjs-dialog-left-right] { - display: flex; - flex-direction: row; - align-content: center; - align-items: center; - justify-content: space-between; - } - [data-nextjs-dialog-left-right] > nav > button { + .dialog-left-right > button { + --bg-alpha: 0.1; + --fg-alpha: 1; + display: inline-flex; align-items: center; justify-content: center; @@ -17,44 +13,44 @@ const styles = css` height: calc(var(--size-gap-double) + var(--size-gap)); font-size: 0; border: none; - background-color: rgba(255, 85, 85, 0.1); - color: var(--color-ansi-red); + + background-color: hsla(var(--color-base), var(--bg-alpha)); + color: hsla(var(--color-base), var(--fg-alpha)); + cursor: pointer; transition: background-color 0.25s ease; } - [data-nextjs-dialog-left-right] > nav > button > svg { - width: auto; - height: calc(var(--size-gap) + var(--size-gap-half)); + + .dialog-left-right[data-severity="error"] > button { + --color-base: var(--color-error-bright-hsl); + } + + .dialog-left-right[data-severity="warning"] > button { + --color-base: var(--color-warning-bright-hsl); } - [data-nextjs-dialog-left-right] > nav > button:hover { - background-color: rgba(255, 85, 85, 0.2); + + .dialog-left-right > button:hover { + --bg-alpha: 0.2; } - [data-nextjs-dialog-left-right] > nav > button:disabled { - background-color: rgba(255, 85, 85, 0.1); - color: rgba(255, 85, 85, 0.4); + + .dialog-left-right > button:disabled { + --bg-alpha: 0.1; + --fg-alpha: 0.4; cursor: not-allowed; } - [data-nextjs-dialog-left-right] > nav > button:first-of-type { + .dialog-left-right > button:first-of-type { border-radius: var(--size-gap-half) 0 0 var(--size-gap-half); margin-right: 1px; } - [data-nextjs-dialog-left-right] > nav > button:last-of-type { + + .dialog-left-right > button:last-of-type { border-radius: 0 var(--size-gap-half) var(--size-gap-half) 0; } - [data-nextjs-dialog-left-right] > button:last-of-type { - border: 0; - padding: 0; - - background-color: transparent; - appearance: none; - - opacity: 0.4; - transition: opacity 0.25s ease; - } - [data-nextjs-dialog-left-right] > button:last-of-type:hover { - opacity: 0.7; + .dialog-left-right > button > svg { + width: auto; + height: var(--size-icon-small); } `; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/Overlay.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/Overlay.tsx index 3c3715f0daca19..8cbaceec3838cf 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/Overlay.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/Overlay.tsx @@ -2,17 +2,14 @@ import * as React from "react"; import { lock, unlock } from "./body-locker"; import allyTrap from "./maintain--tab-focus"; +import { clsx } from "../../helpers/clsx"; export type OverlayProps = React.PropsWithChildren & { className?: string; fixed?: boolean; }; -const Overlay: React.FC<OverlayProps> = function Overlay({ - className, - children, - fixed, -}) { +export function Overlay({ className, children, fixed }: OverlayProps) { React.useEffect(() => { lock(); return () => { @@ -37,14 +34,12 @@ const Overlay: React.FC<OverlayProps> = function Overlay({ }, [overlay]); return ( - <div data-nextjs-dialog-overlay className={className} ref={onOverlay}> + <div className={clsx("dialog-overlay", className)} ref={onOverlay}> <div - data-nextjs-dialog-backdrop - data-nextjs-dialog-backdrop-fixed={fixed ? true : undefined} + className={"dialog-backdrop"} + data-dialog-backdrop-fixed={fixed ? true : undefined} /> {children} </div> ); -}; - -export { Overlay }; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/index.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/index.tsx index a964f036c6f789..ab0c59753650ec 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/index.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/index.tsx @@ -1 +1,2 @@ export { Overlay } from "./Overlay"; +export { styles } from "./styles"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/styles.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/styles.tsx index 471b582eeb1054..8413cef035a32d 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/styles.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Overlay/styles.tsx @@ -1,7 +1,7 @@ import { noop as css } from "../../helpers/noop-template"; const styles = css` - [data-nextjs-dialog-overlay] { + .dialog-overlay { position: fixed; top: 0; right: 0; @@ -18,12 +18,12 @@ const styles = css` } @media (max-height: 812px) { - [data-nextjs-dialog-overlay] { + .dialog-overlay { padding: 15px 15px 0; } } - [data-nextjs-dialog-backdrop] { + .dialog-backdrop { position: fixed; top: 0; right: 0; @@ -34,7 +34,7 @@ const styles = css` z-index: -1; } - [data-nextjs-dialog-backdrop-fixed] { + .dialog-backdrop[data-dialog-backdrop-fixed] { cursor: not-allowed; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/ShadowPortal.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/ShadowPortal.tsx index 4efc6e7945c1c4..18a57a46805eea 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/ShadowPortal.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/ShadowPortal.tsx @@ -6,10 +6,7 @@ export type ShadowPortalProps = { globalOverlay?: boolean; }; -export const ShadowPortal: React.FC<ShadowPortalProps> = function Portal({ - children, - globalOverlay, -}) { +export function ShadowPortal({ children, globalOverlay }: ShadowPortalProps) { const mountNode = React.useRef<HTMLDivElement | null>(null); const portalNode = React.useRef<HTMLElement | null>(null); const shadowNode = React.useRef<ShadowRoot | null>(null); @@ -35,4 +32,4 @@ export const ShadowPortal: React.FC<ShadowPortalProps> = function Portal({ ) : globalOverlay ? null : ( <span ref={mountNode} /> ); -}; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx new file mode 100644 index 00000000000000..089d30d68bd43d --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx @@ -0,0 +1,234 @@ +// TODO: replace with `@react/tabs` + +import * as React from "react"; +import { noop as css } from "../../helpers/noop-template"; +import { createContext } from "../../hooks/context"; +import { clsx } from "../../helpers/clsx"; + +type Merge<P1 = {}, P2 = {}> = Omit<P1, keyof P2> & P2; + +type PropsWithAs<As, OwnProps = {}> = As extends "" + ? { as: keyof JSX.IntrinsicElements } + : As extends React.JSXElementConstructor<infer P> + ? Merge<P, OwnProps & { as: As }> + : As extends keyof JSX.IntrinsicElements + ? Merge<JSX.IntrinsicElements[As], OwnProps & { as: As }> + : never; + +type TabRefs = Record<string, HTMLElement | undefined>; + +type TabsContextType = { + selectedId: string; + tabRefs: Readonly<TabRefs>; + registerTabRef: (id: string, el: HTMLElement | null) => void; + onSelectTab: (id: string) => void; +}; + +const [TabsProvider, useTabsContext] = createContext<TabsContextType>("Tabs"); + +export type TabsProps = { + defaultId: string; + selectedId?: string; + onChange?: (id: string) => void; + children: React.ReactNode; +}; + +export function Tabs({ + defaultId, + selectedId: controlledId, + onChange, + children, +}: TabsProps) { + const [selectedId, setSelectedId] = React.useState(controlledId ?? defaultId); + const [shouldCheckId, setShouldShouldCheckId] = React.useState(false); + + const tabRefs = React.useRef<TabRefs>({}); + + const onSelectTabUnchecked = React.useCallback( + (id: string) => { + onChange && onChange(id); + setSelectedId(id); + }, + [onChange] + ); + + const onSelectTab = React.useCallback( + (id: string) => { + if (id == selectedId) return; + + const tab = tabRefs.current[id]; + if (!tab) { + console.error( + `Tried selecting invalid tab id "${id}", only ${JSON.stringify( + Object.keys(tabRefs.current) + )} are available.` + ); + return; + } + + setTimeout(() => { + tab.focus(); + }, 0); + }, + [selectedId, onSelectTabUnchecked] + ); + + const registerTabRef = React.useCallback( + (id: string, el: HTMLElement | null) => { + if (el == null) { + delete tabRefs.current[id]; + setShouldShouldCheckId(true); + } else { + tabRefs.current[id] = el; + } + }, + [] + ); + + React.useEffect(() => { + if (!shouldCheckId) return; + + const currentTabRef = tabRefs.current[selectedId]; + if (currentTabRef == null) { + const availableIds = Object.keys(tabRefs.current); + if (availableIds.length > 0) { + onSelectTabUnchecked(availableIds[0]); + } + } + + setShouldShouldCheckId(false); + }, [shouldCheckId, selectedId, onSelectTabUnchecked]); + + React.useEffect(() => { + if (controlledId && controlledId != selectedId) { + onSelectTabUnchecked(controlledId); + } + }, [controlledId, selectedId, onSelectTabUnchecked]); + + return ( + <TabsProvider + selectedId={selectedId} + tabRefs={tabRefs.current} + registerTabRef={registerTabRef} + onSelectTab={onSelectTab} + > + {children} + </TabsProvider> + ); +} + +export type TabListProps = { + className?: string; + children: React.ReactNode; +}; + +export function TabList({ className, children }: TabListProps) { + return ( + <div role="tablist" className={clsx("tab-list", className)}> + {children} + </div> + ); +} + +export type TabProps = { + id: string; + next?: string; + prev?: string; + className?: string; + children: React.ReactNode; +}; + +export function Tab({ + id, + next, + prev, + className, + children, + ...rest +}: TabProps & React.HTMLProps<HTMLButtonElement>) { + const { selectedId, registerTabRef, onSelectTab } = useTabsContext("Tab"); + const selected = id == selectedId; + + const click = React.useCallback( + (ev: React.MouseEvent<any>) => { + ev.preventDefault(); + onSelectTab(id); + }, + [id, onSelectTab] + ); + + const keyDown = React.useCallback( + (ev: React.KeyboardEvent<any>) => { + if (prev && ev.key === "ArrowLeft") { + ev.stopPropagation(); + onSelectTab(prev); + } else if (next && ev.key === "ArrowRight") { + ev.stopPropagation(); + onSelectTab(next); + } + }, + [next, prev, onSelectTab] + ); + + const ref = React.useCallback( + (el: HTMLElement | null) => registerTabRef(id, el), + [id, registerTabRef] + ); + + return ( + <button + {...rest} + type="button" + ref={ref} + aria-controls={id} + id={`tab-${id}`} + role="tab" + aria-selected={selected} + tabIndex={selected ? 0 : -1} + className={clsx("tab", className)} + onClick={click} + onKeyDown={keyDown} + > + {children} + </button> + ); +} + +export type TabPanelPropsBase = { + id: string; + className?: string; +}; + +export function TabPanel< + As extends + | keyof JSX.IntrinsicElements + | React.JSXElementConstructor<any> = "div" +>({ + as: Comp = "div", + id, + className, + children, + ...rest +}: PropsWithAs<As, TabPanelPropsBase>) { + const { selectedId } = useTabsContext("Tab"); + const selected = id == selectedId; + + return ( + <Comp + {...rest} + id={id} + aria-labelledby={`tab-${id}`} + role="tabpanel" + className={clsx("tab-panel", className)} + data-hidden={!selected} + > + {children} + </Comp> + ); +} + +export const styles = css` + .tab-panel[data-hidden="true"] { + display: none; + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/Terminal.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/Terminal.tsx index 6842483126f9d0..06be320ab2397b 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/Terminal.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/Terminal.tsx @@ -3,9 +3,7 @@ import * as React from "react"; export type TerminalProps = { content: string }; -export const Terminal: React.FC<TerminalProps> = function Terminal({ - content, -}) { +export function Terminal({ content }: TerminalProps) { const decoded = React.useMemo(() => { return Anser.ansiToJson(content, { json: true, @@ -15,7 +13,7 @@ export const Terminal: React.FC<TerminalProps> = function Terminal({ }, [content]); return ( - <div data-nextjs-terminal> + <div className="terminal"> <pre> {decoded.map((entry, index) => ( <span @@ -35,4 +33,4 @@ export const Terminal: React.FC<TerminalProps> = function Terminal({ </pre> </div> ); -}; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/index.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/index.tsx index 5aaa605e8679f4..f7eb718fba1eff 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/index.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/index.tsx @@ -1 +1,2 @@ export { Terminal } from "./Terminal"; +export { styles } from "./styles"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/styles.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/styles.tsx index 74697e25571244..3a97dbca6cc639 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/styles.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Terminal/styles.tsx @@ -1,27 +1,27 @@ import { noop as css } from "../../helpers/noop-template"; const styles = css` - [data-nextjs-terminal] { + .terminal { border-radius: var(--size-gap-half); background-color: var(--color-ansi-bg); color: var(--color-ansi-fg); } - [data-nextjs-terminal]::selection, - [data-nextjs-terminal] *::selection { + .terminal::selection, + .terminal *::selection { background-color: var(--color-ansi-selection); } - [data-nextjs-terminal] * { + .terminal * { color: inherit; background-color: transparent; - font-family: var(--font-stack-monospace); + font-family: var(--font-mono); } - [data-nextjs-terminal] > * { + .terminal > * { margin: 0; padding: calc(var(--size-gap) + var(--size-gap-half)) calc(var(--size-gap-double) + var(--size-gap-half)); } - [data-nextjs-terminal] pre { + .terminal pre { white-space: pre-wrap; word-break: break-word; } diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/Toast.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/Toast.tsx index bcf1445313c869..844764b152597b 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/Toast.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/Toast.tsx @@ -1,18 +1,15 @@ import * as React from "react"; +import { clsx } from "../../helpers/clsx"; export type ToastProps = React.PropsWithChildren & { onClick?: (ev: React.MouseEvent<HTMLDivElement, MouseEvent>) => void; className?: string; }; -export const Toast: React.FC<ToastProps> = function Toast({ - onClick, - children, - className, -}) { +export function Toast({ onClick, children, className }: ToastProps) { return ( - <div data-nextjs-toast onClick={onClick} className={className}> - <div data-nextjs-toast-wrapper>{children}</div> + <div onClick={onClick} className={clsx("toast", className)}> + <div className="toast-wrapper">{children}</div> </div> ); -}; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/styles.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/styles.ts index cf586866ba830b..85313253b7d2a7 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/styles.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Toast/styles.ts @@ -1,7 +1,7 @@ import { noop as css } from "../../helpers/noop-template"; const styles = css` - [data-nextjs-toast] { + .toast { position: fixed; bottom: var(--size-gap-double); left: var(--size-gap-double); @@ -10,18 +10,18 @@ const styles = css` } @media (max-width: 440px) { - [data-nextjs-toast] { + .toast { max-width: 90vw; left: 5vw; } } - [data-nextjs-toast-wrapper] { + .toast-wrapper { padding: 16px; border-radius: var(--size-gap-half); - font-weight: 500; - color: var(--color-ansi-bright-white); - background-color: var(--color-ansi-red); + font-weight: 600; + color: var(--color-text-white); + background-color: var(--color-error); box-shadow: 0px var(--size-gap-double) var(--size-gap-quad) rgba(0, 0, 0, 0.25); } diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx index c327d96f616ad4..c9af4ec363504e 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx @@ -13,14 +13,11 @@ import { noop as css } from "../helpers/noop-template"; export type BuildErrorProps = { issue: Issue }; -export const BuildError: React.FC<BuildErrorProps> = function BuildError({ - issue, -}) { +export function BuildError({ issue }: BuildErrorProps) { const noop = React.useCallback(() => {}, []); return ( <Overlay fixed> <Dialog - type="error" aria-labelledby="nextjs__container_build_error_label" aria-describedby="nextjs__container_build_error_desc" onClose={noop} @@ -46,7 +43,7 @@ export const BuildError: React.FC<BuildErrorProps> = function BuildError({ </Dialog> </Overlay> ); -}; +} export const styles = css` .nextjs-container-build-error-header > h4 { diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx index 673460b37a38ac..5f11037a167d31 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx @@ -8,24 +8,27 @@ import { } from "../bus"; import { Dialog, - DialogBody, DialogContent, DialogHeader, + DialogHeaderTabList, + DialogProps, } from "../components/Dialog"; -import { LeftRightDialogHeader } from "../components/LeftRightDialogHeader"; import { Overlay } from "../components/Overlay"; -import { Toast } from "../components/Toast"; +import { Tab, TabPanel, Tabs } from "../components/Tabs"; import { getErrorByType, ReadyRuntimeError } from "../helpers/getErrorByType"; import { getErrorSource } from "../helpers/nodeStackFrames"; import { noop as css } from "../helpers/noop-template"; -import { CloseIcon } from "../icons/CloseIcon"; -import { RuntimeError } from "./RuntimeError"; +import { AlertOctagon } from "../icons"; +import { RuntimeErrorsDialogBody } from "./RuntimeError"; +import { ErrorsToast } from "../container/ErrorsToast"; export type SupportedErrorEvent = { id: number; event: UnhandledError | UnhandledRejection; }; -export type ErrorsProps = { errors: SupportedErrorEvent[] }; +export type ErrorsProps = { + errors: SupportedErrorEvent[]; +}; type ReadyErrorEvent = ReadyRuntimeError; @@ -42,36 +45,9 @@ function getErrorSignature(ev: SupportedErrorEvent): string { } } -const HotlinkedText: React.FC<{ - text: string; -}> = function HotlinkedText(props) { - const { text } = props; - - const linkRegex = /https?:\/\/[^\s/$.?#].[^\s"]*/i; - return ( - <> - {linkRegex.test(text) - ? text.split(" ").map((word, index, array) => { - if (linkRegex.test(word)) { - return ( - <React.Fragment key={`link-${index}`}> - <a href={word}>{word}</a> - {index === array.length - 1 ? "" : " "} - </React.Fragment> - ); - } - return index === array.length - 1 ? ( - <React.Fragment key={`text-${index}`}>{word}</React.Fragment> - ) : ( - <React.Fragment key={`text-${index}`}>{word} </React.Fragment> - ); - }) - : text} - </> - ); -}; - -export const Errors: React.FC<ErrorsProps> = function Errors({ errors }) { +function useResolvedErrors( + errors: SupportedErrorEvent[] +): [ReadyRuntimeError[], boolean] { const [lookups, setLookups] = React.useState( {} as { [eventId: string]: ReadyErrorEvent } ); @@ -107,7 +83,7 @@ export const Errors: React.FC<ErrorsProps> = function Errors({ errors }) { }, [errors, lookups]); const isLoading = React.useMemo<boolean>(() => { - return readyErrors.length < 1 && Boolean(errors.length); + return readyErrors.length < 1 && errors.length > 1; }, [errors.length, readyErrors.length]); React.useEffect(() => { @@ -135,36 +111,33 @@ export const Errors: React.FC<ErrorsProps> = function Errors({ errors }) { }; }, [nextError]); + // Reset component state when there are no errors to be displayed. + // This should never happen, but let's handle it. + React.useEffect(() => { + if (errors.length < 1) { + setLookups({}); + } + }, [errors.length]); + + return [readyErrors, isLoading]; +} + +const enum TabId { + RuntimeErrors = "runtime-errors", +} + +export function Errors({ errors }: ErrorsProps) { const [displayState, setDisplayState] = React.useState< "minimized" | "fullscreen" | "hidden" >("fullscreen"); - const [activeIdx, setActiveIndex] = React.useState<number>(0); - const previous = React.useCallback((e?: MouseEvent | TouchEvent) => { - e?.preventDefault(); - setActiveIndex((v) => Math.max(0, v - 1)); - }, []); - const next = React.useCallback( - (e?: MouseEvent | TouchEvent) => { - e?.preventDefault(); - setActiveIndex((v) => - Math.max(0, Math.min(readyErrors.length - 1, v + 1)) - ); - }, - [readyErrors.length] - ); - const activeError = React.useMemo<ReadyErrorEvent | null>( - () => readyErrors[activeIdx] ?? null, - [activeIdx, readyErrors] - ); + const [readyErrors, isLoading] = useResolvedErrors(errors); // Reset component state when there are no errors to be displayed. - // This should never happen, but lets handle it. + // This should never happen, but let's handle it. React.useEffect(() => { if (errors.length < 1) { - setLookups({}); setDisplayState("hidden"); - setActiveIndex(0); } }, [errors.length]); @@ -184,177 +157,178 @@ export const Errors: React.FC<ErrorsProps> = function Errors({ errors }) { [] ); + const hasErrors = errors.length > 0; + const hasServerError = readyErrors.some((err) => + ["server", "edge-server"].includes(getErrorSource(err.error) || "") + ); + const isClosable = !isLoading && !hasServerError; + + const defaultTab = TabId.RuntimeErrors; + const [selectedTab, setSelectedTab] = React.useState<string>(defaultTab); + // This component shouldn't be rendered with no errors, but if it is, let's // handle it gracefully by rendering nothing. - if (errors.length < 1 || activeError == null) { + if (errors.length < 1) { return null; } - if (isLoading) { - // TODO: better loading state - return <Overlay />; - } - if (displayState === "hidden") { return null; } if (displayState === "minimized") { return ( - <Toast className="nextjs-toast-errors-parent" onClick={fullscreen}> - <div className="nextjs-toast-errors"> - <svg - xmlns="http://www.w3.org/2000/svg" - width="24" - height="24" - viewBox="0 0 24 24" - fill="none" - stroke="currentColor" - strokeWidth="2" - strokeLinecap="round" - strokeLinejoin="round" - > - <circle cx="12" cy="12" r="10"></circle> - <line x1="12" y1="8" x2="12" y2="12"></line> - <line x1="12" y1="16" x2="12.01" y2="16"></line> - </svg> - <span> - {readyErrors.length} error - {readyErrors.length > 1 ? "s" : ""} - </span> - <button - data-nextjs-toast-errors-hide-button - className="nextjs-toast-errors-hide-button" - type="button" - onClick={(e) => { - e.stopPropagation(); - hide(); - }} - aria-label="Hide Errors" - > - <CloseIcon /> - </button> - </div> - </Toast> + <ErrorsToast + errorCount={readyErrors.length} + onClick={fullscreen} + onClose={hide} + /> ); } - const isServerError = ["server", "edge-server"].includes( - getErrorSource(activeError.error) || "" + return ( + <ErrorsDialog + aria-labelledby="errors_label" + aria-describedby="errors_desc" + onClose={isClosable ? minimize : undefined} + > + <Tabs + defaultId={defaultTab} + selectedId={selectedTab} + onChange={setSelectedTab} + > + <DialogHeader + className="errors-header" + close={isClosable ? minimize : undefined} + > + <DialogHeaderTabList> + {hasErrors && ( + <Tab id={TabId.RuntimeErrors} data-severity="error"> + <AlertOctagon /> + {isLoading ? "Loading" : readyErrors.length} Runtime Errors + {isLoading ? "..." : null} + </Tab> + )} + </DialogHeaderTabList> + </DialogHeader> + {hasErrors && ( + <TabPanel + as={RuntimeErrorsDialogBody} + id={TabId.RuntimeErrors} + isLoading={isLoading} + readyErrors={readyErrors} + className="errors-body" + /> + )} + </Tabs> + </ErrorsDialog> ); +} +function ErrorsDialog({ children, ...props }: DialogProps) { return ( <Overlay> - <Dialog - type="error" - aria-labelledby="nextjs__container_errors_label" - aria-describedby="nextjs__container_errors_desc" - onClose={isServerError ? undefined : minimize} - > - <DialogContent> - <DialogHeader className="nextjs-container-errors-header"> - <LeftRightDialogHeader - previous={activeIdx > 0 ? previous : null} - next={activeIdx < readyErrors.length - 1 ? next : null} - close={isServerError ? undefined : minimize} - > - <small> - <span>{activeIdx + 1}</span> of{" "} - <span>{readyErrors.length}</span> unhandled error - {readyErrors.length < 2 ? "" : "s"} - </small> - </LeftRightDialogHeader> - <h1 id="nextjs__container_errors_label"> - {isServerError ? "Server Error" : "Unhandled Runtime Error"} - </h1> - <p id="nextjs__container_errors_desc"> - {activeError.error.name}:{" "} - <HotlinkedText text={activeError.error.message} /> - </p> - {isServerError ? ( - <div> - <small> - This error happened while generating the page. Any console - logs will be displayed in the terminal window. - </small> - </div> - ) : undefined} - </DialogHeader> - <DialogBody className="nextjs-container-errors-body"> - <RuntimeError key={activeError.id.toString()} error={activeError} /> - </DialogBody> - </DialogContent> + <Dialog {...props}> + <DialogContent>{children}</DialogContent> </Dialog> </Overlay> ); -}; +} export const styles = css` - .nextjs-container-errors-header > h1 { - font-size: var(--size-font-big); - line-height: var(--size-font-bigger); - font-weight: bold; - margin: 0; - margin-top: calc(var(--size-gap-double) + var(--size-gap-half)); + /** == Header == */ + + .errors-header > .tab-list > .tab > svg { + margin-right: var(--size-gap); } - .nextjs-container-errors-header small { - font-size: var(--size-font-small); - color: var(--color-accents-1); - margin-left: var(--size-gap-double); + + .errors-header > .tab-list > .tab[data-severity="error"] > svg { + color: var(--color-error); } - .nextjs-container-errors-header small > span { - font-family: var(--font-stack-monospace); + + .errors-header > .tab-list > .tab[data-severity="warning"] > svg { + color: var(--color-warning); } - .nextjs-container-errors-header > p { - font-family: var(--font-stack-monospace); - font-size: var(--size-font-small); - line-height: var(--size-font-big); - font-weight: bold; - margin: 0; - margin-top: var(--size-gap-half); - color: var(--color-ansi-red); - white-space: pre-wrap; + + .errors-header > .tab-list > .tab { + position: relative; } - .nextjs-container-errors-header > div > small { - margin: 0; - margin-top: var(--size-gap-half); + + .errors-header > .tab-list > .tab[data-severity="error"]::after { + border-top-color: var(--color-error); } - .nextjs-container-errors-header > p > a { - color: var(--color-ansi-red); + + .errors-header > .tab-list > .tab[data-severity="warning"]::after { + border-top-color: var(--color-warning); } - .nextjs-container-errors-body > h5:not(:first-child) { - margin-top: calc(var(--size-gap-double) + var(--size-gap)); + /** == Body == */ + + .errors-body { + display: flex; + flex-direction: column; + overflow-y: hidden; } - .nextjs-container-errors-body > h5 { + + .errors-body > .title-pagination { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--size-gap); } - .nextjs-toast-errors-parent { - cursor: pointer; - transition: transform 0.2s ease; + .errors-body > .title-pagination > nav > small { + font-size: var(--size-font-small); + color: var(--color-text-dim); + margin-right: var(--size-gap); + opacity: 0.7; } - .nextjs-toast-errors-parent:hover { - transform: scale(1.1); + + .errors-body > .title-pagination > nav > small > span { + font-family: var(--font-mono); } - .nextjs-toast-errors { - display: flex; - align-items: center; - justify-content: flex-start; + + .errors-body > .title-pagination > h1 { + font-size: var(--size-font-big); + color: var(--color-text-dim); + margin: 0; + opacity: 0.9; } - .nextjs-toast-errors > svg { - margin-right: var(--size-gap); + + .errors-body > h2 { + font-family: var(--font-mono); + font-size: var(--size-font-big); + line-height: var(--size-font-bigger); + font-weight: bold; + margin: 0; + margin-bottom: var(--size-gap); + color: var(--color-error); + white-space: pre-wrap; } - .nextjs-toast-errors-hide-button { - margin-left: var(--size-gap-triple); - border: none; - background: none; - color: var(--color-ansi-bright-white); - padding: 0; - transition: opacity 0.25s ease; - opacity: 0.7; + + .errors-body > h2[data-severity="error"] { + color: var(--color-error); + } + + .errors-body > h2[data-severity="warning"] { + color: var(--color-warning); + } + + .errors-body > div > small { + margin: 0; + margin-top: var(--size-gap-half); } - .nextjs-toast-errors-hide-button:hover { - opacity: 1; + + .errors-body > h2 > a { + color: var(--color-error); + } + + .errors-body > h5:not(:first-child) { + margin-top: var(--size-gap-double); + } + + .errors-body > h5 { + margin-bottom: var(--size-gap); } `; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/ErrorsToast.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/ErrorsToast.tsx new file mode 100644 index 00000000000000..0f6c9b0e1b3b5f --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/ErrorsToast.tsx @@ -0,0 +1,77 @@ +import { Toast } from "../components/Toast"; +import { AlertOctagon, CloseIcon } from "../icons"; +import { noop as css } from "../helpers/noop-template"; + +export type ErrorsToastProps = { + errorCount: number; + onClick: () => void; + onClose: () => void; +}; + +export function ErrorsToast({ + errorCount, + onClick, + onClose, +}: ErrorsToastProps) { + return ( + <Toast className="toast-errors" onClick={onClick}> + <div className="toast-errors-body"> + <AlertOctagon /> + <span> + {errorCount} error + {errorCount > 1 ? "s" : ""} + </span> + <button + data-toast-errors-hide-button + className="toast-errors-hide-button" + type="button" + onClick={(e) => { + e.stopPropagation(); + onClose(); + }} + aria-label="Hide Errors" + > + <CloseIcon /> + </button> + </div> + </Toast> + ); +} + +export const styles = css` + .toast-errors { + cursor: pointer; + transition: transform 0.2s ease; + will-change: transform; + } + + .toast-errors:hover { + transform: scale(1.025); + } + + .toast-errors-body { + display: flex; + align-items: center; + align-content: center; + justify-content: flex-start; + } + + .toast-errors-body > svg { + margin-right: var(--size-gap); + } + + .toast-errors-hide-button { + display: flex; + margin-left: var(--size-gap-triple); + border: none; + background: none; + color: var(--color-text-white); + padding: 0; + transition: transform, opacity 0.25s ease; + opacity: 0.7; + } + + .toast-errors-hide-button:hover { + opacity: 1; + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/RuntimeError.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/RuntimeError.tsx index 5861b57298e97f..f7d2eaeede7f2b 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/RuntimeError.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/RuntimeError.tsx @@ -2,15 +2,17 @@ import * as React from "react"; import { StackFrame } from "@vercel/turbopack-next/compiled/stacktrace-parser"; import { CodeFrame } from "../components/CodeFrame"; -import { ReadyRuntimeError } from "../helpers/getErrorByType"; +import { DialogBody, DialogBodyProps } from "../components/Dialog"; +import { LeftRightDialogHeader } from "../components/LeftRightDialogHeader"; +import { clsx } from "../helpers/clsx"; +import { getErrorSource } from "../helpers/nodeStackFrames"; import { noop as css } from "../helpers/noop-template"; +import { ReadyRuntimeError } from "../helpers/getErrorByType"; import { getFrameSource, OriginalStackFrame } from "../helpers/stack-frame"; +import { usePagination } from "../hooks/usePagination"; +import { ExternalLink } from "../icons"; -export type RuntimeErrorProps = { error: ReadyRuntimeError }; - -const CallStackFrame: React.FC<{ - frame: OriginalStackFrame; -}> = function CallStackFrame({ frame }) { +function CallStackFrame({ frame }: { frame: OriginalStackFrame }) { // TODO: ability to expand resolved frames // TODO: render error or external indicator @@ -40,10 +42,8 @@ const CallStackFrame: React.FC<{ }, [hasSource, f]); return ( - <div data-nextjs-call-stack-frame> - <h6 data-nextjs-frame-expanded={Boolean(frame.expanded)}> - {f.methodName} - </h6> + <li className="call-stack-frame" data-expanded={Boolean(frame.expanded)}> + <h6>{f.methodName}</h6> <div data-has-source={hasSource ? "true" : undefined} tabIndex={hasSource ? 10 : undefined} @@ -52,27 +52,15 @@ const CallStackFrame: React.FC<{ title={hasSource ? "Click to open in your editor" : undefined} > <span>{getFrameSource(f)}</span> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 24 24" - fill="none" - stroke="currentColor" - strokeWidth="2" - strokeLinecap="round" - strokeLinejoin="round" - > - <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path> - <polyline points="15 3 21 3 21 9"></polyline> - <line x1="10" y1="14" x2="21" y2="3"></line> - </svg> + <ExternalLink /> </div> - </div> + </li> ); -}; +} -const RuntimeError: React.FC<RuntimeErrorProps> = function RuntimeError({ - error, -}) { +export type RuntimeErrorProps = { error: ReadyRuntimeError }; + +export function RuntimeError({ error }: RuntimeErrorProps) { const firstFirstPartyFrameIndex = React.useMemo<number>(() => { return error.frames.findIndex( (entry) => @@ -124,77 +112,200 @@ const RuntimeError: React.FC<RuntimeErrorProps> = function RuntimeError({ ]); return ( - <React.Fragment> + <> {firstFrame ? ( - <React.Fragment> + <> <h5>Source</h5> - {leadingFrames.map((frame, index) => ( - <CallStackFrame - key={`leading-frame-${index}-${all}`} - frame={frame} - /> - ))} + <ul className="call-stack-frames"> + {leadingFrames.map((frame, index) => ( + <CallStackFrame + key={`leading-frame-${index}-${all}`} + frame={frame} + /> + ))} + </ul> <CodeFrame stackFrame={firstFrame.originalStackFrame!} codeFrame={firstFrame.originalCodeFrame!} /> - </React.Fragment> + </> ) : undefined} {visibleCallStackFrames.length ? ( - <React.Fragment> + <> <h5>Call Stack</h5> - {visibleCallStackFrames.map((frame, index) => ( - <CallStackFrame key={`call-stack-${index}-${all}`} frame={frame} /> - ))} - </React.Fragment> + <ul className="call-stack-frames"> + {visibleCallStackFrames.map((frame, index) => ( + <CallStackFrame + key={`call-stack-${index}-${all}`} + frame={frame} + /> + ))} + </ul> + </> ) : undefined} {canShowMore ? ( - <React.Fragment> + <> <button tabIndex={10} - data-nextjs-data-runtime-error-collapsed-action type="button" onClick={toggleAll} + className="runtime-error-collapsed-action" > {all ? "Hide" : "Show"} collapsed frames </button> - </React.Fragment> + </> ) : undefined} - </React.Fragment> + </> + ); +} + +function HotlinkedText(props: { text: string }) { + const { text } = props; + + const linkRegex = /https?:\/\/[^\s/$.?#].[^\s"]*/i; + return ( + <> + {linkRegex.test(text) + ? text.split(" ").map((word, index, array) => { + if (linkRegex.test(word)) { + return ( + <React.Fragment key={`link-${index}`}> + <a href={word}>{word}</a> + {index === array.length - 1 ? "" : " "} + </React.Fragment> + ); + } + return index === array.length - 1 ? ( + <React.Fragment key={`text-${index}`}>{word}</React.Fragment> + ) : ( + <React.Fragment key={`text-${index}`}>{word} </React.Fragment> + ); + }) + : text} + </> ); +} + +type RuntimeErrorsDialogBodyProps = { + isLoading: boolean; + readyErrors: ReadyRuntimeError[]; + "data-hidden"?: boolean; }; +export function RuntimeErrorsDialogBody({ + isLoading, + readyErrors, + "data-hidden": hidden = false, + className, + ...rest +}: RuntimeErrorsDialogBodyProps & Omit<DialogBodyProps, "children">) { + const [activeError, { previous, next }, activeIdx] = + usePagination(readyErrors); + + if (isLoading) { + return ( + <DialogBody + {...rest} + data-hidden={hidden} + className={clsx("runtime-errors", className)} + > + <h1 id="errors_label">Resolving Source Maps...</h1> + </DialogBody> + ); + } + + if (readyErrors.length < 1 || activeError == null) { + return ( + <DialogBody + {...rest} + data-hidden={hidden} + className={clsx("runtime-errors", className)} + /> + ); + } + + const isServerError = ["server", "edge-server"].includes( + getErrorSource(activeError.error) || "" + ); + + return ( + <DialogBody + {...rest} + data-hidden={hidden} + className={clsx("runtime-errors", className)} + > + <div className="title-pagination"> + <h1 id="errors_label"> + {isServerError ? "Server Error" : "Unhandled Runtime Error"} + </h1> + <LeftRightDialogHeader + hidden={hidden} + previous={activeIdx > 0 ? previous : null} + next={activeIdx < readyErrors.length - 1 ? next : null} + severity="error" + > + <small> + <span>{activeIdx + 1}</span> of <span>{readyErrors.length}</span> + </small> + </LeftRightDialogHeader> + </div> + <h2 id="errors_desc" data-severity="error"> + {activeError.error.name}:{" "} + <HotlinkedText text={activeError.error.message} /> + </h2> + {isServerError ? ( + <div> + <small> + This error happened while generating the page. Any console logs will + be displayed in the terminal window. + </small> + </div> + ) : undefined} + <RuntimeError key={activeError.id.toString()} error={activeError} /> + </DialogBody> + ); +} + export const styles = css` - button[data-nextjs-data-runtime-error-collapsed-action] { + button.runtime-error-collapsed-action { background: none; border: none; padding: 0; font-size: var(--size-font-small); line-height: var(--size-font-bigger); - color: var(--color-accents-3); + color: var(--color-text-dim); + } + + .call-stack-frames { + list-style: none; + padding-left: calc(var(--size-gap) + var(--size-gap-half)); + overflow-y: scroll; } - [data-nextjs-call-stack-frame]:not(:last-child) { + .call-stack-frame:not(:last-child) { margin-bottom: var(--size-gap-double); } - [data-nextjs-call-stack-frame] > h6 { + .call-stack-frame > h6 { margin-top: 0; - margin-bottom: var(--size-gap); - font-family: var(--font-stack-monospace); - color: #222; - } - [data-nextjs-call-stack-frame] > h6[data-nextjs-frame-expanded="false"] { + margin-bottom: 0; + font-family: var(--font-mono); color: #666; } - [data-nextjs-call-stack-frame] > div { + + .call-stack-frame[data-expanded="true"] > h6 { + color: #222; + } + + .call-stack-frame > div { display: flex; align-items: center; padding-left: calc(var(--size-gap) + var(--size-gap-half)); font-size: var(--size-font-small); color: #999; } - [data-nextjs-call-stack-frame] > div > svg { + + .call-stack-frame > div > svg { width: auto; height: var(--size-font-small); margin-left: var(--size-gap); @@ -202,15 +313,15 @@ export const styles = css` display: none; } - [data-nextjs-call-stack-frame] > div[data-has-source] { + .call-stack-frame > div[data-has-source] { cursor: pointer; } - [data-nextjs-call-stack-frame] > div[data-has-source]:hover { + + .call-stack-frame > div[data-has-source]:hover { text-decoration: underline dotted; } - [data-nextjs-call-stack-frame] > div[data-has-source] > svg { + + .call-stack-frame > div[data-has-source] > svg { display: unset; } `; - -export { RuntimeError }; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/clsx.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/clsx.ts new file mode 100644 index 00000000000000..21937f1463ed99 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/helpers/clsx.ts @@ -0,0 +1,71 @@ +/* +MIT License + +Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// This file is based on https://github.com/lukeed/clsx/blob/v1.2.1/src/index.js +// It's been edited for the needs of this project +// See the LICENSE at the top of the file + +export type TruthyClassValue = + | ClassArray + | ClassDictionary + | string + | number + | boolean; +export type ClassValue = TruthyClassValue | null | undefined; +export type ClassDictionary = Record<string, any>; +export type ClassArray = ClassValue[]; + +function toVal(mix: TruthyClassValue) { + let k, + y, + str = ""; + + if (typeof mix === "string" || typeof mix === "number") { + str += mix; + } else if (typeof mix === "object") { + if (Array.isArray(mix)) { + for (k = 0; k < mix.length; k++) { + if (mix[k]) { + if ((y = toVal(mix[k]))) { + str && (str += " "); + str += y; + } + } + } + } else { + for (k in mix) { + if (mix[k]) { + str && (str += " "); + str += k; + } + } + } + } + + return str; +} + +export function clsx(...inputs: ClassValue[]) { + let i = 0, + tmp, + x, + str = ""; + while (i < inputs.length) { + if ((tmp = inputs[i++])) { + if ((x = toVal(tmp))) { + str && (str += " "); + str += x; + } + } + } + return str; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/context.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/context.tsx new file mode 100644 index 00000000000000..8ba8219112f4ae --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/context.tsx @@ -0,0 +1,56 @@ +/* +MIT License + +Copyright (c) 2018-2022, React Training LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// This file is based on https://github.com/reach/reach-ui/blob/v0.18.0/packages/utils/src/context.tsx +// It's been edited for the needs of this project +// See the LICENSE at the top of the file + +import * as React from "react"; + +type ContextProvider<T> = React.FC<React.PropsWithChildren<T>>; + +export function createContext<ContextValueType extends object | null>( + rootComponentName: string, + defaultContext?: ContextValueType +): [ + ContextProvider<ContextValueType>, + (callerComponentName: string) => ContextValueType +] { + const Ctx = React.createContext<ContextValueType | undefined>(defaultContext); + + function Provider(props: React.PropsWithChildren<ContextValueType>) { + const { children, ...context } = props; + const value = React.useMemo( + () => context, + // eslint-disable-next-line react-hooks/exhaustive-deps + Object.values(context) + ) as ContextValueType; + return <Ctx.Provider value={value}>{children}</Ctx.Provider>; + } + + function useContext(callerComponentName: string) { + const context = React.useContext(Ctx); + if (context) { + return context; + } + if (defaultContext) { + return defaultContext; + } + throw Error( + `${callerComponentName} must be rendered inside of a ${rootComponentName} component.` + ); + } + + Ctx.displayName = `${rootComponentName}Context`; + Provider.displayName = `${rootComponentName}Provider`; + return [Provider, useContext]; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/usePagination.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/usePagination.ts new file mode 100644 index 00000000000000..40d851c07b0913 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/hooks/usePagination.ts @@ -0,0 +1,41 @@ +import * as React from "react"; + +export type PaginationActions = { + previous: (e?: React.KeyboardEvent | React.MouseEvent) => void; + next: (e?: React.KeyboardEvent | React.MouseEvent) => void; + setIdx: React.Dispatch<React.SetStateAction<number>>; +}; + +export function usePagination<T>( + items: T[], + defaultIdx: number = 0 +): [T | null, PaginationActions, number] { + const [idx, setIdx] = React.useState(defaultIdx); + + React.useEffect(() => { + if (idx >= items.length && idx > 0) { + setIdx(items.length - 1); + } + }, [idx, items.length]); + + const currentItem = React.useMemo(() => { + return items[idx] ?? null; + }, [items, idx]); + + const actions = React.useMemo( + () => ({ + previous: (e?: React.KeyboardEvent | React.MouseEvent) => { + e?.preventDefault(); + setIdx((idx) => Math.max(0, idx - 1)); + }, + next: (e?: React.KeyboardEvent | React.MouseEvent) => { + e?.preventDefault(); + setIdx((idx) => Math.max(0, Math.min(items.length - 1, idx + 1))); + }, + setIdx, + }), + [items.length] + ); + + return [currentItem, actions, idx]; +} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertOctagon.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertOctagon.tsx new file mode 100644 index 00000000000000..7dc9671c2721d5 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertOctagon.tsx @@ -0,0 +1,11 @@ +import { BaseIcon, IconProps } from "./BaseIcon"; + +export const AlertOctagon = (props: IconProps) => { + return ( + <BaseIcon {...props}> + <polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon> + <line x1="12" y1="8" x2="12" y2="12"></line> + <line x1="12" y1="16" x2="12.01" y2="16"></line> + </BaseIcon> + ); +}; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertTriangle.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertTriangle.tsx new file mode 100644 index 00000000000000..842adda37f8df4 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/AlertTriangle.tsx @@ -0,0 +1,11 @@ +import { BaseIcon, IconProps } from "./BaseIcon"; + +export const AlertTriangle = (props: IconProps) => { + return ( + <BaseIcon {...props}> + <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path> + <line x1="12" y1="9" x2="12" y2="13"></line> + <line x1="12" y1="17" x2="12.01" y2="17"></line> + </BaseIcon> + ); +}; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/BaseIcon.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/BaseIcon.tsx new file mode 100644 index 00000000000000..ed71cacecd3ac8 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/BaseIcon.tsx @@ -0,0 +1,33 @@ +import { SVGProps, ReactNode } from "react"; + +const defaultAttributes: Partial<SVGProps<SVGSVGElement>> = { + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + strokeWidth: 2, + strokeLinecap: "round", + strokeLinejoin: "round", +}; + +export interface IconProps extends Partial<SVGProps<SVGSVGElement>> { + size?: string | number; +} + +export const BaseIcon = ({ + color = "currentColor", + size = 24, + strokeWidth = 2, + ...rest +}: IconProps & { children: ReactNode }) => { + return ( + <svg + {...defaultAttributes} + width={size} + height={size} + stroke={color} + strokeWidth={strokeWidth} + {...rest} + /> + ); +}; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/CloseIcon.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/CloseIcon.tsx index 9c7bd63c694f39..e49594022dac31 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/CloseIcon.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/CloseIcon.tsx @@ -1,30 +1,10 @@ -import * as React from "react"; +import { BaseIcon, IconProps } from "./BaseIcon"; -const CloseIcon = () => { +export const CloseIcon = (props: IconProps) => { return ( - <svg - width="24" - height="24" - viewBox="0 0 24 24" - fill="none" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M18 6L6 18" - stroke="currentColor" - strokeWidth="2" - strokeLinecap="round" - strokeLinejoin="round" - /> - <path - d="M6 6L18 18" - stroke="currentColor" - strokeWidth="2" - strokeLinecap="round" - strokeLinejoin="round" - /> - </svg> + <BaseIcon {...props}> + <line x1="18" y1="6" x2="6" y2="18"></line> + <line x1="6" y1="6" x2="18" y2="18"></line> + </BaseIcon> ); }; - -export { CloseIcon }; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/ExternalLink.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/ExternalLink.tsx new file mode 100644 index 00000000000000..0fb91b6dfda065 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/ExternalLink.tsx @@ -0,0 +1,11 @@ +import { BaseIcon, IconProps } from "./BaseIcon"; + +export const ExternalLink = (props: IconProps) => { + return ( + <BaseIcon {...props}> + <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path> + <polyline points="15 3 21 3 21 9"></polyline> + <line x1="10" y1="14" x2="21" y2="3"></line> + </BaseIcon> + ); +}; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/LICENSE.md b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/LICENSE.md new file mode 100644 index 00000000000000..325e8ff0aae2dd --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/LICENSE.md @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/PackageX.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/PackageX.tsx new file mode 100644 index 00000000000000..62d96d8777ebb1 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/PackageX.tsx @@ -0,0 +1,13 @@ +import { BaseIcon, IconProps } from "./BaseIcon"; + +export const PackageX = (props: IconProps) => { + return ( + <BaseIcon {...props}> + <path d="M21 10V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l2-1.14"></path> + <path d="M16.5 9.4 7.55 4.24"></path> + <polyline points="3.29 7 12 12 20.71 7"></polyline> + <line x1="12" y1="22" x2="12" y2="12"></line> + <path d="m17 13 5 5m-5 0 5-5"></path> + </BaseIcon> + ); +}; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/index.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/index.ts new file mode 100644 index 00000000000000..51ba84f2f371e0 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/icons/index.ts @@ -0,0 +1,6 @@ +export { AlertOctagon } from "./AlertOctagon"; +export { AlertTriangle } from "./AlertTriangle"; +export { CloseIcon } from "./CloseIcon"; +export { ExternalLink } from "./ExternalLink"; +export { IconProps } from "./BaseIcon"; +export { PackageX } from "./PackageX"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/Base.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/Base.tsx index 9e75d9ab4a1f8b..d690eac2835c85 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/Base.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/Base.tsx @@ -1,4 +1,3 @@ -import * as React from "react"; import { noop as css } from "../helpers/noop-template"; export function Base() { @@ -8,6 +7,7 @@ export function Base() { :host { --size-gap-half: 4px; --size-gap: 8px; + --size-gap-big: 12px; --size-gap-double: 16px; --size-gap-triple: 24px; --size-gap-quad: 32px; @@ -17,12 +17,46 @@ export function Base() { --size-font-big: 20px; --size-font-bigger: 24px; - --color-accents-1: #808080; - --color-accents-2: #222222; - --color-accents-3: #404040; + --size-icon: 24px; + --size-icon-small: 12px; - --font-stack-monospace: "SFMono-Regular", Consolas, "Liberation Mono", - Menlo, Courier, monospace; + --size-border-half: 1px; + --size-border: 2px; + --size-border-double: 4px; + + --color-text: hsl(0, 0%, 0%); + --color-text-dim: hsl(0, 0%, 20%); + --color-text-white: hsl(0, 0%, 100%); + + --color-error: hsl(-10, 100%, 45%); + --color-error-bright-hsl: -10, 100%, 67%; + --color-error-bright: hsl(var(--color-error-bright-hsl)); + + --color-warning: hsl(33.3, 100%, 47.5%); + --color-warning-bright-hsl: 33.3, 100%, 50%; + --color-warning-bright: hsl(var(--color-warning-bright-hsl)); + + --color-bg: hsl(0 0% 100%); + --color-bg-secondary: hsl(0 0% 93.5%); + --color-bg-secondary-hover: hsl(0 0% 90%); + + --color-accents-1: hsl(0, 0%, 50%); + --color-accents-2: hsl(0, 0%, 13%); + --color-accents-3: hsl(0, 0%, 25%); + + --color-border: hsla(0, 0%, 80%, 0.7); + + --border-half: var(--size-border-half) solid var(--color-border); + --border: var(--size-border) solid var(--color-border); + + --font-sans: ui-sans-serif, system-ui, -apple-system, + BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, + "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol", "Noto Color Emoji"; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, + serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; --color-ansi-selection: rgba(95, 126, 151, 0.48); --color-ansi-bg: #111111; @@ -47,7 +81,7 @@ export function Base() { } .mono { - font-family: var(--font-stack-monospace); + font-family: var(--font-mono); } h1, @@ -62,20 +96,25 @@ export function Base() { } h1 { - font-size: 40px; + font-size: 26px; } + h2 { - font-size: 32px; + font-size: 24px; } + h3 { - font-size: 28px; + font-size: 22px; } + h4 { - font-size: 24px; + font-size: 20px; } + h5 { - font-size: 20px; + font-size: 18px; } + h6 { font-size: 16px; } diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx index 9a542219e47c20..160c262baad5e9 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx @@ -1,13 +1,15 @@ import * as React from "react"; -import { styles as codeFrame } from "../components/CodeFrame/styles"; +import { styles as codeFrame } from "../components/CodeFrame"; import { styles as dialog } from "../components/Dialog"; -import { styles as leftRightDialogHeader } from "../components/LeftRightDialogHeader/styles"; -import { styles as overlay } from "../components/Overlay/styles"; -import { styles as terminal } from "../components/Terminal/styles"; +import { styles as leftRightDialogHeader } from "../components/LeftRightDialogHeader"; +import { styles as overlay } from "../components/Overlay"; +import { styles as tabs } from "../components/Tabs"; +import { styles as terminal } from "../components/Terminal"; import { styles as toast } from "../components/Toast"; import { styles as buildErrorStyles } from "../container/BuildError"; import { styles as containerErrorStyles } from "../container/Errors"; +import { styles as containerErrorToastStyles } from "../container/ErrorsToast"; import { styles as containerRuntimeErrorStyles } from "../container/RuntimeError"; import { noop as css } from "../helpers/noop-template"; @@ -21,9 +23,11 @@ export function ComponentStyles() { ${leftRightDialogHeader} ${codeFrame} ${terminal} - + ${tabs} + ${buildErrorStyles} ${containerErrorStyles} + ${containerErrorToastStyles} ${containerRuntimeErrorStyles} `} </style> diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/CssReset.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/CssReset.tsx index 3eb3394d33e1d2..ed085b331b0501 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/CssReset.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/CssReset.tsx @@ -1,4 +1,3 @@ -import * as React from "react"; import { noop as css } from "../helpers/noop-template"; export function CssReset() { @@ -47,10 +46,7 @@ export function CssReset() { :host { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, - "Helvetica Neue", Arial, "Noto Sans", sans-serif, - "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", - "Noto Color Emoji"; + font-family: var(--font-sans); font-size: 16px; font-weight: 400; line-height: 1.5; From 65016c65e3b8fc4656a0fd42b0393e0e0a47ad5e Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Tue, 29 Nov 2022 18:05:52 +0100 Subject: [PATCH 245/672] display multiple issues in overlay (vercel/turbo#2803) --- .../crates/next-core/js/src/dev/hmr-client.ts | 45 +++++---- .../crates/next-core/js/src/overlay/client.ts | 6 +- .../src/overlay/internal/ReactDevOverlay.tsx | 32 +++--- .../next-core/js/src/overlay/internal/bus.ts | 10 +- .../internal/components/Tabs/index.tsx | 4 +- .../overlay/internal/container/BuildError.tsx | 65 ------------ .../src/overlay/internal/container/Errors.tsx | 86 +++++++++++----- .../internal/container/TurbopackIssue.tsx | 98 +++++++++++++++++++ .../internal/styles/ComponentStyles.tsx | 4 +- 9 files changed, 210 insertions(+), 140 deletions(-) delete mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx create mode 100644 packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 7480e49b7f0614..74c00cdb353775 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -17,7 +17,7 @@ import { onBeforeRefresh, onBuildOk, onRefresh, - onTurbopackError, + onTurbopackIssues, } from "../overlay/client"; import { addEventListener, sendMessage } from "./websocket"; import { ModuleId } from "@vercel/turbopack-runtime/types"; @@ -95,18 +95,18 @@ type AggregatedUpdates = { }; // we aggregate all updates until the issues are resolved -const chunksWithErrors: Map<ChunkPath, AggregatedUpdates> = new Map(); +const chunksWithUpdates: Map<ChunkPath, AggregatedUpdates> = new Map(); function aggregateUpdates( msg: ServerMessage, - hasErrors: boolean + hasIssues: boolean ): ServerMessage { const key = resourceKey(msg.resource); - const aggregated = chunksWithErrors.get(key); + const aggregated = chunksWithUpdates.get(key); if (msg.type === "issues" && aggregated != null) { - if (!hasErrors) { - chunksWithErrors.delete(key); + if (!hasIssues) { + chunksWithUpdates.delete(key); } return { @@ -124,8 +124,8 @@ function aggregateUpdates( if (msg.type !== "partial") return msg; if (aggregated == null) { - if (hasErrors) { - chunksWithErrors.set(key, { + if (hasIssues) { + chunksWithUpdates.set(key, { added: msg.instruction.added, modified: msg.instruction.modified, deleted: new Set(msg.instruction.deleted), @@ -172,10 +172,10 @@ function aggregateUpdates( aggregated.deleted.add(moduleId); } - if (!hasErrors) { - chunksWithErrors.delete(key); + if (!hasIssues) { + chunksWithUpdates.delete(key); } else { - chunksWithErrors.set(key, aggregated); + chunksWithUpdates.set(key, aggregated); } return { @@ -198,21 +198,20 @@ function compareByList(list: any[], a: any, b: any) { } function handleIssues(msg: ServerMessage): boolean { - let issueToReport = null; + let hasCriticalIssues = false; for (const issue of msg.issues) { if (CRITICAL.includes(issue.severity)) { - issueToReport = issue; - break; + console.error(stripAnsi(issue.formatted)); + hasCriticalIssues = true; } } - if (issueToReport) { - console.error(stripAnsi(issueToReport.formatted)); - onTurbopackError(issueToReport); + if (msg.issues.length > 0) { + onTurbopackIssues(msg.issues); } - return issueToReport != null; + return hasCriticalIssues; } const SEVERITY_ORDER = ["bug", "fatal", "error", "warning", "info", "log"]; @@ -232,20 +231,20 @@ function handleSocketMessage(msg: ServerMessage) { return compareByList(CATEGORY_ORDER, a.category, b.category); }); - const hasErrors = handleIssues(msg); - const aggregatedMsg = aggregateUpdates(msg, hasErrors); + const hasIssues = handleIssues(msg); + const aggregatedMsg = aggregateUpdates(msg, hasIssues); - if (hasErrors) return; + if (hasIssues) return; if (aggregatedMsg.type !== "issues") { onBeforeRefresh(); triggerUpdate(aggregatedMsg); - if (chunksWithErrors.size === 0) { + if (chunksWithUpdates.size === 0) { onRefresh(); } } - if (chunksWithErrors.size === 0) { + if (chunksWithUpdates.size === 0) { onBuildOk(); } } diff --git a/packages/next-swc/crates/next-core/js/src/overlay/client.ts b/packages/next-swc/crates/next-core/js/src/overlay/client.ts index d71db90343f77f..faf93e25b1e0bc 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/client.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/client.ts @@ -85,8 +85,8 @@ function onBuildOk() { Bus.emit({ type: Bus.TYPE_BUILD_OK }); } -function onTurbopackError(issue: Issue) { - Bus.emit({ type: Bus.TYPE_TURBOPACK_ERROR, issue }); +function onTurbopackIssues(issues: Issue[]) { + Bus.emit({ type: Bus.TYPE_TURBOPACK_ISSUES, issues }); } function onBeforeRefresh() { @@ -102,7 +102,7 @@ export { getServerError } from "./internal/helpers/nodeStackFrames"; export { default as ReactDevOverlay } from "./internal/ReactDevOverlay"; export { onBuildOk, - onTurbopackError, + onTurbopackIssues, register, unregister, onBeforeRefresh, diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx index 775c6958b91746..bcc912f3254296 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx @@ -4,7 +4,6 @@ import type { Issue } from "@vercel/turbopack-runtime/types/protocol"; import * as Bus from "./bus"; import { ShadowPortal } from "./components/ShadowPortal"; -import { BuildError } from "./container/BuildError"; import { Errors, SupportedErrorEvent } from "./container/Errors"; import { ErrorBoundary } from "./ErrorBoundary"; import { Base } from "./styles/Base"; @@ -25,7 +24,11 @@ type RefreshState = type OverlayState = { nextId: number; - issue: Issue | null; + + // issues are from turbopack + issues: Issue[]; + + // errors are client side errors: SupportedErrorEvent[]; refreshState: RefreshState; @@ -47,10 +50,10 @@ function pushErrorFilterDuplicates( function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState { switch (ev.type) { case Bus.TYPE_BUILD_OK: { - return { ...state, issue: null }; + return { ...state, issues: [] }; } - case Bus.TYPE_TURBOPACK_ERROR: { - return { ...state, issue: ev.issue }; + case Bus.TYPE_TURBOPACK_ISSUES: { + return { ...state, issues: ev.issues }; } case Bus.TYPE_BEFORE_REFRESH: { return { ...state, refreshState: { type: "pending", errors: [] } }; @@ -58,7 +61,7 @@ function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState { case Bus.TYPE_REFRESH: { return { ...state, - issue: null, + issues: [], errors: // Errors can come in during updates. In this case, UNHANDLED_ERROR // and UNHANDLED_REJECTION events might be dispatched between the @@ -135,7 +138,7 @@ export default function ReactDevOverlay({ React.Reducer<OverlayState, Bus.BusEvent> >(reducer, { nextId: 1, - issue: null, + issues: [], errors: [], refreshState: { type: "idle", @@ -156,8 +159,8 @@ export default function ReactDevOverlay({ [] ); - const hasBuildError = state.issue != null; - const hasRuntimeErrors = Boolean(state.errors.length); + const hasBuildError = state.issues.length > 0; + const hasRuntimeErrors = state.errors.length > 0; const errorType = hasBuildError ? "build" @@ -182,14 +185,9 @@ export default function ReactDevOverlay({ <Base /> <ComponentStyles /> - {shouldPreventDisplay( - errorType, - preventDisplay - ) ? null : hasBuildError ? ( - <BuildError issue={state.issue!} /> - ) : hasRuntimeErrors ? ( - <Errors errors={state.errors} /> - ) : null} + {shouldPreventDisplay(errorType, preventDisplay) ? null : ( + <Errors issues={state.issues} errors={state.errors} /> + )} </ShadowPortal> ) : null} </React.Fragment> diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts index bc6c3ca0d7dcde..b876ad9d2a8418 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts @@ -3,16 +3,16 @@ import { StackFrame } from "stacktrace-parser"; import type { Issue } from "@vercel/turbopack-runtime/types/protocol"; export const TYPE_BUILD_OK = "build-ok"; -export const TYPE_TURBOPACK_ERROR = "turbopack-error"; +export const TYPE_TURBOPACK_ISSUES = "turbopack-error"; export const TYPE_BEFORE_REFRESH = "before-fast-refresh"; export const TYPE_REFRESH = "fast-refresh"; export const TYPE_UNHANDLED_ERROR = "unhandled-error"; export const TYPE_UNHANDLED_REJECTION = "unhandled-rejection"; export type BuildOk = { type: typeof TYPE_BUILD_OK }; -export type TurbopackError = { - type: typeof TYPE_TURBOPACK_ERROR; - issue: Issue; +export type TurbopackIssues = { + type: typeof TYPE_TURBOPACK_ISSUES; + issues: Issue[]; }; export type BeforeFastRefresh = { type: typeof TYPE_BEFORE_REFRESH }; export type FastRefresh = { type: typeof TYPE_REFRESH }; @@ -28,7 +28,7 @@ export type UnhandledRejection = { }; export type BusEvent = | BuildOk - | TurbopackError + | TurbopackIssues | BeforeFastRefresh | FastRefresh | UnhandledError diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx index 089d30d68bd43d..cfb3c1053e352d 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/components/Tabs/index.tsx @@ -19,7 +19,6 @@ type TabRefs = Record<string, HTMLElement | undefined>; type TabsContextType = { selectedId: string; - tabRefs: Readonly<TabRefs>; registerTabRef: (id: string, el: HTMLElement | null) => void; onSelectTab: (id: string) => void; }; @@ -69,6 +68,8 @@ export function Tabs({ setTimeout(() => { tab.focus(); }, 0); + + onSelectTabUnchecked(id); }, [selectedId, onSelectTabUnchecked] ); @@ -108,7 +109,6 @@ export function Tabs({ return ( <TabsProvider selectedId={selectedId} - tabRefs={tabRefs.current} registerTabRef={registerTabRef} onSelectTab={onSelectTab} > diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx deleted file mode 100644 index c9af4ec363504e..00000000000000 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/BuildError.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import * as React from "react"; -import type { Issue } from "@vercel/turbopack-runtime/types/protocol"; - -import { - Dialog, - DialogBody, - DialogContent, - DialogHeader, -} from "../components/Dialog"; -import { Overlay } from "../components/Overlay"; -import { Terminal } from "../components/Terminal"; -import { noop as css } from "../helpers/noop-template"; - -export type BuildErrorProps = { issue: Issue }; - -export function BuildError({ issue }: BuildErrorProps) { - const noop = React.useCallback(() => {}, []); - return ( - <Overlay fixed> - <Dialog - aria-labelledby="nextjs__container_build_error_label" - aria-describedby="nextjs__container_build_error_desc" - onClose={noop} - > - <DialogContent> - <DialogHeader className="nextjs-container-build-error-header"> - <h4 id="nextjs__container_build_error_label"> - Turbopack failed to compile - </h4> - </DialogHeader> - <DialogBody className="nextjs-container-build-error-body"> - <Terminal content={issue.formatted} /> - <footer> - <p id="nextjs__container_build_error_desc"> - <small> - This error occurred during the build process and can only be - dismissed by fixing the error. - </small> - </p> - </footer> - </DialogBody> - </DialogContent> - </Dialog> - </Overlay> - ); -} - -export const styles = css` - .nextjs-container-build-error-header > h4 { - line-height: 1.5; - margin: 0; - padding: 0; - } - - .nextjs-container-build-error-body footer { - margin-top: var(--size-gap); - } - .nextjs-container-build-error-body footer p { - margin: 0; - } - - .nextjs-container-build-error-body small { - color: #757575; - } -`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx index 5f11037a167d31..ea1efd446c838c 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx @@ -1,5 +1,7 @@ import * as React from "react"; +import { Issue } from "@vercel/turbopack-runtime/types/protocol"; + import { TYPE_UNHANDLED_ERROR, TYPE_UNHANDLED_REJECTION, @@ -18,8 +20,9 @@ import { Tab, TabPanel, Tabs } from "../components/Tabs"; import { getErrorByType, ReadyRuntimeError } from "../helpers/getErrorByType"; import { getErrorSource } from "../helpers/nodeStackFrames"; import { noop as css } from "../helpers/noop-template"; -import { AlertOctagon } from "../icons"; +import { AlertOctagon, PackageX } from "../icons"; import { RuntimeErrorsDialogBody } from "./RuntimeError"; +import { TurbopackIssuesDialogBody } from "../container/TurbopackIssue"; import { ErrorsToast } from "../container/ErrorsToast"; export type SupportedErrorEvent = { @@ -27,6 +30,7 @@ export type SupportedErrorEvent = { event: UnhandledError | UnhandledRejection; }; export type ErrorsProps = { + issues: Issue[]; errors: SupportedErrorEvent[]; }; @@ -82,9 +86,7 @@ function useResolvedErrors( return [ready, next]; }, [errors, lookups]); - const isLoading = React.useMemo<boolean>(() => { - return readyErrors.length < 1 && errors.length > 1; - }, [errors.length, readyErrors.length]); + const isLoading = readyErrors.length === 0 && errors.length > 1; React.useEffect(() => { if (nextError == null) { @@ -114,7 +116,7 @@ function useResolvedErrors( // Reset component state when there are no errors to be displayed. // This should never happen, but let's handle it. React.useEffect(() => { - if (errors.length < 1) { + if (errors.length === 0) { setLookups({}); } }, [errors.length]); @@ -123,24 +125,18 @@ function useResolvedErrors( } const enum TabId { + TurbopackIssues = "turbopack-issues", RuntimeErrors = "runtime-errors", } -export function Errors({ errors }: ErrorsProps) { - const [displayState, setDisplayState] = React.useState< +export function Errors({ issues, errors }: ErrorsProps) { + // eslint-disable-next-line prefer-const + let [displayState, setDisplayState] = React.useState< "minimized" | "fullscreen" | "hidden" >("fullscreen"); const [readyErrors, isLoading] = useResolvedErrors(errors); - // Reset component state when there are no errors to be displayed. - // This should never happen, but let's handle it. - React.useEffect(() => { - if (errors.length < 1) { - setDisplayState("hidden"); - } - }, [errors.length]); - const minimize = React.useCallback((e?: MouseEvent | TouchEvent) => { e?.preventDefault(); setDisplayState("minimized"); @@ -157,18 +153,37 @@ export function Errors({ errors }: ErrorsProps) { [] ); - const hasErrors = errors.length > 0; + const hasIssues = issues.length !== 0; + const hasIssueWithError = issues.some((issue) => + ["bug", "fatal", "error"].includes(issue.severity) + ); + + const hasErrors = errors.length !== 0; const hasServerError = readyErrors.some((err) => ["server", "edge-server"].includes(getErrorSource(err.error) || "") ); - const isClosable = !isLoading && !hasServerError; + const isClosable = !isLoading && !hasIssueWithError && !hasServerError; + + const defaultTab = + hasIssueWithError || !hasErrors + ? TabId.TurbopackIssues + : TabId.RuntimeErrors; - const defaultTab = TabId.RuntimeErrors; const [selectedTab, setSelectedTab] = React.useState<string>(defaultTab); + React.useEffect(() => { + if (defaultTab === TabId.TurbopackIssues) { + setSelectedTab(TabId.TurbopackIssues); + } + }, [defaultTab]); + + if (!isClosable) { + displayState = "fullscreen"; + } + // This component shouldn't be rendered with no errors, but if it is, let's // handle it gracefully by rendering nothing. - if (errors.length < 1) { + if (!hasErrors && !hasIssues) { return null; } @@ -179,7 +194,7 @@ export function Errors({ errors }: ErrorsProps) { if (displayState === "minimized") { return ( <ErrorsToast - errorCount={readyErrors.length} + errorCount={readyErrors.length + issues.length} onClick={fullscreen} onClose={hide} /> @@ -202,15 +217,40 @@ export function Errors({ errors }: ErrorsProps) { close={isClosable ? minimize : undefined} > <DialogHeaderTabList> + {hasIssues && ( + <Tab + id={TabId.TurbopackIssues} + next={hasErrors ? TabId.RuntimeErrors : undefined} + data-severity={hasIssueWithError ? "error" : "warning"} + > + <PackageX /> + {issues.length} Turbopack Issue{issues.length > 1 ? "s" : ""} + </Tab> + )} {hasErrors && ( - <Tab id={TabId.RuntimeErrors} data-severity="error"> + <Tab + id={TabId.RuntimeErrors} + prev={hasIssues ? TabId.TurbopackIssues : undefined} + data-severity="error" + > <AlertOctagon /> - {isLoading ? "Loading" : readyErrors.length} Runtime Errors - {isLoading ? "..." : null} + {isLoading + ? "Loading Runtime Errors ..." + : `${readyErrors.length} Runtime Error${ + readyErrors.length > 1 ? "s" : "" + }`} </Tab> )} </DialogHeaderTabList> </DialogHeader> + {hasIssues && ( + <TabPanel + as={TurbopackIssuesDialogBody} + id={TabId.TurbopackIssues} + issues={issues} + className="errors-body" + /> + )} {hasErrors && ( <TabPanel as={RuntimeErrorsDialogBody} diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx new file mode 100644 index 00000000000000..a9bfd1d6d8334c --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx @@ -0,0 +1,98 @@ +import { Issue } from "@vercel/turbopack-runtime/types/protocol"; + +import { LeftRightDialogHeader } from "../components/LeftRightDialogHeader"; +import { DialogBody, DialogBodyProps } from "../components/Dialog"; +import { Terminal } from "../components/Terminal"; +import { noop as css } from "../helpers/noop-template"; +import { clsx } from "../helpers/clsx"; +import { usePagination } from "../hooks/usePagination"; + +type TurbopackIssuesDialogBodyProps = { + issues: Issue[]; + "data-hidden"?: boolean; +}; + +export function TurbopackIssuesDialogBody({ + issues, + "data-hidden": hidden = false, + className, + ...rest +}: TurbopackIssuesDialogBodyProps & Omit<DialogBodyProps, "children">) { + const [activeIssue, { previous, next }, activeIdx] = usePagination(issues); + + const hasIssues = issues.length > 0; + const hasIssueWithError = issues.some((issue) => + ["bug", "fatal", "error"].includes(issue.severity) + ); + + if (!hasIssues || !activeIssue) { + return null; + } + + const activeIssueIsError = ["bug", "fatal", "error"].includes( + activeIssue.severity + ); + + return ( + <DialogBody + {...rest} + data-hidden={hidden} + className={clsx("issues-body", className)} + > + <div className="title-pagination"> + <h1 id="errors_label"> + {hasIssueWithError + ? "Turbopack failed to compile" + : "Turbopack compiled with warnings"} + </h1> + <LeftRightDialogHeader + hidden={hidden} + previous={activeIdx > 0 ? previous : null} + next={activeIdx < issues.length - 1 ? next : null} + severity={activeIssueIsError ? "error" : "warning"} + > + <small> + <span>{activeIdx + 1}</span> of <span>{issues.length}</span> + </small> + </LeftRightDialogHeader> + </div> + + <h2 + id="errors_desc" + data-severity={activeIssueIsError ? "error" : "warning"} + > + {activeIssue.title} + </h2> + + <Terminal content={activeIssue.formatted} /> + {activeIssueIsError && ( + <footer> + <p> + <small> + This error occurred during the build process and can only be + dismissed by fixing the error. + </small> + </p> + </footer> + )} + </DialogBody> + ); +} + +export const styles = css` + .issues-body > .terminal { + margin-top: var(--size-gap-double); + } + + .issues-body > footer { + margin-top: var(--size-gap); + } + + .issues-body > footer > p { + margin: 0; + } + + .issues-body > footer > small { + color: #757575; + } +`; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx index 160c262baad5e9..3085489f689df9 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/styles/ComponentStyles.tsx @@ -7,10 +7,10 @@ import { styles as overlay } from "../components/Overlay"; import { styles as tabs } from "../components/Tabs"; import { styles as terminal } from "../components/Terminal"; import { styles as toast } from "../components/Toast"; -import { styles as buildErrorStyles } from "../container/BuildError"; import { styles as containerErrorStyles } from "../container/Errors"; import { styles as containerErrorToastStyles } from "../container/ErrorsToast"; import { styles as containerRuntimeErrorStyles } from "../container/RuntimeError"; +import { styles as containerTurbopackIssueStyles } from "../container/TurbopackIssue"; import { noop as css } from "../helpers/noop-template"; export function ComponentStyles() { @@ -25,10 +25,10 @@ export function ComponentStyles() { ${terminal} ${tabs} - ${buildErrorStyles} ${containerErrorStyles} ${containerErrorToastStyles} ${containerRuntimeErrorStyles} + ${containerTurbopackIssueStyles} `} </style> ); From d1e72c8b49f870a06606b8f198a0c2a0084e14e4 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Wed, 30 Nov 2022 19:05:07 -0800 Subject: [PATCH 246/672] Run taplo format and check consistency in CI (vercel/turbo#2866) * Add GitHub action step for taplo --check * Run taplo format --- .../next-swc/crates/next-binding/Cargo.toml | 65 ++++++------------- packages/next-swc/crates/next-dev/Cargo.toml | 5 +- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/packages/next-swc/crates/next-binding/Cargo.toml b/packages/next-swc/crates/next-binding/Cargo.toml index 9f0c206c792272..20a5beebb5b42f 100644 --- a/packages/next-swc/crates/next-binding/Cargo.toml +++ b/packages/next-swc/crates/next-binding/Cargo.toml @@ -10,9 +10,7 @@ bench = false [features] __swc = [] -__swc_core = [ - "__swc", -] +__swc_core = ["__swc"] __swc_core_next_core = [ "__swc_core", "swc_core/common_concurrent", @@ -29,7 +27,7 @@ __swc_core_next_core = [ "swc_core/ecma_parser", "swc_core/ecma_parser_typescript", "swc_core/cached", - "swc_core/base" + "swc_core/base", ] __swc_core_binding_napi = [ @@ -54,9 +52,7 @@ __swc_core_binding_napi = [ "swc_core/ecma_utils", "swc_core/ecma_visit", ] -__swc_core_binding_napi_plugin = [ - "swc_core/plugin_transform_host_native" -] +__swc_core_binding_napi_plugin = ["swc_core/plugin_transform_host_native"] __swc_core_binding_wasm = [ "__swc_core", @@ -71,62 +67,41 @@ __swc_core_binding_wasm = [ "swc_core/ecma_parser", "swc_core/ecma_parser_typescript", "swc_core/ecma_utils", - "swc_core/ecma_visit" -] -__swc_core_binding_wasm_plugin = [ - "swc_core/plugin_transform_host_js" + "swc_core/ecma_visit", ] +__swc_core_binding_wasm_plugin = ["swc_core/plugin_transform_host_js"] -__swc_core_testing_transform = [ - "swc_core/testing_transform" -] +__swc_core_testing_transform = ["swc_core/testing_transform"] __turbo = [] -__feature_next_dev_server = [ - "__turbo", - "next-dev/serializable" -] -__feature_node_file_trace = [ - "__turbo", - "node-file-trace/node-api" -] +__feature_next_dev_server = ["__turbo", "next-dev/serializable"] +__feature_node_file_trace = ["__turbo", "node-file-trace/node-api"] __features = [] -__feature_mdx_rs = [ "__features", "mdxjs/serializable"] +__feature_mdx_rs = ["__features", "mdxjs/serializable"] __swc_custom_transform = [] __swc_transform_styled_components = [ "__swc", "__swc_custom_transform", - "styled_components" -] -__swc_transform_styled_jsx = [ - "__swc", - "__swc_custom_transform", - "styled_jsx" -] -__swc_transform_emotion = [ - "__swc", - "__swc_custom_transform", - "swc_emotion" + "styled_components", ] +__swc_transform_styled_jsx = ["__swc", "__swc_custom_transform", "styled_jsx"] +__swc_transform_emotion = ["__swc", "__swc_custom_transform", "swc_emotion"] __swc_transform_modularize_imports = [ "__swc", "__swc_custom_transform", - "modularize_imports" -] -__swc_testing = [ - "__swc", - "testing" + "modularize_imports", ] +__swc_testing = ["__swc", "testing"] [dependencies] -swc_core = { optional = true, workspace = true } mdxjs = { optional = true, workspace = true } +modularize_imports = { optional = true, workspace = true } next-dev = { optional = true, workspace = true } node-file-trace = { optional = true, workspace = true } -styled_components = { optional = true,workspace = true } -styled_jsx = { optional = true,workspace = true} -swc_emotion = { optional = true,workspace = true} -testing = {optional = true, workspace = true} -modularize_imports = { optional = true,workspace = true} \ No newline at end of file +styled_components = { optional = true, workspace = true } +styled_jsx = { optional = true, workspace = true } +swc_core = { optional = true, workspace = true } +swc_emotion = { optional = true, workspace = true } +testing = { optional = true, workspace = true } diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 9217d1f1a70029..29d95a60d627e1 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -76,4 +76,7 @@ nix = "0.25.0" [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } -vergen = { version = "7.3.2", default-features = false, features = ["cargo", "build"] } \ No newline at end of file +vergen = { version = "7.3.2", default-features = false, features = [ + "cargo", + "build", +] } From 235b3c3c08a4198f0d075bd1e6775ee7f4307e84 Mon Sep 17 00:00:00 2001 From: LongYinan <lynweklm@gmail.com> Date: Thu, 1 Dec 2022 13:51:58 +0800 Subject: [PATCH 247/672] Split turbopack-node from next-core (vercel/turbo#2874) --- packages/next-swc/crates/next-core/Cargo.toml | 8 +- .../crates/next-core/src/app_source.rs | 10 +- packages/next-swc/crates/next-core/src/lib.rs | 5 +- .../crates/next-core/src/nodejs/bootstrap.rs | 54 -- .../crates/next-core/src/nodejs/issue.rs | 48 -- .../crates/next-core/src/nodejs/mod.rs | 616 ------------------ .../next-core/src/nodejs/node_api_source.rs | 180 ----- .../crates/next-core/src/nodejs/node_entry.rs | 25 - .../src/nodejs/node_rendered_source.rs | 255 -------- .../crates/next-core/src/nodejs/pool.rs | 283 -------- .../crates/next-core/src/path_regex.rs | 141 ---- .../next-core/src/server_rendered_source.rs | 10 +- .../src/source_map/content_source.rs | 123 ---- .../crates/next-core/src/source_map/mod.rs | 7 - .../crates/next-core/src/source_map/trace.rs | 112 ---- .../next-swc/crates/next-core/src/util.rs | 3 +- 16 files changed, 14 insertions(+), 1866 deletions(-) delete mode 100644 packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs delete mode 100644 packages/next-swc/crates/next-core/src/nodejs/issue.rs delete mode 100644 packages/next-swc/crates/next-core/src/nodejs/mod.rs delete mode 100644 packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs delete mode 100644 packages/next-swc/crates/next-core/src/nodejs/node_entry.rs delete mode 100644 packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs delete mode 100644 packages/next-swc/crates/next-core/src/nodejs/pool.rs delete mode 100644 packages/next-swc/crates/next-core/src/path_regex.rs delete mode 100644 packages/next-swc/crates/next-core/src/source_map/content_source.rs delete mode 100644 packages/next-swc/crates/next-core/src/source_map/mod.rs delete mode 100644 packages/next-swc/crates/next-core/src/source_map/trace.rs diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index ae931ddc1b953f..18efa9083fb9c6 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -10,15 +10,9 @@ bench = false [dependencies] anyhow = "1.0.47" -futures = "0.3.21" -indexmap = { workspace = true, features = ["serde"] } -mime = "0.3.16" rand = "0.8.5" -regex = "1.6.0" serde = "1.0.136" serde_json = "1.0.85" -serde_qs = "0.10.1" -sourcemap = "6.0.1" tokio = { version = "1.21.2", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-env = { path = "../turbo-tasks-env" } @@ -29,7 +23,7 @@ turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } turbopack-ecmascript = { path = "../turbopack-ecmascript" } turbopack-env = { path = "../turbopack-env" } -url = "2.2.2" +turbopack-node = { path = "../turbopack-node" } [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index f4a79a1fa0e051..4016c5f7d39783 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -37,6 +37,11 @@ use turbopack_ecmascript::{ EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, }; use turbopack_env::ProcessEnvAssetVc; +use turbopack_node::{ + create_node_rendered_source, + node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, + NodeEntry, NodeEntryVc, +}; use crate::{ app_render::{ @@ -60,11 +65,6 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - nodejs::{ - create_node_rendered_source, - node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, - NodeEntry, NodeEntryVc, - }, util::regular_expression_for_path, }; diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 51e22652598db7..21cb2b690942a8 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -10,17 +10,15 @@ pub mod next_client; mod next_client_component; mod next_import_map; pub mod next_server; -mod nodejs; -mod path_regex; pub mod react_refresh; mod runtime; mod server_rendered_source; -pub mod source_map; mod util; mod web_entry_source; pub use app_source::create_app_source; pub use server_rendered_source::create_server_rendered_source; +pub use turbopack_node::source_map; pub use web_entry_source::create_web_entry_source; pub fn register() { @@ -28,5 +26,6 @@ pub fn register() { turbo_tasks_fs::register(); turbopack_dev_server::register(); turbopack::register(); + turbopack_node::register(); include!(concat!(env!("OUT_DIR"), "/register.rs")); } diff --git a/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs b/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs deleted file mode 100644 index cecfa962e4c65c..00000000000000 --- a/packages/next-swc/crates/next-core/src/nodejs/bootstrap.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::fmt::Write; - -use anyhow::Result; -use turbo_tasks_fs::{File, FileSystemPathVc}; -use turbopack::ecmascript::utils::stringify_str; -use turbopack_core::{ - asset::{Asset, AssetContentVc, AssetVc}, - chunk::{ChunkGroupVc, ChunkReferenceVc}, - reference::AssetReferencesVc, -}; - -#[turbo_tasks::value(shared)] -pub(super) struct NodeJsBootstrapAsset { - pub(super) path: FileSystemPathVc, - pub(super) chunk_group: ChunkGroupVc, -} - -#[turbo_tasks::value_impl] -impl Asset for NodeJsBootstrapAsset { - #[turbo_tasks::function] - fn path(&self) -> FileSystemPathVc { - self.path - } - - #[turbo_tasks::function] - async fn content(&self) -> Result<AssetContentVc> { - let context_path = self.path.parent().await?; - - // TODO(sokra) We need to have a chunk format for node.js - // but until then this is a simple hack to make it work for now - let mut output = "Error.stackTraceLimit = 100;\nglobal.self = global;\n".to_string(); - - for chunk in self.chunk_group.chunks().await?.iter() { - let path = &*chunk.path().await?; - if let Some(p) = context_path.get_relative_path_to(path) { - if p.ends_with(".js") { - writeln!(&mut output, "require({});", stringify_str(&p))?; - } - } - } - - Ok(File::from(output).into()) - } - - #[turbo_tasks::function] - async fn references(&self) -> Result<AssetReferencesVc> { - let chunks = self.chunk_group.chunks().await?; - let mut references = Vec::new(); - for chunk in chunks.iter() { - references.push(ChunkReferenceVc::new(*chunk).into()); - } - Ok(AssetReferencesVc::cell(references)) - } -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/issue.rs b/packages/next-swc/crates/next-core/src/nodejs/issue.rs deleted file mode 100644 index 5ab99a18aa4f34..00000000000000 --- a/packages/next-swc/crates/next-core/src/nodejs/issue.rs +++ /dev/null @@ -1,48 +0,0 @@ -use anyhow::Result; -use turbo_tasks::primitives::StringVc; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::issue::{Issue, IssueVc}; - -#[turbo_tasks::value(shared)] -#[derive(Copy, Clone)] -pub(super) struct RenderingIssue { - pub context: FileSystemPathVc, - pub message: StringVc, - pub status: Option<i32>, -} - -#[turbo_tasks::value_impl] -impl Issue for RenderingIssue { - #[turbo_tasks::function] - fn title(&self) -> StringVc { - StringVc::cell("Error during SSR Rendering".to_string()) - } - - #[turbo_tasks::function] - fn category(&self) -> StringVc { - StringVc::cell("rendering".to_string()) - } - - #[turbo_tasks::function] - fn context(&self) -> FileSystemPathVc { - self.context - } - - #[turbo_tasks::function] - fn description(&self) -> StringVc { - self.message - } - - #[turbo_tasks::function] - async fn detail(&self) -> Result<StringVc> { - let mut details = vec![]; - - if let Some(status) = self.status { - details.push(format!("Node.js exit code: {status}")); - } - - Ok(StringVc::cell(details.join("\n"))) - } - - // TODO parse stack trace into source location -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/mod.rs b/packages/next-swc/crates/next-core/src/nodejs/mod.rs deleted file mode 100644 index 10b7642a579760..00000000000000 --- a/packages/next-swc/crates/next-core/src/nodejs/mod.rs +++ /dev/null @@ -1,616 +0,0 @@ -use std::{ - collections::{BTreeMap, HashMap, HashSet}, - fmt::Write as _, - path::PathBuf, -}; - -use anyhow::{anyhow, bail, Context, Result}; -use futures::{stream::FuturesUnordered, TryStreamExt}; -use indexmap::{IndexMap, IndexSet}; -use mime::TEXT_HTML_UTF_8; -pub use node_api_source::create_node_api_source; -pub use node_entry::{NodeEntry, NodeEntryVc}; -pub use node_rendered_source::create_node_rendered_source; -use serde::{Deserialize, Serialize}; -use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, TryJoinIterExt}; -use turbo_tasks_fs::{to_sys_path, File, FileContent, FileSystemPathVc}; -use turbopack_core::{ - asset::{Asset, AssetContentVc, AssetVc, AssetsSetVc}, - chunk::{ChunkGroupVc, ChunkingContextVc}, - source_map::GenerateSourceMapVc, - virtual_asset::VirtualAssetVc, -}; -use turbopack_dev_server::{ - html::DevHtmlAssetVc, - source::{query::Query, BodyVc, HeaderValue, ProxyResult, ProxyResultVc}, -}; -use turbopack_ecmascript::{chunk::EcmascriptChunkPlaceablesVc, EcmascriptModuleAssetVc}; - -use self::{ - bootstrap::NodeJsBootstrapAsset, - issue::RenderingIssue, - pool::{NodeJsOperation, NodeJsPool, NodeJsPoolVc}, -}; -use crate::source_map::{SourceMapTraceVc, StackFrame, TraceResult}; - -pub(crate) mod bootstrap; -pub(crate) mod issue; -pub(crate) mod node_api_source; -pub(crate) mod node_entry; -pub(crate) mod node_rendered_source; -pub(crate) mod pool; - -#[turbo_tasks::function] -async fn emit( - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<CompletionVc> { - Ok(CompletionsVc::cell( - internal_assets(intermediate_asset, intermediate_output_path) - .strongly_consistent() - .await? - .iter() - .map(|a| async { - Ok(if *a.path().extension().await? != "map" { - Some(a.content().write(a.path())) - } else { - None - }) - }) - .try_join() - .await? - .into_iter() - .flatten() - .collect(), - ) - .all()) -} - -/// List of the all assets of the "internal" subgraph and a list of boundary -/// assets that are not considered "internal" ("external") -#[derive(Debug)] -#[turbo_tasks::value] -struct SeparatedAssets { - internal_assets: AssetsSetVc, - external_asset_entrypoints: AssetsSetVc, -} - -/// Extracts the subgraph of "internal" assets (assets within the passes -/// directory). Also lists all boundary assets that are not part of the -/// "internal" subgraph. -#[turbo_tasks::function] -async fn internal_assets( - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<AssetsSetVc> { - Ok( - separate_assets(intermediate_asset, intermediate_output_path) - .strongly_consistent() - .await? - .internal_assets, - ) -} - -/// Returns a set of "external" assets on the boundary of the "internal" -/// subgraph -#[turbo_tasks::function] -async fn external_asset_entrypoints( - module: EcmascriptModuleAssetVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: ChunkingContextVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<AssetsSetVc> { - Ok(separate_assets( - get_intermediate_asset( - module, - runtime_entries, - chunking_context, - intermediate_output_path, - ) - .resolve() - .await?, - intermediate_output_path, - ) - .strongly_consistent() - .await? - .external_asset_entrypoints) -} - -/// Splits the asset graph into "internal" assets and boundaries to "external" -/// assets. -#[turbo_tasks::function] -async fn separate_assets( - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<SeparatedAssetsVc> { - enum Type { - Internal(AssetVc, Vec<AssetVc>), - External(AssetVc), - } - let intermediate_output_path = intermediate_output_path.await?; - let mut queue = FuturesUnordered::new(); - let process_asset = |asset: AssetVc| { - let intermediate_output_path = &intermediate_output_path; - async move { - // Assets within the output directory are considered as "internal" and all - // others as "external". We follow references on "internal" assets, but do not - // look into references of "external" assets, since there are no "internal" - // assets behind "externals" - if asset.path().await?.is_inside(intermediate_output_path) { - let mut assets = Vec::new(); - for reference in asset.references().await?.iter() { - for asset in reference.resolve_reference().primary_assets().await?.iter() { - assets.push(*asset); - } - } - Ok::<_, anyhow::Error>(Type::Internal(asset, assets)) - } else { - Ok(Type::External(asset)) - } - } - }; - queue.push(process_asset(intermediate_asset)); - let mut processed = HashSet::new(); - let mut internal_assets = IndexSet::new(); - let mut external_asset_entrypoints = IndexSet::new(); - // TODO(sokra) This is not deterministic, since it's using FuturesUnordered. - // This need to be fixed! - while let Some(item) = queue.try_next().await? { - match item { - Type::Internal(asset, assets) => { - internal_assets.insert(asset); - for asset in assets { - if processed.insert(asset) { - queue.push(process_asset(asset)); - } - } - } - Type::External(asset) => { - external_asset_entrypoints.insert(asset); - } - } - } - Ok(SeparatedAssets { - internal_assets: AssetsSetVc::cell(internal_assets), - external_asset_entrypoints: AssetsSetVc::cell(external_asset_entrypoints), - } - .cell()) -} - -/// Creates a node.js renderer pool for an entrypoint. -#[turbo_tasks::function] -async fn get_renderer_pool( - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<NodeJsPoolVc> { - // Emit a basic package.json that sets the type of the package to commonjs. - // Currently code generated for Node is CommonJS, while authored code may be - // ESM, for example. - // - // Note that this is placed at .next/server/package.json, while Next.js - // currently creates this file at .next/package.json. - emit( - VirtualAssetVc::new( - intermediate_output_path.join("package.json"), - FileContent::Content(File::from("{\"type\": \"commonjs\"}")).into(), - ) - .into(), - intermediate_output_path, - ) - .await?; - - emit(intermediate_asset, intermediate_output_path).await?; - - if let Some(dir) = to_sys_path(intermediate_output_path).await? { - let entrypoint = dir.join("index.js"); - let pool = NodeJsPool::new(dir, entrypoint, HashMap::new(), 4); - Ok(pool.cell()) - } else { - Err(anyhow!("can only render from a disk filesystem")) - } -} - -/// Converts a module graph into node.js executable assets -#[turbo_tasks::function] -pub async fn get_intermediate_asset( - entry_module: EcmascriptModuleAssetVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: ChunkingContextVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<AssetVc> { - let chunk = entry_module.as_evaluated_chunk(chunking_context, Some(runtime_entries)); - let chunk_group = ChunkGroupVc::from_chunk(chunk); - Ok(NodeJsBootstrapAsset { - path: intermediate_output_path.join("index.js"), - chunk_group, - } - .cell() - .into()) -} - -#[turbo_tasks::value(shared)] -pub(super) struct RenderData { - params: IndexMap<String, String>, - method: String, - url: String, - query: Query, - headers: BTreeMap<String, HeaderValue>, - path: String, -} - -#[derive(Deserialize)] -#[serde(untagged)] -pub enum RenderResult { - Simple(String), - Advanced { - body: String, - #[serde(rename = "contentType")] - content_type: Option<String>, - }, -} - -#[derive(Serialize)] -#[serde(tag = "type", rename_all = "camelCase")] -enum RenderStaticOutgoingMessage<'a> { - Headers { data: &'a RenderData }, -} - -#[derive(Deserialize)] -#[serde(tag = "type", rename_all = "camelCase")] -enum RenderStaticIncomingMessage { - Result { result: RenderResult }, - Error(StructuredError), -} - -/// Renders a module as static HTML in a node.js process. -#[turbo_tasks::function] -async fn render_static( - path: FileSystemPathVc, - module: EcmascriptModuleAssetVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - fallback_page: DevHtmlAssetVc, - chunking_context: ChunkingContextVc, - intermediate_output_path: FileSystemPathVc, - data: RenderDataVc, -) -> Result<AssetContentVc> { - let intermediate_asset = get_intermediate_asset( - module, - runtime_entries, - chunking_context, - intermediate_output_path, - ); - let renderer_pool = get_renderer_pool(intermediate_asset, intermediate_output_path); - // Read this strongly consistent, since we don't want to run inconsistent - // node.js code. - let pool = renderer_pool.strongly_consistent().await?; - let mut operation = match pool.operation().await { - Ok(operation) => operation, - Err(err) => return static_error(path, err, None, fallback_page).await, - }; - - match run_static_operation( - &mut operation, - data, - intermediate_asset, - intermediate_output_path, - ) - .await - { - Ok(asset) => Ok(asset), - Err(err) => static_error(path, err, Some(operation), fallback_page).await, - } -} - -async fn run_static_operation( - operation: &mut NodeJsOperation, - data: RenderDataVc, - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<AssetContentVc> { - let data = data.await?; - - operation - .send(RenderStaticOutgoingMessage::Headers { data: &data }) - .await - .context("sending headers to node.js process")?; - match operation - .recv() - .await - .context("receiving from node.js process")? - { - RenderStaticIncomingMessage::Result { - result: RenderResult::Simple(body), - } => Ok(FileContent::Content(File::from(body).with_content_type(TEXT_HTML_UTF_8)).into()), - RenderStaticIncomingMessage::Result { - result: RenderResult::Advanced { body, content_type }, - } => Ok(FileContent::Content( - File::from(body) - .with_content_type(content_type.map_or(Ok(TEXT_HTML_UTF_8), |c| c.parse())?), - ) - .into()), - RenderStaticIncomingMessage::Error(error) => { - bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?) - } - } -} - -async fn static_error( - path: FileSystemPathVc, - error: anyhow::Error, - operation: Option<NodeJsOperation>, - fallback_page: DevHtmlAssetVc, -) -> Result<AssetContentVc> { - let message = format!("{error:?}"); - let status = match operation { - Some(operation) => Some(operation.wait_or_kill().await?), - None => None, - }; - - let html_status = match status { - Some(status) => format!("<h2>Exit status</h2><pre>{status}</pre>"), - None => "<h3>No exit status</pre>".to_owned(), - }; - - let body = format!( - "<script id=\"__NEXT_DATA__\" type=\"application/json\">{{ \"props\": {{}} }}</script> - <div id=\"__next\"> - <h1>Error rendering page</h1> - <h2>Message</h2> - <pre>{message}</pre> - {html_status} - </div>", - ); - - let issue = RenderingIssue { - context: path, - message: StringVc::cell(format!("{error:?}")), - status: status.and_then(|status| status.code()), - }; - - issue.cell().as_issue().emit(); - - let html = fallback_page.with_body(body); - - Ok(html.content()) -} - -async fn trace_stack( - error: StructuredError, - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<String> { - let root = match to_sys_path(intermediate_output_path.root()).await? { - Some(r) => r.to_string_lossy().to_string(), - None => bail!("couldn't extract disk fs from path"), - }; - - let assets = internal_assets(intermediate_asset, intermediate_output_path.root()) - .await? - .iter() - .map(|a| async { - let gen = match GenerateSourceMapVc::resolve_from(*a).await? { - Some(gen) => gen, - None => return Ok(None), - }; - - let path = match to_sys_path(a.path()).await? { - Some(p) => p, - None => PathBuf::from(&a.path().await?.path), - }; - - let p = path.strip_prefix(&root).unwrap(); - Ok(Some(( - p.to_str().unwrap().to_string(), - gen.generate_source_map(), - ))) - }) - .try_join() - .await? - .into_iter() - .flatten() - .collect::<HashMap<_, _>>(); - - let mut message = String::new(); - - macro_rules! write_frame { - ($f:ident, $path:expr) => { - match $f.get_pos() { - Some((l, c)) => match &$f.name { - Some(n) => writeln!(message, " at {} ({}:{}:{})", n, $path, l, c), - None => writeln!(message, " at {}:{}:{}", $path, l, c), - }, - None => writeln!(message, " at {}", $path), - } - }; - } - - writeln!(message, "{}: {}", error.name, error.message)?; - - for frame in &error.stack { - if let Some((line, column)) = frame.get_pos() { - if let Some(path) = frame.file.strip_prefix(&root) { - if let Some(map) = assets.get(path) { - let trace = SourceMapTraceVc::new(*map, line, column, frame.name.clone()) - .trace() - .await?; - if let TraceResult::Found(f) = &*trace { - write_frame!(f, f.file)?; - continue; - } - } - - write_frame!(frame, path)?; - continue; - } - } - - write_frame!(frame, frame.file)?; - } - - Ok(message) -} - -#[turbo_tasks::value(shared)] -pub(super) struct ResponseHeaders { - status: u16, - headers: Vec<String>, -} - -#[derive(Serialize)] -#[serde(tag = "type", rename_all = "camelCase")] -enum RenderProxyOutgoingMessage<'a> { - Headers { data: &'a RenderData }, - BodyChunk { data: &'a [u8] }, - BodyEnd, -} - -#[derive(Deserialize)] -#[serde(tag = "type", rename_all = "camelCase")] -enum RenderProxyIncomingMessage { - Headers { data: ResponseHeaders }, - Body { data: Vec<u8> }, - Error(StructuredError), -} - -#[turbo_tasks::value(shared)] -struct StructuredError { - name: String, - message: String, - stack: Vec<StackFrame>, -} - -/// Renders a module as static HTML in a node.js process. -#[turbo_tasks::function] -async fn render_proxy( - path: FileSystemPathVc, - module: EcmascriptModuleAssetVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - chunking_context: ChunkingContextVc, - intermediate_output_path: FileSystemPathVc, - data: RenderDataVc, - body: BodyVc, -) -> Result<ProxyResultVc> { - let intermediate_asset = get_intermediate_asset( - module, - runtime_entries, - chunking_context, - intermediate_output_path, - ); - let renderer_pool = get_renderer_pool(intermediate_asset, intermediate_output_path); - let pool = renderer_pool.await?; - let mut operation = match pool.operation().await { - Ok(operation) => operation, - Err(err) => { - return proxy_error(path, err, None).await; - } - }; - - match run_proxy_operation( - &mut operation, - data, - body, - intermediate_asset, - intermediate_output_path, - ) - .await - { - Ok(proxy_result) => Ok(proxy_result.cell()), - Err(err) => Ok(proxy_error(path, err, Some(operation)).await?), - } -} - -async fn run_proxy_operation( - operation: &mut NodeJsOperation, - data: RenderDataVc, - body: BodyVc, - intermediate_asset: AssetVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<ProxyResult> { - let data = data.await?; - // First, send the render data. - operation - .send(RenderProxyOutgoingMessage::Headers { data: &data }) - .await?; - - let body = body.await?; - // Then, send the binary body in chunks. - for chunk in body.chunks() { - operation - .send(RenderProxyOutgoingMessage::BodyChunk { - data: chunk.as_bytes(), - }) - .await?; - } - - operation.send(RenderProxyOutgoingMessage::BodyEnd).await?; - - let (status, headers) = match operation.recv().await? { - RenderProxyIncomingMessage::Headers { - data: ResponseHeaders { status, headers }, - } => (status, headers), - RenderProxyIncomingMessage::Error(error) => { - bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?) - } - _ => { - bail!("unexpected response from the Node.js process while reading response headers") - } - }; - - let body = match operation.recv().await? { - RenderProxyIncomingMessage::Body { data: body } => body, - RenderProxyIncomingMessage::Error(error) => { - bail!(trace_stack(error, intermediate_asset, intermediate_output_path).await?) - } - _ => { - bail!("unexpected response from the Node.js process while reading response body") - } - }; - - Ok(ProxyResult { - status, - headers, - body: body.into(), - }) -} - -async fn proxy_error( - path: FileSystemPathVc, - error: anyhow::Error, - operation: Option<NodeJsOperation>, -) -> Result<ProxyResultVc> { - let message = format!("{error:?}"); - - let status = match operation { - Some(operation) => Some(operation.wait_or_kill().await?), - None => None, - }; - - let mut details = vec![]; - if let Some(status) = status { - details.push(format!("status: {status}")); - } - - let body = format!( - "An error occurred while proxying a request to Node.js:\n{message}\n{}", - details.join("\n") - ); - - RenderingIssue { - context: path, - message: StringVc::cell(message), - status: status.and_then(|status| status.code()), - } - .cell() - .as_issue() - .emit(); - - Ok(ProxyResult { - status: 500, - headers: vec![ - "content-type".to_string(), - "text/html; charset=utf-8".to_string(), - ], - body: body.into(), - } - .cell()) -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs deleted file mode 100644 index 264a625394b9f0..00000000000000 --- a/packages/next-swc/crates/next-core/src/nodejs/node_api_source.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::collections::HashSet; - -use anyhow::Result; -use indexmap::IndexMap; -use turbo_tasks::{primitives::StringVc, ValueToString}; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::introspect::{ - asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, -}; -use turbopack_dev_server::source::{ - specificity::SpecificityVc, ContentSource, ContentSourceContent, ContentSourceData, - ContentSourceDataFilter, ContentSourceDataVary, ContentSourceResult, ContentSourceResultVc, - ContentSourceVc, -}; -use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; - -use super::{get_intermediate_asset, render_proxy, NodeEntryVc, RenderData}; -use crate::path_regex::PathRegexVc; - -/// Creates a [NodeApiContentSource]. -#[turbo_tasks::function] -pub fn create_node_api_source( - specificity: SpecificityVc, - server_root: FileSystemPathVc, - path_regex: PathRegexVc, - entry: NodeEntryVc, - runtime_entries: EcmascriptChunkPlaceablesVc, -) -> ContentSourceVc { - NodeApiContentSource { - specificity, - server_root, - path_regex, - entry, - runtime_entries, - } - .cell() - .into() -} - -/// A content source that proxies API requests to one-off Node.js -/// servers running the passed `entry` when it matches a `path_regex`. -/// -/// It needs a temporary directory (`intermediate_output_path`) to place file -/// for Node.js execution during rendering. The `chunking_context` should emit -/// to this directory. -#[turbo_tasks::value] -struct NodeApiContentSource { - specificity: SpecificityVc, - server_root: FileSystemPathVc, - path_regex: PathRegexVc, - entry: NodeEntryVc, - runtime_entries: EcmascriptChunkPlaceablesVc, -} - -impl NodeApiContentSource { - /// Checks if a path matches the regular expression - async fn is_matching_path(&self, path: &str) -> Result<bool> { - Ok(self.path_regex.await?.is_match(path)) - } - - /// Matches a path with the regular expression and returns a JSON object - /// with the named captures - async fn get_matches(&self, path: &str) -> Result<Option<IndexMap<String, String>>> { - Ok(self.path_regex.await?.get_matches(path)) - } -} - -#[turbo_tasks::value_impl] -impl ContentSource for NodeApiContentSource { - #[turbo_tasks::function] - async fn get( - self_vc: NodeApiContentSourceVc, - path: &str, - data: turbo_tasks::Value<ContentSourceData>, - ) -> Result<ContentSourceResultVc> { - let this = self_vc.await?; - if this.is_matching_path(path).await? { - if let Some(params) = this.get_matches(path).await? { - let content = if let ContentSourceData { - headers: Some(headers), - method: Some(method), - url: Some(url), - query: Some(query), - body: Some(body), - .. - } = &*data - { - let entry = this.entry.entry(data.clone()).await?; - ContentSourceContent::HttpProxy(render_proxy( - this.server_root.join(path), - entry.module, - this.runtime_entries, - entry.chunking_context, - entry.intermediate_output_path, - RenderData { - params, - method: method.clone(), - url: url.clone(), - query: query.clone(), - headers: headers.clone(), - path: format!("/{path}"), - } - .cell(), - *body, - )) - .cell() - } else { - ContentSourceContent::NeedData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - method: true, - url: true, - headers: Some(ContentSourceDataFilter::All), - query: Some(ContentSourceDataFilter::All), - body: true, - cache_buster: true, - ..Default::default() - }, - } - .cell() - }; - return Ok(ContentSourceResult { - specificity: this.specificity, - content, - } - .cell()); - } - } - Ok(ContentSourceResultVc::not_found()) - } -} - -#[turbo_tasks::function] -fn introspectable_type() -> StringVc { - StringVc::cell("node api content source".to_string()) -} - -#[turbo_tasks::value_impl] -impl Introspectable for NodeApiContentSource { - #[turbo_tasks::function] - fn ty(&self) -> StringVc { - introspectable_type() - } - - #[turbo_tasks::function] - fn title(&self) -> StringVc { - self.path_regex.to_string() - } - - #[turbo_tasks::function] - async fn details(&self) -> Result<StringVc> { - Ok(StringVc::cell(format!( - "Specificity: {}", - self.specificity.await? - ))) - } - - #[turbo_tasks::function] - async fn children(&self) -> Result<IntrospectableChildrenVc> { - let mut set = HashSet::new(); - for &entry in self.entry.entries().await?.iter() { - let entry = entry.await?; - set.insert(( - StringVc::cell("module".to_string()), - IntrospectableAssetVc::new(entry.module.into()), - )); - set.insert(( - StringVc::cell("intermediate asset".to_string()), - IntrospectableAssetVc::new(get_intermediate_asset( - entry.module, - self.runtime_entries, - entry.chunking_context, - entry.intermediate_output_path, - )), - )); - } - Ok(IntrospectableChildrenVc::cell(set)) - } -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs b/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs deleted file mode 100644 index 6653f4ecd3d55b..00000000000000 --- a/packages/next-swc/crates/next-core/src/nodejs/node_entry.rs +++ /dev/null @@ -1,25 +0,0 @@ -use anyhow::Result; -use turbo_tasks::Value; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::chunk::ChunkingContextVc; -use turbopack_dev_server::source::ContentSourceData; -use turbopack_ecmascript::EcmascriptModuleAssetVc; - -#[turbo_tasks::value(shared)] -pub struct NodeRenderingEntry { - pub module: EcmascriptModuleAssetVc, - pub chunking_context: ChunkingContextVc, - pub intermediate_output_path: FileSystemPathVc, -} - -#[turbo_tasks::value(transparent)] -pub struct NodeRenderingEntries(Vec<NodeRenderingEntryVc>); - -/// Trait that allows to get the entry module for rendering something in Node.js -#[turbo_tasks::value_trait] -pub trait NodeEntry { - fn entry(&self, data: Value<ContentSourceData>) -> NodeRenderingEntryVc; - fn entries(&self) -> NodeRenderingEntriesVc { - NodeRenderingEntriesVc::cell(vec![self.entry(Value::new(Default::default()))]) - } -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs b/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs deleted file mode 100644 index fa248e116cb1bc..00000000000000 --- a/packages/next-swc/crates/next-core/src/nodejs/node_rendered_source.rs +++ /dev/null @@ -1,255 +0,0 @@ -use std::collections::HashSet; - -use anyhow::{anyhow, Result}; -use indexmap::{IndexMap, IndexSet}; -use turbo_tasks::{primitives::StringVc, ValueToString}; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack_core::{ - asset::{Asset, AssetsSetVc}, - introspect::{ - asset::IntrospectableAssetVc, Introspectable, IntrospectableChildrenVc, IntrospectableVc, - }, -}; -use turbopack_dev_server::{ - html::DevHtmlAssetVc, - source::{ - asset_graph::AssetGraphContentSourceVc, - conditional::ConditionalContentSourceVc, - lazy_instatiated::{GetContentSource, GetContentSourceVc, LazyInstantiatedContentSource}, - specificity::SpecificityVc, - ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter, - ContentSourceDataVary, ContentSourceResult, ContentSourceResultVc, ContentSourceVc, - }, -}; -use turbopack_ecmascript::chunk::EcmascriptChunkPlaceablesVc; - -use super::{ - external_asset_entrypoints, get_intermediate_asset, render_static, NodeEntryVc, RenderData, -}; -use crate::path_regex::PathRegexVc; - -/// Creates a content source that renders something in Node.js with the passed -/// `entry` when it matches a `path_regex`. Once rendered it serves -/// all assets referenced by the `entry` that are within the `server_root`. -/// It needs a temporary directory (`intermediate_output_path`) to place file -/// for Node.js execution during rendering. The `chunking_context` should emit -/// to this directory. -#[turbo_tasks::function] -pub fn create_node_rendered_source( - specificity: SpecificityVc, - server_root: FileSystemPathVc, - path_regex: PathRegexVc, - entry: NodeEntryVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - fallback_page: DevHtmlAssetVc, -) -> ContentSourceVc { - let source = NodeRenderContentSource { - specificity, - server_root, - path_regex, - entry, - runtime_entries, - fallback_page, - } - .cell(); - ConditionalContentSourceVc::new( - source.into(), - LazyInstantiatedContentSource { - get_source: source.as_get_content_source(), - } - .cell() - .into(), - ) - .into() -} - -/// see [create_node_rendered_source] -#[turbo_tasks::value] -struct NodeRenderContentSource { - specificity: SpecificityVc, - server_root: FileSystemPathVc, - path_regex: PathRegexVc, - entry: NodeEntryVc, - runtime_entries: EcmascriptChunkPlaceablesVc, - fallback_page: DevHtmlAssetVc, -} - -impl NodeRenderContentSource { - /// Checks if a path matches the regular expression - async fn is_matching_path(&self, path: &str) -> Result<bool> { - // TODO(alexkirsz) This should probably not happen here. - if path.starts_with('_') { - return Ok(false); - } - Ok(self.path_regex.await?.is_match(path)) - } - - /// Matches a path with the regular expression and returns a JSON object - /// with the named captures - async fn get_matches(&self, path: &str) -> Result<Option<IndexMap<String, String>>> { - // TODO(alexkirsz) This should probably not happen here. - if path.starts_with('_') { - return Ok(None); - } - Ok(self.path_regex.await?.get_matches(path)) - } -} - -#[turbo_tasks::value_impl] -impl GetContentSource for NodeRenderContentSource { - /// Returns the [ContentSource] that serves all referenced external - /// assets. This is wrapped into [LazyInstantiatedContentSource]. - #[turbo_tasks::function] - async fn content_source(&self) -> Result<ContentSourceVc> { - let entries = self.entry.entries(); - let mut set = IndexSet::new(); - for reference in self.fallback_page.references().await?.iter() { - set.extend( - reference - .resolve_reference() - .primary_assets() - .await? - .iter() - .copied(), - ) - } - for &entry in entries.await?.iter() { - let entry = entry.await?; - set.extend( - external_asset_entrypoints( - entry.module, - self.runtime_entries, - entry.chunking_context, - entry.intermediate_output_path, - ) - .await? - .iter() - .copied(), - ) - } - Ok( - AssetGraphContentSourceVc::new_lazy_multiple(self.server_root, AssetsSetVc::cell(set)) - .into(), - ) - } -} - -#[turbo_tasks::value_impl] -impl ContentSource for NodeRenderContentSource { - #[turbo_tasks::function] - async fn get( - self_vc: NodeRenderContentSourceVc, - path: &str, - data: turbo_tasks::Value<ContentSourceData>, - ) -> Result<ContentSourceResultVc> { - let this = self_vc.await?; - if this.is_matching_path(path).await? { - if let Some(params) = this.get_matches(path).await? { - let content = if data.method.is_some() - && data.url.is_some() - && data.headers.is_some() - && data.query.is_some() - { - let entry = this.entry.entry(data.clone()).await?; - let asset = render_static( - this.server_root.join(path), - entry.module, - this.runtime_entries, - this.fallback_page, - entry.chunking_context, - entry.intermediate_output_path, - RenderData { - params, - method: data - .method - .clone() - .ok_or_else(|| anyhow!("method needs to be provided"))?, - url: data - .url - .clone() - .ok_or_else(|| anyhow!("url needs to be provided"))?, - query: data - .query - .clone() - .ok_or_else(|| anyhow!("query needs to be provided"))?, - headers: data - .headers - .clone() - .ok_or_else(|| anyhow!("headers needs to be provided"))?, - path: format!("/{path}"), - } - .cell(), - ); - ContentSourceContent::Static(asset.into()).cell() - } else { - ContentSourceContent::NeedData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - method: true, - url: true, - headers: Some(ContentSourceDataFilter::All), - query: Some(ContentSourceDataFilter::All), - ..Default::default() - }, - } - .cell() - }; - return Ok(ContentSourceResult { - specificity: this.specificity, - content, - } - .cell()); - } - } - Ok(ContentSourceResultVc::not_found()) - } -} - -#[turbo_tasks::function] -fn introspectable_type() -> StringVc { - StringVc::cell("node render content source".to_string()) -} - -#[turbo_tasks::value_impl] -impl Introspectable for NodeRenderContentSource { - #[turbo_tasks::function] - fn ty(&self) -> StringVc { - introspectable_type() - } - - #[turbo_tasks::function] - fn title(&self) -> StringVc { - self.path_regex.to_string() - } - - #[turbo_tasks::function] - async fn details(&self) -> Result<StringVc> { - Ok(StringVc::cell(format!( - "Specificity: {}", - self.specificity.await? - ))) - } - - #[turbo_tasks::function] - async fn children(&self) -> Result<IntrospectableChildrenVc> { - let mut set = HashSet::new(); - for &entry in self.entry.entries().await?.iter() { - let entry = entry.await?; - set.insert(( - StringVc::cell("module".to_string()), - IntrospectableAssetVc::new(entry.module.into()), - )); - set.insert(( - StringVc::cell("intermediate asset".to_string()), - IntrospectableAssetVc::new(get_intermediate_asset( - entry.module, - self.runtime_entries, - entry.chunking_context, - entry.intermediate_output_path, - )), - )); - } - Ok(IntrospectableChildrenVc::cell(set)) - } -} diff --git a/packages/next-swc/crates/next-core/src/nodejs/pool.rs b/packages/next-swc/crates/next-core/src/nodejs/pool.rs deleted file mode 100644 index 9a07cfe9cfbf23..00000000000000 --- a/packages/next-swc/crates/next-core/src/nodejs/pool.rs +++ /dev/null @@ -1,283 +0,0 @@ -use std::{ - collections::HashMap, - path::{Path, PathBuf}, - process::{ExitStatus, Stdio}, - sync::{Arc, Mutex}, - time::Duration, -}; - -use anyhow::{bail, Context, Result}; -use serde::{de::DeserializeOwned, Serialize}; -use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::{TcpListener, TcpStream}, - process::{Child, Command}, - select, - sync::{OwnedSemaphorePermit, Semaphore}, - time::sleep, -}; - -enum NodeJsPoolProcess { - Spawned(SpawnedNodeJsPoolProcess), - Running(RunningNodeJsPoolProcess), -} - -struct SpawnedNodeJsPoolProcess { - child: Option<Child>, - listener: TcpListener, -} - -struct RunningNodeJsPoolProcess { - child: Option<Child>, - connection: TcpStream, -} - -impl Drop for SpawnedNodeJsPoolProcess { - fn drop(&mut self) { - if let Some(mut child) = self.child.take() { - tokio::spawn(async move { - let _ = child.kill().await; - }); - } - } -} - -impl Drop for RunningNodeJsPoolProcess { - fn drop(&mut self) { - if let Some(mut child) = self.child.take() { - tokio::spawn(async move { - let _ = child.kill().await; - }); - } - } -} - -const CONNECT_TIMEOUT: Duration = Duration::from_secs(30); - -impl NodeJsPoolProcess { - async fn new(cwd: &Path, env: &HashMap<String, String>, entrypoint: &Path) -> Result<Self> { - let listener = TcpListener::bind("127.0.0.1:0") - .await - .context("binding to a port")?; - let port = listener.local_addr().context("getting port")?.port(); - let mut cmd = Command::new("node"); - cmd.current_dir(cwd); - cmd.arg(entrypoint); - cmd.arg(port.to_string()); - cmd.env_clear(); - cmd.env( - "PATH", - std::env::var("PATH").expect("the PATH environment variable should always be set"), - ); - #[cfg(target_family = "windows")] - cmd.env( - "SystemRoot", - std::env::var("SystemRoot") - .expect("the SystemRoot environment variable should always be set"), - ); - cmd.envs(env); - cmd.stderr(Stdio::inherit()); - cmd.stdout(Stdio::inherit()); - - let child = cmd.spawn().context("spawning node pooled process")?; - - Ok(Self::Spawned(SpawnedNodeJsPoolProcess { - listener, - child: Some(child), - })) - } - - async fn run(self) -> Result<RunningNodeJsPoolProcess> { - Ok(match self { - NodeJsPoolProcess::Spawned(mut spawned) => { - let (connection, _) = select! { - connection = spawned.listener.accept() => connection.context("accepting connection")?, - status = spawned.child.as_mut().unwrap().wait() => { - match status { - Ok(status) => { - bail!("node process exited before we could connect to it with {}", status); - } - Err(err) => { - bail!("node process exited before we could connect to it: {:?}", err); - }, - } - }, - _ = sleep(CONNECT_TIMEOUT) => bail!("timed out waiting for the Node.js process to connect ({:?} timeout)", CONNECT_TIMEOUT), - }; - - RunningNodeJsPoolProcess { - child: spawned.child.take(), - connection, - } - } - NodeJsPoolProcess::Running(running) => running, - }) - } -} - -impl RunningNodeJsPoolProcess { - async fn recv(&mut self) -> Result<Vec<u8>> { - let packet_len = self - .connection - .read_u32() - .await - .context("reading packet length")? - .try_into() - .context("storing packet length")?; - let mut packet_data = vec![0; packet_len]; - self.connection - .read_exact(&mut packet_data) - .await - .context("reading packet data")?; - Ok(packet_data) - } - - async fn send(&mut self, packet_data: Vec<u8>) -> Result<()> { - self.connection - .write_u32( - packet_data - .len() - .try_into() - .context("packet length does not fit into u32")?, - ) - .await - .context("writing packet length")?; - self.connection - .write_all(&packet_data) - .await - .context("writing packet data")?; - Ok(()) - } -} - -/// A pool of Node.js workers operating on [entrypoint] with specific [cwd] and -/// [env]. -/// -/// The pool will spawn processes when needed and reuses old ones. It will never -/// spawn more then a certain number of concurrent processes. This is specified -/// with the `concurrency` argument in the constructor. -/// -/// The worker will *not* use the env of the parent process by default. All env -/// vars need to be provided to make the execution as pure as possible. -#[turbo_tasks::value(into = "new", cell = "new", serialization = "none", eq = "manual")] -pub(super) struct NodeJsPool { - cwd: PathBuf, - entrypoint: PathBuf, - env: HashMap<String, String>, - #[turbo_tasks(trace_ignore, debug_ignore)] - processes: Arc<Mutex<Vec<NodeJsPoolProcess>>>, - #[turbo_tasks(trace_ignore, debug_ignore)] - semaphore: Arc<Semaphore>, -} - -impl NodeJsPool { - pub(super) fn new( - cwd: PathBuf, - entrypoint: PathBuf, - env: HashMap<String, String>, - concurrency: usize, - ) -> Self { - Self { - cwd, - entrypoint, - env, - processes: Arc::new(Mutex::new(Vec::new())), - semaphore: Arc::new(Semaphore::new(concurrency)), - } - } - - async fn acquire_process(&self) -> Result<(NodeJsPoolProcess, OwnedSemaphorePermit)> { - let permit = self.semaphore.clone().acquire_owned().await?; - - let popped = { - let mut processes = self.processes.lock().unwrap(); - processes.pop() - }; - let process = match popped { - Some(process) => process, - None => { - NodeJsPoolProcess::new(self.cwd.as_path(), &self.env, self.entrypoint.as_path()) - .await - .context("creating new process")? - } - }; - Ok((process, permit)) - } - - pub(super) async fn operation(&self) -> Result<NodeJsOperation> { - let (process, permit) = self.acquire_process().await?; - - Ok(NodeJsOperation { - process: Some(process.run().await?), - permit, - processes: self.processes.clone(), - }) - } -} - -pub struct NodeJsOperation { - process: Option<RunningNodeJsPoolProcess>, - // This is used for drop - #[allow(dead_code)] - permit: OwnedSemaphorePermit, - processes: Arc<Mutex<Vec<NodeJsPoolProcess>>>, -} - -impl NodeJsOperation { - fn process_mut(&mut self) -> Result<&mut RunningNodeJsPoolProcess> { - self.process - .as_mut() - .context("Node.js operation already finished") - } - - pub(super) async fn recv<M>(&mut self) -> Result<M> - where - M: DeserializeOwned, - { - let message = self - .process_mut()? - .recv() - .await - .context("receiving message")?; - serde_json::from_slice(&message).context("deserializing message") - } - - pub(super) async fn send<M>(&mut self, message: M) -> Result<()> - where - M: Serialize, - { - self.process_mut()? - .send(serde_json::to_vec(&message).context("serializing message")?) - .await - .context("sending message") - } - - pub(super) async fn wait_or_kill(mut self) -> Result<ExitStatus> { - let mut process = self - .process - .take() - .context("Node.js operation already finished")?; - - let mut child = process - .child - .take() - .context("Node.js operation already finished")?; - - // Ignore error since we are not sure if the process is still alive - let _ = child.start_kill(); - let status = child.wait().await.context("waiting for process end")?; - - Ok(status) - } -} - -impl Drop for NodeJsOperation { - fn drop(&mut self) { - if let Some(process) = self.process.take() { - self.processes - .lock() - .unwrap() - .push(NodeJsPoolProcess::Running(process)); - } - } -} diff --git a/packages/next-swc/crates/next-core/src/path_regex.rs b/packages/next-swc/crates/next-core/src/path_regex.rs deleted file mode 100644 index 6e9aefc5141fe4..00000000000000 --- a/packages/next-swc/crates/next-core/src/path_regex.rs +++ /dev/null @@ -1,141 +0,0 @@ -use anyhow::{Context, Result}; -use indexmap::IndexMap; -use turbo_tasks::{ - primitives::{Regex, StringVc}, - ValueToString, ValueToStringVc, -}; - -/// A regular expression that matches a path, with named capture groups for the -/// dynamic parts of the path. -#[turbo_tasks::value(shared)] -#[derive(Debug)] -pub struct PathRegex { - regex: Regex, - named_params: Vec<String>, -} - -impl PathRegex { - /// Returns true if the given path matches the regular expression. - pub fn is_match(&self, path: &str) -> bool { - self.regex.is_match(path) - } - - /// Matches a path with the regular expression and returns a map with the - /// named captures. - pub fn get_matches(&self, path: &str) -> Option<IndexMap<String, String>> { - self.regex.captures(path).map(|capture| { - self.named_params - .iter() - .enumerate() - .filter_map(|(idx, name)| { - if name.is_empty() { - return None; - } - let value = capture.get(idx + 1)?; - Some((name.to_string(), value.as_str().to_string())) - }) - .collect() - }) - } -} - -#[turbo_tasks::value_impl] -impl ValueToString for PathRegex { - #[turbo_tasks::function] - fn to_string(&self) -> StringVc { - StringVc::cell(self.regex.as_str().to_string()) - } -} - -/// Builder for [PathRegex]. -pub struct PathRegexBuilder { - regex_str: String, - named_params: Vec<String>, -} - -impl PathRegexBuilder { - /// Creates a new [PathRegexBuilder]. - pub fn new() -> Self { - Self { - regex_str: "^".to_string(), - named_params: Default::default(), - } - } - - fn include_slash(&self) -> bool { - self.regex_str.len() > 1 - } - - fn push_str(&mut self, str: &str) { - self.regex_str.push_str(str); - } - - /// Pushes an optional catch all segment to the regex. - pub fn push_optional_catch_all<N, R>(&mut self, name: N, rem: R) - where - N: Into<String>, - R: AsRef<str>, - { - self.push_str(if self.include_slash() { - "(/[^?]+)?" - } else { - "([^?]+)?" - }); - self.push_str(®ex::escape(rem.as_ref())); - self.named_params.push(name.into()); - } - - /// Pushes a catch all segment to the regex. - pub fn push_catch_all<N, R>(&mut self, name: N, rem: R) - where - N: Into<String>, - R: AsRef<str>, - { - if self.include_slash() { - self.push_str("/"); - } - self.push_str("([^?]+)"); - self.push_str(®ex::escape(rem.as_ref())); - self.named_params.push(name.into()); - } - - /// Pushes a dynamic segment to the regex. - pub fn push_dynamic_segment<N, R>(&mut self, name: N, rem: R) - where - N: Into<String>, - R: AsRef<str>, - { - if self.include_slash() { - self.push_str("/"); - } - self.push_str("([^?/]+)"); - self.push_str(®ex::escape(rem.as_ref())); - self.named_params.push(name.into()); - } - - /// Pushes a static segment to the regex. - pub fn push_static_segment<S>(&mut self, segment: S) - where - S: AsRef<str>, - { - if self.include_slash() { - self.push_str("/"); - } - self.push_str(®ex::escape(segment.as_ref())); - } - - /// Builds and returns the [PathRegex]. - pub fn build(mut self) -> Result<PathRegex> { - self.regex_str += "$"; - Ok(PathRegex { - regex: Regex(regex::Regex::new(&self.regex_str).with_context(|| "invalid path regex")?), - named_params: self.named_params, - }) - } -} - -impl Default for PathRegexBuilder { - fn default() -> Self { - Self::new() - } -} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index c7098465498988..d481f47d8d9be8 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -29,6 +29,11 @@ use turbopack_ecmascript::{ EcmascriptModuleAssetType, EcmascriptModuleAssetVc, }; use turbopack_env::ProcessEnvAssetVc; +use turbopack_node::{ + create_node_api_source, create_node_rendered_source, + node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, + NodeEntry, NodeEntryVc, +}; use crate::{ embed_js::{next_js_file, wrap_with_next_js_fs}, @@ -45,11 +50,6 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - nodejs::{ - create_node_api_source, create_node_rendered_source, - node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, - NodeEntry, NodeEntryVc, - }, util::regular_expression_for_path, }; diff --git a/packages/next-swc/crates/next-core/src/source_map/content_source.rs b/packages/next-swc/crates/next-core/src/source_map/content_source.rs deleted file mode 100644 index bb9e7e1ca6ac65..00000000000000 --- a/packages/next-swc/crates/next-core/src/source_map/content_source.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::collections::HashSet; - -use anyhow::Result; -use turbo_tasks::{primitives::StringVc, Value}; -use turbopack_core::{ - introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc}, - source_map::GenerateSourceMapVc, -}; -use turbopack_dev_server::source::{ - ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataVary, - ContentSourceResultVc, ContentSourceVc, -}; -use url::Url; - -use super::{SourceMapTraceVc, StackFrame}; - -/// Responsible for performinmg source map tracging for individual error stack -/// frames. This is the API end of the client's Overlay stack-frame.ts. -#[turbo_tasks::value(shared)] -pub struct NextSourceMapTraceContentSource { - asset_source: ContentSourceVc, -} - -#[turbo_tasks::value_impl] -impl NextSourceMapTraceContentSourceVc { - #[turbo_tasks::function] - pub fn new(asset_source: ContentSourceVc) -> NextSourceMapTraceContentSourceVc { - NextSourceMapTraceContentSource { asset_source }.cell() - } -} - -#[turbo_tasks::value_impl] -impl ContentSource for NextSourceMapTraceContentSource { - #[turbo_tasks::function] - async fn get( - self_vc: NextSourceMapTraceContentSourceVc, - path: &str, - data: Value<ContentSourceData>, - ) -> Result<ContentSourceResultVc> { - let url = match &data.url { - None => { - return Ok(ContentSourceResultVc::exact( - ContentSourceContent::NeedData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - url: true, - ..Default::default() - }, - } - .cell(), - )); - } - Some(query) => query, - }; - - // TODO: It'd be nice if the data.query value contained the unparsed query, so I - // could convert it into my struct. - let query_idx = match url.find('?') { - Some(i) => i, - _ => return Ok(ContentSourceResultVc::not_found()), - }; - let frame: StackFrame = match serde_qs::from_str(&url[query_idx + 1..]) { - Ok(f) => f, - _ => return Ok(ContentSourceResultVc::not_found()), - }; - let (line, column) = match frame.get_pos() { - Some((l, c)) => (l, c), - _ => return Ok(ContentSourceResultVc::not_found()), - }; - - // The file is some percent encoded `http://localhost:3000/_next/foo/bar.js` - let file = match Url::parse(&frame.file) { - Ok(u) => u, - _ => return Ok(ContentSourceResultVc::not_found()), - }; - - let path = match file.path().strip_prefix('/') { - Some(p) => p, - _ => return Ok(ContentSourceResultVc::not_found()), - }; - - let this = self_vc.await?; - let result = this - .asset_source - .get(path, Value::new(Default::default())) - .await?; - let file = match &*result.content.await? { - ContentSourceContent::Static(f) => *f, - _ => return Ok(ContentSourceResultVc::not_found()), - }; - - let gen = match GenerateSourceMapVc::resolve_from(file).await? { - Some(f) => f, - _ => return Ok(ContentSourceResultVc::not_found()), - }; - - let traced = SourceMapTraceVc::new(gen.generate_source_map(), line, column, frame.name); - Ok(ContentSourceResultVc::exact( - ContentSourceContent::Static(traced.content().into()).cell(), - )) - } -} - -#[turbo_tasks::value_impl] -impl Introspectable for NextSourceMapTraceContentSource { - #[turbo_tasks::function] - fn ty(&self) -> StringVc { - StringVc::cell("next source map trace content source".to_string()) - } - - #[turbo_tasks::function] - fn details(&self) -> StringVc { - StringVc::cell( - "supports tracing an error stack frame to its original source location".to_string(), - ) - } - - #[turbo_tasks::function] - async fn children(&self) -> Result<IntrospectableChildrenVc> { - Ok(IntrospectableChildrenVc::cell(HashSet::new())) - } -} diff --git a/packages/next-swc/crates/next-core/src/source_map/mod.rs b/packages/next-swc/crates/next-core/src/source_map/mod.rs deleted file mode 100644 index 9b97d08c86105e..00000000000000 --- a/packages/next-swc/crates/next-core/src/source_map/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod content_source; -pub mod trace; - -pub use content_source::{NextSourceMapTraceContentSource, NextSourceMapTraceContentSourceVc}; -pub use trace::{ - SourceMapTrace, SourceMapTraceVc, StackFrame, StackFrameVc, TraceResult, TraceResultVc, -}; diff --git a/packages/next-swc/crates/next-core/src/source_map/trace.rs b/packages/next-swc/crates/next-core/src/source_map/trace.rs deleted file mode 100644 index f1cdf3e1ed193a..00000000000000 --- a/packages/next-swc/crates/next-core/src/source_map/trace.rs +++ /dev/null @@ -1,112 +0,0 @@ -use anyhow::Result; -use serde_json::json; -use turbo_tasks_fs::File; -use turbopack_core::{ - asset::AssetContentVc, - source_map::{SourceMapVc, Token}, -}; - -/// An individual stack frame, as parsed by the stacktrace-parser npm module. -/// -/// Line and column can be None if the frame is anonymous. -#[turbo_tasks::value(shared)] -#[derive(Debug)] -pub struct StackFrame { - pub file: String, - #[serde(rename = "lineNumber")] - pub line: Option<usize>, - pub column: Option<usize>, - #[serde(rename = "methodName")] - pub name: Option<String>, -} - -impl StackFrame { - pub fn get_pos(&self) -> Option<(usize, usize)> { - match (self.line, self.column) { - (Some(l), Some(c)) => Some((l, c)), - _ => None, - } - } -} - -/// Source Map Trace is a convenient wrapper to perform and consume a source map -/// trace's token. -#[turbo_tasks::value(shared)] -#[derive(Debug)] -pub struct SourceMapTrace { - map: SourceMapVc, - line: usize, - column: usize, - name: Option<String>, -} - -/// The result of performing a source map trace. -#[turbo_tasks::value(shared)] -#[derive(Debug)] -pub enum TraceResult { - NotFound, - Found(StackFrame), -} - -#[turbo_tasks::value_impl] -impl SourceMapTraceVc { - #[turbo_tasks::function] - pub async fn new(map: SourceMapVc, line: usize, column: usize, name: Option<String>) -> Self { - SourceMapTrace { - map, - line, - column, - name, - } - .cell() - } - - /// Traces the line/column through the source map into its original - /// position. - /// - /// This method is god-awful slow. We're getting the content - /// of a .map file, which means we're serializing all of the individual - /// sections into a string and concatenating, taking that and - /// deserializing into a DecodedMap, and then querying it. Besides being a - /// memory hog, it'd be so much faster if we could just directly access - /// the individual sections of the JS file's map without the - /// serialization. - #[turbo_tasks::function] - pub async fn trace(self) -> Result<TraceResultVc> { - let this = self.await?; - - let token = this - .map - .lookup_token(this.line.saturating_sub(1), this.column) - .await?; - let result = match &*token { - Some(Token::Original(t)) => TraceResult::Found(StackFrame { - file: t.original_file.clone(), - line: Some(t.original_line.saturating_add(1)), - column: Some(t.original_column), - name: t.name.clone().or_else(|| this.name.clone()), - }), - _ => TraceResult::NotFound, - }; - - Ok(result.cell()) - } - - /// Takes the trace and generates a (possibly valid) JSON asset content. - #[turbo_tasks::function] - pub async fn content(self) -> Result<AssetContentVc> { - let trace = self.trace().await?; - let result = match &*trace { - // purposefully invalid JSON (it can't be empty), so that the catch handler will default - // to the generated stack frame. - TraceResult::NotFound => "".to_string(), - TraceResult::Found(frame) => json!({ - "originalStackFrame": frame, - // TODO - "originalCodeFrame": null, - }) - .to_string(), - }; - Ok(File::from(result).into()) - } -} diff --git a/packages/next-swc/crates/next-core/src/util.rs b/packages/next-swc/crates/next-core/src/util.rs index 0b62982a011238..2496147979aa2e 100644 --- a/packages/next-swc/crates/next-core/src/util.rs +++ b/packages/next-swc/crates/next-core/src/util.rs @@ -1,8 +1,7 @@ use anyhow::{anyhow, bail, Result}; use turbo_tasks::ValueToString; use turbo_tasks_fs::FileSystemPathVc; - -use crate::path_regex::{PathRegexBuilder, PathRegexVc}; +use turbopack_node::path_regex::{PathRegexBuilder, PathRegexVc}; /// Converts a filename within the server root to a regular expression with /// named capture groups for every dynamic segment. From 32d4cad89a20c70f5a95578d3553c8d30ff32d5d Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Thu, 1 Dec 2022 09:25:52 -0500 Subject: [PATCH 248/672] Support basic next/image loading (vercel/turbo#2481) This implements basic support for serving the images requested by `next/image` and `next/future/image`. The big missing features are: - image width resizing (and thus blurry image placeholders) - image quality encoding - format re-encoding This required a lot more work than I expected, because we have to also override the `remotePatterns` to allow using `next/image` with remote images. The only way I found to do this was to override the `__NEXT_IMAGE_OPTS` env var, which is a special object value injected by webpack's `DefinePlugin` as if it were an `process.env` value. Fixes https://github.com/vercel/web-tooling-internal/issues/5 Porting from https://github.com/vercel/the-three-body/pull/212 Fixes WEB-150 Fixes WEB-2 --- packages/next-swc/crates/next-core/Cargo.toml | 1 + .../crates/next-core/src/app_source.rs | 5 +- packages/next-swc/crates/next-core/src/env.rs | 49 +++++++- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../next-core/src/next_client/context.rs | 4 +- .../crates/next-core/src/next_image/mod.rs | 110 ++++++++++++++++++ .../next-core/src/server_rendered_source.rs | 5 +- packages/next-swc/crates/next-dev/build.rs | 3 +- packages/next-swc/crates/next-dev/src/lib.rs | 53 ++++++--- .../crates/next-dev/test-harness/deferred.js | 8 ++ .../{tests => test-harness}/harness.js | 0 .../crates/next-dev/test-harness/package.json | 10 ++ .../crates/next-dev/tests/integration.rs | 34 +++--- .../next/image/basic/pages/index.js | 50 ++++++++ .../image/basic/public/triangle-black.png | Bin 0 -> 4289 bytes .../crates/next-dev/tests/package.json | 4 +- 16 files changed, 289 insertions(+), 48 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_image/mod.rs create mode 100644 packages/next-swc/crates/next-dev/test-harness/deferred.js rename packages/next-swc/crates/next-dev/{tests => test-harness}/harness.js (100%) create mode 100644 packages/next-swc/crates/next-dev/test-harness/package.json create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/basic/public/triangle-black.png diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 18efa9083fb9c6..465b09129030af 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -10,6 +10,7 @@ bench = false [dependencies] anyhow = "1.0.47" +indexmap = { workspace = true, features = ["serde"] } rand = "0.8.5" serde = "1.0.136" serde_json = "1.0.85" diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 4016c5f7d39783..8e175506034bc2 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -48,6 +48,7 @@ use crate::{ next_layout_entry_transition::NextLayoutEntryTransition, LayoutSegment, LayoutSegmentsVc, }, embed_js::{next_js_file, wrap_with_next_js_fs}, + env::env_for_js, fallback::get_fallback_page, next_client::{ context::{ @@ -252,8 +253,8 @@ pub async fn create_app_source( externals, ); - let server_runtime_entries = - vec![ProcessEnvAssetVc::new(project_root, env).as_ecmascript_chunk_placeable()]; + let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_root, env_for_js(env, false)) + .as_ecmascript_chunk_placeable()]; let fallback_page = get_fallback_page(project_root, server_root, env, browserslist_query); diff --git a/packages/next-swc/crates/next-core/src/env.rs b/packages/next-swc/crates/next-core/src/env.rs index 3e9b4fed1d74a7..3991939a6b4087 100644 --- a/packages/next-swc/crates/next-core/src/env.rs +++ b/packages/next-swc/crates/next-core/src/env.rs @@ -1,13 +1,18 @@ use anyhow::Result; -use turbo_tasks_env::{CommandLineProcessEnvVc, FilterProcessEnvVc, ProcessEnvVc}; +use indexmap::indexmap; +use serde_json::json; +use turbo_tasks_env::{ + CommandLineProcessEnvVc, CustomProcessEnvVc, EnvMapVc, FilterProcessEnvVc, ProcessEnvVc, +}; use turbo_tasks_fs::FileSystemPathVc; -use turbopack_env::TryDotenvProcessEnvVc; +use turbopack_env::{EmbeddableProcessEnvVc, TryDotenvProcessEnvVc}; /// Loads a series of dotenv files according to the precedence rules set by /// https://nextjs.org/docs/basic-features/environment-variables#environment-variable-load-order #[turbo_tasks::function] pub async fn load_env(project_path: FileSystemPathVc) -> Result<ProcessEnvVc> { let env = CommandLineProcessEnvVc::new().as_process_env(); + let node_env = env.read("NODE_ENV").await?; let node_env = node_env.as_deref().unwrap_or("development"); @@ -32,6 +37,42 @@ pub async fn load_env(project_path: FileSystemPathVc) -> Result<ProcessEnvVc> { Ok(env) } -pub fn filter_for_client(env: ProcessEnvVc) -> ProcessEnvVc { - FilterProcessEnvVc::new(env, "NEXT_PUBLIC_".to_string()).into() +/// Creates a ProcessEnvVc safe to use in JS, by stringifying and encoding as +/// regular JS strings. Setting `client` to true will additionally filter the +/// env to just the keys that are acceptable for the client to access. +/// +/// For now, it also injects overridden values as if they were real JS code, eg +/// an Object and not a String. +#[turbo_tasks::function] +pub fn env_for_js(env: ProcessEnvVc, client: bool) -> ProcessEnvVc { + let env = if client { + FilterProcessEnvVc::new(env, "NEXT_PUBLIC_".to_string()).into() + } else { + env + }; + let env = EmbeddableProcessEnvVc::new(env).into(); + + CustomProcessEnvVc::new( + env, + EnvMapVc::cell(indexmap! { + // We need to overload the __NEXT_IMAGE_OPTS to override the default remotePatterns field. + // This allows us to support loading from remote hostnames until we properly support reading + // the next.config.js file. + "__NEXT_IMAGE_OPTS".to_string() => json!({ + "deviceSizes": [640, 750, 828, 1080, 1200, 1920, 2048, 3840], + "imageSizes": [16, 32, 48, 64, 96, 128, 256, 384], + "path": "/_next/image", + "loader": "default", + "domains": [], + "disableStaticImages": false, + "minimumCacheTTL": 60, + "formats": ["image/webp"], + "dangerouslyAllowSVG": false, + "contentSecurityPolicy": "script-src 'none'; frame-src 'none'; sandbox;", + "remotePatterns": [{ "hostname": "**" }], + "unoptimized": false, + }).to_string() + }), + ) + .into() } diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 21cb2b690942a8..a3d7f5b201dfac 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -8,6 +8,7 @@ pub mod env; mod fallback; pub mod next_client; mod next_client_component; +pub mod next_image; mod next_import_map; pub mod next_server; pub mod react_refresh; diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 304ad101a830ca..5e9e02f18f6b83 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -25,7 +25,7 @@ use turbopack_env::ProcessEnvAssetVc; use crate::{ embed_js::attached_next_js_package_path, - env::filter_for_client, + env::env_for_js, next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, next_import_map::{ get_next_client_fallback_import_map, get_next_client_import_map, @@ -202,7 +202,7 @@ pub async fn get_client_runtime_entries( .as_request(); let mut runtime_entries = vec![RuntimeEntry::Ecmascript( - ProcessEnvAssetVc::new(project_root, filter_for_client(env)).into(), + ProcessEnvAssetVc::new(project_root, env_for_js(env, true)).into(), ) .cell()]; diff --git a/packages/next-swc/crates/next-core/src/next_image/mod.rs b/packages/next-swc/crates/next-core/src/next_image/mod.rs new file mode 100644 index 00000000000000..2e95511deb4d70 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_image/mod.rs @@ -0,0 +1,110 @@ +use std::collections::HashSet; + +use anyhow::Result; +use turbo_tasks::{primitives::StringVc, Value}; +use turbopack_core::introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc}; +use turbopack_dev_server::source::{ + query::QueryValue, ContentSource, ContentSourceContent, ContentSourceData, + ContentSourceDataFilter, ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, + ProxyResult, +}; + +/// Serves, resizes, optimizes, and re-encodes images to be used with +/// next/image. +#[turbo_tasks::value(shared)] +pub struct NextImageContentSource { + asset_source: ContentSourceVc, +} + +#[turbo_tasks::value_impl] +impl NextImageContentSourceVc { + #[turbo_tasks::function] + pub fn new(asset_source: ContentSourceVc) -> NextImageContentSourceVc { + NextImageContentSource { asset_source }.cell() + } +} + +#[turbo_tasks::value_impl] +impl ContentSource for NextImageContentSource { + #[turbo_tasks::function] + async fn get( + self_vc: NextImageContentSourceVc, + path: &str, + data: Value<ContentSourceData>, + ) -> Result<ContentSourceResultVc> { + let this = self_vc.await?; + + let query = match &data.query { + None => { + let queries = [ + "url".to_string(), + // TODO: support q and w queries. + ] + .iter() + .cloned() + .collect::<HashSet<_>>(); + + return Ok(ContentSourceResultVc::exact( + ContentSourceContent::NeedData { + source: self_vc.into(), + path: path.to_string(), + vary: ContentSourceDataVary { + url: true, + query: Some(ContentSourceDataFilter::Subset(queries)), + ..Default::default() + }, + } + .cell(), + )); + } + Some(query) => query, + }; + + let url = match query.get("url") { + Some(QueryValue::String(s)) => s, + _ => return Ok(ContentSourceResultVc::not_found()), + }; + + // TODO: consume the assets, resize and reduce quality, re-encode into next-gen + // formats. + if let Some(path) = url.strip_prefix('/') { + let asset = this.asset_source.get(path, Value::new(Default::default())); + // THERE'S A HUGE PERFORMANCE ISSUE IF THIS MISSES + let inner = asset.await?; + if matches!(&*inner.content.await?, ContentSourceContent::Static(..)) { + return Ok(asset); + } + } + + // TODO: This should be downloaded by the server, and resized, etc. + Ok(ContentSourceResultVc::exact( + ContentSourceContent::HttpProxy( + ProxyResult { + status: 302, + headers: vec!["Location".to_string(), url.clone()], + body: "".into(), + } + .cell(), + ) + .cell(), + )) + } +} + +#[turbo_tasks::value_impl] +impl Introspectable for NextImageContentSource { + #[turbo_tasks::function] + fn ty(&self) -> StringVc { + StringVc::cell("next image content source".to_string()) + } + + #[turbo_tasks::function] + fn details(&self) -> StringVc { + StringVc::cell("suports dynamic serving of any statically imported image".to_string()) + } + + #[turbo_tasks::function] + async fn children(&self) -> Result<IntrospectableChildrenVc> { + Ok(IntrospectableChildrenVc::cell(HashSet::new())) + } +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index d481f47d8d9be8..fcdc62fd49ae12 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -37,6 +37,7 @@ use turbopack_node::{ use crate::{ embed_js::{next_js_file, wrap_with_next_js_fs}, + env::env_for_js, fallback::get_fallback_page, next_client::{ context::{ @@ -110,8 +111,8 @@ pub async fn create_server_rendered_source( ) .into(); - let server_runtime_entries = - vec![ProcessEnvAssetVc::new(project_path, env).as_ecmascript_chunk_placeable()]; + let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_path, env_for_js(env, false)) + .as_ecmascript_chunk_placeable()]; let fallback_page = get_fallback_page(project_path, server_root, env, browserslist_query); diff --git a/packages/next-swc/crates/next-dev/build.rs b/packages/next-swc/crates/next-dev/build.rs index ae549614245fdf..ed76fbb01a206b 100644 --- a/packages/next-swc/crates/next-dev/build.rs +++ b/packages/next-swc/crates/next-dev/build.rs @@ -1,8 +1,9 @@ -use turbo_tasks_build::generate_register; +use turbo_tasks_build::{generate_register, rerun_if_glob}; use vergen::{vergen, Config}; fn main() { generate_register(); + rerun_if_glob("tests/integration/*/*", "tests/integration"); // Attempt to collect some build time env values but will skip if there are any // errors. diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index a8a66ad7c0a15e..587c470a1dcb21 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -18,7 +18,7 @@ use anyhow::{anyhow, Context, Result}; use devserver_options::DevServerOptions; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, - source_map::NextSourceMapTraceContentSourceVc, + next_image::NextImageContentSourceVc, source_map::NextSourceMapTraceContentSourceVc, }; use owo_colors::OwoColorize; use turbo_tasks::{ @@ -33,17 +33,23 @@ use turbopack_dev_server::{ fs::DevServerFileSystemVc, introspect::IntrospectionSource, source::{ - combined::CombinedContentSource, router::RouterContentSource, + combined::CombinedContentSourceVc, router::RouterContentSource, static_assets::StaticAssetsContentSourceVc, ContentSourceVc, }, DevServer, }; +#[derive(Clone)] +pub enum EntryRequest { + Relative(String), + Module(String, String), +} + pub struct NextDevServerBuilder { turbo_tasks: Arc<TurboTasks<MemoryBackend>>, project_dir: String, root_dir: String, - entry_requests: Vec<String>, + entry_requests: Vec<EntryRequest>, server_component_externals: Vec<String>, eager_compile: bool, hostname: Option<IpAddr>, @@ -80,7 +86,7 @@ impl NextDevServerBuilder { } } - pub fn entry_request(mut self, entry_asset_path: String) -> NextDevServerBuilder { + pub fn entry_request(mut self, entry_asset_path: EntryRequest) -> NextDevServerBuilder { self.entry_requests.push(entry_asset_path); self } @@ -135,7 +141,6 @@ impl NextDevServerBuilder { let project_dir = self.project_dir; let root_dir = self.root_dir; - let entry_requests = self.entry_requests; let server_component_externals = self.server_component_externals; let eager_compile = self.eager_compile; let show_all = self.show_all; @@ -147,6 +152,7 @@ impl NextDevServerBuilder { log_detail, log_level: self.log_level, }; + let entry_requests = Arc::new(self.entry_requests.clone()); let console_ui = Arc::new(ConsoleUi::new(log_options)); let console_ui_to_dev_server = console_ui.clone(); @@ -160,7 +166,7 @@ impl NextDevServerBuilder { source( root_dir.clone(), project_dir.clone(), - entry_requests.clone(), + entry_requests.clone().into(), eager_compile, turbo_tasks.clone().into(), console_ui.clone().into(), @@ -257,7 +263,7 @@ async fn output_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result<FileSys async fn source( root_dir: String, project_dir: String, - entry_requests: Vec<String>, + entry_requests: TransientInstance<Vec<EntryRequest>>, eager_compile: bool, turbo_tasks: TransientInstance<TurboTasks<MemoryBackend>>, console_ui: TransientInstance<ConsoleUi>, @@ -279,13 +285,19 @@ async fn source( let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let dev_server_root = dev_server_fs.root(); + let entry_requests = entry_requests + .iter() + .map(|r| match r { + EntryRequest::Relative(p) => RequestVc::relative(Value::new(p.clone().into()), false), + EntryRequest::Module(m, p) => { + RequestVc::module(m.clone(), Value::new(p.clone().into())) + } + }) + .collect(); let web_source = create_web_entry_source( project_path, - entry_requests - .iter() - .map(|a| RequestVc::relative(Value::new(a.to_string().into()), false)) - .collect(), + entry_requests, dev_server_root, env, eager_compile, @@ -313,16 +325,19 @@ async fn source( .into(); let static_source = StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into(); - let main_source = CombinedContentSource { - sources: vec![static_source, app_source, rendered_source, web_source], - } - .cell(); + let main_source = + CombinedContentSourceVc::new(vec![static_source, app_source, rendered_source, web_source]); let introspect = IntrospectionSource { roots: HashSet::from([main_source.into()]), } .cell() .into(); - let source_map_trace = NextSourceMapTraceContentSourceVc::new(main_source.into()).into(); + let main_source = main_source.into(); + let source_map_trace = NextSourceMapTraceContentSourceVc::new(main_source).into(); + let img_source = NextImageContentSourceVc::new( + CombinedContentSourceVc::new(vec![static_source, rendered_source]).into(), + ) + .into(); let source = RouterContentSource { routes: vec![ ("__turbopack__/".to_string(), introspect), @@ -331,8 +346,10 @@ async fn source( "__nextjs_original-stack-frame".to_string(), source_map_trace, ), + // TODO: Load path from next.config.js + ("_next/image".to_string(), img_source), ], - fallback: main_source.into(), + fallback: main_source, } .cell() .into(); @@ -389,7 +406,7 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { #[allow(unused_mut)] let mut server = NextDevServerBuilder::new(tt, dir, root_dir) - .entry_request("src/index".into()) + .entry_request(EntryRequest::Relative("src/index".into())) .eager_compile(options.eager_compile) .hostname(options.hostname) .port(options.port) diff --git a/packages/next-swc/crates/next-dev/test-harness/deferred.js b/packages/next-swc/crates/next-dev/test-harness/deferred.js new file mode 100644 index 00000000000000..3d55c043917b37 --- /dev/null +++ b/packages/next-swc/crates/next-dev/test-harness/deferred.js @@ -0,0 +1,8 @@ +export class Deferred { + constructor() { + this.promise = new Promise((res, rej) => { + this.resolve = res; + this.rej = rej; + }); + } +} diff --git a/packages/next-swc/crates/next-dev/tests/harness.js b/packages/next-swc/crates/next-dev/test-harness/harness.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/harness.js rename to packages/next-swc/crates/next-dev/test-harness/harness.js diff --git a/packages/next-swc/crates/next-dev/test-harness/package.json b/packages/next-swc/crates/next-dev/test-harness/package.json new file mode 100644 index 00000000000000..9266a3aa992512 --- /dev/null +++ b/packages/next-swc/crates/next-dev/test-harness/package.json @@ -0,0 +1,10 @@ +{ + "name": "@turbo/pack-test-harness", + "private": true, + "version": "0.0.1", + "main": "./harness.js", + "dependencies": { + "expect": "^24.5.0", + "jest-circus-browser": "^1.0.7" + } +} diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index ee2de8f695ede0..bc6ddac98b50f1 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -15,7 +15,7 @@ use chromiumoxide::{ }; use futures::StreamExt; use lazy_static::lazy_static; -use next_dev::{register, NextDevServerBuilder}; +use next_dev::{register, EntryRequest, NextDevServerBuilder}; use owo_colors::OwoColorize; use serde::Deserialize; use test_generator::test_resources; @@ -118,26 +118,25 @@ async fn run_test(resource: &str) -> JestRunResult { path.to_str().unwrap() ); - let test_entry = path.join("index.js"); - assert!( - test_entry.exists(), - "Test entry {} must exist.", - test_entry.to_str().unwrap() - ); + // Count the number of dirs _under_ crates/next-dev/tests + let test_entry = Path::new(resource).join("index.js"); let package_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let workspace_root = package_root.parent().unwrap().parent().unwrap(); - let project_dir = workspace_root.join("crates/next-dev/tests"); - let workspace_root = workspace_root.to_string_lossy().to_string(); + let project_dir = workspace_root.join(resource); let requested_addr = get_free_local_addr().unwrap(); + let server = NextDevServerBuilder::new( TurboTasks::new(MemoryBackend::new()), - project_dir.to_string_lossy().to_string(), - workspace_root, - ) - .entry_request("harness.js".into()) - .entry_request( - sys_to_unix(test_entry.strip_prefix("tests").unwrap().to_str().unwrap()).to_string(), + sys_to_unix(&project_dir.to_string_lossy()).to_string(), + sys_to_unix(&workspace_root.to_string_lossy()).to_string(), ) + .entry_request(EntryRequest::Module( + "@turbo/pack-test-harness".to_string(), + "".to_string(), + )) + .entry_request(EntryRequest::Relative( + sys_to_unix(test_entry.strip_prefix(resource).unwrap().to_str().unwrap()).to_string(), + )) .eager_compile(false) .hostname(requested_addr.ip()) .port(requested_addr.port()) @@ -152,7 +151,7 @@ async fn run_test(resource: &str) -> JestRunResult { ); tokio::select! { - r = run_browser(server.addr) => r.unwrap(), + r = run_browser(server.addr) => r.expect("error while running browser"), _ = server.future => panic!("Never resolves"), } } @@ -223,7 +222,8 @@ async fn run_test_browser(addr: SocketAddr) -> Result<JestRunResult, Box<dyn std let page = browser.new_page(format!("http://{}", addr)).await?; page.wait_for_navigation().await?; - Ok(page.evaluate("__jest__.run()").await?.into_value()?) + let value = page.evaluate("globalThis.waitForTests?.() ?? __jest__.run()"); + Ok(value.await?.into_value()?) } fn get_free_local_addr() -> Result<SocketAddr, std::io::Error> { diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js new file mode 100644 index 00000000000000..11d73983458476 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js @@ -0,0 +1,50 @@ +import Image from "next/image"; +import img from "../public/triangle-black.png"; +import { useEffect } from "react"; + +import { Deferred } from "@turbo/pack-test-harness/deferred"; + +let testResult = new Deferred(); + +export default function Home() { + useEffect(() => { + // Only run on client + import("@turbo/pack-test-harness").then(runTests); + }); + + return [ + <Image + id="imported" + alt="test imported image" + src={img} + width="100" + height="100" + />, + <Image + id="local" + alt="test src image" + src="/triangle-black.png" + width="100" + height="100" + />, + ]; +} + +globalThis.waitForTests = function () { + return testResult.promise; +}; + +function runTests() { + console.log(document.querySelectorAll("img")); + it("it should link to imported image", function () { + const img = document.querySelector("#imported"); + expect(img.src).toContain(encodeURIComponent("_next/static/assets")); + }); + + it("it should link to local src image", function () { + const img = document.querySelector("#local"); + expect(img.src).toContain("triangle-black"); + }); + + testResult.resolve(__jest__.run()); +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/public/triangle-black.png b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/public/triangle-black.png new file mode 100644 index 0000000000000000000000000000000000000000..351730591885f2b53625436ec159381ba160f355 GIT binary patch literal 4289 zcmV;y5I*mTP)<h;3K|Lk000e1NJLTq0049V003kN1^@s6S4<SV00009a7bBm0064S z0064S0f#`(Qvd(}8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H15Kc)% zK~#90<(+$!Tve6Ef4jTWfuu<Yfy5-8_q+2V353KD!b1p?Fas=zMA0P^P!vRzg(EI; zk^w>l0mEZN9sR?#93H|9Gm1J(5QTx6h0YKO2nIz3G6aY~2op%iW6vMosdS}syXsc; zeN@$aYn|0qeeSvY+`H@Sv+q9NKG)oxW`~(A1KizzoOfT+MqAz;NE>F>4on7in^~*7 z@5#GQX~LR)gqqpWz#+ivz=&oar7d}PAWfLrK%hVHH1H}g&di49+pBcZ)Faf)<^nr_ zmw;B_IpAO2{eoOOmLi%~p=LG>nc6O3CSbs4fW5$ccmGw6-AfHksZcXB;8fs6U;xk_ zs``Y#Q-RyO2`|1`z1;D@W?+-Mzg1jeW<!A0z*E34GVfW+Xga6J%=!Z-18*QxTZ+lR zhk?G~*rr0$DHP~LBkz5{p=LI`P+?{Zft|om;2mI04*g3NO{GvXI}8{NY<Krx0-Jz| zX4YzEt-$TTiNPUy9_S2hng&g!P~bXX1A5*Z1k3<l0Hy#Jh3{W7vk|~w0_%Y_IrTLa zG>w;QW=8@`fZqVyfVa@2iUY%uDK3o0^}x%>^d1G=>+a8I-RCsW6bcRI^a)^%yMMpR zwo6d(;n8M@^EQjg{Uq{eZ!oidaT}T0LBJm16=Z@N9u2S1FjuY)Uq=F$SJ8Yd3JbOY zFNAY7G#Xx^z*WHEMc=P5v(c3r1?5c!UUv8204D)|mrfV6LqpG@X4VD#n(mNZ0e8Cl zhby$b6!<C74~^32fDT}`yFZmecQZkwhyIoW4@dm}a5J0i?i-^Tnb`zj8So77=Ww1v zu>LF*7Hmi~><BfpNx*P-|3yUI2;gpDajEBOW-aLP=5cp_Bckmsz|Y<NzEnD%G8%FY z4c_VDKz}nkBI1zifrY@zh`K2#{I?|Hyi<|Kd}EN&aA-({0uzD0z!2oA?t_`l0FD9v z0IVzyz=ubgp};QSH8blhIq%odd^{GoEVbUJ33qR(0t^N|Q1pEk&=o$n0RIg158pe1 z<BE>G5jZM*?vF-kOZa{|iYgV#c3@QA*IR9A#1T3Rc+t$}n%N=Ye-i_{Zx--xzzJcI zdk9)_nG_yVHUh&#T^9-{EC_ACS|X<(a7_l+lPDU>DKfJKNMS3G$=!y+c5_hZ?@%<d zh9H(-fw^!ba4j$a#c;Qwxb8u~Eoc>HRfI@KBmB|SE-GO(j6#EVdOPqbci)?#%w@oj zvXa?bG?K~vYv2>Wc^S%_gGTg>3}yBT4WZC5S6&^yt_^(Kv}JanIk^>>XJ!M^mYD<^ zLZQIl0>i@RA;6b1ka;2S?}%*n2+$B*-nv()nT-c7Df#!MAySm4%r(FYcYg`dKIfR( zu<|YQN8LL`W_CYvOiFRTyQi{-X=XnJP6OUW5vP$T=6jI4Ka_^dq)^uiHM0)@50p7% zsk{FqVVTo`N$AlA;7zm$elQ9~n7fzjQ?966g_>C#S{j>H=CI!aGu?exLNfaRi-5g7 z1pU8_Mr>j-lSVzyp_foznV>-X#R<wh7V&k@3u%b^U}m$?qf^o{6GdH)P%|5h7M$a7 zX14;9+<i+gWe!Boo3EoE(k|c!?(QK}cskt+=>tMtuVkiydL5zH5>J_+aNpGxkE)D? zz;t(i7KIlNMu7#w-%-F%-2EPuYVkJ-$V?n{H$nry_P@{reO&AX=DGWS*C=x&;_hw- zb|cgJ9bi82V_+`g@=ikDZX06gZwQYyb%VN6XfSOn*`M?k7cT;Ld6gFwWG+P^zTv?C z04JhUiA~7EZ4Gss!}q<&x^<$*r~0{xd9UA<taVODoSwES+qEHH(9t!>{19T>_o+eV z2H-<^-?!pYH*=_&^+l|^4Zyf6o6iBB1O|um#Fcq4uokV2URb5fi;)xc)p|-xtQ&=* z@LDHQ>Y$><>#_*hV-r#O;JawPi;FAJTnKQLnZ+{oLFSjk*Adi{gOs<42<B@f@JC=^ z_`U>K5VP&qfzOA}hafJ|n3yuRvp?<Rwkl*6w|gg!%uMcO-W>=x==<TuT!%*5N@NBP zuh4E1a%fHf1|hbe19!)ed3T9Y9C^4iE3_*-qn5U<C^L(ayU7jI$w9z_=w>ZP;kUlX z441<gG|CM4EA%6H5I8KHH;&BW@^j$q3NpV&G(r7?W_Emqw&^41ky&_58Q4Spt-x75 z)GY^Y?V)ZkQgBN|T?=p~FtUfX3(>YWQFUi?;K(d4zXn=!y{9=VbSffl9T`#A1-yqc zu=|zN9faoG-N1~9w#TDKpfe-t<|FU)yokDKC~4^ov{Y6q^A8mi>cEA0-qYMnZXi96 z1Qr0p%xqN2A)iA@M7z<hCB^tWGPkY3x{~wGL}9vPfiDCqNujO-F(1YOUkt|<<Fj<H zy&h9icR3}b?jCS$uKPCRI6Bu60s&~gJeO|L^LP|+FC6<3U`Y5p0{CC{9~EbWx)!uB zT_9SI1r`;ZXAv+qeC`15CzwbyI_DG}dl!Ld9b~>u<<VIvH~qgFp&=jTSzt^Ez0Cj~ z0~UtBz)+yw%sR|$emJ%eY`7jRG#8_gi*h{hCtzwg?@VB)nT-euOoM=#q3(-lG_DLX zry*zR2s4|Ew#Jzr&VL>H0mQ{6VWB*8<PysbxtY%(#k`G_)sD!{t56KJ9XU;_fbSs& z!Cu78wTRPRh2pTUq7m-MY~O$w@`Uz>p(V2Kp?UE&6!mEf^&pGUfz18(aBP&!a(ECp z#WTLanJd)HCIYzo?=lsfG0bcQ+C}^BOyy>&&_MAx7mcEa+<j+e!ZSpO5kHHZwkhtu zJuBH+&!LNuS^OCCD4P{uKr!M@s@ue)*T`&y22Sf4z#V8lIth)^H#6x#MhH2lzopx8 zdl#7M?k{8^Kg$vN6+~X{gA}?I?c&vJxPkq>@PpB{XM#*dXxJ+Jm*@xd_sDDPK%V6@ z?*3xxoyY)Y_I}_|qCMip?*2&XeMnoO;hFCYL=gc!3cQ7W#XAt;>YG`+_emq99zIUb zR%bm5q@=q2To&8foQQZhFT4BZ;);+%vJTBN-_4*eY2tj!Pay?f@3&L!Matp54wS() z8aN@M{)Z?4@Cq;>uW(rc*Es+Y$SQ>dUj+_r<j~(zl=6Nku-(iS6)HmB%4y;2P!x)5 zRIEY^^OZ0JxH8qAr1-1tL~ET>!uQXjcx_uKPqY88cPB70@6lGnbxuIOK-|Fnd%)yI z9HEnuNgZQ)o6!>}pfHo@yp?tocyBb^jAFlW(Fbj>lL}Jta?NZWQc!;s2p<;y?m=Ge zQOFD*&=kG-=-I?Ol>*G{WV8WfEm-C$yoW7ug@!c1^}t$pzoW{w^U)gSJ?_3c(T*jI z5SM-mS)y9-dz4F)XgoU&lY22*N4&lo0&-w5oC-Wd^!rxo4WFTQWrF73#M2TJ9ibr& z@CxL{gR-^$C1%^xkwPCuYn1EV{m+SYE<u>y&a{!}X`>o!Lk`j_6_1RIggw5cguV69 z)@o-_fm<7n9mW1c>jl8Vygk@5{rv~xd$pCyx9ZZ%4cmfm1tx@*mG`6g?a^f$3O6Cr z*Oh^uG8XVSTa9OpqD=0jaK4!(wn&lW99r0H;yB<O^c*?^z|5xf)F^Oo1|rHv7xI9& zpjC<k_Oz`7tfRWz)k<gqZVoZ;-XkFsG#&A0qUuJXk$OOiAi6P+(?ebeTA5j%w}~z4 z&kB+=wWZ~px-hwcZZQ|J>q@z`pi%Z^L~t&}CxLm0Rabi6QOM&h$jB9;4{5Gz-jGCE zViG3zql9z@N;ZfJbjY`n`J7#xB53=+ZzU=(<VchhG!!{Wd80rpNeju)ReEWHhEZf{ zLx;{PGN-2jhlKCrfn$q~y_FvFLeShhx9HeYfMGeB+D;B6cc)R_0Y>L(a>oO2n%T7Q zY<4AZQwS2wMX3x6!-PKz*lT8;ruVIsW=zilE(nC_3FuWFLrm||-by@gIW3gZO435F z&3es&g|IPG7h>^sAVy!oonMPqAf5-lg%*DYBBsJf#8Nmp;<Q^(;JzOk-P_Q6S$3c- z?H{@OA8YDxji^8?Nehd;R=P@!Ca4woN2=W1qL*f`1wGJbmaZ3M{)+TXZE1O;*6XbG zLN5w}Kb7Il{X~%Y@f>94QEIx*s!eY2PM<@23B7@`#9puJBvm5pCcP1{0=5L1TQiiI z2VO&Q-m0#%7N=-6-5Wy{?*@`4=Ax}@4nxk<><nbCB0pt9jdYc&MrhcZ;7Rs>8{lq~ zSDDHS;6i|5I(kw1!)CS^#d;s|l=!@+m)$*0bxedbunT3VN4}IV3e}F#!mFf;(H8!n z7QTU;u+Fe8c^mScN2DmTT3Sh3=!2fuV<Ywm4eOQV);3Rf_a9UvJci6daDEdaSM5g1 z?Tgl2cewldgk>&6ncek-_;i(+-d;O$5XyOFzX$pz=wY^_<layBP`?~l474XGvkyu% z%FDCusr)YPy^U*fKZlma%3(ZkY0UG*!8G8T=q-Y!Zy+3t$k{v5x@%JCEv+Oi#HOoM zG`WF-xe-NrD&cM9YHzN1WO<o`kth2aGO=C29q#*fmtGR;_5ep9x=ODeof4##q=i^? zl{h2xE5uVKXs^9BF^?^WqtV7t8_*^g>(HtW=<#JVu+iP0M4`ka;=F69UuA-PhN~(b zRbft<gGNC$_I?lAUAoqJY%E$Xy8v;L3ac`&pw*pw(CWt`WR_>4ox#TSLgsAbaOFK$ z#<{mg)f6cTrtJ~5fm5~kPek&nDhw55o{a+jlj&X$Eo8}U4F7*DeBX_BE@?$dzPDPL zLGHtdI@1XF53~#!eVt`~wI88(zov6*7%3m43XiU+T_IQIqczA(lU9;e>5;C|(?#|} zd+hZ_=q8|}iW}R3My3OoRjHKALc7gWk(P+oAOBPb3aYleMA$7Yu0pR#NbuEF+}yQA z?cM_37qi_F=yg_ww%1f4b9Egkr`EDMmO>Hfxpb%JTFbkHz4a>G*m2?5;<m8}$Y=q* zxZMt7q$QFatt71yNmq%w(0daWd{2y<dtXGmiXI&zl0|u^{}e;!U3H+8-j+MdDim$? zord6(%iP!#%d~rp5d4T}XXp(~5A;xa+-e+ca=f<=6p}<)9H~&``ahYH(5LB{XuY9A z+enWNd8fDcP&Wj<t2;_&UbK?5%6f|ED#aIiQObf3psN6%j?wM_j}Cd^=b!-nn27T( zMZtpOBkJ;`m84ZZzMn$TKC)X<7Wz6cxah_XLhlia({^=<QsyCs;c=x(Lt(*l5v%YN ziXNSazgtP8m3_Ob6fX3Zj0E3YbaQX3qTN1^4#jToD>~0Hggxt#2|tr=a`z;POg74L z%lqc1Rc;K|$W*j=oQ2R`h!x*O^t(^Wl{-U+3-5SYia16qfDfV|!D(ny$YYVybSfIf zqtFu6&N{g9X_fbY$%fvQnPuAE&rl%Xq$=AviU<|xE*t3%3|x*9o6Zma+kt`;6X=cv jT?+g~Z#v!pc;Np4bU(8uEXQNW00000NkvXXu0mjf+-xTf literal 0 HcmV?d00001 diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 0d75d04132eeca..3c199f47d134cf 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -1,8 +1,8 @@ { "private": true, "devDependencies": { - "expect": "^24.5.0", - "jest-circus-browser": "^1.0.7", + "@turbo/pack-test-harness": "*", + "next": "13.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-test-renderer": "^18.2.0", From b1eb3ea7a68a57c1c897a1a0f17b474d2369354f Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Thu, 1 Dec 2022 21:02:33 +0100 Subject: [PATCH 249/672] simplify `next-binding` (vercel/turbo#2899) --- .../next-swc/crates/next-binding/Cargo.toml | 4 +- .../next-swc/crates/next-binding/src/lib.rs | 43 ++++++------------- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/packages/next-swc/crates/next-binding/Cargo.toml b/packages/next-swc/crates/next-binding/Cargo.toml index 20a5beebb5b42f..0b51d485c5e32e 100644 --- a/packages/next-swc/crates/next-binding/Cargo.toml +++ b/packages/next-swc/crates/next-binding/Cargo.toml @@ -74,8 +74,8 @@ __swc_core_binding_wasm_plugin = ["swc_core/plugin_transform_host_js"] __swc_core_testing_transform = ["swc_core/testing_transform"] __turbo = [] -__feature_next_dev_server = ["__turbo", "next-dev/serializable"] -__feature_node_file_trace = ["__turbo", "node-file-trace/node-api"] +__turbo_next_dev_server = ["__turbo", "next-dev/serializable"] +__turbo_node_file_trace = ["__turbo", "node-file-trace/node-api"] __features = [] __feature_mdx_rs = ["__features", "mdxjs/serializable"] diff --git a/packages/next-swc/crates/next-binding/src/lib.rs b/packages/next-swc/crates/next-binding/src/lib.rs index 3c41271cdce504..03b0741db72ac6 100644 --- a/packages/next-swc/crates/next-binding/src/lib.rs +++ b/packages/next-swc/crates/next-binding/src/lib.rs @@ -1,53 +1,34 @@ #[cfg(feature = "__swc")] pub mod swc { #[cfg(feature = "__swc_core")] - pub mod core { - pub use swc_core::*; - } + pub use swc_core as core; #[cfg(feature = "__swc_custom_transform")] pub mod custom_transform { + #[cfg(feature = "__swc_transform_modularize_imports")] + pub use modularize_imports; #[cfg(feature = "__swc_transform_styled_components")] - pub mod styled_components { - pub use styled_components::*; - } + pub use styled_components; #[cfg(feature = "__swc_transform_styled_jsx")] - pub mod styled_jsx { - pub use styled_jsx::*; - } + pub use styled_jsx; #[cfg(feature = "__swc_transform_emotion")] - pub mod emotion { - pub use swc_emotion::*; - } - #[cfg(feature = "__swc_transform_modularize_imports")] - pub mod modularize_imports { - pub use modularize_imports::*; - } + pub use swc_emotion as emotion; } #[cfg(feature = "testing")] - pub mod testing { - pub use testing::*; - } + pub use testing; } #[cfg(feature = "__turbo")] pub mod turbo { - #[cfg(feature = "__feature_next_dev_server")] - pub mod dev_server { - pub use next_dev::*; - } - - #[cfg(feature = "__feature_node_file_trace")] - pub mod node_file_trace { - pub use node_file_trace::*; - } + #[cfg(feature = "__turbo_next_dev_server")] + pub use next_dev; + #[cfg(feature = "__turbo_node_file_trace")] + pub use node_file_trace; } #[cfg(feature = "__features")] pub mod features { #[cfg(feature = "__feature_mdx_rs")] - pub mod mdx { - pub use mdxjs::*; - } + pub use mdxjs; } From 122983cf3965ca6c99ef9c3a0d046db840e93645 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Fri, 2 Dec 2022 18:27:02 +0100 Subject: [PATCH 250/672] fix dynamic paths (vercel/turbo#2884) --- .../js/src/entry/server-renderer.tsx | 3 +++ .../crates/next-core/src/app_source.rs | 18 +++++++++------ .../next-core/src/server_rendered_source.rs | 10 +++++--- .../next-swc/crates/next-core/src/util.rs | 23 +++++++++++++++---- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 8498c532136344..4842c7669e15e9 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -130,6 +130,9 @@ async function runOperation( }, }; + if ("getStaticPaths" in otherExports) { + renderOpts.getStaticPaths = otherExports.getStaticPaths; + } if ("getStaticProps" in otherExports) { renderOpts.getStaticProps = otherExports.getStaticProps; } diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 8e175506034bc2..2d97ba3a6a2643 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -3,7 +3,7 @@ use std::{ io::Write, }; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; use turbo_tasks::{ primitives::{StringVc, StringsVc}, TryJoinIterExt, Value, ValueToString, @@ -66,7 +66,7 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - util::regular_expression_for_path, + util::{pathname_for_path, regular_expression_for_path}, }; #[turbo_tasks::function] @@ -315,12 +315,12 @@ async fn create_app_source_for_directory( let layout = files.get("layout"); + // If a page exists but no layout exists, create a basic root layout + // in `app/layout.js` or `app/layout.tsx`. + // // TODO: Use let Some(page_file) = page in expression below when // https://rust-lang.github.io/rfcs/2497-if-let-chains.html lands - if page.is_some() && layout.is_none() && target == server_root { - // If a page exists but no layout exists, create a basic root layout - // in `app/layout.js` or `app/layout.tsx`. - let page_file = page.context("page must not be none")?; + if let (Some(page_file), None, true) = (page, layout, target == server_root) { // Use the extension to determine if the page file is TypeScript. // TODO: Use the presence of a tsconfig.json instead, like Next.js // stable does. @@ -358,10 +358,14 @@ async fn create_app_source_for_directory( list.push(LayoutSegment { files, target }.cell()); layouts = LayoutSegmentsVc::cell(list); if let Some(page_path) = page { + let pathname = pathname_for_path(server_root, target, false); + let path_regex = regular_expression_for_path(server_root, target, false); + sources.push(create_node_rendered_source( specificity, server_root, - regular_expression_for_path(server_root, target, false), + pathname, + path_regex, AppRenderer { context_ssr, context, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index fcdc62fd49ae12..c0dd11ae6e1120 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -51,7 +51,7 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, - util::regular_expression_for_path, + util::{pathname_for_path, regular_expression_for_path}, }; /// Create a content source serving the `pages` or `src/pages` directory as @@ -166,11 +166,14 @@ async fn create_server_rendered_source_for_file( ) .build(); + let pathname = pathname_for_path(server_root, server_path, true); + let path_regex = regular_expression_for_path(server_root, server_path, true); + Ok(if *is_api_path.await? { create_node_api_source( specificity, server_root, - regular_expression_for_path(server_root, server_path, true), + path_regex, SsrEntry { context, entry_asset, @@ -186,7 +189,8 @@ async fn create_server_rendered_source_for_file( create_node_rendered_source( specificity, server_root, - regular_expression_for_path(server_root, server_path, true), + pathname, + path_regex, SsrEntry { context, entry_asset, diff --git a/packages/next-swc/crates/next-core/src/util.rs b/packages/next-swc/crates/next-core/src/util.rs index 2496147979aa2e..3771ae455223f2 100644 --- a/packages/next-swc/crates/next-core/src/util.rs +++ b/packages/next-swc/crates/next-core/src/util.rs @@ -1,16 +1,15 @@ use anyhow::{anyhow, bail, Result}; -use turbo_tasks::ValueToString; +use turbo_tasks::{primitives::StringVc, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; use turbopack_node::path_regex::{PathRegexBuilder, PathRegexVc}; -/// Converts a filename within the server root to a regular expression with -/// named capture groups for every dynamic segment. +/// Converts a filename within the server root into a next pathname. #[turbo_tasks::function] -pub async fn regular_expression_for_path( +pub async fn pathname_for_path( server_root: FileSystemPathVc, server_path: FileSystemPathVc, has_extension: bool, -) -> Result<PathRegexVc> { +) -> Result<StringVc> { let server_path_value = &*server_path.await?; let path = if let Some(path) = server_root.await?.get_path_to(server_path_value) { path @@ -33,6 +32,20 @@ pub async fn regular_expression_for_path( } else { path.strip_suffix("/index").unwrap_or(path) }; + + Ok(StringVc::cell(path.to_string())) +} + +/// Converts a filename within the server root into a regular expression with +/// named capture groups for every dynamic segment. +#[turbo_tasks::function] +pub async fn regular_expression_for_path( + server_root: FileSystemPathVc, + server_path: FileSystemPathVc, + has_extension: bool, +) -> Result<PathRegexVc> { + let path = pathname_for_path(server_root, server_path, has_extension).await?; + let mut path_regex = PathRegexBuilder::new(); for segment in path.split('/') { if let Some(segment) = segment.strip_prefix('[') { From 45079f3afd5e70ab8a01ac913141b4e6c6baa310 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Dec 2022 08:54:50 +0000 Subject: [PATCH 251/672] chore(deps): update rust crate futures to 0.3.25 (vercel/turbo#2915) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [futures](https://rust-lang.github.io/futures-rs) ([source](https://togithub.com/rust-lang/futures-rs)) | dev-dependencies | patch | `0.3.21` -> `0.3.25` | | [futures](https://rust-lang.github.io/futures-rs) ([source](https://togithub.com/rust-lang/futures-rs)) | dependencies | patch | `0.3.21` -> `0.3.25` | | [futures](https://rust-lang.github.io/futures-rs) ([source](https://togithub.com/rust-lang/futures-rs)) | dependencies | patch | `0.3.24` -> `0.3.25` | --- ### ⚠ Dependency Lookup Warnings ⚠ Warnings were logged while processing this repo. Please check the Dependency Dashboard for more information. --- ### Release Notes <details> <summary>rust-lang/futures-rs</summary> ### [`v0.3.25`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0325---2022-10-20) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.24...0.3.25) - Fix soundness issue in `join!` and `try_join!` macros ([#&vercel/turbo#8203;2649](https://togithub.com/rust-lang/futures-rs/issues/2649)) - Implement `Clone` for `sink::Drain` ([#&vercel/turbo#8203;2650](https://togithub.com/rust-lang/futures-rs/issues/2650)) ### [`v0.3.24`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0324---2022-08-29) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.23...0.3.24) - Fix incorrect termination of `select_with_strategy` streams ([#&vercel/turbo#8203;2635](https://togithub.com/rust-lang/futures-rs/issues/2635)) ### [`v0.3.23`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0323---2022-08-14) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.22...0.3.23) - Work around MSRV increase due to a cargo bug. ### [`v0.3.22`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0322---2022-08-14) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.21...0.3.22) - Fix `Sync` impl of `BiLockGuard` ([#&vercel/turbo#8203;2570](https://togithub.com/rust-lang/futures-rs/issues/2570)) - Fix partial iteration in `FuturesUnordered` ([#&vercel/turbo#8203;2574](https://togithub.com/rust-lang/futures-rs/issues/2574)) - Fix false detection of inner panics in `Shared` ([#&vercel/turbo#8203;2576](https://togithub.com/rust-lang/futures-rs/issues/2576)) - Add `Mutex::lock_owned` and `Mutex::try_lock_owned` ([#&vercel/turbo#8203;2571](https://togithub.com/rust-lang/futures-rs/issues/2571)) - Add `io::copy_buf_abortable` ([#&vercel/turbo#8203;2507](https://togithub.com/rust-lang/futures-rs/issues/2507)) - Remove `Unpin` bound from `TryStreamExt::into_async_read` ([#&vercel/turbo#8203;2599](https://togithub.com/rust-lang/futures-rs/issues/2599)) - Make `run_until_stalled` handle self-waking futures ([#&vercel/turbo#8203;2593](https://togithub.com/rust-lang/futures-rs/issues/2593)) - Use `FuturesOrdered` in `try_join_all` ([#&vercel/turbo#8203;2556](https://togithub.com/rust-lang/futures-rs/issues/2556)) - Fix orderings in `LocalPool` waker ([#&vercel/turbo#8203;2608](https://togithub.com/rust-lang/futures-rs/issues/2608)) - Fix `stream::Chunk` adapters size hints ([#&vercel/turbo#8203;2611](https://togithub.com/rust-lang/futures-rs/issues/2611)) - Add `push_front` and `push_back` to `FuturesOrdered` ([#&vercel/turbo#8203;2591](https://togithub.com/rust-lang/futures-rs/issues/2591)) - Deprecate `FuturesOrdered::push` in favor of `FuturesOrdered::push_back` ([#&vercel/turbo#8203;2591](https://togithub.com/rust-lang/futures-rs/issues/2591)) - Performance improvements ([#&vercel/turbo#8203;2583](https://togithub.com/rust-lang/futures-rs/issues/2583), [#&vercel/turbo#8203;2626](https://togithub.com/rust-lang/futures-rs/issues/2626)) - Documentation improvements ([#&vercel/turbo#8203;2579](https://togithub.com/rust-lang/futures-rs/issues/2579), [#&vercel/turbo#8203;2604](https://togithub.com/rust-lang/futures-rs/issues/2604), [#&vercel/turbo#8203;2613](https://togithub.com/rust-lang/futures-rs/issues/2613)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - "after 10pm every weekday,before 5am every weekday,every weekend" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/vercel/turbo). --- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 29d95a60d627e1..2468d2e2d797ec 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -33,7 +33,7 @@ profile = [] anyhow = "1.0.47" clap = { version = "4.0.18", features = ["derive", "env"] } console-subscriber = { version = "0.1.8", optional = true } -futures = "0.3.21" +futures = "0.3.25" mime = "0.3.16" next-core = { path = "../next-core" } owo-colors = "3" From 4d60d684e6bf6f9752e9125c84f3971058ce5db7 Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Sat, 3 Dec 2022 22:11:10 +0100 Subject: [PATCH 252/672] update chromiumoxide (vercel/turbo#2916) updating in hope that this fixes the random errors in test runs --- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 2468d2e2d797ec..b930974a014721 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -53,7 +53,7 @@ url = "2.3.0" webbrowser = "0.7.1" [dev-dependencies] -chromiumoxide = { version = "0.3.5", features = [ +chromiumoxide = { version = "0.4.0", features = [ "tokio-runtime", ], default-features = false } criterion = { version = "0.3.5", features = ["async_tokio"] } From 03d6610412d6bb8260fc40fc7b5857200dcf2585 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Mon, 5 Dec 2022 18:30:28 +0100 Subject: [PATCH 253/672] support `_devPageManifest.json` (vercel/turbo#2885) --- packages/next-swc/crates/next-core/Cargo.toml | 1 + .../crates/next-core/js/src/dev/hmr-client.ts | 2 +- .../next-core/js/src/entry/next-hydrate.tsx | 13 ++- .../js/src/entry/server-renderer.tsx | 2 +- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../next-swc/crates/next-core/src/manifest.rs | 82 +++++++++++++++++++ .../next-core/src/server_rendered_source.rs | 1 + packages/next-swc/crates/next-dev/src/lib.rs | 17 +++- 8 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/manifest.rs diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 465b09129030af..327af9d4b2340e 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -11,6 +11,7 @@ bench = false [dependencies] anyhow = "1.0.47" indexmap = { workspace = true, features = ["serde"] } +mime = "0.3.16" rand = "0.8.5" serde = "1.0.136" serde_json = "1.0.85" diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 74c00cdb353775..4b9a5aa539f65a 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -300,7 +300,7 @@ function triggerUpdate(msg: ServerMessage) { // They must be reloaded here instead. function subscribeToInitialCssChunksUpdates(assetPrefix: string) { const initialCssChunkLinks: NodeListOf<HTMLLinkElement> = - document.head.querySelectorAll("link"); + document.head.querySelectorAll(`link[rel="stylesheet"]`); const cssChunkPrefix = `${assetPrefix}/`; initialCssChunkLinks.forEach((link) => { const href = link.href; diff --git a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx index c5f579540f74c8..d22b4ad4f1a866 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx @@ -20,8 +20,19 @@ import * as page from "."; assetPrefix, }); + const pagePath = window.__NEXT_DATA__.page; + window.__BUILD_MANIFEST = { + [pagePath]: [], + __rewrites: { + beforeFiles: [], + afterFiles: [], + fallback: [], + } as any, + sortedPages: [pagePath, "/_app"], + }; + window.__NEXT_P.push(["/_app", () => _app]); - window.__NEXT_P.push([window.__NEXT_DATA__.page, () => page]); + window.__NEXT_P.push([pagePath, () => page]); console.debug("Hydrating the page"); diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 4842c7669e15e9..488d21bc91973b 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -98,7 +98,7 @@ async function runOperation( ...otherExports, }, pathname: renderData.path, - buildId: "", + buildId: "development", /* RenderOptsPartial */ runtimeConfig: {}, diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index a3d7f5b201dfac..c62500c4993003 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -6,6 +6,7 @@ mod app_source; mod embed_js; pub mod env; mod fallback; +pub mod manifest; pub mod next_client; mod next_client_component; pub mod next_image; diff --git a/packages/next-swc/crates/next-core/src/manifest.rs b/packages/next-swc/crates/next-core/src/manifest.rs new file mode 100644 index 00000000000000..802464d0711147 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/manifest.rs @@ -0,0 +1,82 @@ +use anyhow::Result; +use indexmap::IndexSet; +use mime::APPLICATION_JSON; +use turbo_tasks::primitives::StringsVc; +use turbo_tasks_fs::File; +use turbopack_core::asset::AssetContentVc; +use turbopack_dev_server::source::{ + ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc, +}; +use turbopack_node::{ + node_api_source::NodeApiContentSourceVc, node_rendered_source::NodeRenderContentSourceVc, +}; + +/// A content source which creates the next.js `_devPagesManifest.json` and +/// `_devMiddlewareManifest.json` which are used for client side navigation. +#[turbo_tasks::value(shared)] +pub struct DevManifestContentSource { + pub page_roots: Vec<ContentSourceVc>, +} + +#[turbo_tasks::value_impl] +impl DevManifestContentSourceVc { + #[turbo_tasks::function] + async fn find_routes(self) -> Result<StringsVc> { + let this = &*self.await?; + let mut queue = this.page_roots.clone(); + let mut routes = IndexSet::new(); + + while let Some(content_source) = queue.pop() { + queue.extend(content_source.get_children().await?.iter()); + + if let Some(api_source) = NodeApiContentSourceVc::resolve_from(content_source).await? { + routes.insert(format!("/{}", api_source.get_pathname().await?)); + + continue; + } + + if let Some(page_source) = + NodeRenderContentSourceVc::resolve_from(content_source).await? + { + routes.insert(format!("/{}", page_source.get_pathname().await?)); + + continue; + } + } + + routes.sort(); + + Ok(StringsVc::cell(routes.into_iter().collect())) + } +} + +#[turbo_tasks::value_impl] +impl ContentSource for DevManifestContentSource { + #[turbo_tasks::function] + async fn get( + self_vc: DevManifestContentSourceVc, + path: &str, + _data: turbo_tasks::Value<ContentSourceData>, + ) -> Result<ContentSourceResultVc> { + let manifest_content = match path { + "_next/static/development/_devPagesManifest.json" => { + let pages = &*self_vc.find_routes().await?; + + serde_json::to_string(&serde_json::json!({ + "pages": pages, + }))? + } + "_next/static/development/_devMiddlewareManifest.json" => { + // empty middleware manifest + "[]".to_string() + } + _ => return Ok(ContentSourceResultVc::not_found()), + }; + + let file = File::from(manifest_content).with_content_type(APPLICATION_JSON); + + Ok(ContentSourceResultVc::exact( + ContentSourceContent::Static(AssetContentVc::from(file).into()).cell(), + )) + } +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index c0dd11ae6e1120..0458a6df758bfb 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -173,6 +173,7 @@ async fn create_server_rendered_source_for_file( create_node_api_source( specificity, server_root, + pathname, path_regex, SsrEntry { context, diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 587c470a1dcb21..8097182dc69c3a 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -18,7 +18,8 @@ use anyhow::{anyhow, Context, Result}; use devserver_options::DevServerOptions; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, - next_image::NextImageContentSourceVc, source_map::NextSourceMapTraceContentSourceVc, + manifest::DevManifestContentSource, next_image::NextImageContentSourceVc, + source_map::NextSourceMapTraceContentSourceVc, }; use owo_colors::OwoColorize; use turbo_tasks::{ @@ -325,8 +326,18 @@ async fn source( .into(); let static_source = StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into(); - let main_source = - CombinedContentSourceVc::new(vec![static_source, app_source, rendered_source, web_source]); + let manifest_source = DevManifestContentSource { + page_roots: vec![app_source, rendered_source], + } + .cell() + .into(); + let main_source = CombinedContentSourceVc::new(vec![ + manifest_source, + static_source, + app_source, + rendered_source, + web_source, + ]); let introspect = IntrospectionSource { roots: HashSet::from([main_source.into()]), } From 1b8c636e1eb5f913b5b2fd71110ca8b57ea75165 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Mon, 5 Dec 2022 13:47:21 -0800 Subject: [PATCH 254/672] @next/font [1/n] Add query structure to module requests (vercel/turbo#2743) * Add query structure to module requests * Update crates/next-dev/src/lib.rs Co-authored-by: Justin Ridgewell <justin@ridgewell.name> Co-authored-by: Justin Ridgewell <justin@ridgewell.name> --- packages/next-swc/crates/next-dev/src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 8097182dc69c3a..48cc0837dfd6c7 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -29,7 +29,10 @@ use turbo_tasks::{ use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; -use turbopack_core::{issue::IssueSeverity, resolve::parse::RequestVc}; +use turbopack_core::{ + issue::IssueSeverity, + resolve::{parse::RequestVc, pattern::QueryMapVc}, +}; use turbopack_dev_server::{ fs::DevServerFileSystemVc, introspect::IntrospectionSource, @@ -291,7 +294,7 @@ async fn source( .map(|r| match r { EntryRequest::Relative(p) => RequestVc::relative(Value::new(p.clone().into()), false), EntryRequest::Module(m, p) => { - RequestVc::module(m.clone(), Value::new(p.clone().into())) + RequestVc::module(m.clone(), Value::new(p.clone().into()), QueryMapVc::none()) } }) .collect(); From 807c2b4146019d6c5367c5eb72ae2c65f7d08f5d Mon Sep 17 00:00:00 2001 From: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon, 5 Dec 2022 23:57:30 +0100 Subject: [PATCH 255/672] add memory usage tracking (vercel/turbo#2865) --- packages/next-swc/crates/next-dev/Cargo.toml | 5 +- packages/next-swc/crates/next-dev/src/lib.rs | 47 ++++++++++++++----- packages/next-swc/crates/next-dev/src/main.rs | 18 ++++++- 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index b930974a014721..2601c08ffb259b 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -19,7 +19,7 @@ name = "mod" harness = false [features] -default = ["cli"] +default = ["cli", "custom_allocator"] cli = [] serializable = [] tokio_console = [ @@ -28,6 +28,7 @@ tokio_console = [ "turbo-tasks/tokio_tracing", ] profile = [] +custom_allocator = ["turbo-malloc/custom_allocator"] [dependencies] anyhow = "1.0.47" @@ -41,7 +42,7 @@ portpicker = "0.1.1" serde = "1.0.136" serde_json = "1.0.85" tokio = { version = "1.21.2", features = ["full"] } -turbo-malloc = { path = "../turbo-malloc" } +turbo-malloc = { path = "../turbo-malloc", default-features = false } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } turbo-tasks-memory = { path = "../turbo-tasks-memory" } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 48cc0837dfd6c7..ebad029842dc40 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -22,9 +22,11 @@ use next_core::{ source_map::NextSourceMapTraceContentSourceVc, }; use owo_colors::OwoColorize; +use turbo_malloc::TurboMalloc; use turbo_tasks::{ - primitives::StringsVc, util::FormatDuration, RawVc, StatsType, TransientInstance, - TransientValue, TurboTasks, TurboTasksBackendApi, Value, + primitives::StringsVc, + util::{FormatBytes, FormatDuration}, + RawVc, StatsType, TransientInstance, TransientValue, TurboTasks, TurboTasksBackendApi, Value, }; use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; @@ -462,11 +464,20 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { } let stats_future = async move { - println!( - "{event_type} - initial compilation {start}", - event_type = "event".purple(), - start = FormatDuration(start.elapsed()), - ); + if options.log_detail { + println!( + "{event_type} - initial compilation {start} ({memory})", + event_type = "event".purple(), + start = FormatDuration(start.elapsed()), + memory = FormatBytes(TurboMalloc::memory_usage()) + ); + } else { + println!( + "{event_type} - initial compilation {start}", + event_type = "event".purple(), + start = FormatDuration(start.elapsed()), + ); + } loop { let update_future = profile_timeout( @@ -474,12 +485,22 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { tt_clone.get_or_wait_update_info(Duration::from_millis(100)), ); - let (elapsed, _count) = update_future.await; - println!( - "{event_type} - updated in {elapsed}", - event_type = "event".purple(), - elapsed = FormatDuration(elapsed), - ); + let (elapsed, count) = update_future.await; + if options.log_detail { + println!( + "{event_type} - updated in {elapsed} ({tasks} tasks, {memory})", + event_type = "event".purple(), + elapsed = FormatDuration(elapsed), + tasks = count, + memory = FormatBytes(TurboMalloc::memory_usage()) + ); + } else { + println!( + "{event_type} - updated in {elapsed}", + event_type = "event".purple(), + elapsed = FormatDuration(elapsed), + ); + } } }; diff --git a/packages/next-swc/crates/next-dev/src/main.rs b/packages/next-swc/crates/next-dev/src/main.rs index 2cee37320b0c2f..cad47aa7bd6e31 100644 --- a/packages/next-swc/crates/next-dev/src/main.rs +++ b/packages/next-swc/crates/next-dev/src/main.rs @@ -13,9 +13,23 @@ fn main() -> Result<()> { unimplemented!("Cannot run binary without CLI feature enabled"); } -#[tokio::main] #[cfg(feature = "cli")] -async fn main() -> Result<()> { +fn main() { + use turbo_malloc::TurboMalloc; + + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .on_thread_stop(|| { + TurboMalloc::thread_stop(); + }) + .build() + .unwrap() + .block_on(main_inner()) + .unwrap() +} + +#[cfg(feature = "cli")] +async fn main_inner() -> Result<()> { let options = next_dev::devserver_options::DevServerOptions::parse(); if options.display_version { From 5bd8c379212b85f086c84f4778840f5c0cfbe3b4 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Mon, 5 Dec 2022 16:09:17 -0800 Subject: [PATCH 256/672] @next/font [2/n] Apply next/font swc transform (vercel/turbo#2742) * Check in next-font transform from Next.js repo * Use next-font transform * Run transform via custom rule * Place next/font transform behind cargo feature --- packages/next-swc/crates/next-core/Cargo.toml | 3 + .../next-core/src/next_client/context.rs | 33 ++- .../crates/next-core/src/next_server/mod.rs | 10 +- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-font/Cargo.toml | 15 + .../find_functions_outside_module_scope.rs | 34 +++ .../next-font/src/font_functions_collector.rs | 71 +++++ .../next-font/src/font_imports_generator.rs | 272 ++++++++++++++++++ packages/next-swc/crates/next-font/src/lib.rs | 88 ++++++ 9 files changed, 522 insertions(+), 5 deletions(-) create mode 100644 packages/next-swc/crates/next-font/Cargo.toml create mode 100644 packages/next-swc/crates/next-font/src/find_functions_outside_module_scope.rs create mode 100644 packages/next-swc/crates/next-font/src/font_functions_collector.rs create mode 100644 packages/next-swc/crates/next-font/src/font_imports_generator.rs create mode 100644 packages/next-swc/crates/next-font/src/lib.rs diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 327af9d4b2340e..29c4dd56e1218a 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -29,3 +29,6 @@ turbopack-node = { path = "../turbopack-node" } [build-dependencies] turbo-tasks-build = { path = "../turbo-tasks-build" } + +[features] +next-font = [] diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 5e9e02f18f6b83..97b98753c4f618 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -107,7 +107,7 @@ pub async fn get_client_module_options_context( ..Default::default() }; - Ok(module_options_context.cell()) + Ok(add_next_font_transform(module_options_context.cell())) } #[turbo_tasks::function] @@ -128,12 +128,41 @@ pub async fn add_next_transforms_to_pages( ]), ]), vec![ModuleRuleEffect::AddEcmascriptTransforms( - EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJs]), + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJsPageSsr]), )], )); Ok(module_options_context.cell()) } +#[turbo_tasks::function] +pub async fn add_next_font_transform( + module_options_context: ModuleOptionsContextVc, +) -> Result<ModuleOptionsContextVc> { + #[cfg(not(feature = "next-font"))] + return Ok(module_options_context); + + #[cfg(feature = "next-font")] + { + use turbopack::module_options::{ModuleRule, ModuleRuleCondition, ModuleRuleEffect}; + use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc}; + + let mut module_options_context = module_options_context.await?.clone_value(); + module_options_context.custom_rules.push(ModuleRule::new( + // TODO: Only match in pages (not pages/api), app/, etc. + ModuleRuleCondition::any(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), + ]), + vec![ModuleRuleEffect::AddEcmascriptTransforms( + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJsFont]), + )], + )); + Ok(module_options_context.cell()) + } +} + #[turbo_tasks::function] pub fn get_client_asset_context( project_root: FileSystemPathVc, diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index b1bce0e8ebe360..9618ece8ae7145 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -13,7 +13,9 @@ use turbopack_core::environment::{ }; use turbopack_ecmascript::EcmascriptInputTransform; -use crate::next_import_map::get_next_server_import_map; +use crate::{ + next_client::context::add_next_font_transform, next_import_map::get_next_server_import_map, +}; #[turbo_tasks::value(serialization = "auto_for_input")] #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] @@ -78,7 +80,7 @@ pub fn get_server_environment( #[turbo_tasks::function] pub fn get_server_module_options_context(ty: Value<ServerContextType>) -> ModuleOptionsContextVc { - match ty.into_value() { + let module_options_context = match ty.into_value() { ServerContextType::Pages { .. } => ModuleOptionsContext { enable_typescript_transform: true, enable_styled_jsx: true, @@ -97,5 +99,7 @@ pub fn get_server_module_options_context(ty: Value<ServerContextType>) -> Module ..Default::default() }, } - .cell() + .cell(); + + add_next_font_transform(module_options_context) } diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 2601c08ffb259b..6b9fe23568d6f7 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -29,6 +29,7 @@ tokio_console = [ ] profile = [] custom_allocator = ["turbo-malloc/custom_allocator"] +next-font = ["next-core/next-font"] [dependencies] anyhow = "1.0.47" diff --git a/packages/next-swc/crates/next-font/Cargo.toml b/packages/next-swc/crates/next-font/Cargo.toml new file mode 100644 index 00000000000000..a375c91ca07f56 --- /dev/null +++ b/packages/next-swc/crates/next-font/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "next-font" +version = "0.1.0" +description = "TBD" +license = "MPL-2.0" +edition = "2021" + +[lib] +bench = false + +[dependencies] +fxhash = "0.2.1" +serde = "1.0.136" +serde_json = "1.0.85" +swc_core = { workspace = true } diff --git a/packages/next-swc/crates/next-font/src/find_functions_outside_module_scope.rs b/packages/next-swc/crates/next-font/src/find_functions_outside_module_scope.rs new file mode 100644 index 00000000000000..4648c805c708b3 --- /dev/null +++ b/packages/next-swc/crates/next-font/src/find_functions_outside_module_scope.rs @@ -0,0 +1,34 @@ +use swc_core::{ + common::errors::HANDLER, + ecma::{ + ast::*, + visit::{noop_visit_type, Visit}, + }, +}; + +pub struct FindFunctionsOutsideModuleScope<'a> { + pub state: &'a super::State, +} + +impl<'a> Visit for FindFunctionsOutsideModuleScope<'a> { + noop_visit_type!(); + + fn visit_ident(&mut self, ident: &Ident) { + if self.state.font_functions.get(&ident.to_id()).is_some() + && self + .state + .font_functions_in_allowed_scope + .get(&ident.span.lo) + .is_none() + { + HANDLER.with(|handler| { + handler + .struct_span_err( + ident.span, + "Font loaders must be called and assigned to a const in the module scope", + ) + .emit() + }); + } + } +} diff --git a/packages/next-swc/crates/next-font/src/font_functions_collector.rs b/packages/next-swc/crates/next-font/src/font_functions_collector.rs new file mode 100644 index 00000000000000..1cd2e2c7f62b4f --- /dev/null +++ b/packages/next-swc/crates/next-font/src/font_functions_collector.rs @@ -0,0 +1,71 @@ +use swc_core::{ + common::errors::HANDLER, + ecma::{ + ast::*, + atoms::JsWord, + visit::{noop_visit_type, Visit}, + }, +}; + +pub struct FontFunctionsCollector<'a> { + pub font_loaders: &'a [JsWord], + pub state: &'a mut super::State, +} + +impl<'a> Visit for FontFunctionsCollector<'a> { + noop_visit_type!(); + + fn visit_import_decl(&mut self, import_decl: &ImportDecl) { + if self.font_loaders.contains(&import_decl.src.value) { + self.state + .removeable_module_items + .insert(import_decl.span.lo); + for specifier in &import_decl.specifiers { + match specifier { + ImportSpecifier::Named(ImportNamedSpecifier { + local, imported, .. + }) => { + self.state + .font_functions_in_allowed_scope + .insert(local.span.lo); + + let function_name = if let Some(ModuleExportName::Ident(ident)) = imported { + ident.sym.clone() + } else { + local.sym.clone() + }; + self.state.font_functions.insert( + local.to_id(), + super::FontFunction { + loader: import_decl.src.value.clone(), + function_name: Some(function_name), + }, + ); + } + ImportSpecifier::Default(ImportDefaultSpecifier { local, .. }) => { + self.state + .font_functions_in_allowed_scope + .insert(local.span.lo); + self.state.font_functions.insert( + local.to_id(), + super::FontFunction { + loader: import_decl.src.value.clone(), + function_name: None, + }, + ); + } + ImportSpecifier::Namespace(_) => { + HANDLER.with(|handler| { + handler + .struct_span_err( + import_decl.span, + "Font loaders can't have namespace imports", + ) + .emit() + }); + } + } + } + } + } +} diff --git a/packages/next-swc/crates/next-font/src/font_imports_generator.rs b/packages/next-swc/crates/next-font/src/font_imports_generator.rs new file mode 100644 index 00000000000000..cc7bfeb6c324b5 --- /dev/null +++ b/packages/next-swc/crates/next-font/src/font_imports_generator.rs @@ -0,0 +1,272 @@ +use serde_json::Value; +use swc_core::{ + common::{errors::HANDLER, Spanned, DUMMY_SP}, + ecma::{ + ast::*, + atoms::JsWord, + visit::{noop_visit_type, Visit}, + }, +}; + +pub struct FontImportsGenerator<'a> { + pub state: &'a mut super::State, + pub relative_path: &'a str, +} + +impl<'a> FontImportsGenerator<'a> { + fn check_call_expr( + &mut self, + call_expr: &CallExpr, + variable_name: &Result<Ident, &Pat>, + ) -> Option<ImportDecl> { + if let Callee::Expr(callee_expr) = &call_expr.callee { + if let Expr::Ident(ident) = &**callee_expr { + if let Some(font_function) = self.state.font_functions.get(&ident.to_id()) { + self.state + .font_functions_in_allowed_scope + .insert(ident.span.lo); + + let json: Result<Vec<Value>, ()> = call_expr + .args + .iter() + .map(|expr_or_spread| { + if let Some(span) = expr_or_spread.spread { + HANDLER.with(|handler| { + handler + .struct_span_err(span, "Font loaders don't accept spreads") + .emit() + }); + } + + expr_to_json(&expr_or_spread.expr) + }) + .collect(); + + if let Ok(json) = json { + let function_name = match &font_function.function_name { + Some(function) => String::from(&**function), + None => String::new(), + }; + let mut query_json_values = serde_json::Map::new(); + query_json_values.insert( + String::from("path"), + Value::String(self.relative_path.to_string()), + ); + query_json_values + .insert(String::from("import"), Value::String(function_name)); + query_json_values.insert(String::from("arguments"), Value::Array(json)); + if let Ok(ident) = variable_name { + query_json_values.insert( + String::from("variableName"), + Value::String(ident.sym.to_string()), + ); + } + + let query_json = Value::Object(query_json_values); + + return Some(ImportDecl { + src: Box::new(Str { + value: JsWord::from(format!( + "{}/target.css?{}", + font_function.loader, query_json + )), + raw: None, + span: DUMMY_SP, + }), + specifiers: vec![], + type_only: false, + asserts: None, + span: DUMMY_SP, + }); + } + } + } + } + + None + } + + fn check_var_decl(&mut self, var_decl: &VarDecl) -> Option<Ident> { + if let Some(decl) = var_decl.decls.get(0) { + let ident = match &decl.name { + Pat::Ident(ident) => Ok(ident.id.clone()), + pattern => Err(pattern), + }; + if let Some(expr) = &decl.init { + if let Expr::Call(call_expr) = &**expr { + let import_decl = self.check_call_expr(call_expr, &ident); + + if let Some(mut import_decl) = import_decl { + match var_decl.kind { + VarDeclKind::Const => {} + _ => { + HANDLER.with(|handler| { + handler + .struct_span_err( + var_decl.span, + "Font loader calls must be assigned to a const", + ) + .emit() + }); + } + } + + match ident { + Ok(ident) => { + import_decl.specifiers = + vec![ImportSpecifier::Default(ImportDefaultSpecifier { + span: DUMMY_SP, + local: ident.clone(), + })]; + + self.state + .font_imports + .push(ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl))); + + return Some(ident); + } + Err(pattern) => { + HANDLER.with(|handler| { + handler + .struct_span_err( + pattern.span(), + "Font loader calls must be assigned to an identifier", + ) + .emit() + }); + } + } + } + } + } + } + None + } +} + +impl<'a> Visit for FontImportsGenerator<'a> { + noop_visit_type!(); + + fn visit_module_item(&mut self, item: &ModuleItem) { + match item { + ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))) => { + if self.check_var_decl(var_decl).is_some() { + self.state.removeable_module_items.insert(var_decl.span.lo); + } + } + ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => { + if let Decl::Var(var_decl) = &export_decl.decl { + if let Some(ident) = self.check_var_decl(var_decl) { + self.state + .removeable_module_items + .insert(export_decl.span.lo); + + self.state.font_exports.push(ModuleItem::ModuleDecl( + ModuleDecl::ExportNamed(NamedExport { + span: DUMMY_SP, + specifiers: vec![ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(ident), + span: DUMMY_SP, + exported: None, + is_type_only: false, + })], + src: None, + type_only: false, + asserts: None, + }), + )); + } + } + } + _ => {} + } + } +} + +fn object_lit_to_json(object_lit: &ObjectLit) -> Value { + let mut values = serde_json::Map::new(); + for prop in &object_lit.props { + match prop { + PropOrSpread::Prop(prop) => match &**prop { + Prop::KeyValue(key_val) => { + let key = match &key_val.key { + PropName::Ident(ident) => Ok(String::from(&*ident.sym)), + key => { + HANDLER.with(|handler| { + handler + .struct_span_err(key.span(), "Unexpected object key type") + .emit() + }); + Err(()) + } + }; + let val = expr_to_json(&key_val.value); + if let (Ok(key), Ok(val)) = (key, val) { + values.insert(key, val); + } + } + key => HANDLER.with(|handler| { + handler.struct_span_err(key.span(), "Unexpected key").emit(); + }), + }, + PropOrSpread::Spread(spread_span) => HANDLER.with(|handler| { + handler + .struct_span_err(spread_span.dot3_token, "Unexpected spread") + .emit(); + }), + } + } + + Value::Object(values) +} + +fn expr_to_json(expr: &Expr) -> Result<Value, ()> { + match expr { + Expr::Lit(Lit::Str(str)) => Ok(Value::String(String::from(&*str.value))), + Expr::Lit(Lit::Bool(Bool { value, .. })) => Ok(Value::Bool(*value)), + Expr::Lit(Lit::Num(Number { value, .. })) => { + Ok(Value::Number(serde_json::Number::from_f64(*value).unwrap())) + } + Expr::Object(object_lit) => Ok(object_lit_to_json(object_lit)), + Expr::Array(ArrayLit { + elems, + span: array_span, + .. + }) => { + let elements: Result<Vec<Value>, ()> = elems + .iter() + .map(|e| { + if let Some(expr) = e { + match expr.spread { + Some(spread_span) => HANDLER.with(|handler| { + handler + .struct_span_err(spread_span, "Unexpected spread") + .emit(); + Err(()) + }), + None => expr_to_json(&expr.expr), + } + } else { + HANDLER.with(|handler| { + handler + .struct_span_err(*array_span, "Unexpected empty value in array") + .emit(); + Err(()) + }) + } + }) + .collect(); + + elements.map(Value::Array) + } + lit => HANDLER.with(|handler| { + handler + .struct_span_err( + lit.span(), + "Font loader values must be explicitly written literals.", + ) + .emit(); + Err(()) + }), + } +} diff --git a/packages/next-swc/crates/next-font/src/lib.rs b/packages/next-swc/crates/next-font/src/lib.rs new file mode 100644 index 00000000000000..0427b53d640d5a --- /dev/null +++ b/packages/next-swc/crates/next-font/src/lib.rs @@ -0,0 +1,88 @@ +use fxhash::FxHashSet; +use serde::Deserialize; +use swc_core::{ + common::{collections::AHashMap, BytePos, Spanned}, + ecma::{ + ast::{Id, ModuleItem}, + atoms::JsWord, + visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitWith}, + }, +}; + +mod find_functions_outside_module_scope; +mod font_functions_collector; +mod font_imports_generator; + +#[derive(Clone, Debug, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct Config { + pub font_loaders: Vec<JsWord>, + pub relative_file_path_from_root: JsWord, +} + +pub fn next_font_loaders(config: Config) -> impl Fold + VisitMut { + as_folder(NextFontLoaders { + config, + state: State { + ..Default::default() + }, + }) +} + +#[derive(Debug)] +pub struct FontFunction { + loader: JsWord, + function_name: Option<JsWord>, +} +#[derive(Debug, Default)] +pub struct State { + font_functions: AHashMap<Id, FontFunction>, + removeable_module_items: FxHashSet<BytePos>, + font_imports: Vec<ModuleItem>, + font_exports: Vec<ModuleItem>, + font_functions_in_allowed_scope: FxHashSet<BytePos>, +} + +struct NextFontLoaders { + config: Config, + state: State, +} + +impl VisitMut for NextFontLoaders { + noop_visit_mut_type!(); + + fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) { + // Find imported functions from font loaders + let mut functions_collector = font_functions_collector::FontFunctionsCollector { + font_loaders: &self.config.font_loaders, + state: &mut self.state, + }; + items.visit_with(&mut functions_collector); + + if !self.state.removeable_module_items.is_empty() { + // Generate imports from font function calls + let mut import_generator = font_imports_generator::FontImportsGenerator { + state: &mut self.state, + relative_path: &self.config.relative_file_path_from_root, + }; + items.visit_with(&mut import_generator); + + // Find font function refs in wrong scope + let mut wrong_scope = + find_functions_outside_module_scope::FindFunctionsOutsideModuleScope { + state: &self.state, + }; + items.visit_with(&mut wrong_scope); + + // Remove marked module items + items.retain(|item| !self.state.removeable_module_items.contains(&item.span_lo())); + + // Add font imports and exports + let mut new_items = Vec::new(); + new_items.append(&mut self.state.font_imports); + new_items.append(items); + new_items.append(&mut self.state.font_exports); + *items = new_items; + } + } +} From 93703ccca52310466379a0bb61c393b21c239fa2 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg <alex.kirszenberg@vercel.com> Date: Tue, 6 Dec 2022 15:15:57 +0100 Subject: [PATCH 257/672] Remove unused dependencies (vercel/turbo#2934) * Remove unused dependencies * Add back lazy static as a dev dep * Add back bench dependencies --- packages/next-swc/crates/next-core/Cargo.toml | 3 --- packages/next-swc/crates/next-dev/Cargo.toml | 7 +++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 29c4dd56e1218a..45ea076a6da359 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -12,14 +12,11 @@ bench = false anyhow = "1.0.47" indexmap = { workspace = true, features = ["serde"] } mime = "0.3.16" -rand = "0.8.5" serde = "1.0.136" serde_json = "1.0.85" -tokio = { version = "1.21.2", features = ["full"] } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-env = { path = "../turbo-tasks-env" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } -turbo-tasks-hash = { path = "../turbo-tasks-hash" } turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 6b9fe23568d6f7..1eeada29c33591 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -39,19 +39,15 @@ futures = "0.3.25" mime = "0.3.16" next-core = { path = "../next-core" } owo-colors = "3" -portpicker = "0.1.1" serde = "1.0.136" -serde_json = "1.0.85" tokio = { version = "1.21.2", features = ["full"] } turbo-malloc = { path = "../turbo-malloc", default-features = false } turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } turbo-tasks-memory = { path = "../turbo-tasks-memory" } -turbopack = { path = "../turbopack" } turbopack-cli-utils = { path = "../turbopack-cli-utils" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } -url = "2.3.0" webbrowser = "0.7.1" [dev-dependencies] @@ -63,8 +59,10 @@ fs_extra = "1.2.0" lazy_static = "1.4.0" once_cell = "1.13.0" parking_lot = "0.12.1" +portpicker = "0.1.1" rand = "0.8.5" regex = "1.6.0" +serde_json = "1.0.85" tempfile = "3.3.0" test-generator = "0.3.0" # For matching on errors from chromiumoxide. Keep in @@ -72,6 +70,7 @@ test-generator = "0.3.0" tungstenite = "0.17.3" turbo-tasks-testing = { path = "../turbo-tasks-testing" } turbopack-create-test-app = { path = "../turbopack-create-test-app" } +url = "2.2.2" [target.'cfg(unix)'.dev-dependencies] nix = "0.25.0" From 080390e254ceb6ddca7e736864298eac2930eac5 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Wed, 7 Dec 2022 18:20:24 -0800 Subject: [PATCH 258/672] Validate `@next/font/google` query options (vercel/turbo#2812) --- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../next-core/src/next_font_google/mod.rs | 2 + .../next-core/src/next_font_google/options.rs | 553 ++++++++++++++++++ .../next-core/src/next_font_google/request.rs | 35 ++ 4 files changed, 591 insertions(+) create mode 100644 packages/next-swc/crates/next-core/src/next_font_google/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/next_font_google/options.rs create mode 100644 packages/next-swc/crates/next-core/src/next_font_google/request.rs diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index c62500c4993003..3a4c37cf47993f 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -9,6 +9,7 @@ mod fallback; pub mod manifest; pub mod next_client; mod next_client_component; +mod next_font_google; pub mod next_image; mod next_import_map; pub mod next_server; diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs new file mode 100644 index 00000000000000..c596c9de8a7bf1 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs @@ -0,0 +1,2 @@ +mod options; +pub(crate) mod request; diff --git a/packages/next-swc/crates/next-core/src/next_font_google/options.rs b/packages/next-swc/crates/next-core/src/next_font_google/options.rs new file mode 100644 index 00000000000000..93f4da99ce2ef8 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font_google/options.rs @@ -0,0 +1,553 @@ +use anyhow::{anyhow, Context, Result}; +use indexmap::{indexset, IndexMap, IndexSet}; +use serde::Deserialize; + +use super::request::{NextFontRequest, OneOrManyStrings}; + +#[allow(dead_code)] +const ALLOWED_DISPLAY_VALUES: &[&str] = &["auto", "block", "swap", "fallback", "optional"]; + +#[derive(Debug, PartialEq)] +pub struct NextFontGoogleOptions { + pub font_family: String, + pub weights: FontWeights, + pub styles: IndexSet<String>, + pub display: String, + pub preload: bool, + pub selected_variable_axes: Option<Vec<String>>, + pub fallback: Option<Vec<String>>, + pub adjust_font_fallback: bool, + pub variable: Option<Vec<String>>, + pub subsets: Option<Vec<String>>, +} + +#[derive(Debug, PartialEq)] +#[allow(dead_code)] +pub enum FontWeights { + Variable, + Fixed(IndexSet<String>), +} + +#[derive(Debug, Deserialize)] +pub struct FontDataEntry { + pub weights: Vec<String>, + pub styles: Vec<String>, + pub axes: Option<Vec<Axis>>, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Axis { + pub tag: String, + pub min: f64, + pub max: f64, + pub default_value: f64, +} + +// Transforms the request fields to a struct suitable for making requests to +// Google Fonts. Similar to @next/font/google's validateData: +// https://github.com/vercel/next.js/blob/28454c6ddbc310419467e5415aee26e48d079b46/packages/font/src/google/utils.ts#L22 +#[allow(dead_code)] +pub fn options_from_request( + request: &NextFontRequest, + data: &IndexMap<String, FontDataEntry>, +) -> Result<NextFontGoogleOptions> { + if request.arguments.len() > 1 { + return Err(anyhow!( + "Only zero or one arguments to font functions are currently supported" + )); + } + // Invariant enforced above: either None or Some(the only item in the vec) + let argument = request.arguments.last(); + + // `import` comes from the imported symbol in JS, which separates with _ + let font_family = request.import.replace('_', " "); + let font_data = data.get(&font_family).context("Unknown font")?; + + let requested_weights = argument + .and_then(|argument| { + argument.weight.as_ref().map(|w| match w { + OneOrManyStrings::One(one) => indexset! {one.to_owned()}, + OneOrManyStrings::Many(many) => IndexSet::from_iter(many.iter().cloned()), + }) + }) + .unwrap_or_else(IndexSet::new); + + let mut styles = argument + .and_then(|argument| { + argument.style.as_ref().map(|w| match w { + OneOrManyStrings::One(one) => indexset! {one.to_owned()}, + OneOrManyStrings::Many(many) => IndexSet::from_iter(many.iter().cloned()), + }) + }) + .unwrap_or_else(IndexSet::new); + + let weights = if requested_weights.is_empty() { + if !font_data.weights.contains(&"variable".to_owned()) { + return Err(anyhow!( + "Missing weight for {}. Available weights: {}", + font_family, + font_data.weights.join(", ") + )); + } + + FontWeights::Variable + } else if requested_weights.contains("variable") { + if requested_weights.len() > 1 { + return Err(anyhow!( + "Unexpected `variable` in weight array for font {}. You only need `variable`, it \ + includes all available weights.", + font_family + )); + } + + FontWeights::Variable + } else { + for requested_weight in &requested_weights { + if !font_data.weights.contains(requested_weight) { + return Err(anyhow!( + "Unknown weight {} for font {}.\nAvailable weights: {}", + requested_weight, + font_family, + font_data.weights.join(", ") + )); + } + } + + FontWeights::Fixed(requested_weights) + }; + + if styles.is_empty() { + if font_data.styles.len() == 1 { + styles.insert(font_data.styles[0].clone()); + } else { + styles.insert("normal".to_owned()); + } + } + + for requested_style in &styles { + if !font_data.styles.contains(requested_style) { + return Err(anyhow!( + "Unknown style {} for font {}.\nAvailable styles: {}", + requested_style, + font_family, + font_data.styles.join(", ") + )); + } + } + + let display = argument + .and_then(|a| a.display.to_owned()) + .unwrap_or_else(|| "optional".to_owned()); + + if !ALLOWED_DISPLAY_VALUES.contains(&display.as_ref()) { + return Err(anyhow!( + "Invalid display value {} for font {}.\nAvailable display values: {}", + display, + font_family, + ALLOWED_DISPLAY_VALUES.join(", ") + )); + } + + if let Some(axes) = argument.and_then(|a| a.axes.as_ref()) { + if !axes.is_empty() && !matches!(weights, FontWeights::Variable) { + return Err(anyhow!("Axes can only be defined for variable fonts")); + } + } + + Ok(NextFontGoogleOptions { + font_family, + weights, + styles, + display, + preload: argument.map(|a| a.preload).unwrap_or(true), + selected_variable_axes: argument.and_then(|a| a.axes.clone()), + fallback: argument.and_then(|a| a.fallback.clone()), + adjust_font_fallback: argument.map(|a| a.adjust_font_fallback).unwrap_or(false), + variable: argument.and_then(|a| a.variable.clone()), + subsets: argument.and_then(|a| a.subsets.clone()), + }) +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use indexmap::{indexset, IndexMap}; + + use super::{options_from_request, FontDataEntry, NextFontGoogleOptions}; + use crate::next_font_google::{options::FontWeights, request::NextFontRequest}; + + #[test] + fn test_errors_on_unknown_font() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "Inter", + "path": "index.js", + "variableName": "inter", + "arguments": [{}] + } + "#, + )?; + + match options_from_request(&request, &data) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!(err.to_string(), "Unknown font") + } + } + Ok(()) + } + + #[test] + fn test_default_values_when_no_arguments() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [] + } + "#, + )?; + + assert_eq!( + options_from_request(&request, &data)?, + NextFontGoogleOptions { + font_family: "ABeeZee".to_owned(), + weights: FontWeights::Variable, + styles: indexset! {"normal".to_owned()}, + display: "optional".to_owned(), + preload: true, + selected_variable_axes: None, + fallback: None, + adjust_font_fallback: false, + variable: None, + subsets: None, + }, + ); + + Ok(()) + } + + #[test] + fn test_errors_when_no_weights_chosen_no_variable() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{}] + } + "#, + )?; + + match options_from_request(&request, &data) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + err.to_string(), + "Missing weight for ABeeZee. Available weights: 400" + ) + } + } + Ok(()) + } + + #[test] + fn test_errors_on_unnecessary_weights() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400", "variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{ + "weight": ["400", "variable"] + }] + } + "#, + )?; + + match options_from_request(&request, &data) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + err.to_string(), + "Unexpected `variable` in weight array for font ABeeZee. You only need \ + `variable`, it includes all available weights." + ) + } + } + Ok(()) + } + + #[test] + fn test_errors_on_unvavailable_weights() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400", "variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{ + "weight": ["200"] + }] + } + "#, + )?; + + match options_from_request(&request, &data) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + err.to_string(), + "Unknown weight 200 for font ABeeZee.\nAvailable weights: 400, variable" + ) + } + } + Ok(()) + } + + #[test] + fn test_defaults_to_only_style_when_one_available() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400", "variable"], + "styles": ["italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{ + "weight": ["400"] + }] + } + "#, + )?; + + let options = options_from_request(&request, &data)?; + assert_eq!(options.styles, indexset! {"italic".to_owned()}); + + Ok(()) + } + + #[test] + fn test_defaults_to_normal_style_when_multiple() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400", "variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{ + "weight": ["400"] + }] + } + "#, + )?; + + let options = options_from_request(&request, &data)?; + assert_eq!(options.styles, indexset! {"normal".to_owned()}); + + Ok(()) + } + + #[test] + fn test_errors_on_unknown_styles() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400", "variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{ + "weight": ["400"], + "style": ["foo"] + }] + } + "#, + )?; + + match options_from_request(&request, &data) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + err.to_string(), + "Unknown style foo for font ABeeZee.\nAvailable styles: normal, italic" + ) + } + } + + Ok(()) + } + + #[test] + fn test_errors_on_unknown_display() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400", "variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{ + "weight": ["400"], + "display": "foo" + }] + } + "#, + )?; + + match options_from_request(&request, &data) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + err.to_string(), + "Invalid display value foo for font ABeeZee.\nAvailable display values: auto, \ + block, swap, fallback, optional" + ) + } + } + + Ok(()) + } + + #[test] + fn test_errors_on_axes_without_variable() -> Result<()> { + let data: IndexMap<String, FontDataEntry> = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["400", "variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + let request: NextFontRequest = serde_json::from_str( + r#" + { + "import": "ABeeZee", + "path": "index.js", + "variableName": "abeezee", + "arguments": [{ + "weight": ["400"], + "axes": ["wght"] + }] + } + "#, + )?; + + match options_from_request(&request, &data) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + err.to_string(), + "Axes can only be defined for variable fonts" + ) + } + } + + Ok(()) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_font_google/request.rs b/packages/next-swc/crates/next-core/src/next_font_google/request.rs new file mode 100644 index 00000000000000..ff3994e266233b --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font_google/request.rs @@ -0,0 +1,35 @@ +use serde::Deserialize; + +/// The top-most structure encoded into the query param in requests to +/// `@next/font/google` generated by the @next/font swc transform. e.g. +/// `@next/font/google/target.css?{"path": "index.js", "import": "Inter"...` +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NextFontRequest { + pub path: String, + pub import: String, + pub arguments: Vec<NextFontRequestArguments>, + pub variable_name: String, +} + +#[derive(Debug, Deserialize)] +pub struct NextFontRequestArguments { + pub weight: Option<OneOrManyStrings>, + pub subsets: Option<Vec<String>>, + pub style: Option<OneOrManyStrings>, + pub display: Option<String>, + #[serde(default)] + pub preload: bool, + pub axes: Option<Vec<String>>, + pub fallback: Option<Vec<String>>, + #[serde(default)] + pub adjust_font_fallback: bool, + pub variable: Option<Vec<String>>, +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum OneOrManyStrings { + One(String), + Many(Vec<String>), +} From 199ed0ea0f49b8f43387b1965b7495147130af65 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Wed, 7 Dec 2022 19:38:30 -0800 Subject: [PATCH 259/672] [5/n] `@next/font/google`: Port utilities for generating stylesheet urls (vercel/turbo#2856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement get_font_axes * Implement get_stylesheet_url * Handle font axes without wght Co-authored-by: Hannes Bornö <hannes.borno@vercel.com> * Implement extract_font_urls * Update crates/next-core/src/next_font_google/util.rs Co-authored-by: Justin Ridgewell <justin@ridgewell.name> * Remove extraction of fonts Co-authored-by: Hannes Bornö <hannes.borno@vercel.com> Co-authored-by: Justin Ridgewell <justin@ridgewell.name> --- .../next-core/src/next_font_google/mod.rs | 1 + .../next-core/src/next_font_google/options.rs | 2 + .../next-core/src/next_font_google/util.rs | 453 ++++++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 packages/next-swc/crates/next-core/src/next_font_google/util.rs diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs index c596c9de8a7bf1..2c19ace9911706 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs @@ -1,2 +1,3 @@ mod options; pub(crate) mod request; +mod util; diff --git a/packages/next-swc/crates/next-core/src/next_font_google/options.rs b/packages/next-swc/crates/next-core/src/next_font_google/options.rs index 93f4da99ce2ef8..4e12acdb1f2a6b 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/options.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/options.rs @@ -7,6 +7,8 @@ use super::request::{NextFontRequest, OneOrManyStrings}; #[allow(dead_code)] const ALLOWED_DISPLAY_VALUES: &[&str] = &["auto", "block", "swap", "fallback", "optional"]; +pub type FontData = IndexMap<String, FontDataEntry>; + #[derive(Debug, PartialEq)] pub struct NextFontGoogleOptions { pub font_family: String, diff --git a/packages/next-swc/crates/next-core/src/next_font_google/util.rs b/packages/next-swc/crates/next-core/src/next_font_google/util.rs new file mode 100644 index 00000000000000..dbf3befa2bcbb8 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font_google/util.rs @@ -0,0 +1,453 @@ +use std::cmp::Ordering; + +use anyhow::{anyhow, bail, Context, Result}; +use indexmap::{indexset, IndexSet}; + +use super::options::{FontData, FontWeights}; + +const GOOGLE_FONTS_STYLESHEET_URL: &str = "https://fonts.googleapis.com/css2"; + +#[derive(Debug, PartialEq)] +pub(crate) struct FontAxes { + pub(crate) wght: IndexSet<String>, + pub(crate) ital: IndexSet<FontItal>, + pub(crate) variable_axes: Option<Vec<(String, String)>>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub(crate) enum FontItal { + Italic, + Normal, +} + +// Derived from https://github.com/vercel/next.js/blob/9e098da0915a2a4581bebe2270953a1216be1ba4/packages/font/src/google/utils.ts#L232 +#[allow(dead_code)] +pub(crate) fn get_font_axes( + font_data: &FontData, + font_family: &str, + weights: &FontWeights, + styles: &IndexSet<String>, + selected_variable_axes: &Option<Vec<String>>, +) -> Result<FontAxes> { + let all_axes = &font_data + .get(font_family) + .context("Font family not found")? + .axes; + + let Some(defineable_axes) = all_axes else { + bail!("Font {} has no definable `axes`", font_family); + }; + + let ital = { + let has_italic = styles.contains("italic"); + let has_normal = styles.contains("normal"); + let mut set = IndexSet::new(); + if has_normal { + set.insert(FontItal::Normal); + } + if has_italic { + set.insert(FontItal::Italic); + } + set + }; + + match weights { + FontWeights::Variable => { + if let Some(selected_variable_axes) = selected_variable_axes { + let definable_axes_tags = defineable_axes + .iter() + .map(|axis| axis.tag.to_owned()) + .collect::<Vec<String>>(); + + for tag in selected_variable_axes { + if !definable_axes_tags.contains(tag) { + return Err(anyhow!( + "Invalid axes value {} for font {}.\nAvailable axes: {}", + tag, + font_family, + definable_axes_tags.join(", ") + )); + } + } + } + + let mut weight_axis = None; + let mut variable_axes = vec![]; + for axis in defineable_axes { + if axis.tag == "wght" { + weight_axis = Some(format!("{}..{}", axis.min, axis.max)); + } else if let Some(selected_variable_axes) = selected_variable_axes { + if selected_variable_axes.contains(&axis.tag) { + variable_axes + .push((axis.tag.clone(), format!("{}..{}", axis.min, axis.max))); + } + } + } + + let wght = match weight_axis { + Some(weight_axis) => { + indexset! {weight_axis} + } + None => indexset! {}, + }; + + Ok(FontAxes { + wght, + ital, + variable_axes: Some(variable_axes), + }) + } + FontWeights::Fixed(weights) => Ok(FontAxes { + wght: weights.clone(), + ital, + variable_axes: None, + }), + } +} + +// Derived from https://github.com/vercel/next.js/blob/9e098da0915a2a4581bebe2270953a1216be1ba4/packages/font/src/google/utils.ts#L128 +#[allow(dead_code)] +pub(crate) fn get_stylesheet_url( + font_family: &str, + axes: &FontAxes, + display: &str, +) -> Result<String> { + // Variants are all combinations of weight and style, each variant will result + // in a separate font file + let mut variants: Vec<Vec<(&str, &str)>> = vec![]; + if axes.wght.is_empty() { + let mut variant = vec![]; + if let Some(variable_axes) = &axes.variable_axes { + for (key, val) in variable_axes { + variant.push((key.as_str(), &val[..])); + } + } + variants.push(variant); + } else { + for wght in &axes.wght { + if axes.ital.is_empty() { + let mut variant = vec![]; + variant.push(("wght", &wght[..])); + if let Some(variable_axes) = &axes.variable_axes { + for (key, val) in variable_axes { + variant.push((key, &val[..])); + } + } + variants.push(variant); + } else { + for ital in &axes.ital { + let mut variant = vec![]; + variant.push(( + "ital", + match ital { + FontItal::Normal => "0", + FontItal::Italic => "1", + }, + )); + variant.push(("wght", &wght[..])); + if let Some(variable_axes) = &axes.variable_axes { + for (key, val) in variable_axes { + variant.push((key, &val[..])); + } + } + variants.push(variant); + } + } + } + } + + for variant in &mut variants { + // Sort the pairs within the variant by the tag name + variant.sort_by(|a, b| { + let is_a_lowercase = a.0.chars().next().unwrap_or_default() as usize > 96; + let is_b_lowercase = b.0.chars().next().unwrap_or_default() as usize > 96; + + if is_a_lowercase && !is_b_lowercase { + Ordering::Less + } else if is_b_lowercase && !is_a_lowercase { + Ordering::Greater + } else { + a.0.cmp(b.0) + } + }); + } + + let first_variant = variants + .first() + .context("Requires at least one font variant")?; + // Always use the first variant's keys. There's an implicit invariant from the + // code above that the keys across each variant are identical, and therefore + // will be sorted identically across variants. + // + // Generates a comma-separated list of axis names, e.g. `ital,opsz,wght`. + let variant_keys_str = first_variant + .iter() + .map(|pair| pair.0) + .collect::<Vec<&str>>() + .join(","); + + let mut variant_values = variants + .iter() + .map(|variant| { + variant + .iter() + .map(|pair| pair.1) + .collect::<Vec<&str>>() + .join(",") + }) + .collect::<Vec<String>>(); + variant_values.sort(); + // An encoding of the series of sorted variant values, with variants delimited + // by `;` and the values within a variant delimited by `,` e.g. + // `"0,10..100,500;1,10.100;500"` + let variant_values_str = variant_values.join(";"); + + Ok(format!( + "{}?family={}:{}@{}&display={}", + GOOGLE_FONTS_STYLESHEET_URL, + font_family.replace(' ', "+"), + variant_keys_str, + variant_values_str, + display + )) +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use indexmap::indexset; + + use super::get_font_axes; + use crate::next_font_google::{ + options::{FontData, FontWeights}, + util::{get_stylesheet_url, FontAxes, FontItal}, + }; + + #[test] + fn test_errors_on_unknown_font() -> Result<()> { + let data: FontData = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + match get_font_axes( + &data, + "foobar", + &FontWeights::Variable, + &indexset! {}, + &None, + ) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!(err.to_string(), "Font family not found") + } + } + Ok(()) + } + + #[test] + fn test_errors_on_missing_axes() -> Result<()> { + let data: FontData = serde_json::from_str( + r#" + { + "ABeeZee": { + "weights": ["variable"], + "styles": ["normal", "italic"] + } + } + "#, + )?; + + match get_font_axes( + &data, + "ABeeZee", + &FontWeights::Variable, + &indexset! {}, + &None, + ) { + Ok(_) => panic!(), + Err(err) => { + assert_eq!(err.to_string(), "Font ABeeZee has no definable `axes`") + } + } + Ok(()) + } + + #[test] + fn test_selecting_axes() -> Result<()> { + let data: FontData = serde_json::from_str( + r#" + { + "Inter": { + "weights": [ + "400", + "variable" + ], + "styles": ["normal", "italic"], + "axes": [ + { + "tag": "slnt", + "min": -10, + "max": 0, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + } + } + "#, + )?; + + assert_eq!( + get_font_axes( + &data, + "Inter", + &FontWeights::Variable, + &indexset! {}, + &Some(vec!["slnt".to_owned()]), + )?, + FontAxes { + wght: indexset! {"100..900".to_owned()}, + ital: indexset! {}, + variable_axes: Some(vec![("slnt".to_owned(), "-10..0".to_owned())]) + } + ); + Ok(()) + } + + #[test] + fn test_no_wght_axis() -> Result<()> { + let data: FontData = serde_json::from_str( + r#" + { + "Inter": { + "weights": [ + "400", + "variable" + ], + "styles": ["normal", "italic"], + "axes": [ + { + "tag": "slnt", + "min": -10, + "max": 0, + "defaultValue": 0 + } + ] + } + } + "#, + )?; + + assert_eq!( + get_font_axes( + &data, + "Inter", + &FontWeights::Variable, + &indexset! {}, + &Some(vec!["slnt".to_owned()]), + )?, + FontAxes { + wght: indexset! {}, + ital: indexset! {}, + variable_axes: Some(vec![("slnt".to_owned(), "-10..0".to_owned())]) + } + ); + Ok(()) + } + + #[test] + fn test_stylesheet_url_no_axes() -> Result<()> { + assert_eq!( + get_stylesheet_url( + "Roboto Mono", + &FontAxes { + wght: indexset! {"500".to_owned()}, + ital: indexset! {FontItal::Normal}, + variable_axes: None + }, + "optional" + )?, + "https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,500&display=optional" + ); + + Ok(()) + } + + #[test] + fn test_stylesheet_url_sorts_axes() -> Result<()> { + assert_eq!( + get_stylesheet_url( + "Roboto Serif", + &FontAxes { + wght: indexset! {"500".to_owned()}, + ital: indexset! {FontItal::Normal}, + variable_axes: Some(vec![ + ("GRAD".to_owned(), "-50..100".to_owned()), + ("opsz".to_owned(), "8..144".to_owned()), + ("wdth".to_owned(), "50..150".to_owned()), + ]) + }, + "optional" + )?, + "https://fonts.googleapis.com/css2?family=Roboto+Serif:ital,opsz,wdth,wght,GRAD@0,8..144,50..150,500,-50..100&display=optional" + ); + + Ok(()) + } + + #[test] + fn test_stylesheet_url_encodes_all_weight_ital_combinations() -> Result<()> { + assert_eq!( + get_stylesheet_url( + "Roboto Serif", + &FontAxes { + wght: indexset! {"500".to_owned(), "300".to_owned()}, + ital: indexset! {FontItal::Normal, FontItal::Italic}, + variable_axes: Some(vec![ + ("GRAD".to_owned(), "-50..100".to_owned()), + ("opsz".to_owned(), "8..144".to_owned()), + ("wdth".to_owned(), "50..150".to_owned()), + ]) + }, + "optional" + )?, + // Note ;-delimited sections for normal@300, normal@500, italic@300, italic@500 + "https://fonts.googleapis.com/css2?family=Roboto+Serif:ital,opsz,wdth,wght,GRAD@0,8..144,50..150,300,-50..100;0,8..144,50..150,500,-50..100;1,8..144,50..150,300,-50..100;1,8..144,50..150,500,-50..100&display=optional" + ); + + Ok(()) + } + + #[test] + fn test_variable_font_without_wgth_axis() -> Result<()> { + assert_eq!( + get_stylesheet_url( + "Nabla", + &FontAxes { + wght: indexset! {}, + ital: indexset! {}, + variable_axes: Some(vec![ + ("EDPT".to_owned(), "0..200".to_owned()), + ("EHLT".to_owned(), "0..24".to_owned()), + ]) + }, + "optional" + )?, + "https://fonts.googleapis.com/css2?family=Nabla:EDPT,EHLT@0..200,0..24&display=optional" + ); + + Ok(()) + } +} From 38ab8397a40857e734320dbf4533bcb6992168bf Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Thu, 8 Dec 2022 08:54:11 -0800 Subject: [PATCH 260/672] [6/n] @next/font/google: Cache stylesheet locally (vercel/turbo#2940) * Add font-data.json * Initial implementation of dynamic ImportMapping replacement * Extract font urls * Download fonts * Update stylesheet * Vc-ify * Apply suggestions from code review Co-authored-by: Alex Kirszenberg <alex.kirszenberg@vercel.com> * Check in font-data.json update script and update font-data.json * Add font update to ci schedule * assert -> bail * Remove extraction and caching of fonts Co-authored-by: Alex Kirszenberg <alex.kirszenberg@vercel.com> --- packages/next-swc/crates/next-core/Cargo.toml | 6 + .../next-swc/crates/next-core/src/fallback.rs | 3 +- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../__generated__/font-data.json | 17717 ++++++++++++++++ .../next-core/src/next_font_google/mod.rs | 212 +- .../next-core/src/next_font_google/options.rs | 10 +- .../next-core/src/next_font_google/util.rs | 12 +- .../crates/next-core/src/next_import_map.rs | 27 +- packages/next-swc/crates/next-dev/src/lib.rs | 6 + 9 files changed, 17973 insertions(+), 21 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 45ea076a6da359..7c13650a1d5d6b 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -10,13 +10,19 @@ bench = false [dependencies] anyhow = "1.0.47" +auto-hash-map = { path = "../auto-hash-map" } indexmap = { workspace = true, features = ["serde"] } +indoc = "1.0" mime = "0.3.16" +once_cell = "1.13.0" +qstring = "0.7.2" serde = "1.0.136" serde_json = "1.0.85" turbo-tasks = { path = "../turbo-tasks" } turbo-tasks-env = { path = "../turbo-tasks-env" } +turbo-tasks-fetch = { path = "../turbo-tasks-fetch" } turbo-tasks-fs = { path = "../turbo-tasks-fs" } +turbo-tasks-hash = { path = "../turbo-tasks-hash" } turbopack = { path = "../turbopack" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } diff --git a/packages/next-swc/crates/next-core/src/fallback.rs b/packages/next-swc/crates/next-core/src/fallback.rs index c265b12e6e90c4..4af8404a145232 100644 --- a/packages/next-swc/crates/next-core/src/fallback.rs +++ b/packages/next-swc/crates/next-core/src/fallback.rs @@ -15,7 +15,6 @@ use turbopack_core::{ use turbopack_dev_server::html::DevHtmlAssetVc; use crate::{ - embed_js::attached_next_js_package_path, next_client::context::{ get_client_chunking_context, get_client_environment, get_client_module_options_context, get_client_resolve_options_context, get_client_runtime_entries, ContextType, @@ -39,7 +38,7 @@ pub async fn get_fallback_page( let entries = get_client_runtime_entries(project_root, env, ty); let mut import_map = ImportMap::empty(); - insert_next_shared_aliases(&mut import_map, attached_next_js_package_path(project_root)); + insert_next_shared_aliases(&mut import_map, project_root); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 3a4c37cf47993f..56bdfae37e94c9 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -27,6 +27,7 @@ pub use web_entry_source::create_web_entry_source; pub fn register() { turbo_tasks::register(); turbo_tasks_fs::register(); + turbo_tasks_fetch::register(); turbopack_dev_server::register(); turbopack::register(); turbopack_node::register(); diff --git a/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json b/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json new file mode 100644 index 00000000000000..eede6bc16e5155 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json @@ -0,0 +1,17717 @@ +{ + "ABeeZee": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Abel": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Abhaya Libre": { + "weights": [ + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Aboreto": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Abril Fatface": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Abyssinica SIL": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Aclonica": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Acme": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Actor": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Adamina": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Advent Pro": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Aguafina Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Akaya Kanadaka": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Akaya Telivigala": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Akronim": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Akshar": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Aladin": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alata": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alatsi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Albert Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Aldrich": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alef": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Alegreya": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Alegreya SC": { + "weights": [ + "400", + "500", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Alegreya Sans": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Alegreya Sans SC": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Aleo": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Alex Brush": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alexandria": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Alfa Slab One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alice": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alike": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alike Angular": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alkalami": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Allan": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Allerta": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Allerta Stencil": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Allison": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Allura": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Almarai": { + "weights": [ + "300", + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Almendra": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Almendra Display": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Almendra SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Alumni Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Alumni Sans Collegiate One": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Alumni Sans Inline One": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Alumni Sans Pinstripe": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Amarante": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Amaranth": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Amatic SC": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Amethysta": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Amiko": { + "weights": [ + "400", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Amiri": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Amiri Quran": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Amita": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Anaheim": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Andada Pro": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 840, + "defaultValue": 400 + } + ] + }, + "Andika": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Anek Bangla": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Devanagari": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Gujarati": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Gurmukhi": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Kannada": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Latin": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Malayalam": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Odia": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Tamil": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Anek Telugu": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Angkor": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Annie Use Your Telescope": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Anonymous Pro": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Antic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Antic Didone": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Antic Slab": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Anton": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Antonio": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Anybody": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 50, + "max": 150, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Arapey": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Arbutus": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Arbutus Slab": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Architects Daughter": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Archivo": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Archivo Black": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Archivo Narrow": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Are You Serious": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Aref Ruqaa": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Aref Ruqaa Ink": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Arima": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Arima Madurai": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Arimo": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Arizonia": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Armata": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Arsenal": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Artifika": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Arvo": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Arya": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Asap": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Asap Condensed": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Asar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Asset": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Assistant": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Astloch": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Asul": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Athiti": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Atkinson Hyperlegible": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Atma": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Atomic Age": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Aubrey": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Audiowide": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Autour One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Average": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Average Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Averia Gruesa Libre": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Averia Libre": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Averia Sans Libre": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Averia Serif Libre": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Azeret Mono": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "B612": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "B612 Mono": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "BIZ UDGothic": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "BIZ UDMincho": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "BIZ UDPGothic": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "BIZ UDPMincho": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Babylonica": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bad Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bahiana": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bahianita": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bai Jamjuree": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Bakbak One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ballet": { + "weights": [ + "400", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "opsz", + "min": 16, + "max": 72, + "defaultValue": 16 + } + ] + }, + "Baloo 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Bhai 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Bhaijaan 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Bhaina 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Chettan 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Da 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Paaji 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Tamma 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Tammudu 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Baloo Thambi 2": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Balsamiq Sans": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Balthazar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bangers": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Barlow": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Barlow Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Barlow Semi Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Barriecito": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Barrio": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Basic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Baskervville": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Battambang": { + "weights": [ + "100", + "300", + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Baumans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bayon": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Be Vietnam Pro": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Beau Rivage": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bebas Neue": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Belgrano": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bellefair": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Belleza": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bellota": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Bellota Text": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "BenchNine": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Benne": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bentham": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Berkshire Swash": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Besley": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Beth Ellen": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bevan": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "BhuTuka Expanded One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Big Shoulders Display": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Inline Display": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Inline Text": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Stencil Display": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Stencil Text": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Big Shoulders Text": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Bigelow Rules": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bigshot One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bilbo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bilbo Swash Caps": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "BioRhyme": { + "weights": [ + "200", + "300", + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "BioRhyme Expanded": { + "weights": [ + "200", + "300", + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Birthstone": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Birthstone Bounce": { + "weights": [ + "400", + "500" + ], + "styles": [ + "normal" + ] + }, + "Biryani": { + "weights": [ + "200", + "300", + "400", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Bitter": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Black And White Picture": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Black Han Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Black Ops One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Blaka": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Blaka Hollow": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Blaka Ink": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Blinker": { + "weights": [ + "100", + "200", + "300", + "400", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Bodoni Moda": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 6, + "max": 96, + "defaultValue": 11 + }, + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Bokor": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bona Nova": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Bonbon": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bonheur Royale": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Boogaloo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bowlby One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bowlby One SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Brawler": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Bree Serif": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Brygada 1918": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Bubblegum Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bubbler One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Buda": { + "weights": [ + "300" + ], + "styles": [ + "normal" + ] + }, + "Buenard": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Bungee": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bungee Hairline": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bungee Inline": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bungee Outline": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bungee Shade": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Bungee Spice": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Butcherman": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Butterfly Kids": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cabin": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Cabin Condensed": { + "weights": [ + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Cabin Sketch": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Caesar Dressing": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cagliostro": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cairo": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "1000", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "slnt", + "min": -11, + "max": 11, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Cairo Play": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "1000", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "slnt", + "min": -11, + "max": 11, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Caladea": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Calistoga": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Calligraffitti": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cambay": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Cambo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Candal": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cantarell": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Cantata One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cantora One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Capriola": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Caramel": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Carattere": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cardo": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Carme": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Carrois Gothic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Carrois Gothic SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Carter One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Castoro": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Catamaran": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Caudex": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Caveat": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Caveat Brush": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cedarville Cursive": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ceviche One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Chakra Petch": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Changa": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Changa One": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Chango": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Charis SIL": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Charm": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Charmonman": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Chathura": { + "weights": [ + "100", + "300", + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Chau Philomene One": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Chela One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Chelsea Market": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Chenla": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cherish": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cherry Cream Soda": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cherry Swash": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Chewy": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Chicle": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Chilanka": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Chivo": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Chonburi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cinzel": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Cinzel Decorative": { + "weights": [ + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Clicker Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Coda": { + "weights": [ + "400", + "800" + ], + "styles": [ + "normal" + ] + }, + "Coda Caption": { + "weights": [ + "800" + ], + "styles": [ + "normal" + ] + }, + "Codystar": { + "weights": [ + "300", + "400" + ], + "styles": [ + "normal" + ] + }, + "Coiny": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Combo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Comfortaa": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Comforter": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Comforter Brush": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Comic Neue": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Coming Soon": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Commissioner": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Concert One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Condiment": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Content": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Contrail One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Convergence": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cookie": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Copse": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Corben": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Corinthia": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Cormorant": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Cormorant Garamond": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Cormorant Infant": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Cormorant SC": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Cormorant Unicase": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Cormorant Upright": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Courgette": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Courier Prime": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Cousine": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Coustard": { + "weights": [ + "400", + "900" + ], + "styles": [ + "normal" + ] + }, + "Covered By Your Grace": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Crafty Girls": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Creepster": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Crete Round": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Crimson Pro": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Crimson Text": { + "weights": [ + "400", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Croissant One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Crushed": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cuprum": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Cute Font": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cutive": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Cutive Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "DM Mono": { + "weights": [ + "300", + "400", + "500" + ], + "styles": [ + "normal", + "italic" + ] + }, + "DM Sans": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "DM Serif Display": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "DM Serif Text": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Damion": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dancing Script": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Dangrek": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Darker Grotesque": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "David Libre": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Dawning of a New Day": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Days One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dekko": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dela Gothic One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Delius": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Delius Swash Caps": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Delius Unicase": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Della Respira": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Denk One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Devonshire": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dhurjati": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Didact Gothic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Diplomata": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Diplomata SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Do Hyeon": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dokdo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Domine": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Donegal One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dongle": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Doppio One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dorsa": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dosis": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "DotGothic16": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Dr Sugiyama": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Duru Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "DynaPuff": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Dynalight": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "EB Garamond": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Eagle Lake": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "East Sea Dokdo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Eater": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Economica": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Eczar": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Edu NSW ACT Foundation": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu QLD Beginner": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu SA Beginner": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu TAS Beginner": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Edu VIC WA NT Beginner": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "El Messiri": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Electrolize": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Elsie": { + "weights": [ + "400", + "900" + ], + "styles": [ + "normal" + ] + }, + "Elsie Swash Caps": { + "weights": [ + "400", + "900" + ], + "styles": [ + "normal" + ] + }, + "Emblema One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Emilys Candy": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Encode Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Encode Sans Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Encode Sans Expanded": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Encode Sans SC": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Encode Sans Semi Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Encode Sans Semi Expanded": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Engagement": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Englebert": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Enriqueta": { + "weights": [ + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Ephesis": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Epilogue": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Erica One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Esteban": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Estonia": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Euphoria Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ewert": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Exo": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Exo 2": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Expletus Sans": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Explora": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fahkwang": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Familjen Grotesk": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fanwood Text": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Farro": { + "weights": [ + "300", + "400", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Farsan": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fascinate": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fascinate Inline": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Faster One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fasthand": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fauna One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Faustina": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Federant": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Federo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Felipa": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fenix": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Festive": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Figtree": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Finger Paint": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Finlandica": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fira Code": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fira Mono": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Fira Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Fira Sans Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Fira Sans Extra Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Fjalla One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fjord One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Flamenco": { + "weights": [ + "300", + "400" + ], + "styles": [ + "normal" + ] + }, + "Flavors": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fleur De Leah": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Flow Block": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Flow Circular": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Flow Rounded": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fondamento": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Fontdiner Swanky": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Forum": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fragment Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Francois One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Frank Ruhl Libre": { + "weights": [ + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Fraunces": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "SOFT", + "min": 0, + "max": 100, + "defaultValue": 0 + }, + { + "tag": "WONK", + "min": 0, + "max": 1, + "defaultValue": 0 + }, + { + "tag": "opsz", + "min": 9, + "max": 144, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Freckle Face": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fredericka the Great": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fredoka": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Fredoka One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Freehand": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fresca": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Frijole": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fruktur": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Fugaz One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fuggles": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Fuzzy Bubbles": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "GFS Didot": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "GFS Neohellenic": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Gabriela": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gaegu": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Gafata": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Galada": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Galdeano": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Galindo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gamja Flower": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gantari": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Gayathri": { + "weights": [ + "100", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Gelasio": { + "weights": [ + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Gemunu Libre": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Genos": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Gentium Book Basic": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Gentium Book Plus": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Gentium Plus": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Geo": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Georama": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 150, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Geostar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Geostar Fill": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Germania One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gideon Roman": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gidugu": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gilda Display": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Girassol": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Give You Glory": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Glass Antiqua": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Glegoo": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Gloria Hallelujah": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Glory": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Gluten": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "slnt", + "min": -13, + "max": 13, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Goblin One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gochi Hand": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Goldman": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Gorditas": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Gothic A1": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Gotu": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Goudy Bookletter 1911": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gowun Batang": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Gowun Dodum": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Graduate": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Grand Hotel": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Grandstander": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Grape Nuts": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gravitas One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Great Vibes": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Grechen Fuemen": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Grenze": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Grenze Gotisch": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Grey Qo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Griffy": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gruppo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gudea": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Gugi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gulzar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gupter": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Gurajada": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Gwendolyn": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Habibi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hachi Maru Pop": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hahmlet": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Halant": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Hammersmith One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hanalei": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hanalei Fill": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Handlee": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hanuman": { + "weights": [ + "100", + "300", + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Happy Monkey": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Harmattan": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Headland One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Heebo": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Henny Penny": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hepta Slab": { + "weights": [ + "1", + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 1, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Herr Von Muellerhoff": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hi Melody": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hina Mincho": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hind": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Hind Guntur": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Hind Madurai": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Hind Siliguri": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Hind Vadodara": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Holtwood One SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Homemade Apple": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Homenaje": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hubballi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Hurricane": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Mono": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IBM Plex Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IBM Plex Sans Arabic": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Sans Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IBM Plex Sans Devanagari": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Sans Hebrew": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Sans JP": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Sans KR": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Sans Thai": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Sans Thai Looped": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "IBM Plex Serif": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IM Fell DW Pica": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IM Fell DW Pica SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "IM Fell Double Pica": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IM Fell Double Pica SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "IM Fell English": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IM Fell English SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "IM Fell French Canon": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IM Fell French Canon SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "IM Fell Great Primer": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "IM Fell Great Primer SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ibarra Real Nova": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Iceberg": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Iceland": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Imbue": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "opsz", + "min": 10, + "max": 100, + "defaultValue": 10 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Imperial Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Imprima": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Inconsolata": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 50, + "max": 200, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Inder": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Indie Flower": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ingrid Darling": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Inika": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Inknut Antiqua": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Inria Sans": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Inria Serif": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Inspiration": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Inter": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "slnt", + "min": -10, + "max": 0, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Inter Tight": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Irish Grover": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Island Moments": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Istok Web": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Italiana": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Italianno": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Itim": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jacques Francois": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jacques Francois Shadow": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jaldi": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "JetBrains Mono": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Jim Nightshade": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Joan": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jockey One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jolly Lodger": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jomhuria": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jomolhari": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Josefin Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Josefin Slab": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Jost": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Joti One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jua": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Judson": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Julee": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Julius Sans One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Junge": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Jura": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Just Another Hand": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Just Me Again Down Here": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "K2D": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Kadwa": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Kaisei Decol": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Kaisei HarunoUmi": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Kaisei Opti": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Kaisei Tokumin": { + "weights": [ + "400", + "500", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Kalam": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Kameron": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Kanit": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Kantumruy": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Kantumruy Pro": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Karantina": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Karla": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Karma": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Katibeh": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kaushan Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kavivanar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kavoon": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kdam Thmor Pro": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Keania One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kelly Slab": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kenia": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Khand": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Khmer": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Khula": { + "weights": [ + "300", + "400", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Kings": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kirang Haerang": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kite One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kiwi Maru": { + "weights": [ + "300", + "400", + "500" + ], + "styles": [ + "normal" + ] + }, + "Klee One": { + "weights": [ + "400", + "600" + ], + "styles": [ + "normal" + ] + }, + "Knewave": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "KoHo": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Kodchasan": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Koh Santepheap": { + "weights": [ + "100", + "300", + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Kolker Brush": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kosugi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kosugi Maru": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kotta One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Koulen": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kranky": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kreon": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Kristi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Krona One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Krub": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Kufam": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Kulim Park": { + "weights": [ + "200", + "300", + "400", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Kumar One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kumar One Outline": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Kumbh Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Kurale": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "La Belle Aurore": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lacquer": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Laila": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Lakki Reddy": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lalezar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lancelot": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Langar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lateef": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Lato": { + "weights": [ + "100", + "300", + "400", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Lavishly Yours": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "League Gothic": { + "weights": [ + "400", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + } + ] + }, + "League Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "League Spartan": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Leckerli One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ledger": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lekton": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Lemon": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lemonada": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Lexend": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Deca": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Exa": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Giga": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Mega": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Peta": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Tera": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Lexend Zetta": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Libre Barcode 128": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Barcode 128 Text": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Barcode 39": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Barcode 39 Extended": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Barcode 39 Extended Text": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Barcode 39 Text": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Barcode EAN13 Text": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Baskerville": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Libre Bodoni": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Libre Caslon Display": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Libre Caslon Text": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Libre Franklin": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Licorice": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Life Savers": { + "weights": [ + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Lilita One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lily Script One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Limelight": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Linden Hill": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Literata": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 7, + "max": 72, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Liu Jian Mao Cao": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Livvic": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Lobster": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lobster Two": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Londrina Outline": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Londrina Shadow": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Londrina Sketch": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Londrina Solid": { + "weights": [ + "100", + "300", + "400", + "900" + ], + "styles": [ + "normal" + ] + }, + "Long Cang": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lora": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Love Light": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Love Ya Like A Sister": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Loved by the King": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lovers Quarrel": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Luckiest Guy": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Lusitana": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Lustria": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Luxurious Roman": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Luxurious Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "M PLUS 1": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "M PLUS 1 Code": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "M PLUS 1p": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "M PLUS 2": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "M PLUS Code Latin": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 100, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "M PLUS Rounded 1c": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Ma Shan Zheng": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Macondo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Macondo Swash Caps": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mada": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Magra": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Maiden Orange": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Maitree": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Major Mono Display": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mako": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mali": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Mallanna": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mandali": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Manjari": { + "weights": [ + "100", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Manrope": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Mansalva": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Manuale": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Marcellus": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Marcellus SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Marck Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Margarine": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Marhey": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Markazi Text": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Marko One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Marmelad": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Martel": { + "weights": [ + "200", + "300", + "400", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Martel Sans": { + "weights": [ + "200", + "300", + "400", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Marvel": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Mate": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Mate SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Maven Pro": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "McLaren": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mea Culpa": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Meddon": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "MedievalSharp": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Medula One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Meera Inimai": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Megrim": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Meie Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Meow Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Merienda": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Merienda One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Merriweather": { + "weights": [ + "300", + "400", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Merriweather Sans": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Metal": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Metal Mania": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Metamorphous": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Metrophobic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Michroma": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Milonga": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Miltonian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Miltonian Tattoo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mina": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Mingzat": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Miniver": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Miriam Libre": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Mirza": { + "weights": [ + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Miss Fajardose": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mitr": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Mochiy Pop One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mochiy Pop P One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Modak": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Modern Antiqua": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mogra": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mohave": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Molengo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Molle": { + "weights": [ + "400" + ], + "styles": [ + "italic" + ] + }, + "Monda": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Monofett": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Monoton": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Monsieur La Doulaise": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Montaga": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Montagu Slab": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "opsz", + "min": 16, + "max": 144, + "defaultValue": 144 + }, + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "MonteCarlo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Montez": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Montserrat": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Montserrat Alternates": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Montserrat Subrayada": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Moo Lah Lah": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Moon Dance": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Moul": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Moulpali": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mountains of Christmas": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Mouse Memoirs": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mr Bedfort": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mr Dafoe": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mr De Haviland": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mrs Saint Delafield": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mrs Sheppards": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ms Madi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mukta": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Mukta Mahee": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Mukta Malar": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Mukta Vaani": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Mulish": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "1000", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Murecho": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "MuseoModerno": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "My Soul": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Mystery Quest": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "NTR": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nabla": { + "weights": [ + "400", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "EDPT", + "min": 0, + "max": 200, + "defaultValue": 100 + }, + { + "tag": "EHLT", + "min": 0, + "max": 24, + "defaultValue": 12 + } + ] + }, + "Nanum Brush Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nanum Gothic": { + "weights": [ + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Nanum Gothic Coding": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Nanum Myeongjo": { + "weights": [ + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Nanum Pen Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Neonderthaw": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nerko One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Neucha": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Neuton": { + "weights": [ + "200", + "300", + "400", + "700", + "800" + ], + "styles": [ + "normal", + "italic" + ] + }, + "New Rocker": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "New Tegomin": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "News Cycle": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Newsreader": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 6, + "max": 72, + "defaultValue": 16 + }, + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Niconne": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Niramit": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Nixie One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nobile": { + "weights": [ + "400", + "500", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Nokora": { + "weights": [ + "100", + "300", + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Norican": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nosifer": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Notable": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nothing You Could Do": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noticia Text": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Noto Color Emoji": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Emoji": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Kufi Arabic": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Music": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Naskh Arabic": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Nastaliq Urdu": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Rashi Hebrew": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Noto Sans Adlam": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Adlam Unjoined": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Anatolian Hieroglyphs": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Arabic": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Armenian": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Avestan": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Balinese": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Bamum": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Bassa Vah": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Batak": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Bengali": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Bhaiksuki": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Brahmi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Buginese": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Buhid": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Canadian Aboriginal": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Carian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Caucasian Albanian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Chakma": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Cham": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Cherokee": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Coptic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Cuneiform": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Cypriot": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Deseret": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Devanagari": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Display": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Duployan": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Egyptian Hieroglyphs": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Elbasan": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Elymaic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Ethiopic": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Georgian": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Glagolitic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Gothic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Grantha": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Gujarati": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Gunjala Gondi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Gurmukhi": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans HK": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Hanifi Rohingya": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Hanunoo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Hatran": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Hebrew": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Imperial Aramaic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Indic Siyaq Numbers": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Inscriptional Pahlavi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Inscriptional Parthian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans JP": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Javanese": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans KR": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Kaithi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Kannada": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Kayah Li": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Kharoshthi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Khmer": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Khojki": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Khudawadi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Lao": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Lao Looped": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Lepcha": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Limbu": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Linear A": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Linear B": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Lisu": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Lycian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Lydian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Mahajani": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Malayalam": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Mandaic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Manichaean": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Marchen": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Masaram Gondi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Math": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Mayan Numerals": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Medefaidrin": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Meetei Mayek": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Mende Kikakui": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Meroitic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Miao": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Modi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Mongolian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Mono": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Mro": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Multani": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Myanmar": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans N Ko": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Nabataean": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans New Tai Lue": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Newa": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Nushu": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Ogham": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Ol Chiki": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Old Hungarian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Old Italic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Old North Arabian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Old Permic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Old Persian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Old Sogdian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Old South Arabian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Old Turkic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Oriya": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Osage": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Osmanya": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Pahawh Hmong": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Palmyrene": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Pau Cin Hau": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Phags Pa": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Phoenician": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Psalter Pahlavi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Rejang": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Runic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans SC": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Samaritan": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Saurashtra": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Sharada": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Shavian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Siddham": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Sinhala": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Sogdian": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Sora Sompeng": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Soyombo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Sundanese": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Syloti Nagri": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Symbols": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Symbols 2": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Syriac": { + "weights": [ + "100", + "400", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans TC": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Tagalog": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Tagbanwa": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Tai Le": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Tai Tham": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Sans Tai Viet": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Takri": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Tamil": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Tamil Supplement": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Telugu": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Thaana": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Thai": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Sans Thai Looped": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Tifinagh": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Tirhuta": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Ugaritic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Vai": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Wancho": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Warang Citi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Yi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Sans Zanabazar Square": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Noto Serif Ahom": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Armenian": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Balinese": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Bengali": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Devanagari": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Display": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Dogra": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Ethiopic": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Georgian": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Grantha": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Gujarati": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Gurmukhi": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif HK": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Hebrew": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif JP": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif KR": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Kannada": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Khmer": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Khojki": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Serif Lao": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Malayalam": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Myanmar": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Nyiakeng Puachue Hmong": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Serif Oriya": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Serif SC": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Sinhala": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif TC": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Tamil": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Tangut": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Noto Serif Telugu": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Thai": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Tibetan": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Noto Serif Yezidi": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Noto Traditional Nushu": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Cut": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Flat": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Oval": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Round": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Slim": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nova Square": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Numans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Nunito": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "1000", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Nunito Sans": { + "weights": [ + "200", + "300", + "400", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Nuosu SIL": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Odibee Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Odor Mean Chey": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Offside": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Oi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Old Standard TT": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Oldenburg": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ole": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Oleo Script": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Oleo Script Swash Caps": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Oooh Baby": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Open Sans": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 300, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Oranienbaum": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Orbitron": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Oregano": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Orelega One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Orienta": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Original Surfer": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Oswald": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Outfit": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Over the Rainbow": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Overlock": { + "weights": [ + "400", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Overlock SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Overpass": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Overpass Mono": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Ovo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Oxanium": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Oxygen": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Oxygen Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "PT Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "PT Sans": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "PT Sans Caption": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "PT Sans Narrow": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "PT Serif": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "PT Serif Caption": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Pacifico": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Padauk": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Palanquin": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Palanquin Dark": { + "weights": [ + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Pangolin": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Paprika": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Parisienne": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Passero One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Passion One": { + "weights": [ + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Passions Conflict": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pathway Gothic One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Patrick Hand": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Patrick Hand SC": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pattaya": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Patua One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pavanam": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Paytone One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Peddana": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Peralta": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Permanent Marker": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Petemoss": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Petit Formal Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Petrona": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Philosopher": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Piazzolla": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 8, + "max": 30, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Piedra": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pinyon Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pirata One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Plaster": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Play": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Playball": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Playfair Display": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Playfair Display SC": { + "weights": [ + "400", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Plus Jakarta Sans": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Podkova": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Poiret One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Poller One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Poly": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Pompiere": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pontano Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Poor Story": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Poppins": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Port Lligat Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Port Lligat Slab": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Potta One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pragati Narrow": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Praise": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Prata": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Preahvihear": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Press Start 2P": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Pridi": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Princess Sofia": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Prociono": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Prompt": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Prosto One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Proza Libre": { + "weights": [ + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Public Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Puppies Play": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Puritan": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Purple Purse": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Qahiri": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Quando": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Quantico": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Quattrocento": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Quattrocento Sans": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Questrial": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Quicksand": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Quintessential": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Qwigley": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Qwitcher Grypen": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Racing Sans One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Radio Canada": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Radley": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Rajdhani": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Rakkas": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Raleway": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Raleway Dots": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ramabhadra": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ramaraja": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rambla": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Rammetto One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rampart One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ranchers": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rancho": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ranga": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Rasa": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Rationale": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ravi Prakash": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Readex Pro": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 160, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Recursive": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "1000", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "CASL", + "min": 0, + "max": 1, + "defaultValue": 0 + }, + { + "tag": "CRSV", + "min": 0, + "max": 1, + "defaultValue": 0.5 + }, + { + "tag": "MONO", + "min": 0, + "max": 1, + "defaultValue": 0 + }, + { + "tag": "slnt", + "min": -15, + "max": 0, + "defaultValue": 0 + }, + { + "tag": "wght", + "min": 300, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Red Hat Display": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Red Hat Mono": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Red Hat Text": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Red Rose": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Redacted": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Redacted Script": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Redressed": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Reem Kufi": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Reem Kufi Fun": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Reem Kufi Ink": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Reenie Beanie": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Reggae One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Revalia": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rhodium Libre": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ribeye": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ribeye Marrow": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Righteous": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Risque": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Road Rage": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Roboto": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Roboto Condensed": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Roboto Flex": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "1000", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "GRAD", + "min": -200, + "max": 150, + "defaultValue": 0 + }, + { + "tag": "XTRA", + "min": 323, + "max": 603, + "defaultValue": 468 + }, + { + "tag": "YOPQ", + "min": 25, + "max": 135, + "defaultValue": 79 + }, + { + "tag": "YTAS", + "min": 649, + "max": 854, + "defaultValue": 750 + }, + { + "tag": "YTDE", + "min": -305, + "max": -98, + "defaultValue": -203 + }, + { + "tag": "YTFI", + "min": 560, + "max": 788, + "defaultValue": 738 + }, + { + "tag": "YTLC", + "min": 416, + "max": 570, + "defaultValue": 514 + }, + { + "tag": "YTUC", + "min": 528, + "max": 760, + "defaultValue": 712 + }, + { + "tag": "opsz", + "min": 8, + "max": 144, + "defaultValue": 14 + }, + { + "tag": "slnt", + "min": -10, + "max": 0, + "defaultValue": 0 + }, + { + "tag": "wdth", + "min": 25, + "max": 151, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 1000, + "defaultValue": 400 + } + ] + }, + "Roboto Mono": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Roboto Serif": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "GRAD", + "min": -50, + "max": 100, + "defaultValue": 0 + }, + { + "tag": "opsz", + "min": 8, + "max": 144, + "defaultValue": 14 + }, + { + "tag": "wdth", + "min": 50, + "max": 150, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Roboto Slab": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Rochester": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rock Salt": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "RocknRoll One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rokkitt": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Romanesco": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ropa Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Rosario": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Rosarivo": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Rouge Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rowdies": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Rozha One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Rubik Beastly": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Bubbles": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Burned": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Dirt": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Distressed": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Glitch": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Iso": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Marker Hatch": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Maze": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Microbe": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Mono One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Moonrocks": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Puddles": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Wet Paint": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ruda": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Rufina": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Ruge Boogie": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ruluko": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rum Raisin": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ruslan Display": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Russo One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ruthie": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rye": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "STIX Two Text": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Sacramento": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sahitya": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Sail": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Saira": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 50, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Saira Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Saira Extra Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Saira Semi Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Saira Stencil One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Salsa": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sanchez": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Sancreek": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sansita": { + "weights": [ + "400", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Sansita Swashed": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Sarabun": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Sarala": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Sarina": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sarpanch": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Sassy Frass": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Satisfy": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sawarabi Gothic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sawarabi Mincho": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Scada": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Scheherazade New": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Schoolbell": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Scope One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Seaweed Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Secular One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sedgwick Ave": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sedgwick Ave Display": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sen": { + "weights": [ + "400", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Send Flowers": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sevillana": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Seymour One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shadows Into Light": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shadows Into Light Two": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shalimar": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shanti": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Share": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Share Tech": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Share Tech Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shippori Antique": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shippori Antique B1": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shippori Mincho": { + "weights": [ + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Shippori Mincho B1": { + "weights": [ + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Shojumaru": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Short Stack": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Shrikhand": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Siemreap": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sigmar One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Signika": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Signika Negative": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Silkscreen": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Simonetta": { + "weights": [ + "400", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Single Day": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sintony": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Sirin Stencil": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Six Caps": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Skranji": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Slabo 13px": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Slabo 27px": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Slackey": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Smokum": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Smooch": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Smooch Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Smythe": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sniglet": { + "weights": [ + "400", + "800" + ], + "styles": [ + "normal" + ] + }, + "Snippet": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Snowburst One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sofadi One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sofia": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Solway": { + "weights": [ + "300", + "400", + "500", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Song Myung": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sono": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "MONO", + "min": 0, + "max": 1, + "defaultValue": 1 + }, + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Sonsie One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sora": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Sorts Mill Goudy": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Source Code Pro": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Source Sans 3": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Source Sans Pro": { + "weights": [ + "200", + "300", + "400", + "600", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Source Serif 4": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 8, + "max": 60, + "defaultValue": 14 + }, + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Source Serif Pro": { + "weights": [ + "200", + "300", + "400", + "600", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Space Grotesk": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Space Mono": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Special Elite": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Spectral": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Spectral SC": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Spicy Rice": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Spinnaker": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Spirax": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Splash": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Spline Sans": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Spline Sans Mono": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Squada One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Square Peg": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sree Krushnadevaraya": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sriracha": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Srisakdi": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Staatliches": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Stalemate": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Stalinist One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Stardos Stencil": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Stick": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Stick No Bills": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Stint Ultra Condensed": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Stint Ultra Expanded": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Stoke": { + "weights": [ + "300", + "400" + ], + "styles": [ + "normal" + ] + }, + "Strait": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Style Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Stylish": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sue Ellen Francisco": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Suez One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sulphur Point": { + "weights": [ + "300", + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Sumana": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Sunflower": { + "weights": [ + "300", + "500", + "700" + ], + "styles": [ + "normal" + ] + }, + "Sunshiney": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Supermercado One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Sura": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Suranna": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Suravaram": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Suwannaphum": { + "weights": [ + "100", + "300", + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Swanky and Moo Moo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Syncopate": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Syne": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Syne Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Syne Tactile": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Tai Heritage Pro": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Tajawal": { + "weights": [ + "200", + "300", + "400", + "500", + "700", + "800", + "900" + ], + "styles": [ + "normal" + ] + }, + "Tangerine": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Tapestry": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Taprom": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Tauri": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Taviraj": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Teko": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + }, + "Telex": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Tenali Ramakrishna": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Tenor Sans": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Text Me One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Texturina": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "opsz", + "min": 12, + "max": 72, + "defaultValue": 12 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Thasadith": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "The Girl Next Door": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "The Nautigal": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Tienne": { + "weights": [ + "400", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Tillana": { + "weights": [ + "400", + "500", + "600", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Timmana": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Tinos": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Bangla": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Devanagari Hindi": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Devanagari Marathi": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Devanagari Sanskrit": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Gurmukhi": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Kannada": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Tamil": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tiro Telugu": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Titan One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Titillium Web": { + "weights": [ + "200", + "300", + "400", + "600", + "700", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tomorrow": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Tourney": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Trade Winds": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Train One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Trirong": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Trispace": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, + "Trocchi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Trochut": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Truculenta": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "opsz", + "min": 12, + "max": 72, + "defaultValue": 14 + }, + { + "tag": "wdth", + "min": 75, + "max": 125, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Trykker": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Tulpen One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Turret Road": { + "weights": [ + "200", + "300", + "400", + "500", + "700", + "800" + ], + "styles": [ + "normal" + ] + }, + "Twinkle Star": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ubuntu": { + "weights": [ + "300", + "400", + "500", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Ubuntu Condensed": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ubuntu Mono": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Uchen": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Ultra": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Uncial Antiqua": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Underdog": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Unica One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "UnifrakturCook": { + "weights": [ + "700" + ], + "styles": [ + "normal" + ] + }, + "UnifrakturMaguntia": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Unkempt": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + }, + "Unlock": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Unna": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Updock": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Urbanist": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "VT323": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Vampiro One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Varela": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Varela Round": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Varta": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Vast Shadow": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Vazirmatn": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Vesper Libre": { + "weights": [ + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Viaoda Libre": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Vibes": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Vibur": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Vidaloka": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Viga": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Voces": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Volkhov": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Vollkorn": { + "weights": [ + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Vollkorn SC": { + "weights": [ + "400", + "600", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Voltaire": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Vujahday Script": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Waiting for the Sunrise": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Wallpoet": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Walter Turncoat": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Warnes": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Water Brush": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Waterfall": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Wellfleet": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Wendy One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Whisper": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "WindSong": { + "weights": [ + "400", + "500" + ], + "styles": [ + "normal" + ] + }, + "Wire One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Work Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Xanh Mono": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Yaldevi": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Yanone Kaffeesatz": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Yantramanav": { + "weights": [ + "100", + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Yatra One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yellowtail": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yeon Sung": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yeseva One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yesteryear": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yomogi": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yrsa": { + "weights": [ + "300", + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 700, + "defaultValue": 400 + } + ] + }, + "Yuji Boku": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yuji Mai": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yuji Syuku": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Yusei Magic": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "ZCOOL KuaiLe": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "ZCOOL QingKe HuangYou": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "ZCOOL XiaoWei": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zen Antique": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zen Antique Soft": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zen Dots": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zen Kaku Gothic Antique": { + "weights": [ + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Zen Kaku Gothic New": { + "weights": [ + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Zen Kurenaido": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zen Loop": { + "weights": [ + "400" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Zen Maru Gothic": { + "weights": [ + "300", + "400", + "500", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Zen Old Mincho": { + "weights": [ + "400", + "500", + "600", + "700", + "900" + ], + "styles": [ + "normal" + ] + }, + "Zen Tokyo Zoo": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zeyada": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zhi Mang Xing": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Zilla Slab": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal", + "italic" + ] + }, + "Zilla Slab Highlight": { + "weights": [ + "400", + "700" + ], + "styles": [ + "normal" + ] + } +} diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs index 2c19ace9911706..2ce773d0a613d2 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs @@ -1,3 +1,213 @@ -mod options; +use anyhow::{bail, Context, Result}; +use indexmap::IndexMap; +use indoc::formatdoc; +use once_cell::sync::Lazy; +use turbo_tasks::primitives::{OptionStringVc, StringVc}; +use turbo_tasks_fetch::fetch; +use turbo_tasks_fs::{FileContent, FileSystemPathVc}; +use turbopack_core::{ + resolve::{ + options::{ + ImportMapResult, ImportMapResultVc, ImportMapping, ImportMappingReplacement, + ImportMappingReplacementVc, ImportMappingVc, + }, + parse::{Request, RequestVc}, + ResolveResult, + }, + virtual_asset::VirtualAssetVc, +}; + +use crate::{ + embed_js::attached_next_js_package_path, + next_font_google::{ + options::FontDataEntry, + request::NextFontRequest, + util::{get_font_axes, get_stylesheet_url}, + }, +}; + +pub(crate) mod options; pub(crate) mod request; mod util; + +pub const GOOGLE_FONTS_STYLESHEET_URL: &str = "https://fonts.googleapis.com/css2"; +static FONT_DATA: Lazy<FontData> = + Lazy::new(|| serde_json::from_str(include_str!("__generated__/font-data.json")).unwrap()); + +type FontData = IndexMap<String, FontDataEntry>; + +#[turbo_tasks::value(shared)] +pub struct NextFontGoogleReplacer { + project_path: FileSystemPathVc, +} + +#[turbo_tasks::value_impl] +impl NextFontGoogleReplacerVc { + #[turbo_tasks::function] + pub fn new(project_path: FileSystemPathVc) -> Self { + Self::cell(NextFontGoogleReplacer { project_path }) + } +} + +#[turbo_tasks::value_impl] +impl ImportMappingReplacement for NextFontGoogleReplacer { + #[turbo_tasks::function] + fn replace(&self, _capture: &str) -> ImportMappingVc { + ImportMapping::Ignore.into() + } + + #[turbo_tasks::function] + async fn result(&self, request: RequestVc) -> Result<ImportMapResultVc> { + let request = &*request.await?; + let Request::Module { + module: _, + path: _, + query, + } = request else { + return Ok(ImportMapResult::NoEntry.into()); + }; + + let query = &*query.await?; + let js_asset = VirtualAssetVc::new( + attached_next_js_package_path(self.project_path) + .join("internal/font/google/inter.js"), + FileContent::Content( + formatdoc!( + r#" + import cssModule from "@vercel/turbopack-next/internal/font/google/cssmodule.module.css?{}"; + export default {{ + className: cssModule.className + }}; + "#, + // Pass along whichever options we received to the css handler + qstring::QString::new(query.as_ref().unwrap().iter().collect()) + ) + .into(), + ) + .into(), + ); + + Ok(ImportMapResult::Result(ResolveResult::Single(js_asset.into(), vec![]).into()).into()) + } +} + +#[turbo_tasks::value(shared)] +pub struct NextFontGoogleCssModuleReplacer { + project_path: FileSystemPathVc, +} + +#[turbo_tasks::value_impl] +impl NextFontGoogleCssModuleReplacerVc { + #[turbo_tasks::function] + pub fn new(project_path: FileSystemPathVc) -> Self { + Self::cell(NextFontGoogleCssModuleReplacer { project_path }) + } +} + +#[turbo_tasks::value_impl] +impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { + #[turbo_tasks::function] + fn replace(&self, _capture: &str) -> ImportMappingVc { + ImportMapping::Ignore.into() + } + + #[turbo_tasks::function] + async fn result(&self, request: RequestVc) -> Result<ImportMapResultVc> { + let request = &*request.await?; + let Request::Module { + module: _, + path: _, + query, + } = request else { + return Ok(ImportMapResult::NoEntry.into()); + }; + + let query_map = &*query.await?; + // These are invariants from the next/font swc transform. Regular errors instead + // of Issues should be okay. + let query_map = query_map + .as_ref() + .context("@next/font/google queries must exist")?; + + if query_map.len() != 1 { + bail!("@next/font/google queries must only have one entry"); + } + + let Some((json, _)) = query_map.iter().next() else { + bail!("Expected one entry"); + }; + + let request: StringVc = StringVc::cell(json.to_owned()); + let stylesheet_url = get_stylesheet_url_from_request(request); + + // TODO(WEB-274): Handle this failing (e.g. connection issues). This should be + // an Issue. + let stylesheet_res = fetch( + stylesheet_url, + OptionStringVc::cell(Some( + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like \ + Gecko) Chrome/104.0.0.0 Safari/537.36" + .to_owned(), + )), + ) + .await?; + + // TODO(WEB-274): Emit an issue instead + if stylesheet_res.status >= 400 { + bail!("Expected a successful response for Google fonts stylesheet"); + } + + let stylesheet = &*stylesheet_res.body.to_string().await?; + let options = options_from_request(request).await?; + + let css_asset = VirtualAssetVc::new( + attached_next_js_package_path(self.project_path) + .join("internal/font/google/cssmodule.module.css"), + FileContent::Content( + formatdoc!( + r#" + {} + + .className {{ + font-family: "{}"; + }} + "#, + stylesheet, + options.font_family + ) + .into(), + ) + .into(), + ); + + Ok(ImportMapResult::Result(ResolveResult::Single(css_asset.into(), vec![]).into()).into()) + } +} + +#[turbo_tasks::function] +async fn get_stylesheet_url_from_request(request_json: StringVc) -> Result<StringVc> { + let options = options_from_request(request_json).await?; + + Ok(StringVc::cell(get_stylesheet_url( + GOOGLE_FONTS_STYLESHEET_URL, + &options.font_family, + &get_font_axes( + &FONT_DATA, + &options.font_family, + &options.weights, + &options.styles, + &options.selected_variable_axes, + )?, + &options.display, + )?)) +} + +#[turbo_tasks::value(transparent)] +struct NextFontGoogleOptions(self::options::NextFontGoogleOptions); + +#[turbo_tasks::function] +async fn options_from_request(request: StringVc) -> Result<NextFontGoogleOptionsVc> { + let request: NextFontRequest = serde_json::from_str(&request.await?)?; + + self::options::options_from_request(&request, &FONT_DATA).map(NextFontGoogleOptionsVc::cell) +} diff --git a/packages/next-swc/crates/next-core/src/next_font_google/options.rs b/packages/next-swc/crates/next-core/src/next_font_google/options.rs index 4e12acdb1f2a6b..c0f443cb7a75bc 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/options.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/options.rs @@ -1,15 +1,15 @@ use anyhow::{anyhow, Context, Result}; use indexmap::{indexset, IndexMap, IndexSet}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; +use turbo_tasks::trace::TraceRawVcs; use super::request::{NextFontRequest, OneOrManyStrings}; -#[allow(dead_code)] const ALLOWED_DISPLAY_VALUES: &[&str] = &["auto", "block", "swap", "fallback", "optional"]; pub type FontData = IndexMap<String, FontDataEntry>; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] pub struct NextFontGoogleOptions { pub font_family: String, pub weights: FontWeights, @@ -23,8 +23,7 @@ pub struct NextFontGoogleOptions { pub subsets: Option<Vec<String>>, } -#[derive(Debug, PartialEq)] -#[allow(dead_code)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] pub enum FontWeights { Variable, Fixed(IndexSet<String>), @@ -49,7 +48,6 @@ pub struct Axis { // Transforms the request fields to a struct suitable for making requests to // Google Fonts. Similar to @next/font/google's validateData: // https://github.com/vercel/next.js/blob/28454c6ddbc310419467e5415aee26e48d079b46/packages/font/src/google/utils.ts#L22 -#[allow(dead_code)] pub fn options_from_request( request: &NextFontRequest, data: &IndexMap<String, FontDataEntry>, diff --git a/packages/next-swc/crates/next-core/src/next_font_google/util.rs b/packages/next-swc/crates/next-core/src/next_font_google/util.rs index dbf3befa2bcbb8..842a84d85c49eb 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/util.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/util.rs @@ -5,8 +5,6 @@ use indexmap::{indexset, IndexSet}; use super::options::{FontData, FontWeights}; -const GOOGLE_FONTS_STYLESHEET_URL: &str = "https://fonts.googleapis.com/css2"; - #[derive(Debug, PartialEq)] pub(crate) struct FontAxes { pub(crate) wght: IndexSet<String>, @@ -21,7 +19,6 @@ pub(crate) enum FontItal { } // Derived from https://github.com/vercel/next.js/blob/9e098da0915a2a4581bebe2270953a1216be1ba4/packages/font/src/google/utils.ts#L232 -#[allow(dead_code)] pub(crate) fn get_font_axes( font_data: &FontData, font_family: &str, @@ -106,8 +103,8 @@ pub(crate) fn get_font_axes( } // Derived from https://github.com/vercel/next.js/blob/9e098da0915a2a4581bebe2270953a1216be1ba4/packages/font/src/google/utils.ts#L128 -#[allow(dead_code)] pub(crate) fn get_stylesheet_url( + root_url: &str, font_family: &str, axes: &FontAxes, display: &str, @@ -204,7 +201,7 @@ pub(crate) fn get_stylesheet_url( Ok(format!( "{}?family={}:{}@{}&display={}", - GOOGLE_FONTS_STYLESHEET_URL, + root_url, font_family.replace(' ', "+"), variant_keys_str, variant_values_str, @@ -221,6 +218,7 @@ mod tests { use crate::next_font_google::{ options::{FontData, FontWeights}, util::{get_stylesheet_url, FontAxes, FontItal}, + GOOGLE_FONTS_STYLESHEET_URL, }; #[test] @@ -371,6 +369,7 @@ mod tests { fn test_stylesheet_url_no_axes() -> Result<()> { assert_eq!( get_stylesheet_url( + GOOGLE_FONTS_STYLESHEET_URL, "Roboto Mono", &FontAxes { wght: indexset! {"500".to_owned()}, @@ -389,6 +388,7 @@ mod tests { fn test_stylesheet_url_sorts_axes() -> Result<()> { assert_eq!( get_stylesheet_url( + GOOGLE_FONTS_STYLESHEET_URL, "Roboto Serif", &FontAxes { wght: indexset! {"500".to_owned()}, @@ -411,6 +411,7 @@ mod tests { fn test_stylesheet_url_encodes_all_weight_ital_combinations() -> Result<()> { assert_eq!( get_stylesheet_url( + GOOGLE_FONTS_STYLESHEET_URL, "Roboto Serif", &FontAxes { wght: indexset! {"500".to_owned(), "300".to_owned()}, @@ -434,6 +435,7 @@ mod tests { fn test_variable_font_without_wgth_axis() -> Result<()> { assert_eq!( get_stylesheet_url( + GOOGLE_FONTS_STYLESHEET_URL, "Nabla", &FontAxes { wght: indexset! {}, diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index e02ec301be57fe..b2afb84ada6ef1 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -1,13 +1,15 @@ use anyhow::Result; use turbo_tasks::{primitives::StringsVc, Value}; use turbo_tasks_fs::{glob::GlobVc, FileSystemPathVc}; -use turbopack_core::resolve::options::{ - ImportMap, ImportMapVc, ImportMapping, ImportMappingVc, ResolvedMap, ResolvedMapVc, +use turbopack_core::resolve::{ + options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc, ResolvedMap, ResolvedMapVc}, + AliasPattern, }; use crate::{ embed_js::{attached_next_js_package_path, VIRTUAL_PACKAGE_NAME}, next_client::context::ContextType, + next_font_google::{NextFontGoogleCssModuleReplacerVc, NextFontGoogleReplacerVc}, next_server::ServerContextType, }; @@ -18,9 +20,8 @@ pub fn get_next_client_import_map( ty: Value<ContextType>, ) -> ImportMapVc { let mut import_map = ImportMap::empty(); - let package_root = attached_next_js_package_path(project_path); - insert_next_shared_aliases(&mut import_map, package_root); + insert_next_shared_aliases(&mut import_map, project_path); match ty.into_value() { ContextType::Pages { pages_dir } => { @@ -102,9 +103,8 @@ pub async fn get_next_server_import_map( externals: StringsVc, ) -> Result<ImportMapVc> { let mut import_map = ImportMap::empty(); - let package_root = attached_next_js_package_path(project_path); - insert_next_shared_aliases(&mut import_map, package_root); + insert_next_shared_aliases(&mut import_map, project_path); match ty.into_value() { ServerContextType::Pages { pages_dir } => { @@ -216,7 +216,9 @@ static NEXT_ALIASES: [(&str, &str); 23] = [ ("setImmediate", "next/dist/compiled/setimmediate"), ]; -pub fn insert_next_shared_aliases(import_map: &mut ImportMap, package_root: FileSystemPathVc) { +pub fn insert_next_shared_aliases(import_map: &mut ImportMap, project_path: FileSystemPathVc) { + let package_root = attached_next_js_package_path(project_path); + // we use the next.js hydration code, so we replace the error overlay with our // own import_map.insert_exact_alias( @@ -229,6 +231,17 @@ pub fn insert_next_shared_aliases(import_map: &mut ImportMap, package_root: File &format!("{VIRTUAL_PACKAGE_NAME}/"), package_root, ); + + import_map.insert_alias( + // Request path from js via next-font swc transform + AliasPattern::exact("@next/font/google/target.css"), + ImportMapping::Dynamic(NextFontGoogleReplacerVc::new(project_path).into()).into(), + ); + + import_map.insert_alias( + AliasPattern::exact("@vercel/turbopack-next/internal/font/google/cssmodule.module.css"), + ImportMapping::Dynamic(NextFontGoogleCssModuleReplacerVc::new(project_path).into()).into(), + ); } /// Inserts an alias to an alternative of import mappings into an import map. diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index ebad029842dc40..bf43227345862c 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -331,6 +331,11 @@ async fn source( .into(); let static_source = StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into(); + let next_static_source = StaticAssetsContentSourceVc::new( + "_next/static/".to_owned(), + project_path.join(".next/static"), + ) + .into(); let manifest_source = DevManifestContentSource { page_roots: vec![app_source, rendered_source], } @@ -338,6 +343,7 @@ async fn source( .into(); let main_source = CombinedContentSourceVc::new(vec![ manifest_source, + next_static_source, static_source, app_source, rendered_source, From 69ea0005fb5bb50a981ebc70bb6dbb68adfd993c Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Fri, 9 Dec 2022 21:11:41 +0100 Subject: [PATCH 261/672] page chunk loader (vercel/turbo#2948) --- .../crates/next-core/js/src/dev/hmr-client.ts | 56 ++++--- .../next-core/js/src/entry/next-hydrate.tsx | 28 ++++ .../next-core/js/src/entry/page-loader.ts | 18 +++ .../crates/next-core/js/types/globals.d.ts | 5 + packages/next-swc/crates/next-core/src/lib.rs | 1 + .../crates/next-core/src/page_loader.rs | 139 ++++++++++++++++++ .../next-core/src/server_rendered_source.rs | 61 ++++++-- .../next-swc/crates/next-core/src/util.rs | 11 ++ 8 files changed, 280 insertions(+), 39 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/entry/page-loader.ts create mode 100644 packages/next-swc/crates/next-core/src/page_loader.rs diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 4b9a5aa539f65a..9f6f4879c1c73f 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -1,7 +1,6 @@ import type { ClientMessage, EcmascriptChunkUpdate, - Issue, ResourceIdentifier, ServerMessage, } from "@vercel/turbopack-runtime/types/protocol"; @@ -68,6 +67,7 @@ function sendJSON(message: ClientMessage) { } type ResourceKey = string; + function resourceKey(resource: ResourceIdentifier): ResourceKey { return JSON.stringify({ path: resource.path, @@ -301,30 +301,40 @@ function triggerUpdate(msg: ServerMessage) { function subscribeToInitialCssChunksUpdates(assetPrefix: string) { const initialCssChunkLinks: NodeListOf<HTMLLinkElement> = document.head.querySelectorAll(`link[rel="stylesheet"]`); - const cssChunkPrefix = `${assetPrefix}/`; + initialCssChunkLinks.forEach((link) => { - const href = link.href; - if (href == null) { - return; - } - const { pathname, origin } = new URL(href); - if (origin !== location.origin || !pathname.startsWith(cssChunkPrefix)) { - return; - } + subscribeToCssChunkUpdates(assetPrefix, link); + }); +} + +export function subscribeToCssChunkUpdates( + assetPrefix: string, + link: HTMLLinkElement +) { + const cssChunkPrefix = `${assetPrefix}/`; - const chunkPath = pathname.slice(cssChunkPrefix.length); - onChunkUpdate(chunkPath, (update) => { - switch (update.type) { - case "restart": { - console.info(`Reloading CSS chunk \`${chunkPath}\``); - link.replaceWith(link); - break; - } - case "partial": - throw new Error(`partial CSS chunk updates are not supported`); - default: - throw new Error(`unknown update type \`${update}\``); + const href = link.href; + if (href == null) { + return; + } + + const { pathname, origin } = new URL(href); + if (origin !== location.origin || !pathname.startsWith(cssChunkPrefix)) { + return; + } + + const chunkPath = pathname.slice(cssChunkPrefix.length); + onChunkUpdate(chunkPath, (update) => { + switch (update.type) { + case "restart": { + console.info(`Reloading CSS chunk \`${chunkPath}\``); + link.replaceWith(link); + break; } - }); + case "partial": + throw new Error(`partial CSS chunk updates are not supported`); + default: + throw new Error(`unknown update type \`${update}\``); + } }); } diff --git a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx index d22b4ad4f1a866..d71ecfcfee941e 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx @@ -2,10 +2,29 @@ import "@vercel/turbopack-next/internal/shims-client"; import { initialize, hydrate } from "next/dist/client"; import { initializeHMR } from "@vercel/turbopack-next/dev/client"; +import { subscribeToCssChunkUpdates } from "@vercel/turbopack-next/dev/hmr-client"; import * as _app from "@vercel/turbopack-next/pages/_app"; import * as page from "."; +async function loadPageChunk(assetPrefix: string, chunkPath: string) { + const fullPath = assetPrefix + chunkPath; + + await __turbopack_load__(fullPath); + + // TODO: the turbopack chunk loader should do this somehow + if (chunkPath.endsWith(".css")) { + const link = document.querySelector<HTMLLinkElement>( + `link[href=${JSON.stringify(fullPath)}]` + ); + if (!link) { + throw new Error("stylesheet should be loaded, but is not"); + } + + subscribeToCssChunkUpdates(assetPrefix, link); + } +} + (async () => { console.debug("Initializing Next.js"); @@ -20,6 +39,15 @@ import * as page from "."; assetPrefix, }); + // for the page loader + window.__turbopack_load_page_chunks__ = (page, paths) => { + const chunkPromises = paths.map(loadPageChunk.bind(null, assetPrefix)); + + Promise.all(chunkPromises).catch((err) => + console.error("failed to load chunks for page " + page, err) + ); + }; + const pagePath = window.__NEXT_DATA__.page; window.__BUILD_MANIFEST = { [pagePath]: [], diff --git a/packages/next-swc/crates/next-core/js/src/entry/page-loader.ts b/packages/next-swc/crates/next-core/js/src/entry/page-loader.ts new file mode 100644 index 00000000000000..306f7cf82a28a2 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/page-loader.ts @@ -0,0 +1,18 @@ +import * as page from "."; + +// inserted by rust code +declare const PAGE_PATH: string; + +// Adapted from https://github.com/vercel/next.js/blob/canary/packages/next/build/webpack/loaders/next-client-pages-loader.ts + +(window.__NEXT_P = window.__NEXT_P || []).push([ + PAGE_PATH, + () => { + return page; + }, +]); +if (module.hot) { + module.hot.dispose(function () { + window.__NEXT_P.push([PAGE_PATH]); + }); +} diff --git a/packages/next-swc/crates/next-core/js/types/globals.d.ts b/packages/next-swc/crates/next-core/js/types/globals.d.ts index 77a76a589ac9c2..8aba9430f9ad07 100644 --- a/packages/next-swc/crates/next-core/js/types/globals.d.ts +++ b/packages/next-swc/crates/next-core/js/types/globals.d.ts @@ -15,6 +15,11 @@ declare global { version: string; appDir: boolean; }; + + function __turbopack_load_page_chunks__( + page: string, + paths: string[] + ): unknown; } export {}; diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 56bdfae37e94c9..5385ab90eb859b 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -13,6 +13,7 @@ mod next_font_google; pub mod next_image; mod next_import_map; pub mod next_server; +mod page_loader; pub mod react_refresh; mod runtime; mod server_rendered_source; diff --git a/packages/next-swc/crates/next-core/src/page_loader.rs b/packages/next-swc/crates/next-core/src/page_loader.rs new file mode 100644 index 00000000000000..f4777f4c5dff83 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/page_loader.rs @@ -0,0 +1,139 @@ +use std::io::Write; + +use anyhow::{bail, Result}; +use serde_json::Value; +use turbo_tasks::primitives::StringVc; +use turbo_tasks_fs::{rope::RopeBuilder, File, FileContent, FileSystemPathVc}; +use turbopack_core::{ + asset::{Asset, AssetContentVc, AssetVc}, + chunk::{ChunkGroupVc, ChunkReferenceVc, ChunkingContextVc, ChunksVc}, + context::AssetContextVc, + reference::AssetReferencesVc, + virtual_asset::VirtualAssetVc, +}; +use turbopack_dev_server::source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}; +use turbopack_ecmascript::{ + utils::stringify_str, EcmascriptInputTransform, EcmascriptInputTransformsVc, + EcmascriptModuleAssetType, EcmascriptModuleAssetVc, +}; + +use crate::{embed_js::next_js_file, util::get_asset_path_from_route}; + +#[turbo_tasks::function] +pub async fn create_page_loader( + server_root: FileSystemPathVc, + client_context: AssetContextVc, + client_chunking_context: ChunkingContextVc, + entry_asset: AssetVc, + pathname: StringVc, +) -> Result<ContentSourceVc> { + let asset = PageLoaderAsset { + server_root, + client_context, + client_chunking_context, + entry_asset, + pathname, + } + .cell(); + + Ok(AssetGraphContentSourceVc::new_lazy(server_root, asset.into()).into()) +} + +#[turbo_tasks::value(shared)] +pub struct PageLoaderAsset { + pub server_root: FileSystemPathVc, + pub client_context: AssetContextVc, + pub client_chunking_context: ChunkingContextVc, + pub entry_asset: AssetVc, + pub pathname: StringVc, +} + +#[turbo_tasks::value_impl] +impl PageLoaderAssetVc { + #[turbo_tasks::function] + async fn get_loader_entry_asset(self) -> Result<AssetVc> { + let this = &*self.await?; + + let mut result = RopeBuilder::default(); + writeln!( + result, + "const PAGE_PATH = {};\n", + stringify_str(&format!("/{}", &*this.pathname.await?)) + )?; + + let base_code = next_js_file("entry/page-loader.ts"); + if let FileContent::Content(base_file) = &*base_code.await? { + result += base_file.content() + } else { + bail!("required file `entry/page-loader.ts` not found"); + } + + let file = File::from(result.build()); + + Ok(VirtualAssetVc::new(this.entry_asset.path().join("page-loader.ts"), file.into()).into()) + } + + #[turbo_tasks::function] + async fn get_page_chunks(self) -> Result<ChunksVc> { + let this = &*self.await?; + + let loader_entry_asset = self.get_loader_entry_asset(); + + let asset = EcmascriptModuleAssetVc::new( + loader_entry_asset, + this.client_context, + turbo_tasks::Value::new(EcmascriptModuleAssetType::Typescript), + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::TypeScript]), + this.client_context.environment(), + ); + + let chunk_group = + ChunkGroupVc::from_chunk(asset.as_evaluated_chunk(this.client_chunking_context, None)); + + Ok(chunk_group.chunks()) + } +} + +#[turbo_tasks::value_impl] +impl Asset for PageLoaderAsset { + #[turbo_tasks::function] + async fn path(&self) -> Result<FileSystemPathVc> { + Ok(self + .server_root + .join("_next/static/chunks/pages") + .join(&get_asset_path_from_route(&self.pathname.await?, ".js"))) + } + + #[turbo_tasks::function] + async fn content(self_vc: PageLoaderAssetVc) -> Result<AssetContentVc> { + let this = &*self_vc.await?; + + let chunks = self_vc.get_page_chunks().await?; + + let mut data = Vec::with_capacity(chunks.len()); + for chunk in chunks.iter() { + let path = chunk.path().await?; + data.push(Value::String(path.path.clone())); + } + + let content = format!( + "__turbopack_load_page_chunks__({}, {})\n", + stringify_str(&this.pathname.await?), + Value::Array(data) + ); + + Ok(AssetContentVc::from(File::from(content))) + } + + #[turbo_tasks::function] + async fn references(self_vc: PageLoaderAssetVc) -> Result<AssetReferencesVc> { + let chunks = self_vc.get_page_chunks().await?; + + let mut references = Vec::with_capacity(chunks.len()); + for chunk in chunks.iter() { + references.push(ChunkReferenceVc::new(*chunk).into()); + } + + Ok(AssetReferencesVc::cell(references)) + } +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 0458a6df758bfb..447b34c9a804e0 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -51,6 +51,7 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, + page_loader::create_page_loader, util::{pathname_for_path, regular_expression_for_path}, }; @@ -86,6 +87,13 @@ pub async fn create_server_rendered_source( let client_module_options_context = add_next_transforms_to_pages(client_module_options_context, pages_dir); let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); + let client_context: AssetContextVc = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(HashMap::new()), + client_environment, + client_module_options_context, + client_resolve_options_context, + ) + .into(); let client_runtime_entries = get_client_runtime_entries(project_path, env, ty); @@ -119,6 +127,7 @@ pub async fn create_server_rendered_source( let server_rendered_source = create_server_rendered_source_for_directory( project_path, context, + client_context, pages_dir, SpecificityVc::exact(), 0, @@ -145,6 +154,7 @@ pub async fn create_server_rendered_source( async fn create_server_rendered_source_for_file( context_path: FileSystemPathVc, context: AssetContextVc, + client_context: AssetContextVc, pages_dir: FileSystemPathVc, specificity: SpecificityVc, page_file: FileSystemPathVc, @@ -166,6 +176,12 @@ async fn create_server_rendered_source_for_file( ) .build(); + let client_chunking_context = get_client_chunking_context( + context_path, + server_root, + Value::new(ContextType::Pages { pages_dir }), + ); + let pathname = pathname_for_path(server_root, server_path, true); let path_regex = regular_expression_for_path(server_root, server_path, true); @@ -187,23 +203,33 @@ async fn create_server_rendered_source_for_file( runtime_entries, ) } else { - create_node_rendered_source( - specificity, - server_root, - pathname, - path_regex, - SsrEntry { - context, + CombinedContentSourceVc::new(vec![ + create_node_rendered_source( + specificity, + server_root, + pathname, + path_regex, + SsrEntry { + context, + entry_asset, + is_api_path, + chunking_context, + intermediate_output_path, + } + .cell() + .into(), + runtime_entries, + fallback_page, + ), + create_page_loader( + server_root, + client_context, + client_chunking_context, entry_asset, - is_api_path, - chunking_context, - intermediate_output_path, - } - .cell() - .into(), - runtime_entries, - fallback_page, - ) + pathname, + ), + ]) + .into() }) } @@ -214,6 +240,7 @@ async fn create_server_rendered_source_for_file( async fn create_server_rendered_source_for_directory( context_path: FileSystemPathVc, context: AssetContextVc, + client_context: AssetContextVc, pages_dir: FileSystemPathVc, specificity: SpecificityVc, position: u32, @@ -268,6 +295,7 @@ async fn create_server_rendered_source_for_directory( create_server_rendered_source_for_file( context_path, context, + client_context, pages_dir, specificity, *file, @@ -290,6 +318,7 @@ async fn create_server_rendered_source_for_directory( create_server_rendered_source_for_directory( context_path, context, + client_context, pages_dir, specificity, position + 1, diff --git a/packages/next-swc/crates/next-core/src/util.rs b/packages/next-swc/crates/next-core/src/util.rs index 3771ae455223f2..aa345b92477d79 100644 --- a/packages/next-swc/crates/next-core/src/util.rs +++ b/packages/next-swc/crates/next-core/src/util.rs @@ -84,3 +84,14 @@ pub async fn regular_expression_for_path( } Ok(PathRegexVc::cell(path_regex.build()?)) } + +// Adapted from https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/router/utils/get-asset-path-from-route.ts +pub fn get_asset_path_from_route(route: &str, ext: &str) -> String { + if route.is_empty() { + format!("index{}", ext) + } else if route == "index" || route.starts_with("index/") { + format!("index/{}{}", route, ext) + } else { + format!("{}{}", route, ext) + } +} From 9d03416cc588d3ce90f374369964a12757ff35ba Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Fri, 9 Dec 2022 14:20:15 -0800 Subject: [PATCH 262/672] Remove next_static_source (vercel/turbo#2971) --- packages/next-swc/crates/next-dev/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index bf43227345862c..ebad029842dc40 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -331,11 +331,6 @@ async fn source( .into(); let static_source = StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into(); - let next_static_source = StaticAssetsContentSourceVc::new( - "_next/static/".to_owned(), - project_path.join(".next/static"), - ) - .into(); let manifest_source = DevManifestContentSource { page_roots: vec![app_source, rendered_source], } @@ -343,7 +338,6 @@ async fn source( .into(); let main_source = CombinedContentSourceVc::new(vec![ manifest_source, - next_static_source, static_source, app_source, rendered_source, From 30fa74d3ab0acea2d396ce47d1ad444ce4f94122 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Sat, 10 Dec 2022 01:01:58 +0100 Subject: [PATCH 263/672] page json route (vercel/turbo#2949) --- .../js/src/entry/server-renderer.tsx | 85 +++++++++++++------ .../crates/next-core/js/types/turbopack.d.ts | 2 + .../crates/next-core/src/app_source.rs | 2 +- .../next-core/src/server_rendered_source.rs | 41 ++++++--- .../next-swc/crates/next-core/src/util.rs | 9 +- 5 files changed, 92 insertions(+), 47 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 488d21bc91973b..b1d06f3ba749fd 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -1,13 +1,16 @@ -import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; +import "next/dist/server/node-polyfill-fetch.js"; +import "@vercel/turbopack-next/internal/shims"; import type { IncomingMessage, ServerResponse } from "node:http"; -import "@vercel/turbopack-next/internal/shims"; -import "next/dist/server/node-polyfill-fetch.js"; -import { renderToHTML } from "next/dist/server/render"; -import type { RenderOpts } from "next/dist/server/render"; -import type { RenderData } from "types/turbopack"; +import { renderToHTML, RenderOpts } from "next/dist/server/render"; +import RenderResult from "next/dist/server/render-result"; +import type { BuildManifest } from "next/dist/server/get-page-files"; + import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; +import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; +import type { RenderData } from "types/turbopack"; +import type { ChunkGroup } from "types/next"; import App from "@vercel/turbopack-next/pages/_app"; import Document from "@vercel/turbopack-next/pages/_document"; @@ -15,8 +18,6 @@ import Document from "@vercel/turbopack-next/pages/_document"; import Component, * as otherExports from "."; ("TURBOPACK { transition: next-client }"); import chunkGroup from "."; -import type { BuildManifest } from "next/dist/server/get-page-files"; -import type { ChunkGroup } from "types/next"; const ipc = IPC as Ipc<IpcIncomingMessage, IpcOutgoingMessage>; @@ -46,24 +47,36 @@ type IpcOutgoingMessage = { } } - const html = await runOperation(renderData); + const isDataReq = Boolean( + renderData.query.__nextDataReq || renderData.headers["x-nextjs-data"] + ); + const res = await runOperation(renderData, isDataReq); - if (html == null) { - throw new Error("no html returned"); + if (res == null) { + throw new Error("no render result returned"); } ipc.send({ type: "result", - result: html, + result: { + contentType: isDataReq ? "application/json" : undefined, + body: isDataReq ? JSON.stringify(res.pageData) : res.html, + }, }); } })().catch((err) => { ipc.sendError(err); }); +type OperationResult = { + html: string; + pageData: Object; +}; + async function runOperation( - renderData: RenderData -): Promise<string | undefined> { + renderData: RenderData, + isDataReq: boolean +): Promise<OperationResult | null> { // TODO(alexkirsz) This is missing *a lot* of data, but it's enough to get a // basic render working. @@ -101,6 +114,7 @@ async function runOperation( buildId: "development", /* RenderOptsPartial */ + isDataReq, runtimeConfig: {}, assetPrefix: "", canonicalBase: "", @@ -148,18 +162,33 @@ async function runOperation( const res: ServerResponse = new ServerResponseShim(req) as any; const query = { ...renderData.query, ...renderData.params }; - return ( - await renderToHTML( - /* req: IncomingMessage */ - req, - /* res: ServerResponse */ - res, - /* pathname: string */ - renderData.path, - /* query: ParsedUrlQuery */ - query, - /* renderOpts: RenderOpts */ - renderOpts - ) - )?.toUnchunkedString(); + const renderResult = await renderToHTML( + /* req: IncomingMessage */ + req, + /* res: ServerResponse */ + res, + /* pathname: string */ + renderData.path, + /* query: ParsedUrlQuery */ + query, + /* renderOpts: RenderOpts */ + renderOpts + ); + + const body = renderResult?.toUnchunkedString(); + // TODO(from next.js): change this to a different passing mechanism + const pageData = (renderOpts as any).pageData; + // TODO: handle these + // const sprRevalidate = (renderOpts as any).revalidate; + // const isNotFound = (renderOpts as any).isNotFound; + // const isRedirect = (renderOpts as any).isRedirect; + + if (body == null) { + return null; + } + + return { + html: body, + pageData: pageData, + }; } diff --git a/packages/next-swc/crates/next-core/js/types/turbopack.d.ts b/packages/next-swc/crates/next-core/js/types/turbopack.d.ts index c5db917ff38787..a820e4615397dc 100644 --- a/packages/next-swc/crates/next-core/js/types/turbopack.d.ts +++ b/packages/next-swc/crates/next-core/js/types/turbopack.d.ts @@ -1,3 +1,5 @@ +import { NextParsedUrlQuery } from "next/dist/server/request-meta"; + export type RenderData = { params: Record<string, string>; method: string; diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 2d97ba3a6a2643..c62c50f4a9a49d 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -359,7 +359,7 @@ async fn create_app_source_for_directory( layouts = LayoutSegmentsVc::cell(list); if let Some(page_path) = page { let pathname = pathname_for_path(server_root, target, false); - let path_regex = regular_expression_for_path(server_root, target, false); + let path_regex = regular_expression_for_path(pathname); sources.push(create_node_rendered_source( specificity, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 447b34c9a804e0..fbfbdbf291741f 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use anyhow::Result; use turbo_tasks::{ - primitives::{BoolVc, StringsVc}, + primitives::{BoolVc, StringVc, StringsVc}, Value, }; use turbo_tasks_env::ProcessEnvVc; @@ -52,7 +52,7 @@ use crate::{ get_server_resolve_options_context, ServerContextType, }, page_loader::create_page_loader, - util::{pathname_for_path, regular_expression_for_path}, + util::{get_asset_path_from_route, pathname_for_path, regular_expression_for_path}, }; /// Create a content source serving the `pages` or `src/pages` directory as @@ -183,7 +183,7 @@ async fn create_server_rendered_source_for_file( ); let pathname = pathname_for_path(server_root, server_path, true); - let path_regex = regular_expression_for_path(server_root, server_path, true); + let path_regex = regular_expression_for_path(pathname); Ok(if *is_api_path.await? { create_node_api_source( @@ -203,21 +203,38 @@ async fn create_server_rendered_source_for_file( runtime_entries, ) } else { + let data_pathname = format!( + "_next/data/development/{}", + get_asset_path_from_route(&*pathname.await?, ".json") + ); + let data_path_regex = regular_expression_for_path(StringVc::cell(data_pathname)); + + let ssr_entry = SsrEntry { + context, + entry_asset, + is_api_path, + chunking_context, + intermediate_output_path, + } + .cell() + .into(); + CombinedContentSourceVc::new(vec![ create_node_rendered_source( specificity, server_root, pathname, path_regex, - SsrEntry { - context, - entry_asset, - is_api_path, - chunking_context, - intermediate_output_path, - } - .cell() - .into(), + ssr_entry, + runtime_entries, + fallback_page, + ), + create_node_rendered_source( + specificity, + server_root, + pathname, + data_path_regex, + ssr_entry, runtime_entries, fallback_page, ), diff --git a/packages/next-swc/crates/next-core/src/util.rs b/packages/next-swc/crates/next-core/src/util.rs index aa345b92477d79..3f9406574a9efc 100644 --- a/packages/next-swc/crates/next-core/src/util.rs +++ b/packages/next-swc/crates/next-core/src/util.rs @@ -39,12 +39,8 @@ pub async fn pathname_for_path( /// Converts a filename within the server root into a regular expression with /// named capture groups for every dynamic segment. #[turbo_tasks::function] -pub async fn regular_expression_for_path( - server_root: FileSystemPathVc, - server_path: FileSystemPathVc, - has_extension: bool, -) -> Result<PathRegexVc> { - let path = pathname_for_path(server_root, server_path, has_extension).await?; +pub async fn regular_expression_for_path(pathname: StringVc) -> Result<PathRegexVc> { + let path = pathname.await?; let mut path_regex = PathRegexBuilder::new(); for segment in path.split('/') { @@ -82,6 +78,7 @@ pub async fn regular_expression_for_path( path_regex.push_static_segment(segment); } } + Ok(PathRegexVc::cell(path_regex.build()?)) } From 6483da899199fe039e296a61f8089a8ca055db97 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Tue, 13 Dec 2022 00:38:21 +0100 Subject: [PATCH 264/672] update npm deps (vercel/turbo#2960) --- .../next-swc/crates/next-core/js/build.mjs | 2 +- .../next-swc/crates/next-core/js/package.json | 18 +++++++++--------- .../next-core/js/src/compiled/anser/index.js | 2 +- .../js/src/compiled/css.escape/index.js | 2 +- .../js/src/compiled/platform/index.js | 4 ++-- .../js/src/compiled/source-map/index.js | 2 +- .../js/src/compiled/strip-ansi/LICENSE | 2 +- .../js/src/compiled/strip-ansi/index.js | 2 +- .../js/src/compiled/strip-ansi/package.json | 2 +- .../crates/next-core/js/types/compiled.d.ts | 2 +- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/build.mjs b/packages/next-swc/crates/next-core/js/build.mjs index d8e45c10db75a1..283d6a719a7ec4 100644 --- a/packages/next-swc/crates/next-core/js/build.mjs +++ b/packages/next-swc/crates/next-core/js/build.mjs @@ -45,7 +45,7 @@ const packages = [ }, { name: "strip-ansi", - type: "cjs", + type: "module-default", }, ]; const externals = Object.fromEntries( diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index fe205897e3e430..70d19d94d9e1a7 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -10,22 +10,22 @@ }, "dependencies": { "@vercel/turbopack-runtime": "latest", - "anser": "2.1.1", - "css.escape": "1.5.1", - "next": "13.0.3", + "anser": "^2.1.1", + "css.escape": "^1.5.1", + "next": "^13.0.6", "platform": "1.3.6", "react-dom": "^18.2.0", "react": "^18.2.0", "source-map": "0.8.0-beta.0", - "stacktrace-parser": "0.1.10", - "strip-ansi": "6.0.1" + "stacktrace-parser": "^0.1.10", + "strip-ansi": "^7.0.1" }, "devDependencies": { - "@types/node": "^18.8.4", + "@types/node": "^18.11.11", "@types/platform": "^1.3.4", - "@types/react": "^18.0.21", - "@types/react-dom": "^18.0.6", - "@vercel/ncc": "^0.34.0", + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.9", + "@vercel/ncc": "^0.36.0", "find-up": "^6.3.0" } } diff --git a/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js b/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js index 54253d56e666db..de3a71db9ee61e 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js @@ -1 +1 @@ -(()=>{"use strict";var e={463:e=>{var r=function(){function defineProperties(e,r){for(var s=0;s<r.length;s++){var n=r[s];n.enumerable=n.enumerable||false;n.configurable=true;if("value"in n)n.writable=true;Object.defineProperty(e,n.key,n)}}return function(e,r,s){if(r)defineProperties(e.prototype,r);if(s)defineProperties(e,s);return e}}();function _classCallCheck(e,r){if(!(e instanceof r)){throw new TypeError("Cannot call a class as a function")}}var s=[[{color:"0, 0, 0",class:"ansi-black"},{color:"187, 0, 0",class:"ansi-red"},{color:"0, 187, 0",class:"ansi-green"},{color:"187, 187, 0",class:"ansi-yellow"},{color:"0, 0, 187",class:"ansi-blue"},{color:"187, 0, 187",class:"ansi-magenta"},{color:"0, 187, 187",class:"ansi-cyan"},{color:"255,255,255",class:"ansi-white"}],[{color:"85, 85, 85",class:"ansi-bright-black"},{color:"255, 85, 85",class:"ansi-bright-red"},{color:"0, 255, 0",class:"ansi-bright-green"},{color:"255, 255, 85",class:"ansi-bright-yellow"},{color:"85, 85, 255",class:"ansi-bright-blue"},{color:"255, 85, 255",class:"ansi-bright-magenta"},{color:"85, 255, 255",class:"ansi-bright-cyan"},{color:"255, 255, 255",class:"ansi-bright-white"}]];var n=function(){r(Anser,null,[{key:"escapeForHtml",value:function escapeForHtml(e){return(new Anser).escapeForHtml(e)}},{key:"linkify",value:function linkify(e){return(new Anser).linkify(e)}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return(new Anser).ansiToHtml(e,r)}},{key:"ansiToJson",value:function ansiToJson(e,r){return(new Anser).ansiToJson(e,r)}},{key:"ansiToText",value:function ansiToText(e){return(new Anser).ansiToText(e)}}]);function Anser(){_classCallCheck(this,Anser);this.fg=this.bg=this.fg_truecolor=this.bg_truecolor=null;this.bright=0;this.decorations=[]}r(Anser,[{key:"setupPalette",value:function setupPalette(){this.PALETTE_COLORS=[];for(var e=0;e<2;++e){for(var r=0;r<8;++r){this.PALETTE_COLORS.push(s[e][r].color)}}var n=[0,95,135,175,215,255];var o=function format(e,r,s){return n[e]+", "+n[r]+", "+n[s]};var i=void 0,t=void 0,a=void 0;for(var l=0;l<6;++l){for(var c=0;c<6;++c){for(var u=0;u<6;++u){this.PALETTE_COLORS.push(o(l,c,u))}}}var f=8;for(var h=0;h<24;++h,f+=10){this.PALETTE_COLORS.push(o(f,f,f))}}},{key:"escapeForHtml",value:function escapeForHtml(e){return e.replace(/[&<>\"]/gm,(function(e){return e=="&"?"&":e=='"'?""":e=="<"?"<":e==">"?">":""}))}},{key:"linkify",value:function linkify(e){return e.replace(/(https?:\/\/[^\s]+)/gm,(function(e){return'<a href="'+e+'">'+e+"</a>"}))}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return this.process(e,r,true)}},{key:"ansiToJson",value:function ansiToJson(e,r){r=r||{};r.json=true;r.clearLine=false;return this.process(e,r,true)}},{key:"ansiToText",value:function ansiToText(e){return this.process(e,{},false)}},{key:"process",value:function process(e,r,s){var n=this;var o=this;var i=e.split(/\033\[/);var t=i.shift();if(r===undefined||r===null){r={}}r.clearLine=/\r/.test(e);var a=i.map((function(e){return n.processChunk(e,r,s)}));if(r&&r.json){var l=o.processChunkJson("");l.content=t;l.clearLine=r.clearLine;a.unshift(l);if(r.remove_empty){a=a.filter((function(e){return!e.isEmpty()}))}return a}else{a.unshift(t)}return a.join("")}},{key:"processChunkJson",value:function processChunkJson(e,r,n){r=typeof r=="undefined"?{}:r;var o=r.use_classes=typeof r.use_classes!="undefined"&&r.use_classes;var i=r.key=o?"class":"color";var t={content:e,fg:null,bg:null,fg_truecolor:null,bg_truecolor:null,isInverted:false,clearLine:r.clearLine,decoration:null,decorations:[],was_processed:false,isEmpty:function isEmpty(){return!t.content}};var a=e.match(/^([!\x3c-\x3f]*)([\d;]*)([\x20-\x2c]*[\x40-\x7e])([\s\S]*)/m);if(!a)return t;var l=t.content=a[4];var c=a[2].split(";");if(a[1]!==""||a[3]!=="m"){return t}if(!n){return t}var u=this;while(c.length>0){var f=c.shift();var h=parseInt(f);if(isNaN(h)||h===0){u.fg=u.bg=null;u.decorations=[]}else if(h===1){u.decorations.push("bold")}else if(h===2){u.decorations.push("dim")}else if(h===3){u.decorations.push("italic")}else if(h===4){u.decorations.push("underline")}else if(h===5){u.decorations.push("blink")}else if(h===7){u.decorations.push("reverse")}else if(h===8){u.decorations.push("hidden")}else if(h===9){u.decorations.push("strikethrough")}else if(h===21){u.removeDecoration("bold")}else if(h===22){u.removeDecoration("bold");u.removeDecoration("dim")}else if(h===23){u.removeDecoration("italic")}else if(h===24){u.removeDecoration("underline")}else if(h===25){u.removeDecoration("blink")}else if(h===27){u.removeDecoration("reverse")}else if(h===28){u.removeDecoration("hidden")}else if(h===29){u.removeDecoration("strikethrough")}else if(h===39){u.fg=null}else if(h===49){u.bg=null}else if(h>=30&&h<38){u.fg=s[0][h%10][i]}else if(h>=90&&h<98){u.fg=s[1][h%10][i]}else if(h>=40&&h<48){u.bg=s[0][h%10][i]}else if(h>=100&&h<108){u.bg=s[1][h%10][i]}else if(h===38||h===48){var v=h===38;if(c.length>=1){var g=c.shift();if(g==="5"&&c.length>=1){var p=parseInt(c.shift());if(p>=0&&p<=255){if(!o){if(!this.PALETTE_COLORS){u.setupPalette()}if(v){u.fg=this.PALETTE_COLORS[p]}else{u.bg=this.PALETTE_COLORS[p]}}else{var d=p>=16?"ansi-palette-"+p:s[p>7?1:0][p%8]["class"];if(v){u.fg=d}else{u.bg=d}}}}else if(g==="2"&&c.length>=3){var b=parseInt(c.shift());var _=parseInt(c.shift());var m=parseInt(c.shift());if(b>=0&&b<=255&&_>=0&&_<=255&&m>=0&&m<=255){var k=b+", "+_+", "+m;if(!o){if(v){u.fg=k}else{u.bg=k}}else{if(v){u.fg="ansi-truecolor";u.fg_truecolor=k}else{u.bg="ansi-truecolor";u.bg_truecolor=k}}}}}}}if(u.fg===null&&u.bg===null&&u.decorations.length===0){return t}else{var y=[];var T=[];var w={};t.fg=u.fg;t.bg=u.bg;t.fg_truecolor=u.fg_truecolor;t.bg_truecolor=u.bg_truecolor;t.decorations=u.decorations;t.decoration=u.decorations.slice(-1).pop()||null;t.was_processed=true;return t}}},{key:"processChunk",value:function processChunk(e,r,n){var o=this;r=r||{};var i=this.processChunkJson(e,r,n);var t=r.use_classes;i.decorations=i.decorations.filter((function(e){if(e==="reverse"){if(!i.fg){i.fg=s[0][7][t?"class":"color"]}if(!i.bg){i.bg=s[0][0][t?"class":"color"]}var r=i.fg;i.fg=i.bg;i.bg=r;var n=i.fg_truecolor;i.fg_truecolor=i.bg_truecolor;i.bg_truecolor=n;i.isInverted=true;return false}return true}));if(r.json){return i}if(i.isEmpty()){return""}if(!i.was_processed){return i.content}var a=[];var l=[];var c=[];var u={};var f=function render_data(e){var r=[];var s=void 0;for(s in e){if(e.hasOwnProperty(s)){r.push("data-"+s+'="'+o.escapeForHtml(e[s])+'"')}}return r.length>0?" "+r.join(" "):""};if(i.isInverted){u["ansi-is-inverted"]="true"}if(i.fg){if(t){a.push(i.fg+"-fg");if(i.fg_truecolor!==null){u["ansi-truecolor-fg"]=i.fg_truecolor;i.fg_truecolor=null}}else{a.push("color:rgb("+i.fg+")")}}if(i.bg){if(t){a.push(i.bg+"-bg");if(i.bg_truecolor!==null){u["ansi-truecolor-bg"]=i.bg_truecolor;i.bg_truecolor=null}}else{a.push("background-color:rgb("+i.bg+")")}}i.decorations.forEach((function(e){if(t){l.push("ansi-"+e);return}if(e==="bold"){l.push("font-weight:bold")}else if(e==="dim"){l.push("opacity:0.5")}else if(e==="italic"){l.push("font-style:italic")}else if(e==="hidden"){l.push("visibility:hidden")}else if(e==="strikethrough"){c.push("line-through")}else{c.push(e)}}));if(c.length){l.push("text-decoration:"+c.join(" "))}if(t){return'<span class="'+a.concat(l).join(" ")+'"'+f(u)+">"+i.content+"</span>"}else{return'<span style="'+a.concat(l).join(";")+'"'+f(u)+">"+i.content+"</span>"}}},{key:"removeDecoration",value:function removeDecoration(e){var r=this.decorations.indexOf(e);if(r>=0){this.decorations.splice(r,1)}}}]);return Anser}();e.exports=n}};var r={};function __nccwpck_require__(s){var n=r[s];if(n!==undefined){return n.exports}var o=r[s]={exports:{}};var i=true;try{e[s](o,o.exports,__nccwpck_require__);i=false}finally{if(i)delete r[s]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var s=__nccwpck_require__(463);module.exports=s})(); \ No newline at end of file +(()=>{"use strict";var e={976:e=>{var r=function(){function defineProperties(e,r){for(var s=0;s<r.length;s++){var n=r[s];n.enumerable=n.enumerable||false;n.configurable=true;if("value"in n)n.writable=true;Object.defineProperty(e,n.key,n)}}return function(e,r,s){if(r)defineProperties(e.prototype,r);if(s)defineProperties(e,s);return e}}();function _classCallCheck(e,r){if(!(e instanceof r)){throw new TypeError("Cannot call a class as a function")}}var s=[[{color:"0, 0, 0",class:"ansi-black"},{color:"187, 0, 0",class:"ansi-red"},{color:"0, 187, 0",class:"ansi-green"},{color:"187, 187, 0",class:"ansi-yellow"},{color:"0, 0, 187",class:"ansi-blue"},{color:"187, 0, 187",class:"ansi-magenta"},{color:"0, 187, 187",class:"ansi-cyan"},{color:"255,255,255",class:"ansi-white"}],[{color:"85, 85, 85",class:"ansi-bright-black"},{color:"255, 85, 85",class:"ansi-bright-red"},{color:"0, 255, 0",class:"ansi-bright-green"},{color:"255, 255, 85",class:"ansi-bright-yellow"},{color:"85, 85, 255",class:"ansi-bright-blue"},{color:"255, 85, 255",class:"ansi-bright-magenta"},{color:"85, 255, 255",class:"ansi-bright-cyan"},{color:"255, 255, 255",class:"ansi-bright-white"}]];var n=function(){r(Anser,null,[{key:"escapeForHtml",value:function escapeForHtml(e){return(new Anser).escapeForHtml(e)}},{key:"linkify",value:function linkify(e){return(new Anser).linkify(e)}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return(new Anser).ansiToHtml(e,r)}},{key:"ansiToJson",value:function ansiToJson(e,r){return(new Anser).ansiToJson(e,r)}},{key:"ansiToText",value:function ansiToText(e){return(new Anser).ansiToText(e)}}]);function Anser(){_classCallCheck(this,Anser);this.fg=this.bg=this.fg_truecolor=this.bg_truecolor=null;this.bright=0;this.decorations=[]}r(Anser,[{key:"setupPalette",value:function setupPalette(){this.PALETTE_COLORS=[];for(var e=0;e<2;++e){for(var r=0;r<8;++r){this.PALETTE_COLORS.push(s[e][r].color)}}var n=[0,95,135,175,215,255];var o=function format(e,r,s){return n[e]+", "+n[r]+", "+n[s]};var i=void 0,t=void 0,a=void 0;for(var l=0;l<6;++l){for(var c=0;c<6;++c){for(var u=0;u<6;++u){this.PALETTE_COLORS.push(o(l,c,u))}}}var f=8;for(var h=0;h<24;++h,f+=10){this.PALETTE_COLORS.push(o(f,f,f))}}},{key:"escapeForHtml",value:function escapeForHtml(e){return e.replace(/[&<>\"]/gm,(function(e){return e=="&"?"&":e=='"'?""":e=="<"?"<":e==">"?">":""}))}},{key:"linkify",value:function linkify(e){return e.replace(/(https?:\/\/[^\s]+)/gm,(function(e){return'<a href="'+e+'">'+e+"</a>"}))}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return this.process(e,r,true)}},{key:"ansiToJson",value:function ansiToJson(e,r){r=r||{};r.json=true;r.clearLine=false;return this.process(e,r,true)}},{key:"ansiToText",value:function ansiToText(e){return this.process(e,{},false)}},{key:"process",value:function process(e,r,s){var n=this;var o=this;var i=e.split(/\033\[/);var t=i.shift();if(r===undefined||r===null){r={}}r.clearLine=/\r/.test(e);var a=i.map((function(e){return n.processChunk(e,r,s)}));if(r&&r.json){var l=o.processChunkJson("");l.content=t;l.clearLine=r.clearLine;a.unshift(l);if(r.remove_empty){a=a.filter((function(e){return!e.isEmpty()}))}return a}else{a.unshift(t)}return a.join("")}},{key:"processChunkJson",value:function processChunkJson(e,r,n){r=typeof r=="undefined"?{}:r;var o=r.use_classes=typeof r.use_classes!="undefined"&&r.use_classes;var i=r.key=o?"class":"color";var t={content:e,fg:null,bg:null,fg_truecolor:null,bg_truecolor:null,isInverted:false,clearLine:r.clearLine,decoration:null,decorations:[],was_processed:false,isEmpty:function isEmpty(){return!t.content}};var a=e.match(/^([!\x3c-\x3f]*)([\d;]*)([\x20-\x2c]*[\x40-\x7e])([\s\S]*)/m);if(!a)return t;var l=t.content=a[4];var c=a[2].split(";");if(a[1]!==""||a[3]!=="m"){return t}if(!n){return t}var u=this;while(c.length>0){var f=c.shift();var h=parseInt(f);if(isNaN(h)||h===0){u.fg=u.bg=null;u.decorations=[]}else if(h===1){u.decorations.push("bold")}else if(h===2){u.decorations.push("dim")}else if(h===3){u.decorations.push("italic")}else if(h===4){u.decorations.push("underline")}else if(h===5){u.decorations.push("blink")}else if(h===7){u.decorations.push("reverse")}else if(h===8){u.decorations.push("hidden")}else if(h===9){u.decorations.push("strikethrough")}else if(h===21){u.removeDecoration("bold")}else if(h===22){u.removeDecoration("bold");u.removeDecoration("dim")}else if(h===23){u.removeDecoration("italic")}else if(h===24){u.removeDecoration("underline")}else if(h===25){u.removeDecoration("blink")}else if(h===27){u.removeDecoration("reverse")}else if(h===28){u.removeDecoration("hidden")}else if(h===29){u.removeDecoration("strikethrough")}else if(h===39){u.fg=null}else if(h===49){u.bg=null}else if(h>=30&&h<38){u.fg=s[0][h%10][i]}else if(h>=90&&h<98){u.fg=s[1][h%10][i]}else if(h>=40&&h<48){u.bg=s[0][h%10][i]}else if(h>=100&&h<108){u.bg=s[1][h%10][i]}else if(h===38||h===48){var v=h===38;if(c.length>=1){var g=c.shift();if(g==="5"&&c.length>=1){var p=parseInt(c.shift());if(p>=0&&p<=255){if(!o){if(!this.PALETTE_COLORS){u.setupPalette()}if(v){u.fg=this.PALETTE_COLORS[p]}else{u.bg=this.PALETTE_COLORS[p]}}else{var d=p>=16?"ansi-palette-"+p:s[p>7?1:0][p%8]["class"];if(v){u.fg=d}else{u.bg=d}}}}else if(g==="2"&&c.length>=3){var b=parseInt(c.shift());var _=parseInt(c.shift());var m=parseInt(c.shift());if(b>=0&&b<=255&&_>=0&&_<=255&&m>=0&&m<=255){var k=b+", "+_+", "+m;if(!o){if(v){u.fg=k}else{u.bg=k}}else{if(v){u.fg="ansi-truecolor";u.fg_truecolor=k}else{u.bg="ansi-truecolor";u.bg_truecolor=k}}}}}}}if(u.fg===null&&u.bg===null&&u.decorations.length===0){return t}else{var y=[];var T=[];var w={};t.fg=u.fg;t.bg=u.bg;t.fg_truecolor=u.fg_truecolor;t.bg_truecolor=u.bg_truecolor;t.decorations=u.decorations;t.decoration=u.decorations.slice(-1).pop()||null;t.was_processed=true;return t}}},{key:"processChunk",value:function processChunk(e,r,n){var o=this;r=r||{};var i=this.processChunkJson(e,r,n);var t=r.use_classes;i.decorations=i.decorations.filter((function(e){if(e==="reverse"){if(!i.fg){i.fg=s[0][7][t?"class":"color"]}if(!i.bg){i.bg=s[0][0][t?"class":"color"]}var r=i.fg;i.fg=i.bg;i.bg=r;var n=i.fg_truecolor;i.fg_truecolor=i.bg_truecolor;i.bg_truecolor=n;i.isInverted=true;return false}return true}));if(r.json){return i}if(i.isEmpty()){return""}if(!i.was_processed){return i.content}var a=[];var l=[];var c=[];var u={};var f=function render_data(e){var r=[];var s=void 0;for(s in e){if(e.hasOwnProperty(s)){r.push("data-"+s+'="'+o.escapeForHtml(e[s])+'"')}}return r.length>0?" "+r.join(" "):""};if(i.isInverted){u["ansi-is-inverted"]="true"}if(i.fg){if(t){a.push(i.fg+"-fg");if(i.fg_truecolor!==null){u["ansi-truecolor-fg"]=i.fg_truecolor;i.fg_truecolor=null}}else{a.push("color:rgb("+i.fg+")")}}if(i.bg){if(t){a.push(i.bg+"-bg");if(i.bg_truecolor!==null){u["ansi-truecolor-bg"]=i.bg_truecolor;i.bg_truecolor=null}}else{a.push("background-color:rgb("+i.bg+")")}}i.decorations.forEach((function(e){if(t){l.push("ansi-"+e);return}if(e==="bold"){l.push("font-weight:bold")}else if(e==="dim"){l.push("opacity:0.5")}else if(e==="italic"){l.push("font-style:italic")}else if(e==="hidden"){l.push("visibility:hidden")}else if(e==="strikethrough"){c.push("line-through")}else{c.push(e)}}));if(c.length){l.push("text-decoration:"+c.join(" "))}if(t){return'<span class="'+a.concat(l).join(" ")+'"'+f(u)+">"+i.content+"</span>"}else{return'<span style="'+a.concat(l).join(";")+'"'+f(u)+">"+i.content+"</span>"}}},{key:"removeDecoration",value:function removeDecoration(e){var r=this.decorations.indexOf(e);if(r>=0){this.decorations.splice(r,1)}}}]);return Anser}();e.exports=n}};var r={};function __nccwpck_require__(s){var n=r[s];if(n!==undefined){return n.exports}var o=r[s]={exports:{}};var i=true;try{e[s](o,o.exports,__nccwpck_require__);i=false}finally{if(i)delete r[s]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var s=__nccwpck_require__(976);module.exports=s})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js b/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js index 16322f457bd17b..e18b5542fb2e47 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js @@ -1 +1 @@ -(()=>{var e={8:function(e){(function(r,t){if(true){e.exports=t(r)}else{}})(typeof global!="undefined"?global:this,(function(e){if(e.CSS&&e.CSS.escape){return e.CSS.escape}var cssEscape=function(e){if(arguments.length==0){throw new TypeError("`CSS.escape` requires an argument.")}var r=String(e);var t=r.length;var n=-1;var a;var i="";var u=r.charCodeAt(0);while(++n<t){a=r.charCodeAt(n);if(a==0){i+="�";continue}if(a>=1&&a<=31||a==127||n==0&&a>=48&&a<=57||n==1&&a>=48&&a<=57&&u==45){i+="\\"+a.toString(16)+" ";continue}if(n==0&&t==1&&a==45){i+="\\"+r.charAt(n);continue}if(a>=128||a==45||a==95||a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122){i+=r.charAt(n);continue}i+="\\"+r.charAt(n)}return i};if(!e.CSS){e.CSS={}}e.CSS.escape=cssEscape;return cssEscape}))}};var r={};function __nccwpck_require__(t){var n=r[t];if(n!==undefined){return n.exports}var a=r[t]={exports:{}};var i=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);i=false}finally{if(i)delete r[t]}return a.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(8);module.exports=t})(); \ No newline at end of file +(()=>{var e={4:function(e){(function(r,t){if(true){e.exports=t(r)}else{}})(typeof global!="undefined"?global:this,(function(e){if(e.CSS&&e.CSS.escape){return e.CSS.escape}var cssEscape=function(e){if(arguments.length==0){throw new TypeError("`CSS.escape` requires an argument.")}var r=String(e);var t=r.length;var n=-1;var a;var i="";var u=r.charCodeAt(0);while(++n<t){a=r.charCodeAt(n);if(a==0){i+="�";continue}if(a>=1&&a<=31||a==127||n==0&&a>=48&&a<=57||n==1&&a>=48&&a<=57&&u==45){i+="\\"+a.toString(16)+" ";continue}if(n==0&&t==1&&a==45){i+="\\"+r.charAt(n);continue}if(a>=128||a==45||a==95||a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122){i+=r.charAt(n);continue}i+="\\"+r.charAt(n)}return i};if(!e.CSS){e.CSS={}}e.CSS.escape=cssEscape;return cssEscape}))}};var r={};function __nccwpck_require__(t){var n=r[t];if(n!==undefined){return n.exports}var a=r[t]={exports:{}};var i=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);i=false}finally{if(i)delete r[t]}return a.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(4);module.exports=t})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js b/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js index 3d928e7524ef41..24a243af2f2657 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js @@ -1,7 +1,7 @@ -(()=>{var e={970:function(e,i,t){e=t.nmd(e); +(()=>{var e={651:function(e,i,t){e=t.nmd(e); /*! * Platform.js v1.3.6 * Copyright 2014-2020 Benjamin Tan * Copyright 2011-2013 John-David Dalton * Available under MIT license - */(function(){"use strict";var t={function:true,object:true};var r=t[typeof window]&&window||this;var a=r;var n=t[typeof i]&&i;var o=t["object"]&&e&&!e.nodeType&&e;var l=n&&o&&typeof global=="object"&&global;if(l&&(l.global===l||l.window===l||l.self===l)){r=l}var s=Math.pow(2,53)-1;var f=/\bOpera/;var b=this;var c=Object.prototype;var p=c.hasOwnProperty;var u=c.toString;function capitalize(e){e=String(e);return e.charAt(0).toUpperCase()+e.slice(1)}function cleanupOS(e,i,t){var r={"10.0":"10",6.4:"10 Technical Preview",6.3:"8.1",6.2:"8",6.1:"Server 2008 R2 / 7","6.0":"Server 2008 / Vista",5.2:"Server 2003 / XP 64-bit",5.1:"XP",5.01:"2000 SP1","5.0":"2000","4.0":"NT","4.90":"ME"};if(i&&t&&/^Win/i.test(e)&&!/^Windows Phone /i.test(e)&&(r=r[/[\d.]+$/.exec(e)])){e="Windows "+r}e=String(e);if(i&&t){e=e.replace(RegExp(i,"i"),t)}e=format(e.replace(/ ce$/i," CE").replace(/\bhpw/i,"web").replace(/\bMacintosh\b/,"Mac OS").replace(/_PowerPC\b/i," OS").replace(/\b(OS X) [^ \d]+/i,"$1").replace(/\bMac (OS X)\b/,"$1").replace(/\/(\d)/," $1").replace(/_/g,".").replace(/(?: BePC|[ .]*fc[ \d.]+)$/i,"").replace(/\bx86\.64\b/gi,"x86_64").replace(/\b(Windows Phone) OS\b/,"$1").replace(/\b(Chrome OS \w+) [\d.]+\b/,"$1").split(" on ")[0]);return e}function each(e,i){var t=-1,r=e?e.length:0;if(typeof r=="number"&&r>-1&&r<=s){while(++t<r){i(e[t],t,e)}}else{forOwn(e,i)}}function format(e){e=trim(e);return/^(?:webOS|i(?:OS|P))/.test(e)?e:capitalize(e)}function forOwn(e,i){for(var t in e){if(p.call(e,t)){i(e[t],t,e)}}}function getClassOf(e){return e==null?capitalize(e):u.call(e).slice(8,-1)}function isHostType(e,i){var t=e!=null?typeof e[i]:"number";return!/^(?:boolean|number|string|undefined)$/.test(t)&&(t=="object"?!!e[i]:true)}function qualify(e){return String(e).replace(/([ -])(?!$)/g,"$1?")}function reduce(e,i){var t=null;each(e,(function(r,a){t=i(t,r,a,e)}));return t}function trim(e){return String(e).replace(/^ +| +$/g,"")}function parse(e){var i=r;var t=e&&typeof e=="object"&&getClassOf(e)!="String";if(t){i=e;e=null}var n=i.navigator||{};var o=n.userAgent||"";e||(e=o);var l=t||b==a;var s=t?!!n.likeChrome:/\bChrome\b/.test(e)&&!/internal|\n/i.test(u.toString());var c="Object",p=t?c:"ScriptBridgingProxyObject",d=t?c:"Environment",S=t&&i.java?"JavaPackage":getClassOf(i.java),x=t?c:"RuntimeObject";var m=/\bJava/.test(S)&&i.java;var g=m&&getClassOf(i.environment)==d;var h=m?"a":"α";var v=m?"b":"β";var O=i.document||{};var y=i.operamini||i.opera;var w=f.test(w=t&&y?y["[[Class]]"]:getClassOf(y))?w:y=null;var M;var E=e;var P=[];var C=null;var k=e==o;var B=k&&y&&typeof y.version=="function"&&y.version();var W;var _=getLayout([{label:"EdgeHTML",pattern:"Edge"},"Trident",{label:"WebKit",pattern:"AppleWebKit"},"iCab","Presto","NetFront","Tasman","KHTML","Gecko"]);var R=getName(["Adobe AIR","Arora","Avant Browser","Breach","Camino","Electron","Epiphany","Fennec","Flock","Galeon","GreenBrowser","iCab","Iceweasel","K-Meleon","Konqueror","Lunascape","Maxthon",{label:"Microsoft Edge",pattern:"(?:Edge|Edg|EdgA|EdgiOS)"},"Midori","Nook Browser","PaleMoon","PhantomJS","Raven","Rekonq","RockMelt",{label:"Samsung Internet",pattern:"SamsungBrowser"},"SeaMonkey",{label:"Silk",pattern:"(?:Cloud9|Silk-Accelerated)"},"Sleipnir","SlimBrowser",{label:"SRWare Iron",pattern:"Iron"},"Sunrise","Swiftfox","Vivaldi","Waterfox","WebPositive",{label:"Yandex Browser",pattern:"YaBrowser"},{label:"UC Browser",pattern:"UCBrowser"},"Opera Mini",{label:"Opera Mini",pattern:"OPiOS"},"Opera",{label:"Opera",pattern:"OPR"},"Chromium","Chrome",{label:"Chrome",pattern:"(?:HeadlessChrome)"},{label:"Chrome Mobile",pattern:"(?:CriOS|CrMo)"},{label:"Firefox",pattern:"(?:Firefox|Minefield)"},{label:"Firefox for iOS",pattern:"FxiOS"},{label:"IE",pattern:"IEMobile"},{label:"IE",pattern:"MSIE"},"Safari"]);var A=getProduct([{label:"BlackBerry",pattern:"BB10"},"BlackBerry",{label:"Galaxy S",pattern:"GT-I9000"},{label:"Galaxy S2",pattern:"GT-I9100"},{label:"Galaxy S3",pattern:"GT-I9300"},{label:"Galaxy S4",pattern:"GT-I9500"},{label:"Galaxy S5",pattern:"SM-G900"},{label:"Galaxy S6",pattern:"SM-G920"},{label:"Galaxy S6 Edge",pattern:"SM-G925"},{label:"Galaxy S7",pattern:"SM-G930"},{label:"Galaxy S7 Edge",pattern:"SM-G935"},"Google TV","Lumia","iPad","iPod","iPhone","Kindle",{label:"Kindle Fire",pattern:"(?:Cloud9|Silk-Accelerated)"},"Nexus","Nook","PlayBook","PlayStation Vita","PlayStation","TouchPad","Transformer",{label:"Wii U",pattern:"WiiU"},"Wii","Xbox One",{label:"Xbox 360",pattern:"Xbox"},"Xoom"]);var I=getManufacturer({Apple:{iPad:1,iPhone:1,iPod:1},Alcatel:{},Archos:{},Amazon:{Kindle:1,"Kindle Fire":1},Asus:{Transformer:1},"Barnes & Noble":{Nook:1},BlackBerry:{PlayBook:1},Google:{"Google TV":1,Nexus:1},HP:{TouchPad:1},HTC:{},Huawei:{},Lenovo:{},LG:{},Microsoft:{Xbox:1,"Xbox One":1},Motorola:{Xoom:1},Nintendo:{"Wii U":1,Wii:1},Nokia:{Lumia:1},Oppo:{},Samsung:{"Galaxy S":1,"Galaxy S2":1,"Galaxy S3":1,"Galaxy S4":1},Sony:{PlayStation:1,"PlayStation Vita":1},Xiaomi:{Mi:1,Redmi:1}});var T=getOS(["Windows Phone","KaiOS","Android","CentOS",{label:"Chrome OS",pattern:"CrOS"},"Debian",{label:"DragonFly BSD",pattern:"DragonFly"},"Fedora","FreeBSD","Gentoo","Haiku","Kubuntu","Linux Mint","OpenBSD","Red Hat","SuSE","Ubuntu","Xubuntu","Cygwin","Symbian OS","hpwOS","webOS ","webOS","Tablet OS","Tizen","Linux","Mac OS X","Macintosh","Mac","Windows 98;","Windows "]);function getLayout(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getManufacturer(i){return reduce(i,(function(i,t,r){return i||(t[A]||t[/^[a-z]+(?: +[a-z]+\b)*/i.exec(A)]||RegExp("\\b"+qualify(r)+"(?:\\b|\\w*\\d)","i").exec(e))&&r}))}function getName(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getOS(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+"(?:/[\\d.]+|[ \\w.]*)","i").exec(e))){i=cleanupOS(i,r,t.label||t)}return i}))}function getProduct(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+" *\\d+[.\\w_]*","i").exec(e)||RegExp("\\b"+r+" *\\w+-[\\w]*","i").exec(e)||RegExp("\\b"+r+"(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)","i").exec(e))){if((i=String(t.label&&!RegExp(r,"i").test(t.label)?t.label:i).split("/"))[1]&&!/[\d.]+/.test(i[0])){i[0]+=" "+i[1]}t=t.label||t;i=format(i[0].replace(RegExp(r,"i"),t).replace(RegExp("; *(?:"+t+"[_-])?","i")," ").replace(RegExp("("+t+")[-_.]?(\\w)","i"),"$1 $2"))}return i}))}function getVersion(i){return reduce(i,(function(i,t){return i||(RegExp(t+"(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)","i").exec(e)||0)[1]||null}))}function toStringPlatform(){return this.description||""}_&&(_=[_]);if(/\bAndroid\b/.test(T)&&!A&&(M=/\bAndroid[^;]*;(.*?)(?:Build|\) AppleWebKit)\b/i.exec(e))){A=trim(M[1]).replace(/^[a-z]{2}-[a-z]{2};\s*/i,"")||null}if(I&&!A){A=getProduct([I])}else if(I&&A){A=A.replace(RegExp("^("+qualify(I)+")[-_.\\s]","i"),I+" ").replace(RegExp("^("+qualify(I)+")[-_.]?(\\w)","i"),I+" $2")}if(M=/\bGoogle TV\b/.exec(A)){A=M[0]}if(/\bSimulator\b/i.test(e)){A=(A?A+" ":"")+"Simulator"}if(R=="Opera Mini"&&/\bOPiOS\b/.test(e)){P.push("running in Turbo/Uncompressed mode")}if(R=="IE"&&/\blike iPhone OS\b/.test(e)){M=parse(e.replace(/like iPhone OS/,""));I=M.manufacturer;A=M.product}else if(/^iP/.test(A)){R||(R="Safari");T="iOS"+((M=/ OS ([\d_]+)/i.exec(e))?" "+M[1].replace(/_/g,"."):"")}else if(R=="Konqueror"&&/^Linux\b/i.test(T)){T="Kubuntu"}else if(I&&I!="Google"&&(/Chrome/.test(R)&&!/\bMobile Safari\b/i.test(e)||/\bVita\b/.test(A))||/\bAndroid\b/.test(T)&&/^Chrome/.test(R)&&/\bVersion\//i.test(e)){R="Android Browser";T=/\bAndroid\b/.test(T)?T:"Android"}else if(R=="Silk"){if(!/\bMobi/i.test(e)){T="Android";P.unshift("desktop mode")}if(/Accelerated *= *true/i.test(e)){P.unshift("accelerated")}}else if(R=="UC Browser"&&/\bUCWEB\b/.test(e)){P.push("speed mode")}else if(R=="PaleMoon"&&(M=/\bFirefox\/([\d.]+)\b/.exec(e))){P.push("identifying as Firefox "+M[1])}else if(R=="Firefox"&&(M=/\b(Mobile|Tablet|TV)\b/i.exec(e))){T||(T="Firefox OS");A||(A=M[1])}else if(!R||(M=!/\bMinefield\b/i.test(e)&&/\b(?:Firefox|Safari)\b/.exec(R))){if(R&&!A&&/[\/,]|^[^(]+?\)/.test(e.slice(e.indexOf(M+"/")+8))){R=null}if((M=A||I||T)&&(A||I||/\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(T))){R=/[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(T)?T:M)+" Browser"}}else if(R=="Electron"&&(M=(/\bChrome\/([\d.]+)\b/.exec(e)||0)[1])){P.push("Chromium "+M)}if(!B){B=getVersion(["(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|HeadlessChrome|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$)|UCBrowser|YaBrowser)","Version",qualify(R),"(?:Firefox|Minefield|NetFront)"])}if(M=_=="iCab"&&parseFloat(B)>3&&"WebKit"||/\bOpera\b/.test(R)&&(/\bOPR\b/.test(e)?"Blink":"Presto")||/\b(?:Midori|Nook|Safari)\b/i.test(e)&&!/^(?:Trident|EdgeHTML)$/.test(_)&&"WebKit"||!_&&/\bMSIE\b/i.test(e)&&(T=="Mac OS"?"Tasman":"Trident")||_=="WebKit"&&/\bPlayStation\b(?! Vita\b)/i.test(R)&&"NetFront"){_=[M]}if(R=="IE"&&(M=(/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(e)||0)[1])){R+=" Mobile";T="Windows Phone "+(/\+$/.test(M)?M:M+".x");P.unshift("desktop mode")}else if(/\bWPDesktop\b/i.test(e)){R="IE Mobile";T="Windows Phone 8.x";P.unshift("desktop mode");B||(B=(/\brv:([\d.]+)/.exec(e)||0)[1])}else if(R!="IE"&&_=="Trident"&&(M=/\brv:([\d.]+)/.exec(e))){if(R){P.push("identifying as "+R+(B?" "+B:""))}R="IE";B=M[1]}if(k){if(isHostType(i,"global")){if(m){M=m.lang.System;E=M.getProperty("os.arch");T=T||M.getProperty("os.name")+" "+M.getProperty("os.version")}if(g){try{B=i.require("ringo/engine").version.join(".");R="RingoJS"}catch(e){if((M=i.system)&&M.global.system==i.system){R="Narwhal";T||(T=M[0].os||null)}}if(!R){R="Rhino"}}else if(typeof i.process=="object"&&!i.process.browser&&(M=i.process)){if(typeof M.versions=="object"){if(typeof M.versions.electron=="string"){P.push("Node "+M.versions.node);R="Electron";B=M.versions.electron}else if(typeof M.versions.nw=="string"){P.push("Chromium "+B,"Node "+M.versions.node);R="NW.js";B=M.versions.nw}}if(!R){R="Node.js";E=M.arch;T=M.platform;B=/[\d.]+/.exec(M.version);B=B?B[0]:null}}}else if(getClassOf(M=i.runtime)==p){R="Adobe AIR";T=M.flash.system.Capabilities.os}else if(getClassOf(M=i.phantom)==x){R="PhantomJS";B=(M=M.version||null)&&M.major+"."+M.minor+"."+M.patch}else if(typeof O.documentMode=="number"&&(M=/\bTrident\/(\d+)/i.exec(e))){B=[B,O.documentMode];if((M=+M[1]+4)!=B[1]){P.push("IE "+B[1]+" mode");_&&(_[1]="");B[1]=M}B=R=="IE"?String(B[1].toFixed(1)):B[0]}else if(typeof O.documentMode=="number"&&/^(?:Chrome|Firefox)\b/.test(R)){P.push("masking as "+R+" "+B);R="IE";B="11.0";_=["Trident"];T="Windows"}T=T&&format(T)}if(B&&(M=/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(B)||/(?:alpha|beta)(?: ?\d)?/i.exec(e+";"+(k&&n.appMinorVersion))||/\bMinefield\b/i.test(e)&&"a")){C=/b/i.test(M)?"beta":"alpha";B=B.replace(RegExp(M+"\\+?$"),"")+(C=="beta"?v:h)+(/\d+\+?/.exec(M)||"")}if(R=="Fennec"||R=="Firefox"&&/\b(?:Android|Firefox OS|KaiOS)\b/.test(T)){R="Firefox Mobile"}else if(R=="Maxthon"&&B){B=B.replace(/\.[\d.]+/,".x")}else if(/\bXbox\b/i.test(A)){if(A=="Xbox 360"){T=null}if(A=="Xbox 360"&&/\bIEMobile\b/.test(e)){P.unshift("mobile mode")}}else if((/^(?:Chrome|IE|Opera)$/.test(R)||R&&!A&&!/Browser|Mobi/.test(R))&&(T=="Windows CE"||/Mobi/i.test(e))){R+=" Mobile"}else if(R=="IE"&&k){try{if(i.external===null){P.unshift("platform preview")}}catch(e){P.unshift("embedded")}}else if((/\bBlackBerry\b/.test(A)||/\bBB10\b/.test(e))&&(M=(RegExp(A.replace(/ +/g," *")+"/([.\\d]+)","i").exec(e)||0)[1]||B)){M=[M,/BB10/.test(e)];T=(M[1]?(A=null,I="BlackBerry"):"Device Software")+" "+M[0];B=null}else if(this!=forOwn&&A!="Wii"&&(k&&y||/Opera/.test(R)&&/\b(?:MSIE|Firefox)\b/i.test(e)||R=="Firefox"&&/\bOS X (?:\d+\.){2,}/.test(T)||R=="IE"&&(T&&!/^Win/.test(T)&&B>5.5||/\bWindows XP\b/.test(T)&&B>8||B==8&&!/\bTrident\b/.test(e)))&&!f.test(M=parse.call(forOwn,e.replace(f,"")+";"))&&M.name){M="ing as "+M.name+((M=M.version)?" "+M:"");if(f.test(R)){if(/\bIE\b/.test(M)&&T=="Mac OS"){T=null}M="identify"+M}else{M="mask"+M;if(w){R=format(w.replace(/([a-z])([A-Z])/g,"$1 $2"))}else{R="Opera"}if(/\bIE\b/.test(M)){T=null}if(!k){B=null}}_=["Presto"];P.push(M)}if(M=(/\bAppleWebKit\/([\d.]+\+?)/i.exec(e)||0)[1]){M=[parseFloat(M.replace(/\.(\d)$/,".0$1")),M];if(R=="Safari"&&M[1].slice(-1)=="+"){R="WebKit Nightly";C="alpha";B=M[1].slice(0,-1)}else if(B==M[1]||B==(M[2]=(/\bSafari\/([\d.]+\+?)/i.exec(e)||0)[1])){B=null}M[1]=(/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(e)||0)[1];if(M[0]==537.36&&M[2]==537.36&&parseFloat(M[1])>=28&&_=="WebKit"){_=["Blink"]}if(!k||!s&&!M[1]){_&&(_[1]="like Safari");M=(M=M[0],M<400?1:M<500?2:M<526?3:M<533?4:M<534?"4+":M<535?5:M<537?6:M<538?7:M<601?8:M<602?9:M<604?10:M<606?11:M<608?12:"12")}else{_&&(_[1]="like Chrome");M=M[1]||(M=M[0],M<530?1:M<532?2:M<532.05?3:M<533?4:M<534.03?5:M<534.07?6:M<534.1?7:M<534.13?8:M<534.16?9:M<534.24?10:M<534.3?11:M<535.01?12:M<535.02?"13+":M<535.07?15:M<535.11?16:M<535.19?17:M<536.05?18:M<536.1?19:M<537.01?20:M<537.11?"21+":M<537.13?23:M<537.18?24:M<537.24?25:M<537.36?26:_!="Blink"?"27":"28")}_&&(_[1]+=" "+(M+=typeof M=="number"?".x":/[.+]/.test(M)?"":"+"));if(R=="Safari"&&(!B||parseInt(B)>45)){B=M}else if(R=="Chrome"&&/\bHeadlessChrome/i.test(e)){P.unshift("headless")}}if(R=="Opera"&&(M=/\bzbov|zvav$/.exec(T))){R+=" ";P.unshift("desktop mode");if(M=="zvav"){R+="Mini";B=null}else{R+="Mobile"}T=T.replace(RegExp(" *"+M+"$"),"")}else if(R=="Safari"&&/\bChrome\b/.exec(_&&_[1])){P.unshift("desktop mode");R="Chrome Mobile";B=null;if(/\bOS X\b/.test(T)){I="Apple";T="iOS 4.3+"}else{T=null}}else if(/\bSRWare Iron\b/.test(R)&&!B){B=getVersion("Chrome")}if(B&&B.indexOf(M=/[\d.]+$/.exec(T))==0&&e.indexOf("/"+M+"-")>-1){T=trim(T.replace(M,""))}if(T&&T.indexOf(R)!=-1&&!RegExp(R+" OS").test(T)){T=T.replace(RegExp(" *"+qualify(R)+" *"),"")}if(_&&!/\b(?:Avant|Nook)\b/.test(R)&&(/Browser|Lunascape|Maxthon/.test(R)||R!="Safari"&&/^iOS/.test(T)&&/\bSafari\b/.test(_[1])||/^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(R)&&_[1])){(M=_[_.length-1])&&P.push(M)}if(P.length){P=["("+P.join("; ")+")"]}if(I&&A&&A.indexOf(I)<0){P.push("on "+I)}if(A){P.push((/^on /.test(P[P.length-1])?"":"on ")+A)}if(T){M=/ ([\d.+]+)$/.exec(T);W=M&&T.charAt(T.length-M[0].length-1)=="/";T={architecture:32,family:M&&!W?T.replace(M[0],""):T,version:M?M[1]:null,toString:function(){var e=this.version;return this.family+(e&&!W?" "+e:"")+(this.architecture==64?" 64-bit":"")}}}if((M=/\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(E))&&!/\bi686\b/i.test(E)){if(T){T.architecture=64;T.family=T.family.replace(RegExp(" *"+M),"")}if(R&&(/\bWOW64\b/i.test(e)||k&&/\w(?:86|32)$/.test(n.cpuClass||n.platform)&&!/\bWin64; x64\b/i.test(e))){P.unshift("32-bit")}}else if(T&&/^OS X/.test(T.family)&&R=="Chrome"&&parseFloat(B)>=39){T.architecture=64}e||(e=null);var F={};F.description=e;F.layout=_&&_[0];F.manufacturer=I;F.name=R;F.prerelease=C;F.product=A;F.ua=e;F.version=R&&B;F.os=T||{architecture:null,family:null,version:null,toString:function(){return"null"}};F.parse=parse;F.toString=toStringPlatform;if(F.version){P.unshift(B)}if(F.name){P.unshift(R)}if(T&&R&&!(T==String(T).split(" ")[0]&&(T==R.split(" ")[0]||A))){P.push(A?"("+T+")":"on "+T)}if(P.length){F.description=P.join(" ")}return F}var d=parse();if(typeof define=="function"&&typeof define.amd=="object"&&define.amd){r.platform=d;define((function(){return d}))}else if(n&&o){forOwn(d,(function(e,i){n[i]=e}))}else{r.platform=d}}).call(this)}};var i={};function __nccwpck_require__(t){var r=i[t];if(r!==undefined){return r.exports}var a=i[t]={id:t,loaded:false,exports:{}};var n=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);n=false}finally{if(n)delete i[t]}a.loaded=true;return a.exports}(()=>{__nccwpck_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(970);module.exports=t})(); \ No newline at end of file + */(function(){"use strict";var t={function:true,object:true};var r=t[typeof window]&&window||this;var a=r;var n=t[typeof i]&&i;var o=t["object"]&&e&&!e.nodeType&&e;var l=n&&o&&typeof global=="object"&&global;if(l&&(l.global===l||l.window===l||l.self===l)){r=l}var s=Math.pow(2,53)-1;var f=/\bOpera/;var b=this;var c=Object.prototype;var p=c.hasOwnProperty;var u=c.toString;function capitalize(e){e=String(e);return e.charAt(0).toUpperCase()+e.slice(1)}function cleanupOS(e,i,t){var r={"10.0":"10",6.4:"10 Technical Preview",6.3:"8.1",6.2:"8",6.1:"Server 2008 R2 / 7","6.0":"Server 2008 / Vista",5.2:"Server 2003 / XP 64-bit",5.1:"XP",5.01:"2000 SP1","5.0":"2000","4.0":"NT","4.90":"ME"};if(i&&t&&/^Win/i.test(e)&&!/^Windows Phone /i.test(e)&&(r=r[/[\d.]+$/.exec(e)])){e="Windows "+r}e=String(e);if(i&&t){e=e.replace(RegExp(i,"i"),t)}e=format(e.replace(/ ce$/i," CE").replace(/\bhpw/i,"web").replace(/\bMacintosh\b/,"Mac OS").replace(/_PowerPC\b/i," OS").replace(/\b(OS X) [^ \d]+/i,"$1").replace(/\bMac (OS X)\b/,"$1").replace(/\/(\d)/," $1").replace(/_/g,".").replace(/(?: BePC|[ .]*fc[ \d.]+)$/i,"").replace(/\bx86\.64\b/gi,"x86_64").replace(/\b(Windows Phone) OS\b/,"$1").replace(/\b(Chrome OS \w+) [\d.]+\b/,"$1").split(" on ")[0]);return e}function each(e,i){var t=-1,r=e?e.length:0;if(typeof r=="number"&&r>-1&&r<=s){while(++t<r){i(e[t],t,e)}}else{forOwn(e,i)}}function format(e){e=trim(e);return/^(?:webOS|i(?:OS|P))/.test(e)?e:capitalize(e)}function forOwn(e,i){for(var t in e){if(p.call(e,t)){i(e[t],t,e)}}}function getClassOf(e){return e==null?capitalize(e):u.call(e).slice(8,-1)}function isHostType(e,i){var t=e!=null?typeof e[i]:"number";return!/^(?:boolean|number|string|undefined)$/.test(t)&&(t=="object"?!!e[i]:true)}function qualify(e){return String(e).replace(/([ -])(?!$)/g,"$1?")}function reduce(e,i){var t=null;each(e,(function(r,a){t=i(t,r,a,e)}));return t}function trim(e){return String(e).replace(/^ +| +$/g,"")}function parse(e){var i=r;var t=e&&typeof e=="object"&&getClassOf(e)!="String";if(t){i=e;e=null}var n=i.navigator||{};var o=n.userAgent||"";e||(e=o);var l=t||b==a;var s=t?!!n.likeChrome:/\bChrome\b/.test(e)&&!/internal|\n/i.test(u.toString());var c="Object",p=t?c:"ScriptBridgingProxyObject",d=t?c:"Environment",S=t&&i.java?"JavaPackage":getClassOf(i.java),x=t?c:"RuntimeObject";var m=/\bJava/.test(S)&&i.java;var g=m&&getClassOf(i.environment)==d;var h=m?"a":"α";var v=m?"b":"β";var O=i.document||{};var y=i.operamini||i.opera;var w=f.test(w=t&&y?y["[[Class]]"]:getClassOf(y))?w:y=null;var M;var E=e;var P=[];var C=null;var k=e==o;var B=k&&y&&typeof y.version=="function"&&y.version();var W;var _=getLayout([{label:"EdgeHTML",pattern:"Edge"},"Trident",{label:"WebKit",pattern:"AppleWebKit"},"iCab","Presto","NetFront","Tasman","KHTML","Gecko"]);var R=getName(["Adobe AIR","Arora","Avant Browser","Breach","Camino","Electron","Epiphany","Fennec","Flock","Galeon","GreenBrowser","iCab","Iceweasel","K-Meleon","Konqueror","Lunascape","Maxthon",{label:"Microsoft Edge",pattern:"(?:Edge|Edg|EdgA|EdgiOS)"},"Midori","Nook Browser","PaleMoon","PhantomJS","Raven","Rekonq","RockMelt",{label:"Samsung Internet",pattern:"SamsungBrowser"},"SeaMonkey",{label:"Silk",pattern:"(?:Cloud9|Silk-Accelerated)"},"Sleipnir","SlimBrowser",{label:"SRWare Iron",pattern:"Iron"},"Sunrise","Swiftfox","Vivaldi","Waterfox","WebPositive",{label:"Yandex Browser",pattern:"YaBrowser"},{label:"UC Browser",pattern:"UCBrowser"},"Opera Mini",{label:"Opera Mini",pattern:"OPiOS"},"Opera",{label:"Opera",pattern:"OPR"},"Chromium","Chrome",{label:"Chrome",pattern:"(?:HeadlessChrome)"},{label:"Chrome Mobile",pattern:"(?:CriOS|CrMo)"},{label:"Firefox",pattern:"(?:Firefox|Minefield)"},{label:"Firefox for iOS",pattern:"FxiOS"},{label:"IE",pattern:"IEMobile"},{label:"IE",pattern:"MSIE"},"Safari"]);var A=getProduct([{label:"BlackBerry",pattern:"BB10"},"BlackBerry",{label:"Galaxy S",pattern:"GT-I9000"},{label:"Galaxy S2",pattern:"GT-I9100"},{label:"Galaxy S3",pattern:"GT-I9300"},{label:"Galaxy S4",pattern:"GT-I9500"},{label:"Galaxy S5",pattern:"SM-G900"},{label:"Galaxy S6",pattern:"SM-G920"},{label:"Galaxy S6 Edge",pattern:"SM-G925"},{label:"Galaxy S7",pattern:"SM-G930"},{label:"Galaxy S7 Edge",pattern:"SM-G935"},"Google TV","Lumia","iPad","iPod","iPhone","Kindle",{label:"Kindle Fire",pattern:"(?:Cloud9|Silk-Accelerated)"},"Nexus","Nook","PlayBook","PlayStation Vita","PlayStation","TouchPad","Transformer",{label:"Wii U",pattern:"WiiU"},"Wii","Xbox One",{label:"Xbox 360",pattern:"Xbox"},"Xoom"]);var I=getManufacturer({Apple:{iPad:1,iPhone:1,iPod:1},Alcatel:{},Archos:{},Amazon:{Kindle:1,"Kindle Fire":1},Asus:{Transformer:1},"Barnes & Noble":{Nook:1},BlackBerry:{PlayBook:1},Google:{"Google TV":1,Nexus:1},HP:{TouchPad:1},HTC:{},Huawei:{},Lenovo:{},LG:{},Microsoft:{Xbox:1,"Xbox One":1},Motorola:{Xoom:1},Nintendo:{"Wii U":1,Wii:1},Nokia:{Lumia:1},Oppo:{},Samsung:{"Galaxy S":1,"Galaxy S2":1,"Galaxy S3":1,"Galaxy S4":1},Sony:{PlayStation:1,"PlayStation Vita":1},Xiaomi:{Mi:1,Redmi:1}});var T=getOS(["Windows Phone","KaiOS","Android","CentOS",{label:"Chrome OS",pattern:"CrOS"},"Debian",{label:"DragonFly BSD",pattern:"DragonFly"},"Fedora","FreeBSD","Gentoo","Haiku","Kubuntu","Linux Mint","OpenBSD","Red Hat","SuSE","Ubuntu","Xubuntu","Cygwin","Symbian OS","hpwOS","webOS ","webOS","Tablet OS","Tizen","Linux","Mac OS X","Macintosh","Mac","Windows 98;","Windows "]);function getLayout(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getManufacturer(i){return reduce(i,(function(i,t,r){return i||(t[A]||t[/^[a-z]+(?: +[a-z]+\b)*/i.exec(A)]||RegExp("\\b"+qualify(r)+"(?:\\b|\\w*\\d)","i").exec(e))&&r}))}function getName(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getOS(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+"(?:/[\\d.]+|[ \\w.]*)","i").exec(e))){i=cleanupOS(i,r,t.label||t)}return i}))}function getProduct(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+" *\\d+[.\\w_]*","i").exec(e)||RegExp("\\b"+r+" *\\w+-[\\w]*","i").exec(e)||RegExp("\\b"+r+"(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)","i").exec(e))){if((i=String(t.label&&!RegExp(r,"i").test(t.label)?t.label:i).split("/"))[1]&&!/[\d.]+/.test(i[0])){i[0]+=" "+i[1]}t=t.label||t;i=format(i[0].replace(RegExp(r,"i"),t).replace(RegExp("; *(?:"+t+"[_-])?","i")," ").replace(RegExp("("+t+")[-_.]?(\\w)","i"),"$1 $2"))}return i}))}function getVersion(i){return reduce(i,(function(i,t){return i||(RegExp(t+"(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)","i").exec(e)||0)[1]||null}))}function toStringPlatform(){return this.description||""}_&&(_=[_]);if(/\bAndroid\b/.test(T)&&!A&&(M=/\bAndroid[^;]*;(.*?)(?:Build|\) AppleWebKit)\b/i.exec(e))){A=trim(M[1]).replace(/^[a-z]{2}-[a-z]{2};\s*/i,"")||null}if(I&&!A){A=getProduct([I])}else if(I&&A){A=A.replace(RegExp("^("+qualify(I)+")[-_.\\s]","i"),I+" ").replace(RegExp("^("+qualify(I)+")[-_.]?(\\w)","i"),I+" $2")}if(M=/\bGoogle TV\b/.exec(A)){A=M[0]}if(/\bSimulator\b/i.test(e)){A=(A?A+" ":"")+"Simulator"}if(R=="Opera Mini"&&/\bOPiOS\b/.test(e)){P.push("running in Turbo/Uncompressed mode")}if(R=="IE"&&/\blike iPhone OS\b/.test(e)){M=parse(e.replace(/like iPhone OS/,""));I=M.manufacturer;A=M.product}else if(/^iP/.test(A)){R||(R="Safari");T="iOS"+((M=/ OS ([\d_]+)/i.exec(e))?" "+M[1].replace(/_/g,"."):"")}else if(R=="Konqueror"&&/^Linux\b/i.test(T)){T="Kubuntu"}else if(I&&I!="Google"&&(/Chrome/.test(R)&&!/\bMobile Safari\b/i.test(e)||/\bVita\b/.test(A))||/\bAndroid\b/.test(T)&&/^Chrome/.test(R)&&/\bVersion\//i.test(e)){R="Android Browser";T=/\bAndroid\b/.test(T)?T:"Android"}else if(R=="Silk"){if(!/\bMobi/i.test(e)){T="Android";P.unshift("desktop mode")}if(/Accelerated *= *true/i.test(e)){P.unshift("accelerated")}}else if(R=="UC Browser"&&/\bUCWEB\b/.test(e)){P.push("speed mode")}else if(R=="PaleMoon"&&(M=/\bFirefox\/([\d.]+)\b/.exec(e))){P.push("identifying as Firefox "+M[1])}else if(R=="Firefox"&&(M=/\b(Mobile|Tablet|TV)\b/i.exec(e))){T||(T="Firefox OS");A||(A=M[1])}else if(!R||(M=!/\bMinefield\b/i.test(e)&&/\b(?:Firefox|Safari)\b/.exec(R))){if(R&&!A&&/[\/,]|^[^(]+?\)/.test(e.slice(e.indexOf(M+"/")+8))){R=null}if((M=A||I||T)&&(A||I||/\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(T))){R=/[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(T)?T:M)+" Browser"}}else if(R=="Electron"&&(M=(/\bChrome\/([\d.]+)\b/.exec(e)||0)[1])){P.push("Chromium "+M)}if(!B){B=getVersion(["(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|HeadlessChrome|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$)|UCBrowser|YaBrowser)","Version",qualify(R),"(?:Firefox|Minefield|NetFront)"])}if(M=_=="iCab"&&parseFloat(B)>3&&"WebKit"||/\bOpera\b/.test(R)&&(/\bOPR\b/.test(e)?"Blink":"Presto")||/\b(?:Midori|Nook|Safari)\b/i.test(e)&&!/^(?:Trident|EdgeHTML)$/.test(_)&&"WebKit"||!_&&/\bMSIE\b/i.test(e)&&(T=="Mac OS"?"Tasman":"Trident")||_=="WebKit"&&/\bPlayStation\b(?! Vita\b)/i.test(R)&&"NetFront"){_=[M]}if(R=="IE"&&(M=(/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(e)||0)[1])){R+=" Mobile";T="Windows Phone "+(/\+$/.test(M)?M:M+".x");P.unshift("desktop mode")}else if(/\bWPDesktop\b/i.test(e)){R="IE Mobile";T="Windows Phone 8.x";P.unshift("desktop mode");B||(B=(/\brv:([\d.]+)/.exec(e)||0)[1])}else if(R!="IE"&&_=="Trident"&&(M=/\brv:([\d.]+)/.exec(e))){if(R){P.push("identifying as "+R+(B?" "+B:""))}R="IE";B=M[1]}if(k){if(isHostType(i,"global")){if(m){M=m.lang.System;E=M.getProperty("os.arch");T=T||M.getProperty("os.name")+" "+M.getProperty("os.version")}if(g){try{B=i.require("ringo/engine").version.join(".");R="RingoJS"}catch(e){if((M=i.system)&&M.global.system==i.system){R="Narwhal";T||(T=M[0].os||null)}}if(!R){R="Rhino"}}else if(typeof i.process=="object"&&!i.process.browser&&(M=i.process)){if(typeof M.versions=="object"){if(typeof M.versions.electron=="string"){P.push("Node "+M.versions.node);R="Electron";B=M.versions.electron}else if(typeof M.versions.nw=="string"){P.push("Chromium "+B,"Node "+M.versions.node);R="NW.js";B=M.versions.nw}}if(!R){R="Node.js";E=M.arch;T=M.platform;B=/[\d.]+/.exec(M.version);B=B?B[0]:null}}}else if(getClassOf(M=i.runtime)==p){R="Adobe AIR";T=M.flash.system.Capabilities.os}else if(getClassOf(M=i.phantom)==x){R="PhantomJS";B=(M=M.version||null)&&M.major+"."+M.minor+"."+M.patch}else if(typeof O.documentMode=="number"&&(M=/\bTrident\/(\d+)/i.exec(e))){B=[B,O.documentMode];if((M=+M[1]+4)!=B[1]){P.push("IE "+B[1]+" mode");_&&(_[1]="");B[1]=M}B=R=="IE"?String(B[1].toFixed(1)):B[0]}else if(typeof O.documentMode=="number"&&/^(?:Chrome|Firefox)\b/.test(R)){P.push("masking as "+R+" "+B);R="IE";B="11.0";_=["Trident"];T="Windows"}T=T&&format(T)}if(B&&(M=/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(B)||/(?:alpha|beta)(?: ?\d)?/i.exec(e+";"+(k&&n.appMinorVersion))||/\bMinefield\b/i.test(e)&&"a")){C=/b/i.test(M)?"beta":"alpha";B=B.replace(RegExp(M+"\\+?$"),"")+(C=="beta"?v:h)+(/\d+\+?/.exec(M)||"")}if(R=="Fennec"||R=="Firefox"&&/\b(?:Android|Firefox OS|KaiOS)\b/.test(T)){R="Firefox Mobile"}else if(R=="Maxthon"&&B){B=B.replace(/\.[\d.]+/,".x")}else if(/\bXbox\b/i.test(A)){if(A=="Xbox 360"){T=null}if(A=="Xbox 360"&&/\bIEMobile\b/.test(e)){P.unshift("mobile mode")}}else if((/^(?:Chrome|IE|Opera)$/.test(R)||R&&!A&&!/Browser|Mobi/.test(R))&&(T=="Windows CE"||/Mobi/i.test(e))){R+=" Mobile"}else if(R=="IE"&&k){try{if(i.external===null){P.unshift("platform preview")}}catch(e){P.unshift("embedded")}}else if((/\bBlackBerry\b/.test(A)||/\bBB10\b/.test(e))&&(M=(RegExp(A.replace(/ +/g," *")+"/([.\\d]+)","i").exec(e)||0)[1]||B)){M=[M,/BB10/.test(e)];T=(M[1]?(A=null,I="BlackBerry"):"Device Software")+" "+M[0];B=null}else if(this!=forOwn&&A!="Wii"&&(k&&y||/Opera/.test(R)&&/\b(?:MSIE|Firefox)\b/i.test(e)||R=="Firefox"&&/\bOS X (?:\d+\.){2,}/.test(T)||R=="IE"&&(T&&!/^Win/.test(T)&&B>5.5||/\bWindows XP\b/.test(T)&&B>8||B==8&&!/\bTrident\b/.test(e)))&&!f.test(M=parse.call(forOwn,e.replace(f,"")+";"))&&M.name){M="ing as "+M.name+((M=M.version)?" "+M:"");if(f.test(R)){if(/\bIE\b/.test(M)&&T=="Mac OS"){T=null}M="identify"+M}else{M="mask"+M;if(w){R=format(w.replace(/([a-z])([A-Z])/g,"$1 $2"))}else{R="Opera"}if(/\bIE\b/.test(M)){T=null}if(!k){B=null}}_=["Presto"];P.push(M)}if(M=(/\bAppleWebKit\/([\d.]+\+?)/i.exec(e)||0)[1]){M=[parseFloat(M.replace(/\.(\d)$/,".0$1")),M];if(R=="Safari"&&M[1].slice(-1)=="+"){R="WebKit Nightly";C="alpha";B=M[1].slice(0,-1)}else if(B==M[1]||B==(M[2]=(/\bSafari\/([\d.]+\+?)/i.exec(e)||0)[1])){B=null}M[1]=(/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(e)||0)[1];if(M[0]==537.36&&M[2]==537.36&&parseFloat(M[1])>=28&&_=="WebKit"){_=["Blink"]}if(!k||!s&&!M[1]){_&&(_[1]="like Safari");M=(M=M[0],M<400?1:M<500?2:M<526?3:M<533?4:M<534?"4+":M<535?5:M<537?6:M<538?7:M<601?8:M<602?9:M<604?10:M<606?11:M<608?12:"12")}else{_&&(_[1]="like Chrome");M=M[1]||(M=M[0],M<530?1:M<532?2:M<532.05?3:M<533?4:M<534.03?5:M<534.07?6:M<534.1?7:M<534.13?8:M<534.16?9:M<534.24?10:M<534.3?11:M<535.01?12:M<535.02?"13+":M<535.07?15:M<535.11?16:M<535.19?17:M<536.05?18:M<536.1?19:M<537.01?20:M<537.11?"21+":M<537.13?23:M<537.18?24:M<537.24?25:M<537.36?26:_!="Blink"?"27":"28")}_&&(_[1]+=" "+(M+=typeof M=="number"?".x":/[.+]/.test(M)?"":"+"));if(R=="Safari"&&(!B||parseInt(B)>45)){B=M}else if(R=="Chrome"&&/\bHeadlessChrome/i.test(e)){P.unshift("headless")}}if(R=="Opera"&&(M=/\bzbov|zvav$/.exec(T))){R+=" ";P.unshift("desktop mode");if(M=="zvav"){R+="Mini";B=null}else{R+="Mobile"}T=T.replace(RegExp(" *"+M+"$"),"")}else if(R=="Safari"&&/\bChrome\b/.exec(_&&_[1])){P.unshift("desktop mode");R="Chrome Mobile";B=null;if(/\bOS X\b/.test(T)){I="Apple";T="iOS 4.3+"}else{T=null}}else if(/\bSRWare Iron\b/.test(R)&&!B){B=getVersion("Chrome")}if(B&&B.indexOf(M=/[\d.]+$/.exec(T))==0&&e.indexOf("/"+M+"-")>-1){T=trim(T.replace(M,""))}if(T&&T.indexOf(R)!=-1&&!RegExp(R+" OS").test(T)){T=T.replace(RegExp(" *"+qualify(R)+" *"),"")}if(_&&!/\b(?:Avant|Nook)\b/.test(R)&&(/Browser|Lunascape|Maxthon/.test(R)||R!="Safari"&&/^iOS/.test(T)&&/\bSafari\b/.test(_[1])||/^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(R)&&_[1])){(M=_[_.length-1])&&P.push(M)}if(P.length){P=["("+P.join("; ")+")"]}if(I&&A&&A.indexOf(I)<0){P.push("on "+I)}if(A){P.push((/^on /.test(P[P.length-1])?"":"on ")+A)}if(T){M=/ ([\d.+]+)$/.exec(T);W=M&&T.charAt(T.length-M[0].length-1)=="/";T={architecture:32,family:M&&!W?T.replace(M[0],""):T,version:M?M[1]:null,toString:function(){var e=this.version;return this.family+(e&&!W?" "+e:"")+(this.architecture==64?" 64-bit":"")}}}if((M=/\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(E))&&!/\bi686\b/i.test(E)){if(T){T.architecture=64;T.family=T.family.replace(RegExp(" *"+M),"")}if(R&&(/\bWOW64\b/i.test(e)||k&&/\w(?:86|32)$/.test(n.cpuClass||n.platform)&&!/\bWin64; x64\b/i.test(e))){P.unshift("32-bit")}}else if(T&&/^OS X/.test(T.family)&&R=="Chrome"&&parseFloat(B)>=39){T.architecture=64}e||(e=null);var F={};F.description=e;F.layout=_&&_[0];F.manufacturer=I;F.name=R;F.prerelease=C;F.product=A;F.ua=e;F.version=R&&B;F.os=T||{architecture:null,family:null,version:null,toString:function(){return"null"}};F.parse=parse;F.toString=toStringPlatform;if(F.version){P.unshift(B)}if(F.name){P.unshift(R)}if(T&&R&&!(T==String(T).split(" ")[0]&&(T==R.split(" ")[0]||A))){P.push(A?"("+T+")":"on "+T)}if(P.length){F.description=P.join(" ")}return F}var d=parse();if(typeof define=="function"&&typeof define.amd=="object"&&define.amd){r.platform=d;define((function(){return d}))}else if(n&&o){forOwn(d,(function(e,i){n[i]=e}))}else{r.platform=d}}).call(this)}};var i={};function __nccwpck_require__(t){var r=i[t];if(r!==undefined){return r.exports}var a=i[t]={id:t,loaded:false,exports:{}};var n=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);n=false}finally{if(n)delete i[t]}a.loaded=true;return a.exports}(()=>{__nccwpck_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(651);module.exports=t})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js b/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js index 4bc71988687f6c..65bc0548742798 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js @@ -1 +1 @@ -(()=>{var e={490:(e,n)=>{class ArraySet{constructor(){this._array=[];this._set=new Map}static fromArray(e,n){const t=new ArraySet;for(let r=0,o=e.length;r<o;r++){t.add(e[r],n)}return t}size(){return this._set.size}add(e,n){const t=this.has(e);const r=this._array.length;if(!t||n){this._array.push(e)}if(!t){this._set.set(e,r)}}has(e){return this._set.has(e)}indexOf(e){const n=this._set.get(e);if(n>=0){return n}throw new Error('"'+e+'" is not in the set.')}at(e){if(e>=0&&e<this._array.length){return this._array[e]}throw new Error("No element indexed by "+e)}toArray(){return this._array.slice()}}n.I=ArraySet},905:(e,n,t)=>{const r=t(847);const o=5;const s=1<<o;const i=s-1;const l=s;function toVLQSigned(e){return e<0?(-e<<1)+1:(e<<1)+0}function fromVLQSigned(e){const n=(e&1)===1;const t=e>>1;return n?-t:t}n.encode=function base64VLQ_encode(e){let n="";let t;let s=toVLQSigned(e);do{t=s&i;s>>>=o;if(s>0){t|=l}n+=r.encode(t)}while(s>0);return n}},847:(e,n)=>{const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");n.encode=function(e){if(0<=e&&e<t.length){return t[e]}throw new TypeError("Must be between 0 and 63: "+e)}},705:(e,n)=>{n.GREATEST_LOWER_BOUND=1;n.LEAST_UPPER_BOUND=2;function recursiveSearch(e,t,r,o,s,i){const l=Math.floor((t-e)/2)+e;const a=s(r,o[l],true);if(a===0){return l}else if(a>0){if(t-l>1){return recursiveSearch(l,t,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return t<o.length?t:-1}return l}if(l-e>1){return recursiveSearch(e,l,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return l}return e<0?-1:e}n.search=function search(e,t,r,o){if(t.length===0){return-1}let s=recursiveSearch(-1,t.length,e,t,r,o||n.GREATEST_LOWER_BOUND);if(s<0){return-1}while(s-1>=0){if(r(t[s],t[s-1],true)!==0){break}--s}return s}},13:(e,n,t)=>{const r=t(231);function generatedPositionAfter(e,n){const t=e.generatedLine;const o=n.generatedLine;const s=e.generatedColumn;const i=n.generatedColumn;return o>t||o==t&&i>=s||r.compareByGeneratedPositionsInflated(e,n)<=0}class MappingList{constructor(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}unsortedForEach(e,n){this._array.forEach(e,n)}add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}}toArray(){if(!this._sorted){this._array.sort(r.compareByGeneratedPositionsInflated);this._sorted=true}return this._array}}n.H=MappingList},837:(e,n,t)=>{"use strict";const r=t(147);const o=t(17);e.exports=function readWasm(){return new Promise(((e,n)=>{const o=t.ab+"mappings.wasm";r.readFile(t.ab+"mappings.wasm",null,((t,r)=>{if(t){n(t);return}e(r.buffer)}))}))};e.exports.initialize=e=>{console.debug("SourceMapConsumer.initialize is a no-op when running in node.js")}},651:(e,n,t)=>{var r;const o=t(231);const s=t(705);const i=t(490).I;const l=t(905);const a=t(837);const u=t(443);const c=Symbol("smcInternal");class SourceMapConsumer{constructor(e,n){if(e==c){return Promise.resolve(this)}return _factory(e,n)}static initialize(e){a.initialize(e["lib/mappings.wasm"])}static fromSourceMap(e,n){return _factoryBSM(e,n)}static async with(e,n,t){const r=await new SourceMapConsumer(e,n);try{return await t(r)}finally{r.destroy()}}eachMapping(e,n,t){throw new Error("Subclasses must implement eachMapping")}allGeneratedPositionsFor(e){throw new Error("Subclasses must implement allGeneratedPositionsFor")}destroy(){throw new Error("Subclasses must implement destroy")}}SourceMapConsumer.prototype._version=3;SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;n.SourceMapConsumer=SourceMapConsumer;class BasicSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const l=o.getArg(r,"sources").map(String);const a=o.getArg(r,"names",[]);const c=o.getArg(r,"sourceRoot",null);const g=o.getArg(r,"sourcesContent",null);const f=o.getArg(r,"mappings");const h=o.getArg(r,"file",null);if(s!=t._version){throw new Error("Unsupported version: "+s)}t._sourceLookupCache=new Map;t._names=i.fromArray(a.map(String),true);t._sources=i.fromArray(l,true);t._absoluteSources=i.fromArray(t._sources.toArray().map((function(e){return o.computeSourceURL(c,e,n)})),true);t.sourceRoot=c;t.sourcesContent=g;t._mappings=f;t._sourceMapURL=n;t.file=h;t._computedColumnSpans=false;t._mappingsPtr=0;t._wasm=null;return u().then((e=>{t._wasm=e;return t}))}))}_findSourceIndex(e){const n=this._sourceLookupCache.get(e);if(typeof n==="number"){return n}const t=o.computeSourceURL(null,e,this._sourceMapURL);if(this._absoluteSources.has(t)){const n=this._absoluteSources.indexOf(t);this._sourceLookupCache.set(e,n);return n}const r=o.computeSourceURL(this.sourceRoot,e,this._sourceMapURL);if(this._absoluteSources.has(r)){const n=this._absoluteSources.indexOf(r);this._sourceLookupCache.set(e,n);return n}return-1}static fromSourceMap(e,n){return new BasicSourceMapConsumer(e.toString())}get sources(){return this._absoluteSources.toArray()}_getMappingsPtr(){if(this._mappingsPtr===0){this._parseMappings()}return this._mappingsPtr}_parseMappings(){const e=this._mappings;const n=e.length;const t=this._wasm.exports.allocate_mappings(n);const r=new Uint8Array(this._wasm.exports.memory.buffer,t,n);for(let t=0;t<n;t++){r[t]=e.charCodeAt(t)}const o=this._wasm.exports.parse_mappings(t);if(!o){const e=this._wasm.exports.get_last_error();let n=`Error parsing mappings (code ${e}): `;switch(e){case 1:n+="the mappings contained a negative line, column, source index, or name index";break;case 2:n+="the mappings contained a number larger than 2**32";break;case 3:n+="reached EOF while in the middle of parsing a VLQ";break;case 4:n+="invalid base 64 character while parsing a VLQ";break;default:n+="unknown error code";break}throw new Error(n)}this._mappingsPtr=o}eachMapping(e,n,t){const r=n||null;const o=t||SourceMapConsumer.GENERATED_ORDER;this._wasm.withMappingCallback((n=>{if(n.source!==null){n.source=this._absoluteSources.at(n.source);if(n.name!==null){n.name=this._names.at(n.name)}}if(this._computedColumnSpans&&n.lastGeneratedColumn===null){n.lastGeneratedColumn=Infinity}e.call(r,n)}),(()=>{switch(o){case SourceMapConsumer.GENERATED_ORDER:this._wasm.exports.by_generated_location(this._getMappingsPtr());break;case SourceMapConsumer.ORIGINAL_ORDER:this._wasm.exports.by_original_location(this._getMappingsPtr());break;default:throw new Error("Unknown order of iteration.")}}))}allGeneratedPositionsFor(e){let n=o.getArg(e,"source");const t=o.getArg(e,"line");const r=e.column||0;n=this._findSourceIndex(n);if(n<0){return[]}if(t<1){throw new Error("Line numbers must be >= 1")}if(r<0){throw new Error("Column numbers must be >= 0")}const s=[];this._wasm.withMappingCallback((e=>{let n=e.lastGeneratedColumn;if(this._computedColumnSpans&&n===null){n=Infinity}s.push({line:e.generatedLine,column:e.generatedColumn,lastColumn:n})}),(()=>{this._wasm.exports.all_generated_locations_for(this._getMappingsPtr(),n,t-1,"column"in e,r)}));return s}destroy(){if(this._mappingsPtr!==0){this._wasm.exports.free_mappings(this._mappingsPtr);this._mappingsPtr=0}}computeColumnSpans(){if(this._computedColumnSpans){return}this._wasm.exports.compute_column_spans(this._getMappingsPtr());this._computedColumnSpans=true}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};if(n.generatedLine<1){throw new Error("Line numbers must be >= 1")}if(n.generatedColumn<0){throw new Error("Column numbers must be >= 0")}let t=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(t==null){t=SourceMapConsumer.GREATEST_LOWER_BOUND}let r;this._wasm.withMappingCallback((e=>r=e),(()=>{this._wasm.exports.original_location_for(this._getMappingsPtr(),n.generatedLine-1,n.generatedColumn,t)}));if(r){if(r.generatedLine===n.generatedLine){let e=o.getArg(r,"source",null);if(e!==null){e=this._absoluteSources.at(e)}let n=o.getArg(r,"name",null);if(n!==null){n=this._names.at(n)}return{source:e,line:o.getArg(r,"originalLine",null),column:o.getArg(r,"originalColumn",null),name:n}}}return{source:null,line:null,column:null,name:null}}hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))}sourceContentFor(e,n){if(!this.sourcesContent){return null}const t=this._findSourceIndex(e);if(t>=0){return this.sourcesContent[t]}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}generatedPositionFor(e){let n=o.getArg(e,"source");n=this._findSourceIndex(n);if(n<0){return{line:null,column:null,lastColumn:null}}const t={source:n,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};if(t.originalLine<1){throw new Error("Line numbers must be >= 1")}if(t.originalColumn<0){throw new Error("Column numbers must be >= 0")}let r=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(r==null){r=SourceMapConsumer.GREATEST_LOWER_BOUND}let s;this._wasm.withMappingCallback((e=>s=e),(()=>{this._wasm.exports.generated_location_for(this._getMappingsPtr(),t.source,t.originalLine-1,t.originalColumn,r)}));if(s){if(s.source===t.source){let e=s.lastGeneratedColumn;if(this._computedColumnSpans&&e===null){e=Infinity}return{line:o.getArg(s,"generatedLine",null),column:o.getArg(s,"generatedColumn",null),lastColumn:e}}}return{line:null,column:null,lastColumn:null}}}BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;r=BasicSourceMapConsumer;class IndexedSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const i=o.getArg(r,"sections");if(s!=t._version){throw new Error("Unsupported version: "+s)}let l={line:-1,column:0};return Promise.all(i.map((e=>{if(e.url){throw new Error("Support for url field in sections not implemented.")}const t=o.getArg(e,"offset");const r=o.getArg(t,"line");const s=o.getArg(t,"column");if(r<l.line||r===l.line&&s<l.column){throw new Error("Section offsets must be ordered and non-overlapping.")}l=t;const i=new SourceMapConsumer(o.getArg(e,"map"),n);return i.then((e=>({generatedOffset:{generatedLine:r+1,generatedColumn:s+1},consumer:e})))}))).then((e=>{t._sections=e;return t}))}))}get sources(){const e=[];for(let n=0;n<this._sections.length;n++){for(let t=0;t<this._sections[n].consumer.sources.length;t++){e.push(this._sections[n].consumer.sources[t])}}return e}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};const t=s.search(n,this._sections,(function(e,n){const t=e.generatedLine-n.generatedOffset.generatedLine;if(t){return t}return e.generatedColumn-n.generatedOffset.generatedColumn}));const r=this._sections[t];if(!r){return{source:null,line:null,column:null,name:null}}return r.consumer.originalPositionFor({line:n.generatedLine-(r.generatedOffset.generatedLine-1),column:n.generatedColumn-(r.generatedOffset.generatedLine===n.generatedLine?r.generatedOffset.generatedColumn-1:0),bias:e.bias})}hasContentsOfAllSources(){return this._sections.every((function(e){return e.consumer.hasContentsOfAllSources()}))}sourceContentFor(e,n){for(let n=0;n<this._sections.length;n++){const t=this._sections[n];const r=t.consumer.sourceContentFor(e,true);if(r){return r}}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}_findSectionIndex(e){for(let n=0;n<this._sections.length;n++){const{consumer:t}=this._sections[n];if(t._findSourceIndex(e)!==-1){return n}}return-1}generatedPositionFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;const s=t&&t.consumer.generatedPositionFor(e);if(s&&s.line!==null){const e=t.generatedOffset.generatedLine-1;const n=t.generatedOffset.generatedColumn-1;if(s.line===1){s.column+=n;if(typeof s.lastColumn==="number"){s.lastColumn+=n}}if(s.lastColumn===Infinity&&r&&s.line===r.generatedOffset.generatedLine){s.lastColumn=r.generatedOffset.generatedColumn-2}s.line+=e;return s}return{line:null,column:null,lastColumn:null}}allGeneratedPositionsFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;if(!t)return[];return t.consumer.allGeneratedPositionsFor(e).map((e=>{const n=t.generatedOffset.generatedLine-1;const o=t.generatedOffset.generatedColumn-1;if(e.line===1){e.column+=o;if(typeof e.lastColumn==="number"){e.lastColumn+=o}}if(e.lastColumn===Infinity&&r&&e.line===r.generatedOffset.generatedLine){e.lastColumn=r.generatedOffset.generatedColumn-2}e.line+=n;return e}))}eachMapping(e,n,t){this._sections.forEach(((r,o)=>{const s=o+1<this._sections.length?this._sections[o+1]:null;const{generatedOffset:i}=r;const l=i.generatedLine-1;const a=i.generatedColumn-1;r.consumer.eachMapping((function(n){if(n.generatedLine===1){n.generatedColumn+=a;if(typeof n.lastGeneratedColumn==="number"){n.lastGeneratedColumn+=a}}if(n.lastGeneratedColumn===Infinity&&s&&n.generatedLine===s.generatedOffset.generatedLine){n.lastGeneratedColumn=s.generatedOffset.generatedColumn-2}n.generatedLine+=l;e.call(this,n)}),n,t)}))}computeColumnSpans(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.computeColumnSpans()}}destroy(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.destroy()}}}r=IndexedSourceMapConsumer;function _factory(e,n){let t=e;if(typeof e==="string"){t=o.parseSourceMapInput(e)}const r=t.sections!=null?new IndexedSourceMapConsumer(t,n):new BasicSourceMapConsumer(t,n);return Promise.resolve(r)}function _factoryBSM(e,n){return BasicSourceMapConsumer.fromSourceMap(e,n)}},929:(e,n,t)=>{const r=t(905);const o=t(231);const s=t(490).I;const i=t(13).H;class SourceMapGenerator{constructor(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new s;this._names=new s;this._mappings=new i;this._sourcesContents=null}static fromSourceMap(e){const n=e.sourceRoot;const t=new SourceMapGenerator({file:e.file,sourceRoot:n});e.eachMapping((function(e){const r={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){r.source=e.source;if(n!=null){r.source=o.relative(n,r.source)}r.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){r.name=e.name}}t.addMapping(r)}));e.sources.forEach((function(r){let s=r;if(n!==null){s=o.relative(n,r)}if(!t._sources.has(s)){t._sources.add(s)}const i=e.sourceContentFor(r);if(i!=null){t.setSourceContent(r,i)}}));return t}addMapping(e){const n=o.getArg(e,"generated");const t=o.getArg(e,"original",null);let r=o.getArg(e,"source",null);let s=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(n,t,r,s)}if(r!=null){r=String(r);if(!this._sources.has(r)){this._sources.add(r)}}if(s!=null){s=String(s);if(!this._names.has(s)){this._names.add(s)}}this._mappings.add({generatedLine:n.line,generatedColumn:n.column,originalLine:t!=null&&t.line,originalColumn:t!=null&&t.column,source:r,name:s})}setSourceContent(e,n){let t=e;if(this._sourceRoot!=null){t=o.relative(this._sourceRoot,t)}if(n!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(t)]=n}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(t)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}}applySourceMap(e,n,t){let r=n;if(n==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}r=e.file}const i=this._sourceRoot;if(i!=null){r=o.relative(i,r)}const l=this._mappings.toArray().length>0?new s:this._sources;const a=new s;this._mappings.unsortedForEach((function(n){if(n.source===r&&n.originalLine!=null){const r=e.originalPositionFor({line:n.originalLine,column:n.originalColumn});if(r.source!=null){n.source=r.source;if(t!=null){n.source=o.join(t,n.source)}if(i!=null){n.source=o.relative(i,n.source)}n.originalLine=r.line;n.originalColumn=r.column;if(r.name!=null){n.name=r.name}}}const s=n.source;if(s!=null&&!l.has(s)){l.add(s)}const u=n.name;if(u!=null&&!a.has(u)){a.add(u)}}),this);this._sources=l;this._names=a;e.sources.forEach((function(n){const r=e.sourceContentFor(n);if(r!=null){if(t!=null){n=o.join(t,n)}if(i!=null){n=o.relative(i,n)}this.setSourceContent(n,r)}}),this)}_validateMapping(e,n,t,r){if(n&&typeof n.line!=="number"&&typeof n.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!n&&!t&&!r){}else if(e&&"line"in e&&"column"in e&&n&&"line"in n&&"column"in n&&e.line>0&&e.column>=0&&n.line>0&&n.column>=0&&t){}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:t,original:n,name:r}))}}_serializeMappings(){let e=0;let n=1;let t=0;let s=0;let i=0;let l=0;let a="";let u;let c;let g;let f;const h=this._mappings.toArray();for(let p=0,m=h.length;p<m;p++){c=h[p];u="";if(c.generatedLine!==n){e=0;while(c.generatedLine!==n){u+=";";n++}}else if(p>0){if(!o.compareByGeneratedPositionsInflated(c,h[p-1])){continue}u+=","}u+=r.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);u+=r.encode(f-l);l=f;u+=r.encode(c.originalLine-1-s);s=c.originalLine-1;u+=r.encode(c.originalColumn-t);t=c.originalColumn;if(c.name!=null){g=this._names.indexOf(c.name);u+=r.encode(g-i);i=g}}a+=u}return a}_generateSourcesContent(e,n){return e.map((function(e){if(!this._sourcesContents){return null}if(n!=null){e=o.relative(n,e)}const t=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,t)?this._sourcesContents[t]:null}),this)}toJSON(){const e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e}toString(){return JSON.stringify(this.toJSON())}}SourceMapGenerator.prototype._version=3;n.SourceMapGenerator=SourceMapGenerator},175:(e,n,t)=>{const r=t(929).SourceMapGenerator;const o=t(231);const s=/(\r?\n)/;const i=10;const l="$$$isSourceNode$$$";class SourceNode{constructor(e,n,t,r,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=n==null?null:n;this.source=t==null?null:t;this.name=o==null?null:o;this[l]=true;if(r!=null)this.add(r)}static fromStringWithSourceMap(e,n,t){const r=new SourceNode;const i=e.split(s);let l=0;const shiftNextLine=function(){const e=getNextLine();const n=getNextLine()||"";return e+n;function getNextLine(){return l<i.length?i[l++]:undefined}};let a=1,u=0;let c=null;let g;n.eachMapping((function(e){if(c!==null){if(a<e.generatedLine){addMappingWithCode(c,shiftNextLine());a++;u=0}else{g=i[l]||"";const n=g.substr(0,e.generatedColumn-u);i[l]=g.substr(e.generatedColumn-u);u=e.generatedColumn;addMappingWithCode(c,n);c=e;return}}while(a<e.generatedLine){r.add(shiftNextLine());a++}if(u<e.generatedColumn){g=i[l]||"";r.add(g.substr(0,e.generatedColumn));i[l]=g.substr(e.generatedColumn);u=e.generatedColumn}c=e}),this);if(l<i.length){if(c){addMappingWithCode(c,shiftNextLine())}r.add(i.splice(l).join(""))}n.sources.forEach((function(e){const s=n.sourceContentFor(e);if(s!=null){if(t!=null){e=o.join(t,e)}r.setSourceContent(e,s)}}));return r;function addMappingWithCode(e,n){if(e===null||e.source===undefined){r.add(n)}else{const s=t?o.join(t,e.source):e.source;r.add(new SourceNode(e.originalLine,e.originalColumn,s,n,e.name))}}}add(e){if(Array.isArray(e)){e.forEach((function(e){this.add(e)}),this)}else if(e[l]||typeof e==="string"){if(e){this.children.push(e)}}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}prepend(e){if(Array.isArray(e)){for(let n=e.length-1;n>=0;n--){this.prepend(e[n])}}else if(e[l]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}walk(e){let n;for(let t=0,r=this.children.length;t<r;t++){n=this.children[t];if(n[l]){n.walk(e)}else if(n!==""){e(n,{source:this.source,line:this.line,column:this.column,name:this.name})}}}join(e){let n;let t;const r=this.children.length;if(r>0){n=[];for(t=0;t<r-1;t++){n.push(this.children[t]);n.push(e)}n.push(this.children[t]);this.children=n}return this}replaceRight(e,n){const t=this.children[this.children.length-1];if(t[l]){t.replaceRight(e,n)}else if(typeof t==="string"){this.children[this.children.length-1]=t.replace(e,n)}else{this.children.push("".replace(e,n))}return this}setSourceContent(e,n){this.sourceContents[o.toSetString(e)]=n}walkSourceContents(e){for(let n=0,t=this.children.length;n<t;n++){if(this.children[n][l]){this.children[n].walkSourceContents(e)}}const n=Object.keys(this.sourceContents);for(let t=0,r=n.length;t<r;t++){e(o.fromSetString(n[t]),this.sourceContents[n[t]])}}toString(){let e="";this.walk((function(n){e+=n}));return e}toStringWithSourceMap(e){const n={code:"",line:1,column:0};const t=new r(e);let o=false;let s=null;let l=null;let a=null;let u=null;this.walk((function(e,r){n.code+=e;if(r.source!==null&&r.line!==null&&r.column!==null){if(s!==r.source||l!==r.line||a!==r.column||u!==r.name){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}s=r.source;l=r.line;a=r.column;u=r.name;o=true}else if(o){t.addMapping({generated:{line:n.line,column:n.column}});s=null;o=false}for(let l=0,a=e.length;l<a;l++){if(e.charCodeAt(l)===i){n.line++;n.column=0;if(l+1===a){s=null;o=false}else if(o){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}}else{n.column++}}}));this.walkSourceContents((function(e,n){t.setSourceContent(e,n)}));return{code:n.code,map:t}}}n.SourceNode=SourceNode},881:(e,n,t)=>{"use strict";e.exports=typeof URL==="function"?URL:t(310).URL},231:(e,n,t)=>{const r=t(881);function getArg(e,n,t){if(n in e){return e[n]}else if(arguments.length===3){return t}throw new Error('"'+n+'" is a required argument.')}n.getArg=getArg;const o=function(){const e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}n.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}n.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}const n=e.length;if(n<9){return false}if(e.charCodeAt(n-1)!==95||e.charCodeAt(n-2)!==95||e.charCodeAt(n-3)!==111||e.charCodeAt(n-4)!==116||e.charCodeAt(n-5)!==111||e.charCodeAt(n-6)!==114||e.charCodeAt(n-7)!==112||e.charCodeAt(n-8)!==95||e.charCodeAt(n-9)!==95){return false}for(let t=n-10;t>=0;t--){if(e.charCodeAt(t)!==36){return false}}return true}function strcmp(e,n){if(e===n){return 0}if(e===null){return 1}if(n===null){return-1}if(e>n){return 1}return-1}function compareByGeneratedPositionsInflated(e,n){let t=e.generatedLine-n.generatedLine;if(t!==0){return t}t=e.generatedColumn-n.generatedColumn;if(t!==0){return t}t=strcmp(e.source,n.source);if(t!==0){return t}t=e.originalLine-n.originalLine;if(t!==0){return t}t=e.originalColumn-n.originalColumn;if(t!==0){return t}return strcmp(e.name,n.name)}n.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}n.parseSourceMapInput=parseSourceMapInput;const s="http:";const i=`${s}//host`;function createSafeHandler(e){return n=>{const t=getURLType(n);const o=buildSafeBase(n);const l=new r(n,o);e(l);const a=l.toString();if(t==="absolute"){return a}else if(t==="scheme-relative"){return a.slice(s.length)}else if(t==="path-absolute"){return a.slice(i.length)}return computeRelativeURL(o,a)}}function withBase(e,n){return new r(e,n).toString()}function buildUniqueSegment(e,n){let t=0;do{const r=e+t++;if(n.indexOf(r)===-1)return r}while(true)}function buildSafeBase(e){const n=e.split("..").length-1;const t=buildUniqueSegment("p",e);let r=`${i}/`;for(let e=0;e<n;e++){r+=`${t}/`}return r}const l=/^[A-Za-z0-9\+\-\.]+:/;function getURLType(e){if(e[0]==="/"){if(e[1]==="/")return"scheme-relative";return"path-absolute"}return l.test(e)?"absolute":"path-relative"}function computeRelativeURL(e,n){if(typeof e==="string")e=new r(e);if(typeof n==="string")n=new r(n);const t=n.pathname.split("/");const o=e.pathname.split("/");if(o.length>0&&!o[o.length-1]){o.pop()}while(t.length>0&&o.length>0&&t[0]===o[0]){t.shift();o.shift()}const s=o.map((()=>"..")).concat(t).join("/");return s+n.search+n.hash}const a=createSafeHandler((e=>{e.pathname=e.pathname.replace(/\/?$/,"/")}));const u=createSafeHandler((e=>{e.href=new r(".",e.toString()).toString()}));const c=createSafeHandler((e=>{}));n.normalize=c;function join(e,n){const t=getURLType(n);const r=getURLType(e);e=a(e);if(t==="absolute"){return withBase(n,undefined)}if(r==="absolute"){return withBase(n,e)}if(t==="scheme-relative"){return c(n)}if(r==="scheme-relative"){return withBase(n,withBase(e,i)).slice(s.length)}if(t==="path-absolute"){return c(n)}if(r==="path-absolute"){return withBase(n,withBase(e,i)).slice(i.length)}const o=buildSafeBase(n+e);const l=withBase(n,withBase(e,o));return computeRelativeURL(o,l)}n.join=join;function relative(e,n){const t=relativeIfPossible(e,n);return typeof t==="string"?t:c(n)}n.relative=relative;function relativeIfPossible(e,n){const t=getURLType(e);if(t!==getURLType(n)){return null}const o=buildSafeBase(e+n);const s=new r(e,o);const i=new r(n,o);try{new r("",i.toString())}catch(e){return null}if(i.protocol!==s.protocol||i.user!==s.user||i.password!==s.password||i.hostname!==s.hostname||i.port!==s.port){return null}return computeRelativeURL(s,i)}function computeSourceURL(e,n,t){if(e&&getURLType(n)==="path-absolute"){n=n.replace(/^\//,"")}let r=c(n||"");if(e)r=join(e,r);if(t)r=join(u(t),r);return r}n.computeSourceURL=computeSourceURL},443:(e,n,t)=>{const r=t(837);function Mapping(){this.generatedLine=0;this.generatedColumn=0;this.lastGeneratedColumn=null;this.source=null;this.originalLine=null;this.originalColumn=null;this.name=null}let o=null;e.exports=function wasm(){if(o){return o}const e=[];o=r().then((n=>WebAssembly.instantiate(n,{env:{mapping_callback(n,t,r,o,s,i,l,a,u,c){const g=new Mapping;g.generatedLine=n+1;g.generatedColumn=t;if(r){g.lastGeneratedColumn=o-1}if(s){g.source=i;g.originalLine=l+1;g.originalColumn=a;if(u){g.name=c}}e[e.length-1](g)},start_all_generated_locations_for(){console.time("all_generated_locations_for")},end_all_generated_locations_for(){console.timeEnd("all_generated_locations_for")},start_compute_column_spans(){console.time("compute_column_spans")},end_compute_column_spans(){console.timeEnd("compute_column_spans")},start_generated_location_for(){console.time("generated_location_for")},end_generated_location_for(){console.timeEnd("generated_location_for")},start_original_location_for(){console.time("original_location_for")},end_original_location_for(){console.timeEnd("original_location_for")},start_parse_mappings(){console.time("parse_mappings")},end_parse_mappings(){console.timeEnd("parse_mappings")},start_sort_by_generated_location(){console.time("sort_by_generated_location")},end_sort_by_generated_location(){console.timeEnd("sort_by_generated_location")},start_sort_by_original_location(){console.time("sort_by_original_location")},end_sort_by_original_location(){console.timeEnd("sort_by_original_location")}}}))).then((n=>({exports:n.instance.exports,withMappingCallback:(n,t)=>{e.push(n);try{t()}finally{e.pop()}}}))).then(null,(e=>{o=null;throw e}));return o}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")},310:e=>{"use strict";e.exports=require("url")}};var n={};function __nccwpck_require__(t){var r=n[t];if(r!==undefined){return r.exports}var o=n[t]={exports:{}};var s=true;try{e[t](o,o.exports,__nccwpck_require__);s=false}finally{if(s)delete n[t]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t={};(()=>{var e=t;e.SourceMapGenerator=__nccwpck_require__(929).SourceMapGenerator;e.SourceMapConsumer=__nccwpck_require__(651).SourceMapConsumer;e.SourceNode=__nccwpck_require__(175).SourceNode})();module.exports=t})(); \ No newline at end of file +(()=>{var e={237:(e,n)=>{class ArraySet{constructor(){this._array=[];this._set=new Map}static fromArray(e,n){const t=new ArraySet;for(let r=0,o=e.length;r<o;r++){t.add(e[r],n)}return t}size(){return this._set.size}add(e,n){const t=this.has(e);const r=this._array.length;if(!t||n){this._array.push(e)}if(!t){this._set.set(e,r)}}has(e){return this._set.has(e)}indexOf(e){const n=this._set.get(e);if(n>=0){return n}throw new Error('"'+e+'" is not in the set.')}at(e){if(e>=0&&e<this._array.length){return this._array[e]}throw new Error("No element indexed by "+e)}toArray(){return this._array.slice()}}n.I=ArraySet},717:(e,n,t)=>{const r=t(244);const o=5;const s=1<<o;const i=s-1;const l=s;function toVLQSigned(e){return e<0?(-e<<1)+1:(e<<1)+0}function fromVLQSigned(e){const n=(e&1)===1;const t=e>>1;return n?-t:t}n.encode=function base64VLQ_encode(e){let n="";let t;let s=toVLQSigned(e);do{t=s&i;s>>>=o;if(s>0){t|=l}n+=r.encode(t)}while(s>0);return n}},244:(e,n)=>{const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");n.encode=function(e){if(0<=e&&e<t.length){return t[e]}throw new TypeError("Must be between 0 and 63: "+e)}},797:(e,n)=>{n.GREATEST_LOWER_BOUND=1;n.LEAST_UPPER_BOUND=2;function recursiveSearch(e,t,r,o,s,i){const l=Math.floor((t-e)/2)+e;const a=s(r,o[l],true);if(a===0){return l}else if(a>0){if(t-l>1){return recursiveSearch(l,t,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return t<o.length?t:-1}return l}if(l-e>1){return recursiveSearch(e,l,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return l}return e<0?-1:e}n.search=function search(e,t,r,o){if(t.length===0){return-1}let s=recursiveSearch(-1,t.length,e,t,r,o||n.GREATEST_LOWER_BOUND);if(s<0){return-1}while(s-1>=0){if(r(t[s],t[s-1],true)!==0){break}--s}return s}},167:(e,n,t)=>{const r=t(521);function generatedPositionAfter(e,n){const t=e.generatedLine;const o=n.generatedLine;const s=e.generatedColumn;const i=n.generatedColumn;return o>t||o==t&&i>=s||r.compareByGeneratedPositionsInflated(e,n)<=0}class MappingList{constructor(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}unsortedForEach(e,n){this._array.forEach(e,n)}add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}}toArray(){if(!this._sorted){this._array.sort(r.compareByGeneratedPositionsInflated);this._sorted=true}return this._array}}n.H=MappingList},520:(e,n,t)=>{"use strict";const r=t(147);const o=t(17);e.exports=function readWasm(){return new Promise(((e,n)=>{const o=t.ab+"mappings.wasm";r.readFile(t.ab+"mappings.wasm",null,((t,r)=>{if(t){n(t);return}e(r.buffer)}))}))};e.exports.initialize=e=>{console.debug("SourceMapConsumer.initialize is a no-op when running in node.js")}},494:(e,n,t)=>{var r;const o=t(521);const s=t(797);const i=t(237).I;const l=t(717);const a=t(520);const u=t(734);const c=Symbol("smcInternal");class SourceMapConsumer{constructor(e,n){if(e==c){return Promise.resolve(this)}return _factory(e,n)}static initialize(e){a.initialize(e["lib/mappings.wasm"])}static fromSourceMap(e,n){return _factoryBSM(e,n)}static async with(e,n,t){const r=await new SourceMapConsumer(e,n);try{return await t(r)}finally{r.destroy()}}eachMapping(e,n,t){throw new Error("Subclasses must implement eachMapping")}allGeneratedPositionsFor(e){throw new Error("Subclasses must implement allGeneratedPositionsFor")}destroy(){throw new Error("Subclasses must implement destroy")}}SourceMapConsumer.prototype._version=3;SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;n.SourceMapConsumer=SourceMapConsumer;class BasicSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const l=o.getArg(r,"sources").map(String);const a=o.getArg(r,"names",[]);const c=o.getArg(r,"sourceRoot",null);const g=o.getArg(r,"sourcesContent",null);const f=o.getArg(r,"mappings");const h=o.getArg(r,"file",null);if(s!=t._version){throw new Error("Unsupported version: "+s)}t._sourceLookupCache=new Map;t._names=i.fromArray(a.map(String),true);t._sources=i.fromArray(l,true);t._absoluteSources=i.fromArray(t._sources.toArray().map((function(e){return o.computeSourceURL(c,e,n)})),true);t.sourceRoot=c;t.sourcesContent=g;t._mappings=f;t._sourceMapURL=n;t.file=h;t._computedColumnSpans=false;t._mappingsPtr=0;t._wasm=null;return u().then((e=>{t._wasm=e;return t}))}))}_findSourceIndex(e){const n=this._sourceLookupCache.get(e);if(typeof n==="number"){return n}const t=o.computeSourceURL(null,e,this._sourceMapURL);if(this._absoluteSources.has(t)){const n=this._absoluteSources.indexOf(t);this._sourceLookupCache.set(e,n);return n}const r=o.computeSourceURL(this.sourceRoot,e,this._sourceMapURL);if(this._absoluteSources.has(r)){const n=this._absoluteSources.indexOf(r);this._sourceLookupCache.set(e,n);return n}return-1}static fromSourceMap(e,n){return new BasicSourceMapConsumer(e.toString())}get sources(){return this._absoluteSources.toArray()}_getMappingsPtr(){if(this._mappingsPtr===0){this._parseMappings()}return this._mappingsPtr}_parseMappings(){const e=this._mappings;const n=e.length;const t=this._wasm.exports.allocate_mappings(n);const r=new Uint8Array(this._wasm.exports.memory.buffer,t,n);for(let t=0;t<n;t++){r[t]=e.charCodeAt(t)}const o=this._wasm.exports.parse_mappings(t);if(!o){const e=this._wasm.exports.get_last_error();let n=`Error parsing mappings (code ${e}): `;switch(e){case 1:n+="the mappings contained a negative line, column, source index, or name index";break;case 2:n+="the mappings contained a number larger than 2**32";break;case 3:n+="reached EOF while in the middle of parsing a VLQ";break;case 4:n+="invalid base 64 character while parsing a VLQ";break;default:n+="unknown error code";break}throw new Error(n)}this._mappingsPtr=o}eachMapping(e,n,t){const r=n||null;const o=t||SourceMapConsumer.GENERATED_ORDER;this._wasm.withMappingCallback((n=>{if(n.source!==null){n.source=this._absoluteSources.at(n.source);if(n.name!==null){n.name=this._names.at(n.name)}}if(this._computedColumnSpans&&n.lastGeneratedColumn===null){n.lastGeneratedColumn=Infinity}e.call(r,n)}),(()=>{switch(o){case SourceMapConsumer.GENERATED_ORDER:this._wasm.exports.by_generated_location(this._getMappingsPtr());break;case SourceMapConsumer.ORIGINAL_ORDER:this._wasm.exports.by_original_location(this._getMappingsPtr());break;default:throw new Error("Unknown order of iteration.")}}))}allGeneratedPositionsFor(e){let n=o.getArg(e,"source");const t=o.getArg(e,"line");const r=e.column||0;n=this._findSourceIndex(n);if(n<0){return[]}if(t<1){throw new Error("Line numbers must be >= 1")}if(r<0){throw new Error("Column numbers must be >= 0")}const s=[];this._wasm.withMappingCallback((e=>{let n=e.lastGeneratedColumn;if(this._computedColumnSpans&&n===null){n=Infinity}s.push({line:e.generatedLine,column:e.generatedColumn,lastColumn:n})}),(()=>{this._wasm.exports.all_generated_locations_for(this._getMappingsPtr(),n,t-1,"column"in e,r)}));return s}destroy(){if(this._mappingsPtr!==0){this._wasm.exports.free_mappings(this._mappingsPtr);this._mappingsPtr=0}}computeColumnSpans(){if(this._computedColumnSpans){return}this._wasm.exports.compute_column_spans(this._getMappingsPtr());this._computedColumnSpans=true}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};if(n.generatedLine<1){throw new Error("Line numbers must be >= 1")}if(n.generatedColumn<0){throw new Error("Column numbers must be >= 0")}let t=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(t==null){t=SourceMapConsumer.GREATEST_LOWER_BOUND}let r;this._wasm.withMappingCallback((e=>r=e),(()=>{this._wasm.exports.original_location_for(this._getMappingsPtr(),n.generatedLine-1,n.generatedColumn,t)}));if(r){if(r.generatedLine===n.generatedLine){let e=o.getArg(r,"source",null);if(e!==null){e=this._absoluteSources.at(e)}let n=o.getArg(r,"name",null);if(n!==null){n=this._names.at(n)}return{source:e,line:o.getArg(r,"originalLine",null),column:o.getArg(r,"originalColumn",null),name:n}}}return{source:null,line:null,column:null,name:null}}hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))}sourceContentFor(e,n){if(!this.sourcesContent){return null}const t=this._findSourceIndex(e);if(t>=0){return this.sourcesContent[t]}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}generatedPositionFor(e){let n=o.getArg(e,"source");n=this._findSourceIndex(n);if(n<0){return{line:null,column:null,lastColumn:null}}const t={source:n,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};if(t.originalLine<1){throw new Error("Line numbers must be >= 1")}if(t.originalColumn<0){throw new Error("Column numbers must be >= 0")}let r=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(r==null){r=SourceMapConsumer.GREATEST_LOWER_BOUND}let s;this._wasm.withMappingCallback((e=>s=e),(()=>{this._wasm.exports.generated_location_for(this._getMappingsPtr(),t.source,t.originalLine-1,t.originalColumn,r)}));if(s){if(s.source===t.source){let e=s.lastGeneratedColumn;if(this._computedColumnSpans&&e===null){e=Infinity}return{line:o.getArg(s,"generatedLine",null),column:o.getArg(s,"generatedColumn",null),lastColumn:e}}}return{line:null,column:null,lastColumn:null}}}BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;r=BasicSourceMapConsumer;class IndexedSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const i=o.getArg(r,"sections");if(s!=t._version){throw new Error("Unsupported version: "+s)}let l={line:-1,column:0};return Promise.all(i.map((e=>{if(e.url){throw new Error("Support for url field in sections not implemented.")}const t=o.getArg(e,"offset");const r=o.getArg(t,"line");const s=o.getArg(t,"column");if(r<l.line||r===l.line&&s<l.column){throw new Error("Section offsets must be ordered and non-overlapping.")}l=t;const i=new SourceMapConsumer(o.getArg(e,"map"),n);return i.then((e=>({generatedOffset:{generatedLine:r+1,generatedColumn:s+1},consumer:e})))}))).then((e=>{t._sections=e;return t}))}))}get sources(){const e=[];for(let n=0;n<this._sections.length;n++){for(let t=0;t<this._sections[n].consumer.sources.length;t++){e.push(this._sections[n].consumer.sources[t])}}return e}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};const t=s.search(n,this._sections,(function(e,n){const t=e.generatedLine-n.generatedOffset.generatedLine;if(t){return t}return e.generatedColumn-n.generatedOffset.generatedColumn}));const r=this._sections[t];if(!r){return{source:null,line:null,column:null,name:null}}return r.consumer.originalPositionFor({line:n.generatedLine-(r.generatedOffset.generatedLine-1),column:n.generatedColumn-(r.generatedOffset.generatedLine===n.generatedLine?r.generatedOffset.generatedColumn-1:0),bias:e.bias})}hasContentsOfAllSources(){return this._sections.every((function(e){return e.consumer.hasContentsOfAllSources()}))}sourceContentFor(e,n){for(let n=0;n<this._sections.length;n++){const t=this._sections[n];const r=t.consumer.sourceContentFor(e,true);if(r){return r}}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}_findSectionIndex(e){for(let n=0;n<this._sections.length;n++){const{consumer:t}=this._sections[n];if(t._findSourceIndex(e)!==-1){return n}}return-1}generatedPositionFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;const s=t&&t.consumer.generatedPositionFor(e);if(s&&s.line!==null){const e=t.generatedOffset.generatedLine-1;const n=t.generatedOffset.generatedColumn-1;if(s.line===1){s.column+=n;if(typeof s.lastColumn==="number"){s.lastColumn+=n}}if(s.lastColumn===Infinity&&r&&s.line===r.generatedOffset.generatedLine){s.lastColumn=r.generatedOffset.generatedColumn-2}s.line+=e;return s}return{line:null,column:null,lastColumn:null}}allGeneratedPositionsFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;if(!t)return[];return t.consumer.allGeneratedPositionsFor(e).map((e=>{const n=t.generatedOffset.generatedLine-1;const o=t.generatedOffset.generatedColumn-1;if(e.line===1){e.column+=o;if(typeof e.lastColumn==="number"){e.lastColumn+=o}}if(e.lastColumn===Infinity&&r&&e.line===r.generatedOffset.generatedLine){e.lastColumn=r.generatedOffset.generatedColumn-2}e.line+=n;return e}))}eachMapping(e,n,t){this._sections.forEach(((r,o)=>{const s=o+1<this._sections.length?this._sections[o+1]:null;const{generatedOffset:i}=r;const l=i.generatedLine-1;const a=i.generatedColumn-1;r.consumer.eachMapping((function(n){if(n.generatedLine===1){n.generatedColumn+=a;if(typeof n.lastGeneratedColumn==="number"){n.lastGeneratedColumn+=a}}if(n.lastGeneratedColumn===Infinity&&s&&n.generatedLine===s.generatedOffset.generatedLine){n.lastGeneratedColumn=s.generatedOffset.generatedColumn-2}n.generatedLine+=l;e.call(this,n)}),n,t)}))}computeColumnSpans(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.computeColumnSpans()}}destroy(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.destroy()}}}r=IndexedSourceMapConsumer;function _factory(e,n){let t=e;if(typeof e==="string"){t=o.parseSourceMapInput(e)}const r=t.sections!=null?new IndexedSourceMapConsumer(t,n):new BasicSourceMapConsumer(t,n);return Promise.resolve(r)}function _factoryBSM(e,n){return BasicSourceMapConsumer.fromSourceMap(e,n)}},491:(e,n,t)=>{const r=t(717);const o=t(521);const s=t(237).I;const i=t(167).H;class SourceMapGenerator{constructor(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new s;this._names=new s;this._mappings=new i;this._sourcesContents=null}static fromSourceMap(e){const n=e.sourceRoot;const t=new SourceMapGenerator({file:e.file,sourceRoot:n});e.eachMapping((function(e){const r={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){r.source=e.source;if(n!=null){r.source=o.relative(n,r.source)}r.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){r.name=e.name}}t.addMapping(r)}));e.sources.forEach((function(r){let s=r;if(n!==null){s=o.relative(n,r)}if(!t._sources.has(s)){t._sources.add(s)}const i=e.sourceContentFor(r);if(i!=null){t.setSourceContent(r,i)}}));return t}addMapping(e){const n=o.getArg(e,"generated");const t=o.getArg(e,"original",null);let r=o.getArg(e,"source",null);let s=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(n,t,r,s)}if(r!=null){r=String(r);if(!this._sources.has(r)){this._sources.add(r)}}if(s!=null){s=String(s);if(!this._names.has(s)){this._names.add(s)}}this._mappings.add({generatedLine:n.line,generatedColumn:n.column,originalLine:t!=null&&t.line,originalColumn:t!=null&&t.column,source:r,name:s})}setSourceContent(e,n){let t=e;if(this._sourceRoot!=null){t=o.relative(this._sourceRoot,t)}if(n!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(t)]=n}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(t)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}}applySourceMap(e,n,t){let r=n;if(n==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}r=e.file}const i=this._sourceRoot;if(i!=null){r=o.relative(i,r)}const l=this._mappings.toArray().length>0?new s:this._sources;const a=new s;this._mappings.unsortedForEach((function(n){if(n.source===r&&n.originalLine!=null){const r=e.originalPositionFor({line:n.originalLine,column:n.originalColumn});if(r.source!=null){n.source=r.source;if(t!=null){n.source=o.join(t,n.source)}if(i!=null){n.source=o.relative(i,n.source)}n.originalLine=r.line;n.originalColumn=r.column;if(r.name!=null){n.name=r.name}}}const s=n.source;if(s!=null&&!l.has(s)){l.add(s)}const u=n.name;if(u!=null&&!a.has(u)){a.add(u)}}),this);this._sources=l;this._names=a;e.sources.forEach((function(n){const r=e.sourceContentFor(n);if(r!=null){if(t!=null){n=o.join(t,n)}if(i!=null){n=o.relative(i,n)}this.setSourceContent(n,r)}}),this)}_validateMapping(e,n,t,r){if(n&&typeof n.line!=="number"&&typeof n.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!n&&!t&&!r){}else if(e&&"line"in e&&"column"in e&&n&&"line"in n&&"column"in n&&e.line>0&&e.column>=0&&n.line>0&&n.column>=0&&t){}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:t,original:n,name:r}))}}_serializeMappings(){let e=0;let n=1;let t=0;let s=0;let i=0;let l=0;let a="";let u;let c;let g;let f;const h=this._mappings.toArray();for(let p=0,m=h.length;p<m;p++){c=h[p];u="";if(c.generatedLine!==n){e=0;while(c.generatedLine!==n){u+=";";n++}}else if(p>0){if(!o.compareByGeneratedPositionsInflated(c,h[p-1])){continue}u+=","}u+=r.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);u+=r.encode(f-l);l=f;u+=r.encode(c.originalLine-1-s);s=c.originalLine-1;u+=r.encode(c.originalColumn-t);t=c.originalColumn;if(c.name!=null){g=this._names.indexOf(c.name);u+=r.encode(g-i);i=g}}a+=u}return a}_generateSourcesContent(e,n){return e.map((function(e){if(!this._sourcesContents){return null}if(n!=null){e=o.relative(n,e)}const t=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,t)?this._sourcesContents[t]:null}),this)}toJSON(){const e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e}toString(){return JSON.stringify(this.toJSON())}}SourceMapGenerator.prototype._version=3;n.SourceMapGenerator=SourceMapGenerator},664:(e,n,t)=>{const r=t(491).SourceMapGenerator;const o=t(521);const s=/(\r?\n)/;const i=10;const l="$$$isSourceNode$$$";class SourceNode{constructor(e,n,t,r,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=n==null?null:n;this.source=t==null?null:t;this.name=o==null?null:o;this[l]=true;if(r!=null)this.add(r)}static fromStringWithSourceMap(e,n,t){const r=new SourceNode;const i=e.split(s);let l=0;const shiftNextLine=function(){const e=getNextLine();const n=getNextLine()||"";return e+n;function getNextLine(){return l<i.length?i[l++]:undefined}};let a=1,u=0;let c=null;let g;n.eachMapping((function(e){if(c!==null){if(a<e.generatedLine){addMappingWithCode(c,shiftNextLine());a++;u=0}else{g=i[l]||"";const n=g.substr(0,e.generatedColumn-u);i[l]=g.substr(e.generatedColumn-u);u=e.generatedColumn;addMappingWithCode(c,n);c=e;return}}while(a<e.generatedLine){r.add(shiftNextLine());a++}if(u<e.generatedColumn){g=i[l]||"";r.add(g.substr(0,e.generatedColumn));i[l]=g.substr(e.generatedColumn);u=e.generatedColumn}c=e}),this);if(l<i.length){if(c){addMappingWithCode(c,shiftNextLine())}r.add(i.splice(l).join(""))}n.sources.forEach((function(e){const s=n.sourceContentFor(e);if(s!=null){if(t!=null){e=o.join(t,e)}r.setSourceContent(e,s)}}));return r;function addMappingWithCode(e,n){if(e===null||e.source===undefined){r.add(n)}else{const s=t?o.join(t,e.source):e.source;r.add(new SourceNode(e.originalLine,e.originalColumn,s,n,e.name))}}}add(e){if(Array.isArray(e)){e.forEach((function(e){this.add(e)}),this)}else if(e[l]||typeof e==="string"){if(e){this.children.push(e)}}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}prepend(e){if(Array.isArray(e)){for(let n=e.length-1;n>=0;n--){this.prepend(e[n])}}else if(e[l]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}walk(e){let n;for(let t=0,r=this.children.length;t<r;t++){n=this.children[t];if(n[l]){n.walk(e)}else if(n!==""){e(n,{source:this.source,line:this.line,column:this.column,name:this.name})}}}join(e){let n;let t;const r=this.children.length;if(r>0){n=[];for(t=0;t<r-1;t++){n.push(this.children[t]);n.push(e)}n.push(this.children[t]);this.children=n}return this}replaceRight(e,n){const t=this.children[this.children.length-1];if(t[l]){t.replaceRight(e,n)}else if(typeof t==="string"){this.children[this.children.length-1]=t.replace(e,n)}else{this.children.push("".replace(e,n))}return this}setSourceContent(e,n){this.sourceContents[o.toSetString(e)]=n}walkSourceContents(e){for(let n=0,t=this.children.length;n<t;n++){if(this.children[n][l]){this.children[n].walkSourceContents(e)}}const n=Object.keys(this.sourceContents);for(let t=0,r=n.length;t<r;t++){e(o.fromSetString(n[t]),this.sourceContents[n[t]])}}toString(){let e="";this.walk((function(n){e+=n}));return e}toStringWithSourceMap(e){const n={code:"",line:1,column:0};const t=new r(e);let o=false;let s=null;let l=null;let a=null;let u=null;this.walk((function(e,r){n.code+=e;if(r.source!==null&&r.line!==null&&r.column!==null){if(s!==r.source||l!==r.line||a!==r.column||u!==r.name){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}s=r.source;l=r.line;a=r.column;u=r.name;o=true}else if(o){t.addMapping({generated:{line:n.line,column:n.column}});s=null;o=false}for(let l=0,a=e.length;l<a;l++){if(e.charCodeAt(l)===i){n.line++;n.column=0;if(l+1===a){s=null;o=false}else if(o){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}}else{n.column++}}}));this.walkSourceContents((function(e,n){t.setSourceContent(e,n)}));return{code:n.code,map:t}}}n.SourceNode=SourceNode},834:(e,n,t)=>{"use strict";e.exports=typeof URL==="function"?URL:t(310).URL},521:(e,n,t)=>{const r=t(834);function getArg(e,n,t){if(n in e){return e[n]}else if(arguments.length===3){return t}throw new Error('"'+n+'" is a required argument.')}n.getArg=getArg;const o=function(){const e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}n.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}n.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}const n=e.length;if(n<9){return false}if(e.charCodeAt(n-1)!==95||e.charCodeAt(n-2)!==95||e.charCodeAt(n-3)!==111||e.charCodeAt(n-4)!==116||e.charCodeAt(n-5)!==111||e.charCodeAt(n-6)!==114||e.charCodeAt(n-7)!==112||e.charCodeAt(n-8)!==95||e.charCodeAt(n-9)!==95){return false}for(let t=n-10;t>=0;t--){if(e.charCodeAt(t)!==36){return false}}return true}function strcmp(e,n){if(e===n){return 0}if(e===null){return 1}if(n===null){return-1}if(e>n){return 1}return-1}function compareByGeneratedPositionsInflated(e,n){let t=e.generatedLine-n.generatedLine;if(t!==0){return t}t=e.generatedColumn-n.generatedColumn;if(t!==0){return t}t=strcmp(e.source,n.source);if(t!==0){return t}t=e.originalLine-n.originalLine;if(t!==0){return t}t=e.originalColumn-n.originalColumn;if(t!==0){return t}return strcmp(e.name,n.name)}n.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}n.parseSourceMapInput=parseSourceMapInput;const s="http:";const i=`${s}//host`;function createSafeHandler(e){return n=>{const t=getURLType(n);const o=buildSafeBase(n);const l=new r(n,o);e(l);const a=l.toString();if(t==="absolute"){return a}else if(t==="scheme-relative"){return a.slice(s.length)}else if(t==="path-absolute"){return a.slice(i.length)}return computeRelativeURL(o,a)}}function withBase(e,n){return new r(e,n).toString()}function buildUniqueSegment(e,n){let t=0;do{const r=e+t++;if(n.indexOf(r)===-1)return r}while(true)}function buildSafeBase(e){const n=e.split("..").length-1;const t=buildUniqueSegment("p",e);let r=`${i}/`;for(let e=0;e<n;e++){r+=`${t}/`}return r}const l=/^[A-Za-z0-9\+\-\.]+:/;function getURLType(e){if(e[0]==="/"){if(e[1]==="/")return"scheme-relative";return"path-absolute"}return l.test(e)?"absolute":"path-relative"}function computeRelativeURL(e,n){if(typeof e==="string")e=new r(e);if(typeof n==="string")n=new r(n);const t=n.pathname.split("/");const o=e.pathname.split("/");if(o.length>0&&!o[o.length-1]){o.pop()}while(t.length>0&&o.length>0&&t[0]===o[0]){t.shift();o.shift()}const s=o.map((()=>"..")).concat(t).join("/");return s+n.search+n.hash}const a=createSafeHandler((e=>{e.pathname=e.pathname.replace(/\/?$/,"/")}));const u=createSafeHandler((e=>{e.href=new r(".",e.toString()).toString()}));const c=createSafeHandler((e=>{}));n.normalize=c;function join(e,n){const t=getURLType(n);const r=getURLType(e);e=a(e);if(t==="absolute"){return withBase(n,undefined)}if(r==="absolute"){return withBase(n,e)}if(t==="scheme-relative"){return c(n)}if(r==="scheme-relative"){return withBase(n,withBase(e,i)).slice(s.length)}if(t==="path-absolute"){return c(n)}if(r==="path-absolute"){return withBase(n,withBase(e,i)).slice(i.length)}const o=buildSafeBase(n+e);const l=withBase(n,withBase(e,o));return computeRelativeURL(o,l)}n.join=join;function relative(e,n){const t=relativeIfPossible(e,n);return typeof t==="string"?t:c(n)}n.relative=relative;function relativeIfPossible(e,n){const t=getURLType(e);if(t!==getURLType(n)){return null}const o=buildSafeBase(e+n);const s=new r(e,o);const i=new r(n,o);try{new r("",i.toString())}catch(e){return null}if(i.protocol!==s.protocol||i.user!==s.user||i.password!==s.password||i.hostname!==s.hostname||i.port!==s.port){return null}return computeRelativeURL(s,i)}function computeSourceURL(e,n,t){if(e&&getURLType(n)==="path-absolute"){n=n.replace(/^\//,"")}let r=c(n||"");if(e)r=join(e,r);if(t)r=join(u(t),r);return r}n.computeSourceURL=computeSourceURL},734:(e,n,t)=>{const r=t(520);function Mapping(){this.generatedLine=0;this.generatedColumn=0;this.lastGeneratedColumn=null;this.source=null;this.originalLine=null;this.originalColumn=null;this.name=null}let o=null;e.exports=function wasm(){if(o){return o}const e=[];o=r().then((n=>WebAssembly.instantiate(n,{env:{mapping_callback(n,t,r,o,s,i,l,a,u,c){const g=new Mapping;g.generatedLine=n+1;g.generatedColumn=t;if(r){g.lastGeneratedColumn=o-1}if(s){g.source=i;g.originalLine=l+1;g.originalColumn=a;if(u){g.name=c}}e[e.length-1](g)},start_all_generated_locations_for(){console.time("all_generated_locations_for")},end_all_generated_locations_for(){console.timeEnd("all_generated_locations_for")},start_compute_column_spans(){console.time("compute_column_spans")},end_compute_column_spans(){console.timeEnd("compute_column_spans")},start_generated_location_for(){console.time("generated_location_for")},end_generated_location_for(){console.timeEnd("generated_location_for")},start_original_location_for(){console.time("original_location_for")},end_original_location_for(){console.timeEnd("original_location_for")},start_parse_mappings(){console.time("parse_mappings")},end_parse_mappings(){console.timeEnd("parse_mappings")},start_sort_by_generated_location(){console.time("sort_by_generated_location")},end_sort_by_generated_location(){console.timeEnd("sort_by_generated_location")},start_sort_by_original_location(){console.time("sort_by_original_location")},end_sort_by_original_location(){console.timeEnd("sort_by_original_location")}}}))).then((n=>({exports:n.instance.exports,withMappingCallback:(n,t)=>{e.push(n);try{t()}finally{e.pop()}}}))).then(null,(e=>{o=null;throw e}));return o}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")},310:e=>{"use strict";e.exports=require("url")}};var n={};function __nccwpck_require__(t){var r=n[t];if(r!==undefined){return r.exports}var o=n[t]={exports:{}};var s=true;try{e[t](o,o.exports,__nccwpck_require__);s=false}finally{if(s)delete n[t]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t={};(()=>{var e=t;e.SourceMapGenerator=__nccwpck_require__(491).SourceMapGenerator;e.SourceMapConsumer=__nccwpck_require__(494).SourceMapConsumer;e.SourceNode=__nccwpck_require__(664).SourceNode})();module.exports=t})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/LICENSE b/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/LICENSE index e7af2f77107d73..fa7ceba3eb4a96 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/LICENSE +++ b/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) +Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/index.js b/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/index.js index eca338874898ef..252ac06be26fb8 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/index.js @@ -1 +1 @@ -(()=>{"use strict";var e={625:e=>{e.exports=({onlyFirst:e=false}={})=>{const r=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(r,e?undefined:"g")}},519:(e,r,_)=>{const t=_(625);e.exports=e=>typeof e==="string"?e.replace(t(),""):e}};var r={};function __nccwpck_require__(_){var t=r[_];if(t!==undefined){return t.exports}var a=r[_]={exports:{}};var n=true;try{e[_](a,a.exports,__nccwpck_require__);n=false}finally{if(n)delete r[_]}return a.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var _=__nccwpck_require__(519);module.exports=_})(); \ No newline at end of file +var e={};(()=>{e.d=(t,r)=>{for(var n in r){if(e.o(r,n)&&!e.o(t,n)){Object.defineProperty(t,n,{enumerable:true,get:r[n]})}}}})();(()=>{e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)})();if(typeof e!=="undefined")e.ab=new URL(".",import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/)?1:0,-1)+"/";var t={};e.d(t,{Z:()=>stripAnsi});function ansiRegex({onlyFirst:e=false}={}){const t=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(t,e?undefined:"g")}function stripAnsi(e){if(typeof e!=="string"){throw new TypeError(`Expected a \`string\`, got \`${typeof e}\``)}return e.replace(ansiRegex(),"")}var r=t.Z;export{r as default}; \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/package.json b/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/package.json index c005a27e40f7a1..fbd6457be77790 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/package.json +++ b/packages/next-swc/crates/next-core/js/src/compiled/strip-ansi/package.json @@ -1 +1 @@ -{"name":"strip-ansi","main":"index.js","author":{"name":"Sindre Sorhus","email":"sindresorhus@gmail.com","url":"sindresorhus.com"},"license":"MIT"} +{"name":"strip-ansi","main":"index.js","author":{"name":"Sindre Sorhus","email":"sindresorhus@gmail.com","url":"https://sindresorhus.com"},"license":"MIT"} diff --git a/packages/next-swc/crates/next-core/js/types/compiled.d.ts b/packages/next-swc/crates/next-core/js/types/compiled.d.ts index 78c71c368d18b5..085f4f3f48a312 100644 --- a/packages/next-swc/crates/next-core/js/types/compiled.d.ts +++ b/packages/next-swc/crates/next-core/js/types/compiled.d.ts @@ -24,5 +24,5 @@ declare module "@vercel/turbopack-next/compiled/stacktrace-parser" { declare module "@vercel/turbopack-next/compiled/strip-ansi" { import m from "strip-ansi"; - export = m; + export default m; } From 5904885ba27705cc1663a0d62be1010c39074917 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Mon, 12 Dec 2022 15:39:06 -0800 Subject: [PATCH 265/672] Run setup-node in update-google-fonts workflow (vercel/turbo#2980) * Run setup-node in update-google-fonts workflow * Update Google font-data.json (ce83bb98897404b791fd96f562a95fc0b20b40da) Co-authored-by: wbinnssmith <wbinnssmith@users.noreply.github.com> --- .../__generated__/font-data.json | 179 +++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json b/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json index eede6bc16e5155..c974822c6107cd 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json +++ b/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json @@ -3251,6 +3251,32 @@ } ] }, + "Chivo Mono": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, "Chonburi": { "weights": [ "400" @@ -5072,11 +5098,22 @@ "300", "400", "500", + "600", "700", - "900" + "800", + "900", + "variable" ], "styles": [ "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 300, + "max": 900, + "defaultValue": 400 + } ] }, "Fraunces": { @@ -5982,6 +6019,32 @@ "normal" ] }, + "Hanken Grotesk": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, "Hanuman": { "weights": [ "100", @@ -8772,6 +8835,36 @@ "normal" ] }, + "Martian Mono": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wdth", + "min": 75, + "max": 112.5, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 800, + "defaultValue": 400 + } + ] + }, "Marvel": { "weights": [ "400", @@ -12461,6 +12554,26 @@ "normal" ] }, + "Noto Serif NP Hmong": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, "Noto Serif Nyiakeng Puachue Hmong": { "weights": [ "400", @@ -14830,6 +14943,14 @@ } ] }, + "Rubik 80s Fade": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, "Rubik Beastly": { "weights": [ "400" @@ -14870,6 +14991,14 @@ "normal" ] }, + "Rubik Gemstones": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, "Rubik Glitch": { "weights": [ "400" @@ -14934,6 +15063,30 @@ "normal" ] }, + "Rubik Spray Paint": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Storm": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, + "Rubik Vinyl": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, "Rubik Wet Paint": { "weights": [ "400" @@ -16966,6 +17119,30 @@ "normal" ] }, + "Unbounded": { + "weights": [ + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 200, + "max": 900, + "defaultValue": 400 + } + ] + }, "Uncial Antiqua": { "weights": [ "400" From e3d210fbcbdcf3339957ea62450feecc6160976c Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Mon, 12 Dec 2022 16:22:52 -0800 Subject: [PATCH 266/672] Add font weight, style to css and js properties (vercel/turbo#2963) --- .../next-core/src/next_font_google/mod.rs | 124 +++++++++++++----- .../next-core/src/next_font_google/options.rs | 11 +- .../next-core/src/next_font_google/util.rs | 3 +- 3 files changed, 103 insertions(+), 35 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs index 2ce773d0a613d2..b17301e0248b19 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs @@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result}; use indexmap::IndexMap; use indoc::formatdoc; use once_cell::sync::Lazy; -use turbo_tasks::primitives::{OptionStringVc, StringVc}; +use turbo_tasks::primitives::{OptionStringVc, OptionU16Vc, StringVc}; use turbo_tasks_fetch::fetch; use turbo_tasks_fs::{FileContent, FileSystemPathVc}; use turbopack_core::{ @@ -12,16 +12,17 @@ use turbopack_core::{ ImportMappingReplacementVc, ImportMappingVc, }, parse::{Request, RequestVc}, + pattern::QueryMapVc, ResolveResult, }, virtual_asset::VirtualAssetVc, }; +use self::options::FontWeights; use crate::{ embed_js::attached_next_js_package_path, next_font_google::{ options::FontDataEntry, - request::NextFontRequest, util::{get_font_axes, get_stylesheet_url}, }, }; @@ -62,12 +63,14 @@ impl ImportMappingReplacement for NextFontGoogleReplacer { let Request::Module { module: _, path: _, - query, + query: query_vc } = request else { return Ok(ImportMapResult::NoEntry.into()); }; - let query = &*query.await?; + let query = &*query_vc.await?; + let options = font_options_from_query_map(*query_vc); + let properties = get_font_css_properties(options).await?; let js_asset = VirtualAssetVc::new( attached_next_js_package_path(self.project_path) .join("internal/font/google/inter.js"), @@ -76,11 +79,27 @@ impl ImportMappingReplacement for NextFontGoogleReplacer { r#" import cssModule from "@vercel/turbopack-next/internal/font/google/cssmodule.module.css?{}"; export default {{ - className: cssModule.className + className: cssModule.className, + style: {{ + fontFamily: "{}", + {}{} + }} }}; "#, // Pass along whichever options we received to the css handler - qstring::QString::new(query.as_ref().unwrap().iter().collect()) + qstring::QString::new(query.as_ref().unwrap().iter().collect()), + properties.font_family.await?, + properties + .weight + .await? + .map(|w| format!("fontWeight: {},\n", w)) + .unwrap_or_else(|| "".to_owned()), + properties + .style + .await? + .as_ref() + .map(|s| format!("fontStyle: \"{}\",\n", s)) + .unwrap_or_else(|| "".to_owned()), ) .into(), ) @@ -122,23 +141,8 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { return Ok(ImportMapResult::NoEntry.into()); }; - let query_map = &*query.await?; - // These are invariants from the next/font swc transform. Regular errors instead - // of Issues should be okay. - let query_map = query_map - .as_ref() - .context("@next/font/google queries must exist")?; - - if query_map.len() != 1 { - bail!("@next/font/google queries must only have one entry"); - } - - let Some((json, _)) = query_map.iter().next() else { - bail!("Expected one entry"); - }; - - let request: StringVc = StringVc::cell(json.to_owned()); - let stylesheet_url = get_stylesheet_url_from_request(request); + let options = font_options_from_query_map(*query); + let stylesheet_url = get_stylesheet_url_from_options(options); // TODO(WEB-274): Handle this failing (e.g. connection issues). This should be // an Issue. @@ -158,7 +162,7 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { } let stylesheet = &*stylesheet_res.body.to_string().await?; - let options = options_from_request(request).await?; + let properties = get_font_css_properties(options).await?; let css_asset = VirtualAssetVc::new( attached_next_js_package_path(self.project_path) @@ -169,11 +173,23 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { {} .className {{ - font-family: "{}"; + font-family: {}; + {}{} }} "#, stylesheet, - options.font_family + properties.font_family.await?, + properties + .weight + .await? + .map(|w| format!("font-weight: {};\n", w)) + .unwrap_or_else(|| "".to_owned()), + properties + .style + .await? + .as_ref() + .map(|s| format!("font-style: {};\n", s)) + .unwrap_or_else(|| "".to_owned()), ) .into(), ) @@ -185,8 +201,8 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { } #[turbo_tasks::function] -async fn get_stylesheet_url_from_request(request_json: StringVc) -> Result<StringVc> { - let options = options_from_request(request_json).await?; +async fn get_stylesheet_url_from_options(options: NextFontGoogleOptionsVc) -> Result<StringVc> { + let options = options.await?; Ok(StringVc::cell(get_stylesheet_url( GOOGLE_FONTS_STYLESHEET_URL, @@ -205,9 +221,55 @@ async fn get_stylesheet_url_from_request(request_json: StringVc) -> Result<Strin #[turbo_tasks::value(transparent)] struct NextFontGoogleOptions(self::options::NextFontGoogleOptions); +#[turbo_tasks::value(transparent)] +struct FontCssProperties { + font_family: StringVc, + weight: OptionU16Vc, + style: OptionStringVc, +} + #[turbo_tasks::function] -async fn options_from_request(request: StringVc) -> Result<NextFontGoogleOptionsVc> { - let request: NextFontRequest = serde_json::from_str(&request.await?)?; +async fn get_font_css_properties(options: NextFontGoogleOptionsVc) -> Result<FontCssPropertiesVc> { + let options = &*options.await?; + + let mut font_families = vec![options.font_family.clone()]; + if let Some(fallback) = &options.fallback { + font_families.extend_from_slice(fallback); + } + + Ok(FontCssPropertiesVc::cell(FontCssProperties { + font_family: StringVc::cell( + font_families + .iter() + .map(|f| format!("'{}'", f)) + .collect::<Vec<String>>() + .join(", "), + ), + weight: OptionU16Vc::cell(match &options.weights { + FontWeights::Variable => None, + FontWeights::Fixed(weights) => weights.first().cloned(), + }), + style: OptionStringVc::cell(options.styles.first().cloned()), + })) +} + +#[turbo_tasks::function] +async fn font_options_from_query_map(query: QueryMapVc) -> Result<NextFontGoogleOptionsVc> { + let query_map = &*query.await?; + // These are invariants from the next/font swc transform. Regular errors instead + // of Issues should be okay. + let query_map = query_map + .as_ref() + .context("@next/font/google queries must exist")?; + + if query_map.len() != 1 { + bail!("@next/font/google queries must only have one entry"); + } + + let Some((json, _)) = query_map.iter().next() else { + bail!("Expected one entry"); + }; - self::options::options_from_request(&request, &FONT_DATA).map(NextFontGoogleOptionsVc::cell) + self::options::options_from_request(&serde_json::from_str(json)?, &FONT_DATA) + .map(NextFontGoogleOptionsVc::cell) } diff --git a/packages/next-swc/crates/next-core/src/next_font_google/options.rs b/packages/next-swc/crates/next-core/src/next_font_google/options.rs index c0f443cb7a75bc..885ec331d9c30a 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/options.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/options.rs @@ -26,7 +26,7 @@ pub struct NextFontGoogleOptions { #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] pub enum FontWeights { Variable, - Fixed(IndexSet<String>), + Fixed(IndexSet<u16>), } #[derive(Debug, Deserialize)] @@ -64,7 +64,7 @@ pub fn options_from_request( let font_family = request.import.replace('_', " "); let font_data = data.get(&font_family).context("Unknown font")?; - let requested_weights = argument + let requested_weights: IndexSet<String> = argument .and_then(|argument| { argument.weight.as_ref().map(|w| match w { OneOrManyStrings::One(one) => indexset! {one.to_owned()}, @@ -114,7 +114,12 @@ pub fn options_from_request( } } - FontWeights::Fixed(requested_weights) + let mut weights = indexset! {}; + for weight in requested_weights { + weights.insert(weight.parse()?); + } + + FontWeights::Fixed(weights) }; if styles.is_empty() { diff --git a/packages/next-swc/crates/next-core/src/next_font_google/util.rs b/packages/next-swc/crates/next-core/src/next_font_google/util.rs index 842a84d85c49eb..eec5227f052525 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/util.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/util.rs @@ -94,8 +94,9 @@ pub(crate) fn get_font_axes( variable_axes: Some(variable_axes), }) } + FontWeights::Fixed(weights) => Ok(FontAxes { - wght: weights.clone(), + wght: IndexSet::from_iter(weights.iter().map(|w| w.to_string())), ital, variable_axes: None, }), From d4865631040e12d1a25eed17160b14b827490ae1 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Mon, 12 Dec 2022 17:13:40 -0800 Subject: [PATCH 267/672] turbo-tasks-fetch: Emit issues on failed fetches (vercel/turbo#2964) * Initial implementation of FetchIssue * turbo-tasks-fetch: Emit issues for failed fetches * Use FetchResult and handle failure in `@next/font/google` * Apply suggestions from code review Co-authored-by: Leah <github.leah@hrmny.sh> Co-authored-by: Leah <github.leah@hrmny.sh> --- .../next-core/src/next_font_google/mod.rs | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs index b17301e0248b19..66647ef2b433d6 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs @@ -6,6 +6,7 @@ use turbo_tasks::primitives::{OptionStringVc, OptionU16Vc, StringVc}; use turbo_tasks_fetch::fetch; use turbo_tasks_fs::{FileContent, FileSystemPathVc}; use turbopack_core::{ + issue::IssueSeverity, resolve::{ options::{ ImportMapResult, ImportMapResultVc, ImportMapping, ImportMappingReplacement, @@ -143,9 +144,9 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { let options = font_options_from_query_map(*query); let stylesheet_url = get_stylesheet_url_from_options(options); + let css_virtual_path = attached_next_js_package_path(self.project_path) + .join("internal/font/google/cssmodule.module.css"); - // TODO(WEB-274): Handle this failing (e.g. connection issues). This should be - // an Issue. let stylesheet_res = fetch( stylesheet_url, OptionStringVc::cell(Some( @@ -156,17 +157,28 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { ) .await?; - // TODO(WEB-274): Emit an issue instead - if stylesheet_res.status >= 400 { - bail!("Expected a successful response for Google fonts stylesheet"); - } + let stylesheet = match &*stylesheet_res { + Ok(r) => Some(r.await?.body.to_string().await?.clone()), + Err(err) => { + // Inform the user of the failure to retreive the stylesheet, but don't + // propagate this error. We don't want e.g. offline connections to prevent page + // renders during development. During production builds, however, this error + // should propagate. + // + // TODO(WEB-283): Use fallback in dev in this case + // TODO(WEB-293): Fail production builds (not dev) in this case + err.to_issue(IssueSeverity::Warning.into(), css_virtual_path) + .as_issue() + .emit(); + + None + } + }; - let stylesheet = &*stylesheet_res.body.to_string().await?; let properties = get_font_css_properties(options).await?; let css_asset = VirtualAssetVc::new( - attached_next_js_package_path(self.project_path) - .join("internal/font/google/cssmodule.module.css"), + css_virtual_path, FileContent::Content( formatdoc!( r#" @@ -177,7 +189,7 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { {}{} }} "#, - stylesheet, + stylesheet.unwrap_or_else(|| "".to_owned()), properties.font_family.await?, properties .weight From 3db16aac57f4c5ddd78fea3855185e6664cc5cf9 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Mon, 12 Dec 2022 17:40:30 -0800 Subject: [PATCH 268/672] Unmark @next/font/google as unsupported and move feature to gate @next/font/local only (vercel/turbo#2965) --- packages/next-swc/crates/next-core/Cargo.toml | 2 +- .../next-core/src/next_client/context.rs | 44 +++++++++---------- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 7c13650a1d5d6b..72470b7afff8e9 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -34,4 +34,4 @@ turbopack-node = { path = "../turbopack-node" } turbo-tasks-build = { path = "../turbo-tasks-build" } [features] -next-font = [] +next-font-local = [] diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 97b98753c4f618..f5b99e88b7f511 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -2,7 +2,7 @@ use core::{default::Default, result::Result::Ok}; use std::collections::HashMap; use anyhow::Result; -use turbo_tasks::Value; +use turbo_tasks::{primitives::StringsVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ @@ -138,29 +138,27 @@ pub async fn add_next_transforms_to_pages( pub async fn add_next_font_transform( module_options_context: ModuleOptionsContextVc, ) -> Result<ModuleOptionsContextVc> { - #[cfg(not(feature = "next-font"))] - return Ok(module_options_context); + #[allow(unused_mut)] // This is mutated when next-font-local is enabled + let mut font_loaders = vec!["@next/font/google".to_owned()]; + #[cfg(feature = "next-font-local")] + font_loaders.push("@next/font/local".to_owned()); - #[cfg(feature = "next-font")] - { - use turbopack::module_options::{ModuleRule, ModuleRuleCondition, ModuleRuleEffect}; - use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc}; - - let mut module_options_context = module_options_context.await?.clone_value(); - module_options_context.custom_rules.push(ModuleRule::new( - // TODO: Only match in pages (not pages/api), app/, etc. - ModuleRuleCondition::any(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), - ]), - vec![ModuleRuleEffect::AddEcmascriptTransforms( - EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJsFont]), - )], - )); - Ok(module_options_context.cell()) - } + let mut module_options_context = module_options_context.await?.clone_value(); + module_options_context.custom_rules.push(ModuleRule::new( + // TODO: Only match in pages (not pages/api), app/, etc. + ModuleRuleCondition::any(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), + ]), + vec![ModuleRuleEffect::AddEcmascriptTransforms( + EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJsFont( + StringsVc::cell(font_loaders), + )]), + )], + )); + Ok(module_options_context.cell()) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 1eeada29c33591..e27e8c6a83b4bf 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -29,7 +29,7 @@ tokio_console = [ ] profile = [] custom_allocator = ["turbo-malloc/custom_allocator"] -next-font = ["next-core/next-font"] +next-font-local = ["next-core/next-font-local"] [dependencies] anyhow = "1.0.47" From bcb256acf0c8aa7a042e43edebd4fb05482c0baf Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Mon, 12 Dec 2022 19:42:05 -0800 Subject: [PATCH 269/672] @next/font/google: Hash filenames used in virtual file paths (vercel/turbo#2978) * Implement `DeterministicHash` for `&str` * @next/font/google: Hash filenames used in virtual file paths * Apply suggestions from code review Co-authored-by: Leah <github.leah@hrmny.sh> Co-authored-by: Leah <github.leah@hrmny.sh> --- .../next-core/src/next_font_google/mod.rs | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs index 66647ef2b433d6..d3a14bc13968c7 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs @@ -5,6 +5,7 @@ use once_cell::sync::Lazy; use turbo_tasks::primitives::{OptionStringVc, OptionU16Vc, StringVc}; use turbo_tasks_fetch::fetch; use turbo_tasks_fs::{FileContent, FileSystemPathVc}; +use turbo_tasks_hash::hash_xxh3_hash64; use turbopack_core::{ issue::IssueSeverity, resolve::{ @@ -72,9 +73,10 @@ impl ImportMappingReplacement for NextFontGoogleReplacer { let query = &*query_vc.await?; let options = font_options_from_query_map(*query_vc); let properties = get_font_css_properties(options).await?; + let request_id = get_request_id(*query_vc).await?.await?; let js_asset = VirtualAssetVc::new( attached_next_js_package_path(self.project_path) - .join("internal/font/google/inter.js"), + .join(&format!("internal/font/google/{}.js", request_id)), FileContent::Content( formatdoc!( r#" @@ -137,15 +139,17 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { let Request::Module { module: _, path: _, - query, + query: query_vc, } = request else { return Ok(ImportMapResult::NoEntry.into()); }; + request.request(); - let options = font_options_from_query_map(*query); + let options = font_options_from_query_map(*query_vc); let stylesheet_url = get_stylesheet_url_from_options(options); + let request_id = get_request_id(*query_vc).await?.await?; let css_virtual_path = attached_next_js_package_path(self.project_path) - .join("internal/font/google/cssmodule.module.css"); + .join(&format!("internal/font/google/{}.module.css", request_id)); let stylesheet_res = fetch( stylesheet_url, @@ -212,6 +216,23 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { } } +async fn get_request_id(query_vc: QueryMapVc) -> Result<StringVc> { + let query = &*query_vc.await?; + let query = query.as_ref().context("Query map must be present")?; + let mut to_hash = vec![]; + for (k, v) in query { + to_hash.push(k); + to_hash.push(v); + } + + let options = font_options_from_query_map(query_vc).await?; + Ok(StringVc::cell(format!( + "{}_{:x?}", + options.font_family.to_lowercase().replace(' ', "_"), + hash_xxh3_hash64(to_hash) + ))) +} + #[turbo_tasks::function] async fn get_stylesheet_url_from_options(options: NextFontGoogleOptionsVc) -> Result<StringVc> { let options = options.await?; From 8f3b7ec7bc4edd25c306acce9f18ea25feb4998c Mon Sep 17 00:00:00 2001 From: Nicholas Yang <nicholas.yang@vercel.com> Date: Tue, 13 Dec 2022 11:07:19 -0500 Subject: [PATCH 270/672] feat(rust-port): Split up shim and cli (vercel/turbo#2970) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Created two separate chains for executing commands: One that uses the parsed arguments from clap that are serialized to json, the other that still uses Cobra. Now to test to ensure that both do the same thing * Adjusted json serialization. Now debugging * Hooked up new CLI to commands * Fixing compile error * fixing lint error * Fixing more Go lint errors * Fixing lint errors * fixing up tests * Only using turbo state with link, login, and logout commands * Reverting changes * Removing more changes * Deleting code and fixing lints * Removed unlink command * Fixing bugs * Reverting more changes * fixed all tests * Refactored away duplicates using CLIConfigProvider interface * Lint fixes * Minor order tweak * Added error if command is not handled * PR feedback * Minor fixes. Adding --__test-run flag * Added workaround for subcommand help * Moved logic around to accomodate login/logout/link/unlink * Added some documentation, removed some printf * Adding more tests. * Hooked up link/login/unlink to --__test-run flag. Also added prysk tests for it. * Split up derive into multiple lines * Added comment explaining clap v3 in Cargo.toml * Ported daemon * Cleaning up code. Removed imports * Fix lints * Fixing lints * Ported prune to Rust CLI * Going all the way. Porting run to Rust CLI and upgrading back to clap v4 * Always gotta be testing * Always be testing. Always. Be. Testing. * Added tests for each singular flag. Now for combination tests * WIP: Hooking up Rust CLI to Go run logic * Disable color * Removed root inference from Go side * Fixing compile errors * Update cli/cmd/turbo/main.go Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> * Patching up code for run * PR changes * Restored labeler * Restore og.tsx * Reverted run changes that somehow made it in here * Fix run * Update cli/internal/turbostate/turbostate.go Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> * feat: polyfill `global` with `globalThis` (vercel/turbo#2666) This PR changes the ecmascript chunk logic to polyfill `global` with `globalThis`. A more complex and less performant solution (but with the benefit of us knowing the runtime environment) would be to add an effect for simple identifier expressions. * delete IsYarn util (vercel/turbo#2668) * feat(docs): new authors & consistent filesnames (vercel/turbo#2680) * Added caveat to environment variables docs (vercel/turbo#2703) Co-authored-by: Thomas Knickman <tom.knickman@vercel.com> * Fix publish workflow (vercel/turbo#2681) * change from yarn to pnpm (vercel/turbo#2686) Co-authored-by: Justin Ridgewell <justin@ridgewell.name> * Reverted workflow changes * Fixing tests. Added run args to base * Trying to fix tests * Rewrote some logic around run args handling * Fixing up tests by adding flags and fixing parsing bugs * Hooked up RepoState to Go code * Fixing e2e tests * Fixing e2e * Gotta build shim, not turbo in package.json * Patched integration test * Reverted Cargo.toml * Cargo.lock too * Fixing tests * Moving turbo binary to shim * Fixed tests and CI * Check for TURBO_BINARY_PATH * Ported shell completions to Rust * Fixed logic issue with TURBO_BINARY_PATH * Created .gitignore file with generated rust and header files * Second try on cleaning up generated files * More CI fixes * Realized we still need some inference * Removed files that are edited by run-examples.sh * Switched order of `cargo fmt --check` and `cargo clippy` because `cargo clippy` generates files needed for `cargo fmt --check`. * Cleaning up changes. * Fix one thing break another * Accept integration changes * Deleting more unused code * Test fixes * No longer need this line now that src/ffi.rs is gitignored * PR feedback * Update cli/internal/run/run.go Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> * Fixing typo * Merged main * PR feedback * PR feedback * Merge main * Reverted workflow change * Error on invalid unicode instead of lossy conversion * PR feedback * Squashed commit of the following: commit 096b8b8b357abe985e4116108af8a87aaba968cb Author: David Barrat <david@barrat.io> Date: Mon Dec 5 15:29:41 2022 +0100 Docs: Add Authdog to Turbo Showcase page (vercel/turbo#2921) [Authdog](https://www.authdog.com/) is an Identity and Access Management as a Service platform, built upon Serverless technologies (AWS Lambda, Vercel, Fastly and Cloudflare Workers). I started looking for alternatives to Nx, some times ago and experimented with Turbo, decided to migrate some projects to this tool, awesome stuff! commit e39d65eb5b97140fe6338dabfbd0ac3be2987d8f Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon Dec 5 15:23:40 2022 +0100 enable id reusing (vercel/turbo#2895) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit 6b99818abd358ebb4fa3506b493e2fae34372d25 Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon Dec 5 15:22:53 2022 +0100 Reduce wrapper tasks by eagerly resolving Vcs (vercel/turbo#2933) * resolve codegenerateable before calling it * eagerly resolve some constructors to avoid creating many wrapper tasks Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit ce4c445cd2c17021b4397c8e3cf93d91921146ef Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon Dec 5 15:22:32 2022 +0100 Share TaskInputs between task cache and task (vercel/turbo#2923) Move bound task function into TaskState to allow unloading Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit e1bf5e2cde7ca2006c8a4c3455dec38e971aa3eb Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon Dec 5 14:32:24 2022 +0100 make sure that removing collectibles will cleanup helper entries (vercel/turbo#2872) commit 532eff76326fb9237a450345b45073c1061e5a37 Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon Dec 5 13:27:22 2022 +0100 Reduce the number of Strings and wrapper tasks (vercel/turbo#2834) * use Cow to avoid creating Strings for trait function names * trait calls avoid the resolve trait wrapper task when called on a resolved VC * eagerly resolve some Vc that would otherwise create a lot of wrapper tasks Depends on vercel/turbo#2416 commit dc36fc41586e5763520b4a16d249cdd6779bc902 Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon Dec 5 11:00:10 2022 +0100 reduce number of allocations (vercel/turbo#2833) VecDeque::new always allocates 7 elements commit 4f247be94b03f44765ac8bd334194545cd992b9b Author: Nathan Hammond <nathan.hammond@vercel.com> Date: Mon Dec 5 15:39:15 2022 +0800 Upgrade to Next.js 13 (vercel/turbo#2906) This gets our site updated to Next.js 13 and Nextra 2. As a bonus, this should help prevent some of the issues we're seeing in Sentry. commit 1e818068241c308cd3260bd83eba294d890a6151 Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Mon Dec 5 07:42:19 2022 +0100 shrink lists and sets that are stored in Tasks (vercel/turbo#2873) Reduces memory usage by 14% commit cac79bbe35c5ee7d2bf14625bb709dff8010b8ad Author: Ahab <ahabhgk@gmail.com> Date: Sun Dec 4 13:23:26 2022 +0800 make lazy bundling for dynamic import more lazy (vercel/turbo#2918) For example: ```js // index.js setTimeout(() => { import('./async.js').then(() => console.log('async.js loaded')) }, 1000) ``` ```js // async.js import './async.css'; console.log('async.js content') ``` For now the graph generated by above code will be like this: <img width="1461" alt="Screen Shot 2022-12-03 at 21 22 24" src="https://user-images.githubusercontent.com/42857895/205442932-ebfd5126-ef3d-4205-b5b5-434126ad46f7.png"> The `ChunkGroup_async` will be a async chunk group of `ChunkGroup_index`, pushed at [turbopack-core/src/chunk/mod.rs#L462](https://github.com/vercel/turbo/blob/e1a9bcb94d439856982fd7edb522ba3122699f2d/crates/turbopack-core/src/chunk/mod.rs#L462), and it will have a reference between `ChunkGroup_index` and `ChunkGroup_async`, but `ChunkGroup_async` will also be a chunk group of `ChunkGroup_async-manifest-chunk` created at [turbopack-ecmascript/src/chunk/loader.rs#L165](https://github.com/vercel/turbo/blob/e1a9bcb94d439856982fd7edb522ba3122699f2d/crates/turbopack-ecmascript/src/chunk/loader.rs#L165), and will have a reference between `ChunkGroup_async-manifest-chunk` and `ChunkGroup_async`. This leads to when the browser request '/_a8a837.js', turbopack will compile chunks in `ChunkGroup_index` ('/_a8a837.js'), `ChunkGroup_async-manifest-chunk` ('/src_async.js_manifest-chunk.js'), and also chunks in `ChunkGroup_async` ('/src_async.js', '/src_async.css'), because of the reference between `ChunkGroup_index` and `ChunkGroup_async`. But the expected behavior is only compile chunks in `ChunkGroup_index` and `ChunkGroup_async-manifest-chunk`, so this PR deleted the reference between `ChunkGroup_index` and `ChunkGroup_async`, makes the graph be like this: <img width="1461" alt="Screen Shot 2022-12-03 at 21 50 29" src="https://user-images.githubusercontent.com/42857895/205444165-7b266dce-9aa6-4829-b8dc-d2bf74642aff.png"> And makes chunks in `ChunkGroup_async` to be compiled only when the browser request '/src_async.js_manifest-chunk.js'. commit fd09f2e7cba7bcff030c1f10f31fc0155dd055fe Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Sun Dec 4 03:26:37 2022 +0000 chore(deps): update dependency @types/node to v18.11.10 (vercel/turbo#2928) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Thomas Knickman <tom.knickman@vercel.com> commit 429e91eae5c313556fe8cb0bde87ab521e28d7cf Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Sat Dec 3 22:21:26 2022 -0500 chore(deps): update dependency @babel/core to v7.20.5 (vercel/turbo#2919) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> commit c2d5a07dc58a57434cf2aed00a1ce428215f585e Author: Tobias Koppers <tobias.koppers@googlemail.com> Date: Sat Dec 3 22:11:10 2022 +0100 update chromiumoxide (vercel/turbo#2916) updating in hope that this fixes the random errors in test runs commit e1a9bcb94d439856982fd7edb522ba3122699f2d Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Sat Dec 3 08:54:50 2022 +0000 chore(deps): update rust crate futures to 0.3.25 (vercel/turbo#2915) [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [futures](https://rust-lang.github.io/futures-rs) ([source](https://togithub.com/rust-lang/futures-rs)) | dev-dependencies | patch | `0.3.21` -> `0.3.25` | | [futures](https://rust-lang.github.io/futures-rs) ([source](https://togithub.com/rust-lang/futures-rs)) | dependencies | patch | `0.3.21` -> `0.3.25` | | [futures](https://rust-lang.github.io/futures-rs) ([source](https://togithub.com/rust-lang/futures-rs)) | dependencies | patch | `0.3.24` -> `0.3.25` | --- ### ⚠ Dependency Lookup Warnings ⚠ Warnings were logged while processing this repo. Please check the Dependency Dashboard for more information. --- ### Release Notes <details> <summary>rust-lang/futures-rs</summary> ### [`v0.3.25`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0325---2022-10-20) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.24...0.3.25) - Fix soundness issue in `join!` and `try_join!` macros ([#&vercel/turbo#8203;2649](https://togithub.com/rust-lang/futures-rs/issues/2649)) - Implement `Clone` for `sink::Drain` ([#&vercel/turbo#8203;2650](https://togithub.com/rust-lang/futures-rs/issues/2650)) ### [`v0.3.24`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0324---2022-08-29) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.23...0.3.24) - Fix incorrect termination of `select_with_strategy` streams ([#&vercel/turbo#8203;2635](https://togithub.com/rust-lang/futures-rs/issues/2635)) ### [`v0.3.23`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0323---2022-08-14) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.22...0.3.23) - Work around MSRV increase due to a cargo bug. ### [`v0.3.22`](https://togithub.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#&vercel/turbo#8203;0322---2022-08-14) [Compare Source](https://togithub.com/rust-lang/futures-rs/compare/0.3.21...0.3.22) - Fix `Sync` impl of `BiLockGuard` ([#&vercel/turbo#8203;2570](https://togithub.com/rust-lang/futures-rs/issues/2570)) - Fix partial iteration in `FuturesUnordered` ([#&vercel/turbo#8203;2574](https://togithub.com/rust-lang/futures-rs/issues/2574)) - Fix false detection of inner panics in `Shared` ([#&vercel/turbo#8203;2576](https://togithub.com/rust-lang/futures-rs/issues/2576)) - Add `Mutex::lock_owned` and `Mutex::try_lock_owned` ([#&vercel/turbo#8203;2571](https://togithub.com/rust-lang/futures-rs/issues/2571)) - Add `io::copy_buf_abortable` ([#&vercel/turbo#8203;2507](https://togithub.com/rust-lang/futures-rs/issues/2507)) - Remove `Unpin` bound from `TryStreamExt::into_async_read` ([#&vercel/turbo#8203;2599](https://togithub.com/rust-lang/futures-rs/issues/2599)) - Make `run_until_stalled` handle self-waking futures ([#&vercel/turbo#8203;2593](https://togithub.com/rust-lang/futures-rs/issues/2593)) - Use `FuturesOrdered` in `try_join_all` ([#&vercel/turbo#8203;2556](https://togithub.com/rust-lang/futures-rs/issues/2556)) - Fix orderings in `LocalPool` waker ([#&vercel/turbo#8203;2608](https://togithub.com/rust-lang/futures-rs/issues/2608)) - Fix `stream::Chunk` adapters size hints ([#&vercel/turbo#8203;2611](https://togithub.com/rust-lang/futures-rs/issues/2611)) - Add `push_front` and `push_back` to `FuturesOrdered` ([#&vercel/turbo#8203;2591](https://togithub.com/rust-lang/futures-rs/issues/2591)) - Deprecate `FuturesOrdered::push` in favor of `FuturesOrdered::push_back` ([#&vercel/turbo#8203;2591](https://togithub.com/rust-lang/futures-rs/issues/2591)) - Performance improvements ([#&vercel/turbo#8203;2583](https://togithub.com/rust-lang/futures-rs/issues/2583), [#&vercel/turbo#8203;2626](https://togithub.com/rust-lang/futures-rs/issues/2626)) - Documentation improvements ([#&vercel/turbo#8203;2579](https://togithub.com/rust-lang/futures-rs/issues/2579), [#&vercel/turbo#8203;2604](https://togithub.com/rust-lang/futures-rs/issues/2604), [#&vercel/turbo#8203;2613](https://togithub.com/rust-lang/futures-rs/issues/2613)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - "after 10pm every weekday,before 5am every weekday,every weekend" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/vercel/turbo). commit 93222f2b22d43bd9c1d917350f810e5398ca9d49 Author: Anthony Shew <anthony.shew@vercel.com> Date: Fri Dec 2 16:36:55 2022 -0800 feat(docs): document topology outside of a task (vercel/turbo#2879) * Docs for topology outside of a task Documentation for behavior in vercel/turbo#2855! * Minor cleanup. * Some copy updates and add image. Co-authored-by: Thomas Knickman <tom.knickman@vercel.com> commit f8aaf81cb7c833f672001eb36d30d700e1cf6cc9 Author: Will Binns-Smith <wbinnssmith@gmail.com> Date: Fri Dec 2 16:32:35 2022 -0800 Link to Turbopack's architecture.md from CONTRIBUTING.md (vercel/turbo#2913) commit 07231701892cbca7b73e35bfb490f2514770628e Author: Thomas Knickman <tom.knickman@vercel.com> Date: Fri Dec 2 16:40:08 2022 -0500 feat(docs): add github (vercel/turbo#2912) commit c69298c4a31516129bb62263f163a1da9c5614da Author: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Fri Dec 2 11:58:55 2022 -0800 build(cargo): update swc_core, dependencies to resolve circular deps (vercel/turbo#2869) * build(cargo): bump up swc_core * build(cargo): unpin indexmap * build(cargo): update dependencies * style(cargo): adjust format commit 6965cb81ef5693b3e7a23e6a999be04d6590fad5 Author: Leah <github.leah@hrmny.sh> Date: Fri Dec 2 19:42:05 2022 +0100 set correct cwd for server renderer (vercel/turbo#2886) commit 934567015bc99eb8aa80311623e52ea924cbc424 Author: Leah <github.leah@hrmny.sh> Date: Fri Dec 2 18:27:02 2022 +0100 fix dynamic paths (vercel/turbo#2884) commit eead9063968a3b8571e3ba2c7a897522f890e2fc Author: Nathan Hammond <nathan.hammond@vercel.com> Date: Fri Dec 2 16:09:08 2022 +0800 Fix the missing links. (vercel/turbo#2707) This PR does three things: 1. Prevents double redirects by setting the correct destination the first time. 2. Redirects URLs accidentally recreated in the new scope. 🤦‍♂️ 3. Removes a catch-all to trigger any additional missing links to appear. Changes are easy to review commit-by-commit. commit b8c0c3c74636fd4b0586951011919bc05e1f651d Author: Nathan Hammond <nathan.hammond@vercel.com> Date: Fri Dec 2 14:37:03 2022 +0800 Update lint-staged behavior. (vercel/turbo#2904) Before vercel/turbo#2859: `eslint --quiet --fix` After vercel/turbo#2859: `pnpm run lint --quiet --fix --` => `eslint . --ext js,jsx,ts,tsx --quiet --fix --` After this: `eslint --ext js,jsx,ts,tsx --quiet --fix --` Removes the sneaky `.`. commit 336ea22098ff8825e83baa2561d8ec0acf5b52af Author: Nathan Hammond <nathan.hammond@vercel.com> Date: Fri Dec 2 08:33:21 2022 +0800 Add additional detailed warning message if no tasks were run. (vercel/turbo#2778) This is a quality of life improvement output log so that you don't have to tease it out from the overall run summary and the situation is more-apparent. commit dcb1ab33d1f9571177b9db51e3e0cbbbe8e021e1 Author: Leah <github.leah@hrmny.sh> Date: Thu Dec 1 21:02:33 2022 +0100 simplify `next-binding` (vercel/turbo#2899) commit 22c1440283ed4dfd1e310210108244c4c12d4c56 Author: Justin Ridgewell <justin@ridgewell.name> Date: Thu Dec 1 13:55:15 2022 -0500 Implement import.meta (vercel/turbo#2816) I chose to have the `import.meta.url` to have the relative project path on disk. Webpack makes it the absolute system path, but that would make the JS output system dependent and I didn't like that. Vite doesn't bundle and uses the browser's behavior, which is the dev server path. I'm splitting this from the in-progress PR to implement `new URL(…, import.meta.url)` support. That requires a bunch of changes to the analysis code and a new FS content source, so it's taking longer to ship. Fixes WEB-137. commit 75a7d1ea450cdaa629920464b509f3098997ae06 Author: Thomas Knickman <tom.knickman@vercel.com> Date: Thu Dec 1 11:40:15 2022 -0500 fix(examples): cra pnpm fix (vercel/turbo#2897) * Merged main * Reverting changes that snuck in * Fixing tests * Final fixes for tests * Moving shim to crates/turborepo * More refactoring * First pass at splitting up shim and cli * Fixing tests * Added detection for help flag so users can get help outside of a valid repo * Update crates/turborepo-lib/src/shim.rs Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> * Update crates/turborepo/Cargo.toml Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> * PR feedback and test fixing * Set process's cwd * Have to do inference even with TURBO_BINARY_PATH * Comments * PR feedback * Moved single_package back to RunArgs * Removed print * Fixing bugs * Fixing rust tests * fixing bug with verbosity and Go tests * add local turbo version checking * remove ffi inclusion * Fixed integration tests * Linting fixes * Integrated local_turbo_supports_skip_shim * Fixed bug with cwd and restored yarn.lock * Okay back to setting current_dir * Fixed bug with canonicalization * Removed print starting Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> Co-authored-by: Florentin / 珞辰 <ecklf@icloud.com> Co-authored-by: Chris Olszewski <chris.olszewski@vercel.com> Co-authored-by: Thomas Knickman <tom.knickman@vercel.com> Co-authored-by: Matt Pocock <mattpocockvoice@gmail.com> Co-authored-by: Mehul Kar <mehul.kar@vercel.com> Co-authored-by: Yota Hada <hadayota33@gmail.com> Co-authored-by: Justin Ridgewell <justin@ridgewell.name> --- packages/next-swc/crates/next-dev/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index e27e8c6a83b4bf..987fb456add1a8 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -54,7 +54,7 @@ webbrowser = "0.7.1" chromiumoxide = { version = "0.4.0", features = [ "tokio-runtime", ], default-features = false } -criterion = { version = "0.3.5", features = ["async_tokio"] } +criterion = { version = "0.4.0", features = ["async_tokio"] } fs_extra = "1.2.0" lazy_static = "1.4.0" once_cell = "1.13.0" From 650b80366b858a5fa95791a9f74f815d96224340 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:53:12 -0800 Subject: [PATCH 271/672] style(turbopack): clippy --fix (vercel/turbo#3014) Easy clippy improvements via `clippy --fix`. --- .../next-swc/crates/next-core/src/server_rendered_source.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index fbfbdbf291741f..4a01cd75a60ddb 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -205,7 +205,7 @@ async fn create_server_rendered_source_for_file( } else { let data_pathname = format!( "_next/data/development/{}", - get_asset_path_from_route(&*pathname.await?, ".json") + get_asset_path_from_route(&pathname.await?, ".json") ); let data_path_regex = regular_expression_for_path(StringVc::cell(data_pathname)); From f590196931994d9ae0a71402d511af280be5f933 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Wed, 14 Dec 2022 18:44:32 -0500 Subject: [PATCH 272/672] Add support for new URL (vercel/turbo#2944) Implements `new URL('./path', import.meta.url)`, so that the referenced file acts as a static output file, and transforms the URL into to point to that file in the graph. This is, well, complicated. As you'll see in the comments, we have an "inert" asset that acts as a placeholder until the module chunking algorithm gives us access to a `ChunkingContextVc`. It's unfortunately not available when we're doing the file parsing, but we can insert a reference to that inert asset. That inert asset will eventually create a `UrlAssetChunk` instance, and with that we can finally generate the correct output path for the URL referenced file. We actually discussed whether this could use a `StaticAsset`/`StaticModuleAsset` (a `StaticAsset` can be inserted at parse time), but it turns out that won't give us the necessary control to generate the final `URL` instance. A `StaticModuleAsset` always outputs an absolute path as it's default export, and that just won't work when we're trying to reference the file in node SSR. Fixes WEB-142. Pending WEB-279 for full node SSR support. Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> --- .../next-core/src/next_client/context.rs | 19 ++++++++++++++----- .../next-core/src/server_rendered_source.rs | 6 +++++- .../crates/next-core/src/web_entry_source.rs | 4 +++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index f5b99e88b7f511..3c5aa00d3b231c 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -18,6 +18,7 @@ use turbopack_core::{ chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, context::AssetContextVc, environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, + reference_type::{ReferenceType, UrlReferenceSubType}, resolve::{parse::RequestVc, pattern::Pattern}, }; use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc}; @@ -120,6 +121,9 @@ pub async fn add_next_transforms_to_pages( module_options_context.custom_rules.push(ModuleRule::new( ModuleRuleCondition::all(vec![ ModuleRuleCondition::ResourcePathInExactDirectory(pages_dir.await?), + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType(ReferenceType::Url( + UrlReferenceSubType::Undefined, + ))), ModuleRuleCondition::any(vec![ ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), @@ -146,11 +150,16 @@ pub async fn add_next_font_transform( let mut module_options_context = module_options_context.await?.clone_value(); module_options_context.custom_rules.push(ModuleRule::new( // TODO: Only match in pages (not pages/api), app/, etc. - ModuleRuleCondition::any(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType(ReferenceType::Url( + UrlReferenceSubType::Undefined, + ))), + ModuleRuleCondition::any(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), + ]), ]), vec![ModuleRuleEffect::AddEcmascriptTransforms( EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJsFont( diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 4a01cd75a60ddb..de1d40fd7f467a 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -12,6 +12,7 @@ use turbopack_core::{ asset::AssetVc, chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, context::AssetContextVc, + reference_type::{EntryReferenceSubType, ReferenceType}, source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, }; @@ -166,7 +167,10 @@ async fn create_server_rendered_source_for_file( intermediate_output_path: FileSystemPathVc, ) -> Result<ContentSourceVc> { let source_asset = SourceAssetVc::new(page_file).into(); - let entry_asset = context.process(source_asset); + let entry_asset = context.process( + source_asset, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)), + ); let chunking_context = DevChunkingContextVc::builder( context_path, diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index e103c00b688420..e48b427c27092e 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -5,6 +5,7 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack::ecmascript::EcmascriptModuleAssetVc; use turbopack_core::{ chunk::{ChunkGroupVc, ChunkableAssetVc}, + reference_type::{EntryReferenceSubType, ReferenceType}, resolve::{origin::PlainResolveOriginVc, parse::RequestVc}, }; use turbopack_dev_server::{ @@ -42,8 +43,9 @@ pub async fn create_web_entry_source( let entries = entry_requests .into_iter() .map(|request| async move { + let ty = Value::new(ReferenceType::Entry(EntryReferenceSubType::Web)); Ok(origin - .resolve_asset(request, origin.resolve_options()) + .resolve_asset(request, origin.resolve_options(ty.clone()), ty) .primary_assets() .await? .first() From 9e7bf34b21b607dcca3a35fc62cb904984b4114f Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Wed, 14 Dec 2022 17:07:04 -0800 Subject: [PATCH 273/672] build(next/core): allow to specify tls backend for reqwest (vercel/turbo#2994) Implement / fixes WEB-306. We can't rely on default tls backend for reqwest and hope to work with every target platform we support, due to several constraints. Some target cannot use -sys (openssl-sys), and some can't build rustls due to trasnsitive dep support issue. PR creates explicit opt-in features for those and let upstream application can specify what they need. `next-dev` currently sets `native-tls` as default for the general dev workflow conveniences, but that doesn't mean we promote it as default feature set - next-swc, or other like standalone turbopack will configure features by themselves when build binaries for their own. --- packages/next-swc/crates/next-core/Cargo.toml | 2 ++ packages/next-swc/crates/next-dev/Cargo.toml | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 72470b7afff8e9..19eec7b4ba5f60 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -35,3 +35,5 @@ turbo-tasks-build = { path = "../turbo-tasks-build" } [features] next-font-local = [] +native-tls = ["turbo-tasks-fetch/native-tls"] +rustls-tls = ["turbo-tasks-fetch/rustls-tls"] diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 987fb456add1a8..64c22c0055e2dc 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -19,7 +19,12 @@ name = "mod" harness = false [features] -default = ["cli", "custom_allocator"] +# By default, we enable native-tls for reqwest downstream trasntive features. +# This is for the convinience for all of daily dev workflow i.e running +# `cargo xxx` without explicitly specifying features, not that we want to +# promote this as default backend. Actual configuration is done when build next-swc, +# and also turbopack standalone when we have it. +default = ["cli", "custom_allocator", "native-tls"] cli = [] serializable = [] tokio_console = [ @@ -30,6 +35,8 @@ tokio_console = [ profile = [] custom_allocator = ["turbo-malloc/custom_allocator"] next-font-local = ["next-core/next-font-local"] +native-tls = ["next-core/native-tls"] +rustls-tls = ["next-core/rustls-tls"] [dependencies] anyhow = "1.0.47" From 339777a16ec70fe0fbd1e04cc6a9301b07791a28 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Thu, 15 Dec 2022 09:22:03 -0800 Subject: [PATCH 274/672] feat(mdx): initial turbopack-mdx asset (vercel/turbo#2979) Implements / fix WEB-86. This PR is an initial attempt to support mdx natively inside of turbopack. It uses mdxrs (https://github.com/wooorm/mdxjs-rs) internally to interop - compile - mdx inputs into renderable ecma outputs. PR creates a new type of asset `MDXAsset`, and then let its extension (`.mdx`) can be consumed by turbopack. Since mdx is a variant of ecma asset to be rendered, it requires to perform all of the ecma transforms in the current running turbopack session. But since its AST is not compatible to plain swc (or ecma), it also cannot be passed into existing ecmaassets. MDXAsset does interop for those, by creating a virtualasset for the ecma once mdx is compiled into plain ecma. This might not be feasible appoarch and requires different way to chain asset types, something I'd like to address in this PR. I guess this will be needed for other types of assets in a long run - where input is not an ecma but requires ecma transforms (i.e vue, ng templates). --- .../next-swc/crates/next-core/src/server_rendered_source.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index de1d40fd7f467a..557f6962dfeb97 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -290,7 +290,7 @@ async fn create_server_rendered_source_for_directory( match extension { // pageExtensions option from next.js // defaults: https://github.com/vercel/next.js/blob/611e13f5159457fedf96d850845650616a1f75dd/packages/next/server/config-shared.ts#L499 - "js" | "ts" | "jsx" | "tsx" => { + "js" | "ts" | "jsx" | "tsx" | "mdx" => { let (dev_server_path, intermediate_output_path, specificity) = if basename == "index" { ( From 3ca10da03b592070fd6ac5e3b33984a294153330 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith <wbinnssmith@gmail.com> Date: Fri, 16 Dec 2022 10:56:19 -0800 Subject: [PATCH 275/672] Fix flakey next-dev integration tests (vercel/turbo#3020) Fixes WEB-259 This should address the known cases of flakiness in the next-dev integration test suite. Most notably, it wraps the call to `browser.new_page`, which not only opens a new tab, it also navigates to the destination and waits for it to load. It also: * Migrates test code to `anyhow::Result`, and adds `context` to the `new_page` call should it fail again. * Mitigates flakiness resulting from browser-side Jest timeouts by moving the circular correctness test to a new directory called `__flakey__`. These tests aren't run at all -- unfortunatley it's not possible to customize Jest's timeout with this particular version of `jest-circus-browser`. WEB-319 tracks updating this dependency, which hasn't been maintained in a while, unlike `jest-circus` itself. Test Plan: * [x] Run the Rust test suite in CI until confident there are no intermittent failures. --- .../crates/next-dev/tests/integration.rs | 36 +++++++++++++------ .../circular-correctness/index.js | 0 .../circular-correctness/module-a.js | 0 .../circular-correctness/module-a2.js | 0 .../circular-correctness/module-b.js | 0 .../circular-correctness/module-b2.js | 0 .../circular-correctness/module-c.js | 0 .../circular-correctness/module-x.js | 0 8 files changed, 25 insertions(+), 11 deletions(-) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{ => __flakey__}/circular-correctness/index.js (100%) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{ => __flakey__}/circular-correctness/module-a.js (100%) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{ => __flakey__}/circular-correctness/module-a2.js (100%) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{ => __flakey__}/circular-correctness/module-b.js (100%) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{ => __flakey__}/circular-correctness/module-b2.js (100%) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{ => __flakey__}/circular-correctness/module-c.js (100%) rename packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/{ => __flakey__}/circular-correctness/module-x.js (100%) diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index bc6ddac98b50f1..64df900fc48a2b 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -8,7 +8,7 @@ use std::{ time::Duration, }; -use anyhow::Context; +use anyhow::{anyhow, Context, Result}; use chromiumoxide::{ browser::{Browser, BrowserConfig}, error::CdpError::Ws, @@ -48,10 +48,16 @@ lazy_static! { #[test_resources("crates/next-dev/tests/integration/*/*/*")] #[tokio::main(flavor = "current_thread")] async fn test(resource: &str) { - if resource.ends_with("__skipped__") { + if resource.ends_with("__skipped__") || resource.ends_with("__flakey__") { // "Skip" directories named `__skipped__`, which include test directories to // skip. These tests are not considered truly skipped by `cargo test`, but they // are not run. + // + // All current `__flakey__` tests need longer timeouts, but the current + // build of `jest-circus-browser` does not support configuring this. + // + // TODO(WEB-319): Update the version of `jest-circus` in `jest-circus-browser`, + // which supports configuring this. Or explore an alternative. return; } @@ -156,9 +162,7 @@ async fn run_test(resource: &str) -> JestRunResult { } } -async fn create_browser( - is_debugging: bool, -) -> Result<(Browser, JoinHandle<()>), Box<dyn std::error::Error>> { +async fn create_browser(is_debugging: bool) -> Result<(Browser, JoinHandle<()>)> { let mut config_builder = BrowserConfig::builder(); if is_debugging { config_builder = config_builder @@ -167,7 +171,7 @@ async fn create_browser( } let (browser, mut handler) = retry_async( - config_builder.build()?, + config_builder.build().map_err(|s| anyhow!(s))?, |c| { let c = c.clone(); Browser::launch(c) @@ -190,7 +194,7 @@ async fn create_browser( Ok((browser, thread_handle)) } -async fn run_browser(addr: SocketAddr) -> Result<JestRunResult, Box<dyn std::error::Error>> { +async fn run_browser(addr: SocketAddr) -> Result<JestRunResult> { if *DEBUG_BROWSER { run_debug_browser(addr).await?; } @@ -198,7 +202,7 @@ async fn run_browser(addr: SocketAddr) -> Result<JestRunResult, Box<dyn std::err run_test_browser(addr).await } -async fn run_debug_browser(addr: SocketAddr) -> Result<(), Box<dyn std::error::Error>> { +async fn run_debug_browser(addr: SocketAddr) -> Result<()> { let (browser, handle) = create_browser(true).await?; let page = browser.new_page(format!("http://{}", addr)).await?; @@ -217,10 +221,20 @@ async fn run_debug_browser(addr: SocketAddr) -> Result<(), Box<dyn std::error::E Ok(()) } -async fn run_test_browser(addr: SocketAddr) -> Result<JestRunResult, Box<dyn std::error::Error>> { +async fn run_test_browser(addr: SocketAddr) -> Result<JestRunResult> { let (browser, _) = create_browser(false).await?; - let page = browser.new_page(format!("http://{}", addr)).await?; - page.wait_for_navigation().await?; + + // `browser.new_page()` opens a tab, navigates to the destination, and waits for + // the page to load. chromiumoxide/Chrome DevTools Protocol has been flakey, + // returning `ChannelSendError`s (WEB-259). Retry if necessary. + let page = retry_async( + (), + |_| browser.new_page(format!("http://{}", addr)), + 5, + Duration::from_millis(100), + ) + .await + .context("Failed to create new browser page")?; let value = page.evaluate("globalThis.waitForTests?.() ?? __jest__.run()"); Ok(value.await?.into_value()?) diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/index.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/index.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/index.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-a.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-a.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-a2.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-a2.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-a2.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-b.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-b.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-b2.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-b2.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-b2.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-c.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-c.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-c.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js b/packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-x.js similarity index 100% rename from packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/circular-correctness/module-x.js rename to packages/next-swc/crates/next-dev/tests/integration/webpack/chunks/__flakey__/circular-correctness/module-x.js From 4e59cabbc02cd2d9d9fcee3867c0896a2c25838d Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Fri, 16 Dec 2022 20:59:10 -0800 Subject: [PATCH 276/672] cargo(build): expose tls for next-binding (vercel/turbo#3040) --- packages/next-swc/crates/next-binding/Cargo.toml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-binding/Cargo.toml b/packages/next-swc/crates/next-binding/Cargo.toml index 0b51d485c5e32e..5c781a5c4a395a 100644 --- a/packages/next-swc/crates/next-binding/Cargo.toml +++ b/packages/next-swc/crates/next-binding/Cargo.toml @@ -77,6 +77,10 @@ __turbo = [] __turbo_next_dev_server = ["__turbo", "next-dev/serializable"] __turbo_node_file_trace = ["__turbo", "node-file-trace/node-api"] +# set tls for downstream dependenices of turbo +__turbo_native_tls = ["next-dev/native-tls"] +__turbo_rustls_tls = ["next-dev/rustls-tls"] + __features = [] __feature_mdx_rs = ["__features", "mdxjs/serializable"] @@ -98,7 +102,10 @@ __swc_testing = ["__swc", "testing"] [dependencies] mdxjs = { optional = true, workspace = true } modularize_imports = { optional = true, workspace = true } -next-dev = { optional = true, workspace = true } +# TODO: Not sure what's going on, but using `workspace = true` noops `default-features = false`? +next-dev = { optional = true, path = "../next-dev", version = "0.1.0", default-features = false, features = [ + "custom_allocator", +] } node-file-trace = { optional = true, workspace = true } styled_components = { optional = true, workspace = true } styled_jsx = { optional = true, workspace = true } From f583c9809b5497f1e076a0ee6afdc69fe6d3178e Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Sat, 17 Dec 2022 17:31:38 -0500 Subject: [PATCH 277/672] Remove chunk item source maps from the asset graph (vercel/turbo#3059) In order to serve source maps with HMR updates, we (used to) reference a source map asset for every chunk item using the items version hash (see vercel/turbo#2464 and vercel/turbo#2474 for the headaches this can cause). This update changes that, so that a chunk becomes responsible for giving access to one of its item's source map. We already have the `GenerateSourceMap` trait which assembles the chunk's `Sectioned` source map from all chunk items, so why not just allow access to an individual section? Coupled with a `ContentSource` that can retrieve the chunk, we can then provide access to that chunk's current item source maps per request. --- packages/next-swc/crates/next-dev/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index ebad029842dc40..07af0bec32e6b6 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -40,7 +40,8 @@ use turbopack_dev_server::{ introspect::IntrospectionSource, source::{ combined::CombinedContentSourceVc, router::RouterContentSource, - static_assets::StaticAssetsContentSourceVc, ContentSourceVc, + source_maps::SourceMapContentSourceVc, static_assets::StaticAssetsContentSourceVc, + ContentSourceVc, }, DevServer, }; @@ -349,6 +350,7 @@ async fn source( .cell() .into(); let main_source = main_source.into(); + let source_maps = SourceMapContentSourceVc::new(main_source).into(); let source_map_trace = NextSourceMapTraceContentSourceVc::new(main_source).into(); let img_source = NextImageContentSourceVc::new( CombinedContentSourceVc::new(vec![static_source, rendered_source]).into(), @@ -364,6 +366,7 @@ async fn source( ), // TODO: Load path from next.config.js ("_next/image".to_string(), img_source), + ("__turbopack_sourcemap__/".to_string(), source_maps), ], fallback: main_source, } From 2182d7df0a03f0f489d5b188b92c28dc50de7f51 Mon Sep 17 00:00:00 2001 From: LongYinan <lynweklm@gmail.com> Date: Sun, 18 Dec 2022 08:35:43 +0800 Subject: [PATCH 278/672] Load next config (vercel/turbo#2955) Load next.config.js via turbopack-node Closes WEB-158 Co-authored-by: Justin Ridgewell <justin@ridgewell.name> Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> --- .../next-core/js/src/compiled/anser/index.js | 2 +- .../js/src/compiled/css.escape/index.js | 2 +- .../js/src/compiled/platform/index.js | 4 +- .../js/src/compiled/source-map/index.js | 2 +- .../next-core/js/src/entry/app-renderer.tsx | 3 +- .../next-core/js/src/entry/config/next.js | 9 + .../next-core/js/src/entry/server-api.tsx | 5 +- .../js/src/entry/server-renderer.tsx | 6 +- .../crates/next-core/js/src/internal/error.ts | 18 -- .../crates/next-core/js/src/ipc/evaluate.ts | 44 +++ .../js/src/{internal/ipc.ts => ipc/index.ts} | 27 +- .../crates/next-core/src/app_source.rs | 80 +++-- .../next-swc/crates/next-core/src/embed_js.rs | 11 + packages/next-swc/crates/next-core/src/env.rs | 29 +- .../next-swc/crates/next-core/src/fallback.rs | 4 +- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../next-core/src/next_client/context.rs | 5 +- .../crates/next-core/src/next_config.rs | 279 ++++++++++++++++++ .../crates/next-core/src/next_import_map.rs | 26 +- .../crates/next-core/src/next_server/mod.rs | 39 ++- .../next-core/src/server_rendered_source.rs | 30 +- .../crates/next-core/src/web_entry_source.rs | 4 +- .../{turbopack.rs => turbopack/mod.rs} | 7 + .../benches/bundlers/turbopack/next.config.js | 5 + .../crates/next-dev/src/devserver_options.rs | 5 - packages/next-swc/crates/next-dev/src/lib.rs | 27 +- .../next/image/basic/next.config.js | 6 + 27 files changed, 553 insertions(+), 127 deletions(-) create mode 100644 packages/next-swc/crates/next-core/js/src/entry/config/next.js delete mode 100644 packages/next-swc/crates/next-core/js/src/internal/error.ts create mode 100644 packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts rename packages/next-swc/crates/next-core/js/src/{internal/ipc.ts => ipc/index.ts} (84%) create mode 100644 packages/next-swc/crates/next-core/src/next_config.rs rename packages/next-swc/crates/next-dev/benches/bundlers/{turbopack.rs => turbopack/mod.rs} (94%) create mode 100644 packages/next-swc/crates/next-dev/benches/bundlers/turbopack/next.config.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/basic/next.config.js diff --git a/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js b/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js index de3a71db9ee61e..611c4e40400329 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/anser/index.js @@ -1 +1 @@ -(()=>{"use strict";var e={976:e=>{var r=function(){function defineProperties(e,r){for(var s=0;s<r.length;s++){var n=r[s];n.enumerable=n.enumerable||false;n.configurable=true;if("value"in n)n.writable=true;Object.defineProperty(e,n.key,n)}}return function(e,r,s){if(r)defineProperties(e.prototype,r);if(s)defineProperties(e,s);return e}}();function _classCallCheck(e,r){if(!(e instanceof r)){throw new TypeError("Cannot call a class as a function")}}var s=[[{color:"0, 0, 0",class:"ansi-black"},{color:"187, 0, 0",class:"ansi-red"},{color:"0, 187, 0",class:"ansi-green"},{color:"187, 187, 0",class:"ansi-yellow"},{color:"0, 0, 187",class:"ansi-blue"},{color:"187, 0, 187",class:"ansi-magenta"},{color:"0, 187, 187",class:"ansi-cyan"},{color:"255,255,255",class:"ansi-white"}],[{color:"85, 85, 85",class:"ansi-bright-black"},{color:"255, 85, 85",class:"ansi-bright-red"},{color:"0, 255, 0",class:"ansi-bright-green"},{color:"255, 255, 85",class:"ansi-bright-yellow"},{color:"85, 85, 255",class:"ansi-bright-blue"},{color:"255, 85, 255",class:"ansi-bright-magenta"},{color:"85, 255, 255",class:"ansi-bright-cyan"},{color:"255, 255, 255",class:"ansi-bright-white"}]];var n=function(){r(Anser,null,[{key:"escapeForHtml",value:function escapeForHtml(e){return(new Anser).escapeForHtml(e)}},{key:"linkify",value:function linkify(e){return(new Anser).linkify(e)}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return(new Anser).ansiToHtml(e,r)}},{key:"ansiToJson",value:function ansiToJson(e,r){return(new Anser).ansiToJson(e,r)}},{key:"ansiToText",value:function ansiToText(e){return(new Anser).ansiToText(e)}}]);function Anser(){_classCallCheck(this,Anser);this.fg=this.bg=this.fg_truecolor=this.bg_truecolor=null;this.bright=0;this.decorations=[]}r(Anser,[{key:"setupPalette",value:function setupPalette(){this.PALETTE_COLORS=[];for(var e=0;e<2;++e){for(var r=0;r<8;++r){this.PALETTE_COLORS.push(s[e][r].color)}}var n=[0,95,135,175,215,255];var o=function format(e,r,s){return n[e]+", "+n[r]+", "+n[s]};var i=void 0,t=void 0,a=void 0;for(var l=0;l<6;++l){for(var c=0;c<6;++c){for(var u=0;u<6;++u){this.PALETTE_COLORS.push(o(l,c,u))}}}var f=8;for(var h=0;h<24;++h,f+=10){this.PALETTE_COLORS.push(o(f,f,f))}}},{key:"escapeForHtml",value:function escapeForHtml(e){return e.replace(/[&<>\"]/gm,(function(e){return e=="&"?"&":e=='"'?""":e=="<"?"<":e==">"?">":""}))}},{key:"linkify",value:function linkify(e){return e.replace(/(https?:\/\/[^\s]+)/gm,(function(e){return'<a href="'+e+'">'+e+"</a>"}))}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return this.process(e,r,true)}},{key:"ansiToJson",value:function ansiToJson(e,r){r=r||{};r.json=true;r.clearLine=false;return this.process(e,r,true)}},{key:"ansiToText",value:function ansiToText(e){return this.process(e,{},false)}},{key:"process",value:function process(e,r,s){var n=this;var o=this;var i=e.split(/\033\[/);var t=i.shift();if(r===undefined||r===null){r={}}r.clearLine=/\r/.test(e);var a=i.map((function(e){return n.processChunk(e,r,s)}));if(r&&r.json){var l=o.processChunkJson("");l.content=t;l.clearLine=r.clearLine;a.unshift(l);if(r.remove_empty){a=a.filter((function(e){return!e.isEmpty()}))}return a}else{a.unshift(t)}return a.join("")}},{key:"processChunkJson",value:function processChunkJson(e,r,n){r=typeof r=="undefined"?{}:r;var o=r.use_classes=typeof r.use_classes!="undefined"&&r.use_classes;var i=r.key=o?"class":"color";var t={content:e,fg:null,bg:null,fg_truecolor:null,bg_truecolor:null,isInverted:false,clearLine:r.clearLine,decoration:null,decorations:[],was_processed:false,isEmpty:function isEmpty(){return!t.content}};var a=e.match(/^([!\x3c-\x3f]*)([\d;]*)([\x20-\x2c]*[\x40-\x7e])([\s\S]*)/m);if(!a)return t;var l=t.content=a[4];var c=a[2].split(";");if(a[1]!==""||a[3]!=="m"){return t}if(!n){return t}var u=this;while(c.length>0){var f=c.shift();var h=parseInt(f);if(isNaN(h)||h===0){u.fg=u.bg=null;u.decorations=[]}else if(h===1){u.decorations.push("bold")}else if(h===2){u.decorations.push("dim")}else if(h===3){u.decorations.push("italic")}else if(h===4){u.decorations.push("underline")}else if(h===5){u.decorations.push("blink")}else if(h===7){u.decorations.push("reverse")}else if(h===8){u.decorations.push("hidden")}else if(h===9){u.decorations.push("strikethrough")}else if(h===21){u.removeDecoration("bold")}else if(h===22){u.removeDecoration("bold");u.removeDecoration("dim")}else if(h===23){u.removeDecoration("italic")}else if(h===24){u.removeDecoration("underline")}else if(h===25){u.removeDecoration("blink")}else if(h===27){u.removeDecoration("reverse")}else if(h===28){u.removeDecoration("hidden")}else if(h===29){u.removeDecoration("strikethrough")}else if(h===39){u.fg=null}else if(h===49){u.bg=null}else if(h>=30&&h<38){u.fg=s[0][h%10][i]}else if(h>=90&&h<98){u.fg=s[1][h%10][i]}else if(h>=40&&h<48){u.bg=s[0][h%10][i]}else if(h>=100&&h<108){u.bg=s[1][h%10][i]}else if(h===38||h===48){var v=h===38;if(c.length>=1){var g=c.shift();if(g==="5"&&c.length>=1){var p=parseInt(c.shift());if(p>=0&&p<=255){if(!o){if(!this.PALETTE_COLORS){u.setupPalette()}if(v){u.fg=this.PALETTE_COLORS[p]}else{u.bg=this.PALETTE_COLORS[p]}}else{var d=p>=16?"ansi-palette-"+p:s[p>7?1:0][p%8]["class"];if(v){u.fg=d}else{u.bg=d}}}}else if(g==="2"&&c.length>=3){var b=parseInt(c.shift());var _=parseInt(c.shift());var m=parseInt(c.shift());if(b>=0&&b<=255&&_>=0&&_<=255&&m>=0&&m<=255){var k=b+", "+_+", "+m;if(!o){if(v){u.fg=k}else{u.bg=k}}else{if(v){u.fg="ansi-truecolor";u.fg_truecolor=k}else{u.bg="ansi-truecolor";u.bg_truecolor=k}}}}}}}if(u.fg===null&&u.bg===null&&u.decorations.length===0){return t}else{var y=[];var T=[];var w={};t.fg=u.fg;t.bg=u.bg;t.fg_truecolor=u.fg_truecolor;t.bg_truecolor=u.bg_truecolor;t.decorations=u.decorations;t.decoration=u.decorations.slice(-1).pop()||null;t.was_processed=true;return t}}},{key:"processChunk",value:function processChunk(e,r,n){var o=this;r=r||{};var i=this.processChunkJson(e,r,n);var t=r.use_classes;i.decorations=i.decorations.filter((function(e){if(e==="reverse"){if(!i.fg){i.fg=s[0][7][t?"class":"color"]}if(!i.bg){i.bg=s[0][0][t?"class":"color"]}var r=i.fg;i.fg=i.bg;i.bg=r;var n=i.fg_truecolor;i.fg_truecolor=i.bg_truecolor;i.bg_truecolor=n;i.isInverted=true;return false}return true}));if(r.json){return i}if(i.isEmpty()){return""}if(!i.was_processed){return i.content}var a=[];var l=[];var c=[];var u={};var f=function render_data(e){var r=[];var s=void 0;for(s in e){if(e.hasOwnProperty(s)){r.push("data-"+s+'="'+o.escapeForHtml(e[s])+'"')}}return r.length>0?" "+r.join(" "):""};if(i.isInverted){u["ansi-is-inverted"]="true"}if(i.fg){if(t){a.push(i.fg+"-fg");if(i.fg_truecolor!==null){u["ansi-truecolor-fg"]=i.fg_truecolor;i.fg_truecolor=null}}else{a.push("color:rgb("+i.fg+")")}}if(i.bg){if(t){a.push(i.bg+"-bg");if(i.bg_truecolor!==null){u["ansi-truecolor-bg"]=i.bg_truecolor;i.bg_truecolor=null}}else{a.push("background-color:rgb("+i.bg+")")}}i.decorations.forEach((function(e){if(t){l.push("ansi-"+e);return}if(e==="bold"){l.push("font-weight:bold")}else if(e==="dim"){l.push("opacity:0.5")}else if(e==="italic"){l.push("font-style:italic")}else if(e==="hidden"){l.push("visibility:hidden")}else if(e==="strikethrough"){c.push("line-through")}else{c.push(e)}}));if(c.length){l.push("text-decoration:"+c.join(" "))}if(t){return'<span class="'+a.concat(l).join(" ")+'"'+f(u)+">"+i.content+"</span>"}else{return'<span style="'+a.concat(l).join(";")+'"'+f(u)+">"+i.content+"</span>"}}},{key:"removeDecoration",value:function removeDecoration(e){var r=this.decorations.indexOf(e);if(r>=0){this.decorations.splice(r,1)}}}]);return Anser}();e.exports=n}};var r={};function __nccwpck_require__(s){var n=r[s];if(n!==undefined){return n.exports}var o=r[s]={exports:{}};var i=true;try{e[s](o,o.exports,__nccwpck_require__);i=false}finally{if(i)delete r[s]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var s=__nccwpck_require__(976);module.exports=s})(); \ No newline at end of file +(()=>{"use strict";var e={793:e=>{var r=function(){function defineProperties(e,r){for(var s=0;s<r.length;s++){var n=r[s];n.enumerable=n.enumerable||false;n.configurable=true;if("value"in n)n.writable=true;Object.defineProperty(e,n.key,n)}}return function(e,r,s){if(r)defineProperties(e.prototype,r);if(s)defineProperties(e,s);return e}}();function _classCallCheck(e,r){if(!(e instanceof r)){throw new TypeError("Cannot call a class as a function")}}var s=[[{color:"0, 0, 0",class:"ansi-black"},{color:"187, 0, 0",class:"ansi-red"},{color:"0, 187, 0",class:"ansi-green"},{color:"187, 187, 0",class:"ansi-yellow"},{color:"0, 0, 187",class:"ansi-blue"},{color:"187, 0, 187",class:"ansi-magenta"},{color:"0, 187, 187",class:"ansi-cyan"},{color:"255,255,255",class:"ansi-white"}],[{color:"85, 85, 85",class:"ansi-bright-black"},{color:"255, 85, 85",class:"ansi-bright-red"},{color:"0, 255, 0",class:"ansi-bright-green"},{color:"255, 255, 85",class:"ansi-bright-yellow"},{color:"85, 85, 255",class:"ansi-bright-blue"},{color:"255, 85, 255",class:"ansi-bright-magenta"},{color:"85, 255, 255",class:"ansi-bright-cyan"},{color:"255, 255, 255",class:"ansi-bright-white"}]];var n=function(){r(Anser,null,[{key:"escapeForHtml",value:function escapeForHtml(e){return(new Anser).escapeForHtml(e)}},{key:"linkify",value:function linkify(e){return(new Anser).linkify(e)}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return(new Anser).ansiToHtml(e,r)}},{key:"ansiToJson",value:function ansiToJson(e,r){return(new Anser).ansiToJson(e,r)}},{key:"ansiToText",value:function ansiToText(e){return(new Anser).ansiToText(e)}}]);function Anser(){_classCallCheck(this,Anser);this.fg=this.bg=this.fg_truecolor=this.bg_truecolor=null;this.bright=0;this.decorations=[]}r(Anser,[{key:"setupPalette",value:function setupPalette(){this.PALETTE_COLORS=[];for(var e=0;e<2;++e){for(var r=0;r<8;++r){this.PALETTE_COLORS.push(s[e][r].color)}}var n=[0,95,135,175,215,255];var o=function format(e,r,s){return n[e]+", "+n[r]+", "+n[s]};var i=void 0,t=void 0,a=void 0;for(var l=0;l<6;++l){for(var c=0;c<6;++c){for(var u=0;u<6;++u){this.PALETTE_COLORS.push(o(l,c,u))}}}var f=8;for(var h=0;h<24;++h,f+=10){this.PALETTE_COLORS.push(o(f,f,f))}}},{key:"escapeForHtml",value:function escapeForHtml(e){return e.replace(/[&<>\"]/gm,(function(e){return e=="&"?"&":e=='"'?""":e=="<"?"<":e==">"?">":""}))}},{key:"linkify",value:function linkify(e){return e.replace(/(https?:\/\/[^\s]+)/gm,(function(e){return'<a href="'+e+'">'+e+"</a>"}))}},{key:"ansiToHtml",value:function ansiToHtml(e,r){return this.process(e,r,true)}},{key:"ansiToJson",value:function ansiToJson(e,r){r=r||{};r.json=true;r.clearLine=false;return this.process(e,r,true)}},{key:"ansiToText",value:function ansiToText(e){return this.process(e,{},false)}},{key:"process",value:function process(e,r,s){var n=this;var o=this;var i=e.split(/\033\[/);var t=i.shift();if(r===undefined||r===null){r={}}r.clearLine=/\r/.test(e);var a=i.map((function(e){return n.processChunk(e,r,s)}));if(r&&r.json){var l=o.processChunkJson("");l.content=t;l.clearLine=r.clearLine;a.unshift(l);if(r.remove_empty){a=a.filter((function(e){return!e.isEmpty()}))}return a}else{a.unshift(t)}return a.join("")}},{key:"processChunkJson",value:function processChunkJson(e,r,n){r=typeof r=="undefined"?{}:r;var o=r.use_classes=typeof r.use_classes!="undefined"&&r.use_classes;var i=r.key=o?"class":"color";var t={content:e,fg:null,bg:null,fg_truecolor:null,bg_truecolor:null,isInverted:false,clearLine:r.clearLine,decoration:null,decorations:[],was_processed:false,isEmpty:function isEmpty(){return!t.content}};var a=e.match(/^([!\x3c-\x3f]*)([\d;]*)([\x20-\x2c]*[\x40-\x7e])([\s\S]*)/m);if(!a)return t;var l=t.content=a[4];var c=a[2].split(";");if(a[1]!==""||a[3]!=="m"){return t}if(!n){return t}var u=this;while(c.length>0){var f=c.shift();var h=parseInt(f);if(isNaN(h)||h===0){u.fg=u.bg=null;u.decorations=[]}else if(h===1){u.decorations.push("bold")}else if(h===2){u.decorations.push("dim")}else if(h===3){u.decorations.push("italic")}else if(h===4){u.decorations.push("underline")}else if(h===5){u.decorations.push("blink")}else if(h===7){u.decorations.push("reverse")}else if(h===8){u.decorations.push("hidden")}else if(h===9){u.decorations.push("strikethrough")}else if(h===21){u.removeDecoration("bold")}else if(h===22){u.removeDecoration("bold");u.removeDecoration("dim")}else if(h===23){u.removeDecoration("italic")}else if(h===24){u.removeDecoration("underline")}else if(h===25){u.removeDecoration("blink")}else if(h===27){u.removeDecoration("reverse")}else if(h===28){u.removeDecoration("hidden")}else if(h===29){u.removeDecoration("strikethrough")}else if(h===39){u.fg=null}else if(h===49){u.bg=null}else if(h>=30&&h<38){u.fg=s[0][h%10][i]}else if(h>=90&&h<98){u.fg=s[1][h%10][i]}else if(h>=40&&h<48){u.bg=s[0][h%10][i]}else if(h>=100&&h<108){u.bg=s[1][h%10][i]}else if(h===38||h===48){var v=h===38;if(c.length>=1){var g=c.shift();if(g==="5"&&c.length>=1){var p=parseInt(c.shift());if(p>=0&&p<=255){if(!o){if(!this.PALETTE_COLORS){u.setupPalette()}if(v){u.fg=this.PALETTE_COLORS[p]}else{u.bg=this.PALETTE_COLORS[p]}}else{var d=p>=16?"ansi-palette-"+p:s[p>7?1:0][p%8]["class"];if(v){u.fg=d}else{u.bg=d}}}}else if(g==="2"&&c.length>=3){var b=parseInt(c.shift());var _=parseInt(c.shift());var m=parseInt(c.shift());if(b>=0&&b<=255&&_>=0&&_<=255&&m>=0&&m<=255){var k=b+", "+_+", "+m;if(!o){if(v){u.fg=k}else{u.bg=k}}else{if(v){u.fg="ansi-truecolor";u.fg_truecolor=k}else{u.bg="ansi-truecolor";u.bg_truecolor=k}}}}}}}if(u.fg===null&&u.bg===null&&u.decorations.length===0){return t}else{var y=[];var T=[];var w={};t.fg=u.fg;t.bg=u.bg;t.fg_truecolor=u.fg_truecolor;t.bg_truecolor=u.bg_truecolor;t.decorations=u.decorations;t.decoration=u.decorations.slice(-1).pop()||null;t.was_processed=true;return t}}},{key:"processChunk",value:function processChunk(e,r,n){var o=this;r=r||{};var i=this.processChunkJson(e,r,n);var t=r.use_classes;i.decorations=i.decorations.filter((function(e){if(e==="reverse"){if(!i.fg){i.fg=s[0][7][t?"class":"color"]}if(!i.bg){i.bg=s[0][0][t?"class":"color"]}var r=i.fg;i.fg=i.bg;i.bg=r;var n=i.fg_truecolor;i.fg_truecolor=i.bg_truecolor;i.bg_truecolor=n;i.isInverted=true;return false}return true}));if(r.json){return i}if(i.isEmpty()){return""}if(!i.was_processed){return i.content}var a=[];var l=[];var c=[];var u={};var f=function render_data(e){var r=[];var s=void 0;for(s in e){if(e.hasOwnProperty(s)){r.push("data-"+s+'="'+o.escapeForHtml(e[s])+'"')}}return r.length>0?" "+r.join(" "):""};if(i.isInverted){u["ansi-is-inverted"]="true"}if(i.fg){if(t){a.push(i.fg+"-fg");if(i.fg_truecolor!==null){u["ansi-truecolor-fg"]=i.fg_truecolor;i.fg_truecolor=null}}else{a.push("color:rgb("+i.fg+")")}}if(i.bg){if(t){a.push(i.bg+"-bg");if(i.bg_truecolor!==null){u["ansi-truecolor-bg"]=i.bg_truecolor;i.bg_truecolor=null}}else{a.push("background-color:rgb("+i.bg+")")}}i.decorations.forEach((function(e){if(t){l.push("ansi-"+e);return}if(e==="bold"){l.push("font-weight:bold")}else if(e==="dim"){l.push("opacity:0.5")}else if(e==="italic"){l.push("font-style:italic")}else if(e==="hidden"){l.push("visibility:hidden")}else if(e==="strikethrough"){c.push("line-through")}else{c.push(e)}}));if(c.length){l.push("text-decoration:"+c.join(" "))}if(t){return'<span class="'+a.concat(l).join(" ")+'"'+f(u)+">"+i.content+"</span>"}else{return'<span style="'+a.concat(l).join(";")+'"'+f(u)+">"+i.content+"</span>"}}},{key:"removeDecoration",value:function removeDecoration(e){var r=this.decorations.indexOf(e);if(r>=0){this.decorations.splice(r,1)}}}]);return Anser}();e.exports=n}};var r={};function __nccwpck_require__(s){var n=r[s];if(n!==undefined){return n.exports}var o=r[s]={exports:{}};var i=true;try{e[s](o,o.exports,__nccwpck_require__);i=false}finally{if(i)delete r[s]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var s=__nccwpck_require__(793);module.exports=s})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js b/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js index e18b5542fb2e47..eaedacfcb97e2d 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/css.escape/index.js @@ -1 +1 @@ -(()=>{var e={4:function(e){(function(r,t){if(true){e.exports=t(r)}else{}})(typeof global!="undefined"?global:this,(function(e){if(e.CSS&&e.CSS.escape){return e.CSS.escape}var cssEscape=function(e){if(arguments.length==0){throw new TypeError("`CSS.escape` requires an argument.")}var r=String(e);var t=r.length;var n=-1;var a;var i="";var u=r.charCodeAt(0);while(++n<t){a=r.charCodeAt(n);if(a==0){i+="�";continue}if(a>=1&&a<=31||a==127||n==0&&a>=48&&a<=57||n==1&&a>=48&&a<=57&&u==45){i+="\\"+a.toString(16)+" ";continue}if(n==0&&t==1&&a==45){i+="\\"+r.charAt(n);continue}if(a>=128||a==45||a==95||a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122){i+=r.charAt(n);continue}i+="\\"+r.charAt(n)}return i};if(!e.CSS){e.CSS={}}e.CSS.escape=cssEscape;return cssEscape}))}};var r={};function __nccwpck_require__(t){var n=r[t];if(n!==undefined){return n.exports}var a=r[t]={exports:{}};var i=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);i=false}finally{if(i)delete r[t]}return a.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(4);module.exports=t})(); \ No newline at end of file +(()=>{var e={969:function(e){(function(r,t){if(true){e.exports=t(r)}else{}})(typeof global!="undefined"?global:this,(function(e){if(e.CSS&&e.CSS.escape){return e.CSS.escape}var cssEscape=function(e){if(arguments.length==0){throw new TypeError("`CSS.escape` requires an argument.")}var r=String(e);var t=r.length;var n=-1;var a;var i="";var u=r.charCodeAt(0);while(++n<t){a=r.charCodeAt(n);if(a==0){i+="�";continue}if(a>=1&&a<=31||a==127||n==0&&a>=48&&a<=57||n==1&&a>=48&&a<=57&&u==45){i+="\\"+a.toString(16)+" ";continue}if(n==0&&t==1&&a==45){i+="\\"+r.charAt(n);continue}if(a>=128||a==45||a==95||a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122){i+=r.charAt(n);continue}i+="\\"+r.charAt(n)}return i};if(!e.CSS){e.CSS={}}e.CSS.escape=cssEscape;return cssEscape}))}};var r={};function __nccwpck_require__(t){var n=r[t];if(n!==undefined){return n.exports}var a=r[t]={exports:{}};var i=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);i=false}finally{if(i)delete r[t]}return a.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(969);module.exports=t})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js b/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js index 24a243af2f2657..12fbfe4b24a365 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/platform/index.js @@ -1,7 +1,7 @@ -(()=>{var e={651:function(e,i,t){e=t.nmd(e); +(()=>{var e={797:function(e,i,t){e=t.nmd(e); /*! * Platform.js v1.3.6 * Copyright 2014-2020 Benjamin Tan * Copyright 2011-2013 John-David Dalton * Available under MIT license - */(function(){"use strict";var t={function:true,object:true};var r=t[typeof window]&&window||this;var a=r;var n=t[typeof i]&&i;var o=t["object"]&&e&&!e.nodeType&&e;var l=n&&o&&typeof global=="object"&&global;if(l&&(l.global===l||l.window===l||l.self===l)){r=l}var s=Math.pow(2,53)-1;var f=/\bOpera/;var b=this;var c=Object.prototype;var p=c.hasOwnProperty;var u=c.toString;function capitalize(e){e=String(e);return e.charAt(0).toUpperCase()+e.slice(1)}function cleanupOS(e,i,t){var r={"10.0":"10",6.4:"10 Technical Preview",6.3:"8.1",6.2:"8",6.1:"Server 2008 R2 / 7","6.0":"Server 2008 / Vista",5.2:"Server 2003 / XP 64-bit",5.1:"XP",5.01:"2000 SP1","5.0":"2000","4.0":"NT","4.90":"ME"};if(i&&t&&/^Win/i.test(e)&&!/^Windows Phone /i.test(e)&&(r=r[/[\d.]+$/.exec(e)])){e="Windows "+r}e=String(e);if(i&&t){e=e.replace(RegExp(i,"i"),t)}e=format(e.replace(/ ce$/i," CE").replace(/\bhpw/i,"web").replace(/\bMacintosh\b/,"Mac OS").replace(/_PowerPC\b/i," OS").replace(/\b(OS X) [^ \d]+/i,"$1").replace(/\bMac (OS X)\b/,"$1").replace(/\/(\d)/," $1").replace(/_/g,".").replace(/(?: BePC|[ .]*fc[ \d.]+)$/i,"").replace(/\bx86\.64\b/gi,"x86_64").replace(/\b(Windows Phone) OS\b/,"$1").replace(/\b(Chrome OS \w+) [\d.]+\b/,"$1").split(" on ")[0]);return e}function each(e,i){var t=-1,r=e?e.length:0;if(typeof r=="number"&&r>-1&&r<=s){while(++t<r){i(e[t],t,e)}}else{forOwn(e,i)}}function format(e){e=trim(e);return/^(?:webOS|i(?:OS|P))/.test(e)?e:capitalize(e)}function forOwn(e,i){for(var t in e){if(p.call(e,t)){i(e[t],t,e)}}}function getClassOf(e){return e==null?capitalize(e):u.call(e).slice(8,-1)}function isHostType(e,i){var t=e!=null?typeof e[i]:"number";return!/^(?:boolean|number|string|undefined)$/.test(t)&&(t=="object"?!!e[i]:true)}function qualify(e){return String(e).replace(/([ -])(?!$)/g,"$1?")}function reduce(e,i){var t=null;each(e,(function(r,a){t=i(t,r,a,e)}));return t}function trim(e){return String(e).replace(/^ +| +$/g,"")}function parse(e){var i=r;var t=e&&typeof e=="object"&&getClassOf(e)!="String";if(t){i=e;e=null}var n=i.navigator||{};var o=n.userAgent||"";e||(e=o);var l=t||b==a;var s=t?!!n.likeChrome:/\bChrome\b/.test(e)&&!/internal|\n/i.test(u.toString());var c="Object",p=t?c:"ScriptBridgingProxyObject",d=t?c:"Environment",S=t&&i.java?"JavaPackage":getClassOf(i.java),x=t?c:"RuntimeObject";var m=/\bJava/.test(S)&&i.java;var g=m&&getClassOf(i.environment)==d;var h=m?"a":"α";var v=m?"b":"β";var O=i.document||{};var y=i.operamini||i.opera;var w=f.test(w=t&&y?y["[[Class]]"]:getClassOf(y))?w:y=null;var M;var E=e;var P=[];var C=null;var k=e==o;var B=k&&y&&typeof y.version=="function"&&y.version();var W;var _=getLayout([{label:"EdgeHTML",pattern:"Edge"},"Trident",{label:"WebKit",pattern:"AppleWebKit"},"iCab","Presto","NetFront","Tasman","KHTML","Gecko"]);var R=getName(["Adobe AIR","Arora","Avant Browser","Breach","Camino","Electron","Epiphany","Fennec","Flock","Galeon","GreenBrowser","iCab","Iceweasel","K-Meleon","Konqueror","Lunascape","Maxthon",{label:"Microsoft Edge",pattern:"(?:Edge|Edg|EdgA|EdgiOS)"},"Midori","Nook Browser","PaleMoon","PhantomJS","Raven","Rekonq","RockMelt",{label:"Samsung Internet",pattern:"SamsungBrowser"},"SeaMonkey",{label:"Silk",pattern:"(?:Cloud9|Silk-Accelerated)"},"Sleipnir","SlimBrowser",{label:"SRWare Iron",pattern:"Iron"},"Sunrise","Swiftfox","Vivaldi","Waterfox","WebPositive",{label:"Yandex Browser",pattern:"YaBrowser"},{label:"UC Browser",pattern:"UCBrowser"},"Opera Mini",{label:"Opera Mini",pattern:"OPiOS"},"Opera",{label:"Opera",pattern:"OPR"},"Chromium","Chrome",{label:"Chrome",pattern:"(?:HeadlessChrome)"},{label:"Chrome Mobile",pattern:"(?:CriOS|CrMo)"},{label:"Firefox",pattern:"(?:Firefox|Minefield)"},{label:"Firefox for iOS",pattern:"FxiOS"},{label:"IE",pattern:"IEMobile"},{label:"IE",pattern:"MSIE"},"Safari"]);var A=getProduct([{label:"BlackBerry",pattern:"BB10"},"BlackBerry",{label:"Galaxy S",pattern:"GT-I9000"},{label:"Galaxy S2",pattern:"GT-I9100"},{label:"Galaxy S3",pattern:"GT-I9300"},{label:"Galaxy S4",pattern:"GT-I9500"},{label:"Galaxy S5",pattern:"SM-G900"},{label:"Galaxy S6",pattern:"SM-G920"},{label:"Galaxy S6 Edge",pattern:"SM-G925"},{label:"Galaxy S7",pattern:"SM-G930"},{label:"Galaxy S7 Edge",pattern:"SM-G935"},"Google TV","Lumia","iPad","iPod","iPhone","Kindle",{label:"Kindle Fire",pattern:"(?:Cloud9|Silk-Accelerated)"},"Nexus","Nook","PlayBook","PlayStation Vita","PlayStation","TouchPad","Transformer",{label:"Wii U",pattern:"WiiU"},"Wii","Xbox One",{label:"Xbox 360",pattern:"Xbox"},"Xoom"]);var I=getManufacturer({Apple:{iPad:1,iPhone:1,iPod:1},Alcatel:{},Archos:{},Amazon:{Kindle:1,"Kindle Fire":1},Asus:{Transformer:1},"Barnes & Noble":{Nook:1},BlackBerry:{PlayBook:1},Google:{"Google TV":1,Nexus:1},HP:{TouchPad:1},HTC:{},Huawei:{},Lenovo:{},LG:{},Microsoft:{Xbox:1,"Xbox One":1},Motorola:{Xoom:1},Nintendo:{"Wii U":1,Wii:1},Nokia:{Lumia:1},Oppo:{},Samsung:{"Galaxy S":1,"Galaxy S2":1,"Galaxy S3":1,"Galaxy S4":1},Sony:{PlayStation:1,"PlayStation Vita":1},Xiaomi:{Mi:1,Redmi:1}});var T=getOS(["Windows Phone","KaiOS","Android","CentOS",{label:"Chrome OS",pattern:"CrOS"},"Debian",{label:"DragonFly BSD",pattern:"DragonFly"},"Fedora","FreeBSD","Gentoo","Haiku","Kubuntu","Linux Mint","OpenBSD","Red Hat","SuSE","Ubuntu","Xubuntu","Cygwin","Symbian OS","hpwOS","webOS ","webOS","Tablet OS","Tizen","Linux","Mac OS X","Macintosh","Mac","Windows 98;","Windows "]);function getLayout(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getManufacturer(i){return reduce(i,(function(i,t,r){return i||(t[A]||t[/^[a-z]+(?: +[a-z]+\b)*/i.exec(A)]||RegExp("\\b"+qualify(r)+"(?:\\b|\\w*\\d)","i").exec(e))&&r}))}function getName(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getOS(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+"(?:/[\\d.]+|[ \\w.]*)","i").exec(e))){i=cleanupOS(i,r,t.label||t)}return i}))}function getProduct(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+" *\\d+[.\\w_]*","i").exec(e)||RegExp("\\b"+r+" *\\w+-[\\w]*","i").exec(e)||RegExp("\\b"+r+"(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)","i").exec(e))){if((i=String(t.label&&!RegExp(r,"i").test(t.label)?t.label:i).split("/"))[1]&&!/[\d.]+/.test(i[0])){i[0]+=" "+i[1]}t=t.label||t;i=format(i[0].replace(RegExp(r,"i"),t).replace(RegExp("; *(?:"+t+"[_-])?","i")," ").replace(RegExp("("+t+")[-_.]?(\\w)","i"),"$1 $2"))}return i}))}function getVersion(i){return reduce(i,(function(i,t){return i||(RegExp(t+"(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)","i").exec(e)||0)[1]||null}))}function toStringPlatform(){return this.description||""}_&&(_=[_]);if(/\bAndroid\b/.test(T)&&!A&&(M=/\bAndroid[^;]*;(.*?)(?:Build|\) AppleWebKit)\b/i.exec(e))){A=trim(M[1]).replace(/^[a-z]{2}-[a-z]{2};\s*/i,"")||null}if(I&&!A){A=getProduct([I])}else if(I&&A){A=A.replace(RegExp("^("+qualify(I)+")[-_.\\s]","i"),I+" ").replace(RegExp("^("+qualify(I)+")[-_.]?(\\w)","i"),I+" $2")}if(M=/\bGoogle TV\b/.exec(A)){A=M[0]}if(/\bSimulator\b/i.test(e)){A=(A?A+" ":"")+"Simulator"}if(R=="Opera Mini"&&/\bOPiOS\b/.test(e)){P.push("running in Turbo/Uncompressed mode")}if(R=="IE"&&/\blike iPhone OS\b/.test(e)){M=parse(e.replace(/like iPhone OS/,""));I=M.manufacturer;A=M.product}else if(/^iP/.test(A)){R||(R="Safari");T="iOS"+((M=/ OS ([\d_]+)/i.exec(e))?" "+M[1].replace(/_/g,"."):"")}else if(R=="Konqueror"&&/^Linux\b/i.test(T)){T="Kubuntu"}else if(I&&I!="Google"&&(/Chrome/.test(R)&&!/\bMobile Safari\b/i.test(e)||/\bVita\b/.test(A))||/\bAndroid\b/.test(T)&&/^Chrome/.test(R)&&/\bVersion\//i.test(e)){R="Android Browser";T=/\bAndroid\b/.test(T)?T:"Android"}else if(R=="Silk"){if(!/\bMobi/i.test(e)){T="Android";P.unshift("desktop mode")}if(/Accelerated *= *true/i.test(e)){P.unshift("accelerated")}}else if(R=="UC Browser"&&/\bUCWEB\b/.test(e)){P.push("speed mode")}else if(R=="PaleMoon"&&(M=/\bFirefox\/([\d.]+)\b/.exec(e))){P.push("identifying as Firefox "+M[1])}else if(R=="Firefox"&&(M=/\b(Mobile|Tablet|TV)\b/i.exec(e))){T||(T="Firefox OS");A||(A=M[1])}else if(!R||(M=!/\bMinefield\b/i.test(e)&&/\b(?:Firefox|Safari)\b/.exec(R))){if(R&&!A&&/[\/,]|^[^(]+?\)/.test(e.slice(e.indexOf(M+"/")+8))){R=null}if((M=A||I||T)&&(A||I||/\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(T))){R=/[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(T)?T:M)+" Browser"}}else if(R=="Electron"&&(M=(/\bChrome\/([\d.]+)\b/.exec(e)||0)[1])){P.push("Chromium "+M)}if(!B){B=getVersion(["(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|HeadlessChrome|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$)|UCBrowser|YaBrowser)","Version",qualify(R),"(?:Firefox|Minefield|NetFront)"])}if(M=_=="iCab"&&parseFloat(B)>3&&"WebKit"||/\bOpera\b/.test(R)&&(/\bOPR\b/.test(e)?"Blink":"Presto")||/\b(?:Midori|Nook|Safari)\b/i.test(e)&&!/^(?:Trident|EdgeHTML)$/.test(_)&&"WebKit"||!_&&/\bMSIE\b/i.test(e)&&(T=="Mac OS"?"Tasman":"Trident")||_=="WebKit"&&/\bPlayStation\b(?! Vita\b)/i.test(R)&&"NetFront"){_=[M]}if(R=="IE"&&(M=(/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(e)||0)[1])){R+=" Mobile";T="Windows Phone "+(/\+$/.test(M)?M:M+".x");P.unshift("desktop mode")}else if(/\bWPDesktop\b/i.test(e)){R="IE Mobile";T="Windows Phone 8.x";P.unshift("desktop mode");B||(B=(/\brv:([\d.]+)/.exec(e)||0)[1])}else if(R!="IE"&&_=="Trident"&&(M=/\brv:([\d.]+)/.exec(e))){if(R){P.push("identifying as "+R+(B?" "+B:""))}R="IE";B=M[1]}if(k){if(isHostType(i,"global")){if(m){M=m.lang.System;E=M.getProperty("os.arch");T=T||M.getProperty("os.name")+" "+M.getProperty("os.version")}if(g){try{B=i.require("ringo/engine").version.join(".");R="RingoJS"}catch(e){if((M=i.system)&&M.global.system==i.system){R="Narwhal";T||(T=M[0].os||null)}}if(!R){R="Rhino"}}else if(typeof i.process=="object"&&!i.process.browser&&(M=i.process)){if(typeof M.versions=="object"){if(typeof M.versions.electron=="string"){P.push("Node "+M.versions.node);R="Electron";B=M.versions.electron}else if(typeof M.versions.nw=="string"){P.push("Chromium "+B,"Node "+M.versions.node);R="NW.js";B=M.versions.nw}}if(!R){R="Node.js";E=M.arch;T=M.platform;B=/[\d.]+/.exec(M.version);B=B?B[0]:null}}}else if(getClassOf(M=i.runtime)==p){R="Adobe AIR";T=M.flash.system.Capabilities.os}else if(getClassOf(M=i.phantom)==x){R="PhantomJS";B=(M=M.version||null)&&M.major+"."+M.minor+"."+M.patch}else if(typeof O.documentMode=="number"&&(M=/\bTrident\/(\d+)/i.exec(e))){B=[B,O.documentMode];if((M=+M[1]+4)!=B[1]){P.push("IE "+B[1]+" mode");_&&(_[1]="");B[1]=M}B=R=="IE"?String(B[1].toFixed(1)):B[0]}else if(typeof O.documentMode=="number"&&/^(?:Chrome|Firefox)\b/.test(R)){P.push("masking as "+R+" "+B);R="IE";B="11.0";_=["Trident"];T="Windows"}T=T&&format(T)}if(B&&(M=/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(B)||/(?:alpha|beta)(?: ?\d)?/i.exec(e+";"+(k&&n.appMinorVersion))||/\bMinefield\b/i.test(e)&&"a")){C=/b/i.test(M)?"beta":"alpha";B=B.replace(RegExp(M+"\\+?$"),"")+(C=="beta"?v:h)+(/\d+\+?/.exec(M)||"")}if(R=="Fennec"||R=="Firefox"&&/\b(?:Android|Firefox OS|KaiOS)\b/.test(T)){R="Firefox Mobile"}else if(R=="Maxthon"&&B){B=B.replace(/\.[\d.]+/,".x")}else if(/\bXbox\b/i.test(A)){if(A=="Xbox 360"){T=null}if(A=="Xbox 360"&&/\bIEMobile\b/.test(e)){P.unshift("mobile mode")}}else if((/^(?:Chrome|IE|Opera)$/.test(R)||R&&!A&&!/Browser|Mobi/.test(R))&&(T=="Windows CE"||/Mobi/i.test(e))){R+=" Mobile"}else if(R=="IE"&&k){try{if(i.external===null){P.unshift("platform preview")}}catch(e){P.unshift("embedded")}}else if((/\bBlackBerry\b/.test(A)||/\bBB10\b/.test(e))&&(M=(RegExp(A.replace(/ +/g," *")+"/([.\\d]+)","i").exec(e)||0)[1]||B)){M=[M,/BB10/.test(e)];T=(M[1]?(A=null,I="BlackBerry"):"Device Software")+" "+M[0];B=null}else if(this!=forOwn&&A!="Wii"&&(k&&y||/Opera/.test(R)&&/\b(?:MSIE|Firefox)\b/i.test(e)||R=="Firefox"&&/\bOS X (?:\d+\.){2,}/.test(T)||R=="IE"&&(T&&!/^Win/.test(T)&&B>5.5||/\bWindows XP\b/.test(T)&&B>8||B==8&&!/\bTrident\b/.test(e)))&&!f.test(M=parse.call(forOwn,e.replace(f,"")+";"))&&M.name){M="ing as "+M.name+((M=M.version)?" "+M:"");if(f.test(R)){if(/\bIE\b/.test(M)&&T=="Mac OS"){T=null}M="identify"+M}else{M="mask"+M;if(w){R=format(w.replace(/([a-z])([A-Z])/g,"$1 $2"))}else{R="Opera"}if(/\bIE\b/.test(M)){T=null}if(!k){B=null}}_=["Presto"];P.push(M)}if(M=(/\bAppleWebKit\/([\d.]+\+?)/i.exec(e)||0)[1]){M=[parseFloat(M.replace(/\.(\d)$/,".0$1")),M];if(R=="Safari"&&M[1].slice(-1)=="+"){R="WebKit Nightly";C="alpha";B=M[1].slice(0,-1)}else if(B==M[1]||B==(M[2]=(/\bSafari\/([\d.]+\+?)/i.exec(e)||0)[1])){B=null}M[1]=(/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(e)||0)[1];if(M[0]==537.36&&M[2]==537.36&&parseFloat(M[1])>=28&&_=="WebKit"){_=["Blink"]}if(!k||!s&&!M[1]){_&&(_[1]="like Safari");M=(M=M[0],M<400?1:M<500?2:M<526?3:M<533?4:M<534?"4+":M<535?5:M<537?6:M<538?7:M<601?8:M<602?9:M<604?10:M<606?11:M<608?12:"12")}else{_&&(_[1]="like Chrome");M=M[1]||(M=M[0],M<530?1:M<532?2:M<532.05?3:M<533?4:M<534.03?5:M<534.07?6:M<534.1?7:M<534.13?8:M<534.16?9:M<534.24?10:M<534.3?11:M<535.01?12:M<535.02?"13+":M<535.07?15:M<535.11?16:M<535.19?17:M<536.05?18:M<536.1?19:M<537.01?20:M<537.11?"21+":M<537.13?23:M<537.18?24:M<537.24?25:M<537.36?26:_!="Blink"?"27":"28")}_&&(_[1]+=" "+(M+=typeof M=="number"?".x":/[.+]/.test(M)?"":"+"));if(R=="Safari"&&(!B||parseInt(B)>45)){B=M}else if(R=="Chrome"&&/\bHeadlessChrome/i.test(e)){P.unshift("headless")}}if(R=="Opera"&&(M=/\bzbov|zvav$/.exec(T))){R+=" ";P.unshift("desktop mode");if(M=="zvav"){R+="Mini";B=null}else{R+="Mobile"}T=T.replace(RegExp(" *"+M+"$"),"")}else if(R=="Safari"&&/\bChrome\b/.exec(_&&_[1])){P.unshift("desktop mode");R="Chrome Mobile";B=null;if(/\bOS X\b/.test(T)){I="Apple";T="iOS 4.3+"}else{T=null}}else if(/\bSRWare Iron\b/.test(R)&&!B){B=getVersion("Chrome")}if(B&&B.indexOf(M=/[\d.]+$/.exec(T))==0&&e.indexOf("/"+M+"-")>-1){T=trim(T.replace(M,""))}if(T&&T.indexOf(R)!=-1&&!RegExp(R+" OS").test(T)){T=T.replace(RegExp(" *"+qualify(R)+" *"),"")}if(_&&!/\b(?:Avant|Nook)\b/.test(R)&&(/Browser|Lunascape|Maxthon/.test(R)||R!="Safari"&&/^iOS/.test(T)&&/\bSafari\b/.test(_[1])||/^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(R)&&_[1])){(M=_[_.length-1])&&P.push(M)}if(P.length){P=["("+P.join("; ")+")"]}if(I&&A&&A.indexOf(I)<0){P.push("on "+I)}if(A){P.push((/^on /.test(P[P.length-1])?"":"on ")+A)}if(T){M=/ ([\d.+]+)$/.exec(T);W=M&&T.charAt(T.length-M[0].length-1)=="/";T={architecture:32,family:M&&!W?T.replace(M[0],""):T,version:M?M[1]:null,toString:function(){var e=this.version;return this.family+(e&&!W?" "+e:"")+(this.architecture==64?" 64-bit":"")}}}if((M=/\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(E))&&!/\bi686\b/i.test(E)){if(T){T.architecture=64;T.family=T.family.replace(RegExp(" *"+M),"")}if(R&&(/\bWOW64\b/i.test(e)||k&&/\w(?:86|32)$/.test(n.cpuClass||n.platform)&&!/\bWin64; x64\b/i.test(e))){P.unshift("32-bit")}}else if(T&&/^OS X/.test(T.family)&&R=="Chrome"&&parseFloat(B)>=39){T.architecture=64}e||(e=null);var F={};F.description=e;F.layout=_&&_[0];F.manufacturer=I;F.name=R;F.prerelease=C;F.product=A;F.ua=e;F.version=R&&B;F.os=T||{architecture:null,family:null,version:null,toString:function(){return"null"}};F.parse=parse;F.toString=toStringPlatform;if(F.version){P.unshift(B)}if(F.name){P.unshift(R)}if(T&&R&&!(T==String(T).split(" ")[0]&&(T==R.split(" ")[0]||A))){P.push(A?"("+T+")":"on "+T)}if(P.length){F.description=P.join(" ")}return F}var d=parse();if(typeof define=="function"&&typeof define.amd=="object"&&define.amd){r.platform=d;define((function(){return d}))}else if(n&&o){forOwn(d,(function(e,i){n[i]=e}))}else{r.platform=d}}).call(this)}};var i={};function __nccwpck_require__(t){var r=i[t];if(r!==undefined){return r.exports}var a=i[t]={id:t,loaded:false,exports:{}};var n=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);n=false}finally{if(n)delete i[t]}a.loaded=true;return a.exports}(()=>{__nccwpck_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(651);module.exports=t})(); \ No newline at end of file + */(function(){"use strict";var t={function:true,object:true};var r=t[typeof window]&&window||this;var a=r;var n=t[typeof i]&&i;var o=t["object"]&&e&&!e.nodeType&&e;var l=n&&o&&typeof global=="object"&&global;if(l&&(l.global===l||l.window===l||l.self===l)){r=l}var s=Math.pow(2,53)-1;var f=/\bOpera/;var b=this;var c=Object.prototype;var p=c.hasOwnProperty;var u=c.toString;function capitalize(e){e=String(e);return e.charAt(0).toUpperCase()+e.slice(1)}function cleanupOS(e,i,t){var r={"10.0":"10",6.4:"10 Technical Preview",6.3:"8.1",6.2:"8",6.1:"Server 2008 R2 / 7","6.0":"Server 2008 / Vista",5.2:"Server 2003 / XP 64-bit",5.1:"XP",5.01:"2000 SP1","5.0":"2000","4.0":"NT","4.90":"ME"};if(i&&t&&/^Win/i.test(e)&&!/^Windows Phone /i.test(e)&&(r=r[/[\d.]+$/.exec(e)])){e="Windows "+r}e=String(e);if(i&&t){e=e.replace(RegExp(i,"i"),t)}e=format(e.replace(/ ce$/i," CE").replace(/\bhpw/i,"web").replace(/\bMacintosh\b/,"Mac OS").replace(/_PowerPC\b/i," OS").replace(/\b(OS X) [^ \d]+/i,"$1").replace(/\bMac (OS X)\b/,"$1").replace(/\/(\d)/," $1").replace(/_/g,".").replace(/(?: BePC|[ .]*fc[ \d.]+)$/i,"").replace(/\bx86\.64\b/gi,"x86_64").replace(/\b(Windows Phone) OS\b/,"$1").replace(/\b(Chrome OS \w+) [\d.]+\b/,"$1").split(" on ")[0]);return e}function each(e,i){var t=-1,r=e?e.length:0;if(typeof r=="number"&&r>-1&&r<=s){while(++t<r){i(e[t],t,e)}}else{forOwn(e,i)}}function format(e){e=trim(e);return/^(?:webOS|i(?:OS|P))/.test(e)?e:capitalize(e)}function forOwn(e,i){for(var t in e){if(p.call(e,t)){i(e[t],t,e)}}}function getClassOf(e){return e==null?capitalize(e):u.call(e).slice(8,-1)}function isHostType(e,i){var t=e!=null?typeof e[i]:"number";return!/^(?:boolean|number|string|undefined)$/.test(t)&&(t=="object"?!!e[i]:true)}function qualify(e){return String(e).replace(/([ -])(?!$)/g,"$1?")}function reduce(e,i){var t=null;each(e,(function(r,a){t=i(t,r,a,e)}));return t}function trim(e){return String(e).replace(/^ +| +$/g,"")}function parse(e){var i=r;var t=e&&typeof e=="object"&&getClassOf(e)!="String";if(t){i=e;e=null}var n=i.navigator||{};var o=n.userAgent||"";e||(e=o);var l=t||b==a;var s=t?!!n.likeChrome:/\bChrome\b/.test(e)&&!/internal|\n/i.test(u.toString());var c="Object",p=t?c:"ScriptBridgingProxyObject",d=t?c:"Environment",S=t&&i.java?"JavaPackage":getClassOf(i.java),x=t?c:"RuntimeObject";var m=/\bJava/.test(S)&&i.java;var g=m&&getClassOf(i.environment)==d;var h=m?"a":"α";var v=m?"b":"β";var O=i.document||{};var y=i.operamini||i.opera;var w=f.test(w=t&&y?y["[[Class]]"]:getClassOf(y))?w:y=null;var M;var E=e;var P=[];var C=null;var k=e==o;var B=k&&y&&typeof y.version=="function"&&y.version();var W;var _=getLayout([{label:"EdgeHTML",pattern:"Edge"},"Trident",{label:"WebKit",pattern:"AppleWebKit"},"iCab","Presto","NetFront","Tasman","KHTML","Gecko"]);var R=getName(["Adobe AIR","Arora","Avant Browser","Breach","Camino","Electron","Epiphany","Fennec","Flock","Galeon","GreenBrowser","iCab","Iceweasel","K-Meleon","Konqueror","Lunascape","Maxthon",{label:"Microsoft Edge",pattern:"(?:Edge|Edg|EdgA|EdgiOS)"},"Midori","Nook Browser","PaleMoon","PhantomJS","Raven","Rekonq","RockMelt",{label:"Samsung Internet",pattern:"SamsungBrowser"},"SeaMonkey",{label:"Silk",pattern:"(?:Cloud9|Silk-Accelerated)"},"Sleipnir","SlimBrowser",{label:"SRWare Iron",pattern:"Iron"},"Sunrise","Swiftfox","Vivaldi","Waterfox","WebPositive",{label:"Yandex Browser",pattern:"YaBrowser"},{label:"UC Browser",pattern:"UCBrowser"},"Opera Mini",{label:"Opera Mini",pattern:"OPiOS"},"Opera",{label:"Opera",pattern:"OPR"},"Chromium","Chrome",{label:"Chrome",pattern:"(?:HeadlessChrome)"},{label:"Chrome Mobile",pattern:"(?:CriOS|CrMo)"},{label:"Firefox",pattern:"(?:Firefox|Minefield)"},{label:"Firefox for iOS",pattern:"FxiOS"},{label:"IE",pattern:"IEMobile"},{label:"IE",pattern:"MSIE"},"Safari"]);var A=getProduct([{label:"BlackBerry",pattern:"BB10"},"BlackBerry",{label:"Galaxy S",pattern:"GT-I9000"},{label:"Galaxy S2",pattern:"GT-I9100"},{label:"Galaxy S3",pattern:"GT-I9300"},{label:"Galaxy S4",pattern:"GT-I9500"},{label:"Galaxy S5",pattern:"SM-G900"},{label:"Galaxy S6",pattern:"SM-G920"},{label:"Galaxy S6 Edge",pattern:"SM-G925"},{label:"Galaxy S7",pattern:"SM-G930"},{label:"Galaxy S7 Edge",pattern:"SM-G935"},"Google TV","Lumia","iPad","iPod","iPhone","Kindle",{label:"Kindle Fire",pattern:"(?:Cloud9|Silk-Accelerated)"},"Nexus","Nook","PlayBook","PlayStation Vita","PlayStation","TouchPad","Transformer",{label:"Wii U",pattern:"WiiU"},"Wii","Xbox One",{label:"Xbox 360",pattern:"Xbox"},"Xoom"]);var I=getManufacturer({Apple:{iPad:1,iPhone:1,iPod:1},Alcatel:{},Archos:{},Amazon:{Kindle:1,"Kindle Fire":1},Asus:{Transformer:1},"Barnes & Noble":{Nook:1},BlackBerry:{PlayBook:1},Google:{"Google TV":1,Nexus:1},HP:{TouchPad:1},HTC:{},Huawei:{},Lenovo:{},LG:{},Microsoft:{Xbox:1,"Xbox One":1},Motorola:{Xoom:1},Nintendo:{"Wii U":1,Wii:1},Nokia:{Lumia:1},Oppo:{},Samsung:{"Galaxy S":1,"Galaxy S2":1,"Galaxy S3":1,"Galaxy S4":1},Sony:{PlayStation:1,"PlayStation Vita":1},Xiaomi:{Mi:1,Redmi:1}});var T=getOS(["Windows Phone","KaiOS","Android","CentOS",{label:"Chrome OS",pattern:"CrOS"},"Debian",{label:"DragonFly BSD",pattern:"DragonFly"},"Fedora","FreeBSD","Gentoo","Haiku","Kubuntu","Linux Mint","OpenBSD","Red Hat","SuSE","Ubuntu","Xubuntu","Cygwin","Symbian OS","hpwOS","webOS ","webOS","Tablet OS","Tizen","Linux","Mac OS X","Macintosh","Mac","Windows 98;","Windows "]);function getLayout(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getManufacturer(i){return reduce(i,(function(i,t,r){return i||(t[A]||t[/^[a-z]+(?: +[a-z]+\b)*/i.exec(A)]||RegExp("\\b"+qualify(r)+"(?:\\b|\\w*\\d)","i").exec(e))&&r}))}function getName(i){return reduce(i,(function(i,t){return i||RegExp("\\b"+(t.pattern||qualify(t))+"\\b","i").exec(e)&&(t.label||t)}))}function getOS(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+"(?:/[\\d.]+|[ \\w.]*)","i").exec(e))){i=cleanupOS(i,r,t.label||t)}return i}))}function getProduct(i){return reduce(i,(function(i,t){var r=t.pattern||qualify(t);if(!i&&(i=RegExp("\\b"+r+" *\\d+[.\\w_]*","i").exec(e)||RegExp("\\b"+r+" *\\w+-[\\w]*","i").exec(e)||RegExp("\\b"+r+"(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)","i").exec(e))){if((i=String(t.label&&!RegExp(r,"i").test(t.label)?t.label:i).split("/"))[1]&&!/[\d.]+/.test(i[0])){i[0]+=" "+i[1]}t=t.label||t;i=format(i[0].replace(RegExp(r,"i"),t).replace(RegExp("; *(?:"+t+"[_-])?","i")," ").replace(RegExp("("+t+")[-_.]?(\\w)","i"),"$1 $2"))}return i}))}function getVersion(i){return reduce(i,(function(i,t){return i||(RegExp(t+"(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)","i").exec(e)||0)[1]||null}))}function toStringPlatform(){return this.description||""}_&&(_=[_]);if(/\bAndroid\b/.test(T)&&!A&&(M=/\bAndroid[^;]*;(.*?)(?:Build|\) AppleWebKit)\b/i.exec(e))){A=trim(M[1]).replace(/^[a-z]{2}-[a-z]{2};\s*/i,"")||null}if(I&&!A){A=getProduct([I])}else if(I&&A){A=A.replace(RegExp("^("+qualify(I)+")[-_.\\s]","i"),I+" ").replace(RegExp("^("+qualify(I)+")[-_.]?(\\w)","i"),I+" $2")}if(M=/\bGoogle TV\b/.exec(A)){A=M[0]}if(/\bSimulator\b/i.test(e)){A=(A?A+" ":"")+"Simulator"}if(R=="Opera Mini"&&/\bOPiOS\b/.test(e)){P.push("running in Turbo/Uncompressed mode")}if(R=="IE"&&/\blike iPhone OS\b/.test(e)){M=parse(e.replace(/like iPhone OS/,""));I=M.manufacturer;A=M.product}else if(/^iP/.test(A)){R||(R="Safari");T="iOS"+((M=/ OS ([\d_]+)/i.exec(e))?" "+M[1].replace(/_/g,"."):"")}else if(R=="Konqueror"&&/^Linux\b/i.test(T)){T="Kubuntu"}else if(I&&I!="Google"&&(/Chrome/.test(R)&&!/\bMobile Safari\b/i.test(e)||/\bVita\b/.test(A))||/\bAndroid\b/.test(T)&&/^Chrome/.test(R)&&/\bVersion\//i.test(e)){R="Android Browser";T=/\bAndroid\b/.test(T)?T:"Android"}else if(R=="Silk"){if(!/\bMobi/i.test(e)){T="Android";P.unshift("desktop mode")}if(/Accelerated *= *true/i.test(e)){P.unshift("accelerated")}}else if(R=="UC Browser"&&/\bUCWEB\b/.test(e)){P.push("speed mode")}else if(R=="PaleMoon"&&(M=/\bFirefox\/([\d.]+)\b/.exec(e))){P.push("identifying as Firefox "+M[1])}else if(R=="Firefox"&&(M=/\b(Mobile|Tablet|TV)\b/i.exec(e))){T||(T="Firefox OS");A||(A=M[1])}else if(!R||(M=!/\bMinefield\b/i.test(e)&&/\b(?:Firefox|Safari)\b/.exec(R))){if(R&&!A&&/[\/,]|^[^(]+?\)/.test(e.slice(e.indexOf(M+"/")+8))){R=null}if((M=A||I||T)&&(A||I||/\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(T))){R=/[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(T)?T:M)+" Browser"}}else if(R=="Electron"&&(M=(/\bChrome\/([\d.]+)\b/.exec(e)||0)[1])){P.push("Chromium "+M)}if(!B){B=getVersion(["(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|HeadlessChrome|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$)|UCBrowser|YaBrowser)","Version",qualify(R),"(?:Firefox|Minefield|NetFront)"])}if(M=_=="iCab"&&parseFloat(B)>3&&"WebKit"||/\bOpera\b/.test(R)&&(/\bOPR\b/.test(e)?"Blink":"Presto")||/\b(?:Midori|Nook|Safari)\b/i.test(e)&&!/^(?:Trident|EdgeHTML)$/.test(_)&&"WebKit"||!_&&/\bMSIE\b/i.test(e)&&(T=="Mac OS"?"Tasman":"Trident")||_=="WebKit"&&/\bPlayStation\b(?! Vita\b)/i.test(R)&&"NetFront"){_=[M]}if(R=="IE"&&(M=(/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(e)||0)[1])){R+=" Mobile";T="Windows Phone "+(/\+$/.test(M)?M:M+".x");P.unshift("desktop mode")}else if(/\bWPDesktop\b/i.test(e)){R="IE Mobile";T="Windows Phone 8.x";P.unshift("desktop mode");B||(B=(/\brv:([\d.]+)/.exec(e)||0)[1])}else if(R!="IE"&&_=="Trident"&&(M=/\brv:([\d.]+)/.exec(e))){if(R){P.push("identifying as "+R+(B?" "+B:""))}R="IE";B=M[1]}if(k){if(isHostType(i,"global")){if(m){M=m.lang.System;E=M.getProperty("os.arch");T=T||M.getProperty("os.name")+" "+M.getProperty("os.version")}if(g){try{B=i.require("ringo/engine").version.join(".");R="RingoJS"}catch(e){if((M=i.system)&&M.global.system==i.system){R="Narwhal";T||(T=M[0].os||null)}}if(!R){R="Rhino"}}else if(typeof i.process=="object"&&!i.process.browser&&(M=i.process)){if(typeof M.versions=="object"){if(typeof M.versions.electron=="string"){P.push("Node "+M.versions.node);R="Electron";B=M.versions.electron}else if(typeof M.versions.nw=="string"){P.push("Chromium "+B,"Node "+M.versions.node);R="NW.js";B=M.versions.nw}}if(!R){R="Node.js";E=M.arch;T=M.platform;B=/[\d.]+/.exec(M.version);B=B?B[0]:null}}}else if(getClassOf(M=i.runtime)==p){R="Adobe AIR";T=M.flash.system.Capabilities.os}else if(getClassOf(M=i.phantom)==x){R="PhantomJS";B=(M=M.version||null)&&M.major+"."+M.minor+"."+M.patch}else if(typeof O.documentMode=="number"&&(M=/\bTrident\/(\d+)/i.exec(e))){B=[B,O.documentMode];if((M=+M[1]+4)!=B[1]){P.push("IE "+B[1]+" mode");_&&(_[1]="");B[1]=M}B=R=="IE"?String(B[1].toFixed(1)):B[0]}else if(typeof O.documentMode=="number"&&/^(?:Chrome|Firefox)\b/.test(R)){P.push("masking as "+R+" "+B);R="IE";B="11.0";_=["Trident"];T="Windows"}T=T&&format(T)}if(B&&(M=/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(B)||/(?:alpha|beta)(?: ?\d)?/i.exec(e+";"+(k&&n.appMinorVersion))||/\bMinefield\b/i.test(e)&&"a")){C=/b/i.test(M)?"beta":"alpha";B=B.replace(RegExp(M+"\\+?$"),"")+(C=="beta"?v:h)+(/\d+\+?/.exec(M)||"")}if(R=="Fennec"||R=="Firefox"&&/\b(?:Android|Firefox OS|KaiOS)\b/.test(T)){R="Firefox Mobile"}else if(R=="Maxthon"&&B){B=B.replace(/\.[\d.]+/,".x")}else if(/\bXbox\b/i.test(A)){if(A=="Xbox 360"){T=null}if(A=="Xbox 360"&&/\bIEMobile\b/.test(e)){P.unshift("mobile mode")}}else if((/^(?:Chrome|IE|Opera)$/.test(R)||R&&!A&&!/Browser|Mobi/.test(R))&&(T=="Windows CE"||/Mobi/i.test(e))){R+=" Mobile"}else if(R=="IE"&&k){try{if(i.external===null){P.unshift("platform preview")}}catch(e){P.unshift("embedded")}}else if((/\bBlackBerry\b/.test(A)||/\bBB10\b/.test(e))&&(M=(RegExp(A.replace(/ +/g," *")+"/([.\\d]+)","i").exec(e)||0)[1]||B)){M=[M,/BB10/.test(e)];T=(M[1]?(A=null,I="BlackBerry"):"Device Software")+" "+M[0];B=null}else if(this!=forOwn&&A!="Wii"&&(k&&y||/Opera/.test(R)&&/\b(?:MSIE|Firefox)\b/i.test(e)||R=="Firefox"&&/\bOS X (?:\d+\.){2,}/.test(T)||R=="IE"&&(T&&!/^Win/.test(T)&&B>5.5||/\bWindows XP\b/.test(T)&&B>8||B==8&&!/\bTrident\b/.test(e)))&&!f.test(M=parse.call(forOwn,e.replace(f,"")+";"))&&M.name){M="ing as "+M.name+((M=M.version)?" "+M:"");if(f.test(R)){if(/\bIE\b/.test(M)&&T=="Mac OS"){T=null}M="identify"+M}else{M="mask"+M;if(w){R=format(w.replace(/([a-z])([A-Z])/g,"$1 $2"))}else{R="Opera"}if(/\bIE\b/.test(M)){T=null}if(!k){B=null}}_=["Presto"];P.push(M)}if(M=(/\bAppleWebKit\/([\d.]+\+?)/i.exec(e)||0)[1]){M=[parseFloat(M.replace(/\.(\d)$/,".0$1")),M];if(R=="Safari"&&M[1].slice(-1)=="+"){R="WebKit Nightly";C="alpha";B=M[1].slice(0,-1)}else if(B==M[1]||B==(M[2]=(/\bSafari\/([\d.]+\+?)/i.exec(e)||0)[1])){B=null}M[1]=(/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(e)||0)[1];if(M[0]==537.36&&M[2]==537.36&&parseFloat(M[1])>=28&&_=="WebKit"){_=["Blink"]}if(!k||!s&&!M[1]){_&&(_[1]="like Safari");M=(M=M[0],M<400?1:M<500?2:M<526?3:M<533?4:M<534?"4+":M<535?5:M<537?6:M<538?7:M<601?8:M<602?9:M<604?10:M<606?11:M<608?12:"12")}else{_&&(_[1]="like Chrome");M=M[1]||(M=M[0],M<530?1:M<532?2:M<532.05?3:M<533?4:M<534.03?5:M<534.07?6:M<534.1?7:M<534.13?8:M<534.16?9:M<534.24?10:M<534.3?11:M<535.01?12:M<535.02?"13+":M<535.07?15:M<535.11?16:M<535.19?17:M<536.05?18:M<536.1?19:M<537.01?20:M<537.11?"21+":M<537.13?23:M<537.18?24:M<537.24?25:M<537.36?26:_!="Blink"?"27":"28")}_&&(_[1]+=" "+(M+=typeof M=="number"?".x":/[.+]/.test(M)?"":"+"));if(R=="Safari"&&(!B||parseInt(B)>45)){B=M}else if(R=="Chrome"&&/\bHeadlessChrome/i.test(e)){P.unshift("headless")}}if(R=="Opera"&&(M=/\bzbov|zvav$/.exec(T))){R+=" ";P.unshift("desktop mode");if(M=="zvav"){R+="Mini";B=null}else{R+="Mobile"}T=T.replace(RegExp(" *"+M+"$"),"")}else if(R=="Safari"&&/\bChrome\b/.exec(_&&_[1])){P.unshift("desktop mode");R="Chrome Mobile";B=null;if(/\bOS X\b/.test(T)){I="Apple";T="iOS 4.3+"}else{T=null}}else if(/\bSRWare Iron\b/.test(R)&&!B){B=getVersion("Chrome")}if(B&&B.indexOf(M=/[\d.]+$/.exec(T))==0&&e.indexOf("/"+M+"-")>-1){T=trim(T.replace(M,""))}if(T&&T.indexOf(R)!=-1&&!RegExp(R+" OS").test(T)){T=T.replace(RegExp(" *"+qualify(R)+" *"),"")}if(_&&!/\b(?:Avant|Nook)\b/.test(R)&&(/Browser|Lunascape|Maxthon/.test(R)||R!="Safari"&&/^iOS/.test(T)&&/\bSafari\b/.test(_[1])||/^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(R)&&_[1])){(M=_[_.length-1])&&P.push(M)}if(P.length){P=["("+P.join("; ")+")"]}if(I&&A&&A.indexOf(I)<0){P.push("on "+I)}if(A){P.push((/^on /.test(P[P.length-1])?"":"on ")+A)}if(T){M=/ ([\d.+]+)$/.exec(T);W=M&&T.charAt(T.length-M[0].length-1)=="/";T={architecture:32,family:M&&!W?T.replace(M[0],""):T,version:M?M[1]:null,toString:function(){var e=this.version;return this.family+(e&&!W?" "+e:"")+(this.architecture==64?" 64-bit":"")}}}if((M=/\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(E))&&!/\bi686\b/i.test(E)){if(T){T.architecture=64;T.family=T.family.replace(RegExp(" *"+M),"")}if(R&&(/\bWOW64\b/i.test(e)||k&&/\w(?:86|32)$/.test(n.cpuClass||n.platform)&&!/\bWin64; x64\b/i.test(e))){P.unshift("32-bit")}}else if(T&&/^OS X/.test(T.family)&&R=="Chrome"&&parseFloat(B)>=39){T.architecture=64}e||(e=null);var F={};F.description=e;F.layout=_&&_[0];F.manufacturer=I;F.name=R;F.prerelease=C;F.product=A;F.ua=e;F.version=R&&B;F.os=T||{architecture:null,family:null,version:null,toString:function(){return"null"}};F.parse=parse;F.toString=toStringPlatform;if(F.version){P.unshift(B)}if(F.name){P.unshift(R)}if(T&&R&&!(T==String(T).split(" ")[0]&&(T==R.split(" ")[0]||A))){P.push(A?"("+T+")":"on "+T)}if(P.length){F.description=P.join(" ")}return F}var d=parse();if(typeof define=="function"&&typeof define.amd=="object"&&define.amd){r.platform=d;define((function(){return d}))}else if(n&&o){forOwn(d,(function(e,i){n[i]=e}))}else{r.platform=d}}).call(this)}};var i={};function __nccwpck_require__(t){var r=i[t];if(r!==undefined){return r.exports}var a=i[t]={id:t,loaded:false,exports:{}};var n=true;try{e[t].call(a.exports,a,a.exports,__nccwpck_require__);n=false}finally{if(n)delete i[t]}a.loaded=true;return a.exports}(()=>{__nccwpck_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(797);module.exports=t})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js b/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js index 65bc0548742798..95ad6c4b0aaf7b 100644 --- a/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js +++ b/packages/next-swc/crates/next-core/js/src/compiled/source-map/index.js @@ -1 +1 @@ -(()=>{var e={237:(e,n)=>{class ArraySet{constructor(){this._array=[];this._set=new Map}static fromArray(e,n){const t=new ArraySet;for(let r=0,o=e.length;r<o;r++){t.add(e[r],n)}return t}size(){return this._set.size}add(e,n){const t=this.has(e);const r=this._array.length;if(!t||n){this._array.push(e)}if(!t){this._set.set(e,r)}}has(e){return this._set.has(e)}indexOf(e){const n=this._set.get(e);if(n>=0){return n}throw new Error('"'+e+'" is not in the set.')}at(e){if(e>=0&&e<this._array.length){return this._array[e]}throw new Error("No element indexed by "+e)}toArray(){return this._array.slice()}}n.I=ArraySet},717:(e,n,t)=>{const r=t(244);const o=5;const s=1<<o;const i=s-1;const l=s;function toVLQSigned(e){return e<0?(-e<<1)+1:(e<<1)+0}function fromVLQSigned(e){const n=(e&1)===1;const t=e>>1;return n?-t:t}n.encode=function base64VLQ_encode(e){let n="";let t;let s=toVLQSigned(e);do{t=s&i;s>>>=o;if(s>0){t|=l}n+=r.encode(t)}while(s>0);return n}},244:(e,n)=>{const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");n.encode=function(e){if(0<=e&&e<t.length){return t[e]}throw new TypeError("Must be between 0 and 63: "+e)}},797:(e,n)=>{n.GREATEST_LOWER_BOUND=1;n.LEAST_UPPER_BOUND=2;function recursiveSearch(e,t,r,o,s,i){const l=Math.floor((t-e)/2)+e;const a=s(r,o[l],true);if(a===0){return l}else if(a>0){if(t-l>1){return recursiveSearch(l,t,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return t<o.length?t:-1}return l}if(l-e>1){return recursiveSearch(e,l,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return l}return e<0?-1:e}n.search=function search(e,t,r,o){if(t.length===0){return-1}let s=recursiveSearch(-1,t.length,e,t,r,o||n.GREATEST_LOWER_BOUND);if(s<0){return-1}while(s-1>=0){if(r(t[s],t[s-1],true)!==0){break}--s}return s}},167:(e,n,t)=>{const r=t(521);function generatedPositionAfter(e,n){const t=e.generatedLine;const o=n.generatedLine;const s=e.generatedColumn;const i=n.generatedColumn;return o>t||o==t&&i>=s||r.compareByGeneratedPositionsInflated(e,n)<=0}class MappingList{constructor(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}unsortedForEach(e,n){this._array.forEach(e,n)}add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}}toArray(){if(!this._sorted){this._array.sort(r.compareByGeneratedPositionsInflated);this._sorted=true}return this._array}}n.H=MappingList},520:(e,n,t)=>{"use strict";const r=t(147);const o=t(17);e.exports=function readWasm(){return new Promise(((e,n)=>{const o=t.ab+"mappings.wasm";r.readFile(t.ab+"mappings.wasm",null,((t,r)=>{if(t){n(t);return}e(r.buffer)}))}))};e.exports.initialize=e=>{console.debug("SourceMapConsumer.initialize is a no-op when running in node.js")}},494:(e,n,t)=>{var r;const o=t(521);const s=t(797);const i=t(237).I;const l=t(717);const a=t(520);const u=t(734);const c=Symbol("smcInternal");class SourceMapConsumer{constructor(e,n){if(e==c){return Promise.resolve(this)}return _factory(e,n)}static initialize(e){a.initialize(e["lib/mappings.wasm"])}static fromSourceMap(e,n){return _factoryBSM(e,n)}static async with(e,n,t){const r=await new SourceMapConsumer(e,n);try{return await t(r)}finally{r.destroy()}}eachMapping(e,n,t){throw new Error("Subclasses must implement eachMapping")}allGeneratedPositionsFor(e){throw new Error("Subclasses must implement allGeneratedPositionsFor")}destroy(){throw new Error("Subclasses must implement destroy")}}SourceMapConsumer.prototype._version=3;SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;n.SourceMapConsumer=SourceMapConsumer;class BasicSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const l=o.getArg(r,"sources").map(String);const a=o.getArg(r,"names",[]);const c=o.getArg(r,"sourceRoot",null);const g=o.getArg(r,"sourcesContent",null);const f=o.getArg(r,"mappings");const h=o.getArg(r,"file",null);if(s!=t._version){throw new Error("Unsupported version: "+s)}t._sourceLookupCache=new Map;t._names=i.fromArray(a.map(String),true);t._sources=i.fromArray(l,true);t._absoluteSources=i.fromArray(t._sources.toArray().map((function(e){return o.computeSourceURL(c,e,n)})),true);t.sourceRoot=c;t.sourcesContent=g;t._mappings=f;t._sourceMapURL=n;t.file=h;t._computedColumnSpans=false;t._mappingsPtr=0;t._wasm=null;return u().then((e=>{t._wasm=e;return t}))}))}_findSourceIndex(e){const n=this._sourceLookupCache.get(e);if(typeof n==="number"){return n}const t=o.computeSourceURL(null,e,this._sourceMapURL);if(this._absoluteSources.has(t)){const n=this._absoluteSources.indexOf(t);this._sourceLookupCache.set(e,n);return n}const r=o.computeSourceURL(this.sourceRoot,e,this._sourceMapURL);if(this._absoluteSources.has(r)){const n=this._absoluteSources.indexOf(r);this._sourceLookupCache.set(e,n);return n}return-1}static fromSourceMap(e,n){return new BasicSourceMapConsumer(e.toString())}get sources(){return this._absoluteSources.toArray()}_getMappingsPtr(){if(this._mappingsPtr===0){this._parseMappings()}return this._mappingsPtr}_parseMappings(){const e=this._mappings;const n=e.length;const t=this._wasm.exports.allocate_mappings(n);const r=new Uint8Array(this._wasm.exports.memory.buffer,t,n);for(let t=0;t<n;t++){r[t]=e.charCodeAt(t)}const o=this._wasm.exports.parse_mappings(t);if(!o){const e=this._wasm.exports.get_last_error();let n=`Error parsing mappings (code ${e}): `;switch(e){case 1:n+="the mappings contained a negative line, column, source index, or name index";break;case 2:n+="the mappings contained a number larger than 2**32";break;case 3:n+="reached EOF while in the middle of parsing a VLQ";break;case 4:n+="invalid base 64 character while parsing a VLQ";break;default:n+="unknown error code";break}throw new Error(n)}this._mappingsPtr=o}eachMapping(e,n,t){const r=n||null;const o=t||SourceMapConsumer.GENERATED_ORDER;this._wasm.withMappingCallback((n=>{if(n.source!==null){n.source=this._absoluteSources.at(n.source);if(n.name!==null){n.name=this._names.at(n.name)}}if(this._computedColumnSpans&&n.lastGeneratedColumn===null){n.lastGeneratedColumn=Infinity}e.call(r,n)}),(()=>{switch(o){case SourceMapConsumer.GENERATED_ORDER:this._wasm.exports.by_generated_location(this._getMappingsPtr());break;case SourceMapConsumer.ORIGINAL_ORDER:this._wasm.exports.by_original_location(this._getMappingsPtr());break;default:throw new Error("Unknown order of iteration.")}}))}allGeneratedPositionsFor(e){let n=o.getArg(e,"source");const t=o.getArg(e,"line");const r=e.column||0;n=this._findSourceIndex(n);if(n<0){return[]}if(t<1){throw new Error("Line numbers must be >= 1")}if(r<0){throw new Error("Column numbers must be >= 0")}const s=[];this._wasm.withMappingCallback((e=>{let n=e.lastGeneratedColumn;if(this._computedColumnSpans&&n===null){n=Infinity}s.push({line:e.generatedLine,column:e.generatedColumn,lastColumn:n})}),(()=>{this._wasm.exports.all_generated_locations_for(this._getMappingsPtr(),n,t-1,"column"in e,r)}));return s}destroy(){if(this._mappingsPtr!==0){this._wasm.exports.free_mappings(this._mappingsPtr);this._mappingsPtr=0}}computeColumnSpans(){if(this._computedColumnSpans){return}this._wasm.exports.compute_column_spans(this._getMappingsPtr());this._computedColumnSpans=true}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};if(n.generatedLine<1){throw new Error("Line numbers must be >= 1")}if(n.generatedColumn<0){throw new Error("Column numbers must be >= 0")}let t=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(t==null){t=SourceMapConsumer.GREATEST_LOWER_BOUND}let r;this._wasm.withMappingCallback((e=>r=e),(()=>{this._wasm.exports.original_location_for(this._getMappingsPtr(),n.generatedLine-1,n.generatedColumn,t)}));if(r){if(r.generatedLine===n.generatedLine){let e=o.getArg(r,"source",null);if(e!==null){e=this._absoluteSources.at(e)}let n=o.getArg(r,"name",null);if(n!==null){n=this._names.at(n)}return{source:e,line:o.getArg(r,"originalLine",null),column:o.getArg(r,"originalColumn",null),name:n}}}return{source:null,line:null,column:null,name:null}}hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))}sourceContentFor(e,n){if(!this.sourcesContent){return null}const t=this._findSourceIndex(e);if(t>=0){return this.sourcesContent[t]}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}generatedPositionFor(e){let n=o.getArg(e,"source");n=this._findSourceIndex(n);if(n<0){return{line:null,column:null,lastColumn:null}}const t={source:n,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};if(t.originalLine<1){throw new Error("Line numbers must be >= 1")}if(t.originalColumn<0){throw new Error("Column numbers must be >= 0")}let r=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(r==null){r=SourceMapConsumer.GREATEST_LOWER_BOUND}let s;this._wasm.withMappingCallback((e=>s=e),(()=>{this._wasm.exports.generated_location_for(this._getMappingsPtr(),t.source,t.originalLine-1,t.originalColumn,r)}));if(s){if(s.source===t.source){let e=s.lastGeneratedColumn;if(this._computedColumnSpans&&e===null){e=Infinity}return{line:o.getArg(s,"generatedLine",null),column:o.getArg(s,"generatedColumn",null),lastColumn:e}}}return{line:null,column:null,lastColumn:null}}}BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;r=BasicSourceMapConsumer;class IndexedSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const i=o.getArg(r,"sections");if(s!=t._version){throw new Error("Unsupported version: "+s)}let l={line:-1,column:0};return Promise.all(i.map((e=>{if(e.url){throw new Error("Support for url field in sections not implemented.")}const t=o.getArg(e,"offset");const r=o.getArg(t,"line");const s=o.getArg(t,"column");if(r<l.line||r===l.line&&s<l.column){throw new Error("Section offsets must be ordered and non-overlapping.")}l=t;const i=new SourceMapConsumer(o.getArg(e,"map"),n);return i.then((e=>({generatedOffset:{generatedLine:r+1,generatedColumn:s+1},consumer:e})))}))).then((e=>{t._sections=e;return t}))}))}get sources(){const e=[];for(let n=0;n<this._sections.length;n++){for(let t=0;t<this._sections[n].consumer.sources.length;t++){e.push(this._sections[n].consumer.sources[t])}}return e}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};const t=s.search(n,this._sections,(function(e,n){const t=e.generatedLine-n.generatedOffset.generatedLine;if(t){return t}return e.generatedColumn-n.generatedOffset.generatedColumn}));const r=this._sections[t];if(!r){return{source:null,line:null,column:null,name:null}}return r.consumer.originalPositionFor({line:n.generatedLine-(r.generatedOffset.generatedLine-1),column:n.generatedColumn-(r.generatedOffset.generatedLine===n.generatedLine?r.generatedOffset.generatedColumn-1:0),bias:e.bias})}hasContentsOfAllSources(){return this._sections.every((function(e){return e.consumer.hasContentsOfAllSources()}))}sourceContentFor(e,n){for(let n=0;n<this._sections.length;n++){const t=this._sections[n];const r=t.consumer.sourceContentFor(e,true);if(r){return r}}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}_findSectionIndex(e){for(let n=0;n<this._sections.length;n++){const{consumer:t}=this._sections[n];if(t._findSourceIndex(e)!==-1){return n}}return-1}generatedPositionFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;const s=t&&t.consumer.generatedPositionFor(e);if(s&&s.line!==null){const e=t.generatedOffset.generatedLine-1;const n=t.generatedOffset.generatedColumn-1;if(s.line===1){s.column+=n;if(typeof s.lastColumn==="number"){s.lastColumn+=n}}if(s.lastColumn===Infinity&&r&&s.line===r.generatedOffset.generatedLine){s.lastColumn=r.generatedOffset.generatedColumn-2}s.line+=e;return s}return{line:null,column:null,lastColumn:null}}allGeneratedPositionsFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;if(!t)return[];return t.consumer.allGeneratedPositionsFor(e).map((e=>{const n=t.generatedOffset.generatedLine-1;const o=t.generatedOffset.generatedColumn-1;if(e.line===1){e.column+=o;if(typeof e.lastColumn==="number"){e.lastColumn+=o}}if(e.lastColumn===Infinity&&r&&e.line===r.generatedOffset.generatedLine){e.lastColumn=r.generatedOffset.generatedColumn-2}e.line+=n;return e}))}eachMapping(e,n,t){this._sections.forEach(((r,o)=>{const s=o+1<this._sections.length?this._sections[o+1]:null;const{generatedOffset:i}=r;const l=i.generatedLine-1;const a=i.generatedColumn-1;r.consumer.eachMapping((function(n){if(n.generatedLine===1){n.generatedColumn+=a;if(typeof n.lastGeneratedColumn==="number"){n.lastGeneratedColumn+=a}}if(n.lastGeneratedColumn===Infinity&&s&&n.generatedLine===s.generatedOffset.generatedLine){n.lastGeneratedColumn=s.generatedOffset.generatedColumn-2}n.generatedLine+=l;e.call(this,n)}),n,t)}))}computeColumnSpans(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.computeColumnSpans()}}destroy(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.destroy()}}}r=IndexedSourceMapConsumer;function _factory(e,n){let t=e;if(typeof e==="string"){t=o.parseSourceMapInput(e)}const r=t.sections!=null?new IndexedSourceMapConsumer(t,n):new BasicSourceMapConsumer(t,n);return Promise.resolve(r)}function _factoryBSM(e,n){return BasicSourceMapConsumer.fromSourceMap(e,n)}},491:(e,n,t)=>{const r=t(717);const o=t(521);const s=t(237).I;const i=t(167).H;class SourceMapGenerator{constructor(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new s;this._names=new s;this._mappings=new i;this._sourcesContents=null}static fromSourceMap(e){const n=e.sourceRoot;const t=new SourceMapGenerator({file:e.file,sourceRoot:n});e.eachMapping((function(e){const r={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){r.source=e.source;if(n!=null){r.source=o.relative(n,r.source)}r.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){r.name=e.name}}t.addMapping(r)}));e.sources.forEach((function(r){let s=r;if(n!==null){s=o.relative(n,r)}if(!t._sources.has(s)){t._sources.add(s)}const i=e.sourceContentFor(r);if(i!=null){t.setSourceContent(r,i)}}));return t}addMapping(e){const n=o.getArg(e,"generated");const t=o.getArg(e,"original",null);let r=o.getArg(e,"source",null);let s=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(n,t,r,s)}if(r!=null){r=String(r);if(!this._sources.has(r)){this._sources.add(r)}}if(s!=null){s=String(s);if(!this._names.has(s)){this._names.add(s)}}this._mappings.add({generatedLine:n.line,generatedColumn:n.column,originalLine:t!=null&&t.line,originalColumn:t!=null&&t.column,source:r,name:s})}setSourceContent(e,n){let t=e;if(this._sourceRoot!=null){t=o.relative(this._sourceRoot,t)}if(n!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(t)]=n}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(t)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}}applySourceMap(e,n,t){let r=n;if(n==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}r=e.file}const i=this._sourceRoot;if(i!=null){r=o.relative(i,r)}const l=this._mappings.toArray().length>0?new s:this._sources;const a=new s;this._mappings.unsortedForEach((function(n){if(n.source===r&&n.originalLine!=null){const r=e.originalPositionFor({line:n.originalLine,column:n.originalColumn});if(r.source!=null){n.source=r.source;if(t!=null){n.source=o.join(t,n.source)}if(i!=null){n.source=o.relative(i,n.source)}n.originalLine=r.line;n.originalColumn=r.column;if(r.name!=null){n.name=r.name}}}const s=n.source;if(s!=null&&!l.has(s)){l.add(s)}const u=n.name;if(u!=null&&!a.has(u)){a.add(u)}}),this);this._sources=l;this._names=a;e.sources.forEach((function(n){const r=e.sourceContentFor(n);if(r!=null){if(t!=null){n=o.join(t,n)}if(i!=null){n=o.relative(i,n)}this.setSourceContent(n,r)}}),this)}_validateMapping(e,n,t,r){if(n&&typeof n.line!=="number"&&typeof n.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!n&&!t&&!r){}else if(e&&"line"in e&&"column"in e&&n&&"line"in n&&"column"in n&&e.line>0&&e.column>=0&&n.line>0&&n.column>=0&&t){}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:t,original:n,name:r}))}}_serializeMappings(){let e=0;let n=1;let t=0;let s=0;let i=0;let l=0;let a="";let u;let c;let g;let f;const h=this._mappings.toArray();for(let p=0,m=h.length;p<m;p++){c=h[p];u="";if(c.generatedLine!==n){e=0;while(c.generatedLine!==n){u+=";";n++}}else if(p>0){if(!o.compareByGeneratedPositionsInflated(c,h[p-1])){continue}u+=","}u+=r.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);u+=r.encode(f-l);l=f;u+=r.encode(c.originalLine-1-s);s=c.originalLine-1;u+=r.encode(c.originalColumn-t);t=c.originalColumn;if(c.name!=null){g=this._names.indexOf(c.name);u+=r.encode(g-i);i=g}}a+=u}return a}_generateSourcesContent(e,n){return e.map((function(e){if(!this._sourcesContents){return null}if(n!=null){e=o.relative(n,e)}const t=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,t)?this._sourcesContents[t]:null}),this)}toJSON(){const e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e}toString(){return JSON.stringify(this.toJSON())}}SourceMapGenerator.prototype._version=3;n.SourceMapGenerator=SourceMapGenerator},664:(e,n,t)=>{const r=t(491).SourceMapGenerator;const o=t(521);const s=/(\r?\n)/;const i=10;const l="$$$isSourceNode$$$";class SourceNode{constructor(e,n,t,r,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=n==null?null:n;this.source=t==null?null:t;this.name=o==null?null:o;this[l]=true;if(r!=null)this.add(r)}static fromStringWithSourceMap(e,n,t){const r=new SourceNode;const i=e.split(s);let l=0;const shiftNextLine=function(){const e=getNextLine();const n=getNextLine()||"";return e+n;function getNextLine(){return l<i.length?i[l++]:undefined}};let a=1,u=0;let c=null;let g;n.eachMapping((function(e){if(c!==null){if(a<e.generatedLine){addMappingWithCode(c,shiftNextLine());a++;u=0}else{g=i[l]||"";const n=g.substr(0,e.generatedColumn-u);i[l]=g.substr(e.generatedColumn-u);u=e.generatedColumn;addMappingWithCode(c,n);c=e;return}}while(a<e.generatedLine){r.add(shiftNextLine());a++}if(u<e.generatedColumn){g=i[l]||"";r.add(g.substr(0,e.generatedColumn));i[l]=g.substr(e.generatedColumn);u=e.generatedColumn}c=e}),this);if(l<i.length){if(c){addMappingWithCode(c,shiftNextLine())}r.add(i.splice(l).join(""))}n.sources.forEach((function(e){const s=n.sourceContentFor(e);if(s!=null){if(t!=null){e=o.join(t,e)}r.setSourceContent(e,s)}}));return r;function addMappingWithCode(e,n){if(e===null||e.source===undefined){r.add(n)}else{const s=t?o.join(t,e.source):e.source;r.add(new SourceNode(e.originalLine,e.originalColumn,s,n,e.name))}}}add(e){if(Array.isArray(e)){e.forEach((function(e){this.add(e)}),this)}else if(e[l]||typeof e==="string"){if(e){this.children.push(e)}}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}prepend(e){if(Array.isArray(e)){for(let n=e.length-1;n>=0;n--){this.prepend(e[n])}}else if(e[l]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}walk(e){let n;for(let t=0,r=this.children.length;t<r;t++){n=this.children[t];if(n[l]){n.walk(e)}else if(n!==""){e(n,{source:this.source,line:this.line,column:this.column,name:this.name})}}}join(e){let n;let t;const r=this.children.length;if(r>0){n=[];for(t=0;t<r-1;t++){n.push(this.children[t]);n.push(e)}n.push(this.children[t]);this.children=n}return this}replaceRight(e,n){const t=this.children[this.children.length-1];if(t[l]){t.replaceRight(e,n)}else if(typeof t==="string"){this.children[this.children.length-1]=t.replace(e,n)}else{this.children.push("".replace(e,n))}return this}setSourceContent(e,n){this.sourceContents[o.toSetString(e)]=n}walkSourceContents(e){for(let n=0,t=this.children.length;n<t;n++){if(this.children[n][l]){this.children[n].walkSourceContents(e)}}const n=Object.keys(this.sourceContents);for(let t=0,r=n.length;t<r;t++){e(o.fromSetString(n[t]),this.sourceContents[n[t]])}}toString(){let e="";this.walk((function(n){e+=n}));return e}toStringWithSourceMap(e){const n={code:"",line:1,column:0};const t=new r(e);let o=false;let s=null;let l=null;let a=null;let u=null;this.walk((function(e,r){n.code+=e;if(r.source!==null&&r.line!==null&&r.column!==null){if(s!==r.source||l!==r.line||a!==r.column||u!==r.name){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}s=r.source;l=r.line;a=r.column;u=r.name;o=true}else if(o){t.addMapping({generated:{line:n.line,column:n.column}});s=null;o=false}for(let l=0,a=e.length;l<a;l++){if(e.charCodeAt(l)===i){n.line++;n.column=0;if(l+1===a){s=null;o=false}else if(o){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}}else{n.column++}}}));this.walkSourceContents((function(e,n){t.setSourceContent(e,n)}));return{code:n.code,map:t}}}n.SourceNode=SourceNode},834:(e,n,t)=>{"use strict";e.exports=typeof URL==="function"?URL:t(310).URL},521:(e,n,t)=>{const r=t(834);function getArg(e,n,t){if(n in e){return e[n]}else if(arguments.length===3){return t}throw new Error('"'+n+'" is a required argument.')}n.getArg=getArg;const o=function(){const e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}n.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}n.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}const n=e.length;if(n<9){return false}if(e.charCodeAt(n-1)!==95||e.charCodeAt(n-2)!==95||e.charCodeAt(n-3)!==111||e.charCodeAt(n-4)!==116||e.charCodeAt(n-5)!==111||e.charCodeAt(n-6)!==114||e.charCodeAt(n-7)!==112||e.charCodeAt(n-8)!==95||e.charCodeAt(n-9)!==95){return false}for(let t=n-10;t>=0;t--){if(e.charCodeAt(t)!==36){return false}}return true}function strcmp(e,n){if(e===n){return 0}if(e===null){return 1}if(n===null){return-1}if(e>n){return 1}return-1}function compareByGeneratedPositionsInflated(e,n){let t=e.generatedLine-n.generatedLine;if(t!==0){return t}t=e.generatedColumn-n.generatedColumn;if(t!==0){return t}t=strcmp(e.source,n.source);if(t!==0){return t}t=e.originalLine-n.originalLine;if(t!==0){return t}t=e.originalColumn-n.originalColumn;if(t!==0){return t}return strcmp(e.name,n.name)}n.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}n.parseSourceMapInput=parseSourceMapInput;const s="http:";const i=`${s}//host`;function createSafeHandler(e){return n=>{const t=getURLType(n);const o=buildSafeBase(n);const l=new r(n,o);e(l);const a=l.toString();if(t==="absolute"){return a}else if(t==="scheme-relative"){return a.slice(s.length)}else if(t==="path-absolute"){return a.slice(i.length)}return computeRelativeURL(o,a)}}function withBase(e,n){return new r(e,n).toString()}function buildUniqueSegment(e,n){let t=0;do{const r=e+t++;if(n.indexOf(r)===-1)return r}while(true)}function buildSafeBase(e){const n=e.split("..").length-1;const t=buildUniqueSegment("p",e);let r=`${i}/`;for(let e=0;e<n;e++){r+=`${t}/`}return r}const l=/^[A-Za-z0-9\+\-\.]+:/;function getURLType(e){if(e[0]==="/"){if(e[1]==="/")return"scheme-relative";return"path-absolute"}return l.test(e)?"absolute":"path-relative"}function computeRelativeURL(e,n){if(typeof e==="string")e=new r(e);if(typeof n==="string")n=new r(n);const t=n.pathname.split("/");const o=e.pathname.split("/");if(o.length>0&&!o[o.length-1]){o.pop()}while(t.length>0&&o.length>0&&t[0]===o[0]){t.shift();o.shift()}const s=o.map((()=>"..")).concat(t).join("/");return s+n.search+n.hash}const a=createSafeHandler((e=>{e.pathname=e.pathname.replace(/\/?$/,"/")}));const u=createSafeHandler((e=>{e.href=new r(".",e.toString()).toString()}));const c=createSafeHandler((e=>{}));n.normalize=c;function join(e,n){const t=getURLType(n);const r=getURLType(e);e=a(e);if(t==="absolute"){return withBase(n,undefined)}if(r==="absolute"){return withBase(n,e)}if(t==="scheme-relative"){return c(n)}if(r==="scheme-relative"){return withBase(n,withBase(e,i)).slice(s.length)}if(t==="path-absolute"){return c(n)}if(r==="path-absolute"){return withBase(n,withBase(e,i)).slice(i.length)}const o=buildSafeBase(n+e);const l=withBase(n,withBase(e,o));return computeRelativeURL(o,l)}n.join=join;function relative(e,n){const t=relativeIfPossible(e,n);return typeof t==="string"?t:c(n)}n.relative=relative;function relativeIfPossible(e,n){const t=getURLType(e);if(t!==getURLType(n)){return null}const o=buildSafeBase(e+n);const s=new r(e,o);const i=new r(n,o);try{new r("",i.toString())}catch(e){return null}if(i.protocol!==s.protocol||i.user!==s.user||i.password!==s.password||i.hostname!==s.hostname||i.port!==s.port){return null}return computeRelativeURL(s,i)}function computeSourceURL(e,n,t){if(e&&getURLType(n)==="path-absolute"){n=n.replace(/^\//,"")}let r=c(n||"");if(e)r=join(e,r);if(t)r=join(u(t),r);return r}n.computeSourceURL=computeSourceURL},734:(e,n,t)=>{const r=t(520);function Mapping(){this.generatedLine=0;this.generatedColumn=0;this.lastGeneratedColumn=null;this.source=null;this.originalLine=null;this.originalColumn=null;this.name=null}let o=null;e.exports=function wasm(){if(o){return o}const e=[];o=r().then((n=>WebAssembly.instantiate(n,{env:{mapping_callback(n,t,r,o,s,i,l,a,u,c){const g=new Mapping;g.generatedLine=n+1;g.generatedColumn=t;if(r){g.lastGeneratedColumn=o-1}if(s){g.source=i;g.originalLine=l+1;g.originalColumn=a;if(u){g.name=c}}e[e.length-1](g)},start_all_generated_locations_for(){console.time("all_generated_locations_for")},end_all_generated_locations_for(){console.timeEnd("all_generated_locations_for")},start_compute_column_spans(){console.time("compute_column_spans")},end_compute_column_spans(){console.timeEnd("compute_column_spans")},start_generated_location_for(){console.time("generated_location_for")},end_generated_location_for(){console.timeEnd("generated_location_for")},start_original_location_for(){console.time("original_location_for")},end_original_location_for(){console.timeEnd("original_location_for")},start_parse_mappings(){console.time("parse_mappings")},end_parse_mappings(){console.timeEnd("parse_mappings")},start_sort_by_generated_location(){console.time("sort_by_generated_location")},end_sort_by_generated_location(){console.timeEnd("sort_by_generated_location")},start_sort_by_original_location(){console.time("sort_by_original_location")},end_sort_by_original_location(){console.timeEnd("sort_by_original_location")}}}))).then((n=>({exports:n.instance.exports,withMappingCallback:(n,t)=>{e.push(n);try{t()}finally{e.pop()}}}))).then(null,(e=>{o=null;throw e}));return o}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")},310:e=>{"use strict";e.exports=require("url")}};var n={};function __nccwpck_require__(t){var r=n[t];if(r!==undefined){return r.exports}var o=n[t]={exports:{}};var s=true;try{e[t](o,o.exports,__nccwpck_require__);s=false}finally{if(s)delete n[t]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t={};(()=>{var e=t;e.SourceMapGenerator=__nccwpck_require__(491).SourceMapGenerator;e.SourceMapConsumer=__nccwpck_require__(494).SourceMapConsumer;e.SourceNode=__nccwpck_require__(664).SourceNode})();module.exports=t})(); \ No newline at end of file +(()=>{var e={313:(e,n)=>{class ArraySet{constructor(){this._array=[];this._set=new Map}static fromArray(e,n){const t=new ArraySet;for(let r=0,o=e.length;r<o;r++){t.add(e[r],n)}return t}size(){return this._set.size}add(e,n){const t=this.has(e);const r=this._array.length;if(!t||n){this._array.push(e)}if(!t){this._set.set(e,r)}}has(e){return this._set.has(e)}indexOf(e){const n=this._set.get(e);if(n>=0){return n}throw new Error('"'+e+'" is not in the set.')}at(e){if(e>=0&&e<this._array.length){return this._array[e]}throw new Error("No element indexed by "+e)}toArray(){return this._array.slice()}}n.I=ArraySet},296:(e,n,t)=>{const r=t(612);const o=5;const s=1<<o;const i=s-1;const l=s;function toVLQSigned(e){return e<0?(-e<<1)+1:(e<<1)+0}function fromVLQSigned(e){const n=(e&1)===1;const t=e>>1;return n?-t:t}n.encode=function base64VLQ_encode(e){let n="";let t;let s=toVLQSigned(e);do{t=s&i;s>>>=o;if(s>0){t|=l}n+=r.encode(t)}while(s>0);return n}},612:(e,n)=>{const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");n.encode=function(e){if(0<=e&&e<t.length){return t[e]}throw new TypeError("Must be between 0 and 63: "+e)}},217:(e,n)=>{n.GREATEST_LOWER_BOUND=1;n.LEAST_UPPER_BOUND=2;function recursiveSearch(e,t,r,o,s,i){const l=Math.floor((t-e)/2)+e;const a=s(r,o[l],true);if(a===0){return l}else if(a>0){if(t-l>1){return recursiveSearch(l,t,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return t<o.length?t:-1}return l}if(l-e>1){return recursiveSearch(e,l,r,o,s,i)}if(i==n.LEAST_UPPER_BOUND){return l}return e<0?-1:e}n.search=function search(e,t,r,o){if(t.length===0){return-1}let s=recursiveSearch(-1,t.length,e,t,r,o||n.GREATEST_LOWER_BOUND);if(s<0){return-1}while(s-1>=0){if(r(t[s],t[s-1],true)!==0){break}--s}return s}},627:(e,n,t)=>{const r=t(67);function generatedPositionAfter(e,n){const t=e.generatedLine;const o=n.generatedLine;const s=e.generatedColumn;const i=n.generatedColumn;return o>t||o==t&&i>=s||r.compareByGeneratedPositionsInflated(e,n)<=0}class MappingList{constructor(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}unsortedForEach(e,n){this._array.forEach(e,n)}add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}}toArray(){if(!this._sorted){this._array.sort(r.compareByGeneratedPositionsInflated);this._sorted=true}return this._array}}n.H=MappingList},153:(e,n,t)=>{"use strict";const r=t(147);const o=t(17);e.exports=function readWasm(){return new Promise(((e,n)=>{const o=t.ab+"mappings.wasm";r.readFile(t.ab+"mappings.wasm",null,((t,r)=>{if(t){n(t);return}e(r.buffer)}))}))};e.exports.initialize=e=>{console.debug("SourceMapConsumer.initialize is a no-op when running in node.js")}},316:(e,n,t)=>{var r;const o=t(67);const s=t(217);const i=t(313).I;const l=t(296);const a=t(153);const u=t(482);const c=Symbol("smcInternal");class SourceMapConsumer{constructor(e,n){if(e==c){return Promise.resolve(this)}return _factory(e,n)}static initialize(e){a.initialize(e["lib/mappings.wasm"])}static fromSourceMap(e,n){return _factoryBSM(e,n)}static async with(e,n,t){const r=await new SourceMapConsumer(e,n);try{return await t(r)}finally{r.destroy()}}eachMapping(e,n,t){throw new Error("Subclasses must implement eachMapping")}allGeneratedPositionsFor(e){throw new Error("Subclasses must implement allGeneratedPositionsFor")}destroy(){throw new Error("Subclasses must implement destroy")}}SourceMapConsumer.prototype._version=3;SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;n.SourceMapConsumer=SourceMapConsumer;class BasicSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const l=o.getArg(r,"sources").map(String);const a=o.getArg(r,"names",[]);const c=o.getArg(r,"sourceRoot",null);const g=o.getArg(r,"sourcesContent",null);const f=o.getArg(r,"mappings");const h=o.getArg(r,"file",null);if(s!=t._version){throw new Error("Unsupported version: "+s)}t._sourceLookupCache=new Map;t._names=i.fromArray(a.map(String),true);t._sources=i.fromArray(l,true);t._absoluteSources=i.fromArray(t._sources.toArray().map((function(e){return o.computeSourceURL(c,e,n)})),true);t.sourceRoot=c;t.sourcesContent=g;t._mappings=f;t._sourceMapURL=n;t.file=h;t._computedColumnSpans=false;t._mappingsPtr=0;t._wasm=null;return u().then((e=>{t._wasm=e;return t}))}))}_findSourceIndex(e){const n=this._sourceLookupCache.get(e);if(typeof n==="number"){return n}const t=o.computeSourceURL(null,e,this._sourceMapURL);if(this._absoluteSources.has(t)){const n=this._absoluteSources.indexOf(t);this._sourceLookupCache.set(e,n);return n}const r=o.computeSourceURL(this.sourceRoot,e,this._sourceMapURL);if(this._absoluteSources.has(r)){const n=this._absoluteSources.indexOf(r);this._sourceLookupCache.set(e,n);return n}return-1}static fromSourceMap(e,n){return new BasicSourceMapConsumer(e.toString())}get sources(){return this._absoluteSources.toArray()}_getMappingsPtr(){if(this._mappingsPtr===0){this._parseMappings()}return this._mappingsPtr}_parseMappings(){const e=this._mappings;const n=e.length;const t=this._wasm.exports.allocate_mappings(n);const r=new Uint8Array(this._wasm.exports.memory.buffer,t,n);for(let t=0;t<n;t++){r[t]=e.charCodeAt(t)}const o=this._wasm.exports.parse_mappings(t);if(!o){const e=this._wasm.exports.get_last_error();let n=`Error parsing mappings (code ${e}): `;switch(e){case 1:n+="the mappings contained a negative line, column, source index, or name index";break;case 2:n+="the mappings contained a number larger than 2**32";break;case 3:n+="reached EOF while in the middle of parsing a VLQ";break;case 4:n+="invalid base 64 character while parsing a VLQ";break;default:n+="unknown error code";break}throw new Error(n)}this._mappingsPtr=o}eachMapping(e,n,t){const r=n||null;const o=t||SourceMapConsumer.GENERATED_ORDER;this._wasm.withMappingCallback((n=>{if(n.source!==null){n.source=this._absoluteSources.at(n.source);if(n.name!==null){n.name=this._names.at(n.name)}}if(this._computedColumnSpans&&n.lastGeneratedColumn===null){n.lastGeneratedColumn=Infinity}e.call(r,n)}),(()=>{switch(o){case SourceMapConsumer.GENERATED_ORDER:this._wasm.exports.by_generated_location(this._getMappingsPtr());break;case SourceMapConsumer.ORIGINAL_ORDER:this._wasm.exports.by_original_location(this._getMappingsPtr());break;default:throw new Error("Unknown order of iteration.")}}))}allGeneratedPositionsFor(e){let n=o.getArg(e,"source");const t=o.getArg(e,"line");const r=e.column||0;n=this._findSourceIndex(n);if(n<0){return[]}if(t<1){throw new Error("Line numbers must be >= 1")}if(r<0){throw new Error("Column numbers must be >= 0")}const s=[];this._wasm.withMappingCallback((e=>{let n=e.lastGeneratedColumn;if(this._computedColumnSpans&&n===null){n=Infinity}s.push({line:e.generatedLine,column:e.generatedColumn,lastColumn:n})}),(()=>{this._wasm.exports.all_generated_locations_for(this._getMappingsPtr(),n,t-1,"column"in e,r)}));return s}destroy(){if(this._mappingsPtr!==0){this._wasm.exports.free_mappings(this._mappingsPtr);this._mappingsPtr=0}}computeColumnSpans(){if(this._computedColumnSpans){return}this._wasm.exports.compute_column_spans(this._getMappingsPtr());this._computedColumnSpans=true}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};if(n.generatedLine<1){throw new Error("Line numbers must be >= 1")}if(n.generatedColumn<0){throw new Error("Column numbers must be >= 0")}let t=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(t==null){t=SourceMapConsumer.GREATEST_LOWER_BOUND}let r;this._wasm.withMappingCallback((e=>r=e),(()=>{this._wasm.exports.original_location_for(this._getMappingsPtr(),n.generatedLine-1,n.generatedColumn,t)}));if(r){if(r.generatedLine===n.generatedLine){let e=o.getArg(r,"source",null);if(e!==null){e=this._absoluteSources.at(e)}let n=o.getArg(r,"name",null);if(n!==null){n=this._names.at(n)}return{source:e,line:o.getArg(r,"originalLine",null),column:o.getArg(r,"originalColumn",null),name:n}}}return{source:null,line:null,column:null,name:null}}hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))}sourceContentFor(e,n){if(!this.sourcesContent){return null}const t=this._findSourceIndex(e);if(t>=0){return this.sourcesContent[t]}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}generatedPositionFor(e){let n=o.getArg(e,"source");n=this._findSourceIndex(n);if(n<0){return{line:null,column:null,lastColumn:null}}const t={source:n,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};if(t.originalLine<1){throw new Error("Line numbers must be >= 1")}if(t.originalColumn<0){throw new Error("Column numbers must be >= 0")}let r=o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND);if(r==null){r=SourceMapConsumer.GREATEST_LOWER_BOUND}let s;this._wasm.withMappingCallback((e=>s=e),(()=>{this._wasm.exports.generated_location_for(this._getMappingsPtr(),t.source,t.originalLine-1,t.originalColumn,r)}));if(s){if(s.source===t.source){let e=s.lastGeneratedColumn;if(this._computedColumnSpans&&e===null){e=Infinity}return{line:o.getArg(s,"generatedLine",null),column:o.getArg(s,"generatedColumn",null),lastColumn:e}}}return{line:null,column:null,lastColumn:null}}}BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;r=BasicSourceMapConsumer;class IndexedSourceMapConsumer extends SourceMapConsumer{constructor(e,n){return super(c).then((t=>{let r=e;if(typeof e==="string"){r=o.parseSourceMapInput(e)}const s=o.getArg(r,"version");const i=o.getArg(r,"sections");if(s!=t._version){throw new Error("Unsupported version: "+s)}let l={line:-1,column:0};return Promise.all(i.map((e=>{if(e.url){throw new Error("Support for url field in sections not implemented.")}const t=o.getArg(e,"offset");const r=o.getArg(t,"line");const s=o.getArg(t,"column");if(r<l.line||r===l.line&&s<l.column){throw new Error("Section offsets must be ordered and non-overlapping.")}l=t;const i=new SourceMapConsumer(o.getArg(e,"map"),n);return i.then((e=>({generatedOffset:{generatedLine:r+1,generatedColumn:s+1},consumer:e})))}))).then((e=>{t._sections=e;return t}))}))}get sources(){const e=[];for(let n=0;n<this._sections.length;n++){for(let t=0;t<this._sections[n].consumer.sources.length;t++){e.push(this._sections[n].consumer.sources[t])}}return e}originalPositionFor(e){const n={generatedLine:o.getArg(e,"line"),generatedColumn:o.getArg(e,"column")};const t=s.search(n,this._sections,(function(e,n){const t=e.generatedLine-n.generatedOffset.generatedLine;if(t){return t}return e.generatedColumn-n.generatedOffset.generatedColumn}));const r=this._sections[t];if(!r){return{source:null,line:null,column:null,name:null}}return r.consumer.originalPositionFor({line:n.generatedLine-(r.generatedOffset.generatedLine-1),column:n.generatedColumn-(r.generatedOffset.generatedLine===n.generatedLine?r.generatedOffset.generatedColumn-1:0),bias:e.bias})}hasContentsOfAllSources(){return this._sections.every((function(e){return e.consumer.hasContentsOfAllSources()}))}sourceContentFor(e,n){for(let n=0;n<this._sections.length;n++){const t=this._sections[n];const r=t.consumer.sourceContentFor(e,true);if(r){return r}}if(n){return null}throw new Error('"'+e+'" is not in the SourceMap.')}_findSectionIndex(e){for(let n=0;n<this._sections.length;n++){const{consumer:t}=this._sections[n];if(t._findSourceIndex(e)!==-1){return n}}return-1}generatedPositionFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;const s=t&&t.consumer.generatedPositionFor(e);if(s&&s.line!==null){const e=t.generatedOffset.generatedLine-1;const n=t.generatedOffset.generatedColumn-1;if(s.line===1){s.column+=n;if(typeof s.lastColumn==="number"){s.lastColumn+=n}}if(s.lastColumn===Infinity&&r&&s.line===r.generatedOffset.generatedLine){s.lastColumn=r.generatedOffset.generatedColumn-2}s.line+=e;return s}return{line:null,column:null,lastColumn:null}}allGeneratedPositionsFor(e){const n=this._findSectionIndex(o.getArg(e,"source"));const t=n>=0?this._sections[n]:null;const r=n>=0&&n+1<this._sections.length?this._sections[n+1]:null;if(!t)return[];return t.consumer.allGeneratedPositionsFor(e).map((e=>{const n=t.generatedOffset.generatedLine-1;const o=t.generatedOffset.generatedColumn-1;if(e.line===1){e.column+=o;if(typeof e.lastColumn==="number"){e.lastColumn+=o}}if(e.lastColumn===Infinity&&r&&e.line===r.generatedOffset.generatedLine){e.lastColumn=r.generatedOffset.generatedColumn-2}e.line+=n;return e}))}eachMapping(e,n,t){this._sections.forEach(((r,o)=>{const s=o+1<this._sections.length?this._sections[o+1]:null;const{generatedOffset:i}=r;const l=i.generatedLine-1;const a=i.generatedColumn-1;r.consumer.eachMapping((function(n){if(n.generatedLine===1){n.generatedColumn+=a;if(typeof n.lastGeneratedColumn==="number"){n.lastGeneratedColumn+=a}}if(n.lastGeneratedColumn===Infinity&&s&&n.generatedLine===s.generatedOffset.generatedLine){n.lastGeneratedColumn=s.generatedOffset.generatedColumn-2}n.generatedLine+=l;e.call(this,n)}),n,t)}))}computeColumnSpans(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.computeColumnSpans()}}destroy(){for(let e=0;e<this._sections.length;e++){this._sections[e].consumer.destroy()}}}r=IndexedSourceMapConsumer;function _factory(e,n){let t=e;if(typeof e==="string"){t=o.parseSourceMapInput(e)}const r=t.sections!=null?new IndexedSourceMapConsumer(t,n):new BasicSourceMapConsumer(t,n);return Promise.resolve(r)}function _factoryBSM(e,n){return BasicSourceMapConsumer.fromSourceMap(e,n)}},42:(e,n,t)=>{const r=t(296);const o=t(67);const s=t(313).I;const i=t(627).H;class SourceMapGenerator{constructor(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new s;this._names=new s;this._mappings=new i;this._sourcesContents=null}static fromSourceMap(e){const n=e.sourceRoot;const t=new SourceMapGenerator({file:e.file,sourceRoot:n});e.eachMapping((function(e){const r={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){r.source=e.source;if(n!=null){r.source=o.relative(n,r.source)}r.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){r.name=e.name}}t.addMapping(r)}));e.sources.forEach((function(r){let s=r;if(n!==null){s=o.relative(n,r)}if(!t._sources.has(s)){t._sources.add(s)}const i=e.sourceContentFor(r);if(i!=null){t.setSourceContent(r,i)}}));return t}addMapping(e){const n=o.getArg(e,"generated");const t=o.getArg(e,"original",null);let r=o.getArg(e,"source",null);let s=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(n,t,r,s)}if(r!=null){r=String(r);if(!this._sources.has(r)){this._sources.add(r)}}if(s!=null){s=String(s);if(!this._names.has(s)){this._names.add(s)}}this._mappings.add({generatedLine:n.line,generatedColumn:n.column,originalLine:t!=null&&t.line,originalColumn:t!=null&&t.column,source:r,name:s})}setSourceContent(e,n){let t=e;if(this._sourceRoot!=null){t=o.relative(this._sourceRoot,t)}if(n!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(t)]=n}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(t)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}}applySourceMap(e,n,t){let r=n;if(n==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}r=e.file}const i=this._sourceRoot;if(i!=null){r=o.relative(i,r)}const l=this._mappings.toArray().length>0?new s:this._sources;const a=new s;this._mappings.unsortedForEach((function(n){if(n.source===r&&n.originalLine!=null){const r=e.originalPositionFor({line:n.originalLine,column:n.originalColumn});if(r.source!=null){n.source=r.source;if(t!=null){n.source=o.join(t,n.source)}if(i!=null){n.source=o.relative(i,n.source)}n.originalLine=r.line;n.originalColumn=r.column;if(r.name!=null){n.name=r.name}}}const s=n.source;if(s!=null&&!l.has(s)){l.add(s)}const u=n.name;if(u!=null&&!a.has(u)){a.add(u)}}),this);this._sources=l;this._names=a;e.sources.forEach((function(n){const r=e.sourceContentFor(n);if(r!=null){if(t!=null){n=o.join(t,n)}if(i!=null){n=o.relative(i,n)}this.setSourceContent(n,r)}}),this)}_validateMapping(e,n,t,r){if(n&&typeof n.line!=="number"&&typeof n.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!n&&!t&&!r){}else if(e&&"line"in e&&"column"in e&&n&&"line"in n&&"column"in n&&e.line>0&&e.column>=0&&n.line>0&&n.column>=0&&t){}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:t,original:n,name:r}))}}_serializeMappings(){let e=0;let n=1;let t=0;let s=0;let i=0;let l=0;let a="";let u;let c;let g;let f;const h=this._mappings.toArray();for(let p=0,m=h.length;p<m;p++){c=h[p];u="";if(c.generatedLine!==n){e=0;while(c.generatedLine!==n){u+=";";n++}}else if(p>0){if(!o.compareByGeneratedPositionsInflated(c,h[p-1])){continue}u+=","}u+=r.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);u+=r.encode(f-l);l=f;u+=r.encode(c.originalLine-1-s);s=c.originalLine-1;u+=r.encode(c.originalColumn-t);t=c.originalColumn;if(c.name!=null){g=this._names.indexOf(c.name);u+=r.encode(g-i);i=g}}a+=u}return a}_generateSourcesContent(e,n){return e.map((function(e){if(!this._sourcesContents){return null}if(n!=null){e=o.relative(n,e)}const t=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,t)?this._sourcesContents[t]:null}),this)}toJSON(){const e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e}toString(){return JSON.stringify(this.toJSON())}}SourceMapGenerator.prototype._version=3;n.SourceMapGenerator=SourceMapGenerator},171:(e,n,t)=>{const r=t(42).SourceMapGenerator;const o=t(67);const s=/(\r?\n)/;const i=10;const l="$$$isSourceNode$$$";class SourceNode{constructor(e,n,t,r,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=n==null?null:n;this.source=t==null?null:t;this.name=o==null?null:o;this[l]=true;if(r!=null)this.add(r)}static fromStringWithSourceMap(e,n,t){const r=new SourceNode;const i=e.split(s);let l=0;const shiftNextLine=function(){const e=getNextLine();const n=getNextLine()||"";return e+n;function getNextLine(){return l<i.length?i[l++]:undefined}};let a=1,u=0;let c=null;let g;n.eachMapping((function(e){if(c!==null){if(a<e.generatedLine){addMappingWithCode(c,shiftNextLine());a++;u=0}else{g=i[l]||"";const n=g.substr(0,e.generatedColumn-u);i[l]=g.substr(e.generatedColumn-u);u=e.generatedColumn;addMappingWithCode(c,n);c=e;return}}while(a<e.generatedLine){r.add(shiftNextLine());a++}if(u<e.generatedColumn){g=i[l]||"";r.add(g.substr(0,e.generatedColumn));i[l]=g.substr(e.generatedColumn);u=e.generatedColumn}c=e}),this);if(l<i.length){if(c){addMappingWithCode(c,shiftNextLine())}r.add(i.splice(l).join(""))}n.sources.forEach((function(e){const s=n.sourceContentFor(e);if(s!=null){if(t!=null){e=o.join(t,e)}r.setSourceContent(e,s)}}));return r;function addMappingWithCode(e,n){if(e===null||e.source===undefined){r.add(n)}else{const s=t?o.join(t,e.source):e.source;r.add(new SourceNode(e.originalLine,e.originalColumn,s,n,e.name))}}}add(e){if(Array.isArray(e)){e.forEach((function(e){this.add(e)}),this)}else if(e[l]||typeof e==="string"){if(e){this.children.push(e)}}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}prepend(e){if(Array.isArray(e)){for(let n=e.length-1;n>=0;n--){this.prepend(e[n])}}else if(e[l]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this}walk(e){let n;for(let t=0,r=this.children.length;t<r;t++){n=this.children[t];if(n[l]){n.walk(e)}else if(n!==""){e(n,{source:this.source,line:this.line,column:this.column,name:this.name})}}}join(e){let n;let t;const r=this.children.length;if(r>0){n=[];for(t=0;t<r-1;t++){n.push(this.children[t]);n.push(e)}n.push(this.children[t]);this.children=n}return this}replaceRight(e,n){const t=this.children[this.children.length-1];if(t[l]){t.replaceRight(e,n)}else if(typeof t==="string"){this.children[this.children.length-1]=t.replace(e,n)}else{this.children.push("".replace(e,n))}return this}setSourceContent(e,n){this.sourceContents[o.toSetString(e)]=n}walkSourceContents(e){for(let n=0,t=this.children.length;n<t;n++){if(this.children[n][l]){this.children[n].walkSourceContents(e)}}const n=Object.keys(this.sourceContents);for(let t=0,r=n.length;t<r;t++){e(o.fromSetString(n[t]),this.sourceContents[n[t]])}}toString(){let e="";this.walk((function(n){e+=n}));return e}toStringWithSourceMap(e){const n={code:"",line:1,column:0};const t=new r(e);let o=false;let s=null;let l=null;let a=null;let u=null;this.walk((function(e,r){n.code+=e;if(r.source!==null&&r.line!==null&&r.column!==null){if(s!==r.source||l!==r.line||a!==r.column||u!==r.name){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}s=r.source;l=r.line;a=r.column;u=r.name;o=true}else if(o){t.addMapping({generated:{line:n.line,column:n.column}});s=null;o=false}for(let l=0,a=e.length;l<a;l++){if(e.charCodeAt(l)===i){n.line++;n.column=0;if(l+1===a){s=null;o=false}else if(o){t.addMapping({source:r.source,original:{line:r.line,column:r.column},generated:{line:n.line,column:n.column},name:r.name})}}else{n.column++}}}));this.walkSourceContents((function(e,n){t.setSourceContent(e,n)}));return{code:n.code,map:t}}}n.SourceNode=SourceNode},298:(e,n,t)=>{"use strict";e.exports=typeof URL==="function"?URL:t(310).URL},67:(e,n,t)=>{const r=t(298);function getArg(e,n,t){if(n in e){return e[n]}else if(arguments.length===3){return t}throw new Error('"'+n+'" is a required argument.')}n.getArg=getArg;const o=function(){const e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}n.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}n.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}const n=e.length;if(n<9){return false}if(e.charCodeAt(n-1)!==95||e.charCodeAt(n-2)!==95||e.charCodeAt(n-3)!==111||e.charCodeAt(n-4)!==116||e.charCodeAt(n-5)!==111||e.charCodeAt(n-6)!==114||e.charCodeAt(n-7)!==112||e.charCodeAt(n-8)!==95||e.charCodeAt(n-9)!==95){return false}for(let t=n-10;t>=0;t--){if(e.charCodeAt(t)!==36){return false}}return true}function strcmp(e,n){if(e===n){return 0}if(e===null){return 1}if(n===null){return-1}if(e>n){return 1}return-1}function compareByGeneratedPositionsInflated(e,n){let t=e.generatedLine-n.generatedLine;if(t!==0){return t}t=e.generatedColumn-n.generatedColumn;if(t!==0){return t}t=strcmp(e.source,n.source);if(t!==0){return t}t=e.originalLine-n.originalLine;if(t!==0){return t}t=e.originalColumn-n.originalColumn;if(t!==0){return t}return strcmp(e.name,n.name)}n.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}n.parseSourceMapInput=parseSourceMapInput;const s="http:";const i=`${s}//host`;function createSafeHandler(e){return n=>{const t=getURLType(n);const o=buildSafeBase(n);const l=new r(n,o);e(l);const a=l.toString();if(t==="absolute"){return a}else if(t==="scheme-relative"){return a.slice(s.length)}else if(t==="path-absolute"){return a.slice(i.length)}return computeRelativeURL(o,a)}}function withBase(e,n){return new r(e,n).toString()}function buildUniqueSegment(e,n){let t=0;do{const r=e+t++;if(n.indexOf(r)===-1)return r}while(true)}function buildSafeBase(e){const n=e.split("..").length-1;const t=buildUniqueSegment("p",e);let r=`${i}/`;for(let e=0;e<n;e++){r+=`${t}/`}return r}const l=/^[A-Za-z0-9\+\-\.]+:/;function getURLType(e){if(e[0]==="/"){if(e[1]==="/")return"scheme-relative";return"path-absolute"}return l.test(e)?"absolute":"path-relative"}function computeRelativeURL(e,n){if(typeof e==="string")e=new r(e);if(typeof n==="string")n=new r(n);const t=n.pathname.split("/");const o=e.pathname.split("/");if(o.length>0&&!o[o.length-1]){o.pop()}while(t.length>0&&o.length>0&&t[0]===o[0]){t.shift();o.shift()}const s=o.map((()=>"..")).concat(t).join("/");return s+n.search+n.hash}const a=createSafeHandler((e=>{e.pathname=e.pathname.replace(/\/?$/,"/")}));const u=createSafeHandler((e=>{e.href=new r(".",e.toString()).toString()}));const c=createSafeHandler((e=>{}));n.normalize=c;function join(e,n){const t=getURLType(n);const r=getURLType(e);e=a(e);if(t==="absolute"){return withBase(n,undefined)}if(r==="absolute"){return withBase(n,e)}if(t==="scheme-relative"){return c(n)}if(r==="scheme-relative"){return withBase(n,withBase(e,i)).slice(s.length)}if(t==="path-absolute"){return c(n)}if(r==="path-absolute"){return withBase(n,withBase(e,i)).slice(i.length)}const o=buildSafeBase(n+e);const l=withBase(n,withBase(e,o));return computeRelativeURL(o,l)}n.join=join;function relative(e,n){const t=relativeIfPossible(e,n);return typeof t==="string"?t:c(n)}n.relative=relative;function relativeIfPossible(e,n){const t=getURLType(e);if(t!==getURLType(n)){return null}const o=buildSafeBase(e+n);const s=new r(e,o);const i=new r(n,o);try{new r("",i.toString())}catch(e){return null}if(i.protocol!==s.protocol||i.user!==s.user||i.password!==s.password||i.hostname!==s.hostname||i.port!==s.port){return null}return computeRelativeURL(s,i)}function computeSourceURL(e,n,t){if(e&&getURLType(n)==="path-absolute"){n=n.replace(/^\//,"")}let r=c(n||"");if(e)r=join(e,r);if(t)r=join(u(t),r);return r}n.computeSourceURL=computeSourceURL},482:(e,n,t)=>{const r=t(153);function Mapping(){this.generatedLine=0;this.generatedColumn=0;this.lastGeneratedColumn=null;this.source=null;this.originalLine=null;this.originalColumn=null;this.name=null}let o=null;e.exports=function wasm(){if(o){return o}const e=[];o=r().then((n=>WebAssembly.instantiate(n,{env:{mapping_callback(n,t,r,o,s,i,l,a,u,c){const g=new Mapping;g.generatedLine=n+1;g.generatedColumn=t;if(r){g.lastGeneratedColumn=o-1}if(s){g.source=i;g.originalLine=l+1;g.originalColumn=a;if(u){g.name=c}}e[e.length-1](g)},start_all_generated_locations_for(){console.time("all_generated_locations_for")},end_all_generated_locations_for(){console.timeEnd("all_generated_locations_for")},start_compute_column_spans(){console.time("compute_column_spans")},end_compute_column_spans(){console.timeEnd("compute_column_spans")},start_generated_location_for(){console.time("generated_location_for")},end_generated_location_for(){console.timeEnd("generated_location_for")},start_original_location_for(){console.time("original_location_for")},end_original_location_for(){console.timeEnd("original_location_for")},start_parse_mappings(){console.time("parse_mappings")},end_parse_mappings(){console.timeEnd("parse_mappings")},start_sort_by_generated_location(){console.time("sort_by_generated_location")},end_sort_by_generated_location(){console.timeEnd("sort_by_generated_location")},start_sort_by_original_location(){console.time("sort_by_original_location")},end_sort_by_original_location(){console.timeEnd("sort_by_original_location")}}}))).then((n=>({exports:n.instance.exports,withMappingCallback:(n,t)=>{e.push(n);try{t()}finally{e.pop()}}}))).then(null,(e=>{o=null;throw e}));return o}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")},310:e=>{"use strict";e.exports=require("url")}};var n={};function __nccwpck_require__(t){var r=n[t];if(r!==undefined){return r.exports}var o=n[t]={exports:{}};var s=true;try{e[t](o,o.exports,__nccwpck_require__);s=false}finally{if(s)delete n[t]}return o.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var t={};(()=>{var e=t;e.SourceMapGenerator=__nccwpck_require__(42).SourceMapGenerator;e.SourceMapConsumer=__nccwpck_require__(316).SourceMapConsumer;e.SourceNode=__nccwpck_require__(171).SourceNode})();module.exports=t})(); \ No newline at end of file diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 5a01ba7972e736..4cffd63707a3b8 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -1,5 +1,3 @@ -import type { Ipc } from "@vercel/turbopack-next/internal/ipc"; - // Provided by the rust generate code type FileType = | "layout" @@ -21,6 +19,7 @@ declare global { const IPC: Ipc<unknown, unknown>; } +import type { Ipc } from "@vercel/turbopack-next/ipc/index"; import type { IncomingMessage, ServerResponse } from "node:http"; import type { FlightCSSManifest, diff --git a/packages/next-swc/crates/next-core/js/src/entry/config/next.js b/packages/next-swc/crates/next-core/js/src/entry/config/next.js new file mode 100644 index 00000000000000..ee75fb86e58658 --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/entry/config/next.js @@ -0,0 +1,9 @@ +const loadConfig = require("next/dist/server/config").default; +const { PHASE_DEVELOPMENT_SERVER } = require("next/dist/shared/lib/constants"); + +module.exports = (async () => { + const nextConfig = await loadConfig(PHASE_DEVELOPMENT_SERVER, process.cwd()); + nextConfig.rewrites = await nextConfig.rewrites?.(); + nextConfig.redirects = await nextConfig.redirects?.(); + return nextConfig; +})(); diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx index 0252012db15334..7dc4ca5d29e2d4 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-api.tsx @@ -1,5 +1,8 @@ -import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; +// IPC need to be the first import to allow it to catch errors happening during +// the other imports +import { IPC } from "@vercel/turbopack-next/ipc/index"; +import type { Ipc } from "@vercel/turbopack-next/ipc/index"; import type { ClientRequest, IncomingMessage, Server } from "node:http"; import http, { ServerResponse } from "node:http"; import type { AddressInfo, Socket } from "node:net"; diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index b1d06f3ba749fd..7eb9215a536ae7 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -1,3 +1,7 @@ +// IPC need to be the first import to allow it to catch errors happening during +// the other imports +import { IPC } from "@vercel/turbopack-next/ipc/index"; + import "next/dist/server/node-polyfill-fetch.js"; import "@vercel/turbopack-next/internal/shims"; @@ -8,7 +12,7 @@ import RenderResult from "next/dist/server/render-result"; import type { BuildManifest } from "next/dist/server/get-page-files"; import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; -import IPC, { Ipc } from "@vercel/turbopack-next/internal/ipc"; +import type { Ipc } from "@vercel/turbopack-next/ipc/index"; import type { RenderData } from "types/turbopack"; import type { ChunkGroup } from "types/next"; diff --git a/packages/next-swc/crates/next-core/js/src/internal/error.ts b/packages/next-swc/crates/next-core/js/src/internal/error.ts deleted file mode 100644 index 58b39117d2b344..00000000000000 --- a/packages/next-swc/crates/next-core/js/src/internal/error.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - parse as parseStackTrace, - StackFrame, -} from "@vercel/turbopack-next/compiled/stacktrace-parser"; - -export type StructuredError = { - name: string; - message: string; - stack: StackFrame[]; -}; - -export function structuredError(e: Error): StructuredError { - return { - name: e.name, - message: e.message, - stack: parseStackTrace(e.stack!), - }; -} diff --git a/packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts b/packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts new file mode 100644 index 00000000000000..7c8a8712c1899d --- /dev/null +++ b/packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts @@ -0,0 +1,44 @@ +import { IPC, Ipc } from "./index"; + +type IpcIncomingMessage = { + type: "evaluate"; + filepath: string; + arguments: string[]; +}; + +type IpcOutgoingMessage = { + type: "jsonValue"; + data: string; +}; + +const ipc = IPC as Ipc<IpcIncomingMessage, IpcOutgoingMessage>; + +(async () => { + while (true) { + const msg = await ipc.recv(); + + switch (msg.type) { + case "evaluate": { + const { execute } = eval("require")(msg.filepath); + if (typeof execute !== "function") { + console.error( + `Expected ${msg.filepath} to export a function named "execute"` + ); + process.exit(1); + } + const value = await execute.apply(null, msg.arguments); + await ipc.send({ + type: "jsonValue", + data: JSON.stringify(value), + }); + break; + } + default: { + console.error("unexpected message type", msg.type); + process.exit(1); + } + } + } +})().catch((err) => { + ipc.sendError(err); +}); diff --git a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts b/packages/next-swc/crates/next-core/js/src/ipc/index.ts similarity index 84% rename from packages/next-swc/crates/next-core/js/src/internal/ipc.ts rename to packages/next-swc/crates/next-core/js/src/ipc/index.ts index 4914d0b2be617f..ed92d08cacb133 100644 --- a/packages/next-swc/crates/next-core/js/src/internal/ipc.ts +++ b/packages/next-swc/crates/next-core/js/src/ipc/index.ts @@ -1,6 +1,23 @@ -import net from "node:net"; +import { createConnection } from "node:net"; -import { structuredError } from "@vercel/turbopack-next/internal/error"; +import { + StackFrame, + parse as parseStackTrace, +} from "@vercel/turbopack-next/compiled/stacktrace-parser"; + +export type StructuredError = { + name: string; + message: string; + stack: StackFrame[]; +}; + +export function structuredError(e: Error): StructuredError { + return { + name: e.name, + message: e.message, + stack: parseStackTrace(e.stack!), + }; +} type State = | { @@ -20,7 +37,7 @@ export type Ipc<TIncoming, TOutgoing> = { function createIpc<TIncoming, TOutgoing>( port: number ): Ipc<TIncoming, TOutgoing> { - const socket = net.createConnection(port, "127.0.0.1"); + const socket = createConnection(port, "127.0.0.1"); const packetQueue: Buffer[] = []; const recvPromiseResolveQueue: Array<(message: TIncoming) => void> = []; @@ -120,10 +137,8 @@ function createIpc<TIncoming, TOutgoing>( const PORT = process.argv[2]; -const IPC = createIpc<unknown, unknown>(parseInt(PORT, 10)); +export const IPC = createIpc<unknown, unknown>(parseInt(PORT, 10)); process.on("uncaughtException", (err) => { IPC.sendError(err); }); - -export default IPC; diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index c62c50f4a9a49d..d97c7b6102d8c7 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -4,10 +4,7 @@ use std::{ }; use anyhow::{anyhow, Result}; -use turbo_tasks::{ - primitives::{StringVc, StringsVc}, - TryJoinIterExt, Value, ValueToString, -}; +use turbo_tasks::{primitives::StringVc, TryJoinIterExt, Value, ValueToString}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{ rope::RopeBuilder, DirectoryContent, DirectoryEntry, File, FileContent, FileContentVc, @@ -62,6 +59,7 @@ use crate::{ server_to_client_transition::NextServerToClientTransition, ssr_client_module_transition::NextSSRClientModuleTransition, }, + next_config::NextConfigVc, next_server::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, @@ -100,13 +98,14 @@ async fn next_client_transition( app_dir: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, + next_config: NextConfigVc, ) -> Result<TransitionVc> { let ty = Value::new(ContextType::App { app_dir }); let client_chunking_context = get_client_chunking_context(project_root, server_root, ty); let client_environment = get_client_environment(browserslist_query); let client_module_options_context = get_client_module_options_context(project_root, client_environment, ty); - let client_runtime_entries = get_client_runtime_entries(project_root, env, ty); + let client_runtime_entries = get_client_runtime_entries(project_root, env, ty, next_config); let client_resolve_options_context = get_client_resolve_options_context(project_root, ty); Ok(NextClientTransition { @@ -127,7 +126,7 @@ fn next_ssr_client_module_transition( project_root: FileSystemPathVc, app_dir: FileSystemPathVc, process_env: ProcessEnvVc, - externals: StringsVc, + next_config: NextConfigVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppSSR { app_dir }); NextSSRClientModuleTransition { @@ -135,7 +134,7 @@ fn next_ssr_client_module_transition( ssr_resolve_options_context: get_server_resolve_options_context( project_root, ty, - externals, + next_config, ), ssr_environment: get_server_environment(ty, process_env), } @@ -149,12 +148,12 @@ fn next_layout_entry_transition( app_dir: FileSystemPathVc, server_root: FileSystemPathVc, process_env: ProcessEnvVc, - externals: StringsVc, + next_config: NextConfigVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppRSC { app_dir }); let rsc_environment = get_server_environment(ty, process_env); let rsc_resolve_options_context = - get_server_resolve_options_context(project_root, ty, externals); + get_server_resolve_options_context(project_root, ty, next_config); let rsc_module_options_context = get_server_module_options_context(ty); NextLayoutEntryTransition { @@ -175,14 +174,14 @@ fn app_context( env: ProcessEnvVc, browserslist_query: &str, ssr: bool, - externals: StringsVc, + next_config: NextConfigVc, ) -> AssetContextVc { let next_server_to_client_transition = NextServerToClientTransition { ssr }.cell().into(); let mut transitions = HashMap::new(); transitions.insert( "next-layout-entry".to_string(), - next_layout_entry_transition(project_root, app_dir, server_root, env, externals), + next_layout_entry_transition(project_root, app_dir, server_root, env, next_config), ); transitions.insert( "server-to-client".to_string(), @@ -190,7 +189,14 @@ fn app_context( ); transitions.insert( "next-client".to_string(), - next_client_transition(project_root, server_root, app_dir, env, browserslist_query), + next_client_transition( + project_root, + server_root, + app_dir, + env, + browserslist_query, + next_config, + ), ); transitions.insert( "next-client-chunks".to_string(), @@ -198,7 +204,7 @@ fn app_context( ); transitions.insert( "next-ssr-client-module".to_string(), - next_ssr_client_module_transition(project_root, app_dir, env, externals), + next_ssr_client_module_transition(project_root, app_dir, env, next_config), ); let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir }); @@ -206,7 +212,7 @@ fn app_context( TransitionsByNameVc::cell(transitions), get_server_environment(ssr_ty, env), get_server_module_options_context(ssr_ty), - get_server_resolve_options_context(project_root, ssr_ty, externals), + get_server_resolve_options_context(project_root, ssr_ty, next_config), ) .into() } @@ -215,17 +221,21 @@ fn app_context( /// Next.js app folder. #[turbo_tasks::function] pub async fn create_app_source( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, - externals: StringsVc, + next_config: NextConfigVc, ) -> Result<ContentSourceVc> { - let project_root = wrap_with_next_js_fs(project_root); + let project_path = wrap_with_next_js_fs(project_path); - let app = project_root.join("app"); - let src_app = project_root.join("src/app"); + if !*next_config.app_dir().await? { + return Ok(NoContentSourceVc::new().into()); + } + + let app = project_path.join("app"); + let src_app = project_path.join("src/app"); let app_dir = if *app.get_type().await? == FileSystemEntryType::Directory { app } else if *src_app.get_type().await? == FileSystemEntryType::Directory { @@ -235,33 +245,42 @@ pub async fn create_app_source( }; let context_ssr = app_context( - project_root, + project_path, server_root, app_dir, env, browserslist_query, true, - externals, + next_config, ); let context = app_context( - project_root, + project_path, server_root, app_dir, env, browserslist_query, false, - externals, + next_config, ); - let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_root, env_for_js(env, false)) - .as_ecmascript_chunk_placeable()]; + let server_runtime_entries = + vec![ + ProcessEnvAssetVc::new(project_path, env_for_js(env, false, next_config)) + .as_ecmascript_chunk_placeable(), + ]; - let fallback_page = get_fallback_page(project_root, server_root, env, browserslist_query); + let fallback_page = get_fallback_page( + project_path, + server_root, + env, + browserslist_query, + next_config, + ); Ok(create_app_source_for_directory( context_ssr, context, - project_root, + project_path, SpecificityVc::exact(), 0, app_dir, @@ -505,9 +524,10 @@ impl NodeEntry for AppRenderer { .into_iter() .try_join() .await?; - let mut result = RopeBuilder::from( - "import IPC, { Ipc } from \"@vercel/turbopack-next/internal/ipc\";\n", - ); + // IPC need to be the first import to allow it to catch errors happening during + // the other imports + let mut result = + RopeBuilder::from("import { IPC } from \"@vercel/turbopack-next/ipc/index\";\n"); for (_, imports) in segments.iter() { for (p, identifier, chunks_identifier) in imports.values() { diff --git a/packages/next-swc/crates/next-core/src/embed_js.rs b/packages/next-swc/crates/next-core/src/embed_js.rs index fa032943a3062b..6d0aea1380705f 100644 --- a/packages/next-swc/crates/next-core/src/embed_js.rs +++ b/packages/next-swc/crates/next-core/src/embed_js.rs @@ -2,6 +2,7 @@ use anyhow::Result; use turbo_tasks_fs::{ attach::AttachedFileSystemVc, embed_directory, FileContentVc, FileSystemPathVc, FileSystemVc, }; +use turbopack_core::{asset::AssetVc, virtual_asset::VirtualAssetVc}; pub const VIRTUAL_PACKAGE_NAME: &str = "@vercel/turbopack-next"; @@ -15,6 +16,11 @@ pub(crate) fn next_js_file(path: &str) -> FileContentVc { next_js_fs().root().join(path).read() } +#[turbo_tasks::function] +pub(crate) fn next_js_file_path(path: &str) -> FileSystemPathVc { + next_js_fs().root().join(path) +} + #[turbo_tasks::function] pub(crate) async fn attached_next_js_package_path( project_path: FileSystemPathVc, @@ -30,3 +36,8 @@ pub(crate) async fn wrap_with_next_js_fs( let fs = AttachedFileSystemVc::new(attached_path, next_js_fs()); Ok(fs.convert_path(project_path)) } + +#[turbo_tasks::function] +pub(crate) fn next_asset(asset_path: FileSystemPathVc, path: &str) -> AssetVc { + VirtualAssetVc::new(asset_path, next_js_file(path).into()).into() +} diff --git a/packages/next-swc/crates/next-core/src/env.rs b/packages/next-swc/crates/next-core/src/env.rs index 3991939a6b4087..e80bf12a623fec 100644 --- a/packages/next-swc/crates/next-core/src/env.rs +++ b/packages/next-swc/crates/next-core/src/env.rs @@ -1,12 +1,13 @@ use anyhow::Result; use indexmap::indexmap; -use serde_json::json; use turbo_tasks_env::{ CommandLineProcessEnvVc, CustomProcessEnvVc, EnvMapVc, FilterProcessEnvVc, ProcessEnvVc, }; use turbo_tasks_fs::FileSystemPathVc; use turbopack_env::{EmbeddableProcessEnvVc, TryDotenvProcessEnvVc}; +use crate::next_config::NextConfigVc; + /// Loads a series of dotenv files according to the precedence rules set by /// https://nextjs.org/docs/basic-features/environment-variables#environment-variable-load-order #[turbo_tasks::function] @@ -44,35 +45,27 @@ pub async fn load_env(project_path: FileSystemPathVc) -> Result<ProcessEnvVc> { /// For now, it also injects overridden values as if they were real JS code, eg /// an Object and not a String. #[turbo_tasks::function] -pub fn env_for_js(env: ProcessEnvVc, client: bool) -> ProcessEnvVc { +pub async fn env_for_js( + env: ProcessEnvVc, + client: bool, + next_config: NextConfigVc, +) -> Result<ProcessEnvVc> { let env = if client { FilterProcessEnvVc::new(env, "NEXT_PUBLIC_".to_string()).into() } else { env }; let env = EmbeddableProcessEnvVc::new(env).into(); + let image_config = next_config.image_config().await?; - CustomProcessEnvVc::new( + Ok(CustomProcessEnvVc::new( env, EnvMapVc::cell(indexmap! { // We need to overload the __NEXT_IMAGE_OPTS to override the default remotePatterns field. // This allows us to support loading from remote hostnames until we properly support reading // the next.config.js file. - "__NEXT_IMAGE_OPTS".to_string() => json!({ - "deviceSizes": [640, 750, 828, 1080, 1200, 1920, 2048, 3840], - "imageSizes": [16, 32, 48, 64, 96, 128, 256, 384], - "path": "/_next/image", - "loader": "default", - "domains": [], - "disableStaticImages": false, - "minimumCacheTTL": 60, - "formats": ["image/webp"], - "dangerouslyAllowSVG": false, - "contentSecurityPolicy": "script-src 'none'; frame-src 'none'; sandbox;", - "remotePatterns": [{ "hostname": "**" }], - "unoptimized": false, - }).to_string() + "__NEXT_IMAGE_OPTS".to_string() => serde_json::to_string(&image_config).unwrap() }), ) - .into() + .into()) } diff --git a/packages/next-swc/crates/next-core/src/fallback.rs b/packages/next-swc/crates/next-core/src/fallback.rs index 4af8404a145232..f35e266f1eac70 100644 --- a/packages/next-swc/crates/next-core/src/fallback.rs +++ b/packages/next-swc/crates/next-core/src/fallback.rs @@ -19,6 +19,7 @@ use crate::{ get_client_chunking_context, get_client_environment, get_client_module_options_context, get_client_resolve_options_context, get_client_runtime_entries, ContextType, }, + next_config::NextConfigVc, next_import_map::insert_next_shared_aliases, runtime::resolve_runtime_request, }; @@ -29,13 +30,14 @@ pub async fn get_fallback_page( dev_server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, + next_config: NextConfigVc, ) -> Result<DevHtmlAssetVc> { let ty = Value::new(ContextType::Fallback); let environment = get_client_environment(browserslist_query); let resolve_options_context = get_client_resolve_options_context(project_root, ty); let module_options_context = get_client_module_options_context(project_root, environment, ty); let chunking_context = get_client_chunking_context(project_root, dev_server_root, ty); - let entries = get_client_runtime_entries(project_root, env, ty); + let entries = get_client_runtime_entries(project_root, env, ty, next_config); let mut import_map = ImportMap::empty(); insert_next_shared_aliases(&mut import_map, project_root); diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 5385ab90eb859b..4de2f26674da2b 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -9,6 +9,7 @@ mod fallback; pub mod manifest; pub mod next_client; mod next_client_component; +pub mod next_config; mod next_font_google; pub mod next_image; mod next_import_map; diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 3c5aa00d3b231c..8a92fcf4a633f8 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -28,6 +28,7 @@ use crate::{ embed_js::attached_next_js_package_path, env::env_for_js, next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, + next_config::NextConfigVc, next_import_map::{ get_next_client_fallback_import_map, get_next_client_import_map, get_next_client_resolved_map, @@ -230,6 +231,7 @@ pub async fn get_client_runtime_entries( project_root: FileSystemPathVc, env: ProcessEnvVc, ty: Value<ContextType>, + next_config: NextConfigVc, ) -> Result<RuntimeEntriesVc> { let resolve_options_context = get_client_resolve_options_context(project_root, ty); let enable_react_refresh = @@ -238,7 +240,8 @@ pub async fn get_client_runtime_entries( .as_request(); let mut runtime_entries = vec![RuntimeEntry::Ecmascript( - ProcessEnvAssetVc::new(project_root, env_for_js(env, true)).into(), + //TODO + ProcessEnvAssetVc::new(project_root, env_for_js(env, true, next_config)).into(), ) .cell()]; diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs new file mode 100644 index 00000000000000..def2bc397b034f --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -0,0 +1,279 @@ +use std::collections::HashMap; + +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use turbo_tasks::{ + primitives::{BoolVc, StringsVc}, + trace::TraceRawVcs, + Value, +}; +use turbo_tasks_fs::{FileSystemEntryType, FileSystemPathVc}; +use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; +use turbopack_core::{ + asset::Asset, + environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, + reference_type::{EntryReferenceSubType, ReferenceType}, + source_asset::SourceAssetVc, +}; +use turbopack_ecmascript::{ + chunk::EcmascriptChunkPlaceablesVc, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, + EcmascriptModuleAssetVc, +}; +use turbopack_node::evaluate::{evaluate, JavaScriptValue}; + +use crate::{ + embed_js::next_asset, + next_server::{get_build_module_options_context, get_build_resolve_options_context}, +}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +#[turbo_tasks::value(transparent, serialization = "custom")] +pub struct NextConfig { + pub config_file: Option<String>, + pub config_file_name: String, + pub typescript: Option<TypeScriptConfig>, + pub react_strict_mode: Option<bool>, + pub experimental: Option<ExperimentalConfig>, + pub env: Option<HashMap<String, String>>, + pub compiler: Option<CompilerConfig>, + pub images: ImageConfig, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(rename_all = "camelCase")] +pub struct TypeScriptConfig { + pub ignore_build_errors: Option<bool>, + pub ts_config_path: Option<String>, +} + +#[turbo_tasks::value] +#[derive(Clone, Debug, Ord, PartialOrd)] +#[serde(rename_all = "camelCase")] +pub struct ImageConfig { + pub device_sizes: Vec<u16>, + pub image_sizes: Vec<u16>, + pub path: String, + pub loader: ImageLoader, + pub domains: Vec<String>, + pub disable_static_images: bool, + #[serde(rename(deserialize = "minimumCacheTTL"))] + pub minimum_cache_ttl: u32, + pub formats: Vec<ImageFormat>, + #[serde(rename(deserialize = "dangerouslyAllowSVG"))] + pub dangerously_allow_svg: bool, + pub content_security_policy: String, + pub remote_patterns: Vec<RemotePattern>, + pub unoptimized: bool, +} + +impl Default for ImageConfig { + fn default() -> Self { + // https://github.com/vercel/next.js/blob/327634eb/packages/next/shared/lib/image-config.ts#L100-L114 + Self { + device_sizes: vec![640, 750, 828, 1080, 1200, 1920, 2048, 3840], + image_sizes: vec![16, 32, 48, 64, 96, 128, 256, 384], + path: "/_next/image".to_string(), + loader: ImageLoader::Default, + domains: vec![], + disable_static_images: false, + minimum_cache_ttl: 60, + formats: vec![ImageFormat::Webp], + dangerously_allow_svg: false, + content_security_policy: "".to_string(), + remote_patterns: vec![], + unoptimized: false, + } + } +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(rename_all = "lowercase")] +pub enum ImageLoader { + Default, + Imgix, + Cloudinary, + Akamai, + Custom, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +pub enum ImageFormat { + #[serde(rename(deserialize = "image/webp"))] + Webp, + #[serde(rename(deserialize = "image/avif"))] + Avif, +} + +#[derive( + Clone, Debug, Default, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, +)] +#[serde(rename_all = "camelCase")] +pub struct RemotePattern { + pub protocol: Option<RemotePatternProtocal>, + pub hostname: String, + pub port: Option<String>, + pub pathname: Option<String>, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(rename_all = "lowercase")] +pub enum RemotePatternProtocal { + Http, + Https, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(rename_all = "camelCase")] +pub struct ExperimentalConfig { + pub server_components_external_packages: Option<Vec<String>>, + pub app_dir: Option<bool>, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(rename_all = "camelCase")] +pub struct CompilerConfig { + pub react_remove_properties: Option<bool>, + pub relay: Option<RelayConfig>, + pub remove_console: Option<RemoveConsoleConfig>, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(untagged, rename_all = "camelCase")] +pub enum ReactRemoveProperties { + Boolean(bool), + Config { properties: Option<Vec<String>> }, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(rename_all = "camelCase")] +pub struct RelayConfig { + pub src: String, + pub artifact_directory: Option<String>, + pub language: Option<RelayLanguage>, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(untagged, rename_all = "lowercase")] +pub enum RelayLanguage { + TypeScript, + Flow, + JavaScript, +} + +#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +#[serde(untagged)] +pub enum RemoveConsoleConfig { + Boolean(bool), + Config { exclude: Option<Vec<String>> }, +} + +#[turbo_tasks::value_impl] +impl NextConfigVc { + #[turbo_tasks::function] + pub async fn server_component_externals(self) -> Result<StringsVc> { + Ok(StringsVc::cell( + self.await? + .experimental + .as_ref() + .and_then(|e| e.server_components_external_packages.as_ref()) + .cloned() + .unwrap_or_default(), + )) + } + + #[turbo_tasks::function] + pub async fn app_dir(self) -> Result<BoolVc> { + Ok(BoolVc::cell( + self.await? + .experimental + .as_ref() + .and_then(|e| e.app_dir.as_ref()) + .cloned() + .unwrap_or_default(), + )) + } + + #[turbo_tasks::function] + pub async fn image_config(self) -> Result<ImageConfigVc> { + let mut image_config = self.await?.images.clone(); + // TODO is this the right place to do this? + image_config.remote_patterns.push(RemotePattern { + hostname: "**".to_string(), + ..Default::default() + }); + Ok(image_config.cell()) + } +} + +#[turbo_tasks::function] +pub async fn load_next_config( + project_path: FileSystemPathVc, + intermediate_output_path: FileSystemPathVc, +) -> Result<NextConfigVc> { + let context = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(Default::default()), + EnvironmentVc::new( + Value::new(ExecutionEnvironment::NodeJsBuildTime( + NodeJsEnvironment::default().cell(), + )), + Value::new(EnvironmentIntention::Build), + ), + get_build_module_options_context(), + get_build_resolve_options_context(project_path), + ) + .as_asset_context(); + let next_config_mjs_path = project_path.join("next.config.mjs").realpath(); + let next_config_js_path = project_path.join("next.config.js").realpath(); + let config_asset = if matches!( + &*next_config_mjs_path.get_type().await?, + FileSystemEntryType::File + ) { + Some(SourceAssetVc::new(next_config_mjs_path)) + } else if matches!( + &*next_config_js_path.get_type().await?, + FileSystemEntryType::File + ) { + Some(SourceAssetVc::new(next_config_js_path)) + } else { + None + }; + + let runtime_entries = config_asset.map(|config_asset| { + // TODO this is a hack to add the config to the bundling to make it watched + let config_chunk = EcmascriptModuleAssetVc::new( + config_asset.into(), + context, + Value::new(EcmascriptModuleAssetType::Ecmascript), + EcmascriptInputTransformsVc::cell(vec![]), + context.environment(), + ) + .as_ecmascript_chunk_placeable(); + EcmascriptChunkPlaceablesVc::cell(vec![config_chunk]) + }); + let asset_path = config_asset + .map_or(project_path, |a| a.path()) + .join("load-next-config.js"); + let load_next_config_asset = context.process( + next_asset(asset_path, "entry/config/next.js"), + Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), + ); + let config_value = evaluate( + project_path, + load_next_config_asset, + project_path, + context, + intermediate_output_path, + runtime_entries, + ) + .await?; + match &*config_value { + JavaScriptValue::Value(val) => { + let next_config: NextConfig = serde_json::from_reader(val.read())?; + Ok(next_config.cell()) + } + JavaScriptValue::Stream(_) => { + unimplemented!("Stream not supported now"); + } + } +} diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index b2afb84ada6ef1..ef200020d9f5df 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use turbo_tasks::{primitives::StringsVc, Value}; +use turbo_tasks::Value; use turbo_tasks_fs::{glob::GlobVc, FileSystemPathVc}; use turbopack_core::resolve::{ options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc, ResolvedMap, ResolvedMapVc}, @@ -9,6 +9,7 @@ use turbopack_core::resolve::{ use crate::{ embed_js::{attached_next_js_package_path, VIRTUAL_PACKAGE_NAME}, next_client::context::ContextType, + next_config::NextConfigVc, next_font_google::{NextFontGoogleCssModuleReplacerVc, NextFontGoogleReplacerVc}, next_server::ServerContextType, }; @@ -66,6 +67,25 @@ pub fn get_next_client_import_map( import_map.cell() } +/// Computes the Next-specific client import map. +#[turbo_tasks::function] +pub fn get_next_build_import_map(project_path: FileSystemPathVc) -> ImportMapVc { + let mut import_map = ImportMap::empty(); + + let package_root = attached_next_js_package_path(project_path); + + insert_package_alias( + &mut import_map, + &format!("{VIRTUAL_PACKAGE_NAME}/"), + package_root, + ); + + import_map.insert_exact_alias("next", ImportMapping::External(None).into()); + import_map.insert_wildcard_alias("next/", ImportMapping::External(None).into()); + + import_map.cell() +} + /// Computes the Next-specific client fallback import map, which provides /// polyfills to Node.js externals. #[turbo_tasks::function] @@ -100,7 +120,7 @@ pub fn get_next_client_fallback_import_map(ty: Value<ContextType>) -> ImportMapV pub async fn get_next_server_import_map( project_path: FileSystemPathVc, ty: Value<ServerContextType>, - externals: StringsVc, + next_config: NextConfigVc, ) -> Result<ImportMapVc> { let mut import_map = ImportMap::empty(); @@ -153,7 +173,7 @@ pub async fn get_next_server_import_map( request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); - for external in externals.await?.iter() { + for external in next_config.server_component_externals().await?.iter() { import_map.insert_exact_alias(external, ImportMapping::External(None).into()); import_map.insert_wildcard_alias( format!("{external}/"), diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index 9618ece8ae7145..0d0f30c9373077 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -1,7 +1,4 @@ -use turbo_tasks::{ - primitives::{StringVc, StringsVc}, - Value, -}; +use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ @@ -14,7 +11,9 @@ use turbopack_core::environment::{ use turbopack_ecmascript::EcmascriptInputTransform; use crate::{ - next_client::context::add_next_font_transform, next_import_map::get_next_server_import_map, + next_client::context::add_next_font_transform, + next_config::NextConfigVc, + next_import_map::{get_next_build_import_map, get_next_server_import_map}, }; #[turbo_tasks::value(serialization = "auto_for_input")] @@ -29,9 +28,9 @@ pub enum ServerContextType { pub fn get_server_resolve_options_context( project_path: FileSystemPathVc, ty: Value<ServerContextType>, - externals: StringsVc, + next_config: NextConfigVc, ) -> ResolveOptionsContextVc { - let next_server_import_map = get_next_server_import_map(project_path, ty, externals); + let next_server_import_map = get_next_server_import_map(project_path, ty, next_config); match ty.into_value() { ServerContextType::Pages { .. } | ServerContextType::AppSSR { .. } => { ResolveOptionsContext { @@ -103,3 +102,29 @@ pub fn get_server_module_options_context(ty: Value<ServerContextType>) -> Module add_next_font_transform(module_options_context) } + +#[turbo_tasks::function] +pub fn get_build_resolve_options_context( + project_path: FileSystemPathVc, +) -> ResolveOptionsContextVc { + let next_build_import_map = get_next_build_import_map(project_path); + ResolveOptionsContext { + enable_typescript: true, + enable_node_modules: true, + enable_node_externals: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string()], + import_map: Some(next_build_import_map), + ..Default::default() + } + .cell() +} + +#[turbo_tasks::function] +pub fn get_build_module_options_context() -> ModuleOptionsContextVc { + ModuleOptionsContext { + enable_typescript_transform: true, + ..Default::default() + } + .cell() +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 557f6962dfeb97..33f95911aa23cf 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use anyhow::Result; use turbo_tasks::{ - primitives::{BoolVc, StringVc, StringsVc}, + primitives::{BoolVc, StringVc}, Value, }; use turbo_tasks_env::ProcessEnvVc; @@ -48,6 +48,7 @@ use crate::{ }, NextClientTransition, }, + next_config::NextConfigVc, next_server::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, @@ -60,13 +61,14 @@ use crate::{ /// Next.js pages folder. #[turbo_tasks::function] pub async fn create_server_rendered_source( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, + next_config: NextConfigVc, ) -> Result<ContentSourceVc> { - let project_path = wrap_with_next_js_fs(project_root); + let project_path = wrap_with_next_js_fs(project_path); let pages = project_path.join("pages"); let src_pages = project_path.join("src/pages"); @@ -81,7 +83,6 @@ pub async fn create_server_rendered_source( let ty = Value::new(ContextType::Pages { pages_dir }); let server_ty = Value::new(ServerContextType::Pages { pages_dir }); - let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); let client_module_options_context = get_client_module_options_context(project_path, client_environment, ty); @@ -96,7 +97,9 @@ pub async fn create_server_rendered_source( ) .into(); - let client_runtime_entries = get_client_runtime_entries(project_path, env, ty); + let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); + + let client_runtime_entries = get_client_runtime_entries(project_path, env, ty, next_config); let next_client_transition = NextClientTransition { is_app: false, @@ -116,14 +119,23 @@ pub async fn create_server_rendered_source( TransitionsByNameVc::cell(transitions), get_server_environment(server_ty, env), get_server_module_options_context(server_ty), - get_server_resolve_options_context(project_path, server_ty, StringsVc::empty()), + get_server_resolve_options_context(project_path, server_ty, next_config), ) .into(); - let server_runtime_entries = vec![ProcessEnvAssetVc::new(project_path, env_for_js(env, false)) - .as_ecmascript_chunk_placeable()]; + let server_runtime_entries = + vec![ + ProcessEnvAssetVc::new(project_path, env_for_js(env, false, next_config)) + .as_ecmascript_chunk_placeable(), + ]; - let fallback_page = get_fallback_page(project_path, server_root, env, browserslist_query); + let fallback_page = get_fallback_page( + project_path, + server_root, + env, + browserslist_query, + next_config, + ); let server_rendered_source = create_server_rendered_source_for_directory( project_path, diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index e48b427c27092e..0174c750d96d98 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -19,6 +19,7 @@ use crate::{ get_client_asset_context, get_client_chunking_context, get_client_runtime_entries, ContextType, }, + next_config::NextConfigVc, }; #[turbo_tasks::function] @@ -29,13 +30,14 @@ pub async fn create_web_entry_source( env: ProcessEnvVc, eager_compile: bool, browserslist_query: &str, + next_config: NextConfigVc, ) -> Result<ContentSourceVc> { let project_root = wrap_with_next_js_fs(project_root); let ty = Value::new(ContextType::Other); let context = get_client_asset_context(project_root, browserslist_query, ty); let chunking_context = get_client_chunking_context(project_root, server_root, ty); - let entries = get_client_runtime_entries(project_root, env, ty); + let entries = get_client_runtime_entries(project_root, env, ty, next_config); let runtime_entries = entries.resolve_entries(context); diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/mod.rs similarity index 94% rename from packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs rename to packages/next-swc/crates/next-dev/benches/bundlers/turbopack/mod.rs index ec15749b2dd18d..375bf0886da4e1 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/mod.rs @@ -1,4 +1,5 @@ use std::{ + fs, path::Path, process::{Child, Command, Stdio}, }; @@ -54,6 +55,12 @@ impl Bundler for Turbopack { ], ) .context("failed to install from npm")?; + + fs::write( + install_dir.join("next.config.js"), + include_bytes!("next.config.js"), + )?; + Ok(()) } diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/next.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/next.config.js new file mode 100644 index 00000000000000..ed0e87891f9e83 --- /dev/null +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + experimental: { + appDir: true, + }, +}; diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index 40d33a1ef5a8e6..c7e9ec17706eba 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -92,11 +92,6 @@ pub struct DevServerOptions { #[cfg_attr(feature = "serializable", serde(default))] /// Internal for next.js, no specific usage yet. pub is_next_dev_command: bool, - #[cfg_attr(feature = "cli", clap(long))] - #[cfg_attr(feature = "serializable", serde(default))] - /// Specify server component external packages explicitly. This is an - /// experimental flag. - pub server_components_external_packages: Vec<String>, } #[cfg(feature = "serializable")] diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 07af0bec32e6b6..7556f178d9d7dd 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -18,13 +18,12 @@ use anyhow::{anyhow, Context, Result}; use devserver_options::DevServerOptions; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, - manifest::DevManifestContentSource, next_image::NextImageContentSourceVc, - source_map::NextSourceMapTraceContentSourceVc, + manifest::DevManifestContentSource, next_config::load_next_config, + next_image::NextImageContentSourceVc, source_map::NextSourceMapTraceContentSourceVc, }; use owo_colors::OwoColorize; use turbo_malloc::TurboMalloc; use turbo_tasks::{ - primitives::StringsVc, util::{FormatBytes, FormatDuration}, RawVc, StatsType, TransientInstance, TransientValue, TurboTasks, TurboTasksBackendApi, Value, }; @@ -57,7 +56,6 @@ pub struct NextDevServerBuilder { project_dir: String, root_dir: String, entry_requests: Vec<EntryRequest>, - server_component_externals: Vec<String>, eager_compile: bool, hostname: Option<IpAddr>, port: Option<u16>, @@ -79,7 +77,6 @@ impl NextDevServerBuilder { project_dir, root_dir, entry_requests: vec![], - server_component_externals: vec![], eager_compile: false, hostname: None, port: None, @@ -98,11 +95,6 @@ impl NextDevServerBuilder { self } - pub fn server_component_external(mut self, external: String) -> NextDevServerBuilder { - self.server_component_externals.push(external); - self - } - pub fn eager_compile(mut self, eager_compile: bool) -> NextDevServerBuilder { self.eager_compile = eager_compile; self @@ -148,7 +140,6 @@ impl NextDevServerBuilder { let project_dir = self.project_dir; let root_dir = self.root_dir; - let server_component_externals = self.server_component_externals; let eager_compile = self.eager_compile; let show_all = self.show_all; let log_detail = self.log_detail; @@ -178,7 +169,6 @@ impl NextDevServerBuilder { turbo_tasks.clone().into(), console_ui.clone().into(), browserslist_query.clone(), - server_component_externals.clone(), ) }; @@ -275,7 +265,6 @@ async fn source( turbo_tasks: TransientInstance<TurboTasks<MemoryBackend>>, console_ui: TransientInstance<ConsoleUi>, browserslist_query: String, - server_component_externals: Vec<String>, ) -> Result<ContentSourceVc> { let console_ui = (*console_ui).clone().cell(); let output_fs = output_fs(&project_dir, console_ui); @@ -287,8 +276,10 @@ async fn source( let project_path = fs.root().join(project_relative); let env = load_env(project_path); + let config_output_root = output_fs.root().join(".next/config"); + let next_config = load_next_config(project_path, config_output_root); - let output_root = output_fs.root().join("/.next/server"); + let output_root = output_fs.root().join(".next/server"); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let dev_server_root = dev_server_fs.root(); @@ -309,6 +300,7 @@ async fn source( env, eager_compile, &browserslist_query, + next_config, ); let rendered_source = create_server_rendered_source( project_path, @@ -316,6 +308,7 @@ async fn source( dev_server_root, env, &browserslist_query, + next_config, ); let app_source = create_app_source( project_path, @@ -323,7 +316,7 @@ async fn source( dev_server_root, env, &browserslist_query, - StringsVc::cell(server_component_externals), + next_config, ); let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.into(), @@ -440,10 +433,6 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { #[cfg(feature = "serializable")] { server = server.allow_retry(options.allow_retry); - - for package in options.server_components_external_packages.iter() { - server = server.server_component_external(package.to_string()); - } } let server = server.build().await?; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/next.config.js b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/next.config.js new file mode 100644 index 00000000000000..a691b84021bf4f --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/next.config.js @@ -0,0 +1,6 @@ +/**@type {import('next').NextConfig} */ +const config = { + reactStrictMode: true, +}; + +module.exports = config; From 5337e1fedbf60fef02ab41b3fd5908dbc3809726 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Sun, 18 Dec 2022 08:03:08 -0500 Subject: [PATCH 279/672] Fix nitpicks with load-next-config (vercel/turbo#3064) Re: code review nits from vercel/turbo#2955 --- .../next-swc/crates/next-core/src/next_client/context.rs | 1 - packages/next-swc/crates/next-core/src/next_config.rs | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 8a92fcf4a633f8..83bc8efeec8046 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -240,7 +240,6 @@ pub async fn get_client_runtime_entries( .as_request(); let mut runtime_entries = vec![RuntimeEntry::Ecmascript( - //TODO ProcessEnvAssetVc::new(project_root, env_for_js(env, true, next_config)).into(), ) .cell()]; diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index def2bc397b034f..99b5eef0dd4707 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -196,13 +196,7 @@ impl NextConfigVc { #[turbo_tasks::function] pub async fn image_config(self) -> Result<ImageConfigVc> { - let mut image_config = self.await?.images.clone(); - // TODO is this the right place to do this? - image_config.remote_patterns.push(RemotePattern { - hostname: "**".to_string(), - ..Default::default() - }); - Ok(image_config.cell()) + Ok(self.await?.images.clone().cell()) } } From 7e230495a19a9cc1c3bedf1d28c56655555e4122 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Sun, 18 Dec 2022 16:46:52 -0500 Subject: [PATCH 280/672] Fix source map tracing for HMR updates (vercel/turbo#3063) HMR is handled via an `eval(newCode)`, and that eval will inherit the filepath of the currently running file (in our case, the chunk file that contains the runtime code). To properly trace, we need to know both the chunk and the item ids, so we trace via the correct item's source map. Thankfully, we can use the (underspecified) [`//# sourceUrl` ](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/javascript/source-maps#use--sourceurl-to-name-evaluated-files-in-the-sources-tool) meta comment to name the file we're currently evaluating. That'll get used as the stack frame's file. We can then encode the chunk path and item id into the filename, and let next's stack tracing code handle the rest. This also fixes an off-by-one on the column. Source maps are 0-based, but the line/column of a file as displayed in an editor or dev tools are 1-based. --- packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 167af8a0b7062a..fd3bbba87e2680 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -1,7 +1,7 @@ -use std::{str::FromStr, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; use anyhow::Result; -use mime::Mime; +use mime::TEXT_HTML_UTF_8; use turbo_tasks::{get_invalidator, TurboTasks, TurboTasksBackendApi, Value}; use turbo_tasks_fs::File; use turbo_tasks_memory::{ @@ -115,10 +115,7 @@ impl ContentSource for TurboTasksSource { }; Ok(ContentSourceResultVc::exact( ContentSourceContent::Static( - AssetContentVc::from( - File::from(html).with_content_type(Mime::from_str("text/html")?), - ) - .into(), + AssetContentVc::from(File::from(html).with_content_type(TEXT_HTML_UTF_8)).into(), ) .cell(), )) From 1a66a2a7488a50d205dace67bc43ffc24b430123 Mon Sep 17 00:00:00 2001 From: Leah <github.leah@hrmny.sh> Date: Mon, 19 Dec 2022 18:43:18 +0100 Subject: [PATCH 281/672] set `__NEXT_STRICT_MODE` (vercel/turbo#2878) and `__NEXT_STRICT_MODE_APP` --- packages/next-swc/crates/next-core/src/env.rs | 28 ++++++++++++------- .../crates/next-core/src/next_config.rs | 2 +- packages/next-swc/crates/next-dev/Cargo.toml | 4 +-- .../crates/next-dev/src/devserver_options.rs | 20 +++++++------ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/env.rs b/packages/next-swc/crates/next-core/src/env.rs index e80bf12a623fec..d3bb86aaf6dcdf 100644 --- a/packages/next-swc/crates/next-core/src/env.rs +++ b/packages/next-swc/crates/next-core/src/env.rs @@ -58,14 +58,22 @@ pub async fn env_for_js( let env = EmbeddableProcessEnvVc::new(env).into(); let image_config = next_config.image_config().await?; - Ok(CustomProcessEnvVc::new( - env, - EnvMapVc::cell(indexmap! { - // We need to overload the __NEXT_IMAGE_OPTS to override the default remotePatterns field. - // This allows us to support loading from remote hostnames until we properly support reading - // the next.config.js file. - "__NEXT_IMAGE_OPTS".to_string() => serde_json::to_string(&image_config).unwrap() - }), - ) - .into()) + let next_config = next_config.await?; + + let mut map = indexmap! { + // We need to overload the __NEXT_IMAGE_OPTS to override the default remotePatterns field. + // This allows us to support loading from remote hostnames until we properly support reading + // the next.config.js file. + "__NEXT_IMAGE_OPTS".to_string() => serde_json::to_string(&image_config).unwrap(), + }; + + if next_config.react_strict_mode.unwrap_or(false) { + map.insert("__NEXT_STRICT_MODE".to_string(), "true".to_string()); + } + + if next_config.react_strict_mode.unwrap_or(true) { + map.insert("__NEXT_STRICT_MODE_APP".to_string(), "true".to_string()); + } + + Ok(CustomProcessEnvVc::new(env, EnvMapVc::cell(map)).into()) } diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index 99b5eef0dd4707..ec8f5b5de04e58 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -26,9 +26,9 @@ use crate::{ next_server::{get_build_module_options_context, get_build_resolve_options_context}, }; +#[turbo_tasks::value(serialization = "custom")] #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] -#[turbo_tasks::value(transparent, serialization = "custom")] pub struct NextConfig { pub config_file: Option<String>, pub config_file_name: String, diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 64c22c0055e2dc..8cb782a7903384 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -25,7 +25,7 @@ harness = false # promote this as default backend. Actual configuration is done when build next-swc, # and also turbopack standalone when we have it. default = ["cli", "custom_allocator", "native-tls"] -cli = [] +cli = ["clap"] serializable = [] tokio_console = [ "dep:console-subscriber", @@ -40,7 +40,7 @@ rustls-tls = ["next-core/rustls-tls"] [dependencies] anyhow = "1.0.47" -clap = { version = "4.0.18", features = ["derive", "env"] } +clap = { version = "4.0.18", features = ["derive", "env"], optional = true } console-subscriber = { version = "0.1.8", optional = true } futures = "0.3.25" mime = "0.3.16" diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index c7e9ec17706eba..83a4aaabb962b1 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -58,38 +58,40 @@ pub struct DevServerOptions { #[cfg_attr(feature = "serializable", serde(default))] pub no_open: bool, + /// Filter by issue severity. #[cfg_attr(feature = "cli", clap(short, long))] #[cfg_attr(feature = "serializable", serde(default))] - /// Filter by issue severity. pub log_level: Option<IssueSeverityCliOption>, + /// Show all log messages without limit. #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] - /// Show all log messages without limit. pub show_all: bool, + /// Expand the log details. #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] - /// Expand the log details. pub log_detail: bool, + /// Whether to enable full task stats recording in Turbo Engine. #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] - /// Whether to enable full task stats recording in Turbo Engine. pub full_stats: bool, - // Inherited options from next-dev, need revisit later. - #[cfg_attr(feature = "cli", clap(long))] - #[cfg_attr(feature = "serializable", serde(default))] + // == + // = Inherited options from next-dev, need revisit later. + // == /// If port is not explicitly specified, use different port if it's already /// in use. - pub allow_retry: bool, #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] + pub allow_retry: bool, + /// Internal for next.js, no specific usage yet. - pub dev: bool, #[cfg_attr(feature = "cli", clap(long))] #[cfg_attr(feature = "serializable", serde(default))] + pub dev: bool, + /// Internal for next.js, no specific usage yet. pub is_next_dev_command: bool, } From df7fa75b04f8f03740ab1ce4644fcedb6b88bbbc Mon Sep 17 00:00:00 2001 From: Justin Ridgewell <justin@ridgewell.name> Date: Mon, 19 Dec 2022 14:28:03 -0500 Subject: [PATCH 282/672] Add clap macros for is_next_dev_command (vercel/turbo#3073) Seems vercel/turbo#2878 removed this accidentally --- packages/next-swc/crates/next-dev/src/devserver_options.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/next-swc/crates/next-dev/src/devserver_options.rs b/packages/next-swc/crates/next-dev/src/devserver_options.rs index 83a4aaabb962b1..5b3ea5340ed20b 100644 --- a/packages/next-swc/crates/next-dev/src/devserver_options.rs +++ b/packages/next-swc/crates/next-dev/src/devserver_options.rs @@ -93,6 +93,8 @@ pub struct DevServerOptions { pub dev: bool, /// Internal for next.js, no specific usage yet. + #[cfg_attr(feature = "cli", clap(long))] + #[cfg_attr(feature = "serializable", serde(default))] pub is_next_dev_command: bool, } From 78abb7e5d3c3d62d6ae8be143e2a0a836cc1aed7 Mon Sep 17 00:00:00 2001 From: LongYinan <lynweklm@gmail.com> Date: Tue, 20 Dec 2022 03:38:05 +0800 Subject: [PATCH 283/672] PostCSS support in next-dev (vercel/turbo#3065) This adds the ability to add Source transforms on assets, which modify the source code of an asset before parsing. This adds postcss via node.js as first source transform. Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> --- .../next-core/js/src/entry/config/next.js | 10 +- .../crates/next-core/src/app_source.rs | 93 ++++++++++----- .../next-swc/crates/next-core/src/fallback.rs | 17 +-- packages/next-swc/crates/next-core/src/lib.rs | 4 +- .../next-swc/crates/next-core/src/manifest.rs | 5 +- .../crates/next-core/src/next_build.rs | 49 ++++++++ .../next-core/src/next_client/context.rs | 34 ++++-- .../crates/next-core/src/next_config.rs | 54 +++++---- .../crates/next-core/src/next_server/mod.rs | 27 ++++- .../next-core/src/server_rendered_source.rs | 18 +-- .../crates/next-core/src/web_entry_source.rs | 4 +- packages/next-swc/crates/next-dev/Cargo.toml | 1 + packages/next-swc/crates/next-dev/src/lib.rs | 15 ++- .../crates/next-dev/tests/integration.rs | 3 + .../next/tailwind/basic/next.config.js | 4 + .../next/tailwind/basic/pages/_app.tsx | 8 ++ .../next/tailwind/basic/pages/api/hello.ts | 13 +++ .../next/tailwind/basic/pages/index.jsx | 106 ++++++++++++++++++ .../next/tailwind/basic/postcss.config.js | 6 + .../next/tailwind/basic/public/favicon.ico | Bin 0 -> 15086 bytes .../next/tailwind/basic/public/vercel.svg | 4 + .../next/tailwind/basic/styles/globals.css | 3 + .../next/tailwind/basic/tailwind.config.js | 12 ++ .../next/tailwind/basic/tsconfig.json | 20 ++++ .../crates/next-dev/tests/package.json | 5 +- 25 files changed, 414 insertions(+), 101 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_build.rs create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/next.config.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/_app.tsx create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/api/hello.ts create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/index.jsx create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/postcss.config.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/public/favicon.ico create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/public/vercel.svg create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/styles/globals.css create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tailwind.config.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tsconfig.json diff --git a/packages/next-swc/crates/next-core/js/src/entry/config/next.js b/packages/next-swc/crates/next-core/js/src/entry/config/next.js index ee75fb86e58658..349540a9ca4c20 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/config/next.js +++ b/packages/next-swc/crates/next-core/js/src/entry/config/next.js @@ -1,9 +1,11 @@ -const loadConfig = require("next/dist/server/config").default; -const { PHASE_DEVELOPMENT_SERVER } = require("next/dist/shared/lib/constants"); +import loadConfig from "next/dist/server/config"; +import { PHASE_DEVELOPMENT_SERVER } from "next/dist/shared/lib/constants"; -module.exports = (async () => { +const loadNextConfig = async () => { const nextConfig = await loadConfig(PHASE_DEVELOPMENT_SERVER, process.cwd()); nextConfig.rewrites = await nextConfig.rewrites?.(); nextConfig.redirects = await nextConfig.redirects?.(); return nextConfig; -})(); +}; + +export { loadNextConfig as default }; diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index d97c7b6102d8c7..f1332b7099d586 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -35,9 +35,8 @@ use turbopack_ecmascript::{ }; use turbopack_env::ProcessEnvAssetVc; use turbopack_node::{ - create_node_rendered_source, - node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, - NodeEntry, NodeEntryVc, + execution_context::ExecutionContextVc, render::rendered_source::create_node_rendered_source, + NodeEntry, NodeEntryVc, NodeRenderingEntry, NodeRenderingEntryVc, }; use crate::{ @@ -69,21 +68,22 @@ use crate::{ #[turbo_tasks::function] fn next_client_chunks_transition( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, app_dir: FileSystemPathVc, server_root: FileSystemPathVc, browserslist_query: &str, ) -> TransitionVc { let ty = Value::new(ContextType::App { app_dir }); - let client_chunking_context = get_client_chunking_context(project_root, server_root, ty); + let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); let client_module_options_context = - get_client_module_options_context(project_root, client_environment, ty); + get_client_module_options_context(project_path, execution_context, client_environment, ty); NextClientChunksTransition { client_chunking_context, client_module_options_context, - client_resolve_options_context: get_client_resolve_options_context(project_root, ty), + client_resolve_options_context: get_client_resolve_options_context(project_path, ty), client_environment, server_root, } @@ -93,7 +93,8 @@ fn next_client_chunks_transition( #[turbo_tasks::function] async fn next_client_transition( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, server_root: FileSystemPathVc, app_dir: FileSystemPathVc, env: ProcessEnvVc, @@ -101,12 +102,12 @@ async fn next_client_transition( next_config: NextConfigVc, ) -> Result<TransitionVc> { let ty = Value::new(ContextType::App { app_dir }); - let client_chunking_context = get_client_chunking_context(project_root, server_root, ty); + let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); let client_module_options_context = - get_client_module_options_context(project_root, client_environment, ty); - let client_runtime_entries = get_client_runtime_entries(project_root, env, ty, next_config); - let client_resolve_options_context = get_client_resolve_options_context(project_root, ty); + get_client_module_options_context(project_path, execution_context, client_environment, ty); + let client_runtime_entries = get_client_runtime_entries(project_path, env, ty, next_config); + let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); Ok(NextClientTransition { is_app: true, @@ -123,16 +124,21 @@ async fn next_client_transition( #[turbo_tasks::function] fn next_ssr_client_module_transition( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, app_dir: FileSystemPathVc, process_env: ProcessEnvVc, next_config: NextConfigVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppSSR { app_dir }); NextSSRClientModuleTransition { - ssr_module_options_context: get_server_module_options_context(ty), + ssr_module_options_context: get_server_module_options_context( + project_path, + execution_context, + ty, + ), ssr_resolve_options_context: get_server_resolve_options_context( - project_root, + project_path, ty, next_config, ), @@ -144,7 +150,8 @@ fn next_ssr_client_module_transition( #[turbo_tasks::function] fn next_layout_entry_transition( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, app_dir: FileSystemPathVc, server_root: FileSystemPathVc, process_env: ProcessEnvVc, @@ -153,8 +160,9 @@ fn next_layout_entry_transition( let ty = Value::new(ServerContextType::AppRSC { app_dir }); let rsc_environment = get_server_environment(ty, process_env); let rsc_resolve_options_context = - get_server_resolve_options_context(project_root, ty, next_config); - let rsc_module_options_context = get_server_module_options_context(ty); + get_server_resolve_options_context(project_path, ty, next_config); + let rsc_module_options_context = + get_server_module_options_context(project_path, execution_context, ty); NextLayoutEntryTransition { rsc_environment, @@ -168,7 +176,8 @@ fn next_layout_entry_transition( #[turbo_tasks::function] fn app_context( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, server_root: FileSystemPathVc, app_dir: FileSystemPathVc, env: ProcessEnvVc, @@ -181,7 +190,14 @@ fn app_context( let mut transitions = HashMap::new(); transitions.insert( "next-layout-entry".to_string(), - next_layout_entry_transition(project_root, app_dir, server_root, env, next_config), + next_layout_entry_transition( + project_path, + execution_context, + app_dir, + server_root, + env, + next_config, + ), ); transitions.insert( "server-to-client".to_string(), @@ -190,7 +206,8 @@ fn app_context( transitions.insert( "next-client".to_string(), next_client_transition( - project_root, + project_path, + execution_context, server_root, app_dir, env, @@ -200,19 +217,31 @@ fn app_context( ); transitions.insert( "next-client-chunks".to_string(), - next_client_chunks_transition(project_root, app_dir, server_root, browserslist_query), + next_client_chunks_transition( + project_path, + execution_context, + app_dir, + server_root, + browserslist_query, + ), ); transitions.insert( "next-ssr-client-module".to_string(), - next_ssr_client_module_transition(project_root, app_dir, env, next_config), + next_ssr_client_module_transition( + project_path, + execution_context, + app_dir, + env, + next_config, + ), ); let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir }); ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), get_server_environment(ssr_ty, env), - get_server_module_options_context(ssr_ty), - get_server_resolve_options_context(project_root, ssr_ty, next_config), + get_server_module_options_context(project_path, execution_context, ssr_ty), + get_server_resolve_options_context(project_path, ssr_ty, next_config), ) .into() } @@ -222,6 +251,7 @@ fn app_context( #[turbo_tasks::function] pub async fn create_app_source( project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, @@ -246,6 +276,7 @@ pub async fn create_app_source( let context_ssr = app_context( project_path, + execution_context, server_root, app_dir, env, @@ -255,6 +286,7 @@ pub async fn create_app_source( ); let context = app_context( project_path, + execution_context, server_root, app_dir, env, @@ -271,6 +303,7 @@ pub async fn create_app_source( let fallback_page = get_fallback_page( project_path, + execution_context, server_root, env, browserslist_query, @@ -298,7 +331,7 @@ pub async fn create_app_source( async fn create_app_source_for_directory( context_ssr: AssetContextVc, context: AssetContextVc, - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, specificity: SpecificityVc, position: u32, input_dir: FileSystemPathVc, @@ -392,7 +425,7 @@ async fn create_app_source_for_directory( layout_path: layouts, page_path, target, - project_root, + project_path, intermediate_output_path, } .cell() @@ -422,7 +455,7 @@ async fn create_app_source_for_directory( create_app_source_for_directory( context_ssr, context, - project_root, + project_path, specificity, position, *dir, @@ -449,7 +482,7 @@ struct AppRenderer { layout_path: LayoutSegmentsVc, page_path: FileSystemPathVc, target: FileSystemPathVc, - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, intermediate_output_path: FileSystemPathVc, } @@ -580,7 +613,7 @@ import BOOTSTRAP from {}; }; let chunking_context = DevChunkingContextVc::builder( - self.project_root, + self.project_path, intermediate_output_path, intermediate_output_path.join("chunks"), self.server_root.join("_next/static/assets"), diff --git a/packages/next-swc/crates/next-core/src/fallback.rs b/packages/next-swc/crates/next-core/src/fallback.rs index f35e266f1eac70..3374dd0688de13 100644 --- a/packages/next-swc/crates/next-core/src/fallback.rs +++ b/packages/next-swc/crates/next-core/src/fallback.rs @@ -13,6 +13,7 @@ use turbopack_core::{ resolve::{options::ImportMap, origin::PlainResolveOriginVc}, }; use turbopack_dev_server::html::DevHtmlAssetVc; +use turbopack_node::execution_context::ExecutionContextVc; use crate::{ next_client::context::{ @@ -26,7 +27,8 @@ use crate::{ #[turbo_tasks::function] pub async fn get_fallback_page( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, dev_server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, @@ -34,13 +36,14 @@ pub async fn get_fallback_page( ) -> Result<DevHtmlAssetVc> { let ty = Value::new(ContextType::Fallback); let environment = get_client_environment(browserslist_query); - let resolve_options_context = get_client_resolve_options_context(project_root, ty); - let module_options_context = get_client_module_options_context(project_root, environment, ty); - let chunking_context = get_client_chunking_context(project_root, dev_server_root, ty); - let entries = get_client_runtime_entries(project_root, env, ty, next_config); + let resolve_options_context = get_client_resolve_options_context(project_path, ty); + let module_options_context = + get_client_module_options_context(project_path, execution_context, environment, ty); + let chunking_context = get_client_chunking_context(project_path, dev_server_root, ty); + let entries = get_client_runtime_entries(project_path, env, ty, next_config); let mut import_map = ImportMap::empty(); - insert_next_shared_aliases(&mut import_map, project_root); + insert_next_shared_aliases(&mut import_map, project_path); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -53,7 +56,7 @@ pub async fn get_fallback_page( let runtime_entries = entries.resolve_entries(context); let fallback_chunk = resolve_runtime_request( - PlainResolveOriginVc::new(context, project_root).into(), + PlainResolveOriginVc::new(context, project_path).into(), "entry/fallback", ); diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 4de2f26674da2b..4848b02aa69100 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -7,6 +7,7 @@ mod embed_js; pub mod env; mod fallback; pub mod manifest; +mod next_build; pub mod next_client; mod next_client_component; pub mod next_config; @@ -23,7 +24,6 @@ mod web_entry_source; pub use app_source::create_app_source; pub use server_rendered_source::create_server_rendered_source; -pub use turbopack_node::source_map; pub use web_entry_source::create_web_entry_source; pub fn register() { @@ -31,7 +31,7 @@ pub fn register() { turbo_tasks_fs::register(); turbo_tasks_fetch::register(); turbopack_dev_server::register(); - turbopack::register(); turbopack_node::register(); + turbopack::register(); include!(concat!(env!("OUT_DIR"), "/register.rs")); } diff --git a/packages/next-swc/crates/next-core/src/manifest.rs b/packages/next-swc/crates/next-core/src/manifest.rs index 802464d0711147..408bdfb0e6562b 100644 --- a/packages/next-swc/crates/next-core/src/manifest.rs +++ b/packages/next-swc/crates/next-core/src/manifest.rs @@ -7,8 +7,8 @@ use turbopack_core::asset::AssetContentVc; use turbopack_dev_server::source::{ ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc, }; -use turbopack_node::{ - node_api_source::NodeApiContentSourceVc, node_rendered_source::NodeRenderContentSourceVc, +use turbopack_node::render::{ + node_api_source::NodeApiContentSourceVc, rendered_source::NodeRenderContentSourceVc, }; /// A content source which creates the next.js `_devPagesManifest.json` and @@ -29,6 +29,7 @@ impl DevManifestContentSourceVc { while let Some(content_source) = queue.pop() { queue.extend(content_source.get_children().await?.iter()); + // TODO This shouldn't use casts but an public api instead if let Some(api_source) = NodeApiContentSourceVc::resolve_from(content_source).await? { routes.insert(format!("/{}", api_source.get_pathname().await?)); diff --git a/packages/next-swc/crates/next-core/src/next_build.rs b/packages/next-swc/crates/next-core/src/next_build.rs new file mode 100644 index 00000000000000..5a9593b4c7a376 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_build.rs @@ -0,0 +1,49 @@ +use anyhow::{Context, Result}; +use turbo_tasks::Value; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{resolve_options, resolve_options_context::ResolveOptionsContext}; +use turbopack_core::resolve::{ + options::{ImportMapping, ImportMappingVc}, + parse::RequestVc, + pattern::Pattern, + resolve, +}; + +#[turbo_tasks::function] +pub async fn get_next_package(project_root: FileSystemPathVc) -> Result<FileSystemPathVc> { + let result = resolve( + project_root, + RequestVc::parse(Value::new(Pattern::Constant( + "next/package.json".to_string(), + ))), + resolve_options( + project_root, + ResolveOptionsContext { + enable_node_modules: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string()], + ..Default::default() + } + .cell(), + ), + ); + let assets = result.primary_assets().await?; + let asset = assets.first().context("Next.js package not found")?; + Ok(asset.path().parent()) +} + +#[turbo_tasks::function] +pub async fn get_postcss_package_mapping( + project_path: FileSystemPathVc, +) -> Result<ImportMappingVc> { + Ok(ImportMapping::Alternatives(vec![ + // Prefer the local installed version over the next.js version + ImportMapping::PrimaryAlternative("postcss".to_string(), Some(project_path)).cell(), + ImportMapping::PrimaryAlternative( + "postcss".to_string(), + Some(get_next_package(project_path)), + ) + .cell(), + ]) + .cell()) +} diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 83bc8efeec8046..24a1f47ff998c9 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -8,7 +8,7 @@ use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ module_options::{ module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, - ModuleRule, ModuleRuleCondition, ModuleRuleEffect, + ModuleRule, ModuleRuleCondition, ModuleRuleEffect, PostCssTransformOptions, }, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, transition::TransitionsByNameVc, @@ -23,10 +23,12 @@ use turbopack_core::{ }; use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc}; use turbopack_env::ProcessEnvAssetVc; +use turbopack_node::execution_context::ExecutionContextVc; use crate::{ embed_js::attached_next_js_package_path, env::env_for_js, + next_build::get_postcss_package_mapping, next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, next_config::NextConfigVc, next_import_map::{ @@ -63,12 +65,12 @@ pub enum ContextType { #[turbo_tasks::function] pub fn get_client_resolve_options_context( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, ty: Value<ContextType>, ) -> ResolveOptionsContextVc { - let next_client_import_map = get_next_client_import_map(project_root, ty); + let next_client_import_map = get_next_client_import_map(project_path, ty); let next_client_fallback_import_map = get_next_client_fallback_import_map(ty); - let next_client_resolved_map = get_next_client_resolved_map(project_root, project_root); + let next_client_resolved_map = get_next_client_resolved_map(project_path, project_path); ResolveOptionsContext { enable_typescript: true, enable_react: true, @@ -86,13 +88,14 @@ pub fn get_client_resolve_options_context( #[turbo_tasks::function] pub async fn get_client_module_options_context( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, env: EnvironmentVc, ty: Value<ContextType>, ) -> Result<ModuleOptionsContextVc> { - let resolve_options_context = get_client_resolve_options_context(project_root, ty); + let resolve_options_context = get_client_resolve_options_context(project_path, ty); let enable_react_refresh = - assert_can_resolve_react_refresh(project_root, resolve_options_context) + assert_can_resolve_react_refresh(project_path, resolve_options_context) .await? .is_found(); @@ -104,8 +107,13 @@ pub async fn get_client_module_options_context( enable_react_refresh, enable_styled_components: true, enable_styled_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), enable_typescript_transform: true, preset_env_versions: Some(env), + execution_context: Some(execution_context), ..Default::default() }; @@ -173,13 +181,15 @@ pub async fn add_next_font_transform( #[turbo_tasks::function] pub fn get_client_asset_context( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, browserslist_query: &str, ty: Value<ContextType>, ) -> AssetContextVc { let environment = get_client_environment(browserslist_query); - let resolve_options_context = get_client_resolve_options_context(project_root, ty); - let module_options_context = get_client_module_options_context(project_root, environment, ty); + let resolve_options_context = get_client_resolve_options_context(project_path, ty); + let module_options_context = + get_client_module_options_context(project_path, execution_context, environment, ty); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -194,12 +204,12 @@ pub fn get_client_asset_context( #[turbo_tasks::function] pub fn get_client_chunking_context( - project_root: FileSystemPathVc, + project_path: FileSystemPathVc, server_root: FileSystemPathVc, ty: Value<ContextType>, ) -> ChunkingContextVc { DevChunkingContextVc::builder( - project_root, + project_path, server_root, match ty.into_value() { ContextType::Pages { .. } | ContextType::App { .. } => { diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index ec8f5b5de04e58..ceee16eddc1f04 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -7,25 +7,25 @@ use turbo_tasks::{ trace::TraceRawVcs, Value, }; -use turbo_tasks_fs::{FileSystemEntryType, FileSystemPathVc}; -use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; +use turbo_tasks_fs::FileSystemEntryType; +use turbopack::evaluate_context::node_evaluate_asset_context; use turbopack_core::{ asset::Asset, - environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment}, reference_type::{EntryReferenceSubType, ReferenceType}, + resolve::options::{ImportMap, ImportMapping}, source_asset::SourceAssetVc, }; use turbopack_ecmascript::{ chunk::EcmascriptChunkPlaceablesVc, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, }; -use turbopack_node::evaluate::{evaluate, JavaScriptValue}; - -use crate::{ - embed_js::next_asset, - next_server::{get_build_module_options_context, get_build_resolve_options_context}, +use turbopack_node::{ + evaluate::{evaluate, JavaScriptValue}, + execution_context::{ExecutionContext, ExecutionContextVc}, }; +use crate::embed_js::next_asset; + #[turbo_tasks::value(serialization = "custom")] #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] @@ -201,24 +201,19 @@ impl NextConfigVc { } #[turbo_tasks::function] -pub async fn load_next_config( - project_path: FileSystemPathVc, - intermediate_output_path: FileSystemPathVc, -) -> Result<NextConfigVc> { - let context = ModuleAssetContextVc::new( - TransitionsByNameVc::cell(Default::default()), - EnvironmentVc::new( - Value::new(ExecutionEnvironment::NodeJsBuildTime( - NodeJsEnvironment::default().cell(), - )), - Value::new(EnvironmentIntention::Build), - ), - get_build_module_options_context(), - get_build_resolve_options_context(project_path), - ) - .as_asset_context(); - let next_config_mjs_path = project_path.join("next.config.mjs").realpath(); - let next_config_js_path = project_path.join("next.config.js").realpath(); +pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result<NextConfigVc> { + let ExecutionContext { + project_root, + intermediate_output_path, + } = *execution_context.await?; + let mut import_map = ImportMap::default(); + + import_map.insert_exact_alias("next", ImportMapping::External(None).into()); + import_map.insert_wildcard_alias("next/", ImportMapping::External(None).into()); + + let context = node_evaluate_asset_context(Some(import_map.cell())); + let next_config_mjs_path = project_root.join("next.config.mjs").realpath(); + let next_config_js_path = project_root.join("next.config.js").realpath(); let config_asset = if matches!( &*next_config_mjs_path.get_type().await?, FileSystemEntryType::File @@ -246,19 +241,20 @@ pub async fn load_next_config( EcmascriptChunkPlaceablesVc::cell(vec![config_chunk]) }); let asset_path = config_asset - .map_or(project_path, |a| a.path()) + .map_or(project_root, |a| a.path()) .join("load-next-config.js"); let load_next_config_asset = context.process( next_asset(asset_path, "entry/config/next.js"), Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), ); let config_value = evaluate( - project_path, + project_root, load_next_config_asset, - project_path, + project_root, context, intermediate_output_path, runtime_entries, + vec![], ) .await?; match &*config_value { diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index 0d0f30c9373077..aba1aeaf5fb680 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -2,15 +2,17 @@ use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ - module_options::{ModuleOptionsContext, ModuleOptionsContextVc}, + module_options::{ModuleOptionsContext, ModuleOptionsContextVc, PostCssTransformOptions}, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, }; use turbopack_core::environment::{ EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc, }; use turbopack_ecmascript::EcmascriptInputTransform; +use turbopack_node::execution_context::ExecutionContextVc; use crate::{ + next_build::get_postcss_package_mapping, next_client::context::add_next_font_transform, next_config::NextConfigVc, next_import_map::{get_next_build_import_map, get_next_server_import_map}, @@ -78,23 +80,42 @@ pub fn get_server_environment( } #[turbo_tasks::function] -pub fn get_server_module_options_context(ty: Value<ServerContextType>) -> ModuleOptionsContextVc { +pub fn get_server_module_options_context( + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, + ty: Value<ServerContextType>, +) -> ModuleOptionsContextVc { let module_options_context = match ty.into_value() { ServerContextType::Pages { .. } => ModuleOptionsContext { - enable_typescript_transform: true, enable_styled_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), + enable_typescript_transform: true, + execution_context: Some(execution_context), ..Default::default() }, ServerContextType::AppSSR { .. } => ModuleOptionsContext { enable_styled_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), enable_typescript_transform: true, + execution_context: Some(execution_context), ..Default::default() }, ServerContextType::AppRSC { .. } => ModuleOptionsContext { + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), enable_typescript_transform: true, custom_ecmascript_transforms: vec![EcmascriptInputTransform::ClientDirective( StringVc::cell("server-to-client".to_string()), )], + execution_context: Some(execution_context), ..Default::default() }, } diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 33f95911aa23cf..cc80fe9da8d274 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -31,9 +31,11 @@ use turbopack_ecmascript::{ }; use turbopack_env::ProcessEnvAssetVc; use turbopack_node::{ - create_node_api_source, create_node_rendered_source, - node_entry::{NodeRenderingEntry, NodeRenderingEntryVc}, - NodeEntry, NodeEntryVc, + execution_context::ExecutionContextVc, + render::{ + node_api_source::create_node_api_source, rendered_source::create_node_rendered_source, + }, + NodeEntry, NodeEntryVc, NodeRenderingEntry, NodeRenderingEntryVc, }; use crate::{ @@ -61,14 +63,15 @@ use crate::{ /// Next.js pages folder. #[turbo_tasks::function] pub async fn create_server_rendered_source( - project_path: FileSystemPathVc, + project_root: FileSystemPathVc, + execution_context: ExecutionContextVc, output_path: FileSystemPathVc, server_root: FileSystemPathVc, env: ProcessEnvVc, browserslist_query: &str, next_config: NextConfigVc, ) -> Result<ContentSourceVc> { - let project_path = wrap_with_next_js_fs(project_path); + let project_path = wrap_with_next_js_fs(project_root); let pages = project_path.join("pages"); let src_pages = project_path.join("src/pages"); @@ -85,7 +88,7 @@ pub async fn create_server_rendered_source( let client_environment = get_client_environment(browserslist_query); let client_module_options_context = - get_client_module_options_context(project_path, client_environment, ty); + get_client_module_options_context(project_path, execution_context, client_environment, ty); let client_module_options_context = add_next_transforms_to_pages(client_module_options_context, pages_dir); let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); @@ -118,7 +121,7 @@ pub async fn create_server_rendered_source( let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), get_server_environment(server_ty, env), - get_server_module_options_context(server_ty), + get_server_module_options_context(project_path, execution_context, server_ty), get_server_resolve_options_context(project_path, server_ty, next_config), ) .into(); @@ -131,6 +134,7 @@ pub async fn create_server_rendered_source( let fallback_page = get_fallback_page( project_path, + execution_context, server_root, env, browserslist_query, diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 0174c750d96d98..790421589a34c6 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -12,6 +12,7 @@ use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, }; +use turbopack_node::execution_context::ExecutionContextVc; use crate::{ embed_js::wrap_with_next_js_fs, @@ -25,6 +26,7 @@ use crate::{ #[turbo_tasks::function] pub async fn create_web_entry_source( project_root: FileSystemPathVc, + execution_context: ExecutionContextVc, entry_requests: Vec<RequestVc>, server_root: FileSystemPathVc, env: ProcessEnvVc, @@ -35,7 +37,7 @@ pub async fn create_web_entry_source( let project_root = wrap_with_next_js_fs(project_root); let ty = Value::new(ContextType::Other); - let context = get_client_asset_context(project_root, browserslist_query, ty); + let context = get_client_asset_context(project_root, execution_context, browserslist_query, ty); let chunking_context = get_client_chunking_context(project_root, server_root, ty); let entries = get_client_runtime_entries(project_root, env, ty, next_config); diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index 8cb782a7903384..c5dd0e22524b73 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -55,6 +55,7 @@ turbo-tasks-memory = { path = "../turbo-tasks-memory" } turbopack-cli-utils = { path = "../turbopack-cli-utils" } turbopack-core = { path = "../turbopack-core" } turbopack-dev-server = { path = "../turbopack-dev-server" } +turbopack-node = { path = "../turbopack-node" } webbrowser = "0.7.1" [dev-dependencies] diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 7556f178d9d7dd..7e83889bc28f7f 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -19,7 +19,7 @@ use devserver_options::DevServerOptions; use next_core::{ create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, manifest::DevManifestContentSource, next_config::load_next_config, - next_image::NextImageContentSourceVc, source_map::NextSourceMapTraceContentSourceVc, + next_image::NextImageContentSourceVc, }; use owo_colors::OwoColorize; use turbo_malloc::TurboMalloc; @@ -44,6 +44,9 @@ use turbopack_dev_server::{ }, DevServer, }; +use turbopack_node::{ + execution_context::ExecutionContextVc, source_map::NextSourceMapTraceContentSourceVc, +}; #[derive(Clone)] pub enum EntryRequest { @@ -276,8 +279,11 @@ async fn source( let project_path = fs.root().join(project_relative); let env = load_env(project_path); - let config_output_root = output_fs.root().join(".next/config"); - let next_config = load_next_config(project_path, config_output_root); + let build_output_root = output_fs.root().join(".next/build"); + + let execution_context = ExecutionContextVc::new(project_path, build_output_root); + + let next_config = load_next_config(execution_context.join("next_config")); let output_root = output_fs.root().join(".next/server"); @@ -295,6 +301,7 @@ async fn source( let web_source = create_web_entry_source( project_path, + execution_context, entry_requests, dev_server_root, env, @@ -304,6 +311,7 @@ async fn source( ); let rendered_source = create_server_rendered_source( project_path, + execution_context, output_root.join("pages"), dev_server_root, env, @@ -312,6 +320,7 @@ async fn source( ); let app_source = create_app_source( project_path, + execution_context, output_root.join("app"), dev_server_root, env, diff --git a/packages/next-swc/crates/next-dev/tests/integration.rs b/packages/next-swc/crates/next-dev/tests/integration.rs index 64df900fc48a2b..79b0f8140abc31 100644 --- a/packages/next-swc/crates/next-dev/tests/integration.rs +++ b/packages/next-swc/crates/next-dev/tests/integration.rs @@ -146,6 +146,9 @@ async fn run_test(resource: &str) -> JestRunResult { .eager_compile(false) .hostname(requested_addr.ip()) .port(requested_addr.port()) + .log_level(turbopack_core::issue::IssueSeverity::Warning) + .log_detail(true) + .show_all(true) .build() .await .unwrap(); diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/next.config.js b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/next.config.js new file mode 100644 index 00000000000000..3dd7ef15191a9f --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/next.config.js @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +module.exports = { + reactStrictMode: true, +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/_app.tsx b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/_app.tsx new file mode 100644 index 00000000000000..8c4d5de82a32cb --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/_app.tsx @@ -0,0 +1,8 @@ +import "../styles/globals.css"; +import type { AppProps } from "next/app"; + +function MyApp({ Component, pageProps }: AppProps) { + return <Component {...pageProps} />; +} + +export default MyApp; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/api/hello.ts b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/api/hello.ts new file mode 100644 index 00000000000000..74a3605dbbba72 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/api/hello.ts @@ -0,0 +1,13 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from "next"; + +type Data = { + name: string; +}; + +export default function handler( + req: NextApiRequest, + res: NextApiResponse<Data> +) { + res.status(200).json({ name: "John Doe" }); +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/index.jsx b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/index.jsx new file mode 100644 index 00000000000000..124baa66644b23 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/pages/index.jsx @@ -0,0 +1,106 @@ +import Head from "next/head"; +import Image from "next/image"; +import { useEffect } from "react"; +import { Deferred } from "@turbo/pack-test-harness/deferred"; + +let testResult = new Deferred(); + +const Home = () => { + useEffect(() => { + // Only run on client + import("@turbo/pack-test-harness").then(runTests); + }); + return ( + <div className="flex min-h-screen flex-col items-center justify-center py-2"> + <Head> + <title>Create Next App + + + +
+

+ Welcome to{" "} + + Next.js! + +

+ +

+ Get started by editing{" "} + + pages/index.tsx + +

+ + +
+ + + + ); +}; + +export default Home; + +globalThis.waitForTests = function () { + return testResult.promise; +}; + +function runTests() { + console.log(document.querySelectorAll("footer")); + it("it should apply tailwind styles", function () { + const footer = document.querySelector("footer"); + expect(getComputedStyle(footer).alignItems).toBe("center"); + }); + testResult.resolve(__jest__.run()); +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/postcss.config.js b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/postcss.config.js new file mode 100644 index 00000000000000..12a703d900da81 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/public/favicon.ico b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4965832f2c9b0605eaa189b7c7fb11124d24e48a GIT binary patch literal 15086 zcmeHOOH5Q(7(R0cc?bh2AT>N@1PWL!LLfZKyG5c!MTHoP7_p!sBz0k$?pjS;^lmgJ zU6^i~bWuZYHL)9$wuvEKm~qo~(5=Lvx5&Hv;?X#m}i|`yaGY4gX+&b>tew;gcnRQA1kp zBbm04SRuuE{Hn+&1wk%&g;?wja_Is#1gKoFlI7f`Gt}X*-nsMO30b_J@)EFNhzd1QM zdH&qFb9PVqQOx@clvc#KAu}^GrN`q5oP(8>m4UOcp`k&xwzkTio*p?kI4BPtIwX%B zJN69cGsm=x90<;Wmh-bs>43F}ro$}Of@8)4KHndLiR$nW?*{Rl72JPUqRr3ta6e#A z%DTEbi9N}+xPtd1juj8;(CJt3r9NOgb>KTuK|z7!JB_KsFW3(pBN4oh&M&}Nb$Ee2 z$-arA6a)CdsPj`M#1DS>fqj#KF%0q?w50GN4YbmMZIoF{e1yTR=4ablqXHBB2!`wM z1M1ke9+<);|AI;f=2^F1;G6Wfpql?1d5D4rMr?#f(=hkoH)U`6Gb)#xDLjoKjp)1;Js@2Iy5yk zMXUqj+gyk1i0yLjWS|3sM2-1ECc;MAz<4t0P53%7se$$+5Ex`L5TQO_MMXXi04UDIU+3*7Ez&X|mj9cFYBXqM{M;mw_ zpw>azP*qjMyNSD4hh)XZt$gqf8f?eRSFX8VQ4Y+H3jAtvyTrXr`qHAD6`m;aYmH2zOhJC~_*AuT} zvUxC38|JYN94i(05R)dVKgUQF$}#cxV7xZ4FULqFCNX*Forhgp*yr6;DsIk=ub0Hv zpk2L{9Q&|uI^b<6@i(Y+iSxeO_n**4nRLc`P!3ld5jL=nZRw6;DEJ*1z6Pvg+eW|$lnnjO zjd|8>6l{i~UxI244CGn2kK@cJ|#ecwgSyt&HKA2)z zrOO{op^o*- + + \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/styles/globals.css b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/styles/globals.css new file mode 100644 index 00000000000000..b5c61c956711f9 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/styles/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tailwind.config.js b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tailwind.config.js new file mode 100644 index 00000000000000..25d605c413251b --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tailwind.config.js @@ -0,0 +1,12 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./pages/**/*.{js,ts,jsx,tsx}", + "./components/**/*.{js,ts,jsx,tsx}", + "./app/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tsconfig.json b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tsconfig.json new file mode 100644 index 00000000000000..6cee014958c282 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/tailwind/basic/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/index.jsx"], + "exclude": ["node_modules"] +} diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 3c199f47d134cf..3a8a7e67155fff 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -2,10 +2,13 @@ "private": true, "devDependencies": { "@turbo/pack-test-harness": "*", + "autoprefixer": "^10.4.13", "next": "13.0.1", + "postcss": "^8.4.20", "react": "^18.2.0", "react-dom": "^18.2.0", "react-test-renderer": "^18.2.0", - "styled-jsx": "^5.1.0" + "styled-jsx": "^5.1.0", + "tailwindcss": "^3.2.4" } } From 3ce0c6a917eeee5cea9fb08f0f256c74c1f5063f Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Mon, 19 Dec 2022 17:29:28 -0500 Subject: [PATCH 284/672] Fix postcss nitpicks (vercel/turbo#3077) Re: vercel/turbo#3065 It also fixes the gnarly stack trace error whenever the node code throws, but it doesn't look very pretty. Not sure how to handle it: Screen Shot 2022-12-19 at 3 46 56 PM --- .../crates/next-core/js/src/ipc/evaluate.ts | 44 ------------------- .../crates/next-core/src/next_config.rs | 37 +++++++++------- 2 files changed, 20 insertions(+), 61 deletions(-) delete mode 100644 packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts diff --git a/packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts b/packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts deleted file mode 100644 index 7c8a8712c1899d..00000000000000 --- a/packages/next-swc/crates/next-core/js/src/ipc/evaluate.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { IPC, Ipc } from "./index"; - -type IpcIncomingMessage = { - type: "evaluate"; - filepath: string; - arguments: string[]; -}; - -type IpcOutgoingMessage = { - type: "jsonValue"; - data: string; -}; - -const ipc = IPC as Ipc; - -(async () => { - while (true) { - const msg = await ipc.recv(); - - switch (msg.type) { - case "evaluate": { - const { execute } = eval("require")(msg.filepath); - if (typeof execute !== "function") { - console.error( - `Expected ${msg.filepath} to export a function named "execute"` - ); - process.exit(1); - } - const value = await execute.apply(null, msg.arguments); - await ipc.send({ - type: "jsonValue", - data: JSON.stringify(value), - }); - break; - } - default: { - console.error("unexpected message type", msg.type); - process.exit(1); - } - } - } -})().catch((err) => { - ipc.sendError(err); -}); diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index ceee16eddc1f04..aec505086e5c0f 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -7,12 +7,15 @@ use turbo_tasks::{ trace::TraceRawVcs, Value, }; -use turbo_tasks_fs::FileSystemEntryType; use turbopack::evaluate_context::node_evaluate_asset_context; use turbopack_core::{ asset::Asset, reference_type::{EntryReferenceSubType, ReferenceType}, - resolve::options::{ImportMap, ImportMapping}, + resolve::{ + find_context_file, + options::{ImportMap, ImportMapping}, + FindContextFileResult, + }, source_asset::SourceAssetVc, }; use turbopack_ecmascript::{ @@ -27,7 +30,7 @@ use turbopack_node::{ use crate::embed_js::next_asset; #[turbo_tasks::value(serialization = "custom")] -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct NextConfig { pub config_file: Option, @@ -200,6 +203,15 @@ impl NextConfigVc { } } +fn next_configs() -> StringsVc { + StringsVc::cell( + ["next.config.mjs", "next.config.js"] + .into_iter() + .map(ToOwned::to_owned) + .collect(), + ) +} + #[turbo_tasks::function] pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result { let ExecutionContext { @@ -212,20 +224,10 @@ pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result Some(SourceAssetVc::new(*config_path)), + FindContextFileResult::NotFound(_) => None, }; let runtime_entries = config_asset.map(|config_asset| { @@ -262,6 +264,7 @@ pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result Ok(NextConfig::default().cell()), JavaScriptValue::Stream(_) => { unimplemented!("Stream not supported now"); } From 147745bdb966ad1ea8c09c341f53d9216add9e1f Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 19 Dec 2022 16:26:27 -0800 Subject: [PATCH 285/672] @next/font/google: scope font names (vercel/turbo#3049) Fixes WEB-341 This incorporates a digest of the font request into the name of the font-family defined in the stylesheet, used in the css class, and returned to the JavaScript importer. This makes font-family names returned from `@next/font/google` in stylesheets unguessable. Note that this implementation uses 8-character long hex digests compared to the 6-character version in Next.js+webpack. Test Plan: imported Open Sans as a symbol, verified that stylesheet is updated to reference both `@font-face` definitions and the css class rules with `font-family: '__Open_Sans_3b020fa1';`. Verified that exported js object `style.fontFamily` references the same. --- .../next-core/src/next_font_google/mod.rs | 81 ++++++++++++++----- .../next-core/src/next_font_google/options.rs | 1 + 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs index d3a14bc13968c7..1dff39f2592eaa 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/mod.rs @@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result}; use indexmap::IndexMap; use indoc::formatdoc; use once_cell::sync::Lazy; -use turbo_tasks::primitives::{OptionStringVc, OptionU16Vc, StringVc}; +use turbo_tasks::primitives::{OptionStringVc, OptionU16Vc, StringVc, U32Vc}; use turbo_tasks_fetch::fetch; use turbo_tasks_fs::{FileContent, FileSystemPathVc}; use turbo_tasks_hash::hash_xxh3_hash64; @@ -72,11 +72,11 @@ impl ImportMappingReplacement for NextFontGoogleReplacer { let query = &*query_vc.await?; let options = font_options_from_query_map(*query_vc); - let properties = get_font_css_properties(options).await?; - let request_id = get_request_id(*query_vc).await?.await?; + let properties = + get_font_css_properties(get_scoped_font_family(*query_vc), options).await?; let js_asset = VirtualAssetVc::new( attached_next_js_package_path(self.project_path) - .join(&format!("internal/font/google/{}.js", request_id)), + .join(&format!("internal/font/google/{}.js", get_request_id(*query_vc).await?)), FileContent::Content( formatdoc!( r#" @@ -147,9 +147,11 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { let options = font_options_from_query_map(*query_vc); let stylesheet_url = get_stylesheet_url_from_options(options); - let request_id = get_request_id(*query_vc).await?.await?; - let css_virtual_path = attached_next_js_package_path(self.project_path) - .join(&format!("internal/font/google/{}.module.css", request_id)); + let scoped_font_family = get_scoped_font_family(*query_vc); + let css_virtual_path = attached_next_js_package_path(self.project_path).join(&format!( + "internal/font/google/{}.module.css", + get_request_id(*query_vc).await? + )); let stylesheet_res = fetch( stylesheet_url, @@ -162,7 +164,11 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { .await?; let stylesheet = match &*stylesheet_res { - Ok(r) => Some(r.await?.body.to_string().await?.clone()), + Ok(r) => Some( + update_stylesheet(r.await?.body.to_string(), options, scoped_font_family) + .await? + .clone(), + ), Err(err) => { // Inform the user of the failure to retreive the stylesheet, but don't // propagate this error. We don't want e.g. offline connections to prevent page @@ -179,8 +185,7 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { } }; - let properties = get_font_css_properties(options).await?; - + let properties = get_font_css_properties(scoped_font_family, options).await?; let css_asset = VirtualAssetVc::new( css_virtual_path, FileContent::Content( @@ -216,7 +221,44 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { } } +#[turbo_tasks::function] +async fn update_stylesheet( + stylesheet: StringVc, + options: NextFontGoogleOptionsVc, + scoped_font_family: StringVc, +) -> Result { + // Update font-family definitions to the scoped name + // TODO: Do this more resiliently, e.g. transforming an swc ast + Ok(StringVc::cell(stylesheet.await?.replace( + &format!("font-family: '{}';", &*options.await?.font_family), + &format!("font-family: '{}';", &*scoped_font_family.await?), + ))) +} + +#[turbo_tasks::function] +async fn get_scoped_font_family(query_vc: QueryMapVc) -> Result { + let options = font_options_from_query_map(query_vc).await?; + + Ok(StringVc::cell(format!( + "__{}_{:x?}", + options.font_family.replace(' ', "_"), + *get_request_hash(query_vc).await? + ))) +} + +#[turbo_tasks::function] async fn get_request_id(query_vc: QueryMapVc) -> Result { + let options = font_options_from_query_map(query_vc).await?; + + Ok(StringVc::cell(format!( + "{}_{:x?}", + options.font_family.to_lowercase().replace(' ', "_"), + get_request_hash(query_vc).await?, + ))) +} + +#[turbo_tasks::function] +async fn get_request_hash(query_vc: QueryMapVc) -> Result { let query = &*query_vc.await?; let query = query.as_ref().context("Query map must be present")?; let mut to_hash = vec![]; @@ -225,12 +267,11 @@ async fn get_request_id(query_vc: QueryMapVc) -> Result { to_hash.push(v); } - let options = font_options_from_query_map(query_vc).await?; - Ok(StringVc::cell(format!( - "{}_{:x?}", - options.font_family.to_lowercase().replace(' ', "_"), - hash_xxh3_hash64(to_hash) - ))) + Ok(U32Vc::cell( + // Truncate the has to u32. These hashes are ultimately displayed as 8-character + // hexadecimal values. + hash_xxh3_hash64(to_hash) as u32, + )) } #[turbo_tasks::function] @@ -262,10 +303,14 @@ struct FontCssProperties { } #[turbo_tasks::function] -async fn get_font_css_properties(options: NextFontGoogleOptionsVc) -> Result { +async fn get_font_css_properties( + scoped_font_family: StringVc, + options: NextFontGoogleOptionsVc, +) -> Result { let options = &*options.await?; + let scoped_font_family = &*scoped_font_family.await?; - let mut font_families = vec![options.font_family.clone()]; + let mut font_families = vec![scoped_font_family.clone()]; if let Some(fallback) = &options.fallback { font_families.extend_from_slice(fallback); } diff --git a/packages/next-swc/crates/next-core/src/next_font_google/options.rs b/packages/next-swc/crates/next-core/src/next_font_google/options.rs index 885ec331d9c30a..0ae5cade0e0267 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/options.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/options.rs @@ -11,6 +11,7 @@ pub type FontData = IndexMap; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] pub struct NextFontGoogleOptions { + /// Name of the requested font from Google. Contains literal spaces. pub font_family: String, pub weights: FontWeights, pub styles: IndexSet, From 2080a0f877f3d02671c10a9f97335f340d8cd6af Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 20 Dec 2022 03:33:41 -0500 Subject: [PATCH 286/672] Fixes `new URL()` during SSR (vercel/turbo#3021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A follow up to vercel/turbo#2944, which incorrectly rewrote the `new URL("…", import.meta.url)` to `new URL("…", location.origin)` during server rendering (which obviously doesn't have a `location` object). This PR accomplishes 2 things: - Splits dev server address binding from setting up the handler function - This is necessary so that we can determine the bound server address during devs retry attempts. - Propagates the server address through the `ExecutionEnvironment` to the `UrlAssetReference` I chose to pipe the server address through the `ExecutionEnvironment` instead of the `EnvironmentIntention`, because I don't fully understand the differences between them. It seems like we want it in the intention for the types of rendering, but a server address is really tied to the node process, so I don't know. Fixes WEB-318 --- .../crates/next-core/src/app_source.rs | 17 ++- .../crates/next-core/src/next_server/mod.rs | 5 +- .../next-core/src/server_rendered_source.rs | 4 +- packages/next-swc/crates/next-dev/src/lib.rs | 100 +++++++++--------- 4 files changed, 69 insertions(+), 57 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index f1332b7099d586..4fda17507c6ed3 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -18,6 +18,7 @@ use turbopack::{ use turbopack_core::{ chunk::dev::DevChunkingContextVc, context::AssetContextVc, + environment::ServerAddrVc, issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, virtual_asset::VirtualAssetVc, }; @@ -129,6 +130,7 @@ fn next_ssr_client_module_transition( app_dir: FileSystemPathVc, process_env: ProcessEnvVc, next_config: NextConfigVc, + server_addr: ServerAddrVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppSSR { app_dir }); NextSSRClientModuleTransition { @@ -142,7 +144,7 @@ fn next_ssr_client_module_transition( ty, next_config, ), - ssr_environment: get_server_environment(ty, process_env), + ssr_environment: get_server_environment(ty, process_env, server_addr), } .cell() .into() @@ -156,9 +158,10 @@ fn next_layout_entry_transition( server_root: FileSystemPathVc, process_env: ProcessEnvVc, next_config: NextConfigVc, + server_addr: ServerAddrVc, ) -> TransitionVc { let ty = Value::new(ServerContextType::AppRSC { app_dir }); - let rsc_environment = get_server_environment(ty, process_env); + let rsc_environment = get_server_environment(ty, process_env, server_addr); let rsc_resolve_options_context = get_server_resolve_options_context(project_path, ty, next_config); let rsc_module_options_context = @@ -174,6 +177,7 @@ fn next_layout_entry_transition( .into() } +#[allow(clippy::too_many_arguments)] #[turbo_tasks::function] fn app_context( project_path: FileSystemPathVc, @@ -184,6 +188,7 @@ fn app_context( browserslist_query: &str, ssr: bool, next_config: NextConfigVc, + server_addr: ServerAddrVc, ) -> AssetContextVc { let next_server_to_client_transition = NextServerToClientTransition { ssr }.cell().into(); @@ -197,6 +202,7 @@ fn app_context( server_root, env, next_config, + server_addr, ), ); transitions.insert( @@ -233,13 +239,14 @@ fn app_context( app_dir, env, next_config, + server_addr, ), ); let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir }); ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), - get_server_environment(ssr_ty, env), + get_server_environment(ssr_ty, env, server_addr), get_server_module_options_context(project_path, execution_context, ssr_ty), get_server_resolve_options_context(project_path, ssr_ty, next_config), ) @@ -257,6 +264,7 @@ pub async fn create_app_source( env: ProcessEnvVc, browserslist_query: &str, next_config: NextConfigVc, + server_addr: ServerAddrVc, ) -> Result { let project_path = wrap_with_next_js_fs(project_path); @@ -283,6 +291,7 @@ pub async fn create_app_source( browserslist_query, true, next_config, + server_addr, ); let context = app_context( project_path, @@ -293,6 +302,7 @@ pub async fn create_app_source( browserslist_query, false, next_config, + server_addr, ); let server_runtime_entries = @@ -327,6 +337,7 @@ pub async fn create_app_source( .into()) } +#[allow(clippy::too_many_arguments)] #[turbo_tasks::function] async fn create_app_source_for_directory( context_ssr: AssetContextVc, diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index aba1aeaf5fb680..faa0bd984815fe 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -6,7 +6,7 @@ use turbopack::{ resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, }; use turbopack_core::environment::{ - EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc, + EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc, ServerAddrVc, }; use turbopack_ecmascript::EcmascriptInputTransform; use turbopack_node::execution_context::ExecutionContextVc; @@ -66,10 +66,11 @@ pub fn get_server_resolve_options_context( pub fn get_server_environment( ty: Value, process_env: ProcessEnvVc, + server_addr: ServerAddrVc, ) -> EnvironmentVc { EnvironmentVc::new( Value::new(ExecutionEnvironment::NodeJsLambda( - NodeJsEnvironmentVc::current(process_env), + NodeJsEnvironmentVc::current(process_env, server_addr), )), match ty.into_value() { ServerContextType::Pages { .. } => Value::new(EnvironmentIntention::ServerRendering), diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index cc80fe9da8d274..843056e8247b39 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -12,6 +12,7 @@ use turbopack_core::{ asset::AssetVc, chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, context::AssetContextVc, + environment::ServerAddrVc, reference_type::{EntryReferenceSubType, ReferenceType}, source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, @@ -70,6 +71,7 @@ pub async fn create_server_rendered_source( env: ProcessEnvVc, browserslist_query: &str, next_config: NextConfigVc, + server_addr: ServerAddrVc, ) -> Result { let project_path = wrap_with_next_js_fs(project_root); @@ -120,7 +122,7 @@ pub async fn create_server_rendered_source( transitions.insert("next-client".to_string(), next_client_transition); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), - get_server_environment(server_ty, env), + get_server_environment(server_ty, env, server_addr), get_server_module_options_context(project_path, execution_context, server_ty), get_server_resolve_options_context(project_path, server_ty, next_config), ) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 7e83889bc28f7f..9109bc4d97a614 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -31,6 +31,7 @@ use turbo_tasks_fs::{DiskFileSystemVc, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; use turbopack_core::{ + environment::ServerAddr, issue::IssueSeverity, resolve::{parse::RequestVc, pattern::QueryMapVc}, }; @@ -139,57 +140,21 @@ impl NextDevServerBuilder { } pub async fn build(self) -> Result { - let turbo_tasks = self.turbo_tasks; - - let project_dir = self.project_dir; - let root_dir = self.root_dir; - let eager_compile = self.eager_compile; - let show_all = self.show_all; - let log_detail = self.log_detail; - let browserslist_query = self.browserslist_query; - let log_options = LogOptions { - current_dir: current_dir().unwrap(), - show_all, - log_detail, - log_level: self.log_level, - }; - let entry_requests = Arc::new(self.entry_requests.clone()); - let console_ui = Arc::new(ConsoleUi::new(log_options)); - let console_ui_to_dev_server = console_ui.clone(); - let start_port = self.port.context("port must be set")?; let host = self.hostname.context("hostname must be set")?; - let mut err: Option = None; - - let tasks = turbo_tasks.clone(); - let source = move || { - source( - root_dir.clone(), - project_dir.clone(), - entry_requests.clone().into(), - eager_compile, - turbo_tasks.clone().into(), - console_ui.clone().into(), - browserslist_query.clone(), - ) - }; - // Retry to listen on the different port if the port is already in use. + let mut bound_server = None; for retry_count in 0..10 { let current_port = start_port + retry_count; let addr = SocketAddr::new(host, current_port); - let listen_result = DevServer::listen( - tasks.clone(), - source.clone(), - addr, - console_ui_to_dev_server.clone(), - ); + let listen_result = DevServer::listen(addr); match listen_result { Ok(server) => { - return Ok(server); + bound_server = Some(Ok(server)); + break; } Err(e) => { let should_retry = if self.allow_retry { @@ -211,23 +176,55 @@ impl NextDevServerBuilder { false }; - if !should_retry { - return Err(e); - } else { + if should_retry { println!( "{} - Port {} is in use, trying {} instead", "warn ".yellow(), current_port, current_port + 1 ); + } else { + bound_server = Some(Err(e)); + break; } - - err = Some(e); } } } - Err(err.expect("Should have an error if we get here")) + let server = bound_server.unwrap()?; + + let turbo_tasks = self.turbo_tasks; + let project_dir = self.project_dir; + let root_dir = self.root_dir; + let eager_compile = self.eager_compile; + let show_all = self.show_all; + let log_detail = self.log_detail; + let browserslist_query = self.browserslist_query; + let log_options = LogOptions { + current_dir: current_dir().unwrap(), + show_all, + log_detail, + log_level: self.log_level, + }; + let entry_requests = Arc::new(self.entry_requests); + let console_ui = Arc::new(ConsoleUi::new(log_options)); + let console_ui_to_dev_server = console_ui.clone(); + let server_addr = Arc::new(server.addr); + let tasks = turbo_tasks.clone(); + let source = move || { + source( + root_dir.clone(), + project_dir.clone(), + entry_requests.clone().into(), + eager_compile, + turbo_tasks.clone().into(), + console_ui.clone().into(), + browserslist_query.clone(), + server_addr.clone().into(), + ) + }; + + Ok(server.serve(tasks, source, console_ui_to_dev_server)) } } @@ -259,6 +256,7 @@ async fn output_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result>, console_ui: TransientInstance, browserslist_query: String, + server_addr: TransientInstance, ) -> Result { let console_ui = (*console_ui).clone().cell(); let output_fs = output_fs(&project_dir, console_ui); @@ -286,6 +285,7 @@ async fn source( let next_config = load_next_config(execution_context.join("next_config")); let output_root = output_fs.root().join(".next/server"); + let server_addr = ServerAddr::new(*server_addr).cell(); let dev_server_fs = DevServerFileSystemVc::new().as_file_system(); let dev_server_root = dev_server_fs.root(); @@ -317,6 +317,7 @@ async fn source( env, &browserslist_query, next_config, + server_addr, ); let app_source = create_app_source( project_path, @@ -326,6 +327,7 @@ async fn source( env, &browserslist_query, next_config, + server_addr, ); let viz = turbo_tasks_viz::TurboTasksSource { turbo_tasks: turbo_tasks.into(), @@ -447,11 +449,7 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { let server = server.build().await?; { - let index_uri = if server.addr.ip().is_loopback() || server.addr.ip().is_unspecified() { - format!("http://localhost:{}", server.addr.port()) - } else { - format!("http://{}", server.addr) - }; + let index_uri = ServerAddr::new(server.addr).to_string()?; println!( "{} - started server on {}:{}, url: {}", "ready".green(), From f95036cde0435c0d2b99afd90cb2a78ecaf7fc98 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 20 Dec 2022 14:17:22 +0100 Subject: [PATCH 287/672] Update Vite benchmarks to use Vite 4 (vercel/turbo#3089) --- .../next-swc/crates/next-dev/benches/bundlers/vite/mod.rs | 6 +++--- .../next-dev/benches/bundlers/vite/vite.swc.config.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs index 4170adbd69cf4f..beb652511189d0 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/mod.rs @@ -42,11 +42,11 @@ impl Bundler for Vite { } fn prepare(&self, install_dir: &Path) -> Result<()> { - let mut packages = vec![NpmPackage::new("vite", "^3.2.4")]; + let mut packages = vec![NpmPackage::new("vite", "4.0.2")]; if self.swc { - packages.push(NpmPackage::new("vite-plugin-swc-react-refresh", "^2.2.1")); + packages.push(NpmPackage::new("@vitejs/plugin-react-swc", "3.0.1")); } else { - packages.push(NpmPackage::new("@vitejs/plugin-react", "^2.2.0")); + packages.push(NpmPackage::new("@vitejs/plugin-react", "3.0.0")); }; if self.ssr { packages.push(NpmPackage::new("express", "^4.18.2")); diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js index ad4d9c808f4d74..642ef87a8e9a79 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js +++ b/packages/next-swc/crates/next-dev/benches/bundlers/vite/vite.swc.config.js @@ -1,7 +1,7 @@ import { defineConfig } from "vite"; -import { swcReactRefresh } from "vite-plugin-swc-react-refresh"; +import react from "@vitejs/plugin-react-swc"; export default defineConfig({ - plugins: [swcReactRefresh()], + plugins: [react()], esbuild: { jsx: "automatic" }, }); From 13a02d3728ccb50ce96a3b741f3c969ee969dfee Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 20 Dec 2022 16:54:54 +0100 Subject: [PATCH 288/672] add progress output to command line (vercel/turbo#3061) add counting seconds when something is happening. Only starts to show when compilation takes more than 1s Co-authored-by: Alex Kirszenberg --- packages/next-swc/crates/next-dev/src/lib.rs | 49 ++++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 9109bc4d97a614..bcee97d9af4379 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -8,6 +8,7 @@ use std::{ collections::HashSet, env::current_dir, future::{join, Future}, + io::{stdout, Write}, net::{IpAddr, SocketAddr}, path::MAIN_SEPARATOR, sync::Arc, @@ -478,27 +479,45 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { ); } + let mut progress_counter = 0; loop { let update_future = profile_timeout( tt_clone.as_ref(), - tt_clone.get_or_wait_update_info(Duration::from_millis(100)), + tt_clone.update_info(Duration::from_millis(100), Duration::from_secs(1)), ); - let (elapsed, count) = update_future.await; - if options.log_detail { - println!( - "{event_type} - updated in {elapsed} ({tasks} tasks, {memory})", - event_type = "event".purple(), - elapsed = FormatDuration(elapsed), - tasks = count, - memory = FormatBytes(TurboMalloc::memory_usage()) - ); + if let Some((elapsed, count)) = update_future.await { + progress_counter = 0; + if options.log_detail { + println!( + "\x1b[2K{event_type} - updated in {elapsed} ({tasks} tasks, {memory})", + event_type = "event".purple(), + elapsed = FormatDuration(elapsed), + tasks = count, + memory = FormatBytes(TurboMalloc::memory_usage()) + ); + } else { + println!( + "\x1b[2K{event_type} - updated in {elapsed}", + event_type = "event".purple(), + elapsed = FormatDuration(elapsed), + ); + } } else { - println!( - "{event_type} - updated in {elapsed}", - event_type = "event".purple(), - elapsed = FormatDuration(elapsed), - ); + progress_counter += 1; + if options.log_detail { + print!( + "\x1b[2K{event_type} - updating for {progress_counter}s... ({memory})\r", + event_type = "event".purple(), + memory = FormatBytes(TurboMalloc::memory_usage()) + ); + } else { + print!( + "\x1b[2K{event_type} - updating for {progress_counter}s...\r", + event_type = "event".purple(), + ); + } + let _ = stdout().lock().flush(); } } }; From 16745ac09e5b239aaea1b4d78f739ade785c6226 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 20 Dec 2022 18:26:39 +0100 Subject: [PATCH 289/672] handle dependencies reported by postcss (vercel/turbo#3091) pass the dependencies reported by postcss to turbo-tasks-fs. We don't have a good mechanism to track dependencies back-timed, so we start watching some as soon we know about the dependencies (after postcss compilation) tailwind reports dependencies as directory + glob, so our globbing need some improvements to handle these globs reported by tailwind. e.g. tailwind will rerun when any file changed from the tailwind config `content` globs. fixes WEB-356 Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/next-swc/crates/next-core/src/next_config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index aec505086e5c0f..91b38748338325 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -253,6 +253,7 @@ pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result Date: Wed, 21 Dec 2022 02:38:44 -0500 Subject: [PATCH 290/672] Fix server generation of 404 pages (vercel/turbo#3103) Any `404.js` page would inject a `[...]` path into the server generation. The problem comes from the `pathname_for_path` function, which will extract the extension from that path. In this case, it leads to a basename of `[...` and an extension of `]`, breaking the `regular_expression_for_path` dynamic route parser. Unfortunately, our integration tests timeout when I try to write a basic test case for this, so it's not possible to test at the moment. I've manually verified. Fixes WEB-214 --- .../next-swc/crates/next-core/src/server_rendered_source.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index 843056e8247b39..e9cee8136851d1 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -318,7 +318,7 @@ async fn create_server_rendered_source_for_directory( ) } else if basename == "404" { ( - server_path.join("[...]"), + server_path.join("[...].html"), intermediate_output_path.join(basename), specificity.with_fallback(position), ) From 0ce3005edbe8f717041d6779d21178b471dc7d03 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 21 Dec 2022 09:53:56 +0100 Subject: [PATCH 291/672] add more info to the profiling table (vercel/turbo#3062) --- .../next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index fd3bbba87e2680..20b4d41bbed85a 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -76,13 +76,10 @@ impl ContentSource for TurboTasksSource { let mut stats = Stats::new(); let b = tt.backend(); let active_only = query.contains_key("active"); + let include_unloaded = query.contains_key("unloaded"); b.with_all_cached_tasks(|task| { stats.add_id_conditional(b, task, |_, info| { - (!active_only || info.active) - && info - .executions - .map(|executions| executions > 0) - .unwrap_or(true) + (include_unloaded || !info.unloaded) && (!active_only || info.active) }); }); let tree = stats.treeify(ReferenceType::Dependency); @@ -94,9 +91,7 @@ impl ContentSource for TurboTasksSource { source: self_vc.into(), path: path.to_string(), vary: ContentSourceDataVary { - query: Some(ContentSourceDataFilter::Subset( - ["active".to_string()].into(), - )), + query: Some(ContentSourceDataFilter::All), ..Default::default() }, } From 91d2af216b0685248763899f6d5796656ea94010 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 21 Dec 2022 16:57:53 +0100 Subject: [PATCH 292/672] Avoid creating a new api node.js pool for every request (vercel/turbo#3110) Co-authored-by: Alex Kirszenberg --- .../crates/next-core/src/app_source.rs | 43 ++++++++++++------- .../next-core/src/server_rendered_source.rs | 28 ++++++++---- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 4fda17507c6ed3..b91c9359e7171b 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -498,16 +498,12 @@ struct AppRenderer { } #[turbo_tasks::value_impl] -impl NodeEntry for AppRenderer { +impl AppRendererVc { #[turbo_tasks::function] - async fn entry(&self, data: Value) -> Result { - let is_rsc = if let Some(headers) = data.into_value().headers { - headers.contains_key("rsc") - } else { - false - }; - let layout_path = self.layout_path.await?; - let page = self.page_path; + async fn entry(self, is_rsc: bool) -> Result { + let this = self.await?; + let layout_path = this.layout_path.await?; + let page = this.page_path; let path = page.parent(); let path_value = &*path.await?; let layout_and_page = layout_path @@ -516,7 +512,7 @@ impl NodeEntry for AppRenderer { .chain(std::iter::once( LayoutSegment { files: HashMap::from([("page".to_string(), page)]), - target: self.target, + target: this.target, } .cell(), )) @@ -525,7 +521,7 @@ impl NodeEntry for AppRenderer { let segments: Vec<_> = layout_and_page .into_iter() .fold( - (self.server_root, Vec::new()), + (this.server_root, Vec::new()), |(last_path, mut futures), segment| { (segment.target, { futures.push(async move { @@ -618,19 +614,19 @@ import BOOTSTRAP from {}; let file = File::from(result.build()); let asset = VirtualAssetVc::new(path.join("entry"), file.into()); let (context, intermediate_output_path) = if is_rsc { - (self.context, self.intermediate_output_path.join("rsc")) + (this.context, this.intermediate_output_path.join("rsc")) } else { - (self.context_ssr, self.intermediate_output_path) + (this.context_ssr, this.intermediate_output_path) }; let chunking_context = DevChunkingContextVc::builder( - self.project_path, + this.project_path, intermediate_output_path, intermediate_output_path.join("chunks"), - self.server_root.join("_next/static/assets"), + this.server_root.join("_next/static/assets"), ) .layer("ssr") - .css_chunk_root_path(self.server_root.join("_next/static/chunks")) + .css_chunk_root_path(this.server_root.join("_next/static/chunks")) .build(); Ok(NodeRenderingEntry { @@ -651,6 +647,21 @@ import BOOTSTRAP from {}; } } +#[turbo_tasks::value_impl] +impl NodeEntry for AppRenderer { + #[turbo_tasks::function] + fn entry(self_vc: AppRendererVc, data: Value) -> NodeRenderingEntryVc { + let data = data.into_value(); + let is_rsc = if let Some(headers) = data.headers { + headers.contains_key("rsc") + } else { + false + }; + // Call with only is_rsc as key + self_vc.entry(is_rsc) + } +} + #[turbo_tasks::value(shared)] struct AppSourceIssue { pub severity: IssueSeverityVc, diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/server_rendered_source.rs index e9cee8136851d1..8a87c5e6a83537 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/server_rendered_source.rs @@ -397,17 +397,18 @@ struct SsrEntry { } #[turbo_tasks::value_impl] -impl NodeEntry for SsrEntry { +impl SsrEntryVc { #[turbo_tasks::function] - async fn entry(&self, _data: Value) -> Result { - let virtual_asset = if *self.is_api_path.await? { + async fn entry(self) -> Result { + let this = self.await?; + let virtual_asset = if *this.is_api_path.await? { VirtualAssetVc::new( - self.entry_asset.path().join("server-api.tsx"), + this.entry_asset.path().join("server-api.tsx"), next_js_file("entry/server-api.tsx").into(), ) } else { VirtualAssetVc::new( - self.entry_asset.path().join("server-renderer.tsx"), + this.entry_asset.path().join("server-renderer.tsx"), next_js_file("entry/server-renderer.tsx").into(), ) }; @@ -415,17 +416,26 @@ impl NodeEntry for SsrEntry { Ok(NodeRenderingEntry { module: EcmascriptModuleAssetVc::new( virtual_asset.into(), - self.context, + this.context, Value::new(EcmascriptModuleAssetType::Typescript), EcmascriptInputTransformsVc::cell(vec![ EcmascriptInputTransform::TypeScript, EcmascriptInputTransform::React { refresh: false }, ]), - self.context.environment(), + this.context.environment(), ), - chunking_context: self.chunking_context, - intermediate_output_path: self.intermediate_output_path, + chunking_context: this.chunking_context, + intermediate_output_path: this.intermediate_output_path, } .cell()) } } + +#[turbo_tasks::value_impl] +impl NodeEntry for SsrEntry { + #[turbo_tasks::function] + fn entry(self_vc: SsrEntryVc, _data: Value) -> NodeRenderingEntryVc { + // Call without being keyed by data + self_vc.entry() + } +} From 1a2632d5e560f3c97d520d75ff2583c9ab71047f Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 21 Dec 2022 19:56:52 +0100 Subject: [PATCH 293/672] add rules to alter resolve/module context depending on context path (vercel/turbo#3108) Fixes WEB-43 Closes vercel/turbo#3104 --- .../next-core/src/next_client/context.rs | 27 +++- .../crates/next-core/src/next_import_map.rs | 4 +- .../crates/next-core/src/next_server/mod.rs | 126 ++++++++++++------ 3 files changed, 108 insertions(+), 49 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 24a1f47ff998c9..3ba9c0ab86b996 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -6,6 +6,7 @@ use turbo_tasks::{primitives::StringsVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ + condition::ContextCondition, module_options::{ module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, ModuleRule, ModuleRuleCondition, ModuleRuleEffect, PostCssTransformOptions, @@ -71,9 +72,7 @@ pub fn get_client_resolve_options_context( let next_client_import_map = get_next_client_import_map(project_path, ty); let next_client_fallback_import_map = get_next_client_fallback_import_map(ty); let next_client_resolved_map = get_next_client_resolved_map(project_path, project_path); - ResolveOptionsContext { - enable_typescript: true, - enable_react: true, + let module_options_context = ResolveOptionsContext { enable_node_modules: true, custom_conditions: vec!["development".to_string()], import_map: Some(next_client_import_map), @@ -82,6 +81,15 @@ pub fn get_client_resolve_options_context( browser: true, module: true, ..Default::default() + }; + ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context } .cell() } @@ -99,6 +107,11 @@ pub async fn get_client_module_options_context( .await? .is_found(); + let module_options_context = ModuleOptionsContext { + preset_env_versions: Some(env), + execution_context: Some(execution_context), + ..Default::default() + }; let module_options_context = ModuleOptionsContext { // We don't need to resolve React Refresh for each module. Instead, // we try resolve it once at the root and pass down a context to all @@ -112,9 +125,11 @@ pub async fn get_client_module_options_context( ..Default::default() }), enable_typescript_transform: true, - preset_env_versions: Some(env), - execution_context: Some(execution_context), - ..Default::default() + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context }; Ok(add_next_font_transform(module_options_context.cell())) diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index ef200020d9f5df..b11a41cddbfe37 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -198,7 +198,7 @@ pub fn get_next_client_resolved_map( "**/*/next/dist/client/components/react-dev-overlay/hot-reloader-client.js", ), ImportMapping::PrimaryAlternative( - "@vercel/turbopack-next/dev/hot-reloader".to_string(), + "@vercel/turbopack-next/dev/hot-reloader.tsx".to_string(), Some(root), ) .into(), @@ -243,7 +243,7 @@ pub fn insert_next_shared_aliases(import_map: &mut ImportMap, project_path: File // own import_map.insert_exact_alias( "next/dist/compiled/@next/react-dev-overlay/dist/client", - request_to_import_mapping(package_root, "./overlay/client"), + request_to_import_mapping(package_root, "./overlay/client.ts"), ); insert_package_alias( diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index faa0bd984815fe..60d634e180ddfe 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -2,6 +2,7 @@ use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ + condition::ContextCondition, module_options::{ModuleOptionsContext, ModuleOptionsContextVc, PostCssTransformOptions}, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, }; @@ -35,29 +36,45 @@ pub fn get_server_resolve_options_context( let next_server_import_map = get_next_server_import_map(project_path, ty, next_config); match ty.into_value() { ServerContextType::Pages { .. } | ServerContextType::AppSSR { .. } => { + let resolve_options_context = ResolveOptionsContext { + enable_node_modules: true, + enable_node_externals: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string()], + import_map: Some(next_server_import_map), + module: true, + ..Default::default() + }; ResolveOptionsContext { enable_typescript: true, enable_react: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + resolve_options_context.clone().cell(), + )], + ..resolve_options_context + } + } + ServerContextType::AppRSC { .. } => { + let resolve_options_context = ResolveOptionsContext { enable_node_modules: true, enable_node_externals: true, enable_node_native_modules: true, - custom_conditions: vec!["development".to_string()], + custom_conditions: vec!["development".to_string(), "react-server".to_string()], import_map: Some(next_server_import_map), module: true, ..Default::default() + }; + ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + resolve_options_context.clone().cell(), + )], + ..resolve_options_context } } - ServerContextType::AppRSC { .. } => ResolveOptionsContext { - enable_typescript: true, - enable_react: true, - enable_node_modules: true, - enable_node_externals: true, - enable_node_native_modules: true, - custom_conditions: vec!["development".to_string(), "react-server".to_string()], - import_map: Some(next_server_import_map), - module: true, - ..Default::default() - }, } .cell() } @@ -87,38 +104,65 @@ pub fn get_server_module_options_context( ty: Value, ) -> ModuleOptionsContextVc { let module_options_context = match ty.into_value() { - ServerContextType::Pages { .. } => ModuleOptionsContext { - enable_styled_jsx: true, - enable_postcss_transform: Some(PostCssTransformOptions { - postcss_package: Some(get_postcss_package_mapping(project_path)), + ServerContextType::Pages { .. } => { + let module_options_context = ModuleOptionsContext { + execution_context: Some(execution_context), ..Default::default() - }), - enable_typescript_transform: true, - execution_context: Some(execution_context), - ..Default::default() - }, - ServerContextType::AppSSR { .. } => ModuleOptionsContext { - enable_styled_jsx: true, - enable_postcss_transform: Some(PostCssTransformOptions { - postcss_package: Some(get_postcss_package_mapping(project_path)), + }; + ModuleOptionsContext { + enable_styled_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), + enable_typescript_transform: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context + } + } + ServerContextType::AppSSR { .. } => { + let module_options_context = ModuleOptionsContext { + execution_context: Some(execution_context), ..Default::default() - }), - enable_typescript_transform: true, - execution_context: Some(execution_context), - ..Default::default() - }, - ServerContextType::AppRSC { .. } => ModuleOptionsContext { - enable_postcss_transform: Some(PostCssTransformOptions { - postcss_package: Some(get_postcss_package_mapping(project_path)), + }; + ModuleOptionsContext { + enable_styled_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), + enable_typescript_transform: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context + } + } + ServerContextType::AppRSC { .. } => { + let module_options_context = ModuleOptionsContext { + custom_ecmascript_transforms: vec![EcmascriptInputTransform::ClientDirective( + StringVc::cell("server-to-client".to_string()), + )], + execution_context: Some(execution_context), ..Default::default() - }), - enable_typescript_transform: true, - custom_ecmascript_transforms: vec![EcmascriptInputTransform::ClientDirective( - StringVc::cell("server-to-client".to_string()), - )], - execution_context: Some(execution_context), - ..Default::default() - }, + }; + ModuleOptionsContext { + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), + enable_typescript_transform: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context + } + } } .cell(); From b4da5e00a80aac89bcfb8383db33787084ae3389 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 21 Dec 2022 20:44:18 +0100 Subject: [PATCH 294/672] update to latest next.js (vercel/turbo#3112) * add GlobalError export to layout entry (see https://github.com/vercel/next.js/pull/44066) * update app manifest for CSS (see https://github.com/vercel/next.js/pull/44168) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../next-swc/crates/next-core/js/package.json | 2 +- .../next-core/js/src/entry/app-renderer.tsx | 15 ++++++++------- .../next-core/js/src/entry/app/layout-entry.tsx | 1 + .../next-dev/benches/bundlers/turbopack/mod.rs | 2 +- .../next-swc/crates/next-dev/tests/package.json | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index 70d19d94d9e1a7..092f7c9306efec 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -12,7 +12,7 @@ "@vercel/turbopack-runtime": "latest", "anser": "^2.1.1", "css.escape": "^1.5.1", - "next": "^13.0.6", + "next": "^13.0.8-canary.2", "platform": "1.3.6", "react-dom": "^18.2.0", "react": "^18.2.0", diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 4cffd63707a3b8..d7844e257405c8 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -112,7 +112,7 @@ async function runOperation(renderData: RenderData) { const pageModule = pageItem.page!.module; const Page = pageModule.default; let tree: LoaderTree = ["", {}, { page: [() => Page, "page.js"] }]; - layoutInfoChunks["page.js"] = pageItem.page!.chunks; + layoutInfoChunks["page"] = pageItem.page!.chunks; for (let i = LAYOUT_INFO.length - 2; i >= 0; i--) { const info = LAYOUT_INFO[i]; const components: ComponentsType = {}; @@ -122,7 +122,7 @@ async function runOperation(renderData: RenderData) { } const k = key as FileType; components[k] = [() => info[k]!.module.default, `${k}${i}.js`]; - layoutInfoChunks[`${k}${i}.js`] = info[k]!.chunks; + layoutInfoChunks[`${k}${i}`] = info[k]!.chunks; } tree = [info.segment, { children: tree }, components]; } @@ -145,8 +145,8 @@ async function runOperation(renderData: RenderData) { if (name === "__ssr_module_mapping__") { return manifest; } - if (name === "__client_css_manifest__") { - return {}; + if (name === "__entry_css_files__") { + return __entry_css_files__; } return new Proxy({}, proxyMethodsForModule(name as string, css)); }, @@ -154,14 +154,15 @@ async function runOperation(renderData: RenderData) { }; const manifest: FlightManifest = new Proxy({} as any, proxyMethods(false)); const serverCSSManifest: FlightCSSManifest = {}; - serverCSSManifest.__entry_css__ = {}; + const __entry_css_files__: FlightManifest["__entry_css_files__"] = {}; for (const [key, chunks] of Object.entries(layoutInfoChunks)) { const cssChunks = chunks.filter((path) => path.endsWith(".css")); - serverCSSManifest[key] = cssChunks.map((chunk) => + serverCSSManifest[`${key}.js`] = cssChunks.map((chunk) => JSON.stringify([chunk, [chunk]]) ); + __entry_css_files__[key] = cssChunks; } - serverCSSManifest.__entry_css__ = { + serverCSSManifest.__entry_css_mods__ = { page: serverCSSManifest["page.js"], }; const req: IncomingMessage = { diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx index ad39d203f4a5f7..8fb29229eb8b93 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/layout-entry.tsx @@ -1,6 +1,7 @@ export { default as AppRouter } from "next/dist/client/components/app-router.js"; export { default as LayoutRouter } from "next/dist/client/components/layout-router.js"; export { default as RenderFromTemplateContext } from "next/dist/client/components/render-from-template-context.js"; +export { default as GlobalError } from "next/dist/client/components/error-boundary.js"; export { staticGenerationAsyncStorage } from "next/dist/esm/client/components/static-generation-async-storage.js"; export { requestAsyncStorage } from "next/dist/esm/client/components/request-async-storage.js"; import * as serverHooks from "next/dist/esm/client/components/hooks-server-context.js"; diff --git a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/mod.rs b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/mod.rs index 375bf0886da4e1..06a2550e2e4689 100644 --- a/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/mod.rs +++ b/packages/next-swc/crates/next-dev/benches/bundlers/turbopack/mod.rs @@ -49,7 +49,7 @@ impl Bundler for Turbopack { npm::install( install_dir, &[ - NpmPackage::new("next", "13.0.3"), + NpmPackage::new("next", "13.0.8-canary.2"), // Dependency on this is inserted by swc's preset_env NpmPackage::new("@swc/helpers", "^0.4.11"), ], diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 3a8a7e67155fff..8132728c4f5ea2 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -3,7 +3,7 @@ "devDependencies": { "@turbo/pack-test-harness": "*", "autoprefixer": "^10.4.13", - "next": "13.0.1", + "next": "13.0.8-canary.2", "postcss": "^8.4.20", "react": "^18.2.0", "react-dom": "^18.2.0", From 16b5d734049d0e502822031c663b943e2055f1dc Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Wed, 21 Dec 2022 15:15:21 -0500 Subject: [PATCH 295/672] Fix retrying when port already bound (vercel/turbo#3114) #3021 [removed](https://github.com/vercel/turbo/pull/3021/files#diff-c6405fb94033af4296b1f72626fb990aaf76f645b6ed0f7812c56fcad719cf0eL304-L306) 1 level of error wrapping, and the unwrapping code was not updated to match. --- packages/next-swc/crates/next-dev/src/lib.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index bcee97d9af4379..df00b7e60931c3 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -164,13 +164,9 @@ impl NextDevServerBuilder { // `std::io::ErrorKind::AddrInUse`. e.source() .map(|e| { - e.source() - .map(|e| { - e.downcast_ref::() - .map(|e| e.kind() == std::io::ErrorKind::AddrInUse) - == Some(true) - }) - .unwrap_or_else(|| false) + e.downcast_ref::() + .map(|e| e.kind() == std::io::ErrorKind::AddrInUse) + == Some(true) }) .unwrap_or_else(|| false) } else { From 63c6438a93e99986453fdc6d74b419a4b7c5b430 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 22 Dec 2022 03:35:30 +0100 Subject: [PATCH 296/672] disable counting timer (vercel/turbo#3122) --- packages/next-swc/crates/next-dev/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index df00b7e60931c3..1664a09a22da6e 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -479,7 +479,7 @@ pub async fn start_server(options: &DevServerOptions) -> Result<()> { loop { let update_future = profile_timeout( tt_clone.as_ref(), - tt_clone.update_info(Duration::from_millis(100), Duration::from_secs(1)), + tt_clone.update_info(Duration::from_millis(100), Duration::MAX), ); if let Some((elapsed, count)) = update_future.await { From 8e2672a7a92a8585243b22ee26b99db63a2629b9 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Wed, 21 Dec 2022 23:15:57 -0500 Subject: [PATCH 297/672] Misc ContentSource changes (vercel/turbo#3120) - Adds `details` to `SourceMapContentSource` - Fixes `ty` of `SourceMapContentSource` - Adds default `children` trait method that returns empty children --- packages/next-swc/crates/next-core/src/next_image/mod.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_image/mod.rs b/packages/next-swc/crates/next-core/src/next_image/mod.rs index 2e95511deb4d70..e2e86b8cb61167 100644 --- a/packages/next-swc/crates/next-core/src/next_image/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_image/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use anyhow::Result; use turbo_tasks::{primitives::StringVc, Value}; -use turbopack_core::introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc}; +use turbopack_core::introspect::{Introspectable, IntrospectableVc}; use turbopack_dev_server::source::{ query::QueryValue, ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, @@ -102,9 +102,4 @@ impl Introspectable for NextImageContentSource { fn details(&self) -> StringVc { StringVc::cell("suports dynamic serving of any statically imported image".to_string()) } - - #[turbo_tasks::function] - async fn children(&self) -> Result { - Ok(IntrospectableChildrenVc::cell(HashSet::new())) - } } From 5b7bf963623b7efd2a1b178c36d46a5e9285fbbd Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 22 Dec 2022 05:27:02 +0100 Subject: [PATCH 298/672] separate typescript with types from typescript transformed (vercel/turbo#3118) fixes weird typescript errors caused by types being referenced by .ts files --- packages/next-swc/crates/next-core/src/next_client/context.rs | 1 + packages/next-swc/crates/next-core/src/next_server/mod.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 3ba9c0ab86b996..c6c23a7b3dbbef 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -116,6 +116,7 @@ pub async fn get_client_module_options_context( // We don't need to resolve React Refresh for each module. Instead, // we try resolve it once at the root and pass down a context to all // the modules. + enable_jsx: true, enable_emotion: true, enable_react_refresh, enable_styled_components: true, diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index 60d634e180ddfe..465c449f38d49e 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -110,6 +110,7 @@ pub fn get_server_module_options_context( ..Default::default() }; ModuleOptionsContext { + enable_jsx: true, enable_styled_jsx: true, enable_postcss_transform: Some(PostCssTransformOptions { postcss_package: Some(get_postcss_package_mapping(project_path)), @@ -129,6 +130,7 @@ pub fn get_server_module_options_context( ..Default::default() }; ModuleOptionsContext { + enable_jsx: true, enable_styled_jsx: true, enable_postcss_transform: Some(PostCssTransformOptions { postcss_package: Some(get_postcss_package_mapping(project_path)), @@ -151,6 +153,7 @@ pub fn get_server_module_options_context( ..Default::default() }; ModuleOptionsContext { + enable_jsx: true, enable_postcss_transform: Some(PostCssTransformOptions { postcss_package: Some(get_postcss_package_mapping(project_path)), ..Default::default() From 9a4fe596e0e7db55caaa139c6de6f7f27ad8eaa0 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 22 Dec 2022 05:50:07 -0500 Subject: [PATCH 299/672] Misc fixes to starting dev server (vercel/turbo#3121) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The 10th attempt used to day "trying again" and then didn't try again because the iterator ended… - Swaps a nested `.map() == Some(bool)` for a `and_then` - Extracts into a helper function so code can early return without an `Option` wrapper. --- packages/next-swc/crates/next-dev/src/lib.rs | 64 +++++++++----------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 1664a09a22da6e..6536f11c61b82c 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -44,7 +44,7 @@ use turbopack_dev_server::{ source_maps::SourceMapContentSourceVc, static_assets::StaticAssetsContentSourceVc, ContentSourceVc, }, - DevServer, + DevServer, DevServerBuilder, }; use turbopack_node::{ execution_context::ExecutionContextVc, source_map::NextSourceMapTraceContentSourceVc, @@ -140,38 +140,28 @@ impl NextDevServerBuilder { self } - pub async fn build(self) -> Result { - let start_port = self.port.context("port must be set")?; - let host = self.hostname.context("hostname must be set")?; - - // Retry to listen on the different port if the port is already in use. - let mut bound_server = None; - for retry_count in 0..10 { - let current_port = start_port + retry_count; + /// Attempts to find an open port to bind. + fn find_port(&self, host: IpAddr, port: u16, max_attempts: u16) -> Result { + // max_attempts of 1 means we loop 0 times. + let max_attempts = max_attempts - 1; + let mut attempts = 0; + loop { + let current_port = port + attempts; let addr = SocketAddr::new(host, current_port); - let listen_result = DevServer::listen(addr); - match listen_result { - Ok(server) => { - bound_server = Some(Ok(server)); - break; - } - Err(e) => { - let should_retry = if self.allow_retry { - // Returned error from `listen` is not `std::io::Error` but `anyhow::Error`, - // so we need to access its source to check if it is - // `std::io::ErrorKind::AddrInUse`. - e.source() - .map(|e| { - e.downcast_ref::() - .map(|e| e.kind() == std::io::ErrorKind::AddrInUse) - == Some(true) - }) - .unwrap_or_else(|| false) - } else { - false - }; + if let Err(e) = &listen_result { + if self.allow_retry && attempts < max_attempts { + // Returned error from `listen` is not `std::io::Error` but `anyhow::Error`, + // so we need to access its source to check if it is + // `std::io::ErrorKind::AddrInUse`. + let should_retry = e + .source() + .and_then(|e| { + e.downcast_ref::() + .map(|e| e.kind() == std::io::ErrorKind::AddrInUse) + }) + .unwrap_or(false); if should_retry { println!( @@ -180,15 +170,21 @@ impl NextDevServerBuilder { current_port, current_port + 1 ); - } else { - bound_server = Some(Err(e)); - break; + attempts += 1; + continue; } } } + + return listen_result; } + } + + pub async fn build(self) -> Result { + let port = self.port.context("port must be set")?; + let host = self.hostname.context("hostname must be set")?; - let server = bound_server.unwrap()?; + let server = self.find_port(host, port, 10)?; let turbo_tasks = self.turbo_tasks; let project_dir = self.project_dir; From 87e4a467f993e6162e2faf4c8a2e511ce9cddba2 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 22 Dec 2022 23:08:56 -0500 Subject: [PATCH 300/672] Allow CombinedContentSource to need data without locking up (vercel/turbo#3124) Currently when an individual `ContentSource` inside a `CombinedContentSource` requests additional vary data, the combined source will treat that source as the winner of the query. But, sometimes the vary data is necessary to determine that the content is not found by this source. And if that's the case, we'll hit a 404 when we should actually keep iterating. This is exactly the case we're going to hit with redirect/rewrites. Redirects need to be the very first content source, and I also need query/header/cookie/hostname data in order to determine if a redirect applies. Without this, **every** request becomes a 404. --- packages/next-swc/crates/next-core/src/next_image/mod.rs | 8 ++++---- packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_image/mod.rs b/packages/next-swc/crates/next-core/src/next_image/mod.rs index e2e86b8cb61167..c0d75cc14fc01d 100644 --- a/packages/next-swc/crates/next-core/src/next_image/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_image/mod.rs @@ -6,7 +6,7 @@ use turbopack_core::introspect::{Introspectable, IntrospectableVc}; use turbopack_dev_server::source::{ query::QueryValue, ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter, ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, - ProxyResult, + NeededData, ProxyResult, }; /// Serves, resizes, optimizes, and re-encodes images to be used with @@ -45,7 +45,7 @@ impl ContentSource for NextImageContentSource { .collect::>(); return Ok(ContentSourceResultVc::exact( - ContentSourceContent::NeedData { + ContentSourceContent::NeedData(NeededData { source: self_vc.into(), path: path.to_string(), vary: ContentSourceDataVary { @@ -53,7 +53,7 @@ impl ContentSource for NextImageContentSource { query: Some(ContentSourceDataFilter::Subset(queries)), ..Default::default() }, - } + }) .cell(), )); } @@ -68,7 +68,7 @@ impl ContentSource for NextImageContentSource { // TODO: consume the assets, resize and reduce quality, re-encode into next-gen // formats. if let Some(path) = url.strip_prefix('/') { - let asset = this.asset_source.get(path, Value::new(Default::default())); + let asset = this.asset_source.get(path, Default::default()); // THERE'S A HUGE PERFORMANCE ISSUE IF THIS MISSES let inner = asset.await?; if matches!(&*inner.content.await?, ContentSourceContent::Static(..)) { diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 20b4d41bbed85a..948000b233b788 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -11,7 +11,7 @@ use turbo_tasks_memory::{ use turbopack_core::asset::AssetContentVc; use turbopack_dev_server::source::{ ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter, - ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, + ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, NeededData, }; #[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new", into = "new")] @@ -87,14 +87,14 @@ impl ContentSource for TurboTasksSource { viz::table::wrap_html(&table) } else { return Ok(ContentSourceResultVc::exact( - ContentSourceContent::NeedData { + ContentSourceContent::NeedData(NeededData { source: self_vc.into(), path: path.to_string(), vary: ContentSourceDataVary { query: Some(ContentSourceDataFilter::All), ..Default::default() }, - } + }) .cell(), )); } From f7f2db70bd8a3971386bfc615f78067a3c90b75b Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 3 Jan 2023 11:42:35 +0100 Subject: [PATCH 301/672] Refactor the Next SSG transform to handle the inverse operation (vercel/turbo#2968) ## The original transform The original behavior of the Next SSG transform is to remove `getServerSideProps`, `getStaticProps`, and `getStaticPaths` from Next.js page files so they can be bundled for the client. This is what enables the following code to work properly without advanced tree shaking: ```jsx import db from "db"; import PostCounter from export default function Home(props) { return <>{props.posts.length} post(s); } const postsPromise = db.getPosts(); export async function getStaticProps() { return { props: { posts: await postsPromise, }, }; } ``` The transform is able to remove both `getStaticProps` and all its exclusive, transitive dependencies, so this is what the client would see: ```jsx import PostCounter from "components/PostCounter"; export var __N_SSG = true; export default function Home(props) { return __jsx(PostCounter, { count: props.posts.length }); } ``` ## Adding the inverse operation However, to support proper HMR for these data exports, we need to be able to execute somewhat of an inverse operation: remove the default component export, but preserve all the rest. This allows Turbopack to bundle server-side only declarations, only re-rendering when one of these changes, instead of re-rendering on any server-side and client-side change. From our module above, the updated transform is now also able to generate the following: ```jsx import db from "db"; const postsPromise = db.getPosts(); export async function getStaticProps() { return { props: { posts: await postsPromise } }; } ``` As you can see, this module is no longer importing the `PostCounter`, which means re-rendering will not invalidate when that counter changes. However, if the "db" module changes, we will still be able to detect a change and re-render. ## Other notes * I renamed the transform from "next_ssg" to "next_transform_strip_page_exports". It's much more verbose, but hopefully also much clearer about what it does at a glance. * I took the liberty to clean up and comment some parts of the transform to make it more easily understandable (at least for someone like me, who hasn't written a lot of SWC code). I also fixed a few bugs and edge cases. * I brought over the tests from the transform in the Next.js and added a couple of them. * For now, only the `StripDataExports` filter is used. A future PR will build on this and @ForsakenHarmony's https://github.com/vercel/turbo/pull/2949 PR to actually implement SSR/SSG HMR. ## Reviewing guide 1. The crux of the change is the move (and refactor) of the next ssg transform from https://github.com/vercel/turbo/pull/2968/files#diff-133d73657647ed793ca4782a73552650b32ad565094b1e0faf452ad58705499b to https://github.com/vercel/turbo/pull/2968/files#diff-d6442fa6af9b66e581f062739dd6de2419f5e8f6f3d97cfa63518c72b0a9ee3e. 2. I also added the [errors.rs](https://github.com/vercel/turbo/pull/2968/files#diff-0f308375da4179c0ea5a0fcbd99593b56d6020cd7dec1694ed08f392f1637c09) and [fixture.rs](https://github.com/vercel/turbo/pull/2968/files#diff-6e23f34483fc17a27dfc630edb455ea95e28d5cb350468c2ba01384fbc3c116a) tests. I adapted fixture.rs to execute on the two transform filters: data exports and default export. 3. Most of the tests in `tests/` are copied from https://github.com/vercel/next.js/tree/canary/packages/next-swc/crates/core/tests. The changes I made are: i. https://github.com/vercel/turbo/pull/2968/files#diff-774abee6a1bf139c9ce55e226bf15b52e56ea091170ee5d6295c191fd8d793c7: made this one symmetric for both strip data and strip default transforms. ii. https://github.com/vercel/turbo/pull/2968/files#diff-4792266a264dc67da93748d2c6522917f860527a689891bd5f8f4add9841e7f6 wasn't supported before AFAIK. iii. https://github.com/vercel/turbo/pull/2968/files#diff-a3b12adbce1dec40f39ff8af13ffecbe7f6963e21bc402cef6332ecf5018877e similar to i. --- .../next-core/src/next_client/context.rs | 4 +- .../Cargo.toml | 38 + .../src/lib.rs | 1018 +++++++++++++++++ .../tests/errors.rs | 32 + .../server-side-after-static-paths/input.js | 2 + .../server-side-after-static-paths/output.js | 0 .../output.stderr | 7 + .../server-side-after-static-props/input.js | 2 + .../server-side-after-static-props/output.js | 0 .../output.stderr | 7 + .../static-paths-after-server-side/input.js | 2 + .../static-paths-after-server-side/output.js | 0 .../output.stderr | 7 + .../static-props-after-server-side/input.js | 1 + .../static-props-after-server-side/output.js | 0 .../output.stderr | 6 + .../tests/fixture.rs | 68 ++ .../fixtures/getInitialProps/class/input.js | 11 + .../getInitialProps/class/output-data.js | 0 .../getInitialProps/class/output-default.js | 11 + .../function-anon-function/input.js | 9 + .../function-anon-function/output-data.js | 0 .../function-anon-function/output-default.js | 9 + .../getInitialProps/function-arrow/input.js | 9 + .../function-arrow/output-data.js | 0 .../function-arrow/output-default.js | 9 + .../getInitialProps/function-before/input.js | 9 + .../function-before/output-data.js | 0 .../function-before/output-default.js | 9 + .../function-named-function/input.js | 9 + .../function-named-function/output-data.js | 0 .../function-named-function/output-default.js | 9 + .../getInitialProps/reused-elsewhere/input.js | 9 + .../reused-elsewhere/output-data.js | 5 + .../reused-elsewhere/output-default.js | 8 + .../destructuring-assignment-array/input.js | 15 + .../output-data.js | 10 + .../output-default.js | 6 + .../getServerSideProps/query-usage/input.js | 7 + .../query-usage/output-data.js | 7 + .../query-usage/output-default.js | 10 + .../input.js | 15 + .../output-data.js | 10 + .../output-default.js | 6 + .../destructuring-assignment-array/input.js | 17 + .../output-data.js | 12 + .../output-default.js | 7 + .../destructuring-assignment-object/input.js | 17 + .../output-data.js | 12 + .../output-default.js | 6 + .../getStaticProps/issue-30091/input.js | 14 + .../getStaticProps/issue-30091/output-data.js | 6 + .../issue-30091/output-default.js | 4 + .../getStaticProps/issue-31855/input.js | 16 + .../getStaticProps/issue-31855/output-data.js | 7 + .../issue-31855/output-default.js | 5 + .../fixtures/getStaticProps/no-props/input.js | 3 + .../getStaticProps/no-props/output-default.js | 3 + .../input.js | 11 + .../output-data.js | 5 + .../output-default.js | 5 + .../should-not-mix-up-bindings/input.js | 14 + .../should-not-mix-up-bindings/output-data.js | 14 + .../output-default.js | 11 + .../input.js | 9 + .../output-data.js | 6 + .../output-default.js | 5 + .../input.js | 12 + .../output-data.js | 9 + .../output-default.js | 5 + .../input.js | 15 + .../output-data.js | 10 + .../output-default.js | 12 + .../input.js | 47 + .../output-data.js | 29 + .../output-default.js | 32 + .../input.js | 2 + .../output-data.js | 2 + .../output-default.js | 2 + .../input.js | 5 + .../output-data.js | 1 + .../output-default.js | 4 + .../input.js | 5 + .../output-data.js | 1 + .../output-default.js | 5 + .../input.js | 11 + .../output-data.js | 8 + .../output-default.js | 4 + .../input.js | 11 + .../output-data.js | 8 + .../output-default.js | 4 + .../input.js | 11 + .../output-data.js | 8 + .../output-default.js | 4 + .../input.js | 11 + .../output-data.js | 8 + .../output-default.js | 4 + .../input.js | 79 ++ .../output-data.js | 40 + .../output-default.js | 39 + .../input.js | 9 + .../output-data.js | 4 + .../output-default.js | 4 + .../input.js | 10 + .../output-data.js | 5 + .../output-default.js | 5 + .../input.js | 9 + .../output-data.js | 4 + .../output-default.js | 4 + .../input.js | 6 + .../output-data.js | 2 + .../output-default.js | 4 + .../input.js | 10 + .../output-data.js | 7 + .../output-default.js | 4 + .../should-support-class-exports-2/input.js | 11 + .../output-data.js | 5 + .../output-default.js | 7 + .../should-support-class-exports/input.js | 9 + .../output-data.js | 5 + .../output-default.js | 6 + .../input.js | 13 + .../output-data.js | 8 + .../output-default.js | 8 + .../input.js | 16 + .../output-data.js | 11 + .../output-default.js | 11 + .../input.js | 11 + .../output-data.js | 7 + .../output-default.js | 6 + .../input.js | 13 + .../output-data.js | 8 + .../output-default.js | 8 + .../should-support-full-re-export/input.js | 1 + .../output-data.js | 1 + .../output-default.js | 2 + .../input.js | 2 + .../output-data.js | 2 + .../output-default.js | 2 + .../input.js | 9 + .../output-data.js | 5 + .../output-default.js | 5 + .../tests/fixtures/propTypes/complex/input.js | 11 + .../fixtures/propTypes/complex/output-data.js | 5 + .../propTypes/complex/output-default.js | 7 + .../tests/fixtures/propTypes/simple/input.js | 11 + .../fixtures/propTypes/simple/output-data.js | 1 + .../propTypes/simple/output-default.js | 11 + 148 files changed, 2377 insertions(+), 1 deletion(-) create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/Cargo.toml create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors.rs create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/output.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/output.stderr create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/output.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/output.stderr create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/output.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/output.stderr create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/output.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/output.stderr create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixture.rs create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-default.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/input.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-data.js create mode 100644 packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-default.js diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index c6c23a7b3dbbef..f8cb55e4b86e63 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -157,7 +157,9 @@ pub async fn add_next_transforms_to_pages( ]), ]), vec![ModuleRuleEffect::AddEcmascriptTransforms( - EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::NextJsPageSsr]), + EcmascriptInputTransformsVc::cell(vec![ + EcmascriptInputTransform::NextJsStripPageDataExports, + ]), )], )); Ok(module_options_context.cell()) diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/Cargo.toml b/packages/next-swc/crates/next-transform-strip-page-exports/Cargo.toml new file mode 100644 index 00000000000000..22b4aab3c02839 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "next-transform-strip-page-exports" +version = "0.1.0" +description = "SWC transform to selectively strip Next.js page data or default exports" +license = "MPL-2.0" +edition = "2021" +autobenches = false + +[lib] +bench = false + +[dependencies] +fxhash = "0.2.1" +tracing = "0.1.37" + +swc_core = { workspace = true, features = [ + "ecma_ast", + "common", + "common_concurrent", + "common_sourcemap", + "ecma_codegen", + "ecma_parser", + "ecma_preset_env", + "ecma_transforms", + "ecma_transforms_module", + "ecma_transforms_react", + "ecma_transforms_typescript", + "ecma_quote", + "ecma_visit", + "ecma_visit_path", + "ecma_utils", + "testing", + "base", +] } + +[dev-dependencies] +swc_core = { workspace = true, features = ["testing_transform"] } +testing = "0.31.14" diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs b/packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs new file mode 100644 index 00000000000000..e793d0a6c135cd --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs @@ -0,0 +1,1018 @@ +//! The original transform is available on the Next.js repository: +//! https://github.com/vercel/next.js/blob/f7fecf00cb40c2f784387ff8ccc5e213b8bdd9ca/packages/next-swc/crates/core/src/next_ssg.rs +//! +//! This version adds support for eliminating client-side exports only. + +use std::{cell::RefCell, mem::take, rc::Rc}; + +use fxhash::{FxHashMap, FxHashSet}; +use swc_core::{ + common::{ + errors::HANDLER, + pass::{Repeat, Repeated}, + DUMMY_SP, + }, + ecma::{ + ast::*, + visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Visit, VisitWith}, + }, +}; + +/// Determines which exports to remove. +#[derive(Debug, Default, Clone, Copy)] +pub enum ExportFilter { + /// Strip all data exports (getServerSideProps, + /// getStaticProps, getStaticPaths exports.) and their unique dependencies. + #[default] + StripDataExports, + /// Strip default export and all its unique dependencies. + StripDefaultExport, +} + +#[derive(Debug, Default, Clone, Copy)] +pub enum PageMode { + #[default] + None, + /// The Next.js page is declaring `getServerSideProps`. + Ssr, + /// The Next.js page is declaring `getStaticProps` and/or `getStaticPaths`. + Ssg, +} + +impl PageMode { + /// Which identifier (if any) to export in the output file. + fn data_marker(self) -> Option<&'static str> { + match self { + PageMode::None => None, + PageMode::Ssr => Some("__N_SSP"), + PageMode::Ssg => Some("__N_SSG"), + } + } +} + +/// A transform that either: +/// * strips Next.js data exports (getServerSideProps, getStaticProps, +/// getStaticPaths); or +/// * strips the default export. +/// +/// Note: This transform requires running `resolver` **before** running it. +pub fn next_transform_strip_page_exports( + filter: ExportFilter, + ssr_removed_packages: Rc>>, +) -> impl Fold { + Repeat::new(NextSsg { + state: State { + ssr_removed_packages, + filter, + ..Default::default() + }, + in_lhs_of_var: false, + remove_expression: false, + }) +} + +/// State of the transforms. Shared by the analyzer and the transform. +#[derive(Debug, Default)] +struct State { + filter: ExportFilter, + + page_mode: PageMode, + + exports: FxHashMap, + + /// Identifiers referenced in the body of preserved functions. + /// + /// Cleared before running each pass, because we drop ast nodes between the + /// passes. + refs_from_preserved: FxHashSet, + + /// Identifiers referenced in the body of removed functions or + /// derivatives. + /// + /// Preserved between runs, because we should remember derivatives of data + /// functions as the data function itself is already removed. + refs_from_removed: FxHashSet, + + /// Identifiers of functions currently being declared, the body of which we + /// are currently visiting. + cur_declaring: FxHashSet, + + /// `true` if the transform has added a page mode marker to the AST. + added_data_marker: bool, + + should_run_again: bool, + + /// Track the import packages which are removed alongside + /// `getServerSideProps` in SSR. + ssr_removed_packages: Rc>>, +} + +/// The type of export associated to an identifier. +#[derive(Debug, Clone, Copy)] +enum ExportType { + Default, + GetServerSideProps, + GetStaticPaths, + GetStaticProps, +} + +impl ExportType { + fn from_specifier(specifier: &ExportSpecifier) -> Option> { + match specifier { + ExportSpecifier::Default(ExportDefaultSpecifier { exported, .. }) + | ExportSpecifier::Namespace(ExportNamespaceSpecifier { + name: ModuleExportName::Ident(exported), + .. + }) => { + let export_type = ExportType::from_ident(exported)?; + Some(ExportTypeResult { + exported_ident: exported, + local_ident: None, + export_type, + }) + } + + ExportSpecifier::Named(ExportNamedSpecifier { + exported: Some(ModuleExportName::Ident(exported)), + orig: ModuleExportName::Ident(orig), + .. + }) + | ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(orig @ exported), + .. + }) => { + let export_type = ExportType::from_ident(exported)?; + Some(ExportTypeResult { + exported_ident: exported, + local_ident: Some(orig), + export_type, + }) + } + _ => None, + } + } + + fn from_ident(ident: &Ident) -> Option { + Some(match &*ident.sym { + "default" => ExportType::Default, + "getStaticProps" => ExportType::GetStaticProps, + "getStaticPaths" => ExportType::GetStaticPaths, + "getServerSideProps" => ExportType::GetServerSideProps, + _ => return None, + }) + } +} + +struct ExportTypeResult<'a> { + exported_ident: &'a Ident, + local_ident: Option<&'a Ident>, + export_type: ExportType, +} + +impl State { + fn encounter_export( + &mut self, + exported_ident: &Ident, + local_ident: Option<&Ident>, + export_type: ExportType, + ) { + match export_type { + ExportType::GetServerSideProps => { + if matches!(self.page_mode, PageMode::Ssg) { + HANDLER.with(|handler| { + handler + .struct_span_err( + exported_ident.span, + "You can not use getStaticProps or getStaticPaths with \ + getServerSideProps. To use SSG, please remove getServerSideProps", + ) + .emit() + }); + return; + } + + self.page_mode = PageMode::Ssr; + } + ExportType::GetStaticPaths | ExportType::GetStaticProps => { + if matches!(self.page_mode, PageMode::Ssr) { + HANDLER.with(|handler| { + handler + .struct_span_err( + exported_ident.span, + "You can not use getStaticProps or getStaticPaths with \ + getServerSideProps. To use SSG, please remove getServerSideProps", + ) + .emit() + }); + return; + } + + self.page_mode = PageMode::Ssg; + } + _ => {} + } + + let local_ident = local_ident.unwrap_or(exported_ident); + + self.exports.insert(local_ident.to_id(), export_type); + } + + fn export_type(&self, id: &Id) -> Option { + self.exports.get(id).copied() + } + + fn should_retain_export_type(&self, export_type: ExportType) -> bool { + match (self.filter, export_type) { + ( + ExportFilter::StripDataExports, + ExportType::GetServerSideProps + | ExportType::GetStaticProps + | ExportType::GetStaticPaths, + ) => false, + (ExportFilter::StripDefaultExport, ExportType::Default) => false, + _ => true, + } + } + + fn should_retain_id(&self, id: &Id) -> bool { + if let Some(export_type) = self.export_type(id) { + self.should_retain_export_type(export_type) + } else { + true + } + } + + fn dropping_export(&mut self, export_type: ExportType) -> bool { + if !self.should_retain_export_type(export_type) { + // If there are any assignments on the exported identifier, they'll + // need to be removed as well in the next pass. + self.should_run_again = true; + true + } else { + false + } + } +} + +struct Analyzer<'a> { + state: &'a mut State, + in_lhs_of_var: bool, + in_removed_item: bool, +} + +impl Analyzer<'_> { + fn add_ref(&mut self, id: Id) { + tracing::trace!( + "add_ref({}{:?}, in_removed_item = {:?})", + id.0, + id.1, + self.in_removed_item, + ); + if self.in_removed_item { + self.state.refs_from_removed.insert(id); + } else { + if self.state.cur_declaring.contains(&id) { + return; + } + + self.state.refs_from_preserved.insert(id); + } + } + + fn within_declaration(&mut self, id: &Id, f: impl FnOnce(&mut Self) -> R) -> R { + self.state.cur_declaring.insert(id.clone()); + let res = f(self); + self.state.cur_declaring.remove(id); + res + } + + fn within_removed_item( + &mut self, + in_removed_item: bool, + f: impl FnOnce(&mut Self) -> R, + ) -> R { + let old = self.in_removed_item; + // `in_removed_item` is strictly additive. + self.in_removed_item |= in_removed_item; + let res = f(self); + self.in_removed_item = old; + res + } + + fn within_lhs_of_var(&mut self, in_lhs_of_var: bool, f: impl FnOnce(&mut Self) -> R) -> R { + let old = self.in_lhs_of_var; + self.in_lhs_of_var = in_lhs_of_var; + let res = f(self); + self.in_lhs_of_var = old; + res + } + + fn visit_declaration(&mut self, id: &Id, d: &D) + where + D: VisitWith, + { + self.within_declaration(id, |this| { + let in_removed_item = !this.state.should_retain_id(id); + this.within_removed_item(in_removed_item, |this| { + tracing::trace!( + "transform_page: Handling `{}{:?}`; in_removed_item = {:?}", + id.0, + id.1, + this.in_removed_item + ); + + d.visit_children_with(this); + }); + }); + } +} + +impl Visit for Analyzer<'_> { + // This is important for reducing binary sizes. + noop_visit_type!(); + + fn visit_binding_ident(&mut self, i: &BindingIdent) { + if !self.in_lhs_of_var || self.in_removed_item { + self.add_ref(i.id.to_id()); + } + } + + fn visit_named_export(&mut self, n: &NamedExport) { + for specifier in &n.specifiers { + if let Some(ExportTypeResult { + exported_ident, + local_ident, + export_type, + }) = ExportType::from_specifier(specifier) + { + self.state + .encounter_export(exported_ident, local_ident, export_type); + + if let Some(local_ident) = local_ident { + if self.state.should_retain_export_type(export_type) { + self.add_ref(local_ident.to_id()); + } + } + } + } + } + + fn visit_export_decl(&mut self, s: &ExportDecl) { + match &s.decl { + Decl::Var(d) => { + for decl in &d.decls { + if let Pat::Ident(ident) = &decl.name { + if let Some(export_type) = ExportType::from_ident(ident) { + self.state.encounter_export(ident, None, export_type); + + let retain = self.state.should_retain_export_type(export_type); + + if retain { + self.add_ref(ident.to_id()); + } + + self.within_removed_item(!retain, |this| { + decl.visit_with(this); + }); + } else { + // Always preserve declarations of unknown exports. + self.add_ref(ident.to_id()); + + decl.visit_with(self) + } + } else { + decl.visit_with(self) + } + } + } + Decl::Fn(decl) => { + let ident = &decl.ident; + if let Some(export_type) = ExportType::from_ident(ident) { + self.state.encounter_export(ident, None, export_type); + + let retain = self.state.should_retain_export_type(export_type); + + if retain { + self.add_ref(ident.to_id()); + } + + self.within_removed_item(!retain, |this| { + decl.visit_with(this); + }); + } else { + s.visit_children_with(self); + } + } + _ => s.visit_children_with(self), + } + } + + fn visit_export_default_decl(&mut self, s: &ExportDefaultDecl) { + match &s.decl { + DefaultDecl::Class(ClassExpr { + ident: Some(ident), .. + }) => self + .state + .encounter_export(ident, Some(ident), ExportType::Default), + DefaultDecl::Fn(FnExpr { + ident: Some(ident), .. + }) => self + .state + .encounter_export(ident, Some(ident), ExportType::Default), + _ => {} + } + self.within_removed_item( + matches!(self.state.filter, ExportFilter::StripDefaultExport), + |this| { + s.visit_children_with(this); + }, + ); + } + + fn visit_export_default_expr(&mut self, s: &ExportDefaultExpr) { + self.within_removed_item( + matches!(self.state.filter, ExportFilter::StripDefaultExport), + |this| { + s.visit_children_with(this); + }, + ); + } + + fn visit_expr(&mut self, e: &Expr) { + e.visit_children_with(self); + + if let Expr::Ident(i) = &e { + self.add_ref(i.to_id()); + } + } + + fn visit_jsx_element(&mut self, jsx: &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.visit_children_with(self); + } + + fn visit_fn_decl(&mut self, f: &FnDecl) { + self.visit_declaration(&f.ident.to_id(), f); + } + + fn visit_class_decl(&mut self, c: &ClassDecl) { + self.visit_declaration(&c.ident.to_id(), c); + } + + fn visit_fn_expr(&mut self, f: &FnExpr) { + f.visit_children_with(self); + + if let Some(id) = &f.ident { + self.add_ref(id.to_id()); + } + } + + fn visit_prop(&mut self, p: &Prop) { + p.visit_children_with(self); + + if let Prop::Shorthand(i) = &p { + self.add_ref(i.to_id()); + } + } + + fn visit_var_declarator(&mut self, v: &VarDeclarator) { + let in_removed_item = if let Pat::Ident(name) = &v.name { + !self.state.should_retain_id(&name.id.to_id()) + } else { + false + }; + + self.within_removed_item(in_removed_item, |this| { + this.within_lhs_of_var(true, |this| { + v.name.visit_with(this); + }); + + this.within_lhs_of_var(false, |this| { + v.init.visit_with(this); + }); + }); + } + + fn visit_member_expr(&mut self, e: &MemberExpr) { + let in_removed_item = if let Some(id) = find_member_root_id(e) { + !self.state.should_retain_id(&id) + } else { + false + }; + + self.within_removed_item(in_removed_item, |this| { + e.visit_children_with(this); + }); + } + + fn visit_assign_expr(&mut self, e: &AssignExpr) { + self.within_lhs_of_var(true, |this| { + e.left.visit_with(this); + }); + + self.within_lhs_of_var(false, |this| { + e.right.visit_with(this); + }); + } +} + +/// Actual implementation of the transform. +struct NextSsg { + pub state: State, + in_lhs_of_var: bool, + /// Marker set when a top-level expression item should be removed. This + /// occurs when visiting assignments on eliminated identifiers. + remove_expression: bool, +} + +impl NextSsg { + /// Returns `true` when an identifier should be removed from the output. + fn should_remove(&self, id: &Id) -> bool { + self.state.refs_from_removed.contains(id) && !self.state.refs_from_preserved.contains(id) + } + + /// Mark identifiers in `n` as a candidate for elimination. + fn mark_as_candidate(&mut self, n: &N) + where + N: for<'aa> VisitWith> + std::fmt::Debug, + { + tracing::debug!("mark_as_candidate: {:?}", n); + + let mut v = Analyzer { + state: &mut self.state, + in_lhs_of_var: false, + // Analyzer never change `in_removed_item`, so all identifiers in `n` + // will be marked as referenced from an removed item. + in_removed_item: true, + }; + + n.visit_with(&mut v); + self.state.should_run_again = true; + } + + /// Adds __N_SSG and __N_SSP declarations when eliminating data functions. + fn maybe_add_data_marker(&mut self, items: &mut Vec) { + if !matches!(self.state.filter, ExportFilter::StripDataExports) + || self.state.added_data_marker + || self.state.should_run_again + { + return; + } + + let Some(data_marker) = self.state.page_mode.data_marker() else { + return; + }; + + self.state.added_data_marker = true; + + if items.iter().any(|s| s.is_module_decl()) { + let insert_idx = items.iter().position(|item| { + matches!( + item, + ModuleItem::ModuleDecl( + ModuleDecl::ExportNamed(..) + | ModuleDecl::ExportDecl(..) + | ModuleDecl::ExportDefaultDecl(..) + | ModuleDecl::ExportDefaultExpr(..), + ) + ) + }); + + if let Some(insert_idx) = insert_idx { + items.insert( + insert_idx, + ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { + span: DUMMY_SP, + decl: Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + kind: VarDeclKind::Var, + declare: Default::default(), + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(Ident::new(data_marker.into(), DUMMY_SP).into()), + init: Some(true.into()), + definite: Default::default(), + }], + })), + })), + ); + } + } + } + + fn within_lhs_of_var(&mut self, in_lhs_of_var: bool, f: impl FnOnce(&mut Self) -> R) -> R { + let old = self.in_lhs_of_var; + self.in_lhs_of_var = in_lhs_of_var; + let res = f(self); + self.in_lhs_of_var = old; + res + } +} + +impl Repeated for NextSsg { + fn changed(&self) -> bool { + self.state.should_run_again + } + + fn reset(&mut self) { + self.state.refs_from_preserved.clear(); + self.state.cur_declaring.clear(); + self.state.should_run_again = false; + } +} + +/// `VisitMut` is faster than [Fold], but we use [Fold] because it's much easier +/// to read. +/// +/// Note: We don't implement `fold_script` because next.js doesn't use it. +impl Fold for NextSsg { + // This is important for reducing binary sizes. + noop_fold_type!(); + + fn fold_import_decl(&mut self, mut i: ImportDecl) -> ImportDecl { + // Imports for side effects. + if i.specifiers.is_empty() { + return i; + } + + let import_src = &i.src.value; + + 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()) { + if matches!(self.state.page_mode, PageMode::Ssr) + && matches!(self.state.filter, ExportFilter::StripDataExports) + // filter out non-packages import + // third part packages must start with `a-z` or `@` + && import_src.starts_with(|c: char| c.is_ascii_lowercase() || c == '@') + { + self.state + .ssr_removed_packages + .borrow_mut() + .insert(import_src.to_string()); + } + tracing::trace!( + "Dropping import `{}{:?}` because it should be removed", + local.sym, + local.span.ctxt + ); + + self.state.should_run_again = true; + false + } else { + true + } + } + }); + + i + } + + fn fold_module(&mut self, m: Module) -> Module { + tracing::info!("ssg: Start"); + { + // Fill the state. + let mut v = Analyzer { + state: &mut self.state, + in_lhs_of_var: false, + in_removed_item: false, + }; + m.visit_with(&mut v); + } + + // TODO: Use better detection logic + // if let PageMode::None = self.state.page_mode { + // return m; + // } + + m.fold_children_with(self) + } + + 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 })) + } + ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(e)) => match &e.decl { + Decl::Fn(f) => { + if let Some(export_type) = self.state.export_type(&f.ident.to_id()) { + if self.state.dropping_export(export_type) { + tracing::trace!( + "Dropping an export specifier because it's an SSR/SSG function" + ); + 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 })); + } + } + _ => {} + }, + + ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(_)) + | ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(_)) => { + if self.state.dropping_export(ExportType::Default) { + tracing::trace!("Dropping an export specifier because it's a default export"); + + return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + } + } + _ => {} + } + + i + } + + fn fold_module_items(&mut self, mut items: Vec) -> Vec { + items = items.fold_children_with(self); + + // Drop empty nodes. + items.retain(|s| !matches!(s, ModuleItem::Stmt(Stmt::Empty(..)))); + + self.maybe_add_data_marker(&mut items); + + items + } + + fn fold_named_export(&mut self, mut n: NamedExport) -> NamedExport { + n.specifiers = n.specifiers.fold_with(self); + + n.specifiers.retain(|s| { + let (export_type, local_ref) = match s { + ExportSpecifier::Default(ExportDefaultSpecifier { exported, .. }) + | ExportSpecifier::Namespace(ExportNamespaceSpecifier { + name: ModuleExportName::Ident(exported), + .. + }) => (ExportType::from_ident(exported), None), + ExportSpecifier::Named(ExportNamedSpecifier { + exported: Some(ModuleExportName::Ident(exported)), + orig: ModuleExportName::Ident(orig), + .. + }) + | ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(orig @ exported), + .. + }) => (ExportType::from_ident(exported), Some(orig)), + _ => (None, None), + }; + + let Some(export_type) = export_type else { + return true; + }; + + let retain = self.state.should_retain_export_type(export_type); + + if !retain { + // If the export specifier is not retained, but it refers to a local ident, + // we need to run again to possibly remove the local ident. + if let Some(local_ref) = local_ref { + self.state.should_run_again = true; + self.state.refs_from_removed.insert(local_ref.to_id()); + } + } + + self.state.should_retain_export_type(export_type) + }); + + 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; + tracing::trace!( + "Dropping var `{}{:?}` because it should be removed", + name.id.sym, + name.id.span.ctxt + ); + + 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 }); + } + } + Pat::Expr(expr) => match &**expr { + Expr::Member(member_expr) => match find_member_root_id(member_expr) { + Some(id) => { + if self.should_remove(&id) { + self.state.should_run_again = true; + tracing::trace!( + "Dropping member expression object `{}{:?}` because it should \ + be removed", + id.0, + id.1 + ); + + return Pat::Invalid(Invalid { span: DUMMY_SP }); + } + } + None => {} + }, + _ => {} + }, + _ => {} + } + } + + 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)); + } + _ => {} + } + + self.remove_expression = false; + + 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 }); + } + Stmt::Expr(_) => { + if self.remove_expression { + self.remove_expression = false; + return Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + } + } + _ => {} + } + + s + } + + fn fold_expr(&mut self, e: Expr) -> Expr { + match e { + Expr::Assign(assign_expr) => { + let mut retain = true; + let left = self.within_lhs_of_var(true, |this| assign_expr.left.fold_with(this)); + + let right = self.within_lhs_of_var(false, |this| { + if let PatOrExpr::Pat(pat) = &left { + if pat.is_invalid() { + retain = false; + this.mark_as_candidate(&assign_expr.right); + } + } + assign_expr.right.fold_with(this) + }); + + if retain { + self.remove_expression = false; + Expr::Assign(AssignExpr { + left, + right, + ..assign_expr + }) + } else { + self.remove_expression = true; + *right + } + } + _ => { + self.remove_expression = false; + e.fold_children_with(self) + } + } + } + + /// This method make `name` of [VarDeclarator] to [Pat::Invalid] if it + /// should be removed. + fn fold_var_declarator(&mut self, d: VarDeclarator) -> VarDeclarator { + let name = self.within_lhs_of_var(true, |this| d.name.fold_with(this)); + + let init = self.within_lhs_of_var(false, |this| { + if name.is_invalid() { + this.mark_as_candidate(&d.init); + } + d.init.fold_with(this) + }); + + 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 + } +} + +/// Returns the root identifier of a member expression. +/// +/// e.g. `a.b.c` => `a` +fn find_member_root_id(member_expr: &MemberExpr) -> Option { + match &*member_expr.obj { + Expr::Member(member) => find_member_root_id(&member), + Expr::Ident(ident) => Some(ident.to_id()), + _ => None, + } +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors.rs b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors.rs new file mode 100644 index 00000000000000..20e2af041086df --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors.rs @@ -0,0 +1,32 @@ +use std::path::PathBuf; + +use next_transform_strip_page_exports::{next_transform_strip_page_exports, ExportFilter}; +use swc_core::ecma::{ + parser::{EsConfig, Syntax}, + transforms::testing::{test_fixture, FixtureTestConfig}, +}; +use testing::fixture; + +fn syntax() -> Syntax { + Syntax::Es(EsConfig { + jsx: true, + ..Default::default() + }) +} + +#[fixture("tests/errors/**/input.js")] +fn next_transform_strip_page_exports_errors(input: PathBuf) { + let output = input.parent().unwrap().join("output.js"); + test_fixture( + syntax(), + &|_tr| { + next_transform_strip_page_exports(ExportFilter::StripDataExports, Default::default()) + }, + &input, + &output, + FixtureTestConfig { + allow_error: true, + ..Default::default() + }, + ); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/input.js new file mode 100644 index 00000000000000..46e8e63e218757 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/input.js @@ -0,0 +1,2 @@ +export async function getStaticPaths() {} +export const getServerSideProps = function getServerSideProps() {}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/output.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/output.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/output.stderr b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/output.stderr new file mode 100644 index 00000000000000..3ef8362e8da8f0 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-paths/output.stderr @@ -0,0 +1,7 @@ + + x You can not use getStaticProps or getStaticPaths with getServerSideProps. To use SSG, please remove getServerSideProps + ,-[input.js:1:1] + 1 | export async function getStaticPaths() {} + 2 | export const getServerSideProps = function getServerSideProps() {}; + : ^^^^^^^^^^^^^^^^^^ + `---- diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/input.js new file mode 100644 index 00000000000000..7f865aad22dd43 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/input.js @@ -0,0 +1,2 @@ +export const getStaticProps = async () => {}; +export { a as getServerSideProps }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/output.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/output.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/output.stderr b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/output.stderr new file mode 100644 index 00000000000000..ed2d07c6e9dc12 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/server-side-after-static-props/output.stderr @@ -0,0 +1,7 @@ + + x You can not use getStaticProps or getStaticPaths with getServerSideProps. To use SSG, please remove getServerSideProps + ,-[input.js:1:1] + 1 | export const getStaticProps = async () => {}; + 2 | export { a as getServerSideProps }; + : ^^^^^^^^^^^^^^^^^^ + `---- diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/input.js new file mode 100644 index 00000000000000..e99f872e702b7b --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/input.js @@ -0,0 +1,2 @@ +export { a as getServerSideProps } from "./input"; +export { getStaticPaths } from "a"; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/output.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/output.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/output.stderr b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/output.stderr new file mode 100644 index 00000000000000..4faeb4b62820ff --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-paths-after-server-side/output.stderr @@ -0,0 +1,7 @@ + + x You can not use getStaticProps or getStaticPaths with getServerSideProps. To use SSG, please remove getServerSideProps + ,-[input.js:1:1] + 1 | export { a as getServerSideProps } from "./input"; + 2 | export { getStaticPaths } from "a"; + : ^^^^^^^^^^^^^^ + `---- diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/input.js new file mode 100644 index 00000000000000..bffa3e8b688645 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/input.js @@ -0,0 +1 @@ +export { getStaticProps, getServerSideProps }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/output.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/output.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/output.stderr b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/output.stderr new file mode 100644 index 00000000000000..a6313f9f18373c --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/errors/static-props-after-server-side/output.stderr @@ -0,0 +1,6 @@ + + x You can not use getStaticProps or getStaticPaths with getServerSideProps. To use SSG, please remove getServerSideProps + ,-[input.js:1:1] + 1 | export { getStaticProps, getServerSideProps }; + : ^^^^^^^^^^^^^^^^^^ + `---- diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixture.rs b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixture.rs new file mode 100644 index 00000000000000..9f70523c17914d --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixture.rs @@ -0,0 +1,68 @@ +use std::path::{Path, PathBuf}; + +use next_transform_strip_page_exports::{next_transform_strip_page_exports, ExportFilter}; +use swc_core::{ + common::{chain, comments::SingleThreadedComments, Mark}, + ecma::{ + parser::{EsConfig, Syntax}, + transforms::{ + react::jsx, + testing::{test, test_fixture}, + }, + }, +}; +use testing::fixture; + +fn syntax() -> Syntax { + Syntax::Es(EsConfig { + jsx: true, + ..Default::default() + }) +} + +fn run_test(input: &Path, output: &Path, mode: ExportFilter) { + test_fixture( + syntax(), + &|tr| { + let top_level_mark = Mark::fresh(Mark::root()); + let jsx = jsx::( + tr.cm.clone(), + None, + swc_core::ecma::transforms::react::Options { + next: false.into(), + runtime: None, + import_source: Some("".into()), + pragma: Some("__jsx".into()), + pragma_frag: Some("__jsxFrag".into()), + throw_if_namespace: false.into(), + development: false.into(), + use_builtins: true.into(), + use_spread: true.into(), + refresh: Default::default(), + }, + top_level_mark, + ); + chain!( + next_transform_strip_page_exports(mode, Default::default()), + jsx + ) + }, + input, + output, + Default::default(), + ); +} + +#[fixture("tests/fixtures/**/output-data.js")] +fn next_transform_strip_page_exports_fixture_data(output: PathBuf) { + let input = output.parent().unwrap().join("input.js"); + + run_test(&input, &output, ExportFilter::StripDefaultExport); +} + +#[fixture("tests/fixtures/**/output-default.js")] +fn next_transform_strip_page_exports_fixture_default(output: PathBuf) { + let input = output.parent().unwrap().join("input.js"); + + run_test(&input, &output, ExportFilter::StripDataExports); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/input.js new file mode 100644 index 00000000000000..f64acb718f0533 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/input.js @@ -0,0 +1,11 @@ +export default class Page { + static async getInitialProps() { + return { + prop: true, + }; + } + + render() { + return
; + } +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/output-data.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/output-default.js new file mode 100644 index 00000000000000..f50d84ed84a91e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/class/output-default.js @@ -0,0 +1,11 @@ +export default class Page { + static async getInitialProps() { + return { + prop: true, + }; + } + + render() { + return __jsx("div", null); + } +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/input.js new file mode 100644 index 00000000000000..4240ab7d39f35f --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/input.js @@ -0,0 +1,9 @@ +export default function Page() { + return
; +} + +Page.getInitialProps = function () { + return { + prop: true, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/output-data.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/output-default.js new file mode 100644 index 00000000000000..14860f0da62c8a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-anon-function/output-default.js @@ -0,0 +1,9 @@ +export default function Page() { + return __jsx("div", null); +} + +Page.getInitialProps = function () { + return { + prop: true, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/input.js new file mode 100644 index 00000000000000..fd8e607f372584 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/input.js @@ -0,0 +1,9 @@ +export default function Page() { + return
; +} + +Page.getInitialProps = () => { + return { + prop: true, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/output-data.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/output-default.js new file mode 100644 index 00000000000000..e9563be333cd63 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-arrow/output-default.js @@ -0,0 +1,9 @@ +export default function Page() { + return __jsx("div", null); +} + +Page.getInitialProps = () => { + return { + prop: true, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/input.js new file mode 100644 index 00000000000000..0f9411a9c85c54 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/input.js @@ -0,0 +1,9 @@ +Page.getInitialProps = function () { + return { + prop: true, + }; +}; + +export default function Page() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/output-data.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/output-default.js new file mode 100644 index 00000000000000..8f9ef9687425cd --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-before/output-default.js @@ -0,0 +1,9 @@ +Page.getInitialProps = function () { + return { + prop: true, + }; +}; + +export default function Page() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/input.js new file mode 100644 index 00000000000000..39ce09f03269b1 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/input.js @@ -0,0 +1,9 @@ +export default function Page() { + return
; +} + +Page.getInitialProps = function getInitialProps() { + return { + prop: true, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/output-data.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/output-default.js new file mode 100644 index 00000000000000..f02c56c949c811 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/function-named-function/output-default.js @@ -0,0 +1,9 @@ +export default function Page() { + return __jsx("div", null); +} + +Page.getInitialProps = function getInitialProps() { + return { + prop: true, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/input.js new file mode 100644 index 00000000000000..f1882ad0681cbc --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/input.js @@ -0,0 +1,9 @@ +export default function Page() { + return
; +} + +const getInitialProps = (Page.getInitialProps = function getInitialProps() { + return { + prop: true, + }; +}); diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-data.js new file mode 100644 index 00000000000000..5726a8399bba71 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-data.js @@ -0,0 +1,5 @@ +const getInitialProps = function getInitialProps() { + return { + prop: true, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-default.js new file mode 100644 index 00000000000000..32e7aad0780d2d --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getInitialProps/reused-elsewhere/output-default.js @@ -0,0 +1,8 @@ +export default function Page() { + return __jsx("div", null); +} +const getInitialProps = Page.getInitialProps = function getInitialProps() { + return { + prop: true + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/input.js new file mode 100644 index 00000000000000..61fa5fbebf1f7c --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/input.js @@ -0,0 +1,15 @@ +import fs from "fs"; +import other from "other"; + +const [a, b, ...rest] = fs.promises; +const [foo, bar] = other; + +export async function getServerSideProps() { + a; + b; + rest; + bar; +} +export default function Home() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-data.js new file mode 100644 index 00000000000000..f1ddef4038b4eb --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-data.js @@ -0,0 +1,10 @@ +import fs from "fs"; +import other from "other"; +const [a, b, ...rest] = fs.promises; +const [foo, bar] = other; +export async function getServerSideProps() { + a; + b; + rest; + bar; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-default.js new file mode 100644 index 00000000000000..952dcff2aa8224 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/destructuring-assignment-array/output-default.js @@ -0,0 +1,6 @@ +import other from "other"; +const [foo] = other; +export var __N_SSP = true; +export default function Home() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/input.js new file mode 100644 index 00000000000000..5e2e05fe9cc023 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/input.js @@ -0,0 +1,7 @@ +export async function getServerSideProps({ query }) { + return { props: { prop: query.prop } }; +} + +export default function GspPage({ prop }) { + return
{prop}
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-data.js new file mode 100644 index 00000000000000..cc060155e59085 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-data.js @@ -0,0 +1,7 @@ +export async function getServerSideProps({ query }) { + return { + props: { + prop: query.prop, + }, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-default.js new file mode 100644 index 00000000000000..da565ee9e33b23 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getServerSideProps/query-usage/output-default.js @@ -0,0 +1,10 @@ +export var __N_SSP = true; +export default function GspPage({ prop }) { + return __jsx( + "div", + { + id: "prop", + }, + prop + ); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/input.js new file mode 100644 index 00000000000000..6bc7636d7bc9db --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/input.js @@ -0,0 +1,15 @@ +import fs from "fs"; +import other from "other"; + +const [a, b, ...rest] = fs.promises; +const [foo, bar] = other; + +export async function getStaticProps() { + a; + b; + rest; + bar; +} +export default function Home() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-data.js new file mode 100644 index 00000000000000..0c5c0bb281b256 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-data.js @@ -0,0 +1,10 @@ +import fs from "fs"; +import other from "other"; +const [a, b, ...rest] = fs.promises; +const [foo, bar] = other; +export async function getStaticProps() { + a; + b; + rest; + bar; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-default.js new file mode 100644 index 00000000000000..f81f28fe3b97e1 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array-expr/output-default.js @@ -0,0 +1,6 @@ +import other from "other"; +const [foo] = other; +export var __N_SSG = true; +export default function Home() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/input.js new file mode 100644 index 00000000000000..c122e3537d3119 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/input.js @@ -0,0 +1,17 @@ +import fs from "fs"; +import other from "other"; + +let a, b, rest; +[a, b, ...rest] = fs.promises; +let foo, bar; +[foo, bar] = other; + +export async function getStaticProps() { + a; + b; + rest; + bar; +} +export default function Home() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-data.js new file mode 100644 index 00000000000000..43a16ef1de1350 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-data.js @@ -0,0 +1,12 @@ +import fs from "fs"; +import other from "other"; +let a, b, rest; +[a, b, ...rest] = fs.promises; +let foo, bar; +[foo, bar] = other; +export async function getStaticProps() { + a; + b; + rest; + bar; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-default.js new file mode 100644 index 00000000000000..b7ba6042dfaf55 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-array/output-default.js @@ -0,0 +1,7 @@ +import other from "other"; +let foo; +[foo] = other; +export var __N_SSG = true; +export default function Home() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/input.js new file mode 100644 index 00000000000000..ebbe89b99749f3 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/input.js @@ -0,0 +1,17 @@ +import fs from "fs"; +import other from "other"; + +const { readFile, readdir, access: foo } = fs.promises; +const { a, b, cat: bar, ...rem } = other; + +export async function getStaticProps() { + readFile; + readdir; + foo; + b; + cat; + rem; +} +export default function Home() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-data.js new file mode 100644 index 00000000000000..d792c0c64ea495 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-data.js @@ -0,0 +1,12 @@ +import fs from "fs"; +import other from "other"; +const { readFile, readdir, access: foo } = fs.promises; +const { a, b, cat: bar, ...rem } = other; +export async function getStaticProps() { + readFile; + readdir; + foo; + b; + cat; + rem; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-default.js new file mode 100644 index 00000000000000..aad6c65b1dce1e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/destructuring-assignment-object/output-default.js @@ -0,0 +1,6 @@ +import other from "other"; +const { a, cat: bar } = other; +export var __N_SSG = true; +export default function Home() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/input.js new file mode 100644 index 00000000000000..fa5cda8b2431d9 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/input.js @@ -0,0 +1,14 @@ +export default function Home({}) { + return ( +
+

Hello World

+
+ ); +} + +export async function getStaticProps() { + await import("_http_common").then((http) => console.log(http)); + return { + props: {}, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-data.js new file mode 100644 index 00000000000000..096a3855dfc62a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-data.js @@ -0,0 +1,6 @@ +export async function getStaticProps() { + await import("_http_common").then((http) => console.log(http)); + return { + props: {}, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-default.js new file mode 100644 index 00000000000000..62c495493ca182 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-30091/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Home({}) { + return __jsx("div", null, __jsx("p", null, "Hello World")); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/input.js new file mode 100644 index 00000000000000..4c0241de959d0c --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/input.js @@ -0,0 +1,16 @@ +export const revalidateInSeconds = 5 * 60; + +export const getStaticProps = async () => { + return { + props: {}, + revalidate: revalidateInSeconds, + }; +}; + +export default function Home({}) { + return ( +
+

Hello World

+
+ ); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-data.js new file mode 100644 index 00000000000000..d0cc33b994acae --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-data.js @@ -0,0 +1,7 @@ +export const revalidateInSeconds = 5 * 60; +export const getStaticProps = async () => { + return { + props: {}, + revalidate: revalidateInSeconds, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-default.js new file mode 100644 index 00000000000000..de142d4d1f76fa --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/issue-31855/output-default.js @@ -0,0 +1,5 @@ +export var __N_SSG = true; +export const revalidateInSeconds = 5 * 60; +export default function Home({}) { + return __jsx("div", null, __jsx("p", null, "Hello World")); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/input.js new file mode 100644 index 00000000000000..1cc46031b2d99d --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/input.js @@ -0,0 +1,3 @@ +export default function Home() { + return

Hello World!

; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/output-default.js new file mode 100644 index 00000000000000..7c412e63f4bb9e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/no-props/output-default.js @@ -0,0 +1,3 @@ +export default function Home() { + return __jsx("h1", null, "Hello World!"); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/input.js new file mode 100644 index 00000000000000..ec420374a3419e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/input.js @@ -0,0 +1,11 @@ +function getStaticPaths() { + return []; +} + +export { getStaticPaths }; + +export class MyClass {} + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-data.js new file mode 100644 index 00000000000000..71a6cc73cd4743 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-data.js @@ -0,0 +1,5 @@ +function getStaticPaths() { + return []; +} +export { getStaticPaths }; +export class MyClass {} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-default.js new file mode 100644 index 00000000000000..5b40a8ad4859b0 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-default.js @@ -0,0 +1,5 @@ +export var __N_SSG = true; +export class MyClass {} +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/input.js new file mode 100644 index 00000000000000..c6ce3da19e6f52 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/input.js @@ -0,0 +1,14 @@ +function Function1() { + return { + a: function bug(a) { + return 2; + }, + }; +} + +function Function2() { + var bug = 1; + return { bug }; +} + +export { getStaticProps } from "a"; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-data.js new file mode 100644 index 00000000000000..28d9767ba12cad --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-data.js @@ -0,0 +1,14 @@ +function Function1() { + return { + a: function bug(a) { + return 2; + }, + }; +} +function Function2() { + var bug = 1; + return { + bug, + }; +} +export { getStaticProps } from "a"; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-default.js new file mode 100644 index 00000000000000..e26cd3fad3fa1a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-default.js @@ -0,0 +1,11 @@ +function Function1() { + return { + a: function bug(a) { + return 2; + }, + }; +} +function Function2() { + var bug = 1; + return { bug }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/input.js new file mode 100644 index 00000000000000..b08c98d9c4ee19 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/input.js @@ -0,0 +1,9 @@ +export function getStaticProps() { + return { props: {} }; +} + +export function Noop() {} + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-data.js new file mode 100644 index 00000000000000..f24986955b4990 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-data.js @@ -0,0 +1,6 @@ +export function getStaticProps() { + return { + props: {}, + }; +} +export function Noop() {} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-default.js new file mode 100644 index 00000000000000..4dc6c9e6c5e896 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-default.js @@ -0,0 +1,5 @@ +export var __N_SSG = true; +export function Noop() {} +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/input.js new file mode 100644 index 00000000000000..1d9a656c9b5c81 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/input.js @@ -0,0 +1,12 @@ +export const getStaticPaths = () => { + return []; + }, + foo = 2; + +export const getStaticProps = function () { + return { props: {} }; +}; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-data.js new file mode 100644 index 00000000000000..ed5847c972aeb8 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-data.js @@ -0,0 +1,9 @@ +export const getStaticPaths = () => { + return []; + }, + foo = 2; +export const getStaticProps = function () { + return { + props: {}, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-default.js new file mode 100644 index 00000000000000..6d1d3b7e1b7a12 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-default.js @@ -0,0 +1,5 @@ +export var __N_SSG = true; +export const foo = 2; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/input.js new file mode 100644 index 00000000000000..0485ac51ff275f --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/input.js @@ -0,0 +1,15 @@ +import { foo, bar } from "thing"; + +export default function Home() { + foo; + return
; +} + +export function otherExport() { + foo; + bar; +} + +export async function getStaticProps() { + bar; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-data.js new file mode 100644 index 00000000000000..73c25a47533427 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-data.js @@ -0,0 +1,10 @@ +import { foo, bar } from "thing"; + +export function otherExport() { + foo; + bar; +} + +export async function getStaticProps() { + bar; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-default.js new file mode 100644 index 00000000000000..aee6685064997f --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-default.js @@ -0,0 +1,12 @@ +import { foo, bar } from "thing"; + +export var __N_SSG = true; +export default function Home() { + foo; + return __jsx("div", null); +} + +export function otherExport() { + foo; + bar; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/input.js new file mode 100644 index 00000000000000..f36fb55f1d610a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/input.js @@ -0,0 +1,47 @@ +import { useState, useEffect } from "react"; +import { + Root, + Children, + JSXMemberExpression, + AttributeValue, + AttributeJSX, + ValueInRender, + ValueInEffect, + UnusedInRender, +} from "../"; + +export default function Test() { + const [x, setX] = useState(ValueInRender.value); + useEffect(() => { + setX(ValueInEffect.value); + }, []); + + return ( + +
+ } /> + +
+
+ ); +} + +export async function getStaticProps() { + return { + props: { + // simulate import usage inside getStaticProps + used: [ + // these import references should not be removed + Root.value, + Children.value, + AttributeValue.value, + AttributeJSX.value, + ValueInRender.value, + ValueInEffect.value, + JSXMemberExpression.value, + // this import reference should be removed + UnusedInRender.value, + ], + }, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-data.js new file mode 100644 index 00000000000000..ec988e8ce41f57 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-data.js @@ -0,0 +1,29 @@ +import { + Root, + Children, + JSXMemberExpression, + AttributeValue, + AttributeJSX, + ValueInRender, + ValueInEffect, + UnusedInRender, +} from "../"; +export async function getStaticProps() { + return { + props: { + // simulate import usage inside getStaticProps + used: [ + // these import references should not be removed + Root.value, + Children.value, + AttributeValue.value, + AttributeJSX.value, + ValueInRender.value, + ValueInEffect.value, + JSXMemberExpression.value, + // this import reference should be removed + UnusedInRender.value, + ], + }, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-default.js new file mode 100644 index 00000000000000..83420ec1282dd6 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-default.js @@ -0,0 +1,32 @@ +import { useState, useEffect } from "react"; +import { + Root, + Children, + JSXMemberExpression, + AttributeValue, + AttributeJSX, + ValueInRender, + ValueInEffect, +} from "../"; +export var __N_SSG = true; +export default function Test() { + const [x, setX] = useState(ValueInRender.value); + useEffect(() => { + setX(ValueInEffect.value); + }, []); + return __jsx( + Root, + { + x: x, + }, + __jsx( + "div", + null, + __jsx(Children, { + attr: AttributeValue, + jsx: __jsx(AttributeJSX, null), + }), + __jsx(JSXMemberExpression.Deep.Property, null) + ) + ); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/input.js new file mode 100644 index 00000000000000..3c7f4667581294 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/input.js @@ -0,0 +1,2 @@ +function funfun() {} +(function funfunfun() {}); diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-data.js new file mode 100644 index 00000000000000..3c7f4667581294 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-data.js @@ -0,0 +1,2 @@ +function funfun() {} +(function funfunfun() {}); diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-default.js new file mode 100644 index 00000000000000..3c7f4667581294 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-default.js @@ -0,0 +1,2 @@ +function funfun() {} +(function funfunfun() {}); diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/input.js new file mode 100644 index 00000000000000..a4c2effac69fe0 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/input.js @@ -0,0 +1,5 @@ +export { getStaticPaths, a as getStaticProps } from "."; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-data.js new file mode 100644 index 00000000000000..42914d680a144d --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-data.js @@ -0,0 +1 @@ +export { getStaticPaths, a as getStaticProps } from "."; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/input.js new file mode 100644 index 00000000000000..f0c88085b93b9c --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/input.js @@ -0,0 +1,5 @@ +export { getStaticPaths, a as getStaticProps, foo, bar as baz } from "."; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-data.js new file mode 100644 index 00000000000000..38b1d511e1d48b --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-data.js @@ -0,0 +1 @@ +export { getStaticPaths, a as getStaticProps, foo, bar as baz } from "."; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-default.js new file mode 100644 index 00000000000000..7104a1d0d1aac1 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-default.js @@ -0,0 +1,5 @@ +export var __N_SSG = true; +export { foo, bar as baz } from "."; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/input.js new file mode 100644 index 00000000000000..d7e66fb019e302 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/input.js @@ -0,0 +1,11 @@ +export async function getStaticPaths() { + return []; +} + +export async function getStaticProps() { + return { props: {} }; +} + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-data.js new file mode 100644 index 00000000000000..45e8b11f8bdfb9 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-data.js @@ -0,0 +1,8 @@ +export async function getStaticPaths() { + return []; +} +export async function getStaticProps() { + return { + props: {}, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/input.js new file mode 100644 index 00000000000000..8c7db09226d9cd --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/input.js @@ -0,0 +1,11 @@ +export function getStaticPaths() { + return []; +} + +export function getStaticProps() { + return { props: {} }; +} + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-data.js new file mode 100644 index 00000000000000..38858d59eae13f --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-data.js @@ -0,0 +1,8 @@ +export function getStaticPaths() { + return []; +} +export function getStaticProps() { + return { + props: {}, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/input.js new file mode 100644 index 00000000000000..edde61fcc2ab03 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/input.js @@ -0,0 +1,11 @@ +export const getStaticPaths = async () => { + return []; +}; + +export const getStaticProps = async function () { + return { props: {} }; +}; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-data.js new file mode 100644 index 00000000000000..8fa2e0d0af9742 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-data.js @@ -0,0 +1,8 @@ +export const getStaticPaths = async () => { + return []; +}; +export const getStaticProps = async function () { + return { + props: {}, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/input.js new file mode 100644 index 00000000000000..135f78f34e675c --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/input.js @@ -0,0 +1,11 @@ +export const getStaticPaths = () => { + return []; +}; + +export const getStaticProps = function () { + return { props: {} }; +}; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-data.js new file mode 100644 index 00000000000000..fe89dbf75773b6 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-data.js @@ -0,0 +1,8 @@ +export const getStaticPaths = () => { + return []; +}; +export const getStaticProps = function () { + return { + props: {}, + }; +}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js new file mode 100644 index 00000000000000..d5d1494a2e3c1a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js @@ -0,0 +1,79 @@ +import keep_me from "hello"; +import { keep_me2 } from "hello2"; +import * as keep_me3 from "hello3"; + +import data_only1 from "data_only1"; +import { data_only2 } from "data_only2"; +import { data_only3, shared4 } from "shared4"; +import * as data_only4 from "data_only4"; + +import default_only1 from "default_only1"; +import { default_only2 } from "default_only2"; +import { default_only3, shared5 } from "shared5"; +import * as default_only4 from "default_only4"; + +var leave_me_alone = 1; +function dont_bug_me_either() {} + +const data_inception = "hahaa"; + +var data_var1 = 1; +let data_var2 = 2; +const data_var3 = data_inception + data_only4; + +function data_inception1() { + data_var2; + data_only2; +} + +function data_abc() {} +const data_b = function () { + data_var3; + data_only3; +}; +const data_b2 = function data_apples() {}; +const data_bla = () => { + data_inception1; +}; + +function getStaticProps() { + data_abc(); + data_only1; + data_b; + data_b2; + data_bla(); + return { props: { data_var1 } }; +} + +export { getStaticProps }; + +const default_inception = "hahaa"; + +var default_var1 = 1; +let default_var2 = 2; +const default_var3 = default_inception + default_only4; + +function default_inception1() { + default_var2; + default_only2; +} + +function default_abc() {} +const default_b = function () { + default_var3; + default_only3; +}; +const default_b2 = function default_apples() {}; +const default_bla = () => { + default_inception1; +}; + +export default function Test() { + default_abc(); + default_only1; + default_b; + default_b2; + default_bla(); + const props = { default_var1 }; + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js new file mode 100644 index 00000000000000..49661ed54cd51c --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js @@ -0,0 +1,40 @@ +import keep_me from "hello"; +import { keep_me2 } from "hello2"; +import * as keep_me3 from "hello3"; +import data_only1 from "data_only1"; +import { data_only2 } from "data_only2"; +import { data_only3, shared4 } from "shared4"; +import * as data_only4 from "data_only4"; +import { shared5 } from "shared5"; +var leave_me_alone = 1; +function dont_bug_me_either() {} +const data_inception = "hahaa"; +var data_var1 = 1; +let data_var2 = 2; +const data_var3 = data_inception + data_only4; +function data_inception1() { + data_var2; + data_only2; +} +function data_abc() {} +const data_b = function () { + data_var3; + data_only3; +}; +const data_b2 = function data_apples() {}; +const data_bla = () => { + data_inception1; +}; +function getStaticProps() { + data_abc(); + data_only1; + data_b; + data_b2; + data_bla(); + return { + props: { + data_var1, + }, + }; +} +export { getStaticProps }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js new file mode 100644 index 00000000000000..52a5c607a13078 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js @@ -0,0 +1,39 @@ +import keep_me from "hello"; +import { keep_me2 } from "hello2"; +import * as keep_me3 from "hello3"; +import { shared4 } from "shared4"; +import default_only1 from "default_only1"; +import { default_only2 } from "default_only2"; +import { default_only3, shared5 } from "shared5"; +import * as default_only4 from "default_only4"; +var leave_me_alone = 1; +function dont_bug_me_either() {} +const default_inception = "hahaa"; +var default_var1 = 1; +let default_var2 = 2; +const default_var3 = default_inception + default_only4; +function default_inception1() { + default_var2; + default_only2; +} +function default_abc() {} +const default_b = function () { + default_var3; + default_only3; +}; +const default_b2 = function default_apples() {}; +const default_bla = () => { + default_inception1; +}; +export var __N_SSG = true; +export default function Test() { + default_abc(); + default_only1; + default_b; + default_b2; + default_bla(); + const props = { + default_var1, + }; + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/input.js new file mode 100644 index 00000000000000..a09b8da75e8258 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/input.js @@ -0,0 +1,9 @@ +function getStaticPaths() { + return []; +} + +export { getStaticPaths }; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-data.js new file mode 100644 index 00000000000000..6e4b5b951f239b --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-data.js @@ -0,0 +1,4 @@ +function getStaticPaths() { + return []; +} +export { getStaticPaths }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/input.js new file mode 100644 index 00000000000000..eedc746a55d111 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/input.js @@ -0,0 +1,10 @@ +const getStaticPaths = () => { + return []; + }, + a = 2; + +export { getStaticPaths }; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-data.js new file mode 100644 index 00000000000000..f32022e82e58d1 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-data.js @@ -0,0 +1,5 @@ +const getStaticPaths = () => { + return []; + }, + a = 2; +export { getStaticPaths }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-default.js new file mode 100644 index 00000000000000..2cbcdc774f0ad5 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-default.js @@ -0,0 +1,5 @@ +const a = 2; +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/input.js new file mode 100644 index 00000000000000..1befda3ac567bb --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/input.js @@ -0,0 +1,9 @@ +const getStaticPaths = () => { + return []; +}; + +export { getStaticPaths }; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-data.js new file mode 100644 index 00000000000000..e88f02941dd5b4 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-data.js @@ -0,0 +1,4 @@ +const getStaticPaths = () => { + return []; +}; +export { getStaticPaths }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/input.js new file mode 100644 index 00000000000000..961c1bab125afb --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/input.js @@ -0,0 +1,6 @@ +export { getStaticPaths } from "./input"; +export { a as getStaticProps } from "./input"; + +export default function Test() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-data.js new file mode 100644 index 00000000000000..e50be215a9b2e8 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-data.js @@ -0,0 +1,2 @@ +export { getStaticPaths } from "./input"; +export { a as getStaticProps } from "./input"; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-default.js new file mode 100644 index 00000000000000..7fd316a2988813 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Test() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/input.js new file mode 100644 index 00000000000000..8d1debd949c737 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/input.js @@ -0,0 +1,10 @@ +function fn() { + fn = function () {}; + return fn.apply(this, arguments); +} +export function getStaticProps() { + fn; +} +export default function Home() { + return
; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-data.js new file mode 100644 index 00000000000000..f80108112d3368 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-data.js @@ -0,0 +1,7 @@ +function fn() { + fn = function () {}; + return fn.apply(this, arguments); +} +export function getStaticProps() { + fn; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-default.js new file mode 100644 index 00000000000000..2e2d26c3d4e2db --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-default.js @@ -0,0 +1,4 @@ +export var __N_SSG = true; +export default function Home() { + return __jsx("div", null); +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/input.js new file mode 100644 index 00000000000000..3e4a8b642c29ef --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/input.js @@ -0,0 +1,11 @@ +export function getStaticProps() { + return { props: {} }; +} + +class Test extends React.Component { + render() { + return
; + } +} + +export default Test; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-data.js new file mode 100644 index 00000000000000..d7470adb990f4e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-data.js @@ -0,0 +1,5 @@ +export function getStaticProps() { + return { + props: {}, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-default.js new file mode 100644 index 00000000000000..fde4b23081f158 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-default.js @@ -0,0 +1,7 @@ +class Test extends React.Component { + render() { + return __jsx("div", null); + } +} +export var __N_SSG = true; +export default Test; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/input.js new file mode 100644 index 00000000000000..03c29930ca58ac --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/input.js @@ -0,0 +1,9 @@ +export function getStaticProps() { + return { props: {} }; +} + +export default class Test extends React.Component { + render() { + return
; + } +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-data.js new file mode 100644 index 00000000000000..d7470adb990f4e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-data.js @@ -0,0 +1,5 @@ +export function getStaticProps() { + return { + props: {}, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-default.js new file mode 100644 index 00000000000000..a3211be448d2cb --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-default.js @@ -0,0 +1,6 @@ +export var __N_SSG = true; +export default class Test extends React.Component { + render() { + return __jsx("div", null); + } +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/input.js new file mode 100644 index 00000000000000..6749cc17f98f0a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/input.js @@ -0,0 +1,13 @@ +export function getStaticProps() { + return { props: {} }; +} + +class El extends React.Component { + render() { + return
; + } +} + +const a = 5; + +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-data.js new file mode 100644 index 00000000000000..cf7c57455c3eb3 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-data.js @@ -0,0 +1,8 @@ +export function getStaticProps() { + return { + props: {}, + }; +} + +const a = 5; +export { a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-default.js new file mode 100644 index 00000000000000..294384760bd266 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-default.js @@ -0,0 +1,8 @@ +class El extends React.Component { + render() { + return __jsx("div", null); + } +} +const a = 5; +export var __N_SSG = true; +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/input.js new file mode 100644 index 00000000000000..2b84de68f0d10b --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/input.js @@ -0,0 +1,16 @@ +import { useContext, createContext } from "react"; + +export const context = createContext(); + +export function getStaticProps() { + return { props: {} }; +} + +function El() { + const value = useContext(context); + return
; +} + +const a = 5; + +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-data.js new file mode 100644 index 00000000000000..322406da7e52df --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-data.js @@ -0,0 +1,11 @@ +import { createContext } from "react"; + +export const context = createContext(); + +export function getStaticProps() { + return { + props: {}, + }; +} +const a = 5; +export { a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-default.js new file mode 100644 index 00000000000000..5ab14ace53301a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-default.js @@ -0,0 +1,11 @@ +import { useContext, createContext } from "react"; + +export var __N_SSG = true; +export const context = createContext(); + +function El() { + const value = useContext(context); + return __jsx("div", null); +} +const a = 5; +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/input.js new file mode 100644 index 00000000000000..4d0a8c195fe984 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/input.js @@ -0,0 +1,11 @@ +export function getStaticProps() { + return { props: {} }; +} + +function El() { + return
; +} + +const a = 5; + +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-data.js new file mode 100644 index 00000000000000..c6870230282d7c --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-data.js @@ -0,0 +1,7 @@ +export function getStaticProps() { + return { + props: {}, + }; +} +const a = 5; +export { a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-default.js new file mode 100644 index 00000000000000..bc15afbcd03a19 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-default.js @@ -0,0 +1,6 @@ +function El() { + return __jsx("div", null); +} +const a = 5; +export var __N_SSG = true; +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/input.js new file mode 100644 index 00000000000000..6749cc17f98f0a --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/input.js @@ -0,0 +1,13 @@ +export function getStaticProps() { + return { props: {} }; +} + +class El extends React.Component { + render() { + return
; + } +} + +const a = 5; + +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-data.js new file mode 100644 index 00000000000000..cf7c57455c3eb3 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-data.js @@ -0,0 +1,8 @@ +export function getStaticProps() { + return { + props: {}, + }; +} + +const a = 5; +export { a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-default.js new file mode 100644 index 00000000000000..294384760bd266 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-default.js @@ -0,0 +1,8 @@ +class El extends React.Component { + render() { + return __jsx("div", null); + } +} +const a = 5; +export var __N_SSG = true; +export { El as default, a }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/input.js new file mode 100644 index 00000000000000..4f6644af6ee763 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/input.js @@ -0,0 +1 @@ +export { getStaticProps, default } from "a"; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-data.js new file mode 100644 index 00000000000000..b037fd615f1b0e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-data.js @@ -0,0 +1 @@ +export { getStaticProps } from "a"; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-default.js new file mode 100644 index 00000000000000..d06f18747a17e5 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-default.js @@ -0,0 +1,2 @@ +export var __N_SSG = true; +export { default } from "a"; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/input.js new file mode 100644 index 00000000000000..0fd980a904250b --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/input.js @@ -0,0 +1,2 @@ +export const other = 0, + getStaticProps = async () => {}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-data.js new file mode 100644 index 00000000000000..0fd980a904250b --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-data.js @@ -0,0 +1,2 @@ +export const other = 0, + getStaticProps = async () => {}; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-default.js new file mode 100644 index 00000000000000..e6534f112e6f42 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-default.js @@ -0,0 +1,2 @@ +export var __N_SSG = true; +export const other = 0; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/input.js new file mode 100644 index 00000000000000..9d280bbb567afc --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/input.js @@ -0,0 +1,9 @@ +export function getStaticProps() { + return { props: {} }; +} + +function El() { + return
; +} + +export { El as default }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-data.js new file mode 100644 index 00000000000000..d7470adb990f4e --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-data.js @@ -0,0 +1,5 @@ +export function getStaticProps() { + return { + props: {}, + }; +} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-default.js new file mode 100644 index 00000000000000..bf72e6f62dc801 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-default.js @@ -0,0 +1,5 @@ +function El() { + return __jsx("div", null); +} +export var __N_SSG = true; +export { El as default }; diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/input.js new file mode 100644 index 00000000000000..8f6591ced2c9bf --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/input.js @@ -0,0 +1,11 @@ +import { PropTypes } from "react"; + +export default function Page() { + return
; +} + +const propTypes = identity( + (Page.propTypes = { + prop: PropTypes.bool, + }) +); diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-data.js new file mode 100644 index 00000000000000..4ed271e8cf8245 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-data.js @@ -0,0 +1,5 @@ +import { PropTypes } from "react"; + +const propTypes = identity({ + prop: PropTypes.bool, +}); diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-default.js new file mode 100644 index 00000000000000..f4305833191a04 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/complex/output-default.js @@ -0,0 +1,7 @@ +import { PropTypes } from "react"; +export default function Page() { + return __jsx("div", null); +} +const propTypes = identity(Page.propTypes = { + prop: PropTypes.bool +}); diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/input.js new file mode 100644 index 00000000000000..686b22464e9443 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/input.js @@ -0,0 +1,11 @@ +import { PropTypes } from "react"; + +export default function Page() { + return
; +} + +Page.propTypes = { + prop: PropTypes.bool, +}; + +export function otherExport() {} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-data.js new file mode 100644 index 00000000000000..3b312c7ad34a1d --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-data.js @@ -0,0 +1 @@ +export function otherExport() {} diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-default.js new file mode 100644 index 00000000000000..fd535e4f083665 --- /dev/null +++ b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/propTypes/simple/output-default.js @@ -0,0 +1,11 @@ +import { PropTypes } from "react"; + +export default function Page() { + return __jsx("div", null); +} + +Page.propTypes = { + prop: PropTypes.bool, +}; + +export function otherExport() {} From c1685ab0a81143c0f0abcbdbdb831d745957ccac Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Wed, 4 Jan 2023 16:54:34 +0100 Subject: [PATCH 302/672] Page data HMR (vercel/turbo#3132) Based on vercel/turbo#2968 This builds upon vercel/turbo#2968 and @ForsakenHarmony's work on data routes to enable page data HMR. Page data HMR is a bit more clever than it is in Next.js as we won't re-render a Node.js result for each page file update. Instead, thanks to the `StripPageDefaultExport` transform, there are three versions of the page chunks: * client-side (strips page data exports); * server-side (full); * data server-side (strips page default export). Instead of subscribing to the full server-side result, on hydration, the client-side page separately subscribes to: * client-side updates (already the case); * data server-side updates (new). This means that updating something that only affects the page component will only cause a client-side update and **no Node.js re-rendering**, while updating something that only affects the data will only cause a server-side update. ~~I'm marking this as a draft for now as there are still a few areas to test/investigate:~~ - [x] When something that is used in both the default page export and data exports is changed, this will cause *two* HMR updates: one data update, and one client-side chunk update. **The same case breaks in Next.js, where we will receive a client-side update, but no server-side update, ending up with an incorrect result.** - [x] Differences between `getStaticProps/getServerSideProps`, as well as `getInitialProps` (need to talk with @timneutkens about this) (see https://github.com/vercel/next.js/pull/44523) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../crates/next-core/js/src/dev/hmr-client.ts | 61 ++++-- .../next-core/js/src/dev/hot-reloader.tsx | 4 +- .../next-core/js/src/entry/fallback.tsx | 4 +- .../next-core/js/src/entry/next-hydrate.tsx | 116 ++++++++++- .../js/src/entry/server-renderer.tsx | 14 +- packages/next-swc/crates/next-core/src/lib.rs | 6 +- .../next-core/src/next_client/context.rs | 29 --- .../crates/next-core/src/next_shared/mod.rs | 1 + .../next-core/src/next_shared/transforms.rs | 58 ++++++ ...rver_rendered_source.rs => page_source.rs} | 197 ++++++++++++++---- packages/next-swc/crates/next-dev/src/lib.rs | 18 +- 11 files changed, 400 insertions(+), 108 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_shared/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/next_shared/transforms.rs rename packages/next-swc/crates/next-core/src/{server_rendered_source.rs => page_source.rs} (71%) diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 9f6f4879c1c73f..9251e8f93e648a 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -47,20 +47,25 @@ export function connect({ assetPrefix }: ClientOptions) { } globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS = { push: ([chunkPath, callback]: [ChunkPath, UpdateCallback]) => { - onChunkUpdate(chunkPath, callback); + subscribeToChunkUpdate(chunkPath, callback); }, }; if (Array.isArray(queued)) { for (const [chunkPath, callback] of queued) { - onChunkUpdate(chunkPath, callback); + subscribeToChunkUpdate(chunkPath, callback); } } subscribeToInitialCssChunksUpdates(assetPrefix); } -const updateCallbacks: Map> = new Map(); +type UpdateCallbackSet = { + callbacks: Set; + unsubscribe: () => void; +}; + +const updateCallbackSets: Map = new Map(); function sendJSON(message: ClientMessage) { sendMessage(JSON.stringify(message)); @@ -75,15 +80,22 @@ function resourceKey(resource: ResourceIdentifier): ResourceKey { }); } -function subscribeToUpdates(resource: ResourceIdentifier) { +function subscribeToUpdates(resource: ResourceIdentifier): () => void { sendJSON({ type: "subscribe", ...resource, }); + + return () => { + sendJSON({ + type: "unsubscribe", + ...resource, + }); + }; } function handleSocketConnected() { - for (const key of updateCallbacks.keys()) { + for (const key of updateCallbackSets.keys()) { subscribeToUpdates(JSON.parse(key)); } } @@ -249,8 +261,11 @@ function handleSocketMessage(msg: ServerMessage) { } } -export function onChunkUpdate(chunkPath: ChunkPath, callback: UpdateCallback) { - onUpdate( +export function subscribeToChunkUpdate( + chunkPath: ChunkPath, + callback: UpdateCallback +): () => void { + return subscribeToUpdate( { path: chunkPath, }, @@ -258,33 +273,43 @@ export function onChunkUpdate(chunkPath: ChunkPath, callback: UpdateCallback) { ); } -export function onUpdate( +export function subscribeToUpdate( resource: ResourceIdentifier, callback: UpdateCallback ) { const key = resourceKey(resource); - let callbacks = updateCallbacks.get(key); - if (!callbacks) { - subscribeToUpdates(resource); - updateCallbacks.set(key, (callbacks = new Set([callback]))); + let callbackSet: UpdateCallbackSet; + const existingCallbackSet = updateCallbackSets.get(key); + if (!existingCallbackSet) { + callbackSet = { + callbacks: new Set([callback]), + unsubscribe: subscribeToUpdates(resource), + }; + updateCallbackSets.set(key, callbackSet); } else { - callbacks.add(callback); + existingCallbackSet.callbacks.add(callback); + callbackSet = existingCallbackSet; } return () => { - callbacks!.delete(callback); + callbackSet.callbacks.delete(callback); + + if (callbackSet.callbacks.size === 0) { + callbackSet.unsubscribe(); + updateCallbackSets.delete(key); + } }; } function triggerUpdate(msg: ServerMessage) { const key = resourceKey(msg.resource); - const callbacks = updateCallbacks.get(key); - if (!callbacks) { + const callbackSet = updateCallbackSets.get(key); + if (!callbackSet) { return; } try { - for (const callback of callbacks) { + for (const callback of callbackSet.callbacks) { callback(msg); } } catch (err) { @@ -324,7 +349,7 @@ export function subscribeToCssChunkUpdates( } const chunkPath = pathname.slice(cssChunkPrefix.length); - onChunkUpdate(chunkPath, (update) => { + subscribeToChunkUpdate(chunkPath, (update) => { switch (update.type) { case "restart": { console.info(`Reloading CSS chunk \`${chunkPath}\``); diff --git a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx index 9ba09f5a1cc3fe..cee6684283d877 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx +++ b/packages/next-swc/crates/next-core/js/src/dev/hot-reloader.tsx @@ -3,7 +3,7 @@ import type React from "react"; import { useRouter, usePathname } from "next/dist/client/components/navigation"; import { useEffect } from "react"; -import { onUpdate } from "./hmr-client"; +import { subscribeToUpdate } from "./hmr-client"; import { ReactDevOverlay } from "./client"; type HotReloadProps = React.PropsWithChildren<{ @@ -15,7 +15,7 @@ export default function HotReload({ assetPrefix, children }: HotReloadProps) { const path = usePathname()!.slice(1); useEffect(() => { - const unsubscribe = onUpdate( + const unsubscribe = subscribeToUpdate( { path, headers: { diff --git a/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx b/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx index 2bdd59e608e440..0ce5f210ba9036 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/fallback.tsx @@ -6,11 +6,11 @@ import { initializeHMR, ReactDevOverlay, } from "@vercel/turbopack-next/dev/client"; -import { onUpdate } from "@vercel/turbopack-next/dev/hmr-client"; +import { subscribeToUpdate } from "@vercel/turbopack-next/dev/hmr-client"; const pageChunkPath = location.pathname.slice(1); -onUpdate( +subscribeToUpdate( { path: pageChunkPath, headers: { diff --git a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx index d71ecfcfee941e..f53ceca4c38f49 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/next-hydrate.tsx @@ -1,8 +1,17 @@ import "@vercel/turbopack-next/internal/shims-client"; -import { initialize, hydrate } from "next/dist/client"; +import { initialize, hydrate, router } from "next/dist/client"; +import type { Router } from "next/dist/client/router"; +import { + assign, + urlQueryToSearchParams, +} from "next/dist/shared/lib/router/utils/querystring"; +import { formatWithValidation } from "next/dist/shared/lib/router/utils/format-url"; import { initializeHMR } from "@vercel/turbopack-next/dev/client"; -import { subscribeToCssChunkUpdates } from "@vercel/turbopack-next/dev/hmr-client"; +import { + subscribeToUpdate, + subscribeToCssChunkUpdates, +} from "@vercel/turbopack-next/dev/hmr-client"; import * as _app from "@vercel/turbopack-next/pages/_app"; import * as page from "."; @@ -66,5 +75,108 @@ async function loadPageChunk(assetPrefix: string, chunkPath: string) { await hydrate({}); + // This needs to happen after hydration because the router is initialized + // during hydration. To make this dependency clearer, we pass `router` as an + // explicit argument instead of relying on the `router` import binding. + subscribeToCurrentPageData({ assetPrefix, router }); + console.debug("The page has been hydrated"); })().catch((err) => console.error(err)); + +/** + * Subscribes to the current page's data updates from the HMR server. + * + * Updates on route change. + */ +function subscribeToCurrentPageData({ + router, + assetPrefix, +}: { + router: Router; + assetPrefix: string; +}) { + let dataPath = getCurrentPageDataHref(); + let unsubscribe = subscribeToPageData({ + router, + dataPath, + assetPrefix, + }); + + router.events.on("routeChangeComplete", () => { + const nextDataPath = getCurrentPageDataHref(); + if (dataPath === nextDataPath) { + return; + } + dataPath = nextDataPath; + + unsubscribe(); + unsubscribe = subscribeToPageData({ + router, + dataPath, + assetPrefix, + }); + }); +} + +function getCurrentPageDataHref(): string { + return router.pageLoader.getDataHref({ + asPath: router.asPath, + href: formatWithValidation({ + // No need to pass `router.query` when `skipInterpolation` is true. + pathname: router.pathname, + }), + skipInterpolation: true, + }); +} + +/** + * TODO(alexkirsz): Handle assetPrefix/basePath. + */ +function subscribeToPageData({ + router, + dataPath, + assetPrefix, +}: { + router: Router; + dataPath: string; + assetPrefix: string; +}): () => void { + return subscribeToUpdate( + { + // We need to remove the leading / from the data path as Turbopack + // resources are not prefixed with a /. + path: dataPath.slice(1), + headers: { + // This header is used by the Next.js server to determine whether this + // is a data request. + "x-nextjs-data": "1", + }, + }, + (update) => { + if (update.type !== "restart") { + return; + } + + // This triggers a reload of the page data. + // Adapted from next.js/packages/next/client/next-dev.js. + router + .replace( + router.pathname + + "?" + + String( + assign( + urlQueryToSearchParams(router.query), + new URLSearchParams(location.search) + ) + ), + router.asPath, + { scroll: false } + ) + .catch(() => { + // trigger hard reload when failing to refresh data + // to show error overlay properly + location.reload(); + }); + } + ); +} diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 7eb9215a536ae7..607c5b1d6a87a9 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -8,7 +8,6 @@ import "@vercel/turbopack-next/internal/shims"; import type { IncomingMessage, ServerResponse } from "node:http"; import { renderToHTML, RenderOpts } from "next/dist/server/render"; -import RenderResult from "next/dist/server/render-result"; import type { BuildManifest } from "next/dist/server/get-page-files"; import { ServerResponseShim } from "@vercel/turbopack-next/internal/http"; @@ -102,16 +101,25 @@ async function runOperation( ampFirstPages: [], }; + // When rendering a data request, the default component export is eliminated + // by the Next.js strip export transform. The following checks for this case + // and replaces the default export with a dummy component instead. + const comp = + typeof Component === "undefined" || + (typeof Component === "object" && Object.keys(Component).length === 0) + ? () => {} + : Component; + const renderOpts: RenderOpts = { /* LoadComponentsReturnType */ - Component, + Component: comp, App, Document, pageConfig: {}, buildManifest, reactLoadableManifest: {}, ComponentMod: { - default: Component, + default: comp, ...otherExports, }, pathname: renderData.path, diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 4848b02aa69100..6dd3e53414f955 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -15,15 +15,17 @@ mod next_font_google; pub mod next_image; mod next_import_map; pub mod next_server; +pub mod next_shared; mod page_loader; +mod page_source; pub mod react_refresh; mod runtime; -mod server_rendered_source; mod util; mod web_entry_source; pub use app_source::create_app_source; -pub use server_rendered_source::create_server_rendered_source; +pub use page_source::create_page_source; +pub use turbopack_node::source_map; pub use web_entry_source::create_web_entry_source; pub fn register() { diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index f8cb55e4b86e63..81543f13dc8353 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -136,35 +136,6 @@ pub async fn get_client_module_options_context( Ok(add_next_font_transform(module_options_context.cell())) } -#[turbo_tasks::function] -pub async fn add_next_transforms_to_pages( - module_options_context: ModuleOptionsContextVc, - pages_dir: FileSystemPathVc, -) -> Result { - let mut module_options_context = module_options_context.await?.clone_value(); - // Apply the Next SSG tranform to all pages. - module_options_context.custom_rules.push(ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathInExactDirectory(pages_dir.await?), - ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType(ReferenceType::Url( - UrlReferenceSubType::Undefined, - ))), - ModuleRuleCondition::any(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), - ]), - ]), - vec![ModuleRuleEffect::AddEcmascriptTransforms( - EcmascriptInputTransformsVc::cell(vec![ - EcmascriptInputTransform::NextJsStripPageDataExports, - ]), - )], - )); - Ok(module_options_context.cell()) -} - #[turbo_tasks::function] pub async fn add_next_font_transform( module_options_context: ModuleOptionsContextVc, diff --git a/packages/next-swc/crates/next-core/src/next_shared/mod.rs b/packages/next-swc/crates/next-core/src/next_shared/mod.rs new file mode 100644 index 00000000000000..3276530798b85c --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_shared/mod.rs @@ -0,0 +1 @@ +pub mod transforms; diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms.rs new file mode 100644 index 00000000000000..63ab8fce4b0a94 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms.rs @@ -0,0 +1,58 @@ +use anyhow::Result; +use turbo_tasks::Value; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::module_options::{ + ModuleOptionsContextVc, ModuleRule, ModuleRuleCondition, ModuleRuleEffect, +}; +use turbopack_ecmascript::{ + EcmascriptInputTransform, EcmascriptInputTransformsVc, NextJsPageExportFilter, +}; + +#[turbo_tasks::value(serialization = "auto_for_input")] +#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] +pub enum PageTransformType { + Client, + SsrData, +} + +#[turbo_tasks::function] +pub async fn add_next_transforms_to_pages( + module_options_context: ModuleOptionsContextVc, + pages_dir: FileSystemPathVc, + transform_ty: Value, +) -> Result { + let page_transform = match transform_ty.into_value() { + PageTransformType::Client => EcmascriptInputTransform::NextJsStripPageExports( + NextJsPageExportFilter::StripDataExports, + ), + PageTransformType::SsrData => EcmascriptInputTransform::NextJsStripPageExports( + NextJsPageExportFilter::StripDefaultExport, + ), + }; + let mut module_options_context = module_options_context.await?.clone_value(); + // Apply the Next SSG tranform to all pages. + module_options_context.custom_rules.push(ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathInExactDirectory(pages_dir.await?), + ModuleRuleCondition::not(ModuleRuleCondition::any(vec![ + // TODO(alexkirsz): Possibly ignore _app as well? + ModuleRuleCondition::ResourcePathEquals(pages_dir.join("_document.js").await?), + ModuleRuleCondition::ResourcePathEquals(pages_dir.join("_document.jsx").await?), + ModuleRuleCondition::ResourcePathEquals(pages_dir.join("_document.ts").await?), + ModuleRuleCondition::ResourcePathEquals(pages_dir.join("_document.tsx").await?), + ])), + ]), + ModuleRuleCondition::any(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), + ]), + ]), + vec![ModuleRuleEffect::AddEcmascriptTransforms( + EcmascriptInputTransformsVc::cell(vec![page_transform]), + )], + )); + Ok(module_options_context.cell()) +} diff --git a/packages/next-swc/crates/next-core/src/server_rendered_source.rs b/packages/next-swc/crates/next-core/src/page_source.rs similarity index 71% rename from packages/next-swc/crates/next-core/src/server_rendered_source.rs rename to packages/next-swc/crates/next-core/src/page_source.rs index 8a87c5e6a83537..b777e9476a5e6b 100644 --- a/packages/next-swc/crates/next-core/src/server_rendered_source.rs +++ b/packages/next-swc/crates/next-core/src/page_source.rs @@ -7,12 +7,14 @@ use turbo_tasks::{ }; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}; -use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; +use turbopack::{ + module_options::ModuleOptionsContextVc, transition::TransitionsByNameVc, ModuleAssetContextVc, +}; use turbopack_core::{ asset::AssetVc, chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, context::AssetContextVc, - environment::ServerAddrVc, + environment::{EnvironmentVc, ServerAddrVc}, reference_type::{EntryReferenceSubType, ReferenceType}, source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, @@ -45,9 +47,9 @@ use crate::{ fallback::get_fallback_page, next_client::{ context::{ - add_next_transforms_to_pages, get_client_assets_path, get_client_chunking_context, - get_client_environment, get_client_module_options_context, - get_client_resolve_options_context, get_client_runtime_entries, ContextType, + get_client_assets_path, get_client_chunking_context, get_client_environment, + get_client_module_options_context, get_client_resolve_options_context, + get_client_runtime_entries, ContextType, }, NextClientTransition, }, @@ -56,14 +58,64 @@ use crate::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, + next_shared::transforms::{add_next_transforms_to_pages, PageTransformType}, page_loader::create_page_loader, util::{get_asset_path_from_route, pathname_for_path, regular_expression_for_path}, }; +#[turbo_tasks::function] +fn get_page_client_module_options_context( + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, + client_environment: EnvironmentVc, + ty: Value, +) -> Result { + let client_module_options_context = + get_client_module_options_context(project_path, execution_context, client_environment, ty); + + let client_module_options_context = match ty.into_value() { + ContextType::Pages { pages_dir } => add_next_transforms_to_pages( + client_module_options_context, + pages_dir, + Value::new(PageTransformType::Client), + ), + _ => client_module_options_context, + }; + + Ok(client_module_options_context) +} + +#[turbo_tasks::value(serialization = "auto_for_input")] +#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] +pub enum PageSsrType { + Ssr, + SsrData, +} + +#[turbo_tasks::function] +fn get_page_server_module_options_context( + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, + pages_dir: FileSystemPathVc, + ssr_ty: Value, +) -> ModuleOptionsContextVc { + let server_ty = Value::new(ServerContextType::Pages { pages_dir }); + let server_module_options_context = + get_server_module_options_context(project_path, execution_context, server_ty); + + match ssr_ty.into_value() { + PageSsrType::Ssr => server_module_options_context, + PageSsrType::SsrData => { + let transform_ty = Value::new(PageTransformType::SsrData); + add_next_transforms_to_pages(server_module_options_context, pages_dir, transform_ty) + } + } +} + /// Create a content source serving the `pages` or `src/pages` directory as /// Next.js pages folder. #[turbo_tasks::function] -pub async fn create_server_rendered_source( +pub async fn create_page_source( project_root: FileSystemPathVc, execution_context: ExecutionContextVc, output_path: FileSystemPathVc, @@ -89,10 +141,17 @@ pub async fn create_server_rendered_source( let server_ty = Value::new(ServerContextType::Pages { pages_dir }); let client_environment = get_client_environment(browserslist_query); - let client_module_options_context = - get_client_module_options_context(project_path, execution_context, client_environment, ty); - let client_module_options_context = - add_next_transforms_to_pages(client_module_options_context, pages_dir); + let client_module_options_context = get_page_client_module_options_context( + project_path, + execution_context, + client_environment, + ty, + ); + let client_module_options_context = add_next_transforms_to_pages( + client_module_options_context, + pages_dir, + Value::new(PageTransformType::Client), + ); let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); let client_context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -118,13 +177,42 @@ pub async fn create_server_rendered_source( .cell() .into(); - let mut transitions = HashMap::new(); - transitions.insert("next-client".to_string(), next_client_transition); - let context: AssetContextVc = ModuleAssetContextVc::new( - TransitionsByNameVc::cell(transitions), - get_server_environment(server_ty, env, server_addr), - get_server_module_options_context(project_path, execution_context, server_ty), - get_server_resolve_options_context(project_path, server_ty, next_config), + let server_environment = get_server_environment(server_ty, env, server_addr); + let server_resolve_options_context = + get_server_resolve_options_context(project_path, server_ty, next_config); + + let server_module_options_context = get_page_server_module_options_context( + project_path, + execution_context, + pages_dir, + Value::new(PageSsrType::Ssr), + ); + let server_transitions = TransitionsByNameVc::cell( + [("next-client".to_string(), next_client_transition)] + .into_iter() + .collect(), + ); + + let server_context: AssetContextVc = ModuleAssetContextVc::new( + server_transitions, + server_environment, + server_module_options_context, + server_resolve_options_context, + ) + .into(); + + let server_data_module_options_context = get_page_server_module_options_context( + project_path, + execution_context, + pages_dir, + Value::new(PageSsrType::SsrData), + ); + + let server_data_context: AssetContextVc = ModuleAssetContextVc::new( + TransitionsByNameVc::cell(HashMap::new()), + server_environment, + server_data_module_options_context, + server_resolve_options_context, ) .into(); @@ -143,9 +231,10 @@ pub async fn create_server_rendered_source( next_config, ); - let server_rendered_source = create_server_rendered_source_for_directory( + let page_source = create_page_source_for_directory( project_path, - context, + server_context, + server_data_context, client_context, pages_dir, SpecificityVc::exact(), @@ -162,7 +251,7 @@ pub async fn create_server_rendered_source( AssetGraphContentSourceVc::new_eager(server_root, fallback_page.as_asset()); Ok(CombinedContentSource { - sources: vec![server_rendered_source.into(), fallback_source.into()], + sources: vec![page_source.into(), fallback_source.into()], } .cell() .into()) @@ -170,9 +259,10 @@ pub async fn create_server_rendered_source( /// Handles a single page file in the pages directory #[turbo_tasks::function] -async fn create_server_rendered_source_for_file( +async fn create_page_source_for_file( context_path: FileSystemPathVc, - context: AssetContextVc, + server_context: AssetContextVc, + server_data_context: AssetContextVc, client_context: AssetContextVc, pages_dir: FileSystemPathVc, specificity: SpecificityVc, @@ -185,12 +275,16 @@ async fn create_server_rendered_source_for_file( intermediate_output_path: FileSystemPathVc, ) -> Result { let source_asset = SourceAssetVc::new(page_file).into(); - let entry_asset = context.process( + let entry_asset = server_context.process( + source_asset, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)), + ); + let data_asset = server_data_context.process( source_asset, Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)), ); - let chunking_context = DevChunkingContextVc::builder( + let server_chunking_context = DevChunkingContextVc::builder( context_path, intermediate_output_path, intermediate_output_path.join("chunks"), @@ -198,6 +292,16 @@ async fn create_server_rendered_source_for_file( ) .build(); + let data_intermediate_output_path = intermediate_output_path.join("data"); + + let server_data_chunking_context = DevChunkingContextVc::builder( + context_path, + data_intermediate_output_path, + data_intermediate_output_path.join("chunks"), + get_client_assets_path(server_root, Value::new(ContextType::Pages { pages_dir })), + ) + .build(); + let client_chunking_context = get_client_chunking_context( context_path, server_root, @@ -214,10 +318,10 @@ async fn create_server_rendered_source_for_file( pathname, path_regex, SsrEntry { - context, + context: server_context, entry_asset, is_api_path, - chunking_context, + chunking_context: server_chunking_context, intermediate_output_path, } .cell() @@ -225,22 +329,32 @@ async fn create_server_rendered_source_for_file( runtime_entries, ) } else { - let data_pathname = format!( + let data_pathname = StringVc::cell(format!( "_next/data/development/{}", get_asset_path_from_route(&pathname.await?, ".json") - ); - let data_path_regex = regular_expression_for_path(StringVc::cell(data_pathname)); + )); + let data_path_regex = regular_expression_for_path(data_pathname); let ssr_entry = SsrEntry { - context, + context: server_context, entry_asset, is_api_path, - chunking_context, + chunking_context: server_chunking_context, intermediate_output_path, } .cell() .into(); + let ssr_data_entry = SsrEntry { + context: server_data_context, + entry_asset: data_asset, + is_api_path, + chunking_context: server_data_chunking_context, + intermediate_output_path: data_intermediate_output_path, + } + .cell() + .into(); + CombinedContentSourceVc::new(vec![ create_node_rendered_source( specificity, @@ -254,9 +368,9 @@ async fn create_server_rendered_source_for_file( create_node_rendered_source( specificity, server_root, - pathname, + data_pathname, data_path_regex, - ssr_entry, + ssr_data_entry, runtime_entries, fallback_page, ), @@ -274,11 +388,12 @@ async fn create_server_rendered_source_for_file( /// Handles a directory in the pages directory (or the pages directory itself). /// Calls itself recursively for sub directories or the -/// [create_server_rendered_source_for_file] method for files. +/// [create_page_source_for_file] method for files. #[turbo_tasks::function] -async fn create_server_rendered_source_for_directory( +async fn create_page_source_for_directory( context_path: FileSystemPathVc, - context: AssetContextVc, + server_context: AssetContextVc, + server_data_context: AssetContextVc, client_context: AssetContextVc, pages_dir: FileSystemPathVc, specificity: SpecificityVc, @@ -331,9 +446,10 @@ async fn create_server_rendered_source_for_directory( }; sources.push(( name, - create_server_rendered_source_for_file( + create_page_source_for_file( context_path, - context, + server_context, + server_data_context, client_context, pages_dir, specificity, @@ -354,9 +470,10 @@ async fn create_server_rendered_source_for_directory( DirectoryEntry::Directory(dir) => { sources.push(( name, - create_server_rendered_source_for_directory( + create_page_source_for_directory( context_path, - context, + server_context, + server_data_context, client_context, pages_dir, specificity, diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 6536f11c61b82c..d22c7d550fd0a8 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -18,9 +18,9 @@ use std::{ use anyhow::{anyhow, Context, Result}; use devserver_options::DevServerOptions; use next_core::{ - create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env, + create_app_source, create_page_source, create_web_entry_source, env::load_env, manifest::DevManifestContentSource, next_config::load_next_config, - next_image::NextImageContentSourceVc, + next_image::NextImageContentSourceVc, source_map::NextSourceMapTraceContentSourceVc, }; use owo_colors::OwoColorize; use turbo_malloc::TurboMalloc; @@ -46,9 +46,7 @@ use turbopack_dev_server::{ }, DevServer, DevServerBuilder, }; -use turbopack_node::{ - execution_context::ExecutionContextVc, source_map::NextSourceMapTraceContentSourceVc, -}; +use turbopack_node::execution_context::ExecutionContextVc; #[derive(Clone)] pub enum EntryRequest { @@ -302,7 +300,7 @@ async fn source( &browserslist_query, next_config, ); - let rendered_source = create_server_rendered_source( + let page_source = create_page_source( project_path, execution_context, output_root.join("pages"), @@ -330,7 +328,7 @@ async fn source( let static_source = StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into(); let manifest_source = DevManifestContentSource { - page_roots: vec![app_source, rendered_source], + page_roots: vec![app_source, page_source], } .cell() .into(); @@ -338,7 +336,7 @@ async fn source( manifest_source, static_source, app_source, - rendered_source, + page_source, web_source, ]); let introspect = IntrospectionSource { @@ -350,7 +348,7 @@ async fn source( let source_maps = SourceMapContentSourceVc::new(main_source).into(); let source_map_trace = NextSourceMapTraceContentSourceVc::new(main_source).into(); let img_source = NextImageContentSourceVc::new( - CombinedContentSourceVc::new(vec![static_source, rendered_source]).into(), + CombinedContentSourceVc::new(vec![static_source, page_source]).into(), ) .into(); let source = RouterContentSource { @@ -372,7 +370,7 @@ async fn source( handle_issues(dev_server_fs, console_ui).await?; handle_issues(web_source, console_ui).await?; - handle_issues(rendered_source, console_ui).await?; + handle_issues(page_source, console_ui).await?; Ok(source) } From d79c929de5145f50c16ef0d9bea3bbc117d656ab Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Fri, 6 Jan 2023 11:36:09 +0100 Subject: [PATCH 303/672] Reorganize next_client and next_server modules (vercel/turbo#3182) This is a straightforward chore PR to move next_client and next_server modules around, in order to make navigation and imports more predictable between them. I'm also planning to introduce a next_shared::context in a further PR, hence the changes. --- .../crates/next-core/src/app_source.rs | 10 +- .../next-swc/crates/next-core/src/fallback.rs | 4 +- .../next-core/src/next_client/context.rs | 24 +-- .../crates/next-core/src/next_client/mod.rs | 101 +-------- .../next-core/src/next_client/transition.rs | 99 +++++++++ .../crates/next-core/src/next_import_map.rs | 24 +-- .../next-core/src/next_server/context.rs | 199 +++++++++++++++++ .../crates/next-core/src/next_server/mod.rs | 200 +----------------- .../crates/next-core/src/page_source.rs | 24 ++- .../crates/next-core/src/web_entry_source.rs | 4 +- 10 files changed, 348 insertions(+), 341 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_client/transition.rs create mode 100644 packages/next-swc/crates/next-core/src/next_server/context.rs diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index b91c9359e7171b..8a60eeb95c8e5b 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -50,9 +50,9 @@ use crate::{ next_client::{ context::{ get_client_chunking_context, get_client_environment, get_client_module_options_context, - get_client_resolve_options_context, get_client_runtime_entries, ContextType, + get_client_resolve_options_context, get_client_runtime_entries, ClientContextType, }, - NextClientTransition, + transition::NextClientTransition, }, next_client_component::{ client_chunks_transition::NextClientChunksTransition, @@ -60,7 +60,7 @@ use crate::{ ssr_client_module_transition::NextSSRClientModuleTransition, }, next_config::NextConfigVc, - next_server::{ + next_server::context::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, @@ -75,7 +75,7 @@ fn next_client_chunks_transition( server_root: FileSystemPathVc, browserslist_query: &str, ) -> TransitionVc { - let ty = Value::new(ContextType::App { app_dir }); + let ty = Value::new(ClientContextType::App { app_dir }); let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); @@ -102,7 +102,7 @@ async fn next_client_transition( browserslist_query: &str, next_config: NextConfigVc, ) -> Result { - let ty = Value::new(ContextType::App { app_dir }); + let ty = Value::new(ClientContextType::App { app_dir }); let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); let client_module_options_context = diff --git a/packages/next-swc/crates/next-core/src/fallback.rs b/packages/next-swc/crates/next-core/src/fallback.rs index 3374dd0688de13..296093042d2430 100644 --- a/packages/next-swc/crates/next-core/src/fallback.rs +++ b/packages/next-swc/crates/next-core/src/fallback.rs @@ -18,7 +18,7 @@ use turbopack_node::execution_context::ExecutionContextVc; use crate::{ next_client::context::{ get_client_chunking_context, get_client_environment, get_client_module_options_context, - get_client_resolve_options_context, get_client_runtime_entries, ContextType, + get_client_resolve_options_context, get_client_runtime_entries, ClientContextType, }, next_config::NextConfigVc, next_import_map::insert_next_shared_aliases, @@ -34,7 +34,7 @@ pub async fn get_fallback_page( browserslist_query: &str, next_config: NextConfigVc, ) -> Result { - let ty = Value::new(ContextType::Fallback); + let ty = Value::new(ClientContextType::Fallback); let environment = get_client_environment(browserslist_query); let resolve_options_context = get_client_resolve_options_context(project_path, ty); let module_options_context = diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 81543f13dc8353..b88805681c22f4 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -57,7 +57,7 @@ pub fn get_client_environment(browserslist_query: &str) -> EnvironmentVc { #[turbo_tasks::value(serialization = "auto_for_input")] #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] -pub enum ContextType { +pub enum ClientContextType { Pages { pages_dir: FileSystemPathVc }, App { app_dir: FileSystemPathVc }, Fallback, @@ -67,7 +67,7 @@ pub enum ContextType { #[turbo_tasks::function] pub fn get_client_resolve_options_context( project_path: FileSystemPathVc, - ty: Value, + ty: Value, ) -> ResolveOptionsContextVc { let next_client_import_map = get_next_client_import_map(project_path, ty); let next_client_fallback_import_map = get_next_client_fallback_import_map(ty); @@ -99,7 +99,7 @@ pub async fn get_client_module_options_context( project_path: FileSystemPathVc, execution_context: ExecutionContextVc, env: EnvironmentVc, - ty: Value, + ty: Value, ) -> Result { let resolve_options_context = get_client_resolve_options_context(project_path, ty); let enable_react_refresh = @@ -173,7 +173,7 @@ pub fn get_client_asset_context( project_path: FileSystemPathVc, execution_context: ExecutionContextVc, browserslist_query: &str, - ty: Value, + ty: Value, ) -> AssetContextVc { let environment = get_client_environment(browserslist_query); let resolve_options_context = get_client_resolve_options_context(project_path, ty); @@ -195,16 +195,16 @@ pub fn get_client_asset_context( pub fn get_client_chunking_context( project_path: FileSystemPathVc, server_root: FileSystemPathVc, - ty: Value, + ty: Value, ) -> ChunkingContextVc { DevChunkingContextVc::builder( project_path, server_root, match ty.into_value() { - ContextType::Pages { .. } | ContextType::App { .. } => { + ClientContextType::Pages { .. } | ClientContextType::App { .. } => { server_root.join("/_next/static/chunks") } - ContextType::Fallback | ContextType::Other => server_root.join("/_chunks"), + ClientContextType::Fallback | ClientContextType::Other => server_root.join("/_chunks"), }, get_client_assets_path(server_root, ty), ) @@ -215,13 +215,13 @@ pub fn get_client_chunking_context( #[turbo_tasks::function] pub fn get_client_assets_path( server_root: FileSystemPathVc, - ty: Value, + ty: Value, ) -> FileSystemPathVc { match ty.into_value() { - ContextType::Pages { .. } | ContextType::App { .. } => { + ClientContextType::Pages { .. } | ClientContextType::App { .. } => { server_root.join("/_next/static/assets") } - ContextType::Fallback | ContextType::Other => server_root.join("/_assets"), + ClientContextType::Fallback | ClientContextType::Other => server_root.join("/_assets"), } } @@ -229,7 +229,7 @@ pub fn get_client_assets_path( pub async fn get_client_runtime_entries( project_root: FileSystemPathVc, env: ProcessEnvVc, - ty: Value, + ty: Value, next_config: NextConfigVc, ) -> Result { let resolve_options_context = get_client_resolve_options_context(project_root, ty); @@ -249,7 +249,7 @@ pub async fn get_client_runtime_entries( if let Some(request) = enable_react_refresh { runtime_entries.push(RuntimeEntry::Request(request, project_root.join("_")).cell()) }; - if matches!(ty.into_value(), ContextType::Other) { + if matches!(ty.into_value(), ClientContextType::Other) { runtime_entries.push( RuntimeEntry::Request( RequestVc::parse(Value::new(Pattern::Constant( diff --git a/packages/next-swc/crates/next-core/src/next_client/mod.rs b/packages/next-swc/crates/next-core/src/next_client/mod.rs index c6f54dbe6ef0bb..f0aa8da49b0fe8 100644 --- a/packages/next-swc/crates/next-core/src/next_client/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_client/mod.rs @@ -1,102 +1,3 @@ pub(crate) mod context; pub(crate) mod runtime_entry; - -use anyhow::{bail, Result}; -use turbo_tasks::ValueToString; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack::{ - ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, - module_options::ModuleOptionsContextVc, - resolve_options_context::ResolveOptionsContextVc, - transition::{Transition, TransitionVc}, - ModuleAssetContextVc, -}; -use turbopack_core::{ - asset::AssetVc, - chunk::{ChunkableAssetVc, ChunkingContextVc}, - environment::EnvironmentVc, - virtual_asset::VirtualAssetVc, -}; - -use self::runtime_entry::RuntimeEntriesVc; -use crate::embed_js::next_js_file; - -/// Makes a transition into a next.js client context. -/// -/// It wraps the target asset with client bootstrapping hydration. It changes -/// the environment to be inside of the browser. It offers a module to the -/// importer that exports an array of chunk urls. -#[turbo_tasks::value(shared)] -pub struct NextClientTransition { - pub is_app: bool, - pub client_environment: EnvironmentVc, - pub client_module_options_context: ModuleOptionsContextVc, - pub client_resolve_options_context: ResolveOptionsContextVc, - pub client_chunking_context: ChunkingContextVc, - pub server_root: FileSystemPathVc, - pub runtime_entries: RuntimeEntriesVc, -} - -#[turbo_tasks::value_impl] -impl Transition for NextClientTransition { - #[turbo_tasks::function] - fn process_source(&self, asset: AssetVc) -> AssetVc { - if self.is_app { - VirtualAssetVc::new( - asset.path().join("next-app-hydrate.tsx"), - next_js_file("entry/app/hydrate.tsx").into(), - ) - .into() - } else { - VirtualAssetVc::new( - asset.path().join("next-hydrate.tsx"), - next_js_file("entry/next-hydrate.tsx").into(), - ) - .into() - } - } - - #[turbo_tasks::function] - fn process_environment(&self, _environment: EnvironmentVc) -> EnvironmentVc { - self.client_environment - } - - #[turbo_tasks::function] - fn process_module_options_context( - &self, - _context: ModuleOptionsContextVc, - ) -> ModuleOptionsContextVc { - self.client_module_options_context - } - - #[turbo_tasks::function] - fn process_resolve_options_context( - &self, - _context: ResolveOptionsContextVc, - ) -> ResolveOptionsContextVc { - self.client_resolve_options_context - } - - #[turbo_tasks::function] - async fn process_module( - &self, - asset: AssetVc, - context: ModuleAssetContextVc, - ) -> Result { - let chunkable_asset = match ChunkableAssetVc::resolve_from(asset).await? { - Some(chunkable_asset) => chunkable_asset, - None => bail!("asset {} is not chunkable", asset.path().to_string().await?), - }; - - let runtime_entries = self.runtime_entries.resolve_entries(context.into()); - - let asset = ChunkGroupFilesAsset { - asset: chunkable_asset, - chunking_context: self.client_chunking_context, - base_path: self.server_root.join("_next"), - runtime_entries: Some(runtime_entries), - }; - - Ok(asset.cell().into()) - } -} +pub(crate) mod transition; diff --git a/packages/next-swc/crates/next-core/src/next_client/transition.rs b/packages/next-swc/crates/next-core/src/next_client/transition.rs new file mode 100644 index 00000000000000..03c27a4f67750f --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_client/transition.rs @@ -0,0 +1,99 @@ +use anyhow::{bail, Result}; +use turbo_tasks::ValueToString; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{ + ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, + module_options::ModuleOptionsContextVc, + resolve_options_context::ResolveOptionsContextVc, + transition::{Transition, TransitionVc}, + ModuleAssetContextVc, +}; +use turbopack_core::{ + asset::AssetVc, + chunk::{ChunkableAssetVc, ChunkingContextVc}, + environment::EnvironmentVc, + virtual_asset::VirtualAssetVc, +}; + +use super::runtime_entry::RuntimeEntriesVc; +use crate::embed_js::next_js_file; + +/// Makes a transition into a next.js client context. +/// +/// It wraps the target asset with client bootstrapping hydration. It changes +/// the environment to be inside of the browser. It offers a module to the +/// importer that exports an array of chunk urls. +#[turbo_tasks::value(shared)] +pub struct NextClientTransition { + pub is_app: bool, + pub client_environment: EnvironmentVc, + pub client_module_options_context: ModuleOptionsContextVc, + pub client_resolve_options_context: ResolveOptionsContextVc, + pub client_chunking_context: ChunkingContextVc, + pub server_root: FileSystemPathVc, + pub runtime_entries: RuntimeEntriesVc, +} + +#[turbo_tasks::value_impl] +impl Transition for NextClientTransition { + #[turbo_tasks::function] + fn process_source(&self, asset: AssetVc) -> AssetVc { + if self.is_app { + VirtualAssetVc::new( + asset.path().join("next-app-hydrate.tsx"), + next_js_file("entry/app/hydrate.tsx").into(), + ) + .into() + } else { + VirtualAssetVc::new( + asset.path().join("next-hydrate.tsx"), + next_js_file("entry/next-hydrate.tsx").into(), + ) + .into() + } + } + + #[turbo_tasks::function] + fn process_environment(&self, _environment: EnvironmentVc) -> EnvironmentVc { + self.client_environment + } + + #[turbo_tasks::function] + fn process_module_options_context( + &self, + _context: ModuleOptionsContextVc, + ) -> ModuleOptionsContextVc { + self.client_module_options_context + } + + #[turbo_tasks::function] + fn process_resolve_options_context( + &self, + _context: ResolveOptionsContextVc, + ) -> ResolveOptionsContextVc { + self.client_resolve_options_context + } + + #[turbo_tasks::function] + async fn process_module( + &self, + asset: AssetVc, + context: ModuleAssetContextVc, + ) -> Result { + let chunkable_asset = match ChunkableAssetVc::resolve_from(asset).await? { + Some(chunkable_asset) => chunkable_asset, + None => bail!("asset {} is not chunkable", asset.path().to_string().await?), + }; + + let runtime_entries = self.runtime_entries.resolve_entries(context.into()); + + let asset = ChunkGroupFilesAsset { + asset: chunkable_asset, + chunking_context: self.client_chunking_context, + base_path: self.server_root.join("_next"), + runtime_entries: Some(runtime_entries), + }; + + Ok(asset.cell().into()) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index b11a41cddbfe37..b3c33bc6ecf412 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -8,24 +8,24 @@ use turbopack_core::resolve::{ use crate::{ embed_js::{attached_next_js_package_path, VIRTUAL_PACKAGE_NAME}, - next_client::context::ContextType, + next_client::context::ClientContextType, next_config::NextConfigVc, next_font_google::{NextFontGoogleCssModuleReplacerVc, NextFontGoogleReplacerVc}, - next_server::ServerContextType, + next_server::context::ServerContextType, }; /// Computes the Next-specific client import map. #[turbo_tasks::function] pub fn get_next_client_import_map( project_path: FileSystemPathVc, - ty: Value, + ty: Value, ) -> ImportMapVc { let mut import_map = ImportMap::empty(); insert_next_shared_aliases(&mut import_map, project_path); match ty.into_value() { - ContextType::Pages { pages_dir } => { + ClientContextType::Pages { pages_dir } => { insert_alias_to_alternatives( &mut import_map, format!("{VIRTUAL_PACKAGE_NAME}/pages/_app"), @@ -43,7 +43,7 @@ pub fn get_next_client_import_map( ], ); } - ContextType::App { app_dir } => { + ClientContextType::App { app_dir } => { import_map.insert_exact_alias( "react", request_to_import_mapping(app_dir, "next/dist/compiled/react"), @@ -61,8 +61,8 @@ pub fn get_next_client_import_map( request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); } - ContextType::Fallback => {} - ContextType::Other => {} + ClientContextType::Fallback => {} + ClientContextType::Other => {} } import_map.cell() } @@ -89,14 +89,14 @@ pub fn get_next_build_import_map(project_path: FileSystemPathVc) -> ImportMapVc /// Computes the Next-specific client fallback import map, which provides /// polyfills to Node.js externals. #[turbo_tasks::function] -pub fn get_next_client_fallback_import_map(ty: Value) -> ImportMapVc { +pub fn get_next_client_fallback_import_map(ty: Value) -> ImportMapVc { let mut import_map = ImportMap::empty(); match ty.into_value() { - ContextType::Pages { + ClientContextType::Pages { pages_dir: context_dir, } - | ContextType::App { + | ClientContextType::App { app_dir: context_dir, } => { for (original, alias) in NEXT_ALIASES { @@ -108,8 +108,8 @@ pub fn get_next_client_fallback_import_map(ty: Value) -> ImportMapV ); } } - ContextType::Fallback => {} - ContextType::Other => {} + ClientContextType::Fallback => {} + ClientContextType::Other => {} } import_map.cell() diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs new file mode 100644 index 00000000000000..465c449f38d49e --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -0,0 +1,199 @@ +use turbo_tasks::{primitives::StringVc, Value}; +use turbo_tasks_env::ProcessEnvVc; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack::{ + condition::ContextCondition, + module_options::{ModuleOptionsContext, ModuleOptionsContextVc, PostCssTransformOptions}, + resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, +}; +use turbopack_core::environment::{ + EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc, ServerAddrVc, +}; +use turbopack_ecmascript::EcmascriptInputTransform; +use turbopack_node::execution_context::ExecutionContextVc; + +use crate::{ + next_build::get_postcss_package_mapping, + next_client::context::add_next_font_transform, + next_config::NextConfigVc, + next_import_map::{get_next_build_import_map, get_next_server_import_map}, +}; + +#[turbo_tasks::value(serialization = "auto_for_input")] +#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] +pub enum ServerContextType { + Pages { pages_dir: FileSystemPathVc }, + AppSSR { app_dir: FileSystemPathVc }, + AppRSC { app_dir: FileSystemPathVc }, +} + +#[turbo_tasks::function] +pub fn get_server_resolve_options_context( + project_path: FileSystemPathVc, + ty: Value, + next_config: NextConfigVc, +) -> ResolveOptionsContextVc { + let next_server_import_map = get_next_server_import_map(project_path, ty, next_config); + match ty.into_value() { + ServerContextType::Pages { .. } | ServerContextType::AppSSR { .. } => { + let resolve_options_context = ResolveOptionsContext { + enable_node_modules: true, + enable_node_externals: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string()], + import_map: Some(next_server_import_map), + module: true, + ..Default::default() + }; + ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + resolve_options_context.clone().cell(), + )], + ..resolve_options_context + } + } + ServerContextType::AppRSC { .. } => { + let resolve_options_context = ResolveOptionsContext { + enable_node_modules: true, + enable_node_externals: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string(), "react-server".to_string()], + import_map: Some(next_server_import_map), + module: true, + ..Default::default() + }; + ResolveOptionsContext { + enable_typescript: true, + enable_react: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + resolve_options_context.clone().cell(), + )], + ..resolve_options_context + } + } + } + .cell() +} + +#[turbo_tasks::function] +pub fn get_server_environment( + ty: Value, + process_env: ProcessEnvVc, + server_addr: ServerAddrVc, +) -> EnvironmentVc { + EnvironmentVc::new( + Value::new(ExecutionEnvironment::NodeJsLambda( + NodeJsEnvironmentVc::current(process_env, server_addr), + )), + match ty.into_value() { + ServerContextType::Pages { .. } => Value::new(EnvironmentIntention::ServerRendering), + ServerContextType::AppSSR { .. } => Value::new(EnvironmentIntention::Prerendering), + ServerContextType::AppRSC { .. } => Value::new(EnvironmentIntention::ServerRendering), + }, + ) +} + +#[turbo_tasks::function] +pub fn get_server_module_options_context( + project_path: FileSystemPathVc, + execution_context: ExecutionContextVc, + ty: Value, +) -> ModuleOptionsContextVc { + let module_options_context = match ty.into_value() { + ServerContextType::Pages { .. } => { + let module_options_context = ModuleOptionsContext { + execution_context: Some(execution_context), + ..Default::default() + }; + ModuleOptionsContext { + enable_jsx: true, + enable_styled_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), + enable_typescript_transform: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context + } + } + ServerContextType::AppSSR { .. } => { + let module_options_context = ModuleOptionsContext { + execution_context: Some(execution_context), + ..Default::default() + }; + ModuleOptionsContext { + enable_jsx: true, + enable_styled_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), + enable_typescript_transform: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context + } + } + ServerContextType::AppRSC { .. } => { + let module_options_context = ModuleOptionsContext { + custom_ecmascript_transforms: vec![EcmascriptInputTransform::ClientDirective( + StringVc::cell("server-to-client".to_string()), + )], + execution_context: Some(execution_context), + ..Default::default() + }; + ModuleOptionsContext { + enable_jsx: true, + enable_postcss_transform: Some(PostCssTransformOptions { + postcss_package: Some(get_postcss_package_mapping(project_path)), + ..Default::default() + }), + enable_typescript_transform: true, + rules: vec![( + ContextCondition::InDirectory("node_modules".to_string()), + module_options_context.clone().cell(), + )], + ..module_options_context + } + } + } + .cell(); + + add_next_font_transform(module_options_context) +} + +#[turbo_tasks::function] +pub fn get_build_resolve_options_context( + project_path: FileSystemPathVc, +) -> ResolveOptionsContextVc { + let next_build_import_map = get_next_build_import_map(project_path); + ResolveOptionsContext { + enable_typescript: true, + enable_node_modules: true, + enable_node_externals: true, + enable_node_native_modules: true, + custom_conditions: vec!["development".to_string()], + import_map: Some(next_build_import_map), + ..Default::default() + } + .cell() +} + +#[turbo_tasks::function] +pub fn get_build_module_options_context() -> ModuleOptionsContextVc { + ModuleOptionsContext { + enable_typescript_transform: true, + ..Default::default() + } + .cell() +} diff --git a/packages/next-swc/crates/next-core/src/next_server/mod.rs b/packages/next-swc/crates/next-core/src/next_server/mod.rs index 465c449f38d49e..e3c01fd8bd0b5c 100644 --- a/packages/next-swc/crates/next-core/src/next_server/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_server/mod.rs @@ -1,199 +1 @@ -use turbo_tasks::{primitives::StringVc, Value}; -use turbo_tasks_env::ProcessEnvVc; -use turbo_tasks_fs::FileSystemPathVc; -use turbopack::{ - condition::ContextCondition, - module_options::{ModuleOptionsContext, ModuleOptionsContextVc, PostCssTransformOptions}, - resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, -}; -use turbopack_core::environment::{ - EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc, ServerAddrVc, -}; -use turbopack_ecmascript::EcmascriptInputTransform; -use turbopack_node::execution_context::ExecutionContextVc; - -use crate::{ - next_build::get_postcss_package_mapping, - next_client::context::add_next_font_transform, - next_config::NextConfigVc, - next_import_map::{get_next_build_import_map, get_next_server_import_map}, -}; - -#[turbo_tasks::value(serialization = "auto_for_input")] -#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] -pub enum ServerContextType { - Pages { pages_dir: FileSystemPathVc }, - AppSSR { app_dir: FileSystemPathVc }, - AppRSC { app_dir: FileSystemPathVc }, -} - -#[turbo_tasks::function] -pub fn get_server_resolve_options_context( - project_path: FileSystemPathVc, - ty: Value, - next_config: NextConfigVc, -) -> ResolveOptionsContextVc { - let next_server_import_map = get_next_server_import_map(project_path, ty, next_config); - match ty.into_value() { - ServerContextType::Pages { .. } | ServerContextType::AppSSR { .. } => { - let resolve_options_context = ResolveOptionsContext { - enable_node_modules: true, - enable_node_externals: true, - enable_node_native_modules: true, - custom_conditions: vec!["development".to_string()], - import_map: Some(next_server_import_map), - module: true, - ..Default::default() - }; - ResolveOptionsContext { - enable_typescript: true, - enable_react: true, - rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), - resolve_options_context.clone().cell(), - )], - ..resolve_options_context - } - } - ServerContextType::AppRSC { .. } => { - let resolve_options_context = ResolveOptionsContext { - enable_node_modules: true, - enable_node_externals: true, - enable_node_native_modules: true, - custom_conditions: vec!["development".to_string(), "react-server".to_string()], - import_map: Some(next_server_import_map), - module: true, - ..Default::default() - }; - ResolveOptionsContext { - enable_typescript: true, - enable_react: true, - rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), - resolve_options_context.clone().cell(), - )], - ..resolve_options_context - } - } - } - .cell() -} - -#[turbo_tasks::function] -pub fn get_server_environment( - ty: Value, - process_env: ProcessEnvVc, - server_addr: ServerAddrVc, -) -> EnvironmentVc { - EnvironmentVc::new( - Value::new(ExecutionEnvironment::NodeJsLambda( - NodeJsEnvironmentVc::current(process_env, server_addr), - )), - match ty.into_value() { - ServerContextType::Pages { .. } => Value::new(EnvironmentIntention::ServerRendering), - ServerContextType::AppSSR { .. } => Value::new(EnvironmentIntention::Prerendering), - ServerContextType::AppRSC { .. } => Value::new(EnvironmentIntention::ServerRendering), - }, - ) -} - -#[turbo_tasks::function] -pub fn get_server_module_options_context( - project_path: FileSystemPathVc, - execution_context: ExecutionContextVc, - ty: Value, -) -> ModuleOptionsContextVc { - let module_options_context = match ty.into_value() { - ServerContextType::Pages { .. } => { - let module_options_context = ModuleOptionsContext { - execution_context: Some(execution_context), - ..Default::default() - }; - ModuleOptionsContext { - enable_jsx: true, - enable_styled_jsx: true, - enable_postcss_transform: Some(PostCssTransformOptions { - postcss_package: Some(get_postcss_package_mapping(project_path)), - ..Default::default() - }), - enable_typescript_transform: true, - rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), - module_options_context.clone().cell(), - )], - ..module_options_context - } - } - ServerContextType::AppSSR { .. } => { - let module_options_context = ModuleOptionsContext { - execution_context: Some(execution_context), - ..Default::default() - }; - ModuleOptionsContext { - enable_jsx: true, - enable_styled_jsx: true, - enable_postcss_transform: Some(PostCssTransformOptions { - postcss_package: Some(get_postcss_package_mapping(project_path)), - ..Default::default() - }), - enable_typescript_transform: true, - rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), - module_options_context.clone().cell(), - )], - ..module_options_context - } - } - ServerContextType::AppRSC { .. } => { - let module_options_context = ModuleOptionsContext { - custom_ecmascript_transforms: vec![EcmascriptInputTransform::ClientDirective( - StringVc::cell("server-to-client".to_string()), - )], - execution_context: Some(execution_context), - ..Default::default() - }; - ModuleOptionsContext { - enable_jsx: true, - enable_postcss_transform: Some(PostCssTransformOptions { - postcss_package: Some(get_postcss_package_mapping(project_path)), - ..Default::default() - }), - enable_typescript_transform: true, - rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), - module_options_context.clone().cell(), - )], - ..module_options_context - } - } - } - .cell(); - - add_next_font_transform(module_options_context) -} - -#[turbo_tasks::function] -pub fn get_build_resolve_options_context( - project_path: FileSystemPathVc, -) -> ResolveOptionsContextVc { - let next_build_import_map = get_next_build_import_map(project_path); - ResolveOptionsContext { - enable_typescript: true, - enable_node_modules: true, - enable_node_externals: true, - enable_node_native_modules: true, - custom_conditions: vec!["development".to_string()], - import_map: Some(next_build_import_map), - ..Default::default() - } - .cell() -} - -#[turbo_tasks::function] -pub fn get_build_module_options_context() -> ModuleOptionsContextVc { - ModuleOptionsContext { - enable_typescript_transform: true, - ..Default::default() - } - .cell() -} +pub(crate) mod context; diff --git a/packages/next-swc/crates/next-core/src/page_source.rs b/packages/next-swc/crates/next-core/src/page_source.rs index b777e9476a5e6b..b3fca9cd60edeb 100644 --- a/packages/next-swc/crates/next-core/src/page_source.rs +++ b/packages/next-swc/crates/next-core/src/page_source.rs @@ -49,12 +49,12 @@ use crate::{ context::{ get_client_assets_path, get_client_chunking_context, get_client_environment, get_client_module_options_context, get_client_resolve_options_context, - get_client_runtime_entries, ContextType, + get_client_runtime_entries, ClientContextType, }, - NextClientTransition, + transition::NextClientTransition, }, next_config::NextConfigVc, - next_server::{ + next_server::context::{ get_server_environment, get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, @@ -68,13 +68,13 @@ fn get_page_client_module_options_context( project_path: FileSystemPathVc, execution_context: ExecutionContextVc, client_environment: EnvironmentVc, - ty: Value, + ty: Value, ) -> Result { let client_module_options_context = get_client_module_options_context(project_path, execution_context, client_environment, ty); let client_module_options_context = match ty.into_value() { - ContextType::Pages { pages_dir } => add_next_transforms_to_pages( + ClientContextType::Pages { pages_dir } => add_next_transforms_to_pages( client_module_options_context, pages_dir, Value::new(PageTransformType::Client), @@ -137,7 +137,7 @@ pub async fn create_page_source( return Ok(NoContentSourceVc::new().into()); }; - let ty = Value::new(ContextType::Pages { pages_dir }); + let ty = Value::new(ClientContextType::Pages { pages_dir }); let server_ty = Value::new(ServerContextType::Pages { pages_dir }); let client_environment = get_client_environment(browserslist_query); @@ -288,7 +288,10 @@ async fn create_page_source_for_file( context_path, intermediate_output_path, intermediate_output_path.join("chunks"), - get_client_assets_path(server_root, Value::new(ContextType::Pages { pages_dir })), + get_client_assets_path( + server_root, + Value::new(ClientContextType::Pages { pages_dir }), + ), ) .build(); @@ -298,14 +301,17 @@ async fn create_page_source_for_file( context_path, data_intermediate_output_path, data_intermediate_output_path.join("chunks"), - get_client_assets_path(server_root, Value::new(ContextType::Pages { pages_dir })), + get_client_assets_path( + server_root, + Value::new(ClientContextType::Pages { pages_dir }), + ), ) .build(); let client_chunking_context = get_client_chunking_context( context_path, server_root, - Value::new(ContextType::Pages { pages_dir }), + Value::new(ClientContextType::Pages { pages_dir }), ); let pathname = pathname_for_path(server_root, server_path, true); diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 790421589a34c6..1cd618fa231b2c 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -18,7 +18,7 @@ use crate::{ embed_js::wrap_with_next_js_fs, next_client::context::{ get_client_asset_context, get_client_chunking_context, get_client_runtime_entries, - ContextType, + ClientContextType, }, next_config::NextConfigVc, }; @@ -36,7 +36,7 @@ pub async fn create_web_entry_source( ) -> Result { let project_root = wrap_with_next_js_fs(project_root); - let ty = Value::new(ContextType::Other); + let ty = Value::new(ClientContextType::Other); let context = get_client_asset_context(project_root, execution_context, browserslist_query, ty); let chunking_context = get_client_chunking_context(project_root, server_root, ty); let entries = get_client_runtime_entries(project_root, env, ty, next_config); From 564199f9d143e431bb7ed1d274413d143ecc1772 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 9 Jan 2023 18:30:52 +0100 Subject: [PATCH 304/672] Fix clippy warnings with next-transform-strip-page-exports (vercel/turbo#3220) --- .../src/lib.rs | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs b/packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs index e793d0a6c135cd..baee5950ae8e73 100644 --- a/packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs +++ b/packages/next-swc/crates/next-transform-strip-page-exports/src/lib.rs @@ -222,16 +222,15 @@ impl State { } fn should_retain_export_type(&self, export_type: ExportType) -> bool { - match (self.filter, export_type) { + !matches!( + (self.filter, export_type), ( ExportFilter::StripDataExports, ExportType::GetServerSideProps - | ExportType::GetStaticProps - | ExportType::GetStaticPaths, - ) => false, - (ExportFilter::StripDefaultExport, ExportType::Default) => false, - _ => true, - } + | ExportType::GetStaticProps + | ExportType::GetStaticPaths, + ) | (ExportFilter::StripDefaultExport, ExportType::Default) + ) } fn should_retain_id(&self, id: &Id) -> bool { @@ -880,9 +879,9 @@ impl Fold for NextSsg { return Pat::Invalid(Invalid { span: DUMMY_SP }); } } - Pat::Expr(expr) => match &**expr { - Expr::Member(member_expr) => match find_member_root_id(member_expr) { - Some(id) => { + Pat::Expr(expr) => { + if let Expr::Member(member_expr) = &**expr { + if let Some(id) = find_member_root_id(member_expr) { if self.should_remove(&id) { self.state.should_run_again = true; tracing::trace!( @@ -895,10 +894,8 @@ impl Fold for NextSsg { return Pat::Invalid(Invalid { span: DUMMY_SP }); } } - None => {} - }, - _ => {} - }, + } + } _ => {} } } @@ -1011,7 +1008,7 @@ impl Fold for NextSsg { /// e.g. `a.b.c` => `a` fn find_member_root_id(member_expr: &MemberExpr) -> Option { match &*member_expr.obj { - Expr::Member(member) => find_member_root_id(&member), + Expr::Member(member) => find_member_root_id(member), Expr::Ident(ident) => Some(ident.to_id()), _ => None, } From 9bb83af67204fc19b01cfaea9f231a59e97235d7 Mon Sep 17 00:00:00 2001 From: Ben Plate Date: Mon, 9 Jan 2023 17:12:32 -0700 Subject: [PATCH 305/672] fix(next-core): check axes for variable fonts only (vercel/turbo#3209) Addresses an issue currently affecting non-variable fonts in which `next-dev` errors for non-variable Google fonts. This issue can be replicated by using `next dev --turbo` and using a Google font that isn't variable, like Hind. The problem is resolved by unwrapping axes only if the font is variable. Relevant issue: vercel/next.js#44282 Co-authored-by: Will Binns-Smith --- .../next-core/src/next_font_google/util.rs | 67 +++++++++++++++++-- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_font_google/util.rs b/packages/next-swc/crates/next-core/src/next_font_google/util.rs index eec5227f052525..90244412c9a72b 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/util.rs +++ b/packages/next-swc/crates/next-core/src/next_font_google/util.rs @@ -31,10 +31,6 @@ pub(crate) fn get_font_axes( .context("Font family not found")? .axes; - let Some(defineable_axes) = all_axes else { - bail!("Font {} has no definable `axes`", font_family); - }; - let ital = { let has_italic = styles.contains("italic"); let has_normal = styles.contains("normal"); @@ -50,6 +46,10 @@ pub(crate) fn get_font_axes( match weights { FontWeights::Variable => { + let Some(defineable_axes) = all_axes else { + bail!("Font {} has no definable `axes`", font_family); + }; + if let Some(selected_variable_axes) = selected_variable_axes { let definable_axes_tags = defineable_axes .iter() @@ -366,6 +366,44 @@ mod tests { Ok(()) } + #[test] + fn test_no_variable() -> Result<()> { + let data: FontData = serde_json::from_str( + r#" + { + "Hind": { + "weights": [ + "300", + "400", + "500", + "600", + "700" + ], + "styles": [ + "normal" + ] + } + } + "#, + )?; + + assert_eq!( + get_font_axes( + &data, + "Hind", + &FontWeights::Fixed(indexset! {500}), + &indexset! {}, + &None + )?, + FontAxes { + wght: indexset! {"500".to_owned()}, + ital: indexset! {}, + variable_axes: None + } + ); + Ok(()) + } + #[test] fn test_stylesheet_url_no_axes() -> Result<()> { assert_eq!( @@ -433,7 +471,7 @@ mod tests { } #[test] - fn test_variable_font_without_wgth_axis() -> Result<()> { + fn test_stylesheet_url_variable_font_without_wgth_axis() -> Result<()> { assert_eq!( get_stylesheet_url( GOOGLE_FONTS_STYLESHEET_URL, @@ -453,4 +491,23 @@ mod tests { Ok(()) } + + #[test] + fn test_stylesheet_url_no_variable() -> Result<()> { + assert_eq!( + get_stylesheet_url( + GOOGLE_FONTS_STYLESHEET_URL, + "Hind", + &FontAxes { + wght: indexset! {"500".to_owned()}, + ital: indexset! {}, + variable_axes: None + }, + "optional" + )?, + "https://fonts.googleapis.com/css2?family=Hind:wght@500&display=optional" + ); + + Ok(()) + } } From 457fb81bc968ac706c21277ff332a7e1a77cb212 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 10 Jan 2023 16:22:07 +0100 Subject: [PATCH 306/672] add support for transpilePackages (vercel/turbo#3116) --- .../crates/next-core/src/app_source.rs | 34 +++++++++++++----- .../next-swc/crates/next-core/src/fallback.rs | 11 ++++-- .../next-core/src/next_client/context.rs | 32 ++++++++++------- .../crates/next-core/src/next_config.rs | 8 +++++ .../next-core/src/next_server/context.rs | 28 ++++++++------- .../crates/next-core/src/page_source.rs | 21 ++++++++--- .../next-swc/crates/next-core/src/util.rs | 21 +++++++++++ .../crates/next-core/src/web_entry_source.rs | 8 ++++- .../next-dev/tests/integration/.gitignore | 1 + .../next/image/basic/components/img.jsx | 3 ++ .../next/image/basic/pages/index.js | 2 +- .../image/transpilePackages/next.config.js | 7 ++++ .../node_modules/magic-image/img.jsx | 3 ++ .../node_modules/magic-image/index.jsx | 11 ++++++ .../magic-image/triangle-black.png | Bin 0 -> 4289 bytes .../image/transpilePackages/pages/index.js | 29 +++++++++++++++ 16 files changed, 177 insertions(+), 42 deletions(-) create mode 100644 packages/next-swc/crates/next-dev/tests/integration/.gitignore create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/basic/components/img.jsx create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/next.config.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/img.jsx create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/index.jsx create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/triangle-black.png create mode 100644 packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/pages/index.js diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 8a60eeb95c8e5b..65a00bd8c67c5d 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -74,17 +74,27 @@ fn next_client_chunks_transition( app_dir: FileSystemPathVc, server_root: FileSystemPathVc, browserslist_query: &str, + next_config: NextConfigVc, ) -> TransitionVc { let ty = Value::new(ClientContextType::App { app_dir }); let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); - let client_module_options_context = - get_client_module_options_context(project_path, execution_context, client_environment, ty); + let client_module_options_context = get_client_module_options_context( + project_path, + execution_context, + client_environment, + ty, + next_config, + ); NextClientChunksTransition { client_chunking_context, client_module_options_context, - client_resolve_options_context: get_client_resolve_options_context(project_path, ty), + client_resolve_options_context: get_client_resolve_options_context( + project_path, + ty, + next_config, + ), client_environment, server_root, } @@ -105,10 +115,16 @@ async fn next_client_transition( let ty = Value::new(ClientContextType::App { app_dir }); let client_chunking_context = get_client_chunking_context(project_path, server_root, ty); let client_environment = get_client_environment(browserslist_query); - let client_module_options_context = - get_client_module_options_context(project_path, execution_context, client_environment, ty); + let client_module_options_context = get_client_module_options_context( + project_path, + execution_context, + client_environment, + ty, + next_config, + ); let client_runtime_entries = get_client_runtime_entries(project_path, env, ty, next_config); - let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); + let client_resolve_options_context = + get_client_resolve_options_context(project_path, ty, next_config); Ok(NextClientTransition { is_app: true, @@ -138,6 +154,7 @@ fn next_ssr_client_module_transition( project_path, execution_context, ty, + next_config, ), ssr_resolve_options_context: get_server_resolve_options_context( project_path, @@ -165,7 +182,7 @@ fn next_layout_entry_transition( let rsc_resolve_options_context = get_server_resolve_options_context(project_path, ty, next_config); let rsc_module_options_context = - get_server_module_options_context(project_path, execution_context, ty); + get_server_module_options_context(project_path, execution_context, ty, next_config); NextLayoutEntryTransition { rsc_environment, @@ -229,6 +246,7 @@ fn app_context( app_dir, server_root, browserslist_query, + next_config, ), ); transitions.insert( @@ -247,7 +265,7 @@ fn app_context( ModuleAssetContextVc::new( TransitionsByNameVc::cell(transitions), get_server_environment(ssr_ty, env, server_addr), - get_server_module_options_context(project_path, execution_context, ssr_ty), + get_server_module_options_context(project_path, execution_context, ssr_ty, next_config), get_server_resolve_options_context(project_path, ssr_ty, next_config), ) .into() diff --git a/packages/next-swc/crates/next-core/src/fallback.rs b/packages/next-swc/crates/next-core/src/fallback.rs index 296093042d2430..1cca779bedd830 100644 --- a/packages/next-swc/crates/next-core/src/fallback.rs +++ b/packages/next-swc/crates/next-core/src/fallback.rs @@ -36,9 +36,14 @@ pub async fn get_fallback_page( ) -> Result { let ty = Value::new(ClientContextType::Fallback); let environment = get_client_environment(browserslist_query); - let resolve_options_context = get_client_resolve_options_context(project_path, ty); - let module_options_context = - get_client_module_options_context(project_path, execution_context, environment, ty); + let resolve_options_context = get_client_resolve_options_context(project_path, ty, next_config); + let module_options_context = get_client_module_options_context( + project_path, + execution_context, + environment, + ty, + next_config, + ); let chunking_context = get_client_chunking_context(project_path, dev_server_root, ty); let entries = get_client_runtime_entries(project_path, env, ty, next_config); diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index b88805681c22f4..ec9c8cb1953ab7 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -6,7 +6,6 @@ use turbo_tasks::{primitives::StringsVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ - condition::ContextCondition, module_options::{ module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, ModuleRule, ModuleRuleCondition, ModuleRuleEffect, PostCssTransformOptions, @@ -37,6 +36,7 @@ use crate::{ get_next_client_resolved_map, }, react_refresh::assert_can_resolve_react_refresh, + util::foreign_code_context_condition, }; #[turbo_tasks::function] @@ -65,10 +65,11 @@ pub enum ClientContextType { } #[turbo_tasks::function] -pub fn get_client_resolve_options_context( +pub async fn get_client_resolve_options_context( project_path: FileSystemPathVc, ty: Value, -) -> ResolveOptionsContextVc { + next_config: NextConfigVc, +) -> Result { let next_client_import_map = get_next_client_import_map(project_path, ty); let next_client_fallback_import_map = get_next_client_fallback_import_map(ty); let next_client_resolved_map = get_next_client_resolved_map(project_path, project_path); @@ -82,16 +83,16 @@ pub fn get_client_resolve_options_context( module: true, ..Default::default() }; - ResolveOptionsContext { + Ok(ResolveOptionsContext { enable_typescript: true, enable_react: true, rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), + foreign_code_context_condition(next_config).await?, module_options_context.clone().cell(), )], ..module_options_context } - .cell() + .cell()) } #[turbo_tasks::function] @@ -100,8 +101,9 @@ pub async fn get_client_module_options_context( execution_context: ExecutionContextVc, env: EnvironmentVc, ty: Value, + next_config: NextConfigVc, ) -> Result { - let resolve_options_context = get_client_resolve_options_context(project_path, ty); + let resolve_options_context = get_client_resolve_options_context(project_path, ty, next_config); let enable_react_refresh = assert_can_resolve_react_refresh(project_path, resolve_options_context) .await? @@ -127,7 +129,7 @@ pub async fn get_client_module_options_context( }), enable_typescript_transform: true, rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), + foreign_code_context_condition(next_config).await?, module_options_context.clone().cell(), )], ..module_options_context @@ -174,11 +176,17 @@ pub fn get_client_asset_context( execution_context: ExecutionContextVc, browserslist_query: &str, ty: Value, + next_config: NextConfigVc, ) -> AssetContextVc { let environment = get_client_environment(browserslist_query); - let resolve_options_context = get_client_resolve_options_context(project_path, ty); - let module_options_context = - get_client_module_options_context(project_path, execution_context, environment, ty); + let resolve_options_context = get_client_resolve_options_context(project_path, ty, next_config); + let module_options_context = get_client_module_options_context( + project_path, + execution_context, + environment, + ty, + next_config, + ); let context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), @@ -232,7 +240,7 @@ pub async fn get_client_runtime_entries( ty: Value, next_config: NextConfigVc, ) -> Result { - let resolve_options_context = get_client_resolve_options_context(project_root, ty); + let resolve_options_context = get_client_resolve_options_context(project_root, ty, next_config); let enable_react_refresh = assert_can_resolve_react_refresh(project_root, resolve_options_context) .await? diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index 91b38748338325..e909d284cd5ea7 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -41,6 +41,7 @@ pub struct NextConfig { pub env: Option>, pub compiler: Option, pub images: ImageConfig, + pub transpile_packages: Option>, } #[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] @@ -201,6 +202,13 @@ impl NextConfigVc { pub async fn image_config(self) -> Result { Ok(self.await?.images.clone().cell()) } + + #[turbo_tasks::function] + pub async fn transpile_packages(self) -> Result { + Ok(StringsVc::cell( + self.await?.transpile_packages.clone().unwrap_or_default(), + )) + } } fn next_configs() -> StringsVc { diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index 465c449f38d49e..a3ea72b4595398 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -1,8 +1,8 @@ +use anyhow::Result; use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ - condition::ContextCondition, module_options::{ModuleOptionsContext, ModuleOptionsContextVc, PostCssTransformOptions}, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, }; @@ -17,6 +17,7 @@ use crate::{ next_client::context::add_next_font_transform, next_config::NextConfigVc, next_import_map::{get_next_build_import_map, get_next_server_import_map}, + util::foreign_code_context_condition, }; #[turbo_tasks::value(serialization = "auto_for_input")] @@ -28,13 +29,13 @@ pub enum ServerContextType { } #[turbo_tasks::function] -pub fn get_server_resolve_options_context( +pub async fn get_server_resolve_options_context( project_path: FileSystemPathVc, ty: Value, next_config: NextConfigVc, -) -> ResolveOptionsContextVc { +) -> Result { let next_server_import_map = get_next_server_import_map(project_path, ty, next_config); - match ty.into_value() { + Ok(match ty.into_value() { ServerContextType::Pages { .. } | ServerContextType::AppSSR { .. } => { let resolve_options_context = ResolveOptionsContext { enable_node_modules: true, @@ -49,7 +50,7 @@ pub fn get_server_resolve_options_context( enable_typescript: true, enable_react: true, rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), + foreign_code_context_condition(next_config).await?, resolve_options_context.clone().cell(), )], ..resolve_options_context @@ -69,14 +70,14 @@ pub fn get_server_resolve_options_context( enable_typescript: true, enable_react: true, rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), + foreign_code_context_condition(next_config).await?, resolve_options_context.clone().cell(), )], ..resolve_options_context } } } - .cell() + .cell()) } #[turbo_tasks::function] @@ -98,11 +99,12 @@ pub fn get_server_environment( } #[turbo_tasks::function] -pub fn get_server_module_options_context( +pub async fn get_server_module_options_context( project_path: FileSystemPathVc, execution_context: ExecutionContextVc, ty: Value, -) -> ModuleOptionsContextVc { + next_config: NextConfigVc, +) -> Result { let module_options_context = match ty.into_value() { ServerContextType::Pages { .. } => { let module_options_context = ModuleOptionsContext { @@ -118,7 +120,7 @@ pub fn get_server_module_options_context( }), enable_typescript_transform: true, rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), + foreign_code_context_condition(next_config).await?, module_options_context.clone().cell(), )], ..module_options_context @@ -138,7 +140,7 @@ pub fn get_server_module_options_context( }), enable_typescript_transform: true, rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), + foreign_code_context_condition(next_config).await?, module_options_context.clone().cell(), )], ..module_options_context @@ -160,7 +162,7 @@ pub fn get_server_module_options_context( }), enable_typescript_transform: true, rules: vec![( - ContextCondition::InDirectory("node_modules".to_string()), + foreign_code_context_condition(next_config).await?, module_options_context.clone().cell(), )], ..module_options_context @@ -169,7 +171,7 @@ pub fn get_server_module_options_context( } .cell(); - add_next_font_transform(module_options_context) + Ok(add_next_font_transform(module_options_context)) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/page_source.rs b/packages/next-swc/crates/next-core/src/page_source.rs index b3fca9cd60edeb..93166477228252 100644 --- a/packages/next-swc/crates/next-core/src/page_source.rs +++ b/packages/next-swc/crates/next-core/src/page_source.rs @@ -69,9 +69,15 @@ fn get_page_client_module_options_context( execution_context: ExecutionContextVc, client_environment: EnvironmentVc, ty: Value, + next_config: NextConfigVc, ) -> Result { - let client_module_options_context = - get_client_module_options_context(project_path, execution_context, client_environment, ty); + let client_module_options_context = get_client_module_options_context( + project_path, + execution_context, + client_environment, + ty, + next_config, + ); let client_module_options_context = match ty.into_value() { ClientContextType::Pages { pages_dir } => add_next_transforms_to_pages( @@ -98,10 +104,11 @@ fn get_page_server_module_options_context( execution_context: ExecutionContextVc, pages_dir: FileSystemPathVc, ssr_ty: Value, + next_config: NextConfigVc, ) -> ModuleOptionsContextVc { let server_ty = Value::new(ServerContextType::Pages { pages_dir }); let server_module_options_context = - get_server_module_options_context(project_path, execution_context, server_ty); + get_server_module_options_context(project_path, execution_context, server_ty, next_config); match ssr_ty.into_value() { PageSsrType::Ssr => server_module_options_context, @@ -146,13 +153,15 @@ pub async fn create_page_source( execution_context, client_environment, ty, + next_config, ); let client_module_options_context = add_next_transforms_to_pages( client_module_options_context, pages_dir, Value::new(PageTransformType::Client), ); - let client_resolve_options_context = get_client_resolve_options_context(project_path, ty); + let client_resolve_options_context = + get_client_resolve_options_context(project_path, ty, next_config); let client_context: AssetContextVc = ModuleAssetContextVc::new( TransitionsByNameVc::cell(HashMap::new()), client_environment, @@ -177,6 +186,8 @@ pub async fn create_page_source( .cell() .into(); + let mut transitions = HashMap::new(); + transitions.insert("next-client".to_string(), next_client_transition); let server_environment = get_server_environment(server_ty, env, server_addr); let server_resolve_options_context = get_server_resolve_options_context(project_path, server_ty, next_config); @@ -186,6 +197,7 @@ pub async fn create_page_source( execution_context, pages_dir, Value::new(PageSsrType::Ssr), + next_config, ); let server_transitions = TransitionsByNameVc::cell( [("next-client".to_string(), next_client_transition)] @@ -206,6 +218,7 @@ pub async fn create_page_source( execution_context, pages_dir, Value::new(PageSsrType::SsrData), + next_config, ); let server_data_context: AssetContextVc = ModuleAssetContextVc::new( diff --git a/packages/next-swc/crates/next-core/src/util.rs b/packages/next-swc/crates/next-core/src/util.rs index 3f9406574a9efc..65a8ef11339642 100644 --- a/packages/next-swc/crates/next-core/src/util.rs +++ b/packages/next-swc/crates/next-core/src/util.rs @@ -1,8 +1,11 @@ use anyhow::{anyhow, bail, Result}; use turbo_tasks::{primitives::StringVc, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; +use turbopack::condition::ContextCondition; use turbopack_node::path_regex::{PathRegexBuilder, PathRegexVc}; +use crate::next_config::NextConfigVc; + /// Converts a filename within the server root into a next pathname. #[turbo_tasks::function] pub async fn pathname_for_path( @@ -92,3 +95,21 @@ pub fn get_asset_path_from_route(route: &str, ext: &str) -> String { format!("{}{}", route, ext) } } + +pub async fn foreign_code_context_condition(next_config: NextConfigVc) -> Result { + let transpile_packages = next_config.transpile_packages().await?; + let result = if transpile_packages.is_empty() { + ContextCondition::InDirectory("node_modules".to_string()) + } else { + ContextCondition::all(vec![ + ContextCondition::InDirectory("node_modules".to_string()), + ContextCondition::not(ContextCondition::any( + transpile_packages + .iter() + .map(|package| ContextCondition::InDirectory(format!("node_modules/{package}"))) + .collect(), + )), + ]) + }; + Ok(result) +} diff --git a/packages/next-swc/crates/next-core/src/web_entry_source.rs b/packages/next-swc/crates/next-core/src/web_entry_source.rs index 1cd618fa231b2c..7785c83aeba6f5 100644 --- a/packages/next-swc/crates/next-core/src/web_entry_source.rs +++ b/packages/next-swc/crates/next-core/src/web_entry_source.rs @@ -37,7 +37,13 @@ pub async fn create_web_entry_source( let project_root = wrap_with_next_js_fs(project_root); let ty = Value::new(ClientContextType::Other); - let context = get_client_asset_context(project_root, execution_context, browserslist_query, ty); + let context = get_client_asset_context( + project_root, + execution_context, + browserslist_query, + ty, + next_config, + ); let chunking_context = get_client_chunking_context(project_root, server_root, ty); let entries = get_client_runtime_entries(project_root, env, ty, next_config); diff --git a/packages/next-swc/crates/next-dev/tests/integration/.gitignore b/packages/next-swc/crates/next-dev/tests/integration/.gitignore new file mode 100644 index 00000000000000..cf4bab9ddde9fc --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/.gitignore @@ -0,0 +1 @@ +!node_modules diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/components/img.jsx b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/components/img.jsx new file mode 100644 index 00000000000000..d0307227d43aae --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/components/img.jsx @@ -0,0 +1,3 @@ +import img from "../public/triangle-black.png"; + +export { img }; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js index 11d73983458476..08cd3eea745218 100644 --- a/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/basic/pages/index.js @@ -1,5 +1,5 @@ import Image from "next/image"; -import img from "../public/triangle-black.png"; +import { img } from "../components/img"; import { useEffect } from "react"; import { Deferred } from "@turbo/pack-test-harness/deferred"; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/next.config.js b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/next.config.js new file mode 100644 index 00000000000000..97cc54a9e8361f --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/next.config.js @@ -0,0 +1,7 @@ +/**@type {import('next').NextConfig} */ +const config = { + reactStrictMode: true, + transpilePackages: ["magic-image"], +}; + +module.exports = config; diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/img.jsx b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/img.jsx new file mode 100644 index 00000000000000..1fee5881516697 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/img.jsx @@ -0,0 +1,3 @@ +import img from "./triangle-black.png"; + +export { img } diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/index.jsx b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/index.jsx new file mode 100644 index 00000000000000..6548ea87b8664f --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/index.jsx @@ -0,0 +1,11 @@ +import Image from "next/image"; +import { img } from "./img"; + +export default function MagicImage() { + return test imported image } diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/triangle-black.png b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/node_modules/magic-image/triangle-black.png new file mode 100644 index 0000000000000000000000000000000000000000..351730591885f2b53625436ec159381ba160f355 GIT binary patch literal 4289 zcmV;y5I*mTP)l0mEZN9sR?#93H|9Gm1J(5QTx6h0YKO2nIz3G6aY~2op%iW6vMosdS}syXsc; zeN@$aYn|0qeeSvY+`H@Sv+q9NKG)oxW`~(A1KizzoOfT+MqAz;NE>F>4on7in^~*7 z@5#GQX~LR)gqqpWz#+ivz=&oar7d}PAWfLrK%hVHH1H}g&di49+pBcZ)Faf)<^nr_ zmw;B_IpAO2{eoOOmLi%~p=LG>nc6O3CSbs4fW5$ccmGw6-AfHksZcXB;8fs6U;xk_ zs``Y#Q-RyO2`|1`z1;D@W?+-Mzg1jeWw;QW=8@`fZqVyfVa@2iUY%uDK3o0^}x%>^d1G=>+a8I-RCsW6bcRI^a)^%yMMpR zwo6d(;n8M@^EQjg{Uq{eZ!oidaT}T0LBJm16=Z@N9u2S1FjuY)Uq=F$SJ8Yd3JbOY zFNAY7G#Xx^z*WHEMc=P5v(c3r1?5c!UUv8204D)|mrfV6LqpG@X4VD#n(mNZ0e8Cl zhby$b6!LF*7Hmi~>G5jZM*?vF-kOZa{|iYgV#c3@QA*IR9A#1T3Rc+t$}n%N=Ye-i_{Zx--xzzJcI zdk9)_nG_yVHUh&#T^9-{EC_ACS|X<(a7_l+lPDU>DKfJKNMS3G$=!y+c5_hZ?@%HRfI@KBmB|SE-GO(j6#EVdOPqbci)?#%w@oj zvXa?bG?K~vYv2>Wc^S%_gGTg>3}yBT4WZC5S6&^yt_^(Kv}JanIk^>>XJ!M^mYD<^ zLZQIl0>i@RA;6b1ka;2S?}%*n2+$B*-nv()nT-c7Df#!MAySm4%r(FYcYg`dKIfR( zu<|YQN8LL`W_CYvOiFRTyQi{-X=XnJP6OUW5vP$T=6jI4Ka_^dq)^uiHM0)@50p7% zsk{FqVVTo`N$AlA;7zm$elQ9~n7fzjQ?966g_>C#S{j>H=CI!aGu?exLNfaRi-5g7 z1pU8_Mr>j-lSVzyp_foznV>-X#RtMtuVkiydL5zH5>J_+aNpGxkE)D? zz;t(i7KIlNMu7#w-%-F%-2EPuYVkJ-$V?n{H$nry_P@{reO&AX=DGWS*C=x&;_hw- zb|cgJ9bi82V_+`g@=ikDZX06gZwQYyb%VN6XfSOn*`M?k7cT;Ld6gFwWG+P^zTv?C z04JhUiA~7EZ4Gss!}q<&x^<$*r~0{xd9UA{19T>_o+eV z2H-<^-?!pYH*=_&^+l|^4Zyf6o6iBB1O|um#Fcq4uokV2URb5fi;)xc)p|-xtQ&=* z@LDHQ>Y$><>#_*hV-r#O;JawPi;FAJTnKQLnZ+{oLFSjk*Adi{gOs<42K5VP&qfzOA}hafJ|n3yuRvp?=x==ZP;kUlX z441YWQFUi?;K(d4zXn=!y{9=VbSffl9T`#A1-yqc zu=|zN9faoG-N1~9w#TDKpfe-t<|FU)yokDKC~4^ov{Y6q^A8mi>cEA0-qYMnZXi96 z1Qr0p%xqN2A)iA@M7zu<H0mQ{6VWB*8p(V2Kp?UE&6!mEf^&pGUfz18(aBP&!a(ECp z#WTLanJd)HCIYzo?=lsfG0bcQ+C}^BOyy>&&_MAx7mcEa+@PpB{XM#*dXxJ+Jm*@xd_sDDPK%V6@ z?*3xxoyY)Y_I}_|qCMip?*2&XeMnoO;hFCYL=gc!3cQ7W#XAt;>YG`+_emq99zIUb zR%bm5q@=q2To&8foQQZhFT4BZ;);+%vJTBN-_4*eY2tj!Pay?f@3&L!Matp54wS() z8aN@M{)Z?4@Cq;>uW(rc*Es+Y$SQ>dUj+_r!uQXjcx_uKPqY88cPB70@6lGnbxuIOK-|Fnd%)yI z9HEnuNgZQ)o6!>}pfHo@yp?tocyBb^jAFlW(Fbj>lL}Jta?NZWQc!;s2p<;y?m=Ge zQOFD*&=kG-=-I?Ol>*G{WV8WfEm-C$yoW7ug@!c1^}t$pzoW{w^U)gSJ?_3c(T*jI z5SM-mS)y9-dz4F)XgoU&lY22*N4&lo0&-w5oC-Wd^!rxo4WFTQWrF73#M2TJ9ibr& z@CxL{gR-^$C1%^xkwPCuYn1EV{m+SYEy&a{!}X`>o!Lk`j_6_1RIggw5cguV69 z)@o-_fm<7n9mW1c>jl8Vygk@5{rv~xd$pCyx9ZZ%4cmfm1tx@*mG`6g?a^f$3O6Cr z*Oh^uG8XVSTa9OpqD=0jaK4!(wn&lW99r0H;yBq@z`pi%Z^L~t&}CxLm0Rabi6QOM&h$jB9;4{5Gz-jGCE zViG3zql9z@N;ZfJbjY`n`J7#xB53=+ZzU=(L(a>oO2n%T7Q zY<4AZQwS2wMX3x6!-PKz*lT8;ruVIsW=zilE(nC_3FuWFLrm||-by@gIW3gZO435F z&3es&g|IPG7h>^sAVy!oonMPqAf5-lg%*DYBBsJf#8Nmp;94QEIx*s!eY2PM<@23B7@`#9puJBvm5pCcP1{0=5L1TQiiI z2VO&Q-m0#%7N=-6-5Wy{?*@`4=Ax}@4nxk<>8{lq~ zSDDHS;6i|5I(kw1!)CS^#d;s|l=!@+m)$*0bxedbunT3VN4}IV3e}F#!mFf;(H8!n z7QTU;u+Fe8c^mScN2DmTT3Sh3=!2fuV&6ncek-_;i(+-d;O$5XyOFzX$pz=wY^_(HtW=<#JVu+iP0M4`ka;=F69UuA-PhN~(b zRbft4ox#TSLgsAbaOFK$ z#<{mg)f6cTrtJ~5fm5~kPek&nDhw55o{a+jlj&X$Eo8}U4F7*DeBX_BE@?$dzPDPL zLGHtdI@1XF53~#!eVt`~wI88(zov6*7%3m43XiU+T_IQIqczA(lU9;e>5;C|(?#|} zd+hZ_=q8|}iW}R3My3OoRjHKALc7gWk(P+oAOBPb3aYleMA$7Yu0pR#NbuEF+}yQA z?cM_37qi_F=yg_ww%1f4b9Egkr`EDMmO>Hfxpb%JTFbkHz4a>G*m2?5;~0Hggxt#2|tr=a`z;POg74L z%lqc1Rc;K|$W*j=oQ2R`h!x*O^t(^Wl{-U+3-5SYia16qfDfV|!D(ny$YYVybSfIf zqtFu6&N{g9X_fbY$%fvQnPuAE&rl%Xq$=AviU<|xE*t3%3|x*9o6Zma+kt`;6X=cv jT?+g~Z#v!pc;Np4bU(8uEXQNW00000NkvXXu0mjf+-xTf literal 0 HcmV?d00001 diff --git a/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/pages/index.js b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/pages/index.js new file mode 100644 index 00000000000000..cf1b10a4e58855 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/next/image/transpilePackages/pages/index.js @@ -0,0 +1,29 @@ +import { useEffect } from "react"; +import MagicImage from "magic-image"; + +import { Deferred } from "@turbo/pack-test-harness/deferred"; + +let testResult = new Deferred(); + +export default function Home() { + useEffect(() => { + // Only run on client + import("@turbo/pack-test-harness").then(runTests); + }); + + return ; +} + +globalThis.waitForTests = function () { + return testResult.promise; +}; + +function runTests() { + console.log(document.querySelectorAll("img")); + it("it should link to imported image from a package", function () { + const img = document.querySelector("#magic"); + expect(img.src).toContain(encodeURIComponent("_next/static/assets")); + }); + + testResult.resolve(__jest__.run()); +} From ac4ae8582c177c877e1292280214aece544faba3 Mon Sep 17 00:00:00 2001 From: Thomas Knickman Date: Tue, 10 Jan 2023 13:24:07 -0500 Subject: [PATCH 307/672] fix(next-dev): add name to test package (vercel/turbo#3249) --- packages/next-swc/crates/next-dev/tests/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-dev/tests/package.json b/packages/next-swc/crates/next-dev/tests/package.json index 8132728c4f5ea2..62a64317cd5055 100644 --- a/packages/next-swc/crates/next-dev/tests/package.json +++ b/packages/next-swc/crates/next-dev/tests/package.json @@ -1,4 +1,5 @@ { + "name": "next-dev-tests", "private": true, "devDependencies": { "@turbo/pack-test-harness": "*", From 49c9b4d86958a287eb187fe257aed85dc1db64bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 11 Jan 2023 14:07:59 +0000 Subject: [PATCH 308/672] Update Google font-data.json (2023-01-11) (vercel/turbo#3255) Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action Co-authored-by: Will Binns-Smith <755844+wbinnssmith@users.noreply.github.com> --- .../__generated__/font-data.json | 188 +++++++++++++++++- 1 file changed, 186 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json b/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json index c974822c6107cd..3bf8bca2ae74af 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json +++ b/packages/next-swc/crates/next-core/src/next_font_google/__generated__/font-data.json @@ -92,10 +92,28 @@ "400", "500", "600", - "700" + "700", + "800", + "900", + "variable" ], "styles": [ - "normal" + "normal", + "italic" + ], + "axes": [ + { + "tag": "wdth", + "min": 100, + "max": 200, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } ] }, "Aguafina Script": { @@ -11627,6 +11645,14 @@ "normal" ] }, + "Noto Sans SignWriting": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, "Noto Sans Sinhala": { "weights": [ "100", @@ -11877,6 +11903,26 @@ "normal" ] }, + "Noto Sans Tangsa": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, "Noto Sans Telugu": { "weights": [ "100", @@ -12794,6 +12840,26 @@ } ] }, + "Noto Serif Toto": { + "weights": [ + "400", + "500", + "600", + "700", + "variable" + ], + "styles": [ + "normal" + ], + "axes": [ + { + "tag": "wght", + "min": 400, + "max": 700, + "defaultValue": 400 + } + ] + }, "Noto Serif Yezidi": { "weights": [ "400", @@ -13361,6 +13427,14 @@ "normal" ] }, + "Padyakke Expanded One": { + "weights": [ + "400" + ], + "styles": [ + "normal" + ] + }, "Palanquin": { "weights": [ "100", @@ -14295,6 +14369,12 @@ "normal" ], "axes": [ + { + "tag": "HEXP", + "min": 0, + "max": 100, + "defaultValue": 0 + }, { "tag": "wght", "min": 160, @@ -15910,6 +15990,110 @@ "normal" ] }, + "Sofia Sans": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Sofia Sans Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Sofia Sans Extra Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, + "Sofia Sans Semi Condensed": { + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], + "styles": [ + "normal", + "italic" + ], + "axes": [ + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ] + }, "Solway": { "weights": [ "300", From 33a0d4fa7d608fa6c00a0fb4c206873342b1b846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 12 Jan 2023 10:20:34 +0900 Subject: [PATCH 309/672] Make file paths shorter to fix windows build (vercel/turbo#3256) I verified that CI works with this change. https://github.com/kdy1/turbo-windows-path-length/actions/runs/3889566103/jobs/6638025437 --- x-ref: https://github.com/vercel/next.js/pull/44760 x-ref: https://github.com/vercel/next.js/actions/runs/3888528533/jobs/6635975573 x-ref: https://github.com/vercel/next.js/actions/runs/3888528533/jobs/6635975680 x-ref: https://github.com/vercel/next.js/actions/runs/3888528533/jobs/6635976658 --- .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../{should-not-mix-up-bindings => not-mix-up-bindings}/input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../support-export-named-as-default-with-a-class}/input.js | 0 .../support-export-named-as-default-with-a-class}/output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 .../input.js | 0 .../output-data.js | 0 .../output-default.js | 0 84 files changed, 0 insertions(+), 0 deletions(-) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-crash-for-class-declarations => not-crash-for-class-declarations}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-crash-for-class-declarations => not-crash-for-class-declarations}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-crash-for-class-declarations => not-crash-for-class-declarations}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-mix-up-bindings => not-mix-up-bindings}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-mix-up-bindings => not-mix-up-bindings}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-mix-up-bindings => not-mix-up-bindings}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-extra-named-export-function-declarations => not-remove-extra-named-export-function-declarations}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-extra-named-export-function-declarations => not-remove-extra-named-export-function-declarations}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-extra-named-export-function-declarations => not-remove-extra-named-export-function-declarations}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-extra-named-export-variable-declarations => not-remove-extra-named-export-variable-declarations}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-extra-named-export-variable-declarations => not-remove-extra-named-export-variable-declarations}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-extra-named-export-variable-declarations => not-remove-extra-named-export-variable-declarations}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-import-used-in-other-export => not-remove-import-used-in-other-export}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-import-used-in-other-export => not-remove-import-used-in-other-export}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-import-used-in-other-export => not-remove-import-used-in-other-export}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-import-used-in-render => not-remove-import-used-in-render}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-import-used-in-render => not-remove-import-used-in-render}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-import-used-in-render => not-remove-import-used-in-render}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-unused-function => not-remove-unused-function}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-unused-function => not-remove-unused-function}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-not-remove-unused-function => not-remove-unused-function}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-combined-named-export-specifiers => remove-combined-named-export-specifiers}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-combined-named-export-specifiers => remove-combined-named-export-specifiers}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-combined-named-export-specifiers => remove-combined-named-export-specifiers}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-extra-named-export-specifiers => remove-extra-named-export-specifiers}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-extra-named-export-specifiers => remove-extra-named-export-specifiers}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-extra-named-export-specifiers => remove-extra-named-export-specifiers}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-function-declarations-async => remove-named-export-function-declarations-async}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-function-declarations-async => remove-named-export-function-declarations-async}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-function-declarations-async => remove-named-export-function-declarations-async}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-function-declarations => remove-named-export-function-declarations}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-function-declarations => remove-named-export-function-declarations}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-function-declarations => remove-named-export-function-declarations}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-variable-declarations-async => remove-named-export-variable-declarations-async}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-variable-declarations-async => remove-named-export-variable-declarations-async}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-variable-declarations-async => remove-named-export-variable-declarations-async}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-variable-declarations => remove-named-export-variable-declarations}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-variable-declarations => remove-named-export-variable-declarations}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-named-export-variable-declarations => remove-named-export-variable-declarations}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-function-declarations-dependents-variables-functions-imports => remove-re-exported-function-declarations-dependents-variables-functions-imports}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-function-declarations-dependents-variables-functions-imports => remove-re-exported-function-declarations-dependents-variables-functions-imports}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-function-declarations-dependents-variables-functions-imports => remove-re-exported-function-declarations-dependents-variables-functions-imports}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-function-declarations => remove-re-exported-function-declarations}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-function-declarations => remove-re-exported-function-declarations}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-function-declarations => remove-re-exported-function-declarations}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-variable-declarations-safe => remove-re-exported-variable-declarations-safe}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-variable-declarations-safe => remove-re-exported-variable-declarations-safe}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-variable-declarations-safe => remove-re-exported-variable-declarations-safe}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-variable-declarations => remove-re-exported-variable-declarations}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-variable-declarations => remove-re-exported-variable-declarations}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-re-exported-variable-declarations => remove-re-exported-variable-declarations}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-separate-named-export-specifiers => remove-separate-named-export-specifiers}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-separate-named-export-specifiers => remove-separate-named-export-specifiers}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-remove-separate-named-export-specifiers => remove-separate-named-export-specifiers}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-babel-style-memoized-function => support-babel-style-memoized-function}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-babel-style-memoized-function => support-babel-style-memoized-function}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-babel-style-memoized-function => support-babel-style-memoized-function}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-class-exports-2 => support-class-exports-2}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-class-exports-2 => support-class-exports-2}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-class-exports-2 => support-class-exports-2}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-class-exports => support-class-exports}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-class-exports => support-class-exports}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-class-exports => support-class-exports}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-a-class copy => support-export-named-as-default-with-a-class copy}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-a-class copy => support-export-named-as-default-with-a-class copy}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-a-class copy => support-export-named-as-default-with-a-class copy}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers-and-import => support-export-named-as-default-with-other-specifiers-and-import}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers-and-import => support-export-named-as-default-with-other-specifiers-and-import}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers-and-import => support-export-named-as-default-with-other-specifiers-and-import}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers => support-export-named-as-default-with-other-specifiers}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers => support-export-named-as-default-with-other-specifiers}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers => support-export-named-as-default-with-other-specifiers}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class => support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class => support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class => support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-full-re-export => support-full-re-export}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-full-re-export => support-full-re-export}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-full-re-export => support-full-re-export}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-multiple-export-var-decl => support-multiple-export-var-decl}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-multiple-export-var-decl => support-multiple-export-var-decl}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-multiple-export-var-decl => support-multiple-export-var-decl}/output-default.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-named-export-as-default => support-named-export-as-default}/input.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-named-export-as-default => support-named-export-as-default}/output-data.js (100%) rename packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/{should-support-named-export-as-default => support-named-export-as-default}/output-default.js (100%) diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-crash-for-class-declarations/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-crash-for-class-declarations/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-crash-for-class-declarations/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-crash-for-class-declarations/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-crash-for-class-declarations/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-crash-for-class-declarations/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-crash-for-class-declarations/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-mix-up-bindings/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-mix-up-bindings/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-mix-up-bindings/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-mix-up-bindings/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-mix-up-bindings/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-mix-up-bindings/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-mix-up-bindings/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-function-declarations/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-function-declarations/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-function-declarations/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-function-declarations/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-function-declarations/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-function-declarations/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-function-declarations/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-variable-declarations/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-variable-declarations/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-variable-declarations/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-variable-declarations/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-variable-declarations/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-extra-named-export-variable-declarations/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-extra-named-export-variable-declarations/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-other-export/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-other-export/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-other-export/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-other-export/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-other-export/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-other-export/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-other-export/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-render/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-render/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-render/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-render/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-render/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-import-used-in-render/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-import-used-in-render/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-unused-function/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-unused-function/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-unused-function/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-unused-function/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-unused-function/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-not-remove-unused-function/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/not-remove-unused-function/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-combined-named-export-specifiers/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-combined-named-export-specifiers/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-combined-named-export-specifiers/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-combined-named-export-specifiers/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-combined-named-export-specifiers/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-combined-named-export-specifiers/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-combined-named-export-specifiers/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-extra-named-export-specifiers/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-extra-named-export-specifiers/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-extra-named-export-specifiers/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-extra-named-export-specifiers/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-extra-named-export-specifiers/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-extra-named-export-specifiers/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-extra-named-export-specifiers/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations-async/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations-async/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations-async/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations-async/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations-async/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations-async/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations-async/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-function-declarations/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-function-declarations/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations-async/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations-async/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations-async/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations-async/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations-async/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations-async/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations-async/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-named-export-variable-declarations/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-named-export-variable-declarations/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations-dependents-variables-functions-imports/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations-dependents-variables-functions-imports/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations-dependents-variables-functions-imports/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-function-declarations/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-function-declarations/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations-safe/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations-safe/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations-safe/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations-safe/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations-safe/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations-safe/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations-safe/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-re-exported-variable-declarations/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-re-exported-variable-declarations/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-separate-named-export-specifiers/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-separate-named-export-specifiers/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-separate-named-export-specifiers/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-separate-named-export-specifiers/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-separate-named-export-specifiers/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-remove-separate-named-export-specifiers/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/remove-separate-named-export-specifiers/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-babel-style-memoized-function/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-babel-style-memoized-function/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-babel-style-memoized-function/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-babel-style-memoized-function/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-babel-style-memoized-function/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-babel-style-memoized-function/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-babel-style-memoized-function/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports-2/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports-2/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports-2/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports-2/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports-2/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports-2/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports-2/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-class-exports/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-class-exports/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-a-class copy/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-a-class copy/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-a-class copy/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-a-class copy/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-a-class copy/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-a-class copy/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-a-class copy/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers-and-import/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers-and-import/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers-and-import/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers-and-import/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers-and-import/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers-and-import/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers-and-import/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-export-named-as-default-with-other-specifiers/should-support-export-named-as-default-with-a-class/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-export-named-as-default-with-other-specifiers/support-export-named-as-default-with-a-class/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-full-re-export/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-full-re-export/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-full-re-export/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-full-re-export/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-full-re-export/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-full-re-export/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-full-re-export/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-multiple-export-var-decl/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-multiple-export-var-decl/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-multiple-export-var-decl/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-multiple-export-var-decl/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-multiple-export-var-decl/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-multiple-export-var-decl/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-multiple-export-var-decl/output-default.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/input.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-named-export-as-default/input.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/input.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-named-export-as-default/input.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-data.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-named-export-as-default/output-data.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-data.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-named-export-as-default/output-data.js diff --git a/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-default.js b/packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-named-export-as-default/output-default.js similarity index 100% rename from packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/should-support-named-export-as-default/output-default.js rename to packages/next-swc/crates/next-transform-strip-page-exports/tests/fixtures/getStaticProps/support-named-export-as-default/output-default.js From 753de8b3f8775b3a5d71689f4610b2b357947f00 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 12 Jan 2023 08:58:01 +0100 Subject: [PATCH 310/672] provide resolvedUrl to next.js for rendering (vercel/turbo#3267) --- .../next-swc/crates/next-core/js/src/entry/server-renderer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx index 607c5b1d6a87a9..ad8b7727a035c6 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/server-renderer.tsx @@ -136,6 +136,7 @@ async function runOperation( previewModeSigningKey: "", }, basePath: "", + resolvedUrl: renderData.url, optimizeFonts: false, optimizeCss: false, nextScriptWorkers: false, From 3d99a8bcad12382f30f90c7672e35c32e06a0054 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 12 Jan 2023 09:09:01 +0100 Subject: [PATCH 311/672] fix code generation in shorthand properties (vercel/turbo#3259) --- .../turbopack/basic/shorthand-props/index.js | 52 +++++++++++++++++ .../turbopack/basic/shorthand-props/module.js | 5 ++ .../basic/shorthand-props/reexport.js | 56 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/index.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/module.js create mode 100644 packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/reexport.js diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/index.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/index.js new file mode 100644 index 00000000000000..4d899188fc0e9c --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/index.js @@ -0,0 +1,52 @@ +import def, { named } from "./module.js"; +import { + nested, + nested2, + nested_with_identity, + nested_with_identity2, + double_nested, + double_nested2, + double_nested_with_identity, + double_nested_with_identity2, +} from "./reexport.js"; + +it("support imports in shorthand properties", () => { + expect(def).toBe("default"); + expect(named).toBe("named"); + expect({ def }).toStrictEqual({ def: "default" }); + expect({ named }).toStrictEqual({ named: "named" }); + expect(nested).toStrictEqual({ def: "default", named: "named" }); + expect(nested2).toStrictEqual({ def: "default", named: "named" }); + expect(nested_with_identity).toStrictEqual({ + def: "default", + named: "named", + }); + expect(nested_with_identity2).toStrictEqual({ + def: "default", + named: "named", + }); + expect(double_nested).toStrictEqual({ + nested: { + def: "default", + named: "named", + }, + }); + expect(double_nested2).toStrictEqual({ + nested: { + def: "default", + named: "named", + }, + }); + expect(double_nested_with_identity).toStrictEqual({ + nested: { + def: "default", + named: "named", + }, + }); + expect(double_nested_with_identity2).toStrictEqual({ + nested: { + def: "default", + named: "named", + }, + }); +}); diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/module.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/module.js new file mode 100644 index 00000000000000..9b97b525657bcf --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/module.js @@ -0,0 +1,5 @@ +export const named = "named"; +export default "default"; +export function identity(x) { + return x; +} diff --git a/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/reexport.js b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/reexport.js new file mode 100644 index 00000000000000..467b3f98da6b72 --- /dev/null +++ b/packages/next-swc/crates/next-dev/tests/integration/turbopack/basic/shorthand-props/reexport.js @@ -0,0 +1,56 @@ +import def, { named, identity } from "./module.js"; + +const nested = { + def, + named, +}; + +export const nested2 = { + def, + named, +}; + +const nested_with_identity = identity({ + def, + named, +}); + +export const nested_with_identity2 = identity({ + def, + named, +}); + +const double_nested = { + nested: { + def, + named, + }, +}; + +export const double_nested2 = { + nested: { + def, + named, + }, +}; + +const double_nested_with_identity = { + nested: identity({ + def, + named, + }), +}; + +export const double_nested_with_identity2 = { + nested: identity({ + def, + named, + }), +}; + +export { + nested, + nested_with_identity, + double_nested, + double_nested_with_identity, +}; From 010923e9f9a49d573a492720daf74054d73738f1 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 12 Jan 2023 12:38:17 +0100 Subject: [PATCH 312/672] fix windows paths with --root (vercel/turbo#3281) --- packages/next-swc/crates/next-dev/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index d22c7d550fd0a8..2bd022da4e2590 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -265,8 +265,9 @@ async fn source( let project_relative = project_dir.strip_prefix(&root_dir).unwrap(); let project_relative = project_relative .strip_prefix(MAIN_SEPARATOR) - .unwrap_or(project_relative); - let project_path = fs.root().join(project_relative); + .unwrap_or(project_relative) + .replace(MAIN_SEPARATOR, "/"); + let project_path = fs.root().join(&project_relative); let env = load_env(project_path); let build_output_root = output_fs.root().join(".next/build"); From f4e663bb2aaba57692c6fe4c3cf74ffa1d5a2dae Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Thu, 12 Jan 2023 16:37:44 +0100 Subject: [PATCH 313/672] Add support for dynamic `import()`s on the server-side (vercel/turbo#3193) This PR separates Turbopack's `runtime.js` into two: - the Browser/DOM implementation, which uses `` - ) - ) - } - if (done) { - flightResponseRef.current = null - writer.close() - } else { - const responsePartial = decodeText(value, textDecoder) - const scripts = `${startScriptTag}self.__next_f.push(${htmlEscapeJsonString( - JSON.stringify([1, responsePartial]) - )})` - - writer.write(encodeText(scripts)) - read() - } - }) - } - read() - - return res -} - -/** - * Create a component that renders the Flight stream. - * This is only used for renderToHTML, the Flight response does not need additional wrappers. - */ -function createServerComponentRenderer( - ComponentToRender: (props: Props) => any, - ComponentMod: { - renderToReadableStream: any - __next_app_webpack_require__?: any - }, - { - transformStream, - clientReferenceManifest, - serverContexts, - rscChunks, - }: { - transformStream: TransformStream - clientReferenceManifest: NonNullable - serverContexts: Array< - [ServerContextName: string, JSONValue: Object | number | string] - > - rscChunks: Uint8Array[] - }, - serverComponentsErrorHandler: ReturnType, - nonce?: string -): (props: Props) => JSX.Element { - // We need to expose the `__webpack_require__` API globally for - // react-server-dom-webpack. This is a hack until we find a better way. - if (ComponentMod.__next_app_webpack_require__) { - // @ts-ignore - globalThis.__next_require__ = ComponentMod.__next_app_webpack_require__ - - // @ts-ignore - globalThis.__next_chunk_load__ = () => Promise.resolve() - } - - let RSCStream: ReadableStream - const createRSCStream = (props: Props) => { - if (!RSCStream) { - RSCStream = ComponentMod.renderToReadableStream( - , - clientReferenceManifest.clientModules, - { - context: serverContexts, - onError: serverComponentsErrorHandler, - } - ) - } - return RSCStream - } - - const flightResponseRef: FlightResponseRef = { current: null } - - const writable = transformStream.writable - return function ServerComponentWrapper(props: Props): JSX.Element { - const reqStream = createRSCStream(props) - const response = useFlightResponse( - writable, - reqStream, - clientReferenceManifest, - rscChunks, - flightResponseRef, - nonce - ) - return use(response) - } -} - -/** - * Shorten the dynamic param in order to make it smaller when transmitted to the browser. - */ -function getShortDynamicParamType( - type: DynamicParamTypes -): DynamicParamTypesShort { - switch (type) { - case 'catchall': - return 'c' - case 'optional-catchall': - return 'oc' - case 'dynamic': - return 'd' - default: - throw new Error('Unknown dynamic param type') - } -} - -/** - * Parse dynamic route segment to type of parameter - */ -function getSegmentParam(segment: string): { - param: string - type: DynamicParamTypes -} | null { - if (segment.startsWith('[[...') && segment.endsWith(']]')) { - return { - type: 'optional-catchall', - param: segment.slice(5, -2), - } - } - - if (segment.startsWith('[...') && segment.endsWith(']')) { - return { - type: 'catchall', - param: segment.slice(4, -1), - } - } - - if (segment.startsWith('[') && segment.endsWith(']')) { - return { - type: 'dynamic', - param: segment.slice(1, -1), - } - } - - return null -} - -/** - * Get inline tags based on server CSS manifest. Only used when rendering to HTML. - */ -function getCssInlinedLinkTags( - clientReferenceManifest: ClientReferenceManifest, - serverCSSManifest: ClientCSSReferenceManifest, - filePath: string, - serverCSSForEntries: string[], - injectedCSS: Set, - collectNewCSSImports?: boolean -): string[] { - const layoutOrPageCssModules = serverCSSManifest.cssImports[filePath] - - const filePathWithoutExt = filePath.replace(/\.[^.]+$/, '') - const cssFilesForEntry = new Set( - clientReferenceManifest.cssFiles?.[filePathWithoutExt] || [] - ) - - if (!layoutOrPageCssModules || !cssFilesForEntry.size) { - return [] - } - const chunks = new Set() - - for (const mod of layoutOrPageCssModules) { - // We only include the CSS if it's a global CSS, or it is used by this - // entrypoint. - if ( - serverCSSForEntries.includes(mod) || - !/\.module\.(css|sass|scss)$/.test(mod) - ) { - // If the CSS is already injected by a parent layer, we don't need - // to inject it again. - if (!injectedCSS.has(mod)) { - const modData = - clientReferenceManifest.clientModules[ - getClientReferenceModuleKey(mod, '') - ] - if (modData) { - for (const chunk of modData.chunks) { - // If the current entry in the final tree-shaked bundle has that CSS - // chunk, it means that it's actually used. We should include it. - if (cssFilesForEntry.has(chunk)) { - chunks.add(chunk) - // This might be a new layout, and to make it more efficient and - // not introducing another loop, we mutate the set directly. - if (collectNewCSSImports) { - injectedCSS.add(mod) - } - } - } - } - } - } - } - - return [...chunks] -} - -function getServerCSSForEntries( - serverCSSManifest: ClientCSSReferenceManifest, - entries: string[] -) { - const css = [] - for (const entry of entries) { - const entryName = entry.replace(/\.[^.]+$/, '') - if ( - serverCSSManifest.cssModules && - serverCSSManifest.cssModules[entryName] - ) { - css.push(...serverCSSManifest.cssModules[entryName]) - } - } - return css -} - -/** - * Get inline tags based on server CSS manifest and next/font manifest. Only used when rendering to HTML. - */ -function getPreloadedFontFilesInlineLinkTags( - serverCSSManifest: ClientCSSReferenceManifest, - nextFontManifest: NextFontManifest | undefined, - serverCSSForEntries: string[], - filePath: string | undefined, - injectedFontPreloadTags: Set -): string[] | null { - if (!nextFontManifest || !filePath) { - return null - } - const layoutOrPageCss = serverCSSManifest.cssImports[filePath] - - if (!layoutOrPageCss) { - return null - } - - const fontFiles = new Set() - let foundFontUsage = false - - for (const css of layoutOrPageCss) { - // We only include the CSS if it is used by this entrypoint. - if (serverCSSForEntries.includes(css)) { - const preloadedFontFiles = nextFontManifest.app[css] - if (preloadedFontFiles) { - foundFontUsage = true - for (const fontFile of preloadedFontFiles) { - if (!injectedFontPreloadTags.has(fontFile)) { - fontFiles.add(fontFile) - injectedFontPreloadTags.add(fontFile) - } - } - } - } - } - - // If we find an entry in the manifest but it's empty, add a preconnect tag by returning null. - // Only render a preconnect tag if we previously didn't preload any fonts. - if ( - !foundFontUsage || - (fontFiles.size === 0 && injectedFontPreloadTags.size > 0) - ) { - return null - } - - // Sorting to make order deterministic - return [...fontFiles].sort() -} - -function getScriptNonceFromHeader(cspHeaderValue: string): string | undefined { - const directives = cspHeaderValue - // Directives are split by ';'. - .split(';') - .map((directive) => directive.trim()) - - // First try to find the directive for the 'script-src', otherwise try to - // fallback to the 'default-src'. - const directive = - directives.find((dir) => dir.startsWith('script-src')) || - directives.find((dir) => dir.startsWith('default-src')) - - // If no directive could be found, then we're done. - if (!directive) { - return - } - - // Extract the nonce from the directive - const nonce = directive - .split(' ') - // Remove the 'strict-src'/'default-src' string, this can't be the nonce. - .slice(1) - .map((source) => source.trim()) - // Find the first source with the 'nonce-' prefix. - .find( - (source) => - source.startsWith("'nonce-") && - source.length > 8 && - source.endsWith("'") - ) - // Grab the nonce by trimming the 'nonce-' prefix. - ?.slice(7, -1) - - // If we could't find the nonce, then we're done. - if (!nonce) { - return - } - - // Don't accept the nonce value if it contains HTML escape characters. - // Technically, the spec requires a base64'd value, but this is just an - // extra layer. - if (ESCAPE_REGEX.test(nonce)) { - throw new Error( - 'Nonce value from Content-Security-Policy contained HTML escape characters.\nLearn more: https://nextjs.org/docs/messages/nonce-contained-invalid-characters' - ) - } - - return nonce -} - -async function renderToString(element: React.ReactElement) { - return getTracer().trace(AppRenderSpan.renderToString, async () => { - const renderStream = await ReactDOMServer.renderToReadableStream(element) - await renderStream.allReady - return streamToString(renderStream) - }) -} - -function parseAndValidateFlightRouterState( - stateHeader: string | string[] | undefined -): FlightRouterState | undefined { - if (typeof stateHeader === 'undefined') { - return undefined - } - if (Array.isArray(stateHeader)) { - throw new Error( - 'Multiple router state headers were sent. This is not allowed.' - ) - } - - // We limit the size of the router state header to ~40kb. This is to prevent - // a malicious user from sending a very large header and slowing down the - // resolving of the router state. - // This is around 2,000 nested or parallel route segment states: - // '{"children":["",{}]}'.length === 20. - if (stateHeader.length > 20 * 2000) { - throw new Error('The router state header was too large.') - } - - try { - return flightRouterStateSchema.parse(JSON.parse(stateHeader)) - } catch { - throw new Error('The router state header was sent but could not be parsed.') - } -} - -function validateURL(url: string | undefined): string { - if (!url) { - throw new Error('Invalid request URL') - } - try { - new URL(url, 'http://n') - return url - } catch { - throw new Error('Invalid request URL') - } -} +import { interopDefault } from './interop-default' +import { preloadComponent } from './preload-component' +import { FlightRenderResult } from './flight-render-result' +import { ActionRenderResult } from './action-render-result' +import { createErrorHandler } from './create-error-handler' +import { createServerComponentRenderer } from './create-server-components-renderer' +import { getShortDynamicParamType } from './get-short-dynamic-param-type' +import { getSegmentParam } from './get-segment-param' +import { getCssInlinedLinkTags } from './get-css-inlined-link-tags' +import { getServerCSSForEntries } from './get-server-css-for-entries' +import { getPreloadedFontFilesInlineLinkTags } from './get-preloaded-font-files-inline-link-tags' +import { getScriptNonceFromHeader } from './get-script-nonce-from-header' +import { renderToString } from './render-to-string' +import { parseAndValidateFlightRouterState } from './parse-and-validate-flight-router-state' +import { validateURL } from './validate-url' + +export const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge' export async function renderToHTMLOrFlight( req: IncomingMessage, diff --git a/packages/next/src/server/app-render/interop-default.ts b/packages/next/src/server/app-render/interop-default.ts new file mode 100644 index 00000000000000..fd1ca43d7d3ad0 --- /dev/null +++ b/packages/next/src/server/app-render/interop-default.ts @@ -0,0 +1,6 @@ +/** + * Interop between "export default" and "module.exports". + */ +export function interopDefault(mod: any) { + return mod.default || mod +} diff --git a/packages/next/src/server/app-render/parse-and-validate-flight-router-state.tsx b/packages/next/src/server/app-render/parse-and-validate-flight-router-state.tsx new file mode 100644 index 00000000000000..d6bf3fa8c4f7a5 --- /dev/null +++ b/packages/next/src/server/app-render/parse-and-validate-flight-router-state.tsx @@ -0,0 +1,30 @@ +import { FlightRouterState } from './types' +import { flightRouterStateSchema } from './types' + +export function parseAndValidateFlightRouterState( + stateHeader: string | string[] | undefined +): FlightRouterState | undefined { + if (typeof stateHeader === 'undefined') { + return undefined + } + if (Array.isArray(stateHeader)) { + throw new Error( + 'Multiple router state headers were sent. This is not allowed.' + ) + } + + // We limit the size of the router state header to ~40kb. This is to prevent + // a malicious user from sending a very large header and slowing down the + // resolving of the router state. + // This is around 2,000 nested or parallel route segment states: + // '{"children":["",{}]}'.length === 20. + if (stateHeader.length > 20 * 2000) { + throw new Error('The router state header was too large.') + } + + try { + return flightRouterStateSchema.parse(JSON.parse(stateHeader)) + } catch { + throw new Error('The router state header was sent but could not be parsed.') + } +} diff --git a/packages/next/src/server/app-render/preload-component.ts b/packages/next/src/server/app-render/preload-component.ts new file mode 100644 index 00000000000000..c4b82c006a634c --- /dev/null +++ b/packages/next/src/server/app-render/preload-component.ts @@ -0,0 +1,31 @@ +export function preloadComponent(Component: any, props: any) { + const prev = console.error + // Hide invalid hook call warning when calling component + console.error = function (msg) { + if (msg.startsWith('Warning: Invalid hook call.')) { + // ignore + } else { + // @ts-expect-error argument is defined + prev.apply(console, arguments) + } + } + try { + let result = Component(props) + if (result && typeof result.then === 'function') { + // Catch promise rejections to prevent unhandledRejection errors + result.then( + () => {}, + () => {} + ) + } + return function () { + // We know what this component will render already. + return result + } + } catch (x) { + // something suspended or errored, try again later + } finally { + console.error = prev + } + return Component +} diff --git a/packages/next/src/server/app-render/render-to-string.tsx b/packages/next/src/server/app-render/render-to-string.tsx new file mode 100644 index 00000000000000..0eca1bb36b80a9 --- /dev/null +++ b/packages/next/src/server/app-render/render-to-string.tsx @@ -0,0 +1,13 @@ +import React from 'next/dist/compiled/react' +import ReactDOMServer from 'next/dist/compiled/react-dom/server.browser' +import { streamToString } from '../node-web-streams-helper' +import { AppRenderSpan } from '../lib/trace/constants' +import { getTracer } from '../lib/trace/tracer' + +export async function renderToString(element: React.ReactElement) { + return getTracer().trace(AppRenderSpan.renderToString, async () => { + const renderStream = await ReactDOMServer.renderToReadableStream(element) + await renderStream.allReady + return streamToString(renderStream) + }) +} diff --git a/packages/next/src/server/app-render/use-flight-response.tsx b/packages/next/src/server/app-render/use-flight-response.tsx new file mode 100644 index 00000000000000..80a1f48e64bdf3 --- /dev/null +++ b/packages/next/src/server/app-render/use-flight-response.tsx @@ -0,0 +1,80 @@ +import { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin' +import { + readableStreamTee, + encodeText, + decodeText, +} from '../node-web-streams-helper' +import { htmlEscapeJsonString } from '../htmlescape' +import { isEdgeRuntime } from './index' +import { FlightResponseRef } from './flight-response-ref' + +/** + * Render Flight stream. + * This is only used for renderToHTML, the Flight response does not need additional wrappers. + */ +export function useFlightResponse( + writable: WritableStream, + req: ReadableStream, + clientReferenceManifest: ClientReferenceManifest, + rscChunks: Uint8Array[], + flightResponseRef: FlightResponseRef, + nonce?: string +): Promise { + if (flightResponseRef.current !== null) { + return flightResponseRef.current + } + const { + createFromReadableStream, + } = require('next/dist/compiled/react-server-dom-webpack/client.edge') + + const [renderStream, forwardStream] = readableStreamTee(req) + const res = createFromReadableStream(renderStream, { + moduleMap: isEdgeRuntime + ? clientReferenceManifest.edgeSSRModuleMapping + : clientReferenceManifest.ssrModuleMapping, + }) + flightResponseRef.current = res + + let bootstrapped = false + // We only attach CSS chunks to the inlined data. + const forwardReader = forwardStream.getReader() + const writer = writable.getWriter() + const startScriptTag = nonce + ? `` + ) + ) + } + if (done) { + flightResponseRef.current = null + writer.close() + } else { + const responsePartial = decodeText(value, textDecoder) + const scripts = `${startScriptTag}self.__next_f.push(${htmlEscapeJsonString( + JSON.stringify([1, responsePartial]) + )})` + + writer.write(encodeText(scripts)) + read() + } + }) + } + read() + + return res +} diff --git a/packages/next/src/server/app-render/validate-url.tsx b/packages/next/src/server/app-render/validate-url.tsx new file mode 100644 index 00000000000000..c465690cf8af00 --- /dev/null +++ b/packages/next/src/server/app-render/validate-url.tsx @@ -0,0 +1,11 @@ +export function validateURL(url: string | undefined): string { + if (!url) { + throw new Error('Invalid request URL') + } + try { + new URL(url, 'http://n') + return url + } catch { + throw new Error('Invalid request URL') + } +} From 269780cfbf081d312ca8fcea0afd7d91c51e640a Mon Sep 17 00:00:00 2001 From: Lee Robinson Date: Sun, 19 Mar 2023 13:01:33 -0500 Subject: [PATCH 559/672] Add note about Windows Defender (#47298) https://twitter.com/timneutkens/status/1637504870541320193 --- docs/advanced-features/debugging.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/advanced-features/debugging.md b/docs/advanced-features/debugging.md index 86ba80d0036ed9..847bd7d3eaba4e 100644 --- a/docs/advanced-features/debugging.md +++ b/docs/advanced-features/debugging.md @@ -97,6 +97,8 @@ Windows users may run into an issue when using `NODE_OPTIONS='--inspect'` as tha `cross-env` will set the `NODE_OPTIONS` environment variable regardless of which platform you are on (including Mac, Linux, and Windows) and allow you to debug consistently across devices and operating systems. +> **Note:** Ensure Windows Defender is disabled on your machine. This external service will check _every file read_, which has been reported to greatly increase Fast Refresh time with `next dev`. This is a known issue, not related to Next.js, but it does affect Next.js development. + ## More information To learn more about how to use a JavaScript debugger, take a look at the following documentation: From a76c92971711d53b2f36755ead027d8c54db639d Mon Sep 17 00:00:00 2001 From: meesvandongen <35409045+meesvandongen@users.noreply.github.com> Date: Sun, 19 Mar 2023 20:58:56 +0100 Subject: [PATCH 560/672] fix: typo in output:export error messages (#47252) See changes --- packages/next/src/server/config.ts | 8 ++++---- test/integration/config-output-export/test/index.test.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index b5fba3d992f870..f71a19de2cfbc1 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -263,22 +263,22 @@ function assignDefaults( if (result.output === 'export') { if (result.i18n) { throw new Error( - 'Specified "i18n" cannot but used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' + 'Specified "i18n" cannot be used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' ) } if (result.rewrites) { throw new Error( - 'Specified "rewrites" cannot but used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' + 'Specified "rewrites" cannot be used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' ) } if (result.redirects) { throw new Error( - 'Specified "redirects" cannot but used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' + 'Specified "redirects" cannot be used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' ) } if (result.headers) { throw new Error( - 'Specified "headers" cannot but used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' + 'Specified "headers" cannot be used with "output: export". See more info here: https://nextjs.org/docs/advanced-features/static-html-export' ) } } diff --git a/test/integration/config-output-export/test/index.test.ts b/test/integration/config-output-export/test/index.test.ts index 52d2e4ee18aa15..3a8c2089ea5fb3 100644 --- a/test/integration/config-output-export/test/index.test.ts +++ b/test/integration/config-output-export/test/index.test.ts @@ -59,7 +59,7 @@ describe('config-output-export', () => { }, }) expect(stderr).toContain( - 'Specified "i18n" cannot but used with "output: export".' + 'Specified "i18n" cannot be used with "output: export".' ) }) @@ -69,7 +69,7 @@ describe('config-output-export', () => { rewrites: [{ source: '/from', destination: '/to' }], }) expect(stderr).toContain( - 'Specified "rewrites" cannot but used with "output: export".' + 'Specified "rewrites" cannot be used with "output: export".' ) }) @@ -79,7 +79,7 @@ describe('config-output-export', () => { redirects: [{ source: '/from', destination: '/to', permanent: true }], }) expect(stderr).toContain( - 'Specified "redirects" cannot but used with "output: export".' + 'Specified "redirects" cannot be used with "output: export".' ) }) @@ -94,7 +94,7 @@ describe('config-output-export', () => { ], }) expect(stderr).toContain( - 'Specified "headers" cannot but used with "output: export".' + 'Specified "headers" cannot be used with "output: export".' ) }) From 23c9f0eef20c5f425da28da872b4951d8c4029f9 Mon Sep 17 00:00:00 2001 From: Vlad Filippov Date: Sun, 19 Mar 2023 19:49:49 -0400 Subject: [PATCH 561/672] Fix contributing.md link in the rendering benchmark (#47303) Fixes a 404 issue with the docs --- bench/rendering/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/rendering/readme.md b/bench/rendering/readme.md index 71c7070d8f691c..d4748da296d767 100644 --- a/bench/rendering/readme.md +++ b/bench/rendering/readme.md @@ -2,7 +2,7 @@ ## Installation -Follow the steps in [contributing.md](../contributing.md) +Follow the steps in [contributing.md](../../contributing.md) Both benchmarks use `ab`. So make sure you have that installed. From 7cc4159561f6591140ff669c4ac3c74a049c783b Mon Sep 17 00:00:00 2001 From: Steven Date: Sun, 19 Mar 2023 20:26:00 -0400 Subject: [PATCH 562/672] fix: handle different cases of React `fetchPriority` (#47302) In React 18.3.0 or newer, we must user camelCase `fetchPriority` prop to avoid "Warning: Invalid DOM property". In React 18.2.0 and older, we must use the lowercase `fetchpriority` prop to avoid "Warning: Invalid DOM property". See https://github.com/facebook/react/pull/25927 --- packages/next/src/client/image.tsx | 24 +++++++++++++++---- .../next-image-new/default/pages/priority.js | 6 +++++ .../next-image-new/default/test/index.test.ts | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/next/src/client/image.tsx b/packages/next/src/client/image.tsx index d830fef14ec50c..5e13f317f34ae5 100644 --- a/packages/next/src/client/image.tsx +++ b/packages/next/src/client/image.tsx @@ -8,6 +8,7 @@ import React, { useMemo, useState, forwardRef, + version, } from 'react' import Head from '../shared/lib/head' import { getImageBlurSvg } from '../shared/lib/image-blur-svg' @@ -367,6 +368,23 @@ function handleLoading( }) } +function getDynamicProps( + fetchPriority?: string +): Record { + const [majorStr, minorStr] = version.split('.') + const major = parseInt(majorStr, 10) + const minor = parseInt(minorStr, 10) + if (major > 18 || (major === 18 && minor >= 3)) { + // In React 18.3.0 or newer, we must use camelCase + // prop to avoid "Warning: Invalid DOM property". + // See https://github.com/facebook/react/pull/25927 + return { fetchPriority } + } + // In React 18.2.0 or older, we must use lowercase prop + // to avoid "Warning: Invalid DOM property". + return { fetchpriority: fetchPriority } +} + const ImageElement = forwardRef( ( { @@ -401,10 +419,9 @@ const ImageElement = forwardRef( <> ( imageSrcSet={imgAttributes.srcSet} imageSizes={imgAttributes.sizes} crossOrigin={rest.crossOrigin} - // Keep lowercase until https://github.com/facebook/react/pull/25927 lands - fetchpriority={fetchPriority} + {...getDynamicProps(fetchPriority)} /> ) : null} diff --git a/test/integration/next-image-new/default/pages/priority.js b/test/integration/next-image-new/default/pages/priority.js index 3cc02b89bcbfcd..57f025fe815a13 100644 --- a/test/integration/next-image-new/default/pages/priority.js +++ b/test/integration/next-image-new/default/pages/priority.js @@ -8,6 +8,7 @@ const Page = () => { basic-image { basic-image-crossorigin { load-eager { responsive1 { responsive2 { /> pri-low Date: Mon, 20 Mar 2023 11:29:00 +0200 Subject: [PATCH 563/672] [edge] limit the api surface of `util` (#47292) This makes sure that what works locally will work in production. --- .../webpack/plugins/middleware-plugin.ts | 8 ++- .../next/src/server/web/sandbox/context.ts | 72 ++++++++++++------- .../edge-runtime-node-compatibility.test.ts | 8 +-- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/packages/next/src/build/webpack/plugins/middleware-plugin.ts b/packages/next/src/build/webpack/plugins/middleware-plugin.ts index 648f63ebaade8a..2fe92214c16803 100644 --- a/packages/next/src/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/src/build/webpack/plugins/middleware-plugin.ts @@ -858,17 +858,19 @@ export default class MiddlewarePlugin { } } -const supportedEdgePolyfills = new Set([ +export const SUPPORTED_NATIVE_MODULES = [ 'buffer', 'events', 'assert', 'util', 'async_hooks', -]) +] as const + +const supportedEdgePolyfills = new Set(SUPPORTED_NATIVE_MODULES) export function getEdgePolyfilledModules() { const records: Record = {} - for (const mod of supportedEdgePolyfills) { + for (const mod of SUPPORTED_NATIVE_MODULES) { records[mod] = `commonjs node:${mod}` records[`node:${mod}`] = `commonjs node:${mod}` } diff --git a/packages/next/src/server/web/sandbox/context.ts b/packages/next/src/server/web/sandbox/context.ts index 86b13cd98f0f34..96735e587e84a4 100644 --- a/packages/next/src/server/web/sandbox/context.ts +++ b/packages/next/src/server/web/sandbox/context.ts @@ -13,7 +13,10 @@ import { readFileSync, promises as fs } from 'fs' import { validateURL } from '../utils' import { pick } from '../../../lib/pick' import { fetchInlineAsset } from './fetch-inline-assets' -import type { EdgeFunctionDefinition } from '../../../build/webpack/plugins/middleware-plugin' +import type { + EdgeFunctionDefinition, + SUPPORTED_NATIVE_MODULES, +} from '../../../build/webpack/plugins/middleware-plugin' import { UnwrapPromise } from '../../../lib/coalesced-function' import { runInContext } from 'vm' import BufferImplementation from 'node:buffer' @@ -144,20 +147,19 @@ function getDecorateUnhandledRejection(runtime: EdgeRuntime) { } } -const NativeModuleMap = new Map([ - [ - 'node:buffer', - pick(BufferImplementation, [ +const NativeModuleMap = (() => { + const mods: Record< + `node:${typeof SUPPORTED_NATIVE_MODULES[number]}`, + unknown + > = { + 'node:buffer': pick(BufferImplementation, [ 'constants', 'kMaxLength', 'kStringMaxLength', 'Buffer', 'SlowBuffer', ]), - ], - [ - 'node:events', - pick(EventsImplementation, [ + 'node:events': pick(EventsImplementation, [ 'EventEmitter', 'captureRejectionSymbol', 'defaultMaxListeners', @@ -166,22 +168,42 @@ const NativeModuleMap = new Map([ 'on', 'once', ]), - ], - [ - 'node:async_hooks', - pick(AsyncHooksImplementation, ['AsyncLocalStorage', 'AsyncResource']), - ], - [ - 'node:assert', - // TODO: check if need to pick specific properties - AssertImplementation, - ], - [ - 'node:util', - // TODO: check if need to pick specific properties - UtilImplementation, - ], -]) + 'node:async_hooks': pick(AsyncHooksImplementation, [ + 'AsyncLocalStorage', + 'AsyncResource', + ]), + 'node:assert': pick(AssertImplementation, [ + 'AssertionError', + 'deepEqual', + 'deepStrictEqual', + 'doesNotMatch', + 'doesNotReject', + 'doesNotThrow', + 'equal', + 'fail', + 'ifError', + 'match', + 'notDeepEqual', + 'notDeepStrictEqual', + 'notEqual', + 'notStrictEqual', + 'ok', + 'rejects', + 'strict', + 'strictEqual', + 'throws', + ]), + 'node:util': pick(UtilImplementation, [ + '_extend' as any, + 'callbackify', + 'format', + 'inherits', + 'promisify', + 'types', + ]), + } + return new Map(Object.entries(mods)) +})() /** * Create a module cache specific for the provided parameters. It includes diff --git a/test/e2e/app-dir/edge-runtime-node-compatibility/edge-runtime-node-compatibility.test.ts b/test/e2e/app-dir/edge-runtime-node-compatibility/edge-runtime-node-compatibility.test.ts index ccc7f33aec946d..44ae0ee2652119 100644 --- a/test/e2e/app-dir/edge-runtime-node-compatibility/edge-runtime-node-compatibility.test.ts +++ b/test/e2e/app-dir/edge-runtime-node-compatibility/edge-runtime-node-compatibility.test.ts @@ -15,13 +15,13 @@ createNextDescribe( expect(json).toEqual({ 'Buffer === B.Buffer': true, encoded: Buffer.from('Hello, world!').toString('base64'), - exposedKeys: [ + exposedKeys: expect.arrayContaining([ 'constants', 'kMaxLength', 'kStringMaxLength', 'Buffer', 'SlowBuffer', - ], + ]), }) }) @@ -38,13 +38,13 @@ createNextDescribe( 'typeof B2.Buffer': 'function', 'typeof Buffer': 'function', encoded: 'SGVsbG8sIHdvcmxkIQ==', - exposedKeys: [ + exposedKeys: expect.arrayContaining([ 'constants', 'kMaxLength', 'kStringMaxLength', 'Buffer', 'SlowBuffer', - ], + ]), }) }) } From 8771a5613e0b26029cd4b574338d24f1102fa8ec Mon Sep 17 00:00:00 2001 From: Jimmy Lai Date: Mon, 20 Mar 2023 13:10:13 +0100 Subject: [PATCH 564/672] parallel routes: fix duplicate dev warning (#47317) - there's a warning that happens currently when compiling parallel routes in dev because they all resolve to the same pathname and their identity function is all the same - I'm repurposing their identity fn to include the actual segment it's referring to, instead of all of them the `__next_prallelPaths` string doesn't seem to be used otherwise so I think it's alright to rename fix NEXT-831 ([link](https://linear.app/vercel/issue/NEXT-831)) --- .../server/future/route-matchers/app-page-route-matcher.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/next/src/server/future/route-matchers/app-page-route-matcher.ts b/packages/next/src/server/future/route-matchers/app-page-route-matcher.ts index 54727515c681b8..2cbf6725cefa36 100644 --- a/packages/next/src/server/future/route-matchers/app-page-route-matcher.ts +++ b/packages/next/src/server/future/route-matchers/app-page-route-matcher.ts @@ -3,8 +3,6 @@ import { AppPageRouteDefinition } from '../route-definitions/app-page-route-defi export class AppPageRouteMatcher extends RouteMatcher { public get identity(): string { - return `${ - this.definition.pathname - }?__nextParallelPaths=${this.definition.appPaths.join(',')}}` + return `${this.definition.pathname}?__nextPage=${this.definition.page}}` } } From fd0e81342f72607811a8ce49f9283fe98417281c Mon Sep 17 00:00:00 2001 From: tka5 <38692574+tka5@users.noreply.github.com> Date: Tue, 21 Mar 2023 00:45:45 +0900 Subject: [PATCH 565/672] fix typo (#47235) Co-authored-by: Jan Kaifer --- examples/cms-cosmic/lib/api.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/cms-cosmic/lib/api.tsx b/examples/cms-cosmic/lib/api.tsx index 3bdbe404c8e13c..f84f708795fbb7 100644 --- a/examples/cms-cosmic/lib/api.tsx +++ b/examples/cms-cosmic/lib/api.tsx @@ -40,7 +40,9 @@ export const getAllPostsWithSlug = async () => { return data.objects } -export const getAllPostsForHome = async (preview: boolean): Promise => { +export const getAllPostsForHome = async ( + preview: boolean +): Promise => { const params = { query: { type: 'posts', From 40cb797a341a9fc94495cc66e51f36c2ecbb32c7 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 20 Mar 2023 08:49:23 -0700 Subject: [PATCH 566/672] next/font/local prep: compartmentalize next/font/google (#47213) This PR is largely preparation work for next/font/local by compartmentalizing and modularizing existing pieces of next/font/google. It: * Renames the top level directory to `next_font` * Places next/font/google-specific code into `next_font/google` * Extracts common structures and methods into top-level `font_fallback.rs`, `stylesheet.rs`, `util.rs`, etc. * Updates visibility of structures and functions to use `pub(super)` within `next/font/google` --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/next-swc/crates/next-core/src/lib.rs | 2 +- .../next-core/src/next_font/font_fallback.rs | 60 +++++++++ .../google}/font_fallback.rs | 75 +++--------- .../google}/mod.rs | 114 ++++++------------ .../google}/options.rs | 23 ++-- .../google}/request.rs | 8 +- .../src/next_font/google/stylesheet.rs | 65 ++++++++++ .../google}/util.rs | 66 +++------- .../{next_font_google => next_font}/issue.rs | 0 .../crates/next-core/src/next_font/mod.rs | 5 + .../next-core/src/next_font/stylesheet.rs | 50 ++++++++ .../crates/next-core/src/next_font/util.rs | 65 ++++++++++ .../src/next_font_google/stylesheet.rs | 108 ----------------- .../crates/next-core/src/next_import_map.rs | 2 +- 14 files changed, 338 insertions(+), 305 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_font/font_fallback.rs rename packages/next-swc/crates/next-core/src/{next_font_google => next_font/google}/font_fallback.rs (76%) rename packages/next-swc/crates/next-core/src/{next_font_google => next_font/google}/mod.rs (83%) rename packages/next-swc/crates/next-core/src/{next_font_google => next_font/google}/options.rs (96%) rename packages/next-swc/crates/next-core/src/{next_font_google => next_font/google}/request.rs (86%) create mode 100644 packages/next-swc/crates/next-core/src/next_font/google/stylesheet.rs rename packages/next-swc/crates/next-core/src/{next_font_google => next_font/google}/util.rs (90%) rename packages/next-swc/crates/next-core/src/{next_font_google => next_font}/issue.rs (100%) create mode 100644 packages/next-swc/crates/next-core/src/next_font/mod.rs create mode 100644 packages/next-swc/crates/next-core/src/next_font/stylesheet.rs create mode 100644 packages/next-swc/crates/next-core/src/next_font/util.rs delete mode 100644 packages/next-swc/crates/next-core/src/next_font_google/stylesheet.rs diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index e3e7a2f54fb37d..e5caccb9c3ab0c 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -16,7 +16,7 @@ mod next_client_chunks; mod next_client_component; pub mod next_config; mod next_edge; -mod next_font_google; +mod next_font; pub mod next_image; mod next_import_map; mod next_route_matcher; diff --git a/packages/next-swc/crates/next-core/src/next_font/font_fallback.rs b/packages/next-swc/crates/next-core/src/next_font/font_fallback.rs new file mode 100644 index 00000000000000..517b96c93273ae --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font/font_fallback.rs @@ -0,0 +1,60 @@ +use anyhow::Result; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +use turbo_tasks::{ + primitives::{StringVc, StringsVc}, + trace::TraceRawVcs, +}; + +pub(crate) struct DefaultFallbackFont { + pub name: String, + pub az_avg_width: f64, + pub units_per_em: u32, +} + +// From https://github.com/vercel/next.js/blob/a3893bf69c83fb08e88c87bf8a21d987a0448c8e/packages/font/src/utils.ts#L4 +pub(crate) static DEFAULT_SANS_SERIF_FONT: Lazy = + Lazy::new(|| DefaultFallbackFont { + name: "Arial".to_owned(), + az_avg_width: 934.5116279069767, + units_per_em: 2048, + }); + +pub(crate) static DEFAULT_SERIF_FONT: Lazy = + Lazy::new(|| DefaultFallbackFont { + name: "Times New Roman".to_owned(), + az_avg_width: 854.3953488372093, + units_per_em: 2048, + }); + +#[turbo_tasks::value(shared)] +pub(crate) struct AutomaticFontFallback { + pub scoped_font_family: StringVc, + pub local_font_family: StringVc, + pub adjustment: Option, +} + +#[turbo_tasks::value(shared)] +pub(crate) enum FontFallback { + Automatic(AutomaticFontFallbackVc), + /// There was an issue preparing the font fallback. Since resolving the + /// font css cannot fail, proper Errors cannot be returned. Emit an issue, + /// return this and omit fallback information instead. + Error, + Manual(StringsVc), +} + +#[turbo_tasks::value(transparent)] +pub(crate) struct FontFallbacks(Vec); + +#[derive(Debug, PartialEq, Serialize, Deserialize, TraceRawVcs)] +pub(crate) struct FontAdjustment { + pub ascent: f64, + pub descent: f64, + pub line_gap: f64, + pub size_adjust: f64, +} + +// Necessary since floating points in this struct don't implement Eq, but it's +// required for turbo tasks values. +impl Eq for FontAdjustment {} diff --git a/packages/next-swc/crates/next-core/src/next_font_google/font_fallback.rs b/packages/next-swc/crates/next-core/src/next_font/google/font_fallback.rs similarity index 76% rename from packages/next-swc/crates/next-core/src/next_font_google/font_fallback.rs rename to packages/next-swc/crates/next-core/src/next_font/google/font_fallback.rs index 47ae5f827099e8..27f5f1cb79bbc1 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/font_fallback.rs +++ b/packages/next-swc/crates/next-core/src/next_font/google/font_fallback.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use anyhow::{Context, Result}; -use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use turbo_tasks::{ primitives::{StringVc, StringsVc, U32Vc}, @@ -10,48 +9,22 @@ use turbo_tasks::{ use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::issue::IssueSeverity; -use super::{get_scoped_font_family, options::NextFontGoogleOptionsVc, FontFamilyType}; -use crate::{next_font_google::issue::NextFontIssue, util::load_next_json}; - -struct DefaultFallbackFont { - name: String, - az_avg_width: f64, - units_per_em: u32, -} - -// From https://github.com/vercel/next.js/blob/a3893bf69c83fb08e88c87bf8a21d987a0448c8e/packages/font/src/utils.ts#L4 -static DEFAULT_SANS_SERIF_FONT: Lazy = Lazy::new(|| DefaultFallbackFont { - name: "Arial".to_owned(), - az_avg_width: 934.5116279069767, - units_per_em: 2048, -}); - -static DEFAULT_SERIF_FONT: Lazy = Lazy::new(|| DefaultFallbackFont { - name: "Times New Roman".to_owned(), - az_avg_width: 854.3953488372093, - units_per_em: 2048, -}); - -#[turbo_tasks::value(transparent)] -pub(crate) struct AutomaticFontFallback { - pub scoped_font_family: StringVc, - pub local_font_family: StringVc, - pub adjustment: Option, -} - -#[turbo_tasks::value(transparent)] -pub(crate) enum FontFallback { - Automatic(AutomaticFontFallbackVc), - /// There was an issue loading the font metrics data. Since resolving the - /// font css cannot fail, proper Errors cannot be returned. Emit an issue, - /// return this and omit fallback information instead. - Error, - Manual(StringsVc), -} +use super::options::NextFontGoogleOptionsVc; +use crate::{ + next_font::{ + font_fallback::{ + AutomaticFontFallback, FontAdjustment, FontFallback, FontFallbackVc, + DEFAULT_SANS_SERIF_FONT, DEFAULT_SERIF_FONT, + }, + issue::NextFontIssue, + util::{get_scoped_font_family, FontFamilyType}, + }, + util::load_next_json, +}; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -pub(crate) struct FontMetricsMapEntry { +pub(super) struct FontMetricsMapEntry { category: String, ascent: i32, descent: i32, @@ -61,28 +34,16 @@ pub(crate) struct FontMetricsMapEntry { } #[derive(Deserialize)] -pub(crate) struct FontMetricsMap(pub HashMap); - -#[derive(Debug, PartialEq, Serialize, Deserialize, TraceRawVcs)] -pub(crate) struct FontAdjustment { - pub ascent: f64, - pub descent: f64, - pub line_gap: f64, - pub size_adjust: f64, -} - -// Necessary since floating points in this struct don't implement Eq, but it's -// required for turbo tasks values. -impl Eq for FontAdjustment {} +pub(super) struct FontMetricsMap(pub HashMap); #[derive(Debug, PartialEq, Serialize, Deserialize, TraceRawVcs)] -pub(crate) struct Font { +pub(super) struct Font { pub font_family: String, pub adjustment: Option, } #[turbo_tasks::function] -pub(crate) async fn get_font_fallback( +pub(super) async fn get_font_fallback( context: FileSystemPathVc, options_vc: NextFontGoogleOptionsVc, request_hash: U32Vc, @@ -106,7 +67,7 @@ pub(crate) async fn get_font_fallback( AutomaticFontFallback { scoped_font_family: get_scoped_font_family( FontFamilyType::Fallback.cell(), - options_vc, + options_vc.font_family(), request_hash, ), local_font_family: StringVc::cell(fallback.font_family), @@ -189,7 +150,7 @@ mod tests { use turbo_tasks_fs::json::parse_json_with_source_context; use super::{FontAdjustment, FontMetricsMap}; - use crate::next_font_google::font_fallback::{lookup_fallback, Font}; + use crate::next_font::google::font_fallback::{lookup_fallback, Font}; #[test] fn test_fallback_from_metrics_sans_serif() -> Result<()> { diff --git a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs b/packages/next-swc/crates/next-core/src/next_font/google/mod.rs similarity index 83% rename from packages/next-swc/crates/next-core/src/next_font_google/mod.rs rename to packages/next-swc/crates/next-core/src/next_font/google/mod.rs index 29eb9c9bf48272..559140e1313385 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font/google/mod.rs @@ -2,11 +2,10 @@ use anyhow::{bail, Context, Result}; use indexmap::IndexMap; use indoc::formatdoc; use turbo_tasks::{ - primitives::{OptionStringVc, OptionU16Vc, StringVc, U32Vc}, + primitives::{OptionStringVc, StringVc, U32Vc}, Value, }; use turbo_tasks_fs::{json::parse_json_with_source_context, FileContent, FileSystemPathVc}; -use turbo_tasks_hash::hash_xxh3_hash64; use turbopack_core::{ resolve::{ options::{ @@ -22,26 +21,25 @@ use turbopack_core::{ use turbopack_node::execution_context::ExecutionContextVc; use self::{ - font_fallback::{get_font_fallback, FontFallback, FontFallbackVc}, - options::{FontWeights, NextFontGoogleOptionsVc}, + font_fallback::get_font_fallback, + options::{options_from_request, FontDataEntry, FontWeights, NextFontGoogleOptionsVc}, stylesheet::build_stylesheet, - util::{get_scoped_font_family, FontFamilyType}, + util::{get_font_axes, get_stylesheet_url}, }; -use crate::{ - embed_js::next_js_file_path, - next_font_google::{ - options::FontDataEntry, - util::{get_font_axes, get_stylesheet_url}, +use super::{ + font_fallback::{FontFallback, FontFallbackVc}, + util::{ + get_request_hash, get_request_id, get_scoped_font_family, FontCssProperties, + FontCssPropertiesVc, FontFamilyType, }, - util::load_next_json, }; +use crate::{embed_js::next_js_file_path, util::load_next_json}; -pub(crate) mod font_fallback; -pub(crate) mod issue; -pub(crate) mod options; -pub(crate) mod request; -pub(crate) mod stylesheet; -pub(crate) mod util; +pub mod font_fallback; +pub mod options; +pub mod request; +pub mod stylesheet; +pub mod util; pub const GOOGLE_FONTS_STYLESHEET_URL: &str = "https://fonts.googleapis.com/css2"; @@ -87,7 +85,7 @@ impl ImportMappingReplacement for NextFontGoogleReplacer { let properties = get_font_css_properties(options, fallback, request_hash).await?; let js_asset = VirtualAssetVc::new( next_js_file_path("internal/font/google") - .join(&format!("{}.js", get_request_id(*query_vc, font_data).await?)), + .join(&format!("{}.js", get_request_id(options.font_family(), request_hash).await?)), FileContent::Content( formatdoc!( r#" @@ -112,6 +110,7 @@ impl ImportMappingReplacement for NextFontGoogleReplacer { properties .weight .await? + .as_ref() .map(|w| format!("fontWeight: {},\n", w)) .unwrap_or_else(|| "".to_owned()), properties @@ -169,11 +168,14 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { let options = font_options_from_query_map(*query_vc, font_data); let stylesheet_url = get_stylesheet_url_from_options(options, font_data); let request_hash = get_request_hash(*query_vc); - let scoped_font_family = - get_scoped_font_family(FontFamilyType::WebFont.cell(), options, request_hash); + let scoped_font_family = get_scoped_font_family( + FontFamilyType::WebFont.cell(), + options.font_family(), + request_hash, + ); let css_virtual_path = next_js_file_path("internal/font/google").join(&format!( "/{}.module.css", - get_request_id(*query_vc, font_data).await? + get_request_id(options.font_family(), request_hash).await? )); // When running Next.js integration tests, use the mock data available in @@ -220,7 +222,7 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { let stylesheet = match stylesheet_str { Some(s) => Some( - update_stylesheet(s, options, scoped_font_family) + update_google_stylesheet(s, options, scoped_font_family) .await? .clone_value(), ), @@ -258,7 +260,7 @@ async fn load_font_data(project_root: FileSystemPathVc) -> Result { } #[turbo_tasks::function] -async fn update_stylesheet( +async fn update_google_stylesheet( stylesheet: StringVc, options: NextFontGoogleOptionsVc, scoped_font_family: StringVc, @@ -271,34 +273,6 @@ async fn update_stylesheet( ))) } -#[turbo_tasks::function] -async fn get_request_id(query_vc: QueryMapVc, font_data: FontDataVc) -> Result { - let options = font_options_from_query_map(query_vc, font_data).await?; - - Ok(StringVc::cell(format!( - "{}_{:x?}", - options.font_family.to_lowercase().replace(' ', "_"), - get_request_hash(query_vc).await?, - ))) -} - -#[turbo_tasks::function] -async fn get_request_hash(query_vc: QueryMapVc) -> Result { - let query = &*query_vc.await?; - let query = query.as_ref().context("Query map must be present")?; - let mut to_hash = vec![]; - for (k, v) in query { - to_hash.push(k); - to_hash.push(v); - } - - Ok(U32Vc::cell( - // Truncate the has to u32. These hashes are ultimately displayed as 8-character - // hexadecimal values. - hash_xxh3_hash64(to_hash) as u32, - )) -} - #[turbo_tasks::function] async fn get_stylesheet_url_from_options( options: NextFontGoogleOptionsVc, @@ -331,14 +305,6 @@ async fn get_stylesheet_url_from_options( )?)) } -#[turbo_tasks::value(transparent)] -pub(crate) struct FontCssProperties { - font_family: StringVc, - weight: OptionU16Vc, - style: OptionStringVc, - variable: OptionStringVc, -} - #[turbo_tasks::function] async fn get_font_css_properties( options_vc: NextFontGoogleOptionsVc, @@ -346,10 +312,14 @@ async fn get_font_css_properties( request_hash: U32Vc, ) -> Result { let options = &*options_vc.await?; - let scoped_font_family = - &*get_scoped_font_family(FontFamilyType::WebFont.cell(), options_vc, request_hash).await?; + let scoped_font_family = &*get_scoped_font_family( + FontFamilyType::WebFont.cell(), + options_vc.font_family(), + request_hash, + ) + .await?; - let mut font_families = vec![scoped_font_family.clone()]; + let mut font_families = vec![format!("'{}'", scoped_font_family.clone())]; let font_fallback = &*font_fallback.await?; match font_fallback { FontFallback::Manual(fonts) => { @@ -357,26 +327,16 @@ async fn get_font_css_properties( } FontFallback::Automatic(fallback) => { let fallback = &*fallback.await?; - font_families.push((*fallback.scoped_font_family.await?).clone()); + font_families.push(format!("'{}'", *fallback.scoped_font_family.await?)); } FontFallback::Error => {} } - if let Some(fallback) = &options.fallback { - font_families.extend_from_slice(fallback); - } - Ok(FontCssPropertiesVc::cell(FontCssProperties { - font_family: StringVc::cell( - font_families - .iter() - .map(|f| format!("'{}'", f)) - .collect::>() - .join(", "), - ), - weight: OptionU16Vc::cell(match &options.weights { + font_family: StringVc::cell(font_families.join(", ")), + weight: OptionStringVc::cell(match &options.weights { FontWeights::Variable => None, - FontWeights::Fixed(weights) => weights.first().cloned(), + FontWeights::Fixed(weights) => weights.first().map(|w| w.to_string()), }), style: OptionStringVc::cell(options.styles.first().cloned()), variable: OptionStringVc::cell(options.variable.clone()), @@ -403,7 +363,7 @@ async fn font_options_from_query_map( bail!("Expected one entry"); }; - self::options::options_from_request(&parse_json_with_source_context(json)?, &*font_data.await?) + options_from_request(&parse_json_with_source_context(json)?, &*font_data.await?) .map(|o| NextFontGoogleOptionsVc::new(Value::new(o))) } diff --git a/packages/next-swc/crates/next-core/src/next_font_google/options.rs b/packages/next-swc/crates/next-core/src/next_font/google/options.rs similarity index 96% rename from packages/next-swc/crates/next-core/src/next_font_google/options.rs rename to packages/next-swc/crates/next-core/src/next_font/google/options.rs index 76b564fbb143bc..3730ce559c2322 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/options.rs +++ b/packages/next-swc/crates/next-core/src/next_font/google/options.rs @@ -1,17 +1,17 @@ use anyhow::{anyhow, Context, Result}; use indexmap::{indexset, IndexMap, IndexSet}; use serde::{Deserialize, Serialize}; -use turbo_tasks::{trace::TraceRawVcs, Value}; +use turbo_tasks::{primitives::StringVc, trace::TraceRawVcs, Value}; use super::request::{NextFontRequest, OneOrManyStrings}; const ALLOWED_DISPLAY_VALUES: &[&str] = &["auto", "block", "swap", "fallback", "optional"]; -pub(crate) type FontData = IndexMap; +pub(super) type FontData = IndexMap; #[turbo_tasks::value(serialization = "auto_for_input")] #[derive(Clone, Debug, PartialOrd, Ord, Hash)] -pub(crate) struct NextFontGoogleOptions { +pub(super) struct NextFontGoogleOptions { /// Name of the requested font from Google. Contains literal spaces. pub font_family: String, pub weights: FontWeights, @@ -21,6 +21,8 @@ pub(crate) struct NextFontGoogleOptions { pub selected_variable_axes: Option>, pub fallback: Option>, pub adjust_font_fallback: bool, + /// An optional name for a css custom property (css variable) that applies + /// the font family when used. pub variable: Option, pub subsets: Option>, } @@ -31,18 +33,23 @@ impl NextFontGoogleOptionsVc { pub fn new(options: Value) -> NextFontGoogleOptionsVc { Self::cell(options.into_value()) } + + #[turbo_tasks::function] + pub async fn font_family(self) -> Result { + Ok(StringVc::cell((*self.await?.font_family).to_owned())) + } } #[derive( Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, TraceRawVcs, )] -pub(crate) enum FontWeights { +pub(super) enum FontWeights { Variable, Fixed(Vec), } #[derive(Debug, PartialEq, Eq, Deserialize, Serialize, TraceRawVcs)] -pub(crate) struct FontDataEntry { +pub(super) struct FontDataEntry { pub weights: Vec, pub styles: Vec, pub axes: Option>, @@ -50,7 +57,7 @@ pub(crate) struct FontDataEntry { #[derive(Debug, PartialEq, Deserialize, Serialize, TraceRawVcs)] #[serde(rename_all = "camelCase")] -pub(crate) struct Axis { +pub(super) struct Axis { pub tag: String, pub min: f64, pub max: f64, @@ -61,7 +68,7 @@ impl Eq for Axis {} // Transforms the request fields to a struct suitable for making requests to // Google Fonts. Similar to next/font/google's validateData: // https://github.com/vercel/next.js/blob/28454c6ddbc310419467e5415aee26e48d079b46/packages/font/src/google/utils.ts#L22 -pub(crate) fn options_from_request( +pub(super) fn options_from_request( request: &NextFontRequest, data: &IndexMap, ) -> Result { @@ -194,7 +201,7 @@ mod tests { use turbo_tasks_fs::json::parse_json_with_source_context; use super::{options_from_request, FontDataEntry, NextFontGoogleOptions}; - use crate::next_font_google::{options::FontWeights, request::NextFontRequest}; + use crate::next_font::google::{options::FontWeights, request::NextFontRequest}; #[test] fn test_errors_on_unknown_font() -> Result<()> { diff --git a/packages/next-swc/crates/next-core/src/next_font_google/request.rs b/packages/next-swc/crates/next-core/src/next_font/google/request.rs similarity index 86% rename from packages/next-swc/crates/next-core/src/next_font_google/request.rs rename to packages/next-swc/crates/next-core/src/next_font/google/request.rs index 71d5027d3abae0..fc7302fc2cd45a 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/request.rs +++ b/packages/next-swc/crates/next-core/src/next_font/google/request.rs @@ -5,15 +5,13 @@ use serde::Deserialize; /// `next/font/google/target.css?{"path": "index.js", "import": "Inter"...` #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct NextFontRequest { - pub path: String, +pub(super) struct NextFontRequest { pub import: String, pub arguments: Vec, - pub variable_name: String, } #[derive(Debug, Deserialize)] -pub struct NextFontRequestArguments { +pub(super) struct NextFontRequestArguments { pub weight: Option, pub subsets: Option>, pub style: Option, @@ -29,7 +27,7 @@ pub struct NextFontRequestArguments { #[derive(Debug, Deserialize)] #[serde(untagged)] -pub enum OneOrManyStrings { +pub(super) enum OneOrManyStrings { One(String), Many(Vec), } diff --git a/packages/next-swc/crates/next-core/src/next_font/google/stylesheet.rs b/packages/next-swc/crates/next-core/src/next_font/google/stylesheet.rs new file mode 100644 index 00000000000000..c66b34ce81010a --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font/google/stylesheet.rs @@ -0,0 +1,65 @@ +use anyhow::Result; +use indoc::formatdoc; +use turbo_tasks::primitives::{OptionStringVc, StringVc}; + +use super::FontCssPropertiesVc; +use crate::next_font::{font_fallback::FontFallbackVc, stylesheet::build_fallback_definition}; + +#[turbo_tasks::function] +pub(super) async fn build_stylesheet( + base_stylesheet: OptionStringVc, + font_css_properties: FontCssPropertiesVc, + font_fallback: FontFallbackVc, +) -> Result { + let base_stylesheet = &*base_stylesheet.await?; + let mut stylesheet = base_stylesheet + .as_ref() + .map_or_else(|| "".to_owned(), |s| s.to_owned()); + if let Some(definition) = &*build_fallback_definition(font_fallback).await? { + stylesheet.push_str(definition); + } + stylesheet.push_str(&build_font_class_rules(font_css_properties).await?); + Ok(StringVc::cell(stylesheet)) +} + +#[turbo_tasks::function] +async fn build_font_class_rules(properties: FontCssPropertiesVc) -> Result { + let properties = &*properties.await?; + let font_family = &*properties.font_family.await?; + + let mut result = formatdoc!( + r#" + .className {{ + font-family: {}; + {}{} + }} + "#, + font_family, + properties + .weight + .await? + .as_ref() + .map(|w| format!("font-weight: {};\n", w)) + .unwrap_or_else(|| "".to_owned()), + properties + .style + .await? + .as_ref() + .map(|s| format!("font-style: {};\n", s)) + .unwrap_or_else(|| "".to_owned()), + ); + + if let Some(variable) = &*properties.variable.await? { + result.push_str(&formatdoc!( + r#" + .variable {{ + {}: {}; + }} + "#, + variable, + font_family, + )) + } + + Ok(StringVc::cell(result)) +} diff --git a/packages/next-swc/crates/next-core/src/next_font_google/util.rs b/packages/next-swc/crates/next-core/src/next_font/google/util.rs similarity index 90% rename from packages/next-swc/crates/next-core/src/next_font_google/util.rs rename to packages/next-swc/crates/next-core/src/next_font/google/util.rs index d12037f9e30305..9eaf277067f18e 100644 --- a/packages/next-swc/crates/next-core/src/next_font_google/util.rs +++ b/packages/next-swc/crates/next-core/src/next_font/google/util.rs @@ -2,54 +2,24 @@ use std::cmp::Ordering; use anyhow::{anyhow, bail, Context, Result}; use indexmap::{indexset, IndexSet}; -use turbo_tasks::primitives::{StringVc, U32Vc}; -use super::options::{FontData, FontWeights, NextFontGoogleOptionsVc}; +use super::options::{FontData, FontWeights}; #[derive(Debug, PartialEq)] -pub(crate) struct FontAxes { - pub(crate) wght: IndexSet, - pub(crate) ital: IndexSet, - pub(crate) variable_axes: Option>, +pub(super) struct FontAxes { + pub(super) wght: IndexSet, + pub(super) ital: IndexSet, + pub(super) variable_axes: Option>, } #[derive(Debug, PartialEq, Eq, Hash)] -pub(crate) enum FontItal { +pub(super) enum FontStyle { Italic, Normal, } -#[turbo_tasks::value(shared)] -pub(crate) enum FontFamilyType { - WebFont, - Fallback, -} - -#[turbo_tasks::function] -pub(crate) async fn get_scoped_font_family( - ty: FontFamilyTypeVc, - options: NextFontGoogleOptionsVc, - request_hash: U32Vc, -) -> Result { - let options = options.await?; - let hash = { - let mut hash = format!("{:x?}", request_hash.await?); - hash.truncate(6); - hash - }; - - let font_family_base = options.font_family.replace(' ', "_"); - let ty = &*ty.await?; - let font_family = match ty { - FontFamilyType::WebFont => font_family_base, - FontFamilyType::Fallback => format!("{}_Fallback", font_family_base), - }; - - Ok(StringVc::cell(format!("__{}_{}", font_family, hash))) -} - // Derived from https://github.com/vercel/next.js/blob/9e098da0915a2a4581bebe2270953a1216be1ba4/packages/font/src/google/utils.ts#L232 -pub(crate) fn get_font_axes( +pub(super) fn get_font_axes( font_data: &FontData, font_family: &str, weights: &FontWeights, @@ -66,10 +36,10 @@ pub(crate) fn get_font_axes( let has_normal = styles.contains(&"normal".to_owned()); let mut set = IndexSet::new(); if has_normal { - set.insert(FontItal::Normal); + set.insert(FontStyle::Normal); } if has_italic { - set.insert(FontItal::Italic); + set.insert(FontStyle::Italic); } set }; @@ -134,7 +104,7 @@ pub(crate) fn get_font_axes( } // Derived from https://github.com/vercel/next.js/blob/9e098da0915a2a4581bebe2270953a1216be1ba4/packages/font/src/google/utils.ts#L128 -pub(crate) fn get_stylesheet_url( +pub(super) fn get_stylesheet_url( root_url: &str, font_family: &str, axes: &FontAxes, @@ -170,12 +140,12 @@ pub(crate) fn get_stylesheet_url( // If Normal is the only requested variant, it's safe to omit the ital axis // entirely. Otherwise, include all variants. - if matches!(ital, FontItal::Italic) || axes.ital.len() > 1 { + if matches!(ital, FontStyle::Italic) || axes.ital.len() > 1 { variant.push(( "ital", match ital { - FontItal::Normal => "0", - FontItal::Italic => "1", + FontStyle::Normal => "0", + FontStyle::Italic => "1", }, )); } @@ -264,9 +234,9 @@ mod tests { use turbo_tasks_fs::json::parse_json_with_source_context; use super::get_font_axes; - use crate::next_font_google::{ + use crate::next_font::google::{ options::{FontData, FontWeights}, - util::{get_stylesheet_url, FontAxes, FontItal}, + util::{get_stylesheet_url, FontAxes, FontStyle}, GOOGLE_FONTS_STYLESHEET_URL, }; @@ -442,7 +412,7 @@ mod tests { "Roboto Mono", &FontAxes { wght: indexset! {"500".to_owned()}, - ital: indexset! {FontItal::Normal}, + ital: indexset! {FontStyle::Normal}, variable_axes: None }, "optional" @@ -461,7 +431,7 @@ mod tests { "Roboto Serif", &FontAxes { wght: indexset! {"500".to_owned()}, - ital: indexset! {FontItal::Normal}, + ital: indexset! {FontStyle::Normal}, variable_axes: Some(vec![ ("GRAD".to_owned(), "-50..100".to_owned()), ("opsz".to_owned(), "8..144".to_owned()), @@ -484,7 +454,7 @@ mod tests { "Roboto Serif", &FontAxes { wght: indexset! {"500".to_owned(), "300".to_owned()}, - ital: indexset! {FontItal::Normal, FontItal::Italic}, + ital: indexset! {FontStyle::Normal, FontStyle::Italic}, variable_axes: Some(vec![ ("GRAD".to_owned(), "-50..100".to_owned()), ("opsz".to_owned(), "8..144".to_owned()), diff --git a/packages/next-swc/crates/next-core/src/next_font_google/issue.rs b/packages/next-swc/crates/next-core/src/next_font/issue.rs similarity index 100% rename from packages/next-swc/crates/next-core/src/next_font_google/issue.rs rename to packages/next-swc/crates/next-core/src/next_font/issue.rs diff --git a/packages/next-swc/crates/next-core/src/next_font/mod.rs b/packages/next-swc/crates/next-core/src/next_font/mod.rs new file mode 100644 index 00000000000000..e82dbe1ff81c2f --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font/mod.rs @@ -0,0 +1,5 @@ +pub(crate) mod font_fallback; +pub(crate) mod google; +pub(crate) mod issue; +pub(crate) mod stylesheet; +pub(crate) mod util; diff --git a/packages/next-swc/crates/next-core/src/next_font/stylesheet.rs b/packages/next-swc/crates/next-core/src/next_font/stylesheet.rs new file mode 100644 index 00000000000000..b6ea6e8d3f029e --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font/stylesheet.rs @@ -0,0 +1,50 @@ +use anyhow::Result; +use indoc::formatdoc; +use turbo_tasks::primitives::OptionStringVc; + +use super::font_fallback::{FontFallback, FontFallbackVc}; + +/// Builds `@font-face` stylesheet definition for a given FontFallback +#[turbo_tasks::function] +pub(crate) async fn build_fallback_definition(fallback: FontFallbackVc) -> Result { + Ok(OptionStringVc::cell(match *fallback.await? { + FontFallback::Error => None, + FontFallback::Manual(_) => None, + FontFallback::Automatic(fallback) => { + let fallback = fallback.await?; + + let override_properties = match &fallback.adjustment { + None => "".to_owned(), + Some(adjustment) => formatdoc!( + r#" + ascent-override: {}%; + descent-override: {}%; + line-gap-override: {}%; + size-adjust: {}%; + "#, + format_fixed_percentage(adjustment.ascent), + format_fixed_percentage(adjustment.descent.abs()), + format_fixed_percentage(adjustment.line_gap), + format_fixed_percentage(adjustment.size_adjust) + ), + }; + + Some(formatdoc!( + r#" + @font-face {{ + font-family: '{}'; + src: local("{}"); + {} + }} + "#, + fallback.scoped_font_family.await?, + fallback.local_font_family.await?, + override_properties + )) + } + })) +} + +fn format_fixed_percentage(value: f64) -> String { + format!("{:.2}", value * 100.0) +} diff --git a/packages/next-swc/crates/next-core/src/next_font/util.rs b/packages/next-swc/crates/next-core/src/next_font/util.rs new file mode 100644 index 00000000000000..86cbf71e7b53de --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_font/util.rs @@ -0,0 +1,65 @@ +use anyhow::{Context, Result}; +use turbo_tasks::primitives::{OptionStringVc, StringVc, U32Vc}; +use turbo_tasks_hash::hash_xxh3_hash64; +use turbopack_core::resolve::pattern::QueryMapVc; + +#[turbo_tasks::value(shared)] +pub(crate) struct FontCssProperties { + pub font_family: StringVc, + pub weight: OptionStringVc, + pub style: OptionStringVc, + pub variable: OptionStringVc, +} + +#[turbo_tasks::function] +pub(crate) async fn get_request_hash(query_vc: QueryMapVc) -> Result { + let query = &*query_vc.await?; + let query = query.as_ref().context("Query map must be present")?; + let mut to_hash = vec![]; + for (k, v) in query { + to_hash.push(k); + to_hash.push(v); + } + + Ok(U32Vc::cell( + // Truncate the has to u32. These hashes are ultimately displayed as 8-character + // hexadecimal values. + hash_xxh3_hash64(to_hash) as u32, + )) +} + +#[turbo_tasks::value(shared)] +pub(crate) enum FontFamilyType { + WebFont, + Fallback, +} + +#[turbo_tasks::function] +pub(crate) async fn get_scoped_font_family( + ty: FontFamilyTypeVc, + font_family_name: StringVc, + request_hash: U32Vc, +) -> Result { + let hash = { + let mut hash = format!("{:x?}", request_hash.await?); + hash.truncate(6); + hash + }; + + let font_family_base = font_family_name.await?.replace(' ', "_"); + let font_family_name = match &*ty.await? { + FontFamilyType::WebFont => font_family_base, + FontFamilyType::Fallback => format!("{}_Fallback", font_family_base), + }; + + Ok(StringVc::cell(format!("__{}_{}", font_family_name, hash))) +} + +#[turbo_tasks::function] +pub async fn get_request_id(font_family: StringVc, request_hash: U32Vc) -> Result { + Ok(StringVc::cell(format!( + "{}_{:x?}", + font_family.await?.to_lowercase().replace(' ', "_"), + request_hash.await? + ))) +} diff --git a/packages/next-swc/crates/next-core/src/next_font_google/stylesheet.rs b/packages/next-swc/crates/next-core/src/next_font_google/stylesheet.rs deleted file mode 100644 index 3c0d4f3b55b0ae..00000000000000 --- a/packages/next-swc/crates/next-core/src/next_font_google/stylesheet.rs +++ /dev/null @@ -1,108 +0,0 @@ -use anyhow::Result; -use indoc::formatdoc; -use turbo_tasks::primitives::{OptionStringVc, StringVc}; - -use super::{ - font_fallback::{FontFallback, FontFallbackVc}, - FontCssProperties, FontCssPropertiesVc, -}; - -#[turbo_tasks::function] -pub(crate) async fn build_stylesheet( - base_stylesheet: OptionStringVc, - font_css_properties: FontCssPropertiesVc, - font_fallback: FontFallbackVc, -) -> Result { - let base_stylesheet = &*base_stylesheet.await?; - let mut stylesheet = base_stylesheet - .as_ref() - .map_or_else(|| "".to_owned(), |s| s.to_owned()); - if let Some(definition) = build_fallback_definition(&*font_fallback.await?).await? { - stylesheet.push_str(&definition); - } - stylesheet.push_str(&build_font_class_rules(&*font_css_properties.await?).await?); - Ok(StringVc::cell(stylesheet)) -} - -async fn build_fallback_definition(fallback: &FontFallback) -> Result> { - match fallback { - FontFallback::Error => Ok(None), - FontFallback::Manual(_) => Ok(None), - FontFallback::Automatic(fallback) => { - let fallback = fallback.await?; - - let override_properties = match &fallback.adjustment { - None => "".to_owned(), - Some(adjustment) => formatdoc!( - r#" - ascent-override: {}%; - descent-override: {}%; - line-gap-override: {}%; - size-adjust: {}%; - "#, - format_fixed_percentage(adjustment.ascent), - format_fixed_percentage(adjustment.descent.abs()), - format_fixed_percentage(adjustment.line_gap), - format_fixed_percentage(adjustment.size_adjust) - ), - }; - - Ok(Some(formatdoc!( - r#" - @font-face {{ - font-family: '{}'; - src: local("{}"); - {} - }} - "#, - fallback.scoped_font_family.await?, - fallback.local_font_family.await?, - override_properties - ))) - } - } -} - -async fn build_font_class_rules(properties: &FontCssProperties) -> Result { - let font_family = &*properties.font_family.await?; - - let mut result = formatdoc!( - r#" - .className {{ - font-family: {}; - {}{} - }} - "#, - font_family, - properties - .weight - .await? - .map(|w| format!("font-weight: {};\n", w)) - .unwrap_or_else(|| "".to_owned()), - properties - .style - .await? - .as_ref() - .map(|s| format!("font-style: {};\n", s)) - .unwrap_or_else(|| "".to_owned()), - ); - - if let Some(variable) = &*properties.variable.await? { - result.push_str(&formatdoc!( - r#" - .variable {{ - {}: {}; - }} - "#, - variable, - font_family, - )) - // - } - - Ok(result) -} - -fn format_fixed_percentage(value: f64) -> String { - format!("{:.2}", value * 100.0) -} diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index ead0cf95574f55..34fc8d483e18f2 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -22,7 +22,7 @@ use crate::{ embed_js::{next_js_fs, VIRTUAL_PACKAGE_NAME}, next_client::context::ClientContextType, next_config::NextConfigVc, - next_font_google::{NextFontGoogleCssModuleReplacerVc, NextFontGoogleReplacerVc}, + next_font::google::{NextFontGoogleCssModuleReplacerVc, NextFontGoogleReplacerVc}, next_server::context::ServerContextType, }; From 46201e16448f3d8063b0c865dfa916a900742764 Mon Sep 17 00:00:00 2001 From: Jan Kaifer Date: Mon, 20 Mar 2023 18:17:23 +0100 Subject: [PATCH 567/672] Improve OTEL spans naming (#47209) Adds bunch of default attributes and span names as discussed in https://github.com/vercel/next.js/pull/47066 Also discovered a few issues with our test setup. It's actually quite handy to use jest snapshots for this, thanks for the tip @feedthejim Currently we have following spans: - root span with name `GET /app/rsc-fetch` (both API calls and page requests) - `SERVER` span - attributes: - `"http.method": "GET"` - `"http.status_code": 200` - `"http.target": "/app/rsc-fetch"` - `"next.span_name": "GET /app/rsc-fetch"` - `"next.span_type": "BaseServer.handleRequest"` - fetch span `fetch GET https://vercel.com/` - `CLIENT` span - attributes: - `"http.method": "GET"` - `"http.url": "https://vercel.com/"` - `"net.peer.name": "vercel.com"` - `"next.span_name": "fetch GET https://vercel.com/"` - `"next.span_type": "AppRender.fetch"` - rendering of page `rendering /app/rsc-fetch` - attributes: - `"next.pathname": "/app/rsc-fetch"` - `"next.span_name": "rendering /app/rsc-fetch"` - `"next.span_type": "BaseServer.renderToResponse"` - finding the right page component `resolving route /app/rsc-fetch/page` - attributes - `"next.route": "/app/rsc-fetch/page"` - `"next.span_name": "resolving route /app/rsc-fetch/page"` - `"next.span_type": "NextNodeServer.findPageComponents"` - getServerSideProps `getServerSideProps /pages/getServerSideProps` - attributes - `"next.span_name": "getServerSideProps /pages/getServerSideProps"` - `"next.span_type": "Render.getServerSideProps"` fix NEXT-829 ([link](https://linear.app/vercel/issue/NEXT-829)) --- packages/next/src/server/base-server.ts | 32 +- packages/next/src/server/lib/patch-fetch.ts | 522 +++++++++--------- .../next/src/server/lib/trace/constants.ts | 6 +- packages/next/src/server/lib/trace/tracer.ts | 81 +-- packages/next/src/server/next-server.ts | 11 +- packages/next/src/server/render.tsx | 39 +- .../opentelemetry/app/app/rsc-fetch/page.tsx | 2 +- test/e2e/opentelemetry/constants.ts | 22 +- test/e2e/opentelemetry/opentelemetry.test.ts | 182 ++++-- .../pages/pages/getServerSideProps.tsx | 2 +- 10 files changed, 519 insertions(+), 380 deletions(-) diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 21518094e12988..0854483bd9699d 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -90,7 +90,7 @@ import { AppRouteRouteMatcherProvider } from './future/route-matcher-providers/a import { PagesAPIRouteMatcherProvider } from './future/route-matcher-providers/pages-api-route-matcher-provider' import { PagesRouteMatcherProvider } from './future/route-matcher-providers/pages-route-matcher-provider' import { ServerManifestLoader } from './future/route-matcher-providers/helpers/manifest-loaders/server-manifest-loader' -import { getTracer } from './lib/trace/tracer' +import { getTracer, SpanKind } from './lib/trace/tracer' import { BaseServerSpan } from './lib/trace/constants' import { sendResponse } from './future/route-handlers/app-route-route-handler' import { I18NProvider } from './future/helpers/i18n-provider' @@ -520,7 +520,20 @@ export default abstract class Server { ): Promise { return getTracer().trace( BaseServerSpan.handleRequest, - async () => await this.handleRequestImpl(req, res, parsedUrl) + { + spanName: [req.method, req.url].join(' '), + kind: SpanKind.SERVER, + attributes: { + 'http.method': req.method, + 'http.target': req.url, + }, + }, + async (span) => + await this.handleRequestImpl(req, res, parsedUrl).finally(() => + span?.setAttributes({ + 'http.status_code': res.statusCode, + }) + ) ) } @@ -1907,9 +1920,18 @@ export default abstract class Server { private async renderToResponse( ctx: RequestContext ): Promise { - return getTracer().trace(BaseServerSpan.renderToResponse, async () => { - return this.renderToResponseImpl(ctx) - }) + return getTracer().trace( + BaseServerSpan.renderToResponse, + { + spanName: `rendering page`, + attributes: { + 'next.pathname': ctx.pathname, + }, + }, + async () => { + return this.renderToResponseImpl(ctx) + } + ) } private async renderToResponseImpl( diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index 5628636afb78cb..b4c01b8c66ba9f 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -21,279 +21,273 @@ export function patchFetch({ // @ts-expect-error - we're patching fetch // eslint-disable-next-line no-native-reassign - fetch = getTracer().wrap( - AppRenderSpan.fetch, - { - kind: SpanKind.CLIENT, - }, - async (input: RequestInfo | URL, init: RequestInit | undefined) => { - const staticGenerationStore = staticGenerationAsyncStorage.getStore() - const isRequestInput = - input && - typeof input === 'object' && - typeof (input as Request).method === 'string' - - const getRequestMeta = (field: string) => { - let value = isRequestInput ? (input as any)[field] : null - return value || (init as any)?.[field] - } + fetch = async (input: RequestInfo | URL, init: RequestInit | undefined) => { + let url + try { + url = new URL(input instanceof Request ? input.url : input) + url.username = '' + url.password = '' + } catch { + // Error caused by malformed URL should be handled by native fetch + url = undefined + } - // If the staticGenerationStore is not available, we can't do any - // special treatment of fetch, therefore fallback to the original - // fetch implementation. - if (!staticGenerationStore || (init?.next as any)?.internal) { - return originFetch(input, init) - } + const method = (init?.method || 'GET').toUpperCase() + + return await getTracer().trace( + AppRenderSpan.fetch, + { + kind: SpanKind.CLIENT, + spanName: ['fetch', method, url?.toString() ?? input.toString()] + .filter(Boolean) + .join(' '), + attributes: { + 'http.url': url?.toString(), + 'http.method': method, + 'net.peer.name': url?.hostname, + 'net.peer.port': url?.port || undefined, + }, + }, + async () => { + const staticGenerationStore = staticGenerationAsyncStorage.getStore() + const isRequestInput = + input && + typeof input === 'object' && + typeof (input as Request).method === 'string' + + const getRequestMeta = (field: string) => { + let value = isRequestInput ? (input as any)[field] : null + return value || (init as any)?.[field] + } - let revalidate: number | undefined | false = undefined - // RequestInit doesn't keep extra fields e.g. next so it's - // only available if init is used separate - let curRevalidate = - typeof init?.next?.revalidate !== 'undefined' - ? init?.next?.revalidate - : isRequestInput - ? (input as any).next?.revalidate - : undefined + // If the staticGenerationStore is not available, we can't do any + // special treatment of fetch, therefore fallback to the original + // fetch implementation. + if (!staticGenerationStore || (init?.next as any)?.internal) { + return originFetch(input, init) + } - const _cache = getRequestMeta('cache') + let revalidate: number | undefined | false = undefined + // RequestInit doesn't keep extra fields e.g. next so it's + // only available if init is used separate + let curRevalidate = + typeof init?.next?.revalidate !== 'undefined' + ? init?.next?.revalidate + : isRequestInput + ? (input as any).next?.revalidate + : undefined - if (_cache === 'force-cache') { - curRevalidate = false - } - if (['no-cache', 'no-store'].includes(_cache || '')) { - curRevalidate = 0 - } - if (typeof curRevalidate === 'number') { - revalidate = curRevalidate - } + const _cache = getRequestMeta('cache') - if (curRevalidate === false) { - revalidate = CACHE_ONE_YEAR - } + if (_cache === 'force-cache') { + curRevalidate = false + } + if (['no-cache', 'no-store'].includes(_cache || '')) { + curRevalidate = 0 + } + if (typeof curRevalidate === 'number') { + revalidate = curRevalidate + } - const _headers = getRequestMeta('headers') - const initHeaders: Headers = - typeof _headers?.get === 'function' - ? _headers - : new Headers(_headers || {}) - - const hasUnCacheableHeader = - initHeaders.get('authorization') || initHeaders.get('cookie') - - const isUnCacheableMethod = !['get', 'head'].includes( - getRequestMeta('method')?.toLowerCase() || 'get' - ) - - // if there are authorized headers or a POST method and - // dynamic data usage was present above the tree we bail - // e.g. if cookies() is used before an authed/POST fetch - const autoNoCache = - (hasUnCacheableHeader || isUnCacheableMethod) && - staticGenerationStore.revalidate === 0 - - if (typeof revalidate === 'undefined') { - if (autoNoCache) { - revalidate = 0 - } else { - revalidate = - typeof staticGenerationStore.revalidate === 'boolean' || - typeof staticGenerationStore.revalidate === 'undefined' - ? CACHE_ONE_YEAR - : staticGenerationStore.revalidate + if (curRevalidate === false) { + revalidate = CACHE_ONE_YEAR } - } - if ( - // we don't consider autoNoCache to switch to dynamic during - // revalidate although if it occurs during build we do - !autoNoCache && - (typeof staticGenerationStore.revalidate === 'undefined' || - (typeof revalidate === 'number' && - revalidate < staticGenerationStore.revalidate)) - ) { - staticGenerationStore.revalidate = revalidate - } + const _headers = getRequestMeta('headers') + const initHeaders: Headers = + typeof _headers?.get === 'function' + ? _headers + : new Headers(_headers || {}) - let cacheKey: string | undefined - if ( - staticGenerationStore.incrementalCache && - typeof revalidate === 'number' && - revalidate > 0 - ) { - try { - cacheKey = await staticGenerationStore.incrementalCache.fetchCacheKey( - isRequestInput ? (input as Request).url : input.toString(), - isRequestInput ? (input as RequestInit) : init - ) - } catch (err) { - console.error(`Failed to generate cache key for`, input) - } - } - const requestInputFields = [ - 'cache', - 'credentials', - 'headers', - 'integrity', - 'keepalive', - 'method', - 'mode', - 'redirect', - 'referrer', - 'referrerPolicy', - 'signal', - 'window', - 'duplex', - ] - - if (isRequestInput) { - const reqInput: Request = input as any - const reqOptions: RequestInit = { - body: (reqInput as any)._ogBody || reqInput.body, + const hasUnCacheableHeader = + initHeaders.get('authorization') || initHeaders.get('cookie') + + const isUnCacheableMethod = !['get', 'head'].includes( + getRequestMeta('method')?.toLowerCase() || 'get' + ) + + // if there are authorized headers or a POST method and + // dynamic data usage was present above the tree we bail + // e.g. if cookies() is used before an authed/POST fetch + const autoNoCache = + (hasUnCacheableHeader || isUnCacheableMethod) && + staticGenerationStore.revalidate === 0 + + if (typeof revalidate === 'undefined') { + if (autoNoCache) { + revalidate = 0 + } else { + revalidate = + typeof staticGenerationStore.revalidate === 'boolean' || + typeof staticGenerationStore.revalidate === 'undefined' + ? CACHE_ONE_YEAR + : staticGenerationStore.revalidate + } } - for (const field of requestInputFields) { - // @ts-expect-error custom fields - reqOptions[field] = reqInput[field] + if ( + // we don't consider autoNoCache to switch to dynamic during + // revalidate although if it occurs during build we do + !autoNoCache && + (typeof staticGenerationStore.revalidate === 'undefined' || + (typeof revalidate === 'number' && + revalidate < staticGenerationStore.revalidate)) + ) { + staticGenerationStore.revalidate = revalidate } - input = new Request(reqInput.url, reqOptions) - } else if (init) { - const initialInit = init - init = { - body: (init as any)._ogBody || init.body, + + let cacheKey: string | undefined + if ( + staticGenerationStore.incrementalCache && + typeof revalidate === 'number' && + revalidate > 0 + ) { + try { + cacheKey = + await staticGenerationStore.incrementalCache.fetchCacheKey( + isRequestInput ? (input as Request).url : input.toString(), + isRequestInput ? (input as RequestInit) : init + ) + } catch (err) { + console.error(`Failed to generate cache key for`, input) + } } - for (const field of requestInputFields) { - // @ts-expect-error custom fields - init[field] = initialInit[field] + const requestInputFields = [ + 'cache', + 'credentials', + 'headers', + 'integrity', + 'keepalive', + 'method', + 'mode', + 'redirect', + 'referrer', + 'referrerPolicy', + 'signal', + 'window', + 'duplex', + ] + + if (isRequestInput) { + const reqInput: Request = input as any + const reqOptions: RequestInit = { + body: (reqInput as any)._ogBody || reqInput.body, + } + + for (const field of requestInputFields) { + // @ts-expect-error custom fields + reqOptions[field] = reqInput[field] + } + input = new Request(reqInput.url, reqOptions) + } else if (init) { + const initialInit = init + init = { + body: (init as any)._ogBody || init.body, + } + for (const field of requestInputFields) { + // @ts-expect-error custom fields + init[field] = initialInit[field] + } } - } - const doOriginalFetch = async () => { - return originFetch(input, init).then(async (res) => { - if ( - staticGenerationStore.incrementalCache && - cacheKey && - typeof revalidate === 'number' && - revalidate > 0 - ) { - let base64Body = '' - const resBlob = await res.blob() - const arrayBuffer = await resBlob.arrayBuffer() - - if (process.env.NEXT_RUNTIME === 'edge') { - const { encode } = - require('../../shared/lib/bloom-filter/base64-arraybuffer') as typeof import('../../shared/lib/bloom-filter/base64-arraybuffer') - base64Body = encode(arrayBuffer) - } else { - base64Body = Buffer.from(arrayBuffer).toString('base64') - } + const doOriginalFetch = async () => { + return originFetch(input, init).then(async (res) => { + if ( + staticGenerationStore.incrementalCache && + cacheKey && + typeof revalidate === 'number' && + revalidate > 0 + ) { + let base64Body = '' + const resBlob = await res.blob() + const arrayBuffer = await resBlob.arrayBuffer() + + if (process.env.NEXT_RUNTIME === 'edge') { + const { encode } = + require('../../shared/lib/bloom-filter/base64-arraybuffer') as typeof import('../../shared/lib/bloom-filter/base64-arraybuffer') + base64Body = encode(arrayBuffer) + } else { + base64Body = Buffer.from(arrayBuffer).toString('base64') + } - try { - await staticGenerationStore.incrementalCache.set( - cacheKey, - { - kind: 'FETCH', - data: { - headers: Object.fromEntries(res.headers.entries()), - body: base64Body, - status: res.status, + try { + await staticGenerationStore.incrementalCache.set( + cacheKey, + { + kind: 'FETCH', + data: { + headers: Object.fromEntries(res.headers.entries()), + body: base64Body, + status: res.status, + }, + revalidate, }, revalidate, - }, - revalidate, - true - ) - } catch (err) { - console.warn(`Failed to set fetch cache`, input, err) - } + true + ) + } catch (err) { + console.warn(`Failed to set fetch cache`, input, err) + } - return new Response(resBlob, { - headers: res.headers, - status: res.status, - }) - } - return res - }) - } + return new Response(resBlob, { + headers: res.headers, + status: res.status, + }) + } + return res + }) + } - if (cacheKey && staticGenerationStore?.incrementalCache) { - const entry = await staticGenerationStore.incrementalCache.get( - cacheKey, - true, - revalidate - ) + if (cacheKey && staticGenerationStore?.incrementalCache) { + const entry = await staticGenerationStore.incrementalCache.get( + cacheKey, + true + ) - if (entry?.value && entry.value.kind === 'FETCH') { - // when stale and is revalidating we wait for fresh data - // so the revalidated entry has the updated data - if (!staticGenerationStore.isRevalidate || !entry.isStale) { - if (entry.isStale) { - if (!staticGenerationStore.pendingRevalidates) { - staticGenerationStore.pendingRevalidates = [] + if (entry?.value && entry.value.kind === 'FETCH') { + // when stale and is revalidating we wait for fresh data + // so the revalidated entry has the updated data + if (!staticGenerationStore.isRevalidate || !entry.isStale) { + if (entry.isStale) { + if (!staticGenerationStore.pendingRevalidates) { + staticGenerationStore.pendingRevalidates = [] + } + staticGenerationStore.pendingRevalidates.push( + doOriginalFetch().catch(console.error) + ) } - staticGenerationStore.pendingRevalidates.push( - doOriginalFetch().catch(console.error) - ) - } - const resData = entry.value.data - let decodedBody: ArrayBuffer + const resData = entry.value.data + let decodedBody: ArrayBuffer - if (process.env.NEXT_RUNTIME === 'edge') { - const { decode } = - require('../../shared/lib/bloom-filter/base64-arraybuffer') as typeof import('../../shared/lib/bloom-filter/base64-arraybuffer') - decodedBody = decode(resData.body) - } else { - decodedBody = Buffer.from(resData.body, 'base64').subarray() - } + if (process.env.NEXT_RUNTIME === 'edge') { + const { decode } = + require('../../shared/lib/bloom-filter/base64-arraybuffer') as typeof import('../../shared/lib/bloom-filter/base64-arraybuffer') + decodedBody = decode(resData.body) + } else { + decodedBody = Buffer.from(resData.body, 'base64').subarray() + } - return new Response(decodedBody, { - headers: resData.headers, - status: resData.status, - }) + return new Response(decodedBody, { + headers: resData.headers, + status: resData.status, + }) + } } } - } - if (staticGenerationStore.isStaticGeneration) { - if (init && typeof init === 'object') { - const cache = init.cache - // Delete `cache` property as Cloudflare Workers will throw an error - if (isEdgeRuntime) { - delete init.cache - } - if (cache === 'no-store') { - staticGenerationStore.revalidate = 0 - // TODO: ensure this error isn't logged to the user - // seems it's slipping through currently - const dynamicUsageReason = `no-store fetch ${input}${ - staticGenerationStore.pathname - ? ` ${staticGenerationStore.pathname}` - : '' - }` - const err = new DynamicServerError(dynamicUsageReason) - staticGenerationStore.dynamicUsageStack = err.stack - staticGenerationStore.dynamicUsageDescription = dynamicUsageReason - - throw err - } - - const hasNextConfig = 'next' in init - const next = init.next || {} - if ( - typeof next.revalidate === 'number' && - (typeof staticGenerationStore.revalidate === 'undefined' || - next.revalidate < staticGenerationStore.revalidate) - ) { - const forceDynamic = staticGenerationStore.forceDynamic - - if (!forceDynamic || next.revalidate !== 0) { - staticGenerationStore.revalidate = next.revalidate + if (staticGenerationStore.isStaticGeneration) { + if (init && typeof init === 'object') { + const cache = init.cache + // Delete `cache` property as Cloudflare Workers will throw an error + if (isEdgeRuntime) { + delete init.cache } - - if (!forceDynamic && next.revalidate === 0) { - const dynamicUsageReason = `revalidate: ${ - next.revalidate - } fetch ${input}${ + if (cache === 'no-store') { + staticGenerationStore.revalidate = 0 + // TODO: ensure this error isn't logged to the user + // seems it's slipping through currently + const dynamicUsageReason = `no-store fetch ${input}${ staticGenerationStore.pathname ? ` ${staticGenerationStore.pathname}` : '' @@ -304,13 +298,43 @@ export function patchFetch({ throw err } + + const hasNextConfig = 'next' in init + const next = init.next || {} + if ( + typeof next.revalidate === 'number' && + (typeof staticGenerationStore.revalidate === 'undefined' || + next.revalidate < staticGenerationStore.revalidate) + ) { + const forceDynamic = staticGenerationStore.forceDynamic + + if (!forceDynamic || next.revalidate !== 0) { + staticGenerationStore.revalidate = next.revalidate + } + + if (!forceDynamic && next.revalidate === 0) { + const dynamicUsageReason = `revalidate: ${ + next.revalidate + } fetch ${input}${ + staticGenerationStore.pathname + ? ` ${staticGenerationStore.pathname}` + : '' + }` + const err = new DynamicServerError(dynamicUsageReason) + staticGenerationStore.dynamicUsageStack = err.stack + staticGenerationStore.dynamicUsageDescription = + dynamicUsageReason + + throw err + } + } + if (hasNextConfig) delete init.next } - if (hasNextConfig) delete init.next } - } - return doOriginalFetch() - } - ) + return doOriginalFetch() + } + ) + } ;(fetch as any).__nextPatched = true } diff --git a/packages/next/src/server/lib/trace/constants.ts b/packages/next/src/server/lib/trace/constants.ts index 7b27fe7fd7ccdb..312a2223f22400 100644 --- a/packages/next/src/server/lib/trace/constants.ts +++ b/packages/next/src/server/lib/trace/constants.ts @@ -88,7 +88,7 @@ enum RouterSpan { executeRoute = 'Router.executeRoute', } -type SpanNames = +type SpanTypes = | `${BaseServerSpan}` | `${LoadComponentsSpan}` | `${NextServerSpan}` @@ -100,7 +100,7 @@ type SpanNames = // This list is used to filter out spans that are not relevant to the user export const NextVanillaSpanAllowlist = [ - NextServerSpan.getRequestHandler, + BaseServerSpan.handleRequest, NextNodeServerSpan.findPageComponents, BaseServerSpan.renderToResponse, RenderSpan.getServerSideProps, @@ -113,7 +113,7 @@ export { NextServerSpan, NextNodeServerSpan, StartServerSpan, - SpanNames, + SpanTypes, RenderSpan, RouterSpan, AppRenderSpan, diff --git a/packages/next/src/server/lib/trace/tracer.ts b/packages/next/src/server/lib/trace/tracer.ts index f3f1a307e3d833..45e8a229b7049d 100644 --- a/packages/next/src/server/lib/trace/tracer.ts +++ b/packages/next/src/server/lib/trace/tracer.ts @@ -1,4 +1,4 @@ -import { NextVanillaSpanAllowlist, SpanNames } from './constants' +import { NextVanillaSpanAllowlist, SpanTypes } from './constants' import type { ContextAPI, Span, SpanOptions, Tracer } from '@opentelemetry/api' @@ -24,13 +24,16 @@ const isPromise = (p: any): p is Promise => { } const closeSpanWithError = (span: Span, error?: Error) => { + if (error) { + span.recordException(error) + } span.setStatus({ code: SpanStatusCode.ERROR, message: error?.message }) span.end() } type TracerSpanOptions = SpanOptions & { parentSpan?: Span - tracerName?: string + spanName?: string } interface NextTracer { @@ -52,22 +55,22 @@ interface NextTracer { * */ trace( - name: SpanNames, - fn: (span: Span, done?: (error?: Error) => any) => Promise + type: SpanTypes, + fn: (span?: Span, done?: (error?: Error) => any) => Promise ): Promise trace( - name: SpanNames, - fn: (span: Span, done?: (error?: Error) => any) => T + type: SpanTypes, + fn: (span?: Span, done?: (error?: Error) => any) => T ): T trace( - name: SpanNames, + type: SpanTypes, options: TracerSpanOptions, - fn: (span: Span, done?: (error?: Error) => any) => Promise + fn: (span?: Span, done?: (error?: Error) => any) => Promise ): Promise trace( - name: SpanNames, + type: SpanTypes, options: TracerSpanOptions, - fn: (span: Span, done?: (error?: Error) => any) => T + fn: (span?: Span, done?: (error?: Error) => any) => T ): T /** @@ -84,14 +87,14 @@ interface NextTracer { * * The function doesn't accept a callback and doesn't return a promise, in * which case the span will finish at the end of the function execution. */ - wrap) => any>(name: SpanNames, fn: T): T + wrap) => any>(type: SpanTypes, fn: T): T wrap) => any>( - name: SpanNames, + type: SpanTypes, options: TracerSpanOptions, fn: T ): T wrap) => any>( - name: SpanNames, + type: SpanTypes, options: (...args: any[]) => TracerSpanOptions, fn: T ): T @@ -104,8 +107,8 @@ interface NextTracer { * context via `tracer.getContext().with`. `trace`, or `wrap` is generally recommended as it gracefully * handles context activation. (ref: https://github.com/open-telemetry/opentelemetry-js/issues/1923) */ - startSpan(name: SpanNames): Span - startSpan(name: SpanNames, options: TracerSpanOptions): Span + startSpan(type: SpanTypes): Span + startSpan(type: SpanTypes, options: TracerSpanOptions): Span /** * Returns currently activated span if current context is in the scope of the span. @@ -135,25 +138,25 @@ class NextTracerImpl implements NextTracer { // Trace, wrap implementation is inspired by datadog trace implementation // (https://datadoghq.dev/dd-trace-js/interfaces/tracer.html#trace). public trace( - name: SpanNames, - fn: (span: Span, done?: (error?: Error) => any) => Promise + type: SpanTypes, + fn: (span?: Span, done?: (error?: Error) => any) => Promise ): Promise public trace( - name: SpanNames, - fn: (span: Span, done?: (error?: Error) => any) => T + type: SpanTypes, + fn: (span?: Span, done?: (error?: Error) => any) => T ): T public trace( - name: SpanNames, + type: SpanTypes, options: TracerSpanOptions, - fn: (span: Span, done?: (error?: Error) => any) => Promise + fn: (span?: Span, done?: (error?: Error) => any) => Promise ): Promise public trace( - name: SpanNames, + type: SpanTypes, options: TracerSpanOptions, - fn: (span: Span, done?: (error?: Error) => any) => T + fn: (span?: Span, done?: (error?: Error) => any) => T ): T public trace(...args: Array) { - const [name, fnOrOptions, fnOrEmpty] = args + const [type, fnOrOptions, fnOrEmpty] = args // coerce options form overload const { @@ -170,30 +173,38 @@ class NextTracerImpl implements NextTracer { } : { fn: fnOrEmpty, - options: fnOrOptions, + options: { ...fnOrOptions }, } if ( - !NextVanillaSpanAllowlist.includes(name) && + !NextVanillaSpanAllowlist.includes(type) && process.env.NEXT_OTEL_VERBOSE !== '1' ) { return fn() } + const spanName = options.spanName ?? type + // Trying to get active scoped span to assign parent. If option specifies parent span manually, will try to use it. const spanContext = this.getSpanContext( options?.parentSpan ?? this.getActiveScopeSpan() ) + options.attributes = { + 'next.span_name': spanName, + 'next.span_type': type, + ...options.attributes, + } + const runWithContext = (actualFn: (span: Span) => T | Promise) => spanContext ? this.getTracerInstance().startActiveSpan( - name, + spanName, options, spanContext, actualFn ) - : this.getTracerInstance().startActiveSpan(name, options, actualFn) + : this.getTracerInstance().startActiveSpan(spanName, options, actualFn) return runWithContext((span: Span) => { try { @@ -220,14 +231,14 @@ class NextTracerImpl implements NextTracer { }) } - public wrap) => any>(name: SpanNames, fn: T): T + public wrap) => any>(type: SpanTypes, fn: T): T public wrap) => any>( - name: SpanNames, + type: SpanTypes, options: TracerSpanOptions, fn: T ): T public wrap) => any>( - name: SpanNames, + type: SpanTypes, options: (...args: any[]) => TracerSpanOptions, fn: T ): T @@ -268,15 +279,15 @@ class NextTracerImpl implements NextTracer { } } - public startSpan(name: SpanNames): Span - public startSpan(name: SpanNames, options: TracerSpanOptions): Span + public startSpan(type: SpanTypes): Span + public startSpan(type: SpanTypes, options: TracerSpanOptions): Span public startSpan(...args: Array): Span { - const [name, options]: [string, TracerSpanOptions | undefined] = args as any + const [type, options]: [string, TracerSpanOptions | undefined] = args as any const spanContext = this.getSpanContext( options?.parentSpan ?? this.getActiveScopeSpan() ) - return this.getTracerInstance().startSpan(name, options, spanContext) + return this.getTracerInstance().startSpan(type, options, spanContext) } private getSpanContext(parentSpan?: Span) { diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 3eb23a86b45e7d..9303499e323548 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -958,8 +958,15 @@ export default class NextNodeServer extends BaseServer { params: Params | null isAppPath: boolean }): Promise { - return getTracer().trace(NextNodeServerSpan.findPageComponents, () => - this.findPageComponentsImpl({ pathname, query, params, isAppPath }) + return getTracer().trace( + NextNodeServerSpan.findPageComponents, + { + spanName: `resolving page into components`, + attributes: { + 'next.route': pathname, + }, + }, + () => this.findPageComponentsImpl({ pathname, query, params, isAppPath }) ) } diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 5b1201df6e2863..4782c7fa9bce71 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -962,22 +962,29 @@ export async function renderToHTML( } try { - data = await getTracer().trace(RenderSpan.getServerSideProps, async () => - getServerSideProps({ - req: req as IncomingMessage & { - cookies: NextApiRequestCookies - }, - res: resOrProxy, - query, - resolvedUrl: renderOpts.resolvedUrl as string, - ...(pageIsDynamic ? { params: params as ParsedUrlQuery } : undefined), - ...(previewData !== false - ? { preview: true, previewData: previewData } - : undefined), - locales: renderOpts.locales, - locale: renderOpts.locale, - defaultLocale: renderOpts.defaultLocale, - }) + data = await getTracer().trace( + RenderSpan.getServerSideProps, + { + spanName: `getServerSideProps ${pathname}`, + }, + async () => + getServerSideProps({ + req: req as IncomingMessage & { + cookies: NextApiRequestCookies + }, + res: resOrProxy, + query, + resolvedUrl: renderOpts.resolvedUrl as string, + ...(pageIsDynamic + ? { params: params as ParsedUrlQuery } + : undefined), + ...(previewData !== false + ? { preview: true, previewData: previewData } + : undefined), + locales: renderOpts.locales, + locale: renderOpts.locale, + defaultLocale: renderOpts.defaultLocale, + }) ) canAccessRes = false } catch (serverSidePropsError: any) { diff --git a/test/e2e/opentelemetry/app/app/rsc-fetch/page.tsx b/test/e2e/opentelemetry/app/app/rsc-fetch/page.tsx index 8572a4c45a43a6..797bbd84c4a7e7 100644 --- a/test/e2e/opentelemetry/app/app/rsc-fetch/page.tsx +++ b/test/e2e/opentelemetry/app/app/rsc-fetch/page.tsx @@ -2,6 +2,6 @@ export const dynamic = 'force-dynamic' export default async function Page() { - const data = await fetch('https://user:pass@vercel.com') + const data = await fetch('https://vercel.com') return
{await data.text()}
} diff --git a/test/e2e/opentelemetry/constants.ts b/test/e2e/opentelemetry/constants.ts index d86e7026ebc09c..ce6fd44bf7afc2 100644 --- a/test/e2e/opentelemetry/constants.ts +++ b/test/e2e/opentelemetry/constants.ts @@ -3,16 +3,16 @@ import { SpanKind } from '@opentelemetry/api' export const traceFile = 'otel-trace.txt' export type SavedSpan = { - traceId: string + traceId?: string parentId?: string - traceState: any - name: string - id: string - kind: SpanKind - timestamp: number - duration: number - attributes: Record - status: any - events: any[] - links: any[] + traceState?: any + name?: string + id?: string + kind?: SpanKind + timestamp?: number + duration?: number + attributes?: Record + status?: any + events?: any[] + links?: any[] } diff --git a/test/e2e/opentelemetry/opentelemetry.test.ts b/test/e2e/opentelemetry/opentelemetry.test.ts index 8c81237c5db825..b7557201bbcd4d 100644 --- a/test/e2e/opentelemetry/opentelemetry.test.ts +++ b/test/e2e/opentelemetry/opentelemetry.test.ts @@ -58,13 +58,16 @@ createNextDescribe( delete span.duration delete span.id delete span.links + delete span.events delete span.timestamp delete span.traceId span.parentId = span.parentId === undefined ? undefined : '[parent-id]' return span } const sanitizeSpans = (spans: SavedSpan[]) => - spans.sort((a, b) => a.name.localeCompare(b.name)).map(sanitizeSpan) + spans + .sort((a, b) => (a.name ?? '').localeCompare(b.name ?? '')) + .map(sanitizeSpan) const getSanitizedTraces = async (numberOfRootTraces: number) => { await waitForRootSpan(numberOfRootTraces) @@ -89,31 +92,42 @@ createNextDescribe( expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` Array [ Object { - "attributes": Object {}, - "events": Array [], - "kind": 0, - "name": "BaseServer.renderToResponse", - "parentId": "[parent-id]", + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/pages", + "next.span_name": "GET /pages", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages", + "parentId": undefined, "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.pathname": "/pages", + "next.span_name": "rendering page", + "next.span_type": "BaseServer.renderToResponse", + }, "kind": 0, - "name": "NextNodeServer.findPageComponents", + "name": "rendering page", "parentId": "[parent-id]", "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.route": "/pages", + "next.span_name": "resolving page into components", + "next.span_type": "NextNodeServer.findPageComponents", + }, "kind": 0, - "name": "NextServer.getRequestHandler", - "parentId": undefined, + "name": "resolving page into components", + "parentId": "[parent-id]", "status": Object { "code": 0, }, @@ -128,31 +142,42 @@ createNextDescribe( expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` Array [ Object { - "attributes": Object {}, - "events": Array [], - "kind": 0, - "name": "BaseServer.renderToResponse", - "parentId": "[parent-id]", + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/pages/params/stuff", + "next.span_name": "GET /pages/params/stuff", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/params/stuff", + "parentId": undefined, "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.pathname": "/pages/params/stuff", + "next.span_name": "rendering page", + "next.span_type": "BaseServer.renderToResponse", + }, "kind": 0, - "name": "NextNodeServer.findPageComponents", + "name": "rendering page", "parentId": "[parent-id]", "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.route": "/pages/params/[param]", + "next.span_name": "resolving page into components", + "next.span_type": "NextNodeServer.findPageComponents", + }, "kind": 0, - "name": "NextServer.getRequestHandler", - "parentId": undefined, + "name": "resolving page into components", + "parentId": "[parent-id]", "status": Object { "code": 0, }, @@ -167,42 +192,57 @@ createNextDescribe( expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` Array [ Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "http.method": "GET", + "http.url": "https://vercel.com/", + "net.peer.name": "vercel.com", + "next.span_name": "fetch GET https://vercel.com/", + "next.span_type": "AppRender.fetch", + }, "kind": 2, - "name": "AppRender.fetch", + "name": "fetch GET https://vercel.com/", "parentId": "[parent-id]", "status": Object { - "code": 2, - "message": "Request cannot be constructed from a URL that includes credentials: https://user:pass@vercel.com", + "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], - "kind": 0, - "name": "BaseServer.renderToResponse", - "parentId": "[parent-id]", + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/app/rsc-fetch", + "next.span_name": "GET /app/rsc-fetch", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /app/rsc-fetch", + "parentId": undefined, "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.pathname": "/app/rsc-fetch", + "next.span_name": "rendering page", + "next.span_type": "BaseServer.renderToResponse", + }, "kind": 0, - "name": "NextNodeServer.findPageComponents", + "name": "rendering page", "parentId": "[parent-id]", "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.route": "/app/rsc-fetch/page", + "next.span_name": "resolving page into components", + "next.span_type": "NextNodeServer.findPageComponents", + }, "kind": 0, - "name": "NextServer.getRequestHandler", - "parentId": undefined, + "name": "resolving page into components", + "parentId": "[parent-id]", "status": Object { "code": 0, }, @@ -212,36 +252,59 @@ createNextDescribe( }) it('should handle getServerSideProps', async () => { - await next.fetch('/pager/getServerSideProps') + await next.fetch('/pages/getServerSideProps') expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` Array [ Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/pages/getServerSideProps", + "next.span_name": "GET /pages/getServerSideProps", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/getServerSideProps", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.span_name": "getServerSideProps /pages/getServerSideProps", + "next.span_type": "Render.getServerSideProps", + }, "kind": 0, - "name": "BaseServer.renderToResponse", + "name": "getServerSideProps /pages/getServerSideProps", "parentId": "[parent-id]", "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.pathname": "/pages/getServerSideProps", + "next.span_name": "rendering page", + "next.span_type": "BaseServer.renderToResponse", + }, "kind": 0, - "name": "NextNodeServer.findPageComponents", + "name": "rendering page", "parentId": "[parent-id]", "status": Object { "code": 0, }, }, Object { - "attributes": Object {}, - "events": Array [], + "attributes": Object { + "next.route": "/pages/getServerSideProps", + "next.span_name": "resolving page into components", + "next.span_type": "NextNodeServer.findPageComponents", + }, "kind": 0, - "name": "NextServer.getRequestHandler", - "parentId": undefined, + "name": "resolving page into components", + "parentId": "[parent-id]", "status": Object { "code": 0, }, @@ -256,10 +319,15 @@ createNextDescribe( expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` Array [ Object { - "attributes": Object {}, - "events": Array [], - "kind": 0, - "name": "NextServer.getRequestHandler", + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/api/pages/basic", + "next.span_name": "GET /api/pages/basic", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /api/pages/basic", "parentId": undefined, "status": Object { "code": 0, diff --git a/test/e2e/opentelemetry/pages/pages/getServerSideProps.tsx b/test/e2e/opentelemetry/pages/pages/getServerSideProps.tsx index 9f3e9d965ff1e0..6b90eb9f666802 100644 --- a/test/e2e/opentelemetry/pages/pages/getServerSideProps.tsx +++ b/test/e2e/opentelemetry/pages/pages/getServerSideProps.tsx @@ -1,4 +1,4 @@ -export default async function Page() { +export default function Page() { return
Page
} From afd7a50a7780a56c2ebe1e3dea77d79054bf72f1 Mon Sep 17 00:00:00 2001 From: Yongjun Park Date: Tue, 21 Mar 2023 03:11:11 +0900 Subject: [PATCH 568/672] fix invalid comment in parseParameter function (#47291) I noticed an incorrect comment in ```parseParameter``` function, so I fixed it and added a missing example case. - Rename property ```name``` -> ```key``` - Add ```repeat: true, optional: false``` case https://github.com/vercel/next.js/blob/20b8dda0e8804f3c488b569c3355647ed5da9ac8/packages/next/src/shared/lib/router/utils/route-regex.ts#L15-L21 --- packages/next/src/shared/lib/router/utils/route-regex.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/next/src/shared/lib/router/utils/route-regex.ts b/packages/next/src/shared/lib/router/utils/route-regex.ts index 8ee2423cdbea24..37f0f4be275c93 100644 --- a/packages/next/src/shared/lib/router/utils/route-regex.ts +++ b/packages/next/src/shared/lib/router/utils/route-regex.ts @@ -15,9 +15,10 @@ export interface RouteRegex { /** * Parses a given parameter from a route to a data structure that can be used * to generate the parametrized route. Examples: - * - `[...slug]` -> `{ name: 'slug', repeat: true, optional: true }` - * - `[foo]` -> `{ name: 'foo', repeat: false, optional: true }` - * - `bar` -> `{ name: 'bar', repeat: false, optional: false }` + * - `[...slug]` -> `{ key: 'slug', repeat: true, optional: true }` + * - `...slug` -> `{ key: 'slug', repeat: true, optional: false }` + * - `[foo]` -> `{ key: 'foo', repeat: false, optional: true }` + * - `bar` -> `{ key: 'bar', repeat: false, optional: false }` */ function parseParameter(param: string) { const optional = param.startsWith('[') && param.endsWith(']') From 8a4e8059ede3b5fbce05a734f8b72f68ece21245 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Mon, 20 Mar 2023 19:57:29 +0100 Subject: [PATCH 569/672] Add searchParams to leaf cache key (#47312) ### What? Makes searchParams part of the cache key for dynamic rendering responses. ### Why? Current the cache key only includes the pathname and not the searchParams. This causes issues in a few cases: - Navigation to `/dashboard` then clicking a link to `/dashboard?sort=asc` works, but then when navigating back the cache node for `/dashboard?sort=asc` is used instead of the content for `/dashboard`. - Navigation between different searchParams always had to be a hard navigation as reusing a cache node would result in the wrong result. ### How? Changed the leaf node's name from `''` to `'__PAGE__'` so that it can be distinguished. Then used that `__PAGE__` marker to include the searchParams into the cache key for that leaf node in all places it's used. Ideally the `__PAGE__` key becomes something that can't be addressed in the pathname, since it still has to be serializable I'm thinking a number would be best. Given that the server just provides the cache key and the client only reasons about rendering the tree the current approach of stringifying the searchParams and making that part of the cache key could be replaced with a hash of the stringified result instead. fix NEXT-685 ([link](https://linear.app/vercel/issue/NEXT-685)) Fixes #45026 Fixes NEXT-688 Fixes #46503 --- .../build/webpack/loaders/next-app-loader.ts | 2 +- .../next/src/client/components/navigation.ts | 2 +- .../reducers/navigate-reducer.ts | 16 ++- ...te-flight-router-state-from-loader-tree.ts | 57 +++++++++++ packages/next/src/server/app-render/index.tsx | 99 +++++++++---------- .../src/server/dev/on-demand-entry-handler.ts | 6 +- .../app/app/navigation/searchparams/page.js | 18 ++++ 7 files changed, 136 insertions(+), 64 deletions(-) create mode 100644 packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts create mode 100644 test/e2e/app-dir/app/app/navigation/searchparams/page.js diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index d7e63fcee3f22b..2ad35e69b1314f 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -177,7 +177,7 @@ async function createTreeCodeFromPath( if (resolvedPagePath) pages.push(resolvedPagePath) // Use '' for segment as it's the page. There can't be a segment called '' so this is the safest way to add it. - props[parallelKey] = `['', {}, { + props[parallelKey] = `['__PAGE__', {}, { page: [() => import(/* webpackMode: "eager" */ ${JSON.stringify( resolvedPagePath )}), ${JSON.stringify(resolvedPagePath)}], diff --git a/packages/next/src/client/components/navigation.ts b/packages/next/src/client/components/navigation.ts index c1d29b495ed210..2e38b9c914a263 100644 --- a/packages/next/src/client/components/navigation.ts +++ b/packages/next/src/client/components/navigation.ts @@ -152,7 +152,7 @@ function getSelectedLayoutSegmentPath( if (!node) return segmentPath const segment = node[0] const segmentValue = Array.isArray(segment) ? segment[1] : segment - if (!segmentValue) return segmentPath + if (!segmentValue || segmentValue === '__PAGE__') return segmentPath segmentPath.push(segmentValue) diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts index 24c8b590473d89..ad0fee6b0b8d44 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts @@ -41,13 +41,12 @@ export function navigateReducer( const { url, isExternalUrl, - locationSearch, navigateType, cache, mutable, forceOptimisticNavigation, } = action - const { pathname, search, hash } = url + const { pathname, hash } = url const href = createHrefFromUrl(url) const pendingPush = navigateType === 'push' @@ -110,14 +109,11 @@ export function navigateReducer( const applied = applyFlightData(state, cache, flightDataPath) - const hardNavigate = - // TODO-APP: Revisit searchParams support - search !== locationSearch || - shouldHardNavigate( - // TODO-APP: remove '' - ['', ...flightSegmentPath], - state.tree - ) + const hardNavigate = shouldHardNavigate( + // TODO-APP: remove '' + ['', ...flightSegmentPath], + state.tree + ) if (hardNavigate) { cache.status = CacheStates.READY diff --git a/packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts b/packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts new file mode 100644 index 00000000000000..46afe6473fe85d --- /dev/null +++ b/packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts @@ -0,0 +1,57 @@ +import { LoaderTree } from '../lib/app-dir-module' +import { FlightRouterState, Segment } from './types' +import { GetDynamicParamFromSegment } from './index' + +// TODO-APP: Move __PAGE__ to a shared constant +const PAGE_SEGMENT_KEY = '__PAGE__' + +export function addSearchParamsIfPageSegment( + segment: Segment, + searchParams: any +) { + const isPageSegment = segment === PAGE_SEGMENT_KEY + + if (isPageSegment) { + const stringifiedQuery = JSON.stringify(searchParams) + return stringifiedQuery !== '{}' + ? segment + '?' + stringifiedQuery + : segment + } + + return segment +} + +export function createFlightRouterStateFromLoaderTree( + [segment, parallelRoutes, { layout }]: LoaderTree, + getDynamicParamFromSegment: GetDynamicParamFromSegment, + searchParams: any, + rootLayoutIncluded = false +): FlightRouterState { + const dynamicParam = getDynamicParamFromSegment(segment) + const treeSegment = dynamicParam ? dynamicParam.treeSegment : segment + + const segmentTree: FlightRouterState = [ + addSearchParamsIfPageSegment(treeSegment, searchParams), + {}, + ] + + if (!rootLayoutIncluded && typeof layout !== 'undefined') { + rootLayoutIncluded = true + segmentTree[4] = true + } + + segmentTree[1] = Object.keys(parallelRoutes).reduce( + (existingValue, currentValue) => { + existingValue[currentValue] = createFlightRouterStateFromLoaderTree( + parallelRoutes[currentValue], + getDynamicParamFromSegment, + searchParams, + rootLayoutIncluded + ) + return existingValue + }, + {} as FlightRouterState[1] + ) + + return segmentTree +} diff --git a/packages/next/src/server/app-render/index.tsx b/packages/next/src/server/app-render/index.tsx index a694a49688f7ab..26a236d3d2d819 100644 --- a/packages/next/src/server/app-render/index.tsx +++ b/packages/next/src/server/app-render/index.tsx @@ -12,7 +12,6 @@ import type { import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage' import type { RequestAsyncStorage } from '../../client/components/request-async-storage' import type { MetadataItems } from '../../lib/metadata/resolve-metadata' - // Import builtin react directly to avoid require cache conflicts import React from 'next/dist/compiled/react' import ReactDOMServer from 'next/dist/compiled/react-dom/server.browser' @@ -69,9 +68,23 @@ import { getScriptNonceFromHeader } from './get-script-nonce-from-header' import { renderToString } from './render-to-string' import { parseAndValidateFlightRouterState } from './parse-and-validate-flight-router-state' import { validateURL } from './validate-url' +import { + addSearchParamsIfPageSegment, + createFlightRouterStateFromLoaderTree, +} from './create-flight-router-state-from-loader-tree' export const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge' +export type GetDynamicParamFromSegment = ( + // [slug] / [[slug]] / [...slug] + segment: string +) => { + param: string + value: string | string[] | null + treeSegment: Segment + type: DynamicParamTypesShort +} | null + export async function renderToHTMLOrFlight( req: IncomingMessage, res: ServerResponse, @@ -217,15 +230,10 @@ export async function renderToHTMLOrFlight( /** * Parse the dynamic segment and return the associated value. */ - const getDynamicParamFromSegment = ( + const getDynamicParamFromSegment: GetDynamicParamFromSegment = ( // [slug] / [[slug]] / [...slug] segment: string - ): { - param: string - value: string | string[] | null - treeSegment: Segment - type: DynamicParamTypesShort - } | null => { + ) => { const segmentParam = getSegmentParam(segment) if (!segmentParam) { return null @@ -326,36 +334,6 @@ export async function renderToHTMLOrFlight( return [null, metadataItems] } - const createFlightRouterStateFromLoaderTree = ( - [segment, parallelRoutes, { layout }]: LoaderTree, - rootLayoutIncluded = false - ): FlightRouterState => { - const dynamicParam = getDynamicParamFromSegment(segment) - - const segmentTree: FlightRouterState = [ - dynamicParam ? dynamicParam.treeSegment : segment, - {}, - ] - - if (!rootLayoutIncluded && typeof layout !== 'undefined') { - rootLayoutIncluded = true - segmentTree[4] = true - } - - segmentTree[1] = Object.keys(parallelRoutes).reduce( - (existingValue, currentValue) => { - existingValue[currentValue] = createFlightRouterStateFromLoaderTree( - parallelRoutes[currentValue], - rootLayoutIncluded - ) - return existingValue - }, - {} as FlightRouterState[1] - ) - - return segmentTree - } - let defaultRevalidate: false | undefined | number = false // Collect all server CSS imports used by this specific entry (or entries, for parallel routes). @@ -640,9 +618,12 @@ export async function renderToHTMLOrFlight( const childProp: ChildProp = { // Null indicates the tree is not fully rendered current: null, - segment: childSegmentParam - ? childSegmentParam.treeSegment - : childSegment, + segment: addSearchParamsIfPageSegment( + childSegmentParam + ? childSegmentParam.treeSegment + : childSegment, + query + ), } // This is turned back into an object below. @@ -683,9 +664,12 @@ export async function renderToHTMLOrFlight( const childProp: ChildProp = { current: , - segment: childSegmentParam - ? childSegmentParam.treeSegment - : childSegment, + segment: addSearchParamsIfPageSegment( + childSegmentParam + ? childSegmentParam.treeSegment + : childSegment, + query + ), } const segmentPath = createSegmentPath(currentSegmentPath) @@ -857,6 +841,7 @@ export async function renderToHTMLOrFlight( rootLayoutIncluded: boolean }): Promise => { const [segment, parallelRoutes, components] = loaderTreeToFilter + const parallelRoutesKeys = Object.keys(parallelRoutes) const { layout } = components const isLayout = typeof layout !== 'undefined' @@ -881,9 +866,10 @@ export async function renderToHTMLOrFlight( [segmentParam.param]: segmentParam.value, } : parentParams - const actualSegment: Segment = segmentParam - ? segmentParam.treeSegment - : segment + const actualSegment: Segment = addSearchParamsIfPageSegment( + segmentParam ? segmentParam.treeSegment : segment, + query + ) /** * Decide if the current segment is where rendering has to start. @@ -902,7 +888,11 @@ export async function renderToHTMLOrFlight( return [ actualSegment, // Create router state using the slice of the loaderTree - createFlightRouterStateFromLoaderTree(loaderTreeToFilter), + createFlightRouterStateFromLoaderTree( + loaderTreeToFilter, + getDynamicParamFromSegment, + query + ), // Check if one level down from the common layout has a loading component. If it doesn't only provide the router state as part of the Flight data. isPrefetch && !Boolean(components.loading) ? null @@ -1074,7 +1064,12 @@ export async function renderToHTMLOrFlight( ? { validateRootLayout: { assetPrefix: renderOpts.assetPrefix, - getTree: () => createFlightRouterStateFromLoaderTree(loaderTree), + getTree: () => + createFlightRouterStateFromLoaderTree( + loaderTree, + getDynamicParamFromSegment, + query + ), }, } : {} @@ -1101,7 +1096,11 @@ export async function renderToHTMLOrFlight( asNotFound: props.asNotFound, }) - const initialTree = createFlightRouterStateFromLoaderTree(loaderTree) + const initialTree = createFlightRouterStateFromLoaderTree( + loaderTree, + getDynamicParamFromSegment, + query + ) return ( <> diff --git a/packages/next/src/server/dev/on-demand-entry-handler.ts b/packages/next/src/server/dev/on-demand-entry-handler.ts index 279271cfee8873..44856b5cbf9629 100644 --- a/packages/next/src/server/dev/on-demand-entry-handler.ts +++ b/packages/next/src/server/dev/on-demand-entry-handler.ts @@ -121,9 +121,11 @@ function getEntrypointsFromTree( ? convertDynamicParamTypeToSyntax(segment[2], segment[0]) : segment - const currentPath = [...parentPath, currentSegment] + const isPageSegment = currentSegment.startsWith('__PAGE__') - if (!isFirst && currentSegment === '') { + const currentPath = [...parentPath, isPageSegment ? '' : currentSegment] + + if (!isFirst && isPageSegment) { // TODO get rid of '' at the start of tree return [treePathToEntrypoint(currentPath.slice(1))] } diff --git a/test/e2e/app-dir/app/app/navigation/searchparams/page.js b/test/e2e/app-dir/app/app/navigation/searchparams/page.js new file mode 100644 index 00000000000000..22515e25bc4661 --- /dev/null +++ b/test/e2e/app-dir/app/app/navigation/searchparams/page.js @@ -0,0 +1,18 @@ +import Link from 'next/link' + +export default function Page({ searchParams }) { + return ( + <> +

{JSON.stringify(searchParams)}

+
+ To A +
+
+ To B +
+
+ To A&B +
+ + ) +} From 7696124a5e9a8043c4c100f3162a3ca9d653db49 Mon Sep 17 00:00:00 2001 From: Jan Kaifer Date: Mon, 20 Mar 2023 20:36:49 +0100 Subject: [PATCH 570/672] Remove duplicated if statement (#47322) Came across these two if statements that had equal conditions. The second error could never get thrown. --- packages/next/src/server/render.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 4782c7fa9bce71..e6353f8e0800a6 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -1139,19 +1139,11 @@ export async function renderToHTML( if (process.env.NEXT_RUNTIME === 'edge' && Document.getInitialProps) { // In the Edge runtime, `Document.getInitialProps` isn't supported. // We throw an error here if it's customized. - if (!BuiltinFunctionalDocument) { - throw new Error( - '`getInitialProps` in Document component is not supported with the Edge Runtime.' - ) - } - } - - if (process.env.NEXT_RUNTIME === 'edge' && Document.getInitialProps) { if (BuiltinFunctionalDocument) { Document = BuiltinFunctionalDocument } else { throw new Error( - '`getInitialProps` in Document component is not supported with React Server Components.' + '`getInitialProps` in Document component is not supported with the Edge Runtime.' ) } } From 47ac5d5f8cdee9fd64dbcf2e7714378fb2dcf987 Mon Sep 17 00:00:00 2001 From: Gary Borton Date: Mon, 20 Mar 2023 13:19:25 -0700 Subject: [PATCH 571/672] Add a .catch to shared router for ssg fetching. (#47265) **Description:** I noticed that when a user is on a deployed next.js site, and a fresh deployment is made, requests for ssg data fails w/ a 404. For prefetches (hovering a link) this appears to be handled well, but when the user actually clicks the link it wasn't being handled. This doesn't seem to be a problem as the page still behaves as expected, but the errors being generated are clogging sentry. To fix this, I added a simple `.catch(() => false)` as the return value didn't appear to be used at all. I was able to verify that this works correctly by patching next in a local project and deploying a few times then clicking around. **Issues** As far as I know there's no issue tracking this atm as I chatted w/ Tim in slack and he was under the impression that all of the failures were caught. Console on page navigation before this change: image --------- Co-authored-by: JJ Kasper --- packages/next/src/shared/lib/router/router.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next/src/shared/lib/router/router.ts b/packages/next/src/shared/lib/router/router.ts index 81af1503389f29..28d653bc5760e2 100644 --- a/packages/next/src/shared/lib/router/router.ts +++ b/packages/next/src/shared/lib/router/router.ts @@ -2432,7 +2432,9 @@ export default class Router implements BaseRouter { options.unstable_skipClientCache || (options.priority && !!process.env.__NEXT_OPTIMISTIC_CLIENT_CACHE), - }).then(() => false) + }) + .then(() => false) + .catch(() => false) : false }), this.pageLoader[options.priority ? 'loadPage' : 'prefetch'](route), From feb2aecfa09539ef0fc304260e0e849ae83b1980 Mon Sep 17 00:00:00 2001 From: Jimmy Lai Date: Mon, 20 Mar 2023 21:59:58 +0100 Subject: [PATCH 572/672] parallel routes: fix nested routes (#47323) ### What? There was a bug with supporting nested routes in the parallel routes with named slots that made the request hang ### Why? The request was hanging suspended on the router because the `next-app-loader` was not finding the layout component and thus, it was falling back to a component that returned null, tripping a bit of code in the app router that suspended. ### How? The fix was to fix the next-app-loader loader tree generation to account for parallel routes Closes NEXT- Fixes # fix NEXT-854 ([link](https://linear.app/vercel/issue/NEXT-854)) --------- Co-authored-by: Tim Neutkens --- packages/next/src/build/webpack/loaders/next-app-loader.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index 2ad35e69b1314f..22069538359e55 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -186,7 +186,6 @@ async function createTreeCodeFromPath( continue } - const parallelSegmentPath = segmentPath + '/' + parallelSegment const { treeCode: subtreeCode } = await createSubtreePropsFromSegmentPath( [ ...segments, @@ -195,6 +194,12 @@ async function createTreeCodeFromPath( ] ) + const parallelSegmentPath = + segmentPath + + '/' + + (parallelKey === 'children' ? '' : `@${parallelKey}/`) + + (Array.isArray(parallelSegment) ? parallelSegment[0] : parallelSegment) + // `page` is not included here as it's added above. const filePaths = await Promise.all( Object.values(FILE_TYPES).map(async (file) => { From 5d9b166ebae136e5ad221164b21cda892a7e1003 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Mon, 20 Mar 2023 22:06:42 +0100 Subject: [PATCH 573/672] v13.2.5-canary.9 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index 79db5652028d03..a275ad8f1d01ac 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.2.5-canary.8" + "version": "13.2.5-canary.9" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 3aefea8e6eb69a..19688f5fd21317 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 9887a969634f2a..8b6b79a2a49b4a 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -12,7 +12,7 @@ "test-pack": "cd ../../ && pnpm test-pack eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "13.2.5-canary.8", + "@next/eslint-plugin-next": "13.2.5-canary.9", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.42.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index fe02cf4baffa87..0ad0163d73ad35 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "description": "ESLint plugin for NextJS.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 828903bae4dec0..c95a9a42651f3b 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index e9c26cfc0006c0..6993b7b25c3f4c 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 2ce624dd34e8ef..e188b56b220599 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index bb3662f216d0b0..693e4e3bf978b3 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index c68956eaf69967..9d6d61ca9b12f3 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index e9986af864da58..f35ac073554ddd 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 92f6b93a9c0f47..d73373366e2fe1 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index cd820035f3e547..cbd468aa2ca2df 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index b172f105f25b8e..a0bc9218c39c6b 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "private": true, "scripts": { "clean": "rm -rf ./native/*", diff --git a/packages/next/package.json b/packages/next/package.json index 6e878e42118a0e..9411643f8e2c5b 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -80,7 +80,7 @@ ] }, "dependencies": { - "@next/env": "13.2.5-canary.8", + "@next/env": "13.2.5-canary.9", "@swc/helpers": "0.4.14", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -135,11 +135,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.14.7", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.2.5-canary.8", - "@next/polyfill-nomodule": "13.2.5-canary.8", - "@next/react-dev-overlay": "13.2.5-canary.8", - "@next/react-refresh-utils": "13.2.5-canary.8", - "@next/swc": "13.2.5-canary.8", + "@next/polyfill-module": "13.2.5-canary.9", + "@next/polyfill-nomodule": "13.2.5-canary.9", + "@next/react-dev-overlay": "13.2.5-canary.9", + "@next/react-refresh-utils": "13.2.5-canary.9", + "@next/swc": "13.2.5-canary.9", "@opentelemetry/api": "1.4.1", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index f28845a29a9336..0e9d02fbde9caa 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 01b457a8bb757d..f8a80c7084f8be 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "13.2.5-canary.8", + "version": "13.2.5-canary.9", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da4248179b7abe..c1e49fdb4e33fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -444,7 +444,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 13.2.5-canary.8 + '@next/eslint-plugin-next': 13.2.5-canary.9 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.42.0 eslint: ^7.23.0 || ^8.0.0 @@ -517,12 +517,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.14.7 '@napi-rs/triples': 1.1.0 - '@next/env': 13.2.5-canary.8 - '@next/polyfill-module': 13.2.5-canary.8 - '@next/polyfill-nomodule': 13.2.5-canary.8 - '@next/react-dev-overlay': 13.2.5-canary.8 - '@next/react-refresh-utils': 13.2.5-canary.8 - '@next/swc': 13.2.5-canary.8 + '@next/env': 13.2.5-canary.9 + '@next/polyfill-module': 13.2.5-canary.9 + '@next/polyfill-nomodule': 13.2.5-canary.9 + '@next/react-dev-overlay': 13.2.5-canary.9 + '@next/react-refresh-utils': 13.2.5-canary.9 + '@next/swc': 13.2.5-canary.9 '@opentelemetry/api': 1.4.1 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.14 From 5448c234d6948d007bf9d13dd548fe10336532ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 20 Mar 2023 22:21:29 +0100 Subject: [PATCH 574/672] fix(cli): handle Tailwind CSS + `src/` correctly (#47238) ### What? - [x] fixes a bug in the CLI with the combination of `--tailwind` and `--src-dir` flags. - [x] fixes Tailwind CSS config when `--src-dir` is set - [x] respect `NEXT_TEST_SKIP_CLEANUP` in test utils ### Why? `pnpm create next-app@canary --tailwind --src-dir` should not fail. ### How? We introduced the `app-tw` and `default-tw` templates, so we need to respect them when working with files (in this case, the CLI was erroneously assuming that if `template !== "app"` it must be a pages template.) I also noticed that the `tailwind.config.js` file need to also respect `--src-dir` by prefixing the paths in `content` Fixes #47236 fix NEXT-838 ([link](https://linear.app/vercel/issue/NEXT-838)) Related: #46927, #47276 --------- Co-authored-by: JJ Kasper --- packages/create-next-app/templates/index.ts | 25 +++++++-- .../create-next-app/templates.test.ts | 53 ++++++++++++++++++- test/lib/use-temp-dir.ts | 6 ++- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/packages/create-next-app/templates/index.ts b/packages/create-next-app/templates/index.ts index 9635f9652c7d03..75d4eb36609b28 100644 --- a/packages/create-next-app/templates/index.ts +++ b/packages/create-next-app/templates/index.ts @@ -123,21 +123,38 @@ export const installTemplate = async ({ }) }) ) + + const isAppTemplate = template.startsWith('app') + // Change the `Get started by editing pages/index` / `app/page` to include `src` const indexPageFile = path.join( 'src', - template === 'app' ? 'app' : 'pages', - `${template === 'app' ? 'page' : 'index'}.${mode === 'ts' ? 'tsx' : 'js'}` + isAppTemplate ? 'app' : 'pages', + `${isAppTemplate ? 'page' : 'index'}.${mode === 'ts' ? 'tsx' : 'js'}` ) + await fs.promises.writeFile( indexPageFile, ( await fs.promises.readFile(indexPageFile, 'utf8') ).replace( - template === 'app' ? 'app/page' : 'pages/index', - template === 'app' ? 'src/app/page' : 'src/pages/index' + isAppTemplate ? 'app/page' : 'pages/index', + isAppTemplate ? 'src/app/page' : 'src/pages/index' ) ) + + if (tailwind) { + const tailwindConfigFile = path.join(root, 'tailwind.config.js') + await fs.promises.writeFile( + tailwindConfigFile, + ( + await fs.promises.readFile(tailwindConfigFile, 'utf8') + ).replace( + /\.\/(\w+)\/\*\*\/\*\.\{js,ts,jsx,tsx\}/g, + './src/$1/**/*.{js,ts,jsx,tsx}' + ) + ) + } } /** diff --git a/test/integration/create-next-app/templates.test.ts b/test/integration/create-next-app/templates.test.ts index 10613631f56ed9..5dc3965e05d38c 100644 --- a/test/integration/create-next-app/templates.test.ts +++ b/test/integration/create-next-app/templates.test.ts @@ -309,6 +309,56 @@ describe('create-next-app templates', () => { }) }) + it('should work with --tailwind and --src together', async () => { + await useTempDir(async (cwd) => { + const projectName = 'tailwind-js-src' + + /** + * Start the create-next-app call. + */ + const childProcess = createNextApp( + [ + projectName, + '--js', + '--no-eslint', + '--tailwind', + '--src-dir', + '--no-experimental-app', + `--import-alias=@/*`, + ], + { + cwd, + }, + testVersion + ) + /** + * Wait for the prompt to display. + */ + // await new Promise((resolve) => setTimeout(resolve, 1000)); + /** + * Bind the exit listener. + */ + await new Promise((resolve, reject) => { + childProcess.on('exit', async (exitCode) => { + expect(exitCode).toBe(0) + /** + * Verify it correctly emitted a Tailwind project by looking for tailwind.config.js. + */ + projectFilesShouldExist({ + cwd, + projectName, + files: ['tailwind.config.js'], + }) + resolve() + }) + /** + * Simulate "N" for Tailwind. + */ + childProcess.stdin.write('N\n') + }) + }) + }) + it('should prompt user to choose if --tailwind or --no-tailwind is not provided', async () => { await useTempDir(async (cwd) => { const projectName = 'choose-tailwind' @@ -483,7 +533,7 @@ describe('create-next-app --experimental-app', () => { '--tailwind', '--experimental-app', '--eslint', - '--no-src-dir', + '--src-dir', `--import-alias=@/*`, ], { @@ -499,6 +549,7 @@ describe('create-next-app --experimental-app', () => { projectName, template: 'app-tw', mode: 'ts', + srcDir: true, }) await startsWithoutError( path.join(cwd, projectName), diff --git a/test/lib/use-temp-dir.ts b/test/lib/use-temp-dir.ts index 32db47b6c42a11..e7f6bc0ab0f48b 100644 --- a/test/lib/use-temp-dir.ts +++ b/test/lib/use-temp-dir.ts @@ -4,7 +4,7 @@ import path from 'path' /** * Create a randomly-named directory in `os.tmpdir()`, await a function call, - * and delete the directory when finished. + * and delete the directory when finished, unless `NEXT_TEST_SKIP_CLEANUP` is set. */ export async function useTempDir( fn: (folder: string) => void | Promise, @@ -23,6 +23,8 @@ export async function useTempDir( try { await fn(folder) } finally { - await fs.remove(folder) + if (!process.env.NEXT_TEST_SKIP_CLEANUP) { + await fs.remove(folder) + } } } From dd1de0e4c891b80a590f6421ac1eb82b5848e9e1 Mon Sep 17 00:00:00 2001 From: Mauro Mandracchia Date: Mon, 20 Mar 2023 22:40:24 +0100 Subject: [PATCH 575/672] [Nitpick] Remove unnecessary await in `base-server` (#47313) ### What? Async functions can just be return without await. ### Why? Is just cleaner. Not important and not crucial. Co-authored-by: JJ Kasper --- packages/next/src/server/base-server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 0854483bd9699d..734b32c2d94a4a 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -529,7 +529,7 @@ export default abstract class Server { }, }, async (span) => - await this.handleRequestImpl(req, res, parsedUrl).finally(() => + this.handleRequestImpl(req, res, parsedUrl).finally(() => span?.setAttributes({ 'http.status_code': res.statusCode, }) From 0be4db325e5ac9816f9a8bdbcaae2be6a35ba94f Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 20 Mar 2023 15:52:41 -0600 Subject: [PATCH 576/672] Warn about default exports with App Routes (#47263) When a user exports a default function from a `route.ts` file, they may think that this would be handled in the same way that our `pages/api/` routes handled it. App Routes require an exported function for each HTTP method instead. This adds warnings to the development console when a user provides a default export (or no HTTP method at all). Future ideas: - Error during production build when these conditions are met fix #46375 fix NEXT-660 ([link](https://linear.app/vercel/issue/NEXT-660)) --------- Co-authored-by: JJ Kasper --- .../route-handlers/app-route-route-handler.ts | 58 +++++++++++++------ .../app-routes/app-custom-routes.test.ts | 20 +++++++ .../app-dir/app-routes/app/default/route.ts | 1 + .../app-routes/app/lowercase/delete/route.ts | 7 +-- .../app-routes/app/lowercase/get/route.ts | 6 +- .../app-routes/app/lowercase/head/route.ts | 6 +- .../app-routes/app/lowercase/options/route.ts | 6 +- .../app-routes/app/lowercase/patch/route.ts | 6 +- .../app-routes/app/lowercase/post/route.ts | 6 +- .../app-routes/app/lowercase/put/route.ts | 6 +- 10 files changed, 68 insertions(+), 54 deletions(-) create mode 100644 test/e2e/app-dir/app-routes/app/default/route.ts diff --git a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts index 94dab3bdb2b158..e96a361a697c65 100644 --- a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts @@ -24,7 +24,7 @@ import { handleTemporaryRedirectResponse, } from '../helpers/response-handlers' import { AppRouteRouteMatch } from '../route-matches/app-route-route-match' -import { HTTP_METHOD, isHTTPMethod } from '../../web/http' +import { HTTP_METHOD, HTTP_METHODS, isHTTPMethod } from '../../web/http' import { NextRequest } from '../../web/spec-extension/request' import { fromNodeHeaders } from '../../web/utils' import type { ModuleLoader } from '../helpers/module-loader/module-loader' @@ -340,6 +340,42 @@ function proxyRequest(req: NextRequest, module: AppRouteModule): NextRequest { }) } +/** + * Validate that the module is exporting methods supported by the handler. + * + * @param mod the module to validate + */ +function validateModule(mod: AppRouteModule) { + const { handlers, resolvedPagePath } = mod + + // Print error in development if the exported handlers are in lowercase, only + // uppercase handlers are supported. + const lowercased = HTTP_METHODS.map((method) => method.toLowerCase()) + for (const method of lowercased) { + if (method in handlers) { + Log.error( + `Detected lowercase method '${method}' in '${resolvedPagePath}'. Export the uppercase '${method.toUpperCase()}' method name to fix this error.` + ) + } + } + + // Print error if the module exports a default handler, they must use named + // exports for each HTTP method. + if ('default' in handlers) { + Log.error( + `Detected default export in '${resolvedPagePath}'. Export a named export for each HTTP method instead.` + ) + } + + // If there is no methods exported by this module, then return a not found + // response. + if (!HTTP_METHODS.some((method) => method in handlers)) { + Log.error( + `No HTTP methods exported in '${resolvedPagePath}'. Export a named export for each HTTP method.` + ) + } +} + export class AppRouteRouteHandler implements RouteHandler { constructor( private readonly nextConfigOutput: NextConfig['output'] = undefined, @@ -356,25 +392,11 @@ export class AppRouteRouteHandler implements RouteHandler { if (!isHTTPMethod(method)) return handleBadRequestResponse // Pull out the handlers from the app route module. - const { handlers, resolvedPagePath } = mod + const { handlers } = mod + // If we're in development, then validate the module. if (process.env.NODE_ENV !== 'production') { - // Print error in development if the exported handlers are in lowercase, only uppercase handlers are supported - for (const invalidMethodName of [ - 'get', - 'head', - 'options', - 'post', - 'put', - 'delete', - 'patch', - ]) { - if ((handlers as any)[invalidMethodName]) { - Log.error( - `Detected lowercase method '${invalidMethodName}' in '${resolvedPagePath}'. Export the uppercase '${invalidMethodName.toUpperCase()}' method name to fix this error.` - ) - } - } + validateModule(mod) } // Check to see if the requested method is available. diff --git a/test/e2e/app-dir/app-routes/app-custom-routes.test.ts b/test/e2e/app-dir/app-routes/app-custom-routes.test.ts index 3ed6e9ac5d42d8..868d78563f43a8 100644 --- a/test/e2e/app-dir/app-routes/app-custom-routes.test.ts +++ b/test/e2e/app-dir/app-routes/app-custom-routes.test.ts @@ -551,6 +551,26 @@ createNextDescribe( } ) }) + + describe('invalid exports', () => { + it('should print an error when exporting a default handler in dev', async () => { + const res = await next.fetch('/default') + + // Ensure we get a 405 (Method Not Allowed) response when there is no + // exported handler for the GET method. + expect(res.status).toEqual(405) + + await check(() => { + expect(next.cliOutput).toMatch( + /Detected default export in '.+\/route\.ts'\. Export a named export for each HTTP method instead\./ + ) + expect(next.cliOutput).toMatch( + /No HTTP methods exported in '.+\/route\.ts'\. Export a named export for each HTTP method\./ + ) + return 'yes' + }, 'yes') + }) + }) } } ) diff --git a/test/e2e/app-dir/app-routes/app/default/route.ts b/test/e2e/app-dir/app-routes/app/default/route.ts new file mode 100644 index 00000000000000..83aee80041deb4 --- /dev/null +++ b/test/e2e/app-dir/app-routes/app/default/route.ts @@ -0,0 +1 @@ +export { GET as default } from '../../handlers/hello' diff --git a/test/e2e/app-dir/app-routes/app/lowercase/delete/route.ts b/test/e2e/app-dir/app-routes/app/lowercase/delete/route.ts index cace982012478e..c2f8249b31c696 100644 --- a/test/e2e/app-dir/app-routes/app/lowercase/delete/route.ts +++ b/test/e2e/app-dir/app-routes/app/lowercase/delete/route.ts @@ -1,6 +1 @@ -export const handler = async (): Promise => { - return new Response('hello, world') -} - -const del = handler -export { del as delete } +export { DELETE as delete } from '../../../handlers/hello' diff --git a/test/e2e/app-dir/app-routes/app/lowercase/get/route.ts b/test/e2e/app-dir/app-routes/app/lowercase/get/route.ts index bfcf046950272f..7735df10a0b699 100644 --- a/test/e2e/app-dir/app-routes/app/lowercase/get/route.ts +++ b/test/e2e/app-dir/app-routes/app/lowercase/get/route.ts @@ -1,5 +1 @@ -export const handler = async (): Promise => { - return new Response('hello, world') -} - -export const get = handler +export { GET as get } from '../../../handlers/hello' diff --git a/test/e2e/app-dir/app-routes/app/lowercase/head/route.ts b/test/e2e/app-dir/app-routes/app/lowercase/head/route.ts index 96316c7d764bf9..89f48c695a0d77 100644 --- a/test/e2e/app-dir/app-routes/app/lowercase/head/route.ts +++ b/test/e2e/app-dir/app-routes/app/lowercase/head/route.ts @@ -1,5 +1 @@ -export const handler = async (): Promise => { - return new Response('hello, world') -} - -export const head = handler +export { HEAD as head } from '../../../handlers/hello' diff --git a/test/e2e/app-dir/app-routes/app/lowercase/options/route.ts b/test/e2e/app-dir/app-routes/app/lowercase/options/route.ts index c4047f5e0169a1..59b63b1a3ad393 100644 --- a/test/e2e/app-dir/app-routes/app/lowercase/options/route.ts +++ b/test/e2e/app-dir/app-routes/app/lowercase/options/route.ts @@ -1,5 +1 @@ -export const handler = async (): Promise => { - return new Response('hello, world') -} - -export const options = handler +export { OPTIONS as options } from '../../../handlers/hello' diff --git a/test/e2e/app-dir/app-routes/app/lowercase/patch/route.ts b/test/e2e/app-dir/app-routes/app/lowercase/patch/route.ts index cb35e09f01b34b..91315bbf156db8 100644 --- a/test/e2e/app-dir/app-routes/app/lowercase/patch/route.ts +++ b/test/e2e/app-dir/app-routes/app/lowercase/patch/route.ts @@ -1,5 +1 @@ -export const handler = async (): Promise => { - return new Response('hello, world') -} - -export const patch = handler +export { PATCH as patch } from '../../../handlers/hello' diff --git a/test/e2e/app-dir/app-routes/app/lowercase/post/route.ts b/test/e2e/app-dir/app-routes/app/lowercase/post/route.ts index 4157cb7721d97f..2340ade7585191 100644 --- a/test/e2e/app-dir/app-routes/app/lowercase/post/route.ts +++ b/test/e2e/app-dir/app-routes/app/lowercase/post/route.ts @@ -1,5 +1 @@ -export const handler = async (): Promise => { - return new Response('hello, world') -} - -export const post = handler +export { POST as post } from '../../../handlers/hello' diff --git a/test/e2e/app-dir/app-routes/app/lowercase/put/route.ts b/test/e2e/app-dir/app-routes/app/lowercase/put/route.ts index 777cf912b23d46..b1cda20a07d42c 100644 --- a/test/e2e/app-dir/app-routes/app/lowercase/put/route.ts +++ b/test/e2e/app-dir/app-routes/app/lowercase/put/route.ts @@ -1,5 +1 @@ -export const handler = async (): Promise => { - return new Response('hello, world') -} - -export const put = handler +export { PUT as put } from '../../../handlers/hello' From 4575faa64976a9b732c48cab420641c45649b9ce Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 20 Mar 2023 14:58:39 -0700 Subject: [PATCH 577/672] Update failing e2e deploy test (#47325) The custom handler version of this test isn't expected to handle this accurately. x-ref: https://github.com/vercel/next.js/actions/runs/4472912191/jobs/7859898279 --- .../e2e/app-dir/app-static/app-static.test.ts | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index da322eb276ddbd..08f50ffc8029e2 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -50,40 +50,46 @@ createNextDescribe( }) } - it('should revalidate correctly with config and fetch revalidate', async () => { - const initial$ = await next.render$( - '/variable-config-revalidate/revalidate-3' - ) - const initialDate = initial$('#date').text() - const initialData = initial$('#data').text() + if (!process.env.CUSTOM_CACHE_HANDLER) { + it('should revalidate correctly with config and fetch revalidate', async () => { + const initial$ = await next.render$( + '/variable-config-revalidate/revalidate-3' + ) + const initialDate = initial$('#date').text() + const initialData = initial$('#data').text() - expect(initialDate).toBeTruthy() - expect(initialData).toBeTruthy() + expect(initialDate).toBeTruthy() + expect(initialData).toBeTruthy() - let revalidatedDate - let revalidatedData + let revalidatedDate + let revalidatedData - // wait for a fresh revalidation - await check(async () => { - const $ = await next.render$('/variable-config-revalidate/revalidate-3') + // wait for a fresh revalidation + await check(async () => { + const $ = await next.render$( + '/variable-config-revalidate/revalidate-3' + ) - revalidatedDate = $('#date').text() - revalidatedData = $('#data').text() + revalidatedDate = $('#date').text() + revalidatedData = $('#data').text() - expect(revalidatedData).not.toBe(initialDate) - expect(revalidatedDate).not.toBe(initialData) - return 'success' - }, 'success') + expect(revalidatedData).not.toBe(initialDate) + expect(revalidatedDate).not.toBe(initialData) + return 'success' + }, 'success') - // the date should revalidate first after 3 seconds - // while the fetch data stays in place for 15 seconds - await check(async () => { - const $ = await next.render$('/variable-config-revalidate/revalidate-3') - expect($('#date').text()).not.toBe(revalidatedDate) - expect($('#data').text()).toBe(revalidatedData) - return 'success' - }, 'success') - }) + // the date should revalidate first after 3 seconds + // while the fetch data stays in place for 15 seconds + await check(async () => { + const $ = await next.render$( + '/variable-config-revalidate/revalidate-3' + ) + expect($('#date').text()).not.toBe(revalidatedDate) + expect($('#data').text()).toBe(revalidatedData) + return 'success' + }, 'success') + }) + } it('should include statusCode in cache', async () => { const $ = await next.render$('/variable-revalidate/status-code') From f42825829c5853805d3e0ed23d6246a09c28bfb9 Mon Sep 17 00:00:00 2001 From: RTrace Date: Mon, 20 Mar 2023 15:26:23 -0700 Subject: [PATCH 578/672] Add better-sqlite3 to server external packages (#47327) --- packages/next/src/lib/server-external-packages.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next/src/lib/server-external-packages.json b/packages/next/src/lib/server-external-packages.json index 7ab66f712f1923..2a0a264461ff80 100644 --- a/packages/next/src/lib/server-external-packages.json +++ b/packages/next/src/lib/server-external-packages.json @@ -6,6 +6,7 @@ "autoprefixer", "aws-crt", "bcrypt", + "better-sqlite3", "canvas", "cypress", "eslint", From 2a8961b36b5cbe44ea515bbffbd3e557c74efad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 20 Mar 2023 23:33:44 +0100 Subject: [PATCH 579/672] fix(cli): unify styles/content of templates (#47294) ### What? - fixes some typos - [x] getting started by editing "filename" - [x] match app/pages content - [x] fix utm params - [x] Reverted different text coloring in the CLI as they were hard to read on a dark background - [x] removes 13 ([Slack thread](https://vercel.slack.com/archives/C03KAR5DCKC/p1679151687968809?thread_ts=1679123593.519319&cid=C03KAR5DCKC)) ### Why? Unifying the styles across all templates ### How? Used https://github.com/vercel/next.js/tree/canary/packages/create-next-app/templates/default/js as the base and made sure that all other templates match its content and styling. Related: #46927. This PR was extracted from #47238 to make reviewing easier. fix NEXT-851 ([link](https://linear.app/vercel/issue/NEXT-851)) --------- Co-authored-by: JJ Kasper --- packages/create-next-app/index.ts | 6 +- .../templates/app-tw/js/app/page.js | 41 ++++++----- .../templates/app-tw/js/public/thirteen.svg | 1 - .../templates/app-tw/ts/app/page.tsx | 39 +++++++---- .../templates/app-tw/ts/public/thirteen.svg | 1 - .../templates/app/js/app/page.js | 17 ++++- .../templates/app/js/app/page.module.css | 70 ++++--------------- .../templates/app/js/public/thirteen.svg | 1 - .../templates/app/ts/app/page.module.css | 70 ++++--------------- .../templates/app/ts/app/page.tsx | 17 ++++- .../templates/app/ts/public/thirteen.svg | 1 - .../templates/default-tw/js/pages/index.js | 51 ++++++++------ .../default-tw/js/public/thirteen.svg | 1 - .../templates/default-tw/ts/pages/index.tsx | 51 ++++++++------ .../default-tw/ts/public/thirteen.svg | 1 - .../templates/default/js/pages/index.js | 9 --- .../templates/default/js/public/thirteen.svg | 1 - .../default/js/styles/Home.module.css | 53 +------------- .../templates/default/ts/pages/index.tsx | 9 --- .../templates/default/ts/public/thirteen.svg | 1 - .../default/ts/styles/Home.module.css | 53 +------------- 21 files changed, 172 insertions(+), 322 deletions(-) delete mode 100644 packages/create-next-app/templates/app-tw/js/public/thirteen.svg delete mode 100644 packages/create-next-app/templates/app-tw/ts/public/thirteen.svg delete mode 100644 packages/create-next-app/templates/app/js/public/thirteen.svg delete mode 100644 packages/create-next-app/templates/app/ts/public/thirteen.svg delete mode 100644 packages/create-next-app/templates/default-tw/js/public/thirteen.svg delete mode 100644 packages/create-next-app/templates/default-tw/ts/public/thirteen.svg delete mode 100644 packages/create-next-app/templates/default/js/public/thirteen.svg delete mode 100644 packages/create-next-app/templates/default/ts/public/thirteen.svg diff --git a/packages/create-next-app/index.ts b/packages/create-next-app/index.ts index 873bf9b2d08d06..a7a139e731c914 100644 --- a/packages/create-next-app/index.ts +++ b/packages/create-next-app/index.ts @@ -243,7 +243,7 @@ async function run(): Promise { program.typescript = false program.javascript = true } else { - const styledTypeScript = chalk.hex('#0645ad')('TypeScript') + const styledTypeScript = chalk.hex('#007acc')('TypeScript') const { typescript } = await prompts( { type: 'toggle', @@ -280,7 +280,7 @@ async function run(): Promise { if (ciInfo.isCI) { program.eslint = true } else { - const styledEslint = chalk.hex('#4b32c3')('ESLint') + const styledEslint = chalk.hex('#007acc')('ESLint') const { eslint } = await prompts({ onState: onPromptState, type: 'toggle', @@ -302,7 +302,7 @@ async function run(): Promise { if (ciInfo.isCI) { program.tailwind = false } else { - const tw = chalk.hex('#38BDF8')('Tailwind CSS') + const tw = chalk.hex('#007acc')('Tailwind CSS') const { tailwind } = await prompts({ onState: onPromptState, type: 'toggle', diff --git a/packages/create-next-app/templates/app-tw/js/app/page.js b/packages/create-next-app/templates/app-tw/js/app/page.js index 2dde70859cb6db..17f92c320b9a35 100644 --- a/packages/create-next-app/templates/app-tw/js/app/page.js +++ b/packages/create-next-app/templates/app-tw/js/app/page.js @@ -9,7 +9,7 @@ export default function Home() {

Get started by editing  - app/page.tsx + app/page.js

-
+
-
- 13 -
-
+

Find in-depth information about Next.js features and API.

+ +

+ Learn{' '} + + -> + +

+

+ Learn about Next.js in an interactive course with quizzes! +

+
+

Explore the Next.js 13 playground.

@@ -104,7 +113,7 @@ export default function Home() {

Instantly deploy your Next.js site to a shareable URL with Vercel.

diff --git a/packages/create-next-app/templates/app-tw/js/public/thirteen.svg b/packages/create-next-app/templates/app-tw/js/public/thirteen.svg deleted file mode 100644 index 8977c1bd123cbe..00000000000000 --- a/packages/create-next-app/templates/app-tw/js/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/create-next-app/templates/app-tw/ts/app/page.tsx b/packages/create-next-app/templates/app-tw/ts/app/page.tsx index 2dde70859cb6db..7c63b71360453f 100644 --- a/packages/create-next-app/templates/app-tw/ts/app/page.tsx +++ b/packages/create-next-app/templates/app-tw/ts/app/page.tsx @@ -31,7 +31,7 @@ export default function Home() {
-
+
-
- 13 -
-
+

Find in-depth information about Next.js features and API.

+ +

+ Learn{' '} + + -> + +

+

+ Learn about Next.js in an interactive course with quizzes! +

+
+

Explore the Next.js 13 playground.

@@ -104,7 +113,7 @@ export default function Home() {

Instantly deploy your Next.js site to a shareable URL with Vercel.

diff --git a/packages/create-next-app/templates/app-tw/ts/public/thirteen.svg b/packages/create-next-app/templates/app-tw/ts/public/thirteen.svg deleted file mode 100644 index 8977c1bd123cbe..00000000000000 --- a/packages/create-next-app/templates/app-tw/ts/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/create-next-app/templates/app/js/app/page.js b/packages/create-next-app/templates/app/js/app/page.js index 241b72c0f7f79a..dff89aaea026d1 100644 --- a/packages/create-next-app/templates/app/js/app/page.js +++ b/packages/create-next-app/templates/app/js/app/page.js @@ -40,9 +40,6 @@ export default function Home() { height={37} priority /> -
- 13 -
@@ -60,6 +57,20 @@ export default function Home() {

+ +

+ Learn -> +

+

+ Learn about Next.js in an interactive course with quizzes! +

+
+ \ No newline at end of file diff --git a/packages/create-next-app/templates/app/ts/app/page.module.css b/packages/create-next-app/templates/app/ts/app/page.module.css index 4732b55fdc2370..9411a5e6f26a57 100644 --- a/packages/create-next-app/templates/app/ts/app/page.module.css +++ b/packages/create-next-app/templates/app/ts/app/page.module.css @@ -20,8 +20,8 @@ .description a { display: flex; - align-items: center; justify-content: center; + align-items: center; gap: 0.5rem; } @@ -41,7 +41,7 @@ .grid { display: grid; - grid-template-columns: repeat(3, minmax(33%, auto)); + grid-template-columns: repeat(4, minmax(25%, auto)); width: var(--max-width); max-width: 100%; } @@ -69,7 +69,7 @@ opacity: 0.6; font-size: 0.9rem; line-height: 1.5; - max-width: 34ch; + max-width: 30ch; } .center { @@ -104,53 +104,9 @@ transform: translateZ(0); } -.logo, -.thirteen { +.logo { position: relative; } - -.thirteen { - display: flex; - justify-content: center; - align-items: center; - width: 75px; - height: 75px; - padding: 25px 10px; - margin-left: 16px; - transform: translateZ(0); - border-radius: var(--border-radius); - overflow: hidden; - box-shadow: 0px 2px 8px -1px #0000001a; -} - -.thirteen::before, -.thirteen::after { - content: ''; - position: absolute; - z-index: -1; -} - -/* Conic Gradient Animation */ -.thirteen::before { - animation: 6s rotate linear infinite; - width: 200%; - height: 200%; - background: var(--tile-border); -} - -/* Inner Square */ -.thirteen::after { - inset: 0; - padding: 1px; - border-radius: var(--border-radius); - background: linear-gradient( - to bottom right, - rgba(var(--tile-start-rgb), 1), - rgba(var(--tile-end-rgb), 1) - ); - background-clip: content-box; -} - /* Enable hover only on non-touch devices */ @media (hover: hover) and (pointer: fine) { .card:hover { @@ -164,17 +120,13 @@ } @media (prefers-reduced-motion) { - .thirteen::before { - animation: none; - } - .card:hover span { transform: none; } } -/* Mobile and Tablet */ -@media (max-width: 1023px) { +/* Mobile */ +@media (max-width: 700px) { .content { padding: 4rem; } @@ -250,13 +202,19 @@ } } +/* Tablet and Smaller Desktop */ +@media (min-width: 701px) and (max-width: 1120px) { + .grid { + grid-template-columns: repeat(2, 50%); + } +} + @media (prefers-color-scheme: dark) { .vercelLogo { filter: invert(1); } - .logo, - .thirteen img { + .logo { filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); } } diff --git a/packages/create-next-app/templates/app/ts/app/page.tsx b/packages/create-next-app/templates/app/ts/app/page.tsx index 965f40ed2bd927..01946f7979e18f 100644 --- a/packages/create-next-app/templates/app/ts/app/page.tsx +++ b/packages/create-next-app/templates/app/ts/app/page.tsx @@ -40,9 +40,6 @@ export default function Home() { height={37} priority /> -
- 13 -
@@ -60,6 +57,20 @@ export default function Home() {

+ +

+ Learn -> +

+

+ Learn about Next.js in an interactive course with quizzes! +

+
+ \ No newline at end of file diff --git a/packages/create-next-app/templates/default-tw/js/pages/index.js b/packages/create-next-app/templates/default-tw/js/pages/index.js index 2dde70859cb6db..3642a79d82f71e 100644 --- a/packages/create-next-app/templates/default-tw/js/pages/index.js +++ b/packages/create-next-app/templates/default-tw/js/pages/index.js @@ -9,12 +9,12 @@ export default function Home() { -
+
-
- 13 -
-
+

Find in-depth information about Next.js features and API.

+

+ Learn{' '} + + -> + +

+

+ Learn about Next.js in an interactive course with quizzes! +

+
+ +

- Explore the Next.js 13 playground. + Discover and deploy boilerplate example Next.js projects.

Instantly deploy your Next.js site to a shareable URL with Vercel.

diff --git a/packages/create-next-app/templates/default-tw/js/public/thirteen.svg b/packages/create-next-app/templates/default-tw/js/public/thirteen.svg deleted file mode 100644 index 8977c1bd123cbe..00000000000000 --- a/packages/create-next-app/templates/default-tw/js/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/create-next-app/templates/default-tw/ts/pages/index.tsx b/packages/create-next-app/templates/default-tw/ts/pages/index.tsx index 2dde70859cb6db..744cbef1bb5ab3 100644 --- a/packages/create-next-app/templates/default-tw/ts/pages/index.tsx +++ b/packages/create-next-app/templates/default-tw/ts/pages/index.tsx @@ -9,12 +9,12 @@ export default function Home() {
-
+
-
- 13 -
-
+

Find in-depth information about Next.js features and API.

+

+ Learn{' '} + + -> + +

+

+ Learn about Next.js in an interactive course with quizzes! +

+
+ +

- Explore the Next.js 13 playground. + Discover and deploy boilerplate example Next.js projects.

Instantly deploy your Next.js site to a shareable URL with Vercel.

diff --git a/packages/create-next-app/templates/default-tw/ts/public/thirteen.svg b/packages/create-next-app/templates/default-tw/ts/public/thirteen.svg deleted file mode 100644 index 8977c1bd123cbe..00000000000000 --- a/packages/create-next-app/templates/default-tw/ts/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/create-next-app/templates/default/js/pages/index.js b/packages/create-next-app/templates/default/js/pages/index.js index 486c7fa248e3c7..54bc281694f05d 100644 --- a/packages/create-next-app/templates/default/js/pages/index.js +++ b/packages/create-next-app/templates/default/js/pages/index.js @@ -48,15 +48,6 @@ export default function Home() { height={37} priority /> -
- 13 -
diff --git a/packages/create-next-app/templates/default/js/public/thirteen.svg b/packages/create-next-app/templates/default/js/public/thirteen.svg deleted file mode 100644 index 8977c1bd123cbe..00000000000000 --- a/packages/create-next-app/templates/default/js/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/create-next-app/templates/default/js/styles/Home.module.css b/packages/create-next-app/templates/default/js/styles/Home.module.css index 27dfff5ec4cf88..9411a5e6f26a57 100644 --- a/packages/create-next-app/templates/default/js/styles/Home.module.css +++ b/packages/create-next-app/templates/default/js/styles/Home.module.css @@ -104,53 +104,9 @@ transform: translateZ(0); } -.logo, -.thirteen { +.logo { position: relative; } - -.thirteen { - display: flex; - justify-content: center; - align-items: center; - width: 75px; - height: 75px; - padding: 25px 10px; - margin-left: 16px; - transform: translateZ(0); - border-radius: var(--border-radius); - overflow: hidden; - box-shadow: 0px 2px 8px -1px #0000001a; -} - -.thirteen::before, -.thirteen::after { - content: ''; - position: absolute; - z-index: -1; -} - -/* Conic Gradient Animation */ -.thirteen::before { - animation: 6s rotate linear infinite; - width: 200%; - height: 200%; - background: var(--tile-border); -} - -/* Inner Square */ -.thirteen::after { - inset: 0; - padding: 1px; - border-radius: var(--border-radius); - background: linear-gradient( - to bottom right, - rgba(var(--tile-start-rgb), 1), - rgba(var(--tile-end-rgb), 1) - ); - background-clip: content-box; -} - /* Enable hover only on non-touch devices */ @media (hover: hover) and (pointer: fine) { .card:hover { @@ -164,10 +120,6 @@ } @media (prefers-reduced-motion) { - .thirteen::before { - animation: none; - } - .card:hover span { transform: none; } @@ -262,8 +214,7 @@ filter: invert(1); } - .logo, - .thirteen img { + .logo { filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); } } diff --git a/packages/create-next-app/templates/default/ts/pages/index.tsx b/packages/create-next-app/templates/default/ts/pages/index.tsx index e9211487341314..8c2467c810f5d6 100644 --- a/packages/create-next-app/templates/default/ts/pages/index.tsx +++ b/packages/create-next-app/templates/default/ts/pages/index.tsx @@ -48,15 +48,6 @@ export default function Home() { height={37} priority /> -
- 13 -
diff --git a/packages/create-next-app/templates/default/ts/public/thirteen.svg b/packages/create-next-app/templates/default/ts/public/thirteen.svg deleted file mode 100644 index 8977c1bd123cbe..00000000000000 --- a/packages/create-next-app/templates/default/ts/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/create-next-app/templates/default/ts/styles/Home.module.css b/packages/create-next-app/templates/default/ts/styles/Home.module.css index 27dfff5ec4cf88..9411a5e6f26a57 100644 --- a/packages/create-next-app/templates/default/ts/styles/Home.module.css +++ b/packages/create-next-app/templates/default/ts/styles/Home.module.css @@ -104,53 +104,9 @@ transform: translateZ(0); } -.logo, -.thirteen { +.logo { position: relative; } - -.thirteen { - display: flex; - justify-content: center; - align-items: center; - width: 75px; - height: 75px; - padding: 25px 10px; - margin-left: 16px; - transform: translateZ(0); - border-radius: var(--border-radius); - overflow: hidden; - box-shadow: 0px 2px 8px -1px #0000001a; -} - -.thirteen::before, -.thirteen::after { - content: ''; - position: absolute; - z-index: -1; -} - -/* Conic Gradient Animation */ -.thirteen::before { - animation: 6s rotate linear infinite; - width: 200%; - height: 200%; - background: var(--tile-border); -} - -/* Inner Square */ -.thirteen::after { - inset: 0; - padding: 1px; - border-radius: var(--border-radius); - background: linear-gradient( - to bottom right, - rgba(var(--tile-start-rgb), 1), - rgba(var(--tile-end-rgb), 1) - ); - background-clip: content-box; -} - /* Enable hover only on non-touch devices */ @media (hover: hover) and (pointer: fine) { .card:hover { @@ -164,10 +120,6 @@ } @media (prefers-reduced-motion) { - .thirteen::before { - animation: none; - } - .card:hover span { transform: none; } @@ -262,8 +214,7 @@ filter: invert(1); } - .logo, - .thirteen img { + .logo { filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); } } From 765744e333ad0b856f8c9e57f03c0bf8bf21d3b0 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 20 Mar 2023 16:57:48 -0600 Subject: [PATCH 580/672] Change App Route Route Handler signature (#47268) In preparation for improvements for the runtime support, this changes the handle signature to _always_ return a response object. fix NEXT-679 ([link](https://linear.app/vercel/issue/NEXT-679)) --- .../next-edge-app-route-loader/handle.ts | 17 +- packages/next/src/export/worker.ts | 31 +-- packages/next/src/server/base-server.ts | 81 +++++--- .../route-handler-manager.ts | 15 +- .../route-handlers/app-page-route-handler.ts | 2 +- .../route-handlers/app-route-route-handler.ts | 196 ++++++++---------- .../route-handlers/pages-api-route-handler.ts | 2 +- .../route-handlers/pages-route-handler.ts | 2 +- .../future/route-handlers/route-handler.ts | 5 +- packages/next/src/server/send-response.ts | 57 +++++ 10 files changed, 227 insertions(+), 181 deletions(-) create mode 100644 packages/next/src/server/send-response.ts diff --git a/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts b/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts index cd30c8679fd058..9515af0e1a15b7 100644 --- a/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts +++ b/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts @@ -19,8 +19,12 @@ type HandleProps = { } export function getHandle({ page, mod, nextConfigOutput }: HandleProps) { - const appRouteRouteHandler = new AppRouteRouteHandler(nextConfigOutput) - const appRouteRouteMatcher = new AppRouteRouteMatcher({ + const handler = new AppRouteRouteHandler(nextConfigOutput) + + // Set the module on the handler so it can be used when we handle the request. + handler.module = mod + + const matcher = new AppRouteRouteMatcher({ kind: RouteKind.APP_ROUTE, pathname: normalizeAppPath(page), page: '', @@ -31,17 +35,16 @@ export function getHandle({ page, mod, nextConfigOutput }: HandleProps) { return async function handle(request: Request) { const extendedReq = new WebNextRequest(request) const extendedRes = new WebNextResponse() - const match = appRouteRouteMatcher.match( + const match = matcher.match( removeTrailingSlash(new URL(request.url).pathname) )! - const response = await appRouteRouteHandler.execute( + + const response = await handler.handle( match, - mod, extendedReq, extendedRes, // TODO: pass incrementalCache here - { supportsDynamicHTML: true }, - request + { supportsDynamicHTML: true } ) return response diff --git a/packages/next/src/export/worker.ts b/packages/next/src/export/worker.ts index 8bffda27492079..3b100743533a95 100644 --- a/packages/next/src/export/worker.ts +++ b/packages/next/src/export/worker.ts @@ -41,6 +41,7 @@ import { RouteKind } from '../server/future/route-kind' import { NodeNextRequest, NodeNextResponse } from '../server/base-http/node' import { StaticGenerationContext } from '../server/future/route-handlers/app-route-route-handler' import { isAppRouteRoute } from '../lib/is-app-route-route' +import { AppRouteRouteMatch } from '../server/future/route-matches/app-route-route-match' loadRequireHook() @@ -393,24 +394,26 @@ export default async function exportPage({ incrementalCache: curRenderOpts.incrementalCache, } + const match: AppRouteRouteMatch = { + params: query, + definition: { + filename: posix.join(distDir, 'server', 'app', page), + bundlePath: posix.join('app', page), + kind: RouteKind.APP_ROUTE, + page, + pathname: path, + }, + } + try { - const routeHandler = new AppRouteRouteHandler(nextConfigOuput) - const response: Response = await routeHandler.handle( - { - params: query, - definition: { - filename: posix.join(distDir, 'server', 'app', page), - bundlePath: posix.join('app', page), - kind: RouteKind.APP_ROUTE, - page, - pathname: path, - }, - }, + const handler = new AppRouteRouteHandler(nextConfigOuput) + const response = await handler.handle( + match, nodeReq, nodeRes, - staticContext, - true + staticContext ) + // we don't consider error status for static generation // except for 404 // TODO: do we want to cache other status codes? diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 734b32c2d94a4a..12292fbf3cd805 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -92,8 +92,10 @@ import { PagesRouteMatcherProvider } from './future/route-matcher-providers/page import { ServerManifestLoader } from './future/route-matcher-providers/helpers/manifest-loaders/server-manifest-loader' import { getTracer, SpanKind } from './lib/trace/tracer' import { BaseServerSpan } from './lib/trace/constants' -import { sendResponse } from './future/route-handlers/app-route-route-handler' import { I18NProvider } from './future/helpers/i18n-provider' +import { sendResponse } from './send-response' +import { RouteKind } from './future/route-kind' +import { handleInternalServerErrorResponse } from './future/helpers/response-handlers' export type FindComponentsResult = { components: LoadComponentsReturnType @@ -1456,37 +1458,56 @@ export default abstract class Server { supportsDynamicHTML, incrementalCache, } - let response: Response | undefined = (await this.handlers.handle( - match, - req, - res, - context, - isSSG - )) as any - - if (response) { - if (isSSG && process.env.NEXT_RUNTIME !== 'edge') { - const blob = await response.blob() - const headers = Object.fromEntries(response.headers) - if (!headers['content-type'] && blob.type) { - headers['content-type'] = blob.type - } - const cacheEntry: ResponseCacheEntry = { - value: { - kind: 'ROUTE', - status: response.status, - body: Buffer.from(await blob.arrayBuffer()), - headers, - }, - revalidate: - ((context as any).store as any as { revalidate?: number }) - .revalidate || false, + + try { + // Handle the match and collect the response if it's a static response. + const response = await this.handlers.handle(match, req, res, context) + if (response) { + // If the request is for a static response, we can cache it so long + // as it's not edge. + if (isSSG && process.env.NEXT_RUNTIME !== 'edge') { + const blob = await response.blob() + + // Copy the headers from the response. + const headers = Object.fromEntries(response.headers) + if (!headers['content-type'] && blob.type) { + headers['content-type'] = blob.type + } + + // Create the cache entry for the response. + const cacheEntry: ResponseCacheEntry = { + value: { + kind: 'ROUTE', + status: response.status, + body: Buffer.from(await blob.arrayBuffer()), + headers, + }, + revalidate: + ((context as any).store as any as { revalidate?: number }) + .revalidate || false, + } + + return cacheEntry } - return cacheEntry + + // Send the response now that we have copied it into the cache. + await sendResponse(req, res, response) + + return null + } + } catch (err) { + // If an error was thrown while handling an app route request, we + // should return a 500 response. + if (match.definition.kind === RouteKind.APP_ROUTE) { + // If this is during static generation, throw the error again. + if (isSSG) throw err + + // Otherwise, send a 500 response. + Log.error(err) + await sendResponse(req, res, handleInternalServerErrorResponse()) + + return null } - // dynamic response so send here - await sendResponse(req, res, response) - return null } } diff --git a/packages/next/src/server/future/route-handler-managers/route-handler-manager.ts b/packages/next/src/server/future/route-handler-managers/route-handler-manager.ts index 764c8c2ceaaacc..e226f5e6855f3c 100644 --- a/packages/next/src/server/future/route-handler-managers/route-handler-manager.ts +++ b/packages/next/src/server/future/route-handler-managers/route-handler-manager.ts @@ -26,17 +26,14 @@ export class RouteHandlerManager { match: RouteMatch, req: BaseNextRequest, res: BaseNextResponse, - context?: any, - bubbleResult?: boolean - ): Promise { + context?: any + ): Promise { const handler = this.handlers[match.definition.kind] - if (!handler) return false + if (!handler) return - const result = await handler.handle(match, req, res, context, bubbleResult) + // Get the response from the handler. + const response = await handler.handle(match, req, res, context) - if (bubbleResult) { - return result as any - } - return true + return response } } diff --git a/packages/next/src/server/future/route-handlers/app-page-route-handler.ts b/packages/next/src/server/future/route-handlers/app-page-route-handler.ts index 3f0430d1fd6e6d..782fdd67aca070 100644 --- a/packages/next/src/server/future/route-handlers/app-page-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/app-page-route-handler.ts @@ -2,7 +2,7 @@ import { AppPageRouteMatch } from '../route-matches/app-page-route-match' import { RouteHandler } from './route-handler' export class AppPageRouteHandler implements RouteHandler { - public async handle(): Promise { + public async handle(): Promise { throw new Error('Method not implemented.') } } diff --git a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts index e96a361a697c65..c0732cf0560802 100644 --- a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts @@ -13,8 +13,8 @@ import { RequestAsyncStorageWrapper, type RequestContext, } from '../../async-storage/request-async-storage-wrapper' -import type { BaseNextRequest, BaseNextResponse } from '../../base-http' -import type { NodeNextRequest, NodeNextResponse } from '../../base-http/node' +import { BaseNextRequest, BaseNextResponse } from '../../base-http' +import { NodeNextRequest, NodeNextResponse } from '../../base-http/node' import { getRequestMeta } from '../../request-meta' import { handleBadRequestResponse, @@ -38,6 +38,8 @@ import { AppConfig } from '../../../build/utils' import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies' import { NextURL } from '../../web/next-url' import { NextConfig } from '../../config-shared' +import { AppRouteRouteDefinition } from '../route-definitions/app-route-route-definition' +import { WebNextRequest } from '../../base-http/web' // TODO-APP: This module has a dynamic require so when bundling for edge it causes issues. const NodeModuleLoader = @@ -104,7 +106,7 @@ export type StaticGenerationContext = { * @param req base request to adapt for use with app routes * @returns the wrapped request. */ -function wrapRequest(req: BaseNextRequest): Request { +function wrapRequest(req: BaseNextRequest): NextRequest { const { originalRequest } = req as NodeNextRequest const url = getRequestMeta(originalRequest, '__NEXT_INIT_URL') @@ -123,7 +125,7 @@ function wrapRequest(req: BaseNextRequest): Request { }) } -function resolveHandlerError(err: any, bubbleResult?: boolean): Response { +function resolveHandlerError(err: any): Response | false { if (isRedirectError(err)) { const redirect = getURLFromRedirectError(err) if (!redirect) { @@ -139,60 +141,8 @@ function resolveHandlerError(err: any, bubbleResult?: boolean): Response { return handleNotFoundResponse() } - if (bubbleResult) { - throw err - } - // TODO: validate the correct handling behavior - Log.error(err) - return handleInternalServerErrorResponse() -} - -export async function sendResponse( - req: BaseNextRequest, - res: BaseNextResponse, - response: Response -): Promise { - // Don't use in edge runtime - if (process.env.NEXT_RUNTIME !== 'edge') { - // Copy over the response status. - res.statusCode = response.status - res.statusMessage = response.statusText - - // Copy over the response headers. - response.headers?.forEach((value, name) => { - // The append handling is special cased for `set-cookie`. - if (name.toLowerCase() === 'set-cookie') { - res.setHeader(name, value) - } else { - res.appendHeader(name, value) - } - }) - - /** - * The response can't be directly piped to the underlying response. The - * following is duplicated from the edge runtime handler. - * - * See packages/next/server/next-server.ts - */ - - const originalResponse = (res as NodeNextResponse).originalResponse - - // A response body must not be sent for HEAD requests. See https://httpwg.org/specs/rfc9110.html#HEAD - if (response.body && req.method !== 'HEAD') { - const { consumeUint8ArrayReadableStream } = - require('next/dist/compiled/edge-runtime') as typeof import('next/dist/compiled/edge-runtime') - const iterator = consumeUint8ArrayReadableStream(response.body) - try { - for await (const chunk of iterator) { - originalResponse.write(chunk) - } - } finally { - originalResponse.end() - } - } else { - originalResponse.end() - } - } + // Return false to indicate that this is not a handled error. + return false } function cleanURL(urlString: string): string { @@ -203,7 +153,10 @@ function cleanURL(urlString: string): string { return url.toString() } -function proxyRequest(req: NextRequest, module: AppRouteModule): NextRequest { +function proxyRequest( + req: NextRequest | Request, + module: AppRouteModule +): Request { function handleNextUrlBailout(prop: string | symbol) { switch (prop) { case 'search': @@ -263,30 +216,33 @@ function proxyRequest(req: NextRequest, module: AppRouteModule): NextRequest { } } - const wrappedNextUrl = new Proxy(req.nextUrl, { - get(target, prop) { - handleNextUrlBailout(prop) - - if ( - module.handlers.dynamic === 'force-static' && - typeof prop === 'string' - ) { - const result = handleForceStatic(target.href, prop) - if (result !== undefined) return result - } - const value = (target as any)[prop] + const wrappedNextUrl = + 'nextUrl' in req + ? new Proxy(req.nextUrl, { + get(target, prop) { + handleNextUrlBailout(prop) + + if ( + module.handlers.dynamic === 'force-static' && + typeof prop === 'string' + ) { + const result = handleForceStatic(target.href, prop) + if (result !== undefined) return result + } + const value = (target as any)[prop] - if (typeof value === 'function') { - return value.bind(target) - } - return value - }, - set(target, prop, value) { - handleNextUrlBailout(prop) - ;(target as any)[prop] = value - return true - }, - }) + if (typeof value === 'function') { + return value.bind(target) + } + return value + }, + set(target, prop, value) { + handleNextUrlBailout(prop) + ;(target as any)[prop] = value + return true + }, + }) + : undefined const handleReqBailout = (prop: string | symbol) => { switch (prop) { @@ -377,6 +333,12 @@ function validateModule(mod: AppRouteModule) { } export class AppRouteRouteHandler implements RouteHandler { + /** + * The module for this handler. When set, this will be used instead of loading + * the module from the loader. + */ + public module: AppRouteModule | undefined + constructor( private readonly nextConfigOutput: NextConfig['output'] = undefined, private readonly requestAsyncLocalStorageWrapper: AsyncStorageWrapper< @@ -449,16 +411,38 @@ export class AppRouteRouteHandler implements RouteHandler { return handleMethodNotAllowedResponse } + /** + * Loads and patches the module for the given route definition unless it's + * already been loaded. + * + * @param definition the route definition to load the module for + * @returns the loaded and patched module + */ + private async load( + definition: AppRouteRouteDefinition + ): Promise { + // Modules that have been provided by the user are already patched. + if (this.module) return this.module + + // Load the module using the module loader. + const module = await this.moduleLoader.load(definition.filename) + + // Patch the module with the fetch polyfill. + patchFetch(module) + + return module + } + // TODO-APP: this is temporarily used for edge. public async execute( { params, definition }: AppRouteRouteMatch, - module: AppRouteModule, req: BaseNextRequest, res: BaseNextResponse, - context?: StaticGenerationContext, - // TODO-APP: this is temporarily used for edge. - request?: Request + context?: StaticGenerationContext ): Promise { + // Load the module. + const module = await this.load(definition) + // Get the handler function for the given method. const handle = this.resolve(req.method, module) @@ -544,8 +528,7 @@ export class AppRouteRouteHandler implements RouteHandler { // Wrap the request so we can add additional functionality to cases // that might change it's output or affect the rendering. const wrappedRequest = proxyRequest( - // TODO: investigate why/how this cast is necessary/possible - (request ? request : wrapRequest(req)) as NextRequest, + req instanceof WebNextRequest ? req.request : wrapRequest(req), module ) @@ -601,38 +584,21 @@ export class AppRouteRouteHandler implements RouteHandler { match: AppRouteRouteMatch, req: BaseNextRequest, res: BaseNextResponse, - context?: StaticGenerationContext, - bubbleResult?: boolean - ): Promise { + context?: StaticGenerationContext + ): Promise { try { - // Load the module using the module loader. - const appRouteModule: AppRouteModule = await this.moduleLoader.load( - match.definition.filename - ) - patchFetch(appRouteModule) - // Execute the route to get the response. - const response = await this.execute( - match, - appRouteModule, - req, - res, - context - ) + const response = await this.execute(match, req, res, context) - if (bubbleResult) { - return response - } - // Send the response back to the response. - await sendResponse(req, res, response) + // The response was handled, return it. + return response } catch (err) { - const response = resolveHandlerError(err, bubbleResult) + // Try to resolve the error to a response, else throw it again. + const response = resolveHandlerError(err) + if (!response) throw err - if (bubbleResult) { - return response - } - // Get the correct response based on the error. - await sendResponse(req, res, response) + // The response was resolved, return it. + return response } } } diff --git a/packages/next/src/server/future/route-handlers/pages-api-route-handler.ts b/packages/next/src/server/future/route-handlers/pages-api-route-handler.ts index 7887161394d8d7..fd7860d4e3bd19 100644 --- a/packages/next/src/server/future/route-handlers/pages-api-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/pages-api-route-handler.ts @@ -2,7 +2,7 @@ import { PagesAPIRouteMatch } from '../route-matches/pages-api-route-match' import { RouteHandler } from './route-handler' export class PagesAPIRouteHandler implements RouteHandler { - public async handle(): Promise { + public async handle(): Promise { throw new Error('Method not implemented.') } } diff --git a/packages/next/src/server/future/route-handlers/pages-route-handler.ts b/packages/next/src/server/future/route-handlers/pages-route-handler.ts index f33efb0850f4a9..8538a455abccbd 100644 --- a/packages/next/src/server/future/route-handlers/pages-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/pages-route-handler.ts @@ -2,7 +2,7 @@ import { PagesRouteMatch } from '../route-matches/pages-route-match' import { RouteHandler } from './route-handler' export class PagesRouteHandler implements RouteHandler { - public async handle(): Promise { + public async handle(): Promise { throw new Error('Method not implemented.') } } diff --git a/packages/next/src/server/future/route-handlers/route-handler.ts b/packages/next/src/server/future/route-handlers/route-handler.ts index c0976a90213dac..f9c88f9901de50 100644 --- a/packages/next/src/server/future/route-handlers/route-handler.ts +++ b/packages/next/src/server/future/route-handlers/route-handler.ts @@ -6,7 +6,6 @@ export interface RouteHandler { match: M, req: BaseNextRequest, res: BaseNextResponse, - context?: any, - bubbleResult?: boolean - ): Promise + context?: any + ): Promise } diff --git a/packages/next/src/server/send-response.ts b/packages/next/src/server/send-response.ts new file mode 100644 index 00000000000000..b5fe049f54b0dc --- /dev/null +++ b/packages/next/src/server/send-response.ts @@ -0,0 +1,57 @@ +import type { BaseNextRequest, BaseNextResponse } from './base-http' +import type { NodeNextResponse } from './base-http/node' + +/** + * Sends the response on the underlying next response object. + * + * @param req the underlying request object + * @param res the underlying response object + * @param response the response to send + */ +export async function sendResponse( + req: BaseNextRequest, + res: BaseNextResponse, + response: Response +): Promise { + // Don't use in edge runtime + if (process.env.NEXT_RUNTIME !== 'edge') { + // Copy over the response status. + res.statusCode = response.status + res.statusMessage = response.statusText + + // Copy over the response headers. + response.headers?.forEach((value, name) => { + // The append handling is special cased for `set-cookie`. + if (name.toLowerCase() === 'set-cookie') { + res.setHeader(name, value) + } else { + res.appendHeader(name, value) + } + }) + + /** + * The response can't be directly piped to the underlying response. The + * following is duplicated from the edge runtime handler. + * + * See packages/next/server/next-server.ts + */ + + const originalResponse = (res as NodeNextResponse).originalResponse + + // A response body must not be sent for HEAD requests. See https://httpwg.org/specs/rfc9110.html#HEAD + if (response.body && req.method !== 'HEAD') { + const { consumeUint8ArrayReadableStream } = + require('next/dist/compiled/edge-runtime') as typeof import('next/dist/compiled/edge-runtime') + const iterator = consumeUint8ArrayReadableStream(response.body) + try { + for await (const chunk of iterator) { + originalResponse.write(chunk) + } + } finally { + originalResponse.end() + } + } else { + originalResponse.end() + } + } +} From cf66c2dc74d476e29db592b78e87841e39517ab5 Mon Sep 17 00:00:00 2001 From: shivanshubisht <77038395+shivanshubisht@users.noreply.github.com> Date: Tue, 21 Mar 2023 05:03:12 +0530 Subject: [PATCH 581/672] Replace bg-opacity with bg-color/opacity in tailwindcss templates (#47253) In Tailwind v3, the bg-opacity has been deprecated in favour of bg-color/opacity. https://tailwindcss.com/docs/background-color#changing-the-opacity --------- Co-authored-by: JJ Kasper --- .../create-next-app/templates/app-tw/js/app/page.js | 8 ++++---- .../create-next-app/templates/app-tw/ts/app/page.tsx | 8 ++++---- .../templates/default-tw/js/pages/index.js | 12 ++++++------ .../templates/default-tw/ts/pages/index.tsx | 12 ++++++------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/create-next-app/templates/app-tw/js/app/page.js b/packages/create-next-app/templates/app-tw/js/app/page.js index 17f92c320b9a35..b66378bdfacc41 100644 --- a/packages/create-next-app/templates/app-tw/js/app/page.js +++ b/packages/create-next-app/templates/app-tw/js/app/page.js @@ -7,7 +7,7 @@ export default function Home() { return (
-

+

Get started by editing  app/page.js

@@ -45,7 +45,7 @@ export default function Home() {
@@ -83,7 +83,7 @@ export default function Home() { @@ -102,7 +102,7 @@ export default function Home() { diff --git a/packages/create-next-app/templates/app-tw/ts/app/page.tsx b/packages/create-next-app/templates/app-tw/ts/app/page.tsx index 7c63b71360453f..bb96e07bde4e0b 100644 --- a/packages/create-next-app/templates/app-tw/ts/app/page.tsx +++ b/packages/create-next-app/templates/app-tw/ts/app/page.tsx @@ -7,7 +7,7 @@ export default function Home() { return (
-

+

Get started by editing  app/page.tsx

@@ -45,7 +45,7 @@ export default function Home() {
-
+ -
+
@@ -64,7 +64,7 @@ export default function Home() { @@ -83,7 +83,7 @@ export default function Home() { @@ -102,7 +102,7 @@ export default function Home() { From 1a47872b64c0b8d1765daa91ef656e7310ea79a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Tue, 21 Mar 2023 01:55:56 +0100 Subject: [PATCH 582/672] chore: fix issue labeler (#47206) ### What? A fork of https://github.com/github/issue-labeler that we pull in and maintain. ### Why? The official issue labeler had some issues which I tried to fix in PRs and eventually got merged upstream, but the release cycle was a bit slow, and that GitHub action had many parts we did not really need anyway. So it makes sense to maintain it ourselves. ### How? This PR removes the https://github.com/vercel/next.js/blob/canary/.github/issue-labeler.yml config file, which in our case is just a sublist of https://github.com/vercel/next.js/labels anyway. Instead, we can pull in the labels from GitHub directly and filter out those that we want to apply to issues. This will keep things more in sync. fix NEXT-750 ([link](https://linear.app/vercel/issue/NEXT-750)) --------- --- .eslintignore | 1 + .github/actions/issue-labeler/.gitignore | 1 + .github/actions/issue-labeler/lib/index.js | 7 + .../actions/issue-labeler/lib/licenses.txt | 635 ++++++++++++++++++ .../actions/issue-labeler/lib/package.json | 3 + .github/actions/issue-labeler/package.json | 18 + .github/actions/issue-labeler/src/index.ts | 102 +++ .github/actions/issue-labeler/tsconfig.json | 10 + .github/issue-labeler.yml | 45 -- .github/workflows/issue_labeler.yml | 11 +- .prettierignore | 1 + 11 files changed, 784 insertions(+), 50 deletions(-) create mode 100644 .github/actions/issue-labeler/.gitignore create mode 100644 .github/actions/issue-labeler/lib/index.js create mode 100644 .github/actions/issue-labeler/lib/licenses.txt create mode 100644 .github/actions/issue-labeler/lib/package.json create mode 100644 .github/actions/issue-labeler/package.json create mode 100644 .github/actions/issue-labeler/src/index.ts create mode 100644 .github/actions/issue-labeler/tsconfig.json delete mode 100644 .github/issue-labeler.yml diff --git a/.eslintignore b/.eslintignore index d3507e8b96a9d4..2ccbb94acecb3e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -20,6 +20,7 @@ packages/react-dev-overlay/lib/** **/__tmp__/** .github/actions/next-stats-action/.work .github/actions/issue-validator/index.mjs +.github/actions/issue-labeler/lib/index.js packages/next-codemod/transforms/__testfixtures__/**/* packages/next-codemod/transforms/__tests__/**/* packages/next-codemod/**/*.js diff --git a/.github/actions/issue-labeler/.gitignore b/.github/actions/issue-labeler/.gitignore new file mode 100644 index 00000000000000..40b878db5b1c97 --- /dev/null +++ b/.github/actions/issue-labeler/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/.github/actions/issue-labeler/lib/index.js b/.github/actions/issue-labeler/lib/index.js new file mode 100644 index 00000000000000..0c1bb23d113ab5 --- /dev/null +++ b/.github/actions/issue-labeler/lib/index.js @@ -0,0 +1,7 @@ +import{createRequire as __WEBPACK_EXTERNAL_createRequire}from"module";var __webpack_modules__={7351:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.issue=p.issueCommand=void 0;const s=r(a(2037));const i=a(5278);function issueCommand(e,p,a){const d=new Command(e,p,a);process.stdout.write(d.toString()+s.EOL)}p.issueCommand=issueCommand;function issue(e,p=""){issueCommand(e,{},p)}p.issue=issue;const o="::";class Command{constructor(e,p,a){if(!e){e="missing.command"}this.command=e;this.properties=p;this.message=a}toString(){let e=o+this.command;if(this.properties&&Object.keys(this.properties).length>0){e+=" ";let p=true;for(const a in this.properties){if(this.properties.hasOwnProperty(a)){const d=this.properties[a];if(d){if(p){p=false}else{e+=","}e+=`${a}=${escapeProperty(d)}`}}}}e+=`${o}${escapeData(this.message)}`;return e}}function escapeData(e){return i.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return i.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}},2186:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};var s=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.getIDToken=p.getState=p.saveState=p.group=p.endGroup=p.startGroup=p.info=p.notice=p.warning=p.error=p.debug=p.isDebug=p.setFailed=p.setCommandEcho=p.setOutput=p.getBooleanInput=p.getMultilineInput=p.getInput=p.addPath=p.setSecret=p.exportVariable=p.ExitCode=void 0;const i=a(7351);const o=a(717);const n=a(5278);const l=r(a(2037));const m=r(a(1017));const u=a(8041);var c;(function(e){e[e["Success"]=0]="Success";e[e["Failure"]=1]="Failure"})(c=p.ExitCode||(p.ExitCode={}));function exportVariable(e,p){const a=n.toCommandValue(p);process.env[e]=a;const d=process.env["GITHUB_ENV"]||"";if(d){return o.issueFileCommand("ENV",o.prepareKeyValueMessage(e,p))}i.issueCommand("set-env",{name:e},a)}p.exportVariable=exportVariable;function setSecret(e){i.issueCommand("add-mask",{},e)}p.setSecret=setSecret;function addPath(e){const p=process.env["GITHUB_PATH"]||"";if(p){o.issueFileCommand("PATH",e)}else{i.issueCommand("add-path",{},e)}process.env["PATH"]=`${e}${m.delimiter}${process.env["PATH"]}`}p.addPath=addPath;function getInput(e,p){const a=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(p&&p.required&&!a){throw new Error(`Input required and not supplied: ${e}`)}if(p&&p.trimWhitespace===false){return a}return a.trim()}p.getInput=getInput;function getMultilineInput(e,p){const a=getInput(e,p).split("\n").filter((e=>e!==""));if(p&&p.trimWhitespace===false){return a}return a.map((e=>e.trim()))}p.getMultilineInput=getMultilineInput;function getBooleanInput(e,p){const a=["true","True","TRUE"];const d=["false","False","FALSE"];const t=getInput(e,p);if(a.includes(t))return true;if(d.includes(t))return false;throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${e}\n`+`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``)}p.getBooleanInput=getBooleanInput;function setOutput(e,p){const a=process.env["GITHUB_OUTPUT"]||"";if(a){return o.issueFileCommand("OUTPUT",o.prepareKeyValueMessage(e,p))}process.stdout.write(l.EOL);i.issueCommand("set-output",{name:e},n.toCommandValue(p))}p.setOutput=setOutput;function setCommandEcho(e){i.issue("echo",e?"on":"off")}p.setCommandEcho=setCommandEcho;function setFailed(e){process.exitCode=c.Failure;error(e)}p.setFailed=setFailed;function isDebug(){return process.env["RUNNER_DEBUG"]==="1"}p.isDebug=isDebug;function debug(e){i.issueCommand("debug",{},e)}p.debug=debug;function error(e,p={}){i.issueCommand("error",n.toCommandProperties(p),e instanceof Error?e.toString():e)}p.error=error;function warning(e,p={}){i.issueCommand("warning",n.toCommandProperties(p),e instanceof Error?e.toString():e)}p.warning=warning;function notice(e,p={}){i.issueCommand("notice",n.toCommandProperties(p),e instanceof Error?e.toString():e)}p.notice=notice;function info(e){process.stdout.write(e+l.EOL)}p.info=info;function startGroup(e){i.issue("group",e)}p.startGroup=startGroup;function endGroup(){i.issue("endgroup")}p.endGroup=endGroup;function group(e,p){return s(this,void 0,void 0,(function*(){startGroup(e);let a;try{a=yield p()}finally{endGroup()}return a}))}p.group=group;function saveState(e,p){const a=process.env["GITHUB_STATE"]||"";if(a){return o.issueFileCommand("STATE",o.prepareKeyValueMessage(e,p))}i.issueCommand("save-state",{name:e},n.toCommandValue(p))}p.saveState=saveState;function getState(e){return process.env[`STATE_${e}`]||""}p.getState=getState;function getIDToken(e){return s(this,void 0,void 0,(function*(){return yield u.OidcClient.getIDToken(e)}))}p.getIDToken=getIDToken;var v=a(1327);Object.defineProperty(p,"summary",{enumerable:true,get:function(){return v.summary}});var h=a(1327);Object.defineProperty(p,"markdownSummary",{enumerable:true,get:function(){return h.markdownSummary}});var g=a(2981);Object.defineProperty(p,"toPosixPath",{enumerable:true,get:function(){return g.toPosixPath}});Object.defineProperty(p,"toWin32Path",{enumerable:true,get:function(){return g.toWin32Path}});Object.defineProperty(p,"toPlatformPath",{enumerable:true,get:function(){return g.toPlatformPath}})},717:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.prepareKeyValueMessage=p.issueFileCommand=void 0;const s=r(a(7147));const i=r(a(2037));const o=a(5840);const n=a(5278);function issueFileCommand(e,p){const a=process.env[`GITHUB_${e}`];if(!a){throw new Error(`Unable to find environment variable for file command ${e}`)}if(!s.existsSync(a)){throw new Error(`Missing file at path: ${a}`)}s.appendFileSync(a,`${n.toCommandValue(p)}${i.EOL}`,{encoding:"utf8"})}p.issueFileCommand=issueFileCommand;function prepareKeyValueMessage(e,p){const a=`ghadelimiter_${o.v4()}`;const d=n.toCommandValue(p);if(e.includes(a)){throw new Error(`Unexpected input: name should not contain the delimiter "${a}"`)}if(d.includes(a)){throw new Error(`Unexpected input: value should not contain the delimiter "${a}"`)}return`${e}<<${a}${i.EOL}${d}${i.EOL}${a}`}p.prepareKeyValueMessage=prepareKeyValueMessage},8041:function(e,p,a){var d=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.OidcClient=void 0;const t=a(6255);const r=a(5526);const s=a(2186);class OidcClient{static createHttpClient(e=true,p=10){const a={allowRetries:e,maxRetries:p};return new t.HttpClient("actions/oidc-client",[new r.BearerCredentialHandler(OidcClient.getRequestToken())],a)}static getRequestToken(){const e=process.env["ACTIONS_ID_TOKEN_REQUEST_TOKEN"];if(!e){throw new Error("Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable")}return e}static getIDTokenUrl(){const e=process.env["ACTIONS_ID_TOKEN_REQUEST_URL"];if(!e){throw new Error("Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable")}return e}static getCall(e){var p;return d(this,void 0,void 0,(function*(){const a=OidcClient.createHttpClient();const d=yield a.getJson(e).catch((e=>{throw new Error(`Failed to get ID Token. \n \n Error Code : ${e.statusCode}\n \n Error Message: ${e.result.message}`)}));const t=(p=d.result)===null||p===void 0?void 0:p.value;if(!t){throw new Error("Response json body do not have ID Token field")}return t}))}static getIDToken(e){return d(this,void 0,void 0,(function*(){try{let p=OidcClient.getIDTokenUrl();if(e){const a=encodeURIComponent(e);p=`${p}&audience=${a}`}s.debug(`ID token url is ${p}`);const a=yield OidcClient.getCall(p);s.setSecret(a);return a}catch(e){throw new Error(`Error message: ${e.message}`)}}))}}p.OidcClient=OidcClient},2981:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.toPlatformPath=p.toWin32Path=p.toPosixPath=void 0;const s=r(a(1017));function toPosixPath(e){return e.replace(/[\\]/g,"/")}p.toPosixPath=toPosixPath;function toWin32Path(e){return e.replace(/[/]/g,"\\")}p.toWin32Path=toWin32Path;function toPlatformPath(e){return e.replace(/[/\\]/g,s.sep)}p.toPlatformPath=toPlatformPath},1327:function(e,p,a){var d=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.summary=p.markdownSummary=p.SUMMARY_DOCS_URL=p.SUMMARY_ENV_VAR=void 0;const t=a(2037);const r=a(7147);const{access:s,appendFile:i,writeFile:o}=r.promises;p.SUMMARY_ENV_VAR="GITHUB_STEP_SUMMARY";p.SUMMARY_DOCS_URL="https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary";class Summary{constructor(){this._buffer=""}filePath(){return d(this,void 0,void 0,(function*(){if(this._filePath){return this._filePath}const e=process.env[p.SUMMARY_ENV_VAR];if(!e){throw new Error(`Unable to find environment variable for $${p.SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.`)}try{yield s(e,r.constants.R_OK|r.constants.W_OK)}catch(p){throw new Error(`Unable to access summary file: '${e}'. Check if the file has correct read/write permissions.`)}this._filePath=e;return this._filePath}))}wrap(e,p,a={}){const d=Object.entries(a).map((([e,p])=>` ${e}="${p}"`)).join("");if(!p){return`<${e}${d}>`}return`<${e}${d}>${p}`}write(e){return d(this,void 0,void 0,(function*(){const p=!!(e===null||e===void 0?void 0:e.overwrite);const a=yield this.filePath();const d=p?o:i;yield d(a,this._buffer,{encoding:"utf8"});return this.emptyBuffer()}))}clear(){return d(this,void 0,void 0,(function*(){return this.emptyBuffer().write({overwrite:true})}))}stringify(){return this._buffer}isEmptyBuffer(){return this._buffer.length===0}emptyBuffer(){this._buffer="";return this}addRaw(e,p=false){this._buffer+=e;return p?this.addEOL():this}addEOL(){return this.addRaw(t.EOL)}addCodeBlock(e,p){const a=Object.assign({},p&&{lang:p});const d=this.wrap("pre",this.wrap("code",e),a);return this.addRaw(d).addEOL()}addList(e,p=false){const a=p?"ol":"ul";const d=e.map((e=>this.wrap("li",e))).join("");const t=this.wrap(a,d);return this.addRaw(t).addEOL()}addTable(e){const p=e.map((e=>{const p=e.map((e=>{if(typeof e==="string"){return this.wrap("td",e)}const{header:p,data:a,colspan:d,rowspan:t}=e;const r=p?"th":"td";const s=Object.assign(Object.assign({},d&&{colspan:d}),t&&{rowspan:t});return this.wrap(r,a,s)})).join("");return this.wrap("tr",p)})).join("");const a=this.wrap("table",p);return this.addRaw(a).addEOL()}addDetails(e,p){const a=this.wrap("details",this.wrap("summary",e)+p);return this.addRaw(a).addEOL()}addImage(e,p,a){const{width:d,height:t}=a||{};const r=Object.assign(Object.assign({},d&&{width:d}),t&&{height:t});const s=this.wrap("img",null,Object.assign({src:e,alt:p},r));return this.addRaw(s).addEOL()}addHeading(e,p){const a=`h${p}`;const d=["h1","h2","h3","h4","h5","h6"].includes(a)?a:"h1";const t=this.wrap(d,e);return this.addRaw(t).addEOL()}addSeparator(){const e=this.wrap("hr",null);return this.addRaw(e).addEOL()}addBreak(){const e=this.wrap("br",null);return this.addRaw(e).addEOL()}addQuote(e,p){const a=Object.assign({},p&&{cite:p});const d=this.wrap("blockquote",e,a);return this.addRaw(d).addEOL()}addLink(e,p){const a=this.wrap("a",e,{href:p});return this.addRaw(a).addEOL()}}const n=new Summary;p.markdownSummary=n;p.summary=n},5278:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p.toCommandProperties=p.toCommandValue=void 0;function toCommandValue(e){if(e===null||e===undefined){return""}else if(typeof e==="string"||e instanceof String){return e}return JSON.stringify(e)}p.toCommandValue=toCommandValue;function toCommandProperties(e){if(!Object.keys(e).length){return{}}return{title:e.title,file:e.file,line:e.startLine,endLine:e.endLine,col:e.startColumn,endColumn:e.endColumn}}p.toCommandProperties=toCommandProperties},4087:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p.Context=void 0;const d=a(7147);const t=a(2037);class Context{constructor(){var e,p,a;this.payload={};if(process.env.GITHUB_EVENT_PATH){if(d.existsSync(process.env.GITHUB_EVENT_PATH)){this.payload=JSON.parse(d.readFileSync(process.env.GITHUB_EVENT_PATH,{encoding:"utf8"}))}else{const e=process.env.GITHUB_EVENT_PATH;process.stdout.write(`GITHUB_EVENT_PATH ${e} does not exist${t.EOL}`)}}this.eventName=process.env.GITHUB_EVENT_NAME;this.sha=process.env.GITHUB_SHA;this.ref=process.env.GITHUB_REF;this.workflow=process.env.GITHUB_WORKFLOW;this.action=process.env.GITHUB_ACTION;this.actor=process.env.GITHUB_ACTOR;this.job=process.env.GITHUB_JOB;this.runNumber=parseInt(process.env.GITHUB_RUN_NUMBER,10);this.runId=parseInt(process.env.GITHUB_RUN_ID,10);this.apiUrl=(e=process.env.GITHUB_API_URL)!==null&&e!==void 0?e:`https://api.github.com`;this.serverUrl=(p=process.env.GITHUB_SERVER_URL)!==null&&p!==void 0?p:`https://github.com`;this.graphqlUrl=(a=process.env.GITHUB_GRAPHQL_URL)!==null&&a!==void 0?a:`https://api.github.com/graphql`}get issue(){const e=this.payload;return Object.assign(Object.assign({},this.repo),{number:(e.issue||e.pull_request||e).number})}get repo(){if(process.env.GITHUB_REPOSITORY){const[e,p]=process.env.GITHUB_REPOSITORY.split("/");return{owner:e,repo:p}}if(this.payload.repository){return{owner:this.payload.repository.owner.login,repo:this.payload.repository.name}}throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'")}}p.Context=Context},5438:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.getOctokit=p.context=void 0;const s=r(a(4087));const i=a(3030);p.context=new s.Context;function getOctokit(e,p,...a){const d=i.GitHub.plugin(...a);return new d(i.getOctokitOptions(e,p))}p.getOctokit=getOctokit},7914:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.getApiBaseUrl=p.getProxyAgent=p.getAuthString=void 0;const s=r(a(6255));function getAuthString(e,p){if(!e&&!p.auth){throw new Error("Parameter token or opts.auth is required")}else if(e&&p.auth){throw new Error("Parameters token and opts.auth may not both be specified")}return typeof p.auth==="string"?p.auth:`token ${e}`}p.getAuthString=getAuthString;function getProxyAgent(e){const p=new s.HttpClient;return p.getAgent(e)}p.getProxyAgent=getProxyAgent;function getApiBaseUrl(){return process.env["GITHUB_API_URL"]||"https://api.github.com"}p.getApiBaseUrl=getApiBaseUrl},3030:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.getOctokitOptions=p.GitHub=p.defaults=p.context=void 0;const s=r(a(4087));const i=r(a(7914));const o=a(6762);const n=a(3044);const l=a(4193);p.context=new s.Context;const m=i.getApiBaseUrl();p.defaults={baseUrl:m,request:{agent:i.getProxyAgent(m)}};p.GitHub=o.Octokit.plugin(n.restEndpointMethods,l.paginateRest).defaults(p.defaults);function getOctokitOptions(e,p){const a=Object.assign({},p||{});const d=i.getAuthString(e,a);if(d){a.auth=d}return a}p.getOctokitOptions=getOctokitOptions},5526:function(e,p){var a=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.PersonalAccessTokenCredentialHandler=p.BearerCredentialHandler=p.BasicCredentialHandler=void 0;class BasicCredentialHandler{constructor(e,p){this.username=e;this.password=p}prepareRequest(e){if(!e.headers){throw Error("The request has no headers")}e.headers["Authorization"]=`Basic ${Buffer.from(`${this.username}:${this.password}`).toString("base64")}`}canHandleAuthentication(){return false}handleAuthentication(){return a(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}}p.BasicCredentialHandler=BasicCredentialHandler;class BearerCredentialHandler{constructor(e){this.token=e}prepareRequest(e){if(!e.headers){throw Error("The request has no headers")}e.headers["Authorization"]=`Bearer ${this.token}`}canHandleAuthentication(){return false}handleAuthentication(){return a(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}}p.BearerCredentialHandler=BearerCredentialHandler;class PersonalAccessTokenCredentialHandler{constructor(e){this.token=e}prepareRequest(e){if(!e.headers){throw Error("The request has no headers")}e.headers["Authorization"]=`Basic ${Buffer.from(`PAT:${this.token}`).toString("base64")}`}canHandleAuthentication(){return false}handleAuthentication(){return a(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}}p.PersonalAccessTokenCredentialHandler=PersonalAccessTokenCredentialHandler},6255:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};var s=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.HttpClient=p.isHttps=p.HttpClientResponse=p.HttpClientError=p.getProxyUrl=p.MediaTypes=p.Headers=p.HttpCodes=void 0;const i=r(a(3685));const o=r(a(5687));const n=r(a(9835));const l=r(a(4294));var m;(function(e){e[e["OK"]=200]="OK";e[e["MultipleChoices"]=300]="MultipleChoices";e[e["MovedPermanently"]=301]="MovedPermanently";e[e["ResourceMoved"]=302]="ResourceMoved";e[e["SeeOther"]=303]="SeeOther";e[e["NotModified"]=304]="NotModified";e[e["UseProxy"]=305]="UseProxy";e[e["SwitchProxy"]=306]="SwitchProxy";e[e["TemporaryRedirect"]=307]="TemporaryRedirect";e[e["PermanentRedirect"]=308]="PermanentRedirect";e[e["BadRequest"]=400]="BadRequest";e[e["Unauthorized"]=401]="Unauthorized";e[e["PaymentRequired"]=402]="PaymentRequired";e[e["Forbidden"]=403]="Forbidden";e[e["NotFound"]=404]="NotFound";e[e["MethodNotAllowed"]=405]="MethodNotAllowed";e[e["NotAcceptable"]=406]="NotAcceptable";e[e["ProxyAuthenticationRequired"]=407]="ProxyAuthenticationRequired";e[e["RequestTimeout"]=408]="RequestTimeout";e[e["Conflict"]=409]="Conflict";e[e["Gone"]=410]="Gone";e[e["TooManyRequests"]=429]="TooManyRequests";e[e["InternalServerError"]=500]="InternalServerError";e[e["NotImplemented"]=501]="NotImplemented";e[e["BadGateway"]=502]="BadGateway";e[e["ServiceUnavailable"]=503]="ServiceUnavailable";e[e["GatewayTimeout"]=504]="GatewayTimeout"})(m=p.HttpCodes||(p.HttpCodes={}));var u;(function(e){e["Accept"]="accept";e["ContentType"]="content-type"})(u=p.Headers||(p.Headers={}));var c;(function(e){e["ApplicationJson"]="application/json"})(c=p.MediaTypes||(p.MediaTypes={}));function getProxyUrl(e){const p=n.getProxyUrl(new URL(e));return p?p.href:""}p.getProxyUrl=getProxyUrl;const v=[m.MovedPermanently,m.ResourceMoved,m.SeeOther,m.TemporaryRedirect,m.PermanentRedirect];const h=[m.BadGateway,m.ServiceUnavailable,m.GatewayTimeout];const g=["OPTIONS","GET","DELETE","HEAD"];const w=10;const _=5;class HttpClientError extends Error{constructor(e,p){super(e);this.name="HttpClientError";this.statusCode=p;Object.setPrototypeOf(this,HttpClientError.prototype)}}p.HttpClientError=HttpClientError;class HttpClientResponse{constructor(e){this.message=e}readBody(){return s(this,void 0,void 0,(function*(){return new Promise((e=>s(this,void 0,void 0,(function*(){let p=Buffer.alloc(0);this.message.on("data",(e=>{p=Buffer.concat([p,e])}));this.message.on("end",(()=>{e(p.toString())}))}))))}))}}p.HttpClientResponse=HttpClientResponse;function isHttps(e){const p=new URL(e);return p.protocol==="https:"}p.isHttps=isHttps;class HttpClient{constructor(e,p,a){this._ignoreSslError=false;this._allowRedirects=true;this._allowRedirectDowngrade=false;this._maxRedirects=50;this._allowRetries=false;this._maxRetries=1;this._keepAlive=false;this._disposed=false;this.userAgent=e;this.handlers=p||[];this.requestOptions=a;if(a){if(a.ignoreSslError!=null){this._ignoreSslError=a.ignoreSslError}this._socketTimeout=a.socketTimeout;if(a.allowRedirects!=null){this._allowRedirects=a.allowRedirects}if(a.allowRedirectDowngrade!=null){this._allowRedirectDowngrade=a.allowRedirectDowngrade}if(a.maxRedirects!=null){this._maxRedirects=Math.max(a.maxRedirects,0)}if(a.keepAlive!=null){this._keepAlive=a.keepAlive}if(a.allowRetries!=null){this._allowRetries=a.allowRetries}if(a.maxRetries!=null){this._maxRetries=a.maxRetries}}}options(e,p){return s(this,void 0,void 0,(function*(){return this.request("OPTIONS",e,null,p||{})}))}get(e,p){return s(this,void 0,void 0,(function*(){return this.request("GET",e,null,p||{})}))}del(e,p){return s(this,void 0,void 0,(function*(){return this.request("DELETE",e,null,p||{})}))}post(e,p,a){return s(this,void 0,void 0,(function*(){return this.request("POST",e,p,a||{})}))}patch(e,p,a){return s(this,void 0,void 0,(function*(){return this.request("PATCH",e,p,a||{})}))}put(e,p,a){return s(this,void 0,void 0,(function*(){return this.request("PUT",e,p,a||{})}))}head(e,p){return s(this,void 0,void 0,(function*(){return this.request("HEAD",e,null,p||{})}))}sendStream(e,p,a,d){return s(this,void 0,void 0,(function*(){return this.request(e,p,a,d)}))}getJson(e,p={}){return s(this,void 0,void 0,(function*(){p[u.Accept]=this._getExistingOrDefaultHeader(p,u.Accept,c.ApplicationJson);const a=yield this.get(e,p);return this._processResponse(a,this.requestOptions)}))}postJson(e,p,a={}){return s(this,void 0,void 0,(function*(){const d=JSON.stringify(p,null,2);a[u.Accept]=this._getExistingOrDefaultHeader(a,u.Accept,c.ApplicationJson);a[u.ContentType]=this._getExistingOrDefaultHeader(a,u.ContentType,c.ApplicationJson);const t=yield this.post(e,d,a);return this._processResponse(t,this.requestOptions)}))}putJson(e,p,a={}){return s(this,void 0,void 0,(function*(){const d=JSON.stringify(p,null,2);a[u.Accept]=this._getExistingOrDefaultHeader(a,u.Accept,c.ApplicationJson);a[u.ContentType]=this._getExistingOrDefaultHeader(a,u.ContentType,c.ApplicationJson);const t=yield this.put(e,d,a);return this._processResponse(t,this.requestOptions)}))}patchJson(e,p,a={}){return s(this,void 0,void 0,(function*(){const d=JSON.stringify(p,null,2);a[u.Accept]=this._getExistingOrDefaultHeader(a,u.Accept,c.ApplicationJson);a[u.ContentType]=this._getExistingOrDefaultHeader(a,u.ContentType,c.ApplicationJson);const t=yield this.patch(e,d,a);return this._processResponse(t,this.requestOptions)}))}request(e,p,a,d){return s(this,void 0,void 0,(function*(){if(this._disposed){throw new Error("Client has already been disposed.")}const t=new URL(p);let r=this._prepareRequest(e,t,d);const s=this._allowRetries&&g.includes(e)?this._maxRetries+1:1;let i=0;let o;do{o=yield this.requestRaw(r,a);if(o&&o.message&&o.message.statusCode===m.Unauthorized){let e;for(const p of this.handlers){if(p.canHandleAuthentication(o)){e=p;break}}if(e){return e.handleAuthentication(this,r,a)}else{return o}}let p=this._maxRedirects;while(o.message.statusCode&&v.includes(o.message.statusCode)&&this._allowRedirects&&p>0){const s=o.message.headers["location"];if(!s){break}const i=new URL(s);if(t.protocol==="https:"&&t.protocol!==i.protocol&&!this._allowRedirectDowngrade){throw new Error("Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.")}yield o.readBody();if(i.hostname!==t.hostname){for(const e in d){if(e.toLowerCase()==="authorization"){delete d[e]}}}r=this._prepareRequest(e,i,d);o=yield this.requestRaw(r,a);p--}if(!o.message.statusCode||!h.includes(o.message.statusCode)){return o}i+=1;if(i{function callbackForResult(e,p){if(e){d(e)}else if(!p){d(new Error("Unknown error"))}else{a(p)}}this.requestRawWithCallback(e,p,callbackForResult)}))}))}requestRawWithCallback(e,p,a){if(typeof p==="string"){if(!e.options.headers){e.options.headers={}}e.options.headers["Content-Length"]=Buffer.byteLength(p,"utf8")}let d=false;function handleResult(e,p){if(!d){d=true;a(e,p)}}const t=e.httpModule.request(e.options,(e=>{const p=new HttpClientResponse(e);handleResult(undefined,p)}));let r;t.on("socket",(e=>{r=e}));t.setTimeout(this._socketTimeout||3*6e4,(()=>{if(r){r.end()}handleResult(new Error(`Request timeout: ${e.options.path}`))}));t.on("error",(function(e){handleResult(e)}));if(p&&typeof p==="string"){t.write(p,"utf8")}if(p&&typeof p!=="string"){p.on("close",(function(){t.end()}));p.pipe(t)}else{t.end()}}getAgent(e){const p=new URL(e);return this._getAgent(p)}_prepareRequest(e,p,a){const d={};d.parsedUrl=p;const t=d.parsedUrl.protocol==="https:";d.httpModule=t?o:i;const r=t?443:80;d.options={};d.options.host=d.parsedUrl.hostname;d.options.port=d.parsedUrl.port?parseInt(d.parsedUrl.port):r;d.options.path=(d.parsedUrl.pathname||"")+(d.parsedUrl.search||"");d.options.method=e;d.options.headers=this._mergeHeaders(a);if(this.userAgent!=null){d.options.headers["user-agent"]=this.userAgent}d.options.agent=this._getAgent(d.parsedUrl);if(this.handlers){for(const e of this.handlers){e.prepareRequest(d.options)}}return d}_mergeHeaders(e){if(this.requestOptions&&this.requestOptions.headers){return Object.assign({},lowercaseKeys(this.requestOptions.headers),lowercaseKeys(e||{}))}return lowercaseKeys(e||{})}_getExistingOrDefaultHeader(e,p,a){let d;if(this.requestOptions&&this.requestOptions.headers){d=lowercaseKeys(this.requestOptions.headers)[p]}return e[p]||d||a}_getAgent(e){let p;const a=n.getProxyUrl(e);const d=a&&a.hostname;if(this._keepAlive&&d){p=this._proxyAgent}if(this._keepAlive&&!d){p=this._agent}if(p){return p}const t=e.protocol==="https:";let r=100;if(this.requestOptions){r=this.requestOptions.maxSockets||i.globalAgent.maxSockets}if(a&&a.hostname){const e={maxSockets:r,keepAlive:this._keepAlive,proxy:Object.assign(Object.assign({},(a.username||a.password)&&{proxyAuth:`${a.username}:${a.password}`}),{host:a.hostname,port:a.port})};let d;const s=a.protocol==="https:";if(t){d=s?l.httpsOverHttps:l.httpsOverHttp}else{d=s?l.httpOverHttps:l.httpOverHttp}p=d(e);this._proxyAgent=p}if(this._keepAlive&&!p){const e={keepAlive:this._keepAlive,maxSockets:r};p=t?new o.Agent(e):new i.Agent(e);this._agent=p}if(!p){p=t?o.globalAgent:i.globalAgent}if(t&&this._ignoreSslError){p.options=Object.assign(p.options||{},{rejectUnauthorized:false})}return p}_performExponentialBackoff(e){return s(this,void 0,void 0,(function*(){e=Math.min(w,e);const p=_*Math.pow(2,e);return new Promise((e=>setTimeout((()=>e()),p)))}))}_processResponse(e,p){return s(this,void 0,void 0,(function*(){return new Promise(((a,d)=>s(this,void 0,void 0,(function*(){const t=e.message.statusCode||0;const r={statusCode:t,result:null,headers:{}};if(t===m.NotFound){a(r)}function dateTimeDeserializer(e,p){if(typeof p==="string"){const e=new Date(p);if(!isNaN(e.valueOf())){return e}}return p}let s;let i;try{i=yield e.readBody();if(i&&i.length>0){if(p&&p.deserializeDates){s=JSON.parse(i,dateTimeDeserializer)}else{s=JSON.parse(i)}r.result=s}r.headers=e.message.headers}catch(e){}if(t>299){let e;if(s&&s.message){e=s.message}else if(i&&i.length>0){e=i}else{e=`Failed request: (${t})`}const p=new HttpClientError(e,t);p.result=r.result;d(p)}else{a(r)}}))))}))}}p.HttpClient=HttpClient;const lowercaseKeys=e=>Object.keys(e).reduce(((p,a)=>(p[a.toLowerCase()]=e[a],p)),{})},9835:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p.checkBypass=p.getProxyUrl=void 0;function getProxyUrl(e){const p=e.protocol==="https:";if(checkBypass(e)){return undefined}const a=(()=>{if(p){return process.env["https_proxy"]||process.env["HTTPS_PROXY"]}else{return process.env["http_proxy"]||process.env["HTTP_PROXY"]}})();if(a){return new URL(a)}else{return undefined}}p.getProxyUrl=getProxyUrl;function checkBypass(e){if(!e.hostname){return false}const p=e.hostname;if(isLoopbackAddress(p)){return true}const a=process.env["no_proxy"]||process.env["NO_PROXY"]||"";if(!a){return false}let d;if(e.port){d=Number(e.port)}else if(e.protocol==="http:"){d=80}else if(e.protocol==="https:"){d=443}const t=[e.hostname.toUpperCase()];if(typeof d==="number"){t.push(`${t[0]}:${d}`)}for(const e of a.split(",").map((e=>e.trim().toUpperCase())).filter((e=>e))){if(e==="*"||t.some((p=>p===e||p.endsWith(`.${e}`)||e.startsWith(".")&&p.endsWith(`${e}`)))){return true}}return false}p.checkBypass=checkBypass;function isLoopbackAddress(e){const p=e.toLowerCase();return p==="localhost"||p.startsWith("127.")||p.startsWith("[::1]")||p.startsWith("[0:0:0:0:0:0:0:1]")}},334:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});const a=/^v1\./;const d=/^ghs_/;const t=/^ghu_/;async function auth(e){const p=e.split(/\./).length===3;const r=a.test(e)||d.test(e);const s=t.test(e);const i=p?"app":r?"installation":s?"user-to-server":"oauth";return{type:"token",token:e,tokenType:i}}function withAuthorizationPrefix(e){if(e.split(/\./).length===3){return`bearer ${e}`}return`token ${e}`}async function hook(e,p,a,d){const t=p.endpoint.merge(a,d);t.headers.authorization=withAuthorizationPrefix(e);return p(t)}const r=function createTokenAuth(e){if(!e){throw new Error("[@octokit/auth-token] No token passed to createTokenAuth")}if(typeof e!=="string"){throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string")}e=e.replace(/^(token|bearer) +/i,"");return Object.assign(auth.bind(null,e),{hook:hook.bind(null,e)})};p.createTokenAuth=r},6762:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});var d=a(5030);var t=a(3682);var r=a(6234);var s=a(8467);var i=a(334);function _objectWithoutPropertiesLoose(e,p){if(e==null)return{};var a={};var d=Object.keys(e);var t,r;for(r=0;r=0)continue;a[t]=e[t]}return a}function _objectWithoutProperties(e,p){if(e==null)return{};var a=_objectWithoutPropertiesLoose(e,p);var d,t;if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,d))continue;a[d]=e[d]}}return a}const o="3.6.0";const n=["authStrategy"];class Octokit{constructor(e={}){const p=new t.Collection;const a={baseUrl:r.request.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},e.request,{hook:p.bind(null,"request")}),mediaType:{previews:[],format:""}};a.headers["user-agent"]=[e.userAgent,`octokit-core.js/${o} ${d.getUserAgent()}`].filter(Boolean).join(" ");if(e.baseUrl){a.baseUrl=e.baseUrl}if(e.previews){a.mediaType.previews=e.previews}if(e.timeZone){a.headers["time-zone"]=e.timeZone}this.request=r.request.defaults(a);this.graphql=s.withCustomRequest(this.request).defaults(a);this.log=Object.assign({debug:()=>{},info:()=>{},warn:console.warn.bind(console),error:console.error.bind(console)},e.log);this.hook=p;if(!e.authStrategy){if(!e.auth){this.auth=async()=>({type:"unauthenticated"})}else{const a=i.createTokenAuth(e.auth);p.wrap("request",a.hook);this.auth=a}}else{const{authStrategy:a}=e,d=_objectWithoutProperties(e,n);const t=a(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:d},e.auth));p.wrap("request",t.hook);this.auth=t}const l=this.constructor;l.plugins.forEach((p=>{Object.assign(this,p(this,e))}))}static defaults(e){const p=class extends(this){constructor(...p){const a=p[0]||{};if(typeof e==="function"){super(e(a));return}super(Object.assign({},e,a,a.userAgent&&e.userAgent?{userAgent:`${a.userAgent} ${e.userAgent}`}:null))}};return p}static plugin(...e){var p;const a=this.plugins;const d=(p=class extends(this){},p.plugins=a.concat(e.filter((e=>!a.includes(e)))),p);return d}}Octokit.VERSION=o;Octokit.plugins=[];p.Octokit=Octokit},9440:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});var d=a(3287);var t=a(5030);function lowercaseKeys(e){if(!e){return{}}return Object.keys(e).reduce(((p,a)=>{p[a.toLowerCase()]=e[a];return p}),{})}function mergeDeep(e,p){const a=Object.assign({},e);Object.keys(p).forEach((t=>{if(d.isPlainObject(p[t])){if(!(t in e))Object.assign(a,{[t]:p[t]});else a[t]=mergeDeep(e[t],p[t])}else{Object.assign(a,{[t]:p[t]})}}));return a}function removeUndefinedProperties(e){for(const p in e){if(e[p]===undefined){delete e[p]}}return e}function merge(e,p,a){if(typeof p==="string"){let[e,d]=p.split(" ");a=Object.assign(d?{method:e,url:d}:{url:e},a)}else{a=Object.assign({},p)}a.headers=lowercaseKeys(a.headers);removeUndefinedProperties(a);removeUndefinedProperties(a.headers);const d=mergeDeep(e||{},a);if(e&&e.mediaType.previews.length){d.mediaType.previews=e.mediaType.previews.filter((e=>!d.mediaType.previews.includes(e))).concat(d.mediaType.previews)}d.mediaType.previews=d.mediaType.previews.map((e=>e.replace(/-preview/,"")));return d}function addQueryParameters(e,p){const a=/\?/.test(e)?"&":"?";const d=Object.keys(p);if(d.length===0){return e}return e+a+d.map((e=>{if(e==="q"){return"q="+p.q.split("+").map(encodeURIComponent).join("+")}return`${e}=${encodeURIComponent(p[e])}`})).join("&")}const r=/\{[^}]+\}/g;function removeNonChars(e){return e.replace(/^\W+|\W+$/g,"").split(/,/)}function extractUrlVariableNames(e){const p=e.match(r);if(!p){return[]}return p.map(removeNonChars).reduce(((e,p)=>e.concat(p)),[])}function omit(e,p){return Object.keys(e).filter((e=>!p.includes(e))).reduce(((p,a)=>{p[a]=e[a];return p}),{})}function encodeReserved(e){return e.split(/(%[0-9A-Fa-f]{2})/g).map((function(e){if(!/%[0-9A-Fa-f]/.test(e)){e=encodeURI(e).replace(/%5B/g,"[").replace(/%5D/g,"]")}return e})).join("")}function encodeUnreserved(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function encodeValue(e,p,a){p=e==="+"||e==="#"?encodeReserved(p):encodeUnreserved(p);if(a){return encodeUnreserved(a)+"="+p}else{return p}}function isDefined(e){return e!==undefined&&e!==null}function isKeyOperator(e){return e===";"||e==="&"||e==="?"}function getValues(e,p,a,d){var t=e[a],r=[];if(isDefined(t)&&t!==""){if(typeof t==="string"||typeof t==="number"||typeof t==="boolean"){t=t.toString();if(d&&d!=="*"){t=t.substring(0,parseInt(d,10))}r.push(encodeValue(p,t,isKeyOperator(p)?a:""))}else{if(d==="*"){if(Array.isArray(t)){t.filter(isDefined).forEach((function(e){r.push(encodeValue(p,e,isKeyOperator(p)?a:""))}))}else{Object.keys(t).forEach((function(e){if(isDefined(t[e])){r.push(encodeValue(p,t[e],e))}}))}}else{const e=[];if(Array.isArray(t)){t.filter(isDefined).forEach((function(a){e.push(encodeValue(p,a))}))}else{Object.keys(t).forEach((function(a){if(isDefined(t[a])){e.push(encodeUnreserved(a));e.push(encodeValue(p,t[a].toString()))}}))}if(isKeyOperator(p)){r.push(encodeUnreserved(a)+"="+e.join(","))}else if(e.length!==0){r.push(e.join(","))}}}}else{if(p===";"){if(isDefined(t)){r.push(encodeUnreserved(a))}}else if(t===""&&(p==="&"||p==="?")){r.push(encodeUnreserved(a)+"=")}else if(t===""){r.push("")}}return r}function parseUrl(e){return{expand:expand.bind(null,e)}}function expand(e,p){var a=["+","#",".","/",";","?","&"];return e.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g,(function(e,d,t){if(d){let e="";const t=[];if(a.indexOf(d.charAt(0))!==-1){e=d.charAt(0);d=d.substr(1)}d.split(/,/g).forEach((function(a){var d=/([^:\*]*)(?::(\d+)|(\*))?/.exec(a);t.push(getValues(p,e,d[1],d[2]||d[3]))}));if(e&&e!=="+"){var r=",";if(e==="?"){r="&"}else if(e!=="#"){r=e}return(t.length!==0?e:"")+t.join(r)}else{return t.join(",")}}else{return encodeReserved(t)}}))}function parse(e){let p=e.method.toUpperCase();let a=(e.url||"/").replace(/:([a-z]\w+)/g,"{$1}");let d=Object.assign({},e.headers);let t;let r=omit(e,["method","baseUrl","url","headers","request","mediaType"]);const s=extractUrlVariableNames(a);a=parseUrl(a).expand(r);if(!/^http/.test(a)){a=e.baseUrl+a}const i=Object.keys(e).filter((e=>s.includes(e))).concat("baseUrl");const o=omit(r,i);const n=/application\/octet-stream/i.test(d.accept);if(!n){if(e.mediaType.format){d.accept=d.accept.split(/,/).map((p=>p.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/,`application/vnd$1$2.${e.mediaType.format}`))).join(",")}if(e.mediaType.previews.length){const p=d.accept.match(/[\w-]+(?=-preview)/g)||[];d.accept=p.concat(e.mediaType.previews).map((p=>{const a=e.mediaType.format?`.${e.mediaType.format}`:"+json";return`application/vnd.github.${p}-preview${a}`})).join(",")}}if(["GET","HEAD"].includes(p)){a=addQueryParameters(a,o)}else{if("data"in o){t=o.data}else{if(Object.keys(o).length){t=o}else{d["content-length"]=0}}}if(!d["content-type"]&&typeof t!=="undefined"){d["content-type"]="application/json; charset=utf-8"}if(["PATCH","PUT"].includes(p)&&typeof t==="undefined"){t=""}return Object.assign({method:p,url:a,headers:d},typeof t!=="undefined"?{body:t}:null,e.request?{request:e.request}:null)}function endpointWithDefaults(e,p,a){return parse(merge(e,p,a))}function withDefaults(e,p){const a=merge(e,p);const d=endpointWithDefaults.bind(null,a);return Object.assign(d,{DEFAULTS:a,defaults:withDefaults.bind(null,a),merge:merge.bind(null,a),parse:parse})}const s="6.0.12";const i=`octokit-endpoint.js/${s} ${t.getUserAgent()}`;const o={method:"GET",baseUrl:"https://api.github.com",headers:{accept:"application/vnd.github.v3+json","user-agent":i},mediaType:{format:"",previews:[]}};const n=withDefaults(null,o);p.endpoint=n},8467:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});var d=a(6234);var t=a(5030);const r="4.8.0";function _buildMessageForResponseErrors(e){return`Request failed due to following response errors:\n`+e.errors.map((e=>` - ${e.message}`)).join("\n")}class GraphqlResponseError extends Error{constructor(e,p,a){super(_buildMessageForResponseErrors(a));this.request=e;this.headers=p;this.response=a;this.name="GraphqlResponseError";this.errors=a.errors;this.data=a.data;if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}}}const s=["method","baseUrl","url","headers","request","query","mediaType"];const i=["query","method","url"];const o=/\/api\/v3\/?$/;function graphql(e,p,a){if(a){if(typeof p==="string"&&"query"in a){return Promise.reject(new Error(`[@octokit/graphql] "query" cannot be used as variable name`))}for(const e in a){if(!i.includes(e))continue;return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}}const d=typeof p==="string"?Object.assign({query:p},a):p;const t=Object.keys(d).reduce(((e,p)=>{if(s.includes(p)){e[p]=d[p];return e}if(!e.variables){e.variables={}}e.variables[p]=d[p];return e}),{});const r=d.baseUrl||e.endpoint.DEFAULTS.baseUrl;if(o.test(r)){t.url=r.replace(o,"/api/graphql")}return e(t).then((e=>{if(e.data.errors){const p={};for(const a of Object.keys(e.headers)){p[a]=e.headers[a]}throw new GraphqlResponseError(t,p,e.data)}return e.data.data}))}function withDefaults(e,p){const a=e.defaults(p);const newApi=(e,p)=>graphql(a,e,p);return Object.assign(newApi,{defaults:withDefaults.bind(null,a),endpoint:d.request.endpoint})}const n=withDefaults(d.request,{headers:{"user-agent":`octokit-graphql.js/${r} ${t.getUserAgent()}`},method:"POST",url:"/graphql"});function withCustomRequest(e){return withDefaults(e,{method:"POST",url:"/graphql"})}p.GraphqlResponseError=GraphqlResponseError;p.graphql=n;p.withCustomRequest=withCustomRequest},4193:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});const a="2.21.3";function ownKeys(e,p){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(e);p&&(d=d.filter((function(p){return Object.getOwnPropertyDescriptor(e,p).enumerable}))),a.push.apply(a,d)}return a}function _objectSpread2(e){for(var p=1;p({async next(){if(!i)return{done:true};try{const e=await t({method:r,url:i,headers:s});const p=normalizePaginatedListResponse(e);i=((p.headers.link||"").match(/<([^>]+)>;\s*rel="next"/)||[])[1];return{value:p}}catch(e){if(e.status!==409)throw e;i="";return{value:{status:200,headers:{},data:[]}}}}})}}function paginate(e,p,a,d){if(typeof a==="function"){d=a;a=undefined}return gather(e,[],iterator(e,p,a)[Symbol.asyncIterator](),d)}function gather(e,p,a,d){return a.next().then((t=>{if(t.done){return p}let r=false;function done(){r=true}p=p.concat(d?d(t.value,done):t.value.data);if(r){return p}return gather(e,p,a,d)}))}const d=Object.assign(paginate,{iterator:iterator});const t=["GET /app/hook/deliveries","GET /app/installations","GET /applications/grants","GET /authorizations","GET /enterprises/{enterprise}/actions/permissions/organizations","GET /enterprises/{enterprise}/actions/runner-groups","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/organizations","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/runners","GET /enterprises/{enterprise}/actions/runners","GET /enterprises/{enterprise}/audit-log","GET /enterprises/{enterprise}/secret-scanning/alerts","GET /enterprises/{enterprise}/settings/billing/advanced-security","GET /events","GET /gists","GET /gists/public","GET /gists/starred","GET /gists/{gist_id}/comments","GET /gists/{gist_id}/commits","GET /gists/{gist_id}/forks","GET /installation/repositories","GET /issues","GET /licenses","GET /marketplace_listing/plans","GET /marketplace_listing/plans/{plan_id}/accounts","GET /marketplace_listing/stubbed/plans","GET /marketplace_listing/stubbed/plans/{plan_id}/accounts","GET /networks/{owner}/{repo}/events","GET /notifications","GET /organizations","GET /orgs/{org}/actions/cache/usage-by-repository","GET /orgs/{org}/actions/permissions/repositories","GET /orgs/{org}/actions/runner-groups","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/runners","GET /orgs/{org}/actions/runners","GET /orgs/{org}/actions/secrets","GET /orgs/{org}/actions/secrets/{secret_name}/repositories","GET /orgs/{org}/audit-log","GET /orgs/{org}/blocks","GET /orgs/{org}/code-scanning/alerts","GET /orgs/{org}/codespaces","GET /orgs/{org}/credential-authorizations","GET /orgs/{org}/dependabot/secrets","GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories","GET /orgs/{org}/events","GET /orgs/{org}/external-groups","GET /orgs/{org}/failed_invitations","GET /orgs/{org}/hooks","GET /orgs/{org}/hooks/{hook_id}/deliveries","GET /orgs/{org}/installations","GET /orgs/{org}/invitations","GET /orgs/{org}/invitations/{invitation_id}/teams","GET /orgs/{org}/issues","GET /orgs/{org}/members","GET /orgs/{org}/migrations","GET /orgs/{org}/migrations/{migration_id}/repositories","GET /orgs/{org}/outside_collaborators","GET /orgs/{org}/packages","GET /orgs/{org}/packages/{package_type}/{package_name}/versions","GET /orgs/{org}/projects","GET /orgs/{org}/public_members","GET /orgs/{org}/repos","GET /orgs/{org}/secret-scanning/alerts","GET /orgs/{org}/settings/billing/advanced-security","GET /orgs/{org}/team-sync/groups","GET /orgs/{org}/teams","GET /orgs/{org}/teams/{team_slug}/discussions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions","GET /orgs/{org}/teams/{team_slug}/invitations","GET /orgs/{org}/teams/{team_slug}/members","GET /orgs/{org}/teams/{team_slug}/projects","GET /orgs/{org}/teams/{team_slug}/repos","GET /orgs/{org}/teams/{team_slug}/teams","GET /projects/columns/{column_id}/cards","GET /projects/{project_id}/collaborators","GET /projects/{project_id}/columns","GET /repos/{owner}/{repo}/actions/artifacts","GET /repos/{owner}/{repo}/actions/caches","GET /repos/{owner}/{repo}/actions/runners","GET /repos/{owner}/{repo}/actions/runs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts","GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs","GET /repos/{owner}/{repo}/actions/secrets","GET /repos/{owner}/{repo}/actions/workflows","GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs","GET /repos/{owner}/{repo}/assignees","GET /repos/{owner}/{repo}/branches","GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations","GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs","GET /repos/{owner}/{repo}/code-scanning/alerts","GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances","GET /repos/{owner}/{repo}/code-scanning/analyses","GET /repos/{owner}/{repo}/codespaces","GET /repos/{owner}/{repo}/codespaces/devcontainers","GET /repos/{owner}/{repo}/codespaces/secrets","GET /repos/{owner}/{repo}/collaborators","GET /repos/{owner}/{repo}/comments","GET /repos/{owner}/{repo}/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/commits","GET /repos/{owner}/{repo}/commits/{commit_sha}/comments","GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls","GET /repos/{owner}/{repo}/commits/{ref}/check-runs","GET /repos/{owner}/{repo}/commits/{ref}/check-suites","GET /repos/{owner}/{repo}/commits/{ref}/status","GET /repos/{owner}/{repo}/commits/{ref}/statuses","GET /repos/{owner}/{repo}/contributors","GET /repos/{owner}/{repo}/dependabot/secrets","GET /repos/{owner}/{repo}/deployments","GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses","GET /repos/{owner}/{repo}/environments","GET /repos/{owner}/{repo}/events","GET /repos/{owner}/{repo}/forks","GET /repos/{owner}/{repo}/git/matching-refs/{ref}","GET /repos/{owner}/{repo}/hooks","GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries","GET /repos/{owner}/{repo}/invitations","GET /repos/{owner}/{repo}/issues","GET /repos/{owner}/{repo}/issues/comments","GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/issues/events","GET /repos/{owner}/{repo}/issues/{issue_number}/comments","GET /repos/{owner}/{repo}/issues/{issue_number}/events","GET /repos/{owner}/{repo}/issues/{issue_number}/labels","GET /repos/{owner}/{repo}/issues/{issue_number}/reactions","GET /repos/{owner}/{repo}/issues/{issue_number}/timeline","GET /repos/{owner}/{repo}/keys","GET /repos/{owner}/{repo}/labels","GET /repos/{owner}/{repo}/milestones","GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels","GET /repos/{owner}/{repo}/notifications","GET /repos/{owner}/{repo}/pages/builds","GET /repos/{owner}/{repo}/projects","GET /repos/{owner}/{repo}/pulls","GET /repos/{owner}/{repo}/pulls/comments","GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/pulls/{pull_number}/comments","GET /repos/{owner}/{repo}/pulls/{pull_number}/commits","GET /repos/{owner}/{repo}/pulls/{pull_number}/files","GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments","GET /repos/{owner}/{repo}/releases","GET /repos/{owner}/{repo}/releases/{release_id}/assets","GET /repos/{owner}/{repo}/releases/{release_id}/reactions","GET /repos/{owner}/{repo}/secret-scanning/alerts","GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations","GET /repos/{owner}/{repo}/stargazers","GET /repos/{owner}/{repo}/subscribers","GET /repos/{owner}/{repo}/tags","GET /repos/{owner}/{repo}/teams","GET /repos/{owner}/{repo}/topics","GET /repositories","GET /repositories/{repository_id}/environments/{environment_name}/secrets","GET /search/code","GET /search/commits","GET /search/issues","GET /search/labels","GET /search/repositories","GET /search/topics","GET /search/users","GET /teams/{team_id}/discussions","GET /teams/{team_id}/discussions/{discussion_number}/comments","GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /teams/{team_id}/discussions/{discussion_number}/reactions","GET /teams/{team_id}/invitations","GET /teams/{team_id}/members","GET /teams/{team_id}/projects","GET /teams/{team_id}/repos","GET /teams/{team_id}/teams","GET /user/blocks","GET /user/codespaces","GET /user/codespaces/secrets","GET /user/emails","GET /user/followers","GET /user/following","GET /user/gpg_keys","GET /user/installations","GET /user/installations/{installation_id}/repositories","GET /user/issues","GET /user/keys","GET /user/marketplace_purchases","GET /user/marketplace_purchases/stubbed","GET /user/memberships/orgs","GET /user/migrations","GET /user/migrations/{migration_id}/repositories","GET /user/orgs","GET /user/packages","GET /user/packages/{package_type}/{package_name}/versions","GET /user/public_emails","GET /user/repos","GET /user/repository_invitations","GET /user/starred","GET /user/subscriptions","GET /user/teams","GET /users","GET /users/{username}/events","GET /users/{username}/events/orgs/{org}","GET /users/{username}/events/public","GET /users/{username}/followers","GET /users/{username}/following","GET /users/{username}/gists","GET /users/{username}/gpg_keys","GET /users/{username}/keys","GET /users/{username}/orgs","GET /users/{username}/packages","GET /users/{username}/projects","GET /users/{username}/received_events","GET /users/{username}/received_events/public","GET /users/{username}/repos","GET /users/{username}/starred","GET /users/{username}/subscriptions"];function isPaginatingEndpoint(e){if(typeof e==="string"){return t.includes(e)}else{return false}}function paginateRest(e){return{paginate:Object.assign(paginate.bind(null,e),{iterator:iterator.bind(null,e)})}}paginateRest.VERSION=a;p.composePaginateRest=d;p.isPaginatingEndpoint=isPaginatingEndpoint;p.paginateRest=paginateRest;p.paginatingEndpoints=t},3044:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});function ownKeys(e,p){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(e);if(p){d=d.filter((function(p){return Object.getOwnPropertyDescriptor(e,p).enumerable}))}a.push.apply(a,d)}return a}function _objectSpread2(e){for(var p=1;p{Object.defineProperty(p,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var d=a(8932);var t=_interopDefault(a(1223));const r=t((e=>console.warn(e)));const s=t((e=>console.warn(e)));class RequestError extends Error{constructor(e,p,a){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="HttpError";this.status=p;let t;if("headers"in a&&typeof a.headers!=="undefined"){t=a.headers}if("response"in a){this.response=a.response;t=a.response.headers}const i=Object.assign({},a.request);if(a.request.headers.authorization){i.headers=Object.assign({},a.request.headers,{authorization:a.request.headers.authorization.replace(/ .*$/," [REDACTED]")})}i.url=i.url.replace(/\bclient_secret=\w+/g,"client_secret=[REDACTED]").replace(/\baccess_token=\w+/g,"access_token=[REDACTED]");this.request=i;Object.defineProperty(this,"code",{get(){r(new d.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`."));return p}});Object.defineProperty(this,"headers",{get(){s(new d.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."));return t||{}}})}}p.RequestError=RequestError},6234:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var d=a(9440);var t=a(5030);var r=a(3287);var s=_interopDefault(a(467));var i=a(537);const o="5.6.3";function getBufferResponse(e){return e.arrayBuffer()}function fetchWrapper(e){const p=e.request&&e.request.log?e.request.log:console;if(r.isPlainObject(e.body)||Array.isArray(e.body)){e.body=JSON.stringify(e.body)}let a={};let d;let t;const o=e.request&&e.request.fetch||s;return o(e.url,Object.assign({method:e.method,body:e.body,headers:e.headers,redirect:e.redirect},e.request)).then((async r=>{t=r.url;d=r.status;for(const e of r.headers){a[e[0]]=e[1]}if("deprecation"in a){const d=a.link&&a.link.match(/<([^>]+)>; rel="deprecation"/);const t=d&&d.pop();p.warn(`[@octokit/request] "${e.method} ${e.url}" is deprecated. It is scheduled to be removed on ${a.sunset}${t?`. See ${t}`:""}`)}if(d===204||d===205){return}if(e.method==="HEAD"){if(d<400){return}throw new i.RequestError(r.statusText,d,{response:{url:t,status:d,headers:a,data:undefined},request:e})}if(d===304){throw new i.RequestError("Not modified",d,{response:{url:t,status:d,headers:a,data:await getResponseData(r)},request:e})}if(d>=400){const p=await getResponseData(r);const s=new i.RequestError(toErrorMessage(p),d,{response:{url:t,status:d,headers:a,data:p},request:e});throw s}return getResponseData(r)})).then((e=>({status:d,url:t,headers:a,data:e}))).catch((p=>{if(p instanceof i.RequestError)throw p;throw new i.RequestError(p.message,500,{request:e})}))}async function getResponseData(e){const p=e.headers.get("content-type");if(/application\/json/.test(p)){return e.json()}if(!p||/^text\/|charset=utf-8$/.test(p)){return e.text()}return getBufferResponse(e)}function toErrorMessage(e){if(typeof e==="string")return e;if("message"in e){if(Array.isArray(e.errors)){return`${e.message}: ${e.errors.map(JSON.stringify).join(", ")}`}return e.message}return`Unknown error: ${JSON.stringify(e)}`}function withDefaults(e,p){const a=e.defaults(p);const newApi=function(e,p){const d=a.merge(e,p);if(!d.request||!d.request.hook){return fetchWrapper(a.parse(d))}const request=(e,p)=>fetchWrapper(a.parse(a.merge(e,p)));Object.assign(request,{endpoint:a,defaults:withDefaults.bind(null,a)});return d.request.hook(request,d)};return Object.assign(newApi,{endpoint:a,defaults:withDefaults.bind(null,a)})}const n=withDefaults(d.endpoint,{headers:{"user-agent":`octokit-request.js/${o} ${t.getUserAgent()}`}});p.request=n},3682:(e,p,a)=>{var d=a(4670);var t=a(5549);var r=a(6819);var s=Function.bind;var i=s.bind(s);function bindApi(e,p,a){var d=i(r,null).apply(null,a?[p,a]:[p]);e.api={remove:d};e.remove=d;["before","error","after","wrap"].forEach((function(d){var r=a?[p,d,a]:[p,d];e[d]=e.api[d]=i(t,null).apply(null,r)}))}function HookSingular(){var e="h";var p={registry:{}};var a=d.bind(null,p,e);bindApi(a,p,e);return a}function HookCollection(){var e={registry:{}};var p=d.bind(null,e);bindApi(p,e);return p}var o=false;function Hook(){if(!o){console.warn('[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4');o=true}return HookCollection()}Hook.Singular=HookSingular.bind();Hook.Collection=HookCollection.bind();e.exports=Hook;e.exports.Hook=Hook;e.exports.Singular=Hook.Singular;e.exports.Collection=Hook.Collection},5549:e=>{e.exports=addHook;function addHook(e,p,a,d){var t=d;if(!e.registry[a]){e.registry[a]=[]}if(p==="before"){d=function(e,p){return Promise.resolve().then(t.bind(null,p)).then(e.bind(null,p))}}if(p==="after"){d=function(e,p){var a;return Promise.resolve().then(e.bind(null,p)).then((function(e){a=e;return t(a,p)})).then((function(){return a}))}}if(p==="error"){d=function(e,p){return Promise.resolve().then(e.bind(null,p)).catch((function(e){return t(e,p)}))}}e.registry[a].push({hook:d,orig:t})}},4670:e=>{e.exports=register;function register(e,p,a,d){if(typeof a!=="function"){throw new Error("method for before hook must be a function")}if(!d){d={}}if(Array.isArray(p)){return p.reverse().reduce((function(p,a){return register.bind(null,e,a,p,d)}),a)()}return Promise.resolve().then((function(){if(!e.registry[p]){return a(d)}return e.registry[p].reduce((function(e,p){return p.hook.bind(null,e,d)}),a)()}))}},6819:e=>{e.exports=removeHook;function removeHook(e,p,a){if(!e.registry[p]){return}var d=e.registry[p].map((function(e){return e.orig})).indexOf(a);if(d===-1){return}e.registry[p].splice(d,1)}},8932:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});class Deprecation extends Error{constructor(e){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="Deprecation"}}p.Deprecation=Deprecation},3287:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true}); +/*! + * is-plain-object + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */function isObject(e){return Object.prototype.toString.call(e)==="[object Object]"}function isPlainObject(e){var p,a;if(isObject(e)===false)return false;p=e.constructor;if(p===undefined)return true;a=p.prototype;if(isObject(a)===false)return false;if(a.hasOwnProperty("isPrototypeOf")===false){return false}return true}p.isPlainObject=isPlainObject},467:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var d=_interopDefault(a(2781));var t=_interopDefault(a(3685));var r=_interopDefault(a(7310));var s=_interopDefault(a(8665));var i=_interopDefault(a(5687));var o=_interopDefault(a(9796));const n=d.Readable;const l=Symbol("buffer");const m=Symbol("type");class Blob{constructor(){this[m]="";const e=arguments[0];const p=arguments[1];const a=[];let d=0;if(e){const p=e;const t=Number(p.length);for(let e=0;e1&&arguments[1]!==undefined?arguments[1]:{},t=a.size;let r=t===undefined?0:t;var s=a.timeout;let i=s===undefined?0:s;if(e==null){e=null}else if(isURLSearchParams(e)){e=Buffer.from(e.toString())}else if(isBlob(e));else if(Buffer.isBuffer(e));else if(Object.prototype.toString.call(e)==="[object ArrayBuffer]"){e=Buffer.from(e)}else if(ArrayBuffer.isView(e)){e=Buffer.from(e.buffer,e.byteOffset,e.byteLength)}else if(e instanceof d);else{e=Buffer.from(String(e))}this[c]={body:e,disturbed:false,error:null};this.size=r;this.timeout=i;if(e instanceof d){e.on("error",(function(e){const a=e.name==="AbortError"?e:new FetchError(`Invalid response body while trying to fetch ${p.url}: ${e.message}`,"system",e);p[c].error=a}))}}Body.prototype={get body(){return this[c].body},get bodyUsed(){return this[c].disturbed},arrayBuffer(){return consumeBody.call(this).then((function(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}))},blob(){let e=this.headers&&this.headers.get("content-type")||"";return consumeBody.call(this).then((function(p){return Object.assign(new Blob([],{type:e.toLowerCase()}),{[l]:p})}))},json(){var e=this;return consumeBody.call(this).then((function(p){try{return JSON.parse(p.toString())}catch(p){return Body.Promise.reject(new FetchError(`invalid json response body at ${e.url} reason: ${p.message}`,"invalid-json"))}}))},text(){return consumeBody.call(this).then((function(e){return e.toString()}))},buffer(){return consumeBody.call(this)},textConverted(){var e=this;return consumeBody.call(this).then((function(p){return convertBody(p,e.headers)}))}};Object.defineProperties(Body.prototype,{body:{enumerable:true},bodyUsed:{enumerable:true},arrayBuffer:{enumerable:true},blob:{enumerable:true},json:{enumerable:true},text:{enumerable:true}});Body.mixIn=function(e){for(const p of Object.getOwnPropertyNames(Body.prototype)){if(!(p in e)){const a=Object.getOwnPropertyDescriptor(Body.prototype,p);Object.defineProperty(e,p,a)}}};function consumeBody(){var e=this;if(this[c].disturbed){return Body.Promise.reject(new TypeError(`body used already for: ${this.url}`))}this[c].disturbed=true;if(this[c].error){return Body.Promise.reject(this[c].error)}let p=this.body;if(p===null){return Body.Promise.resolve(Buffer.alloc(0))}if(isBlob(p)){p=p.stream()}if(Buffer.isBuffer(p)){return Body.Promise.resolve(p)}if(!(p instanceof d)){return Body.Promise.resolve(Buffer.alloc(0))}let a=[];let t=0;let r=false;return new Body.Promise((function(d,s){let i;if(e.timeout){i=setTimeout((function(){r=true;s(new FetchError(`Response timeout while trying to fetch ${e.url} (over ${e.timeout}ms)`,"body-timeout"))}),e.timeout)}p.on("error",(function(p){if(p.name==="AbortError"){r=true;s(p)}else{s(new FetchError(`Invalid response body while trying to fetch ${e.url}: ${p.message}`,"system",p))}}));p.on("data",(function(p){if(r||p===null){return}if(e.size&&t+p.length>e.size){r=true;s(new FetchError(`content size at ${e.url} over limit: ${e.size}`,"max-size"));return}t+=p.length;a.push(p)}));p.on("end",(function(){if(r){return}clearTimeout(i);try{d(Buffer.concat(a,t))}catch(p){s(new FetchError(`Could not create Buffer from response body for ${e.url}: ${p.message}`,"system",p))}}))}))}function convertBody(e,p){if(typeof u!=="function"){throw new Error("The package `encoding` must be installed to use the textConverted() function")}const a=p.get("content-type");let d="utf-8";let t,r;if(a){t=/charset=([^;]*)/i.exec(a)}r=e.slice(0,1024).toString();if(!t&&r){t=/0&&arguments[0]!==undefined?arguments[0]:undefined;this[w]=Object.create(null);if(e instanceof Headers){const p=e.raw();const a=Object.keys(p);for(const e of a){for(const a of p[e]){this.append(e,a)}}return}if(e==null);else if(typeof e==="object"){const p=e[Symbol.iterator];if(p!=null){if(typeof p!=="function"){throw new TypeError("Header pairs must be iterable")}const a=[];for(const p of e){if(typeof p!=="object"||typeof p[Symbol.iterator]!=="function"){throw new TypeError("Each header pair must be iterable")}a.push(Array.from(p))}for(const e of a){if(e.length!==2){throw new TypeError("Each header pair must be a name/value tuple")}this.append(e[0],e[1])}}else{for(const p of Object.keys(e)){const a=e[p];this.append(p,a)}}}else{throw new TypeError("Provided initializer must be an object")}}get(e){e=`${e}`;validateName(e);const p=find(this[w],e);if(p===undefined){return null}return this[w][p].join(", ")}forEach(e){let p=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;let a=getHeaders(this);let d=0;while(d1&&arguments[1]!==undefined?arguments[1]:"key+value";const a=Object.keys(e[w]).sort();return a.map(p==="key"?function(e){return e.toLowerCase()}:p==="value"?function(p){return e[w][p].join(", ")}:function(p){return[p.toLowerCase(),e[w][p].join(", ")]})}const _=Symbol("internal");function createHeadersIterator(e,p){const a=Object.create(T);a[_]={target:e,kind:p,index:0};return a}const T=Object.setPrototypeOf({next(){if(!this||Object.getPrototypeOf(this)!==T){throw new TypeError("Value of `this` is not a HeadersIterator")}var e=this[_];const p=e.target,a=e.kind,d=e.index;const t=getHeaders(p,a);const r=t.length;if(d>=r){return{value:undefined,done:true}}this[_].index=d+1;return{value:t[d],done:false}}},Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));Object.defineProperty(T,Symbol.toStringTag,{value:"HeadersIterator",writable:false,enumerable:false,configurable:true});function exportNodeCompatibleHeaders(e){const p=Object.assign({__proto__:null},e[w]);const a=find(e[w],"Host");if(a!==undefined){p[a]=p[a][0]}return p}function createHeadersLenient(e){const p=new Headers;for(const a of Object.keys(e)){if(h.test(a)){continue}if(Array.isArray(e[a])){for(const d of e[a]){if(g.test(d)){continue}if(p[w][a]===undefined){p[w][a]=[d]}else{p[w][a].push(d)}}}else if(!g.test(e[a])){p[w][a]=[e[a]]}}return p}const E=Symbol("Response internals");const b=t.STATUS_CODES;class Response{constructor(){let e=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;let p=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};Body.call(this,e,p);const a=p.status||200;const d=new Headers(p.headers);if(e!=null&&!d.has("Content-Type")){const p=extractContentType(e);if(p){d.append("Content-Type",p)}}this[E]={url:p.url,status:a,statusText:p.statusText||b[a],headers:d,counter:p.counter}}get url(){return this[E].url||""}get status(){return this[E].status}get ok(){return this[E].status>=200&&this[E].status<300}get redirected(){return this[E].counter>0}get statusText(){return this[E].statusText}get headers(){return this[E].headers}clone(){return new Response(clone(this),{url:this.url,status:this.status,statusText:this.statusText,headers:this.headers,ok:this.ok,redirected:this.redirected})}}Body.mixIn(Response.prototype);Object.defineProperties(Response.prototype,{url:{enumerable:true},status:{enumerable:true},ok:{enumerable:true},redirected:{enumerable:true},statusText:{enumerable:true},headers:{enumerable:true},clone:{enumerable:true}});Object.defineProperty(Response.prototype,Symbol.toStringTag,{value:"Response",writable:false,enumerable:false,configurable:true});const y=Symbol("Request internals");const S=r.URL||s.URL;const D=r.parse;const P=r.format;function parseURL(e){if(/^[a-zA-Z][a-zA-Z\d+\-.]*:/.exec(e)){e=new S(e).toString()}return D(e)}const A="destroy"in d.Readable.prototype;function isRequest(e){return typeof e==="object"&&typeof e[y]==="object"}function isAbortSignal(e){const p=e&&typeof e==="object"&&Object.getPrototypeOf(e);return!!(p&&p.constructor.name==="AbortSignal")}class Request{constructor(e){let p=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};let a;if(!isRequest(e)){if(e&&e.href){a=parseURL(e.href)}else{a=parseURL(`${e}`)}e={}}else{a=parseURL(e.url)}let d=p.method||e.method||"GET";d=d.toUpperCase();if((p.body!=null||isRequest(e)&&e.body!==null)&&(d==="GET"||d==="HEAD")){throw new TypeError("Request with GET/HEAD method cannot have body")}let t=p.body!=null?p.body:isRequest(e)&&e.body!==null?clone(e):null;Body.call(this,t,{timeout:p.timeout||e.timeout||0,size:p.size||e.size||0});const r=new Headers(p.headers||e.headers||{});if(t!=null&&!r.has("Content-Type")){const e=extractContentType(t);if(e){r.append("Content-Type",e)}}let s=isRequest(e)?e.signal:null;if("signal"in p)s=p.signal;if(s!=null&&!isAbortSignal(s)){throw new TypeError("Expected signal to be an instanceof AbortSignal")}this[y]={method:d,redirect:p.redirect||e.redirect||"follow",headers:r,parsedURL:a,signal:s};this.follow=p.follow!==undefined?p.follow:e.follow!==undefined?e.follow:20;this.compress=p.compress!==undefined?p.compress:e.compress!==undefined?e.compress:true;this.counter=p.counter||e.counter||0;this.agent=p.agent||e.agent}get method(){return this[y].method}get url(){return P(this[y].parsedURL)}get headers(){return this[y].headers}get redirect(){return this[y].redirect}get signal(){return this[y].signal}clone(){return new Request(this)}}Body.mixIn(Request.prototype);Object.defineProperty(Request.prototype,Symbol.toStringTag,{value:"Request",writable:false,enumerable:false,configurable:true});Object.defineProperties(Request.prototype,{method:{enumerable:true},url:{enumerable:true},headers:{enumerable:true},redirect:{enumerable:true},clone:{enumerable:true},signal:{enumerable:true}});function getNodeRequestOptions(e){const p=e[y].parsedURL;const a=new Headers(e[y].headers);if(!a.has("Accept")){a.set("Accept","*/*")}if(!p.protocol||!p.hostname){throw new TypeError("Only absolute URLs are supported")}if(!/^https?:$/.test(p.protocol)){throw new TypeError("Only HTTP(S) protocols are supported")}if(e.signal&&e.body instanceof d.Readable&&!A){throw new Error("Cancellation of streamed requests with AbortSignal is not supported in node < 8")}let t=null;if(e.body==null&&/^(POST|PUT)$/i.test(e.method)){t="0"}if(e.body!=null){const p=getTotalBytes(e);if(typeof p==="number"){t=String(p)}}if(t){a.set("Content-Length",t)}if(!a.has("User-Agent")){a.set("User-Agent","node-fetch/1.0 (+https://github.com/bitinn/node-fetch)")}if(e.compress&&!a.has("Accept-Encoding")){a.set("Accept-Encoding","gzip,deflate")}let r=e.agent;if(typeof r==="function"){r=r(p)}if(!a.has("Connection")&&!r){a.set("Connection","close")}return Object.assign({},p,{method:e.method,headers:exportNodeCompatibleHeaders(a),agent:r})}function AbortError(e){Error.call(this,e);this.type="aborted";this.message=e;Error.captureStackTrace(this,this.constructor)}AbortError.prototype=Object.create(Error.prototype);AbortError.prototype.constructor=AbortError;AbortError.prototype.name="AbortError";const O=r.URL||s.URL;const k=d.PassThrough;const N=function isDomainOrSubdomain(e,p){const a=new O(p).hostname;const d=new O(e).hostname;return a===d||a[a.length-d.length-1]==="."&&a.endsWith(d)};const R=function isSameProtocol(e,p){const a=new O(p).protocol;const d=new O(e).protocol;return a===d};function fetch(e,p){if(!fetch.Promise){throw new Error("native promise missing, set fetch.Promise to your favorite alternative")}Body.Promise=fetch.Promise;return new fetch.Promise((function(a,r){const s=new Request(e,p);const n=getNodeRequestOptions(s);const l=(n.protocol==="https:"?i:t).request;const m=s.signal;let u=null;const c=function abort(){let e=new AbortError("The user aborted a request.");r(e);if(s.body&&s.body instanceof d.Readable){destroyStream(s.body,e)}if(!u||!u.body)return;u.body.emit("error",e)};if(m&&m.aborted){c();return}const v=function abortAndFinalize(){c();finalize()};const h=l(n);let g;if(m){m.addEventListener("abort",v)}function finalize(){h.abort();if(m)m.removeEventListener("abort",v);clearTimeout(g)}if(s.timeout){h.once("socket",(function(e){g=setTimeout((function(){r(new FetchError(`network timeout at: ${s.url}`,"request-timeout"));finalize()}),s.timeout)}))}h.on("error",(function(e){r(new FetchError(`request to ${s.url} failed, reason: ${e.message}`,"system",e));if(u&&u.body){destroyStream(u.body,e)}finalize()}));fixResponseChunkedTransferBadEnding(h,(function(e){if(m&&m.aborted){return}if(u&&u.body){destroyStream(u.body,e)}}));if(parseInt(process.version.substring(1))<14){h.on("socket",(function(e){e.addListener("close",(function(p){const a=e.listenerCount("data")>0;if(u&&a&&!p&&!(m&&m.aborted)){const e=new Error("Premature close");e.code="ERR_STREAM_PREMATURE_CLOSE";u.body.emit("error",e)}}))}))}h.on("response",(function(e){clearTimeout(g);const p=createHeadersLenient(e.headers);if(fetch.isRedirect(e.statusCode)){const d=p.get("Location");let t=null;try{t=d===null?null:new O(d,s.url).toString()}catch(e){if(s.redirect!=="manual"){r(new FetchError(`uri requested responds with an invalid redirect URL: ${d}`,"invalid-redirect"));finalize();return}}switch(s.redirect){case"error":r(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${s.url}`,"no-redirect"));finalize();return;case"manual":if(t!==null){try{p.set("Location",t)}catch(e){r(e)}}break;case"follow":if(t===null){break}if(s.counter>=s.follow){r(new FetchError(`maximum redirect reached at: ${s.url}`,"max-redirect"));finalize();return}const d={headers:new Headers(s.headers),follow:s.follow,counter:s.counter+1,agent:s.agent,compress:s.compress,method:s.method,body:s.body,signal:s.signal,timeout:s.timeout,size:s.size};if(!N(s.url,t)||!R(s.url,t)){for(const e of["authorization","www-authenticate","cookie","cookie2"]){d.headers.delete(e)}}if(e.statusCode!==303&&s.body&&getTotalBytes(s)===null){r(new FetchError("Cannot follow redirect with body being a readable stream","unsupported-redirect"));finalize();return}if(e.statusCode===303||(e.statusCode===301||e.statusCode===302)&&s.method==="POST"){d.method="GET";d.body=undefined;d.headers.delete("content-length")}a(fetch(new Request(t,d)));finalize();return}}e.once("end",(function(){if(m)m.removeEventListener("abort",v)}));let d=e.pipe(new k);const t={url:s.url,status:e.statusCode,statusText:e.statusMessage,headers:p,size:s.size,timeout:s.timeout,counter:s.counter};const i=p.get("Content-Encoding");if(!s.compress||s.method==="HEAD"||i===null||e.statusCode===204||e.statusCode===304){u=new Response(d,t);a(u);return}const n={flush:o.Z_SYNC_FLUSH,finishFlush:o.Z_SYNC_FLUSH};if(i=="gzip"||i=="x-gzip"){d=d.pipe(o.createGunzip(n));u=new Response(d,t);a(u);return}if(i=="deflate"||i=="x-deflate"){const p=e.pipe(new k);p.once("data",(function(e){if((e[0]&15)===8){d=d.pipe(o.createInflate())}else{d=d.pipe(o.createInflateRaw())}u=new Response(d,t);a(u)}));p.on("end",(function(){if(!u){u=new Response(d,t);a(u)}}));return}if(i=="br"&&typeof o.createBrotliDecompress==="function"){d=d.pipe(o.createBrotliDecompress());u=new Response(d,t);a(u);return}u=new Response(d,t);a(u)}));writeToStream(h,s)}))}function fixResponseChunkedTransferBadEnding(e,p){let a;e.on("socket",(function(e){a=e}));e.on("response",(function(e){const d=e.headers;if(d["transfer-encoding"]==="chunked"&&!d["content-length"]){e.once("close",(function(e){const d=a.listenerCount("data")>0;if(d&&!e){const e=new Error("Premature close");e.code="ERR_STREAM_PREMATURE_CLOSE";p(e)}}))}}))}function destroyStream(e,p){if(e.destroy){e.destroy(p)}else{e.emit("error",p);e.end()}}fetch.isRedirect=function(e){return e===301||e===302||e===303||e===307||e===308};fetch.Promise=global.Promise;e.exports=p=fetch;Object.defineProperty(p,"__esModule",{value:true});p["default"]=p;p.Headers=Headers;p.Request=Request;p.Response=Response;p.FetchError=FetchError},1223:(e,p,a)=>{var d=a(2940);e.exports=d(once);e.exports.strict=d(onceStrict);once.proto=once((function(){Object.defineProperty(Function.prototype,"once",{value:function(){return once(this)},configurable:true});Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return onceStrict(this)},configurable:true})}));function once(e){var f=function(){if(f.called)return f.value;f.called=true;return f.value=e.apply(this,arguments)};f.called=false;return f}function onceStrict(e){var f=function(){if(f.called)throw new Error(f.onceError);f.called=true;return f.value=e.apply(this,arguments)};var p=e.name||"Function wrapped with `once`";f.onceError=p+" shouldn't be called more than once";f.called=false;return f}},4256:(e,p,a)=>{var d=a(5477);var t=a(2020);var r={TRANSITIONAL:0,NONTRANSITIONAL:1};function normalize(e){return e.split("\0").map((function(e){return e.normalize("NFC")})).join("\0")}function findStatus(e){var p=0;var a=t.length-1;while(p<=a){var d=Math.floor((p+a)/2);var r=t[d];if(r[0][0]<=e&&r[0][1]>=e){return r}else if(r[0][0]>e){a=d-1}else{p=d+1}}return null}var s=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g;function countSymbols(e){return e.replace(s,"_").length}function mapChars(e,p,a){var d=false;var t="";var s=countSymbols(e);for(var i=0;i253||i.length===0){r.error=true}for(var o=0;o63||s.length===0){r.error=true;break}}}if(r.error)return null;return s.join(".")};e.exports.toUnicode=function(e,p){var a=processing(e,p,r.NONTRANSITIONAL);return{domain:a.string,error:a.error}};e.exports.PROCESSING_OPTIONS=r},4294:(e,p,a)=>{e.exports=a(4219)},4219:(e,p,a)=>{var d=a(1808);var t=a(4404);var r=a(3685);var s=a(5687);var i=a(2361);var o=a(9491);var n=a(3837);p.httpOverHttp=httpOverHttp;p.httpsOverHttp=httpsOverHttp;p.httpOverHttps=httpOverHttps;p.httpsOverHttps=httpsOverHttps;function httpOverHttp(e){var p=new TunnelingAgent(e);p.request=r.request;return p}function httpsOverHttp(e){var p=new TunnelingAgent(e);p.request=r.request;p.createSocket=createSecureSocket;p.defaultPort=443;return p}function httpOverHttps(e){var p=new TunnelingAgent(e);p.request=s.request;return p}function httpsOverHttps(e){var p=new TunnelingAgent(e);p.request=s.request;p.createSocket=createSecureSocket;p.defaultPort=443;return p}function TunnelingAgent(e){var p=this;p.options=e||{};p.proxyOptions=p.options.proxy||{};p.maxSockets=p.options.maxSockets||r.Agent.defaultMaxSockets;p.requests=[];p.sockets=[];p.on("free",(function onFree(e,a,d,t){var r=toOptions(a,d,t);for(var s=0,i=p.requests.length;s=this.maxSockets){t.requests.push(r);return}t.createSocket(r,(function(p){p.on("free",onFree);p.on("close",onCloseOrRemove);p.on("agentRemove",onCloseOrRemove);e.onSocket(p);function onFree(){t.emit("free",p,r)}function onCloseOrRemove(e){t.removeSocket(p);p.removeListener("free",onFree);p.removeListener("close",onCloseOrRemove);p.removeListener("agentRemove",onCloseOrRemove)}}))};TunnelingAgent.prototype.createSocket=function createSocket(e,p){var a=this;var d={};a.sockets.push(d);var t=mergeOptions({},a.proxyOptions,{method:"CONNECT",path:e.host+":"+e.port,agent:false,headers:{host:e.host+":"+e.port}});if(e.localAddress){t.localAddress=e.localAddress}if(t.proxyAuth){t.headers=t.headers||{};t.headers["Proxy-Authorization"]="Basic "+new Buffer(t.proxyAuth).toString("base64")}l("making CONNECT request");var r=a.request(t);r.useChunkedEncodingByDefault=false;r.once("response",onResponse);r.once("upgrade",onUpgrade);r.once("connect",onConnect);r.once("error",onError);r.end();function onResponse(e){e.upgrade=true}function onUpgrade(e,p,a){process.nextTick((function(){onConnect(e,p,a)}))}function onConnect(t,s,i){r.removeAllListeners();s.removeAllListeners();if(t.statusCode!==200){l("tunneling socket could not be established, statusCode=%d",t.statusCode);s.destroy();var o=new Error("tunneling socket could not be established, "+"statusCode="+t.statusCode);o.code="ECONNRESET";e.request.emit("error",o);a.removeSocket(d);return}if(i.length>0){l("got illegal response body from proxy");s.destroy();var o=new Error("got illegal response body from proxy");o.code="ECONNRESET";e.request.emit("error",o);a.removeSocket(d);return}l("tunneling connection has established");a.sockets[a.sockets.indexOf(d)]=s;return p(s)}function onError(p){r.removeAllListeners();l("tunneling socket could not be established, cause=%s\n",p.message,p.stack);var t=new Error("tunneling socket could not be established, "+"cause="+p.message);t.code="ECONNRESET";e.request.emit("error",t);a.removeSocket(d)}};TunnelingAgent.prototype.removeSocket=function removeSocket(e){var p=this.sockets.indexOf(e);if(p===-1){return}this.sockets.splice(p,1);var a=this.requests.shift();if(a){this.createSocket(a,(function(e){a.request.onSocket(e)}))}};function createSecureSocket(e,p){var a=this;TunnelingAgent.prototype.createSocket.call(a,e,(function(d){var r=e.request.getHeader("host");var s=mergeOptions({},a.options,{socket:d,servername:r?r.replace(/:.*$/,""):e.host});var i=t.connect(0,s);a.sockets[a.sockets.indexOf(d)]=i;p(i)}))}function toOptions(e,p,a){if(typeof e==="string"){return{host:e,port:p,localAddress:a}}return e}function mergeOptions(e){for(var p=1,a=arguments.length;p{Object.defineProperty(p,"__esModule",{value:true});function getUserAgent(){if(typeof navigator==="object"&&"userAgent"in navigator){return navigator.userAgent}if(typeof process==="object"&&"version"in process){return`Node.js/${process.version.substr(1)} (${process.platform}; ${process.arch})`}return""}p.getUserAgent=getUserAgent},5840:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});Object.defineProperty(p,"v1",{enumerable:true,get:function(){return d.default}});Object.defineProperty(p,"v3",{enumerable:true,get:function(){return t.default}});Object.defineProperty(p,"v4",{enumerable:true,get:function(){return r.default}});Object.defineProperty(p,"v5",{enumerable:true,get:function(){return s.default}});Object.defineProperty(p,"NIL",{enumerable:true,get:function(){return i.default}});Object.defineProperty(p,"version",{enumerable:true,get:function(){return o.default}});Object.defineProperty(p,"validate",{enumerable:true,get:function(){return n.default}});Object.defineProperty(p,"stringify",{enumerable:true,get:function(){return l.default}});Object.defineProperty(p,"parse",{enumerable:true,get:function(){return m.default}});var d=_interopRequireDefault(a(8628));var t=_interopRequireDefault(a(6409));var r=_interopRequireDefault(a(5122));var s=_interopRequireDefault(a(9120));var i=_interopRequireDefault(a(5332));var o=_interopRequireDefault(a(1595));var n=_interopRequireDefault(a(6900));var l=_interopRequireDefault(a(8950));var m=_interopRequireDefault(a(2746));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}},4569:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6113));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function md5(e){if(Array.isArray(e)){e=Buffer.from(e)}else if(typeof e==="string"){e=Buffer.from(e,"utf8")}return d.default.createHash("md5").update(e).digest()}var t=md5;p["default"]=t},5332:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var a="00000000-0000-0000-0000-000000000000";p["default"]=a},2746:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6900));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function parse(e){if(!(0,d.default)(e)){throw TypeError("Invalid UUID")}let p;const a=new Uint8Array(16);a[0]=(p=parseInt(e.slice(0,8),16))>>>24;a[1]=p>>>16&255;a[2]=p>>>8&255;a[3]=p&255;a[4]=(p=parseInt(e.slice(9,13),16))>>>8;a[5]=p&255;a[6]=(p=parseInt(e.slice(14,18),16))>>>8;a[7]=p&255;a[8]=(p=parseInt(e.slice(19,23),16))>>>8;a[9]=p&255;a[10]=(p=parseInt(e.slice(24,36),16))/1099511627776&255;a[11]=p/4294967296&255;a[12]=p>>>24&255;a[13]=p>>>16&255;a[14]=p>>>8&255;a[15]=p&255;return a}var t=parse;p["default"]=t},814:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var a=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;p["default"]=a},807:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=rng;var d=_interopRequireDefault(a(6113));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const t=new Uint8Array(256);let r=t.length;function rng(){if(r>t.length-16){d.default.randomFillSync(t);r=0}return t.slice(r,r+=16)}},5274:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6113));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function sha1(e){if(Array.isArray(e)){e=Buffer.from(e)}else if(typeof e==="string"){e=Buffer.from(e,"utf8")}return d.default.createHash("sha1").update(e).digest()}var t=sha1;p["default"]=t},8950:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6900));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const t=[];for(let e=0;e<256;++e){t.push((e+256).toString(16).substr(1))}function stringify(e,p=0){const a=(t[e[p+0]]+t[e[p+1]]+t[e[p+2]]+t[e[p+3]]+"-"+t[e[p+4]]+t[e[p+5]]+"-"+t[e[p+6]]+t[e[p+7]]+"-"+t[e[p+8]]+t[e[p+9]]+"-"+t[e[p+10]]+t[e[p+11]]+t[e[p+12]]+t[e[p+13]]+t[e[p+14]]+t[e[p+15]]).toLowerCase();if(!(0,d.default)(a)){throw TypeError("Stringified UUID is invalid")}return a}var r=stringify;p["default"]=r},8628:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(807));var t=_interopRequireDefault(a(8950));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}let r;let s;let i=0;let o=0;function v1(e,p,a){let n=p&&a||0;const l=p||new Array(16);e=e||{};let m=e.node||r;let u=e.clockseq!==undefined?e.clockseq:s;if(m==null||u==null){const p=e.random||(e.rng||d.default)();if(m==null){m=r=[p[0]|1,p[1],p[2],p[3],p[4],p[5]]}if(u==null){u=s=(p[6]<<8|p[7])&16383}}let c=e.msecs!==undefined?e.msecs:Date.now();let v=e.nsecs!==undefined?e.nsecs:o+1;const h=c-i+(v-o)/1e4;if(h<0&&e.clockseq===undefined){u=u+1&16383}if((h<0||c>i)&&e.nsecs===undefined){v=0}if(v>=1e4){throw new Error("uuid.v1(): Can't create more than 10M uuids/sec")}i=c;o=v;s=u;c+=122192928e5;const g=((c&268435455)*1e4+v)%4294967296;l[n++]=g>>>24&255;l[n++]=g>>>16&255;l[n++]=g>>>8&255;l[n++]=g&255;const w=c/4294967296*1e4&268435455;l[n++]=w>>>8&255;l[n++]=w&255;l[n++]=w>>>24&15|16;l[n++]=w>>>16&255;l[n++]=u>>>8|128;l[n++]=u&255;for(let e=0;e<6;++e){l[n+e]=m[e]}return p||(0,t.default)(l)}var n=v1;p["default"]=n},6409:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(5998));var t=_interopRequireDefault(a(4569));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const r=(0,d.default)("v3",48,t.default);var s=r;p["default"]=s},5998:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=_default;p.URL=p.DNS=void 0;var d=_interopRequireDefault(a(8950));var t=_interopRequireDefault(a(2746));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function stringToBytes(e){e=unescape(encodeURIComponent(e));const p=[];for(let a=0;a{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(807));var t=_interopRequireDefault(a(8950));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function v4(e,p,a){e=e||{};const r=e.random||(e.rng||d.default)();r[6]=r[6]&15|64;r[8]=r[8]&63|128;if(p){a=a||0;for(let e=0;e<16;++e){p[a+e]=r[e]}return p}return(0,t.default)(r)}var r=v4;p["default"]=r},9120:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(5998));var t=_interopRequireDefault(a(5274));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const r=(0,d.default)("v5",80,t.default);var s=r;p["default"]=s},6900:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(814));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function validate(e){return typeof e==="string"&&d.default.test(e)}var t=validate;p["default"]=t},1595:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6900));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function version(e){if(!(0,d.default)(e)){throw TypeError("Invalid UUID")}return parseInt(e.substr(14,1),16)}var t=version;p["default"]=t},4886:e=>{var p={};e.exports=p;function sign(e){return e<0?-1:1}function evenRound(e){if(e%1===.5&&(e&1)===0){return Math.floor(e)}else{return Math.round(e)}}function createNumberConversion(e,p){if(!p.unsigned){--e}const a=p.unsigned?0:-Math.pow(2,e);const d=Math.pow(2,e)-1;const t=p.moduloBitLength?Math.pow(2,p.moduloBitLength):Math.pow(2,e);const r=p.moduloBitLength?Math.pow(2,p.moduloBitLength-1):Math.pow(2,e-1);return function(e,s){if(!s)s={};let i=+e;if(s.enforceRange){if(!Number.isFinite(i)){throw new TypeError("Argument is not a finite number")}i=sign(i)*Math.floor(Math.abs(i));if(id){throw new TypeError("Argument is not in byte range")}return i}if(!isNaN(i)&&s.clamp){i=evenRound(i);if(id)i=d;return i}if(!Number.isFinite(i)||i===0){return 0}i=sign(i)*Math.floor(Math.abs(i));i=i%t;if(!p.unsigned&&i>=r){return i-t}else if(p.unsigned){if(i<0){i+=t}else if(i===-0){return 0}}return i}}p["void"]=function(){return undefined};p["boolean"]=function(e){return!!e};p["byte"]=createNumberConversion(8,{unsigned:false});p["octet"]=createNumberConversion(8,{unsigned:true});p["short"]=createNumberConversion(16,{unsigned:false});p["unsigned short"]=createNumberConversion(16,{unsigned:true});p["long"]=createNumberConversion(32,{unsigned:false});p["unsigned long"]=createNumberConversion(32,{unsigned:true});p["long long"]=createNumberConversion(32,{unsigned:false,moduloBitLength:64});p["unsigned long long"]=createNumberConversion(32,{unsigned:true,moduloBitLength:64});p["double"]=function(e){const p=+e;if(!Number.isFinite(p)){throw new TypeError("Argument is not a finite floating-point value")}return p};p["unrestricted double"]=function(e){const p=+e;if(isNaN(p)){throw new TypeError("Argument is NaN")}return p};p["float"]=p["double"];p["unrestricted float"]=p["unrestricted double"];p["DOMString"]=function(e,p){if(!p)p={};if(p.treatNullAsEmptyString&&e===null){return""}return String(e)};p["ByteString"]=function(e,p){const a=String(e);let d=undefined;for(let e=0;(d=a.codePointAt(e))!==undefined;++e){if(d>255){throw new TypeError("Argument is not a valid bytestring")}}return a};p["USVString"]=function(e){const p=String(e);const a=p.length;const d=[];for(let e=0;e57343){d.push(String.fromCodePoint(t))}else if(56320<=t&&t<=57343){d.push(String.fromCodePoint(65533))}else{if(e===a-1){d.push(String.fromCodePoint(65533))}else{const a=p.charCodeAt(e+1);if(56320<=a&&a<=57343){const p=t&1023;const r=a&1023;d.push(String.fromCodePoint((2<<15)+(2<<9)*p+r));++e}else{d.push(String.fromCodePoint(65533))}}}}return d.join("")};p["Date"]=function(e,p){if(!(e instanceof Date)){throw new TypeError("Argument is not a Date object")}if(isNaN(e)){return undefined}return e};p["RegExp"]=function(e,p){if(!(e instanceof RegExp)){e=new RegExp(e)}return e}},7537:(e,p,a)=>{const d=a(2158);p.implementation=class URLImpl{constructor(e){const p=e[0];const a=e[1];let t=null;if(a!==undefined){t=d.basicURLParse(a);if(t==="failure"){throw new TypeError("Invalid base URL")}}const r=d.basicURLParse(p,{baseURL:t});if(r==="failure"){throw new TypeError("Invalid URL")}this._url=r}get href(){return d.serializeURL(this._url)}set href(e){const p=d.basicURLParse(e);if(p==="failure"){throw new TypeError("Invalid URL")}this._url=p}get origin(){return d.serializeURLOrigin(this._url)}get protocol(){return this._url.scheme+":"}set protocol(e){d.basicURLParse(e+":",{url:this._url,stateOverride:"scheme start"})}get username(){return this._url.username}set username(e){if(d.cannotHaveAUsernamePasswordPort(this._url)){return}d.setTheUsername(this._url,e)}get password(){return this._url.password}set password(e){if(d.cannotHaveAUsernamePasswordPort(this._url)){return}d.setThePassword(this._url,e)}get host(){const e=this._url;if(e.host===null){return""}if(e.port===null){return d.serializeHost(e.host)}return d.serializeHost(e.host)+":"+d.serializeInteger(e.port)}set host(e){if(this._url.cannotBeABaseURL){return}d.basicURLParse(e,{url:this._url,stateOverride:"host"})}get hostname(){if(this._url.host===null){return""}return d.serializeHost(this._url.host)}set hostname(e){if(this._url.cannotBeABaseURL){return}d.basicURLParse(e,{url:this._url,stateOverride:"hostname"})}get port(){if(this._url.port===null){return""}return d.serializeInteger(this._url.port)}set port(e){if(d.cannotHaveAUsernamePasswordPort(this._url)){return}if(e===""){this._url.port=null}else{d.basicURLParse(e,{url:this._url,stateOverride:"port"})}}get pathname(){if(this._url.cannotBeABaseURL){return this._url.path[0]}if(this._url.path.length===0){return""}return"/"+this._url.path.join("/")}set pathname(e){if(this._url.cannotBeABaseURL){return}this._url.path=[];d.basicURLParse(e,{url:this._url,stateOverride:"path start"})}get search(){if(this._url.query===null||this._url.query===""){return""}return"?"+this._url.query}set search(e){const p=this._url;if(e===""){p.query=null;return}const a=e[0]==="?"?e.substring(1):e;p.query="";d.basicURLParse(a,{url:p,stateOverride:"query"})}get hash(){if(this._url.fragment===null||this._url.fragment===""){return""}return"#"+this._url.fragment}set hash(e){if(e===""){this._url.fragment=null;return}const p=e[0]==="#"?e.substring(1):e;this._url.fragment="";d.basicURLParse(p,{url:this._url,stateOverride:"fragment"})}toJSON(){return this.href}}},3394:(e,p,a)=>{const d=a(4886);const t=a(3185);const r=a(7537);const s=t.implSymbol;function URL(p){if(!this||this[s]||!(this instanceof URL)){throw new TypeError("Failed to construct 'URL': Please use the 'new' operator, this DOM object constructor cannot be called as a function.")}if(arguments.length<1){throw new TypeError("Failed to construct 'URL': 1 argument required, but only "+arguments.length+" present.")}const a=[];for(let e=0;e{p.URL=a(3394)["interface"];p.serializeURL=a(2158).serializeURL;p.serializeURLOrigin=a(2158).serializeURLOrigin;p.basicURLParse=a(2158).basicURLParse;p.setTheUsername=a(2158).setTheUsername;p.setThePassword=a(2158).setThePassword;p.serializeHost=a(2158).serializeHost;p.serializeInteger=a(2158).serializeInteger;p.parseURL=a(2158).parseURL},2158:(e,p,a)=>{const d=a(5477);const t=a(4256);const r={ftp:21,file:null,gopher:70,http:80,https:443,ws:80,wss:443};const s=Symbol("failure");function countSymbols(e){return d.ucs2.decode(e).length}function at(e,p){const a=e[p];return isNaN(a)?undefined:String.fromCodePoint(a)}function isASCIIDigit(e){return e>=48&&e<=57}function isASCIIAlpha(e){return e>=65&&e<=90||e>=97&&e<=122}function isASCIIAlphanumeric(e){return isASCIIAlpha(e)||isASCIIDigit(e)}function isASCIIHex(e){return isASCIIDigit(e)||e>=65&&e<=70||e>=97&&e<=102}function isSingleDot(e){return e==="."||e.toLowerCase()==="%2e"}function isDoubleDot(e){e=e.toLowerCase();return e===".."||e==="%2e."||e===".%2e"||e==="%2e%2e"}function isWindowsDriveLetterCodePoints(e,p){return isASCIIAlpha(e)&&(p===58||p===124)}function isWindowsDriveLetterString(e){return e.length===2&&isASCIIAlpha(e.codePointAt(0))&&(e[1]===":"||e[1]==="|")}function isNormalizedWindowsDriveLetterString(e){return e.length===2&&isASCIIAlpha(e.codePointAt(0))&&e[1]===":"}function containsForbiddenHostCodePoint(e){return e.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/)!==-1}function containsForbiddenHostCodePointExcludingPercent(e){return e.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/)!==-1}function isSpecialScheme(e){return r[e]!==undefined}function isSpecial(e){return isSpecialScheme(e.scheme)}function defaultPort(e){return r[e]}function percentEncode(e){let p=e.toString(16).toUpperCase();if(p.length===1){p="0"+p}return"%"+p}function utf8PercentEncode(e){const p=new Buffer(e);let a="";for(let e=0;e126}const i=new Set([32,34,35,60,62,63,96,123,125]);function isPathPercentEncode(e){return isC0ControlPercentEncode(e)||i.has(e)}const o=new Set([47,58,59,61,64,91,92,93,94,124]);function isUserinfoPercentEncode(e){return isPathPercentEncode(e)||o.has(e)}function percentEncodeChar(e,p){const a=String.fromCodePoint(e);if(p(e)){return utf8PercentEncode(a)}return a}function parseIPv4Number(e){let p=10;if(e.length>=2&&e.charAt(0)==="0"&&e.charAt(1).toLowerCase()==="x"){e=e.substring(2);p=16}else if(e.length>=2&&e.charAt(0)==="0"){e=e.substring(1);p=8}if(e===""){return 0}const a=p===10?/[^0-9]/:p===16?/[^0-9A-Fa-f]/:/[^0-7]/;if(a.test(e)){return s}return parseInt(e,p)}function parseIPv4(e){const p=e.split(".");if(p[p.length-1]===""){if(p.length>1){p.pop()}}if(p.length>4){return e}const a=[];for(const d of p){if(d===""){return e}const p=parseIPv4Number(d);if(p===s){return e}a.push(p)}for(let e=0;e255){return s}}if(a[a.length-1]>=Math.pow(256,5-a.length)){return s}let d=a.pop();let t=0;for(const e of a){d+=e*Math.pow(256,3-t);++t}return d}function serializeIPv4(e){let p="";let a=e;for(let e=1;e<=4;++e){p=String(a%256)+p;if(e!==4){p="."+p}a=Math.floor(a/256)}return p}function parseIPv6(e){const p=[0,0,0,0,0,0,0,0];let a=0;let t=null;let r=0;e=d.ucs2.decode(e);if(e[r]===58){if(e[r+1]!==58){return s}r+=2;++a;t=a}while(r6){return s}let d=0;while(e[r]!==undefined){let t=null;if(d>0){if(e[r]===46&&d<4){++r}else{return s}}if(!isASCIIDigit(e[r])){return s}while(isASCIIDigit(e[r])){const p=parseInt(at(e,r));if(t===null){t=p}else if(t===0){return s}else{t=t*10+p}if(t>255){return s}++r}p[a]=p[a]*256+t;++d;if(d===2||d===4){++a}}if(d!==4){return s}break}else if(e[r]===58){++r;if(e[r]===undefined){return s}}else if(e[r]!==undefined){return s}p[a]=d;++a}if(t!==null){let e=a-t;a=7;while(a!==0&&e>0){const d=p[t+e-1];p[t+e-1]=p[a];p[a]=d;--a;--e}}else if(t===null&&a!==8){return s}return p}function serializeIPv6(e){let p="";const a=findLongestZeroSequence(e);const d=a.idx;let t=false;for(let a=0;a<=7;++a){if(t&&e[a]===0){continue}else if(t){t=false}if(d===a){const e=a===0?"::":":";p+=e;t=true;continue}p+=e[a].toString(16);if(a!==7){p+=":"}}return p}function parseHost(e,p){if(e[0]==="["){if(e[e.length-1]!=="]"){return s}return parseIPv6(e.substring(1,e.length-1))}if(!p){return parseOpaqueHost(e)}const a=utf8PercentDecode(e);const d=t.toASCII(a,false,t.PROCESSING_OPTIONS.NONTRANSITIONAL,false);if(d===null){return s}if(containsForbiddenHostCodePoint(d)){return s}const r=parseIPv4(d);if(typeof r==="number"||r===s){return r}return d}function parseOpaqueHost(e){if(containsForbiddenHostCodePointExcludingPercent(e)){return s}let p="";const a=d.ucs2.decode(e);for(let e=0;ea){p=d;a=t}d=null;t=0}else{if(d===null){d=r}++t}}if(t>a){p=d;a=t}return{idx:p,len:a}}function serializeHost(e){if(typeof e==="number"){return serializeIPv4(e)}if(e instanceof Array){return"["+serializeIPv6(e)+"]"}return e}function trimControlChars(e){return e.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g,"")}function trimTabAndNewline(e){return e.replace(/\u0009|\u000A|\u000D/g,"")}function shortenPath(e){const p=e.path;if(p.length===0){return}if(e.scheme==="file"&&p.length===1&&isNormalizedWindowsDriveLetter(p[0])){return}p.pop()}function includesCredentials(e){return e.username!==""||e.password!==""}function cannotHaveAUsernamePasswordPort(e){return e.host===null||e.host===""||e.cannotBeABaseURL||e.scheme==="file"}function isNormalizedWindowsDriveLetter(e){return/^[A-Za-z]:$/.test(e)}function URLStateMachine(e,p,a,t,r){this.pointer=0;this.input=e;this.base=p||null;this.encodingOverride=a||"utf-8";this.stateOverride=r;this.url=t;this.failure=false;this.parseError=false;if(!this.url){this.url={scheme:"",username:"",password:"",host:null,port:null,path:[],query:null,fragment:null,cannotBeABaseURL:false};const e=trimControlChars(this.input);if(e!==this.input){this.parseError=true}this.input=e}const i=trimTabAndNewline(this.input);if(i!==this.input){this.parseError=true}this.input=i;this.state=r||"scheme start";this.buffer="";this.atFlag=false;this.arrFlag=false;this.passwordTokenSeenFlag=false;this.input=d.ucs2.decode(this.input);for(;this.pointer<=this.input.length;++this.pointer){const e=this.input[this.pointer];const p=isNaN(e)?undefined:String.fromCodePoint(e);const a=this["parse "+this.state](e,p);if(!a){break}else if(a===s){this.failure=true;break}}}URLStateMachine.prototype["parse scheme start"]=function parseSchemeStart(e,p){if(isASCIIAlpha(e)){this.buffer+=p.toLowerCase();this.state="scheme"}else if(!this.stateOverride){this.state="no scheme";--this.pointer}else{this.parseError=true;return s}return true};URLStateMachine.prototype["parse scheme"]=function parseScheme(e,p){if(isASCIIAlphanumeric(e)||e===43||e===45||e===46){this.buffer+=p.toLowerCase()}else if(e===58){if(this.stateOverride){if(isSpecial(this.url)&&!isSpecialScheme(this.buffer)){return false}if(!isSpecial(this.url)&&isSpecialScheme(this.buffer)){return false}if((includesCredentials(this.url)||this.url.port!==null)&&this.buffer==="file"){return false}if(this.url.scheme==="file"&&(this.url.host===""||this.url.host===null)){return false}}this.url.scheme=this.buffer;this.buffer="";if(this.stateOverride){return false}if(this.url.scheme==="file"){if(this.input[this.pointer+1]!==47||this.input[this.pointer+2]!==47){this.parseError=true}this.state="file"}else if(isSpecial(this.url)&&this.base!==null&&this.base.scheme===this.url.scheme){this.state="special relative or authority"}else if(isSpecial(this.url)){this.state="special authority slashes"}else if(this.input[this.pointer+1]===47){this.state="path or authority";++this.pointer}else{this.url.cannotBeABaseURL=true;this.url.path.push("");this.state="cannot-be-a-base-URL path"}}else if(!this.stateOverride){this.buffer="";this.state="no scheme";this.pointer=-1}else{this.parseError=true;return s}return true};URLStateMachine.prototype["parse no scheme"]=function parseNoScheme(e){if(this.base===null||this.base.cannotBeABaseURL&&e!==35){return s}else if(this.base.cannotBeABaseURL&&e===35){this.url.scheme=this.base.scheme;this.url.path=this.base.path.slice();this.url.query=this.base.query;this.url.fragment="";this.url.cannotBeABaseURL=true;this.state="fragment"}else if(this.base.scheme==="file"){this.state="file";--this.pointer}else{this.state="relative";--this.pointer}return true};URLStateMachine.prototype["parse special relative or authority"]=function parseSpecialRelativeOrAuthority(e){if(e===47&&this.input[this.pointer+1]===47){this.state="special authority ignore slashes";++this.pointer}else{this.parseError=true;this.state="relative";--this.pointer}return true};URLStateMachine.prototype["parse path or authority"]=function parsePathOrAuthority(e){if(e===47){this.state="authority"}else{this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse relative"]=function parseRelative(e){this.url.scheme=this.base.scheme;if(isNaN(e)){this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice();this.url.query=this.base.query}else if(e===47){this.state="relative slash"}else if(e===63){this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice();this.url.query="";this.state="query"}else if(e===35){this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice();this.url.query=this.base.query;this.url.fragment="";this.state="fragment"}else if(isSpecial(this.url)&&e===92){this.parseError=true;this.state="relative slash"}else{this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice(0,this.base.path.length-1);this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse relative slash"]=function parseRelativeSlash(e){if(isSpecial(this.url)&&(e===47||e===92)){if(e===92){this.parseError=true}this.state="special authority ignore slashes"}else if(e===47){this.state="authority"}else{this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse special authority slashes"]=function parseSpecialAuthoritySlashes(e){if(e===47&&this.input[this.pointer+1]===47){this.state="special authority ignore slashes";++this.pointer}else{this.parseError=true;this.state="special authority ignore slashes";--this.pointer}return true};URLStateMachine.prototype["parse special authority ignore slashes"]=function parseSpecialAuthorityIgnoreSlashes(e){if(e!==47&&e!==92){this.state="authority";--this.pointer}else{this.parseError=true}return true};URLStateMachine.prototype["parse authority"]=function parseAuthority(e,p){if(e===64){this.parseError=true;if(this.atFlag){this.buffer="%40"+this.buffer}this.atFlag=true;const e=countSymbols(this.buffer);for(let p=0;pMath.pow(2,16)-1){this.parseError=true;return s}this.url.port=e===defaultPort(this.url.scheme)?null:e;this.buffer=""}if(this.stateOverride){return false}this.state="path start";--this.pointer}else{this.parseError=true;return s}return true};const n=new Set([47,92,63,35]);URLStateMachine.prototype["parse file"]=function parseFile(e){this.url.scheme="file";if(e===47||e===92){if(e===92){this.parseError=true}this.state="file slash"}else if(this.base!==null&&this.base.scheme==="file"){if(isNaN(e)){this.url.host=this.base.host;this.url.path=this.base.path.slice();this.url.query=this.base.query}else if(e===63){this.url.host=this.base.host;this.url.path=this.base.path.slice();this.url.query="";this.state="query"}else if(e===35){this.url.host=this.base.host;this.url.path=this.base.path.slice();this.url.query=this.base.query;this.url.fragment="";this.state="fragment"}else{if(this.input.length-this.pointer-1===0||!isWindowsDriveLetterCodePoints(e,this.input[this.pointer+1])||this.input.length-this.pointer-1>=2&&!n.has(this.input[this.pointer+2])){this.url.host=this.base.host;this.url.path=this.base.path.slice();shortenPath(this.url)}else{this.parseError=true}this.state="path";--this.pointer}}else{this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse file slash"]=function parseFileSlash(e){if(e===47||e===92){if(e===92){this.parseError=true}this.state="file host"}else{if(this.base!==null&&this.base.scheme==="file"){if(isNormalizedWindowsDriveLetterString(this.base.path[0])){this.url.path.push(this.base.path[0])}else{this.url.host=this.base.host}}this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse file host"]=function parseFileHost(e,p){if(isNaN(e)||e===47||e===92||e===63||e===35){--this.pointer;if(!this.stateOverride&&isWindowsDriveLetterString(this.buffer)){this.parseError=true;this.state="path"}else if(this.buffer===""){this.url.host="";if(this.stateOverride){return false}this.state="path start"}else{let e=parseHost(this.buffer,isSpecial(this.url));if(e===s){return s}if(e==="localhost"){e=""}this.url.host=e;if(this.stateOverride){return false}this.buffer="";this.state="path start"}}else{this.buffer+=p}return true};URLStateMachine.prototype["parse path start"]=function parsePathStart(e){if(isSpecial(this.url)){if(e===92){this.parseError=true}this.state="path";if(e!==47&&e!==92){--this.pointer}}else if(!this.stateOverride&&e===63){this.url.query="";this.state="query"}else if(!this.stateOverride&&e===35){this.url.fragment="";this.state="fragment"}else if(e!==undefined){this.state="path";if(e!==47){--this.pointer}}return true};URLStateMachine.prototype["parse path"]=function parsePath(e){if(isNaN(e)||e===47||isSpecial(this.url)&&e===92||!this.stateOverride&&(e===63||e===35)){if(isSpecial(this.url)&&e===92){this.parseError=true}if(isDoubleDot(this.buffer)){shortenPath(this.url);if(e!==47&&!(isSpecial(this.url)&&e===92)){this.url.path.push("")}}else if(isSingleDot(this.buffer)&&e!==47&&!(isSpecial(this.url)&&e===92)){this.url.path.push("")}else if(!isSingleDot(this.buffer)){if(this.url.scheme==="file"&&this.url.path.length===0&&isWindowsDriveLetterString(this.buffer)){if(this.url.host!==""&&this.url.host!==null){this.parseError=true;this.url.host=""}this.buffer=this.buffer[0]+":"}this.url.path.push(this.buffer)}this.buffer="";if(this.url.scheme==="file"&&(e===undefined||e===63||e===35)){while(this.url.path.length>1&&this.url.path[0]===""){this.parseError=true;this.url.path.shift()}}if(e===63){this.url.query="";this.state="query"}if(e===35){this.url.fragment="";this.state="fragment"}}else{if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}this.buffer+=percentEncodeChar(e,isPathPercentEncode)}return true};URLStateMachine.prototype["parse cannot-be-a-base-URL path"]=function parseCannotBeABaseURLPath(e){if(e===63){this.url.query="";this.state="query"}else if(e===35){this.url.fragment="";this.state="fragment"}else{if(!isNaN(e)&&e!==37){this.parseError=true}if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}if(!isNaN(e)){this.url.path[0]=this.url.path[0]+percentEncodeChar(e,isC0ControlPercentEncode)}}return true};URLStateMachine.prototype["parse query"]=function parseQuery(e,p){if(isNaN(e)||!this.stateOverride&&e===35){if(!isSpecial(this.url)||this.url.scheme==="ws"||this.url.scheme==="wss"){this.encodingOverride="utf-8"}const p=new Buffer(this.buffer);for(let e=0;e126||p[e]===34||p[e]===35||p[e]===60||p[e]===62){this.url.query+=percentEncode(p[e])}else{this.url.query+=String.fromCodePoint(p[e])}}this.buffer="";if(e===35){this.url.fragment="";this.state="fragment"}}else{if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}this.buffer+=p}return true};URLStateMachine.prototype["parse fragment"]=function parseFragment(e){if(isNaN(e)){}else if(e===0){this.parseError=true}else{if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}this.url.fragment+=percentEncodeChar(e,isC0ControlPercentEncode)}return true};function serializeURL(e,p){let a=e.scheme+":";if(e.host!==null){a+="//";if(e.username!==""||e.password!==""){a+=e.username;if(e.password!==""){a+=":"+e.password}a+="@"}a+=serializeHost(e.host);if(e.port!==null){a+=":"+e.port}}else if(e.host===null&&e.scheme==="file"){a+="//"}if(e.cannotBeABaseURL){a+=e.path[0]}else{for(const p of e.path){a+="/"+p}}if(e.query!==null){a+="?"+e.query}if(!p&&e.fragment!==null){a+="#"+e.fragment}return a}function serializeOrigin(e){let p=e.scheme+"://";p+=serializeHost(e.host);if(e.port!==null){p+=":"+e.port}return p}e.exports.serializeURL=serializeURL;e.exports.serializeURLOrigin=function(p){switch(p.scheme){case"blob":try{return e.exports.serializeURLOrigin(e.exports.parseURL(p.path[0]))}catch(e){return"null"}case"ftp":case"gopher":case"http":case"https":case"ws":case"wss":return serializeOrigin({scheme:p.scheme,host:p.host,port:p.port});case"file":return"file://";default:return"null"}};e.exports.basicURLParse=function(e,p){if(p===undefined){p={}}const a=new URLStateMachine(e,p.baseURL,p.encodingOverride,p.url,p.stateOverride);if(a.failure){return"failure"}return a.url};e.exports.setTheUsername=function(e,p){e.username="";const a=d.ucs2.decode(p);for(let p=0;p{e.exports.mixin=function mixin(e,p){const a=Object.getOwnPropertyNames(p);for(let d=0;d{e.exports=wrappy;function wrappy(e,p){if(e&&p)return wrappy(e)(p);if(typeof e!=="function")throw new TypeError("need wrapper function");Object.keys(e).forEach((function(p){wrapper[p]=e[p]}));return wrapper;function wrapper(){var p=new Array(arguments.length);for(var a=0;a{module.exports=eval("require")("encoding")},9491:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("assert")},6113:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("crypto")},2361:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("events")},7147:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("fs")},3685:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("http")},5687:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("https")},1808:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("net")},2037:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("os")},1017:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("path")},5477:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("punycode")},2781:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("stream")},4404:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("tls")},7310:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("url")},3837:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("util")},9796:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("zlib")},2020:e=>{e.exports=JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"],[[47,47],"disallowed_STD3_valid"],[[48,57],"valid"],[[58,64],"disallowed_STD3_valid"],[[65,65],"mapped",[97]],[[66,66],"mapped",[98]],[[67,67],"mapped",[99]],[[68,68],"mapped",[100]],[[69,69],"mapped",[101]],[[70,70],"mapped",[102]],[[71,71],"mapped",[103]],[[72,72],"mapped",[104]],[[73,73],"mapped",[105]],[[74,74],"mapped",[106]],[[75,75],"mapped",[107]],[[76,76],"mapped",[108]],[[77,77],"mapped",[109]],[[78,78],"mapped",[110]],[[79,79],"mapped",[111]],[[80,80],"mapped",[112]],[[81,81],"mapped",[113]],[[82,82],"mapped",[114]],[[83,83],"mapped",[115]],[[84,84],"mapped",[116]],[[85,85],"mapped",[117]],[[86,86],"mapped",[118]],[[87,87],"mapped",[119]],[[88,88],"mapped",[120]],[[89,89],"mapped",[121]],[[90,90],"mapped",[122]],[[91,96],"disallowed_STD3_valid"],[[97,122],"valid"],[[123,127],"disallowed_STD3_valid"],[[128,159],"disallowed"],[[160,160],"disallowed_STD3_mapped",[32]],[[161,167],"valid",[],"NV8"],[[168,168],"disallowed_STD3_mapped",[32,776]],[[169,169],"valid",[],"NV8"],[[170,170],"mapped",[97]],[[171,172],"valid",[],"NV8"],[[173,173],"ignored"],[[174,174],"valid",[],"NV8"],[[175,175],"disallowed_STD3_mapped",[32,772]],[[176,177],"valid",[],"NV8"],[[178,178],"mapped",[50]],[[179,179],"mapped",[51]],[[180,180],"disallowed_STD3_mapped",[32,769]],[[181,181],"mapped",[956]],[[182,182],"valid",[],"NV8"],[[183,183],"valid"],[[184,184],"disallowed_STD3_mapped",[32,807]],[[185,185],"mapped",[49]],[[186,186],"mapped",[111]],[[187,187],"valid",[],"NV8"],[[188,188],"mapped",[49,8260,52]],[[189,189],"mapped",[49,8260,50]],[[190,190],"mapped",[51,8260,52]],[[191,191],"valid",[],"NV8"],[[192,192],"mapped",[224]],[[193,193],"mapped",[225]],[[194,194],"mapped",[226]],[[195,195],"mapped",[227]],[[196,196],"mapped",[228]],[[197,197],"mapped",[229]],[[198,198],"mapped",[230]],[[199,199],"mapped",[231]],[[200,200],"mapped",[232]],[[201,201],"mapped",[233]],[[202,202],"mapped",[234]],[[203,203],"mapped",[235]],[[204,204],"mapped",[236]],[[205,205],"mapped",[237]],[[206,206],"mapped",[238]],[[207,207],"mapped",[239]],[[208,208],"mapped",[240]],[[209,209],"mapped",[241]],[[210,210],"mapped",[242]],[[211,211],"mapped",[243]],[[212,212],"mapped",[244]],[[213,213],"mapped",[245]],[[214,214],"mapped",[246]],[[215,215],"valid",[],"NV8"],[[216,216],"mapped",[248]],[[217,217],"mapped",[249]],[[218,218],"mapped",[250]],[[219,219],"mapped",[251]],[[220,220],"mapped",[252]],[[221,221],"mapped",[253]],[[222,222],"mapped",[254]],[[223,223],"deviation",[115,115]],[[224,246],"valid"],[[247,247],"valid",[],"NV8"],[[248,255],"valid"],[[256,256],"mapped",[257]],[[257,257],"valid"],[[258,258],"mapped",[259]],[[259,259],"valid"],[[260,260],"mapped",[261]],[[261,261],"valid"],[[262,262],"mapped",[263]],[[263,263],"valid"],[[264,264],"mapped",[265]],[[265,265],"valid"],[[266,266],"mapped",[267]],[[267,267],"valid"],[[268,268],"mapped",[269]],[[269,269],"valid"],[[270,270],"mapped",[271]],[[271,271],"valid"],[[272,272],"mapped",[273]],[[273,273],"valid"],[[274,274],"mapped",[275]],[[275,275],"valid"],[[276,276],"mapped",[277]],[[277,277],"valid"],[[278,278],"mapped",[279]],[[279,279],"valid"],[[280,280],"mapped",[281]],[[281,281],"valid"],[[282,282],"mapped",[283]],[[283,283],"valid"],[[284,284],"mapped",[285]],[[285,285],"valid"],[[286,286],"mapped",[287]],[[287,287],"valid"],[[288,288],"mapped",[289]],[[289,289],"valid"],[[290,290],"mapped",[291]],[[291,291],"valid"],[[292,292],"mapped",[293]],[[293,293],"valid"],[[294,294],"mapped",[295]],[[295,295],"valid"],[[296,296],"mapped",[297]],[[297,297],"valid"],[[298,298],"mapped",[299]],[[299,299],"valid"],[[300,300],"mapped",[301]],[[301,301],"valid"],[[302,302],"mapped",[303]],[[303,303],"valid"],[[304,304],"mapped",[105,775]],[[305,305],"valid"],[[306,307],"mapped",[105,106]],[[308,308],"mapped",[309]],[[309,309],"valid"],[[310,310],"mapped",[311]],[[311,312],"valid"],[[313,313],"mapped",[314]],[[314,314],"valid"],[[315,315],"mapped",[316]],[[316,316],"valid"],[[317,317],"mapped",[318]],[[318,318],"valid"],[[319,320],"mapped",[108,183]],[[321,321],"mapped",[322]],[[322,322],"valid"],[[323,323],"mapped",[324]],[[324,324],"valid"],[[325,325],"mapped",[326]],[[326,326],"valid"],[[327,327],"mapped",[328]],[[328,328],"valid"],[[329,329],"mapped",[700,110]],[[330,330],"mapped",[331]],[[331,331],"valid"],[[332,332],"mapped",[333]],[[333,333],"valid"],[[334,334],"mapped",[335]],[[335,335],"valid"],[[336,336],"mapped",[337]],[[337,337],"valid"],[[338,338],"mapped",[339]],[[339,339],"valid"],[[340,340],"mapped",[341]],[[341,341],"valid"],[[342,342],"mapped",[343]],[[343,343],"valid"],[[344,344],"mapped",[345]],[[345,345],"valid"],[[346,346],"mapped",[347]],[[347,347],"valid"],[[348,348],"mapped",[349]],[[349,349],"valid"],[[350,350],"mapped",[351]],[[351,351],"valid"],[[352,352],"mapped",[353]],[[353,353],"valid"],[[354,354],"mapped",[355]],[[355,355],"valid"],[[356,356],"mapped",[357]],[[357,357],"valid"],[[358,358],"mapped",[359]],[[359,359],"valid"],[[360,360],"mapped",[361]],[[361,361],"valid"],[[362,362],"mapped",[363]],[[363,363],"valid"],[[364,364],"mapped",[365]],[[365,365],"valid"],[[366,366],"mapped",[367]],[[367,367],"valid"],[[368,368],"mapped",[369]],[[369,369],"valid"],[[370,370],"mapped",[371]],[[371,371],"valid"],[[372,372],"mapped",[373]],[[373,373],"valid"],[[374,374],"mapped",[375]],[[375,375],"valid"],[[376,376],"mapped",[255]],[[377,377],"mapped",[378]],[[378,378],"valid"],[[379,379],"mapped",[380]],[[380,380],"valid"],[[381,381],"mapped",[382]],[[382,382],"valid"],[[383,383],"mapped",[115]],[[384,384],"valid"],[[385,385],"mapped",[595]],[[386,386],"mapped",[387]],[[387,387],"valid"],[[388,388],"mapped",[389]],[[389,389],"valid"],[[390,390],"mapped",[596]],[[391,391],"mapped",[392]],[[392,392],"valid"],[[393,393],"mapped",[598]],[[394,394],"mapped",[599]],[[395,395],"mapped",[396]],[[396,397],"valid"],[[398,398],"mapped",[477]],[[399,399],"mapped",[601]],[[400,400],"mapped",[603]],[[401,401],"mapped",[402]],[[402,402],"valid"],[[403,403],"mapped",[608]],[[404,404],"mapped",[611]],[[405,405],"valid"],[[406,406],"mapped",[617]],[[407,407],"mapped",[616]],[[408,408],"mapped",[409]],[[409,411],"valid"],[[412,412],"mapped",[623]],[[413,413],"mapped",[626]],[[414,414],"valid"],[[415,415],"mapped",[629]],[[416,416],"mapped",[417]],[[417,417],"valid"],[[418,418],"mapped",[419]],[[419,419],"valid"],[[420,420],"mapped",[421]],[[421,421],"valid"],[[422,422],"mapped",[640]],[[423,423],"mapped",[424]],[[424,424],"valid"],[[425,425],"mapped",[643]],[[426,427],"valid"],[[428,428],"mapped",[429]],[[429,429],"valid"],[[430,430],"mapped",[648]],[[431,431],"mapped",[432]],[[432,432],"valid"],[[433,433],"mapped",[650]],[[434,434],"mapped",[651]],[[435,435],"mapped",[436]],[[436,436],"valid"],[[437,437],"mapped",[438]],[[438,438],"valid"],[[439,439],"mapped",[658]],[[440,440],"mapped",[441]],[[441,443],"valid"],[[444,444],"mapped",[445]],[[445,451],"valid"],[[452,454],"mapped",[100,382]],[[455,457],"mapped",[108,106]],[[458,460],"mapped",[110,106]],[[461,461],"mapped",[462]],[[462,462],"valid"],[[463,463],"mapped",[464]],[[464,464],"valid"],[[465,465],"mapped",[466]],[[466,466],"valid"],[[467,467],"mapped",[468]],[[468,468],"valid"],[[469,469],"mapped",[470]],[[470,470],"valid"],[[471,471],"mapped",[472]],[[472,472],"valid"],[[473,473],"mapped",[474]],[[474,474],"valid"],[[475,475],"mapped",[476]],[[476,477],"valid"],[[478,478],"mapped",[479]],[[479,479],"valid"],[[480,480],"mapped",[481]],[[481,481],"valid"],[[482,482],"mapped",[483]],[[483,483],"valid"],[[484,484],"mapped",[485]],[[485,485],"valid"],[[486,486],"mapped",[487]],[[487,487],"valid"],[[488,488],"mapped",[489]],[[489,489],"valid"],[[490,490],"mapped",[491]],[[491,491],"valid"],[[492,492],"mapped",[493]],[[493,493],"valid"],[[494,494],"mapped",[495]],[[495,496],"valid"],[[497,499],"mapped",[100,122]],[[500,500],"mapped",[501]],[[501,501],"valid"],[[502,502],"mapped",[405]],[[503,503],"mapped",[447]],[[504,504],"mapped",[505]],[[505,505],"valid"],[[506,506],"mapped",[507]],[[507,507],"valid"],[[508,508],"mapped",[509]],[[509,509],"valid"],[[510,510],"mapped",[511]],[[511,511],"valid"],[[512,512],"mapped",[513]],[[513,513],"valid"],[[514,514],"mapped",[515]],[[515,515],"valid"],[[516,516],"mapped",[517]],[[517,517],"valid"],[[518,518],"mapped",[519]],[[519,519],"valid"],[[520,520],"mapped",[521]],[[521,521],"valid"],[[522,522],"mapped",[523]],[[523,523],"valid"],[[524,524],"mapped",[525]],[[525,525],"valid"],[[526,526],"mapped",[527]],[[527,527],"valid"],[[528,528],"mapped",[529]],[[529,529],"valid"],[[530,530],"mapped",[531]],[[531,531],"valid"],[[532,532],"mapped",[533]],[[533,533],"valid"],[[534,534],"mapped",[535]],[[535,535],"valid"],[[536,536],"mapped",[537]],[[537,537],"valid"],[[538,538],"mapped",[539]],[[539,539],"valid"],[[540,540],"mapped",[541]],[[541,541],"valid"],[[542,542],"mapped",[543]],[[543,543],"valid"],[[544,544],"mapped",[414]],[[545,545],"valid"],[[546,546],"mapped",[547]],[[547,547],"valid"],[[548,548],"mapped",[549]],[[549,549],"valid"],[[550,550],"mapped",[551]],[[551,551],"valid"],[[552,552],"mapped",[553]],[[553,553],"valid"],[[554,554],"mapped",[555]],[[555,555],"valid"],[[556,556],"mapped",[557]],[[557,557],"valid"],[[558,558],"mapped",[559]],[[559,559],"valid"],[[560,560],"mapped",[561]],[[561,561],"valid"],[[562,562],"mapped",[563]],[[563,563],"valid"],[[564,566],"valid"],[[567,569],"valid"],[[570,570],"mapped",[11365]],[[571,571],"mapped",[572]],[[572,572],"valid"],[[573,573],"mapped",[410]],[[574,574],"mapped",[11366]],[[575,576],"valid"],[[577,577],"mapped",[578]],[[578,578],"valid"],[[579,579],"mapped",[384]],[[580,580],"mapped",[649]],[[581,581],"mapped",[652]],[[582,582],"mapped",[583]],[[583,583],"valid"],[[584,584],"mapped",[585]],[[585,585],"valid"],[[586,586],"mapped",[587]],[[587,587],"valid"],[[588,588],"mapped",[589]],[[589,589],"valid"],[[590,590],"mapped",[591]],[[591,591],"valid"],[[592,680],"valid"],[[681,685],"valid"],[[686,687],"valid"],[[688,688],"mapped",[104]],[[689,689],"mapped",[614]],[[690,690],"mapped",[106]],[[691,691],"mapped",[114]],[[692,692],"mapped",[633]],[[693,693],"mapped",[635]],[[694,694],"mapped",[641]],[[695,695],"mapped",[119]],[[696,696],"mapped",[121]],[[697,705],"valid"],[[706,709],"valid",[],"NV8"],[[710,721],"valid"],[[722,727],"valid",[],"NV8"],[[728,728],"disallowed_STD3_mapped",[32,774]],[[729,729],"disallowed_STD3_mapped",[32,775]],[[730,730],"disallowed_STD3_mapped",[32,778]],[[731,731],"disallowed_STD3_mapped",[32,808]],[[732,732],"disallowed_STD3_mapped",[32,771]],[[733,733],"disallowed_STD3_mapped",[32,779]],[[734,734],"valid",[],"NV8"],[[735,735],"valid",[],"NV8"],[[736,736],"mapped",[611]],[[737,737],"mapped",[108]],[[738,738],"mapped",[115]],[[739,739],"mapped",[120]],[[740,740],"mapped",[661]],[[741,745],"valid",[],"NV8"],[[746,747],"valid",[],"NV8"],[[748,748],"valid"],[[749,749],"valid",[],"NV8"],[[750,750],"valid"],[[751,767],"valid",[],"NV8"],[[768,831],"valid"],[[832,832],"mapped",[768]],[[833,833],"mapped",[769]],[[834,834],"valid"],[[835,835],"mapped",[787]],[[836,836],"mapped",[776,769]],[[837,837],"mapped",[953]],[[838,846],"valid"],[[847,847],"ignored"],[[848,855],"valid"],[[856,860],"valid"],[[861,863],"valid"],[[864,865],"valid"],[[866,866],"valid"],[[867,879],"valid"],[[880,880],"mapped",[881]],[[881,881],"valid"],[[882,882],"mapped",[883]],[[883,883],"valid"],[[884,884],"mapped",[697]],[[885,885],"valid"],[[886,886],"mapped",[887]],[[887,887],"valid"],[[888,889],"disallowed"],[[890,890],"disallowed_STD3_mapped",[32,953]],[[891,893],"valid"],[[894,894],"disallowed_STD3_mapped",[59]],[[895,895],"mapped",[1011]],[[896,899],"disallowed"],[[900,900],"disallowed_STD3_mapped",[32,769]],[[901,901],"disallowed_STD3_mapped",[32,776,769]],[[902,902],"mapped",[940]],[[903,903],"mapped",[183]],[[904,904],"mapped",[941]],[[905,905],"mapped",[942]],[[906,906],"mapped",[943]],[[907,907],"disallowed"],[[908,908],"mapped",[972]],[[909,909],"disallowed"],[[910,910],"mapped",[973]],[[911,911],"mapped",[974]],[[912,912],"valid"],[[913,913],"mapped",[945]],[[914,914],"mapped",[946]],[[915,915],"mapped",[947]],[[916,916],"mapped",[948]],[[917,917],"mapped",[949]],[[918,918],"mapped",[950]],[[919,919],"mapped",[951]],[[920,920],"mapped",[952]],[[921,921],"mapped",[953]],[[922,922],"mapped",[954]],[[923,923],"mapped",[955]],[[924,924],"mapped",[956]],[[925,925],"mapped",[957]],[[926,926],"mapped",[958]],[[927,927],"mapped",[959]],[[928,928],"mapped",[960]],[[929,929],"mapped",[961]],[[930,930],"disallowed"],[[931,931],"mapped",[963]],[[932,932],"mapped",[964]],[[933,933],"mapped",[965]],[[934,934],"mapped",[966]],[[935,935],"mapped",[967]],[[936,936],"mapped",[968]],[[937,937],"mapped",[969]],[[938,938],"mapped",[970]],[[939,939],"mapped",[971]],[[940,961],"valid"],[[962,962],"deviation",[963]],[[963,974],"valid"],[[975,975],"mapped",[983]],[[976,976],"mapped",[946]],[[977,977],"mapped",[952]],[[978,978],"mapped",[965]],[[979,979],"mapped",[973]],[[980,980],"mapped",[971]],[[981,981],"mapped",[966]],[[982,982],"mapped",[960]],[[983,983],"valid"],[[984,984],"mapped",[985]],[[985,985],"valid"],[[986,986],"mapped",[987]],[[987,987],"valid"],[[988,988],"mapped",[989]],[[989,989],"valid"],[[990,990],"mapped",[991]],[[991,991],"valid"],[[992,992],"mapped",[993]],[[993,993],"valid"],[[994,994],"mapped",[995]],[[995,995],"valid"],[[996,996],"mapped",[997]],[[997,997],"valid"],[[998,998],"mapped",[999]],[[999,999],"valid"],[[1000,1000],"mapped",[1001]],[[1001,1001],"valid"],[[1002,1002],"mapped",[1003]],[[1003,1003],"valid"],[[1004,1004],"mapped",[1005]],[[1005,1005],"valid"],[[1006,1006],"mapped",[1007]],[[1007,1007],"valid"],[[1008,1008],"mapped",[954]],[[1009,1009],"mapped",[961]],[[1010,1010],"mapped",[963]],[[1011,1011],"valid"],[[1012,1012],"mapped",[952]],[[1013,1013],"mapped",[949]],[[1014,1014],"valid",[],"NV8"],[[1015,1015],"mapped",[1016]],[[1016,1016],"valid"],[[1017,1017],"mapped",[963]],[[1018,1018],"mapped",[1019]],[[1019,1019],"valid"],[[1020,1020],"valid"],[[1021,1021],"mapped",[891]],[[1022,1022],"mapped",[892]],[[1023,1023],"mapped",[893]],[[1024,1024],"mapped",[1104]],[[1025,1025],"mapped",[1105]],[[1026,1026],"mapped",[1106]],[[1027,1027],"mapped",[1107]],[[1028,1028],"mapped",[1108]],[[1029,1029],"mapped",[1109]],[[1030,1030],"mapped",[1110]],[[1031,1031],"mapped",[1111]],[[1032,1032],"mapped",[1112]],[[1033,1033],"mapped",[1113]],[[1034,1034],"mapped",[1114]],[[1035,1035],"mapped",[1115]],[[1036,1036],"mapped",[1116]],[[1037,1037],"mapped",[1117]],[[1038,1038],"mapped",[1118]],[[1039,1039],"mapped",[1119]],[[1040,1040],"mapped",[1072]],[[1041,1041],"mapped",[1073]],[[1042,1042],"mapped",[1074]],[[1043,1043],"mapped",[1075]],[[1044,1044],"mapped",[1076]],[[1045,1045],"mapped",[1077]],[[1046,1046],"mapped",[1078]],[[1047,1047],"mapped",[1079]],[[1048,1048],"mapped",[1080]],[[1049,1049],"mapped",[1081]],[[1050,1050],"mapped",[1082]],[[1051,1051],"mapped",[1083]],[[1052,1052],"mapped",[1084]],[[1053,1053],"mapped",[1085]],[[1054,1054],"mapped",[1086]],[[1055,1055],"mapped",[1087]],[[1056,1056],"mapped",[1088]],[[1057,1057],"mapped",[1089]],[[1058,1058],"mapped",[1090]],[[1059,1059],"mapped",[1091]],[[1060,1060],"mapped",[1092]],[[1061,1061],"mapped",[1093]],[[1062,1062],"mapped",[1094]],[[1063,1063],"mapped",[1095]],[[1064,1064],"mapped",[1096]],[[1065,1065],"mapped",[1097]],[[1066,1066],"mapped",[1098]],[[1067,1067],"mapped",[1099]],[[1068,1068],"mapped",[1100]],[[1069,1069],"mapped",[1101]],[[1070,1070],"mapped",[1102]],[[1071,1071],"mapped",[1103]],[[1072,1103],"valid"],[[1104,1104],"valid"],[[1105,1116],"valid"],[[1117,1117],"valid"],[[1118,1119],"valid"],[[1120,1120],"mapped",[1121]],[[1121,1121],"valid"],[[1122,1122],"mapped",[1123]],[[1123,1123],"valid"],[[1124,1124],"mapped",[1125]],[[1125,1125],"valid"],[[1126,1126],"mapped",[1127]],[[1127,1127],"valid"],[[1128,1128],"mapped",[1129]],[[1129,1129],"valid"],[[1130,1130],"mapped",[1131]],[[1131,1131],"valid"],[[1132,1132],"mapped",[1133]],[[1133,1133],"valid"],[[1134,1134],"mapped",[1135]],[[1135,1135],"valid"],[[1136,1136],"mapped",[1137]],[[1137,1137],"valid"],[[1138,1138],"mapped",[1139]],[[1139,1139],"valid"],[[1140,1140],"mapped",[1141]],[[1141,1141],"valid"],[[1142,1142],"mapped",[1143]],[[1143,1143],"valid"],[[1144,1144],"mapped",[1145]],[[1145,1145],"valid"],[[1146,1146],"mapped",[1147]],[[1147,1147],"valid"],[[1148,1148],"mapped",[1149]],[[1149,1149],"valid"],[[1150,1150],"mapped",[1151]],[[1151,1151],"valid"],[[1152,1152],"mapped",[1153]],[[1153,1153],"valid"],[[1154,1154],"valid",[],"NV8"],[[1155,1158],"valid"],[[1159,1159],"valid"],[[1160,1161],"valid",[],"NV8"],[[1162,1162],"mapped",[1163]],[[1163,1163],"valid"],[[1164,1164],"mapped",[1165]],[[1165,1165],"valid"],[[1166,1166],"mapped",[1167]],[[1167,1167],"valid"],[[1168,1168],"mapped",[1169]],[[1169,1169],"valid"],[[1170,1170],"mapped",[1171]],[[1171,1171],"valid"],[[1172,1172],"mapped",[1173]],[[1173,1173],"valid"],[[1174,1174],"mapped",[1175]],[[1175,1175],"valid"],[[1176,1176],"mapped",[1177]],[[1177,1177],"valid"],[[1178,1178],"mapped",[1179]],[[1179,1179],"valid"],[[1180,1180],"mapped",[1181]],[[1181,1181],"valid"],[[1182,1182],"mapped",[1183]],[[1183,1183],"valid"],[[1184,1184],"mapped",[1185]],[[1185,1185],"valid"],[[1186,1186],"mapped",[1187]],[[1187,1187],"valid"],[[1188,1188],"mapped",[1189]],[[1189,1189],"valid"],[[1190,1190],"mapped",[1191]],[[1191,1191],"valid"],[[1192,1192],"mapped",[1193]],[[1193,1193],"valid"],[[1194,1194],"mapped",[1195]],[[1195,1195],"valid"],[[1196,1196],"mapped",[1197]],[[1197,1197],"valid"],[[1198,1198],"mapped",[1199]],[[1199,1199],"valid"],[[1200,1200],"mapped",[1201]],[[1201,1201],"valid"],[[1202,1202],"mapped",[1203]],[[1203,1203],"valid"],[[1204,1204],"mapped",[1205]],[[1205,1205],"valid"],[[1206,1206],"mapped",[1207]],[[1207,1207],"valid"],[[1208,1208],"mapped",[1209]],[[1209,1209],"valid"],[[1210,1210],"mapped",[1211]],[[1211,1211],"valid"],[[1212,1212],"mapped",[1213]],[[1213,1213],"valid"],[[1214,1214],"mapped",[1215]],[[1215,1215],"valid"],[[1216,1216],"disallowed"],[[1217,1217],"mapped",[1218]],[[1218,1218],"valid"],[[1219,1219],"mapped",[1220]],[[1220,1220],"valid"],[[1221,1221],"mapped",[1222]],[[1222,1222],"valid"],[[1223,1223],"mapped",[1224]],[[1224,1224],"valid"],[[1225,1225],"mapped",[1226]],[[1226,1226],"valid"],[[1227,1227],"mapped",[1228]],[[1228,1228],"valid"],[[1229,1229],"mapped",[1230]],[[1230,1230],"valid"],[[1231,1231],"valid"],[[1232,1232],"mapped",[1233]],[[1233,1233],"valid"],[[1234,1234],"mapped",[1235]],[[1235,1235],"valid"],[[1236,1236],"mapped",[1237]],[[1237,1237],"valid"],[[1238,1238],"mapped",[1239]],[[1239,1239],"valid"],[[1240,1240],"mapped",[1241]],[[1241,1241],"valid"],[[1242,1242],"mapped",[1243]],[[1243,1243],"valid"],[[1244,1244],"mapped",[1245]],[[1245,1245],"valid"],[[1246,1246],"mapped",[1247]],[[1247,1247],"valid"],[[1248,1248],"mapped",[1249]],[[1249,1249],"valid"],[[1250,1250],"mapped",[1251]],[[1251,1251],"valid"],[[1252,1252],"mapped",[1253]],[[1253,1253],"valid"],[[1254,1254],"mapped",[1255]],[[1255,1255],"valid"],[[1256,1256],"mapped",[1257]],[[1257,1257],"valid"],[[1258,1258],"mapped",[1259]],[[1259,1259],"valid"],[[1260,1260],"mapped",[1261]],[[1261,1261],"valid"],[[1262,1262],"mapped",[1263]],[[1263,1263],"valid"],[[1264,1264],"mapped",[1265]],[[1265,1265],"valid"],[[1266,1266],"mapped",[1267]],[[1267,1267],"valid"],[[1268,1268],"mapped",[1269]],[[1269,1269],"valid"],[[1270,1270],"mapped",[1271]],[[1271,1271],"valid"],[[1272,1272],"mapped",[1273]],[[1273,1273],"valid"],[[1274,1274],"mapped",[1275]],[[1275,1275],"valid"],[[1276,1276],"mapped",[1277]],[[1277,1277],"valid"],[[1278,1278],"mapped",[1279]],[[1279,1279],"valid"],[[1280,1280],"mapped",[1281]],[[1281,1281],"valid"],[[1282,1282],"mapped",[1283]],[[1283,1283],"valid"],[[1284,1284],"mapped",[1285]],[[1285,1285],"valid"],[[1286,1286],"mapped",[1287]],[[1287,1287],"valid"],[[1288,1288],"mapped",[1289]],[[1289,1289],"valid"],[[1290,1290],"mapped",[1291]],[[1291,1291],"valid"],[[1292,1292],"mapped",[1293]],[[1293,1293],"valid"],[[1294,1294],"mapped",[1295]],[[1295,1295],"valid"],[[1296,1296],"mapped",[1297]],[[1297,1297],"valid"],[[1298,1298],"mapped",[1299]],[[1299,1299],"valid"],[[1300,1300],"mapped",[1301]],[[1301,1301],"valid"],[[1302,1302],"mapped",[1303]],[[1303,1303],"valid"],[[1304,1304],"mapped",[1305]],[[1305,1305],"valid"],[[1306,1306],"mapped",[1307]],[[1307,1307],"valid"],[[1308,1308],"mapped",[1309]],[[1309,1309],"valid"],[[1310,1310],"mapped",[1311]],[[1311,1311],"valid"],[[1312,1312],"mapped",[1313]],[[1313,1313],"valid"],[[1314,1314],"mapped",[1315]],[[1315,1315],"valid"],[[1316,1316],"mapped",[1317]],[[1317,1317],"valid"],[[1318,1318],"mapped",[1319]],[[1319,1319],"valid"],[[1320,1320],"mapped",[1321]],[[1321,1321],"valid"],[[1322,1322],"mapped",[1323]],[[1323,1323],"valid"],[[1324,1324],"mapped",[1325]],[[1325,1325],"valid"],[[1326,1326],"mapped",[1327]],[[1327,1327],"valid"],[[1328,1328],"disallowed"],[[1329,1329],"mapped",[1377]],[[1330,1330],"mapped",[1378]],[[1331,1331],"mapped",[1379]],[[1332,1332],"mapped",[1380]],[[1333,1333],"mapped",[1381]],[[1334,1334],"mapped",[1382]],[[1335,1335],"mapped",[1383]],[[1336,1336],"mapped",[1384]],[[1337,1337],"mapped",[1385]],[[1338,1338],"mapped",[1386]],[[1339,1339],"mapped",[1387]],[[1340,1340],"mapped",[1388]],[[1341,1341],"mapped",[1389]],[[1342,1342],"mapped",[1390]],[[1343,1343],"mapped",[1391]],[[1344,1344],"mapped",[1392]],[[1345,1345],"mapped",[1393]],[[1346,1346],"mapped",[1394]],[[1347,1347],"mapped",[1395]],[[1348,1348],"mapped",[1396]],[[1349,1349],"mapped",[1397]],[[1350,1350],"mapped",[1398]],[[1351,1351],"mapped",[1399]],[[1352,1352],"mapped",[1400]],[[1353,1353],"mapped",[1401]],[[1354,1354],"mapped",[1402]],[[1355,1355],"mapped",[1403]],[[1356,1356],"mapped",[1404]],[[1357,1357],"mapped",[1405]],[[1358,1358],"mapped",[1406]],[[1359,1359],"mapped",[1407]],[[1360,1360],"mapped",[1408]],[[1361,1361],"mapped",[1409]],[[1362,1362],"mapped",[1410]],[[1363,1363],"mapped",[1411]],[[1364,1364],"mapped",[1412]],[[1365,1365],"mapped",[1413]],[[1366,1366],"mapped",[1414]],[[1367,1368],"disallowed"],[[1369,1369],"valid"],[[1370,1375],"valid",[],"NV8"],[[1376,1376],"disallowed"],[[1377,1414],"valid"],[[1415,1415],"mapped",[1381,1410]],[[1416,1416],"disallowed"],[[1417,1417],"valid",[],"NV8"],[[1418,1418],"valid",[],"NV8"],[[1419,1420],"disallowed"],[[1421,1422],"valid",[],"NV8"],[[1423,1423],"valid",[],"NV8"],[[1424,1424],"disallowed"],[[1425,1441],"valid"],[[1442,1442],"valid"],[[1443,1455],"valid"],[[1456,1465],"valid"],[[1466,1466],"valid"],[[1467,1469],"valid"],[[1470,1470],"valid",[],"NV8"],[[1471,1471],"valid"],[[1472,1472],"valid",[],"NV8"],[[1473,1474],"valid"],[[1475,1475],"valid",[],"NV8"],[[1476,1476],"valid"],[[1477,1477],"valid"],[[1478,1478],"valid",[],"NV8"],[[1479,1479],"valid"],[[1480,1487],"disallowed"],[[1488,1514],"valid"],[[1515,1519],"disallowed"],[[1520,1524],"valid"],[[1525,1535],"disallowed"],[[1536,1539],"disallowed"],[[1540,1540],"disallowed"],[[1541,1541],"disallowed"],[[1542,1546],"valid",[],"NV8"],[[1547,1547],"valid",[],"NV8"],[[1548,1548],"valid",[],"NV8"],[[1549,1551],"valid",[],"NV8"],[[1552,1557],"valid"],[[1558,1562],"valid"],[[1563,1563],"valid",[],"NV8"],[[1564,1564],"disallowed"],[[1565,1565],"disallowed"],[[1566,1566],"valid",[],"NV8"],[[1567,1567],"valid",[],"NV8"],[[1568,1568],"valid"],[[1569,1594],"valid"],[[1595,1599],"valid"],[[1600,1600],"valid",[],"NV8"],[[1601,1618],"valid"],[[1619,1621],"valid"],[[1622,1624],"valid"],[[1625,1630],"valid"],[[1631,1631],"valid"],[[1632,1641],"valid"],[[1642,1645],"valid",[],"NV8"],[[1646,1647],"valid"],[[1648,1652],"valid"],[[1653,1653],"mapped",[1575,1652]],[[1654,1654],"mapped",[1608,1652]],[[1655,1655],"mapped",[1735,1652]],[[1656,1656],"mapped",[1610,1652]],[[1657,1719],"valid"],[[1720,1721],"valid"],[[1722,1726],"valid"],[[1727,1727],"valid"],[[1728,1742],"valid"],[[1743,1743],"valid"],[[1744,1747],"valid"],[[1748,1748],"valid",[],"NV8"],[[1749,1756],"valid"],[[1757,1757],"disallowed"],[[1758,1758],"valid",[],"NV8"],[[1759,1768],"valid"],[[1769,1769],"valid",[],"NV8"],[[1770,1773],"valid"],[[1774,1775],"valid"],[[1776,1785],"valid"],[[1786,1790],"valid"],[[1791,1791],"valid"],[[1792,1805],"valid",[],"NV8"],[[1806,1806],"disallowed"],[[1807,1807],"disallowed"],[[1808,1836],"valid"],[[1837,1839],"valid"],[[1840,1866],"valid"],[[1867,1868],"disallowed"],[[1869,1871],"valid"],[[1872,1901],"valid"],[[1902,1919],"valid"],[[1920,1968],"valid"],[[1969,1969],"valid"],[[1970,1983],"disallowed"],[[1984,2037],"valid"],[[2038,2042],"valid",[],"NV8"],[[2043,2047],"disallowed"],[[2048,2093],"valid"],[[2094,2095],"disallowed"],[[2096,2110],"valid",[],"NV8"],[[2111,2111],"disallowed"],[[2112,2139],"valid"],[[2140,2141],"disallowed"],[[2142,2142],"valid",[],"NV8"],[[2143,2207],"disallowed"],[[2208,2208],"valid"],[[2209,2209],"valid"],[[2210,2220],"valid"],[[2221,2226],"valid"],[[2227,2228],"valid"],[[2229,2274],"disallowed"],[[2275,2275],"valid"],[[2276,2302],"valid"],[[2303,2303],"valid"],[[2304,2304],"valid"],[[2305,2307],"valid"],[[2308,2308],"valid"],[[2309,2361],"valid"],[[2362,2363],"valid"],[[2364,2381],"valid"],[[2382,2382],"valid"],[[2383,2383],"valid"],[[2384,2388],"valid"],[[2389,2389],"valid"],[[2390,2391],"valid"],[[2392,2392],"mapped",[2325,2364]],[[2393,2393],"mapped",[2326,2364]],[[2394,2394],"mapped",[2327,2364]],[[2395,2395],"mapped",[2332,2364]],[[2396,2396],"mapped",[2337,2364]],[[2397,2397],"mapped",[2338,2364]],[[2398,2398],"mapped",[2347,2364]],[[2399,2399],"mapped",[2351,2364]],[[2400,2403],"valid"],[[2404,2405],"valid",[],"NV8"],[[2406,2415],"valid"],[[2416,2416],"valid",[],"NV8"],[[2417,2418],"valid"],[[2419,2423],"valid"],[[2424,2424],"valid"],[[2425,2426],"valid"],[[2427,2428],"valid"],[[2429,2429],"valid"],[[2430,2431],"valid"],[[2432,2432],"valid"],[[2433,2435],"valid"],[[2436,2436],"disallowed"],[[2437,2444],"valid"],[[2445,2446],"disallowed"],[[2447,2448],"valid"],[[2449,2450],"disallowed"],[[2451,2472],"valid"],[[2473,2473],"disallowed"],[[2474,2480],"valid"],[[2481,2481],"disallowed"],[[2482,2482],"valid"],[[2483,2485],"disallowed"],[[2486,2489],"valid"],[[2490,2491],"disallowed"],[[2492,2492],"valid"],[[2493,2493],"valid"],[[2494,2500],"valid"],[[2501,2502],"disallowed"],[[2503,2504],"valid"],[[2505,2506],"disallowed"],[[2507,2509],"valid"],[[2510,2510],"valid"],[[2511,2518],"disallowed"],[[2519,2519],"valid"],[[2520,2523],"disallowed"],[[2524,2524],"mapped",[2465,2492]],[[2525,2525],"mapped",[2466,2492]],[[2526,2526],"disallowed"],[[2527,2527],"mapped",[2479,2492]],[[2528,2531],"valid"],[[2532,2533],"disallowed"],[[2534,2545],"valid"],[[2546,2554],"valid",[],"NV8"],[[2555,2555],"valid",[],"NV8"],[[2556,2560],"disallowed"],[[2561,2561],"valid"],[[2562,2562],"valid"],[[2563,2563],"valid"],[[2564,2564],"disallowed"],[[2565,2570],"valid"],[[2571,2574],"disallowed"],[[2575,2576],"valid"],[[2577,2578],"disallowed"],[[2579,2600],"valid"],[[2601,2601],"disallowed"],[[2602,2608],"valid"],[[2609,2609],"disallowed"],[[2610,2610],"valid"],[[2611,2611],"mapped",[2610,2620]],[[2612,2612],"disallowed"],[[2613,2613],"valid"],[[2614,2614],"mapped",[2616,2620]],[[2615,2615],"disallowed"],[[2616,2617],"valid"],[[2618,2619],"disallowed"],[[2620,2620],"valid"],[[2621,2621],"disallowed"],[[2622,2626],"valid"],[[2627,2630],"disallowed"],[[2631,2632],"valid"],[[2633,2634],"disallowed"],[[2635,2637],"valid"],[[2638,2640],"disallowed"],[[2641,2641],"valid"],[[2642,2648],"disallowed"],[[2649,2649],"mapped",[2582,2620]],[[2650,2650],"mapped",[2583,2620]],[[2651,2651],"mapped",[2588,2620]],[[2652,2652],"valid"],[[2653,2653],"disallowed"],[[2654,2654],"mapped",[2603,2620]],[[2655,2661],"disallowed"],[[2662,2676],"valid"],[[2677,2677],"valid"],[[2678,2688],"disallowed"],[[2689,2691],"valid"],[[2692,2692],"disallowed"],[[2693,2699],"valid"],[[2700,2700],"valid"],[[2701,2701],"valid"],[[2702,2702],"disallowed"],[[2703,2705],"valid"],[[2706,2706],"disallowed"],[[2707,2728],"valid"],[[2729,2729],"disallowed"],[[2730,2736],"valid"],[[2737,2737],"disallowed"],[[2738,2739],"valid"],[[2740,2740],"disallowed"],[[2741,2745],"valid"],[[2746,2747],"disallowed"],[[2748,2757],"valid"],[[2758,2758],"disallowed"],[[2759,2761],"valid"],[[2762,2762],"disallowed"],[[2763,2765],"valid"],[[2766,2767],"disallowed"],[[2768,2768],"valid"],[[2769,2783],"disallowed"],[[2784,2784],"valid"],[[2785,2787],"valid"],[[2788,2789],"disallowed"],[[2790,2799],"valid"],[[2800,2800],"valid",[],"NV8"],[[2801,2801],"valid",[],"NV8"],[[2802,2808],"disallowed"],[[2809,2809],"valid"],[[2810,2816],"disallowed"],[[2817,2819],"valid"],[[2820,2820],"disallowed"],[[2821,2828],"valid"],[[2829,2830],"disallowed"],[[2831,2832],"valid"],[[2833,2834],"disallowed"],[[2835,2856],"valid"],[[2857,2857],"disallowed"],[[2858,2864],"valid"],[[2865,2865],"disallowed"],[[2866,2867],"valid"],[[2868,2868],"disallowed"],[[2869,2869],"valid"],[[2870,2873],"valid"],[[2874,2875],"disallowed"],[[2876,2883],"valid"],[[2884,2884],"valid"],[[2885,2886],"disallowed"],[[2887,2888],"valid"],[[2889,2890],"disallowed"],[[2891,2893],"valid"],[[2894,2901],"disallowed"],[[2902,2903],"valid"],[[2904,2907],"disallowed"],[[2908,2908],"mapped",[2849,2876]],[[2909,2909],"mapped",[2850,2876]],[[2910,2910],"disallowed"],[[2911,2913],"valid"],[[2914,2915],"valid"],[[2916,2917],"disallowed"],[[2918,2927],"valid"],[[2928,2928],"valid",[],"NV8"],[[2929,2929],"valid"],[[2930,2935],"valid",[],"NV8"],[[2936,2945],"disallowed"],[[2946,2947],"valid"],[[2948,2948],"disallowed"],[[2949,2954],"valid"],[[2955,2957],"disallowed"],[[2958,2960],"valid"],[[2961,2961],"disallowed"],[[2962,2965],"valid"],[[2966,2968],"disallowed"],[[2969,2970],"valid"],[[2971,2971],"disallowed"],[[2972,2972],"valid"],[[2973,2973],"disallowed"],[[2974,2975],"valid"],[[2976,2978],"disallowed"],[[2979,2980],"valid"],[[2981,2983],"disallowed"],[[2984,2986],"valid"],[[2987,2989],"disallowed"],[[2990,2997],"valid"],[[2998,2998],"valid"],[[2999,3001],"valid"],[[3002,3005],"disallowed"],[[3006,3010],"valid"],[[3011,3013],"disallowed"],[[3014,3016],"valid"],[[3017,3017],"disallowed"],[[3018,3021],"valid"],[[3022,3023],"disallowed"],[[3024,3024],"valid"],[[3025,3030],"disallowed"],[[3031,3031],"valid"],[[3032,3045],"disallowed"],[[3046,3046],"valid"],[[3047,3055],"valid"],[[3056,3058],"valid",[],"NV8"],[[3059,3066],"valid",[],"NV8"],[[3067,3071],"disallowed"],[[3072,3072],"valid"],[[3073,3075],"valid"],[[3076,3076],"disallowed"],[[3077,3084],"valid"],[[3085,3085],"disallowed"],[[3086,3088],"valid"],[[3089,3089],"disallowed"],[[3090,3112],"valid"],[[3113,3113],"disallowed"],[[3114,3123],"valid"],[[3124,3124],"valid"],[[3125,3129],"valid"],[[3130,3132],"disallowed"],[[3133,3133],"valid"],[[3134,3140],"valid"],[[3141,3141],"disallowed"],[[3142,3144],"valid"],[[3145,3145],"disallowed"],[[3146,3149],"valid"],[[3150,3156],"disallowed"],[[3157,3158],"valid"],[[3159,3159],"disallowed"],[[3160,3161],"valid"],[[3162,3162],"valid"],[[3163,3167],"disallowed"],[[3168,3169],"valid"],[[3170,3171],"valid"],[[3172,3173],"disallowed"],[[3174,3183],"valid"],[[3184,3191],"disallowed"],[[3192,3199],"valid",[],"NV8"],[[3200,3200],"disallowed"],[[3201,3201],"valid"],[[3202,3203],"valid"],[[3204,3204],"disallowed"],[[3205,3212],"valid"],[[3213,3213],"disallowed"],[[3214,3216],"valid"],[[3217,3217],"disallowed"],[[3218,3240],"valid"],[[3241,3241],"disallowed"],[[3242,3251],"valid"],[[3252,3252],"disallowed"],[[3253,3257],"valid"],[[3258,3259],"disallowed"],[[3260,3261],"valid"],[[3262,3268],"valid"],[[3269,3269],"disallowed"],[[3270,3272],"valid"],[[3273,3273],"disallowed"],[[3274,3277],"valid"],[[3278,3284],"disallowed"],[[3285,3286],"valid"],[[3287,3293],"disallowed"],[[3294,3294],"valid"],[[3295,3295],"disallowed"],[[3296,3297],"valid"],[[3298,3299],"valid"],[[3300,3301],"disallowed"],[[3302,3311],"valid"],[[3312,3312],"disallowed"],[[3313,3314],"valid"],[[3315,3328],"disallowed"],[[3329,3329],"valid"],[[3330,3331],"valid"],[[3332,3332],"disallowed"],[[3333,3340],"valid"],[[3341,3341],"disallowed"],[[3342,3344],"valid"],[[3345,3345],"disallowed"],[[3346,3368],"valid"],[[3369,3369],"valid"],[[3370,3385],"valid"],[[3386,3386],"valid"],[[3387,3388],"disallowed"],[[3389,3389],"valid"],[[3390,3395],"valid"],[[3396,3396],"valid"],[[3397,3397],"disallowed"],[[3398,3400],"valid"],[[3401,3401],"disallowed"],[[3402,3405],"valid"],[[3406,3406],"valid"],[[3407,3414],"disallowed"],[[3415,3415],"valid"],[[3416,3422],"disallowed"],[[3423,3423],"valid"],[[3424,3425],"valid"],[[3426,3427],"valid"],[[3428,3429],"disallowed"],[[3430,3439],"valid"],[[3440,3445],"valid",[],"NV8"],[[3446,3448],"disallowed"],[[3449,3449],"valid",[],"NV8"],[[3450,3455],"valid"],[[3456,3457],"disallowed"],[[3458,3459],"valid"],[[3460,3460],"disallowed"],[[3461,3478],"valid"],[[3479,3481],"disallowed"],[[3482,3505],"valid"],[[3506,3506],"disallowed"],[[3507,3515],"valid"],[[3516,3516],"disallowed"],[[3517,3517],"valid"],[[3518,3519],"disallowed"],[[3520,3526],"valid"],[[3527,3529],"disallowed"],[[3530,3530],"valid"],[[3531,3534],"disallowed"],[[3535,3540],"valid"],[[3541,3541],"disallowed"],[[3542,3542],"valid"],[[3543,3543],"disallowed"],[[3544,3551],"valid"],[[3552,3557],"disallowed"],[[3558,3567],"valid"],[[3568,3569],"disallowed"],[[3570,3571],"valid"],[[3572,3572],"valid",[],"NV8"],[[3573,3584],"disallowed"],[[3585,3634],"valid"],[[3635,3635],"mapped",[3661,3634]],[[3636,3642],"valid"],[[3643,3646],"disallowed"],[[3647,3647],"valid",[],"NV8"],[[3648,3662],"valid"],[[3663,3663],"valid",[],"NV8"],[[3664,3673],"valid"],[[3674,3675],"valid",[],"NV8"],[[3676,3712],"disallowed"],[[3713,3714],"valid"],[[3715,3715],"disallowed"],[[3716,3716],"valid"],[[3717,3718],"disallowed"],[[3719,3720],"valid"],[[3721,3721],"disallowed"],[[3722,3722],"valid"],[[3723,3724],"disallowed"],[[3725,3725],"valid"],[[3726,3731],"disallowed"],[[3732,3735],"valid"],[[3736,3736],"disallowed"],[[3737,3743],"valid"],[[3744,3744],"disallowed"],[[3745,3747],"valid"],[[3748,3748],"disallowed"],[[3749,3749],"valid"],[[3750,3750],"disallowed"],[[3751,3751],"valid"],[[3752,3753],"disallowed"],[[3754,3755],"valid"],[[3756,3756],"disallowed"],[[3757,3762],"valid"],[[3763,3763],"mapped",[3789,3762]],[[3764,3769],"valid"],[[3770,3770],"disallowed"],[[3771,3773],"valid"],[[3774,3775],"disallowed"],[[3776,3780],"valid"],[[3781,3781],"disallowed"],[[3782,3782],"valid"],[[3783,3783],"disallowed"],[[3784,3789],"valid"],[[3790,3791],"disallowed"],[[3792,3801],"valid"],[[3802,3803],"disallowed"],[[3804,3804],"mapped",[3755,3737]],[[3805,3805],"mapped",[3755,3745]],[[3806,3807],"valid"],[[3808,3839],"disallowed"],[[3840,3840],"valid"],[[3841,3850],"valid",[],"NV8"],[[3851,3851],"valid"],[[3852,3852],"mapped",[3851]],[[3853,3863],"valid",[],"NV8"],[[3864,3865],"valid"],[[3866,3871],"valid",[],"NV8"],[[3872,3881],"valid"],[[3882,3892],"valid",[],"NV8"],[[3893,3893],"valid"],[[3894,3894],"valid",[],"NV8"],[[3895,3895],"valid"],[[3896,3896],"valid",[],"NV8"],[[3897,3897],"valid"],[[3898,3901],"valid",[],"NV8"],[[3902,3906],"valid"],[[3907,3907],"mapped",[3906,4023]],[[3908,3911],"valid"],[[3912,3912],"disallowed"],[[3913,3916],"valid"],[[3917,3917],"mapped",[3916,4023]],[[3918,3921],"valid"],[[3922,3922],"mapped",[3921,4023]],[[3923,3926],"valid"],[[3927,3927],"mapped",[3926,4023]],[[3928,3931],"valid"],[[3932,3932],"mapped",[3931,4023]],[[3933,3944],"valid"],[[3945,3945],"mapped",[3904,4021]],[[3946,3946],"valid"],[[3947,3948],"valid"],[[3949,3952],"disallowed"],[[3953,3954],"valid"],[[3955,3955],"mapped",[3953,3954]],[[3956,3956],"valid"],[[3957,3957],"mapped",[3953,3956]],[[3958,3958],"mapped",[4018,3968]],[[3959,3959],"mapped",[4018,3953,3968]],[[3960,3960],"mapped",[4019,3968]],[[3961,3961],"mapped",[4019,3953,3968]],[[3962,3968],"valid"],[[3969,3969],"mapped",[3953,3968]],[[3970,3972],"valid"],[[3973,3973],"valid",[],"NV8"],[[3974,3979],"valid"],[[3980,3983],"valid"],[[3984,3986],"valid"],[[3987,3987],"mapped",[3986,4023]],[[3988,3989],"valid"],[[3990,3990],"valid"],[[3991,3991],"valid"],[[3992,3992],"disallowed"],[[3993,3996],"valid"],[[3997,3997],"mapped",[3996,4023]],[[3998,4001],"valid"],[[4002,4002],"mapped",[4001,4023]],[[4003,4006],"valid"],[[4007,4007],"mapped",[4006,4023]],[[4008,4011],"valid"],[[4012,4012],"mapped",[4011,4023]],[[4013,4013],"valid"],[[4014,4016],"valid"],[[4017,4023],"valid"],[[4024,4024],"valid"],[[4025,4025],"mapped",[3984,4021]],[[4026,4028],"valid"],[[4029,4029],"disallowed"],[[4030,4037],"valid",[],"NV8"],[[4038,4038],"valid"],[[4039,4044],"valid",[],"NV8"],[[4045,4045],"disallowed"],[[4046,4046],"valid",[],"NV8"],[[4047,4047],"valid",[],"NV8"],[[4048,4049],"valid",[],"NV8"],[[4050,4052],"valid",[],"NV8"],[[4053,4056],"valid",[],"NV8"],[[4057,4058],"valid",[],"NV8"],[[4059,4095],"disallowed"],[[4096,4129],"valid"],[[4130,4130],"valid"],[[4131,4135],"valid"],[[4136,4136],"valid"],[[4137,4138],"valid"],[[4139,4139],"valid"],[[4140,4146],"valid"],[[4147,4149],"valid"],[[4150,4153],"valid"],[[4154,4159],"valid"],[[4160,4169],"valid"],[[4170,4175],"valid",[],"NV8"],[[4176,4185],"valid"],[[4186,4249],"valid"],[[4250,4253],"valid"],[[4254,4255],"valid",[],"NV8"],[[4256,4293],"disallowed"],[[4294,4294],"disallowed"],[[4295,4295],"mapped",[11559]],[[4296,4300],"disallowed"],[[4301,4301],"mapped",[11565]],[[4302,4303],"disallowed"],[[4304,4342],"valid"],[[4343,4344],"valid"],[[4345,4346],"valid"],[[4347,4347],"valid",[],"NV8"],[[4348,4348],"mapped",[4316]],[[4349,4351],"valid"],[[4352,4441],"valid",[],"NV8"],[[4442,4446],"valid",[],"NV8"],[[4447,4448],"disallowed"],[[4449,4514],"valid",[],"NV8"],[[4515,4519],"valid",[],"NV8"],[[4520,4601],"valid",[],"NV8"],[[4602,4607],"valid",[],"NV8"],[[4608,4614],"valid"],[[4615,4615],"valid"],[[4616,4678],"valid"],[[4679,4679],"valid"],[[4680,4680],"valid"],[[4681,4681],"disallowed"],[[4682,4685],"valid"],[[4686,4687],"disallowed"],[[4688,4694],"valid"],[[4695,4695],"disallowed"],[[4696,4696],"valid"],[[4697,4697],"disallowed"],[[4698,4701],"valid"],[[4702,4703],"disallowed"],[[4704,4742],"valid"],[[4743,4743],"valid"],[[4744,4744],"valid"],[[4745,4745],"disallowed"],[[4746,4749],"valid"],[[4750,4751],"disallowed"],[[4752,4782],"valid"],[[4783,4783],"valid"],[[4784,4784],"valid"],[[4785,4785],"disallowed"],[[4786,4789],"valid"],[[4790,4791],"disallowed"],[[4792,4798],"valid"],[[4799,4799],"disallowed"],[[4800,4800],"valid"],[[4801,4801],"disallowed"],[[4802,4805],"valid"],[[4806,4807],"disallowed"],[[4808,4814],"valid"],[[4815,4815],"valid"],[[4816,4822],"valid"],[[4823,4823],"disallowed"],[[4824,4846],"valid"],[[4847,4847],"valid"],[[4848,4878],"valid"],[[4879,4879],"valid"],[[4880,4880],"valid"],[[4881,4881],"disallowed"],[[4882,4885],"valid"],[[4886,4887],"disallowed"],[[4888,4894],"valid"],[[4895,4895],"valid"],[[4896,4934],"valid"],[[4935,4935],"valid"],[[4936,4954],"valid"],[[4955,4956],"disallowed"],[[4957,4958],"valid"],[[4959,4959],"valid"],[[4960,4960],"valid",[],"NV8"],[[4961,4988],"valid",[],"NV8"],[[4989,4991],"disallowed"],[[4992,5007],"valid"],[[5008,5017],"valid",[],"NV8"],[[5018,5023],"disallowed"],[[5024,5108],"valid"],[[5109,5109],"valid"],[[5110,5111],"disallowed"],[[5112,5112],"mapped",[5104]],[[5113,5113],"mapped",[5105]],[[5114,5114],"mapped",[5106]],[[5115,5115],"mapped",[5107]],[[5116,5116],"mapped",[5108]],[[5117,5117],"mapped",[5109]],[[5118,5119],"disallowed"],[[5120,5120],"valid",[],"NV8"],[[5121,5740],"valid"],[[5741,5742],"valid",[],"NV8"],[[5743,5750],"valid"],[[5751,5759],"valid"],[[5760,5760],"disallowed"],[[5761,5786],"valid"],[[5787,5788],"valid",[],"NV8"],[[5789,5791],"disallowed"],[[5792,5866],"valid"],[[5867,5872],"valid",[],"NV8"],[[5873,5880],"valid"],[[5881,5887],"disallowed"],[[5888,5900],"valid"],[[5901,5901],"disallowed"],[[5902,5908],"valid"],[[5909,5919],"disallowed"],[[5920,5940],"valid"],[[5941,5942],"valid",[],"NV8"],[[5943,5951],"disallowed"],[[5952,5971],"valid"],[[5972,5983],"disallowed"],[[5984,5996],"valid"],[[5997,5997],"disallowed"],[[5998,6000],"valid"],[[6001,6001],"disallowed"],[[6002,6003],"valid"],[[6004,6015],"disallowed"],[[6016,6067],"valid"],[[6068,6069],"disallowed"],[[6070,6099],"valid"],[[6100,6102],"valid",[],"NV8"],[[6103,6103],"valid"],[[6104,6107],"valid",[],"NV8"],[[6108,6108],"valid"],[[6109,6109],"valid"],[[6110,6111],"disallowed"],[[6112,6121],"valid"],[[6122,6127],"disallowed"],[[6128,6137],"valid",[],"NV8"],[[6138,6143],"disallowed"],[[6144,6149],"valid",[],"NV8"],[[6150,6150],"disallowed"],[[6151,6154],"valid",[],"NV8"],[[6155,6157],"ignored"],[[6158,6158],"disallowed"],[[6159,6159],"disallowed"],[[6160,6169],"valid"],[[6170,6175],"disallowed"],[[6176,6263],"valid"],[[6264,6271],"disallowed"],[[6272,6313],"valid"],[[6314,6314],"valid"],[[6315,6319],"disallowed"],[[6320,6389],"valid"],[[6390,6399],"disallowed"],[[6400,6428],"valid"],[[6429,6430],"valid"],[[6431,6431],"disallowed"],[[6432,6443],"valid"],[[6444,6447],"disallowed"],[[6448,6459],"valid"],[[6460,6463],"disallowed"],[[6464,6464],"valid",[],"NV8"],[[6465,6467],"disallowed"],[[6468,6469],"valid",[],"NV8"],[[6470,6509],"valid"],[[6510,6511],"disallowed"],[[6512,6516],"valid"],[[6517,6527],"disallowed"],[[6528,6569],"valid"],[[6570,6571],"valid"],[[6572,6575],"disallowed"],[[6576,6601],"valid"],[[6602,6607],"disallowed"],[[6608,6617],"valid"],[[6618,6618],"valid",[],"XV8"],[[6619,6621],"disallowed"],[[6622,6623],"valid",[],"NV8"],[[6624,6655],"valid",[],"NV8"],[[6656,6683],"valid"],[[6684,6685],"disallowed"],[[6686,6687],"valid",[],"NV8"],[[6688,6750],"valid"],[[6751,6751],"disallowed"],[[6752,6780],"valid"],[[6781,6782],"disallowed"],[[6783,6793],"valid"],[[6794,6799],"disallowed"],[[6800,6809],"valid"],[[6810,6815],"disallowed"],[[6816,6822],"valid",[],"NV8"],[[6823,6823],"valid"],[[6824,6829],"valid",[],"NV8"],[[6830,6831],"disallowed"],[[6832,6845],"valid"],[[6846,6846],"valid",[],"NV8"],[[6847,6911],"disallowed"],[[6912,6987],"valid"],[[6988,6991],"disallowed"],[[6992,7001],"valid"],[[7002,7018],"valid",[],"NV8"],[[7019,7027],"valid"],[[7028,7036],"valid",[],"NV8"],[[7037,7039],"disallowed"],[[7040,7082],"valid"],[[7083,7085],"valid"],[[7086,7097],"valid"],[[7098,7103],"valid"],[[7104,7155],"valid"],[[7156,7163],"disallowed"],[[7164,7167],"valid",[],"NV8"],[[7168,7223],"valid"],[[7224,7226],"disallowed"],[[7227,7231],"valid",[],"NV8"],[[7232,7241],"valid"],[[7242,7244],"disallowed"],[[7245,7293],"valid"],[[7294,7295],"valid",[],"NV8"],[[7296,7359],"disallowed"],[[7360,7367],"valid",[],"NV8"],[[7368,7375],"disallowed"],[[7376,7378],"valid"],[[7379,7379],"valid",[],"NV8"],[[7380,7410],"valid"],[[7411,7414],"valid"],[[7415,7415],"disallowed"],[[7416,7417],"valid"],[[7418,7423],"disallowed"],[[7424,7467],"valid"],[[7468,7468],"mapped",[97]],[[7469,7469],"mapped",[230]],[[7470,7470],"mapped",[98]],[[7471,7471],"valid"],[[7472,7472],"mapped",[100]],[[7473,7473],"mapped",[101]],[[7474,7474],"mapped",[477]],[[7475,7475],"mapped",[103]],[[7476,7476],"mapped",[104]],[[7477,7477],"mapped",[105]],[[7478,7478],"mapped",[106]],[[7479,7479],"mapped",[107]],[[7480,7480],"mapped",[108]],[[7481,7481],"mapped",[109]],[[7482,7482],"mapped",[110]],[[7483,7483],"valid"],[[7484,7484],"mapped",[111]],[[7485,7485],"mapped",[547]],[[7486,7486],"mapped",[112]],[[7487,7487],"mapped",[114]],[[7488,7488],"mapped",[116]],[[7489,7489],"mapped",[117]],[[7490,7490],"mapped",[119]],[[7491,7491],"mapped",[97]],[[7492,7492],"mapped",[592]],[[7493,7493],"mapped",[593]],[[7494,7494],"mapped",[7426]],[[7495,7495],"mapped",[98]],[[7496,7496],"mapped",[100]],[[7497,7497],"mapped",[101]],[[7498,7498],"mapped",[601]],[[7499,7499],"mapped",[603]],[[7500,7500],"mapped",[604]],[[7501,7501],"mapped",[103]],[[7502,7502],"valid"],[[7503,7503],"mapped",[107]],[[7504,7504],"mapped",[109]],[[7505,7505],"mapped",[331]],[[7506,7506],"mapped",[111]],[[7507,7507],"mapped",[596]],[[7508,7508],"mapped",[7446]],[[7509,7509],"mapped",[7447]],[[7510,7510],"mapped",[112]],[[7511,7511],"mapped",[116]],[[7512,7512],"mapped",[117]],[[7513,7513],"mapped",[7453]],[[7514,7514],"mapped",[623]],[[7515,7515],"mapped",[118]],[[7516,7516],"mapped",[7461]],[[7517,7517],"mapped",[946]],[[7518,7518],"mapped",[947]],[[7519,7519],"mapped",[948]],[[7520,7520],"mapped",[966]],[[7521,7521],"mapped",[967]],[[7522,7522],"mapped",[105]],[[7523,7523],"mapped",[114]],[[7524,7524],"mapped",[117]],[[7525,7525],"mapped",[118]],[[7526,7526],"mapped",[946]],[[7527,7527],"mapped",[947]],[[7528,7528],"mapped",[961]],[[7529,7529],"mapped",[966]],[[7530,7530],"mapped",[967]],[[7531,7531],"valid"],[[7532,7543],"valid"],[[7544,7544],"mapped",[1085]],[[7545,7578],"valid"],[[7579,7579],"mapped",[594]],[[7580,7580],"mapped",[99]],[[7581,7581],"mapped",[597]],[[7582,7582],"mapped",[240]],[[7583,7583],"mapped",[604]],[[7584,7584],"mapped",[102]],[[7585,7585],"mapped",[607]],[[7586,7586],"mapped",[609]],[[7587,7587],"mapped",[613]],[[7588,7588],"mapped",[616]],[[7589,7589],"mapped",[617]],[[7590,7590],"mapped",[618]],[[7591,7591],"mapped",[7547]],[[7592,7592],"mapped",[669]],[[7593,7593],"mapped",[621]],[[7594,7594],"mapped",[7557]],[[7595,7595],"mapped",[671]],[[7596,7596],"mapped",[625]],[[7597,7597],"mapped",[624]],[[7598,7598],"mapped",[626]],[[7599,7599],"mapped",[627]],[[7600,7600],"mapped",[628]],[[7601,7601],"mapped",[629]],[[7602,7602],"mapped",[632]],[[7603,7603],"mapped",[642]],[[7604,7604],"mapped",[643]],[[7605,7605],"mapped",[427]],[[7606,7606],"mapped",[649]],[[7607,7607],"mapped",[650]],[[7608,7608],"mapped",[7452]],[[7609,7609],"mapped",[651]],[[7610,7610],"mapped",[652]],[[7611,7611],"mapped",[122]],[[7612,7612],"mapped",[656]],[[7613,7613],"mapped",[657]],[[7614,7614],"mapped",[658]],[[7615,7615],"mapped",[952]],[[7616,7619],"valid"],[[7620,7626],"valid"],[[7627,7654],"valid"],[[7655,7669],"valid"],[[7670,7675],"disallowed"],[[7676,7676],"valid"],[[7677,7677],"valid"],[[7678,7679],"valid"],[[7680,7680],"mapped",[7681]],[[7681,7681],"valid"],[[7682,7682],"mapped",[7683]],[[7683,7683],"valid"],[[7684,7684],"mapped",[7685]],[[7685,7685],"valid"],[[7686,7686],"mapped",[7687]],[[7687,7687],"valid"],[[7688,7688],"mapped",[7689]],[[7689,7689],"valid"],[[7690,7690],"mapped",[7691]],[[7691,7691],"valid"],[[7692,7692],"mapped",[7693]],[[7693,7693],"valid"],[[7694,7694],"mapped",[7695]],[[7695,7695],"valid"],[[7696,7696],"mapped",[7697]],[[7697,7697],"valid"],[[7698,7698],"mapped",[7699]],[[7699,7699],"valid"],[[7700,7700],"mapped",[7701]],[[7701,7701],"valid"],[[7702,7702],"mapped",[7703]],[[7703,7703],"valid"],[[7704,7704],"mapped",[7705]],[[7705,7705],"valid"],[[7706,7706],"mapped",[7707]],[[7707,7707],"valid"],[[7708,7708],"mapped",[7709]],[[7709,7709],"valid"],[[7710,7710],"mapped",[7711]],[[7711,7711],"valid"],[[7712,7712],"mapped",[7713]],[[7713,7713],"valid"],[[7714,7714],"mapped",[7715]],[[7715,7715],"valid"],[[7716,7716],"mapped",[7717]],[[7717,7717],"valid"],[[7718,7718],"mapped",[7719]],[[7719,7719],"valid"],[[7720,7720],"mapped",[7721]],[[7721,7721],"valid"],[[7722,7722],"mapped",[7723]],[[7723,7723],"valid"],[[7724,7724],"mapped",[7725]],[[7725,7725],"valid"],[[7726,7726],"mapped",[7727]],[[7727,7727],"valid"],[[7728,7728],"mapped",[7729]],[[7729,7729],"valid"],[[7730,7730],"mapped",[7731]],[[7731,7731],"valid"],[[7732,7732],"mapped",[7733]],[[7733,7733],"valid"],[[7734,7734],"mapped",[7735]],[[7735,7735],"valid"],[[7736,7736],"mapped",[7737]],[[7737,7737],"valid"],[[7738,7738],"mapped",[7739]],[[7739,7739],"valid"],[[7740,7740],"mapped",[7741]],[[7741,7741],"valid"],[[7742,7742],"mapped",[7743]],[[7743,7743],"valid"],[[7744,7744],"mapped",[7745]],[[7745,7745],"valid"],[[7746,7746],"mapped",[7747]],[[7747,7747],"valid"],[[7748,7748],"mapped",[7749]],[[7749,7749],"valid"],[[7750,7750],"mapped",[7751]],[[7751,7751],"valid"],[[7752,7752],"mapped",[7753]],[[7753,7753],"valid"],[[7754,7754],"mapped",[7755]],[[7755,7755],"valid"],[[7756,7756],"mapped",[7757]],[[7757,7757],"valid"],[[7758,7758],"mapped",[7759]],[[7759,7759],"valid"],[[7760,7760],"mapped",[7761]],[[7761,7761],"valid"],[[7762,7762],"mapped",[7763]],[[7763,7763],"valid"],[[7764,7764],"mapped",[7765]],[[7765,7765],"valid"],[[7766,7766],"mapped",[7767]],[[7767,7767],"valid"],[[7768,7768],"mapped",[7769]],[[7769,7769],"valid"],[[7770,7770],"mapped",[7771]],[[7771,7771],"valid"],[[7772,7772],"mapped",[7773]],[[7773,7773],"valid"],[[7774,7774],"mapped",[7775]],[[7775,7775],"valid"],[[7776,7776],"mapped",[7777]],[[7777,7777],"valid"],[[7778,7778],"mapped",[7779]],[[7779,7779],"valid"],[[7780,7780],"mapped",[7781]],[[7781,7781],"valid"],[[7782,7782],"mapped",[7783]],[[7783,7783],"valid"],[[7784,7784],"mapped",[7785]],[[7785,7785],"valid"],[[7786,7786],"mapped",[7787]],[[7787,7787],"valid"],[[7788,7788],"mapped",[7789]],[[7789,7789],"valid"],[[7790,7790],"mapped",[7791]],[[7791,7791],"valid"],[[7792,7792],"mapped",[7793]],[[7793,7793],"valid"],[[7794,7794],"mapped",[7795]],[[7795,7795],"valid"],[[7796,7796],"mapped",[7797]],[[7797,7797],"valid"],[[7798,7798],"mapped",[7799]],[[7799,7799],"valid"],[[7800,7800],"mapped",[7801]],[[7801,7801],"valid"],[[7802,7802],"mapped",[7803]],[[7803,7803],"valid"],[[7804,7804],"mapped",[7805]],[[7805,7805],"valid"],[[7806,7806],"mapped",[7807]],[[7807,7807],"valid"],[[7808,7808],"mapped",[7809]],[[7809,7809],"valid"],[[7810,7810],"mapped",[7811]],[[7811,7811],"valid"],[[7812,7812],"mapped",[7813]],[[7813,7813],"valid"],[[7814,7814],"mapped",[7815]],[[7815,7815],"valid"],[[7816,7816],"mapped",[7817]],[[7817,7817],"valid"],[[7818,7818],"mapped",[7819]],[[7819,7819],"valid"],[[7820,7820],"mapped",[7821]],[[7821,7821],"valid"],[[7822,7822],"mapped",[7823]],[[7823,7823],"valid"],[[7824,7824],"mapped",[7825]],[[7825,7825],"valid"],[[7826,7826],"mapped",[7827]],[[7827,7827],"valid"],[[7828,7828],"mapped",[7829]],[[7829,7833],"valid"],[[7834,7834],"mapped",[97,702]],[[7835,7835],"mapped",[7777]],[[7836,7837],"valid"],[[7838,7838],"mapped",[115,115]],[[7839,7839],"valid"],[[7840,7840],"mapped",[7841]],[[7841,7841],"valid"],[[7842,7842],"mapped",[7843]],[[7843,7843],"valid"],[[7844,7844],"mapped",[7845]],[[7845,7845],"valid"],[[7846,7846],"mapped",[7847]],[[7847,7847],"valid"],[[7848,7848],"mapped",[7849]],[[7849,7849],"valid"],[[7850,7850],"mapped",[7851]],[[7851,7851],"valid"],[[7852,7852],"mapped",[7853]],[[7853,7853],"valid"],[[7854,7854],"mapped",[7855]],[[7855,7855],"valid"],[[7856,7856],"mapped",[7857]],[[7857,7857],"valid"],[[7858,7858],"mapped",[7859]],[[7859,7859],"valid"],[[7860,7860],"mapped",[7861]],[[7861,7861],"valid"],[[7862,7862],"mapped",[7863]],[[7863,7863],"valid"],[[7864,7864],"mapped",[7865]],[[7865,7865],"valid"],[[7866,7866],"mapped",[7867]],[[7867,7867],"valid"],[[7868,7868],"mapped",[7869]],[[7869,7869],"valid"],[[7870,7870],"mapped",[7871]],[[7871,7871],"valid"],[[7872,7872],"mapped",[7873]],[[7873,7873],"valid"],[[7874,7874],"mapped",[7875]],[[7875,7875],"valid"],[[7876,7876],"mapped",[7877]],[[7877,7877],"valid"],[[7878,7878],"mapped",[7879]],[[7879,7879],"valid"],[[7880,7880],"mapped",[7881]],[[7881,7881],"valid"],[[7882,7882],"mapped",[7883]],[[7883,7883],"valid"],[[7884,7884],"mapped",[7885]],[[7885,7885],"valid"],[[7886,7886],"mapped",[7887]],[[7887,7887],"valid"],[[7888,7888],"mapped",[7889]],[[7889,7889],"valid"],[[7890,7890],"mapped",[7891]],[[7891,7891],"valid"],[[7892,7892],"mapped",[7893]],[[7893,7893],"valid"],[[7894,7894],"mapped",[7895]],[[7895,7895],"valid"],[[7896,7896],"mapped",[7897]],[[7897,7897],"valid"],[[7898,7898],"mapped",[7899]],[[7899,7899],"valid"],[[7900,7900],"mapped",[7901]],[[7901,7901],"valid"],[[7902,7902],"mapped",[7903]],[[7903,7903],"valid"],[[7904,7904],"mapped",[7905]],[[7905,7905],"valid"],[[7906,7906],"mapped",[7907]],[[7907,7907],"valid"],[[7908,7908],"mapped",[7909]],[[7909,7909],"valid"],[[7910,7910],"mapped",[7911]],[[7911,7911],"valid"],[[7912,7912],"mapped",[7913]],[[7913,7913],"valid"],[[7914,7914],"mapped",[7915]],[[7915,7915],"valid"],[[7916,7916],"mapped",[7917]],[[7917,7917],"valid"],[[7918,7918],"mapped",[7919]],[[7919,7919],"valid"],[[7920,7920],"mapped",[7921]],[[7921,7921],"valid"],[[7922,7922],"mapped",[7923]],[[7923,7923],"valid"],[[7924,7924],"mapped",[7925]],[[7925,7925],"valid"],[[7926,7926],"mapped",[7927]],[[7927,7927],"valid"],[[7928,7928],"mapped",[7929]],[[7929,7929],"valid"],[[7930,7930],"mapped",[7931]],[[7931,7931],"valid"],[[7932,7932],"mapped",[7933]],[[7933,7933],"valid"],[[7934,7934],"mapped",[7935]],[[7935,7935],"valid"],[[7936,7943],"valid"],[[7944,7944],"mapped",[7936]],[[7945,7945],"mapped",[7937]],[[7946,7946],"mapped",[7938]],[[7947,7947],"mapped",[7939]],[[7948,7948],"mapped",[7940]],[[7949,7949],"mapped",[7941]],[[7950,7950],"mapped",[7942]],[[7951,7951],"mapped",[7943]],[[7952,7957],"valid"],[[7958,7959],"disallowed"],[[7960,7960],"mapped",[7952]],[[7961,7961],"mapped",[7953]],[[7962,7962],"mapped",[7954]],[[7963,7963],"mapped",[7955]],[[7964,7964],"mapped",[7956]],[[7965,7965],"mapped",[7957]],[[7966,7967],"disallowed"],[[7968,7975],"valid"],[[7976,7976],"mapped",[7968]],[[7977,7977],"mapped",[7969]],[[7978,7978],"mapped",[7970]],[[7979,7979],"mapped",[7971]],[[7980,7980],"mapped",[7972]],[[7981,7981],"mapped",[7973]],[[7982,7982],"mapped",[7974]],[[7983,7983],"mapped",[7975]],[[7984,7991],"valid"],[[7992,7992],"mapped",[7984]],[[7993,7993],"mapped",[7985]],[[7994,7994],"mapped",[7986]],[[7995,7995],"mapped",[7987]],[[7996,7996],"mapped",[7988]],[[7997,7997],"mapped",[7989]],[[7998,7998],"mapped",[7990]],[[7999,7999],"mapped",[7991]],[[8000,8005],"valid"],[[8006,8007],"disallowed"],[[8008,8008],"mapped",[8000]],[[8009,8009],"mapped",[8001]],[[8010,8010],"mapped",[8002]],[[8011,8011],"mapped",[8003]],[[8012,8012],"mapped",[8004]],[[8013,8013],"mapped",[8005]],[[8014,8015],"disallowed"],[[8016,8023],"valid"],[[8024,8024],"disallowed"],[[8025,8025],"mapped",[8017]],[[8026,8026],"disallowed"],[[8027,8027],"mapped",[8019]],[[8028,8028],"disallowed"],[[8029,8029],"mapped",[8021]],[[8030,8030],"disallowed"],[[8031,8031],"mapped",[8023]],[[8032,8039],"valid"],[[8040,8040],"mapped",[8032]],[[8041,8041],"mapped",[8033]],[[8042,8042],"mapped",[8034]],[[8043,8043],"mapped",[8035]],[[8044,8044],"mapped",[8036]],[[8045,8045],"mapped",[8037]],[[8046,8046],"mapped",[8038]],[[8047,8047],"mapped",[8039]],[[8048,8048],"valid"],[[8049,8049],"mapped",[940]],[[8050,8050],"valid"],[[8051,8051],"mapped",[941]],[[8052,8052],"valid"],[[8053,8053],"mapped",[942]],[[8054,8054],"valid"],[[8055,8055],"mapped",[943]],[[8056,8056],"valid"],[[8057,8057],"mapped",[972]],[[8058,8058],"valid"],[[8059,8059],"mapped",[973]],[[8060,8060],"valid"],[[8061,8061],"mapped",[974]],[[8062,8063],"disallowed"],[[8064,8064],"mapped",[7936,953]],[[8065,8065],"mapped",[7937,953]],[[8066,8066],"mapped",[7938,953]],[[8067,8067],"mapped",[7939,953]],[[8068,8068],"mapped",[7940,953]],[[8069,8069],"mapped",[7941,953]],[[8070,8070],"mapped",[7942,953]],[[8071,8071],"mapped",[7943,953]],[[8072,8072],"mapped",[7936,953]],[[8073,8073],"mapped",[7937,953]],[[8074,8074],"mapped",[7938,953]],[[8075,8075],"mapped",[7939,953]],[[8076,8076],"mapped",[7940,953]],[[8077,8077],"mapped",[7941,953]],[[8078,8078],"mapped",[7942,953]],[[8079,8079],"mapped",[7943,953]],[[8080,8080],"mapped",[7968,953]],[[8081,8081],"mapped",[7969,953]],[[8082,8082],"mapped",[7970,953]],[[8083,8083],"mapped",[7971,953]],[[8084,8084],"mapped",[7972,953]],[[8085,8085],"mapped",[7973,953]],[[8086,8086],"mapped",[7974,953]],[[8087,8087],"mapped",[7975,953]],[[8088,8088],"mapped",[7968,953]],[[8089,8089],"mapped",[7969,953]],[[8090,8090],"mapped",[7970,953]],[[8091,8091],"mapped",[7971,953]],[[8092,8092],"mapped",[7972,953]],[[8093,8093],"mapped",[7973,953]],[[8094,8094],"mapped",[7974,953]],[[8095,8095],"mapped",[7975,953]],[[8096,8096],"mapped",[8032,953]],[[8097,8097],"mapped",[8033,953]],[[8098,8098],"mapped",[8034,953]],[[8099,8099],"mapped",[8035,953]],[[8100,8100],"mapped",[8036,953]],[[8101,8101],"mapped",[8037,953]],[[8102,8102],"mapped",[8038,953]],[[8103,8103],"mapped",[8039,953]],[[8104,8104],"mapped",[8032,953]],[[8105,8105],"mapped",[8033,953]],[[8106,8106],"mapped",[8034,953]],[[8107,8107],"mapped",[8035,953]],[[8108,8108],"mapped",[8036,953]],[[8109,8109],"mapped",[8037,953]],[[8110,8110],"mapped",[8038,953]],[[8111,8111],"mapped",[8039,953]],[[8112,8113],"valid"],[[8114,8114],"mapped",[8048,953]],[[8115,8115],"mapped",[945,953]],[[8116,8116],"mapped",[940,953]],[[8117,8117],"disallowed"],[[8118,8118],"valid"],[[8119,8119],"mapped",[8118,953]],[[8120,8120],"mapped",[8112]],[[8121,8121],"mapped",[8113]],[[8122,8122],"mapped",[8048]],[[8123,8123],"mapped",[940]],[[8124,8124],"mapped",[945,953]],[[8125,8125],"disallowed_STD3_mapped",[32,787]],[[8126,8126],"mapped",[953]],[[8127,8127],"disallowed_STD3_mapped",[32,787]],[[8128,8128],"disallowed_STD3_mapped",[32,834]],[[8129,8129],"disallowed_STD3_mapped",[32,776,834]],[[8130,8130],"mapped",[8052,953]],[[8131,8131],"mapped",[951,953]],[[8132,8132],"mapped",[942,953]],[[8133,8133],"disallowed"],[[8134,8134],"valid"],[[8135,8135],"mapped",[8134,953]],[[8136,8136],"mapped",[8050]],[[8137,8137],"mapped",[941]],[[8138,8138],"mapped",[8052]],[[8139,8139],"mapped",[942]],[[8140,8140],"mapped",[951,953]],[[8141,8141],"disallowed_STD3_mapped",[32,787,768]],[[8142,8142],"disallowed_STD3_mapped",[32,787,769]],[[8143,8143],"disallowed_STD3_mapped",[32,787,834]],[[8144,8146],"valid"],[[8147,8147],"mapped",[912]],[[8148,8149],"disallowed"],[[8150,8151],"valid"],[[8152,8152],"mapped",[8144]],[[8153,8153],"mapped",[8145]],[[8154,8154],"mapped",[8054]],[[8155,8155],"mapped",[943]],[[8156,8156],"disallowed"],[[8157,8157],"disallowed_STD3_mapped",[32,788,768]],[[8158,8158],"disallowed_STD3_mapped",[32,788,769]],[[8159,8159],"disallowed_STD3_mapped",[32,788,834]],[[8160,8162],"valid"],[[8163,8163],"mapped",[944]],[[8164,8167],"valid"],[[8168,8168],"mapped",[8160]],[[8169,8169],"mapped",[8161]],[[8170,8170],"mapped",[8058]],[[8171,8171],"mapped",[973]],[[8172,8172],"mapped",[8165]],[[8173,8173],"disallowed_STD3_mapped",[32,776,768]],[[8174,8174],"disallowed_STD3_mapped",[32,776,769]],[[8175,8175],"disallowed_STD3_mapped",[96]],[[8176,8177],"disallowed"],[[8178,8178],"mapped",[8060,953]],[[8179,8179],"mapped",[969,953]],[[8180,8180],"mapped",[974,953]],[[8181,8181],"disallowed"],[[8182,8182],"valid"],[[8183,8183],"mapped",[8182,953]],[[8184,8184],"mapped",[8056]],[[8185,8185],"mapped",[972]],[[8186,8186],"mapped",[8060]],[[8187,8187],"mapped",[974]],[[8188,8188],"mapped",[969,953]],[[8189,8189],"disallowed_STD3_mapped",[32,769]],[[8190,8190],"disallowed_STD3_mapped",[32,788]],[[8191,8191],"disallowed"],[[8192,8202],"disallowed_STD3_mapped",[32]],[[8203,8203],"ignored"],[[8204,8205],"deviation",[]],[[8206,8207],"disallowed"],[[8208,8208],"valid",[],"NV8"],[[8209,8209],"mapped",[8208]],[[8210,8214],"valid",[],"NV8"],[[8215,8215],"disallowed_STD3_mapped",[32,819]],[[8216,8227],"valid",[],"NV8"],[[8228,8230],"disallowed"],[[8231,8231],"valid",[],"NV8"],[[8232,8238],"disallowed"],[[8239,8239],"disallowed_STD3_mapped",[32]],[[8240,8242],"valid",[],"NV8"],[[8243,8243],"mapped",[8242,8242]],[[8244,8244],"mapped",[8242,8242,8242]],[[8245,8245],"valid",[],"NV8"],[[8246,8246],"mapped",[8245,8245]],[[8247,8247],"mapped",[8245,8245,8245]],[[8248,8251],"valid",[],"NV8"],[[8252,8252],"disallowed_STD3_mapped",[33,33]],[[8253,8253],"valid",[],"NV8"],[[8254,8254],"disallowed_STD3_mapped",[32,773]],[[8255,8262],"valid",[],"NV8"],[[8263,8263],"disallowed_STD3_mapped",[63,63]],[[8264,8264],"disallowed_STD3_mapped",[63,33]],[[8265,8265],"disallowed_STD3_mapped",[33,63]],[[8266,8269],"valid",[],"NV8"],[[8270,8274],"valid",[],"NV8"],[[8275,8276],"valid",[],"NV8"],[[8277,8278],"valid",[],"NV8"],[[8279,8279],"mapped",[8242,8242,8242,8242]],[[8280,8286],"valid",[],"NV8"],[[8287,8287],"disallowed_STD3_mapped",[32]],[[8288,8288],"ignored"],[[8289,8291],"disallowed"],[[8292,8292],"ignored"],[[8293,8293],"disallowed"],[[8294,8297],"disallowed"],[[8298,8303],"disallowed"],[[8304,8304],"mapped",[48]],[[8305,8305],"mapped",[105]],[[8306,8307],"disallowed"],[[8308,8308],"mapped",[52]],[[8309,8309],"mapped",[53]],[[8310,8310],"mapped",[54]],[[8311,8311],"mapped",[55]],[[8312,8312],"mapped",[56]],[[8313,8313],"mapped",[57]],[[8314,8314],"disallowed_STD3_mapped",[43]],[[8315,8315],"mapped",[8722]],[[8316,8316],"disallowed_STD3_mapped",[61]],[[8317,8317],"disallowed_STD3_mapped",[40]],[[8318,8318],"disallowed_STD3_mapped",[41]],[[8319,8319],"mapped",[110]],[[8320,8320],"mapped",[48]],[[8321,8321],"mapped",[49]],[[8322,8322],"mapped",[50]],[[8323,8323],"mapped",[51]],[[8324,8324],"mapped",[52]],[[8325,8325],"mapped",[53]],[[8326,8326],"mapped",[54]],[[8327,8327],"mapped",[55]],[[8328,8328],"mapped",[56]],[[8329,8329],"mapped",[57]],[[8330,8330],"disallowed_STD3_mapped",[43]],[[8331,8331],"mapped",[8722]],[[8332,8332],"disallowed_STD3_mapped",[61]],[[8333,8333],"disallowed_STD3_mapped",[40]],[[8334,8334],"disallowed_STD3_mapped",[41]],[[8335,8335],"disallowed"],[[8336,8336],"mapped",[97]],[[8337,8337],"mapped",[101]],[[8338,8338],"mapped",[111]],[[8339,8339],"mapped",[120]],[[8340,8340],"mapped",[601]],[[8341,8341],"mapped",[104]],[[8342,8342],"mapped",[107]],[[8343,8343],"mapped",[108]],[[8344,8344],"mapped",[109]],[[8345,8345],"mapped",[110]],[[8346,8346],"mapped",[112]],[[8347,8347],"mapped",[115]],[[8348,8348],"mapped",[116]],[[8349,8351],"disallowed"],[[8352,8359],"valid",[],"NV8"],[[8360,8360],"mapped",[114,115]],[[8361,8362],"valid",[],"NV8"],[[8363,8363],"valid",[],"NV8"],[[8364,8364],"valid",[],"NV8"],[[8365,8367],"valid",[],"NV8"],[[8368,8369],"valid",[],"NV8"],[[8370,8373],"valid",[],"NV8"],[[8374,8376],"valid",[],"NV8"],[[8377,8377],"valid",[],"NV8"],[[8378,8378],"valid",[],"NV8"],[[8379,8381],"valid",[],"NV8"],[[8382,8382],"valid",[],"NV8"],[[8383,8399],"disallowed"],[[8400,8417],"valid",[],"NV8"],[[8418,8419],"valid",[],"NV8"],[[8420,8426],"valid",[],"NV8"],[[8427,8427],"valid",[],"NV8"],[[8428,8431],"valid",[],"NV8"],[[8432,8432],"valid",[],"NV8"],[[8433,8447],"disallowed"],[[8448,8448],"disallowed_STD3_mapped",[97,47,99]],[[8449,8449],"disallowed_STD3_mapped",[97,47,115]],[[8450,8450],"mapped",[99]],[[8451,8451],"mapped",[176,99]],[[8452,8452],"valid",[],"NV8"],[[8453,8453],"disallowed_STD3_mapped",[99,47,111]],[[8454,8454],"disallowed_STD3_mapped",[99,47,117]],[[8455,8455],"mapped",[603]],[[8456,8456],"valid",[],"NV8"],[[8457,8457],"mapped",[176,102]],[[8458,8458],"mapped",[103]],[[8459,8462],"mapped",[104]],[[8463,8463],"mapped",[295]],[[8464,8465],"mapped",[105]],[[8466,8467],"mapped",[108]],[[8468,8468],"valid",[],"NV8"],[[8469,8469],"mapped",[110]],[[8470,8470],"mapped",[110,111]],[[8471,8472],"valid",[],"NV8"],[[8473,8473],"mapped",[112]],[[8474,8474],"mapped",[113]],[[8475,8477],"mapped",[114]],[[8478,8479],"valid",[],"NV8"],[[8480,8480],"mapped",[115,109]],[[8481,8481],"mapped",[116,101,108]],[[8482,8482],"mapped",[116,109]],[[8483,8483],"valid",[],"NV8"],[[8484,8484],"mapped",[122]],[[8485,8485],"valid",[],"NV8"],[[8486,8486],"mapped",[969]],[[8487,8487],"valid",[],"NV8"],[[8488,8488],"mapped",[122]],[[8489,8489],"valid",[],"NV8"],[[8490,8490],"mapped",[107]],[[8491,8491],"mapped",[229]],[[8492,8492],"mapped",[98]],[[8493,8493],"mapped",[99]],[[8494,8494],"valid",[],"NV8"],[[8495,8496],"mapped",[101]],[[8497,8497],"mapped",[102]],[[8498,8498],"disallowed"],[[8499,8499],"mapped",[109]],[[8500,8500],"mapped",[111]],[[8501,8501],"mapped",[1488]],[[8502,8502],"mapped",[1489]],[[8503,8503],"mapped",[1490]],[[8504,8504],"mapped",[1491]],[[8505,8505],"mapped",[105]],[[8506,8506],"valid",[],"NV8"],[[8507,8507],"mapped",[102,97,120]],[[8508,8508],"mapped",[960]],[[8509,8510],"mapped",[947]],[[8511,8511],"mapped",[960]],[[8512,8512],"mapped",[8721]],[[8513,8516],"valid",[],"NV8"],[[8517,8518],"mapped",[100]],[[8519,8519],"mapped",[101]],[[8520,8520],"mapped",[105]],[[8521,8521],"mapped",[106]],[[8522,8523],"valid",[],"NV8"],[[8524,8524],"valid",[],"NV8"],[[8525,8525],"valid",[],"NV8"],[[8526,8526],"valid"],[[8527,8527],"valid",[],"NV8"],[[8528,8528],"mapped",[49,8260,55]],[[8529,8529],"mapped",[49,8260,57]],[[8530,8530],"mapped",[49,8260,49,48]],[[8531,8531],"mapped",[49,8260,51]],[[8532,8532],"mapped",[50,8260,51]],[[8533,8533],"mapped",[49,8260,53]],[[8534,8534],"mapped",[50,8260,53]],[[8535,8535],"mapped",[51,8260,53]],[[8536,8536],"mapped",[52,8260,53]],[[8537,8537],"mapped",[49,8260,54]],[[8538,8538],"mapped",[53,8260,54]],[[8539,8539],"mapped",[49,8260,56]],[[8540,8540],"mapped",[51,8260,56]],[[8541,8541],"mapped",[53,8260,56]],[[8542,8542],"mapped",[55,8260,56]],[[8543,8543],"mapped",[49,8260]],[[8544,8544],"mapped",[105]],[[8545,8545],"mapped",[105,105]],[[8546,8546],"mapped",[105,105,105]],[[8547,8547],"mapped",[105,118]],[[8548,8548],"mapped",[118]],[[8549,8549],"mapped",[118,105]],[[8550,8550],"mapped",[118,105,105]],[[8551,8551],"mapped",[118,105,105,105]],[[8552,8552],"mapped",[105,120]],[[8553,8553],"mapped",[120]],[[8554,8554],"mapped",[120,105]],[[8555,8555],"mapped",[120,105,105]],[[8556,8556],"mapped",[108]],[[8557,8557],"mapped",[99]],[[8558,8558],"mapped",[100]],[[8559,8559],"mapped",[109]],[[8560,8560],"mapped",[105]],[[8561,8561],"mapped",[105,105]],[[8562,8562],"mapped",[105,105,105]],[[8563,8563],"mapped",[105,118]],[[8564,8564],"mapped",[118]],[[8565,8565],"mapped",[118,105]],[[8566,8566],"mapped",[118,105,105]],[[8567,8567],"mapped",[118,105,105,105]],[[8568,8568],"mapped",[105,120]],[[8569,8569],"mapped",[120]],[[8570,8570],"mapped",[120,105]],[[8571,8571],"mapped",[120,105,105]],[[8572,8572],"mapped",[108]],[[8573,8573],"mapped",[99]],[[8574,8574],"mapped",[100]],[[8575,8575],"mapped",[109]],[[8576,8578],"valid",[],"NV8"],[[8579,8579],"disallowed"],[[8580,8580],"valid"],[[8581,8584],"valid",[],"NV8"],[[8585,8585],"mapped",[48,8260,51]],[[8586,8587],"valid",[],"NV8"],[[8588,8591],"disallowed"],[[8592,8682],"valid",[],"NV8"],[[8683,8691],"valid",[],"NV8"],[[8692,8703],"valid",[],"NV8"],[[8704,8747],"valid",[],"NV8"],[[8748,8748],"mapped",[8747,8747]],[[8749,8749],"mapped",[8747,8747,8747]],[[8750,8750],"valid",[],"NV8"],[[8751,8751],"mapped",[8750,8750]],[[8752,8752],"mapped",[8750,8750,8750]],[[8753,8799],"valid",[],"NV8"],[[8800,8800],"disallowed_STD3_valid"],[[8801,8813],"valid",[],"NV8"],[[8814,8815],"disallowed_STD3_valid"],[[8816,8945],"valid",[],"NV8"],[[8946,8959],"valid",[],"NV8"],[[8960,8960],"valid",[],"NV8"],[[8961,8961],"valid",[],"NV8"],[[8962,9000],"valid",[],"NV8"],[[9001,9001],"mapped",[12296]],[[9002,9002],"mapped",[12297]],[[9003,9082],"valid",[],"NV8"],[[9083,9083],"valid",[],"NV8"],[[9084,9084],"valid",[],"NV8"],[[9085,9114],"valid",[],"NV8"],[[9115,9166],"valid",[],"NV8"],[[9167,9168],"valid",[],"NV8"],[[9169,9179],"valid",[],"NV8"],[[9180,9191],"valid",[],"NV8"],[[9192,9192],"valid",[],"NV8"],[[9193,9203],"valid",[],"NV8"],[[9204,9210],"valid",[],"NV8"],[[9211,9215],"disallowed"],[[9216,9252],"valid",[],"NV8"],[[9253,9254],"valid",[],"NV8"],[[9255,9279],"disallowed"],[[9280,9290],"valid",[],"NV8"],[[9291,9311],"disallowed"],[[9312,9312],"mapped",[49]],[[9313,9313],"mapped",[50]],[[9314,9314],"mapped",[51]],[[9315,9315],"mapped",[52]],[[9316,9316],"mapped",[53]],[[9317,9317],"mapped",[54]],[[9318,9318],"mapped",[55]],[[9319,9319],"mapped",[56]],[[9320,9320],"mapped",[57]],[[9321,9321],"mapped",[49,48]],[[9322,9322],"mapped",[49,49]],[[9323,9323],"mapped",[49,50]],[[9324,9324],"mapped",[49,51]],[[9325,9325],"mapped",[49,52]],[[9326,9326],"mapped",[49,53]],[[9327,9327],"mapped",[49,54]],[[9328,9328],"mapped",[49,55]],[[9329,9329],"mapped",[49,56]],[[9330,9330],"mapped",[49,57]],[[9331,9331],"mapped",[50,48]],[[9332,9332],"disallowed_STD3_mapped",[40,49,41]],[[9333,9333],"disallowed_STD3_mapped",[40,50,41]],[[9334,9334],"disallowed_STD3_mapped",[40,51,41]],[[9335,9335],"disallowed_STD3_mapped",[40,52,41]],[[9336,9336],"disallowed_STD3_mapped",[40,53,41]],[[9337,9337],"disallowed_STD3_mapped",[40,54,41]],[[9338,9338],"disallowed_STD3_mapped",[40,55,41]],[[9339,9339],"disallowed_STD3_mapped",[40,56,41]],[[9340,9340],"disallowed_STD3_mapped",[40,57,41]],[[9341,9341],"disallowed_STD3_mapped",[40,49,48,41]],[[9342,9342],"disallowed_STD3_mapped",[40,49,49,41]],[[9343,9343],"disallowed_STD3_mapped",[40,49,50,41]],[[9344,9344],"disallowed_STD3_mapped",[40,49,51,41]],[[9345,9345],"disallowed_STD3_mapped",[40,49,52,41]],[[9346,9346],"disallowed_STD3_mapped",[40,49,53,41]],[[9347,9347],"disallowed_STD3_mapped",[40,49,54,41]],[[9348,9348],"disallowed_STD3_mapped",[40,49,55,41]],[[9349,9349],"disallowed_STD3_mapped",[40,49,56,41]],[[9350,9350],"disallowed_STD3_mapped",[40,49,57,41]],[[9351,9351],"disallowed_STD3_mapped",[40,50,48,41]],[[9352,9371],"disallowed"],[[9372,9372],"disallowed_STD3_mapped",[40,97,41]],[[9373,9373],"disallowed_STD3_mapped",[40,98,41]],[[9374,9374],"disallowed_STD3_mapped",[40,99,41]],[[9375,9375],"disallowed_STD3_mapped",[40,100,41]],[[9376,9376],"disallowed_STD3_mapped",[40,101,41]],[[9377,9377],"disallowed_STD3_mapped",[40,102,41]],[[9378,9378],"disallowed_STD3_mapped",[40,103,41]],[[9379,9379],"disallowed_STD3_mapped",[40,104,41]],[[9380,9380],"disallowed_STD3_mapped",[40,105,41]],[[9381,9381],"disallowed_STD3_mapped",[40,106,41]],[[9382,9382],"disallowed_STD3_mapped",[40,107,41]],[[9383,9383],"disallowed_STD3_mapped",[40,108,41]],[[9384,9384],"disallowed_STD3_mapped",[40,109,41]],[[9385,9385],"disallowed_STD3_mapped",[40,110,41]],[[9386,9386],"disallowed_STD3_mapped",[40,111,41]],[[9387,9387],"disallowed_STD3_mapped",[40,112,41]],[[9388,9388],"disallowed_STD3_mapped",[40,113,41]],[[9389,9389],"disallowed_STD3_mapped",[40,114,41]],[[9390,9390],"disallowed_STD3_mapped",[40,115,41]],[[9391,9391],"disallowed_STD3_mapped",[40,116,41]],[[9392,9392],"disallowed_STD3_mapped",[40,117,41]],[[9393,9393],"disallowed_STD3_mapped",[40,118,41]],[[9394,9394],"disallowed_STD3_mapped",[40,119,41]],[[9395,9395],"disallowed_STD3_mapped",[40,120,41]],[[9396,9396],"disallowed_STD3_mapped",[40,121,41]],[[9397,9397],"disallowed_STD3_mapped",[40,122,41]],[[9398,9398],"mapped",[97]],[[9399,9399],"mapped",[98]],[[9400,9400],"mapped",[99]],[[9401,9401],"mapped",[100]],[[9402,9402],"mapped",[101]],[[9403,9403],"mapped",[102]],[[9404,9404],"mapped",[103]],[[9405,9405],"mapped",[104]],[[9406,9406],"mapped",[105]],[[9407,9407],"mapped",[106]],[[9408,9408],"mapped",[107]],[[9409,9409],"mapped",[108]],[[9410,9410],"mapped",[109]],[[9411,9411],"mapped",[110]],[[9412,9412],"mapped",[111]],[[9413,9413],"mapped",[112]],[[9414,9414],"mapped",[113]],[[9415,9415],"mapped",[114]],[[9416,9416],"mapped",[115]],[[9417,9417],"mapped",[116]],[[9418,9418],"mapped",[117]],[[9419,9419],"mapped",[118]],[[9420,9420],"mapped",[119]],[[9421,9421],"mapped",[120]],[[9422,9422],"mapped",[121]],[[9423,9423],"mapped",[122]],[[9424,9424],"mapped",[97]],[[9425,9425],"mapped",[98]],[[9426,9426],"mapped",[99]],[[9427,9427],"mapped",[100]],[[9428,9428],"mapped",[101]],[[9429,9429],"mapped",[102]],[[9430,9430],"mapped",[103]],[[9431,9431],"mapped",[104]],[[9432,9432],"mapped",[105]],[[9433,9433],"mapped",[106]],[[9434,9434],"mapped",[107]],[[9435,9435],"mapped",[108]],[[9436,9436],"mapped",[109]],[[9437,9437],"mapped",[110]],[[9438,9438],"mapped",[111]],[[9439,9439],"mapped",[112]],[[9440,9440],"mapped",[113]],[[9441,9441],"mapped",[114]],[[9442,9442],"mapped",[115]],[[9443,9443],"mapped",[116]],[[9444,9444],"mapped",[117]],[[9445,9445],"mapped",[118]],[[9446,9446],"mapped",[119]],[[9447,9447],"mapped",[120]],[[9448,9448],"mapped",[121]],[[9449,9449],"mapped",[122]],[[9450,9450],"mapped",[48]],[[9451,9470],"valid",[],"NV8"],[[9471,9471],"valid",[],"NV8"],[[9472,9621],"valid",[],"NV8"],[[9622,9631],"valid",[],"NV8"],[[9632,9711],"valid",[],"NV8"],[[9712,9719],"valid",[],"NV8"],[[9720,9727],"valid",[],"NV8"],[[9728,9747],"valid",[],"NV8"],[[9748,9749],"valid",[],"NV8"],[[9750,9751],"valid",[],"NV8"],[[9752,9752],"valid",[],"NV8"],[[9753,9753],"valid",[],"NV8"],[[9754,9839],"valid",[],"NV8"],[[9840,9841],"valid",[],"NV8"],[[9842,9853],"valid",[],"NV8"],[[9854,9855],"valid",[],"NV8"],[[9856,9865],"valid",[],"NV8"],[[9866,9873],"valid",[],"NV8"],[[9874,9884],"valid",[],"NV8"],[[9885,9885],"valid",[],"NV8"],[[9886,9887],"valid",[],"NV8"],[[9888,9889],"valid",[],"NV8"],[[9890,9905],"valid",[],"NV8"],[[9906,9906],"valid",[],"NV8"],[[9907,9916],"valid",[],"NV8"],[[9917,9919],"valid",[],"NV8"],[[9920,9923],"valid",[],"NV8"],[[9924,9933],"valid",[],"NV8"],[[9934,9934],"valid",[],"NV8"],[[9935,9953],"valid",[],"NV8"],[[9954,9954],"valid",[],"NV8"],[[9955,9955],"valid",[],"NV8"],[[9956,9959],"valid",[],"NV8"],[[9960,9983],"valid",[],"NV8"],[[9984,9984],"valid",[],"NV8"],[[9985,9988],"valid",[],"NV8"],[[9989,9989],"valid",[],"NV8"],[[9990,9993],"valid",[],"NV8"],[[9994,9995],"valid",[],"NV8"],[[9996,10023],"valid",[],"NV8"],[[10024,10024],"valid",[],"NV8"],[[10025,10059],"valid",[],"NV8"],[[10060,10060],"valid",[],"NV8"],[[10061,10061],"valid",[],"NV8"],[[10062,10062],"valid",[],"NV8"],[[10063,10066],"valid",[],"NV8"],[[10067,10069],"valid",[],"NV8"],[[10070,10070],"valid",[],"NV8"],[[10071,10071],"valid",[],"NV8"],[[10072,10078],"valid",[],"NV8"],[[10079,10080],"valid",[],"NV8"],[[10081,10087],"valid",[],"NV8"],[[10088,10101],"valid",[],"NV8"],[[10102,10132],"valid",[],"NV8"],[[10133,10135],"valid",[],"NV8"],[[10136,10159],"valid",[],"NV8"],[[10160,10160],"valid",[],"NV8"],[[10161,10174],"valid",[],"NV8"],[[10175,10175],"valid",[],"NV8"],[[10176,10182],"valid",[],"NV8"],[[10183,10186],"valid",[],"NV8"],[[10187,10187],"valid",[],"NV8"],[[10188,10188],"valid",[],"NV8"],[[10189,10189],"valid",[],"NV8"],[[10190,10191],"valid",[],"NV8"],[[10192,10219],"valid",[],"NV8"],[[10220,10223],"valid",[],"NV8"],[[10224,10239],"valid",[],"NV8"],[[10240,10495],"valid",[],"NV8"],[[10496,10763],"valid",[],"NV8"],[[10764,10764],"mapped",[8747,8747,8747,8747]],[[10765,10867],"valid",[],"NV8"],[[10868,10868],"disallowed_STD3_mapped",[58,58,61]],[[10869,10869],"disallowed_STD3_mapped",[61,61]],[[10870,10870],"disallowed_STD3_mapped",[61,61,61]],[[10871,10971],"valid",[],"NV8"],[[10972,10972],"mapped",[10973,824]],[[10973,11007],"valid",[],"NV8"],[[11008,11021],"valid",[],"NV8"],[[11022,11027],"valid",[],"NV8"],[[11028,11034],"valid",[],"NV8"],[[11035,11039],"valid",[],"NV8"],[[11040,11043],"valid",[],"NV8"],[[11044,11084],"valid",[],"NV8"],[[11085,11087],"valid",[],"NV8"],[[11088,11092],"valid",[],"NV8"],[[11093,11097],"valid",[],"NV8"],[[11098,11123],"valid",[],"NV8"],[[11124,11125],"disallowed"],[[11126,11157],"valid",[],"NV8"],[[11158,11159],"disallowed"],[[11160,11193],"valid",[],"NV8"],[[11194,11196],"disallowed"],[[11197,11208],"valid",[],"NV8"],[[11209,11209],"disallowed"],[[11210,11217],"valid",[],"NV8"],[[11218,11243],"disallowed"],[[11244,11247],"valid",[],"NV8"],[[11248,11263],"disallowed"],[[11264,11264],"mapped",[11312]],[[11265,11265],"mapped",[11313]],[[11266,11266],"mapped",[11314]],[[11267,11267],"mapped",[11315]],[[11268,11268],"mapped",[11316]],[[11269,11269],"mapped",[11317]],[[11270,11270],"mapped",[11318]],[[11271,11271],"mapped",[11319]],[[11272,11272],"mapped",[11320]],[[11273,11273],"mapped",[11321]],[[11274,11274],"mapped",[11322]],[[11275,11275],"mapped",[11323]],[[11276,11276],"mapped",[11324]],[[11277,11277],"mapped",[11325]],[[11278,11278],"mapped",[11326]],[[11279,11279],"mapped",[11327]],[[11280,11280],"mapped",[11328]],[[11281,11281],"mapped",[11329]],[[11282,11282],"mapped",[11330]],[[11283,11283],"mapped",[11331]],[[11284,11284],"mapped",[11332]],[[11285,11285],"mapped",[11333]],[[11286,11286],"mapped",[11334]],[[11287,11287],"mapped",[11335]],[[11288,11288],"mapped",[11336]],[[11289,11289],"mapped",[11337]],[[11290,11290],"mapped",[11338]],[[11291,11291],"mapped",[11339]],[[11292,11292],"mapped",[11340]],[[11293,11293],"mapped",[11341]],[[11294,11294],"mapped",[11342]],[[11295,11295],"mapped",[11343]],[[11296,11296],"mapped",[11344]],[[11297,11297],"mapped",[11345]],[[11298,11298],"mapped",[11346]],[[11299,11299],"mapped",[11347]],[[11300,11300],"mapped",[11348]],[[11301,11301],"mapped",[11349]],[[11302,11302],"mapped",[11350]],[[11303,11303],"mapped",[11351]],[[11304,11304],"mapped",[11352]],[[11305,11305],"mapped",[11353]],[[11306,11306],"mapped",[11354]],[[11307,11307],"mapped",[11355]],[[11308,11308],"mapped",[11356]],[[11309,11309],"mapped",[11357]],[[11310,11310],"mapped",[11358]],[[11311,11311],"disallowed"],[[11312,11358],"valid"],[[11359,11359],"disallowed"],[[11360,11360],"mapped",[11361]],[[11361,11361],"valid"],[[11362,11362],"mapped",[619]],[[11363,11363],"mapped",[7549]],[[11364,11364],"mapped",[637]],[[11365,11366],"valid"],[[11367,11367],"mapped",[11368]],[[11368,11368],"valid"],[[11369,11369],"mapped",[11370]],[[11370,11370],"valid"],[[11371,11371],"mapped",[11372]],[[11372,11372],"valid"],[[11373,11373],"mapped",[593]],[[11374,11374],"mapped",[625]],[[11375,11375],"mapped",[592]],[[11376,11376],"mapped",[594]],[[11377,11377],"valid"],[[11378,11378],"mapped",[11379]],[[11379,11379],"valid"],[[11380,11380],"valid"],[[11381,11381],"mapped",[11382]],[[11382,11383],"valid"],[[11384,11387],"valid"],[[11388,11388],"mapped",[106]],[[11389,11389],"mapped",[118]],[[11390,11390],"mapped",[575]],[[11391,11391],"mapped",[576]],[[11392,11392],"mapped",[11393]],[[11393,11393],"valid"],[[11394,11394],"mapped",[11395]],[[11395,11395],"valid"],[[11396,11396],"mapped",[11397]],[[11397,11397],"valid"],[[11398,11398],"mapped",[11399]],[[11399,11399],"valid"],[[11400,11400],"mapped",[11401]],[[11401,11401],"valid"],[[11402,11402],"mapped",[11403]],[[11403,11403],"valid"],[[11404,11404],"mapped",[11405]],[[11405,11405],"valid"],[[11406,11406],"mapped",[11407]],[[11407,11407],"valid"],[[11408,11408],"mapped",[11409]],[[11409,11409],"valid"],[[11410,11410],"mapped",[11411]],[[11411,11411],"valid"],[[11412,11412],"mapped",[11413]],[[11413,11413],"valid"],[[11414,11414],"mapped",[11415]],[[11415,11415],"valid"],[[11416,11416],"mapped",[11417]],[[11417,11417],"valid"],[[11418,11418],"mapped",[11419]],[[11419,11419],"valid"],[[11420,11420],"mapped",[11421]],[[11421,11421],"valid"],[[11422,11422],"mapped",[11423]],[[11423,11423],"valid"],[[11424,11424],"mapped",[11425]],[[11425,11425],"valid"],[[11426,11426],"mapped",[11427]],[[11427,11427],"valid"],[[11428,11428],"mapped",[11429]],[[11429,11429],"valid"],[[11430,11430],"mapped",[11431]],[[11431,11431],"valid"],[[11432,11432],"mapped",[11433]],[[11433,11433],"valid"],[[11434,11434],"mapped",[11435]],[[11435,11435],"valid"],[[11436,11436],"mapped",[11437]],[[11437,11437],"valid"],[[11438,11438],"mapped",[11439]],[[11439,11439],"valid"],[[11440,11440],"mapped",[11441]],[[11441,11441],"valid"],[[11442,11442],"mapped",[11443]],[[11443,11443],"valid"],[[11444,11444],"mapped",[11445]],[[11445,11445],"valid"],[[11446,11446],"mapped",[11447]],[[11447,11447],"valid"],[[11448,11448],"mapped",[11449]],[[11449,11449],"valid"],[[11450,11450],"mapped",[11451]],[[11451,11451],"valid"],[[11452,11452],"mapped",[11453]],[[11453,11453],"valid"],[[11454,11454],"mapped",[11455]],[[11455,11455],"valid"],[[11456,11456],"mapped",[11457]],[[11457,11457],"valid"],[[11458,11458],"mapped",[11459]],[[11459,11459],"valid"],[[11460,11460],"mapped",[11461]],[[11461,11461],"valid"],[[11462,11462],"mapped",[11463]],[[11463,11463],"valid"],[[11464,11464],"mapped",[11465]],[[11465,11465],"valid"],[[11466,11466],"mapped",[11467]],[[11467,11467],"valid"],[[11468,11468],"mapped",[11469]],[[11469,11469],"valid"],[[11470,11470],"mapped",[11471]],[[11471,11471],"valid"],[[11472,11472],"mapped",[11473]],[[11473,11473],"valid"],[[11474,11474],"mapped",[11475]],[[11475,11475],"valid"],[[11476,11476],"mapped",[11477]],[[11477,11477],"valid"],[[11478,11478],"mapped",[11479]],[[11479,11479],"valid"],[[11480,11480],"mapped",[11481]],[[11481,11481],"valid"],[[11482,11482],"mapped",[11483]],[[11483,11483],"valid"],[[11484,11484],"mapped",[11485]],[[11485,11485],"valid"],[[11486,11486],"mapped",[11487]],[[11487,11487],"valid"],[[11488,11488],"mapped",[11489]],[[11489,11489],"valid"],[[11490,11490],"mapped",[11491]],[[11491,11492],"valid"],[[11493,11498],"valid",[],"NV8"],[[11499,11499],"mapped",[11500]],[[11500,11500],"valid"],[[11501,11501],"mapped",[11502]],[[11502,11505],"valid"],[[11506,11506],"mapped",[11507]],[[11507,11507],"valid"],[[11508,11512],"disallowed"],[[11513,11519],"valid",[],"NV8"],[[11520,11557],"valid"],[[11558,11558],"disallowed"],[[11559,11559],"valid"],[[11560,11564],"disallowed"],[[11565,11565],"valid"],[[11566,11567],"disallowed"],[[11568,11621],"valid"],[[11622,11623],"valid"],[[11624,11630],"disallowed"],[[11631,11631],"mapped",[11617]],[[11632,11632],"valid",[],"NV8"],[[11633,11646],"disallowed"],[[11647,11647],"valid"],[[11648,11670],"valid"],[[11671,11679],"disallowed"],[[11680,11686],"valid"],[[11687,11687],"disallowed"],[[11688,11694],"valid"],[[11695,11695],"disallowed"],[[11696,11702],"valid"],[[11703,11703],"disallowed"],[[11704,11710],"valid"],[[11711,11711],"disallowed"],[[11712,11718],"valid"],[[11719,11719],"disallowed"],[[11720,11726],"valid"],[[11727,11727],"disallowed"],[[11728,11734],"valid"],[[11735,11735],"disallowed"],[[11736,11742],"valid"],[[11743,11743],"disallowed"],[[11744,11775],"valid"],[[11776,11799],"valid",[],"NV8"],[[11800,11803],"valid",[],"NV8"],[[11804,11805],"valid",[],"NV8"],[[11806,11822],"valid",[],"NV8"],[[11823,11823],"valid"],[[11824,11824],"valid",[],"NV8"],[[11825,11825],"valid",[],"NV8"],[[11826,11835],"valid",[],"NV8"],[[11836,11842],"valid",[],"NV8"],[[11843,11903],"disallowed"],[[11904,11929],"valid",[],"NV8"],[[11930,11930],"disallowed"],[[11931,11934],"valid",[],"NV8"],[[11935,11935],"mapped",[27597]],[[11936,12018],"valid",[],"NV8"],[[12019,12019],"mapped",[40863]],[[12020,12031],"disallowed"],[[12032,12032],"mapped",[19968]],[[12033,12033],"mapped",[20008]],[[12034,12034],"mapped",[20022]],[[12035,12035],"mapped",[20031]],[[12036,12036],"mapped",[20057]],[[12037,12037],"mapped",[20101]],[[12038,12038],"mapped",[20108]],[[12039,12039],"mapped",[20128]],[[12040,12040],"mapped",[20154]],[[12041,12041],"mapped",[20799]],[[12042,12042],"mapped",[20837]],[[12043,12043],"mapped",[20843]],[[12044,12044],"mapped",[20866]],[[12045,12045],"mapped",[20886]],[[12046,12046],"mapped",[20907]],[[12047,12047],"mapped",[20960]],[[12048,12048],"mapped",[20981]],[[12049,12049],"mapped",[20992]],[[12050,12050],"mapped",[21147]],[[12051,12051],"mapped",[21241]],[[12052,12052],"mapped",[21269]],[[12053,12053],"mapped",[21274]],[[12054,12054],"mapped",[21304]],[[12055,12055],"mapped",[21313]],[[12056,12056],"mapped",[21340]],[[12057,12057],"mapped",[21353]],[[12058,12058],"mapped",[21378]],[[12059,12059],"mapped",[21430]],[[12060,12060],"mapped",[21448]],[[12061,12061],"mapped",[21475]],[[12062,12062],"mapped",[22231]],[[12063,12063],"mapped",[22303]],[[12064,12064],"mapped",[22763]],[[12065,12065],"mapped",[22786]],[[12066,12066],"mapped",[22794]],[[12067,12067],"mapped",[22805]],[[12068,12068],"mapped",[22823]],[[12069,12069],"mapped",[22899]],[[12070,12070],"mapped",[23376]],[[12071,12071],"mapped",[23424]],[[12072,12072],"mapped",[23544]],[[12073,12073],"mapped",[23567]],[[12074,12074],"mapped",[23586]],[[12075,12075],"mapped",[23608]],[[12076,12076],"mapped",[23662]],[[12077,12077],"mapped",[23665]],[[12078,12078],"mapped",[24027]],[[12079,12079],"mapped",[24037]],[[12080,12080],"mapped",[24049]],[[12081,12081],"mapped",[24062]],[[12082,12082],"mapped",[24178]],[[12083,12083],"mapped",[24186]],[[12084,12084],"mapped",[24191]],[[12085,12085],"mapped",[24308]],[[12086,12086],"mapped",[24318]],[[12087,12087],"mapped",[24331]],[[12088,12088],"mapped",[24339]],[[12089,12089],"mapped",[24400]],[[12090,12090],"mapped",[24417]],[[12091,12091],"mapped",[24435]],[[12092,12092],"mapped",[24515]],[[12093,12093],"mapped",[25096]],[[12094,12094],"mapped",[25142]],[[12095,12095],"mapped",[25163]],[[12096,12096],"mapped",[25903]],[[12097,12097],"mapped",[25908]],[[12098,12098],"mapped",[25991]],[[12099,12099],"mapped",[26007]],[[12100,12100],"mapped",[26020]],[[12101,12101],"mapped",[26041]],[[12102,12102],"mapped",[26080]],[[12103,12103],"mapped",[26085]],[[12104,12104],"mapped",[26352]],[[12105,12105],"mapped",[26376]],[[12106,12106],"mapped",[26408]],[[12107,12107],"mapped",[27424]],[[12108,12108],"mapped",[27490]],[[12109,12109],"mapped",[27513]],[[12110,12110],"mapped",[27571]],[[12111,12111],"mapped",[27595]],[[12112,12112],"mapped",[27604]],[[12113,12113],"mapped",[27611]],[[12114,12114],"mapped",[27663]],[[12115,12115],"mapped",[27668]],[[12116,12116],"mapped",[27700]],[[12117,12117],"mapped",[28779]],[[12118,12118],"mapped",[29226]],[[12119,12119],"mapped",[29238]],[[12120,12120],"mapped",[29243]],[[12121,12121],"mapped",[29247]],[[12122,12122],"mapped",[29255]],[[12123,12123],"mapped",[29273]],[[12124,12124],"mapped",[29275]],[[12125,12125],"mapped",[29356]],[[12126,12126],"mapped",[29572]],[[12127,12127],"mapped",[29577]],[[12128,12128],"mapped",[29916]],[[12129,12129],"mapped",[29926]],[[12130,12130],"mapped",[29976]],[[12131,12131],"mapped",[29983]],[[12132,12132],"mapped",[29992]],[[12133,12133],"mapped",[30000]],[[12134,12134],"mapped",[30091]],[[12135,12135],"mapped",[30098]],[[12136,12136],"mapped",[30326]],[[12137,12137],"mapped",[30333]],[[12138,12138],"mapped",[30382]],[[12139,12139],"mapped",[30399]],[[12140,12140],"mapped",[30446]],[[12141,12141],"mapped",[30683]],[[12142,12142],"mapped",[30690]],[[12143,12143],"mapped",[30707]],[[12144,12144],"mapped",[31034]],[[12145,12145],"mapped",[31160]],[[12146,12146],"mapped",[31166]],[[12147,12147],"mapped",[31348]],[[12148,12148],"mapped",[31435]],[[12149,12149],"mapped",[31481]],[[12150,12150],"mapped",[31859]],[[12151,12151],"mapped",[31992]],[[12152,12152],"mapped",[32566]],[[12153,12153],"mapped",[32593]],[[12154,12154],"mapped",[32650]],[[12155,12155],"mapped",[32701]],[[12156,12156],"mapped",[32769]],[[12157,12157],"mapped",[32780]],[[12158,12158],"mapped",[32786]],[[12159,12159],"mapped",[32819]],[[12160,12160],"mapped",[32895]],[[12161,12161],"mapped",[32905]],[[12162,12162],"mapped",[33251]],[[12163,12163],"mapped",[33258]],[[12164,12164],"mapped",[33267]],[[12165,12165],"mapped",[33276]],[[12166,12166],"mapped",[33292]],[[12167,12167],"mapped",[33307]],[[12168,12168],"mapped",[33311]],[[12169,12169],"mapped",[33390]],[[12170,12170],"mapped",[33394]],[[12171,12171],"mapped",[33400]],[[12172,12172],"mapped",[34381]],[[12173,12173],"mapped",[34411]],[[12174,12174],"mapped",[34880]],[[12175,12175],"mapped",[34892]],[[12176,12176],"mapped",[34915]],[[12177,12177],"mapped",[35198]],[[12178,12178],"mapped",[35211]],[[12179,12179],"mapped",[35282]],[[12180,12180],"mapped",[35328]],[[12181,12181],"mapped",[35895]],[[12182,12182],"mapped",[35910]],[[12183,12183],"mapped",[35925]],[[12184,12184],"mapped",[35960]],[[12185,12185],"mapped",[35997]],[[12186,12186],"mapped",[36196]],[[12187,12187],"mapped",[36208]],[[12188,12188],"mapped",[36275]],[[12189,12189],"mapped",[36523]],[[12190,12190],"mapped",[36554]],[[12191,12191],"mapped",[36763]],[[12192,12192],"mapped",[36784]],[[12193,12193],"mapped",[36789]],[[12194,12194],"mapped",[37009]],[[12195,12195],"mapped",[37193]],[[12196,12196],"mapped",[37318]],[[12197,12197],"mapped",[37324]],[[12198,12198],"mapped",[37329]],[[12199,12199],"mapped",[38263]],[[12200,12200],"mapped",[38272]],[[12201,12201],"mapped",[38428]],[[12202,12202],"mapped",[38582]],[[12203,12203],"mapped",[38585]],[[12204,12204],"mapped",[38632]],[[12205,12205],"mapped",[38737]],[[12206,12206],"mapped",[38750]],[[12207,12207],"mapped",[38754]],[[12208,12208],"mapped",[38761]],[[12209,12209],"mapped",[38859]],[[12210,12210],"mapped",[38893]],[[12211,12211],"mapped",[38899]],[[12212,12212],"mapped",[38913]],[[12213,12213],"mapped",[39080]],[[12214,12214],"mapped",[39131]],[[12215,12215],"mapped",[39135]],[[12216,12216],"mapped",[39318]],[[12217,12217],"mapped",[39321]],[[12218,12218],"mapped",[39340]],[[12219,12219],"mapped",[39592]],[[12220,12220],"mapped",[39640]],[[12221,12221],"mapped",[39647]],[[12222,12222],"mapped",[39717]],[[12223,12223],"mapped",[39727]],[[12224,12224],"mapped",[39730]],[[12225,12225],"mapped",[39740]],[[12226,12226],"mapped",[39770]],[[12227,12227],"mapped",[40165]],[[12228,12228],"mapped",[40565]],[[12229,12229],"mapped",[40575]],[[12230,12230],"mapped",[40613]],[[12231,12231],"mapped",[40635]],[[12232,12232],"mapped",[40643]],[[12233,12233],"mapped",[40653]],[[12234,12234],"mapped",[40657]],[[12235,12235],"mapped",[40697]],[[12236,12236],"mapped",[40701]],[[12237,12237],"mapped",[40718]],[[12238,12238],"mapped",[40723]],[[12239,12239],"mapped",[40736]],[[12240,12240],"mapped",[40763]],[[12241,12241],"mapped",[40778]],[[12242,12242],"mapped",[40786]],[[12243,12243],"mapped",[40845]],[[12244,12244],"mapped",[40860]],[[12245,12245],"mapped",[40864]],[[12246,12271],"disallowed"],[[12272,12283],"disallowed"],[[12284,12287],"disallowed"],[[12288,12288],"disallowed_STD3_mapped",[32]],[[12289,12289],"valid",[],"NV8"],[[12290,12290],"mapped",[46]],[[12291,12292],"valid",[],"NV8"],[[12293,12295],"valid"],[[12296,12329],"valid",[],"NV8"],[[12330,12333],"valid"],[[12334,12341],"valid",[],"NV8"],[[12342,12342],"mapped",[12306]],[[12343,12343],"valid",[],"NV8"],[[12344,12344],"mapped",[21313]],[[12345,12345],"mapped",[21316]],[[12346,12346],"mapped",[21317]],[[12347,12347],"valid",[],"NV8"],[[12348,12348],"valid"],[[12349,12349],"valid",[],"NV8"],[[12350,12350],"valid",[],"NV8"],[[12351,12351],"valid",[],"NV8"],[[12352,12352],"disallowed"],[[12353,12436],"valid"],[[12437,12438],"valid"],[[12439,12440],"disallowed"],[[12441,12442],"valid"],[[12443,12443],"disallowed_STD3_mapped",[32,12441]],[[12444,12444],"disallowed_STD3_mapped",[32,12442]],[[12445,12446],"valid"],[[12447,12447],"mapped",[12424,12426]],[[12448,12448],"valid",[],"NV8"],[[12449,12542],"valid"],[[12543,12543],"mapped",[12467,12488]],[[12544,12548],"disallowed"],[[12549,12588],"valid"],[[12589,12589],"valid"],[[12590,12592],"disallowed"],[[12593,12593],"mapped",[4352]],[[12594,12594],"mapped",[4353]],[[12595,12595],"mapped",[4522]],[[12596,12596],"mapped",[4354]],[[12597,12597],"mapped",[4524]],[[12598,12598],"mapped",[4525]],[[12599,12599],"mapped",[4355]],[[12600,12600],"mapped",[4356]],[[12601,12601],"mapped",[4357]],[[12602,12602],"mapped",[4528]],[[12603,12603],"mapped",[4529]],[[12604,12604],"mapped",[4530]],[[12605,12605],"mapped",[4531]],[[12606,12606],"mapped",[4532]],[[12607,12607],"mapped",[4533]],[[12608,12608],"mapped",[4378]],[[12609,12609],"mapped",[4358]],[[12610,12610],"mapped",[4359]],[[12611,12611],"mapped",[4360]],[[12612,12612],"mapped",[4385]],[[12613,12613],"mapped",[4361]],[[12614,12614],"mapped",[4362]],[[12615,12615],"mapped",[4363]],[[12616,12616],"mapped",[4364]],[[12617,12617],"mapped",[4365]],[[12618,12618],"mapped",[4366]],[[12619,12619],"mapped",[4367]],[[12620,12620],"mapped",[4368]],[[12621,12621],"mapped",[4369]],[[12622,12622],"mapped",[4370]],[[12623,12623],"mapped",[4449]],[[12624,12624],"mapped",[4450]],[[12625,12625],"mapped",[4451]],[[12626,12626],"mapped",[4452]],[[12627,12627],"mapped",[4453]],[[12628,12628],"mapped",[4454]],[[12629,12629],"mapped",[4455]],[[12630,12630],"mapped",[4456]],[[12631,12631],"mapped",[4457]],[[12632,12632],"mapped",[4458]],[[12633,12633],"mapped",[4459]],[[12634,12634],"mapped",[4460]],[[12635,12635],"mapped",[4461]],[[12636,12636],"mapped",[4462]],[[12637,12637],"mapped",[4463]],[[12638,12638],"mapped",[4464]],[[12639,12639],"mapped",[4465]],[[12640,12640],"mapped",[4466]],[[12641,12641],"mapped",[4467]],[[12642,12642],"mapped",[4468]],[[12643,12643],"mapped",[4469]],[[12644,12644],"disallowed"],[[12645,12645],"mapped",[4372]],[[12646,12646],"mapped",[4373]],[[12647,12647],"mapped",[4551]],[[12648,12648],"mapped",[4552]],[[12649,12649],"mapped",[4556]],[[12650,12650],"mapped",[4558]],[[12651,12651],"mapped",[4563]],[[12652,12652],"mapped",[4567]],[[12653,12653],"mapped",[4569]],[[12654,12654],"mapped",[4380]],[[12655,12655],"mapped",[4573]],[[12656,12656],"mapped",[4575]],[[12657,12657],"mapped",[4381]],[[12658,12658],"mapped",[4382]],[[12659,12659],"mapped",[4384]],[[12660,12660],"mapped",[4386]],[[12661,12661],"mapped",[4387]],[[12662,12662],"mapped",[4391]],[[12663,12663],"mapped",[4393]],[[12664,12664],"mapped",[4395]],[[12665,12665],"mapped",[4396]],[[12666,12666],"mapped",[4397]],[[12667,12667],"mapped",[4398]],[[12668,12668],"mapped",[4399]],[[12669,12669],"mapped",[4402]],[[12670,12670],"mapped",[4406]],[[12671,12671],"mapped",[4416]],[[12672,12672],"mapped",[4423]],[[12673,12673],"mapped",[4428]],[[12674,12674],"mapped",[4593]],[[12675,12675],"mapped",[4594]],[[12676,12676],"mapped",[4439]],[[12677,12677],"mapped",[4440]],[[12678,12678],"mapped",[4441]],[[12679,12679],"mapped",[4484]],[[12680,12680],"mapped",[4485]],[[12681,12681],"mapped",[4488]],[[12682,12682],"mapped",[4497]],[[12683,12683],"mapped",[4498]],[[12684,12684],"mapped",[4500]],[[12685,12685],"mapped",[4510]],[[12686,12686],"mapped",[4513]],[[12687,12687],"disallowed"],[[12688,12689],"valid",[],"NV8"],[[12690,12690],"mapped",[19968]],[[12691,12691],"mapped",[20108]],[[12692,12692],"mapped",[19977]],[[12693,12693],"mapped",[22235]],[[12694,12694],"mapped",[19978]],[[12695,12695],"mapped",[20013]],[[12696,12696],"mapped",[19979]],[[12697,12697],"mapped",[30002]],[[12698,12698],"mapped",[20057]],[[12699,12699],"mapped",[19993]],[[12700,12700],"mapped",[19969]],[[12701,12701],"mapped",[22825]],[[12702,12702],"mapped",[22320]],[[12703,12703],"mapped",[20154]],[[12704,12727],"valid"],[[12728,12730],"valid"],[[12731,12735],"disallowed"],[[12736,12751],"valid",[],"NV8"],[[12752,12771],"valid",[],"NV8"],[[12772,12783],"disallowed"],[[12784,12799],"valid"],[[12800,12800],"disallowed_STD3_mapped",[40,4352,41]],[[12801,12801],"disallowed_STD3_mapped",[40,4354,41]],[[12802,12802],"disallowed_STD3_mapped",[40,4355,41]],[[12803,12803],"disallowed_STD3_mapped",[40,4357,41]],[[12804,12804],"disallowed_STD3_mapped",[40,4358,41]],[[12805,12805],"disallowed_STD3_mapped",[40,4359,41]],[[12806,12806],"disallowed_STD3_mapped",[40,4361,41]],[[12807,12807],"disallowed_STD3_mapped",[40,4363,41]],[[12808,12808],"disallowed_STD3_mapped",[40,4364,41]],[[12809,12809],"disallowed_STD3_mapped",[40,4366,41]],[[12810,12810],"disallowed_STD3_mapped",[40,4367,41]],[[12811,12811],"disallowed_STD3_mapped",[40,4368,41]],[[12812,12812],"disallowed_STD3_mapped",[40,4369,41]],[[12813,12813],"disallowed_STD3_mapped",[40,4370,41]],[[12814,12814],"disallowed_STD3_mapped",[40,44032,41]],[[12815,12815],"disallowed_STD3_mapped",[40,45208,41]],[[12816,12816],"disallowed_STD3_mapped",[40,45796,41]],[[12817,12817],"disallowed_STD3_mapped",[40,46972,41]],[[12818,12818],"disallowed_STD3_mapped",[40,47560,41]],[[12819,12819],"disallowed_STD3_mapped",[40,48148,41]],[[12820,12820],"disallowed_STD3_mapped",[40,49324,41]],[[12821,12821],"disallowed_STD3_mapped",[40,50500,41]],[[12822,12822],"disallowed_STD3_mapped",[40,51088,41]],[[12823,12823],"disallowed_STD3_mapped",[40,52264,41]],[[12824,12824],"disallowed_STD3_mapped",[40,52852,41]],[[12825,12825],"disallowed_STD3_mapped",[40,53440,41]],[[12826,12826],"disallowed_STD3_mapped",[40,54028,41]],[[12827,12827],"disallowed_STD3_mapped",[40,54616,41]],[[12828,12828],"disallowed_STD3_mapped",[40,51452,41]],[[12829,12829],"disallowed_STD3_mapped",[40,50724,51204,41]],[[12830,12830],"disallowed_STD3_mapped",[40,50724,54980,41]],[[12831,12831],"disallowed"],[[12832,12832],"disallowed_STD3_mapped",[40,19968,41]],[[12833,12833],"disallowed_STD3_mapped",[40,20108,41]],[[12834,12834],"disallowed_STD3_mapped",[40,19977,41]],[[12835,12835],"disallowed_STD3_mapped",[40,22235,41]],[[12836,12836],"disallowed_STD3_mapped",[40,20116,41]],[[12837,12837],"disallowed_STD3_mapped",[40,20845,41]],[[12838,12838],"disallowed_STD3_mapped",[40,19971,41]],[[12839,12839],"disallowed_STD3_mapped",[40,20843,41]],[[12840,12840],"disallowed_STD3_mapped",[40,20061,41]],[[12841,12841],"disallowed_STD3_mapped",[40,21313,41]],[[12842,12842],"disallowed_STD3_mapped",[40,26376,41]],[[12843,12843],"disallowed_STD3_mapped",[40,28779,41]],[[12844,12844],"disallowed_STD3_mapped",[40,27700,41]],[[12845,12845],"disallowed_STD3_mapped",[40,26408,41]],[[12846,12846],"disallowed_STD3_mapped",[40,37329,41]],[[12847,12847],"disallowed_STD3_mapped",[40,22303,41]],[[12848,12848],"disallowed_STD3_mapped",[40,26085,41]],[[12849,12849],"disallowed_STD3_mapped",[40,26666,41]],[[12850,12850],"disallowed_STD3_mapped",[40,26377,41]],[[12851,12851],"disallowed_STD3_mapped",[40,31038,41]],[[12852,12852],"disallowed_STD3_mapped",[40,21517,41]],[[12853,12853],"disallowed_STD3_mapped",[40,29305,41]],[[12854,12854],"disallowed_STD3_mapped",[40,36001,41]],[[12855,12855],"disallowed_STD3_mapped",[40,31069,41]],[[12856,12856],"disallowed_STD3_mapped",[40,21172,41]],[[12857,12857],"disallowed_STD3_mapped",[40,20195,41]],[[12858,12858],"disallowed_STD3_mapped",[40,21628,41]],[[12859,12859],"disallowed_STD3_mapped",[40,23398,41]],[[12860,12860],"disallowed_STD3_mapped",[40,30435,41]],[[12861,12861],"disallowed_STD3_mapped",[40,20225,41]],[[12862,12862],"disallowed_STD3_mapped",[40,36039,41]],[[12863,12863],"disallowed_STD3_mapped",[40,21332,41]],[[12864,12864],"disallowed_STD3_mapped",[40,31085,41]],[[12865,12865],"disallowed_STD3_mapped",[40,20241,41]],[[12866,12866],"disallowed_STD3_mapped",[40,33258,41]],[[12867,12867],"disallowed_STD3_mapped",[40,33267,41]],[[12868,12868],"mapped",[21839]],[[12869,12869],"mapped",[24188]],[[12870,12870],"mapped",[25991]],[[12871,12871],"mapped",[31631]],[[12872,12879],"valid",[],"NV8"],[[12880,12880],"mapped",[112,116,101]],[[12881,12881],"mapped",[50,49]],[[12882,12882],"mapped",[50,50]],[[12883,12883],"mapped",[50,51]],[[12884,12884],"mapped",[50,52]],[[12885,12885],"mapped",[50,53]],[[12886,12886],"mapped",[50,54]],[[12887,12887],"mapped",[50,55]],[[12888,12888],"mapped",[50,56]],[[12889,12889],"mapped",[50,57]],[[12890,12890],"mapped",[51,48]],[[12891,12891],"mapped",[51,49]],[[12892,12892],"mapped",[51,50]],[[12893,12893],"mapped",[51,51]],[[12894,12894],"mapped",[51,52]],[[12895,12895],"mapped",[51,53]],[[12896,12896],"mapped",[4352]],[[12897,12897],"mapped",[4354]],[[12898,12898],"mapped",[4355]],[[12899,12899],"mapped",[4357]],[[12900,12900],"mapped",[4358]],[[12901,12901],"mapped",[4359]],[[12902,12902],"mapped",[4361]],[[12903,12903],"mapped",[4363]],[[12904,12904],"mapped",[4364]],[[12905,12905],"mapped",[4366]],[[12906,12906],"mapped",[4367]],[[12907,12907],"mapped",[4368]],[[12908,12908],"mapped",[4369]],[[12909,12909],"mapped",[4370]],[[12910,12910],"mapped",[44032]],[[12911,12911],"mapped",[45208]],[[12912,12912],"mapped",[45796]],[[12913,12913],"mapped",[46972]],[[12914,12914],"mapped",[47560]],[[12915,12915],"mapped",[48148]],[[12916,12916],"mapped",[49324]],[[12917,12917],"mapped",[50500]],[[12918,12918],"mapped",[51088]],[[12919,12919],"mapped",[52264]],[[12920,12920],"mapped",[52852]],[[12921,12921],"mapped",[53440]],[[12922,12922],"mapped",[54028]],[[12923,12923],"mapped",[54616]],[[12924,12924],"mapped",[52280,44256]],[[12925,12925],"mapped",[51452,51032]],[[12926,12926],"mapped",[50864]],[[12927,12927],"valid",[],"NV8"],[[12928,12928],"mapped",[19968]],[[12929,12929],"mapped",[20108]],[[12930,12930],"mapped",[19977]],[[12931,12931],"mapped",[22235]],[[12932,12932],"mapped",[20116]],[[12933,12933],"mapped",[20845]],[[12934,12934],"mapped",[19971]],[[12935,12935],"mapped",[20843]],[[12936,12936],"mapped",[20061]],[[12937,12937],"mapped",[21313]],[[12938,12938],"mapped",[26376]],[[12939,12939],"mapped",[28779]],[[12940,12940],"mapped",[27700]],[[12941,12941],"mapped",[26408]],[[12942,12942],"mapped",[37329]],[[12943,12943],"mapped",[22303]],[[12944,12944],"mapped",[26085]],[[12945,12945],"mapped",[26666]],[[12946,12946],"mapped",[26377]],[[12947,12947],"mapped",[31038]],[[12948,12948],"mapped",[21517]],[[12949,12949],"mapped",[29305]],[[12950,12950],"mapped",[36001]],[[12951,12951],"mapped",[31069]],[[12952,12952],"mapped",[21172]],[[12953,12953],"mapped",[31192]],[[12954,12954],"mapped",[30007]],[[12955,12955],"mapped",[22899]],[[12956,12956],"mapped",[36969]],[[12957,12957],"mapped",[20778]],[[12958,12958],"mapped",[21360]],[[12959,12959],"mapped",[27880]],[[12960,12960],"mapped",[38917]],[[12961,12961],"mapped",[20241]],[[12962,12962],"mapped",[20889]],[[12963,12963],"mapped",[27491]],[[12964,12964],"mapped",[19978]],[[12965,12965],"mapped",[20013]],[[12966,12966],"mapped",[19979]],[[12967,12967],"mapped",[24038]],[[12968,12968],"mapped",[21491]],[[12969,12969],"mapped",[21307]],[[12970,12970],"mapped",[23447]],[[12971,12971],"mapped",[23398]],[[12972,12972],"mapped",[30435]],[[12973,12973],"mapped",[20225]],[[12974,12974],"mapped",[36039]],[[12975,12975],"mapped",[21332]],[[12976,12976],"mapped",[22812]],[[12977,12977],"mapped",[51,54]],[[12978,12978],"mapped",[51,55]],[[12979,12979],"mapped",[51,56]],[[12980,12980],"mapped",[51,57]],[[12981,12981],"mapped",[52,48]],[[12982,12982],"mapped",[52,49]],[[12983,12983],"mapped",[52,50]],[[12984,12984],"mapped",[52,51]],[[12985,12985],"mapped",[52,52]],[[12986,12986],"mapped",[52,53]],[[12987,12987],"mapped",[52,54]],[[12988,12988],"mapped",[52,55]],[[12989,12989],"mapped",[52,56]],[[12990,12990],"mapped",[52,57]],[[12991,12991],"mapped",[53,48]],[[12992,12992],"mapped",[49,26376]],[[12993,12993],"mapped",[50,26376]],[[12994,12994],"mapped",[51,26376]],[[12995,12995],"mapped",[52,26376]],[[12996,12996],"mapped",[53,26376]],[[12997,12997],"mapped",[54,26376]],[[12998,12998],"mapped",[55,26376]],[[12999,12999],"mapped",[56,26376]],[[13000,13000],"mapped",[57,26376]],[[13001,13001],"mapped",[49,48,26376]],[[13002,13002],"mapped",[49,49,26376]],[[13003,13003],"mapped",[49,50,26376]],[[13004,13004],"mapped",[104,103]],[[13005,13005],"mapped",[101,114,103]],[[13006,13006],"mapped",[101,118]],[[13007,13007],"mapped",[108,116,100]],[[13008,13008],"mapped",[12450]],[[13009,13009],"mapped",[12452]],[[13010,13010],"mapped",[12454]],[[13011,13011],"mapped",[12456]],[[13012,13012],"mapped",[12458]],[[13013,13013],"mapped",[12459]],[[13014,13014],"mapped",[12461]],[[13015,13015],"mapped",[12463]],[[13016,13016],"mapped",[12465]],[[13017,13017],"mapped",[12467]],[[13018,13018],"mapped",[12469]],[[13019,13019],"mapped",[12471]],[[13020,13020],"mapped",[12473]],[[13021,13021],"mapped",[12475]],[[13022,13022],"mapped",[12477]],[[13023,13023],"mapped",[12479]],[[13024,13024],"mapped",[12481]],[[13025,13025],"mapped",[12484]],[[13026,13026],"mapped",[12486]],[[13027,13027],"mapped",[12488]],[[13028,13028],"mapped",[12490]],[[13029,13029],"mapped",[12491]],[[13030,13030],"mapped",[12492]],[[13031,13031],"mapped",[12493]],[[13032,13032],"mapped",[12494]],[[13033,13033],"mapped",[12495]],[[13034,13034],"mapped",[12498]],[[13035,13035],"mapped",[12501]],[[13036,13036],"mapped",[12504]],[[13037,13037],"mapped",[12507]],[[13038,13038],"mapped",[12510]],[[13039,13039],"mapped",[12511]],[[13040,13040],"mapped",[12512]],[[13041,13041],"mapped",[12513]],[[13042,13042],"mapped",[12514]],[[13043,13043],"mapped",[12516]],[[13044,13044],"mapped",[12518]],[[13045,13045],"mapped",[12520]],[[13046,13046],"mapped",[12521]],[[13047,13047],"mapped",[12522]],[[13048,13048],"mapped",[12523]],[[13049,13049],"mapped",[12524]],[[13050,13050],"mapped",[12525]],[[13051,13051],"mapped",[12527]],[[13052,13052],"mapped",[12528]],[[13053,13053],"mapped",[12529]],[[13054,13054],"mapped",[12530]],[[13055,13055],"disallowed"],[[13056,13056],"mapped",[12450,12497,12540,12488]],[[13057,13057],"mapped",[12450,12523,12501,12449]],[[13058,13058],"mapped",[12450,12531,12506,12450]],[[13059,13059],"mapped",[12450,12540,12523]],[[13060,13060],"mapped",[12452,12491,12531,12464]],[[13061,13061],"mapped",[12452,12531,12481]],[[13062,13062],"mapped",[12454,12457,12531]],[[13063,13063],"mapped",[12456,12473,12463,12540,12489]],[[13064,13064],"mapped",[12456,12540,12459,12540]],[[13065,13065],"mapped",[12458,12531,12473]],[[13066,13066],"mapped",[12458,12540,12512]],[[13067,13067],"mapped",[12459,12452,12522]],[[13068,13068],"mapped",[12459,12521,12483,12488]],[[13069,13069],"mapped",[12459,12525,12522,12540]],[[13070,13070],"mapped",[12460,12525,12531]],[[13071,13071],"mapped",[12460,12531,12510]],[[13072,13072],"mapped",[12462,12460]],[[13073,13073],"mapped",[12462,12491,12540]],[[13074,13074],"mapped",[12461,12517,12522,12540]],[[13075,13075],"mapped",[12462,12523,12480,12540]],[[13076,13076],"mapped",[12461,12525]],[[13077,13077],"mapped",[12461,12525,12464,12521,12512]],[[13078,13078],"mapped",[12461,12525,12513,12540,12488,12523]],[[13079,13079],"mapped",[12461,12525,12527,12483,12488]],[[13080,13080],"mapped",[12464,12521,12512]],[[13081,13081],"mapped",[12464,12521,12512,12488,12531]],[[13082,13082],"mapped",[12463,12523,12476,12452,12525]],[[13083,13083],"mapped",[12463,12525,12540,12493]],[[13084,13084],"mapped",[12465,12540,12473]],[[13085,13085],"mapped",[12467,12523,12490]],[[13086,13086],"mapped",[12467,12540,12509]],[[13087,13087],"mapped",[12469,12452,12463,12523]],[[13088,13088],"mapped",[12469,12531,12481,12540,12512]],[[13089,13089],"mapped",[12471,12522,12531,12464]],[[13090,13090],"mapped",[12475,12531,12481]],[[13091,13091],"mapped",[12475,12531,12488]],[[13092,13092],"mapped",[12480,12540,12473]],[[13093,13093],"mapped",[12487,12471]],[[13094,13094],"mapped",[12489,12523]],[[13095,13095],"mapped",[12488,12531]],[[13096,13096],"mapped",[12490,12494]],[[13097,13097],"mapped",[12494,12483,12488]],[[13098,13098],"mapped",[12495,12452,12484]],[[13099,13099],"mapped",[12497,12540,12475,12531,12488]],[[13100,13100],"mapped",[12497,12540,12484]],[[13101,13101],"mapped",[12496,12540,12524,12523]],[[13102,13102],"mapped",[12500,12450,12473,12488,12523]],[[13103,13103],"mapped",[12500,12463,12523]],[[13104,13104],"mapped",[12500,12467]],[[13105,13105],"mapped",[12499,12523]],[[13106,13106],"mapped",[12501,12449,12521,12483,12489]],[[13107,13107],"mapped",[12501,12451,12540,12488]],[[13108,13108],"mapped",[12502,12483,12471,12455,12523]],[[13109,13109],"mapped",[12501,12521,12531]],[[13110,13110],"mapped",[12504,12463,12479,12540,12523]],[[13111,13111],"mapped",[12506,12477]],[[13112,13112],"mapped",[12506,12491,12498]],[[13113,13113],"mapped",[12504,12523,12484]],[[13114,13114],"mapped",[12506,12531,12473]],[[13115,13115],"mapped",[12506,12540,12472]],[[13116,13116],"mapped",[12505,12540,12479]],[[13117,13117],"mapped",[12509,12452,12531,12488]],[[13118,13118],"mapped",[12508,12523,12488]],[[13119,13119],"mapped",[12507,12531]],[[13120,13120],"mapped",[12509,12531,12489]],[[13121,13121],"mapped",[12507,12540,12523]],[[13122,13122],"mapped",[12507,12540,12531]],[[13123,13123],"mapped",[12510,12452,12463,12525]],[[13124,13124],"mapped",[12510,12452,12523]],[[13125,13125],"mapped",[12510,12483,12495]],[[13126,13126],"mapped",[12510,12523,12463]],[[13127,13127],"mapped",[12510,12531,12471,12519,12531]],[[13128,13128],"mapped",[12511,12463,12525,12531]],[[13129,13129],"mapped",[12511,12522]],[[13130,13130],"mapped",[12511,12522,12496,12540,12523]],[[13131,13131],"mapped",[12513,12460]],[[13132,13132],"mapped",[12513,12460,12488,12531]],[[13133,13133],"mapped",[12513,12540,12488,12523]],[[13134,13134],"mapped",[12516,12540,12489]],[[13135,13135],"mapped",[12516,12540,12523]],[[13136,13136],"mapped",[12518,12450,12531]],[[13137,13137],"mapped",[12522,12483,12488,12523]],[[13138,13138],"mapped",[12522,12521]],[[13139,13139],"mapped",[12523,12500,12540]],[[13140,13140],"mapped",[12523,12540,12502,12523]],[[13141,13141],"mapped",[12524,12512]],[[13142,13142],"mapped",[12524,12531,12488,12466,12531]],[[13143,13143],"mapped",[12527,12483,12488]],[[13144,13144],"mapped",[48,28857]],[[13145,13145],"mapped",[49,28857]],[[13146,13146],"mapped",[50,28857]],[[13147,13147],"mapped",[51,28857]],[[13148,13148],"mapped",[52,28857]],[[13149,13149],"mapped",[53,28857]],[[13150,13150],"mapped",[54,28857]],[[13151,13151],"mapped",[55,28857]],[[13152,13152],"mapped",[56,28857]],[[13153,13153],"mapped",[57,28857]],[[13154,13154],"mapped",[49,48,28857]],[[13155,13155],"mapped",[49,49,28857]],[[13156,13156],"mapped",[49,50,28857]],[[13157,13157],"mapped",[49,51,28857]],[[13158,13158],"mapped",[49,52,28857]],[[13159,13159],"mapped",[49,53,28857]],[[13160,13160],"mapped",[49,54,28857]],[[13161,13161],"mapped",[49,55,28857]],[[13162,13162],"mapped",[49,56,28857]],[[13163,13163],"mapped",[49,57,28857]],[[13164,13164],"mapped",[50,48,28857]],[[13165,13165],"mapped",[50,49,28857]],[[13166,13166],"mapped",[50,50,28857]],[[13167,13167],"mapped",[50,51,28857]],[[13168,13168],"mapped",[50,52,28857]],[[13169,13169],"mapped",[104,112,97]],[[13170,13170],"mapped",[100,97]],[[13171,13171],"mapped",[97,117]],[[13172,13172],"mapped",[98,97,114]],[[13173,13173],"mapped",[111,118]],[[13174,13174],"mapped",[112,99]],[[13175,13175],"mapped",[100,109]],[[13176,13176],"mapped",[100,109,50]],[[13177,13177],"mapped",[100,109,51]],[[13178,13178],"mapped",[105,117]],[[13179,13179],"mapped",[24179,25104]],[[13180,13180],"mapped",[26157,21644]],[[13181,13181],"mapped",[22823,27491]],[[13182,13182],"mapped",[26126,27835]],[[13183,13183],"mapped",[26666,24335,20250,31038]],[[13184,13184],"mapped",[112,97]],[[13185,13185],"mapped",[110,97]],[[13186,13186],"mapped",[956,97]],[[13187,13187],"mapped",[109,97]],[[13188,13188],"mapped",[107,97]],[[13189,13189],"mapped",[107,98]],[[13190,13190],"mapped",[109,98]],[[13191,13191],"mapped",[103,98]],[[13192,13192],"mapped",[99,97,108]],[[13193,13193],"mapped",[107,99,97,108]],[[13194,13194],"mapped",[112,102]],[[13195,13195],"mapped",[110,102]],[[13196,13196],"mapped",[956,102]],[[13197,13197],"mapped",[956,103]],[[13198,13198],"mapped",[109,103]],[[13199,13199],"mapped",[107,103]],[[13200,13200],"mapped",[104,122]],[[13201,13201],"mapped",[107,104,122]],[[13202,13202],"mapped",[109,104,122]],[[13203,13203],"mapped",[103,104,122]],[[13204,13204],"mapped",[116,104,122]],[[13205,13205],"mapped",[956,108]],[[13206,13206],"mapped",[109,108]],[[13207,13207],"mapped",[100,108]],[[13208,13208],"mapped",[107,108]],[[13209,13209],"mapped",[102,109]],[[13210,13210],"mapped",[110,109]],[[13211,13211],"mapped",[956,109]],[[13212,13212],"mapped",[109,109]],[[13213,13213],"mapped",[99,109]],[[13214,13214],"mapped",[107,109]],[[13215,13215],"mapped",[109,109,50]],[[13216,13216],"mapped",[99,109,50]],[[13217,13217],"mapped",[109,50]],[[13218,13218],"mapped",[107,109,50]],[[13219,13219],"mapped",[109,109,51]],[[13220,13220],"mapped",[99,109,51]],[[13221,13221],"mapped",[109,51]],[[13222,13222],"mapped",[107,109,51]],[[13223,13223],"mapped",[109,8725,115]],[[13224,13224],"mapped",[109,8725,115,50]],[[13225,13225],"mapped",[112,97]],[[13226,13226],"mapped",[107,112,97]],[[13227,13227],"mapped",[109,112,97]],[[13228,13228],"mapped",[103,112,97]],[[13229,13229],"mapped",[114,97,100]],[[13230,13230],"mapped",[114,97,100,8725,115]],[[13231,13231],"mapped",[114,97,100,8725,115,50]],[[13232,13232],"mapped",[112,115]],[[13233,13233],"mapped",[110,115]],[[13234,13234],"mapped",[956,115]],[[13235,13235],"mapped",[109,115]],[[13236,13236],"mapped",[112,118]],[[13237,13237],"mapped",[110,118]],[[13238,13238],"mapped",[956,118]],[[13239,13239],"mapped",[109,118]],[[13240,13240],"mapped",[107,118]],[[13241,13241],"mapped",[109,118]],[[13242,13242],"mapped",[112,119]],[[13243,13243],"mapped",[110,119]],[[13244,13244],"mapped",[956,119]],[[13245,13245],"mapped",[109,119]],[[13246,13246],"mapped",[107,119]],[[13247,13247],"mapped",[109,119]],[[13248,13248],"mapped",[107,969]],[[13249,13249],"mapped",[109,969]],[[13250,13250],"disallowed"],[[13251,13251],"mapped",[98,113]],[[13252,13252],"mapped",[99,99]],[[13253,13253],"mapped",[99,100]],[[13254,13254],"mapped",[99,8725,107,103]],[[13255,13255],"disallowed"],[[13256,13256],"mapped",[100,98]],[[13257,13257],"mapped",[103,121]],[[13258,13258],"mapped",[104,97]],[[13259,13259],"mapped",[104,112]],[[13260,13260],"mapped",[105,110]],[[13261,13261],"mapped",[107,107]],[[13262,13262],"mapped",[107,109]],[[13263,13263],"mapped",[107,116]],[[13264,13264],"mapped",[108,109]],[[13265,13265],"mapped",[108,110]],[[13266,13266],"mapped",[108,111,103]],[[13267,13267],"mapped",[108,120]],[[13268,13268],"mapped",[109,98]],[[13269,13269],"mapped",[109,105,108]],[[13270,13270],"mapped",[109,111,108]],[[13271,13271],"mapped",[112,104]],[[13272,13272],"disallowed"],[[13273,13273],"mapped",[112,112,109]],[[13274,13274],"mapped",[112,114]],[[13275,13275],"mapped",[115,114]],[[13276,13276],"mapped",[115,118]],[[13277,13277],"mapped",[119,98]],[[13278,13278],"mapped",[118,8725,109]],[[13279,13279],"mapped",[97,8725,109]],[[13280,13280],"mapped",[49,26085]],[[13281,13281],"mapped",[50,26085]],[[13282,13282],"mapped",[51,26085]],[[13283,13283],"mapped",[52,26085]],[[13284,13284],"mapped",[53,26085]],[[13285,13285],"mapped",[54,26085]],[[13286,13286],"mapped",[55,26085]],[[13287,13287],"mapped",[56,26085]],[[13288,13288],"mapped",[57,26085]],[[13289,13289],"mapped",[49,48,26085]],[[13290,13290],"mapped",[49,49,26085]],[[13291,13291],"mapped",[49,50,26085]],[[13292,13292],"mapped",[49,51,26085]],[[13293,13293],"mapped",[49,52,26085]],[[13294,13294],"mapped",[49,53,26085]],[[13295,13295],"mapped",[49,54,26085]],[[13296,13296],"mapped",[49,55,26085]],[[13297,13297],"mapped",[49,56,26085]],[[13298,13298],"mapped",[49,57,26085]],[[13299,13299],"mapped",[50,48,26085]],[[13300,13300],"mapped",[50,49,26085]],[[13301,13301],"mapped",[50,50,26085]],[[13302,13302],"mapped",[50,51,26085]],[[13303,13303],"mapped",[50,52,26085]],[[13304,13304],"mapped",[50,53,26085]],[[13305,13305],"mapped",[50,54,26085]],[[13306,13306],"mapped",[50,55,26085]],[[13307,13307],"mapped",[50,56,26085]],[[13308,13308],"mapped",[50,57,26085]],[[13309,13309],"mapped",[51,48,26085]],[[13310,13310],"mapped",[51,49,26085]],[[13311,13311],"mapped",[103,97,108]],[[13312,19893],"valid"],[[19894,19903],"disallowed"],[[19904,19967],"valid",[],"NV8"],[[19968,40869],"valid"],[[40870,40891],"valid"],[[40892,40899],"valid"],[[40900,40907],"valid"],[[40908,40908],"valid"],[[40909,40917],"valid"],[[40918,40959],"disallowed"],[[40960,42124],"valid"],[[42125,42127],"disallowed"],[[42128,42145],"valid",[],"NV8"],[[42146,42147],"valid",[],"NV8"],[[42148,42163],"valid",[],"NV8"],[[42164,42164],"valid",[],"NV8"],[[42165,42176],"valid",[],"NV8"],[[42177,42177],"valid",[],"NV8"],[[42178,42180],"valid",[],"NV8"],[[42181,42181],"valid",[],"NV8"],[[42182,42182],"valid",[],"NV8"],[[42183,42191],"disallowed"],[[42192,42237],"valid"],[[42238,42239],"valid",[],"NV8"],[[42240,42508],"valid"],[[42509,42511],"valid",[],"NV8"],[[42512,42539],"valid"],[[42540,42559],"disallowed"],[[42560,42560],"mapped",[42561]],[[42561,42561],"valid"],[[42562,42562],"mapped",[42563]],[[42563,42563],"valid"],[[42564,42564],"mapped",[42565]],[[42565,42565],"valid"],[[42566,42566],"mapped",[42567]],[[42567,42567],"valid"],[[42568,42568],"mapped",[42569]],[[42569,42569],"valid"],[[42570,42570],"mapped",[42571]],[[42571,42571],"valid"],[[42572,42572],"mapped",[42573]],[[42573,42573],"valid"],[[42574,42574],"mapped",[42575]],[[42575,42575],"valid"],[[42576,42576],"mapped",[42577]],[[42577,42577],"valid"],[[42578,42578],"mapped",[42579]],[[42579,42579],"valid"],[[42580,42580],"mapped",[42581]],[[42581,42581],"valid"],[[42582,42582],"mapped",[42583]],[[42583,42583],"valid"],[[42584,42584],"mapped",[42585]],[[42585,42585],"valid"],[[42586,42586],"mapped",[42587]],[[42587,42587],"valid"],[[42588,42588],"mapped",[42589]],[[42589,42589],"valid"],[[42590,42590],"mapped",[42591]],[[42591,42591],"valid"],[[42592,42592],"mapped",[42593]],[[42593,42593],"valid"],[[42594,42594],"mapped",[42595]],[[42595,42595],"valid"],[[42596,42596],"mapped",[42597]],[[42597,42597],"valid"],[[42598,42598],"mapped",[42599]],[[42599,42599],"valid"],[[42600,42600],"mapped",[42601]],[[42601,42601],"valid"],[[42602,42602],"mapped",[42603]],[[42603,42603],"valid"],[[42604,42604],"mapped",[42605]],[[42605,42607],"valid"],[[42608,42611],"valid",[],"NV8"],[[42612,42619],"valid"],[[42620,42621],"valid"],[[42622,42622],"valid",[],"NV8"],[[42623,42623],"valid"],[[42624,42624],"mapped",[42625]],[[42625,42625],"valid"],[[42626,42626],"mapped",[42627]],[[42627,42627],"valid"],[[42628,42628],"mapped",[42629]],[[42629,42629],"valid"],[[42630,42630],"mapped",[42631]],[[42631,42631],"valid"],[[42632,42632],"mapped",[42633]],[[42633,42633],"valid"],[[42634,42634],"mapped",[42635]],[[42635,42635],"valid"],[[42636,42636],"mapped",[42637]],[[42637,42637],"valid"],[[42638,42638],"mapped",[42639]],[[42639,42639],"valid"],[[42640,42640],"mapped",[42641]],[[42641,42641],"valid"],[[42642,42642],"mapped",[42643]],[[42643,42643],"valid"],[[42644,42644],"mapped",[42645]],[[42645,42645],"valid"],[[42646,42646],"mapped",[42647]],[[42647,42647],"valid"],[[42648,42648],"mapped",[42649]],[[42649,42649],"valid"],[[42650,42650],"mapped",[42651]],[[42651,42651],"valid"],[[42652,42652],"mapped",[1098]],[[42653,42653],"mapped",[1100]],[[42654,42654],"valid"],[[42655,42655],"valid"],[[42656,42725],"valid"],[[42726,42735],"valid",[],"NV8"],[[42736,42737],"valid"],[[42738,42743],"valid",[],"NV8"],[[42744,42751],"disallowed"],[[42752,42774],"valid",[],"NV8"],[[42775,42778],"valid"],[[42779,42783],"valid"],[[42784,42785],"valid",[],"NV8"],[[42786,42786],"mapped",[42787]],[[42787,42787],"valid"],[[42788,42788],"mapped",[42789]],[[42789,42789],"valid"],[[42790,42790],"mapped",[42791]],[[42791,42791],"valid"],[[42792,42792],"mapped",[42793]],[[42793,42793],"valid"],[[42794,42794],"mapped",[42795]],[[42795,42795],"valid"],[[42796,42796],"mapped",[42797]],[[42797,42797],"valid"],[[42798,42798],"mapped",[42799]],[[42799,42801],"valid"],[[42802,42802],"mapped",[42803]],[[42803,42803],"valid"],[[42804,42804],"mapped",[42805]],[[42805,42805],"valid"],[[42806,42806],"mapped",[42807]],[[42807,42807],"valid"],[[42808,42808],"mapped",[42809]],[[42809,42809],"valid"],[[42810,42810],"mapped",[42811]],[[42811,42811],"valid"],[[42812,42812],"mapped",[42813]],[[42813,42813],"valid"],[[42814,42814],"mapped",[42815]],[[42815,42815],"valid"],[[42816,42816],"mapped",[42817]],[[42817,42817],"valid"],[[42818,42818],"mapped",[42819]],[[42819,42819],"valid"],[[42820,42820],"mapped",[42821]],[[42821,42821],"valid"],[[42822,42822],"mapped",[42823]],[[42823,42823],"valid"],[[42824,42824],"mapped",[42825]],[[42825,42825],"valid"],[[42826,42826],"mapped",[42827]],[[42827,42827],"valid"],[[42828,42828],"mapped",[42829]],[[42829,42829],"valid"],[[42830,42830],"mapped",[42831]],[[42831,42831],"valid"],[[42832,42832],"mapped",[42833]],[[42833,42833],"valid"],[[42834,42834],"mapped",[42835]],[[42835,42835],"valid"],[[42836,42836],"mapped",[42837]],[[42837,42837],"valid"],[[42838,42838],"mapped",[42839]],[[42839,42839],"valid"],[[42840,42840],"mapped",[42841]],[[42841,42841],"valid"],[[42842,42842],"mapped",[42843]],[[42843,42843],"valid"],[[42844,42844],"mapped",[42845]],[[42845,42845],"valid"],[[42846,42846],"mapped",[42847]],[[42847,42847],"valid"],[[42848,42848],"mapped",[42849]],[[42849,42849],"valid"],[[42850,42850],"mapped",[42851]],[[42851,42851],"valid"],[[42852,42852],"mapped",[42853]],[[42853,42853],"valid"],[[42854,42854],"mapped",[42855]],[[42855,42855],"valid"],[[42856,42856],"mapped",[42857]],[[42857,42857],"valid"],[[42858,42858],"mapped",[42859]],[[42859,42859],"valid"],[[42860,42860],"mapped",[42861]],[[42861,42861],"valid"],[[42862,42862],"mapped",[42863]],[[42863,42863],"valid"],[[42864,42864],"mapped",[42863]],[[42865,42872],"valid"],[[42873,42873],"mapped",[42874]],[[42874,42874],"valid"],[[42875,42875],"mapped",[42876]],[[42876,42876],"valid"],[[42877,42877],"mapped",[7545]],[[42878,42878],"mapped",[42879]],[[42879,42879],"valid"],[[42880,42880],"mapped",[42881]],[[42881,42881],"valid"],[[42882,42882],"mapped",[42883]],[[42883,42883],"valid"],[[42884,42884],"mapped",[42885]],[[42885,42885],"valid"],[[42886,42886],"mapped",[42887]],[[42887,42888],"valid"],[[42889,42890],"valid",[],"NV8"],[[42891,42891],"mapped",[42892]],[[42892,42892],"valid"],[[42893,42893],"mapped",[613]],[[42894,42894],"valid"],[[42895,42895],"valid"],[[42896,42896],"mapped",[42897]],[[42897,42897],"valid"],[[42898,42898],"mapped",[42899]],[[42899,42899],"valid"],[[42900,42901],"valid"],[[42902,42902],"mapped",[42903]],[[42903,42903],"valid"],[[42904,42904],"mapped",[42905]],[[42905,42905],"valid"],[[42906,42906],"mapped",[42907]],[[42907,42907],"valid"],[[42908,42908],"mapped",[42909]],[[42909,42909],"valid"],[[42910,42910],"mapped",[42911]],[[42911,42911],"valid"],[[42912,42912],"mapped",[42913]],[[42913,42913],"valid"],[[42914,42914],"mapped",[42915]],[[42915,42915],"valid"],[[42916,42916],"mapped",[42917]],[[42917,42917],"valid"],[[42918,42918],"mapped",[42919]],[[42919,42919],"valid"],[[42920,42920],"mapped",[42921]],[[42921,42921],"valid"],[[42922,42922],"mapped",[614]],[[42923,42923],"mapped",[604]],[[42924,42924],"mapped",[609]],[[42925,42925],"mapped",[620]],[[42926,42927],"disallowed"],[[42928,42928],"mapped",[670]],[[42929,42929],"mapped",[647]],[[42930,42930],"mapped",[669]],[[42931,42931],"mapped",[43859]],[[42932,42932],"mapped",[42933]],[[42933,42933],"valid"],[[42934,42934],"mapped",[42935]],[[42935,42935],"valid"],[[42936,42998],"disallowed"],[[42999,42999],"valid"],[[43000,43000],"mapped",[295]],[[43001,43001],"mapped",[339]],[[43002,43002],"valid"],[[43003,43007],"valid"],[[43008,43047],"valid"],[[43048,43051],"valid",[],"NV8"],[[43052,43055],"disallowed"],[[43056,43065],"valid",[],"NV8"],[[43066,43071],"disallowed"],[[43072,43123],"valid"],[[43124,43127],"valid",[],"NV8"],[[43128,43135],"disallowed"],[[43136,43204],"valid"],[[43205,43213],"disallowed"],[[43214,43215],"valid",[],"NV8"],[[43216,43225],"valid"],[[43226,43231],"disallowed"],[[43232,43255],"valid"],[[43256,43258],"valid",[],"NV8"],[[43259,43259],"valid"],[[43260,43260],"valid",[],"NV8"],[[43261,43261],"valid"],[[43262,43263],"disallowed"],[[43264,43309],"valid"],[[43310,43311],"valid",[],"NV8"],[[43312,43347],"valid"],[[43348,43358],"disallowed"],[[43359,43359],"valid",[],"NV8"],[[43360,43388],"valid",[],"NV8"],[[43389,43391],"disallowed"],[[43392,43456],"valid"],[[43457,43469],"valid",[],"NV8"],[[43470,43470],"disallowed"],[[43471,43481],"valid"],[[43482,43485],"disallowed"],[[43486,43487],"valid",[],"NV8"],[[43488,43518],"valid"],[[43519,43519],"disallowed"],[[43520,43574],"valid"],[[43575,43583],"disallowed"],[[43584,43597],"valid"],[[43598,43599],"disallowed"],[[43600,43609],"valid"],[[43610,43611],"disallowed"],[[43612,43615],"valid",[],"NV8"],[[43616,43638],"valid"],[[43639,43641],"valid",[],"NV8"],[[43642,43643],"valid"],[[43644,43647],"valid"],[[43648,43714],"valid"],[[43715,43738],"disallowed"],[[43739,43741],"valid"],[[43742,43743],"valid",[],"NV8"],[[43744,43759],"valid"],[[43760,43761],"valid",[],"NV8"],[[43762,43766],"valid"],[[43767,43776],"disallowed"],[[43777,43782],"valid"],[[43783,43784],"disallowed"],[[43785,43790],"valid"],[[43791,43792],"disallowed"],[[43793,43798],"valid"],[[43799,43807],"disallowed"],[[43808,43814],"valid"],[[43815,43815],"disallowed"],[[43816,43822],"valid"],[[43823,43823],"disallowed"],[[43824,43866],"valid"],[[43867,43867],"valid",[],"NV8"],[[43868,43868],"mapped",[42791]],[[43869,43869],"mapped",[43831]],[[43870,43870],"mapped",[619]],[[43871,43871],"mapped",[43858]],[[43872,43875],"valid"],[[43876,43877],"valid"],[[43878,43887],"disallowed"],[[43888,43888],"mapped",[5024]],[[43889,43889],"mapped",[5025]],[[43890,43890],"mapped",[5026]],[[43891,43891],"mapped",[5027]],[[43892,43892],"mapped",[5028]],[[43893,43893],"mapped",[5029]],[[43894,43894],"mapped",[5030]],[[43895,43895],"mapped",[5031]],[[43896,43896],"mapped",[5032]],[[43897,43897],"mapped",[5033]],[[43898,43898],"mapped",[5034]],[[43899,43899],"mapped",[5035]],[[43900,43900],"mapped",[5036]],[[43901,43901],"mapped",[5037]],[[43902,43902],"mapped",[5038]],[[43903,43903],"mapped",[5039]],[[43904,43904],"mapped",[5040]],[[43905,43905],"mapped",[5041]],[[43906,43906],"mapped",[5042]],[[43907,43907],"mapped",[5043]],[[43908,43908],"mapped",[5044]],[[43909,43909],"mapped",[5045]],[[43910,43910],"mapped",[5046]],[[43911,43911],"mapped",[5047]],[[43912,43912],"mapped",[5048]],[[43913,43913],"mapped",[5049]],[[43914,43914],"mapped",[5050]],[[43915,43915],"mapped",[5051]],[[43916,43916],"mapped",[5052]],[[43917,43917],"mapped",[5053]],[[43918,43918],"mapped",[5054]],[[43919,43919],"mapped",[5055]],[[43920,43920],"mapped",[5056]],[[43921,43921],"mapped",[5057]],[[43922,43922],"mapped",[5058]],[[43923,43923],"mapped",[5059]],[[43924,43924],"mapped",[5060]],[[43925,43925],"mapped",[5061]],[[43926,43926],"mapped",[5062]],[[43927,43927],"mapped",[5063]],[[43928,43928],"mapped",[5064]],[[43929,43929],"mapped",[5065]],[[43930,43930],"mapped",[5066]],[[43931,43931],"mapped",[5067]],[[43932,43932],"mapped",[5068]],[[43933,43933],"mapped",[5069]],[[43934,43934],"mapped",[5070]],[[43935,43935],"mapped",[5071]],[[43936,43936],"mapped",[5072]],[[43937,43937],"mapped",[5073]],[[43938,43938],"mapped",[5074]],[[43939,43939],"mapped",[5075]],[[43940,43940],"mapped",[5076]],[[43941,43941],"mapped",[5077]],[[43942,43942],"mapped",[5078]],[[43943,43943],"mapped",[5079]],[[43944,43944],"mapped",[5080]],[[43945,43945],"mapped",[5081]],[[43946,43946],"mapped",[5082]],[[43947,43947],"mapped",[5083]],[[43948,43948],"mapped",[5084]],[[43949,43949],"mapped",[5085]],[[43950,43950],"mapped",[5086]],[[43951,43951],"mapped",[5087]],[[43952,43952],"mapped",[5088]],[[43953,43953],"mapped",[5089]],[[43954,43954],"mapped",[5090]],[[43955,43955],"mapped",[5091]],[[43956,43956],"mapped",[5092]],[[43957,43957],"mapped",[5093]],[[43958,43958],"mapped",[5094]],[[43959,43959],"mapped",[5095]],[[43960,43960],"mapped",[5096]],[[43961,43961],"mapped",[5097]],[[43962,43962],"mapped",[5098]],[[43963,43963],"mapped",[5099]],[[43964,43964],"mapped",[5100]],[[43965,43965],"mapped",[5101]],[[43966,43966],"mapped",[5102]],[[43967,43967],"mapped",[5103]],[[43968,44010],"valid"],[[44011,44011],"valid",[],"NV8"],[[44012,44013],"valid"],[[44014,44015],"disallowed"],[[44016,44025],"valid"],[[44026,44031],"disallowed"],[[44032,55203],"valid"],[[55204,55215],"disallowed"],[[55216,55238],"valid",[],"NV8"],[[55239,55242],"disallowed"],[[55243,55291],"valid",[],"NV8"],[[55292,55295],"disallowed"],[[55296,57343],"disallowed"],[[57344,63743],"disallowed"],[[63744,63744],"mapped",[35912]],[[63745,63745],"mapped",[26356]],[[63746,63746],"mapped",[36554]],[[63747,63747],"mapped",[36040]],[[63748,63748],"mapped",[28369]],[[63749,63749],"mapped",[20018]],[[63750,63750],"mapped",[21477]],[[63751,63752],"mapped",[40860]],[[63753,63753],"mapped",[22865]],[[63754,63754],"mapped",[37329]],[[63755,63755],"mapped",[21895]],[[63756,63756],"mapped",[22856]],[[63757,63757],"mapped",[25078]],[[63758,63758],"mapped",[30313]],[[63759,63759],"mapped",[32645]],[[63760,63760],"mapped",[34367]],[[63761,63761],"mapped",[34746]],[[63762,63762],"mapped",[35064]],[[63763,63763],"mapped",[37007]],[[63764,63764],"mapped",[27138]],[[63765,63765],"mapped",[27931]],[[63766,63766],"mapped",[28889]],[[63767,63767],"mapped",[29662]],[[63768,63768],"mapped",[33853]],[[63769,63769],"mapped",[37226]],[[63770,63770],"mapped",[39409]],[[63771,63771],"mapped",[20098]],[[63772,63772],"mapped",[21365]],[[63773,63773],"mapped",[27396]],[[63774,63774],"mapped",[29211]],[[63775,63775],"mapped",[34349]],[[63776,63776],"mapped",[40478]],[[63777,63777],"mapped",[23888]],[[63778,63778],"mapped",[28651]],[[63779,63779],"mapped",[34253]],[[63780,63780],"mapped",[35172]],[[63781,63781],"mapped",[25289]],[[63782,63782],"mapped",[33240]],[[63783,63783],"mapped",[34847]],[[63784,63784],"mapped",[24266]],[[63785,63785],"mapped",[26391]],[[63786,63786],"mapped",[28010]],[[63787,63787],"mapped",[29436]],[[63788,63788],"mapped",[37070]],[[63789,63789],"mapped",[20358]],[[63790,63790],"mapped",[20919]],[[63791,63791],"mapped",[21214]],[[63792,63792],"mapped",[25796]],[[63793,63793],"mapped",[27347]],[[63794,63794],"mapped",[29200]],[[63795,63795],"mapped",[30439]],[[63796,63796],"mapped",[32769]],[[63797,63797],"mapped",[34310]],[[63798,63798],"mapped",[34396]],[[63799,63799],"mapped",[36335]],[[63800,63800],"mapped",[38706]],[[63801,63801],"mapped",[39791]],[[63802,63802],"mapped",[40442]],[[63803,63803],"mapped",[30860]],[[63804,63804],"mapped",[31103]],[[63805,63805],"mapped",[32160]],[[63806,63806],"mapped",[33737]],[[63807,63807],"mapped",[37636]],[[63808,63808],"mapped",[40575]],[[63809,63809],"mapped",[35542]],[[63810,63810],"mapped",[22751]],[[63811,63811],"mapped",[24324]],[[63812,63812],"mapped",[31840]],[[63813,63813],"mapped",[32894]],[[63814,63814],"mapped",[29282]],[[63815,63815],"mapped",[30922]],[[63816,63816],"mapped",[36034]],[[63817,63817],"mapped",[38647]],[[63818,63818],"mapped",[22744]],[[63819,63819],"mapped",[23650]],[[63820,63820],"mapped",[27155]],[[63821,63821],"mapped",[28122]],[[63822,63822],"mapped",[28431]],[[63823,63823],"mapped",[32047]],[[63824,63824],"mapped",[32311]],[[63825,63825],"mapped",[38475]],[[63826,63826],"mapped",[21202]],[[63827,63827],"mapped",[32907]],[[63828,63828],"mapped",[20956]],[[63829,63829],"mapped",[20940]],[[63830,63830],"mapped",[31260]],[[63831,63831],"mapped",[32190]],[[63832,63832],"mapped",[33777]],[[63833,63833],"mapped",[38517]],[[63834,63834],"mapped",[35712]],[[63835,63835],"mapped",[25295]],[[63836,63836],"mapped",[27138]],[[63837,63837],"mapped",[35582]],[[63838,63838],"mapped",[20025]],[[63839,63839],"mapped",[23527]],[[63840,63840],"mapped",[24594]],[[63841,63841],"mapped",[29575]],[[63842,63842],"mapped",[30064]],[[63843,63843],"mapped",[21271]],[[63844,63844],"mapped",[30971]],[[63845,63845],"mapped",[20415]],[[63846,63846],"mapped",[24489]],[[63847,63847],"mapped",[19981]],[[63848,63848],"mapped",[27852]],[[63849,63849],"mapped",[25976]],[[63850,63850],"mapped",[32034]],[[63851,63851],"mapped",[21443]],[[63852,63852],"mapped",[22622]],[[63853,63853],"mapped",[30465]],[[63854,63854],"mapped",[33865]],[[63855,63855],"mapped",[35498]],[[63856,63856],"mapped",[27578]],[[63857,63857],"mapped",[36784]],[[63858,63858],"mapped",[27784]],[[63859,63859],"mapped",[25342]],[[63860,63860],"mapped",[33509]],[[63861,63861],"mapped",[25504]],[[63862,63862],"mapped",[30053]],[[63863,63863],"mapped",[20142]],[[63864,63864],"mapped",[20841]],[[63865,63865],"mapped",[20937]],[[63866,63866],"mapped",[26753]],[[63867,63867],"mapped",[31975]],[[63868,63868],"mapped",[33391]],[[63869,63869],"mapped",[35538]],[[63870,63870],"mapped",[37327]],[[63871,63871],"mapped",[21237]],[[63872,63872],"mapped",[21570]],[[63873,63873],"mapped",[22899]],[[63874,63874],"mapped",[24300]],[[63875,63875],"mapped",[26053]],[[63876,63876],"mapped",[28670]],[[63877,63877],"mapped",[31018]],[[63878,63878],"mapped",[38317]],[[63879,63879],"mapped",[39530]],[[63880,63880],"mapped",[40599]],[[63881,63881],"mapped",[40654]],[[63882,63882],"mapped",[21147]],[[63883,63883],"mapped",[26310]],[[63884,63884],"mapped",[27511]],[[63885,63885],"mapped",[36706]],[[63886,63886],"mapped",[24180]],[[63887,63887],"mapped",[24976]],[[63888,63888],"mapped",[25088]],[[63889,63889],"mapped",[25754]],[[63890,63890],"mapped",[28451]],[[63891,63891],"mapped",[29001]],[[63892,63892],"mapped",[29833]],[[63893,63893],"mapped",[31178]],[[63894,63894],"mapped",[32244]],[[63895,63895],"mapped",[32879]],[[63896,63896],"mapped",[36646]],[[63897,63897],"mapped",[34030]],[[63898,63898],"mapped",[36899]],[[63899,63899],"mapped",[37706]],[[63900,63900],"mapped",[21015]],[[63901,63901],"mapped",[21155]],[[63902,63902],"mapped",[21693]],[[63903,63903],"mapped",[28872]],[[63904,63904],"mapped",[35010]],[[63905,63905],"mapped",[35498]],[[63906,63906],"mapped",[24265]],[[63907,63907],"mapped",[24565]],[[63908,63908],"mapped",[25467]],[[63909,63909],"mapped",[27566]],[[63910,63910],"mapped",[31806]],[[63911,63911],"mapped",[29557]],[[63912,63912],"mapped",[20196]],[[63913,63913],"mapped",[22265]],[[63914,63914],"mapped",[23527]],[[63915,63915],"mapped",[23994]],[[63916,63916],"mapped",[24604]],[[63917,63917],"mapped",[29618]],[[63918,63918],"mapped",[29801]],[[63919,63919],"mapped",[32666]],[[63920,63920],"mapped",[32838]],[[63921,63921],"mapped",[37428]],[[63922,63922],"mapped",[38646]],[[63923,63923],"mapped",[38728]],[[63924,63924],"mapped",[38936]],[[63925,63925],"mapped",[20363]],[[63926,63926],"mapped",[31150]],[[63927,63927],"mapped",[37300]],[[63928,63928],"mapped",[38584]],[[63929,63929],"mapped",[24801]],[[63930,63930],"mapped",[20102]],[[63931,63931],"mapped",[20698]],[[63932,63932],"mapped",[23534]],[[63933,63933],"mapped",[23615]],[[63934,63934],"mapped",[26009]],[[63935,63935],"mapped",[27138]],[[63936,63936],"mapped",[29134]],[[63937,63937],"mapped",[30274]],[[63938,63938],"mapped",[34044]],[[63939,63939],"mapped",[36988]],[[63940,63940],"mapped",[40845]],[[63941,63941],"mapped",[26248]],[[63942,63942],"mapped",[38446]],[[63943,63943],"mapped",[21129]],[[63944,63944],"mapped",[26491]],[[63945,63945],"mapped",[26611]],[[63946,63946],"mapped",[27969]],[[63947,63947],"mapped",[28316]],[[63948,63948],"mapped",[29705]],[[63949,63949],"mapped",[30041]],[[63950,63950],"mapped",[30827]],[[63951,63951],"mapped",[32016]],[[63952,63952],"mapped",[39006]],[[63953,63953],"mapped",[20845]],[[63954,63954],"mapped",[25134]],[[63955,63955],"mapped",[38520]],[[63956,63956],"mapped",[20523]],[[63957,63957],"mapped",[23833]],[[63958,63958],"mapped",[28138]],[[63959,63959],"mapped",[36650]],[[63960,63960],"mapped",[24459]],[[63961,63961],"mapped",[24900]],[[63962,63962],"mapped",[26647]],[[63963,63963],"mapped",[29575]],[[63964,63964],"mapped",[38534]],[[63965,63965],"mapped",[21033]],[[63966,63966],"mapped",[21519]],[[63967,63967],"mapped",[23653]],[[63968,63968],"mapped",[26131]],[[63969,63969],"mapped",[26446]],[[63970,63970],"mapped",[26792]],[[63971,63971],"mapped",[27877]],[[63972,63972],"mapped",[29702]],[[63973,63973],"mapped",[30178]],[[63974,63974],"mapped",[32633]],[[63975,63975],"mapped",[35023]],[[63976,63976],"mapped",[35041]],[[63977,63977],"mapped",[37324]],[[63978,63978],"mapped",[38626]],[[63979,63979],"mapped",[21311]],[[63980,63980],"mapped",[28346]],[[63981,63981],"mapped",[21533]],[[63982,63982],"mapped",[29136]],[[63983,63983],"mapped",[29848]],[[63984,63984],"mapped",[34298]],[[63985,63985],"mapped",[38563]],[[63986,63986],"mapped",[40023]],[[63987,63987],"mapped",[40607]],[[63988,63988],"mapped",[26519]],[[63989,63989],"mapped",[28107]],[[63990,63990],"mapped",[33256]],[[63991,63991],"mapped",[31435]],[[63992,63992],"mapped",[31520]],[[63993,63993],"mapped",[31890]],[[63994,63994],"mapped",[29376]],[[63995,63995],"mapped",[28825]],[[63996,63996],"mapped",[35672]],[[63997,63997],"mapped",[20160]],[[63998,63998],"mapped",[33590]],[[63999,63999],"mapped",[21050]],[[64000,64000],"mapped",[20999]],[[64001,64001],"mapped",[24230]],[[64002,64002],"mapped",[25299]],[[64003,64003],"mapped",[31958]],[[64004,64004],"mapped",[23429]],[[64005,64005],"mapped",[27934]],[[64006,64006],"mapped",[26292]],[[64007,64007],"mapped",[36667]],[[64008,64008],"mapped",[34892]],[[64009,64009],"mapped",[38477]],[[64010,64010],"mapped",[35211]],[[64011,64011],"mapped",[24275]],[[64012,64012],"mapped",[20800]],[[64013,64013],"mapped",[21952]],[[64014,64015],"valid"],[[64016,64016],"mapped",[22618]],[[64017,64017],"valid"],[[64018,64018],"mapped",[26228]],[[64019,64020],"valid"],[[64021,64021],"mapped",[20958]],[[64022,64022],"mapped",[29482]],[[64023,64023],"mapped",[30410]],[[64024,64024],"mapped",[31036]],[[64025,64025],"mapped",[31070]],[[64026,64026],"mapped",[31077]],[[64027,64027],"mapped",[31119]],[[64028,64028],"mapped",[38742]],[[64029,64029],"mapped",[31934]],[[64030,64030],"mapped",[32701]],[[64031,64031],"valid"],[[64032,64032],"mapped",[34322]],[[64033,64033],"valid"],[[64034,64034],"mapped",[35576]],[[64035,64036],"valid"],[[64037,64037],"mapped",[36920]],[[64038,64038],"mapped",[37117]],[[64039,64041],"valid"],[[64042,64042],"mapped",[39151]],[[64043,64043],"mapped",[39164]],[[64044,64044],"mapped",[39208]],[[64045,64045],"mapped",[40372]],[[64046,64046],"mapped",[37086]],[[64047,64047],"mapped",[38583]],[[64048,64048],"mapped",[20398]],[[64049,64049],"mapped",[20711]],[[64050,64050],"mapped",[20813]],[[64051,64051],"mapped",[21193]],[[64052,64052],"mapped",[21220]],[[64053,64053],"mapped",[21329]],[[64054,64054],"mapped",[21917]],[[64055,64055],"mapped",[22022]],[[64056,64056],"mapped",[22120]],[[64057,64057],"mapped",[22592]],[[64058,64058],"mapped",[22696]],[[64059,64059],"mapped",[23652]],[[64060,64060],"mapped",[23662]],[[64061,64061],"mapped",[24724]],[[64062,64062],"mapped",[24936]],[[64063,64063],"mapped",[24974]],[[64064,64064],"mapped",[25074]],[[64065,64065],"mapped",[25935]],[[64066,64066],"mapped",[26082]],[[64067,64067],"mapped",[26257]],[[64068,64068],"mapped",[26757]],[[64069,64069],"mapped",[28023]],[[64070,64070],"mapped",[28186]],[[64071,64071],"mapped",[28450]],[[64072,64072],"mapped",[29038]],[[64073,64073],"mapped",[29227]],[[64074,64074],"mapped",[29730]],[[64075,64075],"mapped",[30865]],[[64076,64076],"mapped",[31038]],[[64077,64077],"mapped",[31049]],[[64078,64078],"mapped",[31048]],[[64079,64079],"mapped",[31056]],[[64080,64080],"mapped",[31062]],[[64081,64081],"mapped",[31069]],[[64082,64082],"mapped",[31117]],[[64083,64083],"mapped",[31118]],[[64084,64084],"mapped",[31296]],[[64085,64085],"mapped",[31361]],[[64086,64086],"mapped",[31680]],[[64087,64087],"mapped",[32244]],[[64088,64088],"mapped",[32265]],[[64089,64089],"mapped",[32321]],[[64090,64090],"mapped",[32626]],[[64091,64091],"mapped",[32773]],[[64092,64092],"mapped",[33261]],[[64093,64094],"mapped",[33401]],[[64095,64095],"mapped",[33879]],[[64096,64096],"mapped",[35088]],[[64097,64097],"mapped",[35222]],[[64098,64098],"mapped",[35585]],[[64099,64099],"mapped",[35641]],[[64100,64100],"mapped",[36051]],[[64101,64101],"mapped",[36104]],[[64102,64102],"mapped",[36790]],[[64103,64103],"mapped",[36920]],[[64104,64104],"mapped",[38627]],[[64105,64105],"mapped",[38911]],[[64106,64106],"mapped",[38971]],[[64107,64107],"mapped",[24693]],[[64108,64108],"mapped",[148206]],[[64109,64109],"mapped",[33304]],[[64110,64111],"disallowed"],[[64112,64112],"mapped",[20006]],[[64113,64113],"mapped",[20917]],[[64114,64114],"mapped",[20840]],[[64115,64115],"mapped",[20352]],[[64116,64116],"mapped",[20805]],[[64117,64117],"mapped",[20864]],[[64118,64118],"mapped",[21191]],[[64119,64119],"mapped",[21242]],[[64120,64120],"mapped",[21917]],[[64121,64121],"mapped",[21845]],[[64122,64122],"mapped",[21913]],[[64123,64123],"mapped",[21986]],[[64124,64124],"mapped",[22618]],[[64125,64125],"mapped",[22707]],[[64126,64126],"mapped",[22852]],[[64127,64127],"mapped",[22868]],[[64128,64128],"mapped",[23138]],[[64129,64129],"mapped",[23336]],[[64130,64130],"mapped",[24274]],[[64131,64131],"mapped",[24281]],[[64132,64132],"mapped",[24425]],[[64133,64133],"mapped",[24493]],[[64134,64134],"mapped",[24792]],[[64135,64135],"mapped",[24910]],[[64136,64136],"mapped",[24840]],[[64137,64137],"mapped",[24974]],[[64138,64138],"mapped",[24928]],[[64139,64139],"mapped",[25074]],[[64140,64140],"mapped",[25140]],[[64141,64141],"mapped",[25540]],[[64142,64142],"mapped",[25628]],[[64143,64143],"mapped",[25682]],[[64144,64144],"mapped",[25942]],[[64145,64145],"mapped",[26228]],[[64146,64146],"mapped",[26391]],[[64147,64147],"mapped",[26395]],[[64148,64148],"mapped",[26454]],[[64149,64149],"mapped",[27513]],[[64150,64150],"mapped",[27578]],[[64151,64151],"mapped",[27969]],[[64152,64152],"mapped",[28379]],[[64153,64153],"mapped",[28363]],[[64154,64154],"mapped",[28450]],[[64155,64155],"mapped",[28702]],[[64156,64156],"mapped",[29038]],[[64157,64157],"mapped",[30631]],[[64158,64158],"mapped",[29237]],[[64159,64159],"mapped",[29359]],[[64160,64160],"mapped",[29482]],[[64161,64161],"mapped",[29809]],[[64162,64162],"mapped",[29958]],[[64163,64163],"mapped",[30011]],[[64164,64164],"mapped",[30237]],[[64165,64165],"mapped",[30239]],[[64166,64166],"mapped",[30410]],[[64167,64167],"mapped",[30427]],[[64168,64168],"mapped",[30452]],[[64169,64169],"mapped",[30538]],[[64170,64170],"mapped",[30528]],[[64171,64171],"mapped",[30924]],[[64172,64172],"mapped",[31409]],[[64173,64173],"mapped",[31680]],[[64174,64174],"mapped",[31867]],[[64175,64175],"mapped",[32091]],[[64176,64176],"mapped",[32244]],[[64177,64177],"mapped",[32574]],[[64178,64178],"mapped",[32773]],[[64179,64179],"mapped",[33618]],[[64180,64180],"mapped",[33775]],[[64181,64181],"mapped",[34681]],[[64182,64182],"mapped",[35137]],[[64183,64183],"mapped",[35206]],[[64184,64184],"mapped",[35222]],[[64185,64185],"mapped",[35519]],[[64186,64186],"mapped",[35576]],[[64187,64187],"mapped",[35531]],[[64188,64188],"mapped",[35585]],[[64189,64189],"mapped",[35582]],[[64190,64190],"mapped",[35565]],[[64191,64191],"mapped",[35641]],[[64192,64192],"mapped",[35722]],[[64193,64193],"mapped",[36104]],[[64194,64194],"mapped",[36664]],[[64195,64195],"mapped",[36978]],[[64196,64196],"mapped",[37273]],[[64197,64197],"mapped",[37494]],[[64198,64198],"mapped",[38524]],[[64199,64199],"mapped",[38627]],[[64200,64200],"mapped",[38742]],[[64201,64201],"mapped",[38875]],[[64202,64202],"mapped",[38911]],[[64203,64203],"mapped",[38923]],[[64204,64204],"mapped",[38971]],[[64205,64205],"mapped",[39698]],[[64206,64206],"mapped",[40860]],[[64207,64207],"mapped",[141386]],[[64208,64208],"mapped",[141380]],[[64209,64209],"mapped",[144341]],[[64210,64210],"mapped",[15261]],[[64211,64211],"mapped",[16408]],[[64212,64212],"mapped",[16441]],[[64213,64213],"mapped",[152137]],[[64214,64214],"mapped",[154832]],[[64215,64215],"mapped",[163539]],[[64216,64216],"mapped",[40771]],[[64217,64217],"mapped",[40846]],[[64218,64255],"disallowed"],[[64256,64256],"mapped",[102,102]],[[64257,64257],"mapped",[102,105]],[[64258,64258],"mapped",[102,108]],[[64259,64259],"mapped",[102,102,105]],[[64260,64260],"mapped",[102,102,108]],[[64261,64262],"mapped",[115,116]],[[64263,64274],"disallowed"],[[64275,64275],"mapped",[1396,1398]],[[64276,64276],"mapped",[1396,1381]],[[64277,64277],"mapped",[1396,1387]],[[64278,64278],"mapped",[1406,1398]],[[64279,64279],"mapped",[1396,1389]],[[64280,64284],"disallowed"],[[64285,64285],"mapped",[1497,1460]],[[64286,64286],"valid"],[[64287,64287],"mapped",[1522,1463]],[[64288,64288],"mapped",[1506]],[[64289,64289],"mapped",[1488]],[[64290,64290],"mapped",[1491]],[[64291,64291],"mapped",[1492]],[[64292,64292],"mapped",[1499]],[[64293,64293],"mapped",[1500]],[[64294,64294],"mapped",[1501]],[[64295,64295],"mapped",[1512]],[[64296,64296],"mapped",[1514]],[[64297,64297],"disallowed_STD3_mapped",[43]],[[64298,64298],"mapped",[1513,1473]],[[64299,64299],"mapped",[1513,1474]],[[64300,64300],"mapped",[1513,1468,1473]],[[64301,64301],"mapped",[1513,1468,1474]],[[64302,64302],"mapped",[1488,1463]],[[64303,64303],"mapped",[1488,1464]],[[64304,64304],"mapped",[1488,1468]],[[64305,64305],"mapped",[1489,1468]],[[64306,64306],"mapped",[1490,1468]],[[64307,64307],"mapped",[1491,1468]],[[64308,64308],"mapped",[1492,1468]],[[64309,64309],"mapped",[1493,1468]],[[64310,64310],"mapped",[1494,1468]],[[64311,64311],"disallowed"],[[64312,64312],"mapped",[1496,1468]],[[64313,64313],"mapped",[1497,1468]],[[64314,64314],"mapped",[1498,1468]],[[64315,64315],"mapped",[1499,1468]],[[64316,64316],"mapped",[1500,1468]],[[64317,64317],"disallowed"],[[64318,64318],"mapped",[1502,1468]],[[64319,64319],"disallowed"],[[64320,64320],"mapped",[1504,1468]],[[64321,64321],"mapped",[1505,1468]],[[64322,64322],"disallowed"],[[64323,64323],"mapped",[1507,1468]],[[64324,64324],"mapped",[1508,1468]],[[64325,64325],"disallowed"],[[64326,64326],"mapped",[1510,1468]],[[64327,64327],"mapped",[1511,1468]],[[64328,64328],"mapped",[1512,1468]],[[64329,64329],"mapped",[1513,1468]],[[64330,64330],"mapped",[1514,1468]],[[64331,64331],"mapped",[1493,1465]],[[64332,64332],"mapped",[1489,1471]],[[64333,64333],"mapped",[1499,1471]],[[64334,64334],"mapped",[1508,1471]],[[64335,64335],"mapped",[1488,1500]],[[64336,64337],"mapped",[1649]],[[64338,64341],"mapped",[1659]],[[64342,64345],"mapped",[1662]],[[64346,64349],"mapped",[1664]],[[64350,64353],"mapped",[1658]],[[64354,64357],"mapped",[1663]],[[64358,64361],"mapped",[1657]],[[64362,64365],"mapped",[1700]],[[64366,64369],"mapped",[1702]],[[64370,64373],"mapped",[1668]],[[64374,64377],"mapped",[1667]],[[64378,64381],"mapped",[1670]],[[64382,64385],"mapped",[1671]],[[64386,64387],"mapped",[1677]],[[64388,64389],"mapped",[1676]],[[64390,64391],"mapped",[1678]],[[64392,64393],"mapped",[1672]],[[64394,64395],"mapped",[1688]],[[64396,64397],"mapped",[1681]],[[64398,64401],"mapped",[1705]],[[64402,64405],"mapped",[1711]],[[64406,64409],"mapped",[1715]],[[64410,64413],"mapped",[1713]],[[64414,64415],"mapped",[1722]],[[64416,64419],"mapped",[1723]],[[64420,64421],"mapped",[1728]],[[64422,64425],"mapped",[1729]],[[64426,64429],"mapped",[1726]],[[64430,64431],"mapped",[1746]],[[64432,64433],"mapped",[1747]],[[64434,64449],"valid",[],"NV8"],[[64450,64466],"disallowed"],[[64467,64470],"mapped",[1709]],[[64471,64472],"mapped",[1735]],[[64473,64474],"mapped",[1734]],[[64475,64476],"mapped",[1736]],[[64477,64477],"mapped",[1735,1652]],[[64478,64479],"mapped",[1739]],[[64480,64481],"mapped",[1733]],[[64482,64483],"mapped",[1737]],[[64484,64487],"mapped",[1744]],[[64488,64489],"mapped",[1609]],[[64490,64491],"mapped",[1574,1575]],[[64492,64493],"mapped",[1574,1749]],[[64494,64495],"mapped",[1574,1608]],[[64496,64497],"mapped",[1574,1735]],[[64498,64499],"mapped",[1574,1734]],[[64500,64501],"mapped",[1574,1736]],[[64502,64504],"mapped",[1574,1744]],[[64505,64507],"mapped",[1574,1609]],[[64508,64511],"mapped",[1740]],[[64512,64512],"mapped",[1574,1580]],[[64513,64513],"mapped",[1574,1581]],[[64514,64514],"mapped",[1574,1605]],[[64515,64515],"mapped",[1574,1609]],[[64516,64516],"mapped",[1574,1610]],[[64517,64517],"mapped",[1576,1580]],[[64518,64518],"mapped",[1576,1581]],[[64519,64519],"mapped",[1576,1582]],[[64520,64520],"mapped",[1576,1605]],[[64521,64521],"mapped",[1576,1609]],[[64522,64522],"mapped",[1576,1610]],[[64523,64523],"mapped",[1578,1580]],[[64524,64524],"mapped",[1578,1581]],[[64525,64525],"mapped",[1578,1582]],[[64526,64526],"mapped",[1578,1605]],[[64527,64527],"mapped",[1578,1609]],[[64528,64528],"mapped",[1578,1610]],[[64529,64529],"mapped",[1579,1580]],[[64530,64530],"mapped",[1579,1605]],[[64531,64531],"mapped",[1579,1609]],[[64532,64532],"mapped",[1579,1610]],[[64533,64533],"mapped",[1580,1581]],[[64534,64534],"mapped",[1580,1605]],[[64535,64535],"mapped",[1581,1580]],[[64536,64536],"mapped",[1581,1605]],[[64537,64537],"mapped",[1582,1580]],[[64538,64538],"mapped",[1582,1581]],[[64539,64539],"mapped",[1582,1605]],[[64540,64540],"mapped",[1587,1580]],[[64541,64541],"mapped",[1587,1581]],[[64542,64542],"mapped",[1587,1582]],[[64543,64543],"mapped",[1587,1605]],[[64544,64544],"mapped",[1589,1581]],[[64545,64545],"mapped",[1589,1605]],[[64546,64546],"mapped",[1590,1580]],[[64547,64547],"mapped",[1590,1581]],[[64548,64548],"mapped",[1590,1582]],[[64549,64549],"mapped",[1590,1605]],[[64550,64550],"mapped",[1591,1581]],[[64551,64551],"mapped",[1591,1605]],[[64552,64552],"mapped",[1592,1605]],[[64553,64553],"mapped",[1593,1580]],[[64554,64554],"mapped",[1593,1605]],[[64555,64555],"mapped",[1594,1580]],[[64556,64556],"mapped",[1594,1605]],[[64557,64557],"mapped",[1601,1580]],[[64558,64558],"mapped",[1601,1581]],[[64559,64559],"mapped",[1601,1582]],[[64560,64560],"mapped",[1601,1605]],[[64561,64561],"mapped",[1601,1609]],[[64562,64562],"mapped",[1601,1610]],[[64563,64563],"mapped",[1602,1581]],[[64564,64564],"mapped",[1602,1605]],[[64565,64565],"mapped",[1602,1609]],[[64566,64566],"mapped",[1602,1610]],[[64567,64567],"mapped",[1603,1575]],[[64568,64568],"mapped",[1603,1580]],[[64569,64569],"mapped",[1603,1581]],[[64570,64570],"mapped",[1603,1582]],[[64571,64571],"mapped",[1603,1604]],[[64572,64572],"mapped",[1603,1605]],[[64573,64573],"mapped",[1603,1609]],[[64574,64574],"mapped",[1603,1610]],[[64575,64575],"mapped",[1604,1580]],[[64576,64576],"mapped",[1604,1581]],[[64577,64577],"mapped",[1604,1582]],[[64578,64578],"mapped",[1604,1605]],[[64579,64579],"mapped",[1604,1609]],[[64580,64580],"mapped",[1604,1610]],[[64581,64581],"mapped",[1605,1580]],[[64582,64582],"mapped",[1605,1581]],[[64583,64583],"mapped",[1605,1582]],[[64584,64584],"mapped",[1605,1605]],[[64585,64585],"mapped",[1605,1609]],[[64586,64586],"mapped",[1605,1610]],[[64587,64587],"mapped",[1606,1580]],[[64588,64588],"mapped",[1606,1581]],[[64589,64589],"mapped",[1606,1582]],[[64590,64590],"mapped",[1606,1605]],[[64591,64591],"mapped",[1606,1609]],[[64592,64592],"mapped",[1606,1610]],[[64593,64593],"mapped",[1607,1580]],[[64594,64594],"mapped",[1607,1605]],[[64595,64595],"mapped",[1607,1609]],[[64596,64596],"mapped",[1607,1610]],[[64597,64597],"mapped",[1610,1580]],[[64598,64598],"mapped",[1610,1581]],[[64599,64599],"mapped",[1610,1582]],[[64600,64600],"mapped",[1610,1605]],[[64601,64601],"mapped",[1610,1609]],[[64602,64602],"mapped",[1610,1610]],[[64603,64603],"mapped",[1584,1648]],[[64604,64604],"mapped",[1585,1648]],[[64605,64605],"mapped",[1609,1648]],[[64606,64606],"disallowed_STD3_mapped",[32,1612,1617]],[[64607,64607],"disallowed_STD3_mapped",[32,1613,1617]],[[64608,64608],"disallowed_STD3_mapped",[32,1614,1617]],[[64609,64609],"disallowed_STD3_mapped",[32,1615,1617]],[[64610,64610],"disallowed_STD3_mapped",[32,1616,1617]],[[64611,64611],"disallowed_STD3_mapped",[32,1617,1648]],[[64612,64612],"mapped",[1574,1585]],[[64613,64613],"mapped",[1574,1586]],[[64614,64614],"mapped",[1574,1605]],[[64615,64615],"mapped",[1574,1606]],[[64616,64616],"mapped",[1574,1609]],[[64617,64617],"mapped",[1574,1610]],[[64618,64618],"mapped",[1576,1585]],[[64619,64619],"mapped",[1576,1586]],[[64620,64620],"mapped",[1576,1605]],[[64621,64621],"mapped",[1576,1606]],[[64622,64622],"mapped",[1576,1609]],[[64623,64623],"mapped",[1576,1610]],[[64624,64624],"mapped",[1578,1585]],[[64625,64625],"mapped",[1578,1586]],[[64626,64626],"mapped",[1578,1605]],[[64627,64627],"mapped",[1578,1606]],[[64628,64628],"mapped",[1578,1609]],[[64629,64629],"mapped",[1578,1610]],[[64630,64630],"mapped",[1579,1585]],[[64631,64631],"mapped",[1579,1586]],[[64632,64632],"mapped",[1579,1605]],[[64633,64633],"mapped",[1579,1606]],[[64634,64634],"mapped",[1579,1609]],[[64635,64635],"mapped",[1579,1610]],[[64636,64636],"mapped",[1601,1609]],[[64637,64637],"mapped",[1601,1610]],[[64638,64638],"mapped",[1602,1609]],[[64639,64639],"mapped",[1602,1610]],[[64640,64640],"mapped",[1603,1575]],[[64641,64641],"mapped",[1603,1604]],[[64642,64642],"mapped",[1603,1605]],[[64643,64643],"mapped",[1603,1609]],[[64644,64644],"mapped",[1603,1610]],[[64645,64645],"mapped",[1604,1605]],[[64646,64646],"mapped",[1604,1609]],[[64647,64647],"mapped",[1604,1610]],[[64648,64648],"mapped",[1605,1575]],[[64649,64649],"mapped",[1605,1605]],[[64650,64650],"mapped",[1606,1585]],[[64651,64651],"mapped",[1606,1586]],[[64652,64652],"mapped",[1606,1605]],[[64653,64653],"mapped",[1606,1606]],[[64654,64654],"mapped",[1606,1609]],[[64655,64655],"mapped",[1606,1610]],[[64656,64656],"mapped",[1609,1648]],[[64657,64657],"mapped",[1610,1585]],[[64658,64658],"mapped",[1610,1586]],[[64659,64659],"mapped",[1610,1605]],[[64660,64660],"mapped",[1610,1606]],[[64661,64661],"mapped",[1610,1609]],[[64662,64662],"mapped",[1610,1610]],[[64663,64663],"mapped",[1574,1580]],[[64664,64664],"mapped",[1574,1581]],[[64665,64665],"mapped",[1574,1582]],[[64666,64666],"mapped",[1574,1605]],[[64667,64667],"mapped",[1574,1607]],[[64668,64668],"mapped",[1576,1580]],[[64669,64669],"mapped",[1576,1581]],[[64670,64670],"mapped",[1576,1582]],[[64671,64671],"mapped",[1576,1605]],[[64672,64672],"mapped",[1576,1607]],[[64673,64673],"mapped",[1578,1580]],[[64674,64674],"mapped",[1578,1581]],[[64675,64675],"mapped",[1578,1582]],[[64676,64676],"mapped",[1578,1605]],[[64677,64677],"mapped",[1578,1607]],[[64678,64678],"mapped",[1579,1605]],[[64679,64679],"mapped",[1580,1581]],[[64680,64680],"mapped",[1580,1605]],[[64681,64681],"mapped",[1581,1580]],[[64682,64682],"mapped",[1581,1605]],[[64683,64683],"mapped",[1582,1580]],[[64684,64684],"mapped",[1582,1605]],[[64685,64685],"mapped",[1587,1580]],[[64686,64686],"mapped",[1587,1581]],[[64687,64687],"mapped",[1587,1582]],[[64688,64688],"mapped",[1587,1605]],[[64689,64689],"mapped",[1589,1581]],[[64690,64690],"mapped",[1589,1582]],[[64691,64691],"mapped",[1589,1605]],[[64692,64692],"mapped",[1590,1580]],[[64693,64693],"mapped",[1590,1581]],[[64694,64694],"mapped",[1590,1582]],[[64695,64695],"mapped",[1590,1605]],[[64696,64696],"mapped",[1591,1581]],[[64697,64697],"mapped",[1592,1605]],[[64698,64698],"mapped",[1593,1580]],[[64699,64699],"mapped",[1593,1605]],[[64700,64700],"mapped",[1594,1580]],[[64701,64701],"mapped",[1594,1605]],[[64702,64702],"mapped",[1601,1580]],[[64703,64703],"mapped",[1601,1581]],[[64704,64704],"mapped",[1601,1582]],[[64705,64705],"mapped",[1601,1605]],[[64706,64706],"mapped",[1602,1581]],[[64707,64707],"mapped",[1602,1605]],[[64708,64708],"mapped",[1603,1580]],[[64709,64709],"mapped",[1603,1581]],[[64710,64710],"mapped",[1603,1582]],[[64711,64711],"mapped",[1603,1604]],[[64712,64712],"mapped",[1603,1605]],[[64713,64713],"mapped",[1604,1580]],[[64714,64714],"mapped",[1604,1581]],[[64715,64715],"mapped",[1604,1582]],[[64716,64716],"mapped",[1604,1605]],[[64717,64717],"mapped",[1604,1607]],[[64718,64718],"mapped",[1605,1580]],[[64719,64719],"mapped",[1605,1581]],[[64720,64720],"mapped",[1605,1582]],[[64721,64721],"mapped",[1605,1605]],[[64722,64722],"mapped",[1606,1580]],[[64723,64723],"mapped",[1606,1581]],[[64724,64724],"mapped",[1606,1582]],[[64725,64725],"mapped",[1606,1605]],[[64726,64726],"mapped",[1606,1607]],[[64727,64727],"mapped",[1607,1580]],[[64728,64728],"mapped",[1607,1605]],[[64729,64729],"mapped",[1607,1648]],[[64730,64730],"mapped",[1610,1580]],[[64731,64731],"mapped",[1610,1581]],[[64732,64732],"mapped",[1610,1582]],[[64733,64733],"mapped",[1610,1605]],[[64734,64734],"mapped",[1610,1607]],[[64735,64735],"mapped",[1574,1605]],[[64736,64736],"mapped",[1574,1607]],[[64737,64737],"mapped",[1576,1605]],[[64738,64738],"mapped",[1576,1607]],[[64739,64739],"mapped",[1578,1605]],[[64740,64740],"mapped",[1578,1607]],[[64741,64741],"mapped",[1579,1605]],[[64742,64742],"mapped",[1579,1607]],[[64743,64743],"mapped",[1587,1605]],[[64744,64744],"mapped",[1587,1607]],[[64745,64745],"mapped",[1588,1605]],[[64746,64746],"mapped",[1588,1607]],[[64747,64747],"mapped",[1603,1604]],[[64748,64748],"mapped",[1603,1605]],[[64749,64749],"mapped",[1604,1605]],[[64750,64750],"mapped",[1606,1605]],[[64751,64751],"mapped",[1606,1607]],[[64752,64752],"mapped",[1610,1605]],[[64753,64753],"mapped",[1610,1607]],[[64754,64754],"mapped",[1600,1614,1617]],[[64755,64755],"mapped",[1600,1615,1617]],[[64756,64756],"mapped",[1600,1616,1617]],[[64757,64757],"mapped",[1591,1609]],[[64758,64758],"mapped",[1591,1610]],[[64759,64759],"mapped",[1593,1609]],[[64760,64760],"mapped",[1593,1610]],[[64761,64761],"mapped",[1594,1609]],[[64762,64762],"mapped",[1594,1610]],[[64763,64763],"mapped",[1587,1609]],[[64764,64764],"mapped",[1587,1610]],[[64765,64765],"mapped",[1588,1609]],[[64766,64766],"mapped",[1588,1610]],[[64767,64767],"mapped",[1581,1609]],[[64768,64768],"mapped",[1581,1610]],[[64769,64769],"mapped",[1580,1609]],[[64770,64770],"mapped",[1580,1610]],[[64771,64771],"mapped",[1582,1609]],[[64772,64772],"mapped",[1582,1610]],[[64773,64773],"mapped",[1589,1609]],[[64774,64774],"mapped",[1589,1610]],[[64775,64775],"mapped",[1590,1609]],[[64776,64776],"mapped",[1590,1610]],[[64777,64777],"mapped",[1588,1580]],[[64778,64778],"mapped",[1588,1581]],[[64779,64779],"mapped",[1588,1582]],[[64780,64780],"mapped",[1588,1605]],[[64781,64781],"mapped",[1588,1585]],[[64782,64782],"mapped",[1587,1585]],[[64783,64783],"mapped",[1589,1585]],[[64784,64784],"mapped",[1590,1585]],[[64785,64785],"mapped",[1591,1609]],[[64786,64786],"mapped",[1591,1610]],[[64787,64787],"mapped",[1593,1609]],[[64788,64788],"mapped",[1593,1610]],[[64789,64789],"mapped",[1594,1609]],[[64790,64790],"mapped",[1594,1610]],[[64791,64791],"mapped",[1587,1609]],[[64792,64792],"mapped",[1587,1610]],[[64793,64793],"mapped",[1588,1609]],[[64794,64794],"mapped",[1588,1610]],[[64795,64795],"mapped",[1581,1609]],[[64796,64796],"mapped",[1581,1610]],[[64797,64797],"mapped",[1580,1609]],[[64798,64798],"mapped",[1580,1610]],[[64799,64799],"mapped",[1582,1609]],[[64800,64800],"mapped",[1582,1610]],[[64801,64801],"mapped",[1589,1609]],[[64802,64802],"mapped",[1589,1610]],[[64803,64803],"mapped",[1590,1609]],[[64804,64804],"mapped",[1590,1610]],[[64805,64805],"mapped",[1588,1580]],[[64806,64806],"mapped",[1588,1581]],[[64807,64807],"mapped",[1588,1582]],[[64808,64808],"mapped",[1588,1605]],[[64809,64809],"mapped",[1588,1585]],[[64810,64810],"mapped",[1587,1585]],[[64811,64811],"mapped",[1589,1585]],[[64812,64812],"mapped",[1590,1585]],[[64813,64813],"mapped",[1588,1580]],[[64814,64814],"mapped",[1588,1581]],[[64815,64815],"mapped",[1588,1582]],[[64816,64816],"mapped",[1588,1605]],[[64817,64817],"mapped",[1587,1607]],[[64818,64818],"mapped",[1588,1607]],[[64819,64819],"mapped",[1591,1605]],[[64820,64820],"mapped",[1587,1580]],[[64821,64821],"mapped",[1587,1581]],[[64822,64822],"mapped",[1587,1582]],[[64823,64823],"mapped",[1588,1580]],[[64824,64824],"mapped",[1588,1581]],[[64825,64825],"mapped",[1588,1582]],[[64826,64826],"mapped",[1591,1605]],[[64827,64827],"mapped",[1592,1605]],[[64828,64829],"mapped",[1575,1611]],[[64830,64831],"valid",[],"NV8"],[[64832,64847],"disallowed"],[[64848,64848],"mapped",[1578,1580,1605]],[[64849,64850],"mapped",[1578,1581,1580]],[[64851,64851],"mapped",[1578,1581,1605]],[[64852,64852],"mapped",[1578,1582,1605]],[[64853,64853],"mapped",[1578,1605,1580]],[[64854,64854],"mapped",[1578,1605,1581]],[[64855,64855],"mapped",[1578,1605,1582]],[[64856,64857],"mapped",[1580,1605,1581]],[[64858,64858],"mapped",[1581,1605,1610]],[[64859,64859],"mapped",[1581,1605,1609]],[[64860,64860],"mapped",[1587,1581,1580]],[[64861,64861],"mapped",[1587,1580,1581]],[[64862,64862],"mapped",[1587,1580,1609]],[[64863,64864],"mapped",[1587,1605,1581]],[[64865,64865],"mapped",[1587,1605,1580]],[[64866,64867],"mapped",[1587,1605,1605]],[[64868,64869],"mapped",[1589,1581,1581]],[[64870,64870],"mapped",[1589,1605,1605]],[[64871,64872],"mapped",[1588,1581,1605]],[[64873,64873],"mapped",[1588,1580,1610]],[[64874,64875],"mapped",[1588,1605,1582]],[[64876,64877],"mapped",[1588,1605,1605]],[[64878,64878],"mapped",[1590,1581,1609]],[[64879,64880],"mapped",[1590,1582,1605]],[[64881,64882],"mapped",[1591,1605,1581]],[[64883,64883],"mapped",[1591,1605,1605]],[[64884,64884],"mapped",[1591,1605,1610]],[[64885,64885],"mapped",[1593,1580,1605]],[[64886,64887],"mapped",[1593,1605,1605]],[[64888,64888],"mapped",[1593,1605,1609]],[[64889,64889],"mapped",[1594,1605,1605]],[[64890,64890],"mapped",[1594,1605,1610]],[[64891,64891],"mapped",[1594,1605,1609]],[[64892,64893],"mapped",[1601,1582,1605]],[[64894,64894],"mapped",[1602,1605,1581]],[[64895,64895],"mapped",[1602,1605,1605]],[[64896,64896],"mapped",[1604,1581,1605]],[[64897,64897],"mapped",[1604,1581,1610]],[[64898,64898],"mapped",[1604,1581,1609]],[[64899,64900],"mapped",[1604,1580,1580]],[[64901,64902],"mapped",[1604,1582,1605]],[[64903,64904],"mapped",[1604,1605,1581]],[[64905,64905],"mapped",[1605,1581,1580]],[[64906,64906],"mapped",[1605,1581,1605]],[[64907,64907],"mapped",[1605,1581,1610]],[[64908,64908],"mapped",[1605,1580,1581]],[[64909,64909],"mapped",[1605,1580,1605]],[[64910,64910],"mapped",[1605,1582,1580]],[[64911,64911],"mapped",[1605,1582,1605]],[[64912,64913],"disallowed"],[[64914,64914],"mapped",[1605,1580,1582]],[[64915,64915],"mapped",[1607,1605,1580]],[[64916,64916],"mapped",[1607,1605,1605]],[[64917,64917],"mapped",[1606,1581,1605]],[[64918,64918],"mapped",[1606,1581,1609]],[[64919,64920],"mapped",[1606,1580,1605]],[[64921,64921],"mapped",[1606,1580,1609]],[[64922,64922],"mapped",[1606,1605,1610]],[[64923,64923],"mapped",[1606,1605,1609]],[[64924,64925],"mapped",[1610,1605,1605]],[[64926,64926],"mapped",[1576,1582,1610]],[[64927,64927],"mapped",[1578,1580,1610]],[[64928,64928],"mapped",[1578,1580,1609]],[[64929,64929],"mapped",[1578,1582,1610]],[[64930,64930],"mapped",[1578,1582,1609]],[[64931,64931],"mapped",[1578,1605,1610]],[[64932,64932],"mapped",[1578,1605,1609]],[[64933,64933],"mapped",[1580,1605,1610]],[[64934,64934],"mapped",[1580,1581,1609]],[[64935,64935],"mapped",[1580,1605,1609]],[[64936,64936],"mapped",[1587,1582,1609]],[[64937,64937],"mapped",[1589,1581,1610]],[[64938,64938],"mapped",[1588,1581,1610]],[[64939,64939],"mapped",[1590,1581,1610]],[[64940,64940],"mapped",[1604,1580,1610]],[[64941,64941],"mapped",[1604,1605,1610]],[[64942,64942],"mapped",[1610,1581,1610]],[[64943,64943],"mapped",[1610,1580,1610]],[[64944,64944],"mapped",[1610,1605,1610]],[[64945,64945],"mapped",[1605,1605,1610]],[[64946,64946],"mapped",[1602,1605,1610]],[[64947,64947],"mapped",[1606,1581,1610]],[[64948,64948],"mapped",[1602,1605,1581]],[[64949,64949],"mapped",[1604,1581,1605]],[[64950,64950],"mapped",[1593,1605,1610]],[[64951,64951],"mapped",[1603,1605,1610]],[[64952,64952],"mapped",[1606,1580,1581]],[[64953,64953],"mapped",[1605,1582,1610]],[[64954,64954],"mapped",[1604,1580,1605]],[[64955,64955],"mapped",[1603,1605,1605]],[[64956,64956],"mapped",[1604,1580,1605]],[[64957,64957],"mapped",[1606,1580,1581]],[[64958,64958],"mapped",[1580,1581,1610]],[[64959,64959],"mapped",[1581,1580,1610]],[[64960,64960],"mapped",[1605,1580,1610]],[[64961,64961],"mapped",[1601,1605,1610]],[[64962,64962],"mapped",[1576,1581,1610]],[[64963,64963],"mapped",[1603,1605,1605]],[[64964,64964],"mapped",[1593,1580,1605]],[[64965,64965],"mapped",[1589,1605,1605]],[[64966,64966],"mapped",[1587,1582,1610]],[[64967,64967],"mapped",[1606,1580,1610]],[[64968,64975],"disallowed"],[[64976,65007],"disallowed"],[[65008,65008],"mapped",[1589,1604,1746]],[[65009,65009],"mapped",[1602,1604,1746]],[[65010,65010],"mapped",[1575,1604,1604,1607]],[[65011,65011],"mapped",[1575,1603,1576,1585]],[[65012,65012],"mapped",[1605,1581,1605,1583]],[[65013,65013],"mapped",[1589,1604,1593,1605]],[[65014,65014],"mapped",[1585,1587,1608,1604]],[[65015,65015],"mapped",[1593,1604,1610,1607]],[[65016,65016],"mapped",[1608,1587,1604,1605]],[[65017,65017],"mapped",[1589,1604,1609]],[[65018,65018],"disallowed_STD3_mapped",[1589,1604,1609,32,1575,1604,1604,1607,32,1593,1604,1610,1607,32,1608,1587,1604,1605]],[[65019,65019],"disallowed_STD3_mapped",[1580,1604,32,1580,1604,1575,1604,1607]],[[65020,65020],"mapped",[1585,1740,1575,1604]],[[65021,65021],"valid",[],"NV8"],[[65022,65023],"disallowed"],[[65024,65039],"ignored"],[[65040,65040],"disallowed_STD3_mapped",[44]],[[65041,65041],"mapped",[12289]],[[65042,65042],"disallowed"],[[65043,65043],"disallowed_STD3_mapped",[58]],[[65044,65044],"disallowed_STD3_mapped",[59]],[[65045,65045],"disallowed_STD3_mapped",[33]],[[65046,65046],"disallowed_STD3_mapped",[63]],[[65047,65047],"mapped",[12310]],[[65048,65048],"mapped",[12311]],[[65049,65049],"disallowed"],[[65050,65055],"disallowed"],[[65056,65059],"valid"],[[65060,65062],"valid"],[[65063,65069],"valid"],[[65070,65071],"valid"],[[65072,65072],"disallowed"],[[65073,65073],"mapped",[8212]],[[65074,65074],"mapped",[8211]],[[65075,65076],"disallowed_STD3_mapped",[95]],[[65077,65077],"disallowed_STD3_mapped",[40]],[[65078,65078],"disallowed_STD3_mapped",[41]],[[65079,65079],"disallowed_STD3_mapped",[123]],[[65080,65080],"disallowed_STD3_mapped",[125]],[[65081,65081],"mapped",[12308]],[[65082,65082],"mapped",[12309]],[[65083,65083],"mapped",[12304]],[[65084,65084],"mapped",[12305]],[[65085,65085],"mapped",[12298]],[[65086,65086],"mapped",[12299]],[[65087,65087],"mapped",[12296]],[[65088,65088],"mapped",[12297]],[[65089,65089],"mapped",[12300]],[[65090,65090],"mapped",[12301]],[[65091,65091],"mapped",[12302]],[[65092,65092],"mapped",[12303]],[[65093,65094],"valid",[],"NV8"],[[65095,65095],"disallowed_STD3_mapped",[91]],[[65096,65096],"disallowed_STD3_mapped",[93]],[[65097,65100],"disallowed_STD3_mapped",[32,773]],[[65101,65103],"disallowed_STD3_mapped",[95]],[[65104,65104],"disallowed_STD3_mapped",[44]],[[65105,65105],"mapped",[12289]],[[65106,65106],"disallowed"],[[65107,65107],"disallowed"],[[65108,65108],"disallowed_STD3_mapped",[59]],[[65109,65109],"disallowed_STD3_mapped",[58]],[[65110,65110],"disallowed_STD3_mapped",[63]],[[65111,65111],"disallowed_STD3_mapped",[33]],[[65112,65112],"mapped",[8212]],[[65113,65113],"disallowed_STD3_mapped",[40]],[[65114,65114],"disallowed_STD3_mapped",[41]],[[65115,65115],"disallowed_STD3_mapped",[123]],[[65116,65116],"disallowed_STD3_mapped",[125]],[[65117,65117],"mapped",[12308]],[[65118,65118],"mapped",[12309]],[[65119,65119],"disallowed_STD3_mapped",[35]],[[65120,65120],"disallowed_STD3_mapped",[38]],[[65121,65121],"disallowed_STD3_mapped",[42]],[[65122,65122],"disallowed_STD3_mapped",[43]],[[65123,65123],"mapped",[45]],[[65124,65124],"disallowed_STD3_mapped",[60]],[[65125,65125],"disallowed_STD3_mapped",[62]],[[65126,65126],"disallowed_STD3_mapped",[61]],[[65127,65127],"disallowed"],[[65128,65128],"disallowed_STD3_mapped",[92]],[[65129,65129],"disallowed_STD3_mapped",[36]],[[65130,65130],"disallowed_STD3_mapped",[37]],[[65131,65131],"disallowed_STD3_mapped",[64]],[[65132,65135],"disallowed"],[[65136,65136],"disallowed_STD3_mapped",[32,1611]],[[65137,65137],"mapped",[1600,1611]],[[65138,65138],"disallowed_STD3_mapped",[32,1612]],[[65139,65139],"valid"],[[65140,65140],"disallowed_STD3_mapped",[32,1613]],[[65141,65141],"disallowed"],[[65142,65142],"disallowed_STD3_mapped",[32,1614]],[[65143,65143],"mapped",[1600,1614]],[[65144,65144],"disallowed_STD3_mapped",[32,1615]],[[65145,65145],"mapped",[1600,1615]],[[65146,65146],"disallowed_STD3_mapped",[32,1616]],[[65147,65147],"mapped",[1600,1616]],[[65148,65148],"disallowed_STD3_mapped",[32,1617]],[[65149,65149],"mapped",[1600,1617]],[[65150,65150],"disallowed_STD3_mapped",[32,1618]],[[65151,65151],"mapped",[1600,1618]],[[65152,65152],"mapped",[1569]],[[65153,65154],"mapped",[1570]],[[65155,65156],"mapped",[1571]],[[65157,65158],"mapped",[1572]],[[65159,65160],"mapped",[1573]],[[65161,65164],"mapped",[1574]],[[65165,65166],"mapped",[1575]],[[65167,65170],"mapped",[1576]],[[65171,65172],"mapped",[1577]],[[65173,65176],"mapped",[1578]],[[65177,65180],"mapped",[1579]],[[65181,65184],"mapped",[1580]],[[65185,65188],"mapped",[1581]],[[65189,65192],"mapped",[1582]],[[65193,65194],"mapped",[1583]],[[65195,65196],"mapped",[1584]],[[65197,65198],"mapped",[1585]],[[65199,65200],"mapped",[1586]],[[65201,65204],"mapped",[1587]],[[65205,65208],"mapped",[1588]],[[65209,65212],"mapped",[1589]],[[65213,65216],"mapped",[1590]],[[65217,65220],"mapped",[1591]],[[65221,65224],"mapped",[1592]],[[65225,65228],"mapped",[1593]],[[65229,65232],"mapped",[1594]],[[65233,65236],"mapped",[1601]],[[65237,65240],"mapped",[1602]],[[65241,65244],"mapped",[1603]],[[65245,65248],"mapped",[1604]],[[65249,65252],"mapped",[1605]],[[65253,65256],"mapped",[1606]],[[65257,65260],"mapped",[1607]],[[65261,65262],"mapped",[1608]],[[65263,65264],"mapped",[1609]],[[65265,65268],"mapped",[1610]],[[65269,65270],"mapped",[1604,1570]],[[65271,65272],"mapped",[1604,1571]],[[65273,65274],"mapped",[1604,1573]],[[65275,65276],"mapped",[1604,1575]],[[65277,65278],"disallowed"],[[65279,65279],"ignored"],[[65280,65280],"disallowed"],[[65281,65281],"disallowed_STD3_mapped",[33]],[[65282,65282],"disallowed_STD3_mapped",[34]],[[65283,65283],"disallowed_STD3_mapped",[35]],[[65284,65284],"disallowed_STD3_mapped",[36]],[[65285,65285],"disallowed_STD3_mapped",[37]],[[65286,65286],"disallowed_STD3_mapped",[38]],[[65287,65287],"disallowed_STD3_mapped",[39]],[[65288,65288],"disallowed_STD3_mapped",[40]],[[65289,65289],"disallowed_STD3_mapped",[41]],[[65290,65290],"disallowed_STD3_mapped",[42]],[[65291,65291],"disallowed_STD3_mapped",[43]],[[65292,65292],"disallowed_STD3_mapped",[44]],[[65293,65293],"mapped",[45]],[[65294,65294],"mapped",[46]],[[65295,65295],"disallowed_STD3_mapped",[47]],[[65296,65296],"mapped",[48]],[[65297,65297],"mapped",[49]],[[65298,65298],"mapped",[50]],[[65299,65299],"mapped",[51]],[[65300,65300],"mapped",[52]],[[65301,65301],"mapped",[53]],[[65302,65302],"mapped",[54]],[[65303,65303],"mapped",[55]],[[65304,65304],"mapped",[56]],[[65305,65305],"mapped",[57]],[[65306,65306],"disallowed_STD3_mapped",[58]],[[65307,65307],"disallowed_STD3_mapped",[59]],[[65308,65308],"disallowed_STD3_mapped",[60]],[[65309,65309],"disallowed_STD3_mapped",[61]],[[65310,65310],"disallowed_STD3_mapped",[62]],[[65311,65311],"disallowed_STD3_mapped",[63]],[[65312,65312],"disallowed_STD3_mapped",[64]],[[65313,65313],"mapped",[97]],[[65314,65314],"mapped",[98]],[[65315,65315],"mapped",[99]],[[65316,65316],"mapped",[100]],[[65317,65317],"mapped",[101]],[[65318,65318],"mapped",[102]],[[65319,65319],"mapped",[103]],[[65320,65320],"mapped",[104]],[[65321,65321],"mapped",[105]],[[65322,65322],"mapped",[106]],[[65323,65323],"mapped",[107]],[[65324,65324],"mapped",[108]],[[65325,65325],"mapped",[109]],[[65326,65326],"mapped",[110]],[[65327,65327],"mapped",[111]],[[65328,65328],"mapped",[112]],[[65329,65329],"mapped",[113]],[[65330,65330],"mapped",[114]],[[65331,65331],"mapped",[115]],[[65332,65332],"mapped",[116]],[[65333,65333],"mapped",[117]],[[65334,65334],"mapped",[118]],[[65335,65335],"mapped",[119]],[[65336,65336],"mapped",[120]],[[65337,65337],"mapped",[121]],[[65338,65338],"mapped",[122]],[[65339,65339],"disallowed_STD3_mapped",[91]],[[65340,65340],"disallowed_STD3_mapped",[92]],[[65341,65341],"disallowed_STD3_mapped",[93]],[[65342,65342],"disallowed_STD3_mapped",[94]],[[65343,65343],"disallowed_STD3_mapped",[95]],[[65344,65344],"disallowed_STD3_mapped",[96]],[[65345,65345],"mapped",[97]],[[65346,65346],"mapped",[98]],[[65347,65347],"mapped",[99]],[[65348,65348],"mapped",[100]],[[65349,65349],"mapped",[101]],[[65350,65350],"mapped",[102]],[[65351,65351],"mapped",[103]],[[65352,65352],"mapped",[104]],[[65353,65353],"mapped",[105]],[[65354,65354],"mapped",[106]],[[65355,65355],"mapped",[107]],[[65356,65356],"mapped",[108]],[[65357,65357],"mapped",[109]],[[65358,65358],"mapped",[110]],[[65359,65359],"mapped",[111]],[[65360,65360],"mapped",[112]],[[65361,65361],"mapped",[113]],[[65362,65362],"mapped",[114]],[[65363,65363],"mapped",[115]],[[65364,65364],"mapped",[116]],[[65365,65365],"mapped",[117]],[[65366,65366],"mapped",[118]],[[65367,65367],"mapped",[119]],[[65368,65368],"mapped",[120]],[[65369,65369],"mapped",[121]],[[65370,65370],"mapped",[122]],[[65371,65371],"disallowed_STD3_mapped",[123]],[[65372,65372],"disallowed_STD3_mapped",[124]],[[65373,65373],"disallowed_STD3_mapped",[125]],[[65374,65374],"disallowed_STD3_mapped",[126]],[[65375,65375],"mapped",[10629]],[[65376,65376],"mapped",[10630]],[[65377,65377],"mapped",[46]],[[65378,65378],"mapped",[12300]],[[65379,65379],"mapped",[12301]],[[65380,65380],"mapped",[12289]],[[65381,65381],"mapped",[12539]],[[65382,65382],"mapped",[12530]],[[65383,65383],"mapped",[12449]],[[65384,65384],"mapped",[12451]],[[65385,65385],"mapped",[12453]],[[65386,65386],"mapped",[12455]],[[65387,65387],"mapped",[12457]],[[65388,65388],"mapped",[12515]],[[65389,65389],"mapped",[12517]],[[65390,65390],"mapped",[12519]],[[65391,65391],"mapped",[12483]],[[65392,65392],"mapped",[12540]],[[65393,65393],"mapped",[12450]],[[65394,65394],"mapped",[12452]],[[65395,65395],"mapped",[12454]],[[65396,65396],"mapped",[12456]],[[65397,65397],"mapped",[12458]],[[65398,65398],"mapped",[12459]],[[65399,65399],"mapped",[12461]],[[65400,65400],"mapped",[12463]],[[65401,65401],"mapped",[12465]],[[65402,65402],"mapped",[12467]],[[65403,65403],"mapped",[12469]],[[65404,65404],"mapped",[12471]],[[65405,65405],"mapped",[12473]],[[65406,65406],"mapped",[12475]],[[65407,65407],"mapped",[12477]],[[65408,65408],"mapped",[12479]],[[65409,65409],"mapped",[12481]],[[65410,65410],"mapped",[12484]],[[65411,65411],"mapped",[12486]],[[65412,65412],"mapped",[12488]],[[65413,65413],"mapped",[12490]],[[65414,65414],"mapped",[12491]],[[65415,65415],"mapped",[12492]],[[65416,65416],"mapped",[12493]],[[65417,65417],"mapped",[12494]],[[65418,65418],"mapped",[12495]],[[65419,65419],"mapped",[12498]],[[65420,65420],"mapped",[12501]],[[65421,65421],"mapped",[12504]],[[65422,65422],"mapped",[12507]],[[65423,65423],"mapped",[12510]],[[65424,65424],"mapped",[12511]],[[65425,65425],"mapped",[12512]],[[65426,65426],"mapped",[12513]],[[65427,65427],"mapped",[12514]],[[65428,65428],"mapped",[12516]],[[65429,65429],"mapped",[12518]],[[65430,65430],"mapped",[12520]],[[65431,65431],"mapped",[12521]],[[65432,65432],"mapped",[12522]],[[65433,65433],"mapped",[12523]],[[65434,65434],"mapped",[12524]],[[65435,65435],"mapped",[12525]],[[65436,65436],"mapped",[12527]],[[65437,65437],"mapped",[12531]],[[65438,65438],"mapped",[12441]],[[65439,65439],"mapped",[12442]],[[65440,65440],"disallowed"],[[65441,65441],"mapped",[4352]],[[65442,65442],"mapped",[4353]],[[65443,65443],"mapped",[4522]],[[65444,65444],"mapped",[4354]],[[65445,65445],"mapped",[4524]],[[65446,65446],"mapped",[4525]],[[65447,65447],"mapped",[4355]],[[65448,65448],"mapped",[4356]],[[65449,65449],"mapped",[4357]],[[65450,65450],"mapped",[4528]],[[65451,65451],"mapped",[4529]],[[65452,65452],"mapped",[4530]],[[65453,65453],"mapped",[4531]],[[65454,65454],"mapped",[4532]],[[65455,65455],"mapped",[4533]],[[65456,65456],"mapped",[4378]],[[65457,65457],"mapped",[4358]],[[65458,65458],"mapped",[4359]],[[65459,65459],"mapped",[4360]],[[65460,65460],"mapped",[4385]],[[65461,65461],"mapped",[4361]],[[65462,65462],"mapped",[4362]],[[65463,65463],"mapped",[4363]],[[65464,65464],"mapped",[4364]],[[65465,65465],"mapped",[4365]],[[65466,65466],"mapped",[4366]],[[65467,65467],"mapped",[4367]],[[65468,65468],"mapped",[4368]],[[65469,65469],"mapped",[4369]],[[65470,65470],"mapped",[4370]],[[65471,65473],"disallowed"],[[65474,65474],"mapped",[4449]],[[65475,65475],"mapped",[4450]],[[65476,65476],"mapped",[4451]],[[65477,65477],"mapped",[4452]],[[65478,65478],"mapped",[4453]],[[65479,65479],"mapped",[4454]],[[65480,65481],"disallowed"],[[65482,65482],"mapped",[4455]],[[65483,65483],"mapped",[4456]],[[65484,65484],"mapped",[4457]],[[65485,65485],"mapped",[4458]],[[65486,65486],"mapped",[4459]],[[65487,65487],"mapped",[4460]],[[65488,65489],"disallowed"],[[65490,65490],"mapped",[4461]],[[65491,65491],"mapped",[4462]],[[65492,65492],"mapped",[4463]],[[65493,65493],"mapped",[4464]],[[65494,65494],"mapped",[4465]],[[65495,65495],"mapped",[4466]],[[65496,65497],"disallowed"],[[65498,65498],"mapped",[4467]],[[65499,65499],"mapped",[4468]],[[65500,65500],"mapped",[4469]],[[65501,65503],"disallowed"],[[65504,65504],"mapped",[162]],[[65505,65505],"mapped",[163]],[[65506,65506],"mapped",[172]],[[65507,65507],"disallowed_STD3_mapped",[32,772]],[[65508,65508],"mapped",[166]],[[65509,65509],"mapped",[165]],[[65510,65510],"mapped",[8361]],[[65511,65511],"disallowed"],[[65512,65512],"mapped",[9474]],[[65513,65513],"mapped",[8592]],[[65514,65514],"mapped",[8593]],[[65515,65515],"mapped",[8594]],[[65516,65516],"mapped",[8595]],[[65517,65517],"mapped",[9632]],[[65518,65518],"mapped",[9675]],[[65519,65528],"disallowed"],[[65529,65531],"disallowed"],[[65532,65532],"disallowed"],[[65533,65533],"disallowed"],[[65534,65535],"disallowed"],[[65536,65547],"valid"],[[65548,65548],"disallowed"],[[65549,65574],"valid"],[[65575,65575],"disallowed"],[[65576,65594],"valid"],[[65595,65595],"disallowed"],[[65596,65597],"valid"],[[65598,65598],"disallowed"],[[65599,65613],"valid"],[[65614,65615],"disallowed"],[[65616,65629],"valid"],[[65630,65663],"disallowed"],[[65664,65786],"valid"],[[65787,65791],"disallowed"],[[65792,65794],"valid",[],"NV8"],[[65795,65798],"disallowed"],[[65799,65843],"valid",[],"NV8"],[[65844,65846],"disallowed"],[[65847,65855],"valid",[],"NV8"],[[65856,65930],"valid",[],"NV8"],[[65931,65932],"valid",[],"NV8"],[[65933,65935],"disallowed"],[[65936,65947],"valid",[],"NV8"],[[65948,65951],"disallowed"],[[65952,65952],"valid",[],"NV8"],[[65953,65999],"disallowed"],[[66000,66044],"valid",[],"NV8"],[[66045,66045],"valid"],[[66046,66175],"disallowed"],[[66176,66204],"valid"],[[66205,66207],"disallowed"],[[66208,66256],"valid"],[[66257,66271],"disallowed"],[[66272,66272],"valid"],[[66273,66299],"valid",[],"NV8"],[[66300,66303],"disallowed"],[[66304,66334],"valid"],[[66335,66335],"valid"],[[66336,66339],"valid",[],"NV8"],[[66340,66351],"disallowed"],[[66352,66368],"valid"],[[66369,66369],"valid",[],"NV8"],[[66370,66377],"valid"],[[66378,66378],"valid",[],"NV8"],[[66379,66383],"disallowed"],[[66384,66426],"valid"],[[66427,66431],"disallowed"],[[66432,66461],"valid"],[[66462,66462],"disallowed"],[[66463,66463],"valid",[],"NV8"],[[66464,66499],"valid"],[[66500,66503],"disallowed"],[[66504,66511],"valid"],[[66512,66517],"valid",[],"NV8"],[[66518,66559],"disallowed"],[[66560,66560],"mapped",[66600]],[[66561,66561],"mapped",[66601]],[[66562,66562],"mapped",[66602]],[[66563,66563],"mapped",[66603]],[[66564,66564],"mapped",[66604]],[[66565,66565],"mapped",[66605]],[[66566,66566],"mapped",[66606]],[[66567,66567],"mapped",[66607]],[[66568,66568],"mapped",[66608]],[[66569,66569],"mapped",[66609]],[[66570,66570],"mapped",[66610]],[[66571,66571],"mapped",[66611]],[[66572,66572],"mapped",[66612]],[[66573,66573],"mapped",[66613]],[[66574,66574],"mapped",[66614]],[[66575,66575],"mapped",[66615]],[[66576,66576],"mapped",[66616]],[[66577,66577],"mapped",[66617]],[[66578,66578],"mapped",[66618]],[[66579,66579],"mapped",[66619]],[[66580,66580],"mapped",[66620]],[[66581,66581],"mapped",[66621]],[[66582,66582],"mapped",[66622]],[[66583,66583],"mapped",[66623]],[[66584,66584],"mapped",[66624]],[[66585,66585],"mapped",[66625]],[[66586,66586],"mapped",[66626]],[[66587,66587],"mapped",[66627]],[[66588,66588],"mapped",[66628]],[[66589,66589],"mapped",[66629]],[[66590,66590],"mapped",[66630]],[[66591,66591],"mapped",[66631]],[[66592,66592],"mapped",[66632]],[[66593,66593],"mapped",[66633]],[[66594,66594],"mapped",[66634]],[[66595,66595],"mapped",[66635]],[[66596,66596],"mapped",[66636]],[[66597,66597],"mapped",[66637]],[[66598,66598],"mapped",[66638]],[[66599,66599],"mapped",[66639]],[[66600,66637],"valid"],[[66638,66717],"valid"],[[66718,66719],"disallowed"],[[66720,66729],"valid"],[[66730,66815],"disallowed"],[[66816,66855],"valid"],[[66856,66863],"disallowed"],[[66864,66915],"valid"],[[66916,66926],"disallowed"],[[66927,66927],"valid",[],"NV8"],[[66928,67071],"disallowed"],[[67072,67382],"valid"],[[67383,67391],"disallowed"],[[67392,67413],"valid"],[[67414,67423],"disallowed"],[[67424,67431],"valid"],[[67432,67583],"disallowed"],[[67584,67589],"valid"],[[67590,67591],"disallowed"],[[67592,67592],"valid"],[[67593,67593],"disallowed"],[[67594,67637],"valid"],[[67638,67638],"disallowed"],[[67639,67640],"valid"],[[67641,67643],"disallowed"],[[67644,67644],"valid"],[[67645,67646],"disallowed"],[[67647,67647],"valid"],[[67648,67669],"valid"],[[67670,67670],"disallowed"],[[67671,67679],"valid",[],"NV8"],[[67680,67702],"valid"],[[67703,67711],"valid",[],"NV8"],[[67712,67742],"valid"],[[67743,67750],"disallowed"],[[67751,67759],"valid",[],"NV8"],[[67760,67807],"disallowed"],[[67808,67826],"valid"],[[67827,67827],"disallowed"],[[67828,67829],"valid"],[[67830,67834],"disallowed"],[[67835,67839],"valid",[],"NV8"],[[67840,67861],"valid"],[[67862,67865],"valid",[],"NV8"],[[67866,67867],"valid",[],"NV8"],[[67868,67870],"disallowed"],[[67871,67871],"valid",[],"NV8"],[[67872,67897],"valid"],[[67898,67902],"disallowed"],[[67903,67903],"valid",[],"NV8"],[[67904,67967],"disallowed"],[[67968,68023],"valid"],[[68024,68027],"disallowed"],[[68028,68029],"valid",[],"NV8"],[[68030,68031],"valid"],[[68032,68047],"valid",[],"NV8"],[[68048,68049],"disallowed"],[[68050,68095],"valid",[],"NV8"],[[68096,68099],"valid"],[[68100,68100],"disallowed"],[[68101,68102],"valid"],[[68103,68107],"disallowed"],[[68108,68115],"valid"],[[68116,68116],"disallowed"],[[68117,68119],"valid"],[[68120,68120],"disallowed"],[[68121,68147],"valid"],[[68148,68151],"disallowed"],[[68152,68154],"valid"],[[68155,68158],"disallowed"],[[68159,68159],"valid"],[[68160,68167],"valid",[],"NV8"],[[68168,68175],"disallowed"],[[68176,68184],"valid",[],"NV8"],[[68185,68191],"disallowed"],[[68192,68220],"valid"],[[68221,68223],"valid",[],"NV8"],[[68224,68252],"valid"],[[68253,68255],"valid",[],"NV8"],[[68256,68287],"disallowed"],[[68288,68295],"valid"],[[68296,68296],"valid",[],"NV8"],[[68297,68326],"valid"],[[68327,68330],"disallowed"],[[68331,68342],"valid",[],"NV8"],[[68343,68351],"disallowed"],[[68352,68405],"valid"],[[68406,68408],"disallowed"],[[68409,68415],"valid",[],"NV8"],[[68416,68437],"valid"],[[68438,68439],"disallowed"],[[68440,68447],"valid",[],"NV8"],[[68448,68466],"valid"],[[68467,68471],"disallowed"],[[68472,68479],"valid",[],"NV8"],[[68480,68497],"valid"],[[68498,68504],"disallowed"],[[68505,68508],"valid",[],"NV8"],[[68509,68520],"disallowed"],[[68521,68527],"valid",[],"NV8"],[[68528,68607],"disallowed"],[[68608,68680],"valid"],[[68681,68735],"disallowed"],[[68736,68736],"mapped",[68800]],[[68737,68737],"mapped",[68801]],[[68738,68738],"mapped",[68802]],[[68739,68739],"mapped",[68803]],[[68740,68740],"mapped",[68804]],[[68741,68741],"mapped",[68805]],[[68742,68742],"mapped",[68806]],[[68743,68743],"mapped",[68807]],[[68744,68744],"mapped",[68808]],[[68745,68745],"mapped",[68809]],[[68746,68746],"mapped",[68810]],[[68747,68747],"mapped",[68811]],[[68748,68748],"mapped",[68812]],[[68749,68749],"mapped",[68813]],[[68750,68750],"mapped",[68814]],[[68751,68751],"mapped",[68815]],[[68752,68752],"mapped",[68816]],[[68753,68753],"mapped",[68817]],[[68754,68754],"mapped",[68818]],[[68755,68755],"mapped",[68819]],[[68756,68756],"mapped",[68820]],[[68757,68757],"mapped",[68821]],[[68758,68758],"mapped",[68822]],[[68759,68759],"mapped",[68823]],[[68760,68760],"mapped",[68824]],[[68761,68761],"mapped",[68825]],[[68762,68762],"mapped",[68826]],[[68763,68763],"mapped",[68827]],[[68764,68764],"mapped",[68828]],[[68765,68765],"mapped",[68829]],[[68766,68766],"mapped",[68830]],[[68767,68767],"mapped",[68831]],[[68768,68768],"mapped",[68832]],[[68769,68769],"mapped",[68833]],[[68770,68770],"mapped",[68834]],[[68771,68771],"mapped",[68835]],[[68772,68772],"mapped",[68836]],[[68773,68773],"mapped",[68837]],[[68774,68774],"mapped",[68838]],[[68775,68775],"mapped",[68839]],[[68776,68776],"mapped",[68840]],[[68777,68777],"mapped",[68841]],[[68778,68778],"mapped",[68842]],[[68779,68779],"mapped",[68843]],[[68780,68780],"mapped",[68844]],[[68781,68781],"mapped",[68845]],[[68782,68782],"mapped",[68846]],[[68783,68783],"mapped",[68847]],[[68784,68784],"mapped",[68848]],[[68785,68785],"mapped",[68849]],[[68786,68786],"mapped",[68850]],[[68787,68799],"disallowed"],[[68800,68850],"valid"],[[68851,68857],"disallowed"],[[68858,68863],"valid",[],"NV8"],[[68864,69215],"disallowed"],[[69216,69246],"valid",[],"NV8"],[[69247,69631],"disallowed"],[[69632,69702],"valid"],[[69703,69709],"valid",[],"NV8"],[[69710,69713],"disallowed"],[[69714,69733],"valid",[],"NV8"],[[69734,69743],"valid"],[[69744,69758],"disallowed"],[[69759,69759],"valid"],[[69760,69818],"valid"],[[69819,69820],"valid",[],"NV8"],[[69821,69821],"disallowed"],[[69822,69825],"valid",[],"NV8"],[[69826,69839],"disallowed"],[[69840,69864],"valid"],[[69865,69871],"disallowed"],[[69872,69881],"valid"],[[69882,69887],"disallowed"],[[69888,69940],"valid"],[[69941,69941],"disallowed"],[[69942,69951],"valid"],[[69952,69955],"valid",[],"NV8"],[[69956,69967],"disallowed"],[[69968,70003],"valid"],[[70004,70005],"valid",[],"NV8"],[[70006,70006],"valid"],[[70007,70015],"disallowed"],[[70016,70084],"valid"],[[70085,70088],"valid",[],"NV8"],[[70089,70089],"valid",[],"NV8"],[[70090,70092],"valid"],[[70093,70093],"valid",[],"NV8"],[[70094,70095],"disallowed"],[[70096,70105],"valid"],[[70106,70106],"valid"],[[70107,70107],"valid",[],"NV8"],[[70108,70108],"valid"],[[70109,70111],"valid",[],"NV8"],[[70112,70112],"disallowed"],[[70113,70132],"valid",[],"NV8"],[[70133,70143],"disallowed"],[[70144,70161],"valid"],[[70162,70162],"disallowed"],[[70163,70199],"valid"],[[70200,70205],"valid",[],"NV8"],[[70206,70271],"disallowed"],[[70272,70278],"valid"],[[70279,70279],"disallowed"],[[70280,70280],"valid"],[[70281,70281],"disallowed"],[[70282,70285],"valid"],[[70286,70286],"disallowed"],[[70287,70301],"valid"],[[70302,70302],"disallowed"],[[70303,70312],"valid"],[[70313,70313],"valid",[],"NV8"],[[70314,70319],"disallowed"],[[70320,70378],"valid"],[[70379,70383],"disallowed"],[[70384,70393],"valid"],[[70394,70399],"disallowed"],[[70400,70400],"valid"],[[70401,70403],"valid"],[[70404,70404],"disallowed"],[[70405,70412],"valid"],[[70413,70414],"disallowed"],[[70415,70416],"valid"],[[70417,70418],"disallowed"],[[70419,70440],"valid"],[[70441,70441],"disallowed"],[[70442,70448],"valid"],[[70449,70449],"disallowed"],[[70450,70451],"valid"],[[70452,70452],"disallowed"],[[70453,70457],"valid"],[[70458,70459],"disallowed"],[[70460,70468],"valid"],[[70469,70470],"disallowed"],[[70471,70472],"valid"],[[70473,70474],"disallowed"],[[70475,70477],"valid"],[[70478,70479],"disallowed"],[[70480,70480],"valid"],[[70481,70486],"disallowed"],[[70487,70487],"valid"],[[70488,70492],"disallowed"],[[70493,70499],"valid"],[[70500,70501],"disallowed"],[[70502,70508],"valid"],[[70509,70511],"disallowed"],[[70512,70516],"valid"],[[70517,70783],"disallowed"],[[70784,70853],"valid"],[[70854,70854],"valid",[],"NV8"],[[70855,70855],"valid"],[[70856,70863],"disallowed"],[[70864,70873],"valid"],[[70874,71039],"disallowed"],[[71040,71093],"valid"],[[71094,71095],"disallowed"],[[71096,71104],"valid"],[[71105,71113],"valid",[],"NV8"],[[71114,71127],"valid",[],"NV8"],[[71128,71133],"valid"],[[71134,71167],"disallowed"],[[71168,71232],"valid"],[[71233,71235],"valid",[],"NV8"],[[71236,71236],"valid"],[[71237,71247],"disallowed"],[[71248,71257],"valid"],[[71258,71295],"disallowed"],[[71296,71351],"valid"],[[71352,71359],"disallowed"],[[71360,71369],"valid"],[[71370,71423],"disallowed"],[[71424,71449],"valid"],[[71450,71452],"disallowed"],[[71453,71467],"valid"],[[71468,71471],"disallowed"],[[71472,71481],"valid"],[[71482,71487],"valid",[],"NV8"],[[71488,71839],"disallowed"],[[71840,71840],"mapped",[71872]],[[71841,71841],"mapped",[71873]],[[71842,71842],"mapped",[71874]],[[71843,71843],"mapped",[71875]],[[71844,71844],"mapped",[71876]],[[71845,71845],"mapped",[71877]],[[71846,71846],"mapped",[71878]],[[71847,71847],"mapped",[71879]],[[71848,71848],"mapped",[71880]],[[71849,71849],"mapped",[71881]],[[71850,71850],"mapped",[71882]],[[71851,71851],"mapped",[71883]],[[71852,71852],"mapped",[71884]],[[71853,71853],"mapped",[71885]],[[71854,71854],"mapped",[71886]],[[71855,71855],"mapped",[71887]],[[71856,71856],"mapped",[71888]],[[71857,71857],"mapped",[71889]],[[71858,71858],"mapped",[71890]],[[71859,71859],"mapped",[71891]],[[71860,71860],"mapped",[71892]],[[71861,71861],"mapped",[71893]],[[71862,71862],"mapped",[71894]],[[71863,71863],"mapped",[71895]],[[71864,71864],"mapped",[71896]],[[71865,71865],"mapped",[71897]],[[71866,71866],"mapped",[71898]],[[71867,71867],"mapped",[71899]],[[71868,71868],"mapped",[71900]],[[71869,71869],"mapped",[71901]],[[71870,71870],"mapped",[71902]],[[71871,71871],"mapped",[71903]],[[71872,71913],"valid"],[[71914,71922],"valid",[],"NV8"],[[71923,71934],"disallowed"],[[71935,71935],"valid"],[[71936,72383],"disallowed"],[[72384,72440],"valid"],[[72441,73727],"disallowed"],[[73728,74606],"valid"],[[74607,74648],"valid"],[[74649,74649],"valid"],[[74650,74751],"disallowed"],[[74752,74850],"valid",[],"NV8"],[[74851,74862],"valid",[],"NV8"],[[74863,74863],"disallowed"],[[74864,74867],"valid",[],"NV8"],[[74868,74868],"valid",[],"NV8"],[[74869,74879],"disallowed"],[[74880,75075],"valid"],[[75076,77823],"disallowed"],[[77824,78894],"valid"],[[78895,82943],"disallowed"],[[82944,83526],"valid"],[[83527,92159],"disallowed"],[[92160,92728],"valid"],[[92729,92735],"disallowed"],[[92736,92766],"valid"],[[92767,92767],"disallowed"],[[92768,92777],"valid"],[[92778,92781],"disallowed"],[[92782,92783],"valid",[],"NV8"],[[92784,92879],"disallowed"],[[92880,92909],"valid"],[[92910,92911],"disallowed"],[[92912,92916],"valid"],[[92917,92917],"valid",[],"NV8"],[[92918,92927],"disallowed"],[[92928,92982],"valid"],[[92983,92991],"valid",[],"NV8"],[[92992,92995],"valid"],[[92996,92997],"valid",[],"NV8"],[[92998,93007],"disallowed"],[[93008,93017],"valid"],[[93018,93018],"disallowed"],[[93019,93025],"valid",[],"NV8"],[[93026,93026],"disallowed"],[[93027,93047],"valid"],[[93048,93052],"disallowed"],[[93053,93071],"valid"],[[93072,93951],"disallowed"],[[93952,94020],"valid"],[[94021,94031],"disallowed"],[[94032,94078],"valid"],[[94079,94094],"disallowed"],[[94095,94111],"valid"],[[94112,110591],"disallowed"],[[110592,110593],"valid"],[[110594,113663],"disallowed"],[[113664,113770],"valid"],[[113771,113775],"disallowed"],[[113776,113788],"valid"],[[113789,113791],"disallowed"],[[113792,113800],"valid"],[[113801,113807],"disallowed"],[[113808,113817],"valid"],[[113818,113819],"disallowed"],[[113820,113820],"valid",[],"NV8"],[[113821,113822],"valid"],[[113823,113823],"valid",[],"NV8"],[[113824,113827],"ignored"],[[113828,118783],"disallowed"],[[118784,119029],"valid",[],"NV8"],[[119030,119039],"disallowed"],[[119040,119078],"valid",[],"NV8"],[[119079,119080],"disallowed"],[[119081,119081],"valid",[],"NV8"],[[119082,119133],"valid",[],"NV8"],[[119134,119134],"mapped",[119127,119141]],[[119135,119135],"mapped",[119128,119141]],[[119136,119136],"mapped",[119128,119141,119150]],[[119137,119137],"mapped",[119128,119141,119151]],[[119138,119138],"mapped",[119128,119141,119152]],[[119139,119139],"mapped",[119128,119141,119153]],[[119140,119140],"mapped",[119128,119141,119154]],[[119141,119154],"valid",[],"NV8"],[[119155,119162],"disallowed"],[[119163,119226],"valid",[],"NV8"],[[119227,119227],"mapped",[119225,119141]],[[119228,119228],"mapped",[119226,119141]],[[119229,119229],"mapped",[119225,119141,119150]],[[119230,119230],"mapped",[119226,119141,119150]],[[119231,119231],"mapped",[119225,119141,119151]],[[119232,119232],"mapped",[119226,119141,119151]],[[119233,119261],"valid",[],"NV8"],[[119262,119272],"valid",[],"NV8"],[[119273,119295],"disallowed"],[[119296,119365],"valid",[],"NV8"],[[119366,119551],"disallowed"],[[119552,119638],"valid",[],"NV8"],[[119639,119647],"disallowed"],[[119648,119665],"valid",[],"NV8"],[[119666,119807],"disallowed"],[[119808,119808],"mapped",[97]],[[119809,119809],"mapped",[98]],[[119810,119810],"mapped",[99]],[[119811,119811],"mapped",[100]],[[119812,119812],"mapped",[101]],[[119813,119813],"mapped",[102]],[[119814,119814],"mapped",[103]],[[119815,119815],"mapped",[104]],[[119816,119816],"mapped",[105]],[[119817,119817],"mapped",[106]],[[119818,119818],"mapped",[107]],[[119819,119819],"mapped",[108]],[[119820,119820],"mapped",[109]],[[119821,119821],"mapped",[110]],[[119822,119822],"mapped",[111]],[[119823,119823],"mapped",[112]],[[119824,119824],"mapped",[113]],[[119825,119825],"mapped",[114]],[[119826,119826],"mapped",[115]],[[119827,119827],"mapped",[116]],[[119828,119828],"mapped",[117]],[[119829,119829],"mapped",[118]],[[119830,119830],"mapped",[119]],[[119831,119831],"mapped",[120]],[[119832,119832],"mapped",[121]],[[119833,119833],"mapped",[122]],[[119834,119834],"mapped",[97]],[[119835,119835],"mapped",[98]],[[119836,119836],"mapped",[99]],[[119837,119837],"mapped",[100]],[[119838,119838],"mapped",[101]],[[119839,119839],"mapped",[102]],[[119840,119840],"mapped",[103]],[[119841,119841],"mapped",[104]],[[119842,119842],"mapped",[105]],[[119843,119843],"mapped",[106]],[[119844,119844],"mapped",[107]],[[119845,119845],"mapped",[108]],[[119846,119846],"mapped",[109]],[[119847,119847],"mapped",[110]],[[119848,119848],"mapped",[111]],[[119849,119849],"mapped",[112]],[[119850,119850],"mapped",[113]],[[119851,119851],"mapped",[114]],[[119852,119852],"mapped",[115]],[[119853,119853],"mapped",[116]],[[119854,119854],"mapped",[117]],[[119855,119855],"mapped",[118]],[[119856,119856],"mapped",[119]],[[119857,119857],"mapped",[120]],[[119858,119858],"mapped",[121]],[[119859,119859],"mapped",[122]],[[119860,119860],"mapped",[97]],[[119861,119861],"mapped",[98]],[[119862,119862],"mapped",[99]],[[119863,119863],"mapped",[100]],[[119864,119864],"mapped",[101]],[[119865,119865],"mapped",[102]],[[119866,119866],"mapped",[103]],[[119867,119867],"mapped",[104]],[[119868,119868],"mapped",[105]],[[119869,119869],"mapped",[106]],[[119870,119870],"mapped",[107]],[[119871,119871],"mapped",[108]],[[119872,119872],"mapped",[109]],[[119873,119873],"mapped",[110]],[[119874,119874],"mapped",[111]],[[119875,119875],"mapped",[112]],[[119876,119876],"mapped",[113]],[[119877,119877],"mapped",[114]],[[119878,119878],"mapped",[115]],[[119879,119879],"mapped",[116]],[[119880,119880],"mapped",[117]],[[119881,119881],"mapped",[118]],[[119882,119882],"mapped",[119]],[[119883,119883],"mapped",[120]],[[119884,119884],"mapped",[121]],[[119885,119885],"mapped",[122]],[[119886,119886],"mapped",[97]],[[119887,119887],"mapped",[98]],[[119888,119888],"mapped",[99]],[[119889,119889],"mapped",[100]],[[119890,119890],"mapped",[101]],[[119891,119891],"mapped",[102]],[[119892,119892],"mapped",[103]],[[119893,119893],"disallowed"],[[119894,119894],"mapped",[105]],[[119895,119895],"mapped",[106]],[[119896,119896],"mapped",[107]],[[119897,119897],"mapped",[108]],[[119898,119898],"mapped",[109]],[[119899,119899],"mapped",[110]],[[119900,119900],"mapped",[111]],[[119901,119901],"mapped",[112]],[[119902,119902],"mapped",[113]],[[119903,119903],"mapped",[114]],[[119904,119904],"mapped",[115]],[[119905,119905],"mapped",[116]],[[119906,119906],"mapped",[117]],[[119907,119907],"mapped",[118]],[[119908,119908],"mapped",[119]],[[119909,119909],"mapped",[120]],[[119910,119910],"mapped",[121]],[[119911,119911],"mapped",[122]],[[119912,119912],"mapped",[97]],[[119913,119913],"mapped",[98]],[[119914,119914],"mapped",[99]],[[119915,119915],"mapped",[100]],[[119916,119916],"mapped",[101]],[[119917,119917],"mapped",[102]],[[119918,119918],"mapped",[103]],[[119919,119919],"mapped",[104]],[[119920,119920],"mapped",[105]],[[119921,119921],"mapped",[106]],[[119922,119922],"mapped",[107]],[[119923,119923],"mapped",[108]],[[119924,119924],"mapped",[109]],[[119925,119925],"mapped",[110]],[[119926,119926],"mapped",[111]],[[119927,119927],"mapped",[112]],[[119928,119928],"mapped",[113]],[[119929,119929],"mapped",[114]],[[119930,119930],"mapped",[115]],[[119931,119931],"mapped",[116]],[[119932,119932],"mapped",[117]],[[119933,119933],"mapped",[118]],[[119934,119934],"mapped",[119]],[[119935,119935],"mapped",[120]],[[119936,119936],"mapped",[121]],[[119937,119937],"mapped",[122]],[[119938,119938],"mapped",[97]],[[119939,119939],"mapped",[98]],[[119940,119940],"mapped",[99]],[[119941,119941],"mapped",[100]],[[119942,119942],"mapped",[101]],[[119943,119943],"mapped",[102]],[[119944,119944],"mapped",[103]],[[119945,119945],"mapped",[104]],[[119946,119946],"mapped",[105]],[[119947,119947],"mapped",[106]],[[119948,119948],"mapped",[107]],[[119949,119949],"mapped",[108]],[[119950,119950],"mapped",[109]],[[119951,119951],"mapped",[110]],[[119952,119952],"mapped",[111]],[[119953,119953],"mapped",[112]],[[119954,119954],"mapped",[113]],[[119955,119955],"mapped",[114]],[[119956,119956],"mapped",[115]],[[119957,119957],"mapped",[116]],[[119958,119958],"mapped",[117]],[[119959,119959],"mapped",[118]],[[119960,119960],"mapped",[119]],[[119961,119961],"mapped",[120]],[[119962,119962],"mapped",[121]],[[119963,119963],"mapped",[122]],[[119964,119964],"mapped",[97]],[[119965,119965],"disallowed"],[[119966,119966],"mapped",[99]],[[119967,119967],"mapped",[100]],[[119968,119969],"disallowed"],[[119970,119970],"mapped",[103]],[[119971,119972],"disallowed"],[[119973,119973],"mapped",[106]],[[119974,119974],"mapped",[107]],[[119975,119976],"disallowed"],[[119977,119977],"mapped",[110]],[[119978,119978],"mapped",[111]],[[119979,119979],"mapped",[112]],[[119980,119980],"mapped",[113]],[[119981,119981],"disallowed"],[[119982,119982],"mapped",[115]],[[119983,119983],"mapped",[116]],[[119984,119984],"mapped",[117]],[[119985,119985],"mapped",[118]],[[119986,119986],"mapped",[119]],[[119987,119987],"mapped",[120]],[[119988,119988],"mapped",[121]],[[119989,119989],"mapped",[122]],[[119990,119990],"mapped",[97]],[[119991,119991],"mapped",[98]],[[119992,119992],"mapped",[99]],[[119993,119993],"mapped",[100]],[[119994,119994],"disallowed"],[[119995,119995],"mapped",[102]],[[119996,119996],"disallowed"],[[119997,119997],"mapped",[104]],[[119998,119998],"mapped",[105]],[[119999,119999],"mapped",[106]],[[120000,120000],"mapped",[107]],[[120001,120001],"mapped",[108]],[[120002,120002],"mapped",[109]],[[120003,120003],"mapped",[110]],[[120004,120004],"disallowed"],[[120005,120005],"mapped",[112]],[[120006,120006],"mapped",[113]],[[120007,120007],"mapped",[114]],[[120008,120008],"mapped",[115]],[[120009,120009],"mapped",[116]],[[120010,120010],"mapped",[117]],[[120011,120011],"mapped",[118]],[[120012,120012],"mapped",[119]],[[120013,120013],"mapped",[120]],[[120014,120014],"mapped",[121]],[[120015,120015],"mapped",[122]],[[120016,120016],"mapped",[97]],[[120017,120017],"mapped",[98]],[[120018,120018],"mapped",[99]],[[120019,120019],"mapped",[100]],[[120020,120020],"mapped",[101]],[[120021,120021],"mapped",[102]],[[120022,120022],"mapped",[103]],[[120023,120023],"mapped",[104]],[[120024,120024],"mapped",[105]],[[120025,120025],"mapped",[106]],[[120026,120026],"mapped",[107]],[[120027,120027],"mapped",[108]],[[120028,120028],"mapped",[109]],[[120029,120029],"mapped",[110]],[[120030,120030],"mapped",[111]],[[120031,120031],"mapped",[112]],[[120032,120032],"mapped",[113]],[[120033,120033],"mapped",[114]],[[120034,120034],"mapped",[115]],[[120035,120035],"mapped",[116]],[[120036,120036],"mapped",[117]],[[120037,120037],"mapped",[118]],[[120038,120038],"mapped",[119]],[[120039,120039],"mapped",[120]],[[120040,120040],"mapped",[121]],[[120041,120041],"mapped",[122]],[[120042,120042],"mapped",[97]],[[120043,120043],"mapped",[98]],[[120044,120044],"mapped",[99]],[[120045,120045],"mapped",[100]],[[120046,120046],"mapped",[101]],[[120047,120047],"mapped",[102]],[[120048,120048],"mapped",[103]],[[120049,120049],"mapped",[104]],[[120050,120050],"mapped",[105]],[[120051,120051],"mapped",[106]],[[120052,120052],"mapped",[107]],[[120053,120053],"mapped",[108]],[[120054,120054],"mapped",[109]],[[120055,120055],"mapped",[110]],[[120056,120056],"mapped",[111]],[[120057,120057],"mapped",[112]],[[120058,120058],"mapped",[113]],[[120059,120059],"mapped",[114]],[[120060,120060],"mapped",[115]],[[120061,120061],"mapped",[116]],[[120062,120062],"mapped",[117]],[[120063,120063],"mapped",[118]],[[120064,120064],"mapped",[119]],[[120065,120065],"mapped",[120]],[[120066,120066],"mapped",[121]],[[120067,120067],"mapped",[122]],[[120068,120068],"mapped",[97]],[[120069,120069],"mapped",[98]],[[120070,120070],"disallowed"],[[120071,120071],"mapped",[100]],[[120072,120072],"mapped",[101]],[[120073,120073],"mapped",[102]],[[120074,120074],"mapped",[103]],[[120075,120076],"disallowed"],[[120077,120077],"mapped",[106]],[[120078,120078],"mapped",[107]],[[120079,120079],"mapped",[108]],[[120080,120080],"mapped",[109]],[[120081,120081],"mapped",[110]],[[120082,120082],"mapped",[111]],[[120083,120083],"mapped",[112]],[[120084,120084],"mapped",[113]],[[120085,120085],"disallowed"],[[120086,120086],"mapped",[115]],[[120087,120087],"mapped",[116]],[[120088,120088],"mapped",[117]],[[120089,120089],"mapped",[118]],[[120090,120090],"mapped",[119]],[[120091,120091],"mapped",[120]],[[120092,120092],"mapped",[121]],[[120093,120093],"disallowed"],[[120094,120094],"mapped",[97]],[[120095,120095],"mapped",[98]],[[120096,120096],"mapped",[99]],[[120097,120097],"mapped",[100]],[[120098,120098],"mapped",[101]],[[120099,120099],"mapped",[102]],[[120100,120100],"mapped",[103]],[[120101,120101],"mapped",[104]],[[120102,120102],"mapped",[105]],[[120103,120103],"mapped",[106]],[[120104,120104],"mapped",[107]],[[120105,120105],"mapped",[108]],[[120106,120106],"mapped",[109]],[[120107,120107],"mapped",[110]],[[120108,120108],"mapped",[111]],[[120109,120109],"mapped",[112]],[[120110,120110],"mapped",[113]],[[120111,120111],"mapped",[114]],[[120112,120112],"mapped",[115]],[[120113,120113],"mapped",[116]],[[120114,120114],"mapped",[117]],[[120115,120115],"mapped",[118]],[[120116,120116],"mapped",[119]],[[120117,120117],"mapped",[120]],[[120118,120118],"mapped",[121]],[[120119,120119],"mapped",[122]],[[120120,120120],"mapped",[97]],[[120121,120121],"mapped",[98]],[[120122,120122],"disallowed"],[[120123,120123],"mapped",[100]],[[120124,120124],"mapped",[101]],[[120125,120125],"mapped",[102]],[[120126,120126],"mapped",[103]],[[120127,120127],"disallowed"],[[120128,120128],"mapped",[105]],[[120129,120129],"mapped",[106]],[[120130,120130],"mapped",[107]],[[120131,120131],"mapped",[108]],[[120132,120132],"mapped",[109]],[[120133,120133],"disallowed"],[[120134,120134],"mapped",[111]],[[120135,120137],"disallowed"],[[120138,120138],"mapped",[115]],[[120139,120139],"mapped",[116]],[[120140,120140],"mapped",[117]],[[120141,120141],"mapped",[118]],[[120142,120142],"mapped",[119]],[[120143,120143],"mapped",[120]],[[120144,120144],"mapped",[121]],[[120145,120145],"disallowed"],[[120146,120146],"mapped",[97]],[[120147,120147],"mapped",[98]],[[120148,120148],"mapped",[99]],[[120149,120149],"mapped",[100]],[[120150,120150],"mapped",[101]],[[120151,120151],"mapped",[102]],[[120152,120152],"mapped",[103]],[[120153,120153],"mapped",[104]],[[120154,120154],"mapped",[105]],[[120155,120155],"mapped",[106]],[[120156,120156],"mapped",[107]],[[120157,120157],"mapped",[108]],[[120158,120158],"mapped",[109]],[[120159,120159],"mapped",[110]],[[120160,120160],"mapped",[111]],[[120161,120161],"mapped",[112]],[[120162,120162],"mapped",[113]],[[120163,120163],"mapped",[114]],[[120164,120164],"mapped",[115]],[[120165,120165],"mapped",[116]],[[120166,120166],"mapped",[117]],[[120167,120167],"mapped",[118]],[[120168,120168],"mapped",[119]],[[120169,120169],"mapped",[120]],[[120170,120170],"mapped",[121]],[[120171,120171],"mapped",[122]],[[120172,120172],"mapped",[97]],[[120173,120173],"mapped",[98]],[[120174,120174],"mapped",[99]],[[120175,120175],"mapped",[100]],[[120176,120176],"mapped",[101]],[[120177,120177],"mapped",[102]],[[120178,120178],"mapped",[103]],[[120179,120179],"mapped",[104]],[[120180,120180],"mapped",[105]],[[120181,120181],"mapped",[106]],[[120182,120182],"mapped",[107]],[[120183,120183],"mapped",[108]],[[120184,120184],"mapped",[109]],[[120185,120185],"mapped",[110]],[[120186,120186],"mapped",[111]],[[120187,120187],"mapped",[112]],[[120188,120188],"mapped",[113]],[[120189,120189],"mapped",[114]],[[120190,120190],"mapped",[115]],[[120191,120191],"mapped",[116]],[[120192,120192],"mapped",[117]],[[120193,120193],"mapped",[118]],[[120194,120194],"mapped",[119]],[[120195,120195],"mapped",[120]],[[120196,120196],"mapped",[121]],[[120197,120197],"mapped",[122]],[[120198,120198],"mapped",[97]],[[120199,120199],"mapped",[98]],[[120200,120200],"mapped",[99]],[[120201,120201],"mapped",[100]],[[120202,120202],"mapped",[101]],[[120203,120203],"mapped",[102]],[[120204,120204],"mapped",[103]],[[120205,120205],"mapped",[104]],[[120206,120206],"mapped",[105]],[[120207,120207],"mapped",[106]],[[120208,120208],"mapped",[107]],[[120209,120209],"mapped",[108]],[[120210,120210],"mapped",[109]],[[120211,120211],"mapped",[110]],[[120212,120212],"mapped",[111]],[[120213,120213],"mapped",[112]],[[120214,120214],"mapped",[113]],[[120215,120215],"mapped",[114]],[[120216,120216],"mapped",[115]],[[120217,120217],"mapped",[116]],[[120218,120218],"mapped",[117]],[[120219,120219],"mapped",[118]],[[120220,120220],"mapped",[119]],[[120221,120221],"mapped",[120]],[[120222,120222],"mapped",[121]],[[120223,120223],"mapped",[122]],[[120224,120224],"mapped",[97]],[[120225,120225],"mapped",[98]],[[120226,120226],"mapped",[99]],[[120227,120227],"mapped",[100]],[[120228,120228],"mapped",[101]],[[120229,120229],"mapped",[102]],[[120230,120230],"mapped",[103]],[[120231,120231],"mapped",[104]],[[120232,120232],"mapped",[105]],[[120233,120233],"mapped",[106]],[[120234,120234],"mapped",[107]],[[120235,120235],"mapped",[108]],[[120236,120236],"mapped",[109]],[[120237,120237],"mapped",[110]],[[120238,120238],"mapped",[111]],[[120239,120239],"mapped",[112]],[[120240,120240],"mapped",[113]],[[120241,120241],"mapped",[114]],[[120242,120242],"mapped",[115]],[[120243,120243],"mapped",[116]],[[120244,120244],"mapped",[117]],[[120245,120245],"mapped",[118]],[[120246,120246],"mapped",[119]],[[120247,120247],"mapped",[120]],[[120248,120248],"mapped",[121]],[[120249,120249],"mapped",[122]],[[120250,120250],"mapped",[97]],[[120251,120251],"mapped",[98]],[[120252,120252],"mapped",[99]],[[120253,120253],"mapped",[100]],[[120254,120254],"mapped",[101]],[[120255,120255],"mapped",[102]],[[120256,120256],"mapped",[103]],[[120257,120257],"mapped",[104]],[[120258,120258],"mapped",[105]],[[120259,120259],"mapped",[106]],[[120260,120260],"mapped",[107]],[[120261,120261],"mapped",[108]],[[120262,120262],"mapped",[109]],[[120263,120263],"mapped",[110]],[[120264,120264],"mapped",[111]],[[120265,120265],"mapped",[112]],[[120266,120266],"mapped",[113]],[[120267,120267],"mapped",[114]],[[120268,120268],"mapped",[115]],[[120269,120269],"mapped",[116]],[[120270,120270],"mapped",[117]],[[120271,120271],"mapped",[118]],[[120272,120272],"mapped",[119]],[[120273,120273],"mapped",[120]],[[120274,120274],"mapped",[121]],[[120275,120275],"mapped",[122]],[[120276,120276],"mapped",[97]],[[120277,120277],"mapped",[98]],[[120278,120278],"mapped",[99]],[[120279,120279],"mapped",[100]],[[120280,120280],"mapped",[101]],[[120281,120281],"mapped",[102]],[[120282,120282],"mapped",[103]],[[120283,120283],"mapped",[104]],[[120284,120284],"mapped",[105]],[[120285,120285],"mapped",[106]],[[120286,120286],"mapped",[107]],[[120287,120287],"mapped",[108]],[[120288,120288],"mapped",[109]],[[120289,120289],"mapped",[110]],[[120290,120290],"mapped",[111]],[[120291,120291],"mapped",[112]],[[120292,120292],"mapped",[113]],[[120293,120293],"mapped",[114]],[[120294,120294],"mapped",[115]],[[120295,120295],"mapped",[116]],[[120296,120296],"mapped",[117]],[[120297,120297],"mapped",[118]],[[120298,120298],"mapped",[119]],[[120299,120299],"mapped",[120]],[[120300,120300],"mapped",[121]],[[120301,120301],"mapped",[122]],[[120302,120302],"mapped",[97]],[[120303,120303],"mapped",[98]],[[120304,120304],"mapped",[99]],[[120305,120305],"mapped",[100]],[[120306,120306],"mapped",[101]],[[120307,120307],"mapped",[102]],[[120308,120308],"mapped",[103]],[[120309,120309],"mapped",[104]],[[120310,120310],"mapped",[105]],[[120311,120311],"mapped",[106]],[[120312,120312],"mapped",[107]],[[120313,120313],"mapped",[108]],[[120314,120314],"mapped",[109]],[[120315,120315],"mapped",[110]],[[120316,120316],"mapped",[111]],[[120317,120317],"mapped",[112]],[[120318,120318],"mapped",[113]],[[120319,120319],"mapped",[114]],[[120320,120320],"mapped",[115]],[[120321,120321],"mapped",[116]],[[120322,120322],"mapped",[117]],[[120323,120323],"mapped",[118]],[[120324,120324],"mapped",[119]],[[120325,120325],"mapped",[120]],[[120326,120326],"mapped",[121]],[[120327,120327],"mapped",[122]],[[120328,120328],"mapped",[97]],[[120329,120329],"mapped",[98]],[[120330,120330],"mapped",[99]],[[120331,120331],"mapped",[100]],[[120332,120332],"mapped",[101]],[[120333,120333],"mapped",[102]],[[120334,120334],"mapped",[103]],[[120335,120335],"mapped",[104]],[[120336,120336],"mapped",[105]],[[120337,120337],"mapped",[106]],[[120338,120338],"mapped",[107]],[[120339,120339],"mapped",[108]],[[120340,120340],"mapped",[109]],[[120341,120341],"mapped",[110]],[[120342,120342],"mapped",[111]],[[120343,120343],"mapped",[112]],[[120344,120344],"mapped",[113]],[[120345,120345],"mapped",[114]],[[120346,120346],"mapped",[115]],[[120347,120347],"mapped",[116]],[[120348,120348],"mapped",[117]],[[120349,120349],"mapped",[118]],[[120350,120350],"mapped",[119]],[[120351,120351],"mapped",[120]],[[120352,120352],"mapped",[121]],[[120353,120353],"mapped",[122]],[[120354,120354],"mapped",[97]],[[120355,120355],"mapped",[98]],[[120356,120356],"mapped",[99]],[[120357,120357],"mapped",[100]],[[120358,120358],"mapped",[101]],[[120359,120359],"mapped",[102]],[[120360,120360],"mapped",[103]],[[120361,120361],"mapped",[104]],[[120362,120362],"mapped",[105]],[[120363,120363],"mapped",[106]],[[120364,120364],"mapped",[107]],[[120365,120365],"mapped",[108]],[[120366,120366],"mapped",[109]],[[120367,120367],"mapped",[110]],[[120368,120368],"mapped",[111]],[[120369,120369],"mapped",[112]],[[120370,120370],"mapped",[113]],[[120371,120371],"mapped",[114]],[[120372,120372],"mapped",[115]],[[120373,120373],"mapped",[116]],[[120374,120374],"mapped",[117]],[[120375,120375],"mapped",[118]],[[120376,120376],"mapped",[119]],[[120377,120377],"mapped",[120]],[[120378,120378],"mapped",[121]],[[120379,120379],"mapped",[122]],[[120380,120380],"mapped",[97]],[[120381,120381],"mapped",[98]],[[120382,120382],"mapped",[99]],[[120383,120383],"mapped",[100]],[[120384,120384],"mapped",[101]],[[120385,120385],"mapped",[102]],[[120386,120386],"mapped",[103]],[[120387,120387],"mapped",[104]],[[120388,120388],"mapped",[105]],[[120389,120389],"mapped",[106]],[[120390,120390],"mapped",[107]],[[120391,120391],"mapped",[108]],[[120392,120392],"mapped",[109]],[[120393,120393],"mapped",[110]],[[120394,120394],"mapped",[111]],[[120395,120395],"mapped",[112]],[[120396,120396],"mapped",[113]],[[120397,120397],"mapped",[114]],[[120398,120398],"mapped",[115]],[[120399,120399],"mapped",[116]],[[120400,120400],"mapped",[117]],[[120401,120401],"mapped",[118]],[[120402,120402],"mapped",[119]],[[120403,120403],"mapped",[120]],[[120404,120404],"mapped",[121]],[[120405,120405],"mapped",[122]],[[120406,120406],"mapped",[97]],[[120407,120407],"mapped",[98]],[[120408,120408],"mapped",[99]],[[120409,120409],"mapped",[100]],[[120410,120410],"mapped",[101]],[[120411,120411],"mapped",[102]],[[120412,120412],"mapped",[103]],[[120413,120413],"mapped",[104]],[[120414,120414],"mapped",[105]],[[120415,120415],"mapped",[106]],[[120416,120416],"mapped",[107]],[[120417,120417],"mapped",[108]],[[120418,120418],"mapped",[109]],[[120419,120419],"mapped",[110]],[[120420,120420],"mapped",[111]],[[120421,120421],"mapped",[112]],[[120422,120422],"mapped",[113]],[[120423,120423],"mapped",[114]],[[120424,120424],"mapped",[115]],[[120425,120425],"mapped",[116]],[[120426,120426],"mapped",[117]],[[120427,120427],"mapped",[118]],[[120428,120428],"mapped",[119]],[[120429,120429],"mapped",[120]],[[120430,120430],"mapped",[121]],[[120431,120431],"mapped",[122]],[[120432,120432],"mapped",[97]],[[120433,120433],"mapped",[98]],[[120434,120434],"mapped",[99]],[[120435,120435],"mapped",[100]],[[120436,120436],"mapped",[101]],[[120437,120437],"mapped",[102]],[[120438,120438],"mapped",[103]],[[120439,120439],"mapped",[104]],[[120440,120440],"mapped",[105]],[[120441,120441],"mapped",[106]],[[120442,120442],"mapped",[107]],[[120443,120443],"mapped",[108]],[[120444,120444],"mapped",[109]],[[120445,120445],"mapped",[110]],[[120446,120446],"mapped",[111]],[[120447,120447],"mapped",[112]],[[120448,120448],"mapped",[113]],[[120449,120449],"mapped",[114]],[[120450,120450],"mapped",[115]],[[120451,120451],"mapped",[116]],[[120452,120452],"mapped",[117]],[[120453,120453],"mapped",[118]],[[120454,120454],"mapped",[119]],[[120455,120455],"mapped",[120]],[[120456,120456],"mapped",[121]],[[120457,120457],"mapped",[122]],[[120458,120458],"mapped",[97]],[[120459,120459],"mapped",[98]],[[120460,120460],"mapped",[99]],[[120461,120461],"mapped",[100]],[[120462,120462],"mapped",[101]],[[120463,120463],"mapped",[102]],[[120464,120464],"mapped",[103]],[[120465,120465],"mapped",[104]],[[120466,120466],"mapped",[105]],[[120467,120467],"mapped",[106]],[[120468,120468],"mapped",[107]],[[120469,120469],"mapped",[108]],[[120470,120470],"mapped",[109]],[[120471,120471],"mapped",[110]],[[120472,120472],"mapped",[111]],[[120473,120473],"mapped",[112]],[[120474,120474],"mapped",[113]],[[120475,120475],"mapped",[114]],[[120476,120476],"mapped",[115]],[[120477,120477],"mapped",[116]],[[120478,120478],"mapped",[117]],[[120479,120479],"mapped",[118]],[[120480,120480],"mapped",[119]],[[120481,120481],"mapped",[120]],[[120482,120482],"mapped",[121]],[[120483,120483],"mapped",[122]],[[120484,120484],"mapped",[305]],[[120485,120485],"mapped",[567]],[[120486,120487],"disallowed"],[[120488,120488],"mapped",[945]],[[120489,120489],"mapped",[946]],[[120490,120490],"mapped",[947]],[[120491,120491],"mapped",[948]],[[120492,120492],"mapped",[949]],[[120493,120493],"mapped",[950]],[[120494,120494],"mapped",[951]],[[120495,120495],"mapped",[952]],[[120496,120496],"mapped",[953]],[[120497,120497],"mapped",[954]],[[120498,120498],"mapped",[955]],[[120499,120499],"mapped",[956]],[[120500,120500],"mapped",[957]],[[120501,120501],"mapped",[958]],[[120502,120502],"mapped",[959]],[[120503,120503],"mapped",[960]],[[120504,120504],"mapped",[961]],[[120505,120505],"mapped",[952]],[[120506,120506],"mapped",[963]],[[120507,120507],"mapped",[964]],[[120508,120508],"mapped",[965]],[[120509,120509],"mapped",[966]],[[120510,120510],"mapped",[967]],[[120511,120511],"mapped",[968]],[[120512,120512],"mapped",[969]],[[120513,120513],"mapped",[8711]],[[120514,120514],"mapped",[945]],[[120515,120515],"mapped",[946]],[[120516,120516],"mapped",[947]],[[120517,120517],"mapped",[948]],[[120518,120518],"mapped",[949]],[[120519,120519],"mapped",[950]],[[120520,120520],"mapped",[951]],[[120521,120521],"mapped",[952]],[[120522,120522],"mapped",[953]],[[120523,120523],"mapped",[954]],[[120524,120524],"mapped",[955]],[[120525,120525],"mapped",[956]],[[120526,120526],"mapped",[957]],[[120527,120527],"mapped",[958]],[[120528,120528],"mapped",[959]],[[120529,120529],"mapped",[960]],[[120530,120530],"mapped",[961]],[[120531,120532],"mapped",[963]],[[120533,120533],"mapped",[964]],[[120534,120534],"mapped",[965]],[[120535,120535],"mapped",[966]],[[120536,120536],"mapped",[967]],[[120537,120537],"mapped",[968]],[[120538,120538],"mapped",[969]],[[120539,120539],"mapped",[8706]],[[120540,120540],"mapped",[949]],[[120541,120541],"mapped",[952]],[[120542,120542],"mapped",[954]],[[120543,120543],"mapped",[966]],[[120544,120544],"mapped",[961]],[[120545,120545],"mapped",[960]],[[120546,120546],"mapped",[945]],[[120547,120547],"mapped",[946]],[[120548,120548],"mapped",[947]],[[120549,120549],"mapped",[948]],[[120550,120550],"mapped",[949]],[[120551,120551],"mapped",[950]],[[120552,120552],"mapped",[951]],[[120553,120553],"mapped",[952]],[[120554,120554],"mapped",[953]],[[120555,120555],"mapped",[954]],[[120556,120556],"mapped",[955]],[[120557,120557],"mapped",[956]],[[120558,120558],"mapped",[957]],[[120559,120559],"mapped",[958]],[[120560,120560],"mapped",[959]],[[120561,120561],"mapped",[960]],[[120562,120562],"mapped",[961]],[[120563,120563],"mapped",[952]],[[120564,120564],"mapped",[963]],[[120565,120565],"mapped",[964]],[[120566,120566],"mapped",[965]],[[120567,120567],"mapped",[966]],[[120568,120568],"mapped",[967]],[[120569,120569],"mapped",[968]],[[120570,120570],"mapped",[969]],[[120571,120571],"mapped",[8711]],[[120572,120572],"mapped",[945]],[[120573,120573],"mapped",[946]],[[120574,120574],"mapped",[947]],[[120575,120575],"mapped",[948]],[[120576,120576],"mapped",[949]],[[120577,120577],"mapped",[950]],[[120578,120578],"mapped",[951]],[[120579,120579],"mapped",[952]],[[120580,120580],"mapped",[953]],[[120581,120581],"mapped",[954]],[[120582,120582],"mapped",[955]],[[120583,120583],"mapped",[956]],[[120584,120584],"mapped",[957]],[[120585,120585],"mapped",[958]],[[120586,120586],"mapped",[959]],[[120587,120587],"mapped",[960]],[[120588,120588],"mapped",[961]],[[120589,120590],"mapped",[963]],[[120591,120591],"mapped",[964]],[[120592,120592],"mapped",[965]],[[120593,120593],"mapped",[966]],[[120594,120594],"mapped",[967]],[[120595,120595],"mapped",[968]],[[120596,120596],"mapped",[969]],[[120597,120597],"mapped",[8706]],[[120598,120598],"mapped",[949]],[[120599,120599],"mapped",[952]],[[120600,120600],"mapped",[954]],[[120601,120601],"mapped",[966]],[[120602,120602],"mapped",[961]],[[120603,120603],"mapped",[960]],[[120604,120604],"mapped",[945]],[[120605,120605],"mapped",[946]],[[120606,120606],"mapped",[947]],[[120607,120607],"mapped",[948]],[[120608,120608],"mapped",[949]],[[120609,120609],"mapped",[950]],[[120610,120610],"mapped",[951]],[[120611,120611],"mapped",[952]],[[120612,120612],"mapped",[953]],[[120613,120613],"mapped",[954]],[[120614,120614],"mapped",[955]],[[120615,120615],"mapped",[956]],[[120616,120616],"mapped",[957]],[[120617,120617],"mapped",[958]],[[120618,120618],"mapped",[959]],[[120619,120619],"mapped",[960]],[[120620,120620],"mapped",[961]],[[120621,120621],"mapped",[952]],[[120622,120622],"mapped",[963]],[[120623,120623],"mapped",[964]],[[120624,120624],"mapped",[965]],[[120625,120625],"mapped",[966]],[[120626,120626],"mapped",[967]],[[120627,120627],"mapped",[968]],[[120628,120628],"mapped",[969]],[[120629,120629],"mapped",[8711]],[[120630,120630],"mapped",[945]],[[120631,120631],"mapped",[946]],[[120632,120632],"mapped",[947]],[[120633,120633],"mapped",[948]],[[120634,120634],"mapped",[949]],[[120635,120635],"mapped",[950]],[[120636,120636],"mapped",[951]],[[120637,120637],"mapped",[952]],[[120638,120638],"mapped",[953]],[[120639,120639],"mapped",[954]],[[120640,120640],"mapped",[955]],[[120641,120641],"mapped",[956]],[[120642,120642],"mapped",[957]],[[120643,120643],"mapped",[958]],[[120644,120644],"mapped",[959]],[[120645,120645],"mapped",[960]],[[120646,120646],"mapped",[961]],[[120647,120648],"mapped",[963]],[[120649,120649],"mapped",[964]],[[120650,120650],"mapped",[965]],[[120651,120651],"mapped",[966]],[[120652,120652],"mapped",[967]],[[120653,120653],"mapped",[968]],[[120654,120654],"mapped",[969]],[[120655,120655],"mapped",[8706]],[[120656,120656],"mapped",[949]],[[120657,120657],"mapped",[952]],[[120658,120658],"mapped",[954]],[[120659,120659],"mapped",[966]],[[120660,120660],"mapped",[961]],[[120661,120661],"mapped",[960]],[[120662,120662],"mapped",[945]],[[120663,120663],"mapped",[946]],[[120664,120664],"mapped",[947]],[[120665,120665],"mapped",[948]],[[120666,120666],"mapped",[949]],[[120667,120667],"mapped",[950]],[[120668,120668],"mapped",[951]],[[120669,120669],"mapped",[952]],[[120670,120670],"mapped",[953]],[[120671,120671],"mapped",[954]],[[120672,120672],"mapped",[955]],[[120673,120673],"mapped",[956]],[[120674,120674],"mapped",[957]],[[120675,120675],"mapped",[958]],[[120676,120676],"mapped",[959]],[[120677,120677],"mapped",[960]],[[120678,120678],"mapped",[961]],[[120679,120679],"mapped",[952]],[[120680,120680],"mapped",[963]],[[120681,120681],"mapped",[964]],[[120682,120682],"mapped",[965]],[[120683,120683],"mapped",[966]],[[120684,120684],"mapped",[967]],[[120685,120685],"mapped",[968]],[[120686,120686],"mapped",[969]],[[120687,120687],"mapped",[8711]],[[120688,120688],"mapped",[945]],[[120689,120689],"mapped",[946]],[[120690,120690],"mapped",[947]],[[120691,120691],"mapped",[948]],[[120692,120692],"mapped",[949]],[[120693,120693],"mapped",[950]],[[120694,120694],"mapped",[951]],[[120695,120695],"mapped",[952]],[[120696,120696],"mapped",[953]],[[120697,120697],"mapped",[954]],[[120698,120698],"mapped",[955]],[[120699,120699],"mapped",[956]],[[120700,120700],"mapped",[957]],[[120701,120701],"mapped",[958]],[[120702,120702],"mapped",[959]],[[120703,120703],"mapped",[960]],[[120704,120704],"mapped",[961]],[[120705,120706],"mapped",[963]],[[120707,120707],"mapped",[964]],[[120708,120708],"mapped",[965]],[[120709,120709],"mapped",[966]],[[120710,120710],"mapped",[967]],[[120711,120711],"mapped",[968]],[[120712,120712],"mapped",[969]],[[120713,120713],"mapped",[8706]],[[120714,120714],"mapped",[949]],[[120715,120715],"mapped",[952]],[[120716,120716],"mapped",[954]],[[120717,120717],"mapped",[966]],[[120718,120718],"mapped",[961]],[[120719,120719],"mapped",[960]],[[120720,120720],"mapped",[945]],[[120721,120721],"mapped",[946]],[[120722,120722],"mapped",[947]],[[120723,120723],"mapped",[948]],[[120724,120724],"mapped",[949]],[[120725,120725],"mapped",[950]],[[120726,120726],"mapped",[951]],[[120727,120727],"mapped",[952]],[[120728,120728],"mapped",[953]],[[120729,120729],"mapped",[954]],[[120730,120730],"mapped",[955]],[[120731,120731],"mapped",[956]],[[120732,120732],"mapped",[957]],[[120733,120733],"mapped",[958]],[[120734,120734],"mapped",[959]],[[120735,120735],"mapped",[960]],[[120736,120736],"mapped",[961]],[[120737,120737],"mapped",[952]],[[120738,120738],"mapped",[963]],[[120739,120739],"mapped",[964]],[[120740,120740],"mapped",[965]],[[120741,120741],"mapped",[966]],[[120742,120742],"mapped",[967]],[[120743,120743],"mapped",[968]],[[120744,120744],"mapped",[969]],[[120745,120745],"mapped",[8711]],[[120746,120746],"mapped",[945]],[[120747,120747],"mapped",[946]],[[120748,120748],"mapped",[947]],[[120749,120749],"mapped",[948]],[[120750,120750],"mapped",[949]],[[120751,120751],"mapped",[950]],[[120752,120752],"mapped",[951]],[[120753,120753],"mapped",[952]],[[120754,120754],"mapped",[953]],[[120755,120755],"mapped",[954]],[[120756,120756],"mapped",[955]],[[120757,120757],"mapped",[956]],[[120758,120758],"mapped",[957]],[[120759,120759],"mapped",[958]],[[120760,120760],"mapped",[959]],[[120761,120761],"mapped",[960]],[[120762,120762],"mapped",[961]],[[120763,120764],"mapped",[963]],[[120765,120765],"mapped",[964]],[[120766,120766],"mapped",[965]],[[120767,120767],"mapped",[966]],[[120768,120768],"mapped",[967]],[[120769,120769],"mapped",[968]],[[120770,120770],"mapped",[969]],[[120771,120771],"mapped",[8706]],[[120772,120772],"mapped",[949]],[[120773,120773],"mapped",[952]],[[120774,120774],"mapped",[954]],[[120775,120775],"mapped",[966]],[[120776,120776],"mapped",[961]],[[120777,120777],"mapped",[960]],[[120778,120779],"mapped",[989]],[[120780,120781],"disallowed"],[[120782,120782],"mapped",[48]],[[120783,120783],"mapped",[49]],[[120784,120784],"mapped",[50]],[[120785,120785],"mapped",[51]],[[120786,120786],"mapped",[52]],[[120787,120787],"mapped",[53]],[[120788,120788],"mapped",[54]],[[120789,120789],"mapped",[55]],[[120790,120790],"mapped",[56]],[[120791,120791],"mapped",[57]],[[120792,120792],"mapped",[48]],[[120793,120793],"mapped",[49]],[[120794,120794],"mapped",[50]],[[120795,120795],"mapped",[51]],[[120796,120796],"mapped",[52]],[[120797,120797],"mapped",[53]],[[120798,120798],"mapped",[54]],[[120799,120799],"mapped",[55]],[[120800,120800],"mapped",[56]],[[120801,120801],"mapped",[57]],[[120802,120802],"mapped",[48]],[[120803,120803],"mapped",[49]],[[120804,120804],"mapped",[50]],[[120805,120805],"mapped",[51]],[[120806,120806],"mapped",[52]],[[120807,120807],"mapped",[53]],[[120808,120808],"mapped",[54]],[[120809,120809],"mapped",[55]],[[120810,120810],"mapped",[56]],[[120811,120811],"mapped",[57]],[[120812,120812],"mapped",[48]],[[120813,120813],"mapped",[49]],[[120814,120814],"mapped",[50]],[[120815,120815],"mapped",[51]],[[120816,120816],"mapped",[52]],[[120817,120817],"mapped",[53]],[[120818,120818],"mapped",[54]],[[120819,120819],"mapped",[55]],[[120820,120820],"mapped",[56]],[[120821,120821],"mapped",[57]],[[120822,120822],"mapped",[48]],[[120823,120823],"mapped",[49]],[[120824,120824],"mapped",[50]],[[120825,120825],"mapped",[51]],[[120826,120826],"mapped",[52]],[[120827,120827],"mapped",[53]],[[120828,120828],"mapped",[54]],[[120829,120829],"mapped",[55]],[[120830,120830],"mapped",[56]],[[120831,120831],"mapped",[57]],[[120832,121343],"valid",[],"NV8"],[[121344,121398],"valid"],[[121399,121402],"valid",[],"NV8"],[[121403,121452],"valid"],[[121453,121460],"valid",[],"NV8"],[[121461,121461],"valid"],[[121462,121475],"valid",[],"NV8"],[[121476,121476],"valid"],[[121477,121483],"valid",[],"NV8"],[[121484,121498],"disallowed"],[[121499,121503],"valid"],[[121504,121504],"disallowed"],[[121505,121519],"valid"],[[121520,124927],"disallowed"],[[124928,125124],"valid"],[[125125,125126],"disallowed"],[[125127,125135],"valid",[],"NV8"],[[125136,125142],"valid"],[[125143,126463],"disallowed"],[[126464,126464],"mapped",[1575]],[[126465,126465],"mapped",[1576]],[[126466,126466],"mapped",[1580]],[[126467,126467],"mapped",[1583]],[[126468,126468],"disallowed"],[[126469,126469],"mapped",[1608]],[[126470,126470],"mapped",[1586]],[[126471,126471],"mapped",[1581]],[[126472,126472],"mapped",[1591]],[[126473,126473],"mapped",[1610]],[[126474,126474],"mapped",[1603]],[[126475,126475],"mapped",[1604]],[[126476,126476],"mapped",[1605]],[[126477,126477],"mapped",[1606]],[[126478,126478],"mapped",[1587]],[[126479,126479],"mapped",[1593]],[[126480,126480],"mapped",[1601]],[[126481,126481],"mapped",[1589]],[[126482,126482],"mapped",[1602]],[[126483,126483],"mapped",[1585]],[[126484,126484],"mapped",[1588]],[[126485,126485],"mapped",[1578]],[[126486,126486],"mapped",[1579]],[[126487,126487],"mapped",[1582]],[[126488,126488],"mapped",[1584]],[[126489,126489],"mapped",[1590]],[[126490,126490],"mapped",[1592]],[[126491,126491],"mapped",[1594]],[[126492,126492],"mapped",[1646]],[[126493,126493],"mapped",[1722]],[[126494,126494],"mapped",[1697]],[[126495,126495],"mapped",[1647]],[[126496,126496],"disallowed"],[[126497,126497],"mapped",[1576]],[[126498,126498],"mapped",[1580]],[[126499,126499],"disallowed"],[[126500,126500],"mapped",[1607]],[[126501,126502],"disallowed"],[[126503,126503],"mapped",[1581]],[[126504,126504],"disallowed"],[[126505,126505],"mapped",[1610]],[[126506,126506],"mapped",[1603]],[[126507,126507],"mapped",[1604]],[[126508,126508],"mapped",[1605]],[[126509,126509],"mapped",[1606]],[[126510,126510],"mapped",[1587]],[[126511,126511],"mapped",[1593]],[[126512,126512],"mapped",[1601]],[[126513,126513],"mapped",[1589]],[[126514,126514],"mapped",[1602]],[[126515,126515],"disallowed"],[[126516,126516],"mapped",[1588]],[[126517,126517],"mapped",[1578]],[[126518,126518],"mapped",[1579]],[[126519,126519],"mapped",[1582]],[[126520,126520],"disallowed"],[[126521,126521],"mapped",[1590]],[[126522,126522],"disallowed"],[[126523,126523],"mapped",[1594]],[[126524,126529],"disallowed"],[[126530,126530],"mapped",[1580]],[[126531,126534],"disallowed"],[[126535,126535],"mapped",[1581]],[[126536,126536],"disallowed"],[[126537,126537],"mapped",[1610]],[[126538,126538],"disallowed"],[[126539,126539],"mapped",[1604]],[[126540,126540],"disallowed"],[[126541,126541],"mapped",[1606]],[[126542,126542],"mapped",[1587]],[[126543,126543],"mapped",[1593]],[[126544,126544],"disallowed"],[[126545,126545],"mapped",[1589]],[[126546,126546],"mapped",[1602]],[[126547,126547],"disallowed"],[[126548,126548],"mapped",[1588]],[[126549,126550],"disallowed"],[[126551,126551],"mapped",[1582]],[[126552,126552],"disallowed"],[[126553,126553],"mapped",[1590]],[[126554,126554],"disallowed"],[[126555,126555],"mapped",[1594]],[[126556,126556],"disallowed"],[[126557,126557],"mapped",[1722]],[[126558,126558],"disallowed"],[[126559,126559],"mapped",[1647]],[[126560,126560],"disallowed"],[[126561,126561],"mapped",[1576]],[[126562,126562],"mapped",[1580]],[[126563,126563],"disallowed"],[[126564,126564],"mapped",[1607]],[[126565,126566],"disallowed"],[[126567,126567],"mapped",[1581]],[[126568,126568],"mapped",[1591]],[[126569,126569],"mapped",[1610]],[[126570,126570],"mapped",[1603]],[[126571,126571],"disallowed"],[[126572,126572],"mapped",[1605]],[[126573,126573],"mapped",[1606]],[[126574,126574],"mapped",[1587]],[[126575,126575],"mapped",[1593]],[[126576,126576],"mapped",[1601]],[[126577,126577],"mapped",[1589]],[[126578,126578],"mapped",[1602]],[[126579,126579],"disallowed"],[[126580,126580],"mapped",[1588]],[[126581,126581],"mapped",[1578]],[[126582,126582],"mapped",[1579]],[[126583,126583],"mapped",[1582]],[[126584,126584],"disallowed"],[[126585,126585],"mapped",[1590]],[[126586,126586],"mapped",[1592]],[[126587,126587],"mapped",[1594]],[[126588,126588],"mapped",[1646]],[[126589,126589],"disallowed"],[[126590,126590],"mapped",[1697]],[[126591,126591],"disallowed"],[[126592,126592],"mapped",[1575]],[[126593,126593],"mapped",[1576]],[[126594,126594],"mapped",[1580]],[[126595,126595],"mapped",[1583]],[[126596,126596],"mapped",[1607]],[[126597,126597],"mapped",[1608]],[[126598,126598],"mapped",[1586]],[[126599,126599],"mapped",[1581]],[[126600,126600],"mapped",[1591]],[[126601,126601],"mapped",[1610]],[[126602,126602],"disallowed"],[[126603,126603],"mapped",[1604]],[[126604,126604],"mapped",[1605]],[[126605,126605],"mapped",[1606]],[[126606,126606],"mapped",[1587]],[[126607,126607],"mapped",[1593]],[[126608,126608],"mapped",[1601]],[[126609,126609],"mapped",[1589]],[[126610,126610],"mapped",[1602]],[[126611,126611],"mapped",[1585]],[[126612,126612],"mapped",[1588]],[[126613,126613],"mapped",[1578]],[[126614,126614],"mapped",[1579]],[[126615,126615],"mapped",[1582]],[[126616,126616],"mapped",[1584]],[[126617,126617],"mapped",[1590]],[[126618,126618],"mapped",[1592]],[[126619,126619],"mapped",[1594]],[[126620,126624],"disallowed"],[[126625,126625],"mapped",[1576]],[[126626,126626],"mapped",[1580]],[[126627,126627],"mapped",[1583]],[[126628,126628],"disallowed"],[[126629,126629],"mapped",[1608]],[[126630,126630],"mapped",[1586]],[[126631,126631],"mapped",[1581]],[[126632,126632],"mapped",[1591]],[[126633,126633],"mapped",[1610]],[[126634,126634],"disallowed"],[[126635,126635],"mapped",[1604]],[[126636,126636],"mapped",[1605]],[[126637,126637],"mapped",[1606]],[[126638,126638],"mapped",[1587]],[[126639,126639],"mapped",[1593]],[[126640,126640],"mapped",[1601]],[[126641,126641],"mapped",[1589]],[[126642,126642],"mapped",[1602]],[[126643,126643],"mapped",[1585]],[[126644,126644],"mapped",[1588]],[[126645,126645],"mapped",[1578]],[[126646,126646],"mapped",[1579]],[[126647,126647],"mapped",[1582]],[[126648,126648],"mapped",[1584]],[[126649,126649],"mapped",[1590]],[[126650,126650],"mapped",[1592]],[[126651,126651],"mapped",[1594]],[[126652,126703],"disallowed"],[[126704,126705],"valid",[],"NV8"],[[126706,126975],"disallowed"],[[126976,127019],"valid",[],"NV8"],[[127020,127023],"disallowed"],[[127024,127123],"valid",[],"NV8"],[[127124,127135],"disallowed"],[[127136,127150],"valid",[],"NV8"],[[127151,127152],"disallowed"],[[127153,127166],"valid",[],"NV8"],[[127167,127167],"valid",[],"NV8"],[[127168,127168],"disallowed"],[[127169,127183],"valid",[],"NV8"],[[127184,127184],"disallowed"],[[127185,127199],"valid",[],"NV8"],[[127200,127221],"valid",[],"NV8"],[[127222,127231],"disallowed"],[[127232,127232],"disallowed"],[[127233,127233],"disallowed_STD3_mapped",[48,44]],[[127234,127234],"disallowed_STD3_mapped",[49,44]],[[127235,127235],"disallowed_STD3_mapped",[50,44]],[[127236,127236],"disallowed_STD3_mapped",[51,44]],[[127237,127237],"disallowed_STD3_mapped",[52,44]],[[127238,127238],"disallowed_STD3_mapped",[53,44]],[[127239,127239],"disallowed_STD3_mapped",[54,44]],[[127240,127240],"disallowed_STD3_mapped",[55,44]],[[127241,127241],"disallowed_STD3_mapped",[56,44]],[[127242,127242],"disallowed_STD3_mapped",[57,44]],[[127243,127244],"valid",[],"NV8"],[[127245,127247],"disallowed"],[[127248,127248],"disallowed_STD3_mapped",[40,97,41]],[[127249,127249],"disallowed_STD3_mapped",[40,98,41]],[[127250,127250],"disallowed_STD3_mapped",[40,99,41]],[[127251,127251],"disallowed_STD3_mapped",[40,100,41]],[[127252,127252],"disallowed_STD3_mapped",[40,101,41]],[[127253,127253],"disallowed_STD3_mapped",[40,102,41]],[[127254,127254],"disallowed_STD3_mapped",[40,103,41]],[[127255,127255],"disallowed_STD3_mapped",[40,104,41]],[[127256,127256],"disallowed_STD3_mapped",[40,105,41]],[[127257,127257],"disallowed_STD3_mapped",[40,106,41]],[[127258,127258],"disallowed_STD3_mapped",[40,107,41]],[[127259,127259],"disallowed_STD3_mapped",[40,108,41]],[[127260,127260],"disallowed_STD3_mapped",[40,109,41]],[[127261,127261],"disallowed_STD3_mapped",[40,110,41]],[[127262,127262],"disallowed_STD3_mapped",[40,111,41]],[[127263,127263],"disallowed_STD3_mapped",[40,112,41]],[[127264,127264],"disallowed_STD3_mapped",[40,113,41]],[[127265,127265],"disallowed_STD3_mapped",[40,114,41]],[[127266,127266],"disallowed_STD3_mapped",[40,115,41]],[[127267,127267],"disallowed_STD3_mapped",[40,116,41]],[[127268,127268],"disallowed_STD3_mapped",[40,117,41]],[[127269,127269],"disallowed_STD3_mapped",[40,118,41]],[[127270,127270],"disallowed_STD3_mapped",[40,119,41]],[[127271,127271],"disallowed_STD3_mapped",[40,120,41]],[[127272,127272],"disallowed_STD3_mapped",[40,121,41]],[[127273,127273],"disallowed_STD3_mapped",[40,122,41]],[[127274,127274],"mapped",[12308,115,12309]],[[127275,127275],"mapped",[99]],[[127276,127276],"mapped",[114]],[[127277,127277],"mapped",[99,100]],[[127278,127278],"mapped",[119,122]],[[127279,127279],"disallowed"],[[127280,127280],"mapped",[97]],[[127281,127281],"mapped",[98]],[[127282,127282],"mapped",[99]],[[127283,127283],"mapped",[100]],[[127284,127284],"mapped",[101]],[[127285,127285],"mapped",[102]],[[127286,127286],"mapped",[103]],[[127287,127287],"mapped",[104]],[[127288,127288],"mapped",[105]],[[127289,127289],"mapped",[106]],[[127290,127290],"mapped",[107]],[[127291,127291],"mapped",[108]],[[127292,127292],"mapped",[109]],[[127293,127293],"mapped",[110]],[[127294,127294],"mapped",[111]],[[127295,127295],"mapped",[112]],[[127296,127296],"mapped",[113]],[[127297,127297],"mapped",[114]],[[127298,127298],"mapped",[115]],[[127299,127299],"mapped",[116]],[[127300,127300],"mapped",[117]],[[127301,127301],"mapped",[118]],[[127302,127302],"mapped",[119]],[[127303,127303],"mapped",[120]],[[127304,127304],"mapped",[121]],[[127305,127305],"mapped",[122]],[[127306,127306],"mapped",[104,118]],[[127307,127307],"mapped",[109,118]],[[127308,127308],"mapped",[115,100]],[[127309,127309],"mapped",[115,115]],[[127310,127310],"mapped",[112,112,118]],[[127311,127311],"mapped",[119,99]],[[127312,127318],"valid",[],"NV8"],[[127319,127319],"valid",[],"NV8"],[[127320,127326],"valid",[],"NV8"],[[127327,127327],"valid",[],"NV8"],[[127328,127337],"valid",[],"NV8"],[[127338,127338],"mapped",[109,99]],[[127339,127339],"mapped",[109,100]],[[127340,127343],"disallowed"],[[127344,127352],"valid",[],"NV8"],[[127353,127353],"valid",[],"NV8"],[[127354,127354],"valid",[],"NV8"],[[127355,127356],"valid",[],"NV8"],[[127357,127358],"valid",[],"NV8"],[[127359,127359],"valid",[],"NV8"],[[127360,127369],"valid",[],"NV8"],[[127370,127373],"valid",[],"NV8"],[[127374,127375],"valid",[],"NV8"],[[127376,127376],"mapped",[100,106]],[[127377,127386],"valid",[],"NV8"],[[127387,127461],"disallowed"],[[127462,127487],"valid",[],"NV8"],[[127488,127488],"mapped",[12411,12363]],[[127489,127489],"mapped",[12467,12467]],[[127490,127490],"mapped",[12469]],[[127491,127503],"disallowed"],[[127504,127504],"mapped",[25163]],[[127505,127505],"mapped",[23383]],[[127506,127506],"mapped",[21452]],[[127507,127507],"mapped",[12487]],[[127508,127508],"mapped",[20108]],[[127509,127509],"mapped",[22810]],[[127510,127510],"mapped",[35299]],[[127511,127511],"mapped",[22825]],[[127512,127512],"mapped",[20132]],[[127513,127513],"mapped",[26144]],[[127514,127514],"mapped",[28961]],[[127515,127515],"mapped",[26009]],[[127516,127516],"mapped",[21069]],[[127517,127517],"mapped",[24460]],[[127518,127518],"mapped",[20877]],[[127519,127519],"mapped",[26032]],[[127520,127520],"mapped",[21021]],[[127521,127521],"mapped",[32066]],[[127522,127522],"mapped",[29983]],[[127523,127523],"mapped",[36009]],[[127524,127524],"mapped",[22768]],[[127525,127525],"mapped",[21561]],[[127526,127526],"mapped",[28436]],[[127527,127527],"mapped",[25237]],[[127528,127528],"mapped",[25429]],[[127529,127529],"mapped",[19968]],[[127530,127530],"mapped",[19977]],[[127531,127531],"mapped",[36938]],[[127532,127532],"mapped",[24038]],[[127533,127533],"mapped",[20013]],[[127534,127534],"mapped",[21491]],[[127535,127535],"mapped",[25351]],[[127536,127536],"mapped",[36208]],[[127537,127537],"mapped",[25171]],[[127538,127538],"mapped",[31105]],[[127539,127539],"mapped",[31354]],[[127540,127540],"mapped",[21512]],[[127541,127541],"mapped",[28288]],[[127542,127542],"mapped",[26377]],[[127543,127543],"mapped",[26376]],[[127544,127544],"mapped",[30003]],[[127545,127545],"mapped",[21106]],[[127546,127546],"mapped",[21942]],[[127547,127551],"disallowed"],[[127552,127552],"mapped",[12308,26412,12309]],[[127553,127553],"mapped",[12308,19977,12309]],[[127554,127554],"mapped",[12308,20108,12309]],[[127555,127555],"mapped",[12308,23433,12309]],[[127556,127556],"mapped",[12308,28857,12309]],[[127557,127557],"mapped",[12308,25171,12309]],[[127558,127558],"mapped",[12308,30423,12309]],[[127559,127559],"mapped",[12308,21213,12309]],[[127560,127560],"mapped",[12308,25943,12309]],[[127561,127567],"disallowed"],[[127568,127568],"mapped",[24471]],[[127569,127569],"mapped",[21487]],[[127570,127743],"disallowed"],[[127744,127776],"valid",[],"NV8"],[[127777,127788],"valid",[],"NV8"],[[127789,127791],"valid",[],"NV8"],[[127792,127797],"valid",[],"NV8"],[[127798,127798],"valid",[],"NV8"],[[127799,127868],"valid",[],"NV8"],[[127869,127869],"valid",[],"NV8"],[[127870,127871],"valid",[],"NV8"],[[127872,127891],"valid",[],"NV8"],[[127892,127903],"valid",[],"NV8"],[[127904,127940],"valid",[],"NV8"],[[127941,127941],"valid",[],"NV8"],[[127942,127946],"valid",[],"NV8"],[[127947,127950],"valid",[],"NV8"],[[127951,127955],"valid",[],"NV8"],[[127956,127967],"valid",[],"NV8"],[[127968,127984],"valid",[],"NV8"],[[127985,127991],"valid",[],"NV8"],[[127992,127999],"valid",[],"NV8"],[[128000,128062],"valid",[],"NV8"],[[128063,128063],"valid",[],"NV8"],[[128064,128064],"valid",[],"NV8"],[[128065,128065],"valid",[],"NV8"],[[128066,128247],"valid",[],"NV8"],[[128248,128248],"valid",[],"NV8"],[[128249,128252],"valid",[],"NV8"],[[128253,128254],"valid",[],"NV8"],[[128255,128255],"valid",[],"NV8"],[[128256,128317],"valid",[],"NV8"],[[128318,128319],"valid",[],"NV8"],[[128320,128323],"valid",[],"NV8"],[[128324,128330],"valid",[],"NV8"],[[128331,128335],"valid",[],"NV8"],[[128336,128359],"valid",[],"NV8"],[[128360,128377],"valid",[],"NV8"],[[128378,128378],"disallowed"],[[128379,128419],"valid",[],"NV8"],[[128420,128420],"disallowed"],[[128421,128506],"valid",[],"NV8"],[[128507,128511],"valid",[],"NV8"],[[128512,128512],"valid",[],"NV8"],[[128513,128528],"valid",[],"NV8"],[[128529,128529],"valid",[],"NV8"],[[128530,128532],"valid",[],"NV8"],[[128533,128533],"valid",[],"NV8"],[[128534,128534],"valid",[],"NV8"],[[128535,128535],"valid",[],"NV8"],[[128536,128536],"valid",[],"NV8"],[[128537,128537],"valid",[],"NV8"],[[128538,128538],"valid",[],"NV8"],[[128539,128539],"valid",[],"NV8"],[[128540,128542],"valid",[],"NV8"],[[128543,128543],"valid",[],"NV8"],[[128544,128549],"valid",[],"NV8"],[[128550,128551],"valid",[],"NV8"],[[128552,128555],"valid",[],"NV8"],[[128556,128556],"valid",[],"NV8"],[[128557,128557],"valid",[],"NV8"],[[128558,128559],"valid",[],"NV8"],[[128560,128563],"valid",[],"NV8"],[[128564,128564],"valid",[],"NV8"],[[128565,128576],"valid",[],"NV8"],[[128577,128578],"valid",[],"NV8"],[[128579,128580],"valid",[],"NV8"],[[128581,128591],"valid",[],"NV8"],[[128592,128639],"valid",[],"NV8"],[[128640,128709],"valid",[],"NV8"],[[128710,128719],"valid",[],"NV8"],[[128720,128720],"valid",[],"NV8"],[[128721,128735],"disallowed"],[[128736,128748],"valid",[],"NV8"],[[128749,128751],"disallowed"],[[128752,128755],"valid",[],"NV8"],[[128756,128767],"disallowed"],[[128768,128883],"valid",[],"NV8"],[[128884,128895],"disallowed"],[[128896,128980],"valid",[],"NV8"],[[128981,129023],"disallowed"],[[129024,129035],"valid",[],"NV8"],[[129036,129039],"disallowed"],[[129040,129095],"valid",[],"NV8"],[[129096,129103],"disallowed"],[[129104,129113],"valid",[],"NV8"],[[129114,129119],"disallowed"],[[129120,129159],"valid",[],"NV8"],[[129160,129167],"disallowed"],[[129168,129197],"valid",[],"NV8"],[[129198,129295],"disallowed"],[[129296,129304],"valid",[],"NV8"],[[129305,129407],"disallowed"],[[129408,129412],"valid",[],"NV8"],[[129413,129471],"disallowed"],[[129472,129472],"valid",[],"NV8"],[[129473,131069],"disallowed"],[[131070,131071],"disallowed"],[[131072,173782],"valid"],[[173783,173823],"disallowed"],[[173824,177972],"valid"],[[177973,177983],"disallowed"],[[177984,178205],"valid"],[[178206,178207],"disallowed"],[[178208,183969],"valid"],[[183970,194559],"disallowed"],[[194560,194560],"mapped",[20029]],[[194561,194561],"mapped",[20024]],[[194562,194562],"mapped",[20033]],[[194563,194563],"mapped",[131362]],[[194564,194564],"mapped",[20320]],[[194565,194565],"mapped",[20398]],[[194566,194566],"mapped",[20411]],[[194567,194567],"mapped",[20482]],[[194568,194568],"mapped",[20602]],[[194569,194569],"mapped",[20633]],[[194570,194570],"mapped",[20711]],[[194571,194571],"mapped",[20687]],[[194572,194572],"mapped",[13470]],[[194573,194573],"mapped",[132666]],[[194574,194574],"mapped",[20813]],[[194575,194575],"mapped",[20820]],[[194576,194576],"mapped",[20836]],[[194577,194577],"mapped",[20855]],[[194578,194578],"mapped",[132380]],[[194579,194579],"mapped",[13497]],[[194580,194580],"mapped",[20839]],[[194581,194581],"mapped",[20877]],[[194582,194582],"mapped",[132427]],[[194583,194583],"mapped",[20887]],[[194584,194584],"mapped",[20900]],[[194585,194585],"mapped",[20172]],[[194586,194586],"mapped",[20908]],[[194587,194587],"mapped",[20917]],[[194588,194588],"mapped",[168415]],[[194589,194589],"mapped",[20981]],[[194590,194590],"mapped",[20995]],[[194591,194591],"mapped",[13535]],[[194592,194592],"mapped",[21051]],[[194593,194593],"mapped",[21062]],[[194594,194594],"mapped",[21106]],[[194595,194595],"mapped",[21111]],[[194596,194596],"mapped",[13589]],[[194597,194597],"mapped",[21191]],[[194598,194598],"mapped",[21193]],[[194599,194599],"mapped",[21220]],[[194600,194600],"mapped",[21242]],[[194601,194601],"mapped",[21253]],[[194602,194602],"mapped",[21254]],[[194603,194603],"mapped",[21271]],[[194604,194604],"mapped",[21321]],[[194605,194605],"mapped",[21329]],[[194606,194606],"mapped",[21338]],[[194607,194607],"mapped",[21363]],[[194608,194608],"mapped",[21373]],[[194609,194611],"mapped",[21375]],[[194612,194612],"mapped",[133676]],[[194613,194613],"mapped",[28784]],[[194614,194614],"mapped",[21450]],[[194615,194615],"mapped",[21471]],[[194616,194616],"mapped",[133987]],[[194617,194617],"mapped",[21483]],[[194618,194618],"mapped",[21489]],[[194619,194619],"mapped",[21510]],[[194620,194620],"mapped",[21662]],[[194621,194621],"mapped",[21560]],[[194622,194622],"mapped",[21576]],[[194623,194623],"mapped",[21608]],[[194624,194624],"mapped",[21666]],[[194625,194625],"mapped",[21750]],[[194626,194626],"mapped",[21776]],[[194627,194627],"mapped",[21843]],[[194628,194628],"mapped",[21859]],[[194629,194630],"mapped",[21892]],[[194631,194631],"mapped",[21913]],[[194632,194632],"mapped",[21931]],[[194633,194633],"mapped",[21939]],[[194634,194634],"mapped",[21954]],[[194635,194635],"mapped",[22294]],[[194636,194636],"mapped",[22022]],[[194637,194637],"mapped",[22295]],[[194638,194638],"mapped",[22097]],[[194639,194639],"mapped",[22132]],[[194640,194640],"mapped",[20999]],[[194641,194641],"mapped",[22766]],[[194642,194642],"mapped",[22478]],[[194643,194643],"mapped",[22516]],[[194644,194644],"mapped",[22541]],[[194645,194645],"mapped",[22411]],[[194646,194646],"mapped",[22578]],[[194647,194647],"mapped",[22577]],[[194648,194648],"mapped",[22700]],[[194649,194649],"mapped",[136420]],[[194650,194650],"mapped",[22770]],[[194651,194651],"mapped",[22775]],[[194652,194652],"mapped",[22790]],[[194653,194653],"mapped",[22810]],[[194654,194654],"mapped",[22818]],[[194655,194655],"mapped",[22882]],[[194656,194656],"mapped",[136872]],[[194657,194657],"mapped",[136938]],[[194658,194658],"mapped",[23020]],[[194659,194659],"mapped",[23067]],[[194660,194660],"mapped",[23079]],[[194661,194661],"mapped",[23000]],[[194662,194662],"mapped",[23142]],[[194663,194663],"mapped",[14062]],[[194664,194664],"disallowed"],[[194665,194665],"mapped",[23304]],[[194666,194667],"mapped",[23358]],[[194668,194668],"mapped",[137672]],[[194669,194669],"mapped",[23491]],[[194670,194670],"mapped",[23512]],[[194671,194671],"mapped",[23527]],[[194672,194672],"mapped",[23539]],[[194673,194673],"mapped",[138008]],[[194674,194674],"mapped",[23551]],[[194675,194675],"mapped",[23558]],[[194676,194676],"disallowed"],[[194677,194677],"mapped",[23586]],[[194678,194678],"mapped",[14209]],[[194679,194679],"mapped",[23648]],[[194680,194680],"mapped",[23662]],[[194681,194681],"mapped",[23744]],[[194682,194682],"mapped",[23693]],[[194683,194683],"mapped",[138724]],[[194684,194684],"mapped",[23875]],[[194685,194685],"mapped",[138726]],[[194686,194686],"mapped",[23918]],[[194687,194687],"mapped",[23915]],[[194688,194688],"mapped",[23932]],[[194689,194689],"mapped",[24033]],[[194690,194690],"mapped",[24034]],[[194691,194691],"mapped",[14383]],[[194692,194692],"mapped",[24061]],[[194693,194693],"mapped",[24104]],[[194694,194694],"mapped",[24125]],[[194695,194695],"mapped",[24169]],[[194696,194696],"mapped",[14434]],[[194697,194697],"mapped",[139651]],[[194698,194698],"mapped",[14460]],[[194699,194699],"mapped",[24240]],[[194700,194700],"mapped",[24243]],[[194701,194701],"mapped",[24246]],[[194702,194702],"mapped",[24266]],[[194703,194703],"mapped",[172946]],[[194704,194704],"mapped",[24318]],[[194705,194706],"mapped",[140081]],[[194707,194707],"mapped",[33281]],[[194708,194709],"mapped",[24354]],[[194710,194710],"mapped",[14535]],[[194711,194711],"mapped",[144056]],[[194712,194712],"mapped",[156122]],[[194713,194713],"mapped",[24418]],[[194714,194714],"mapped",[24427]],[[194715,194715],"mapped",[14563]],[[194716,194716],"mapped",[24474]],[[194717,194717],"mapped",[24525]],[[194718,194718],"mapped",[24535]],[[194719,194719],"mapped",[24569]],[[194720,194720],"mapped",[24705]],[[194721,194721],"mapped",[14650]],[[194722,194722],"mapped",[14620]],[[194723,194723],"mapped",[24724]],[[194724,194724],"mapped",[141012]],[[194725,194725],"mapped",[24775]],[[194726,194726],"mapped",[24904]],[[194727,194727],"mapped",[24908]],[[194728,194728],"mapped",[24910]],[[194729,194729],"mapped",[24908]],[[194730,194730],"mapped",[24954]],[[194731,194731],"mapped",[24974]],[[194732,194732],"mapped",[25010]],[[194733,194733],"mapped",[24996]],[[194734,194734],"mapped",[25007]],[[194735,194735],"mapped",[25054]],[[194736,194736],"mapped",[25074]],[[194737,194737],"mapped",[25078]],[[194738,194738],"mapped",[25104]],[[194739,194739],"mapped",[25115]],[[194740,194740],"mapped",[25181]],[[194741,194741],"mapped",[25265]],[[194742,194742],"mapped",[25300]],[[194743,194743],"mapped",[25424]],[[194744,194744],"mapped",[142092]],[[194745,194745],"mapped",[25405]],[[194746,194746],"mapped",[25340]],[[194747,194747],"mapped",[25448]],[[194748,194748],"mapped",[25475]],[[194749,194749],"mapped",[25572]],[[194750,194750],"mapped",[142321]],[[194751,194751],"mapped",[25634]],[[194752,194752],"mapped",[25541]],[[194753,194753],"mapped",[25513]],[[194754,194754],"mapped",[14894]],[[194755,194755],"mapped",[25705]],[[194756,194756],"mapped",[25726]],[[194757,194757],"mapped",[25757]],[[194758,194758],"mapped",[25719]],[[194759,194759],"mapped",[14956]],[[194760,194760],"mapped",[25935]],[[194761,194761],"mapped",[25964]],[[194762,194762],"mapped",[143370]],[[194763,194763],"mapped",[26083]],[[194764,194764],"mapped",[26360]],[[194765,194765],"mapped",[26185]],[[194766,194766],"mapped",[15129]],[[194767,194767],"mapped",[26257]],[[194768,194768],"mapped",[15112]],[[194769,194769],"mapped",[15076]],[[194770,194770],"mapped",[20882]],[[194771,194771],"mapped",[20885]],[[194772,194772],"mapped",[26368]],[[194773,194773],"mapped",[26268]],[[194774,194774],"mapped",[32941]],[[194775,194775],"mapped",[17369]],[[194776,194776],"mapped",[26391]],[[194777,194777],"mapped",[26395]],[[194778,194778],"mapped",[26401]],[[194779,194779],"mapped",[26462]],[[194780,194780],"mapped",[26451]],[[194781,194781],"mapped",[144323]],[[194782,194782],"mapped",[15177]],[[194783,194783],"mapped",[26618]],[[194784,194784],"mapped",[26501]],[[194785,194785],"mapped",[26706]],[[194786,194786],"mapped",[26757]],[[194787,194787],"mapped",[144493]],[[194788,194788],"mapped",[26766]],[[194789,194789],"mapped",[26655]],[[194790,194790],"mapped",[26900]],[[194791,194791],"mapped",[15261]],[[194792,194792],"mapped",[26946]],[[194793,194793],"mapped",[27043]],[[194794,194794],"mapped",[27114]],[[194795,194795],"mapped",[27304]],[[194796,194796],"mapped",[145059]],[[194797,194797],"mapped",[27355]],[[194798,194798],"mapped",[15384]],[[194799,194799],"mapped",[27425]],[[194800,194800],"mapped",[145575]],[[194801,194801],"mapped",[27476]],[[194802,194802],"mapped",[15438]],[[194803,194803],"mapped",[27506]],[[194804,194804],"mapped",[27551]],[[194805,194805],"mapped",[27578]],[[194806,194806],"mapped",[27579]],[[194807,194807],"mapped",[146061]],[[194808,194808],"mapped",[138507]],[[194809,194809],"mapped",[146170]],[[194810,194810],"mapped",[27726]],[[194811,194811],"mapped",[146620]],[[194812,194812],"mapped",[27839]],[[194813,194813],"mapped",[27853]],[[194814,194814],"mapped",[27751]],[[194815,194815],"mapped",[27926]],[[194816,194816],"mapped",[27966]],[[194817,194817],"mapped",[28023]],[[194818,194818],"mapped",[27969]],[[194819,194819],"mapped",[28009]],[[194820,194820],"mapped",[28024]],[[194821,194821],"mapped",[28037]],[[194822,194822],"mapped",[146718]],[[194823,194823],"mapped",[27956]],[[194824,194824],"mapped",[28207]],[[194825,194825],"mapped",[28270]],[[194826,194826],"mapped",[15667]],[[194827,194827],"mapped",[28363]],[[194828,194828],"mapped",[28359]],[[194829,194829],"mapped",[147153]],[[194830,194830],"mapped",[28153]],[[194831,194831],"mapped",[28526]],[[194832,194832],"mapped",[147294]],[[194833,194833],"mapped",[147342]],[[194834,194834],"mapped",[28614]],[[194835,194835],"mapped",[28729]],[[194836,194836],"mapped",[28702]],[[194837,194837],"mapped",[28699]],[[194838,194838],"mapped",[15766]],[[194839,194839],"mapped",[28746]],[[194840,194840],"mapped",[28797]],[[194841,194841],"mapped",[28791]],[[194842,194842],"mapped",[28845]],[[194843,194843],"mapped",[132389]],[[194844,194844],"mapped",[28997]],[[194845,194845],"mapped",[148067]],[[194846,194846],"mapped",[29084]],[[194847,194847],"disallowed"],[[194848,194848],"mapped",[29224]],[[194849,194849],"mapped",[29237]],[[194850,194850],"mapped",[29264]],[[194851,194851],"mapped",[149000]],[[194852,194852],"mapped",[29312]],[[194853,194853],"mapped",[29333]],[[194854,194854],"mapped",[149301]],[[194855,194855],"mapped",[149524]],[[194856,194856],"mapped",[29562]],[[194857,194857],"mapped",[29579]],[[194858,194858],"mapped",[16044]],[[194859,194859],"mapped",[29605]],[[194860,194861],"mapped",[16056]],[[194862,194862],"mapped",[29767]],[[194863,194863],"mapped",[29788]],[[194864,194864],"mapped",[29809]],[[194865,194865],"mapped",[29829]],[[194866,194866],"mapped",[29898]],[[194867,194867],"mapped",[16155]],[[194868,194868],"mapped",[29988]],[[194869,194869],"mapped",[150582]],[[194870,194870],"mapped",[30014]],[[194871,194871],"mapped",[150674]],[[194872,194872],"mapped",[30064]],[[194873,194873],"mapped",[139679]],[[194874,194874],"mapped",[30224]],[[194875,194875],"mapped",[151457]],[[194876,194876],"mapped",[151480]],[[194877,194877],"mapped",[151620]],[[194878,194878],"mapped",[16380]],[[194879,194879],"mapped",[16392]],[[194880,194880],"mapped",[30452]],[[194881,194881],"mapped",[151795]],[[194882,194882],"mapped",[151794]],[[194883,194883],"mapped",[151833]],[[194884,194884],"mapped",[151859]],[[194885,194885],"mapped",[30494]],[[194886,194887],"mapped",[30495]],[[194888,194888],"mapped",[30538]],[[194889,194889],"mapped",[16441]],[[194890,194890],"mapped",[30603]],[[194891,194891],"mapped",[16454]],[[194892,194892],"mapped",[16534]],[[194893,194893],"mapped",[152605]],[[194894,194894],"mapped",[30798]],[[194895,194895],"mapped",[30860]],[[194896,194896],"mapped",[30924]],[[194897,194897],"mapped",[16611]],[[194898,194898],"mapped",[153126]],[[194899,194899],"mapped",[31062]],[[194900,194900],"mapped",[153242]],[[194901,194901],"mapped",[153285]],[[194902,194902],"mapped",[31119]],[[194903,194903],"mapped",[31211]],[[194904,194904],"mapped",[16687]],[[194905,194905],"mapped",[31296]],[[194906,194906],"mapped",[31306]],[[194907,194907],"mapped",[31311]],[[194908,194908],"mapped",[153980]],[[194909,194910],"mapped",[154279]],[[194911,194911],"disallowed"],[[194912,194912],"mapped",[16898]],[[194913,194913],"mapped",[154539]],[[194914,194914],"mapped",[31686]],[[194915,194915],"mapped",[31689]],[[194916,194916],"mapped",[16935]],[[194917,194917],"mapped",[154752]],[[194918,194918],"mapped",[31954]],[[194919,194919],"mapped",[17056]],[[194920,194920],"mapped",[31976]],[[194921,194921],"mapped",[31971]],[[194922,194922],"mapped",[32000]],[[194923,194923],"mapped",[155526]],[[194924,194924],"mapped",[32099]],[[194925,194925],"mapped",[17153]],[[194926,194926],"mapped",[32199]],[[194927,194927],"mapped",[32258]],[[194928,194928],"mapped",[32325]],[[194929,194929],"mapped",[17204]],[[194930,194930],"mapped",[156200]],[[194931,194931],"mapped",[156231]],[[194932,194932],"mapped",[17241]],[[194933,194933],"mapped",[156377]],[[194934,194934],"mapped",[32634]],[[194935,194935],"mapped",[156478]],[[194936,194936],"mapped",[32661]],[[194937,194937],"mapped",[32762]],[[194938,194938],"mapped",[32773]],[[194939,194939],"mapped",[156890]],[[194940,194940],"mapped",[156963]],[[194941,194941],"mapped",[32864]],[[194942,194942],"mapped",[157096]],[[194943,194943],"mapped",[32880]],[[194944,194944],"mapped",[144223]],[[194945,194945],"mapped",[17365]],[[194946,194946],"mapped",[32946]],[[194947,194947],"mapped",[33027]],[[194948,194948],"mapped",[17419]],[[194949,194949],"mapped",[33086]],[[194950,194950],"mapped",[23221]],[[194951,194951],"mapped",[157607]],[[194952,194952],"mapped",[157621]],[[194953,194953],"mapped",[144275]],[[194954,194954],"mapped",[144284]],[[194955,194955],"mapped",[33281]],[[194956,194956],"mapped",[33284]],[[194957,194957],"mapped",[36766]],[[194958,194958],"mapped",[17515]],[[194959,194959],"mapped",[33425]],[[194960,194960],"mapped",[33419]],[[194961,194961],"mapped",[33437]],[[194962,194962],"mapped",[21171]],[[194963,194963],"mapped",[33457]],[[194964,194964],"mapped",[33459]],[[194965,194965],"mapped",[33469]],[[194966,194966],"mapped",[33510]],[[194967,194967],"mapped",[158524]],[[194968,194968],"mapped",[33509]],[[194969,194969],"mapped",[33565]],[[194970,194970],"mapped",[33635]],[[194971,194971],"mapped",[33709]],[[194972,194972],"mapped",[33571]],[[194973,194973],"mapped",[33725]],[[194974,194974],"mapped",[33767]],[[194975,194975],"mapped",[33879]],[[194976,194976],"mapped",[33619]],[[194977,194977],"mapped",[33738]],[[194978,194978],"mapped",[33740]],[[194979,194979],"mapped",[33756]],[[194980,194980],"mapped",[158774]],[[194981,194981],"mapped",[159083]],[[194982,194982],"mapped",[158933]],[[194983,194983],"mapped",[17707]],[[194984,194984],"mapped",[34033]],[[194985,194985],"mapped",[34035]],[[194986,194986],"mapped",[34070]],[[194987,194987],"mapped",[160714]],[[194988,194988],"mapped",[34148]],[[194989,194989],"mapped",[159532]],[[194990,194990],"mapped",[17757]],[[194991,194991],"mapped",[17761]],[[194992,194992],"mapped",[159665]],[[194993,194993],"mapped",[159954]],[[194994,194994],"mapped",[17771]],[[194995,194995],"mapped",[34384]],[[194996,194996],"mapped",[34396]],[[194997,194997],"mapped",[34407]],[[194998,194998],"mapped",[34409]],[[194999,194999],"mapped",[34473]],[[195000,195000],"mapped",[34440]],[[195001,195001],"mapped",[34574]],[[195002,195002],"mapped",[34530]],[[195003,195003],"mapped",[34681]],[[195004,195004],"mapped",[34600]],[[195005,195005],"mapped",[34667]],[[195006,195006],"mapped",[34694]],[[195007,195007],"disallowed"],[[195008,195008],"mapped",[34785]],[[195009,195009],"mapped",[34817]],[[195010,195010],"mapped",[17913]],[[195011,195011],"mapped",[34912]],[[195012,195012],"mapped",[34915]],[[195013,195013],"mapped",[161383]],[[195014,195014],"mapped",[35031]],[[195015,195015],"mapped",[35038]],[[195016,195016],"mapped",[17973]],[[195017,195017],"mapped",[35066]],[[195018,195018],"mapped",[13499]],[[195019,195019],"mapped",[161966]],[[195020,195020],"mapped",[162150]],[[195021,195021],"mapped",[18110]],[[195022,195022],"mapped",[18119]],[[195023,195023],"mapped",[35488]],[[195024,195024],"mapped",[35565]],[[195025,195025],"mapped",[35722]],[[195026,195026],"mapped",[35925]],[[195027,195027],"mapped",[162984]],[[195028,195028],"mapped",[36011]],[[195029,195029],"mapped",[36033]],[[195030,195030],"mapped",[36123]],[[195031,195031],"mapped",[36215]],[[195032,195032],"mapped",[163631]],[[195033,195033],"mapped",[133124]],[[195034,195034],"mapped",[36299]],[[195035,195035],"mapped",[36284]],[[195036,195036],"mapped",[36336]],[[195037,195037],"mapped",[133342]],[[195038,195038],"mapped",[36564]],[[195039,195039],"mapped",[36664]],[[195040,195040],"mapped",[165330]],[[195041,195041],"mapped",[165357]],[[195042,195042],"mapped",[37012]],[[195043,195043],"mapped",[37105]],[[195044,195044],"mapped",[37137]],[[195045,195045],"mapped",[165678]],[[195046,195046],"mapped",[37147]],[[195047,195047],"mapped",[37432]],[[195048,195048],"mapped",[37591]],[[195049,195049],"mapped",[37592]],[[195050,195050],"mapped",[37500]],[[195051,195051],"mapped",[37881]],[[195052,195052],"mapped",[37909]],[[195053,195053],"mapped",[166906]],[[195054,195054],"mapped",[38283]],[[195055,195055],"mapped",[18837]],[[195056,195056],"mapped",[38327]],[[195057,195057],"mapped",[167287]],[[195058,195058],"mapped",[18918]],[[195059,195059],"mapped",[38595]],[[195060,195060],"mapped",[23986]],[[195061,195061],"mapped",[38691]],[[195062,195062],"mapped",[168261]],[[195063,195063],"mapped",[168474]],[[195064,195064],"mapped",[19054]],[[195065,195065],"mapped",[19062]],[[195066,195066],"mapped",[38880]],[[195067,195067],"mapped",[168970]],[[195068,195068],"mapped",[19122]],[[195069,195069],"mapped",[169110]],[[195070,195071],"mapped",[38923]],[[195072,195072],"mapped",[38953]],[[195073,195073],"mapped",[169398]],[[195074,195074],"mapped",[39138]],[[195075,195075],"mapped",[19251]],[[195076,195076],"mapped",[39209]],[[195077,195077],"mapped",[39335]],[[195078,195078],"mapped",[39362]],[[195079,195079],"mapped",[39422]],[[195080,195080],"mapped",[19406]],[[195081,195081],"mapped",[170800]],[[195082,195082],"mapped",[39698]],[[195083,195083],"mapped",[40000]],[[195084,195084],"mapped",[40189]],[[195085,195085],"mapped",[19662]],[[195086,195086],"mapped",[19693]],[[195087,195087],"mapped",[40295]],[[195088,195088],"mapped",[172238]],[[195089,195089],"mapped",[19704]],[[195090,195090],"mapped",[172293]],[[195091,195091],"mapped",[172558]],[[195092,195092],"mapped",[172689]],[[195093,195093],"mapped",[40635]],[[195094,195094],"mapped",[19798]],[[195095,195095],"mapped",[40697]],[[195096,195096],"mapped",[40702]],[[195097,195097],"mapped",[40709]],[[195098,195098],"mapped",[40719]],[[195099,195099],"mapped",[40726]],[[195100,195100],"mapped",[40763]],[[195101,195101],"mapped",[173568]],[[195102,196605],"disallowed"],[[196606,196607],"disallowed"],[[196608,262141],"disallowed"],[[262142,262143],"disallowed"],[[262144,327677],"disallowed"],[[327678,327679],"disallowed"],[[327680,393213],"disallowed"],[[393214,393215],"disallowed"],[[393216,458749],"disallowed"],[[458750,458751],"disallowed"],[[458752,524285],"disallowed"],[[524286,524287],"disallowed"],[[524288,589821],"disallowed"],[[589822,589823],"disallowed"],[[589824,655357],"disallowed"],[[655358,655359],"disallowed"],[[655360,720893],"disallowed"],[[720894,720895],"disallowed"],[[720896,786429],"disallowed"],[[786430,786431],"disallowed"],[[786432,851965],"disallowed"],[[851966,851967],"disallowed"],[[851968,917501],"disallowed"],[[917502,917503],"disallowed"],[[917504,917504],"disallowed"],[[917505,917505],"disallowed"],[[917506,917535],"disallowed"],[[917536,917631],"disallowed"],[[917632,917759],"disallowed"],[[917760,917999],"ignored"],[[918000,983037],"disallowed"],[[983038,983039],"disallowed"],[[983040,1048573],"disallowed"],[[1048574,1048575],"disallowed"],[[1048576,1114109],"disallowed"],[[1114110,1114111],"disallowed"]]')}};var __webpack_module_cache__={};function __nccwpck_require__(e){var p=__webpack_module_cache__[e];if(p!==undefined){return p.exports}var a=__webpack_module_cache__[e]={exports:{}};var d=true;try{__webpack_modules__[e].call(a.exports,a,a.exports,__nccwpck_require__);d=false}finally{if(d)delete __webpack_module_cache__[e]}return a.exports}(()=>{__nccwpck_require__.n=e=>{var p=e&&e.__esModule?()=>e["default"]:()=>e;__nccwpck_require__.d(p,{a:p});return p}})();(()=>{__nccwpck_require__.d=(e,p)=>{for(var a in p){if(__nccwpck_require__.o(p,a)&&!__nccwpck_require__.o(e,a)){Object.defineProperty(e,a,{enumerable:true,get:p[a]})}}}})();(()=>{__nccwpck_require__.o=(e,p)=>Object.prototype.hasOwnProperty.call(e,p)})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=new URL(".",import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/)?1:0,-1)+"/";var __webpack_exports__={};(()=>{var e=__nccwpck_require__(2186);var p=__nccwpck_require__.n(e);var a=__nccwpck_require__(5438);var d=__nccwpck_require__.n(a);async function run(){const p=process.env.GITHUB_TOKEN;if(!p)throw new Error("No GITHUB_TOKEN provided");const{issue:d}=a.context.payload;if(!d)return console.log("Not an issue, exiting");const{body:t,number:r,title:s}=d;if(!r)return console.log("Could not get issue number, exiting");if(!t)return console.log("Could not get issue body, exiting");if(!s)return console.log("Could not get issue title, exiting");const{rest:i}=(0,a.getOctokit)(p);const o=await loadAreaLabels(i);(0,e.debug)(`Loaded labels: ${Array.from(o.keys()).join(", ")}`);const n=[];const l=t.split("Which area(s) of Next.js are affected? (leave empty if unsure)")[1]?.split("Link to the code that reproduces this issue")[0];if(!l){console.log(`Issue #${r} does not contain a match section, likely not a bug template, exiting`);return}(0,e.debug)(`Match section: ${l}`);for(const[e,p]of o.entries()){if(l.includes(p)){n.push(e)}}(0,e.debug)(`Labels to add: ${n.join(", ")}`);if(!n.length)return console.log("No labels to add, exiting");await addLabels(i,r,n);(0,e.debug)(`Added labels to issue #${r}: ${n.join(", ")}`)}async function loadAreaLabels(e){try{const{data:p}=await e.issues.listLabelsForRepo({owner:a.context.repo.owner,repo:a.context.repo.repo,per_page:100});const d=new Map;for(const e of p){if(e.name.startsWith("area:")&&e.description){d.set(e.name,e.description)}}return d}catch(e){console.error("Error loading labels: "+e);throw e}}async function addLabels(p,d,t){try{const r=t.map((e=>`"${e}"`)).join(", ");(0,e.debug)(`Adding label(s) (${r}) to issue #${d}`);return await p.issues.addLabels({owner:a.context.repo.owner,repo:a.context.repo.repo,issue_number:d,labels:t})}catch(e){console.error(`Could not add label(s) ${t} to issue #${d}`);throw e}}run().catch(e.setFailed)})(); \ No newline at end of file diff --git a/.github/actions/issue-labeler/lib/licenses.txt b/.github/actions/issue-labeler/lib/licenses.txt new file mode 100644 index 00000000000000..bac409bc854960 --- /dev/null +++ b/.github/actions/issue-labeler/lib/licenses.txt @@ -0,0 +1,635 @@ +@actions/core +MIT +The MIT License (MIT) + +Copyright 2019 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@actions/github +MIT +The MIT License (MIT) + +Copyright 2019 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@actions/http-client +MIT +Actions Http Client for Node.js + +Copyright (c) GitHub, Inc. + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@octokit/auth-token +MIT +The MIT License + +Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/core +MIT +The MIT License + +Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/endpoint +MIT +The MIT License + +Copyright (c) 2018 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/graphql +MIT +The MIT License + +Copyright (c) 2018 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/plugin-paginate-rest +MIT +MIT License Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@octokit/plugin-rest-endpoint-methods +MIT +MIT License Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@octokit/request +MIT +The MIT License + +Copyright (c) 2018 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/request-error +MIT +The MIT License + +Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@vercel/ncc +MIT +Copyright 2018 ZEIT, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +before-after-hook +Apache-2.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Gregor Martynus and other contributors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +deprecation +ISC +The ISC License + +Copyright (c) Gregor Martynus and contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +is-plain-object +MIT +The MIT License (MIT) + +Copyright (c) 2014-2017, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node-fetch +MIT +The MIT License (MIT) + +Copyright (c) 2016 David Frank + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +once +ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +tr46 +MIT + +tunnel +MIT +The MIT License (MIT) + +Copyright (c) 2012 Koichi Kobayashi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +universal-user-agent +ISC +# [ISC License](https://spdx.org/licenses/ISC) + +Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +uuid +MIT +The MIT License (MIT) + +Copyright (c) 2010-2020 Robert Kieffer and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +webidl-conversions +BSD-2-Clause +# The BSD 2-Clause License + +Copyright (c) 2014, Domenic Denicola +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +whatwg-url +MIT +The MIT License (MIT) + +Copyright (c) 2015–2016 Sebastian Mayr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +wrappy +ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/.github/actions/issue-labeler/lib/package.json b/.github/actions/issue-labeler/lib/package.json new file mode 100644 index 00000000000000..3dbc1ca591c055 --- /dev/null +++ b/.github/actions/issue-labeler/lib/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/.github/actions/issue-labeler/package.json b/.github/actions/issue-labeler/package.json new file mode 100644 index 00000000000000..59efafe4bcff01 --- /dev/null +++ b/.github/actions/issue-labeler/package.json @@ -0,0 +1,18 @@ +{ + "private": true, + "name": "issue-labeler", + "type": "module", + "exports": "./lib/index.js", + "scripts": { + "build": "pnpm types && pnpm ncc -m -o ./lib build src/index.ts --license licenses.txt", + "types": "tsc" + }, + "dependencies": { + "@actions/core": "^1.10.0", + "@actions/github": "^5.1.1" + }, + "devDependencies": { + "@types/node": "^18.15.3", + "@vercel/ncc": "0.36.1" + } +} diff --git a/.github/actions/issue-labeler/src/index.ts b/.github/actions/issue-labeler/src/index.ts new file mode 100644 index 00000000000000..2093575c79ac0e --- /dev/null +++ b/.github/actions/issue-labeler/src/index.ts @@ -0,0 +1,102 @@ +import { setFailed, debug } from '@actions/core' +import { context, getOctokit } from '@actions/github' + +type GitHubClient = ReturnType['rest'] + +async function run() { + const token = process.env.GITHUB_TOKEN + if (!token) throw new Error('No GITHUB_TOKEN provided') + + const { issue } = context.payload + if (!issue) return console.log('Not an issue, exiting') + + const { body: issue_body, number: issue_number, title: issue_title } = issue + if (!issue_number) return console.log('Could not get issue number, exiting') + if (!issue_body) return console.log('Could not get issue body, exiting') + if (!issue_title) return console.log('Could not get issue title, exiting') + + // A client to load data from GitHub + const { rest: client } = getOctokit(token) + + // Load our regex rules from the repo labels + const labels = await loadAreaLabels(client) + + debug(`Loaded labels: ${Array.from(labels.keys()).join(', ')}`) + + /** List of labels to add */ + const toAdd: string[] = [] + + // https://github.com/vercel/next.js/blame/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml + + const matchSection = issue_body + .split('Which area(s) of Next.js are affected? (leave empty if unsure)')[1] + ?.split('Link to the code that reproduces this issue')[0] + + if (!matchSection) { + console.log( + `Issue #${issue_number} does not contain a match section, likely not a bug template, exiting` + ) + return + } + + debug(`Match section: ${matchSection}`) + + for (const [label, description] of labels.entries()) { + if (matchSection.includes(description)) { + toAdd.push(label) + } + } + + debug(`Labels to add: ${toAdd.join(', ')}`) + + if (!toAdd.length) return console.log('No labels to add, exiting') + + await addLabels(client, issue_number, toAdd) + + debug(`Added labels to issue #${issue_number}: ${toAdd.join(', ')}`) +} + +/** Load label descriptions from the repo. */ +async function loadAreaLabels(client: GitHubClient) { + try { + const { data } = await client.issues.listLabelsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100, + }) + + const labels = new Map() + // Only load labels that start with `area:` and have a description + for (const label of data) { + if (label.name.startsWith('area:') && label.description) { + labels.set(label.name, label.description) + } + } + return labels + } catch (error) { + console.error('Error loading labels: ' + error) + throw error + } +} + +async function addLabels( + client: GitHubClient, + issue_number: number, + labels: string[] +) { + try { + const formatted = labels.map((l) => `"${l}"`).join(', ') + debug(`Adding label(s) (${formatted}) to issue #${issue_number}`) + return await client.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + labels, + }) + } catch (error) { + console.error(`Could not add label(s) ${labels} to issue #${issue_number}`) + throw error + } +} + +run().catch(setFailed) diff --git a/.github/actions/issue-labeler/tsconfig.json b/.github/actions/issue-labeler/tsconfig.json new file mode 100644 index 00000000000000..4f78c139cbfa66 --- /dev/null +++ b/.github/actions/issue-labeler/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "noEmit": true, + "target": "esnext", + "moduleResolution": "node", + "rootDir": "./src", + "strict": true, + "noImplicitAny": true + } +} diff --git a/.github/issue-labeler.yml b/.github/issue-labeler.yml deleted file mode 100644 index cedfa239fae049..00000000000000 --- a/.github/issue-labeler.yml +++ /dev/null @@ -1,45 +0,0 @@ -# https://github.com/github/issue-labeler#basic-examples - -# Should match the list "Which area(s) of Next.js are affected?" in: -# https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml -'area: app': 'App directory (appDir: true)' -'area: create-next-app': 'CLI (create-next-app)' -'area: data fetching': 'Data fetching (gS(S)P, getInitialProps)' -'area: Edge': 'Middleware / Edge (API routes, runtime)' -'area: ESLint': 'ESLint (eslint-config-next)' -'area: export': 'Static HTML Export (next export)' -'area: Font Optimization': 'Font optimization (@next/font)' -'area: I18n': 'Internationalzation (i18n)' -'area: Jest': 'Jest (next/jest)' -'area: MDX': 'MDX (@next/mdx)' -'area: Metadata': 'Metadata (metadata, generateMetadata, next/head, head.js)' -'area: next/dynamic': 'Dynamic imports (next/dynamic)' -'area: next/image': 'Image optmization (next/image, next/legacy/image)' -'area: next/script': 'Script optimizatzion (next/script)' -'area: package manager': 'Package manager (npm, pnpm, Yarn)' -'area: Routing': 'Routing (next/router, next/navigation, next/link)' -'area: standalone mode': 'Standalone mode (output: "standalone")' -'area: SWC Minify': 'SWC minifier (swcMinify: true)' -'area: SWC transforms': 'SWC transpilation' -'area: Turbopack': 'Turbopack (--turbo)' -'area: TypeScript': 'TypeScript' -# Less used/old/redundant labels -# area: AMP -# area: API routes -# area: Application Code -# area: Codemods -# area: Compiler Performance -# area: Compiler -# area: Concurrent Features -# area: Debugger -# area: Developer Experience -# area: Ecosystem -# area: experimental -# area: Middleware -# area: Reliability -# area: Repository Maintenance -# area: Server Components -# area: Static Generation -# area: styled-jsx -# area: Tracing -# area: URL Imports diff --git a/.github/workflows/issue_labeler.yml b/.github/workflows/issue_labeler.yml index b6a1fff60064bd..adc3f0f5b603c9 100644 --- a/.github/workflows/issue_labeler.yml +++ b/.github/workflows/issue_labeler.yml @@ -13,9 +13,10 @@ jobs: name: Triage runs-on: ubuntu-latest steps: - - uses: github/issue-labeler@v3.0 + - uses: actions/setup-node@v3 with: - repo-token: '${{ secrets.GITHUB_TOKEN }}' - configuration-path: '.github/issue-labeler.yml' - enable-versioned-regex: 0 - sync-labels: 0 + node-version: 18 + - name: 'Run issue labeler' + run: node ./.github/actions/issue-labeler/lib + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.prettierignore b/.prettierignore index ca921842afb8bf..0c00bf252d776d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,6 +12,7 @@ packages/react-dev-overlay/lib/** lerna.json .github/actions/next-stats-action/.work .github/actions/issue-validator/index.mjs +.github/actions/issue-labeler/lib/index.js packages/next-swc/crates/**/* packages/next-swc/target/**/* packages/next-swc/native/**/* From 17e1cc7a7b46408cc49060255f943bce769b5683 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 20 Mar 2023 18:20:45 -0700 Subject: [PATCH 583/672] v13.2.5-canary.10 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index a275ad8f1d01ac..f2580d77d9b11c 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.2.5-canary.9" + "version": "13.2.5-canary.10" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 19688f5fd21317..fa084e638e1914 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 8b6b79a2a49b4a..df19cb52ec2e6a 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -12,7 +12,7 @@ "test-pack": "cd ../../ && pnpm test-pack eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "13.2.5-canary.9", + "@next/eslint-plugin-next": "13.2.5-canary.10", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.42.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 0ad0163d73ad35..b1d90c2c7d3ac4 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "description": "ESLint plugin for NextJS.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index c95a9a42651f3b..6e7203064decee 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 6993b7b25c3f4c..4d9dbccd88aa11 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index e188b56b220599..ec1c701d1b5253 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 693e4e3bf978b3..b255acb6382f47 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 9d6d61ca9b12f3..5b9cb816ad55db 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index f35ac073554ddd..1e9c796b1fd165 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index d73373366e2fe1..8fb451a9d80068 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index cbd468aa2ca2df..af72c85afbe82b 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index a0bc9218c39c6b..1c6a946c33c6a2 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "private": true, "scripts": { "clean": "rm -rf ./native/*", diff --git a/packages/next/package.json b/packages/next/package.json index 9411643f8e2c5b..77f50890cb1c05 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -80,7 +80,7 @@ ] }, "dependencies": { - "@next/env": "13.2.5-canary.9", + "@next/env": "13.2.5-canary.10", "@swc/helpers": "0.4.14", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -135,11 +135,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.14.7", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.2.5-canary.9", - "@next/polyfill-nomodule": "13.2.5-canary.9", - "@next/react-dev-overlay": "13.2.5-canary.9", - "@next/react-refresh-utils": "13.2.5-canary.9", - "@next/swc": "13.2.5-canary.9", + "@next/polyfill-module": "13.2.5-canary.10", + "@next/polyfill-nomodule": "13.2.5-canary.10", + "@next/react-dev-overlay": "13.2.5-canary.10", + "@next/react-refresh-utils": "13.2.5-canary.10", + "@next/swc": "13.2.5-canary.10", "@opentelemetry/api": "1.4.1", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 0e9d02fbde9caa..ab613888ee29a5 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index f8a80c7084f8be..8d283d41541bee 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "13.2.5-canary.9", + "version": "13.2.5-canary.10", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1e49fdb4e33fb..d6990e9804b6e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -444,7 +444,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 13.2.5-canary.9 + '@next/eslint-plugin-next': 13.2.5-canary.10 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.42.0 eslint: ^7.23.0 || ^8.0.0 @@ -517,12 +517,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.14.7 '@napi-rs/triples': 1.1.0 - '@next/env': 13.2.5-canary.9 - '@next/polyfill-module': 13.2.5-canary.9 - '@next/polyfill-nomodule': 13.2.5-canary.9 - '@next/react-dev-overlay': 13.2.5-canary.9 - '@next/react-refresh-utils': 13.2.5-canary.9 - '@next/swc': 13.2.5-canary.9 + '@next/env': 13.2.5-canary.10 + '@next/polyfill-module': 13.2.5-canary.10 + '@next/polyfill-nomodule': 13.2.5-canary.10 + '@next/react-dev-overlay': 13.2.5-canary.10 + '@next/react-refresh-utils': 13.2.5-canary.10 + '@next/swc': 13.2.5-canary.10 '@opentelemetry/api': 1.4.1 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.14 From 509ed00fc163bc185221cd8d9b40c726ac36aadf Mon Sep 17 00:00:00 2001 From: LongYinan Date: Tue, 21 Mar 2023 18:25:08 +0800 Subject: [PATCH 584/672] Calling turbopack from the next build CLI (#46602) Close WEB-661 --- .github/workflows/build_test_deploy.yml | 2 + packages/next-swc/Cargo.lock | 14 +++ packages/next-swc/Cargo.toml | 1 + packages/next-swc/crates/napi/Cargo.toml | 1 + .../next-swc/crates/napi/src/turbopack.rs | 103 +++++++++++++++++- .../next-swc/crates/next-binding/Cargo.toml | 4 + .../next-swc/crates/next-binding/src/lib.rs | 2 + .../next-swc/crates/next-build/Cargo.toml | 27 +++++ packages/next-swc/crates/next-build/build.rs | 13 +++ .../next-swc/crates/next-build/src/lib.rs | 33 ++++++ packages/next/src/build/index.ts | 24 ++-- packages/next/src/build/swc/index.ts | 3 + packages/next/src/build/webpack-build.ts | 6 +- packages/next/src/cli/next-build.ts | 4 +- 14 files changed, 223 insertions(+), 14 deletions(-) create mode 100644 packages/next-swc/crates/next-build/Cargo.toml create mode 100644 packages/next-swc/crates/next-build/build.rs create mode 100644 packages/next-swc/crates/next-build/src/lib.rs diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index e8f52df18ccb35..0ad4b7744b6b65 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -1498,6 +1498,8 @@ jobs: with: envs: DEBUG RUSTUP_HOME CARGO_HOME RUSTUP_IO_THREADS CARGO_PROFILE_RELEASE_LTO NAPI_CLI_VERSION RUST_TOOLCHAIN PNPM_VERSION VM_RELEASE usesh: true + sync: rsync + copyback: false mem: 6000 prepare: | pkg install -y -f curl node libnghttp2 diff --git a/packages/next-swc/Cargo.lock b/packages/next-swc/Cargo.lock index 05043a146b14f3..c1b5fd0fa8805f 100644 --- a/packages/next-swc/Cargo.lock +++ b/packages/next-swc/Cargo.lock @@ -3008,6 +3008,7 @@ version = "0.1.0" dependencies = [ "mdxjs", "modularize_imports", + "next-build", "next-dev", "node-file-trace", "styled_components", @@ -3017,6 +3018,19 @@ dependencies = [ "testing", ] +[[package]] +name = "next-build" +version = "0.1.0" +dependencies = [ + "anyhow", + "next-core", + "turbo-malloc", + "turbo-tasks", + "turbo-tasks-build", + "turbo-tasks-memory", + "vergen", +] + [[package]] name = "next-core" version = "0.1.0" diff --git a/packages/next-swc/Cargo.toml b/packages/next-swc/Cargo.toml index 2172348cdd5e41..5c1214882069d6 100644 --- a/packages/next-swc/Cargo.toml +++ b/packages/next-swc/Cargo.toml @@ -5,6 +5,7 @@ members = [ "crates/napi", "crates/wasm", "crates/next-binding", + "crates/next-build", "crates/next-core", "crates/next-dev", "crates/next-dev-tests", diff --git a/packages/next-swc/crates/napi/Cargo.toml b/packages/next-swc/crates/napi/Cargo.toml index 657d2a41c814e1..bd45cc8ba79b17 100644 --- a/packages/next-swc/crates/napi/Cargo.toml +++ b/packages/next-swc/crates/napi/Cargo.toml @@ -44,6 +44,7 @@ turbo-tasks = { workspace = true } turbo-tasks-memory = { workspace = true } next-binding = { path = "../next-binding", features = [ "__swc_core_binding_napi", + "__turbo_next_build", "__turbo_next_dev_server", "__turbo_node_file_trace", "__feature_mdx_rs", diff --git a/packages/next-swc/crates/napi/src/turbopack.rs b/packages/next-swc/crates/napi/src/turbopack.rs index 61ea6f3689147a..4e2aa29d391248 100644 --- a/packages/next-swc/crates/napi/src/turbopack.rs +++ b/packages/next-swc/crates/napi/src/turbopack.rs @@ -1,9 +1,110 @@ +use std::convert::TryFrom; + use crate::util::MapErr; use napi::bindgen_prelude::*; -use next_binding::turbo::next_dev::{devserver_options::DevServerOptions, start_server}; +use next_binding::turbo::{ + next_build::{next_build as turbo_next_build, NextBuildOptions}, + next_dev::{devserver_options::DevServerOptions, start_server}, +}; #[napi] pub async fn start_turbo_dev(options: Buffer) -> napi::Result<()> { let options: DevServerOptions = serde_json::from_slice(&options)?; start_server(&options).await.convert_err() } + +#[napi(object, object_to_js = false)] +#[derive(Debug)] +pub struct NextBuildContext { + pub dir: Option, + pub app_dir: Option, + pub pages_dir: Option, + pub rewrites: Option, + pub original_rewrites: Option, + pub original_redirects: Option>, +} + +#[napi(object, object_to_js = false)] +#[derive(Debug)] +pub struct Rewrites { + pub fallback: Vec, + pub after_files: Vec, + pub before_files: Vec, +} + +#[napi(object, object_to_js = false)] +#[derive(Debug)] +pub struct Rewrite { + pub source: String, + pub destination: String, +} + +#[napi(object, object_to_js = false)] +#[derive(Debug)] +pub struct Redirect { + pub source: String, + pub destination: String, + pub permanent: Option, + pub status_code: Option, + pub has: Option, + pub missing: Option, +} + +#[derive(Debug)] +pub struct RouteHas { + pub r#type: RouteType, + pub key: Option, + pub value: Option, +} + +#[derive(Debug)] +pub enum RouteType { + Header, + Query, + Cookie, + Host, +} + +impl TryFrom for RouteType { + type Error = napi::Error; + + fn try_from(value: String) -> Result { + match value.as_str() { + "header" => Ok(RouteType::Header), + "query" => Ok(RouteType::Query), + "cookie" => Ok(RouteType::Cookie), + "host" => Ok(RouteType::Host), + _ => Err(napi::Error::new( + napi::Status::InvalidArg, + "Invalid route type", + )), + } + } +} + +impl FromNapiValue for RouteHas { + unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let object = Object::from_napi_value(env, napi_val)?; + let r#type = object.get_named_property::("type")?; + Ok(RouteHas { + r#type: RouteType::try_from(r#type)?, + key: object.get("key")?, + value: object.get("value")?, + }) + } +} + +impl From for NextBuildOptions { + fn from(value: NextBuildContext) -> Self { + Self { + dir: value.dir, + memory_limit: None, + full_stats: None, + } + } +} + +#[napi] +pub async fn next_build(ctx: NextBuildContext) -> napi::Result<()> { + turbo_next_build(ctx.into()).await.convert_err() +} diff --git a/packages/next-swc/crates/next-binding/Cargo.toml b/packages/next-swc/crates/next-binding/Cargo.toml index 2242f10c4e7a7b..668e4731d9d24e 100644 --- a/packages/next-swc/crates/next-binding/Cargo.toml +++ b/packages/next-swc/crates/next-binding/Cargo.toml @@ -74,6 +74,7 @@ __swc_core_binding_wasm_plugin = ["swc_core/plugin_transform_host_js"] __swc_core_testing_transform = ["swc_core/testing_transform"] __turbo = [] +__turbo_next_build = ["__turbo", "next-build"] __turbo_next_dev_server = ["__turbo", "next-dev/serializable"] __turbo_node_file_trace = ["__turbo", "node-file-trace/node-api"] @@ -102,6 +103,9 @@ __swc_testing = ["__swc", "testing"] [dependencies] mdxjs = { optional = true, workspace = true } modularize_imports = { optional = true, workspace = true } +next-build = { optional = true, path = "../next-build", default-features = false, features = [ + "custom_allocator", +] } # TODO: Not sure what's going on, but using `workspace = true` noops `default-features = false`? next-dev = { optional = true, path = "../next-dev", default-features = false, features = [ "custom_allocator", diff --git a/packages/next-swc/crates/next-binding/src/lib.rs b/packages/next-swc/crates/next-binding/src/lib.rs index 03b0741db72ac6..db7756d02efaf1 100644 --- a/packages/next-swc/crates/next-binding/src/lib.rs +++ b/packages/next-swc/crates/next-binding/src/lib.rs @@ -21,6 +21,8 @@ pub mod swc { #[cfg(feature = "__turbo")] pub mod turbo { + #[cfg(feature = "__turbo_next_build")] + pub use next_build; #[cfg(feature = "__turbo_next_dev_server")] pub use next_dev; #[cfg(feature = "__turbo_node_file_trace")] diff --git a/packages/next-swc/crates/next-build/Cargo.toml b/packages/next-swc/crates/next-build/Cargo.toml new file mode 100644 index 00000000000000..8d4ab64f93bb03 --- /dev/null +++ b/packages/next-swc/crates/next-build/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "next-build" +version = "0.1.0" +description = "TBD" +license = "MPL-2.0" +edition = "2021" +autobenches = false + +[features] +next-font-local = ["next-core/next-font-local"] +native-tls = ["next-core/native-tls"] +rustls-tls = ["next-core/rustls-tls"] +custom_allocator = ["turbo-malloc/custom_allocator"] + +[dependencies] +anyhow = "1.0.47" +next-core = { workspace = true } +turbo-malloc = { workspace = true, default-features = false } +turbo-tasks = { workspace = true } +turbo-tasks-memory = { workspace = true } + +[build-dependencies] +turbo-tasks-build = { workspace = true } +vergen = { version = "7.3.2", default-features = false, features = [ + "cargo", + "build", +] } \ No newline at end of file diff --git a/packages/next-swc/crates/next-build/build.rs b/packages/next-swc/crates/next-build/build.rs new file mode 100644 index 00000000000000..cc35b5e2440c1b --- /dev/null +++ b/packages/next-swc/crates/next-build/build.rs @@ -0,0 +1,13 @@ +use turbo_tasks_build::{generate_register, rerun_if_glob}; + +use vergen::{vergen, Config}; + +fn main() { + generate_register(); + + rerun_if_glob("tests/integration/*/*", "tests/integration"); + + // Attempt to collect some build time env values but will skip if there are any + // errors. + let _ = vergen(Config::default()); +} diff --git a/packages/next-swc/crates/next-build/src/lib.rs b/packages/next-swc/crates/next-build/src/lib.rs new file mode 100644 index 00000000000000..e9d04ee7658dee --- /dev/null +++ b/packages/next-swc/crates/next-build/src/lib.rs @@ -0,0 +1,33 @@ +use turbo_tasks::{NothingVc, StatsType, TurboTasks, TurboTasksBackendApi}; +use turbo_tasks_memory::MemoryBackend; + +pub fn register() { + turbo_tasks::register(); + include!(concat!(env!("OUT_DIR"), "/register.rs")); +} + +pub struct NextBuildOptions { + pub dir: Option, + pub memory_limit: Option, + pub full_stats: Option, +} + +pub async fn next_build(options: NextBuildOptions) -> anyhow::Result<()> { + register(); + let tt = TurboTasks::new(MemoryBackend::new( + options.memory_limit.map_or(usize::MAX, |l| l * 1024 * 1024), + )); + let stats_type = match options.full_stats { + Some(true) => StatsType::Full, + _ => StatsType::Essential, + }; + tt.set_stats_type(stats_type); + let task = tt.spawn_root_task(move || { + Box::pin(async move { + // run next build here + Ok(NothingVc::new().into()) + }) + }); + tt.wait_task_completion(task, true).await?; + Ok(()) +} diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 4f62bd3aa2e3f2..2aa333e22c4e34 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -255,7 +255,8 @@ export default async function build( debugOutput = false, runLint = true, noMangling = false, - appDirOnly = false + appDirOnly = false, + turboNextBuild = false ): Promise { try { const nextBuildSpan = trace('next-build', undefined, { @@ -1010,8 +1011,17 @@ export default async function build( ignore: [] as string[], })) + let binding = (await loadBindings()) as any + + async function turbopackBuild() { + const turboNextBuildStart = process.hrtime() + await binding.turbo.nextBuild(NextBuildContext) + const [duration] = process.hrtime(turboNextBuildStart) + return { duration, turbotraceContext: null } + } + const { duration: webpackBuildDuration, turbotraceContext } = - await webpackBuild() + turboNextBuild ? await turbopackBuild() : await webpackBuild() telemetry.record( eventBuildCompleted(pagesPaths, { @@ -1026,7 +1036,6 @@ export default async function build( if (!turbotraceContext) { return } - let binding = (await loadBindings()) as any if ( !binding?.isWasm && typeof binding.turbo.startTrace === 'function' @@ -1069,11 +1078,9 @@ export default async function build( if (filesTracedFromEntries.length) { // The turbo trace doesn't provide the traced file type and reason at present // let's write the traced files into the first [entry].nft.json - // @ts-expect-error types - const [[, entryName]] = Array.from(entryNameMap.entries()).filter( - // @ts-expect-error types - ([k]) => k.startsWith(turbotraceContextAppDir) - ) + const [[, entryName]] = Array.from<[string, string]>( + entryNameMap.entries() + ).filter(([k]) => k.startsWith(turbotraceContextAppDir)) const traceOutputPath = path.join( outputPath, `../${entryName}.js.nft.json` @@ -1797,7 +1804,6 @@ export default async function build( } else if (config.outputFileTracing) { let nodeFileTrace: any if (config.experimental.turbotrace) { - let binding = (await loadBindings()) as any if (!binding?.isWasm) { nodeFileTrace = binding.turbo.startTrace } diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index 36473fc6189f91..ca33f8a337de75 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -471,6 +471,9 @@ function loadNative(isCustomTurbopack = false) { require(__INTERNAL_CUSTOM_TURBOPACK_BINDINGS).startDev(devOptions) } }, + nextBuild: (options: unknown) => { + return bindings.nextBuild(options) + }, startTrace: (options = {}, turboTasks: unknown) => bindings.runTurboTracing( toBuffer({ exact: true, ...options }), diff --git a/packages/next/src/build/webpack-build.ts b/packages/next/src/build/webpack-build.ts index 088bf4b67ace92..f2832bed8d64ef 100644 --- a/packages/next/src/build/webpack-build.ts +++ b/packages/next/src/build/webpack-build.ts @@ -409,7 +409,7 @@ async function webpackBuildWithWorker() { const combinedResult = { duration: 0, - turbotraceContext: {} as any, + turbotraceContext: {} as TurbotraceContext, } // order matters here const ORDERED_COMPILER_NAMES = [ @@ -447,9 +447,9 @@ async function webpackBuildWithWorker() { if (curResult.turbotraceContext?.entriesTrace) { combinedResult.turbotraceContext = curResult.turbotraceContext - const { entryNameMap } = combinedResult.turbotraceContext.entriesTrace + const { entryNameMap } = combinedResult.turbotraceContext.entriesTrace! if (entryNameMap) { - combinedResult.turbotraceContext.entriesTrace.entryNameMap = new Map( + combinedResult.turbotraceContext.entriesTrace!.entryNameMap = new Map( entryNameMap ) } diff --git a/packages/next/src/cli/next-build.ts b/packages/next/src/cli/next-build.ts index a2d5546ef2dec8..fb2dc714b92620 100755 --- a/packages/next/src/cli/next-build.ts +++ b/packages/next/src/cli/next-build.ts @@ -17,6 +17,7 @@ const nextBuild: CliCommand = (argv) => { '--no-lint': Boolean, '--no-mangling': Boolean, '--experimental-app-only': Boolean, + '--experimental-turbo': Boolean, // Aliases '-h': '--help', '-d': '--debug', @@ -76,7 +77,8 @@ const nextBuild: CliCommand = (argv) => { args['--debug'] || process.env.NEXT_DEBUG_BUILD, !args['--no-lint'], args['--no-mangling'], - args['--experimental-app-only'] + args['--experimental-app-only'], + args['--experimental-turbo'] ).catch((err) => { console.error('') if ( From ed539c5dca7bd4d1c9cc9cd99c4b3d947e54c88e Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 21 Mar 2023 12:48:48 +0100 Subject: [PATCH 585/672] Update Turbopack to turbopack-230321.1 (#47342) Updates Turbopack to latest nightly and fix build errors. # New features * https://github.com/vercel/turbo/pull/4198 # Bug Fixes * https://github.com/vercel/turbo/pull/4241 # Misc. * https://github.com/vercel/turbo/pull/4249 --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/next-swc/Cargo.lock | 55 ++++++++--------- packages/next-swc/Cargo.toml | 60 +++++++++---------- .../next_layout_entry_transition.rs | 8 ++- .../crates/next-core/src/app_source.rs | 8 ++- .../next-core/src/next_client/context.rs | 10 +++- .../next-core/src/next_client/transition.rs | 8 ++- .../server_to_client_transition.rs | 8 ++- .../next-core/src/next_server/context.rs | 21 +++++-- .../crates/next-core/src/page_source.rs | 8 ++- 9 files changed, 111 insertions(+), 75 deletions(-) diff --git a/packages/next-swc/Cargo.lock b/packages/next-swc/Cargo.lock index c1b5fd0fa8805f..b61f60a8e49baa 100644 --- a/packages/next-swc/Cargo.lock +++ b/packages/next-swc/Cargo.lock @@ -337,7 +337,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "serde", ] @@ -3235,7 +3235,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "clap 4.1.8", @@ -5090,6 +5090,7 @@ dependencies = [ "swc_ecma_transforms_base", "swc_ecma_transforms_module", "swc_ecma_transforms_optimization", + "swc_ecma_transforms_proposal", "swc_ecma_transforms_react", "swc_ecma_transforms_testing", "swc_ecma_transforms_typescript", @@ -6540,7 +6541,7 @@ dependencies = [ [[package]] name = "turbo-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "mimalloc", ] @@ -6548,7 +6549,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "auto-hash-map", @@ -6578,7 +6579,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "cargo-lock", @@ -6590,7 +6591,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "dotenvy", @@ -6604,7 +6605,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "indexmap", @@ -6621,7 +6622,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "auto-hash-map", @@ -6650,7 +6651,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "base16", "hex", @@ -6662,7 +6663,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -6676,7 +6677,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "proc-macro2", "quote", @@ -6686,7 +6687,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "auto-hash-map", @@ -6708,7 +6709,7 @@ dependencies = [ [[package]] name = "turbo-tasks-testing" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "auto-hash-map", @@ -6720,7 +6721,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "async-recursion", @@ -6746,7 +6747,7 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "clap 4.1.8", @@ -6762,7 +6763,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "async-trait", @@ -6789,7 +6790,7 @@ dependencies = [ [[package]] name = "turbopack-create-test-app" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "clap 4.1.8", @@ -6802,7 +6803,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "async-trait", @@ -6824,7 +6825,7 @@ dependencies = [ [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "async-compression", @@ -6856,7 +6857,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "async-trait", @@ -6891,7 +6892,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "serde", @@ -6906,7 +6907,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "serde", @@ -6921,7 +6922,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "mdxjs", @@ -6936,7 +6937,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "futures", @@ -6962,7 +6963,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "serde", @@ -6978,7 +6979,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "swc_core", "turbo-tasks", @@ -6989,7 +6990,7 @@ dependencies = [ [[package]] name = "turbopack-test-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230317.2#11cca6719665fbb17d6750d8c62bd95fe4f2998e" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" dependencies = [ "anyhow", "once_cell", diff --git a/packages/next-swc/Cargo.toml b/packages/next-swc/Cargo.toml index 5c1214882069d6..63cc60356edb24 100644 --- a/packages/next-swc/Cargo.toml +++ b/packages/next-swc/Cargo.toml @@ -46,36 +46,36 @@ swc_emotion = { version = "0.29.10" } testing = { version = "0.31.31" } # Turbo crates -auto-hash-map = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -node-file-trace = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -swc-ast-explorer = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-malloc = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2", default-features = false } -turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-build = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-fetch = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2", default-features = false } -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-hash = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-macros = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-macros-shared = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-memory = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-tasks-testing = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbo-updater = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-cli-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-core = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-create-test-app = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-css = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-dev-server = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-ecmascript = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-json = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-mdx = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-node = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-static = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-swc-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-test-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } -turbopack-tests = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230317.2" } +auto-hash-map = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +node-file-trace = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +swc-ast-explorer = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-malloc = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1", default-features = false } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-build = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-fetch = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1", default-features = false } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-hash = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-macros = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-macros-shared = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-memory = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-tasks-testing = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbo-updater = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-cli-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-core = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-create-test-app = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-css = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-dev-server = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-ecmascript = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-json = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-mdx = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-node = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-static = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-swc-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-test-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +turbopack-tests = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } # General Deps diff --git a/packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs b/packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs index 2590f5634ff378..0d999f19100423 100644 --- a/packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs +++ b/packages/next-swc/crates/next-core/src/app_render/next_layout_entry_transition.rs @@ -1,6 +1,6 @@ use anyhow::Result; use indexmap::indexmap; -use turbo_tasks::Value; +use turbo_tasks::{primitives::OptionStringVc, Value}; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ self, @@ -69,7 +69,11 @@ impl Transition for NextLayoutEntryTransition { EcmascriptInputTransform::TypeScript { use_define_for_class_fields: false, }, - EcmascriptInputTransform::React { refresh: false }, + EcmascriptInputTransform::React { + refresh: false, + import_source: OptionStringVc::cell(None), + runtime: OptionStringVc::cell(None), + }, ]), context.compile_time_info(), InnerAssetsVc::cell(indexmap! { diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index b77a312a990dd1..6fb38b0e1aa870 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::{anyhow, Result}; use indexmap::indexmap; -use turbo_tasks::{TryJoinIterExt, Value, ValueToString}; +use turbo_tasks::{primitives::OptionStringVc, TryJoinIterExt, Value, ValueToString}; use turbo_tasks_env::{CustomProcessEnvVc, EnvMapVc, ProcessEnvVc}; use turbo_tasks_fs::{rope::RopeBuilder, File, FileContent, FileSystemPathVc}; use turbopack::{ @@ -658,7 +658,11 @@ import BOOTSTRAP from {}; context, Value::new(EcmascriptModuleAssetType::Typescript), EcmascriptInputTransformsVc::cell(vec![ - EcmascriptInputTransform::React { refresh: false }, + EcmascriptInputTransform::React { + refresh: false, + import_source: OptionStringVc::cell(None), + runtime: OptionStringVc::cell(None), + }, EcmascriptInputTransform::TypeScript { use_define_for_class_fields: false, }, diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 9a7cac3860e49b..2ed2fecca3b91e 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -8,7 +8,7 @@ use turbo_tasks_fs::{FileSystem, FileSystemPathVc}; use turbopack::{ module_options::{ module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, - PostCssTransformOptions, WebpackLoadersOptions, + JsxTransformOptions, PostCssTransformOptions, WebpackLoadersOptions, }, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, transition::TransitionsByNameVc, @@ -156,7 +156,13 @@ pub async fn get_client_module_options_context( // We don't need to resolve React Refresh for each module. Instead, // we try resolve it once at the root and pass down a context to all // the modules. - enable_jsx: true, + enable_jsx: Some( + JsxTransformOptions { + import_source: None, + runtime: None, + } + .cell(), + ), enable_emotion: true, enable_react_refresh, enable_styled_components: true, diff --git a/packages/next-swc/crates/next-core/src/next_client/transition.rs b/packages/next-swc/crates/next-core/src/next_client/transition.rs index 8557b3f4105e7e..1e49c2d02ee41c 100644 --- a/packages/next-swc/crates/next-core/src/next_client/transition.rs +++ b/packages/next-swc/crates/next-core/src/next_client/transition.rs @@ -1,6 +1,6 @@ use anyhow::Result; use indexmap::indexmap; -use turbo_tasks::Value; +use turbo_tasks::{primitives::OptionStringVc, Value}; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, @@ -83,7 +83,11 @@ impl Transition for NextClientTransition { EcmascriptInputTransform::TypeScript { use_define_for_class_fields: false, }, - EcmascriptInputTransform::React { refresh: false }, + EcmascriptInputTransform::React { + refresh: false, + import_source: OptionStringVc::cell(None), + runtime: OptionStringVc::cell(None), + }, ]), context.compile_time_info(), InnerAssetsVc::cell(indexmap! { diff --git a/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs b/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs index acc7bdc0235635..078175ec016bd1 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/server_to_client_transition.rs @@ -1,6 +1,6 @@ use anyhow::Result; use indexmap::indexmap; -use turbo_tasks::Value; +use turbo_tasks::{primitives::OptionStringVc, Value}; use turbopack::{ transition::{Transition, TransitionVc}, ModuleAssetContextVc, @@ -57,7 +57,11 @@ impl Transition for NextServerToClientTransition { EcmascriptInputTransform::TypeScript { use_define_for_class_fields: false, }, - EcmascriptInputTransform::React { refresh: false }, + EcmascriptInputTransform::React { + refresh: false, + import_source: OptionStringVc::cell(None), + runtime: OptionStringVc::cell(None), + }, ]), context.compile_time_info(), InnerAssetsVc::cell(indexmap! { diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index e8e8de3bdb6fbb..ab5e851129c85b 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -4,8 +4,8 @@ use turbo_tasks_env::ProcessEnvVc; use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ module_options::{ - ModuleOptionsContext, ModuleOptionsContextVc, PostCssTransformOptions, - WebpackLoadersOptions, + JsxTransformOptions, JsxTransformOptionsVc, ModuleOptionsContext, ModuleOptionsContextVc, + PostCssTransformOptions, WebpackLoadersOptions, }, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, }; @@ -238,7 +238,7 @@ pub async fn get_server_module_options_context( ..Default::default() }; ModuleOptionsContext { - enable_jsx: true, + enable_jsx: Some(get_jsx_transform_options()), enable_styled_jsx: true, enable_postcss_transform, enable_webpack_loaders, @@ -257,7 +257,7 @@ pub async fn get_server_module_options_context( ..Default::default() }; ModuleOptionsContext { - enable_jsx: true, + enable_jsx: Some(get_jsx_transform_options()), enable_styled_jsx: true, enable_postcss_transform, enable_webpack_loaders, @@ -279,7 +279,7 @@ pub async fn get_server_module_options_context( ..Default::default() }; ModuleOptionsContext { - enable_jsx: true, + enable_jsx: Some(get_jsx_transform_options()), enable_postcss_transform, enable_webpack_loaders, enable_typescript_transform: Some(tsconfig), @@ -314,7 +314,7 @@ pub async fn get_server_module_options_context( ..Default::default() }; ModuleOptionsContext { - enable_jsx: true, + enable_jsx: Some(get_jsx_transform_options()), enable_styled_jsx: true, enable_postcss_transform, enable_webpack_loaders, @@ -333,6 +333,15 @@ pub async fn get_server_module_options_context( Ok(module_options_context) } +#[turbo_tasks::function] +pub fn get_jsx_transform_options() -> JsxTransformOptionsVc { + JsxTransformOptions { + import_source: None, + runtime: None, + } + .cell() +} + #[turbo_tasks::function] pub fn get_build_module_options_context() -> ModuleOptionsContextVc { ModuleOptionsContext { diff --git a/packages/next-swc/crates/next-core/src/page_source.rs b/packages/next-swc/crates/next-core/src/page_source.rs index fa6c2c7259de1e..a83682aacdc113 100644 --- a/packages/next-swc/crates/next-core/src/page_source.rs +++ b/packages/next-swc/crates/next-core/src/page_source.rs @@ -2,7 +2,7 @@ use anyhow::Result; use indexmap::indexmap; use serde::{Deserialize, Serialize}; use turbo_tasks::{ - primitives::{StringVc, StringsVc}, + primitives::{OptionStringVc, StringVc, StringsVc}, trace::TraceRawVcs, Value, }; @@ -721,7 +721,11 @@ impl SsrEntryVc { EcmascriptInputTransform::TypeScript { use_define_for_class_fields: false, }, - EcmascriptInputTransform::React { refresh: false }, + EcmascriptInputTransform::React { + refresh: false, + import_source: OptionStringVc::cell(None), + runtime: OptionStringVc::cell(None), + }, ]), this.context.compile_time_info(), InnerAssetsVc::cell(inner_assets), From 316638bc031f3a0c2125e07c1c36f16fe1bbf67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Tue, 21 Mar 2023 14:27:09 +0100 Subject: [PATCH 586/672] chore: add checkout step to issue labeler action (#47346) --- .github/workflows/issue_labeler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/issue_labeler.yml b/.github/workflows/issue_labeler.yml index adc3f0f5b603c9..4c0c31427c7174 100644 --- a/.github/workflows/issue_labeler.yml +++ b/.github/workflows/issue_labeler.yml @@ -13,6 +13,7 @@ jobs: name: Triage runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 18 From ed9435cdbf53f4ae7137c9731d77b64b555aeee0 Mon Sep 17 00:00:00 2001 From: Jimmy Lai Date: Tue, 21 Mar 2023 16:30:40 +0100 Subject: [PATCH 587/672] parallel routes: fix HMR refetch issue (#47343) - I noticed that on parallel routes, we kept refetching all the time the tree - this was caused by the HMR ping interval + a mismatch on how we recreated the entrypoint path from the router state, causing the server to always invalidate the parallel route - this fixes it to respect the format fix NEXT-860 ([link](https://linear.app/vercel/issue/NEXT-860)) --- packages/next/src/server/dev/on-demand-entry-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/src/server/dev/on-demand-entry-handler.ts b/packages/next/src/server/dev/on-demand-entry-handler.ts index 44856b5cbf9629..4ad7a5d85bf5aa 100644 --- a/packages/next/src/server/dev/on-demand-entry-handler.ts +++ b/packages/next/src/server/dev/on-demand-entry-handler.ts @@ -54,7 +54,7 @@ function treePathToEntrypoint( const path = (parentPath ? parentPath + '/' : '') + (parallelRouteKey !== 'children' && !segment.startsWith('@') - ? parallelRouteKey + '/' + ? `@${parallelRouteKey}/` : '') + (segment === '' ? 'page' : segment) From 93152db9b181c4643cfed424b79c653da8d3ea85 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Tue, 21 Mar 2023 16:55:32 +0100 Subject: [PATCH 588/672] Fix bad route path for custom metadata routes (#47286) We introduced static route `robots.txt` and dynamic route `robots.js` for metadata, it should still allow users to create their own customized version. This issue is caused by a route conflicts. Only append `/route` to page path when there's not ending with `/route` Fixes #47198 Closes NEXT-850 --- .../build/webpack/loaders/next-app-loader.ts | 4 +++- .../src/lib/metadata/get-metadata-route.ts | 6 ++++- .../next/src/server/lib/find-page-file.ts | 12 ++++++---- .../app-routes/app-custom-routes.test.ts | 11 +++++++++ .../app-routes/app/robots.txt/route.ts | 6 +++++ test/e2e/app-dir/app-routes/tsconfig.json | 24 +++++++++++++++++++ test/unit/find-page-file.test.ts | 5 ++-- 7 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 test/e2e/app-dir/app-routes/app/robots.txt/route.ts create mode 100644 test/e2e/app-dir/app-routes/tsconfig.json diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index 22069538359e55..b32bdf0c599b41 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -75,7 +75,9 @@ async function createAppRouteCode({ // This, when used with the resolver will give us the pathname to the built // route handler file. let resolvedPagePath = (await resolver(routePath))! - if (isMetadataRoute(name)) { + + const filename = path.parse(resolvedPagePath).name + if (isMetadataRoute(name) && filename !== 'route') { resolvedPagePath = `next-metadata-route-loader?${stringify({ pageExtensions, })}!${resolvedPagePath + METADATA_RESOURCE_QUERY}` diff --git a/packages/next/src/lib/metadata/get-metadata-route.ts b/packages/next/src/lib/metadata/get-metadata-route.ts index 10b56b893d60d5..325b45697718e7 100644 --- a/packages/next/src/lib/metadata/get-metadata-route.ts +++ b/packages/next/src/lib/metadata/get-metadata-route.ts @@ -23,7 +23,11 @@ export function normalizeMetadataRoute(page: string) { if (route === '/manifest') { route += '.webmanifest' } - route = `${route}/route` + // Support both / and custom routes //route.ts. + // If it's a metadata file route, we need to append /route to the page. + if (!route.endsWith('/route')) { + route = `${route}/route` + } } return route } diff --git a/packages/next/src/server/lib/find-page-file.ts b/packages/next/src/server/lib/find-page-file.ts index 6cf514a8342741..e0f6e84e3bd768 100644 --- a/packages/next/src/server/lib/find-page-file.ts +++ b/packages/next/src/server/lib/find-page-file.ts @@ -2,7 +2,7 @@ import { fileExists } from '../../lib/file-exists' import { getPagePaths } from '../../shared/lib/page-path/get-page-paths' import { nonNullable } from '../../lib/non-nullable' import { join, sep, normalize } from 'path' -import { promises } from 'fs' +import { promises as fsPromises } from 'fs' import { warn } from '../../build/output/log' import chalk from '../../lib/chalk' import { isMetadataRouteFile } from '../../lib/metadata/is-metadata-route' @@ -11,7 +11,7 @@ async function isTrueCasePagePath(pagePath: string, pagesDir: string) { const pageSegments = normalize(pagePath).split(sep).filter(Boolean) const segmentExistsPromises = pageSegments.map(async (segment, i) => { const segmentParentDir = join(pagesDir, ...pageSegments.slice(0, i)) - const parentDirEntries = await promises.readdir(segmentParentDir) + const parentDirEntries = await fsPromises.readdir(segmentParentDir) return parentDirEntries.includes(segment) }) @@ -104,11 +104,13 @@ export function createValidFileMatcher( */ /** - * Match the file if it's a metadata route file, static: if the file is a static metadata file - * + * Match the file if it's a metadata route file, static: if the file is a static metadata file. + * It needs to be a file which doesn't match the custom metadata routes e.g. `app/robots.txt/route.js` */ function isMetadataFile(filePath: string) { - const appDirRelativePath = filePath.replace(appDirPath || '', '') + const appDirRelativePath = appDirPath + ? filePath.replace(appDirPath, '') + : filePath return isMetadataRouteFile(appDirRelativePath, pageExtensions, true) } diff --git a/test/e2e/app-dir/app-routes/app-custom-routes.test.ts b/test/e2e/app-dir/app-routes/app-custom-routes.test.ts index 868d78563f43a8..7961719270ac17 100644 --- a/test/e2e/app-dir/app-routes/app-custom-routes.test.ts +++ b/test/e2e/app-dir/app-routes/app-custom-routes.test.ts @@ -521,6 +521,17 @@ createNextDescribe( }) }) + describe('customized metadata routes', () => { + it('should work if conflict with metadata routes convention', async () => { + const res = await next.fetch('/robots.txt') + + expect(res.status).toEqual(200) + expect(await res.text()).toBe( + 'User-agent: *\nAllow: /\n\nSitemap: https://www.example.com/sitemap.xml' + ) + }) + }) + if (isNextDev) { describe('lowercase exports', () => { it.each([ diff --git a/test/e2e/app-dir/app-routes/app/robots.txt/route.ts b/test/e2e/app-dir/app-routes/app/robots.txt/route.ts new file mode 100644 index 00000000000000..55d59f988b32e3 --- /dev/null +++ b/test/e2e/app-dir/app-routes/app/robots.txt/route.ts @@ -0,0 +1,6 @@ +export async function GET() { + return new Response(`User-agent: * +Allow: / + +Sitemap: https://www.example.com/sitemap.xml`) +} diff --git a/test/e2e/app-dir/app-routes/tsconfig.json b/test/e2e/app-dir/app-routes/tsconfig.json new file mode 100644 index 00000000000000..8334cf0c311eb2 --- /dev/null +++ b/test/e2e/app-dir/app-routes/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "incremental": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules", "**/*.test.ts"] +} diff --git a/test/unit/find-page-file.test.ts b/test/unit/find-page-file.test.ts index f1748dd26c7fec..09dc5f0c160950 100644 --- a/test/unit/find-page-file.test.ts +++ b/test/unit/find-page-file.test.ts @@ -4,7 +4,6 @@ import { createValidFileMatcher, } from 'next/dist/server/lib/find-page-file' import { normalizePagePath } from 'next/dist/shared/lib/page-path/normalize-page-path' - import { join } from 'path' const resolveDataDir = join(__dirname, 'isolated', '_resolvedata') @@ -71,9 +70,9 @@ describe('createPageFileMatcher', () => { }) describe('isMetadataRouteFile', () => { - const pageExtensions = ['tsx', 'ts', 'jsx', 'js'] - const fileMatcher = createValidFileMatcher(pageExtensions, 'app') it('should determine top level metadata routes', () => { + const pageExtensions = ['tsx', 'ts', 'jsx', 'js'] + const fileMatcher = createValidFileMatcher(pageExtensions, 'app') expect(fileMatcher.isMetadataFile('app/route.js')).toBe(false) expect(fileMatcher.isMetadataFile('app/page.js')).toBe(false) expect(fileMatcher.isMetadataFile('pages/index.js')).toBe(false) From 86bf30a44827ba651a4274abc67fd43d4bd6139b Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 21 Mar 2023 10:24:21 -0700 Subject: [PATCH 589/672] Fix POST fetch request cache heuristic in POST route handler (#47333) This ensures we properly bail from caching POST requests when a route is dynamic e.g. a POST route handler --- .../components/static-generation-bailout.ts | 5 ++++- .../e2e/app-dir/app-static/app-static.test.ts | 21 +++++++++++++++++++ .../app/route-handler/post/route.js | 12 +++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/e2e/app-dir/app-static/app/route-handler/post/route.js diff --git a/packages/next/src/client/components/static-generation-bailout.ts b/packages/next/src/client/components/static-generation-bailout.ts index bdd41053df31b6..ae89f65d3df69a 100644 --- a/packages/next/src/client/components/static-generation-bailout.ts +++ b/packages/next/src/client/components/static-generation-bailout.ts @@ -14,8 +14,11 @@ export function staticGenerationBailout(reason: string): boolean | never { ) } - if (staticGenerationStore?.isStaticGeneration) { + if (staticGenerationStore) { staticGenerationStore.revalidate = 0 + } + + if (staticGenerationStore?.isStaticGeneration) { const err = new DynamicServerError(reason) staticGenerationStore.dynamicUsageDescription = reason diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index 08f50ffc8029e2..c0e506198d1757 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -50,6 +50,26 @@ createNextDescribe( }) } + it('should correctly skip caching POST fetch for POST handler', async () => { + const res = await next.fetch('/route-handler/post', { + method: 'POST', + }) + expect(res.status).toBe(200) + + const data = await res.json() + expect(data).toBeTruthy() + + for (let i = 0; i < 5; i++) { + const res2 = await next.fetch('/route-handler/post', { + method: 'POST', + }) + expect(res2.status).toBe(200) + const newData = await res2.json() + expect(newData).toBeTruthy() + expect(newData).not.toEqual(data) + } + }) + if (!process.env.CUSTOM_CACHE_HANDLER) { it('should revalidate correctly with config and fetch revalidate', async () => { const initial$ = await next.render$( @@ -192,6 +212,7 @@ createNextDescribe( 'partial-gen-params-no-additional-slug/fr/second.html', 'partial-gen-params-no-additional-slug/fr/second.rsc', 'partial-gen-params/[lang]/[slug]/page.js', + 'route-handler/post/route.js', 'ssg-preview.html', 'ssg-preview.rsc', 'ssg-preview/[[...route]]/page.js', diff --git a/test/e2e/app-dir/app-static/app/route-handler/post/route.js b/test/e2e/app-dir/app-static/app/route-handler/post/route.js new file mode 100644 index 00000000000000..bbdfe54c435253 --- /dev/null +++ b/test/e2e/app-dir/app-static/app/route-handler/post/route.js @@ -0,0 +1,12 @@ +import { NextResponse } from 'next/server' + +export async function POST() { + const data = await fetch( + 'https://next-data-api-endpoint.vercel.app/api/random', + { + method: 'POST', + } + ).then((res) => res.text()) + + return NextResponse.json({ data }) +} From 75c6b100090c2cb1854ef888257ff8348a2df956 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Tue, 21 Mar 2023 19:25:20 +0100 Subject: [PATCH 590/672] Fix: only apply metadata dynamic image routes convention for app dir (#47367) We shouldn't detect icon/og/etc. metadata image convention as image dynamic routes under `pages/` dir, they should be only apply in `app/` dir. This PR changed the normalization rule that we only apply them when page is from `app/`. So when you're using `icon.js` under `pages/` it won't get effected. --- packages/next/src/build/entries.ts | 3 ++- packages/next/src/server/dev/next-dev-server.ts | 6 ++++-- .../absolute-filename-normalizer.test.ts | 11 +++++------ .../normalizers/absolute-filename-normalizer.ts | 6 ++++-- .../dev/dev-app-page-route-matcher-provider.ts | 6 +++++- .../dev/dev-app-route-route-matcher-provider.ts | 6 +++++- .../dev/dev-pages-api-route-matcher-provider.ts | 6 +++++- .../dev/dev-pages-route-matcher-provider.ts | 6 +++++- .../shared/lib/page-path/absolute-path-to-page.ts | 13 +++++++------ test/e2e/app-dir/metadata/metadata.test.ts | 7 +++++++ test/e2e/app-dir/metadata/pages/blog/icon.tsx | 3 +++ .../app-dir/metadata/pages/blog/opengraph-image.tsx | 3 +++ test/e2e/app-dir/metadata/tsconfig.json | 3 ++- 13 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 test/e2e/app-dir/metadata/pages/blog/icon.tsx create mode 100644 test/e2e/app-dir/metadata/pages/blog/opengraph-image.tsx diff --git a/packages/next/src/build/entries.ts b/packages/next/src/build/entries.ts index 50181dbb8725ba..66ac0b34845caf 100644 --- a/packages/next/src/build/entries.ts +++ b/packages/next/src/build/entries.ts @@ -111,7 +111,8 @@ export function createPagesMapping({ ) ) - const route = normalizeMetadataRoute(pageKey) + const route = + pagesType === 'app' ? normalizeMetadataRoute(pageKey) : pageKey result[route] = normalizedPath return result }, diff --git a/packages/next/src/server/dev/next-dev-server.ts b/packages/next/src/server/dev/next-dev-server.ts index 3b48a16a5f5ff2..e49383423ebf1d 100644 --- a/packages/next/src/server/dev/next-dev-server.ts +++ b/packages/next/src/server/dev/next-dev-server.ts @@ -492,9 +492,10 @@ export default class DevServer extends Server { devPageFiles.add(fileName) const rootFile = absolutePathToPage(fileName, { - pagesDir: this.dir, + dir: this.dir, extensions: this.nextConfig.pageExtensions, keepIndex: false, + pagesType: 'root', }) const staticInfo = await getPageStaticInfo({ @@ -531,9 +532,10 @@ export default class DevServer extends Server { } let pageName = absolutePathToPage(fileName, { - pagesDir: isAppPath ? this.appDir! : this.pagesDir!, + dir: isAppPath ? this.appDir! : this.pagesDir!, extensions: this.nextConfig.pageExtensions, keepIndex: isAppPath, + pagesType: isAppPath ? 'app' : 'pages', }) if ( diff --git a/packages/next/src/server/future/normalizers/absolute-filename-normalizer.test.ts b/packages/next/src/server/future/normalizers/absolute-filename-normalizer.test.ts index df253729b38c74..100d96be4a3c54 100644 --- a/packages/next/src/server/future/normalizers/absolute-filename-normalizer.test.ts +++ b/packages/next/src/server/future/normalizers/absolute-filename-normalizer.test.ts @@ -20,12 +20,11 @@ describe('AbsoluteFilenameNormalizer', () => { ])( "normalizes '$pathname' to '$expected'", ({ pathname, expected, name }) => { - const normalizer = new AbsoluteFilenameNormalizer(`/${name}`, [ - 'ts', - 'tsx', - 'js', - 'jsx', - ]) + const normalizer = new AbsoluteFilenameNormalizer( + `/${name}`, + ['ts', 'tsx', 'js', 'jsx'], + name as 'app' | 'pages' | 'root' + ) expect(normalizer.normalize(pathname)).toEqual(expected) } diff --git a/packages/next/src/server/future/normalizers/absolute-filename-normalizer.ts b/packages/next/src/server/future/normalizers/absolute-filename-normalizer.ts index c3a787f7012536..f5a5f78d488b6f 100644 --- a/packages/next/src/server/future/normalizers/absolute-filename-normalizer.ts +++ b/packages/next/src/server/future/normalizers/absolute-filename-normalizer.ts @@ -14,14 +14,16 @@ export class AbsoluteFilenameNormalizer implements Normalizer { */ constructor( private readonly dir: string, - private readonly extensions: ReadonlyArray + private readonly extensions: ReadonlyArray, + private readonly pagesType: 'pages' | 'app' | 'root' ) {} public normalize(pathname: string): string { return absolutePathToPage(pathname, { extensions: this.extensions, keepIndex: false, - pagesDir: this.dir, + dir: this.dir, + pagesType: this.pagesType, }) } } diff --git a/packages/next/src/server/future/route-matcher-providers/dev/dev-app-page-route-matcher-provider.ts b/packages/next/src/server/future/route-matcher-providers/dev/dev-app-page-route-matcher-provider.ts index 8a5bed49c135e0..c45b65aa749ddb 100644 --- a/packages/next/src/server/future/route-matcher-providers/dev/dev-app-page-route-matcher-provider.ts +++ b/packages/next/src/server/future/route-matcher-providers/dev/dev-app-page-route-matcher-provider.ts @@ -28,7 +28,11 @@ export class DevAppPageRouteMatcherProvider extends FileCacheRouteMatcherProvide // directory. this.expression = new RegExp(`[/\\\\]page\\.(?:${extensions.join('|')})$`) - const pageNormalizer = new AbsoluteFilenameNormalizer(appDir, extensions) + const pageNormalizer = new AbsoluteFilenameNormalizer( + appDir, + extensions, + 'app' + ) this.normalizers = { page: pageNormalizer, diff --git a/packages/next/src/server/future/route-matcher-providers/dev/dev-app-route-route-matcher-provider.ts b/packages/next/src/server/future/route-matcher-providers/dev/dev-app-route-route-matcher-provider.ts index b64d3e320526a2..81a662bfea78e8 100644 --- a/packages/next/src/server/future/route-matcher-providers/dev/dev-app-route-route-matcher-provider.ts +++ b/packages/next/src/server/future/route-matcher-providers/dev/dev-app-route-route-matcher-provider.ts @@ -24,7 +24,11 @@ export class DevAppRouteRouteMatcherProvider extends FileCacheRouteMatcherProvid ) { super(appDir, reader) - const pageNormalizer = new AbsoluteFilenameNormalizer(appDir, extensions) + const pageNormalizer = new AbsoluteFilenameNormalizer( + appDir, + extensions, + 'app' + ) this.normalizers = { page: pageNormalizer, diff --git a/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-api-route-matcher-provider.ts b/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-api-route-matcher-provider.ts index 5ba1b186f4e159..1822d7a90be321 100644 --- a/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-api-route-matcher-provider.ts +++ b/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-api-route-matcher-provider.ts @@ -34,7 +34,11 @@ export class DevPagesAPIRouteMatcherProvider extends FileCacheRouteMatcherProvid // pages directory. this.expression = new RegExp(`\\.(?:${extensions.join('|')})$`) - const pageNormalizer = new AbsoluteFilenameNormalizer(pagesDir, extensions) + const pageNormalizer = new AbsoluteFilenameNormalizer( + pagesDir, + extensions, + 'pages' + ) const bundlePathNormalizer = new Normalizers([ pageNormalizer, diff --git a/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-route-matcher-provider.ts b/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-route-matcher-provider.ts index 302c5e26e93447..1d8066bef8fac4 100644 --- a/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-route-matcher-provider.ts +++ b/packages/next/src/server/future/route-matcher-providers/dev/dev-pages-route-matcher-provider.ts @@ -34,7 +34,11 @@ export class DevPagesRouteMatcherProvider extends FileCacheRouteMatcherProvider< // pages directory. this.expression = new RegExp(`\\.(?:${extensions.join('|')})$`) - const pageNormalizer = new AbsoluteFilenameNormalizer(pagesDir, extensions) + const pageNormalizer = new AbsoluteFilenameNormalizer( + pagesDir, + extensions, + 'pages' + ) this.normalizers = { page: pageNormalizer, diff --git a/packages/next/src/shared/lib/page-path/absolute-path-to-page.ts b/packages/next/src/shared/lib/page-path/absolute-path-to-page.ts index 7f9bfc3c5bf70d..7341a45ac60434 100644 --- a/packages/next/src/shared/lib/page-path/absolute-path-to-page.ts +++ b/packages/next/src/shared/lib/page-path/absolute-path-to-page.ts @@ -14,26 +14,27 @@ import { normalizeMetadataRoute } from '../../../lib/metadata/get-metadata-route * - `/Users/rick/my-project/app/sitemap.js` -> `/sitemap/route` * * @param filepath Absolute path to the page. - * @param opts.pagesDir Absolute path to the pages folder. + * @param opts.dir Absolute path to the pages/app folder. * @param opts.extensions Extensions allowed for the page. * @param opts.keepIndex When true the trailing `index` kept in the path. + * @param opts.pagesType Whether the page is in the pages or app directory. */ export function absolutePathToPage( pagePath: string, options: { extensions: string[] | readonly string[] keepIndex: boolean - pagesDir: string + dir: string + pagesType: 'pages' | 'app' | 'root' } ) { + const isAppDir = options.pagesType === 'app' const page = removePagePathTail( - normalizePathSep( - ensureLeadingSlash(path.relative(options.pagesDir, pagePath)) - ), + normalizePathSep(ensureLeadingSlash(path.relative(options.dir, pagePath))), { extensions: options.extensions, keepIndex: options.keepIndex, } ) - return normalizeMetadataRoute(page) + return isAppDir ? normalizeMetadataRoute(page) : page } diff --git a/test/e2e/app-dir/metadata/metadata.test.ts b/test/e2e/app-dir/metadata/metadata.test.ts index 473282c78df896..3e5c40ab067728 100644 --- a/test/e2e/app-dir/metadata/metadata.test.ts +++ b/test/e2e/app-dir/metadata/metadata.test.ts @@ -756,5 +756,12 @@ createNextDescribe( } }) }) + + it('should not effect metadata images convention like files under pages directory', async () => { + const iconHtml = await next.render('/blog/icon') + const ogHtml = await next.render('/blog/opengraph-image') + expect(iconHtml).toContain('pages-icon-page') + expect(ogHtml).toContain('pages-opengraph-image-page') + }) } ) diff --git a/test/e2e/app-dir/metadata/pages/blog/icon.tsx b/test/e2e/app-dir/metadata/pages/blog/icon.tsx new file mode 100644 index 00000000000000..b4c2e5c95cc70f --- /dev/null +++ b/test/e2e/app-dir/metadata/pages/blog/icon.tsx @@ -0,0 +1,3 @@ +export default function page() { + return <>pages-icon-page +} diff --git a/test/e2e/app-dir/metadata/pages/blog/opengraph-image.tsx b/test/e2e/app-dir/metadata/pages/blog/opengraph-image.tsx new file mode 100644 index 00000000000000..2818d35a1e1075 --- /dev/null +++ b/test/e2e/app-dir/metadata/pages/blog/opengraph-image.tsx @@ -0,0 +1,3 @@ +export default function page() { + return <>pages-opengraph-image-page +} diff --git a/test/e2e/app-dir/metadata/tsconfig.json b/test/e2e/app-dir/metadata/tsconfig.json index 8334cf0c311eb2..eca3706463f966 100644 --- a/test/e2e/app-dir/metadata/tsconfig.json +++ b/test/e2e/app-dir/metadata/tsconfig.json @@ -17,7 +17,8 @@ { "name": "next" } - ] + ], + "strictNullChecks": true }, "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules", "**/*.test.ts"] From 4ffaf5067ff0fa58e034c5d2ddcff84166a8805e Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 21 Mar 2023 12:17:30 -0700 Subject: [PATCH 591/672] v13.2.5-canary.11 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index f2580d77d9b11c..f12bd45912f4b4 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.2.5-canary.10" + "version": "13.2.5-canary.11" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index fa084e638e1914..a2fe0689c689a7 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index df19cb52ec2e6a..0d0b3a1e55a56f 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -12,7 +12,7 @@ "test-pack": "cd ../../ && pnpm test-pack eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "13.2.5-canary.10", + "@next/eslint-plugin-next": "13.2.5-canary.11", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.42.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index b1d90c2c7d3ac4..c690edc0951315 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "description": "ESLint plugin for NextJS.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 6e7203064decee..36ac36a5920c14 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 4d9dbccd88aa11..7b259475eb8c75 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index ec1c701d1b5253..d56857740f9184 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index b255acb6382f47..ddda3a0746c16b 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 5b9cb816ad55db..bc44d5e3b0bcd7 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 1e9c796b1fd165..d1951578a4573c 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 8fb451a9d80068..a0f697c62d66b8 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index af72c85afbe82b..9a8219e1233e9a 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 1c6a946c33c6a2..346f6fccfd5335 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "private": true, "scripts": { "clean": "rm -rf ./native/*", diff --git a/packages/next/package.json b/packages/next/package.json index 77f50890cb1c05..96cef759654d2d 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -80,7 +80,7 @@ ] }, "dependencies": { - "@next/env": "13.2.5-canary.10", + "@next/env": "13.2.5-canary.11", "@swc/helpers": "0.4.14", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -135,11 +135,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.14.7", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.2.5-canary.10", - "@next/polyfill-nomodule": "13.2.5-canary.10", - "@next/react-dev-overlay": "13.2.5-canary.10", - "@next/react-refresh-utils": "13.2.5-canary.10", - "@next/swc": "13.2.5-canary.10", + "@next/polyfill-module": "13.2.5-canary.11", + "@next/polyfill-nomodule": "13.2.5-canary.11", + "@next/react-dev-overlay": "13.2.5-canary.11", + "@next/react-refresh-utils": "13.2.5-canary.11", + "@next/swc": "13.2.5-canary.11", "@opentelemetry/api": "1.4.1", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index ab613888ee29a5..40038c0a4d0c07 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 8d283d41541bee..49e02abca0b845 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "13.2.5-canary.10", + "version": "13.2.5-canary.11", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6990e9804b6e3..13312658bfbd25 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -444,7 +444,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 13.2.5-canary.10 + '@next/eslint-plugin-next': 13.2.5-canary.11 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.42.0 eslint: ^7.23.0 || ^8.0.0 @@ -517,12 +517,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.14.7 '@napi-rs/triples': 1.1.0 - '@next/env': 13.2.5-canary.10 - '@next/polyfill-module': 13.2.5-canary.10 - '@next/polyfill-nomodule': 13.2.5-canary.10 - '@next/react-dev-overlay': 13.2.5-canary.10 - '@next/react-refresh-utils': 13.2.5-canary.10 - '@next/swc': 13.2.5-canary.10 + '@next/env': 13.2.5-canary.11 + '@next/polyfill-module': 13.2.5-canary.11 + '@next/polyfill-nomodule': 13.2.5-canary.11 + '@next/react-dev-overlay': 13.2.5-canary.11 + '@next/react-refresh-utils': 13.2.5-canary.11 + '@next/swc': 13.2.5-canary.11 '@opentelemetry/api': 1.4.1 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.14 From 4942394bd90d73a447c5b370c3d9949c18dc807f Mon Sep 17 00:00:00 2001 From: Alexander Grattan <51346343+agrattan0820@users.noreply.github.com> Date: Tue, 21 Mar 2023 15:31:22 -0400 Subject: [PATCH 592/672] fix: update capitalization of ISR doc heading (#47370) Makes the capitalization for `On-demand Revalidation` correct and consistent with the rest of the page by changing it to `On-Demand Revalidation`. Thanks for this awesome framework! ![nextjs-isr-doc-change](https://user-images.githubusercontent.com/51346343/226716622-c2b77d39-780a-448e-96a7-ed417cdf2353.png) --- .../data-fetching/incremental-static-regeneration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basic-features/data-fetching/incremental-static-regeneration.md b/docs/basic-features/data-fetching/incremental-static-regeneration.md index fee7f272b253e5..778d18233f8570 100644 --- a/docs/basic-features/data-fetching/incremental-static-regeneration.md +++ b/docs/basic-features/data-fetching/incremental-static-regeneration.md @@ -92,7 +92,7 @@ When a request is made to a path that hasn’t been generated, Next.js will serv > Note: Check if your upstream data provider has caching enabled by default. You might need to disable (e.g. `useCdn: false`), otherwise a revalidation won't be able to pull fresh data to update the ISR cache. Caching can occur at a CDN (for an endpoint being requested) when it returns the `Cache-Control` header. -## On-demand Revalidation +## On-Demand Revalidation If you set a `revalidate` time of `60`, all visitors will see the same generated version of your site for one minute. The only way to invalidate the cache is from someone visiting that page after the minute has passed. From 250160f4a919b0255a2886505b4ff0914659f53f Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Tue, 21 Mar 2023 21:17:15 +0100 Subject: [PATCH 593/672] Ensure all server entry exports are functions (#47364)Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> When using a "use server" module, only exporting async functions is permitted. However, since we cannot perform static analysis on all exported value types (e.g., `export const foo = condition ? A : B`), we have added a runtime ensure function to validate that these are indeed valid functions. By implementing this, we can prevent any strange errors like "Can't access $$typeof of undefined or null" that may arise when exporting `undefined` or `null` from a server entry. Moreover, this measure helps avoid any potential mistakes that may occur. fix NEXT-865 ([link](https://linear.app/vercel/issue/NEXT-865)) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../crates/core/src/server_actions.rs | 50 ++++++++++++++++++- .../tests/errors/server-actions/1/output.js | 6 ++- .../tests/errors/server-actions/2/output.js | 6 ++- .../tests/errors/server-actions/3/output.js | 6 ++- .../tests/errors/server-actions/4/output.js | 4 +- .../tests/errors/server-actions/5/output.js | 4 +- .../tests/errors/server-actions/6/output.js | 2 + .../fixture/server-actions/client/1/output.js | 5 ++ .../fixture/server-actions/client/2/output.js | 4 ++ .../server-actions/server/10/output.js | 6 ++- .../server-actions/server/11/output.js | 6 ++- .../server-actions/server/12/output.js | 6 ++- .../server-actions/server/13/output.js | 5 ++ .../server-actions/server/14/output.js | 4 ++ .../server-actions/server/15/output.js | 4 ++ .../server-actions/server/17/output.js | 7 ++- .../fixture/server-actions/server/20/input.js | 4 ++ .../server-actions/server/20/output.js | 12 +++++ .../fixture/server-actions/server/3/output.js | 6 ++- .../fixture/server-actions/server/4/output.js | 6 +++ .../fixture/server-actions/server/9/output.js | 6 +++ packages/next/src/build/webpack-config.ts | 6 ++- .../next-flight-loader/action-proxy.ts | 10 ++++ packages/next/src/lib/constants.ts | 1 + 24 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 packages/next-swc/crates/core/tests/fixture/server-actions/server/20/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/server-actions/server/20/output.js create mode 100644 packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts diff --git a/packages/next-swc/crates/core/src/server_actions.rs b/packages/next-swc/crates/core/src/server_actions.rs index 04d20154c84bc8..682be084e3b7f9 100644 --- a/packages/next-swc/crates/core/src/server_actions.rs +++ b/packages/next-swc/crates/core/src/server_actions.rs @@ -918,8 +918,56 @@ impl VisitMut for ServerActions { } } } - new.extend(self.annotations.drain(..).map(ModuleItem::Stmt)); new.append(&mut self.extra_items); + + // Ensure that the exports are valid by appending a check + // import { ensureServerEntryExports } from 'private-next-rsc-action-proxy' + // ensureServerEntryExports([action1, action2, ...]) + let ensure_ident = private_ident!("ensureServerEntryExports"); + new.push(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + span: DUMMY_SP, + specifiers: vec![ImportSpecifier::Default(ImportDefaultSpecifier { + span: DUMMY_SP, + local: ensure_ident.clone(), + })], + src: Box::new(Str { + span: DUMMY_SP, + value: "private-next-rsc-action-proxy".into(), + raw: None, + }), + type_only: false, + asserts: None, + }))); + new.push(ModuleItem::Stmt(Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + callee: Callee::Expr(Box::new(Expr::Ident(ensure_ident))), + args: vec![ExprOrSpread { + spread: None, + expr: Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: self + .exported_idents + .iter() + .map(|e| { + Some(ExprOrSpread { + spread: None, + expr: Box::new(Expr::Ident(Ident::new( + e.0 .0.clone(), + DUMMY_SP.with_ctxt(e.0 .1), + ))), + }) + }) + .collect(), + })), + }], + type_args: None, + })), + }))); + + // Append annotations to the end of the file. + new.extend(self.annotations.drain(..).map(ModuleItem::Stmt)); } *stmts = new; diff --git a/packages/next-swc/crates/core/tests/errors/server-actions/1/output.js b/packages/next-swc/crates/core/tests/errors/server-actions/1/output.js index fe1f9b5e419692..725953f18f7cad 100644 --- a/packages/next-swc/crates/core/tests/errors/server-actions/1/output.js +++ b/packages/next-swc/crates/core/tests/errors/server-actions/1/output.js @@ -1,5 +1,9 @@ /* __next_internal_action_entry_do_not_use__ foo */ export function foo() {} +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "ab21efdafbe611287bc25c0462b1e0510d13e48b"; foo.$$bound = []; -foo.$$with_bound = false; \ No newline at end of file +foo.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/errors/server-actions/2/output.js b/packages/next-swc/crates/core/tests/errors/server-actions/2/output.js index b98851f749bb9d..3ddf5e9827f705 100644 --- a/packages/next-swc/crates/core/tests/errors/server-actions/2/output.js +++ b/packages/next-swc/crates/core/tests/errors/server-actions/2/output.js @@ -1,6 +1,10 @@ /* __next_internal_action_entry_do_not_use__ bar */ 'use strict'; export function bar() {} +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + bar +]); bar.$$typeof = Symbol.for("react.server.reference"); bar.$$id = "ac840dcaf5e8197cb02b7f3a43c119b7a770b272"; bar.$$bound = []; -bar.$$with_bound = false; \ No newline at end of file +bar.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/errors/server-actions/3/output.js b/packages/next-swc/crates/core/tests/errors/server-actions/3/output.js index 9281f5cc67ca60..283f959071f74d 100644 --- a/packages/next-swc/crates/core/tests/errors/server-actions/3/output.js +++ b/packages/next-swc/crates/core/tests/errors/server-actions/3/output.js @@ -1,5 +1,9 @@ /* __next_internal_action_entry_do_not_use__ x */ export const x = 1; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + x +]); x.$$typeof = Symbol.for("react.server.reference"); x.$$id = "b78c261f135a7a852508c2920bd7228020ff4bd7"; x.$$bound = []; -x.$$with_bound = false; \ No newline at end of file +x.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/errors/server-actions/4/output.js b/packages/next-swc/crates/core/tests/errors/server-actions/4/output.js index 6ac5833f5d59ea..24f1addb5b5b81 100644 --- a/packages/next-swc/crates/core/tests/errors/server-actions/4/output.js +++ b/packages/next-swc/crates/core/tests/errors/server-actions/4/output.js @@ -2,4 +2,6 @@ render() { return null; } -} \ No newline at end of file +} +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([]); diff --git a/packages/next-swc/crates/core/tests/errors/server-actions/5/output.js b/packages/next-swc/crates/core/tests/errors/server-actions/5/output.js index 9a400e2863967a..85182d36a4e61e 100644 --- a/packages/next-swc/crates/core/tests/errors/server-actions/5/output.js +++ b/packages/next-swc/crates/core/tests/errors/server-actions/5/output.js @@ -1 +1,3 @@ -/* __next_internal_action_entry_do_not_use__ */ export * from 'foo'; \ No newline at end of file +/* __next_internal_action_entry_do_not_use__ */ export * from 'foo'; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([]); diff --git a/packages/next-swc/crates/core/tests/errors/server-actions/6/output.js b/packages/next-swc/crates/core/tests/errors/server-actions/6/output.js index e2549fdd660874..1dc6cc01c51b80 100644 --- a/packages/next-swc/crates/core/tests/errors/server-actions/6/output.js +++ b/packages/next-swc/crates/core/tests/errors/server-actions/6/output.js @@ -1 +1,3 @@ /* __next_internal_action_entry_do_not_use__ */ export default (()=>{}); +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([]); diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/client/1/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/client/1/output.js index 54a1f58a993009..e20beb9f5cf385 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/client/1/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/client/1/output.js @@ -5,6 +5,11 @@ export default async function $$ACTION_0(...args) { return __build_action__($$ACTION_0, args); }; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + myAction, + $$ACTION_0 +]); myAction.$$typeof = Symbol.for("react.server.reference"); myAction.$$id = "e10665baac148856374b2789aceb970f66fec33e"; myAction.$$bound = []; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/client/2/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/client/2/output.js index 79f02202730f0e..26ea8ab043a935 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/client/2/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/client/2/output.js @@ -2,6 +2,10 @@ /* __next_internal_action_entry_do_not_use__ foo */ export async function foo(...args) { return __build_action__(foo, args); } +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "ab21efdafbe611287bc25c0462b1e0510d13e48b"; foo.$$bound = []; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/10/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/10/output.js index 4ef5905d8d8b4e..6d28f3be329449 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/10/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/10/output.js @@ -1,5 +1,9 @@ /* __next_internal_action_entry_do_not_use__ default */ export default async function foo() {} +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d"; foo.$$bound = []; -foo.$$with_bound = false; \ No newline at end of file +foo.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/11/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/11/output.js index 0880e2140d45a4..4fa8fc7623ec1d 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/11/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/11/output.js @@ -1,5 +1,9 @@ /* __next_internal_action_entry_do_not_use__ default */ export default async function $$ACTION_0() {} +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + $$ACTION_0 +]); $$ACTION_0.$$typeof = Symbol.for("react.server.reference"); $$ACTION_0.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d"; $$ACTION_0.$$bound = []; -$$ACTION_0.$$with_bound = false; \ No newline at end of file +$$ACTION_0.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/12/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/12/output.js index a7e16701db9d13..6f1f44821c8d8d 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/12/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/12/output.js @@ -1,6 +1,10 @@ /* __next_internal_action_entry_do_not_use__ default */ async function foo() {} export default foo; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d"; foo.$$bound = []; -foo.$$with_bound = false; \ No newline at end of file +foo.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/13/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/13/output.js index 2e5a29dd45f1ae..73da396ed13cf9 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/13/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/13/output.js @@ -2,6 +2,11 @@ export default foo; const bar = async function() {}; export { bar }; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo, + bar +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d"; foo.$$bound = []; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/14/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/14/output.js index 68e617c562f7f4..ca245c4c4ac97e 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/14/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/14/output.js @@ -1,6 +1,10 @@ /* __next_internal_action_entry_do_not_use__ foo */ export async function foo() { async function bar() {} } +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "ab21efdafbe611287bc25c0462b1e0510d13e48b"; foo.$$bound = []; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/15/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/15/output.js index edb9e19ee2eeed..339217292bb941 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/15/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/15/output.js @@ -2,6 +2,10 @@ console.log(a, b); }; var $$ACTION_0; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + $$ACTION_0 +]); $$ACTION_0.$$typeof = Symbol.for("react.server.reference"); $$ACTION_0.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d"; $$ACTION_0.$$bound = []; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/17/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/17/output.js index ab8210696a2735..145e5316ba46d8 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/17/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/17/output.js @@ -1,6 +1,11 @@ /* __next_internal_action_entry_do_not_use__ foo,bar */ export const foo = async ()=>{}; const bar = async ()=>{}; export { bar }; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo, + bar +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "ab21efdafbe611287bc25c0462b1e0510d13e48b"; foo.$$bound = []; @@ -8,4 +13,4 @@ foo.$$with_bound = false; bar.$$typeof = Symbol.for("react.server.reference"); bar.$$id = "ac840dcaf5e8197cb02b7f3a43c119b7a770b272"; bar.$$bound = []; -bar.$$with_bound = false; \ No newline at end of file +bar.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/20/input.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/20/input.js new file mode 100644 index 00000000000000..79c9846d0dbfa1 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/20/input.js @@ -0,0 +1,4 @@ +'use server' + +const [foo] = [null] +export default foo diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/20/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/20/output.js new file mode 100644 index 00000000000000..d3bb75796f2657 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/20/output.js @@ -0,0 +1,12 @@ +/* __next_internal_action_entry_do_not_use__ default */ const [foo] = [ + null +]; +export default foo; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo +]); +foo.$$typeof = Symbol.for("react.server.reference"); +foo.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d"; +foo.$$bound = []; +foo.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/3/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/3/output.js index 7f1bf0b049bf75..d3a64d674d6e92 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/3/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/3/output.js @@ -2,7 +2,11 @@ /* __next_internal_action_entry_do_not_use__ myAction */ export async function myAction(a, b, c) { console.log('a'); } +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + myAction +]); myAction.$$typeof = Symbol.for("react.server.reference"); myAction.$$id = "e10665baac148856374b2789aceb970f66fec33e"; myAction.$$bound = []; -myAction.$$with_bound = false; \ No newline at end of file +myAction.$$with_bound = false; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/4/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/4/output.js index 97cc9e04a7b930..0107e24e604507 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/4/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/4/output.js @@ -5,6 +5,12 @@ function d() {} function Foo() { async function e() {} } +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + a, + b, + c +]); a.$$typeof = Symbol.for("react.server.reference"); a.$$id = "6e7bc104e4d6e7fda190c4a51be969cfd0be6d6d"; a.$$bound = []; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/9/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/9/output.js index 54ae6ec82221b3..629c132bd0c112 100644 --- a/packages/next-swc/crates/core/tests/fixture/server-actions/server/9/output.js +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/9/output.js @@ -5,6 +5,12 @@ async function bar() {} export { bar as baz }; async function qux() {} export { qux as default }; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + foo, + bar, + qux +]); foo.$$typeof = Symbol.for("react.server.reference"); foo.$$id = "ab21efdafbe611287bc25c0462b1e0510d13e48b"; foo.$$bound = []; diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index af45f5c9770e4c..e1c3e52b53b4f9 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -12,6 +12,7 @@ import { APP_DIR_ALIAS, WEBPACK_LAYERS, RSC_MOD_REF_PROXY_ALIAS, + RSC_ACTION_PROXY_ALIAS, } from '../lib/constants' import { fileExists } from '../lib/file-exists' import { CustomRoutes } from '../lib/load-custom-routes.js' @@ -1053,6 +1054,9 @@ export default async function getBaseWebpackConfig( [RSC_MOD_REF_PROXY_ALIAS]: 'next/dist/build/webpack/loaders/next-flight-loader/module-proxy', + [RSC_ACTION_PROXY_ALIAS]: + 'next/dist/build/webpack/loaders/next-flight-loader/action-proxy', + ...(isClient || isEdgeServer ? { [clientResolveRewrites]: hasRewrites @@ -1237,7 +1241,7 @@ export default async function getBaseWebpackConfig( } const notExternalModules = - /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-mod-ref-proxy$)/ + /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-mod-ref-proxy|private-next-rsc-action-proxy$)/ if (notExternalModules.test(request)) { return } diff --git a/packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts b/packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts new file mode 100644 index 00000000000000..c77aa92c5aad69 --- /dev/null +++ b/packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts @@ -0,0 +1,10 @@ +export default function ensureServerEntryExports(actions: any[]) { + for (let i = 0; i < actions.length; i++) { + const action = actions[i] + if (typeof action !== 'function') { + throw new Error( + `A "use server" file can only export async functions, found ${typeof action}.` + ) + } + } +} diff --git a/packages/next/src/lib/constants.ts b/packages/next/src/lib/constants.ts index f16ccb893b47e6..5290d2b30cee7f 100644 --- a/packages/next/src/lib/constants.ts +++ b/packages/next/src/lib/constants.ts @@ -18,6 +18,7 @@ export const DOT_NEXT_ALIAS = 'private-dot-next' export const ROOT_DIR_ALIAS = 'private-next-root-dir' export const APP_DIR_ALIAS = 'private-next-app-dir' export const RSC_MOD_REF_PROXY_ALIAS = 'private-next-rsc-mod-ref-proxy' +export const RSC_ACTION_PROXY_ALIAS = 'private-next-rsc-action-proxy' export const PUBLIC_DIR_MIDDLEWARE_CONFLICT = `You can not have a '_next' folder inside of your public folder. This conflicts with the internal '/_next' route. https://nextjs.org/docs/messages/public-next-folder-conflict` From c14c83a299725c05c56d2d12b3198da543c8d4af Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 21 Mar 2023 14:55:04 -0600 Subject: [PATCH 594/672] Marks app paths in dev as supporting dynamic html (#46848) This marks all pages in development as supporting dynamic HTML. Detection for runtime violations of dynamic generation is completed during the production build. Fixes #46356 fix NEXT-644 ([link](https://linear.app/vercel/issue/NEXT-644)) Co-authored-by: Tim Neutkens <6324199+timneutkens@users.noreply.github.com> Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com> --- packages/next/src/server/base-server.ts | 58 ++++++++++++------- .../e2e/app-dir/app-static/app-static.test.ts | 21 +++++++ .../force-dynamic-prerender/[slug]/page.js | 19 ++++++ 3 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 test/e2e/app-dir/app-static/app/force-dynamic-prerender/[slug]/page.js diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 12292fbf3cd805..7b8c1843b6a4c6 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -1322,6 +1322,16 @@ export default abstract class Server { opts.isBot = isBotRequest } + // In development, we always want to generate dynamic HTML. + if ( + !isDataReq && + isAppPath && + opts.dev && + opts.supportsDynamicHTML === false + ) { + opts.supportsDynamicHTML = true + } + const defaultLocale = isSSG ? this.nextConfig.i18n?.defaultLocale : query.__nextDefaultLocale @@ -1446,7 +1456,9 @@ export default abstract class Server { let isRevalidate = false const doRender: () => Promise = async () => { - const supportsDynamicHTML = !(isSSG || hasStaticPaths) + // In development, we always want to generate dynamic HTML. + const supportsDynamicHTML = + (!isDataReq && opts.dev) || !(isSSG || hasStaticPaths) const match = pathname !== '/_error' && !is404Page && !is500Page @@ -1667,43 +1679,45 @@ export default abstract class Server { fallbackMode = 'blocking' } + // We use `ssgCacheKey` here as it is normalized to match the encoding + // from getStaticPaths along with including the locale. + // + // We use the `resolvedUrlPathname` for the development case when this + // is an app path since it doesn't include locale information. + let staticPathKey = + ssgCacheKey ?? (opts.dev && isAppPath ? resolvedUrlPathname : null) + if (staticPathKey && query.amp) { + staticPathKey = staticPathKey.replace(/\.amp$/, '') + } + + const isPageIncludedInStaticPaths = + staticPathKey && staticPaths?.includes(staticPathKey) + // When we did not respond from cache, we need to choose to block on // rendering or return a skeleton. // - // * Data requests always block. - // - // * Blocking mode fallback always blocks. - // - // * Preview mode toggles all pages to be resolved in a blocking manner. - // - // * Non-dynamic pages should block (though this is an impossible + // - Data requests always block. + // - Blocking mode fallback always blocks. + // - Preview mode toggles all pages to be resolved in a blocking manner. + // - Non-dynamic pages should block (though this is an impossible // case in production). - // - // * Dynamic pages should return their skeleton if not defined in + // - Dynamic pages should return their skeleton if not defined in // getStaticPaths, then finish the data request on the client-side. // if ( process.env.NEXT_RUNTIME !== 'edge' && - this.minimalMode !== true && + !this.minimalMode && fallbackMode !== 'blocking' && - ssgCacheKey && + staticPathKey && !didRespond && !isPreviewMode && isDynamicPathname && - // Development should trigger fallback when the path is not in - // `getStaticPaths` - (isProduction || - !staticPaths || - !staticPaths.includes( - // we use ssgCacheKey here as it is normalized to match the - // encoding from getStaticPaths along with including the locale - query.amp ? ssgCacheKey.replace(/\.amp$/, '') : ssgCacheKey - )) + (isProduction || !staticPaths || !isPageIncludedInStaticPaths) ) { if ( // In development, fall through to render to handle missing // getStaticPaths. - (isProduction || staticPaths) && + (isProduction || (staticPaths && staticPaths?.length > 0)) && // When fallback isn't present, abort this render so we 404 fallbackMode !== 'static' ) { diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index c0e506198d1757..39177d3c143d96 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -163,6 +163,7 @@ createNextDescribe( 'dynamic-no-gen-params-ssr/[slug]/page.js', 'dynamic-no-gen-params/[slug]/page.js', 'force-dynamic-no-prerender/[id]/page.js', + 'force-dynamic-prerender/[slug]/page.js', 'force-static/[slug]/page.js', 'force-static/first.html', 'force-static/first.rsc', @@ -1148,6 +1149,26 @@ createNextDescribe( } }) + it('should allow dynamic routes to access cookies', async () => { + for (const slug of ['books', 'frameworks']) { + for (let i = 0; i < 2; i++) { + let $ = await next.render$( + `/force-dynamic-prerender/${slug}`, + {}, + { headers: { cookie: 'session=value' } } + ) + + expect($('#slug').text()).toBe(slug) + expect($('#cookie-result').text()).toBe('has cookie') + + $ = await next.render$(`/force-dynamic-prerender/${slug}`) + + expect($('#slug').text()).toBe(slug) + expect($('#cookie-result').text()).toBe('no cookie') + } + } + }) + it('should not error with generateStaticParams and dynamic data', async () => { const res = await next.fetch('/gen-params-dynamic/one') const html = await res.text() diff --git a/test/e2e/app-dir/app-static/app/force-dynamic-prerender/[slug]/page.js b/test/e2e/app-dir/app-static/app/force-dynamic-prerender/[slug]/page.js new file mode 100644 index 00000000000000..829fbcb150e2e6 --- /dev/null +++ b/test/e2e/app-dir/app-static/app/force-dynamic-prerender/[slug]/page.js @@ -0,0 +1,19 @@ +import { cookies } from 'next/headers' + +export const dynamic = 'force-dynamic' +export const dynamicParams = true +export const revalidate = 60 + +export const generateStaticParams = async () => { + return [{ slug: 'frameworks' }] +} + +export default function Page({ params }) { + const result = cookies().get('session')?.value ? 'has cookie' : 'no cookie' + return ( +
+
{params.slug}
+ +
+ ) +} From 5eaaa3fbf7e669314e9f054d558a93ccb5c2beb9 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 21 Mar 2023 18:22:34 -0400 Subject: [PATCH 595/672] fix: add pretty error for `exportPathMap` with `app` dir (#47371) The `exportPathMap` feature has been unofficially deprecated for a long time since introducing `getStaticPaths()`. For the `app` dir, the same can be accomplished with `generateStaticParams()`. This PR adds a pretty error when using `exportPathMap` with `app` and updates documentation to reflect the current status. fix NEXT-836 ([link](https://linear.app/vercel/issue/NEXT-836)) --- docs/advanced-features/static-html-export.md | 2 +- .../next.config.js/exportPathMap.md | 4 ++-- packages/next/src/build/index.ts | 15 +++++++++++-- packages/next/src/export/index.ts | 7 +------ .../app-dir-export/test/index.test.ts | 21 +++++++++++++++++++ 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/docs/advanced-features/static-html-export.md b/docs/advanced-features/static-html-export.md index 26fd0c2561d843..e7eae0c5d33f8c 100644 --- a/docs/advanced-features/static-html-export.md +++ b/docs/advanced-features/static-html-export.md @@ -46,7 +46,7 @@ Running `npm run build` will generate an `out` directory. For more advanced scenarios, you can define a parameter called [`exportPathMap`](/docs/api-reference/next.config.js/exportPathMap.md) in your [`next.config.js`](/docs/api-reference/next.config.js/introduction.md) file to configure exactly which pages will be generated. -> **Warning**: Using `exportPathMap` for defining routes with any `getStaticPaths` powered page is now ignored and gets overridden. We recommend not to use them together. +> **Warning**: Using `exportPathMap` is deprecated and is overridden by `getStaticPaths` inside `pages`. We recommend not to use them together. ## Supported Features diff --git a/docs/api-reference/next.config.js/exportPathMap.md b/docs/api-reference/next.config.js/exportPathMap.md index 4180363e6dcfd6..80eff054d087a0 100644 --- a/docs/api-reference/next.config.js/exportPathMap.md +++ b/docs/api-reference/next.config.js/exportPathMap.md @@ -4,7 +4,7 @@ description: Customize the pages that will be exported as HTML files when using # exportPathMap -> This feature is exclusive to `next export`. Please refer to [Static HTML export](/docs/advanced-features/static-html-export.md) if you want to learn more about it. +> This feature is exclusive to `next export` and currently **deprecated** in favor of `getStaticPaths` with `pages` or `generateStaticParams` with `app`.
Examples @@ -79,7 +79,7 @@ module.exports = { next export -o outdir ``` -> **Warning**: Using `exportPathMap` for defining routes with any `getStaticPaths` powered page is now ignored and gets overridden. We recommend not to use them together. +> **Warning**: Using `exportPathMap` is deprecated and is overridden by `getStaticPaths` inside `pages`. We recommend not to use them together. ## Related diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 2aa333e22c4e34..ef8b373b124786 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -135,6 +135,7 @@ import { normalizePathSep } from '../shared/lib/page-path/normalize-path-sep' import { isAppRouteRoute } from '../lib/is-app-route-route' import { createClientRouterFilter } from '../lib/create-client-router-filter' import { createValidFileMatcher } from '../server/lib/find-page-file' +import type { ExportOptions } from '../export' export type SsgRoute = { initialRevalidateSeconds: number | false @@ -467,6 +468,7 @@ export default async function build( // prevent showing jest-worker internal error as it // isn't helpful for users and clutters output if (isError(err) && err.message === 'Call retries were exceeded') { + await telemetry.flush() process.exit(1) } throw err @@ -478,6 +480,14 @@ export default async function build( // directory. if (!appDir) await startTypeChecking() + if (appDir && 'exportPathMap' in config) { + Log.error( + 'The "exportPathMap" configuration cannot be used with the "app" directory. Please use generateStaticParams() instead.' + ) + await telemetry.flush() + process.exit(1) + } + const buildLintEvent: EventBuildFeatureUsage = { featureName: 'build-lint', invocationCount: shouldLint ? 1 : 0, @@ -637,6 +647,7 @@ export default async function build( for (const [pagePath, appPath] of conflictingAppPagePaths) { Log.error(` "${pagePath}" - "${appPath}"`) } + await telemetry.flush() process.exit(1) } @@ -2291,7 +2302,7 @@ export default async function build( ) const exportApp: typeof import('../export').default = require('../export').default - const exportOptions = { + const exportOptions: ExportOptions = { silent: false, buildExport: true, debugOutput, @@ -2309,7 +2320,7 @@ export default async function build( : undefined, appPaths, } - const exportConfig: any = { + const exportConfig: NextConfigComplete = { ...config, initialPageRevalidationMap: {}, initialPageMetaMap: {}, diff --git a/packages/next/src/export/index.ts b/packages/next/src/export/index.ts index 2b3d9e658fd0b4..dd506428486806 100644 --- a/packages/next/src/export/index.ts +++ b/packages/next/src/export/index.ts @@ -143,7 +143,7 @@ const createProgress = (total: number, label: string) => { } } -interface ExportOptions { +export interface ExportOptions { outdir: string silent?: boolean threads?: number @@ -369,11 +369,6 @@ export default async function exportApp( // Get the exportPathMap from the config file if (typeof nextConfig.exportPathMap !== 'function') { - if (!options.silent) { - Log.info( - `No "exportPathMap" found in "${nextConfig.configFile}". Generating map from "./pages"` - ) - } nextConfig.exportPathMap = async (defaultMap) => { return defaultMap } diff --git a/test/integration/app-dir-export/test/index.test.ts b/test/integration/app-dir-export/test/index.test.ts index f937d7874a289b..61e6ea933f9437 100644 --- a/test/integration/app-dir-export/test/index.test.ts +++ b/test/integration/app-dir-export/test/index.test.ts @@ -235,4 +235,25 @@ describe('app dir with output export', () => { 'export const dynamic = "force-dynamic" on page "/api/json" cannot be used with "output: export".' ) }) + it('should throw when exportPathMap configured', async () => { + nextConfig.replace( + 'trailingSlash: true,', + `trailingSlash: true, + exportPathMap: async function (map) { + return map + },` + ) + await fs.remove(distDir) + await fs.remove(exportDir) + let result = { code: 0, stderr: '' } + try { + result = await nextBuild(appDir, [], { stderr: true }) + } finally { + nextConfig.restore() + } + expect(result.code).toBe(1) + expect(result.stderr).toContain( + 'The "exportPathMap" configuration cannot be used with the "app" directory. Please use generateStaticParams() instead.' + ) + }) }) From fed3ffa865464d2a960d8e2fd7468cdef19cd147 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 21 Mar 2023 16:09:52 -0700 Subject: [PATCH 596/672] Skip extra swc builds (#47378) This removes some extra swc builds which are rarely if ever used and are also prone to breaking fairly often due to the extra configuration required to build them. x-ref: [slack thread](https://vercel.slack.com/archives/C04KC8A53T7/p1679434160981059) --- .github/workflows/build_test_deploy.yml | 134 ------------------ .../napi/npm/android-arm-eabi/README.md | 3 - .../napi/npm/android-arm-eabi/package.json | 18 --- .../crates/napi/npm/android-arm64/README.md | 3 - .../napi/npm/android-arm64/package.json | 18 --- .../crates/napi/npm/freebsd-x64/README.md | 3 - .../crates/napi/npm/freebsd-x64/package.json | 18 --- .../napi/npm/linux-arm-gnueabihf/README.md | 3 - .../napi/npm/linux-arm-gnueabihf/package.json | 18 --- packages/next-swc/package.json | 4 - scripts/install-native.mjs | 3 - scripts/pull-freebsd-cache.js | 30 ---- 12 files changed, 255 deletions(-) delete mode 100644 packages/next-swc/crates/napi/npm/android-arm-eabi/README.md delete mode 100644 packages/next-swc/crates/napi/npm/android-arm-eabi/package.json delete mode 100644 packages/next-swc/crates/napi/npm/android-arm64/README.md delete mode 100644 packages/next-swc/crates/napi/npm/android-arm64/package.json delete mode 100644 packages/next-swc/crates/napi/npm/freebsd-x64/README.md delete mode 100644 packages/next-swc/crates/napi/npm/freebsd-x64/package.json delete mode 100644 packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/README.md delete mode 100644 packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/package.json delete mode 100755 scripts/pull-freebsd-cache.js diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 0ad4b7744b6b65..3695eb96e5f7b6 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -915,7 +915,6 @@ jobs: - build - build-wasm - build-native - - build-native-freebsd env: NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }} steps: @@ -1300,45 +1299,6 @@ jobs: export CC_aarch64_unknown_linux_gnu=/usr/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-gcc && turbo run build-native -- --release --target aarch64-unknown-linux-gnu && llvm-strip -x packages/next-swc/native/next-swc.*.node - - host: ubuntu-latest - target: 'armv7-unknown-linux-gnueabihf' - setup: | - sudo apt-get update - sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y - build: | - npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" "turbo@${TURBO_VERSION}" && if [ ! -f $(dirname $(which yarn))/pnpm ]; then ln -s $(which yarn) $(dirname $(which yarn))/pnpm;fi - turbo run build-native-no-plugin -- --release --target armv7-unknown-linux-gnueabihf - arm-linux-gnueabihf-strip packages/next-swc/native/next-swc.*.node - - host: ubuntu-latest - target: aarch64-linux-android - build: | - export CLANG_VERSION=`ls ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang | sed 's/ *$//g'` - export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang" - export CC="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang" - export CXX="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang++" - export AR="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" - export PATH="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${PATH}" - touch "${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/${CLANG_VERSION}/lib/linux/aarch64/libgcc.a" - chmod 777 "${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/${CLANG_VERSION}/lib/linux/aarch64/libgcc.a" - echo "INPUT(-lunwind)" > "${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/${CLANG_VERSION}/lib/linux/aarch64/libgcc.a" - npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" "turbo@${TURBO_VERSION}" && if [ ! -f $(dirname $(which yarn))/pnpm ]; then ln -s $(which yarn) $(dirname $(which yarn))/pnpm;fi - turbo run build-native -- --release --target aarch64-linux-android - ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip packages/next-swc/native/next-swc.*.node - - host: ubuntu-latest - target: armv7-linux-androideabi - build: | - export CLANG_VERSION=`ls ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang | sed 's/ *$//g'` - export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang" - export CC="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang" - export CXX="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang++" - export AR="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" - export PATH="${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${PATH}" - touch "${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/${CLANG_VERSION}/lib/linux/arm/libgcc.a" - chmod 777 "${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/${CLANG_VERSION}/lib/linux/arm/libgcc.a" - echo "INPUT(-lunwind)" > "${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/${CLANG_VERSION}/lib/linux/arm/libgcc.a" - npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" "turbo@${TURBO_VERSION}" "pnpm@${PNPM_VERSION}" - turbo run build-native-no-plugin -- --release --target armv7-linux-androideabi - ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip packages/next-swc/native/next-swc.*.node - host: ubuntu-latest target: 'aarch64-unknown-linux-musl' docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2022-10-24-alpine @@ -1441,100 +1401,6 @@ jobs: name: next-swc-binaries path: packages/next-swc/native/next-swc.*.node - build-native-freebsd: - if: ${{ needs.build.outputs.isRelease == 'true' || (needs.build.outputs.turboToken != 'empty') }} - needs: build - name: stable - x86_64-unknown-freebsd - node@16 - runs-on: macos-12 - env: - TURBO_TEAM: 'vercel' - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_REMOTE_ONLY: 'true' - steps: - - name: tune mac network - run: sudo sysctl -w net.link.generic.system.hwcksum_tx=0 && sudo sysctl -w net.link.generic.system.hwcksum_rx=0 - - uses: actions/checkout@v3 - - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 16 - check-latest: true - - - run: npm i -g turbo@${{ env.TURBO_VERSION }} pnpm@${PNPM_VERSION} - - - name: Delete useless files - run: | - rm -rf bench - rm -rf docs - rm -rf errors - rm -rf examples - rm -rf test - - - run: node scripts/normalize-version-bump.js - - # attempt pulling existing turbo cache, this must be done - # outside of the freeBSD vm as there isn't a turbo build - # for freeBSD currently - - run: node ./scripts/pull-freebsd-cache.js - - - name: check build exists - run: if [ -f packages/next-swc/native/next-swc.freebsd-x64.node ]; then echo "BUILD_EXISTS=yes" >> $GITHUB_OUTPUT; else echo "BUILD_EXISTS=no" >> $GITHUB_OUTPUT; fi - id: build-exists - - - run: echo "${{steps.build-exists.outputs.BUILD_EXISTS}}" - - - name: Build - id: build - uses: vmactions/freebsd-vm@v0 - if: ${{ steps.build-exists.outputs.BUILD_EXISTS == 'no' }} - env: - DEBUG: napi:* - RUSTUP_HOME: /usr/local/rustup - CARGO_HOME: /usr/local/cargo - RUSTUP_IO_THREADS: 1 - # Disable LTO, or the lld may crash with OOM - CARGO_PROFILE_RELEASE_LTO: false - with: - envs: DEBUG RUSTUP_HOME CARGO_HOME RUSTUP_IO_THREADS CARGO_PROFILE_RELEASE_LTO NAPI_CLI_VERSION RUST_TOOLCHAIN PNPM_VERSION VM_RELEASE - usesh: true - sync: rsync - copyback: false - mem: 6000 - prepare: | - pkg install -y -f curl node libnghttp2 - curl -qL https://www.npmjs.com/install.sh | sh - npm i -g pnpm@${PNPM_VERSION} "@napi-rs/cli@${NAPI_CLI_VERSION}" - curl https://sh.rustup.rs -sSf --output rustup.sh - sh rustup.sh -y --profile minimal --default-toolchain stable - export PATH="/usr/local/cargo/bin:$PATH" - echo "~~~~ rustc --version ~~~~" - rustc --version - echo "~~~~ node -v ~~~~" - node -v - run: | - export PATH="/usr/local/cargo/bin:$PATH" - pwd - ls -lah - whoami - env - freebsd-version - GITHUB_EVENT_PATH='' pnpm --filter=@next/swc run build-native-no-plugin --platform --release --target x86_64-unknown-freebsd - rm -rf node_modules - rm -rf packages/next-swc/target - - - name: cache build - if: ${{ steps.build-exists.outputs.BUILD_EXISTS == 'no' }} - run: pnpm turbo run --force cache-build-native -- --platform --release --target x86_64-unknown-freebsd - - - name: Upload artifact - if: ${{ needs.build.outputs.isRelease == 'true' }} - uses: actions/upload-artifact@v3 - with: - name: next-swc-binaries - path: packages/next-swc/native/next-swc.*.node - if-no-files-found: error - build-wasm: needs: build if: ${{ needs.build.outputs.isRelease == 'true' || (needs.build.outputs.turboToken != 'empty') }} diff --git a/packages/next-swc/crates/napi/npm/android-arm-eabi/README.md b/packages/next-swc/crates/napi/npm/android-arm-eabi/README.md deleted file mode 100644 index 7044554db68c73..00000000000000 --- a/packages/next-swc/crates/napi/npm/android-arm-eabi/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `@next/swc-android-arm-eabi` - -This is the **android-arm-eabi** binary for `@next/swc` diff --git a/packages/next-swc/crates/napi/npm/android-arm-eabi/package.json b/packages/next-swc/crates/napi/npm/android-arm-eabi/package.json deleted file mode 100644 index 69ec8a4b23a91b..00000000000000 --- a/packages/next-swc/crates/napi/npm/android-arm-eabi/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@next/swc-android-arm-eabi", - "version": "0.0.0", - "os": [ - "android" - ], - "cpu": [ - "arm" - ], - "main": "next-swc.android-arm-eabi.node", - "files": [ - "next-swc.android-arm-eabi.node" - ], - "license": "MIT", - "engines": { - "node": ">= 10" - } -} diff --git a/packages/next-swc/crates/napi/npm/android-arm64/README.md b/packages/next-swc/crates/napi/npm/android-arm64/README.md deleted file mode 100644 index 4b204578351aea..00000000000000 --- a/packages/next-swc/crates/napi/npm/android-arm64/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `@next/swc-android-arm64` - -This is the **android-arm64** binary for `@next/swc` diff --git a/packages/next-swc/crates/napi/npm/android-arm64/package.json b/packages/next-swc/crates/napi/npm/android-arm64/package.json deleted file mode 100644 index e251bb0d78388d..00000000000000 --- a/packages/next-swc/crates/napi/npm/android-arm64/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@next/swc-android-arm64", - "version": "0.0.0", - "os": [ - "android" - ], - "cpu": [ - "arm64" - ], - "main": "next-swc.android-arm64.node", - "files": [ - "next-swc.android-arm64.node" - ], - "license": "MIT", - "engines": { - "node": ">= 10" - } -} diff --git a/packages/next-swc/crates/napi/npm/freebsd-x64/README.md b/packages/next-swc/crates/napi/npm/freebsd-x64/README.md deleted file mode 100644 index 8a9ba18e17b4d1..00000000000000 --- a/packages/next-swc/crates/napi/npm/freebsd-x64/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `@next/swc-freebsd-x64` - -This is the **x86_64-unknown-freebsd** binary for `@next/swc` diff --git a/packages/next-swc/crates/napi/npm/freebsd-x64/package.json b/packages/next-swc/crates/napi/npm/freebsd-x64/package.json deleted file mode 100644 index d76208230f26df..00000000000000 --- a/packages/next-swc/crates/napi/npm/freebsd-x64/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@next/swc-freebsd-x64", - "version": "0.0.0", - "os": [ - "freebsd" - ], - "cpu": [ - "x64" - ], - "main": "next-swc.freebsd-x64.node", - "files": [ - "next-swc.freebsd-x64.node" - ], - "license": "MIT", - "engines": { - "node": ">= 10" - } -} diff --git a/packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/README.md b/packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/README.md deleted file mode 100644 index 499a9b79845a29..00000000000000 --- a/packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `@next/swc-linux-arm-gnueabihf` - -This is the **linux-arm-gnueabihf** binary for `@next/swc` diff --git a/packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/package.json b/packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/package.json deleted file mode 100644 index 3049a54a6dff8d..00000000000000 --- a/packages/next-swc/crates/napi/npm/linux-arm-gnueabihf/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@next/swc-linux-arm-gnueabihf", - "version": "0.0.0", - "os": [ - "linux" - ], - "cpu": [ - "arm" - ], - "main": "next-swc.linux-arm-gnueabihf.node", - "files": [ - "next-swc.linux-arm-gnueabihf.node" - ], - "license": "MIT", - "engines": { - "node": ">= 10" - } -} diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 346f6fccfd5335..e3dda9900df580 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -19,11 +19,7 @@ "additional": [ "i686-pc-windows-msvc", "aarch64-unknown-linux-gnu", - "armv7-unknown-linux-gnueabihf", "aarch64-apple-darwin", - "aarch64-linux-android", - "arm-linux-androideabi", - "x86_64-unknown-freebsd", "x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl", "aarch64-pc-windows-msvc" diff --git a/scripts/install-native.mjs b/scripts/install-native.mjs index 08010a37cd821d..84b38263143a82 100644 --- a/scripts/install-native.mjs +++ b/scripts/install-native.mjs @@ -41,11 +41,8 @@ import fs from 'fs-extra' name: 'dummy-package', version: '1.0.0', optionalDependencies: { - '@next/swc-android-arm64': 'canary', - '@next/swc-android-arm-eabi': 'canary', '@next/swc-darwin-arm64': 'canary', '@next/swc-darwin-x64': 'canary', - '@next/swc-linux-arm-gnueabihf': 'canary', '@next/swc-linux-arm64-gnu': 'canary', '@next/swc-linux-arm64-musl': 'canary', '@next/swc-linux-x64-gnu': 'canary', diff --git a/scripts/pull-freebsd-cache.js b/scripts/pull-freebsd-cache.js deleted file mode 100755 index 8e26caaca230cb..00000000000000 --- a/scripts/pull-freebsd-cache.js +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env node -// @ts-check - -const { execSync } = require('child_process') - -;(async function () { - const turboResult = execSync( - `pnpm turbo run cache-build-native --dry=json -- --platform --release --target x86_64-unknown-freebsd` - ).toString() - - const turboData = JSON.parse(turboResult) - - const task = turboData.tasks.find((t) => t.command !== '') - - if (!task) { - console.warn(`Failed to find related turbo task`, turboResult) - return - } - - // pull cache if it was available - if (task.cacheState.local || task.cacheState.remote) { - const pullResult = execSync( - `pnpm turbo run cache-build-native -- --platform --release --target x86_64-unknown-freebsd` - ).toString() - console.log(pullResult) - } else { - console.warn(`No turbo cache was available, continuing...`) - console.warn(task) - } -})() From 2e7dfca362931be99e34eccec36074ab4a46ffba Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 21 Mar 2023 16:23:51 -0700 Subject: [PATCH 597/672] v13.2.5-canary.12 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index f12bd45912f4b4..66c65dc21c1e63 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.2.5-canary.11" + "version": "13.2.5-canary.12" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index a2fe0689c689a7..ce360d1652421a 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 0d0b3a1e55a56f..e6c42dd9200ea3 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -12,7 +12,7 @@ "test-pack": "cd ../../ && pnpm test-pack eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "13.2.5-canary.11", + "@next/eslint-plugin-next": "13.2.5-canary.12", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.42.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index c690edc0951315..d09ef604a22734 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "description": "ESLint plugin for NextJS.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 36ac36a5920c14..d433a789bdc79f 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 7b259475eb8c75..2a22afb0ba2105 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index d56857740f9184..9cebd7d282507a 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index ddda3a0746c16b..54bb50e872b3b1 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index bc44d5e3b0bcd7..a9cd1745ed0ad1 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index d1951578a4573c..150da5957709ca 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index a0f697c62d66b8..533d5a976a3c21 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 9a8219e1233e9a..6c01d635d2f609 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index e3dda9900df580..9c3698a202278f 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "private": true, "scripts": { "clean": "rm -rf ./native/*", diff --git a/packages/next/package.json b/packages/next/package.json index 96cef759654d2d..0bcbec88b214f3 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -80,7 +80,7 @@ ] }, "dependencies": { - "@next/env": "13.2.5-canary.11", + "@next/env": "13.2.5-canary.12", "@swc/helpers": "0.4.14", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -135,11 +135,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.14.7", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.2.5-canary.11", - "@next/polyfill-nomodule": "13.2.5-canary.11", - "@next/react-dev-overlay": "13.2.5-canary.11", - "@next/react-refresh-utils": "13.2.5-canary.11", - "@next/swc": "13.2.5-canary.11", + "@next/polyfill-module": "13.2.5-canary.12", + "@next/polyfill-nomodule": "13.2.5-canary.12", + "@next/react-dev-overlay": "13.2.5-canary.12", + "@next/react-refresh-utils": "13.2.5-canary.12", + "@next/swc": "13.2.5-canary.12", "@opentelemetry/api": "1.4.1", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 40038c0a4d0c07..efe69132d1f33b 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 49e02abca0b845..6b99cd65887935 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "13.2.5-canary.11", + "version": "13.2.5-canary.12", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13312658bfbd25..0f4df575d7fac8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -444,7 +444,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 13.2.5-canary.11 + '@next/eslint-plugin-next': 13.2.5-canary.12 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.42.0 eslint: ^7.23.0 || ^8.0.0 @@ -517,12 +517,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.14.7 '@napi-rs/triples': 1.1.0 - '@next/env': 13.2.5-canary.11 - '@next/polyfill-module': 13.2.5-canary.11 - '@next/polyfill-nomodule': 13.2.5-canary.11 - '@next/react-dev-overlay': 13.2.5-canary.11 - '@next/react-refresh-utils': 13.2.5-canary.11 - '@next/swc': 13.2.5-canary.11 + '@next/env': 13.2.5-canary.12 + '@next/polyfill-module': 13.2.5-canary.12 + '@next/polyfill-nomodule': 13.2.5-canary.12 + '@next/react-dev-overlay': 13.2.5-canary.12 + '@next/react-refresh-utils': 13.2.5-canary.12 + '@next/swc': 13.2.5-canary.12 '@opentelemetry/api': 1.4.1 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.14 From 66b346ed236da291176f002326e88ceab3da3c10 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Tue, 21 Mar 2023 16:40:44 -0700 Subject: [PATCH 598/672] Don't set git config `features.manyFiles` on post install (#47375) This reverts #31408, as it also sets the git config value `index.skipHash` which breaks cargo at the moment: https://github.com/rust-lang/cargo/issues/11857 Contributors docs have been updated to recommend a shallow clone in #44158, which should alleviate some of the issues that manyFiles addresses. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 985a7f9131a7ef..e958e56ad6cd9c 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "next-no-sourcemaps": "cross-env NEXT_TELEMETRY_DISABLED=1 node --trace-deprecation packages/next/dist/bin/next", "clean-trace-jaeger": "rm -rf test/integration/basic/.next && TRACE_TARGET=JAEGER pnpm next build test/integration/basic", "debug": "cross-env NEXT_TELEMETRY_DISABLED=1 node --inspect packages/next/dist/bin/next", - "postinstall": "git config feature.manyFiles true && node scripts/install-native.mjs", + "postinstall": "git config index.skipHash false && node scripts/install-native.mjs", "version": "npx pnpm@7.24.3 install && IS_PUBLISH=yes ./scripts/check-pre-compiled.sh && git add .", "prepare": "husky install", "sync-react": "node ./scripts/sync-react.js" From ac8741236a2a57d02a985e3f1abd7b1c0f85cdd3 Mon Sep 17 00:00:00 2001 From: vinay <94120295+vinaykulk621@users.noreply.github.com> Date: Wed, 22 Mar 2023 05:27:26 +0530 Subject: [PATCH 599/672] fix(cli): change file name from `route.ts` to `route.js` (#47352) Wrong file for api endpoint `/hello` in create-next-app template for app directory with tailwindcss. The file was `route.ts` in javascript version of the template, changed it to `route.js`. --- .../create-next-app/templates/app-tw/js/app/api/hello/route.js | 3 +++ .../create-next-app/templates/app-tw/js/app/api/hello/route.ts | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 packages/create-next-app/templates/app-tw/js/app/api/hello/route.js delete mode 100644 packages/create-next-app/templates/app-tw/js/app/api/hello/route.ts diff --git a/packages/create-next-app/templates/app-tw/js/app/api/hello/route.js b/packages/create-next-app/templates/app-tw/js/app/api/hello/route.js new file mode 100644 index 00000000000000..fec2f838029699 --- /dev/null +++ b/packages/create-next-app/templates/app-tw/js/app/api/hello/route.js @@ -0,0 +1,3 @@ +export async function GET(request) { + return new Response('Hello, Next.js!') +} diff --git a/packages/create-next-app/templates/app-tw/js/app/api/hello/route.ts b/packages/create-next-app/templates/app-tw/js/app/api/hello/route.ts deleted file mode 100644 index d1cc6ee25fedf4..00000000000000 --- a/packages/create-next-app/templates/app-tw/js/app/api/hello/route.ts +++ /dev/null @@ -1,3 +0,0 @@ -export async function GET(request: Request) { - return new Response('Hello, Next.js!') -} From 985028b4bcd9adc7da4028aadc9badba13f75b8c Mon Sep 17 00:00:00 2001 From: Muhammad Uzair Date: Wed, 22 Mar 2023 05:03:20 +0500 Subject: [PATCH 600/672] chore(examples): fix Mongoose deprecation warning (#47358) Upgraded mongoose to the latest version. Mongoose Deprecation Fixed for issue #47336 --------- Co-authored-by: JJ Kasper --- examples/with-mongodb-mongoose/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-mongodb-mongoose/package.json b/examples/with-mongodb-mongoose/package.json index ae7bd0a841dad4..060607a2905b08 100644 --- a/examples/with-mongodb-mongoose/package.json +++ b/examples/with-mongodb-mongoose/package.json @@ -6,7 +6,7 @@ "start": "next start" }, "dependencies": { - "mongoose": "^6.0.11", + "mongoose": "^7.0.2", "next": "latest", "react": "^18.2.0", "react-dom": "^18.2.0", From 2e144330d9048879389dac375d7c20021553b603 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 22 Mar 2023 02:28:24 +0100 Subject: [PATCH 601/672] Simplify moduleProxy alias (#47381) Currently, the client entry loader creates the code of `import { createProxy } from "private-next-rsc-mod-ref-proxy"` and then we alias it to the target file. This process is redundant and risky. If the loader-created code is somehow marked as external (due to the effect of both our complex external handling and `transpilePackages`), that alias can't be correctly resolved. Hence this PR simplifies it by creating the target import path directly from the loader. **Note that in the future we should change it directly on the SWC side, and convert this loader to Rust.** --- packages/next/src/build/webpack-config.ts | 6 +----- .../build/webpack/loaders/next-flight-loader/index.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index e1c3e52b53b4f9..a72608e90754ed 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -11,7 +11,6 @@ import { ROOT_DIR_ALIAS, APP_DIR_ALIAS, WEBPACK_LAYERS, - RSC_MOD_REF_PROXY_ALIAS, RSC_ACTION_PROXY_ALIAS, } from '../lib/constants' import { fileExists } from '../lib/file-exists' @@ -1051,9 +1050,6 @@ export default async function getBaseWebpackConfig( ...(isClient || isEdgeServer ? getOptimizedAliases() : {}), ...getReactProfilingInProduction(), - [RSC_MOD_REF_PROXY_ALIAS]: - 'next/dist/build/webpack/loaders/next-flight-loader/module-proxy', - [RSC_ACTION_PROXY_ALIAS]: 'next/dist/build/webpack/loaders/next-flight-loader/action-proxy', @@ -1241,7 +1237,7 @@ export default async function getBaseWebpackConfig( } const notExternalModules = - /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-mod-ref-proxy|private-next-rsc-action-proxy$)/ + /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-action-proxy$)/ if (notExternalModules.test(request)) { return } diff --git a/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts b/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts index 26c76898eb7a03..f8f8ebc3ede451 100644 --- a/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts +++ b/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts @@ -1,9 +1,12 @@ +import { RSC_MOD_REF_PROXY_ALIAS } from '../../../../lib/constants' import { RSC_MODULE_TYPES } from '../../../../shared/lib/constants' import { warnOnce } from '../../../../shared/lib/utils/warn-once' import { getRSCModuleInformation } from '../../../analysis/get-page-static-info' import { getModuleBuildInfo } from '../get-module-build-info' const noopHeadPath = require.resolve('next/dist/client/components/noop-head') +const moduleProxy = + 'next/dist/build/webpack/loaders/next-flight-loader/module-proxy' export default async function transformSource( this: any, @@ -47,7 +50,7 @@ export default async function transformSource( } let esmSource = ` - import { createProxy } from "private-next-rsc-mod-ref-proxy" + import { createProxy } from "${moduleProxy}" const proxy = createProxy(${proxyFilepath}) ` let cnt = 0 @@ -70,5 +73,9 @@ export default async function transformSource( } } - return callback(null, source, sourceMap) + return callback( + null, + source.replace(RSC_MOD_REF_PROXY_ALIAS, moduleProxy), + sourceMap + ) } From 054f786c8c59662c8e0e78e3c1af00a6e7a071fe Mon Sep 17 00:00:00 2001 From: Mark Ladyshau <47859603+mrkldshv@users.noreply.github.com> Date: Wed, 22 Mar 2023 03:15:52 +0100 Subject: [PATCH 602/672] Skip warning if there is app directory for `no-html-link-for-pages` rule (#42516) Skips pages directory warning if there is app directory in the root for `no-html-link-for-pages` lint rule. Fixes #42448. ## Bug - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm build && pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- .../src/rules/no-html-link-for-pages.ts | 15 +- .../no-html-link-for-pages.test.ts | 158 ++++++++++++++---- .../with-app-dir/app/index.jsx | 1 + .../custom-pages/[profile]/index.tsx | 1 + .../custom-pages/index.jsx | 1 + .../custom-pages/list/[foo]/[id].jsx | 1 + .../without-pages-dir/index.jsx | 1 + 7 files changed, 143 insertions(+), 35 deletions(-) create mode 100644 test/unit/eslint-plugin-next/with-app-dir/app/index.jsx create mode 100644 test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/[profile]/index.tsx create mode 100644 test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/index.jsx create mode 100644 test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/list/[foo]/[id].jsx create mode 100644 test/unit/eslint-plugin-next/without-pages-dir/index.jsx diff --git a/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts b/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts index b5b06727f53c55..dbb8b43c47ccd9 100644 --- a/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts +++ b/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts @@ -74,7 +74,20 @@ export = defineRule({ } return fsExistsSyncCache[dir] }) - if (foundPagesDirs.length === 0) { + + const appDirs = rootDirs + .map((dir) => [path.join(dir, 'app'), path.join(dir, 'src', 'app')]) + .flat() + + const foundAppDirs = appDirs.filter((dir) => { + if (fsExistsSyncCache[dir] === undefined) { + fsExistsSyncCache[dir] = fs.existsSync(dir) + } + return fsExistsSyncCache[dir] + }) + + // warn if there are no pages and app directories + if (foundPagesDirs.length === 0 && foundAppDirs.length === 0) { pagesDirWarning(pagesDirs) return {} } diff --git a/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts b/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts index 0f2c0f629713ef..fe3ac7b4292035 100644 --- a/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts +++ b/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts @@ -4,10 +4,21 @@ import { Linter } from 'eslint' import assert from 'assert' import path from 'path' -const linter = new Linter({ cwd: __dirname }) +const withCustomPagesDirectory = path.join(__dirname, 'with-custom-pages-dir') + +const withoutPagesLinter = new Linter({ + cwd: path.join(__dirname, 'without-pages-dir'), +}) +const withAppLinter = new Linter({ + cwd: path.join(__dirname, 'with-app-dir'), +}) +const withCustomPagesLinter = new Linter({ + cwd: withCustomPagesDirectory, +}) + const linterConfig: any = { rules: { - 'no-html-link-for-pages': [2, path.join(__dirname, 'custom-pages')], + 'no-html-link-for-pages': [2], }, parserOptions: { ecmaVersion: 2018, @@ -18,20 +29,35 @@ const linterConfig: any = { }, }, } +const linterConfigWithCustomDirectory: any = { + ...linterConfig, + rules: { + 'no-html-link-for-pages': [ + 2, + path.join(withCustomPagesDirectory, 'custom-pages'), + ], + }, +} const linterConfigWithMultipleDirectories = { ...linterConfig, rules: { 'no-html-link-for-pages': [ 2, [ - path.join(__dirname, 'custom-pages'), - path.join(__dirname, 'custom-pages/list'), + path.join(withCustomPagesDirectory, 'custom-pages'), + path.join(withCustomPagesDirectory, 'custom-pages/list'), ], ], }, } -linter.defineRules({ +withoutPagesLinter.defineRules({ + 'no-html-link-for-pages': rule, +}) +withAppLinter.defineRules({ + 'no-html-link-for-pages': rule, +}) +withCustomPagesLinter.defineRules({ 'no-html-link-for-pages': rule, }) @@ -186,15 +212,47 @@ export class Blah extends Head { ` describe('no-html-link-for-pages', function () { - it('valid link element', function () { - const report = linter.verify(validCode, linterConfig, { + it('prints warning when there are no "pages" or "app" directories', function () { + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation() + withoutPagesLinter.verify(validCode, linterConfig, { filename: 'foo.js', }) + const rootDirectory = path.join(__dirname, 'without-pages-dir') + expect(consoleSpy).toHaveBeenCalledWith( + `Pages directory cannot be found at ${path.join( + rootDirectory, + 'pages' + )} or ${path.join( + rootDirectory, + 'src', + 'pages' + )}. If using a custom path, please configure with the \`no-html-link-for-pages\` rule in your eslint config file.` + ) + + consoleSpy.mockRestore() + }) + it('does not print warning when there is "app" directory and no "pages" directory', function () { + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation() + withAppLinter.verify(validCode, linterConfig, { + filename: 'foo.js', + }) + expect(consoleSpy).not.toHaveBeenCalled() + + consoleSpy.mockRestore() + }) + it('valid link element', function () { + const report = withCustomPagesLinter.verify( + validCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.deepEqual(report, []) }) it('valid link element with multiple directories', function () { - const report = linter.verify( + const report = withCustomPagesLinter.verify( validCode, linterConfigWithMultipleDirectories, { @@ -205,44 +263,68 @@ describe('no-html-link-for-pages', function () { }) it('valid anchor element', function () { - const report = linter.verify(validAnchorCode, linterConfig, { - filename: 'foo.js', - }) + const report = withCustomPagesLinter.verify( + validAnchorCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.deepEqual(report, []) }) it('valid external link element', function () { - const report = linter.verify(validExternalLinkCode, linterConfig, { - filename: 'foo.js', - }) + const report = withCustomPagesLinter.verify( + validExternalLinkCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.deepEqual(report, []) }) it('valid download link element', function () { - const report = linter.verify(validDownloadLinkCode, linterConfig, { - filename: 'foo.js', - }) + const report = withCustomPagesLinter.verify( + validDownloadLinkCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.deepEqual(report, []) }) it('valid target="_blank" link element', function () { - const report = linter.verify(validTargetBlankLinkCode, linterConfig, { - filename: 'foo.js', - }) + const report = withCustomPagesLinter.verify( + validTargetBlankLinkCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.deepEqual(report, []) }) it('valid public file link element', function () { - const report = linter.verify(validPublicFile, linterConfig, { - filename: 'foo.js', - }) + const report = withCustomPagesLinter.verify( + validPublicFile, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.deepEqual(report, []) }) it('invalid static route', function () { - const [report] = linter.verify(invalidStaticCode, linterConfig, { - filename: 'foo.js', - }) + const [report] = withCustomPagesLinter.verify( + invalidStaticCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.notEqual(report, undefined, 'No lint errors found.') assert.equal( report.message, @@ -251,17 +333,21 @@ describe('no-html-link-for-pages', function () { }) it('invalid dynamic route', function () { - const [report] = linter.verify(invalidDynamicCode, linterConfig, { - filename: 'foo.js', - }) + const [report] = withCustomPagesLinter.verify( + invalidDynamicCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.notEqual(report, undefined, 'No lint errors found.') assert.equal( report.message, 'Do not use an `` element to navigate to `/list/foo/bar/`. Use `` from `next/link` instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages' ) - const [secondReport] = linter.verify( + const [secondReport] = withCustomPagesLinter.verify( secondInvalidDynamicCode, - linterConfig, + linterConfigWithCustomDirectory, { filename: 'foo.js', } @@ -271,9 +357,13 @@ describe('no-html-link-for-pages', function () { secondReport.message, 'Do not use an `` element to navigate to `/list/foo/`. Use `` from `next/link` instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages' ) - const [thirdReport] = linter.verify(thirdInvalidDynamicCode, linterConfig, { - filename: 'foo.js', - }) + const [thirdReport] = withCustomPagesLinter.verify( + thirdInvalidDynamicCode, + linterConfigWithCustomDirectory, + { + filename: 'foo.js', + } + ) assert.notEqual(thirdReport, undefined, 'No lint errors found.') assert.equal( thirdReport.message, diff --git a/test/unit/eslint-plugin-next/with-app-dir/app/index.jsx b/test/unit/eslint-plugin-next/with-app-dir/app/index.jsx new file mode 100644 index 00000000000000..ead516c976e9b3 --- /dev/null +++ b/test/unit/eslint-plugin-next/with-app-dir/app/index.jsx @@ -0,0 +1 @@ +export default () => {} diff --git a/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/[profile]/index.tsx b/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/[profile]/index.tsx new file mode 100644 index 00000000000000..ead516c976e9b3 --- /dev/null +++ b/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/[profile]/index.tsx @@ -0,0 +1 @@ +export default () => {} diff --git a/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/index.jsx b/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/index.jsx new file mode 100644 index 00000000000000..ead516c976e9b3 --- /dev/null +++ b/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/index.jsx @@ -0,0 +1 @@ +export default () => {} diff --git a/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/list/[foo]/[id].jsx b/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/list/[foo]/[id].jsx new file mode 100644 index 00000000000000..ead516c976e9b3 --- /dev/null +++ b/test/unit/eslint-plugin-next/with-custom-pages-dir/custom-pages/list/[foo]/[id].jsx @@ -0,0 +1 @@ +export default () => {} diff --git a/test/unit/eslint-plugin-next/without-pages-dir/index.jsx b/test/unit/eslint-plugin-next/without-pages-dir/index.jsx new file mode 100644 index 00000000000000..ead516c976e9b3 --- /dev/null +++ b/test/unit/eslint-plugin-next/without-pages-dir/index.jsx @@ -0,0 +1 @@ +export default () => {} From 48948022c7d195f58cc37e59d848f9e2ca59bcf7 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 22 Mar 2023 09:34:50 +0100 Subject: [PATCH 603/672] Catch redirect() in root layout (#47345) ### What? Adds the error boundary used to catch `redirect()` above the root layout. ### Why? Currently calling `redirect()` in the root layout causes `NEXT_REDIRECT` to bubble up to the error boundary because we didn't have a redirect-boundary above the place where the root layout is rendered client-side. ### How? - Moved redirect-boundary into a separate file - Added redirect-boundary around the `cache.subTreeData` in app-router (around the root layout) fix NEXT-315 ([link](https://linear.app/vercel/issue/NEXT-315)) Fixes #42556 I've verified the reproduction shown in #42556 has been fixed earlier, there was another report about calling `redirect()` in the root layout and that's what this PR fixes. Since that issue has many comments here's some additional context: - `redirect()` can only be called during React component rendering. - This means you can't run `redirect()` in `onClick` or `useEffect()` handlers. - Calling `redirect()` in a server component or during prerendering of client components it will add the right meta tag to trigger a redirect - `` - Because of streaming rendering by the time your code runs the browser will have already received the start of the stream and headers will have been sent, as such you can't modify the headers, hence why the meta tag is used instead of `location`. - Calling `redirect()` in client components is supported while rendering, e.g. if you have a condition: ```tsx 'use client' import { useState } from 'react' import { redirect } from 'next/navigation' export function ClientComponent() { const [clicked, setClicked] = useState() if(clicked) { redirect('/another-page') } return <> } ``` --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/next/src/client/app-index.tsx | 17 +++++ .../next/src/client/components/app-router.tsx | 7 +- .../client/components/is-next-router-error.ts | 8 +++ .../src/client/components/layout-router.tsx | 59 +--------------- .../internal/helpers/use-error-handler.ts | 9 +-- .../client/components/redirect-boundary.tsx | 70 +++++++++++++++++++ .../root-layout-redirect/app/layout.tsx | 21 ++++++ .../app-dir/root-layout-redirect/app/page.tsx | 3 + .../root-layout-redirect/app/result/page.tsx | 3 + .../root-layout-redirect/next.config.js | 8 +++ .../root-layout-redirect.test.ts | 33 +++++++++ .../root-layout-redirect/tsconfig.json | 24 +++++++ 12 files changed, 196 insertions(+), 66 deletions(-) create mode 100644 packages/next/src/client/components/is-next-router-error.ts create mode 100644 packages/next/src/client/components/redirect-boundary.tsx create mode 100644 test/e2e/app-dir/root-layout-redirect/app/layout.tsx create mode 100644 test/e2e/app-dir/root-layout-redirect/app/page.tsx create mode 100644 test/e2e/app-dir/root-layout-redirect/app/result/page.tsx create mode 100644 test/e2e/app-dir/root-layout-redirect/next.config.js create mode 100644 test/e2e/app-dir/root-layout-redirect/root-layout-redirect.test.ts create mode 100644 test/e2e/app-dir/root-layout-redirect/tsconfig.json diff --git a/packages/next/src/client/app-index.tsx b/packages/next/src/client/app-index.tsx index 346210335b52c5..ebbe4aec34b091 100644 --- a/packages/next/src/client/app-index.tsx +++ b/packages/next/src/client/app-index.tsx @@ -9,6 +9,23 @@ import { HeadManagerContext } from '../shared/lib/head-manager-context' import { GlobalLayoutRouterContext } from '../shared/lib/app-router-context' import onRecoverableError from './on-recoverable-error' import { callServer } from './app-call-server' +import { isNextRouterError } from './components/is-next-router-error' + +// Since React doesn't call onerror for errors caught in error boundaries. +const origConsoleError = window.console.error +window.console.error = (...args) => { + if (isNextRouterError(args[0])) { + return + } + origConsoleError.apply(window.console, args) +} + +window.addEventListener('error', (ev: WindowEventMap['error']): void => { + if (isNextRouterError(ev.error)) { + ev.preventDefault() + return + } +}) /// diff --git a/packages/next/src/client/components/app-router.tsx b/packages/next/src/client/components/app-router.tsx index d8d33c448d4286..724a53fba07a18 100644 --- a/packages/next/src/client/components/app-router.tsx +++ b/packages/next/src/client/components/app-router.tsx @@ -41,6 +41,7 @@ import { import { isBot } from '../../shared/lib/router/utils/is-bot' import { addBasePath } from '../add-base-path' import { AppRouterAnnouncer } from './app-router-announcer' +import { RedirectBoundary } from './redirect-boundary' const isServer = typeof window === 'undefined' @@ -312,8 +313,10 @@ function Router({ const content = ( <> - {cache.subTreeData} - + + {cache.subTreeData} + + ) diff --git a/packages/next/src/client/components/is-next-router-error.ts b/packages/next/src/client/components/is-next-router-error.ts new file mode 100644 index 00000000000000..11ed7395820284 --- /dev/null +++ b/packages/next/src/client/components/is-next-router-error.ts @@ -0,0 +1,8 @@ +import { isNotFoundError } from './not-found' +import { isRedirectError } from './redirect' + +export function isNextRouterError(error: any): boolean { + return ( + error && error.digest && (isRedirectError(error) || isNotFoundError(error)) + ) +} diff --git a/packages/next/src/client/components/layout-router.tsx b/packages/next/src/client/components/layout-router.tsx index adae12cce64a72..8caf691646b1b7 100644 --- a/packages/next/src/client/components/layout-router.tsx +++ b/packages/next/src/client/components/layout-router.tsx @@ -1,9 +1,6 @@ 'use client' -import type { - AppRouterInstance, - ChildSegmentMap, -} from '../../shared/lib/app-router-context' +import type { ChildSegmentMap } from '../../shared/lib/app-router-context' import type { FlightRouterState, FlightSegmentPath, @@ -12,7 +9,7 @@ import type { import type { ErrorComponent } from './error-boundary' import { FocusAndScrollRef } from './router-reducer/router-reducer-types' -import React, { useContext, useEffect, useMemo, use } from 'react' +import React, { useContext, useMemo, use } from 'react' import ReactDOM from 'react-dom' import { CacheStates, @@ -24,10 +21,9 @@ import { fetchServerResponse } from './router-reducer/fetch-server-response' import { createInfinitePromise } from './infinite-promise' import { ErrorBoundary } from './error-boundary' import { matchSegment } from './match-segments' -import { useRouter } from './navigation' import { handleSmoothScroll } from '../../shared/lib/router/utils/handle-smooth-scroll' -import { getURLFromRedirectError, isRedirectError } from './redirect' import { findHeadInCache } from './router-reducer/reducers/find-head-in-cache' +import { RedirectBoundary } from './redirect-boundary' /** * Add refetch marker to router state at the point of the current layout segment. @@ -422,55 +418,6 @@ function LoadingBoundary({ return <>{children} } -interface RedirectBoundaryProps { - router: AppRouterInstance - children: React.ReactNode -} - -function HandleRedirect({ redirect }: { redirect: string }) { - const router = useRouter() - - useEffect(() => { - router.replace(redirect, {}) - }, [redirect, router]) - return null -} - -class RedirectErrorBoundary extends React.Component< - RedirectBoundaryProps, - { redirect: string | null } -> { - constructor(props: RedirectBoundaryProps) { - super(props) - this.state = { redirect: null } - } - - static getDerivedStateFromError(error: any) { - if (isRedirectError(error)) { - const url = getURLFromRedirectError(error) - return { redirect: url } - } - // Re-throw if error is not for redirect - throw error - } - - render() { - const redirect = this.state.redirect - if (redirect !== null) { - return - } - - return this.props.children - } -} - -function RedirectBoundary({ children }: { children: React.ReactNode }) { - const router = useRouter() - return ( - {children} - ) -} - interface NotFoundBoundaryProps { notFound?: React.ReactNode notFoundStyles?: React.ReactNode diff --git a/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-error-handler.ts b/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-error-handler.ts index 66ab3130245ce2..27a7a61f85f334 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-error-handler.ts +++ b/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-error-handler.ts @@ -1,10 +1,9 @@ import { useEffect } from 'react' -import { isNotFoundError } from '../../../not-found' -import { isRedirectError } from '../../../redirect' import { hydrationErrorWarning, hydrationErrorComponentStack, } from './hydration-error-info' +import { isNextRouterError } from '../../../is-next-router-error' export type ErrorHandler = (error: Error) => void @@ -12,12 +11,6 @@ export const RuntimeErrorHandler = { hadRuntimeError: false, } -function isNextRouterError(error: any): boolean { - return ( - error && error.digest && (isRedirectError(error) || isNotFoundError(error)) - ) -} - function isHydrationError(error: Error): boolean { return ( error.message.match(/(hydration|content does not match|did not match)/i) != diff --git a/packages/next/src/client/components/redirect-boundary.tsx b/packages/next/src/client/components/redirect-boundary.tsx new file mode 100644 index 00000000000000..3ae9afbd5dbf25 --- /dev/null +++ b/packages/next/src/client/components/redirect-boundary.tsx @@ -0,0 +1,70 @@ +'use client' +import React, { useEffect } from 'react' +import { AppRouterInstance } from '../../shared/lib/app-router-context' +import { useRouter } from './navigation' +import { getURLFromRedirectError, isRedirectError } from './redirect' + +interface RedirectBoundaryProps { + router: AppRouterInstance + children: React.ReactNode +} + +function HandleRedirect({ + redirect, + reset, +}: { + redirect: string + reset: () => void +}) { + const router = useRouter() + + useEffect(() => { + // @ts-ignore startTransition exists + React.startTransition(() => { + router.replace(redirect, {}) + reset() + }) + }, [redirect, reset, router]) + + return null +} + +export class RedirectErrorBoundary extends React.Component< + RedirectBoundaryProps, + { redirect: string | null } +> { + constructor(props: RedirectBoundaryProps) { + super(props) + this.state = { redirect: null } + } + + static getDerivedStateFromError(error: any) { + if (isRedirectError(error)) { + const url = getURLFromRedirectError(error) + return { redirect: url } + } + // Re-throw if error is not for redirect + throw error + } + + render() { + const redirect = this.state.redirect + if (redirect !== null) { + return ( + this.setState({ redirect: null })} + /> + ) + } + + return this.props.children + } +} + +export function RedirectBoundary({ children }: { children: React.ReactNode }) { + const router = useRouter() + return ( + {children} + ) +} diff --git a/test/e2e/app-dir/root-layout-redirect/app/layout.tsx b/test/e2e/app-dir/root-layout-redirect/app/layout.tsx new file mode 100644 index 00000000000000..221e081c1e1268 --- /dev/null +++ b/test/e2e/app-dir/root-layout-redirect/app/layout.tsx @@ -0,0 +1,21 @@ +'use client' +import React, { useState } from 'react' +import { redirect } from 'next/navigation' + +export default function Root({ children }: { children: React.ReactNode }) { + const [clicked, setClicked] = useState(false) + if (clicked) { + redirect('/result') + } + + return ( + + + + {children} + + + ) +} diff --git a/test/e2e/app-dir/root-layout-redirect/app/page.tsx b/test/e2e/app-dir/root-layout-redirect/app/page.tsx new file mode 100644 index 00000000000000..ff7159d9149fee --- /dev/null +++ b/test/e2e/app-dir/root-layout-redirect/app/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return

hello world

+} diff --git a/test/e2e/app-dir/root-layout-redirect/app/result/page.tsx b/test/e2e/app-dir/root-layout-redirect/app/result/page.tsx new file mode 100644 index 00000000000000..d589ad53e779c4 --- /dev/null +++ b/test/e2e/app-dir/root-layout-redirect/app/result/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return

Result Page

+} diff --git a/test/e2e/app-dir/root-layout-redirect/next.config.js b/test/e2e/app-dir/root-layout-redirect/next.config.js new file mode 100644 index 00000000000000..bf49894afd4006 --- /dev/null +++ b/test/e2e/app-dir/root-layout-redirect/next.config.js @@ -0,0 +1,8 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = { + experimental: { appDir: true }, +} + +module.exports = nextConfig diff --git a/test/e2e/app-dir/root-layout-redirect/root-layout-redirect.test.ts b/test/e2e/app-dir/root-layout-redirect/root-layout-redirect.test.ts new file mode 100644 index 00000000000000..33cc7e04e71ec3 --- /dev/null +++ b/test/e2e/app-dir/root-layout-redirect/root-layout-redirect.test.ts @@ -0,0 +1,33 @@ +import { createNextDescribe } from 'e2e-utils' + +createNextDescribe( + 'root-layout-redirect', + { + files: __dirname, + }, + ({ next }) => { + it('should work using browser', async () => { + const browser = await next.browser('/') + + expect( + await browser + .elementByCss('#trigger-redirect') + .click() + .waitForElementByCss('#result') + .text() + ).toBe('Result Page') + + const browserLogs = await browser.log('browser') + + let foundErrors = false + + browserLogs.forEach((log) => { + if (log.source === 'error') { + foundErrors = true + } + }) + + expect(foundErrors).toBe(false) + }) + } +) diff --git a/test/e2e/app-dir/root-layout-redirect/tsconfig.json b/test/e2e/app-dir/root-layout-redirect/tsconfig.json new file mode 100644 index 00000000000000..d2bc2ac5e3cea1 --- /dev/null +++ b/test/e2e/app-dir/root-layout-redirect/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "incremental": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} From f029023a3c8f1caf65109f208c1b666fe51d2e21 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 22 Mar 2023 10:26:19 +0100 Subject: [PATCH 604/672] Add useParams() (#47373) ### What? Adds `useParams` to read the canonical parameters. ```tsx 'use client' import { useParams } from 'next/navigation' export default function Page() { const { id } = useParams() return (
{id}
) } ``` ### Why? Allows for accessing segment parameters for the entire page. ### How? It uses a similar resolving of `useSelectedLayoutSegments` which resolve `children` and if `children` is not available the first available parallel route instead. Closes NEXT-99 --- .../next/src/client/components/navigation.ts | 35 ++++++++++++++++ .../use-params/app/[id]/[id2]/page.tsx | 11 +++++ test/e2e/app-dir/use-params/app/[id]/page.tsx | 10 +++++ test/e2e/app-dir/use-params/app/layout.tsx | 7 ++++ test/e2e/app-dir/use-params/app/page.tsx | 18 +++++++++ test/e2e/app-dir/use-params/next.config.js | 8 ++++ test/e2e/app-dir/use-params/tsconfig.json | 24 +++++++++++ .../e2e/app-dir/use-params/use-params.test.ts | 40 +++++++++++++++++++ 8 files changed, 153 insertions(+) create mode 100644 test/e2e/app-dir/use-params/app/[id]/[id2]/page.tsx create mode 100644 test/e2e/app-dir/use-params/app/[id]/page.tsx create mode 100644 test/e2e/app-dir/use-params/app/layout.tsx create mode 100644 test/e2e/app-dir/use-params/app/page.tsx create mode 100644 test/e2e/app-dir/use-params/next.config.js create mode 100644 test/e2e/app-dir/use-params/tsconfig.json create mode 100644 test/e2e/app-dir/use-params/use-params.test.ts diff --git a/packages/next/src/client/components/navigation.ts b/packages/next/src/client/components/navigation.ts index 2e38b9c914a263..1aacdae8421aa0 100644 --- a/packages/next/src/client/components/navigation.ts +++ b/packages/next/src/client/components/navigation.ts @@ -4,6 +4,7 @@ import { useContext, useMemo } from 'react' import type { FlightRouterState } from '../../server/app-render/types' import { AppRouterContext, + GlobalLayoutRouterContext, LayoutRouterContext, } from '../../shared/lib/app-router-context' import { @@ -132,7 +133,41 @@ export function useRouter(): import('../../shared/lib/app-router-context').AppRo return router } +interface Params { + [key: string]: string +} +// TODO-APP: handle parallel routes +function getSelectedParams( + tree: FlightRouterState, + params: Params = {} +): Params { + // After first parallel route prefer children, if there's no children pick the first parallel route. + const parallelRoutes = tree[1] + const node = parallelRoutes.children ?? Object.values(parallelRoutes)[0] + + if (!node) return params + const segment = node[0] + const isDynamicParameter = Array.isArray(segment) + const segmentValue = isDynamicParameter ? segment[1] : segment + if (!segmentValue || segmentValue === '__PAGE__') return params + + if (isDynamicParameter) { + params[segment[0]] = segment[1] + } + + return getSelectedParams(node, params) +} + +export function useParams() { + clientHookInServerComponentError('useParams') + const { tree } = useContext(GlobalLayoutRouterContext) + return getSelectedParams(tree) +} + // TODO-APP: handle parallel routes +/** + * Get the canonical parameters from the current level to the leaf node. + */ function getSelectedLayoutSegmentPath( tree: FlightRouterState, parallelRouteKey: string, diff --git a/test/e2e/app-dir/use-params/app/[id]/[id2]/page.tsx b/test/e2e/app-dir/use-params/app/[id]/[id2]/page.tsx new file mode 100644 index 00000000000000..fddfc884181b6e --- /dev/null +++ b/test/e2e/app-dir/use-params/app/[id]/[id2]/page.tsx @@ -0,0 +1,11 @@ +'use client' +import { useParams } from 'next/navigation' +export default function Page() { + const { id, id2 } = useParams() + return ( +
+
{id}
+
{id2}
+
+ ) +} diff --git a/test/e2e/app-dir/use-params/app/[id]/page.tsx b/test/e2e/app-dir/use-params/app/[id]/page.tsx new file mode 100644 index 00000000000000..2f2455d1ca438b --- /dev/null +++ b/test/e2e/app-dir/use-params/app/[id]/page.tsx @@ -0,0 +1,10 @@ +'use client' +import { useParams } from 'next/navigation' +export default function Page() { + const { id } = useParams() + return ( +
+
{id}
+
+ ) +} diff --git a/test/e2e/app-dir/use-params/app/layout.tsx b/test/e2e/app-dir/use-params/app/layout.tsx new file mode 100644 index 00000000000000..e7077399c03ce1 --- /dev/null +++ b/test/e2e/app-dir/use-params/app/layout.tsx @@ -0,0 +1,7 @@ +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/test/e2e/app-dir/use-params/app/page.tsx b/test/e2e/app-dir/use-params/app/page.tsx new file mode 100644 index 00000000000000..f1988b697d0819 --- /dev/null +++ b/test/e2e/app-dir/use-params/app/page.tsx @@ -0,0 +1,18 @@ +import Link from 'next/link' + +export default function Page() { + return ( + <> +
+ + To /a + +
+
+ + To /a/b + +
+ + ) +} diff --git a/test/e2e/app-dir/use-params/next.config.js b/test/e2e/app-dir/use-params/next.config.js new file mode 100644 index 00000000000000..bf49894afd4006 --- /dev/null +++ b/test/e2e/app-dir/use-params/next.config.js @@ -0,0 +1,8 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = { + experimental: { appDir: true }, +} + +module.exports = nextConfig diff --git a/test/e2e/app-dir/use-params/tsconfig.json b/test/e2e/app-dir/use-params/tsconfig.json new file mode 100644 index 00000000000000..d2bc2ac5e3cea1 --- /dev/null +++ b/test/e2e/app-dir/use-params/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "incremental": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/test/e2e/app-dir/use-params/use-params.test.ts b/test/e2e/app-dir/use-params/use-params.test.ts new file mode 100644 index 00000000000000..2685137f10295b --- /dev/null +++ b/test/e2e/app-dir/use-params/use-params.test.ts @@ -0,0 +1,40 @@ +import { createNextDescribe } from 'e2e-utils' + +createNextDescribe( + 'use-params', + { + files: __dirname, + }, + ({ next }) => { + it('should work for single dynamic param', async () => { + const $ = await next.render$('/a/b') + expect($('#param-id').text()).toBe('a') + }) + it('should work for nested dynamic params', async () => { + const $ = await next.render$('/a/b') + expect($('#param-id').text()).toBe('a') + expect($('#param-id2').text()).toBe('b') + }) + + it('should work for single dynamic param client navigating', async () => { + const browser = await next.browser('/') + expect( + await browser + .elementByCss('#to-a') + .click() + .waitForElementByCss('#param-id') + .text() + ).toBe('a') + }) + + it('should work for nested dynamic params client navigating', async () => { + const browser = await next.browser('/') + await browser + .elementByCss('#to-a-b') + .click() + .waitForElementByCss('#param-id') + expect(await browser.elementByCss('#param-id').text()).toBe('a') + expect(await browser.elementByCss('#param-id2').text()).toBe('b') + }) + } +) From 8195e1947bc8f36ae357b9cf1c04db4b97f6dbd0 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Wed, 22 Mar 2023 11:28:49 +0100 Subject: [PATCH 605/672] Refactor ES chunk evaluate logic into a Runtime trait (#47116) This is the Next.js side of https://github.com/vercel/turbo/pull/4141 --- packages/next-swc/Cargo.lock | 420 +++++++++--------- packages/next-swc/Cargo.toml | 61 +-- packages/next-swc/crates/next-core/Cargo.toml | 1 + .../next-swc/crates/next-core/js/package.json | 2 +- .../crates/next-core/js/src/dev/hmr-client.ts | 4 +- .../crates/next-core/js/src/overlay/client.ts | 2 +- .../src/overlay/internal/ReactDevOverlay.tsx | 2 +- .../next-core/js/src/overlay/internal/bus.ts | 2 +- .../src/overlay/internal/container/Errors.tsx | 2 +- .../internal/container/TurbopackIssue.tsx | 2 +- .../crates/next-core/js/types/next.d.ts | 2 +- .../crates/next-core/src/app_source.rs | 13 +- packages/next-swc/crates/next-core/src/lib.rs | 1 + .../next-core/src/next_client/context.rs | 3 +- .../next-core/src/next_client/transition.rs | 11 +- .../in_chunking_context_asset.rs | 13 +- .../src/next_client_chunks/with_chunks.rs | 44 +- .../with_chunking_context_scope_asset.rs | 17 +- .../with_client_chunks.rs | 46 +- .../crates/next-core/src/next_config.rs | 7 +- .../next-core/src/next_edge/transition.rs | 9 +- .../next-core/src/next_font/google/mod.rs | 1 - .../crates/next-core/src/page_loader.rs | 10 +- .../crates/next-core/src/page_source.rs | 4 +- .../next-swc/crates/next-core/src/router.rs | 11 +- .../next-swc/crates/next-core/src/runtime.rs | 2 +- ... => Issue while running loader-7fb4cb.txt} | 2 +- ... => Issue while running loader-e84abe.txt} | 2 +- packages/next-swc/crates/next-dev/Cargo.toml | 2 + packages/next-swc/crates/next-dev/src/lib.rs | 15 +- pnpm-lock.yaml | 12 +- 31 files changed, 385 insertions(+), 340 deletions(-) rename packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/{Issue while running loader-54f34f.txt => Issue while running loader-7fb4cb.txt} (80%) rename packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/{Issue while running loader-873d9c.txt => Issue while running loader-e84abe.txt} (80%) diff --git a/packages/next-swc/Cargo.lock b/packages/next-swc/Cargo.lock index b61f60a8e49baa..221526d2d40593 100644 --- a/packages/next-swc/Cargo.lock +++ b/packages/next-swc/Cargo.lock @@ -18,7 +18,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.2", + "gimli 0.27.1", ] [[package]] @@ -294,9 +294,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.66" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84f9ebcc6c1f5b8cb160f6990096a5c127f423fcb6e1ccc46c370cbdfb75dfc" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -337,7 +337,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "serde", ] @@ -456,9 +456,9 @@ dependencies = [ [[package]] name = "binding_macros" -version = "0.44.5" +version = "0.44.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae33074ad17e2ccbc4f05ba97345ff513d9f70968bd2559c00733f294d5a4c6" +checksum = "a038911a0bafe08b6872e7da37360ea9939b58778b4169eb7156dca9855c5de0" dependencies = [ "anyhow", "console_error_panic_hook", @@ -755,7 +755,7 @@ checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.2", + "clap_lex 0.3.1", "is-terminal", "once_cell", "strsim", @@ -786,9 +786,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] @@ -1065,9 +1065,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.7" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -1075,9 +1075,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", @@ -1086,22 +1086,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" dependencies = [ "autocfg", "cfg-if 1.0.0", "crossbeam-utils", - "memoffset 0.8.0", + "memoffset 0.7.1", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" dependencies = [ "cfg-if 1.0.0", ] @@ -1190,9 +1190,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.92" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" +checksum = "90d59d9acd2a682b4e40605a242f6670eaa58c5957471cbf85e8aa6a0b97a5e8" dependencies = [ "cc", "cxxbridge-flags", @@ -1202,9 +1202,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.92" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" +checksum = "ebfa40bda659dd5c864e65f4c9a2b0aff19bea56b017b9b77c73d3766a453a38" dependencies = [ "cc", "codespan-reporting", @@ -1217,15 +1217,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.92" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" +checksum = "457ce6757c5c70dc6ecdbda6925b958aae7f959bda7d8fb9bde889e34a09dc03" [[package]] name = "cxxbridge-macro" -version = "1.0.92" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" +checksum = "ebf883b7aacd7b2aeb2a7b338648ee19f57c140d4ee8e52c68979c6b2f7f2263" dependencies = [ "proc-macro2", "quote", @@ -1314,12 +1314,6 @@ dependencies = [ "parking_lot_core 0.9.7", ] -[[package]] -name = "data-encoding" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" - [[package]] name = "debugid" version = "0.8.0" @@ -1423,11 +1417,11 @@ dependencies = [ [[package]] name = "enum-iterator" -version = "1.4.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "706d9e7cf1c7664859d79cd524e4e53ea2b67ea03c98cc2870c5e539695d597e" +checksum = "9ea166b3f7dc1032f7866d13f8d8e02c8d87507b61750176b86554964dc6a7bf" dependencies = [ - "enum-iterator-derive 1.2.0", + "enum-iterator-derive 1.1.0", ] [[package]] @@ -1443,9 +1437,9 @@ dependencies = [ [[package]] name = "enum-iterator-derive" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355f93763ef7b0ae1c43c4d8eccc9d5848d84ad1a1d8ce61c421d1ac85a19d05" +checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce" dependencies = [ "proc-macro2", "quote", @@ -1500,9 +1494,9 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.3.25" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2b0c2380453a92ea8b6c8e5f64ecaafccddde8ceab55ff7a8ac1029f894569" +checksum = "e4ca605381c017ec7a5fef5e548f1cfaa419ed0f6df6367339300db74c92aa7d" dependencies = [ "serde", ] @@ -1847,9 +1841,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "glob" @@ -1871,9 +1865,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -1988,9 +1982,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", @@ -2251,9 +2245,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", "windows-sys 0.45.0", @@ -2276,9 +2270,9 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-macro" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7d079e129b77477a49c5c4f1cfe9ce6c2c909ef52520693e8e811a714c7b20" +checksum = "1c068d4c6b922cd6284c609cfa6dec0e41615c9c5a1a4ba729a970d8daba05fb" dependencies = [ "Inflector", "pmutil", @@ -2289,9 +2283,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", @@ -2343,9 +2337,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "jni" @@ -2721,15 +2715,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - [[package]] name = "miette" version = "4.7.1" @@ -3057,6 +3042,7 @@ dependencies = [ "turbo-tasks-hash", "turbopack", "turbopack-core", + "turbopack-dev", "turbopack-dev-server", "turbopack-ecmascript", "turbopack-env", @@ -3094,9 +3080,11 @@ dependencies = [ "turbo-tasks-fs", "turbo-tasks-memory", "turbo-tasks-testing", + "turbopack", "turbopack-cli-utils", "turbopack-core", "turbopack-create-test-app", + "turbopack-dev", "turbopack-dev-server", "turbopack-node", "url", @@ -3235,7 +3223,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "clap 4.1.8", @@ -3939,15 +3927,18 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.5.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f851a03551ceefd30132e447f07f96cb7011d6b658374f3aed847333adb5559" +checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" +dependencies = [ + "cty", +] [[package]] name = "rayon" -version = "1.7.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ "either", "rayon-core", @@ -3955,9 +3946,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -4042,9 +4033,9 @@ dependencies = [ [[package]] name = "relative-path" -version = "1.8.0" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" +checksum = "d3bf6b372449361333ac1f498b7edae4dd5e70dccd7c0c2a7c7bce8f05ede648" [[package]] name = "rend" @@ -4169,9 +4160,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.9" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", @@ -4204,15 +4195,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "ryu-js" @@ -4252,9 +4243,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.5" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" [[package]] name = "sct" @@ -4394,16 +4385,16 @@ dependencies = [ "serde", "serde_json", "thiserror", - "time 0.3.20", + "time 0.3.17", "url", "uuid", ] [[package]] name = "serde" -version = "1.0.156" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] @@ -4430,9 +4421,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -4441,9 +4432,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "indexmap", "itoa", @@ -4453,9 +4444,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.10" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0969fff533976baadd92e08b1d102c5a3d8a8049eadfd69d4d1e3c5b2ed189" +checksum = "26b04f22b563c91331a10074bda3dd5492e3cc39d56bd557e91c0af42b6c7341" dependencies = [ "serde", ] @@ -4607,9 +4598,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ "autocfg", ] @@ -4650,9 +4641,9 @@ checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi 0.3.9", @@ -4660,11 +4651,11 @@ dependencies = [ [[package]] name = "sourcemap" -version = "6.2.3" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed16231c92d0a6f0388f56e0ab2be24ecff1173f8e22f0ea5e074d0525631cb" +checksum = "aebe057d110ddba043708da3fb010bf562ff6e9d4d60c9ee92860527bcbeccd6" dependencies = [ - "data-encoding", + "base64 0.13.1", "if_chain", "rustc_version 0.2.3", "serde", @@ -4890,9 +4881,9 @@ dependencies = [ [[package]] name = "swc" -version = "0.255.5" +version = "0.255.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e71658e15d689c1eb1a8706b0bb102b5e7c857cf90c2e4def40d5185b6bf5c" +checksum = "b08774e54fabd2394cbc0da9636c769b1ab9e65c1686268b97c815395a818679" dependencies = [ "ahash", "anyhow", @@ -4957,9 +4948,9 @@ dependencies = [ [[package]] name = "swc_bundler" -version = "0.208.4" +version = "0.208.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5adaebcfcb3ebc1b4d6418838250bb12f257bab9277fa2b2c61bb3324152c78f" +checksum = "eb1fb437dd26e1a128136f6e342c1648a934b10f3c98b3fc9bc91ad4710027bb" dependencies = [ "ahash", "anyhow", @@ -5062,9 +5053,9 @@ dependencies = [ [[package]] name = "swc_core" -version = "0.69.6" +version = "0.69.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7636640b21db7639b4bb485f9c6e0420fc340dea8ee7e4b43aa653980b8fe4be" +checksum = "1e5de5c999b4c92d181b79097647b73b173bd3f017a0fe56b3b681cdbbc4fef4" dependencies = [ "binding_macros", "swc", @@ -5122,9 +5113,9 @@ dependencies = [ [[package]] name = "swc_css_codegen" -version = "0.144.13" +version = "0.144.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b065170be02e897c6432eb0d434a91bf45c9c22e72e2fc0bb8982238fd777a0" +checksum = "bbfa6ae6065fa3a75c3bd9d4e8747d692a57ab5ac3259c5b3e5811965cce92d4" dependencies = [ "auto_impl", "bitflags", @@ -5152,9 +5143,9 @@ dependencies = [ [[package]] name = "swc_css_compat" -version = "0.20.13" +version = "0.20.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd067de48dc56a831e4d2c4f6af85911e6e433bfe4ec58851add31a15efc48e1" +checksum = "608c5e294e2fcbea240831e02863c68e765d2508c42cc3bda492a18198e3081f" dependencies = [ "bitflags", "once_cell", @@ -5169,9 +5160,9 @@ dependencies = [ [[package]] name = "swc_css_modules" -version = "0.21.15" +version = "0.21.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7dc9e75708f5b156513996634a27f4e50cf87bd526fac6c0814ca754b991ca7" +checksum = "1d3b768156027bb4f57cefa4eec66d2f2b122eb81937c62f2f820123b7617727" dependencies = [ "rustc-hash", "serde", @@ -5185,9 +5176,9 @@ dependencies = [ [[package]] name = "swc_css_parser" -version = "0.143.11" +version = "0.143.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e77940eb1bd7ecde34e4a82edb6d083b8bc231a034452e87c408422da3403fa" +checksum = "ab4dc464bb7b97db5cb057164af91d1a374bffa48170d67604c7f3158639ed27" dependencies = [ "bitflags", "lexical", @@ -5199,9 +5190,9 @@ dependencies = [ [[package]] name = "swc_css_prefixer" -version = "0.146.13" +version = "0.146.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb87426f777b6039936b67973cc1eddcf6907a3f650619f74fcf794bd9697c95" +checksum = "97fb14aeb39b8b43c2c84b4ec8ed3d7af419204385621dcd837a9d0cf8da9cbb" dependencies = [ "once_cell", "preset_env_base", @@ -5262,9 +5253,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "0.135.2" +version = "0.135.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78d196e6979af0cbb91084361ca006db292a6374f75ec04cbb55306051cc4f50" +checksum = "3a5280ef3bfa40a8ab3fa16ceba1bac038957c835a8d3742d3bd9bb067f3e427" dependencies = [ "memchr", "num-bigint", @@ -5294,9 +5285,9 @@ dependencies = [ [[package]] name = "swc_ecma_ext_transforms" -version = "0.99.3" +version = "0.99.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a44571524cc41f43f95327b5a1fce6a13b8559211f206c7c8094dbd4ec601f" +checksum = "c38e93d4c2593c16693521863df1be40a731479b51622f031d89f696de5028d9" dependencies = [ "phf", "swc_atoms", @@ -5308,9 +5299,9 @@ dependencies = [ [[package]] name = "swc_ecma_lints" -version = "0.77.3" +version = "0.77.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ccf829a21404d67a6319b43d2e28e2396fa19a926d0250699dcda815d17fb80" +checksum = "1aff33c34012b2d43ba6716aa233e36db8486715a696cc6aea44ab61c682b0cd" dependencies = [ "ahash", "auto_impl", @@ -5351,9 +5342,9 @@ dependencies = [ [[package]] name = "swc_ecma_minifier" -version = "0.175.4" +version = "0.175.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "988c3b9ff43c2dd1647afb5224a63e7fe2f70bb1b5a596caff5754a5cf0acd42" +checksum = "204f60e7f17f944d4d6fc059bec0659004c5c2ecc5f0fe8e1d015acb68d8489b" dependencies = [ "ahash", "arrayvec", @@ -5387,9 +5378,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.130.2" +version = "0.130.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "042435aaeb71c4416cde440323ac9fa2c24121c2ec150f0cb79999c2e6ceffaa" +checksum = "ace449290ab97f779573b8c9f5de43ce414a7c49043f0a61bd6e9a22173b2482" dependencies = [ "either", "enum_kind", @@ -5408,9 +5399,9 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "0.189.4" +version = "0.189.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c29560d4b7d011936068a34f62e06f9882f10bc0ca21f59f23295f7ffc4592" +checksum = "eb1632c57e30d4b805f30a72a36603336f211dbefd7396ee33209d84f0bc7922" dependencies = [ "ahash", "anyhow", @@ -5433,9 +5424,9 @@ dependencies = [ [[package]] name = "swc_ecma_quote_macros" -version = "0.41.2" +version = "0.41.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9be9e04f5baca8b0c8f837eb944844c3f1f54f76918c098dfc6ff007b3c58a" +checksum = "2103be5c172525c2001be6392d257de7bad3b0ec17e1ad9abf05e4adff4f0b5f" dependencies = [ "anyhow", "pmutil", @@ -5463,9 +5454,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "0.212.4" +version = "0.212.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ff3c3edd36cbffd22afb1523589cf479c1336468ff68e66a0c5845f0824136" +checksum = "ba4fb67fcbfd44d5d8b2ba28454ff0ab3ef4e57a545c8fbd4c796e0243b78d11" dependencies = [ "swc_atoms", "swc_common", @@ -5483,9 +5474,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "0.122.3" +version = "0.122.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4141092b17cd85eefc224b035b717e03c910b9fd58e4e637ffd05236d7e13b" +checksum = "2063b150343891e8f6eaccd67f546a3cd3c1c4b1ec6a0958681aa766d8d04993" dependencies = [ "better_scoped_tls", "bitflags", @@ -5506,9 +5497,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.111.3" +version = "0.111.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5022c592f0ae17f4dc42031e1c4c60b7e6d2d8d1c2428b986759a92ea853801" +checksum = "1b32dd8c0c1411d933fbf268205637d3668761b58694c8b9ceb4e1ee271f6af6" dependencies = [ "swc_atoms", "swc_common", @@ -5520,9 +5511,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "0.148.4" +version = "0.148.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55fa22cc1600ae6c543b1a259e479f424d7925ad93bd2d5dd10e5ac8cbf8c3c3" +checksum = "9d876c0f73579657c12c4f3efc55bea0fd78839d4de03d6b5809685e9577ecf1" dependencies = [ "ahash", "arrayvec", @@ -5560,9 +5551,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "0.165.4" +version = "0.165.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd383aeb03aed8e5f5530bef9c47e9ef2bd11d20ef5c4095f015e3b97c7c64c" +checksum = "2680f2b8a9b2ced927c7a2f787a43793e5f5fe2eb0a7fd8bd554352106eddeb7" dependencies = [ "Inflector", "ahash", @@ -5588,9 +5579,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.181.4" +version = "0.181.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584b8d5b1ea8d174453eeff6abb66ed2e58cbd67b6e83a4d4b8154b463ef4dd3" +checksum = "af72bda74e48705a053a5b7198f3dbca2b4c75343f1d0af5f9c8180303be5ce7" dependencies = [ "ahash", "dashmap", @@ -5614,9 +5605,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.156.4" +version = "0.156.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4015c3ab090f27eee0834d45bdcf9666dc6329ed06845d1882cdfe6f4826fca" +checksum = "d5ebd1c133fd4da55715c5957fdd831e639d9affaeb83660462e02cbf5225ff1" dependencies = [ "either", "serde", @@ -5633,9 +5624,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.167.4" +version = "0.167.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db1c7801b1d7741ab335441dd301ddcc4183fb250d5e6efaab33b03def268c06" +checksum = "a2d1f8c586abc99ab052e60e647e6a2ea8b62bf30c1bbacd16eced2157e190c1" dependencies = [ "ahash", "base64 0.13.1", @@ -5660,9 +5651,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_testing" -version = "0.125.3" +version = "0.125.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e91bd2d3ab3607e92f3e9d3a2b923073914665c964ff5e3ec5d61430ce2a82e" +checksum = "c04a4b965b755cf9701c572d91f84908f2e0f75bca65dd8b94f5b4bffb672700" dependencies = [ "ansi_term", "anyhow", @@ -5686,9 +5677,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.171.4" +version = "0.171.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142e8fb5ebe870bc51b3a95c0214af9112d3475b7cd5be4f13b87f3be664841a" +checksum = "033082e0f39e04ceeef6f07ec453aa045d8b909fa8ff01cd23e333d0f153a6c8" dependencies = [ "serde", "swc_atoms", @@ -5702,9 +5693,9 @@ dependencies = [ [[package]] name = "swc_ecma_usage_analyzer" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50c51a53b5be1892cc07e79a060bd8fdaed46fbdd4406bd9c2a6630c187094" +checksum = "c14f5ea9df6057d2f2ab2ac69309f21b84ba42172fcfa124ae279bf0f6ef23e9" dependencies = [ "ahash", "indexmap", @@ -5720,9 +5711,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.113.3" +version = "0.113.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c44885603c09926118708f4352e04242c2482bc16eb51ad7beb8ad4cf5f7bb6" +checksum = "cbd48f4c207b9dc261d4f7ce88571a0b26f53f5bd16b3b147ea536bf02e41f90" dependencies = [ "indexmap", "num_cpus", @@ -5808,9 +5799,9 @@ dependencies = [ [[package]] name = "swc_graph_analyzer" -version = "0.18.40" +version = "0.18.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8669bea09e5f7795ab2262087e548a1496672d10327d532f26a142e8e5fe9c0" +checksum = "b25ac475500b0776f1bb82da02eff867819b3c653130023ea957cbd1e91befa8" dependencies = [ "ahash", "auto_impl", @@ -5883,9 +5874,9 @@ dependencies = [ [[package]] name = "swc_plugin_runner" -version = "0.91.2" +version = "0.91.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce0dc5a3847776e684ac334884932e38bd885890f8975dd5f2e316ed7d7a6af3" +checksum = "970c8dd16f5b8083345d2c4ea86d945d5abd6c08ffe1419cd72ac02cf01fdf3d" dependencies = [ "anyhow", "enumset", @@ -5906,9 +5897,9 @@ dependencies = [ [[package]] name = "swc_timer" -version = "0.17.39" +version = "0.17.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9499135206c03f84a565beb2bf50214ba125bf531ff0d2e45b830d58bbf370b" +checksum = "f8bf7db20a9aca571d89bf052fc1fc419caeb98963ca9c63d1ca7a1b8c67ff9f" dependencies = [ "tracing", ] @@ -5950,9 +5941,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.109" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -6005,9 +5996,9 @@ dependencies = [ [[package]] name = "testing" -version = "0.31.39" +version = "0.31.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35fe40c981fab28b566fe4f346ded8d507043b7003ddcf29a612e117a51ba5ae" +checksum = "dda8d4f62089d08b0575a92273f2c824ca6e3958cd23ad2a0eb3f25438a0e9c9" dependencies = [ "ansi_term", "difference", @@ -6024,9 +6015,9 @@ dependencies = [ [[package]] name = "testing_macros" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74ff09d2d4d4b7ea140ff67eb7ed8fd35a708e2c327bcde5a25707d66840099" +checksum = "e6d536c776d47c59f8f47fbf4e7062b23095be9fce218d11d9c9fb988b579dfa" dependencies = [ "anyhow", "glob", @@ -6058,18 +6049,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -6135,14 +6126,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.20" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ "itoa", "serde", "time-core", - "time-macros 0.2.8", + "time-macros 0.2.6", ] [[package]] @@ -6163,9 +6154,9 @@ dependencies = [ [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" dependencies = [ "time-core", ] @@ -6210,9 +6201,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "bytes", @@ -6226,7 +6217,7 @@ dependencies = [ "socket2", "tokio-macros", "tracing", - "windows-sys 0.45.0", + "windows-sys 0.42.0", ] [[package]] @@ -6273,9 +6264,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite", @@ -6541,7 +6532,7 @@ dependencies = [ [[package]] name = "turbo-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "mimalloc", ] @@ -6549,7 +6540,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "auto-hash-map", @@ -6579,7 +6570,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "cargo-lock", @@ -6591,7 +6582,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "dotenvy", @@ -6605,7 +6596,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "indexmap", @@ -6622,7 +6613,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "auto-hash-map", @@ -6651,7 +6642,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "base16", "hex", @@ -6663,7 +6654,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -6677,7 +6668,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "proc-macro2", "quote", @@ -6687,7 +6678,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "auto-hash-map", @@ -6709,7 +6700,7 @@ dependencies = [ [[package]] name = "turbo-tasks-testing" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "auto-hash-map", @@ -6721,7 +6712,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "async-recursion", @@ -6747,7 +6738,7 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "clap 4.1.8", @@ -6763,7 +6754,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "async-trait", @@ -6790,7 +6781,7 @@ dependencies = [ [[package]] name = "turbopack-create-test-app" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "clap 4.1.8", @@ -6803,7 +6794,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "async-trait", @@ -6822,10 +6813,29 @@ dependencies = [ "turbopack-swc-utils", ] +[[package]] +name = "turbopack-dev" +version = "0.1.0" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" +dependencies = [ + "anyhow", + "indexmap", + "indoc", + "serde", + "serde_json", + "serde_qs", + "turbo-tasks", + "turbo-tasks-build", + "turbo-tasks-fs", + "turbo-tasks-hash", + "turbopack-core", + "turbopack-ecmascript", +] + [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "async-compression", @@ -6857,7 +6867,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "async-trait", @@ -6892,7 +6902,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "serde", @@ -6907,7 +6917,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "serde", @@ -6922,7 +6932,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "mdxjs", @@ -6937,7 +6947,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "futures", @@ -6963,7 +6973,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "serde", @@ -6979,7 +6989,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "swc_core", "turbo-tasks", @@ -6990,7 +7000,7 @@ dependencies = [ [[package]] name = "turbopack-test-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230321.1#4e461236222a57a22da484836bcf76a50b72890f" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230322.2#abc1f63953ea48046ff3fbab3bf5b51db6288385" dependencies = [ "anyhow", "once_cell", @@ -7008,7 +7018,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "rand", "static_assertions", ] @@ -7063,9 +7073,9 @@ checksum = "d70b6494226b36008c8366c288d77190b3fad2eb4c10533139c1c1f461127f1a" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-linebreak" @@ -7174,11 +7184,11 @@ checksum = "f21b881cd6636ece9735721cf03c1fe1e774fe258683d084bb2812ab67435749" dependencies = [ "anyhow", "cfg-if 1.0.0", - "enum-iterator 1.4.0", + "enum-iterator 1.3.0", "getset", "rustversion", "thiserror", - "time 0.3.20", + "time 0.3.17", ] [[package]] diff --git a/packages/next-swc/Cargo.toml b/packages/next-swc/Cargo.toml index 63cc60356edb24..060f8dcc54df22 100644 --- a/packages/next-swc/Cargo.toml +++ b/packages/next-swc/Cargo.toml @@ -46,36 +46,37 @@ swc_emotion = { version = "0.29.10" } testing = { version = "0.31.31" } # Turbo crates -auto-hash-map = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -node-file-trace = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -swc-ast-explorer = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-malloc = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1", default-features = false } -turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-build = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-fetch = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1", default-features = false } -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-hash = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-macros = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-macros-shared = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-memory = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-tasks-testing = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbo-updater = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-cli-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-core = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-create-test-app = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-css = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-dev-server = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-ecmascript = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-json = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-mdx = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-node = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-static = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-swc-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-test-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } -turbopack-tests = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230321.1" } +auto-hash-map = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +node-file-trace = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +swc-ast-explorer = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-malloc = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2", default-features = false } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-build = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-fetch = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2", default-features = false } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-hash = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-macros = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-macros-shared = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-memory = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-tasks-testing = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbo-updater = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-cli-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-core = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-create-test-app = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-css = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-dev = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-dev-server = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-ecmascript = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-env = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-json = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-mdx = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-node = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-static = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-swc-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-test-utils = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } +turbopack-tests = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230322.2" } # General Deps diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 2292683878c782..c9cf734676ebf3 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -26,6 +26,7 @@ turbo-tasks-fs = { workspace = true } turbo-tasks-hash = { workspace = true } turbopack = { workspace = true } turbopack-core = { workspace = true } +turbopack-dev = { workspace = true } turbopack-dev-server = { workspace = true } turbopack-ecmascript = { workspace = true } turbopack-env = { workspace = true } diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index e0545cfa8019ed..2d4cb4ae8bd913 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -9,7 +9,7 @@ "build:compiled": "node build.mjs" }, "dependencies": { - "@vercel/turbopack-runtime": "https://gitpkg.now.sh/vercel/turbo/crates/turbopack-ecmascript/js?8a8038f94", + "@vercel/turbopack-dev-runtime": "https://gitpkg.now.sh/vercel/turbo/crates/turbopack-dev/js?turbopack-230321.3", "anser": "^2.1.1", "css.escape": "^1.5.1", "next": "*", diff --git a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts index 4654a1af2acf7b..b62e03c282f5a3 100644 --- a/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts +++ b/packages/next-swc/crates/next-core/js/src/dev/hmr-client.ts @@ -8,13 +8,13 @@ import type { Issue, ResourceIdentifier, ServerMessage, -} from "@vercel/turbopack-runtime/types/protocol"; +} from "@vercel/turbopack-dev-runtime/types/protocol"; import type { ChunkPath, ModuleId, UpdateCallback, TurbopackGlobals, -} from "@vercel/turbopack-runtime/types"; +} from "@vercel/turbopack-dev-runtime/types"; import stripAnsi from "@vercel/turbopack-next/compiled/strip-ansi"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/client.ts b/packages/next-swc/crates/next-core/js/src/overlay/client.ts index faf93e25b1e0bc..efed3e7ae6a4f6 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/client.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/client.ts @@ -1,4 +1,4 @@ -import type { Issue } from "@vercel/turbopack-runtime/types/protocol"; +import type { Issue } from "@vercel/turbopack-dev-runtime/types/protocol"; import * as Bus from "./internal/bus"; import { parseStack } from "./internal/helpers/parseStack"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx index 24d36689a4d15e..54d53ff2a6096f 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/ReactDevOverlay.tsx @@ -1,6 +1,6 @@ import * as React from "react"; -import type { Issue } from "@vercel/turbopack-runtime/types/protocol"; +import type { Issue } from "@vercel/turbopack-dev-runtime/types/protocol"; import * as Bus from "./bus"; import { ShadowPortal } from "./components/ShadowPortal"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts b/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts index 6569e53dfd4f93..861e1da1f69c33 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/bus.ts @@ -1,6 +1,6 @@ import { StackFrame } from "stacktrace-parser"; -import type { Issue } from "@vercel/turbopack-runtime/types/protocol"; +import type { Issue } from "@vercel/turbopack-dev-runtime/types/protocol"; export const TYPE_BUILD_OK = "build-ok"; export const TYPE_TURBOPACK_ISSUES = "turbopack-error"; diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx index 34d9ba8dab9362..f9ecdc42218af7 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/Errors.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import { Issue } from '@vercel/turbopack-runtime/types/protocol' +import { Issue } from '@vercel/turbopack-dev-runtime/types/protocol' import { TYPE_UNHANDLED_ERROR, diff --git a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx index 3442f63fdce3be..5a71759333e6c4 100644 --- a/packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx +++ b/packages/next-swc/crates/next-core/js/src/overlay/internal/container/TurbopackIssue.tsx @@ -1,4 +1,4 @@ -import { Issue } from '@vercel/turbopack-runtime/types/protocol' +import { Issue } from '@vercel/turbopack-dev-runtime/types/protocol' import { LeftRightDialogHeader } from '../components/LeftRightDialogHeader' import { DialogBody, DialogBodyProps } from '../components/Dialog' diff --git a/packages/next-swc/crates/next-core/js/types/next.d.ts b/packages/next-swc/crates/next-core/js/types/next.d.ts index 82e53f22c3903c..91363c695edb6d 100644 --- a/packages/next-swc/crates/next-core/js/types/next.d.ts +++ b/packages/next-swc/crates/next-core/js/types/next.d.ts @@ -1,3 +1,3 @@ -import { ChunkPath } from "@vercel/turbopack-runtime/types"; +import { ChunkPath } from "@vercel/turbopack-dev-runtime/types"; export type ChunkGroup = ChunkPath[]; diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 6fb38b0e1aa870..f967d842da7db3 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -15,7 +15,6 @@ use turbopack::{ ModuleAssetContextVc, }; use turbopack_core::{ - chunk::dev::DevChunkingContextVc, compile_time_info::CompileTimeInfoVc, context::{AssetContext, AssetContextVc}, environment::{EnvironmentIntention, ServerAddrVc}, @@ -23,6 +22,7 @@ use turbopack_core::{ source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, }; +use turbopack_dev::DevChunkingContextVc; use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{ @@ -30,7 +30,7 @@ use turbopack_dev_server::{ }, }; use turbopack_ecmascript::{ - chunk::EcmascriptChunkPlaceablesVc, magic_identifier, utils::stringify_js, + chunk::EcmascriptChunkPlaceablesVc, magic_identifier, utils::StringifyJs, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, InnerAssetsVc, }; use turbopack_env::ProcessEnvAssetVc; @@ -107,7 +107,6 @@ async fn next_client_transition( Ok(NextClientTransition { is_app: true, - server_root, client_chunking_context, client_module_options_context, client_resolve_options_context, @@ -575,7 +574,7 @@ impl AppRendererVc { )); } } - Ok((stringify_js(segment_path), imports)) + Ok((StringifyJs(segment_path).to_string(), imports)) }); futures }) @@ -600,7 +599,7 @@ impl AppRendererVc { "import {}, {{ chunks as {} }} from {};\n", identifier, chunks_identifier, - stringify_js(p) + StringifyJs(p) )? } } @@ -610,7 +609,7 @@ impl AppRendererVc { r#"("TURBOPACK {{ transition: next-client }}"); import BOOTSTRAP from {}; "#, - stringify_js(&page) + StringifyJs(&page) )?; } @@ -621,7 +620,7 @@ import BOOTSTRAP from {}; writeln!( result, " {key}: {{ module: {identifier}, chunks: {chunks_identifier} }},", - key = stringify_js(key), + key = StringifyJs(key), )?; } result += " },"; diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index e5caccb9c3ab0c..382fde7c0f70d6 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -42,6 +42,7 @@ pub fn register() { turbo_tasks::register(); turbo_tasks_fs::register(); turbo_tasks_fetch::register(); + turbopack_dev::register(); turbopack_dev_server::register(); turbopack_node::register(); turbopack::register(); diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index 2ed2fecca3b91e..5d61e484973244 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -15,13 +15,14 @@ use turbopack::{ ModuleAssetContextVc, }; use turbopack_core::{ - chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, + chunk::ChunkingContextVc, compile_time_defines, compile_time_info::{CompileTimeDefinesVc, CompileTimeInfo, CompileTimeInfoVc}, context::AssetContextVc, environment::{BrowserEnvironment, EnvironmentIntention, EnvironmentVc, ExecutionEnvironment}, resolve::{parse::RequestVc, pattern::Pattern}, }; +use turbopack_dev::DevChunkingContextVc; use turbopack_env::ProcessEnvAssetVc; use turbopack_node::execution_context::ExecutionContextVc; diff --git a/packages/next-swc/crates/next-core/src/next_client/transition.rs b/packages/next-swc/crates/next-core/src/next_client/transition.rs index 1e49c2d02ee41c..4ba66d7c83a91f 100644 --- a/packages/next-swc/crates/next-core/src/next_client/transition.rs +++ b/packages/next-swc/crates/next-core/src/next_client/transition.rs @@ -1,7 +1,6 @@ use anyhow::Result; use indexmap::indexmap; use turbo_tasks::{primitives::OptionStringVc, Value}; -use turbo_tasks_fs::FileSystemPathVc; use turbopack::{ ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, module_options::ModuleOptionsContextVc, @@ -10,7 +9,9 @@ use turbopack::{ ModuleAssetContextVc, }; use turbopack_core::{ - asset::AssetVc, chunk::ChunkingContextVc, compile_time_info::CompileTimeInfoVc, + asset::AssetVc, + chunk::{ChunkingContext, ChunkingContextVc}, + compile_time_info::CompileTimeInfoVc, context::AssetContext, }; use turbopack_ecmascript::{ @@ -33,7 +34,6 @@ pub struct NextClientTransition { pub client_module_options_context: ModuleOptionsContextVc, pub client_resolve_options_context: ResolveOptionsContextVc, pub client_chunking_context: ChunkingContextVc, - pub server_root: FileSystemPathVc, pub runtime_entries: RuntimeEntriesVc, } @@ -99,9 +99,10 @@ impl Transition for NextClientTransition { let asset = ChunkGroupFilesAsset { asset: asset.into(), + // This ensures that the chunk group files asset will strip out the _next prefix from + // all chunk paths, which is what the Next.js renderer code expects. + client_root: self.client_chunking_context.output_root().join("_next"), chunking_context: self.client_chunking_context, - base_path: self.server_root.join("_next"), - server_root: self.server_root, runtime_entries: Some(runtime_entries), }; diff --git a/packages/next-swc/crates/next-core/src/next_client_chunks/in_chunking_context_asset.rs b/packages/next-swc/crates/next-core/src/next_client_chunks/in_chunking_context_asset.rs index 6e62d29a88c624..25bc5552f8351b 100644 --- a/packages/next-swc/crates/next-core/src/next_client_chunks/in_chunking_context_asset.rs +++ b/packages/next-swc/crates/next-core/src/next_client_chunks/in_chunking_context_asset.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{bail, Result}; use turbo_tasks::{primitives::StringVc, Value}; use turbopack::ecmascript::chunk::{ EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkVc, @@ -13,6 +13,7 @@ use turbopack_core::{ ident::AssetIdentVc, reference::AssetReferencesVc, }; +use turbopack_ecmascript::chunk::EcmascriptChunkingContextVc; #[turbo_tasks::function] fn modifier() -> StringVc { @@ -58,8 +59,14 @@ impl ChunkableAsset for InChunkingContextAsset { #[turbo_tasks::value_impl] impl EcmascriptChunkPlaceable for InChunkingContextAsset { #[turbo_tasks::function] - fn as_chunk_item(&self, _context: ChunkingContextVc) -> EcmascriptChunkItemVc { - self.asset.as_chunk_item(self.chunking_context) + async fn as_chunk_item( + &self, + _context: EcmascriptChunkingContextVc, + ) -> Result { + let Some(chunking_context) = EcmascriptChunkingContextVc::resolve_from(&self.chunking_context).await? else { + bail!("chunking context is not an EcmascriptChunkingContext") + }; + Ok(self.asset.as_chunk_item(chunking_context)) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/next_client_chunks/with_chunks.rs b/packages/next-swc/crates/next-core/src/next_client_chunks/with_chunks.rs index 502b96f5e9d62b..fdbe5a99f59427 100644 --- a/packages/next-swc/crates/next-core/src/next_client_chunks/with_chunks.rs +++ b/packages/next-swc/crates/next-core/src/next_client_chunks/with_chunks.rs @@ -2,13 +2,10 @@ use anyhow::{bail, Result}; use indoc::formatdoc; use turbo_tasks::{primitives::StringVc, TryJoinIterExt, Value}; use turbo_tasks_fs::FileSystemPathVc; -use turbopack::ecmascript::{ - chunk::{ - EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, - EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, - EcmascriptChunkVc, EcmascriptExports, EcmascriptExportsVc, - }, - utils::stringify_js, +use turbopack::ecmascript::chunk::{ + EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, + EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkVc, + EcmascriptExports, EcmascriptExportsVc, }; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc}, @@ -20,7 +17,7 @@ use turbopack_core::{ ident::AssetIdentVc, reference::AssetReferencesVc, }; -use turbopack_ecmascript::utils::stringify_js_pretty; +use turbopack_ecmascript::{chunk::EcmascriptChunkingContextVc, utils::StringifyJs}; #[turbo_tasks::function] fn modifier() -> StringVc { @@ -79,7 +76,7 @@ impl EcmascriptChunkPlaceable for WithChunksAsset { #[turbo_tasks::function] async fn as_chunk_item( self_vc: WithChunksAssetVc, - context: ChunkingContextVc, + context: EcmascriptChunkingContextVc, ) -> Result { Ok(WithChunksChunkItem { context, @@ -113,20 +110,24 @@ impl WithChunksAssetVc { #[turbo_tasks::value] struct WithChunksChunkItem { - context: ChunkingContextVc, + context: EcmascriptChunkingContextVc, inner: WithChunksAssetVc, } #[turbo_tasks::value_impl] impl EcmascriptChunkItem for WithChunksChunkItem { #[turbo_tasks::function] - fn chunking_context(&self) -> ChunkingContextVc { + fn chunking_context(&self) -> EcmascriptChunkingContextVc { self.context } #[turbo_tasks::function] async fn content(&self) -> Result { let inner = self.inner.await?; + let Some(inner_chunking_context) = EcmascriptChunkingContextVc::resolve_from(inner.chunking_context).await? else { + bail!("the chunking context is not an EcmascriptChunkingContextVc"); + }; + let group = self.inner.chunk_group(); let chunks = group.chunks().await?; let server_root = inner.server_root.await?; @@ -144,25 +145,24 @@ impl EcmascriptChunkItem for WithChunksChunkItem { client_chunks.push(serde_json::Value::String(path.to_string())); } } - let module_id = stringify_js( - &*inner - .asset - .as_chunk_item(inner.chunking_context) - .id() - .await?, - ); + let module_id = &*inner + .asset + .as_chunk_item(inner_chunking_context) + .id() + .await?; Ok(EcmascriptChunkItemContent { inner_code: formatdoc! { r#" __turbopack_esm__({{ default: () => {}, - chunks: () => {}, + chunks: () => chunks, chunkListPath: () => {}, }}); + const chunks = {:#}; "#, - module_id, - stringify_js_pretty(&client_chunks), - stringify_js(&chunk_list_path), + StringifyJs(&module_id), + StringifyJs(&chunk_list_path), + StringifyJs(&client_chunks), } .into(), ..Default::default() diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs index 563ef462073126..56d6a9dcbb30c9 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{Context, Result}; use turbo_tasks::{primitives::StringVc, Value}; use turbopack::ecmascript::chunk::{ EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkVc, @@ -13,6 +13,7 @@ use turbopack_core::{ ident::AssetIdentVc, reference::AssetReferencesVc, }; +use turbopack_ecmascript::chunk::EcmascriptChunkingContextVc; #[turbo_tasks::function] fn modifier() -> StringVc { @@ -63,8 +64,18 @@ impl ChunkableAsset for WithChunkingContextScopeAsset { #[turbo_tasks::value_impl] impl EcmascriptChunkPlaceable for WithChunkingContextScopeAsset { #[turbo_tasks::function] - fn as_chunk_item(&self, context: ChunkingContextVc) -> EcmascriptChunkItemVc { - self.asset.as_chunk_item(context.with_layer(&self.layer)) + async fn as_chunk_item( + &self, + context: EcmascriptChunkingContextVc, + ) -> Result { + Ok(self.asset.as_chunk_item( + EcmascriptChunkingContextVc::resolve_from(context.with_layer(&self.layer)) + .await? + .context( + "ChunkingContextVc::with_layer should not return a different kind of chunking \ + context", + )?, + )) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs index 98252cf1fecc86..038d696114c0ea 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs @@ -1,14 +1,11 @@ -use anyhow::Result; +use anyhow::{Context, Result}; use indoc::formatdoc; use turbo_tasks::{primitives::StringVc, Value, ValueToString, ValueToStringVc}; use turbo_tasks_fs::FileSystemPathVc; -use turbopack::ecmascript::{ - chunk::{ - EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, - EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, - EcmascriptChunkVc, EcmascriptExports, EcmascriptExportsVc, - }, - utils::stringify_js, +use turbopack::ecmascript::chunk::{ + EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, + EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkVc, + EcmascriptExports, EcmascriptExportsVc, }; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc}, @@ -21,7 +18,7 @@ use turbopack_core::{ reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, resolve::{ResolveResult, ResolveResultVc}, }; -use turbopack_ecmascript::utils::stringify_js_pretty; +use turbopack_ecmascript::{chunk::EcmascriptChunkingContextVc, utils::StringifyJs}; #[turbo_tasks::function] fn modifier() -> StringVc { @@ -76,16 +73,21 @@ impl ChunkableAsset for WithClientChunksAsset { #[turbo_tasks::value_impl] impl EcmascriptChunkPlaceable for WithClientChunksAsset { #[turbo_tasks::function] - fn as_chunk_item( + async fn as_chunk_item( self_vc: WithClientChunksAssetVc, - context: ChunkingContextVc, - ) -> EcmascriptChunkItemVc { - WithClientChunksChunkItem { - context: context.with_layer("rsc"), + context: EcmascriptChunkingContextVc, + ) -> Result { + Ok(WithClientChunksChunkItem { + context: EcmascriptChunkingContextVc::resolve_from(context.with_layer("rsc")) + .await? + .context( + "ChunkingContextVc::with_layer should not return a different kind of chunking \ + context", + )?, inner: self_vc, } .cell() - .into() + .into()) } #[turbo_tasks::function] @@ -97,14 +99,14 @@ impl EcmascriptChunkPlaceable for WithClientChunksAsset { #[turbo_tasks::value] struct WithClientChunksChunkItem { - context: ChunkingContextVc, + context: EcmascriptChunkingContextVc, inner: WithClientChunksAssetVc, } #[turbo_tasks::value_impl] impl EcmascriptChunkItem for WithClientChunksChunkItem { #[turbo_tasks::function] - fn chunking_context(&self) -> ChunkingContextVc { + fn chunking_context(&self) -> EcmascriptChunkingContextVc { self.context } @@ -113,7 +115,7 @@ impl EcmascriptChunkItem for WithClientChunksChunkItem { let inner = self.inner.await?; let group = ChunkGroupVc::from_asset( inner.asset.into(), - self.context, + self.context.into(), Value::new(AvailabilityInfo::Root { current_availability_root: inner.asset.into(), }), @@ -140,7 +142,7 @@ impl EcmascriptChunkItem for WithClientChunksChunkItem { } } - let module_id = stringify_js(&*inner.asset.as_chunk_item(self.context).id().await?); + let module_id = inner.asset.as_chunk_item(self.context).id().await?; Ok(EcmascriptChunkItemContent { inner_code: formatdoc!( // We store the chunks in a binding, otherwise a new array would be created every @@ -150,10 +152,10 @@ impl EcmascriptChunkItem for WithClientChunksChunkItem { default: () => __turbopack_import__({}), chunks: () => chunks, }}); - const chunks = {}; + const chunks = {:#}; "#, - module_id, - stringify_js_pretty(&client_chunks), + StringifyJs(&module_id), + StringifyJs(&client_chunks), ) .into(), ..Default::default() diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index 1df9a67e9275db..a0abf4dc1f1254 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -13,6 +13,7 @@ use turbopack::evaluate_context::node_evaluate_asset_context; use turbopack_core::{ asset::Asset, changed::any_content_changed, + chunk::ChunkingContext, context::AssetContext, ident::AssetIdentVc, issue::IssueContextExt, @@ -558,7 +559,7 @@ pub async fn load_next_config_internal( ) -> Result { let ExecutionContext { project_path, - intermediate_output_path, + chunking_context, env, } = *execution_context.await?; let mut import_map = ImportMap::default(); @@ -587,14 +588,14 @@ pub async fn load_next_config_internal( next_asset("entry/config/next.js"), Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), ); + let config_value = evaluate( - project_path, load_next_config_asset, project_path, env, config_asset.map_or_else(|| AssetIdentVc::from_path(project_path), |c| c.ident()), context, - intermediate_output_path, + chunking_context.with_layer("next_config"), None, vec![], config_changed, diff --git a/packages/next-swc/crates/next-core/src/next_edge/transition.rs b/packages/next-swc/crates/next-core/src/next_edge/transition.rs index b761c54684b6d8..b1777ed886d91b 100644 --- a/packages/next-swc/crates/next-core/src/next_edge/transition.rs +++ b/packages/next-swc/crates/next-core/src/next_edge/transition.rs @@ -16,7 +16,7 @@ use turbopack_core::{ virtual_asset::VirtualAssetVc, }; use turbopack_ecmascript::{ - chunk_group_files_asset::ChunkGroupFilesAsset, utils::stringify_js, EcmascriptInputTransform, + chunk_group_files_asset::ChunkGroupFilesAsset, utils::StringifyJs, EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, InnerAssetsVc, }; @@ -85,8 +85,8 @@ impl Transition for NextEdgeTransition { let mut new_content = RopeBuilder::from( format!( "const NAME={};\nconst PAGE = {};\n", - stringify_js(&self.entry_name), - stringify_js(path) + StringifyJs(&self.entry_name), + StringifyJs(path) ) .into_bytes(), ); @@ -112,9 +112,8 @@ impl Transition for NextEdgeTransition { let asset = ChunkGroupFilesAsset { asset: new_asset.into(), + client_root: self.output_path, chunking_context: self.edge_chunking_context, - base_path: self.output_path, - server_root: self.output_path, runtime_entries: None, }; diff --git a/packages/next-swc/crates/next-core/src/next_font/google/mod.rs b/packages/next-swc/crates/next-core/src/next_font/google/mod.rs index 559140e1313385..e250ffd563c4a1 100644 --- a/packages/next-swc/crates/next-core/src/next_font/google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font/google/mod.rs @@ -436,7 +436,6 @@ async fn get_mock_stylesheet( let root = mock_fs.root(); let val = evaluate( - loader_path, mocked_response_asset, root, env, diff --git a/packages/next-swc/crates/next-core/src/page_loader.rs b/packages/next-swc/crates/next-core/src/page_loader.rs index 1fe1218016a341..15fc2c154c4e81 100644 --- a/packages/next-swc/crates/next-core/src/page_loader.rs +++ b/packages/next-swc/crates/next-core/src/page_loader.rs @@ -15,7 +15,7 @@ use turbopack_core::{ }; use turbopack_dev_server::source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}; use turbopack_ecmascript::{ - utils::stringify_js, EcmascriptInputTransform, EcmascriptInputTransformsVc, + utils::StringifyJs, EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, InnerAssetsVc, }; @@ -60,7 +60,7 @@ impl PageLoaderAssetVc { writeln!( result, "const PAGE_PATH = {};\n", - stringify_js(&format!("/{}", &*this.pathname.await?)) + StringifyJs(&format_args!("/{}", &*this.pathname.await?)) )?; let page_loader_path = next_js_file_path("entry/page-loader.ts"); @@ -137,9 +137,9 @@ impl Asset for PageLoaderAsset { .collect(); let content = format!( - "__turbopack_load_page_chunks__({}, {})\n", - stringify_js(&this.pathname.await?), - stringify_js(&chunk_paths) + "__turbopack_load_page_chunks__({}, {:#})\n", + StringifyJs(&this.pathname.await?), + StringifyJs(&chunk_paths) ); Ok(AssetContentVc::from(File::from(content))) diff --git a/packages/next-swc/crates/next-core/src/page_source.rs b/packages/next-swc/crates/next-core/src/page_source.rs index a83682aacdc113..8b0911d8f4dfec 100644 --- a/packages/next-swc/crates/next-core/src/page_source.rs +++ b/packages/next-swc/crates/next-core/src/page_source.rs @@ -11,12 +11,13 @@ use turbo_tasks_fs::{FileContent, FileSystemPathVc}; use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc}; use turbopack_core::{ asset::AssetVc, - chunk::{dev::DevChunkingContextVc, ChunkingContextVc}, + chunk::ChunkingContextVc, context::{AssetContext, AssetContextVc}, environment::{EnvironmentIntention, ServerAddrVc}, reference_type::{EntryReferenceSubType, ReferenceType}, source_asset::SourceAssetVc, }; +use turbopack_dev::DevChunkingContextVc; use turbopack_dev_server::{ html::DevHtmlAssetVc, source::{ @@ -123,7 +124,6 @@ pub async fn create_page_source( client_module_options_context, client_resolve_options_context, client_compile_time_info, - server_root, runtime_entries: client_runtime_entries, } .cell() diff --git a/packages/next-swc/crates/next-core/src/router.rs b/packages/next-swc/crates/next-core/src/router.rs index 420d053cf8a47d..55ba662ba1296f 100644 --- a/packages/next-swc/crates/next-core/src/router.rs +++ b/packages/next-swc/crates/next-core/src/router.rs @@ -13,7 +13,7 @@ use turbopack::{evaluate_context::node_evaluate_asset_context, transition::Trans use turbopack_core::{ asset::AssetVc, changed::any_content_changed, - chunk::dev::DevChunkingContextVc, + chunk::ChunkingContext, context::{AssetContext, AssetContextVc}, environment::{EnvironmentIntention::Middleware, ServerAddrVc}, ident::AssetIdentVc, @@ -23,6 +23,7 @@ use turbopack_core::{ source_asset::SourceAssetVc, virtual_asset::VirtualAssetVc, }; +use turbopack_dev::DevChunkingContextVc; use turbopack_ecmascript::{ EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, InnerAssetsVc, OptionEcmascriptModuleAssetVc, @@ -354,10 +355,9 @@ async fn route_internal( ) -> Result { let ExecutionContext { project_path, - intermediate_output_path, + chunking_context, env, } = *execution_context.await?; - let intermediate_output_path = intermediate_output_path.join("router"); let context = node_evaluate_asset_context( project_path, @@ -365,7 +365,7 @@ async fn route_internal( Some(edge_transition_map( server_addr, project_path, - intermediate_output_path, + chunking_context.output_root(), next_config, execution_context, )), @@ -382,13 +382,12 @@ async fn route_internal( bail!("Next.js requires a disk path to check for valid routes"); }; let result = evaluate( - project_path, router_asset, project_path, env, AssetIdentVc::from_path(project_path), context, - intermediate_output_path, + chunking_context.with_layer("router"), None, vec![ JsonValueVc::cell(request), diff --git a/packages/next-swc/crates/next-core/src/runtime.rs b/packages/next-swc/crates/next-core/src/runtime.rs index 77c998e822ec63..67181ca203d03c 100644 --- a/packages/next-swc/crates/next-core/src/runtime.rs +++ b/packages/next-swc/crates/next-core/src/runtime.rs @@ -18,7 +18,7 @@ pub async fn resolve_runtime_request( bail!("turbopack runtime asset is not placeable") } } else { - // The @vercel/turbopack-runtime module is not installed. + // The @vercel/turbopack-dev-runtime module is not installed. bail!("could not resolve the `{}` module", runtime_request_path) } } diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-54f34f.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-7fb4cb.txt similarity index 80% rename from packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-54f34f.txt rename to packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-7fb4cb.txt index c0778f339087a8..0377b6c1d6b3b2 100644 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-54f34f.txt +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-7fb4cb.txt @@ -3,7 +3,7 @@ PlainIssue { context: "[project]/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/pages/hello.emit", category: "loaders", title: "Issue while running loader", - description: "Error: Error!\n at module.exports (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/node_modules/emit-loader/index.js:4:18)\n at LOADER_EXECUTION (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4134)\n at runSyncOrAsync (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4145)\n at iterateNormalLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5782)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5426)\n at readResource (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts_fa48d1._.js:55:17)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:6160)\n at processResource (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5308)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4667)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4764)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4896)\n at handleResult (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:1424)\n at loadLoader (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:963)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4794)\n at runLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:8590)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts_fa48d1._.js:35:9)\n at \n at Module.transform (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts_fa48d1._.js:28:12)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]__c3ef78._.js:13:212)\n at Module.run (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_ipc_evaluate.ts_f5e151._.js:172:45)\n", + description: "Error: Error!\n at module.exports (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/node_modules/emit-loader/index.js:4:18)\n at LOADER_EXECUTION (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4134)\n at runSyncOrAsync (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4145)\n at iterateNormalLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5782)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5426)\n at readResource (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_transforms_webpack-loaders.ts_59baa9._.js:55:17)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:6160)\n at processResource (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5308)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4667)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4764)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4896)\n at handleResult (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:1424)\n at loadLoader (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:963)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4794)\n at runLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:8590)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_transforms_webpack-loaders.ts_59baa9._.js:35:9)\n at \n at Module.transform (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_transforms_webpack-loaders.ts_59baa9._.js:28:12)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]__6b13f0._.js:13:229)\n at Module.run (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_ipc_evaluate.ts_7910c7._.js:172:45)\n", detail: "", documentation_link: "", source: None, diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-873d9c.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-e84abe.txt similarity index 80% rename from packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-873d9c.txt rename to packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-e84abe.txt index fdca80ecd975bd..bf53e85959bfe1 100644 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-873d9c.txt +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/issues/Issue while running loader-e84abe.txt @@ -3,7 +3,7 @@ PlainIssue { context: "[project]/packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/pages/hello.emit", category: "loaders", title: "Issue while running loader", - description: "Error: Warning!\n at module.exports (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/node_modules/emit-loader/index.js:2:20)\n at LOADER_EXECUTION (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4134)\n at runSyncOrAsync (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4145)\n at iterateNormalLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5782)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5426)\n at readResource (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts_fa48d1._.js:55:17)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:6160)\n at processResource (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5308)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4667)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4764)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4896)\n at handleResult (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:1424)\n at loadLoader (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:963)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4794)\n at runLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:8590)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts_fa48d1._.js:35:9)\n at \n at Module.transform (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts_fa48d1._.js:28:12)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]__c3ef78._.js:13:212)\n at Module.run (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_ipc_evaluate.ts_f5e151._.js:172:45)\n", + description: "Error: Warning!\n at module.exports (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/node_modules/emit-loader/index.js:2:20)\n at LOADER_EXECUTION (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4134)\n at runSyncOrAsync (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4145)\n at iterateNormalLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5782)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5426)\n at readResource (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_transforms_webpack-loaders.ts_59baa9._.js:55:17)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:6160)\n at processResource (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:5308)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4667)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4764)\n at (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4896)\n at handleResult (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:1424)\n at loadLoader (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:963)\n at iteratePitchingLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:4794)\n at runLoaders (packages/next/dist/compiled/loader-runner/LoaderRunner.js:1:8590)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_transforms_webpack-loaders.ts_59baa9._.js:35:9)\n at \n at Module.transform (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_transforms_webpack-loaders.ts_59baa9._.js:28:12)\n at (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]__6b13f0._.js:13:229)\n at Module.run (packages/next-swc/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/chunks/webpack_loaders/[turbopack-node]_ipc_evaluate.ts_7910c7._.js:172:45)\n", detail: "", documentation_link: "", source: None, diff --git a/packages/next-swc/crates/next-dev/Cargo.toml b/packages/next-swc/crates/next-dev/Cargo.toml index b7a3b778e1623e..668acc5a4fad25 100644 --- a/packages/next-swc/crates/next-dev/Cargo.toml +++ b/packages/next-swc/crates/next-dev/Cargo.toml @@ -57,8 +57,10 @@ turbo-malloc = { workspace = true, default-features = false } turbo-tasks = { workspace = true } turbo-tasks-fs = { workspace = true } turbo-tasks-memory = { workspace = true } +turbopack = { workspace = true } turbopack-cli-utils = { workspace = true } turbopack-core = { workspace = true } +turbopack-dev = { workspace = true } turbopack-dev-server = { workspace = true } turbopack-node = { workspace = true } webbrowser = { workspace = true } diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index 6ab2201a933ee5..64f0cf89a3273b 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -34,6 +34,7 @@ use turbo_tasks::{ }; use turbo_tasks_fs::{DiskFileSystemVc, FileSystem, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; +use turbopack::evaluate_context::node_build_environment; use turbopack_cli_utils::issue::{ConsoleUiVc, LogOptions}; use turbopack_core::{ environment::ServerAddr, @@ -41,6 +42,7 @@ use turbopack_core::{ resolve::{parse::RequestVc, pattern::QueryMapVc}, server_fs::ServerFileSystemVc, }; +use turbopack_dev::DevChunkingContextVc; use turbopack_dev_server::{ introspect::IntrospectionSource, source::{ @@ -274,9 +276,18 @@ async fn source( let env = load_env(project_path); let build_output_root = output_fs.root().join(".next/build"); - let execution_context = ExecutionContextVc::new(project_path, build_output_root, env); + let build_chunking_context = DevChunkingContextVc::builder( + project_path, + build_output_root, + build_output_root.join("chunks"), + build_output_root.join("assets"), + node_build_environment(), + ) + .build(); + + let execution_context = ExecutionContextVc::new(project_path, build_chunking_context, env); - let next_config = load_next_config(execution_context.join("next_config")); + let next_config = load_next_config(execution_context.with_layer("next_config")); let output_root = output_fs.root().join(".next/server"); let server_addr = ServerAddr::new(*server_addr).cell(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f4df575d7fac8..f6eab37e04e64b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -992,7 +992,7 @@ importers: '@types/react': ^18.0.26 '@types/react-dom': ^18.0.9 '@vercel/ncc': ^0.36.0 - '@vercel/turbopack-runtime': https://gitpkg.now.sh/vercel/turbo/crates/turbopack-ecmascript/js?8a8038f94 + '@vercel/turbopack-dev-runtime': https://gitpkg.now.sh/vercel/turbo/crates/turbopack-dev/js?turbopack-230321.3 anser: ^2.1.1 css.escape: ^1.5.1 find-up: ^6.3.0 @@ -1004,7 +1004,7 @@ importers: stacktrace-parser: ^0.1.10 strip-ansi: ^7.0.1 dependencies: - '@vercel/turbopack-runtime': '@gitpkg.now.sh/vercel/turbo/crates/turbopack-ecmascript/js?8a8038f94_react-refresh@0.12.0' + '@vercel/turbopack-dev-runtime': '@gitpkg.now.sh/vercel/turbo/crates/turbopack-dev/js?turbopack-230321.3_react-refresh@0.12.0' anser: 2.1.1 css.escape: 1.5.1 next: link:../../../../next @@ -25414,10 +25414,10 @@ packages: /zwitch/2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - '@gitpkg.now.sh/vercel/turbo/crates/turbopack-ecmascript/js?8a8038f94_react-refresh@0.12.0': - resolution: {tarball: https://gitpkg.now.sh/vercel/turbo/crates/turbopack-ecmascript/js?8a8038f94} - id: '@gitpkg.now.sh/vercel/turbo/crates/turbopack-ecmascript/js?8a8038f94' - name: '@vercel/turbopack-runtime' + '@gitpkg.now.sh/vercel/turbo/crates/turbopack-dev/js?turbopack-230321.3_react-refresh@0.12.0': + resolution: {tarball: https://gitpkg.now.sh/vercel/turbo/crates/turbopack-dev/js?turbopack-230321.3} + id: '@gitpkg.now.sh/vercel/turbo/crates/turbopack-dev/js?turbopack-230321.3' + name: '@vercel/turbopack-dev-runtime' version: 0.0.0 dependencies: '@next/react-refresh-utils': 13.2.4_react-refresh@0.12.0 From c04ca8df8430fc959de25dd167398bc07cfa5318 Mon Sep 17 00:00:00 2001 From: Jan Kaifer Date: Wed, 22 Mar 2023 13:01:33 +0100 Subject: [PATCH 606/672] Add more spans into OTEL instrumentation to wrap all user defined functions (#47368) - Move span wrapping rendering closer to the user code and don't add span when we have cache-hit - Add `getStaticProps` span - Add spans around API handlers (pages and app) - Add `generateMetadata` span - Clarify naming that we use `page` for entrypoints like `/path/[param]/page` or `/path/[param]/layout`. And `route` for `/path/[param]` fix NEXT-857 ([link](https://linear.app/vercel/issue/NEXT-857)) --- .github/actions/issue-labeler/lib/index.js | 9118 ++++++++++++++++- .../next/src/lib/metadata/resolve-metadata.ts | 42 +- packages/next/src/server/api-utils/node.ts | 10 +- ...te-flight-router-state-from-loader-tree.ts | 4 +- packages/next/src/server/app-render/index.tsx | 61 +- .../route-handlers/app-route-route-handler.ts | 27 +- .../next/src/server/lib/app-dir-module.ts | 14 +- .../next/src/server/lib/trace/constants.ts | 27 +- packages/next/src/server/render.tsx | 32 +- packages/next/src/shared/lib/constants.ts | 1 + .../api => api/app/[param]}/data/route.ts | 2 + .../opentelemetry/app/app/[param]/layout.tsx | 16 + .../app/app/[param]/loading/loading.tsx | 4 + .../app/app/[param]/loading/page1/page.tsx | 14 + .../app/app/[param]/loading/page2/page.tsx | 14 + .../app/app/{ => [param]}/rsc-fetch/page.tsx | 6 +- test/e2e/opentelemetry/app/app/layout.tsx | 7 - test/e2e/opentelemetry/opentelemetry.test.ts | 464 +- test/e2e/opentelemetry/package.json | 13 + .../pages/api/pages/{ => [param]}/basic.ts | 0 .../{ => [param]}/getServerSideProps.tsx | 0 .../pages/pages/[param]/getStaticProps.tsx | 17 + test/e2e/opentelemetry/pages/pages/index.tsx | 3 - .../pages/pages/params/[param].tsx | 3 - test/lib/create-next-install.js | 1 + 25 files changed, 9599 insertions(+), 301 deletions(-) rename test/e2e/opentelemetry/app/{app/api => api/app/[param]}/data/route.ts (68%) create mode 100644 test/e2e/opentelemetry/app/app/[param]/layout.tsx create mode 100644 test/e2e/opentelemetry/app/app/[param]/loading/loading.tsx create mode 100644 test/e2e/opentelemetry/app/app/[param]/loading/page1/page.tsx create mode 100644 test/e2e/opentelemetry/app/app/[param]/loading/page2/page.tsx rename test/e2e/opentelemetry/app/app/{ => [param]}/rsc-fetch/page.tsx (62%) delete mode 100644 test/e2e/opentelemetry/app/app/layout.tsx create mode 100644 test/e2e/opentelemetry/package.json rename test/e2e/opentelemetry/pages/api/pages/{ => [param]}/basic.ts (100%) rename test/e2e/opentelemetry/pages/pages/{ => [param]}/getServerSideProps.tsx (100%) create mode 100644 test/e2e/opentelemetry/pages/pages/[param]/getStaticProps.tsx delete mode 100644 test/e2e/opentelemetry/pages/pages/index.tsx delete mode 100644 test/e2e/opentelemetry/pages/pages/params/[param].tsx diff --git a/.github/actions/issue-labeler/lib/index.js b/.github/actions/issue-labeler/lib/index.js index 0c1bb23d113ab5..fc3d2508e46cb3 100644 --- a/.github/actions/issue-labeler/lib/index.js +++ b/.github/actions/issue-labeler/lib/index.js @@ -1,7 +1,9111 @@ -import{createRequire as __WEBPACK_EXTERNAL_createRequire}from"module";var __webpack_modules__={7351:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.issue=p.issueCommand=void 0;const s=r(a(2037));const i=a(5278);function issueCommand(e,p,a){const d=new Command(e,p,a);process.stdout.write(d.toString()+s.EOL)}p.issueCommand=issueCommand;function issue(e,p=""){issueCommand(e,{},p)}p.issue=issue;const o="::";class Command{constructor(e,p,a){if(!e){e="missing.command"}this.command=e;this.properties=p;this.message=a}toString(){let e=o+this.command;if(this.properties&&Object.keys(this.properties).length>0){e+=" ";let p=true;for(const a in this.properties){if(this.properties.hasOwnProperty(a)){const d=this.properties[a];if(d){if(p){p=false}else{e+=","}e+=`${a}=${escapeProperty(d)}`}}}}e+=`${o}${escapeData(this.message)}`;return e}}function escapeData(e){return i.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return i.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}},2186:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};var s=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.getIDToken=p.getState=p.saveState=p.group=p.endGroup=p.startGroup=p.info=p.notice=p.warning=p.error=p.debug=p.isDebug=p.setFailed=p.setCommandEcho=p.setOutput=p.getBooleanInput=p.getMultilineInput=p.getInput=p.addPath=p.setSecret=p.exportVariable=p.ExitCode=void 0;const i=a(7351);const o=a(717);const n=a(5278);const l=r(a(2037));const m=r(a(1017));const u=a(8041);var c;(function(e){e[e["Success"]=0]="Success";e[e["Failure"]=1]="Failure"})(c=p.ExitCode||(p.ExitCode={}));function exportVariable(e,p){const a=n.toCommandValue(p);process.env[e]=a;const d=process.env["GITHUB_ENV"]||"";if(d){return o.issueFileCommand("ENV",o.prepareKeyValueMessage(e,p))}i.issueCommand("set-env",{name:e},a)}p.exportVariable=exportVariable;function setSecret(e){i.issueCommand("add-mask",{},e)}p.setSecret=setSecret;function addPath(e){const p=process.env["GITHUB_PATH"]||"";if(p){o.issueFileCommand("PATH",e)}else{i.issueCommand("add-path",{},e)}process.env["PATH"]=`${e}${m.delimiter}${process.env["PATH"]}`}p.addPath=addPath;function getInput(e,p){const a=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(p&&p.required&&!a){throw new Error(`Input required and not supplied: ${e}`)}if(p&&p.trimWhitespace===false){return a}return a.trim()}p.getInput=getInput;function getMultilineInput(e,p){const a=getInput(e,p).split("\n").filter((e=>e!==""));if(p&&p.trimWhitespace===false){return a}return a.map((e=>e.trim()))}p.getMultilineInput=getMultilineInput;function getBooleanInput(e,p){const a=["true","True","TRUE"];const d=["false","False","FALSE"];const t=getInput(e,p);if(a.includes(t))return true;if(d.includes(t))return false;throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${e}\n`+`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``)}p.getBooleanInput=getBooleanInput;function setOutput(e,p){const a=process.env["GITHUB_OUTPUT"]||"";if(a){return o.issueFileCommand("OUTPUT",o.prepareKeyValueMessage(e,p))}process.stdout.write(l.EOL);i.issueCommand("set-output",{name:e},n.toCommandValue(p))}p.setOutput=setOutput;function setCommandEcho(e){i.issue("echo",e?"on":"off")}p.setCommandEcho=setCommandEcho;function setFailed(e){process.exitCode=c.Failure;error(e)}p.setFailed=setFailed;function isDebug(){return process.env["RUNNER_DEBUG"]==="1"}p.isDebug=isDebug;function debug(e){i.issueCommand("debug",{},e)}p.debug=debug;function error(e,p={}){i.issueCommand("error",n.toCommandProperties(p),e instanceof Error?e.toString():e)}p.error=error;function warning(e,p={}){i.issueCommand("warning",n.toCommandProperties(p),e instanceof Error?e.toString():e)}p.warning=warning;function notice(e,p={}){i.issueCommand("notice",n.toCommandProperties(p),e instanceof Error?e.toString():e)}p.notice=notice;function info(e){process.stdout.write(e+l.EOL)}p.info=info;function startGroup(e){i.issue("group",e)}p.startGroup=startGroup;function endGroup(){i.issue("endgroup")}p.endGroup=endGroup;function group(e,p){return s(this,void 0,void 0,(function*(){startGroup(e);let a;try{a=yield p()}finally{endGroup()}return a}))}p.group=group;function saveState(e,p){const a=process.env["GITHUB_STATE"]||"";if(a){return o.issueFileCommand("STATE",o.prepareKeyValueMessage(e,p))}i.issueCommand("save-state",{name:e},n.toCommandValue(p))}p.saveState=saveState;function getState(e){return process.env[`STATE_${e}`]||""}p.getState=getState;function getIDToken(e){return s(this,void 0,void 0,(function*(){return yield u.OidcClient.getIDToken(e)}))}p.getIDToken=getIDToken;var v=a(1327);Object.defineProperty(p,"summary",{enumerable:true,get:function(){return v.summary}});var h=a(1327);Object.defineProperty(p,"markdownSummary",{enumerable:true,get:function(){return h.markdownSummary}});var g=a(2981);Object.defineProperty(p,"toPosixPath",{enumerable:true,get:function(){return g.toPosixPath}});Object.defineProperty(p,"toWin32Path",{enumerable:true,get:function(){return g.toWin32Path}});Object.defineProperty(p,"toPlatformPath",{enumerable:true,get:function(){return g.toPlatformPath}})},717:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.prepareKeyValueMessage=p.issueFileCommand=void 0;const s=r(a(7147));const i=r(a(2037));const o=a(5840);const n=a(5278);function issueFileCommand(e,p){const a=process.env[`GITHUB_${e}`];if(!a){throw new Error(`Unable to find environment variable for file command ${e}`)}if(!s.existsSync(a)){throw new Error(`Missing file at path: ${a}`)}s.appendFileSync(a,`${n.toCommandValue(p)}${i.EOL}`,{encoding:"utf8"})}p.issueFileCommand=issueFileCommand;function prepareKeyValueMessage(e,p){const a=`ghadelimiter_${o.v4()}`;const d=n.toCommandValue(p);if(e.includes(a)){throw new Error(`Unexpected input: name should not contain the delimiter "${a}"`)}if(d.includes(a)){throw new Error(`Unexpected input: value should not contain the delimiter "${a}"`)}return`${e}<<${a}${i.EOL}${d}${i.EOL}${a}`}p.prepareKeyValueMessage=prepareKeyValueMessage},8041:function(e,p,a){var d=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.OidcClient=void 0;const t=a(6255);const r=a(5526);const s=a(2186);class OidcClient{static createHttpClient(e=true,p=10){const a={allowRetries:e,maxRetries:p};return new t.HttpClient("actions/oidc-client",[new r.BearerCredentialHandler(OidcClient.getRequestToken())],a)}static getRequestToken(){const e=process.env["ACTIONS_ID_TOKEN_REQUEST_TOKEN"];if(!e){throw new Error("Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable")}return e}static getIDTokenUrl(){const e=process.env["ACTIONS_ID_TOKEN_REQUEST_URL"];if(!e){throw new Error("Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable")}return e}static getCall(e){var p;return d(this,void 0,void 0,(function*(){const a=OidcClient.createHttpClient();const d=yield a.getJson(e).catch((e=>{throw new Error(`Failed to get ID Token. \n \n Error Code : ${e.statusCode}\n \n Error Message: ${e.result.message}`)}));const t=(p=d.result)===null||p===void 0?void 0:p.value;if(!t){throw new Error("Response json body do not have ID Token field")}return t}))}static getIDToken(e){return d(this,void 0,void 0,(function*(){try{let p=OidcClient.getIDTokenUrl();if(e){const a=encodeURIComponent(e);p=`${p}&audience=${a}`}s.debug(`ID token url is ${p}`);const a=yield OidcClient.getCall(p);s.setSecret(a);return a}catch(e){throw new Error(`Error message: ${e.message}`)}}))}}p.OidcClient=OidcClient},2981:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.toPlatformPath=p.toWin32Path=p.toPosixPath=void 0;const s=r(a(1017));function toPosixPath(e){return e.replace(/[\\]/g,"/")}p.toPosixPath=toPosixPath;function toWin32Path(e){return e.replace(/[/]/g,"\\")}p.toWin32Path=toWin32Path;function toPlatformPath(e){return e.replace(/[/\\]/g,s.sep)}p.toPlatformPath=toPlatformPath},1327:function(e,p,a){var d=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.summary=p.markdownSummary=p.SUMMARY_DOCS_URL=p.SUMMARY_ENV_VAR=void 0;const t=a(2037);const r=a(7147);const{access:s,appendFile:i,writeFile:o}=r.promises;p.SUMMARY_ENV_VAR="GITHUB_STEP_SUMMARY";p.SUMMARY_DOCS_URL="https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary";class Summary{constructor(){this._buffer=""}filePath(){return d(this,void 0,void 0,(function*(){if(this._filePath){return this._filePath}const e=process.env[p.SUMMARY_ENV_VAR];if(!e){throw new Error(`Unable to find environment variable for $${p.SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.`)}try{yield s(e,r.constants.R_OK|r.constants.W_OK)}catch(p){throw new Error(`Unable to access summary file: '${e}'. Check if the file has correct read/write permissions.`)}this._filePath=e;return this._filePath}))}wrap(e,p,a={}){const d=Object.entries(a).map((([e,p])=>` ${e}="${p}"`)).join("");if(!p){return`<${e}${d}>`}return`<${e}${d}>${p}`}write(e){return d(this,void 0,void 0,(function*(){const p=!!(e===null||e===void 0?void 0:e.overwrite);const a=yield this.filePath();const d=p?o:i;yield d(a,this._buffer,{encoding:"utf8"});return this.emptyBuffer()}))}clear(){return d(this,void 0,void 0,(function*(){return this.emptyBuffer().write({overwrite:true})}))}stringify(){return this._buffer}isEmptyBuffer(){return this._buffer.length===0}emptyBuffer(){this._buffer="";return this}addRaw(e,p=false){this._buffer+=e;return p?this.addEOL():this}addEOL(){return this.addRaw(t.EOL)}addCodeBlock(e,p){const a=Object.assign({},p&&{lang:p});const d=this.wrap("pre",this.wrap("code",e),a);return this.addRaw(d).addEOL()}addList(e,p=false){const a=p?"ol":"ul";const d=e.map((e=>this.wrap("li",e))).join("");const t=this.wrap(a,d);return this.addRaw(t).addEOL()}addTable(e){const p=e.map((e=>{const p=e.map((e=>{if(typeof e==="string"){return this.wrap("td",e)}const{header:p,data:a,colspan:d,rowspan:t}=e;const r=p?"th":"td";const s=Object.assign(Object.assign({},d&&{colspan:d}),t&&{rowspan:t});return this.wrap(r,a,s)})).join("");return this.wrap("tr",p)})).join("");const a=this.wrap("table",p);return this.addRaw(a).addEOL()}addDetails(e,p){const a=this.wrap("details",this.wrap("summary",e)+p);return this.addRaw(a).addEOL()}addImage(e,p,a){const{width:d,height:t}=a||{};const r=Object.assign(Object.assign({},d&&{width:d}),t&&{height:t});const s=this.wrap("img",null,Object.assign({src:e,alt:p},r));return this.addRaw(s).addEOL()}addHeading(e,p){const a=`h${p}`;const d=["h1","h2","h3","h4","h5","h6"].includes(a)?a:"h1";const t=this.wrap(d,e);return this.addRaw(t).addEOL()}addSeparator(){const e=this.wrap("hr",null);return this.addRaw(e).addEOL()}addBreak(){const e=this.wrap("br",null);return this.addRaw(e).addEOL()}addQuote(e,p){const a=Object.assign({},p&&{cite:p});const d=this.wrap("blockquote",e,a);return this.addRaw(d).addEOL()}addLink(e,p){const a=this.wrap("a",e,{href:p});return this.addRaw(a).addEOL()}}const n=new Summary;p.markdownSummary=n;p.summary=n},5278:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p.toCommandProperties=p.toCommandValue=void 0;function toCommandValue(e){if(e===null||e===undefined){return""}else if(typeof e==="string"||e instanceof String){return e}return JSON.stringify(e)}p.toCommandValue=toCommandValue;function toCommandProperties(e){if(!Object.keys(e).length){return{}}return{title:e.title,file:e.file,line:e.startLine,endLine:e.endLine,col:e.startColumn,endColumn:e.endColumn}}p.toCommandProperties=toCommandProperties},4087:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p.Context=void 0;const d=a(7147);const t=a(2037);class Context{constructor(){var e,p,a;this.payload={};if(process.env.GITHUB_EVENT_PATH){if(d.existsSync(process.env.GITHUB_EVENT_PATH)){this.payload=JSON.parse(d.readFileSync(process.env.GITHUB_EVENT_PATH,{encoding:"utf8"}))}else{const e=process.env.GITHUB_EVENT_PATH;process.stdout.write(`GITHUB_EVENT_PATH ${e} does not exist${t.EOL}`)}}this.eventName=process.env.GITHUB_EVENT_NAME;this.sha=process.env.GITHUB_SHA;this.ref=process.env.GITHUB_REF;this.workflow=process.env.GITHUB_WORKFLOW;this.action=process.env.GITHUB_ACTION;this.actor=process.env.GITHUB_ACTOR;this.job=process.env.GITHUB_JOB;this.runNumber=parseInt(process.env.GITHUB_RUN_NUMBER,10);this.runId=parseInt(process.env.GITHUB_RUN_ID,10);this.apiUrl=(e=process.env.GITHUB_API_URL)!==null&&e!==void 0?e:`https://api.github.com`;this.serverUrl=(p=process.env.GITHUB_SERVER_URL)!==null&&p!==void 0?p:`https://github.com`;this.graphqlUrl=(a=process.env.GITHUB_GRAPHQL_URL)!==null&&a!==void 0?a:`https://api.github.com/graphql`}get issue(){const e=this.payload;return Object.assign(Object.assign({},this.repo),{number:(e.issue||e.pull_request||e).number})}get repo(){if(process.env.GITHUB_REPOSITORY){const[e,p]=process.env.GITHUB_REPOSITORY.split("/");return{owner:e,repo:p}}if(this.payload.repository){return{owner:this.payload.repository.owner.login,repo:this.payload.repository.name}}throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'")}}p.Context=Context},5438:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.getOctokit=p.context=void 0;const s=r(a(4087));const i=a(3030);p.context=new s.Context;function getOctokit(e,p,...a){const d=i.GitHub.plugin(...a);return new d(i.getOctokitOptions(e,p))}p.getOctokit=getOctokit},7914:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.getApiBaseUrl=p.getProxyAgent=p.getAuthString=void 0;const s=r(a(6255));function getAuthString(e,p){if(!e&&!p.auth){throw new Error("Parameter token or opts.auth is required")}else if(e&&p.auth){throw new Error("Parameters token and opts.auth may not both be specified")}return typeof p.auth==="string"?p.auth:`token ${e}`}p.getAuthString=getAuthString;function getProxyAgent(e){const p=new s.HttpClient;return p.getAgent(e)}p.getProxyAgent=getProxyAgent;function getApiBaseUrl(){return process.env["GITHUB_API_URL"]||"https://api.github.com"}p.getApiBaseUrl=getApiBaseUrl},3030:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};Object.defineProperty(p,"__esModule",{value:true});p.getOctokitOptions=p.GitHub=p.defaults=p.context=void 0;const s=r(a(4087));const i=r(a(7914));const o=a(6762);const n=a(3044);const l=a(4193);p.context=new s.Context;const m=i.getApiBaseUrl();p.defaults={baseUrl:m,request:{agent:i.getProxyAgent(m)}};p.GitHub=o.Octokit.plugin(n.restEndpointMethods,l.paginateRest).defaults(p.defaults);function getOctokitOptions(e,p){const a=Object.assign({},p||{});const d=i.getAuthString(e,a);if(d){a.auth=d}return a}p.getOctokitOptions=getOctokitOptions},5526:function(e,p){var a=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.PersonalAccessTokenCredentialHandler=p.BearerCredentialHandler=p.BasicCredentialHandler=void 0;class BasicCredentialHandler{constructor(e,p){this.username=e;this.password=p}prepareRequest(e){if(!e.headers){throw Error("The request has no headers")}e.headers["Authorization"]=`Basic ${Buffer.from(`${this.username}:${this.password}`).toString("base64")}`}canHandleAuthentication(){return false}handleAuthentication(){return a(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}}p.BasicCredentialHandler=BasicCredentialHandler;class BearerCredentialHandler{constructor(e){this.token=e}prepareRequest(e){if(!e.headers){throw Error("The request has no headers")}e.headers["Authorization"]=`Bearer ${this.token}`}canHandleAuthentication(){return false}handleAuthentication(){return a(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}}p.BearerCredentialHandler=BearerCredentialHandler;class PersonalAccessTokenCredentialHandler{constructor(e){this.token=e}prepareRequest(e){if(!e.headers){throw Error("The request has no headers")}e.headers["Authorization"]=`Basic ${Buffer.from(`PAT:${this.token}`).toString("base64")}`}canHandleAuthentication(){return false}handleAuthentication(){return a(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}}p.PersonalAccessTokenCredentialHandler=PersonalAccessTokenCredentialHandler},6255:function(e,p,a){var d=this&&this.__createBinding||(Object.create?function(e,p,a,d){if(d===undefined)d=a;Object.defineProperty(e,d,{enumerable:true,get:function(){return p[a]}})}:function(e,p,a,d){if(d===undefined)d=a;e[d]=p[a]});var t=this&&this.__setModuleDefault||(Object.create?function(e,p){Object.defineProperty(e,"default",{enumerable:true,value:p})}:function(e,p){e["default"]=p});var r=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var p={};if(e!=null)for(var a in e)if(a!=="default"&&Object.hasOwnProperty.call(e,a))d(p,e,a);t(p,e);return p};var s=this&&this.__awaiter||function(e,p,a,d){function adopt(e){return e instanceof a?e:new a((function(p){p(e)}))}return new(a||(a=Promise))((function(a,t){function fulfilled(e){try{step(d.next(e))}catch(e){t(e)}}function rejected(e){try{step(d["throw"](e))}catch(e){t(e)}}function step(e){e.done?a(e.value):adopt(e.value).then(fulfilled,rejected)}step((d=d.apply(e,p||[])).next())}))};Object.defineProperty(p,"__esModule",{value:true});p.HttpClient=p.isHttps=p.HttpClientResponse=p.HttpClientError=p.getProxyUrl=p.MediaTypes=p.Headers=p.HttpCodes=void 0;const i=r(a(3685));const o=r(a(5687));const n=r(a(9835));const l=r(a(4294));var m;(function(e){e[e["OK"]=200]="OK";e[e["MultipleChoices"]=300]="MultipleChoices";e[e["MovedPermanently"]=301]="MovedPermanently";e[e["ResourceMoved"]=302]="ResourceMoved";e[e["SeeOther"]=303]="SeeOther";e[e["NotModified"]=304]="NotModified";e[e["UseProxy"]=305]="UseProxy";e[e["SwitchProxy"]=306]="SwitchProxy";e[e["TemporaryRedirect"]=307]="TemporaryRedirect";e[e["PermanentRedirect"]=308]="PermanentRedirect";e[e["BadRequest"]=400]="BadRequest";e[e["Unauthorized"]=401]="Unauthorized";e[e["PaymentRequired"]=402]="PaymentRequired";e[e["Forbidden"]=403]="Forbidden";e[e["NotFound"]=404]="NotFound";e[e["MethodNotAllowed"]=405]="MethodNotAllowed";e[e["NotAcceptable"]=406]="NotAcceptable";e[e["ProxyAuthenticationRequired"]=407]="ProxyAuthenticationRequired";e[e["RequestTimeout"]=408]="RequestTimeout";e[e["Conflict"]=409]="Conflict";e[e["Gone"]=410]="Gone";e[e["TooManyRequests"]=429]="TooManyRequests";e[e["InternalServerError"]=500]="InternalServerError";e[e["NotImplemented"]=501]="NotImplemented";e[e["BadGateway"]=502]="BadGateway";e[e["ServiceUnavailable"]=503]="ServiceUnavailable";e[e["GatewayTimeout"]=504]="GatewayTimeout"})(m=p.HttpCodes||(p.HttpCodes={}));var u;(function(e){e["Accept"]="accept";e["ContentType"]="content-type"})(u=p.Headers||(p.Headers={}));var c;(function(e){e["ApplicationJson"]="application/json"})(c=p.MediaTypes||(p.MediaTypes={}));function getProxyUrl(e){const p=n.getProxyUrl(new URL(e));return p?p.href:""}p.getProxyUrl=getProxyUrl;const v=[m.MovedPermanently,m.ResourceMoved,m.SeeOther,m.TemporaryRedirect,m.PermanentRedirect];const h=[m.BadGateway,m.ServiceUnavailable,m.GatewayTimeout];const g=["OPTIONS","GET","DELETE","HEAD"];const w=10;const _=5;class HttpClientError extends Error{constructor(e,p){super(e);this.name="HttpClientError";this.statusCode=p;Object.setPrototypeOf(this,HttpClientError.prototype)}}p.HttpClientError=HttpClientError;class HttpClientResponse{constructor(e){this.message=e}readBody(){return s(this,void 0,void 0,(function*(){return new Promise((e=>s(this,void 0,void 0,(function*(){let p=Buffer.alloc(0);this.message.on("data",(e=>{p=Buffer.concat([p,e])}));this.message.on("end",(()=>{e(p.toString())}))}))))}))}}p.HttpClientResponse=HttpClientResponse;function isHttps(e){const p=new URL(e);return p.protocol==="https:"}p.isHttps=isHttps;class HttpClient{constructor(e,p,a){this._ignoreSslError=false;this._allowRedirects=true;this._allowRedirectDowngrade=false;this._maxRedirects=50;this._allowRetries=false;this._maxRetries=1;this._keepAlive=false;this._disposed=false;this.userAgent=e;this.handlers=p||[];this.requestOptions=a;if(a){if(a.ignoreSslError!=null){this._ignoreSslError=a.ignoreSslError}this._socketTimeout=a.socketTimeout;if(a.allowRedirects!=null){this._allowRedirects=a.allowRedirects}if(a.allowRedirectDowngrade!=null){this._allowRedirectDowngrade=a.allowRedirectDowngrade}if(a.maxRedirects!=null){this._maxRedirects=Math.max(a.maxRedirects,0)}if(a.keepAlive!=null){this._keepAlive=a.keepAlive}if(a.allowRetries!=null){this._allowRetries=a.allowRetries}if(a.maxRetries!=null){this._maxRetries=a.maxRetries}}}options(e,p){return s(this,void 0,void 0,(function*(){return this.request("OPTIONS",e,null,p||{})}))}get(e,p){return s(this,void 0,void 0,(function*(){return this.request("GET",e,null,p||{})}))}del(e,p){return s(this,void 0,void 0,(function*(){return this.request("DELETE",e,null,p||{})}))}post(e,p,a){return s(this,void 0,void 0,(function*(){return this.request("POST",e,p,a||{})}))}patch(e,p,a){return s(this,void 0,void 0,(function*(){return this.request("PATCH",e,p,a||{})}))}put(e,p,a){return s(this,void 0,void 0,(function*(){return this.request("PUT",e,p,a||{})}))}head(e,p){return s(this,void 0,void 0,(function*(){return this.request("HEAD",e,null,p||{})}))}sendStream(e,p,a,d){return s(this,void 0,void 0,(function*(){return this.request(e,p,a,d)}))}getJson(e,p={}){return s(this,void 0,void 0,(function*(){p[u.Accept]=this._getExistingOrDefaultHeader(p,u.Accept,c.ApplicationJson);const a=yield this.get(e,p);return this._processResponse(a,this.requestOptions)}))}postJson(e,p,a={}){return s(this,void 0,void 0,(function*(){const d=JSON.stringify(p,null,2);a[u.Accept]=this._getExistingOrDefaultHeader(a,u.Accept,c.ApplicationJson);a[u.ContentType]=this._getExistingOrDefaultHeader(a,u.ContentType,c.ApplicationJson);const t=yield this.post(e,d,a);return this._processResponse(t,this.requestOptions)}))}putJson(e,p,a={}){return s(this,void 0,void 0,(function*(){const d=JSON.stringify(p,null,2);a[u.Accept]=this._getExistingOrDefaultHeader(a,u.Accept,c.ApplicationJson);a[u.ContentType]=this._getExistingOrDefaultHeader(a,u.ContentType,c.ApplicationJson);const t=yield this.put(e,d,a);return this._processResponse(t,this.requestOptions)}))}patchJson(e,p,a={}){return s(this,void 0,void 0,(function*(){const d=JSON.stringify(p,null,2);a[u.Accept]=this._getExistingOrDefaultHeader(a,u.Accept,c.ApplicationJson);a[u.ContentType]=this._getExistingOrDefaultHeader(a,u.ContentType,c.ApplicationJson);const t=yield this.patch(e,d,a);return this._processResponse(t,this.requestOptions)}))}request(e,p,a,d){return s(this,void 0,void 0,(function*(){if(this._disposed){throw new Error("Client has already been disposed.")}const t=new URL(p);let r=this._prepareRequest(e,t,d);const s=this._allowRetries&&g.includes(e)?this._maxRetries+1:1;let i=0;let o;do{o=yield this.requestRaw(r,a);if(o&&o.message&&o.message.statusCode===m.Unauthorized){let e;for(const p of this.handlers){if(p.canHandleAuthentication(o)){e=p;break}}if(e){return e.handleAuthentication(this,r,a)}else{return o}}let p=this._maxRedirects;while(o.message.statusCode&&v.includes(o.message.statusCode)&&this._allowRedirects&&p>0){const s=o.message.headers["location"];if(!s){break}const i=new URL(s);if(t.protocol==="https:"&&t.protocol!==i.protocol&&!this._allowRedirectDowngrade){throw new Error("Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.")}yield o.readBody();if(i.hostname!==t.hostname){for(const e in d){if(e.toLowerCase()==="authorization"){delete d[e]}}}r=this._prepareRequest(e,i,d);o=yield this.requestRaw(r,a);p--}if(!o.message.statusCode||!h.includes(o.message.statusCode)){return o}i+=1;if(i{function callbackForResult(e,p){if(e){d(e)}else if(!p){d(new Error("Unknown error"))}else{a(p)}}this.requestRawWithCallback(e,p,callbackForResult)}))}))}requestRawWithCallback(e,p,a){if(typeof p==="string"){if(!e.options.headers){e.options.headers={}}e.options.headers["Content-Length"]=Buffer.byteLength(p,"utf8")}let d=false;function handleResult(e,p){if(!d){d=true;a(e,p)}}const t=e.httpModule.request(e.options,(e=>{const p=new HttpClientResponse(e);handleResult(undefined,p)}));let r;t.on("socket",(e=>{r=e}));t.setTimeout(this._socketTimeout||3*6e4,(()=>{if(r){r.end()}handleResult(new Error(`Request timeout: ${e.options.path}`))}));t.on("error",(function(e){handleResult(e)}));if(p&&typeof p==="string"){t.write(p,"utf8")}if(p&&typeof p!=="string"){p.on("close",(function(){t.end()}));p.pipe(t)}else{t.end()}}getAgent(e){const p=new URL(e);return this._getAgent(p)}_prepareRequest(e,p,a){const d={};d.parsedUrl=p;const t=d.parsedUrl.protocol==="https:";d.httpModule=t?o:i;const r=t?443:80;d.options={};d.options.host=d.parsedUrl.hostname;d.options.port=d.parsedUrl.port?parseInt(d.parsedUrl.port):r;d.options.path=(d.parsedUrl.pathname||"")+(d.parsedUrl.search||"");d.options.method=e;d.options.headers=this._mergeHeaders(a);if(this.userAgent!=null){d.options.headers["user-agent"]=this.userAgent}d.options.agent=this._getAgent(d.parsedUrl);if(this.handlers){for(const e of this.handlers){e.prepareRequest(d.options)}}return d}_mergeHeaders(e){if(this.requestOptions&&this.requestOptions.headers){return Object.assign({},lowercaseKeys(this.requestOptions.headers),lowercaseKeys(e||{}))}return lowercaseKeys(e||{})}_getExistingOrDefaultHeader(e,p,a){let d;if(this.requestOptions&&this.requestOptions.headers){d=lowercaseKeys(this.requestOptions.headers)[p]}return e[p]||d||a}_getAgent(e){let p;const a=n.getProxyUrl(e);const d=a&&a.hostname;if(this._keepAlive&&d){p=this._proxyAgent}if(this._keepAlive&&!d){p=this._agent}if(p){return p}const t=e.protocol==="https:";let r=100;if(this.requestOptions){r=this.requestOptions.maxSockets||i.globalAgent.maxSockets}if(a&&a.hostname){const e={maxSockets:r,keepAlive:this._keepAlive,proxy:Object.assign(Object.assign({},(a.username||a.password)&&{proxyAuth:`${a.username}:${a.password}`}),{host:a.hostname,port:a.port})};let d;const s=a.protocol==="https:";if(t){d=s?l.httpsOverHttps:l.httpsOverHttp}else{d=s?l.httpOverHttps:l.httpOverHttp}p=d(e);this._proxyAgent=p}if(this._keepAlive&&!p){const e={keepAlive:this._keepAlive,maxSockets:r};p=t?new o.Agent(e):new i.Agent(e);this._agent=p}if(!p){p=t?o.globalAgent:i.globalAgent}if(t&&this._ignoreSslError){p.options=Object.assign(p.options||{},{rejectUnauthorized:false})}return p}_performExponentialBackoff(e){return s(this,void 0,void 0,(function*(){e=Math.min(w,e);const p=_*Math.pow(2,e);return new Promise((e=>setTimeout((()=>e()),p)))}))}_processResponse(e,p){return s(this,void 0,void 0,(function*(){return new Promise(((a,d)=>s(this,void 0,void 0,(function*(){const t=e.message.statusCode||0;const r={statusCode:t,result:null,headers:{}};if(t===m.NotFound){a(r)}function dateTimeDeserializer(e,p){if(typeof p==="string"){const e=new Date(p);if(!isNaN(e.valueOf())){return e}}return p}let s;let i;try{i=yield e.readBody();if(i&&i.length>0){if(p&&p.deserializeDates){s=JSON.parse(i,dateTimeDeserializer)}else{s=JSON.parse(i)}r.result=s}r.headers=e.message.headers}catch(e){}if(t>299){let e;if(s&&s.message){e=s.message}else if(i&&i.length>0){e=i}else{e=`Failed request: (${t})`}const p=new HttpClientError(e,t);p.result=r.result;d(p)}else{a(r)}}))))}))}}p.HttpClient=HttpClient;const lowercaseKeys=e=>Object.keys(e).reduce(((p,a)=>(p[a.toLowerCase()]=e[a],p)),{})},9835:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p.checkBypass=p.getProxyUrl=void 0;function getProxyUrl(e){const p=e.protocol==="https:";if(checkBypass(e)){return undefined}const a=(()=>{if(p){return process.env["https_proxy"]||process.env["HTTPS_PROXY"]}else{return process.env["http_proxy"]||process.env["HTTP_PROXY"]}})();if(a){return new URL(a)}else{return undefined}}p.getProxyUrl=getProxyUrl;function checkBypass(e){if(!e.hostname){return false}const p=e.hostname;if(isLoopbackAddress(p)){return true}const a=process.env["no_proxy"]||process.env["NO_PROXY"]||"";if(!a){return false}let d;if(e.port){d=Number(e.port)}else if(e.protocol==="http:"){d=80}else if(e.protocol==="https:"){d=443}const t=[e.hostname.toUpperCase()];if(typeof d==="number"){t.push(`${t[0]}:${d}`)}for(const e of a.split(",").map((e=>e.trim().toUpperCase())).filter((e=>e))){if(e==="*"||t.some((p=>p===e||p.endsWith(`.${e}`)||e.startsWith(".")&&p.endsWith(`${e}`)))){return true}}return false}p.checkBypass=checkBypass;function isLoopbackAddress(e){const p=e.toLowerCase();return p==="localhost"||p.startsWith("127.")||p.startsWith("[::1]")||p.startsWith("[0:0:0:0:0:0:0:1]")}},334:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});const a=/^v1\./;const d=/^ghs_/;const t=/^ghu_/;async function auth(e){const p=e.split(/\./).length===3;const r=a.test(e)||d.test(e);const s=t.test(e);const i=p?"app":r?"installation":s?"user-to-server":"oauth";return{type:"token",token:e,tokenType:i}}function withAuthorizationPrefix(e){if(e.split(/\./).length===3){return`bearer ${e}`}return`token ${e}`}async function hook(e,p,a,d){const t=p.endpoint.merge(a,d);t.headers.authorization=withAuthorizationPrefix(e);return p(t)}const r=function createTokenAuth(e){if(!e){throw new Error("[@octokit/auth-token] No token passed to createTokenAuth")}if(typeof e!=="string"){throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string")}e=e.replace(/^(token|bearer) +/i,"");return Object.assign(auth.bind(null,e),{hook:hook.bind(null,e)})};p.createTokenAuth=r},6762:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});var d=a(5030);var t=a(3682);var r=a(6234);var s=a(8467);var i=a(334);function _objectWithoutPropertiesLoose(e,p){if(e==null)return{};var a={};var d=Object.keys(e);var t,r;for(r=0;r=0)continue;a[t]=e[t]}return a}function _objectWithoutProperties(e,p){if(e==null)return{};var a=_objectWithoutPropertiesLoose(e,p);var d,t;if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,d))continue;a[d]=e[d]}}return a}const o="3.6.0";const n=["authStrategy"];class Octokit{constructor(e={}){const p=new t.Collection;const a={baseUrl:r.request.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},e.request,{hook:p.bind(null,"request")}),mediaType:{previews:[],format:""}};a.headers["user-agent"]=[e.userAgent,`octokit-core.js/${o} ${d.getUserAgent()}`].filter(Boolean).join(" ");if(e.baseUrl){a.baseUrl=e.baseUrl}if(e.previews){a.mediaType.previews=e.previews}if(e.timeZone){a.headers["time-zone"]=e.timeZone}this.request=r.request.defaults(a);this.graphql=s.withCustomRequest(this.request).defaults(a);this.log=Object.assign({debug:()=>{},info:()=>{},warn:console.warn.bind(console),error:console.error.bind(console)},e.log);this.hook=p;if(!e.authStrategy){if(!e.auth){this.auth=async()=>({type:"unauthenticated"})}else{const a=i.createTokenAuth(e.auth);p.wrap("request",a.hook);this.auth=a}}else{const{authStrategy:a}=e,d=_objectWithoutProperties(e,n);const t=a(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:d},e.auth));p.wrap("request",t.hook);this.auth=t}const l=this.constructor;l.plugins.forEach((p=>{Object.assign(this,p(this,e))}))}static defaults(e){const p=class extends(this){constructor(...p){const a=p[0]||{};if(typeof e==="function"){super(e(a));return}super(Object.assign({},e,a,a.userAgent&&e.userAgent?{userAgent:`${a.userAgent} ${e.userAgent}`}:null))}};return p}static plugin(...e){var p;const a=this.plugins;const d=(p=class extends(this){},p.plugins=a.concat(e.filter((e=>!a.includes(e)))),p);return d}}Octokit.VERSION=o;Octokit.plugins=[];p.Octokit=Octokit},9440:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});var d=a(3287);var t=a(5030);function lowercaseKeys(e){if(!e){return{}}return Object.keys(e).reduce(((p,a)=>{p[a.toLowerCase()]=e[a];return p}),{})}function mergeDeep(e,p){const a=Object.assign({},e);Object.keys(p).forEach((t=>{if(d.isPlainObject(p[t])){if(!(t in e))Object.assign(a,{[t]:p[t]});else a[t]=mergeDeep(e[t],p[t])}else{Object.assign(a,{[t]:p[t]})}}));return a}function removeUndefinedProperties(e){for(const p in e){if(e[p]===undefined){delete e[p]}}return e}function merge(e,p,a){if(typeof p==="string"){let[e,d]=p.split(" ");a=Object.assign(d?{method:e,url:d}:{url:e},a)}else{a=Object.assign({},p)}a.headers=lowercaseKeys(a.headers);removeUndefinedProperties(a);removeUndefinedProperties(a.headers);const d=mergeDeep(e||{},a);if(e&&e.mediaType.previews.length){d.mediaType.previews=e.mediaType.previews.filter((e=>!d.mediaType.previews.includes(e))).concat(d.mediaType.previews)}d.mediaType.previews=d.mediaType.previews.map((e=>e.replace(/-preview/,"")));return d}function addQueryParameters(e,p){const a=/\?/.test(e)?"&":"?";const d=Object.keys(p);if(d.length===0){return e}return e+a+d.map((e=>{if(e==="q"){return"q="+p.q.split("+").map(encodeURIComponent).join("+")}return`${e}=${encodeURIComponent(p[e])}`})).join("&")}const r=/\{[^}]+\}/g;function removeNonChars(e){return e.replace(/^\W+|\W+$/g,"").split(/,/)}function extractUrlVariableNames(e){const p=e.match(r);if(!p){return[]}return p.map(removeNonChars).reduce(((e,p)=>e.concat(p)),[])}function omit(e,p){return Object.keys(e).filter((e=>!p.includes(e))).reduce(((p,a)=>{p[a]=e[a];return p}),{})}function encodeReserved(e){return e.split(/(%[0-9A-Fa-f]{2})/g).map((function(e){if(!/%[0-9A-Fa-f]/.test(e)){e=encodeURI(e).replace(/%5B/g,"[").replace(/%5D/g,"]")}return e})).join("")}function encodeUnreserved(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function encodeValue(e,p,a){p=e==="+"||e==="#"?encodeReserved(p):encodeUnreserved(p);if(a){return encodeUnreserved(a)+"="+p}else{return p}}function isDefined(e){return e!==undefined&&e!==null}function isKeyOperator(e){return e===";"||e==="&"||e==="?"}function getValues(e,p,a,d){var t=e[a],r=[];if(isDefined(t)&&t!==""){if(typeof t==="string"||typeof t==="number"||typeof t==="boolean"){t=t.toString();if(d&&d!=="*"){t=t.substring(0,parseInt(d,10))}r.push(encodeValue(p,t,isKeyOperator(p)?a:""))}else{if(d==="*"){if(Array.isArray(t)){t.filter(isDefined).forEach((function(e){r.push(encodeValue(p,e,isKeyOperator(p)?a:""))}))}else{Object.keys(t).forEach((function(e){if(isDefined(t[e])){r.push(encodeValue(p,t[e],e))}}))}}else{const e=[];if(Array.isArray(t)){t.filter(isDefined).forEach((function(a){e.push(encodeValue(p,a))}))}else{Object.keys(t).forEach((function(a){if(isDefined(t[a])){e.push(encodeUnreserved(a));e.push(encodeValue(p,t[a].toString()))}}))}if(isKeyOperator(p)){r.push(encodeUnreserved(a)+"="+e.join(","))}else if(e.length!==0){r.push(e.join(","))}}}}else{if(p===";"){if(isDefined(t)){r.push(encodeUnreserved(a))}}else if(t===""&&(p==="&"||p==="?")){r.push(encodeUnreserved(a)+"=")}else if(t===""){r.push("")}}return r}function parseUrl(e){return{expand:expand.bind(null,e)}}function expand(e,p){var a=["+","#",".","/",";","?","&"];return e.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g,(function(e,d,t){if(d){let e="";const t=[];if(a.indexOf(d.charAt(0))!==-1){e=d.charAt(0);d=d.substr(1)}d.split(/,/g).forEach((function(a){var d=/([^:\*]*)(?::(\d+)|(\*))?/.exec(a);t.push(getValues(p,e,d[1],d[2]||d[3]))}));if(e&&e!=="+"){var r=",";if(e==="?"){r="&"}else if(e!=="#"){r=e}return(t.length!==0?e:"")+t.join(r)}else{return t.join(",")}}else{return encodeReserved(t)}}))}function parse(e){let p=e.method.toUpperCase();let a=(e.url||"/").replace(/:([a-z]\w+)/g,"{$1}");let d=Object.assign({},e.headers);let t;let r=omit(e,["method","baseUrl","url","headers","request","mediaType"]);const s=extractUrlVariableNames(a);a=parseUrl(a).expand(r);if(!/^http/.test(a)){a=e.baseUrl+a}const i=Object.keys(e).filter((e=>s.includes(e))).concat("baseUrl");const o=omit(r,i);const n=/application\/octet-stream/i.test(d.accept);if(!n){if(e.mediaType.format){d.accept=d.accept.split(/,/).map((p=>p.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/,`application/vnd$1$2.${e.mediaType.format}`))).join(",")}if(e.mediaType.previews.length){const p=d.accept.match(/[\w-]+(?=-preview)/g)||[];d.accept=p.concat(e.mediaType.previews).map((p=>{const a=e.mediaType.format?`.${e.mediaType.format}`:"+json";return`application/vnd.github.${p}-preview${a}`})).join(",")}}if(["GET","HEAD"].includes(p)){a=addQueryParameters(a,o)}else{if("data"in o){t=o.data}else{if(Object.keys(o).length){t=o}else{d["content-length"]=0}}}if(!d["content-type"]&&typeof t!=="undefined"){d["content-type"]="application/json; charset=utf-8"}if(["PATCH","PUT"].includes(p)&&typeof t==="undefined"){t=""}return Object.assign({method:p,url:a,headers:d},typeof t!=="undefined"?{body:t}:null,e.request?{request:e.request}:null)}function endpointWithDefaults(e,p,a){return parse(merge(e,p,a))}function withDefaults(e,p){const a=merge(e,p);const d=endpointWithDefaults.bind(null,a);return Object.assign(d,{DEFAULTS:a,defaults:withDefaults.bind(null,a),merge:merge.bind(null,a),parse:parse})}const s="6.0.12";const i=`octokit-endpoint.js/${s} ${t.getUserAgent()}`;const o={method:"GET",baseUrl:"https://api.github.com",headers:{accept:"application/vnd.github.v3+json","user-agent":i},mediaType:{format:"",previews:[]}};const n=withDefaults(null,o);p.endpoint=n},8467:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});var d=a(6234);var t=a(5030);const r="4.8.0";function _buildMessageForResponseErrors(e){return`Request failed due to following response errors:\n`+e.errors.map((e=>` - ${e.message}`)).join("\n")}class GraphqlResponseError extends Error{constructor(e,p,a){super(_buildMessageForResponseErrors(a));this.request=e;this.headers=p;this.response=a;this.name="GraphqlResponseError";this.errors=a.errors;this.data=a.data;if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}}}const s=["method","baseUrl","url","headers","request","query","mediaType"];const i=["query","method","url"];const o=/\/api\/v3\/?$/;function graphql(e,p,a){if(a){if(typeof p==="string"&&"query"in a){return Promise.reject(new Error(`[@octokit/graphql] "query" cannot be used as variable name`))}for(const e in a){if(!i.includes(e))continue;return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}}const d=typeof p==="string"?Object.assign({query:p},a):p;const t=Object.keys(d).reduce(((e,p)=>{if(s.includes(p)){e[p]=d[p];return e}if(!e.variables){e.variables={}}e.variables[p]=d[p];return e}),{});const r=d.baseUrl||e.endpoint.DEFAULTS.baseUrl;if(o.test(r)){t.url=r.replace(o,"/api/graphql")}return e(t).then((e=>{if(e.data.errors){const p={};for(const a of Object.keys(e.headers)){p[a]=e.headers[a]}throw new GraphqlResponseError(t,p,e.data)}return e.data.data}))}function withDefaults(e,p){const a=e.defaults(p);const newApi=(e,p)=>graphql(a,e,p);return Object.assign(newApi,{defaults:withDefaults.bind(null,a),endpoint:d.request.endpoint})}const n=withDefaults(d.request,{headers:{"user-agent":`octokit-graphql.js/${r} ${t.getUserAgent()}`},method:"POST",url:"/graphql"});function withCustomRequest(e){return withDefaults(e,{method:"POST",url:"/graphql"})}p.GraphqlResponseError=GraphqlResponseError;p.graphql=n;p.withCustomRequest=withCustomRequest},4193:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});const a="2.21.3";function ownKeys(e,p){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(e);p&&(d=d.filter((function(p){return Object.getOwnPropertyDescriptor(e,p).enumerable}))),a.push.apply(a,d)}return a}function _objectSpread2(e){for(var p=1;p({async next(){if(!i)return{done:true};try{const e=await t({method:r,url:i,headers:s});const p=normalizePaginatedListResponse(e);i=((p.headers.link||"").match(/<([^>]+)>;\s*rel="next"/)||[])[1];return{value:p}}catch(e){if(e.status!==409)throw e;i="";return{value:{status:200,headers:{},data:[]}}}}})}}function paginate(e,p,a,d){if(typeof a==="function"){d=a;a=undefined}return gather(e,[],iterator(e,p,a)[Symbol.asyncIterator](),d)}function gather(e,p,a,d){return a.next().then((t=>{if(t.done){return p}let r=false;function done(){r=true}p=p.concat(d?d(t.value,done):t.value.data);if(r){return p}return gather(e,p,a,d)}))}const d=Object.assign(paginate,{iterator:iterator});const t=["GET /app/hook/deliveries","GET /app/installations","GET /applications/grants","GET /authorizations","GET /enterprises/{enterprise}/actions/permissions/organizations","GET /enterprises/{enterprise}/actions/runner-groups","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/organizations","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/runners","GET /enterprises/{enterprise}/actions/runners","GET /enterprises/{enterprise}/audit-log","GET /enterprises/{enterprise}/secret-scanning/alerts","GET /enterprises/{enterprise}/settings/billing/advanced-security","GET /events","GET /gists","GET /gists/public","GET /gists/starred","GET /gists/{gist_id}/comments","GET /gists/{gist_id}/commits","GET /gists/{gist_id}/forks","GET /installation/repositories","GET /issues","GET /licenses","GET /marketplace_listing/plans","GET /marketplace_listing/plans/{plan_id}/accounts","GET /marketplace_listing/stubbed/plans","GET /marketplace_listing/stubbed/plans/{plan_id}/accounts","GET /networks/{owner}/{repo}/events","GET /notifications","GET /organizations","GET /orgs/{org}/actions/cache/usage-by-repository","GET /orgs/{org}/actions/permissions/repositories","GET /orgs/{org}/actions/runner-groups","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/runners","GET /orgs/{org}/actions/runners","GET /orgs/{org}/actions/secrets","GET /orgs/{org}/actions/secrets/{secret_name}/repositories","GET /orgs/{org}/audit-log","GET /orgs/{org}/blocks","GET /orgs/{org}/code-scanning/alerts","GET /orgs/{org}/codespaces","GET /orgs/{org}/credential-authorizations","GET /orgs/{org}/dependabot/secrets","GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories","GET /orgs/{org}/events","GET /orgs/{org}/external-groups","GET /orgs/{org}/failed_invitations","GET /orgs/{org}/hooks","GET /orgs/{org}/hooks/{hook_id}/deliveries","GET /orgs/{org}/installations","GET /orgs/{org}/invitations","GET /orgs/{org}/invitations/{invitation_id}/teams","GET /orgs/{org}/issues","GET /orgs/{org}/members","GET /orgs/{org}/migrations","GET /orgs/{org}/migrations/{migration_id}/repositories","GET /orgs/{org}/outside_collaborators","GET /orgs/{org}/packages","GET /orgs/{org}/packages/{package_type}/{package_name}/versions","GET /orgs/{org}/projects","GET /orgs/{org}/public_members","GET /orgs/{org}/repos","GET /orgs/{org}/secret-scanning/alerts","GET /orgs/{org}/settings/billing/advanced-security","GET /orgs/{org}/team-sync/groups","GET /orgs/{org}/teams","GET /orgs/{org}/teams/{team_slug}/discussions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions","GET /orgs/{org}/teams/{team_slug}/invitations","GET /orgs/{org}/teams/{team_slug}/members","GET /orgs/{org}/teams/{team_slug}/projects","GET /orgs/{org}/teams/{team_slug}/repos","GET /orgs/{org}/teams/{team_slug}/teams","GET /projects/columns/{column_id}/cards","GET /projects/{project_id}/collaborators","GET /projects/{project_id}/columns","GET /repos/{owner}/{repo}/actions/artifacts","GET /repos/{owner}/{repo}/actions/caches","GET /repos/{owner}/{repo}/actions/runners","GET /repos/{owner}/{repo}/actions/runs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts","GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs","GET /repos/{owner}/{repo}/actions/secrets","GET /repos/{owner}/{repo}/actions/workflows","GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs","GET /repos/{owner}/{repo}/assignees","GET /repos/{owner}/{repo}/branches","GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations","GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs","GET /repos/{owner}/{repo}/code-scanning/alerts","GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances","GET /repos/{owner}/{repo}/code-scanning/analyses","GET /repos/{owner}/{repo}/codespaces","GET /repos/{owner}/{repo}/codespaces/devcontainers","GET /repos/{owner}/{repo}/codespaces/secrets","GET /repos/{owner}/{repo}/collaborators","GET /repos/{owner}/{repo}/comments","GET /repos/{owner}/{repo}/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/commits","GET /repos/{owner}/{repo}/commits/{commit_sha}/comments","GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls","GET /repos/{owner}/{repo}/commits/{ref}/check-runs","GET /repos/{owner}/{repo}/commits/{ref}/check-suites","GET /repos/{owner}/{repo}/commits/{ref}/status","GET /repos/{owner}/{repo}/commits/{ref}/statuses","GET /repos/{owner}/{repo}/contributors","GET /repos/{owner}/{repo}/dependabot/secrets","GET /repos/{owner}/{repo}/deployments","GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses","GET /repos/{owner}/{repo}/environments","GET /repos/{owner}/{repo}/events","GET /repos/{owner}/{repo}/forks","GET /repos/{owner}/{repo}/git/matching-refs/{ref}","GET /repos/{owner}/{repo}/hooks","GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries","GET /repos/{owner}/{repo}/invitations","GET /repos/{owner}/{repo}/issues","GET /repos/{owner}/{repo}/issues/comments","GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/issues/events","GET /repos/{owner}/{repo}/issues/{issue_number}/comments","GET /repos/{owner}/{repo}/issues/{issue_number}/events","GET /repos/{owner}/{repo}/issues/{issue_number}/labels","GET /repos/{owner}/{repo}/issues/{issue_number}/reactions","GET /repos/{owner}/{repo}/issues/{issue_number}/timeline","GET /repos/{owner}/{repo}/keys","GET /repos/{owner}/{repo}/labels","GET /repos/{owner}/{repo}/milestones","GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels","GET /repos/{owner}/{repo}/notifications","GET /repos/{owner}/{repo}/pages/builds","GET /repos/{owner}/{repo}/projects","GET /repos/{owner}/{repo}/pulls","GET /repos/{owner}/{repo}/pulls/comments","GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/pulls/{pull_number}/comments","GET /repos/{owner}/{repo}/pulls/{pull_number}/commits","GET /repos/{owner}/{repo}/pulls/{pull_number}/files","GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments","GET /repos/{owner}/{repo}/releases","GET /repos/{owner}/{repo}/releases/{release_id}/assets","GET /repos/{owner}/{repo}/releases/{release_id}/reactions","GET /repos/{owner}/{repo}/secret-scanning/alerts","GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations","GET /repos/{owner}/{repo}/stargazers","GET /repos/{owner}/{repo}/subscribers","GET /repos/{owner}/{repo}/tags","GET /repos/{owner}/{repo}/teams","GET /repos/{owner}/{repo}/topics","GET /repositories","GET /repositories/{repository_id}/environments/{environment_name}/secrets","GET /search/code","GET /search/commits","GET /search/issues","GET /search/labels","GET /search/repositories","GET /search/topics","GET /search/users","GET /teams/{team_id}/discussions","GET /teams/{team_id}/discussions/{discussion_number}/comments","GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /teams/{team_id}/discussions/{discussion_number}/reactions","GET /teams/{team_id}/invitations","GET /teams/{team_id}/members","GET /teams/{team_id}/projects","GET /teams/{team_id}/repos","GET /teams/{team_id}/teams","GET /user/blocks","GET /user/codespaces","GET /user/codespaces/secrets","GET /user/emails","GET /user/followers","GET /user/following","GET /user/gpg_keys","GET /user/installations","GET /user/installations/{installation_id}/repositories","GET /user/issues","GET /user/keys","GET /user/marketplace_purchases","GET /user/marketplace_purchases/stubbed","GET /user/memberships/orgs","GET /user/migrations","GET /user/migrations/{migration_id}/repositories","GET /user/orgs","GET /user/packages","GET /user/packages/{package_type}/{package_name}/versions","GET /user/public_emails","GET /user/repos","GET /user/repository_invitations","GET /user/starred","GET /user/subscriptions","GET /user/teams","GET /users","GET /users/{username}/events","GET /users/{username}/events/orgs/{org}","GET /users/{username}/events/public","GET /users/{username}/followers","GET /users/{username}/following","GET /users/{username}/gists","GET /users/{username}/gpg_keys","GET /users/{username}/keys","GET /users/{username}/orgs","GET /users/{username}/packages","GET /users/{username}/projects","GET /users/{username}/received_events","GET /users/{username}/received_events/public","GET /users/{username}/repos","GET /users/{username}/starred","GET /users/{username}/subscriptions"];function isPaginatingEndpoint(e){if(typeof e==="string"){return t.includes(e)}else{return false}}function paginateRest(e){return{paginate:Object.assign(paginate.bind(null,e),{iterator:iterator.bind(null,e)})}}paginateRest.VERSION=a;p.composePaginateRest=d;p.isPaginatingEndpoint=isPaginatingEndpoint;p.paginateRest=paginateRest;p.paginatingEndpoints=t},3044:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});function ownKeys(e,p){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(e);if(p){d=d.filter((function(p){return Object.getOwnPropertyDescriptor(e,p).enumerable}))}a.push.apply(a,d)}return a}function _objectSpread2(e){for(var p=1;p{Object.defineProperty(p,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var d=a(8932);var t=_interopDefault(a(1223));const r=t((e=>console.warn(e)));const s=t((e=>console.warn(e)));class RequestError extends Error{constructor(e,p,a){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="HttpError";this.status=p;let t;if("headers"in a&&typeof a.headers!=="undefined"){t=a.headers}if("response"in a){this.response=a.response;t=a.response.headers}const i=Object.assign({},a.request);if(a.request.headers.authorization){i.headers=Object.assign({},a.request.headers,{authorization:a.request.headers.authorization.replace(/ .*$/," [REDACTED]")})}i.url=i.url.replace(/\bclient_secret=\w+/g,"client_secret=[REDACTED]").replace(/\baccess_token=\w+/g,"access_token=[REDACTED]");this.request=i;Object.defineProperty(this,"code",{get(){r(new d.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`."));return p}});Object.defineProperty(this,"headers",{get(){s(new d.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."));return t||{}}})}}p.RequestError=RequestError},6234:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var d=a(9440);var t=a(5030);var r=a(3287);var s=_interopDefault(a(467));var i=a(537);const o="5.6.3";function getBufferResponse(e){return e.arrayBuffer()}function fetchWrapper(e){const p=e.request&&e.request.log?e.request.log:console;if(r.isPlainObject(e.body)||Array.isArray(e.body)){e.body=JSON.stringify(e.body)}let a={};let d;let t;const o=e.request&&e.request.fetch||s;return o(e.url,Object.assign({method:e.method,body:e.body,headers:e.headers,redirect:e.redirect},e.request)).then((async r=>{t=r.url;d=r.status;for(const e of r.headers){a[e[0]]=e[1]}if("deprecation"in a){const d=a.link&&a.link.match(/<([^>]+)>; rel="deprecation"/);const t=d&&d.pop();p.warn(`[@octokit/request] "${e.method} ${e.url}" is deprecated. It is scheduled to be removed on ${a.sunset}${t?`. See ${t}`:""}`)}if(d===204||d===205){return}if(e.method==="HEAD"){if(d<400){return}throw new i.RequestError(r.statusText,d,{response:{url:t,status:d,headers:a,data:undefined},request:e})}if(d===304){throw new i.RequestError("Not modified",d,{response:{url:t,status:d,headers:a,data:await getResponseData(r)},request:e})}if(d>=400){const p=await getResponseData(r);const s=new i.RequestError(toErrorMessage(p),d,{response:{url:t,status:d,headers:a,data:p},request:e});throw s}return getResponseData(r)})).then((e=>({status:d,url:t,headers:a,data:e}))).catch((p=>{if(p instanceof i.RequestError)throw p;throw new i.RequestError(p.message,500,{request:e})}))}async function getResponseData(e){const p=e.headers.get("content-type");if(/application\/json/.test(p)){return e.json()}if(!p||/^text\/|charset=utf-8$/.test(p)){return e.text()}return getBufferResponse(e)}function toErrorMessage(e){if(typeof e==="string")return e;if("message"in e){if(Array.isArray(e.errors)){return`${e.message}: ${e.errors.map(JSON.stringify).join(", ")}`}return e.message}return`Unknown error: ${JSON.stringify(e)}`}function withDefaults(e,p){const a=e.defaults(p);const newApi=function(e,p){const d=a.merge(e,p);if(!d.request||!d.request.hook){return fetchWrapper(a.parse(d))}const request=(e,p)=>fetchWrapper(a.parse(a.merge(e,p)));Object.assign(request,{endpoint:a,defaults:withDefaults.bind(null,a)});return d.request.hook(request,d)};return Object.assign(newApi,{endpoint:a,defaults:withDefaults.bind(null,a)})}const n=withDefaults(d.endpoint,{headers:{"user-agent":`octokit-request.js/${o} ${t.getUserAgent()}`}});p.request=n},3682:(e,p,a)=>{var d=a(4670);var t=a(5549);var r=a(6819);var s=Function.bind;var i=s.bind(s);function bindApi(e,p,a){var d=i(r,null).apply(null,a?[p,a]:[p]);e.api={remove:d};e.remove=d;["before","error","after","wrap"].forEach((function(d){var r=a?[p,d,a]:[p,d];e[d]=e.api[d]=i(t,null).apply(null,r)}))}function HookSingular(){var e="h";var p={registry:{}};var a=d.bind(null,p,e);bindApi(a,p,e);return a}function HookCollection(){var e={registry:{}};var p=d.bind(null,e);bindApi(p,e);return p}var o=false;function Hook(){if(!o){console.warn('[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4');o=true}return HookCollection()}Hook.Singular=HookSingular.bind();Hook.Collection=HookCollection.bind();e.exports=Hook;e.exports.Hook=Hook;e.exports.Singular=Hook.Singular;e.exports.Collection=Hook.Collection},5549:e=>{e.exports=addHook;function addHook(e,p,a,d){var t=d;if(!e.registry[a]){e.registry[a]=[]}if(p==="before"){d=function(e,p){return Promise.resolve().then(t.bind(null,p)).then(e.bind(null,p))}}if(p==="after"){d=function(e,p){var a;return Promise.resolve().then(e.bind(null,p)).then((function(e){a=e;return t(a,p)})).then((function(){return a}))}}if(p==="error"){d=function(e,p){return Promise.resolve().then(e.bind(null,p)).catch((function(e){return t(e,p)}))}}e.registry[a].push({hook:d,orig:t})}},4670:e=>{e.exports=register;function register(e,p,a,d){if(typeof a!=="function"){throw new Error("method for before hook must be a function")}if(!d){d={}}if(Array.isArray(p)){return p.reverse().reduce((function(p,a){return register.bind(null,e,a,p,d)}),a)()}return Promise.resolve().then((function(){if(!e.registry[p]){return a(d)}return e.registry[p].reduce((function(e,p){return p.hook.bind(null,e,d)}),a)()}))}},6819:e=>{e.exports=removeHook;function removeHook(e,p,a){if(!e.registry[p]){return}var d=e.registry[p].map((function(e){return e.orig})).indexOf(a);if(d===-1){return}e.registry[p].splice(d,1)}},8932:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});class Deprecation extends Error{constructor(e){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="Deprecation"}}p.Deprecation=Deprecation},3287:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true}); -/*! - * is-plain-object - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */function isObject(e){return Object.prototype.toString.call(e)==="[object Object]"}function isPlainObject(e){var p,a;if(isObject(e)===false)return false;p=e.constructor;if(p===undefined)return true;a=p.prototype;if(isObject(a)===false)return false;if(a.hasOwnProperty("isPrototypeOf")===false){return false}return true}p.isPlainObject=isPlainObject},467:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var d=_interopDefault(a(2781));var t=_interopDefault(a(3685));var r=_interopDefault(a(7310));var s=_interopDefault(a(8665));var i=_interopDefault(a(5687));var o=_interopDefault(a(9796));const n=d.Readable;const l=Symbol("buffer");const m=Symbol("type");class Blob{constructor(){this[m]="";const e=arguments[0];const p=arguments[1];const a=[];let d=0;if(e){const p=e;const t=Number(p.length);for(let e=0;e1&&arguments[1]!==undefined?arguments[1]:{},t=a.size;let r=t===undefined?0:t;var s=a.timeout;let i=s===undefined?0:s;if(e==null){e=null}else if(isURLSearchParams(e)){e=Buffer.from(e.toString())}else if(isBlob(e));else if(Buffer.isBuffer(e));else if(Object.prototype.toString.call(e)==="[object ArrayBuffer]"){e=Buffer.from(e)}else if(ArrayBuffer.isView(e)){e=Buffer.from(e.buffer,e.byteOffset,e.byteLength)}else if(e instanceof d);else{e=Buffer.from(String(e))}this[c]={body:e,disturbed:false,error:null};this.size=r;this.timeout=i;if(e instanceof d){e.on("error",(function(e){const a=e.name==="AbortError"?e:new FetchError(`Invalid response body while trying to fetch ${p.url}: ${e.message}`,"system",e);p[c].error=a}))}}Body.prototype={get body(){return this[c].body},get bodyUsed(){return this[c].disturbed},arrayBuffer(){return consumeBody.call(this).then((function(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}))},blob(){let e=this.headers&&this.headers.get("content-type")||"";return consumeBody.call(this).then((function(p){return Object.assign(new Blob([],{type:e.toLowerCase()}),{[l]:p})}))},json(){var e=this;return consumeBody.call(this).then((function(p){try{return JSON.parse(p.toString())}catch(p){return Body.Promise.reject(new FetchError(`invalid json response body at ${e.url} reason: ${p.message}`,"invalid-json"))}}))},text(){return consumeBody.call(this).then((function(e){return e.toString()}))},buffer(){return consumeBody.call(this)},textConverted(){var e=this;return consumeBody.call(this).then((function(p){return convertBody(p,e.headers)}))}};Object.defineProperties(Body.prototype,{body:{enumerable:true},bodyUsed:{enumerable:true},arrayBuffer:{enumerable:true},blob:{enumerable:true},json:{enumerable:true},text:{enumerable:true}});Body.mixIn=function(e){for(const p of Object.getOwnPropertyNames(Body.prototype)){if(!(p in e)){const a=Object.getOwnPropertyDescriptor(Body.prototype,p);Object.defineProperty(e,p,a)}}};function consumeBody(){var e=this;if(this[c].disturbed){return Body.Promise.reject(new TypeError(`body used already for: ${this.url}`))}this[c].disturbed=true;if(this[c].error){return Body.Promise.reject(this[c].error)}let p=this.body;if(p===null){return Body.Promise.resolve(Buffer.alloc(0))}if(isBlob(p)){p=p.stream()}if(Buffer.isBuffer(p)){return Body.Promise.resolve(p)}if(!(p instanceof d)){return Body.Promise.resolve(Buffer.alloc(0))}let a=[];let t=0;let r=false;return new Body.Promise((function(d,s){let i;if(e.timeout){i=setTimeout((function(){r=true;s(new FetchError(`Response timeout while trying to fetch ${e.url} (over ${e.timeout}ms)`,"body-timeout"))}),e.timeout)}p.on("error",(function(p){if(p.name==="AbortError"){r=true;s(p)}else{s(new FetchError(`Invalid response body while trying to fetch ${e.url}: ${p.message}`,"system",p))}}));p.on("data",(function(p){if(r||p===null){return}if(e.size&&t+p.length>e.size){r=true;s(new FetchError(`content size at ${e.url} over limit: ${e.size}`,"max-size"));return}t+=p.length;a.push(p)}));p.on("end",(function(){if(r){return}clearTimeout(i);try{d(Buffer.concat(a,t))}catch(p){s(new FetchError(`Could not create Buffer from response body for ${e.url}: ${p.message}`,"system",p))}}))}))}function convertBody(e,p){if(typeof u!=="function"){throw new Error("The package `encoding` must be installed to use the textConverted() function")}const a=p.get("content-type");let d="utf-8";let t,r;if(a){t=/charset=([^;]*)/i.exec(a)}r=e.slice(0,1024).toString();if(!t&&r){t=/0&&arguments[0]!==undefined?arguments[0]:undefined;this[w]=Object.create(null);if(e instanceof Headers){const p=e.raw();const a=Object.keys(p);for(const e of a){for(const a of p[e]){this.append(e,a)}}return}if(e==null);else if(typeof e==="object"){const p=e[Symbol.iterator];if(p!=null){if(typeof p!=="function"){throw new TypeError("Header pairs must be iterable")}const a=[];for(const p of e){if(typeof p!=="object"||typeof p[Symbol.iterator]!=="function"){throw new TypeError("Each header pair must be iterable")}a.push(Array.from(p))}for(const e of a){if(e.length!==2){throw new TypeError("Each header pair must be a name/value tuple")}this.append(e[0],e[1])}}else{for(const p of Object.keys(e)){const a=e[p];this.append(p,a)}}}else{throw new TypeError("Provided initializer must be an object")}}get(e){e=`${e}`;validateName(e);const p=find(this[w],e);if(p===undefined){return null}return this[w][p].join(", ")}forEach(e){let p=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;let a=getHeaders(this);let d=0;while(d1&&arguments[1]!==undefined?arguments[1]:"key+value";const a=Object.keys(e[w]).sort();return a.map(p==="key"?function(e){return e.toLowerCase()}:p==="value"?function(p){return e[w][p].join(", ")}:function(p){return[p.toLowerCase(),e[w][p].join(", ")]})}const _=Symbol("internal");function createHeadersIterator(e,p){const a=Object.create(T);a[_]={target:e,kind:p,index:0};return a}const T=Object.setPrototypeOf({next(){if(!this||Object.getPrototypeOf(this)!==T){throw new TypeError("Value of `this` is not a HeadersIterator")}var e=this[_];const p=e.target,a=e.kind,d=e.index;const t=getHeaders(p,a);const r=t.length;if(d>=r){return{value:undefined,done:true}}this[_].index=d+1;return{value:t[d],done:false}}},Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));Object.defineProperty(T,Symbol.toStringTag,{value:"HeadersIterator",writable:false,enumerable:false,configurable:true});function exportNodeCompatibleHeaders(e){const p=Object.assign({__proto__:null},e[w]);const a=find(e[w],"Host");if(a!==undefined){p[a]=p[a][0]}return p}function createHeadersLenient(e){const p=new Headers;for(const a of Object.keys(e)){if(h.test(a)){continue}if(Array.isArray(e[a])){for(const d of e[a]){if(g.test(d)){continue}if(p[w][a]===undefined){p[w][a]=[d]}else{p[w][a].push(d)}}}else if(!g.test(e[a])){p[w][a]=[e[a]]}}return p}const E=Symbol("Response internals");const b=t.STATUS_CODES;class Response{constructor(){let e=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;let p=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};Body.call(this,e,p);const a=p.status||200;const d=new Headers(p.headers);if(e!=null&&!d.has("Content-Type")){const p=extractContentType(e);if(p){d.append("Content-Type",p)}}this[E]={url:p.url,status:a,statusText:p.statusText||b[a],headers:d,counter:p.counter}}get url(){return this[E].url||""}get status(){return this[E].status}get ok(){return this[E].status>=200&&this[E].status<300}get redirected(){return this[E].counter>0}get statusText(){return this[E].statusText}get headers(){return this[E].headers}clone(){return new Response(clone(this),{url:this.url,status:this.status,statusText:this.statusText,headers:this.headers,ok:this.ok,redirected:this.redirected})}}Body.mixIn(Response.prototype);Object.defineProperties(Response.prototype,{url:{enumerable:true},status:{enumerable:true},ok:{enumerable:true},redirected:{enumerable:true},statusText:{enumerable:true},headers:{enumerable:true},clone:{enumerable:true}});Object.defineProperty(Response.prototype,Symbol.toStringTag,{value:"Response",writable:false,enumerable:false,configurable:true});const y=Symbol("Request internals");const S=r.URL||s.URL;const D=r.parse;const P=r.format;function parseURL(e){if(/^[a-zA-Z][a-zA-Z\d+\-.]*:/.exec(e)){e=new S(e).toString()}return D(e)}const A="destroy"in d.Readable.prototype;function isRequest(e){return typeof e==="object"&&typeof e[y]==="object"}function isAbortSignal(e){const p=e&&typeof e==="object"&&Object.getPrototypeOf(e);return!!(p&&p.constructor.name==="AbortSignal")}class Request{constructor(e){let p=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};let a;if(!isRequest(e)){if(e&&e.href){a=parseURL(e.href)}else{a=parseURL(`${e}`)}e={}}else{a=parseURL(e.url)}let d=p.method||e.method||"GET";d=d.toUpperCase();if((p.body!=null||isRequest(e)&&e.body!==null)&&(d==="GET"||d==="HEAD")){throw new TypeError("Request with GET/HEAD method cannot have body")}let t=p.body!=null?p.body:isRequest(e)&&e.body!==null?clone(e):null;Body.call(this,t,{timeout:p.timeout||e.timeout||0,size:p.size||e.size||0});const r=new Headers(p.headers||e.headers||{});if(t!=null&&!r.has("Content-Type")){const e=extractContentType(t);if(e){r.append("Content-Type",e)}}let s=isRequest(e)?e.signal:null;if("signal"in p)s=p.signal;if(s!=null&&!isAbortSignal(s)){throw new TypeError("Expected signal to be an instanceof AbortSignal")}this[y]={method:d,redirect:p.redirect||e.redirect||"follow",headers:r,parsedURL:a,signal:s};this.follow=p.follow!==undefined?p.follow:e.follow!==undefined?e.follow:20;this.compress=p.compress!==undefined?p.compress:e.compress!==undefined?e.compress:true;this.counter=p.counter||e.counter||0;this.agent=p.agent||e.agent}get method(){return this[y].method}get url(){return P(this[y].parsedURL)}get headers(){return this[y].headers}get redirect(){return this[y].redirect}get signal(){return this[y].signal}clone(){return new Request(this)}}Body.mixIn(Request.prototype);Object.defineProperty(Request.prototype,Symbol.toStringTag,{value:"Request",writable:false,enumerable:false,configurable:true});Object.defineProperties(Request.prototype,{method:{enumerable:true},url:{enumerable:true},headers:{enumerable:true},redirect:{enumerable:true},clone:{enumerable:true},signal:{enumerable:true}});function getNodeRequestOptions(e){const p=e[y].parsedURL;const a=new Headers(e[y].headers);if(!a.has("Accept")){a.set("Accept","*/*")}if(!p.protocol||!p.hostname){throw new TypeError("Only absolute URLs are supported")}if(!/^https?:$/.test(p.protocol)){throw new TypeError("Only HTTP(S) protocols are supported")}if(e.signal&&e.body instanceof d.Readable&&!A){throw new Error("Cancellation of streamed requests with AbortSignal is not supported in node < 8")}let t=null;if(e.body==null&&/^(POST|PUT)$/i.test(e.method)){t="0"}if(e.body!=null){const p=getTotalBytes(e);if(typeof p==="number"){t=String(p)}}if(t){a.set("Content-Length",t)}if(!a.has("User-Agent")){a.set("User-Agent","node-fetch/1.0 (+https://github.com/bitinn/node-fetch)")}if(e.compress&&!a.has("Accept-Encoding")){a.set("Accept-Encoding","gzip,deflate")}let r=e.agent;if(typeof r==="function"){r=r(p)}if(!a.has("Connection")&&!r){a.set("Connection","close")}return Object.assign({},p,{method:e.method,headers:exportNodeCompatibleHeaders(a),agent:r})}function AbortError(e){Error.call(this,e);this.type="aborted";this.message=e;Error.captureStackTrace(this,this.constructor)}AbortError.prototype=Object.create(Error.prototype);AbortError.prototype.constructor=AbortError;AbortError.prototype.name="AbortError";const O=r.URL||s.URL;const k=d.PassThrough;const N=function isDomainOrSubdomain(e,p){const a=new O(p).hostname;const d=new O(e).hostname;return a===d||a[a.length-d.length-1]==="."&&a.endsWith(d)};const R=function isSameProtocol(e,p){const a=new O(p).protocol;const d=new O(e).protocol;return a===d};function fetch(e,p){if(!fetch.Promise){throw new Error("native promise missing, set fetch.Promise to your favorite alternative")}Body.Promise=fetch.Promise;return new fetch.Promise((function(a,r){const s=new Request(e,p);const n=getNodeRequestOptions(s);const l=(n.protocol==="https:"?i:t).request;const m=s.signal;let u=null;const c=function abort(){let e=new AbortError("The user aborted a request.");r(e);if(s.body&&s.body instanceof d.Readable){destroyStream(s.body,e)}if(!u||!u.body)return;u.body.emit("error",e)};if(m&&m.aborted){c();return}const v=function abortAndFinalize(){c();finalize()};const h=l(n);let g;if(m){m.addEventListener("abort",v)}function finalize(){h.abort();if(m)m.removeEventListener("abort",v);clearTimeout(g)}if(s.timeout){h.once("socket",(function(e){g=setTimeout((function(){r(new FetchError(`network timeout at: ${s.url}`,"request-timeout"));finalize()}),s.timeout)}))}h.on("error",(function(e){r(new FetchError(`request to ${s.url} failed, reason: ${e.message}`,"system",e));if(u&&u.body){destroyStream(u.body,e)}finalize()}));fixResponseChunkedTransferBadEnding(h,(function(e){if(m&&m.aborted){return}if(u&&u.body){destroyStream(u.body,e)}}));if(parseInt(process.version.substring(1))<14){h.on("socket",(function(e){e.addListener("close",(function(p){const a=e.listenerCount("data")>0;if(u&&a&&!p&&!(m&&m.aborted)){const e=new Error("Premature close");e.code="ERR_STREAM_PREMATURE_CLOSE";u.body.emit("error",e)}}))}))}h.on("response",(function(e){clearTimeout(g);const p=createHeadersLenient(e.headers);if(fetch.isRedirect(e.statusCode)){const d=p.get("Location");let t=null;try{t=d===null?null:new O(d,s.url).toString()}catch(e){if(s.redirect!=="manual"){r(new FetchError(`uri requested responds with an invalid redirect URL: ${d}`,"invalid-redirect"));finalize();return}}switch(s.redirect){case"error":r(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${s.url}`,"no-redirect"));finalize();return;case"manual":if(t!==null){try{p.set("Location",t)}catch(e){r(e)}}break;case"follow":if(t===null){break}if(s.counter>=s.follow){r(new FetchError(`maximum redirect reached at: ${s.url}`,"max-redirect"));finalize();return}const d={headers:new Headers(s.headers),follow:s.follow,counter:s.counter+1,agent:s.agent,compress:s.compress,method:s.method,body:s.body,signal:s.signal,timeout:s.timeout,size:s.size};if(!N(s.url,t)||!R(s.url,t)){for(const e of["authorization","www-authenticate","cookie","cookie2"]){d.headers.delete(e)}}if(e.statusCode!==303&&s.body&&getTotalBytes(s)===null){r(new FetchError("Cannot follow redirect with body being a readable stream","unsupported-redirect"));finalize();return}if(e.statusCode===303||(e.statusCode===301||e.statusCode===302)&&s.method==="POST"){d.method="GET";d.body=undefined;d.headers.delete("content-length")}a(fetch(new Request(t,d)));finalize();return}}e.once("end",(function(){if(m)m.removeEventListener("abort",v)}));let d=e.pipe(new k);const t={url:s.url,status:e.statusCode,statusText:e.statusMessage,headers:p,size:s.size,timeout:s.timeout,counter:s.counter};const i=p.get("Content-Encoding");if(!s.compress||s.method==="HEAD"||i===null||e.statusCode===204||e.statusCode===304){u=new Response(d,t);a(u);return}const n={flush:o.Z_SYNC_FLUSH,finishFlush:o.Z_SYNC_FLUSH};if(i=="gzip"||i=="x-gzip"){d=d.pipe(o.createGunzip(n));u=new Response(d,t);a(u);return}if(i=="deflate"||i=="x-deflate"){const p=e.pipe(new k);p.once("data",(function(e){if((e[0]&15)===8){d=d.pipe(o.createInflate())}else{d=d.pipe(o.createInflateRaw())}u=new Response(d,t);a(u)}));p.on("end",(function(){if(!u){u=new Response(d,t);a(u)}}));return}if(i=="br"&&typeof o.createBrotliDecompress==="function"){d=d.pipe(o.createBrotliDecompress());u=new Response(d,t);a(u);return}u=new Response(d,t);a(u)}));writeToStream(h,s)}))}function fixResponseChunkedTransferBadEnding(e,p){let a;e.on("socket",(function(e){a=e}));e.on("response",(function(e){const d=e.headers;if(d["transfer-encoding"]==="chunked"&&!d["content-length"]){e.once("close",(function(e){const d=a.listenerCount("data")>0;if(d&&!e){const e=new Error("Premature close");e.code="ERR_STREAM_PREMATURE_CLOSE";p(e)}}))}}))}function destroyStream(e,p){if(e.destroy){e.destroy(p)}else{e.emit("error",p);e.end()}}fetch.isRedirect=function(e){return e===301||e===302||e===303||e===307||e===308};fetch.Promise=global.Promise;e.exports=p=fetch;Object.defineProperty(p,"__esModule",{value:true});p["default"]=p;p.Headers=Headers;p.Request=Request;p.Response=Response;p.FetchError=FetchError},1223:(e,p,a)=>{var d=a(2940);e.exports=d(once);e.exports.strict=d(onceStrict);once.proto=once((function(){Object.defineProperty(Function.prototype,"once",{value:function(){return once(this)},configurable:true});Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return onceStrict(this)},configurable:true})}));function once(e){var f=function(){if(f.called)return f.value;f.called=true;return f.value=e.apply(this,arguments)};f.called=false;return f}function onceStrict(e){var f=function(){if(f.called)throw new Error(f.onceError);f.called=true;return f.value=e.apply(this,arguments)};var p=e.name||"Function wrapped with `once`";f.onceError=p+" shouldn't be called more than once";f.called=false;return f}},4256:(e,p,a)=>{var d=a(5477);var t=a(2020);var r={TRANSITIONAL:0,NONTRANSITIONAL:1};function normalize(e){return e.split("\0").map((function(e){return e.normalize("NFC")})).join("\0")}function findStatus(e){var p=0;var a=t.length-1;while(p<=a){var d=Math.floor((p+a)/2);var r=t[d];if(r[0][0]<=e&&r[0][1]>=e){return r}else if(r[0][0]>e){a=d-1}else{p=d+1}}return null}var s=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g;function countSymbols(e){return e.replace(s,"_").length}function mapChars(e,p,a){var d=false;var t="";var s=countSymbols(e);for(var i=0;i253||i.length===0){r.error=true}for(var o=0;o63||s.length===0){r.error=true;break}}}if(r.error)return null;return s.join(".")};e.exports.toUnicode=function(e,p){var a=processing(e,p,r.NONTRANSITIONAL);return{domain:a.string,error:a.error}};e.exports.PROCESSING_OPTIONS=r},4294:(e,p,a)=>{e.exports=a(4219)},4219:(e,p,a)=>{var d=a(1808);var t=a(4404);var r=a(3685);var s=a(5687);var i=a(2361);var o=a(9491);var n=a(3837);p.httpOverHttp=httpOverHttp;p.httpsOverHttp=httpsOverHttp;p.httpOverHttps=httpOverHttps;p.httpsOverHttps=httpsOverHttps;function httpOverHttp(e){var p=new TunnelingAgent(e);p.request=r.request;return p}function httpsOverHttp(e){var p=new TunnelingAgent(e);p.request=r.request;p.createSocket=createSecureSocket;p.defaultPort=443;return p}function httpOverHttps(e){var p=new TunnelingAgent(e);p.request=s.request;return p}function httpsOverHttps(e){var p=new TunnelingAgent(e);p.request=s.request;p.createSocket=createSecureSocket;p.defaultPort=443;return p}function TunnelingAgent(e){var p=this;p.options=e||{};p.proxyOptions=p.options.proxy||{};p.maxSockets=p.options.maxSockets||r.Agent.defaultMaxSockets;p.requests=[];p.sockets=[];p.on("free",(function onFree(e,a,d,t){var r=toOptions(a,d,t);for(var s=0,i=p.requests.length;s=this.maxSockets){t.requests.push(r);return}t.createSocket(r,(function(p){p.on("free",onFree);p.on("close",onCloseOrRemove);p.on("agentRemove",onCloseOrRemove);e.onSocket(p);function onFree(){t.emit("free",p,r)}function onCloseOrRemove(e){t.removeSocket(p);p.removeListener("free",onFree);p.removeListener("close",onCloseOrRemove);p.removeListener("agentRemove",onCloseOrRemove)}}))};TunnelingAgent.prototype.createSocket=function createSocket(e,p){var a=this;var d={};a.sockets.push(d);var t=mergeOptions({},a.proxyOptions,{method:"CONNECT",path:e.host+":"+e.port,agent:false,headers:{host:e.host+":"+e.port}});if(e.localAddress){t.localAddress=e.localAddress}if(t.proxyAuth){t.headers=t.headers||{};t.headers["Proxy-Authorization"]="Basic "+new Buffer(t.proxyAuth).toString("base64")}l("making CONNECT request");var r=a.request(t);r.useChunkedEncodingByDefault=false;r.once("response",onResponse);r.once("upgrade",onUpgrade);r.once("connect",onConnect);r.once("error",onError);r.end();function onResponse(e){e.upgrade=true}function onUpgrade(e,p,a){process.nextTick((function(){onConnect(e,p,a)}))}function onConnect(t,s,i){r.removeAllListeners();s.removeAllListeners();if(t.statusCode!==200){l("tunneling socket could not be established, statusCode=%d",t.statusCode);s.destroy();var o=new Error("tunneling socket could not be established, "+"statusCode="+t.statusCode);o.code="ECONNRESET";e.request.emit("error",o);a.removeSocket(d);return}if(i.length>0){l("got illegal response body from proxy");s.destroy();var o=new Error("got illegal response body from proxy");o.code="ECONNRESET";e.request.emit("error",o);a.removeSocket(d);return}l("tunneling connection has established");a.sockets[a.sockets.indexOf(d)]=s;return p(s)}function onError(p){r.removeAllListeners();l("tunneling socket could not be established, cause=%s\n",p.message,p.stack);var t=new Error("tunneling socket could not be established, "+"cause="+p.message);t.code="ECONNRESET";e.request.emit("error",t);a.removeSocket(d)}};TunnelingAgent.prototype.removeSocket=function removeSocket(e){var p=this.sockets.indexOf(e);if(p===-1){return}this.sockets.splice(p,1);var a=this.requests.shift();if(a){this.createSocket(a,(function(e){a.request.onSocket(e)}))}};function createSecureSocket(e,p){var a=this;TunnelingAgent.prototype.createSocket.call(a,e,(function(d){var r=e.request.getHeader("host");var s=mergeOptions({},a.options,{socket:d,servername:r?r.replace(/:.*$/,""):e.host});var i=t.connect(0,s);a.sockets[a.sockets.indexOf(d)]=i;p(i)}))}function toOptions(e,p,a){if(typeof e==="string"){return{host:e,port:p,localAddress:a}}return e}function mergeOptions(e){for(var p=1,a=arguments.length;p{Object.defineProperty(p,"__esModule",{value:true});function getUserAgent(){if(typeof navigator==="object"&&"userAgent"in navigator){return navigator.userAgent}if(typeof process==="object"&&"version"in process){return`Node.js/${process.version.substr(1)} (${process.platform}; ${process.arch})`}return""}p.getUserAgent=getUserAgent},5840:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});Object.defineProperty(p,"v1",{enumerable:true,get:function(){return d.default}});Object.defineProperty(p,"v3",{enumerable:true,get:function(){return t.default}});Object.defineProperty(p,"v4",{enumerable:true,get:function(){return r.default}});Object.defineProperty(p,"v5",{enumerable:true,get:function(){return s.default}});Object.defineProperty(p,"NIL",{enumerable:true,get:function(){return i.default}});Object.defineProperty(p,"version",{enumerable:true,get:function(){return o.default}});Object.defineProperty(p,"validate",{enumerable:true,get:function(){return n.default}});Object.defineProperty(p,"stringify",{enumerable:true,get:function(){return l.default}});Object.defineProperty(p,"parse",{enumerable:true,get:function(){return m.default}});var d=_interopRequireDefault(a(8628));var t=_interopRequireDefault(a(6409));var r=_interopRequireDefault(a(5122));var s=_interopRequireDefault(a(9120));var i=_interopRequireDefault(a(5332));var o=_interopRequireDefault(a(1595));var n=_interopRequireDefault(a(6900));var l=_interopRequireDefault(a(8950));var m=_interopRequireDefault(a(2746));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}},4569:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6113));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function md5(e){if(Array.isArray(e)){e=Buffer.from(e)}else if(typeof e==="string"){e=Buffer.from(e,"utf8")}return d.default.createHash("md5").update(e).digest()}var t=md5;p["default"]=t},5332:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var a="00000000-0000-0000-0000-000000000000";p["default"]=a},2746:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6900));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function parse(e){if(!(0,d.default)(e)){throw TypeError("Invalid UUID")}let p;const a=new Uint8Array(16);a[0]=(p=parseInt(e.slice(0,8),16))>>>24;a[1]=p>>>16&255;a[2]=p>>>8&255;a[3]=p&255;a[4]=(p=parseInt(e.slice(9,13),16))>>>8;a[5]=p&255;a[6]=(p=parseInt(e.slice(14,18),16))>>>8;a[7]=p&255;a[8]=(p=parseInt(e.slice(19,23),16))>>>8;a[9]=p&255;a[10]=(p=parseInt(e.slice(24,36),16))/1099511627776&255;a[11]=p/4294967296&255;a[12]=p>>>24&255;a[13]=p>>>16&255;a[14]=p>>>8&255;a[15]=p&255;return a}var t=parse;p["default"]=t},814:(e,p)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var a=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;p["default"]=a},807:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=rng;var d=_interopRequireDefault(a(6113));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const t=new Uint8Array(256);let r=t.length;function rng(){if(r>t.length-16){d.default.randomFillSync(t);r=0}return t.slice(r,r+=16)}},5274:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6113));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function sha1(e){if(Array.isArray(e)){e=Buffer.from(e)}else if(typeof e==="string"){e=Buffer.from(e,"utf8")}return d.default.createHash("sha1").update(e).digest()}var t=sha1;p["default"]=t},8950:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6900));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const t=[];for(let e=0;e<256;++e){t.push((e+256).toString(16).substr(1))}function stringify(e,p=0){const a=(t[e[p+0]]+t[e[p+1]]+t[e[p+2]]+t[e[p+3]]+"-"+t[e[p+4]]+t[e[p+5]]+"-"+t[e[p+6]]+t[e[p+7]]+"-"+t[e[p+8]]+t[e[p+9]]+"-"+t[e[p+10]]+t[e[p+11]]+t[e[p+12]]+t[e[p+13]]+t[e[p+14]]+t[e[p+15]]).toLowerCase();if(!(0,d.default)(a)){throw TypeError("Stringified UUID is invalid")}return a}var r=stringify;p["default"]=r},8628:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(807));var t=_interopRequireDefault(a(8950));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}let r;let s;let i=0;let o=0;function v1(e,p,a){let n=p&&a||0;const l=p||new Array(16);e=e||{};let m=e.node||r;let u=e.clockseq!==undefined?e.clockseq:s;if(m==null||u==null){const p=e.random||(e.rng||d.default)();if(m==null){m=r=[p[0]|1,p[1],p[2],p[3],p[4],p[5]]}if(u==null){u=s=(p[6]<<8|p[7])&16383}}let c=e.msecs!==undefined?e.msecs:Date.now();let v=e.nsecs!==undefined?e.nsecs:o+1;const h=c-i+(v-o)/1e4;if(h<0&&e.clockseq===undefined){u=u+1&16383}if((h<0||c>i)&&e.nsecs===undefined){v=0}if(v>=1e4){throw new Error("uuid.v1(): Can't create more than 10M uuids/sec")}i=c;o=v;s=u;c+=122192928e5;const g=((c&268435455)*1e4+v)%4294967296;l[n++]=g>>>24&255;l[n++]=g>>>16&255;l[n++]=g>>>8&255;l[n++]=g&255;const w=c/4294967296*1e4&268435455;l[n++]=w>>>8&255;l[n++]=w&255;l[n++]=w>>>24&15|16;l[n++]=w>>>16&255;l[n++]=u>>>8|128;l[n++]=u&255;for(let e=0;e<6;++e){l[n+e]=m[e]}return p||(0,t.default)(l)}var n=v1;p["default"]=n},6409:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(5998));var t=_interopRequireDefault(a(4569));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const r=(0,d.default)("v3",48,t.default);var s=r;p["default"]=s},5998:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=_default;p.URL=p.DNS=void 0;var d=_interopRequireDefault(a(8950));var t=_interopRequireDefault(a(2746));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function stringToBytes(e){e=unescape(encodeURIComponent(e));const p=[];for(let a=0;a{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(807));var t=_interopRequireDefault(a(8950));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function v4(e,p,a){e=e||{};const r=e.random||(e.rng||d.default)();r[6]=r[6]&15|64;r[8]=r[8]&63|128;if(p){a=a||0;for(let e=0;e<16;++e){p[a+e]=r[e]}return p}return(0,t.default)(r)}var r=v4;p["default"]=r},9120:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(5998));var t=_interopRequireDefault(a(5274));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const r=(0,d.default)("v5",80,t.default);var s=r;p["default"]=s},6900:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(814));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function validate(e){return typeof e==="string"&&d.default.test(e)}var t=validate;p["default"]=t},1595:(e,p,a)=>{Object.defineProperty(p,"__esModule",{value:true});p["default"]=void 0;var d=_interopRequireDefault(a(6900));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function version(e){if(!(0,d.default)(e)){throw TypeError("Invalid UUID")}return parseInt(e.substr(14,1),16)}var t=version;p["default"]=t},4886:e=>{var p={};e.exports=p;function sign(e){return e<0?-1:1}function evenRound(e){if(e%1===.5&&(e&1)===0){return Math.floor(e)}else{return Math.round(e)}}function createNumberConversion(e,p){if(!p.unsigned){--e}const a=p.unsigned?0:-Math.pow(2,e);const d=Math.pow(2,e)-1;const t=p.moduloBitLength?Math.pow(2,p.moduloBitLength):Math.pow(2,e);const r=p.moduloBitLength?Math.pow(2,p.moduloBitLength-1):Math.pow(2,e-1);return function(e,s){if(!s)s={};let i=+e;if(s.enforceRange){if(!Number.isFinite(i)){throw new TypeError("Argument is not a finite number")}i=sign(i)*Math.floor(Math.abs(i));if(id){throw new TypeError("Argument is not in byte range")}return i}if(!isNaN(i)&&s.clamp){i=evenRound(i);if(id)i=d;return i}if(!Number.isFinite(i)||i===0){return 0}i=sign(i)*Math.floor(Math.abs(i));i=i%t;if(!p.unsigned&&i>=r){return i-t}else if(p.unsigned){if(i<0){i+=t}else if(i===-0){return 0}}return i}}p["void"]=function(){return undefined};p["boolean"]=function(e){return!!e};p["byte"]=createNumberConversion(8,{unsigned:false});p["octet"]=createNumberConversion(8,{unsigned:true});p["short"]=createNumberConversion(16,{unsigned:false});p["unsigned short"]=createNumberConversion(16,{unsigned:true});p["long"]=createNumberConversion(32,{unsigned:false});p["unsigned long"]=createNumberConversion(32,{unsigned:true});p["long long"]=createNumberConversion(32,{unsigned:false,moduloBitLength:64});p["unsigned long long"]=createNumberConversion(32,{unsigned:true,moduloBitLength:64});p["double"]=function(e){const p=+e;if(!Number.isFinite(p)){throw new TypeError("Argument is not a finite floating-point value")}return p};p["unrestricted double"]=function(e){const p=+e;if(isNaN(p)){throw new TypeError("Argument is NaN")}return p};p["float"]=p["double"];p["unrestricted float"]=p["unrestricted double"];p["DOMString"]=function(e,p){if(!p)p={};if(p.treatNullAsEmptyString&&e===null){return""}return String(e)};p["ByteString"]=function(e,p){const a=String(e);let d=undefined;for(let e=0;(d=a.codePointAt(e))!==undefined;++e){if(d>255){throw new TypeError("Argument is not a valid bytestring")}}return a};p["USVString"]=function(e){const p=String(e);const a=p.length;const d=[];for(let e=0;e57343){d.push(String.fromCodePoint(t))}else if(56320<=t&&t<=57343){d.push(String.fromCodePoint(65533))}else{if(e===a-1){d.push(String.fromCodePoint(65533))}else{const a=p.charCodeAt(e+1);if(56320<=a&&a<=57343){const p=t&1023;const r=a&1023;d.push(String.fromCodePoint((2<<15)+(2<<9)*p+r));++e}else{d.push(String.fromCodePoint(65533))}}}}return d.join("")};p["Date"]=function(e,p){if(!(e instanceof Date)){throw new TypeError("Argument is not a Date object")}if(isNaN(e)){return undefined}return e};p["RegExp"]=function(e,p){if(!(e instanceof RegExp)){e=new RegExp(e)}return e}},7537:(e,p,a)=>{const d=a(2158);p.implementation=class URLImpl{constructor(e){const p=e[0];const a=e[1];let t=null;if(a!==undefined){t=d.basicURLParse(a);if(t==="failure"){throw new TypeError("Invalid base URL")}}const r=d.basicURLParse(p,{baseURL:t});if(r==="failure"){throw new TypeError("Invalid URL")}this._url=r}get href(){return d.serializeURL(this._url)}set href(e){const p=d.basicURLParse(e);if(p==="failure"){throw new TypeError("Invalid URL")}this._url=p}get origin(){return d.serializeURLOrigin(this._url)}get protocol(){return this._url.scheme+":"}set protocol(e){d.basicURLParse(e+":",{url:this._url,stateOverride:"scheme start"})}get username(){return this._url.username}set username(e){if(d.cannotHaveAUsernamePasswordPort(this._url)){return}d.setTheUsername(this._url,e)}get password(){return this._url.password}set password(e){if(d.cannotHaveAUsernamePasswordPort(this._url)){return}d.setThePassword(this._url,e)}get host(){const e=this._url;if(e.host===null){return""}if(e.port===null){return d.serializeHost(e.host)}return d.serializeHost(e.host)+":"+d.serializeInteger(e.port)}set host(e){if(this._url.cannotBeABaseURL){return}d.basicURLParse(e,{url:this._url,stateOverride:"host"})}get hostname(){if(this._url.host===null){return""}return d.serializeHost(this._url.host)}set hostname(e){if(this._url.cannotBeABaseURL){return}d.basicURLParse(e,{url:this._url,stateOverride:"hostname"})}get port(){if(this._url.port===null){return""}return d.serializeInteger(this._url.port)}set port(e){if(d.cannotHaveAUsernamePasswordPort(this._url)){return}if(e===""){this._url.port=null}else{d.basicURLParse(e,{url:this._url,stateOverride:"port"})}}get pathname(){if(this._url.cannotBeABaseURL){return this._url.path[0]}if(this._url.path.length===0){return""}return"/"+this._url.path.join("/")}set pathname(e){if(this._url.cannotBeABaseURL){return}this._url.path=[];d.basicURLParse(e,{url:this._url,stateOverride:"path start"})}get search(){if(this._url.query===null||this._url.query===""){return""}return"?"+this._url.query}set search(e){const p=this._url;if(e===""){p.query=null;return}const a=e[0]==="?"?e.substring(1):e;p.query="";d.basicURLParse(a,{url:p,stateOverride:"query"})}get hash(){if(this._url.fragment===null||this._url.fragment===""){return""}return"#"+this._url.fragment}set hash(e){if(e===""){this._url.fragment=null;return}const p=e[0]==="#"?e.substring(1):e;this._url.fragment="";d.basicURLParse(p,{url:this._url,stateOverride:"fragment"})}toJSON(){return this.href}}},3394:(e,p,a)=>{const d=a(4886);const t=a(3185);const r=a(7537);const s=t.implSymbol;function URL(p){if(!this||this[s]||!(this instanceof URL)){throw new TypeError("Failed to construct 'URL': Please use the 'new' operator, this DOM object constructor cannot be called as a function.")}if(arguments.length<1){throw new TypeError("Failed to construct 'URL': 1 argument required, but only "+arguments.length+" present.")}const a=[];for(let e=0;e{p.URL=a(3394)["interface"];p.serializeURL=a(2158).serializeURL;p.serializeURLOrigin=a(2158).serializeURLOrigin;p.basicURLParse=a(2158).basicURLParse;p.setTheUsername=a(2158).setTheUsername;p.setThePassword=a(2158).setThePassword;p.serializeHost=a(2158).serializeHost;p.serializeInteger=a(2158).serializeInteger;p.parseURL=a(2158).parseURL},2158:(e,p,a)=>{const d=a(5477);const t=a(4256);const r={ftp:21,file:null,gopher:70,http:80,https:443,ws:80,wss:443};const s=Symbol("failure");function countSymbols(e){return d.ucs2.decode(e).length}function at(e,p){const a=e[p];return isNaN(a)?undefined:String.fromCodePoint(a)}function isASCIIDigit(e){return e>=48&&e<=57}function isASCIIAlpha(e){return e>=65&&e<=90||e>=97&&e<=122}function isASCIIAlphanumeric(e){return isASCIIAlpha(e)||isASCIIDigit(e)}function isASCIIHex(e){return isASCIIDigit(e)||e>=65&&e<=70||e>=97&&e<=102}function isSingleDot(e){return e==="."||e.toLowerCase()==="%2e"}function isDoubleDot(e){e=e.toLowerCase();return e===".."||e==="%2e."||e===".%2e"||e==="%2e%2e"}function isWindowsDriveLetterCodePoints(e,p){return isASCIIAlpha(e)&&(p===58||p===124)}function isWindowsDriveLetterString(e){return e.length===2&&isASCIIAlpha(e.codePointAt(0))&&(e[1]===":"||e[1]==="|")}function isNormalizedWindowsDriveLetterString(e){return e.length===2&&isASCIIAlpha(e.codePointAt(0))&&e[1]===":"}function containsForbiddenHostCodePoint(e){return e.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/)!==-1}function containsForbiddenHostCodePointExcludingPercent(e){return e.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/)!==-1}function isSpecialScheme(e){return r[e]!==undefined}function isSpecial(e){return isSpecialScheme(e.scheme)}function defaultPort(e){return r[e]}function percentEncode(e){let p=e.toString(16).toUpperCase();if(p.length===1){p="0"+p}return"%"+p}function utf8PercentEncode(e){const p=new Buffer(e);let a="";for(let e=0;e126}const i=new Set([32,34,35,60,62,63,96,123,125]);function isPathPercentEncode(e){return isC0ControlPercentEncode(e)||i.has(e)}const o=new Set([47,58,59,61,64,91,92,93,94,124]);function isUserinfoPercentEncode(e){return isPathPercentEncode(e)||o.has(e)}function percentEncodeChar(e,p){const a=String.fromCodePoint(e);if(p(e)){return utf8PercentEncode(a)}return a}function parseIPv4Number(e){let p=10;if(e.length>=2&&e.charAt(0)==="0"&&e.charAt(1).toLowerCase()==="x"){e=e.substring(2);p=16}else if(e.length>=2&&e.charAt(0)==="0"){e=e.substring(1);p=8}if(e===""){return 0}const a=p===10?/[^0-9]/:p===16?/[^0-9A-Fa-f]/:/[^0-7]/;if(a.test(e)){return s}return parseInt(e,p)}function parseIPv4(e){const p=e.split(".");if(p[p.length-1]===""){if(p.length>1){p.pop()}}if(p.length>4){return e}const a=[];for(const d of p){if(d===""){return e}const p=parseIPv4Number(d);if(p===s){return e}a.push(p)}for(let e=0;e255){return s}}if(a[a.length-1]>=Math.pow(256,5-a.length)){return s}let d=a.pop();let t=0;for(const e of a){d+=e*Math.pow(256,3-t);++t}return d}function serializeIPv4(e){let p="";let a=e;for(let e=1;e<=4;++e){p=String(a%256)+p;if(e!==4){p="."+p}a=Math.floor(a/256)}return p}function parseIPv6(e){const p=[0,0,0,0,0,0,0,0];let a=0;let t=null;let r=0;e=d.ucs2.decode(e);if(e[r]===58){if(e[r+1]!==58){return s}r+=2;++a;t=a}while(r6){return s}let d=0;while(e[r]!==undefined){let t=null;if(d>0){if(e[r]===46&&d<4){++r}else{return s}}if(!isASCIIDigit(e[r])){return s}while(isASCIIDigit(e[r])){const p=parseInt(at(e,r));if(t===null){t=p}else if(t===0){return s}else{t=t*10+p}if(t>255){return s}++r}p[a]=p[a]*256+t;++d;if(d===2||d===4){++a}}if(d!==4){return s}break}else if(e[r]===58){++r;if(e[r]===undefined){return s}}else if(e[r]!==undefined){return s}p[a]=d;++a}if(t!==null){let e=a-t;a=7;while(a!==0&&e>0){const d=p[t+e-1];p[t+e-1]=p[a];p[a]=d;--a;--e}}else if(t===null&&a!==8){return s}return p}function serializeIPv6(e){let p="";const a=findLongestZeroSequence(e);const d=a.idx;let t=false;for(let a=0;a<=7;++a){if(t&&e[a]===0){continue}else if(t){t=false}if(d===a){const e=a===0?"::":":";p+=e;t=true;continue}p+=e[a].toString(16);if(a!==7){p+=":"}}return p}function parseHost(e,p){if(e[0]==="["){if(e[e.length-1]!=="]"){return s}return parseIPv6(e.substring(1,e.length-1))}if(!p){return parseOpaqueHost(e)}const a=utf8PercentDecode(e);const d=t.toASCII(a,false,t.PROCESSING_OPTIONS.NONTRANSITIONAL,false);if(d===null){return s}if(containsForbiddenHostCodePoint(d)){return s}const r=parseIPv4(d);if(typeof r==="number"||r===s){return r}return d}function parseOpaqueHost(e){if(containsForbiddenHostCodePointExcludingPercent(e)){return s}let p="";const a=d.ucs2.decode(e);for(let e=0;ea){p=d;a=t}d=null;t=0}else{if(d===null){d=r}++t}}if(t>a){p=d;a=t}return{idx:p,len:a}}function serializeHost(e){if(typeof e==="number"){return serializeIPv4(e)}if(e instanceof Array){return"["+serializeIPv6(e)+"]"}return e}function trimControlChars(e){return e.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g,"")}function trimTabAndNewline(e){return e.replace(/\u0009|\u000A|\u000D/g,"")}function shortenPath(e){const p=e.path;if(p.length===0){return}if(e.scheme==="file"&&p.length===1&&isNormalizedWindowsDriveLetter(p[0])){return}p.pop()}function includesCredentials(e){return e.username!==""||e.password!==""}function cannotHaveAUsernamePasswordPort(e){return e.host===null||e.host===""||e.cannotBeABaseURL||e.scheme==="file"}function isNormalizedWindowsDriveLetter(e){return/^[A-Za-z]:$/.test(e)}function URLStateMachine(e,p,a,t,r){this.pointer=0;this.input=e;this.base=p||null;this.encodingOverride=a||"utf-8";this.stateOverride=r;this.url=t;this.failure=false;this.parseError=false;if(!this.url){this.url={scheme:"",username:"",password:"",host:null,port:null,path:[],query:null,fragment:null,cannotBeABaseURL:false};const e=trimControlChars(this.input);if(e!==this.input){this.parseError=true}this.input=e}const i=trimTabAndNewline(this.input);if(i!==this.input){this.parseError=true}this.input=i;this.state=r||"scheme start";this.buffer="";this.atFlag=false;this.arrFlag=false;this.passwordTokenSeenFlag=false;this.input=d.ucs2.decode(this.input);for(;this.pointer<=this.input.length;++this.pointer){const e=this.input[this.pointer];const p=isNaN(e)?undefined:String.fromCodePoint(e);const a=this["parse "+this.state](e,p);if(!a){break}else if(a===s){this.failure=true;break}}}URLStateMachine.prototype["parse scheme start"]=function parseSchemeStart(e,p){if(isASCIIAlpha(e)){this.buffer+=p.toLowerCase();this.state="scheme"}else if(!this.stateOverride){this.state="no scheme";--this.pointer}else{this.parseError=true;return s}return true};URLStateMachine.prototype["parse scheme"]=function parseScheme(e,p){if(isASCIIAlphanumeric(e)||e===43||e===45||e===46){this.buffer+=p.toLowerCase()}else if(e===58){if(this.stateOverride){if(isSpecial(this.url)&&!isSpecialScheme(this.buffer)){return false}if(!isSpecial(this.url)&&isSpecialScheme(this.buffer)){return false}if((includesCredentials(this.url)||this.url.port!==null)&&this.buffer==="file"){return false}if(this.url.scheme==="file"&&(this.url.host===""||this.url.host===null)){return false}}this.url.scheme=this.buffer;this.buffer="";if(this.stateOverride){return false}if(this.url.scheme==="file"){if(this.input[this.pointer+1]!==47||this.input[this.pointer+2]!==47){this.parseError=true}this.state="file"}else if(isSpecial(this.url)&&this.base!==null&&this.base.scheme===this.url.scheme){this.state="special relative or authority"}else if(isSpecial(this.url)){this.state="special authority slashes"}else if(this.input[this.pointer+1]===47){this.state="path or authority";++this.pointer}else{this.url.cannotBeABaseURL=true;this.url.path.push("");this.state="cannot-be-a-base-URL path"}}else if(!this.stateOverride){this.buffer="";this.state="no scheme";this.pointer=-1}else{this.parseError=true;return s}return true};URLStateMachine.prototype["parse no scheme"]=function parseNoScheme(e){if(this.base===null||this.base.cannotBeABaseURL&&e!==35){return s}else if(this.base.cannotBeABaseURL&&e===35){this.url.scheme=this.base.scheme;this.url.path=this.base.path.slice();this.url.query=this.base.query;this.url.fragment="";this.url.cannotBeABaseURL=true;this.state="fragment"}else if(this.base.scheme==="file"){this.state="file";--this.pointer}else{this.state="relative";--this.pointer}return true};URLStateMachine.prototype["parse special relative or authority"]=function parseSpecialRelativeOrAuthority(e){if(e===47&&this.input[this.pointer+1]===47){this.state="special authority ignore slashes";++this.pointer}else{this.parseError=true;this.state="relative";--this.pointer}return true};URLStateMachine.prototype["parse path or authority"]=function parsePathOrAuthority(e){if(e===47){this.state="authority"}else{this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse relative"]=function parseRelative(e){this.url.scheme=this.base.scheme;if(isNaN(e)){this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice();this.url.query=this.base.query}else if(e===47){this.state="relative slash"}else if(e===63){this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice();this.url.query="";this.state="query"}else if(e===35){this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice();this.url.query=this.base.query;this.url.fragment="";this.state="fragment"}else if(isSpecial(this.url)&&e===92){this.parseError=true;this.state="relative slash"}else{this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.url.path=this.base.path.slice(0,this.base.path.length-1);this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse relative slash"]=function parseRelativeSlash(e){if(isSpecial(this.url)&&(e===47||e===92)){if(e===92){this.parseError=true}this.state="special authority ignore slashes"}else if(e===47){this.state="authority"}else{this.url.username=this.base.username;this.url.password=this.base.password;this.url.host=this.base.host;this.url.port=this.base.port;this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse special authority slashes"]=function parseSpecialAuthoritySlashes(e){if(e===47&&this.input[this.pointer+1]===47){this.state="special authority ignore slashes";++this.pointer}else{this.parseError=true;this.state="special authority ignore slashes";--this.pointer}return true};URLStateMachine.prototype["parse special authority ignore slashes"]=function parseSpecialAuthorityIgnoreSlashes(e){if(e!==47&&e!==92){this.state="authority";--this.pointer}else{this.parseError=true}return true};URLStateMachine.prototype["parse authority"]=function parseAuthority(e,p){if(e===64){this.parseError=true;if(this.atFlag){this.buffer="%40"+this.buffer}this.atFlag=true;const e=countSymbols(this.buffer);for(let p=0;pMath.pow(2,16)-1){this.parseError=true;return s}this.url.port=e===defaultPort(this.url.scheme)?null:e;this.buffer=""}if(this.stateOverride){return false}this.state="path start";--this.pointer}else{this.parseError=true;return s}return true};const n=new Set([47,92,63,35]);URLStateMachine.prototype["parse file"]=function parseFile(e){this.url.scheme="file";if(e===47||e===92){if(e===92){this.parseError=true}this.state="file slash"}else if(this.base!==null&&this.base.scheme==="file"){if(isNaN(e)){this.url.host=this.base.host;this.url.path=this.base.path.slice();this.url.query=this.base.query}else if(e===63){this.url.host=this.base.host;this.url.path=this.base.path.slice();this.url.query="";this.state="query"}else if(e===35){this.url.host=this.base.host;this.url.path=this.base.path.slice();this.url.query=this.base.query;this.url.fragment="";this.state="fragment"}else{if(this.input.length-this.pointer-1===0||!isWindowsDriveLetterCodePoints(e,this.input[this.pointer+1])||this.input.length-this.pointer-1>=2&&!n.has(this.input[this.pointer+2])){this.url.host=this.base.host;this.url.path=this.base.path.slice();shortenPath(this.url)}else{this.parseError=true}this.state="path";--this.pointer}}else{this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse file slash"]=function parseFileSlash(e){if(e===47||e===92){if(e===92){this.parseError=true}this.state="file host"}else{if(this.base!==null&&this.base.scheme==="file"){if(isNormalizedWindowsDriveLetterString(this.base.path[0])){this.url.path.push(this.base.path[0])}else{this.url.host=this.base.host}}this.state="path";--this.pointer}return true};URLStateMachine.prototype["parse file host"]=function parseFileHost(e,p){if(isNaN(e)||e===47||e===92||e===63||e===35){--this.pointer;if(!this.stateOverride&&isWindowsDriveLetterString(this.buffer)){this.parseError=true;this.state="path"}else if(this.buffer===""){this.url.host="";if(this.stateOverride){return false}this.state="path start"}else{let e=parseHost(this.buffer,isSpecial(this.url));if(e===s){return s}if(e==="localhost"){e=""}this.url.host=e;if(this.stateOverride){return false}this.buffer="";this.state="path start"}}else{this.buffer+=p}return true};URLStateMachine.prototype["parse path start"]=function parsePathStart(e){if(isSpecial(this.url)){if(e===92){this.parseError=true}this.state="path";if(e!==47&&e!==92){--this.pointer}}else if(!this.stateOverride&&e===63){this.url.query="";this.state="query"}else if(!this.stateOverride&&e===35){this.url.fragment="";this.state="fragment"}else if(e!==undefined){this.state="path";if(e!==47){--this.pointer}}return true};URLStateMachine.prototype["parse path"]=function parsePath(e){if(isNaN(e)||e===47||isSpecial(this.url)&&e===92||!this.stateOverride&&(e===63||e===35)){if(isSpecial(this.url)&&e===92){this.parseError=true}if(isDoubleDot(this.buffer)){shortenPath(this.url);if(e!==47&&!(isSpecial(this.url)&&e===92)){this.url.path.push("")}}else if(isSingleDot(this.buffer)&&e!==47&&!(isSpecial(this.url)&&e===92)){this.url.path.push("")}else if(!isSingleDot(this.buffer)){if(this.url.scheme==="file"&&this.url.path.length===0&&isWindowsDriveLetterString(this.buffer)){if(this.url.host!==""&&this.url.host!==null){this.parseError=true;this.url.host=""}this.buffer=this.buffer[0]+":"}this.url.path.push(this.buffer)}this.buffer="";if(this.url.scheme==="file"&&(e===undefined||e===63||e===35)){while(this.url.path.length>1&&this.url.path[0]===""){this.parseError=true;this.url.path.shift()}}if(e===63){this.url.query="";this.state="query"}if(e===35){this.url.fragment="";this.state="fragment"}}else{if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}this.buffer+=percentEncodeChar(e,isPathPercentEncode)}return true};URLStateMachine.prototype["parse cannot-be-a-base-URL path"]=function parseCannotBeABaseURLPath(e){if(e===63){this.url.query="";this.state="query"}else if(e===35){this.url.fragment="";this.state="fragment"}else{if(!isNaN(e)&&e!==37){this.parseError=true}if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}if(!isNaN(e)){this.url.path[0]=this.url.path[0]+percentEncodeChar(e,isC0ControlPercentEncode)}}return true};URLStateMachine.prototype["parse query"]=function parseQuery(e,p){if(isNaN(e)||!this.stateOverride&&e===35){if(!isSpecial(this.url)||this.url.scheme==="ws"||this.url.scheme==="wss"){this.encodingOverride="utf-8"}const p=new Buffer(this.buffer);for(let e=0;e126||p[e]===34||p[e]===35||p[e]===60||p[e]===62){this.url.query+=percentEncode(p[e])}else{this.url.query+=String.fromCodePoint(p[e])}}this.buffer="";if(e===35){this.url.fragment="";this.state="fragment"}}else{if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}this.buffer+=p}return true};URLStateMachine.prototype["parse fragment"]=function parseFragment(e){if(isNaN(e)){}else if(e===0){this.parseError=true}else{if(e===37&&(!isASCIIHex(this.input[this.pointer+1])||!isASCIIHex(this.input[this.pointer+2]))){this.parseError=true}this.url.fragment+=percentEncodeChar(e,isC0ControlPercentEncode)}return true};function serializeURL(e,p){let a=e.scheme+":";if(e.host!==null){a+="//";if(e.username!==""||e.password!==""){a+=e.username;if(e.password!==""){a+=":"+e.password}a+="@"}a+=serializeHost(e.host);if(e.port!==null){a+=":"+e.port}}else if(e.host===null&&e.scheme==="file"){a+="//"}if(e.cannotBeABaseURL){a+=e.path[0]}else{for(const p of e.path){a+="/"+p}}if(e.query!==null){a+="?"+e.query}if(!p&&e.fragment!==null){a+="#"+e.fragment}return a}function serializeOrigin(e){let p=e.scheme+"://";p+=serializeHost(e.host);if(e.port!==null){p+=":"+e.port}return p}e.exports.serializeURL=serializeURL;e.exports.serializeURLOrigin=function(p){switch(p.scheme){case"blob":try{return e.exports.serializeURLOrigin(e.exports.parseURL(p.path[0]))}catch(e){return"null"}case"ftp":case"gopher":case"http":case"https":case"ws":case"wss":return serializeOrigin({scheme:p.scheme,host:p.host,port:p.port});case"file":return"file://";default:return"null"}};e.exports.basicURLParse=function(e,p){if(p===undefined){p={}}const a=new URLStateMachine(e,p.baseURL,p.encodingOverride,p.url,p.stateOverride);if(a.failure){return"failure"}return a.url};e.exports.setTheUsername=function(e,p){e.username="";const a=d.ucs2.decode(p);for(let p=0;p{e.exports.mixin=function mixin(e,p){const a=Object.getOwnPropertyNames(p);for(let d=0;d{e.exports=wrappy;function wrappy(e,p){if(e&&p)return wrappy(e)(p);if(typeof e!=="function")throw new TypeError("need wrapper function");Object.keys(e).forEach((function(p){wrapper[p]=e[p]}));return wrapper;function wrapper(){var p=new Array(arguments.length);for(var a=0;a{module.exports=eval("require")("encoding")},9491:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("assert")},6113:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("crypto")},2361:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("events")},7147:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("fs")},3685:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("http")},5687:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("https")},1808:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("net")},2037:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("os")},1017:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("path")},5477:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("punycode")},2781:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("stream")},4404:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("tls")},7310:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("url")},3837:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("util")},9796:e=>{e.exports=__WEBPACK_EXTERNAL_createRequire(import.meta.url)("zlib")},2020:e=>{e.exports=JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"],[[47,47],"disallowed_STD3_valid"],[[48,57],"valid"],[[58,64],"disallowed_STD3_valid"],[[65,65],"mapped",[97]],[[66,66],"mapped",[98]],[[67,67],"mapped",[99]],[[68,68],"mapped",[100]],[[69,69],"mapped",[101]],[[70,70],"mapped",[102]],[[71,71],"mapped",[103]],[[72,72],"mapped",[104]],[[73,73],"mapped",[105]],[[74,74],"mapped",[106]],[[75,75],"mapped",[107]],[[76,76],"mapped",[108]],[[77,77],"mapped",[109]],[[78,78],"mapped",[110]],[[79,79],"mapped",[111]],[[80,80],"mapped",[112]],[[81,81],"mapped",[113]],[[82,82],"mapped",[114]],[[83,83],"mapped",[115]],[[84,84],"mapped",[116]],[[85,85],"mapped",[117]],[[86,86],"mapped",[118]],[[87,87],"mapped",[119]],[[88,88],"mapped",[120]],[[89,89],"mapped",[121]],[[90,90],"mapped",[122]],[[91,96],"disallowed_STD3_valid"],[[97,122],"valid"],[[123,127],"disallowed_STD3_valid"],[[128,159],"disallowed"],[[160,160],"disallowed_STD3_mapped",[32]],[[161,167],"valid",[],"NV8"],[[168,168],"disallowed_STD3_mapped",[32,776]],[[169,169],"valid",[],"NV8"],[[170,170],"mapped",[97]],[[171,172],"valid",[],"NV8"],[[173,173],"ignored"],[[174,174],"valid",[],"NV8"],[[175,175],"disallowed_STD3_mapped",[32,772]],[[176,177],"valid",[],"NV8"],[[178,178],"mapped",[50]],[[179,179],"mapped",[51]],[[180,180],"disallowed_STD3_mapped",[32,769]],[[181,181],"mapped",[956]],[[182,182],"valid",[],"NV8"],[[183,183],"valid"],[[184,184],"disallowed_STD3_mapped",[32,807]],[[185,185],"mapped",[49]],[[186,186],"mapped",[111]],[[187,187],"valid",[],"NV8"],[[188,188],"mapped",[49,8260,52]],[[189,189],"mapped",[49,8260,50]],[[190,190],"mapped",[51,8260,52]],[[191,191],"valid",[],"NV8"],[[192,192],"mapped",[224]],[[193,193],"mapped",[225]],[[194,194],"mapped",[226]],[[195,195],"mapped",[227]],[[196,196],"mapped",[228]],[[197,197],"mapped",[229]],[[198,198],"mapped",[230]],[[199,199],"mapped",[231]],[[200,200],"mapped",[232]],[[201,201],"mapped",[233]],[[202,202],"mapped",[234]],[[203,203],"mapped",[235]],[[204,204],"mapped",[236]],[[205,205],"mapped",[237]],[[206,206],"mapped",[238]],[[207,207],"mapped",[239]],[[208,208],"mapped",[240]],[[209,209],"mapped",[241]],[[210,210],"mapped",[242]],[[211,211],"mapped",[243]],[[212,212],"mapped",[244]],[[213,213],"mapped",[245]],[[214,214],"mapped",[246]],[[215,215],"valid",[],"NV8"],[[216,216],"mapped",[248]],[[217,217],"mapped",[249]],[[218,218],"mapped",[250]],[[219,219],"mapped",[251]],[[220,220],"mapped",[252]],[[221,221],"mapped",[253]],[[222,222],"mapped",[254]],[[223,223],"deviation",[115,115]],[[224,246],"valid"],[[247,247],"valid",[],"NV8"],[[248,255],"valid"],[[256,256],"mapped",[257]],[[257,257],"valid"],[[258,258],"mapped",[259]],[[259,259],"valid"],[[260,260],"mapped",[261]],[[261,261],"valid"],[[262,262],"mapped",[263]],[[263,263],"valid"],[[264,264],"mapped",[265]],[[265,265],"valid"],[[266,266],"mapped",[267]],[[267,267],"valid"],[[268,268],"mapped",[269]],[[269,269],"valid"],[[270,270],"mapped",[271]],[[271,271],"valid"],[[272,272],"mapped",[273]],[[273,273],"valid"],[[274,274],"mapped",[275]],[[275,275],"valid"],[[276,276],"mapped",[277]],[[277,277],"valid"],[[278,278],"mapped",[279]],[[279,279],"valid"],[[280,280],"mapped",[281]],[[281,281],"valid"],[[282,282],"mapped",[283]],[[283,283],"valid"],[[284,284],"mapped",[285]],[[285,285],"valid"],[[286,286],"mapped",[287]],[[287,287],"valid"],[[288,288],"mapped",[289]],[[289,289],"valid"],[[290,290],"mapped",[291]],[[291,291],"valid"],[[292,292],"mapped",[293]],[[293,293],"valid"],[[294,294],"mapped",[295]],[[295,295],"valid"],[[296,296],"mapped",[297]],[[297,297],"valid"],[[298,298],"mapped",[299]],[[299,299],"valid"],[[300,300],"mapped",[301]],[[301,301],"valid"],[[302,302],"mapped",[303]],[[303,303],"valid"],[[304,304],"mapped",[105,775]],[[305,305],"valid"],[[306,307],"mapped",[105,106]],[[308,308],"mapped",[309]],[[309,309],"valid"],[[310,310],"mapped",[311]],[[311,312],"valid"],[[313,313],"mapped",[314]],[[314,314],"valid"],[[315,315],"mapped",[316]],[[316,316],"valid"],[[317,317],"mapped",[318]],[[318,318],"valid"],[[319,320],"mapped",[108,183]],[[321,321],"mapped",[322]],[[322,322],"valid"],[[323,323],"mapped",[324]],[[324,324],"valid"],[[325,325],"mapped",[326]],[[326,326],"valid"],[[327,327],"mapped",[328]],[[328,328],"valid"],[[329,329],"mapped",[700,110]],[[330,330],"mapped",[331]],[[331,331],"valid"],[[332,332],"mapped",[333]],[[333,333],"valid"],[[334,334],"mapped",[335]],[[335,335],"valid"],[[336,336],"mapped",[337]],[[337,337],"valid"],[[338,338],"mapped",[339]],[[339,339],"valid"],[[340,340],"mapped",[341]],[[341,341],"valid"],[[342,342],"mapped",[343]],[[343,343],"valid"],[[344,344],"mapped",[345]],[[345,345],"valid"],[[346,346],"mapped",[347]],[[347,347],"valid"],[[348,348],"mapped",[349]],[[349,349],"valid"],[[350,350],"mapped",[351]],[[351,351],"valid"],[[352,352],"mapped",[353]],[[353,353],"valid"],[[354,354],"mapped",[355]],[[355,355],"valid"],[[356,356],"mapped",[357]],[[357,357],"valid"],[[358,358],"mapped",[359]],[[359,359],"valid"],[[360,360],"mapped",[361]],[[361,361],"valid"],[[362,362],"mapped",[363]],[[363,363],"valid"],[[364,364],"mapped",[365]],[[365,365],"valid"],[[366,366],"mapped",[367]],[[367,367],"valid"],[[368,368],"mapped",[369]],[[369,369],"valid"],[[370,370],"mapped",[371]],[[371,371],"valid"],[[372,372],"mapped",[373]],[[373,373],"valid"],[[374,374],"mapped",[375]],[[375,375],"valid"],[[376,376],"mapped",[255]],[[377,377],"mapped",[378]],[[378,378],"valid"],[[379,379],"mapped",[380]],[[380,380],"valid"],[[381,381],"mapped",[382]],[[382,382],"valid"],[[383,383],"mapped",[115]],[[384,384],"valid"],[[385,385],"mapped",[595]],[[386,386],"mapped",[387]],[[387,387],"valid"],[[388,388],"mapped",[389]],[[389,389],"valid"],[[390,390],"mapped",[596]],[[391,391],"mapped",[392]],[[392,392],"valid"],[[393,393],"mapped",[598]],[[394,394],"mapped",[599]],[[395,395],"mapped",[396]],[[396,397],"valid"],[[398,398],"mapped",[477]],[[399,399],"mapped",[601]],[[400,400],"mapped",[603]],[[401,401],"mapped",[402]],[[402,402],"valid"],[[403,403],"mapped",[608]],[[404,404],"mapped",[611]],[[405,405],"valid"],[[406,406],"mapped",[617]],[[407,407],"mapped",[616]],[[408,408],"mapped",[409]],[[409,411],"valid"],[[412,412],"mapped",[623]],[[413,413],"mapped",[626]],[[414,414],"valid"],[[415,415],"mapped",[629]],[[416,416],"mapped",[417]],[[417,417],"valid"],[[418,418],"mapped",[419]],[[419,419],"valid"],[[420,420],"mapped",[421]],[[421,421],"valid"],[[422,422],"mapped",[640]],[[423,423],"mapped",[424]],[[424,424],"valid"],[[425,425],"mapped",[643]],[[426,427],"valid"],[[428,428],"mapped",[429]],[[429,429],"valid"],[[430,430],"mapped",[648]],[[431,431],"mapped",[432]],[[432,432],"valid"],[[433,433],"mapped",[650]],[[434,434],"mapped",[651]],[[435,435],"mapped",[436]],[[436,436],"valid"],[[437,437],"mapped",[438]],[[438,438],"valid"],[[439,439],"mapped",[658]],[[440,440],"mapped",[441]],[[441,443],"valid"],[[444,444],"mapped",[445]],[[445,451],"valid"],[[452,454],"mapped",[100,382]],[[455,457],"mapped",[108,106]],[[458,460],"mapped",[110,106]],[[461,461],"mapped",[462]],[[462,462],"valid"],[[463,463],"mapped",[464]],[[464,464],"valid"],[[465,465],"mapped",[466]],[[466,466],"valid"],[[467,467],"mapped",[468]],[[468,468],"valid"],[[469,469],"mapped",[470]],[[470,470],"valid"],[[471,471],"mapped",[472]],[[472,472],"valid"],[[473,473],"mapped",[474]],[[474,474],"valid"],[[475,475],"mapped",[476]],[[476,477],"valid"],[[478,478],"mapped",[479]],[[479,479],"valid"],[[480,480],"mapped",[481]],[[481,481],"valid"],[[482,482],"mapped",[483]],[[483,483],"valid"],[[484,484],"mapped",[485]],[[485,485],"valid"],[[486,486],"mapped",[487]],[[487,487],"valid"],[[488,488],"mapped",[489]],[[489,489],"valid"],[[490,490],"mapped",[491]],[[491,491],"valid"],[[492,492],"mapped",[493]],[[493,493],"valid"],[[494,494],"mapped",[495]],[[495,496],"valid"],[[497,499],"mapped",[100,122]],[[500,500],"mapped",[501]],[[501,501],"valid"],[[502,502],"mapped",[405]],[[503,503],"mapped",[447]],[[504,504],"mapped",[505]],[[505,505],"valid"],[[506,506],"mapped",[507]],[[507,507],"valid"],[[508,508],"mapped",[509]],[[509,509],"valid"],[[510,510],"mapped",[511]],[[511,511],"valid"],[[512,512],"mapped",[513]],[[513,513],"valid"],[[514,514],"mapped",[515]],[[515,515],"valid"],[[516,516],"mapped",[517]],[[517,517],"valid"],[[518,518],"mapped",[519]],[[519,519],"valid"],[[520,520],"mapped",[521]],[[521,521],"valid"],[[522,522],"mapped",[523]],[[523,523],"valid"],[[524,524],"mapped",[525]],[[525,525],"valid"],[[526,526],"mapped",[527]],[[527,527],"valid"],[[528,528],"mapped",[529]],[[529,529],"valid"],[[530,530],"mapped",[531]],[[531,531],"valid"],[[532,532],"mapped",[533]],[[533,533],"valid"],[[534,534],"mapped",[535]],[[535,535],"valid"],[[536,536],"mapped",[537]],[[537,537],"valid"],[[538,538],"mapped",[539]],[[539,539],"valid"],[[540,540],"mapped",[541]],[[541,541],"valid"],[[542,542],"mapped",[543]],[[543,543],"valid"],[[544,544],"mapped",[414]],[[545,545],"valid"],[[546,546],"mapped",[547]],[[547,547],"valid"],[[548,548],"mapped",[549]],[[549,549],"valid"],[[550,550],"mapped",[551]],[[551,551],"valid"],[[552,552],"mapped",[553]],[[553,553],"valid"],[[554,554],"mapped",[555]],[[555,555],"valid"],[[556,556],"mapped",[557]],[[557,557],"valid"],[[558,558],"mapped",[559]],[[559,559],"valid"],[[560,560],"mapped",[561]],[[561,561],"valid"],[[562,562],"mapped",[563]],[[563,563],"valid"],[[564,566],"valid"],[[567,569],"valid"],[[570,570],"mapped",[11365]],[[571,571],"mapped",[572]],[[572,572],"valid"],[[573,573],"mapped",[410]],[[574,574],"mapped",[11366]],[[575,576],"valid"],[[577,577],"mapped",[578]],[[578,578],"valid"],[[579,579],"mapped",[384]],[[580,580],"mapped",[649]],[[581,581],"mapped",[652]],[[582,582],"mapped",[583]],[[583,583],"valid"],[[584,584],"mapped",[585]],[[585,585],"valid"],[[586,586],"mapped",[587]],[[587,587],"valid"],[[588,588],"mapped",[589]],[[589,589],"valid"],[[590,590],"mapped",[591]],[[591,591],"valid"],[[592,680],"valid"],[[681,685],"valid"],[[686,687],"valid"],[[688,688],"mapped",[104]],[[689,689],"mapped",[614]],[[690,690],"mapped",[106]],[[691,691],"mapped",[114]],[[692,692],"mapped",[633]],[[693,693],"mapped",[635]],[[694,694],"mapped",[641]],[[695,695],"mapped",[119]],[[696,696],"mapped",[121]],[[697,705],"valid"],[[706,709],"valid",[],"NV8"],[[710,721],"valid"],[[722,727],"valid",[],"NV8"],[[728,728],"disallowed_STD3_mapped",[32,774]],[[729,729],"disallowed_STD3_mapped",[32,775]],[[730,730],"disallowed_STD3_mapped",[32,778]],[[731,731],"disallowed_STD3_mapped",[32,808]],[[732,732],"disallowed_STD3_mapped",[32,771]],[[733,733],"disallowed_STD3_mapped",[32,779]],[[734,734],"valid",[],"NV8"],[[735,735],"valid",[],"NV8"],[[736,736],"mapped",[611]],[[737,737],"mapped",[108]],[[738,738],"mapped",[115]],[[739,739],"mapped",[120]],[[740,740],"mapped",[661]],[[741,745],"valid",[],"NV8"],[[746,747],"valid",[],"NV8"],[[748,748],"valid"],[[749,749],"valid",[],"NV8"],[[750,750],"valid"],[[751,767],"valid",[],"NV8"],[[768,831],"valid"],[[832,832],"mapped",[768]],[[833,833],"mapped",[769]],[[834,834],"valid"],[[835,835],"mapped",[787]],[[836,836],"mapped",[776,769]],[[837,837],"mapped",[953]],[[838,846],"valid"],[[847,847],"ignored"],[[848,855],"valid"],[[856,860],"valid"],[[861,863],"valid"],[[864,865],"valid"],[[866,866],"valid"],[[867,879],"valid"],[[880,880],"mapped",[881]],[[881,881],"valid"],[[882,882],"mapped",[883]],[[883,883],"valid"],[[884,884],"mapped",[697]],[[885,885],"valid"],[[886,886],"mapped",[887]],[[887,887],"valid"],[[888,889],"disallowed"],[[890,890],"disallowed_STD3_mapped",[32,953]],[[891,893],"valid"],[[894,894],"disallowed_STD3_mapped",[59]],[[895,895],"mapped",[1011]],[[896,899],"disallowed"],[[900,900],"disallowed_STD3_mapped",[32,769]],[[901,901],"disallowed_STD3_mapped",[32,776,769]],[[902,902],"mapped",[940]],[[903,903],"mapped",[183]],[[904,904],"mapped",[941]],[[905,905],"mapped",[942]],[[906,906],"mapped",[943]],[[907,907],"disallowed"],[[908,908],"mapped",[972]],[[909,909],"disallowed"],[[910,910],"mapped",[973]],[[911,911],"mapped",[974]],[[912,912],"valid"],[[913,913],"mapped",[945]],[[914,914],"mapped",[946]],[[915,915],"mapped",[947]],[[916,916],"mapped",[948]],[[917,917],"mapped",[949]],[[918,918],"mapped",[950]],[[919,919],"mapped",[951]],[[920,920],"mapped",[952]],[[921,921],"mapped",[953]],[[922,922],"mapped",[954]],[[923,923],"mapped",[955]],[[924,924],"mapped",[956]],[[925,925],"mapped",[957]],[[926,926],"mapped",[958]],[[927,927],"mapped",[959]],[[928,928],"mapped",[960]],[[929,929],"mapped",[961]],[[930,930],"disallowed"],[[931,931],"mapped",[963]],[[932,932],"mapped",[964]],[[933,933],"mapped",[965]],[[934,934],"mapped",[966]],[[935,935],"mapped",[967]],[[936,936],"mapped",[968]],[[937,937],"mapped",[969]],[[938,938],"mapped",[970]],[[939,939],"mapped",[971]],[[940,961],"valid"],[[962,962],"deviation",[963]],[[963,974],"valid"],[[975,975],"mapped",[983]],[[976,976],"mapped",[946]],[[977,977],"mapped",[952]],[[978,978],"mapped",[965]],[[979,979],"mapped",[973]],[[980,980],"mapped",[971]],[[981,981],"mapped",[966]],[[982,982],"mapped",[960]],[[983,983],"valid"],[[984,984],"mapped",[985]],[[985,985],"valid"],[[986,986],"mapped",[987]],[[987,987],"valid"],[[988,988],"mapped",[989]],[[989,989],"valid"],[[990,990],"mapped",[991]],[[991,991],"valid"],[[992,992],"mapped",[993]],[[993,993],"valid"],[[994,994],"mapped",[995]],[[995,995],"valid"],[[996,996],"mapped",[997]],[[997,997],"valid"],[[998,998],"mapped",[999]],[[999,999],"valid"],[[1000,1000],"mapped",[1001]],[[1001,1001],"valid"],[[1002,1002],"mapped",[1003]],[[1003,1003],"valid"],[[1004,1004],"mapped",[1005]],[[1005,1005],"valid"],[[1006,1006],"mapped",[1007]],[[1007,1007],"valid"],[[1008,1008],"mapped",[954]],[[1009,1009],"mapped",[961]],[[1010,1010],"mapped",[963]],[[1011,1011],"valid"],[[1012,1012],"mapped",[952]],[[1013,1013],"mapped",[949]],[[1014,1014],"valid",[],"NV8"],[[1015,1015],"mapped",[1016]],[[1016,1016],"valid"],[[1017,1017],"mapped",[963]],[[1018,1018],"mapped",[1019]],[[1019,1019],"valid"],[[1020,1020],"valid"],[[1021,1021],"mapped",[891]],[[1022,1022],"mapped",[892]],[[1023,1023],"mapped",[893]],[[1024,1024],"mapped",[1104]],[[1025,1025],"mapped",[1105]],[[1026,1026],"mapped",[1106]],[[1027,1027],"mapped",[1107]],[[1028,1028],"mapped",[1108]],[[1029,1029],"mapped",[1109]],[[1030,1030],"mapped",[1110]],[[1031,1031],"mapped",[1111]],[[1032,1032],"mapped",[1112]],[[1033,1033],"mapped",[1113]],[[1034,1034],"mapped",[1114]],[[1035,1035],"mapped",[1115]],[[1036,1036],"mapped",[1116]],[[1037,1037],"mapped",[1117]],[[1038,1038],"mapped",[1118]],[[1039,1039],"mapped",[1119]],[[1040,1040],"mapped",[1072]],[[1041,1041],"mapped",[1073]],[[1042,1042],"mapped",[1074]],[[1043,1043],"mapped",[1075]],[[1044,1044],"mapped",[1076]],[[1045,1045],"mapped",[1077]],[[1046,1046],"mapped",[1078]],[[1047,1047],"mapped",[1079]],[[1048,1048],"mapped",[1080]],[[1049,1049],"mapped",[1081]],[[1050,1050],"mapped",[1082]],[[1051,1051],"mapped",[1083]],[[1052,1052],"mapped",[1084]],[[1053,1053],"mapped",[1085]],[[1054,1054],"mapped",[1086]],[[1055,1055],"mapped",[1087]],[[1056,1056],"mapped",[1088]],[[1057,1057],"mapped",[1089]],[[1058,1058],"mapped",[1090]],[[1059,1059],"mapped",[1091]],[[1060,1060],"mapped",[1092]],[[1061,1061],"mapped",[1093]],[[1062,1062],"mapped",[1094]],[[1063,1063],"mapped",[1095]],[[1064,1064],"mapped",[1096]],[[1065,1065],"mapped",[1097]],[[1066,1066],"mapped",[1098]],[[1067,1067],"mapped",[1099]],[[1068,1068],"mapped",[1100]],[[1069,1069],"mapped",[1101]],[[1070,1070],"mapped",[1102]],[[1071,1071],"mapped",[1103]],[[1072,1103],"valid"],[[1104,1104],"valid"],[[1105,1116],"valid"],[[1117,1117],"valid"],[[1118,1119],"valid"],[[1120,1120],"mapped",[1121]],[[1121,1121],"valid"],[[1122,1122],"mapped",[1123]],[[1123,1123],"valid"],[[1124,1124],"mapped",[1125]],[[1125,1125],"valid"],[[1126,1126],"mapped",[1127]],[[1127,1127],"valid"],[[1128,1128],"mapped",[1129]],[[1129,1129],"valid"],[[1130,1130],"mapped",[1131]],[[1131,1131],"valid"],[[1132,1132],"mapped",[1133]],[[1133,1133],"valid"],[[1134,1134],"mapped",[1135]],[[1135,1135],"valid"],[[1136,1136],"mapped",[1137]],[[1137,1137],"valid"],[[1138,1138],"mapped",[1139]],[[1139,1139],"valid"],[[1140,1140],"mapped",[1141]],[[1141,1141],"valid"],[[1142,1142],"mapped",[1143]],[[1143,1143],"valid"],[[1144,1144],"mapped",[1145]],[[1145,1145],"valid"],[[1146,1146],"mapped",[1147]],[[1147,1147],"valid"],[[1148,1148],"mapped",[1149]],[[1149,1149],"valid"],[[1150,1150],"mapped",[1151]],[[1151,1151],"valid"],[[1152,1152],"mapped",[1153]],[[1153,1153],"valid"],[[1154,1154],"valid",[],"NV8"],[[1155,1158],"valid"],[[1159,1159],"valid"],[[1160,1161],"valid",[],"NV8"],[[1162,1162],"mapped",[1163]],[[1163,1163],"valid"],[[1164,1164],"mapped",[1165]],[[1165,1165],"valid"],[[1166,1166],"mapped",[1167]],[[1167,1167],"valid"],[[1168,1168],"mapped",[1169]],[[1169,1169],"valid"],[[1170,1170],"mapped",[1171]],[[1171,1171],"valid"],[[1172,1172],"mapped",[1173]],[[1173,1173],"valid"],[[1174,1174],"mapped",[1175]],[[1175,1175],"valid"],[[1176,1176],"mapped",[1177]],[[1177,1177],"valid"],[[1178,1178],"mapped",[1179]],[[1179,1179],"valid"],[[1180,1180],"mapped",[1181]],[[1181,1181],"valid"],[[1182,1182],"mapped",[1183]],[[1183,1183],"valid"],[[1184,1184],"mapped",[1185]],[[1185,1185],"valid"],[[1186,1186],"mapped",[1187]],[[1187,1187],"valid"],[[1188,1188],"mapped",[1189]],[[1189,1189],"valid"],[[1190,1190],"mapped",[1191]],[[1191,1191],"valid"],[[1192,1192],"mapped",[1193]],[[1193,1193],"valid"],[[1194,1194],"mapped",[1195]],[[1195,1195],"valid"],[[1196,1196],"mapped",[1197]],[[1197,1197],"valid"],[[1198,1198],"mapped",[1199]],[[1199,1199],"valid"],[[1200,1200],"mapped",[1201]],[[1201,1201],"valid"],[[1202,1202],"mapped",[1203]],[[1203,1203],"valid"],[[1204,1204],"mapped",[1205]],[[1205,1205],"valid"],[[1206,1206],"mapped",[1207]],[[1207,1207],"valid"],[[1208,1208],"mapped",[1209]],[[1209,1209],"valid"],[[1210,1210],"mapped",[1211]],[[1211,1211],"valid"],[[1212,1212],"mapped",[1213]],[[1213,1213],"valid"],[[1214,1214],"mapped",[1215]],[[1215,1215],"valid"],[[1216,1216],"disallowed"],[[1217,1217],"mapped",[1218]],[[1218,1218],"valid"],[[1219,1219],"mapped",[1220]],[[1220,1220],"valid"],[[1221,1221],"mapped",[1222]],[[1222,1222],"valid"],[[1223,1223],"mapped",[1224]],[[1224,1224],"valid"],[[1225,1225],"mapped",[1226]],[[1226,1226],"valid"],[[1227,1227],"mapped",[1228]],[[1228,1228],"valid"],[[1229,1229],"mapped",[1230]],[[1230,1230],"valid"],[[1231,1231],"valid"],[[1232,1232],"mapped",[1233]],[[1233,1233],"valid"],[[1234,1234],"mapped",[1235]],[[1235,1235],"valid"],[[1236,1236],"mapped",[1237]],[[1237,1237],"valid"],[[1238,1238],"mapped",[1239]],[[1239,1239],"valid"],[[1240,1240],"mapped",[1241]],[[1241,1241],"valid"],[[1242,1242],"mapped",[1243]],[[1243,1243],"valid"],[[1244,1244],"mapped",[1245]],[[1245,1245],"valid"],[[1246,1246],"mapped",[1247]],[[1247,1247],"valid"],[[1248,1248],"mapped",[1249]],[[1249,1249],"valid"],[[1250,1250],"mapped",[1251]],[[1251,1251],"valid"],[[1252,1252],"mapped",[1253]],[[1253,1253],"valid"],[[1254,1254],"mapped",[1255]],[[1255,1255],"valid"],[[1256,1256],"mapped",[1257]],[[1257,1257],"valid"],[[1258,1258],"mapped",[1259]],[[1259,1259],"valid"],[[1260,1260],"mapped",[1261]],[[1261,1261],"valid"],[[1262,1262],"mapped",[1263]],[[1263,1263],"valid"],[[1264,1264],"mapped",[1265]],[[1265,1265],"valid"],[[1266,1266],"mapped",[1267]],[[1267,1267],"valid"],[[1268,1268],"mapped",[1269]],[[1269,1269],"valid"],[[1270,1270],"mapped",[1271]],[[1271,1271],"valid"],[[1272,1272],"mapped",[1273]],[[1273,1273],"valid"],[[1274,1274],"mapped",[1275]],[[1275,1275],"valid"],[[1276,1276],"mapped",[1277]],[[1277,1277],"valid"],[[1278,1278],"mapped",[1279]],[[1279,1279],"valid"],[[1280,1280],"mapped",[1281]],[[1281,1281],"valid"],[[1282,1282],"mapped",[1283]],[[1283,1283],"valid"],[[1284,1284],"mapped",[1285]],[[1285,1285],"valid"],[[1286,1286],"mapped",[1287]],[[1287,1287],"valid"],[[1288,1288],"mapped",[1289]],[[1289,1289],"valid"],[[1290,1290],"mapped",[1291]],[[1291,1291],"valid"],[[1292,1292],"mapped",[1293]],[[1293,1293],"valid"],[[1294,1294],"mapped",[1295]],[[1295,1295],"valid"],[[1296,1296],"mapped",[1297]],[[1297,1297],"valid"],[[1298,1298],"mapped",[1299]],[[1299,1299],"valid"],[[1300,1300],"mapped",[1301]],[[1301,1301],"valid"],[[1302,1302],"mapped",[1303]],[[1303,1303],"valid"],[[1304,1304],"mapped",[1305]],[[1305,1305],"valid"],[[1306,1306],"mapped",[1307]],[[1307,1307],"valid"],[[1308,1308],"mapped",[1309]],[[1309,1309],"valid"],[[1310,1310],"mapped",[1311]],[[1311,1311],"valid"],[[1312,1312],"mapped",[1313]],[[1313,1313],"valid"],[[1314,1314],"mapped",[1315]],[[1315,1315],"valid"],[[1316,1316],"mapped",[1317]],[[1317,1317],"valid"],[[1318,1318],"mapped",[1319]],[[1319,1319],"valid"],[[1320,1320],"mapped",[1321]],[[1321,1321],"valid"],[[1322,1322],"mapped",[1323]],[[1323,1323],"valid"],[[1324,1324],"mapped",[1325]],[[1325,1325],"valid"],[[1326,1326],"mapped",[1327]],[[1327,1327],"valid"],[[1328,1328],"disallowed"],[[1329,1329],"mapped",[1377]],[[1330,1330],"mapped",[1378]],[[1331,1331],"mapped",[1379]],[[1332,1332],"mapped",[1380]],[[1333,1333],"mapped",[1381]],[[1334,1334],"mapped",[1382]],[[1335,1335],"mapped",[1383]],[[1336,1336],"mapped",[1384]],[[1337,1337],"mapped",[1385]],[[1338,1338],"mapped",[1386]],[[1339,1339],"mapped",[1387]],[[1340,1340],"mapped",[1388]],[[1341,1341],"mapped",[1389]],[[1342,1342],"mapped",[1390]],[[1343,1343],"mapped",[1391]],[[1344,1344],"mapped",[1392]],[[1345,1345],"mapped",[1393]],[[1346,1346],"mapped",[1394]],[[1347,1347],"mapped",[1395]],[[1348,1348],"mapped",[1396]],[[1349,1349],"mapped",[1397]],[[1350,1350],"mapped",[1398]],[[1351,1351],"mapped",[1399]],[[1352,1352],"mapped",[1400]],[[1353,1353],"mapped",[1401]],[[1354,1354],"mapped",[1402]],[[1355,1355],"mapped",[1403]],[[1356,1356],"mapped",[1404]],[[1357,1357],"mapped",[1405]],[[1358,1358],"mapped",[1406]],[[1359,1359],"mapped",[1407]],[[1360,1360],"mapped",[1408]],[[1361,1361],"mapped",[1409]],[[1362,1362],"mapped",[1410]],[[1363,1363],"mapped",[1411]],[[1364,1364],"mapped",[1412]],[[1365,1365],"mapped",[1413]],[[1366,1366],"mapped",[1414]],[[1367,1368],"disallowed"],[[1369,1369],"valid"],[[1370,1375],"valid",[],"NV8"],[[1376,1376],"disallowed"],[[1377,1414],"valid"],[[1415,1415],"mapped",[1381,1410]],[[1416,1416],"disallowed"],[[1417,1417],"valid",[],"NV8"],[[1418,1418],"valid",[],"NV8"],[[1419,1420],"disallowed"],[[1421,1422],"valid",[],"NV8"],[[1423,1423],"valid",[],"NV8"],[[1424,1424],"disallowed"],[[1425,1441],"valid"],[[1442,1442],"valid"],[[1443,1455],"valid"],[[1456,1465],"valid"],[[1466,1466],"valid"],[[1467,1469],"valid"],[[1470,1470],"valid",[],"NV8"],[[1471,1471],"valid"],[[1472,1472],"valid",[],"NV8"],[[1473,1474],"valid"],[[1475,1475],"valid",[],"NV8"],[[1476,1476],"valid"],[[1477,1477],"valid"],[[1478,1478],"valid",[],"NV8"],[[1479,1479],"valid"],[[1480,1487],"disallowed"],[[1488,1514],"valid"],[[1515,1519],"disallowed"],[[1520,1524],"valid"],[[1525,1535],"disallowed"],[[1536,1539],"disallowed"],[[1540,1540],"disallowed"],[[1541,1541],"disallowed"],[[1542,1546],"valid",[],"NV8"],[[1547,1547],"valid",[],"NV8"],[[1548,1548],"valid",[],"NV8"],[[1549,1551],"valid",[],"NV8"],[[1552,1557],"valid"],[[1558,1562],"valid"],[[1563,1563],"valid",[],"NV8"],[[1564,1564],"disallowed"],[[1565,1565],"disallowed"],[[1566,1566],"valid",[],"NV8"],[[1567,1567],"valid",[],"NV8"],[[1568,1568],"valid"],[[1569,1594],"valid"],[[1595,1599],"valid"],[[1600,1600],"valid",[],"NV8"],[[1601,1618],"valid"],[[1619,1621],"valid"],[[1622,1624],"valid"],[[1625,1630],"valid"],[[1631,1631],"valid"],[[1632,1641],"valid"],[[1642,1645],"valid",[],"NV8"],[[1646,1647],"valid"],[[1648,1652],"valid"],[[1653,1653],"mapped",[1575,1652]],[[1654,1654],"mapped",[1608,1652]],[[1655,1655],"mapped",[1735,1652]],[[1656,1656],"mapped",[1610,1652]],[[1657,1719],"valid"],[[1720,1721],"valid"],[[1722,1726],"valid"],[[1727,1727],"valid"],[[1728,1742],"valid"],[[1743,1743],"valid"],[[1744,1747],"valid"],[[1748,1748],"valid",[],"NV8"],[[1749,1756],"valid"],[[1757,1757],"disallowed"],[[1758,1758],"valid",[],"NV8"],[[1759,1768],"valid"],[[1769,1769],"valid",[],"NV8"],[[1770,1773],"valid"],[[1774,1775],"valid"],[[1776,1785],"valid"],[[1786,1790],"valid"],[[1791,1791],"valid"],[[1792,1805],"valid",[],"NV8"],[[1806,1806],"disallowed"],[[1807,1807],"disallowed"],[[1808,1836],"valid"],[[1837,1839],"valid"],[[1840,1866],"valid"],[[1867,1868],"disallowed"],[[1869,1871],"valid"],[[1872,1901],"valid"],[[1902,1919],"valid"],[[1920,1968],"valid"],[[1969,1969],"valid"],[[1970,1983],"disallowed"],[[1984,2037],"valid"],[[2038,2042],"valid",[],"NV8"],[[2043,2047],"disallowed"],[[2048,2093],"valid"],[[2094,2095],"disallowed"],[[2096,2110],"valid",[],"NV8"],[[2111,2111],"disallowed"],[[2112,2139],"valid"],[[2140,2141],"disallowed"],[[2142,2142],"valid",[],"NV8"],[[2143,2207],"disallowed"],[[2208,2208],"valid"],[[2209,2209],"valid"],[[2210,2220],"valid"],[[2221,2226],"valid"],[[2227,2228],"valid"],[[2229,2274],"disallowed"],[[2275,2275],"valid"],[[2276,2302],"valid"],[[2303,2303],"valid"],[[2304,2304],"valid"],[[2305,2307],"valid"],[[2308,2308],"valid"],[[2309,2361],"valid"],[[2362,2363],"valid"],[[2364,2381],"valid"],[[2382,2382],"valid"],[[2383,2383],"valid"],[[2384,2388],"valid"],[[2389,2389],"valid"],[[2390,2391],"valid"],[[2392,2392],"mapped",[2325,2364]],[[2393,2393],"mapped",[2326,2364]],[[2394,2394],"mapped",[2327,2364]],[[2395,2395],"mapped",[2332,2364]],[[2396,2396],"mapped",[2337,2364]],[[2397,2397],"mapped",[2338,2364]],[[2398,2398],"mapped",[2347,2364]],[[2399,2399],"mapped",[2351,2364]],[[2400,2403],"valid"],[[2404,2405],"valid",[],"NV8"],[[2406,2415],"valid"],[[2416,2416],"valid",[],"NV8"],[[2417,2418],"valid"],[[2419,2423],"valid"],[[2424,2424],"valid"],[[2425,2426],"valid"],[[2427,2428],"valid"],[[2429,2429],"valid"],[[2430,2431],"valid"],[[2432,2432],"valid"],[[2433,2435],"valid"],[[2436,2436],"disallowed"],[[2437,2444],"valid"],[[2445,2446],"disallowed"],[[2447,2448],"valid"],[[2449,2450],"disallowed"],[[2451,2472],"valid"],[[2473,2473],"disallowed"],[[2474,2480],"valid"],[[2481,2481],"disallowed"],[[2482,2482],"valid"],[[2483,2485],"disallowed"],[[2486,2489],"valid"],[[2490,2491],"disallowed"],[[2492,2492],"valid"],[[2493,2493],"valid"],[[2494,2500],"valid"],[[2501,2502],"disallowed"],[[2503,2504],"valid"],[[2505,2506],"disallowed"],[[2507,2509],"valid"],[[2510,2510],"valid"],[[2511,2518],"disallowed"],[[2519,2519],"valid"],[[2520,2523],"disallowed"],[[2524,2524],"mapped",[2465,2492]],[[2525,2525],"mapped",[2466,2492]],[[2526,2526],"disallowed"],[[2527,2527],"mapped",[2479,2492]],[[2528,2531],"valid"],[[2532,2533],"disallowed"],[[2534,2545],"valid"],[[2546,2554],"valid",[],"NV8"],[[2555,2555],"valid",[],"NV8"],[[2556,2560],"disallowed"],[[2561,2561],"valid"],[[2562,2562],"valid"],[[2563,2563],"valid"],[[2564,2564],"disallowed"],[[2565,2570],"valid"],[[2571,2574],"disallowed"],[[2575,2576],"valid"],[[2577,2578],"disallowed"],[[2579,2600],"valid"],[[2601,2601],"disallowed"],[[2602,2608],"valid"],[[2609,2609],"disallowed"],[[2610,2610],"valid"],[[2611,2611],"mapped",[2610,2620]],[[2612,2612],"disallowed"],[[2613,2613],"valid"],[[2614,2614],"mapped",[2616,2620]],[[2615,2615],"disallowed"],[[2616,2617],"valid"],[[2618,2619],"disallowed"],[[2620,2620],"valid"],[[2621,2621],"disallowed"],[[2622,2626],"valid"],[[2627,2630],"disallowed"],[[2631,2632],"valid"],[[2633,2634],"disallowed"],[[2635,2637],"valid"],[[2638,2640],"disallowed"],[[2641,2641],"valid"],[[2642,2648],"disallowed"],[[2649,2649],"mapped",[2582,2620]],[[2650,2650],"mapped",[2583,2620]],[[2651,2651],"mapped",[2588,2620]],[[2652,2652],"valid"],[[2653,2653],"disallowed"],[[2654,2654],"mapped",[2603,2620]],[[2655,2661],"disallowed"],[[2662,2676],"valid"],[[2677,2677],"valid"],[[2678,2688],"disallowed"],[[2689,2691],"valid"],[[2692,2692],"disallowed"],[[2693,2699],"valid"],[[2700,2700],"valid"],[[2701,2701],"valid"],[[2702,2702],"disallowed"],[[2703,2705],"valid"],[[2706,2706],"disallowed"],[[2707,2728],"valid"],[[2729,2729],"disallowed"],[[2730,2736],"valid"],[[2737,2737],"disallowed"],[[2738,2739],"valid"],[[2740,2740],"disallowed"],[[2741,2745],"valid"],[[2746,2747],"disallowed"],[[2748,2757],"valid"],[[2758,2758],"disallowed"],[[2759,2761],"valid"],[[2762,2762],"disallowed"],[[2763,2765],"valid"],[[2766,2767],"disallowed"],[[2768,2768],"valid"],[[2769,2783],"disallowed"],[[2784,2784],"valid"],[[2785,2787],"valid"],[[2788,2789],"disallowed"],[[2790,2799],"valid"],[[2800,2800],"valid",[],"NV8"],[[2801,2801],"valid",[],"NV8"],[[2802,2808],"disallowed"],[[2809,2809],"valid"],[[2810,2816],"disallowed"],[[2817,2819],"valid"],[[2820,2820],"disallowed"],[[2821,2828],"valid"],[[2829,2830],"disallowed"],[[2831,2832],"valid"],[[2833,2834],"disallowed"],[[2835,2856],"valid"],[[2857,2857],"disallowed"],[[2858,2864],"valid"],[[2865,2865],"disallowed"],[[2866,2867],"valid"],[[2868,2868],"disallowed"],[[2869,2869],"valid"],[[2870,2873],"valid"],[[2874,2875],"disallowed"],[[2876,2883],"valid"],[[2884,2884],"valid"],[[2885,2886],"disallowed"],[[2887,2888],"valid"],[[2889,2890],"disallowed"],[[2891,2893],"valid"],[[2894,2901],"disallowed"],[[2902,2903],"valid"],[[2904,2907],"disallowed"],[[2908,2908],"mapped",[2849,2876]],[[2909,2909],"mapped",[2850,2876]],[[2910,2910],"disallowed"],[[2911,2913],"valid"],[[2914,2915],"valid"],[[2916,2917],"disallowed"],[[2918,2927],"valid"],[[2928,2928],"valid",[],"NV8"],[[2929,2929],"valid"],[[2930,2935],"valid",[],"NV8"],[[2936,2945],"disallowed"],[[2946,2947],"valid"],[[2948,2948],"disallowed"],[[2949,2954],"valid"],[[2955,2957],"disallowed"],[[2958,2960],"valid"],[[2961,2961],"disallowed"],[[2962,2965],"valid"],[[2966,2968],"disallowed"],[[2969,2970],"valid"],[[2971,2971],"disallowed"],[[2972,2972],"valid"],[[2973,2973],"disallowed"],[[2974,2975],"valid"],[[2976,2978],"disallowed"],[[2979,2980],"valid"],[[2981,2983],"disallowed"],[[2984,2986],"valid"],[[2987,2989],"disallowed"],[[2990,2997],"valid"],[[2998,2998],"valid"],[[2999,3001],"valid"],[[3002,3005],"disallowed"],[[3006,3010],"valid"],[[3011,3013],"disallowed"],[[3014,3016],"valid"],[[3017,3017],"disallowed"],[[3018,3021],"valid"],[[3022,3023],"disallowed"],[[3024,3024],"valid"],[[3025,3030],"disallowed"],[[3031,3031],"valid"],[[3032,3045],"disallowed"],[[3046,3046],"valid"],[[3047,3055],"valid"],[[3056,3058],"valid",[],"NV8"],[[3059,3066],"valid",[],"NV8"],[[3067,3071],"disallowed"],[[3072,3072],"valid"],[[3073,3075],"valid"],[[3076,3076],"disallowed"],[[3077,3084],"valid"],[[3085,3085],"disallowed"],[[3086,3088],"valid"],[[3089,3089],"disallowed"],[[3090,3112],"valid"],[[3113,3113],"disallowed"],[[3114,3123],"valid"],[[3124,3124],"valid"],[[3125,3129],"valid"],[[3130,3132],"disallowed"],[[3133,3133],"valid"],[[3134,3140],"valid"],[[3141,3141],"disallowed"],[[3142,3144],"valid"],[[3145,3145],"disallowed"],[[3146,3149],"valid"],[[3150,3156],"disallowed"],[[3157,3158],"valid"],[[3159,3159],"disallowed"],[[3160,3161],"valid"],[[3162,3162],"valid"],[[3163,3167],"disallowed"],[[3168,3169],"valid"],[[3170,3171],"valid"],[[3172,3173],"disallowed"],[[3174,3183],"valid"],[[3184,3191],"disallowed"],[[3192,3199],"valid",[],"NV8"],[[3200,3200],"disallowed"],[[3201,3201],"valid"],[[3202,3203],"valid"],[[3204,3204],"disallowed"],[[3205,3212],"valid"],[[3213,3213],"disallowed"],[[3214,3216],"valid"],[[3217,3217],"disallowed"],[[3218,3240],"valid"],[[3241,3241],"disallowed"],[[3242,3251],"valid"],[[3252,3252],"disallowed"],[[3253,3257],"valid"],[[3258,3259],"disallowed"],[[3260,3261],"valid"],[[3262,3268],"valid"],[[3269,3269],"disallowed"],[[3270,3272],"valid"],[[3273,3273],"disallowed"],[[3274,3277],"valid"],[[3278,3284],"disallowed"],[[3285,3286],"valid"],[[3287,3293],"disallowed"],[[3294,3294],"valid"],[[3295,3295],"disallowed"],[[3296,3297],"valid"],[[3298,3299],"valid"],[[3300,3301],"disallowed"],[[3302,3311],"valid"],[[3312,3312],"disallowed"],[[3313,3314],"valid"],[[3315,3328],"disallowed"],[[3329,3329],"valid"],[[3330,3331],"valid"],[[3332,3332],"disallowed"],[[3333,3340],"valid"],[[3341,3341],"disallowed"],[[3342,3344],"valid"],[[3345,3345],"disallowed"],[[3346,3368],"valid"],[[3369,3369],"valid"],[[3370,3385],"valid"],[[3386,3386],"valid"],[[3387,3388],"disallowed"],[[3389,3389],"valid"],[[3390,3395],"valid"],[[3396,3396],"valid"],[[3397,3397],"disallowed"],[[3398,3400],"valid"],[[3401,3401],"disallowed"],[[3402,3405],"valid"],[[3406,3406],"valid"],[[3407,3414],"disallowed"],[[3415,3415],"valid"],[[3416,3422],"disallowed"],[[3423,3423],"valid"],[[3424,3425],"valid"],[[3426,3427],"valid"],[[3428,3429],"disallowed"],[[3430,3439],"valid"],[[3440,3445],"valid",[],"NV8"],[[3446,3448],"disallowed"],[[3449,3449],"valid",[],"NV8"],[[3450,3455],"valid"],[[3456,3457],"disallowed"],[[3458,3459],"valid"],[[3460,3460],"disallowed"],[[3461,3478],"valid"],[[3479,3481],"disallowed"],[[3482,3505],"valid"],[[3506,3506],"disallowed"],[[3507,3515],"valid"],[[3516,3516],"disallowed"],[[3517,3517],"valid"],[[3518,3519],"disallowed"],[[3520,3526],"valid"],[[3527,3529],"disallowed"],[[3530,3530],"valid"],[[3531,3534],"disallowed"],[[3535,3540],"valid"],[[3541,3541],"disallowed"],[[3542,3542],"valid"],[[3543,3543],"disallowed"],[[3544,3551],"valid"],[[3552,3557],"disallowed"],[[3558,3567],"valid"],[[3568,3569],"disallowed"],[[3570,3571],"valid"],[[3572,3572],"valid",[],"NV8"],[[3573,3584],"disallowed"],[[3585,3634],"valid"],[[3635,3635],"mapped",[3661,3634]],[[3636,3642],"valid"],[[3643,3646],"disallowed"],[[3647,3647],"valid",[],"NV8"],[[3648,3662],"valid"],[[3663,3663],"valid",[],"NV8"],[[3664,3673],"valid"],[[3674,3675],"valid",[],"NV8"],[[3676,3712],"disallowed"],[[3713,3714],"valid"],[[3715,3715],"disallowed"],[[3716,3716],"valid"],[[3717,3718],"disallowed"],[[3719,3720],"valid"],[[3721,3721],"disallowed"],[[3722,3722],"valid"],[[3723,3724],"disallowed"],[[3725,3725],"valid"],[[3726,3731],"disallowed"],[[3732,3735],"valid"],[[3736,3736],"disallowed"],[[3737,3743],"valid"],[[3744,3744],"disallowed"],[[3745,3747],"valid"],[[3748,3748],"disallowed"],[[3749,3749],"valid"],[[3750,3750],"disallowed"],[[3751,3751],"valid"],[[3752,3753],"disallowed"],[[3754,3755],"valid"],[[3756,3756],"disallowed"],[[3757,3762],"valid"],[[3763,3763],"mapped",[3789,3762]],[[3764,3769],"valid"],[[3770,3770],"disallowed"],[[3771,3773],"valid"],[[3774,3775],"disallowed"],[[3776,3780],"valid"],[[3781,3781],"disallowed"],[[3782,3782],"valid"],[[3783,3783],"disallowed"],[[3784,3789],"valid"],[[3790,3791],"disallowed"],[[3792,3801],"valid"],[[3802,3803],"disallowed"],[[3804,3804],"mapped",[3755,3737]],[[3805,3805],"mapped",[3755,3745]],[[3806,3807],"valid"],[[3808,3839],"disallowed"],[[3840,3840],"valid"],[[3841,3850],"valid",[],"NV8"],[[3851,3851],"valid"],[[3852,3852],"mapped",[3851]],[[3853,3863],"valid",[],"NV8"],[[3864,3865],"valid"],[[3866,3871],"valid",[],"NV8"],[[3872,3881],"valid"],[[3882,3892],"valid",[],"NV8"],[[3893,3893],"valid"],[[3894,3894],"valid",[],"NV8"],[[3895,3895],"valid"],[[3896,3896],"valid",[],"NV8"],[[3897,3897],"valid"],[[3898,3901],"valid",[],"NV8"],[[3902,3906],"valid"],[[3907,3907],"mapped",[3906,4023]],[[3908,3911],"valid"],[[3912,3912],"disallowed"],[[3913,3916],"valid"],[[3917,3917],"mapped",[3916,4023]],[[3918,3921],"valid"],[[3922,3922],"mapped",[3921,4023]],[[3923,3926],"valid"],[[3927,3927],"mapped",[3926,4023]],[[3928,3931],"valid"],[[3932,3932],"mapped",[3931,4023]],[[3933,3944],"valid"],[[3945,3945],"mapped",[3904,4021]],[[3946,3946],"valid"],[[3947,3948],"valid"],[[3949,3952],"disallowed"],[[3953,3954],"valid"],[[3955,3955],"mapped",[3953,3954]],[[3956,3956],"valid"],[[3957,3957],"mapped",[3953,3956]],[[3958,3958],"mapped",[4018,3968]],[[3959,3959],"mapped",[4018,3953,3968]],[[3960,3960],"mapped",[4019,3968]],[[3961,3961],"mapped",[4019,3953,3968]],[[3962,3968],"valid"],[[3969,3969],"mapped",[3953,3968]],[[3970,3972],"valid"],[[3973,3973],"valid",[],"NV8"],[[3974,3979],"valid"],[[3980,3983],"valid"],[[3984,3986],"valid"],[[3987,3987],"mapped",[3986,4023]],[[3988,3989],"valid"],[[3990,3990],"valid"],[[3991,3991],"valid"],[[3992,3992],"disallowed"],[[3993,3996],"valid"],[[3997,3997],"mapped",[3996,4023]],[[3998,4001],"valid"],[[4002,4002],"mapped",[4001,4023]],[[4003,4006],"valid"],[[4007,4007],"mapped",[4006,4023]],[[4008,4011],"valid"],[[4012,4012],"mapped",[4011,4023]],[[4013,4013],"valid"],[[4014,4016],"valid"],[[4017,4023],"valid"],[[4024,4024],"valid"],[[4025,4025],"mapped",[3984,4021]],[[4026,4028],"valid"],[[4029,4029],"disallowed"],[[4030,4037],"valid",[],"NV8"],[[4038,4038],"valid"],[[4039,4044],"valid",[],"NV8"],[[4045,4045],"disallowed"],[[4046,4046],"valid",[],"NV8"],[[4047,4047],"valid",[],"NV8"],[[4048,4049],"valid",[],"NV8"],[[4050,4052],"valid",[],"NV8"],[[4053,4056],"valid",[],"NV8"],[[4057,4058],"valid",[],"NV8"],[[4059,4095],"disallowed"],[[4096,4129],"valid"],[[4130,4130],"valid"],[[4131,4135],"valid"],[[4136,4136],"valid"],[[4137,4138],"valid"],[[4139,4139],"valid"],[[4140,4146],"valid"],[[4147,4149],"valid"],[[4150,4153],"valid"],[[4154,4159],"valid"],[[4160,4169],"valid"],[[4170,4175],"valid",[],"NV8"],[[4176,4185],"valid"],[[4186,4249],"valid"],[[4250,4253],"valid"],[[4254,4255],"valid",[],"NV8"],[[4256,4293],"disallowed"],[[4294,4294],"disallowed"],[[4295,4295],"mapped",[11559]],[[4296,4300],"disallowed"],[[4301,4301],"mapped",[11565]],[[4302,4303],"disallowed"],[[4304,4342],"valid"],[[4343,4344],"valid"],[[4345,4346],"valid"],[[4347,4347],"valid",[],"NV8"],[[4348,4348],"mapped",[4316]],[[4349,4351],"valid"],[[4352,4441],"valid",[],"NV8"],[[4442,4446],"valid",[],"NV8"],[[4447,4448],"disallowed"],[[4449,4514],"valid",[],"NV8"],[[4515,4519],"valid",[],"NV8"],[[4520,4601],"valid",[],"NV8"],[[4602,4607],"valid",[],"NV8"],[[4608,4614],"valid"],[[4615,4615],"valid"],[[4616,4678],"valid"],[[4679,4679],"valid"],[[4680,4680],"valid"],[[4681,4681],"disallowed"],[[4682,4685],"valid"],[[4686,4687],"disallowed"],[[4688,4694],"valid"],[[4695,4695],"disallowed"],[[4696,4696],"valid"],[[4697,4697],"disallowed"],[[4698,4701],"valid"],[[4702,4703],"disallowed"],[[4704,4742],"valid"],[[4743,4743],"valid"],[[4744,4744],"valid"],[[4745,4745],"disallowed"],[[4746,4749],"valid"],[[4750,4751],"disallowed"],[[4752,4782],"valid"],[[4783,4783],"valid"],[[4784,4784],"valid"],[[4785,4785],"disallowed"],[[4786,4789],"valid"],[[4790,4791],"disallowed"],[[4792,4798],"valid"],[[4799,4799],"disallowed"],[[4800,4800],"valid"],[[4801,4801],"disallowed"],[[4802,4805],"valid"],[[4806,4807],"disallowed"],[[4808,4814],"valid"],[[4815,4815],"valid"],[[4816,4822],"valid"],[[4823,4823],"disallowed"],[[4824,4846],"valid"],[[4847,4847],"valid"],[[4848,4878],"valid"],[[4879,4879],"valid"],[[4880,4880],"valid"],[[4881,4881],"disallowed"],[[4882,4885],"valid"],[[4886,4887],"disallowed"],[[4888,4894],"valid"],[[4895,4895],"valid"],[[4896,4934],"valid"],[[4935,4935],"valid"],[[4936,4954],"valid"],[[4955,4956],"disallowed"],[[4957,4958],"valid"],[[4959,4959],"valid"],[[4960,4960],"valid",[],"NV8"],[[4961,4988],"valid",[],"NV8"],[[4989,4991],"disallowed"],[[4992,5007],"valid"],[[5008,5017],"valid",[],"NV8"],[[5018,5023],"disallowed"],[[5024,5108],"valid"],[[5109,5109],"valid"],[[5110,5111],"disallowed"],[[5112,5112],"mapped",[5104]],[[5113,5113],"mapped",[5105]],[[5114,5114],"mapped",[5106]],[[5115,5115],"mapped",[5107]],[[5116,5116],"mapped",[5108]],[[5117,5117],"mapped",[5109]],[[5118,5119],"disallowed"],[[5120,5120],"valid",[],"NV8"],[[5121,5740],"valid"],[[5741,5742],"valid",[],"NV8"],[[5743,5750],"valid"],[[5751,5759],"valid"],[[5760,5760],"disallowed"],[[5761,5786],"valid"],[[5787,5788],"valid",[],"NV8"],[[5789,5791],"disallowed"],[[5792,5866],"valid"],[[5867,5872],"valid",[],"NV8"],[[5873,5880],"valid"],[[5881,5887],"disallowed"],[[5888,5900],"valid"],[[5901,5901],"disallowed"],[[5902,5908],"valid"],[[5909,5919],"disallowed"],[[5920,5940],"valid"],[[5941,5942],"valid",[],"NV8"],[[5943,5951],"disallowed"],[[5952,5971],"valid"],[[5972,5983],"disallowed"],[[5984,5996],"valid"],[[5997,5997],"disallowed"],[[5998,6000],"valid"],[[6001,6001],"disallowed"],[[6002,6003],"valid"],[[6004,6015],"disallowed"],[[6016,6067],"valid"],[[6068,6069],"disallowed"],[[6070,6099],"valid"],[[6100,6102],"valid",[],"NV8"],[[6103,6103],"valid"],[[6104,6107],"valid",[],"NV8"],[[6108,6108],"valid"],[[6109,6109],"valid"],[[6110,6111],"disallowed"],[[6112,6121],"valid"],[[6122,6127],"disallowed"],[[6128,6137],"valid",[],"NV8"],[[6138,6143],"disallowed"],[[6144,6149],"valid",[],"NV8"],[[6150,6150],"disallowed"],[[6151,6154],"valid",[],"NV8"],[[6155,6157],"ignored"],[[6158,6158],"disallowed"],[[6159,6159],"disallowed"],[[6160,6169],"valid"],[[6170,6175],"disallowed"],[[6176,6263],"valid"],[[6264,6271],"disallowed"],[[6272,6313],"valid"],[[6314,6314],"valid"],[[6315,6319],"disallowed"],[[6320,6389],"valid"],[[6390,6399],"disallowed"],[[6400,6428],"valid"],[[6429,6430],"valid"],[[6431,6431],"disallowed"],[[6432,6443],"valid"],[[6444,6447],"disallowed"],[[6448,6459],"valid"],[[6460,6463],"disallowed"],[[6464,6464],"valid",[],"NV8"],[[6465,6467],"disallowed"],[[6468,6469],"valid",[],"NV8"],[[6470,6509],"valid"],[[6510,6511],"disallowed"],[[6512,6516],"valid"],[[6517,6527],"disallowed"],[[6528,6569],"valid"],[[6570,6571],"valid"],[[6572,6575],"disallowed"],[[6576,6601],"valid"],[[6602,6607],"disallowed"],[[6608,6617],"valid"],[[6618,6618],"valid",[],"XV8"],[[6619,6621],"disallowed"],[[6622,6623],"valid",[],"NV8"],[[6624,6655],"valid",[],"NV8"],[[6656,6683],"valid"],[[6684,6685],"disallowed"],[[6686,6687],"valid",[],"NV8"],[[6688,6750],"valid"],[[6751,6751],"disallowed"],[[6752,6780],"valid"],[[6781,6782],"disallowed"],[[6783,6793],"valid"],[[6794,6799],"disallowed"],[[6800,6809],"valid"],[[6810,6815],"disallowed"],[[6816,6822],"valid",[],"NV8"],[[6823,6823],"valid"],[[6824,6829],"valid",[],"NV8"],[[6830,6831],"disallowed"],[[6832,6845],"valid"],[[6846,6846],"valid",[],"NV8"],[[6847,6911],"disallowed"],[[6912,6987],"valid"],[[6988,6991],"disallowed"],[[6992,7001],"valid"],[[7002,7018],"valid",[],"NV8"],[[7019,7027],"valid"],[[7028,7036],"valid",[],"NV8"],[[7037,7039],"disallowed"],[[7040,7082],"valid"],[[7083,7085],"valid"],[[7086,7097],"valid"],[[7098,7103],"valid"],[[7104,7155],"valid"],[[7156,7163],"disallowed"],[[7164,7167],"valid",[],"NV8"],[[7168,7223],"valid"],[[7224,7226],"disallowed"],[[7227,7231],"valid",[],"NV8"],[[7232,7241],"valid"],[[7242,7244],"disallowed"],[[7245,7293],"valid"],[[7294,7295],"valid",[],"NV8"],[[7296,7359],"disallowed"],[[7360,7367],"valid",[],"NV8"],[[7368,7375],"disallowed"],[[7376,7378],"valid"],[[7379,7379],"valid",[],"NV8"],[[7380,7410],"valid"],[[7411,7414],"valid"],[[7415,7415],"disallowed"],[[7416,7417],"valid"],[[7418,7423],"disallowed"],[[7424,7467],"valid"],[[7468,7468],"mapped",[97]],[[7469,7469],"mapped",[230]],[[7470,7470],"mapped",[98]],[[7471,7471],"valid"],[[7472,7472],"mapped",[100]],[[7473,7473],"mapped",[101]],[[7474,7474],"mapped",[477]],[[7475,7475],"mapped",[103]],[[7476,7476],"mapped",[104]],[[7477,7477],"mapped",[105]],[[7478,7478],"mapped",[106]],[[7479,7479],"mapped",[107]],[[7480,7480],"mapped",[108]],[[7481,7481],"mapped",[109]],[[7482,7482],"mapped",[110]],[[7483,7483],"valid"],[[7484,7484],"mapped",[111]],[[7485,7485],"mapped",[547]],[[7486,7486],"mapped",[112]],[[7487,7487],"mapped",[114]],[[7488,7488],"mapped",[116]],[[7489,7489],"mapped",[117]],[[7490,7490],"mapped",[119]],[[7491,7491],"mapped",[97]],[[7492,7492],"mapped",[592]],[[7493,7493],"mapped",[593]],[[7494,7494],"mapped",[7426]],[[7495,7495],"mapped",[98]],[[7496,7496],"mapped",[100]],[[7497,7497],"mapped",[101]],[[7498,7498],"mapped",[601]],[[7499,7499],"mapped",[603]],[[7500,7500],"mapped",[604]],[[7501,7501],"mapped",[103]],[[7502,7502],"valid"],[[7503,7503],"mapped",[107]],[[7504,7504],"mapped",[109]],[[7505,7505],"mapped",[331]],[[7506,7506],"mapped",[111]],[[7507,7507],"mapped",[596]],[[7508,7508],"mapped",[7446]],[[7509,7509],"mapped",[7447]],[[7510,7510],"mapped",[112]],[[7511,7511],"mapped",[116]],[[7512,7512],"mapped",[117]],[[7513,7513],"mapped",[7453]],[[7514,7514],"mapped",[623]],[[7515,7515],"mapped",[118]],[[7516,7516],"mapped",[7461]],[[7517,7517],"mapped",[946]],[[7518,7518],"mapped",[947]],[[7519,7519],"mapped",[948]],[[7520,7520],"mapped",[966]],[[7521,7521],"mapped",[967]],[[7522,7522],"mapped",[105]],[[7523,7523],"mapped",[114]],[[7524,7524],"mapped",[117]],[[7525,7525],"mapped",[118]],[[7526,7526],"mapped",[946]],[[7527,7527],"mapped",[947]],[[7528,7528],"mapped",[961]],[[7529,7529],"mapped",[966]],[[7530,7530],"mapped",[967]],[[7531,7531],"valid"],[[7532,7543],"valid"],[[7544,7544],"mapped",[1085]],[[7545,7578],"valid"],[[7579,7579],"mapped",[594]],[[7580,7580],"mapped",[99]],[[7581,7581],"mapped",[597]],[[7582,7582],"mapped",[240]],[[7583,7583],"mapped",[604]],[[7584,7584],"mapped",[102]],[[7585,7585],"mapped",[607]],[[7586,7586],"mapped",[609]],[[7587,7587],"mapped",[613]],[[7588,7588],"mapped",[616]],[[7589,7589],"mapped",[617]],[[7590,7590],"mapped",[618]],[[7591,7591],"mapped",[7547]],[[7592,7592],"mapped",[669]],[[7593,7593],"mapped",[621]],[[7594,7594],"mapped",[7557]],[[7595,7595],"mapped",[671]],[[7596,7596],"mapped",[625]],[[7597,7597],"mapped",[624]],[[7598,7598],"mapped",[626]],[[7599,7599],"mapped",[627]],[[7600,7600],"mapped",[628]],[[7601,7601],"mapped",[629]],[[7602,7602],"mapped",[632]],[[7603,7603],"mapped",[642]],[[7604,7604],"mapped",[643]],[[7605,7605],"mapped",[427]],[[7606,7606],"mapped",[649]],[[7607,7607],"mapped",[650]],[[7608,7608],"mapped",[7452]],[[7609,7609],"mapped",[651]],[[7610,7610],"mapped",[652]],[[7611,7611],"mapped",[122]],[[7612,7612],"mapped",[656]],[[7613,7613],"mapped",[657]],[[7614,7614],"mapped",[658]],[[7615,7615],"mapped",[952]],[[7616,7619],"valid"],[[7620,7626],"valid"],[[7627,7654],"valid"],[[7655,7669],"valid"],[[7670,7675],"disallowed"],[[7676,7676],"valid"],[[7677,7677],"valid"],[[7678,7679],"valid"],[[7680,7680],"mapped",[7681]],[[7681,7681],"valid"],[[7682,7682],"mapped",[7683]],[[7683,7683],"valid"],[[7684,7684],"mapped",[7685]],[[7685,7685],"valid"],[[7686,7686],"mapped",[7687]],[[7687,7687],"valid"],[[7688,7688],"mapped",[7689]],[[7689,7689],"valid"],[[7690,7690],"mapped",[7691]],[[7691,7691],"valid"],[[7692,7692],"mapped",[7693]],[[7693,7693],"valid"],[[7694,7694],"mapped",[7695]],[[7695,7695],"valid"],[[7696,7696],"mapped",[7697]],[[7697,7697],"valid"],[[7698,7698],"mapped",[7699]],[[7699,7699],"valid"],[[7700,7700],"mapped",[7701]],[[7701,7701],"valid"],[[7702,7702],"mapped",[7703]],[[7703,7703],"valid"],[[7704,7704],"mapped",[7705]],[[7705,7705],"valid"],[[7706,7706],"mapped",[7707]],[[7707,7707],"valid"],[[7708,7708],"mapped",[7709]],[[7709,7709],"valid"],[[7710,7710],"mapped",[7711]],[[7711,7711],"valid"],[[7712,7712],"mapped",[7713]],[[7713,7713],"valid"],[[7714,7714],"mapped",[7715]],[[7715,7715],"valid"],[[7716,7716],"mapped",[7717]],[[7717,7717],"valid"],[[7718,7718],"mapped",[7719]],[[7719,7719],"valid"],[[7720,7720],"mapped",[7721]],[[7721,7721],"valid"],[[7722,7722],"mapped",[7723]],[[7723,7723],"valid"],[[7724,7724],"mapped",[7725]],[[7725,7725],"valid"],[[7726,7726],"mapped",[7727]],[[7727,7727],"valid"],[[7728,7728],"mapped",[7729]],[[7729,7729],"valid"],[[7730,7730],"mapped",[7731]],[[7731,7731],"valid"],[[7732,7732],"mapped",[7733]],[[7733,7733],"valid"],[[7734,7734],"mapped",[7735]],[[7735,7735],"valid"],[[7736,7736],"mapped",[7737]],[[7737,7737],"valid"],[[7738,7738],"mapped",[7739]],[[7739,7739],"valid"],[[7740,7740],"mapped",[7741]],[[7741,7741],"valid"],[[7742,7742],"mapped",[7743]],[[7743,7743],"valid"],[[7744,7744],"mapped",[7745]],[[7745,7745],"valid"],[[7746,7746],"mapped",[7747]],[[7747,7747],"valid"],[[7748,7748],"mapped",[7749]],[[7749,7749],"valid"],[[7750,7750],"mapped",[7751]],[[7751,7751],"valid"],[[7752,7752],"mapped",[7753]],[[7753,7753],"valid"],[[7754,7754],"mapped",[7755]],[[7755,7755],"valid"],[[7756,7756],"mapped",[7757]],[[7757,7757],"valid"],[[7758,7758],"mapped",[7759]],[[7759,7759],"valid"],[[7760,7760],"mapped",[7761]],[[7761,7761],"valid"],[[7762,7762],"mapped",[7763]],[[7763,7763],"valid"],[[7764,7764],"mapped",[7765]],[[7765,7765],"valid"],[[7766,7766],"mapped",[7767]],[[7767,7767],"valid"],[[7768,7768],"mapped",[7769]],[[7769,7769],"valid"],[[7770,7770],"mapped",[7771]],[[7771,7771],"valid"],[[7772,7772],"mapped",[7773]],[[7773,7773],"valid"],[[7774,7774],"mapped",[7775]],[[7775,7775],"valid"],[[7776,7776],"mapped",[7777]],[[7777,7777],"valid"],[[7778,7778],"mapped",[7779]],[[7779,7779],"valid"],[[7780,7780],"mapped",[7781]],[[7781,7781],"valid"],[[7782,7782],"mapped",[7783]],[[7783,7783],"valid"],[[7784,7784],"mapped",[7785]],[[7785,7785],"valid"],[[7786,7786],"mapped",[7787]],[[7787,7787],"valid"],[[7788,7788],"mapped",[7789]],[[7789,7789],"valid"],[[7790,7790],"mapped",[7791]],[[7791,7791],"valid"],[[7792,7792],"mapped",[7793]],[[7793,7793],"valid"],[[7794,7794],"mapped",[7795]],[[7795,7795],"valid"],[[7796,7796],"mapped",[7797]],[[7797,7797],"valid"],[[7798,7798],"mapped",[7799]],[[7799,7799],"valid"],[[7800,7800],"mapped",[7801]],[[7801,7801],"valid"],[[7802,7802],"mapped",[7803]],[[7803,7803],"valid"],[[7804,7804],"mapped",[7805]],[[7805,7805],"valid"],[[7806,7806],"mapped",[7807]],[[7807,7807],"valid"],[[7808,7808],"mapped",[7809]],[[7809,7809],"valid"],[[7810,7810],"mapped",[7811]],[[7811,7811],"valid"],[[7812,7812],"mapped",[7813]],[[7813,7813],"valid"],[[7814,7814],"mapped",[7815]],[[7815,7815],"valid"],[[7816,7816],"mapped",[7817]],[[7817,7817],"valid"],[[7818,7818],"mapped",[7819]],[[7819,7819],"valid"],[[7820,7820],"mapped",[7821]],[[7821,7821],"valid"],[[7822,7822],"mapped",[7823]],[[7823,7823],"valid"],[[7824,7824],"mapped",[7825]],[[7825,7825],"valid"],[[7826,7826],"mapped",[7827]],[[7827,7827],"valid"],[[7828,7828],"mapped",[7829]],[[7829,7833],"valid"],[[7834,7834],"mapped",[97,702]],[[7835,7835],"mapped",[7777]],[[7836,7837],"valid"],[[7838,7838],"mapped",[115,115]],[[7839,7839],"valid"],[[7840,7840],"mapped",[7841]],[[7841,7841],"valid"],[[7842,7842],"mapped",[7843]],[[7843,7843],"valid"],[[7844,7844],"mapped",[7845]],[[7845,7845],"valid"],[[7846,7846],"mapped",[7847]],[[7847,7847],"valid"],[[7848,7848],"mapped",[7849]],[[7849,7849],"valid"],[[7850,7850],"mapped",[7851]],[[7851,7851],"valid"],[[7852,7852],"mapped",[7853]],[[7853,7853],"valid"],[[7854,7854],"mapped",[7855]],[[7855,7855],"valid"],[[7856,7856],"mapped",[7857]],[[7857,7857],"valid"],[[7858,7858],"mapped",[7859]],[[7859,7859],"valid"],[[7860,7860],"mapped",[7861]],[[7861,7861],"valid"],[[7862,7862],"mapped",[7863]],[[7863,7863],"valid"],[[7864,7864],"mapped",[7865]],[[7865,7865],"valid"],[[7866,7866],"mapped",[7867]],[[7867,7867],"valid"],[[7868,7868],"mapped",[7869]],[[7869,7869],"valid"],[[7870,7870],"mapped",[7871]],[[7871,7871],"valid"],[[7872,7872],"mapped",[7873]],[[7873,7873],"valid"],[[7874,7874],"mapped",[7875]],[[7875,7875],"valid"],[[7876,7876],"mapped",[7877]],[[7877,7877],"valid"],[[7878,7878],"mapped",[7879]],[[7879,7879],"valid"],[[7880,7880],"mapped",[7881]],[[7881,7881],"valid"],[[7882,7882],"mapped",[7883]],[[7883,7883],"valid"],[[7884,7884],"mapped",[7885]],[[7885,7885],"valid"],[[7886,7886],"mapped",[7887]],[[7887,7887],"valid"],[[7888,7888],"mapped",[7889]],[[7889,7889],"valid"],[[7890,7890],"mapped",[7891]],[[7891,7891],"valid"],[[7892,7892],"mapped",[7893]],[[7893,7893],"valid"],[[7894,7894],"mapped",[7895]],[[7895,7895],"valid"],[[7896,7896],"mapped",[7897]],[[7897,7897],"valid"],[[7898,7898],"mapped",[7899]],[[7899,7899],"valid"],[[7900,7900],"mapped",[7901]],[[7901,7901],"valid"],[[7902,7902],"mapped",[7903]],[[7903,7903],"valid"],[[7904,7904],"mapped",[7905]],[[7905,7905],"valid"],[[7906,7906],"mapped",[7907]],[[7907,7907],"valid"],[[7908,7908],"mapped",[7909]],[[7909,7909],"valid"],[[7910,7910],"mapped",[7911]],[[7911,7911],"valid"],[[7912,7912],"mapped",[7913]],[[7913,7913],"valid"],[[7914,7914],"mapped",[7915]],[[7915,7915],"valid"],[[7916,7916],"mapped",[7917]],[[7917,7917],"valid"],[[7918,7918],"mapped",[7919]],[[7919,7919],"valid"],[[7920,7920],"mapped",[7921]],[[7921,7921],"valid"],[[7922,7922],"mapped",[7923]],[[7923,7923],"valid"],[[7924,7924],"mapped",[7925]],[[7925,7925],"valid"],[[7926,7926],"mapped",[7927]],[[7927,7927],"valid"],[[7928,7928],"mapped",[7929]],[[7929,7929],"valid"],[[7930,7930],"mapped",[7931]],[[7931,7931],"valid"],[[7932,7932],"mapped",[7933]],[[7933,7933],"valid"],[[7934,7934],"mapped",[7935]],[[7935,7935],"valid"],[[7936,7943],"valid"],[[7944,7944],"mapped",[7936]],[[7945,7945],"mapped",[7937]],[[7946,7946],"mapped",[7938]],[[7947,7947],"mapped",[7939]],[[7948,7948],"mapped",[7940]],[[7949,7949],"mapped",[7941]],[[7950,7950],"mapped",[7942]],[[7951,7951],"mapped",[7943]],[[7952,7957],"valid"],[[7958,7959],"disallowed"],[[7960,7960],"mapped",[7952]],[[7961,7961],"mapped",[7953]],[[7962,7962],"mapped",[7954]],[[7963,7963],"mapped",[7955]],[[7964,7964],"mapped",[7956]],[[7965,7965],"mapped",[7957]],[[7966,7967],"disallowed"],[[7968,7975],"valid"],[[7976,7976],"mapped",[7968]],[[7977,7977],"mapped",[7969]],[[7978,7978],"mapped",[7970]],[[7979,7979],"mapped",[7971]],[[7980,7980],"mapped",[7972]],[[7981,7981],"mapped",[7973]],[[7982,7982],"mapped",[7974]],[[7983,7983],"mapped",[7975]],[[7984,7991],"valid"],[[7992,7992],"mapped",[7984]],[[7993,7993],"mapped",[7985]],[[7994,7994],"mapped",[7986]],[[7995,7995],"mapped",[7987]],[[7996,7996],"mapped",[7988]],[[7997,7997],"mapped",[7989]],[[7998,7998],"mapped",[7990]],[[7999,7999],"mapped",[7991]],[[8000,8005],"valid"],[[8006,8007],"disallowed"],[[8008,8008],"mapped",[8000]],[[8009,8009],"mapped",[8001]],[[8010,8010],"mapped",[8002]],[[8011,8011],"mapped",[8003]],[[8012,8012],"mapped",[8004]],[[8013,8013],"mapped",[8005]],[[8014,8015],"disallowed"],[[8016,8023],"valid"],[[8024,8024],"disallowed"],[[8025,8025],"mapped",[8017]],[[8026,8026],"disallowed"],[[8027,8027],"mapped",[8019]],[[8028,8028],"disallowed"],[[8029,8029],"mapped",[8021]],[[8030,8030],"disallowed"],[[8031,8031],"mapped",[8023]],[[8032,8039],"valid"],[[8040,8040],"mapped",[8032]],[[8041,8041],"mapped",[8033]],[[8042,8042],"mapped",[8034]],[[8043,8043],"mapped",[8035]],[[8044,8044],"mapped",[8036]],[[8045,8045],"mapped",[8037]],[[8046,8046],"mapped",[8038]],[[8047,8047],"mapped",[8039]],[[8048,8048],"valid"],[[8049,8049],"mapped",[940]],[[8050,8050],"valid"],[[8051,8051],"mapped",[941]],[[8052,8052],"valid"],[[8053,8053],"mapped",[942]],[[8054,8054],"valid"],[[8055,8055],"mapped",[943]],[[8056,8056],"valid"],[[8057,8057],"mapped",[972]],[[8058,8058],"valid"],[[8059,8059],"mapped",[973]],[[8060,8060],"valid"],[[8061,8061],"mapped",[974]],[[8062,8063],"disallowed"],[[8064,8064],"mapped",[7936,953]],[[8065,8065],"mapped",[7937,953]],[[8066,8066],"mapped",[7938,953]],[[8067,8067],"mapped",[7939,953]],[[8068,8068],"mapped",[7940,953]],[[8069,8069],"mapped",[7941,953]],[[8070,8070],"mapped",[7942,953]],[[8071,8071],"mapped",[7943,953]],[[8072,8072],"mapped",[7936,953]],[[8073,8073],"mapped",[7937,953]],[[8074,8074],"mapped",[7938,953]],[[8075,8075],"mapped",[7939,953]],[[8076,8076],"mapped",[7940,953]],[[8077,8077],"mapped",[7941,953]],[[8078,8078],"mapped",[7942,953]],[[8079,8079],"mapped",[7943,953]],[[8080,8080],"mapped",[7968,953]],[[8081,8081],"mapped",[7969,953]],[[8082,8082],"mapped",[7970,953]],[[8083,8083],"mapped",[7971,953]],[[8084,8084],"mapped",[7972,953]],[[8085,8085],"mapped",[7973,953]],[[8086,8086],"mapped",[7974,953]],[[8087,8087],"mapped",[7975,953]],[[8088,8088],"mapped",[7968,953]],[[8089,8089],"mapped",[7969,953]],[[8090,8090],"mapped",[7970,953]],[[8091,8091],"mapped",[7971,953]],[[8092,8092],"mapped",[7972,953]],[[8093,8093],"mapped",[7973,953]],[[8094,8094],"mapped",[7974,953]],[[8095,8095],"mapped",[7975,953]],[[8096,8096],"mapped",[8032,953]],[[8097,8097],"mapped",[8033,953]],[[8098,8098],"mapped",[8034,953]],[[8099,8099],"mapped",[8035,953]],[[8100,8100],"mapped",[8036,953]],[[8101,8101],"mapped",[8037,953]],[[8102,8102],"mapped",[8038,953]],[[8103,8103],"mapped",[8039,953]],[[8104,8104],"mapped",[8032,953]],[[8105,8105],"mapped",[8033,953]],[[8106,8106],"mapped",[8034,953]],[[8107,8107],"mapped",[8035,953]],[[8108,8108],"mapped",[8036,953]],[[8109,8109],"mapped",[8037,953]],[[8110,8110],"mapped",[8038,953]],[[8111,8111],"mapped",[8039,953]],[[8112,8113],"valid"],[[8114,8114],"mapped",[8048,953]],[[8115,8115],"mapped",[945,953]],[[8116,8116],"mapped",[940,953]],[[8117,8117],"disallowed"],[[8118,8118],"valid"],[[8119,8119],"mapped",[8118,953]],[[8120,8120],"mapped",[8112]],[[8121,8121],"mapped",[8113]],[[8122,8122],"mapped",[8048]],[[8123,8123],"mapped",[940]],[[8124,8124],"mapped",[945,953]],[[8125,8125],"disallowed_STD3_mapped",[32,787]],[[8126,8126],"mapped",[953]],[[8127,8127],"disallowed_STD3_mapped",[32,787]],[[8128,8128],"disallowed_STD3_mapped",[32,834]],[[8129,8129],"disallowed_STD3_mapped",[32,776,834]],[[8130,8130],"mapped",[8052,953]],[[8131,8131],"mapped",[951,953]],[[8132,8132],"mapped",[942,953]],[[8133,8133],"disallowed"],[[8134,8134],"valid"],[[8135,8135],"mapped",[8134,953]],[[8136,8136],"mapped",[8050]],[[8137,8137],"mapped",[941]],[[8138,8138],"mapped",[8052]],[[8139,8139],"mapped",[942]],[[8140,8140],"mapped",[951,953]],[[8141,8141],"disallowed_STD3_mapped",[32,787,768]],[[8142,8142],"disallowed_STD3_mapped",[32,787,769]],[[8143,8143],"disallowed_STD3_mapped",[32,787,834]],[[8144,8146],"valid"],[[8147,8147],"mapped",[912]],[[8148,8149],"disallowed"],[[8150,8151],"valid"],[[8152,8152],"mapped",[8144]],[[8153,8153],"mapped",[8145]],[[8154,8154],"mapped",[8054]],[[8155,8155],"mapped",[943]],[[8156,8156],"disallowed"],[[8157,8157],"disallowed_STD3_mapped",[32,788,768]],[[8158,8158],"disallowed_STD3_mapped",[32,788,769]],[[8159,8159],"disallowed_STD3_mapped",[32,788,834]],[[8160,8162],"valid"],[[8163,8163],"mapped",[944]],[[8164,8167],"valid"],[[8168,8168],"mapped",[8160]],[[8169,8169],"mapped",[8161]],[[8170,8170],"mapped",[8058]],[[8171,8171],"mapped",[973]],[[8172,8172],"mapped",[8165]],[[8173,8173],"disallowed_STD3_mapped",[32,776,768]],[[8174,8174],"disallowed_STD3_mapped",[32,776,769]],[[8175,8175],"disallowed_STD3_mapped",[96]],[[8176,8177],"disallowed"],[[8178,8178],"mapped",[8060,953]],[[8179,8179],"mapped",[969,953]],[[8180,8180],"mapped",[974,953]],[[8181,8181],"disallowed"],[[8182,8182],"valid"],[[8183,8183],"mapped",[8182,953]],[[8184,8184],"mapped",[8056]],[[8185,8185],"mapped",[972]],[[8186,8186],"mapped",[8060]],[[8187,8187],"mapped",[974]],[[8188,8188],"mapped",[969,953]],[[8189,8189],"disallowed_STD3_mapped",[32,769]],[[8190,8190],"disallowed_STD3_mapped",[32,788]],[[8191,8191],"disallowed"],[[8192,8202],"disallowed_STD3_mapped",[32]],[[8203,8203],"ignored"],[[8204,8205],"deviation",[]],[[8206,8207],"disallowed"],[[8208,8208],"valid",[],"NV8"],[[8209,8209],"mapped",[8208]],[[8210,8214],"valid",[],"NV8"],[[8215,8215],"disallowed_STD3_mapped",[32,819]],[[8216,8227],"valid",[],"NV8"],[[8228,8230],"disallowed"],[[8231,8231],"valid",[],"NV8"],[[8232,8238],"disallowed"],[[8239,8239],"disallowed_STD3_mapped",[32]],[[8240,8242],"valid",[],"NV8"],[[8243,8243],"mapped",[8242,8242]],[[8244,8244],"mapped",[8242,8242,8242]],[[8245,8245],"valid",[],"NV8"],[[8246,8246],"mapped",[8245,8245]],[[8247,8247],"mapped",[8245,8245,8245]],[[8248,8251],"valid",[],"NV8"],[[8252,8252],"disallowed_STD3_mapped",[33,33]],[[8253,8253],"valid",[],"NV8"],[[8254,8254],"disallowed_STD3_mapped",[32,773]],[[8255,8262],"valid",[],"NV8"],[[8263,8263],"disallowed_STD3_mapped",[63,63]],[[8264,8264],"disallowed_STD3_mapped",[63,33]],[[8265,8265],"disallowed_STD3_mapped",[33,63]],[[8266,8269],"valid",[],"NV8"],[[8270,8274],"valid",[],"NV8"],[[8275,8276],"valid",[],"NV8"],[[8277,8278],"valid",[],"NV8"],[[8279,8279],"mapped",[8242,8242,8242,8242]],[[8280,8286],"valid",[],"NV8"],[[8287,8287],"disallowed_STD3_mapped",[32]],[[8288,8288],"ignored"],[[8289,8291],"disallowed"],[[8292,8292],"ignored"],[[8293,8293],"disallowed"],[[8294,8297],"disallowed"],[[8298,8303],"disallowed"],[[8304,8304],"mapped",[48]],[[8305,8305],"mapped",[105]],[[8306,8307],"disallowed"],[[8308,8308],"mapped",[52]],[[8309,8309],"mapped",[53]],[[8310,8310],"mapped",[54]],[[8311,8311],"mapped",[55]],[[8312,8312],"mapped",[56]],[[8313,8313],"mapped",[57]],[[8314,8314],"disallowed_STD3_mapped",[43]],[[8315,8315],"mapped",[8722]],[[8316,8316],"disallowed_STD3_mapped",[61]],[[8317,8317],"disallowed_STD3_mapped",[40]],[[8318,8318],"disallowed_STD3_mapped",[41]],[[8319,8319],"mapped",[110]],[[8320,8320],"mapped",[48]],[[8321,8321],"mapped",[49]],[[8322,8322],"mapped",[50]],[[8323,8323],"mapped",[51]],[[8324,8324],"mapped",[52]],[[8325,8325],"mapped",[53]],[[8326,8326],"mapped",[54]],[[8327,8327],"mapped",[55]],[[8328,8328],"mapped",[56]],[[8329,8329],"mapped",[57]],[[8330,8330],"disallowed_STD3_mapped",[43]],[[8331,8331],"mapped",[8722]],[[8332,8332],"disallowed_STD3_mapped",[61]],[[8333,8333],"disallowed_STD3_mapped",[40]],[[8334,8334],"disallowed_STD3_mapped",[41]],[[8335,8335],"disallowed"],[[8336,8336],"mapped",[97]],[[8337,8337],"mapped",[101]],[[8338,8338],"mapped",[111]],[[8339,8339],"mapped",[120]],[[8340,8340],"mapped",[601]],[[8341,8341],"mapped",[104]],[[8342,8342],"mapped",[107]],[[8343,8343],"mapped",[108]],[[8344,8344],"mapped",[109]],[[8345,8345],"mapped",[110]],[[8346,8346],"mapped",[112]],[[8347,8347],"mapped",[115]],[[8348,8348],"mapped",[116]],[[8349,8351],"disallowed"],[[8352,8359],"valid",[],"NV8"],[[8360,8360],"mapped",[114,115]],[[8361,8362],"valid",[],"NV8"],[[8363,8363],"valid",[],"NV8"],[[8364,8364],"valid",[],"NV8"],[[8365,8367],"valid",[],"NV8"],[[8368,8369],"valid",[],"NV8"],[[8370,8373],"valid",[],"NV8"],[[8374,8376],"valid",[],"NV8"],[[8377,8377],"valid",[],"NV8"],[[8378,8378],"valid",[],"NV8"],[[8379,8381],"valid",[],"NV8"],[[8382,8382],"valid",[],"NV8"],[[8383,8399],"disallowed"],[[8400,8417],"valid",[],"NV8"],[[8418,8419],"valid",[],"NV8"],[[8420,8426],"valid",[],"NV8"],[[8427,8427],"valid",[],"NV8"],[[8428,8431],"valid",[],"NV8"],[[8432,8432],"valid",[],"NV8"],[[8433,8447],"disallowed"],[[8448,8448],"disallowed_STD3_mapped",[97,47,99]],[[8449,8449],"disallowed_STD3_mapped",[97,47,115]],[[8450,8450],"mapped",[99]],[[8451,8451],"mapped",[176,99]],[[8452,8452],"valid",[],"NV8"],[[8453,8453],"disallowed_STD3_mapped",[99,47,111]],[[8454,8454],"disallowed_STD3_mapped",[99,47,117]],[[8455,8455],"mapped",[603]],[[8456,8456],"valid",[],"NV8"],[[8457,8457],"mapped",[176,102]],[[8458,8458],"mapped",[103]],[[8459,8462],"mapped",[104]],[[8463,8463],"mapped",[295]],[[8464,8465],"mapped",[105]],[[8466,8467],"mapped",[108]],[[8468,8468],"valid",[],"NV8"],[[8469,8469],"mapped",[110]],[[8470,8470],"mapped",[110,111]],[[8471,8472],"valid",[],"NV8"],[[8473,8473],"mapped",[112]],[[8474,8474],"mapped",[113]],[[8475,8477],"mapped",[114]],[[8478,8479],"valid",[],"NV8"],[[8480,8480],"mapped",[115,109]],[[8481,8481],"mapped",[116,101,108]],[[8482,8482],"mapped",[116,109]],[[8483,8483],"valid",[],"NV8"],[[8484,8484],"mapped",[122]],[[8485,8485],"valid",[],"NV8"],[[8486,8486],"mapped",[969]],[[8487,8487],"valid",[],"NV8"],[[8488,8488],"mapped",[122]],[[8489,8489],"valid",[],"NV8"],[[8490,8490],"mapped",[107]],[[8491,8491],"mapped",[229]],[[8492,8492],"mapped",[98]],[[8493,8493],"mapped",[99]],[[8494,8494],"valid",[],"NV8"],[[8495,8496],"mapped",[101]],[[8497,8497],"mapped",[102]],[[8498,8498],"disallowed"],[[8499,8499],"mapped",[109]],[[8500,8500],"mapped",[111]],[[8501,8501],"mapped",[1488]],[[8502,8502],"mapped",[1489]],[[8503,8503],"mapped",[1490]],[[8504,8504],"mapped",[1491]],[[8505,8505],"mapped",[105]],[[8506,8506],"valid",[],"NV8"],[[8507,8507],"mapped",[102,97,120]],[[8508,8508],"mapped",[960]],[[8509,8510],"mapped",[947]],[[8511,8511],"mapped",[960]],[[8512,8512],"mapped",[8721]],[[8513,8516],"valid",[],"NV8"],[[8517,8518],"mapped",[100]],[[8519,8519],"mapped",[101]],[[8520,8520],"mapped",[105]],[[8521,8521],"mapped",[106]],[[8522,8523],"valid",[],"NV8"],[[8524,8524],"valid",[],"NV8"],[[8525,8525],"valid",[],"NV8"],[[8526,8526],"valid"],[[8527,8527],"valid",[],"NV8"],[[8528,8528],"mapped",[49,8260,55]],[[8529,8529],"mapped",[49,8260,57]],[[8530,8530],"mapped",[49,8260,49,48]],[[8531,8531],"mapped",[49,8260,51]],[[8532,8532],"mapped",[50,8260,51]],[[8533,8533],"mapped",[49,8260,53]],[[8534,8534],"mapped",[50,8260,53]],[[8535,8535],"mapped",[51,8260,53]],[[8536,8536],"mapped",[52,8260,53]],[[8537,8537],"mapped",[49,8260,54]],[[8538,8538],"mapped",[53,8260,54]],[[8539,8539],"mapped",[49,8260,56]],[[8540,8540],"mapped",[51,8260,56]],[[8541,8541],"mapped",[53,8260,56]],[[8542,8542],"mapped",[55,8260,56]],[[8543,8543],"mapped",[49,8260]],[[8544,8544],"mapped",[105]],[[8545,8545],"mapped",[105,105]],[[8546,8546],"mapped",[105,105,105]],[[8547,8547],"mapped",[105,118]],[[8548,8548],"mapped",[118]],[[8549,8549],"mapped",[118,105]],[[8550,8550],"mapped",[118,105,105]],[[8551,8551],"mapped",[118,105,105,105]],[[8552,8552],"mapped",[105,120]],[[8553,8553],"mapped",[120]],[[8554,8554],"mapped",[120,105]],[[8555,8555],"mapped",[120,105,105]],[[8556,8556],"mapped",[108]],[[8557,8557],"mapped",[99]],[[8558,8558],"mapped",[100]],[[8559,8559],"mapped",[109]],[[8560,8560],"mapped",[105]],[[8561,8561],"mapped",[105,105]],[[8562,8562],"mapped",[105,105,105]],[[8563,8563],"mapped",[105,118]],[[8564,8564],"mapped",[118]],[[8565,8565],"mapped",[118,105]],[[8566,8566],"mapped",[118,105,105]],[[8567,8567],"mapped",[118,105,105,105]],[[8568,8568],"mapped",[105,120]],[[8569,8569],"mapped",[120]],[[8570,8570],"mapped",[120,105]],[[8571,8571],"mapped",[120,105,105]],[[8572,8572],"mapped",[108]],[[8573,8573],"mapped",[99]],[[8574,8574],"mapped",[100]],[[8575,8575],"mapped",[109]],[[8576,8578],"valid",[],"NV8"],[[8579,8579],"disallowed"],[[8580,8580],"valid"],[[8581,8584],"valid",[],"NV8"],[[8585,8585],"mapped",[48,8260,51]],[[8586,8587],"valid",[],"NV8"],[[8588,8591],"disallowed"],[[8592,8682],"valid",[],"NV8"],[[8683,8691],"valid",[],"NV8"],[[8692,8703],"valid",[],"NV8"],[[8704,8747],"valid",[],"NV8"],[[8748,8748],"mapped",[8747,8747]],[[8749,8749],"mapped",[8747,8747,8747]],[[8750,8750],"valid",[],"NV8"],[[8751,8751],"mapped",[8750,8750]],[[8752,8752],"mapped",[8750,8750,8750]],[[8753,8799],"valid",[],"NV8"],[[8800,8800],"disallowed_STD3_valid"],[[8801,8813],"valid",[],"NV8"],[[8814,8815],"disallowed_STD3_valid"],[[8816,8945],"valid",[],"NV8"],[[8946,8959],"valid",[],"NV8"],[[8960,8960],"valid",[],"NV8"],[[8961,8961],"valid",[],"NV8"],[[8962,9000],"valid",[],"NV8"],[[9001,9001],"mapped",[12296]],[[9002,9002],"mapped",[12297]],[[9003,9082],"valid",[],"NV8"],[[9083,9083],"valid",[],"NV8"],[[9084,9084],"valid",[],"NV8"],[[9085,9114],"valid",[],"NV8"],[[9115,9166],"valid",[],"NV8"],[[9167,9168],"valid",[],"NV8"],[[9169,9179],"valid",[],"NV8"],[[9180,9191],"valid",[],"NV8"],[[9192,9192],"valid",[],"NV8"],[[9193,9203],"valid",[],"NV8"],[[9204,9210],"valid",[],"NV8"],[[9211,9215],"disallowed"],[[9216,9252],"valid",[],"NV8"],[[9253,9254],"valid",[],"NV8"],[[9255,9279],"disallowed"],[[9280,9290],"valid",[],"NV8"],[[9291,9311],"disallowed"],[[9312,9312],"mapped",[49]],[[9313,9313],"mapped",[50]],[[9314,9314],"mapped",[51]],[[9315,9315],"mapped",[52]],[[9316,9316],"mapped",[53]],[[9317,9317],"mapped",[54]],[[9318,9318],"mapped",[55]],[[9319,9319],"mapped",[56]],[[9320,9320],"mapped",[57]],[[9321,9321],"mapped",[49,48]],[[9322,9322],"mapped",[49,49]],[[9323,9323],"mapped",[49,50]],[[9324,9324],"mapped",[49,51]],[[9325,9325],"mapped",[49,52]],[[9326,9326],"mapped",[49,53]],[[9327,9327],"mapped",[49,54]],[[9328,9328],"mapped",[49,55]],[[9329,9329],"mapped",[49,56]],[[9330,9330],"mapped",[49,57]],[[9331,9331],"mapped",[50,48]],[[9332,9332],"disallowed_STD3_mapped",[40,49,41]],[[9333,9333],"disallowed_STD3_mapped",[40,50,41]],[[9334,9334],"disallowed_STD3_mapped",[40,51,41]],[[9335,9335],"disallowed_STD3_mapped",[40,52,41]],[[9336,9336],"disallowed_STD3_mapped",[40,53,41]],[[9337,9337],"disallowed_STD3_mapped",[40,54,41]],[[9338,9338],"disallowed_STD3_mapped",[40,55,41]],[[9339,9339],"disallowed_STD3_mapped",[40,56,41]],[[9340,9340],"disallowed_STD3_mapped",[40,57,41]],[[9341,9341],"disallowed_STD3_mapped",[40,49,48,41]],[[9342,9342],"disallowed_STD3_mapped",[40,49,49,41]],[[9343,9343],"disallowed_STD3_mapped",[40,49,50,41]],[[9344,9344],"disallowed_STD3_mapped",[40,49,51,41]],[[9345,9345],"disallowed_STD3_mapped",[40,49,52,41]],[[9346,9346],"disallowed_STD3_mapped",[40,49,53,41]],[[9347,9347],"disallowed_STD3_mapped",[40,49,54,41]],[[9348,9348],"disallowed_STD3_mapped",[40,49,55,41]],[[9349,9349],"disallowed_STD3_mapped",[40,49,56,41]],[[9350,9350],"disallowed_STD3_mapped",[40,49,57,41]],[[9351,9351],"disallowed_STD3_mapped",[40,50,48,41]],[[9352,9371],"disallowed"],[[9372,9372],"disallowed_STD3_mapped",[40,97,41]],[[9373,9373],"disallowed_STD3_mapped",[40,98,41]],[[9374,9374],"disallowed_STD3_mapped",[40,99,41]],[[9375,9375],"disallowed_STD3_mapped",[40,100,41]],[[9376,9376],"disallowed_STD3_mapped",[40,101,41]],[[9377,9377],"disallowed_STD3_mapped",[40,102,41]],[[9378,9378],"disallowed_STD3_mapped",[40,103,41]],[[9379,9379],"disallowed_STD3_mapped",[40,104,41]],[[9380,9380],"disallowed_STD3_mapped",[40,105,41]],[[9381,9381],"disallowed_STD3_mapped",[40,106,41]],[[9382,9382],"disallowed_STD3_mapped",[40,107,41]],[[9383,9383],"disallowed_STD3_mapped",[40,108,41]],[[9384,9384],"disallowed_STD3_mapped",[40,109,41]],[[9385,9385],"disallowed_STD3_mapped",[40,110,41]],[[9386,9386],"disallowed_STD3_mapped",[40,111,41]],[[9387,9387],"disallowed_STD3_mapped",[40,112,41]],[[9388,9388],"disallowed_STD3_mapped",[40,113,41]],[[9389,9389],"disallowed_STD3_mapped",[40,114,41]],[[9390,9390],"disallowed_STD3_mapped",[40,115,41]],[[9391,9391],"disallowed_STD3_mapped",[40,116,41]],[[9392,9392],"disallowed_STD3_mapped",[40,117,41]],[[9393,9393],"disallowed_STD3_mapped",[40,118,41]],[[9394,9394],"disallowed_STD3_mapped",[40,119,41]],[[9395,9395],"disallowed_STD3_mapped",[40,120,41]],[[9396,9396],"disallowed_STD3_mapped",[40,121,41]],[[9397,9397],"disallowed_STD3_mapped",[40,122,41]],[[9398,9398],"mapped",[97]],[[9399,9399],"mapped",[98]],[[9400,9400],"mapped",[99]],[[9401,9401],"mapped",[100]],[[9402,9402],"mapped",[101]],[[9403,9403],"mapped",[102]],[[9404,9404],"mapped",[103]],[[9405,9405],"mapped",[104]],[[9406,9406],"mapped",[105]],[[9407,9407],"mapped",[106]],[[9408,9408],"mapped",[107]],[[9409,9409],"mapped",[108]],[[9410,9410],"mapped",[109]],[[9411,9411],"mapped",[110]],[[9412,9412],"mapped",[111]],[[9413,9413],"mapped",[112]],[[9414,9414],"mapped",[113]],[[9415,9415],"mapped",[114]],[[9416,9416],"mapped",[115]],[[9417,9417],"mapped",[116]],[[9418,9418],"mapped",[117]],[[9419,9419],"mapped",[118]],[[9420,9420],"mapped",[119]],[[9421,9421],"mapped",[120]],[[9422,9422],"mapped",[121]],[[9423,9423],"mapped",[122]],[[9424,9424],"mapped",[97]],[[9425,9425],"mapped",[98]],[[9426,9426],"mapped",[99]],[[9427,9427],"mapped",[100]],[[9428,9428],"mapped",[101]],[[9429,9429],"mapped",[102]],[[9430,9430],"mapped",[103]],[[9431,9431],"mapped",[104]],[[9432,9432],"mapped",[105]],[[9433,9433],"mapped",[106]],[[9434,9434],"mapped",[107]],[[9435,9435],"mapped",[108]],[[9436,9436],"mapped",[109]],[[9437,9437],"mapped",[110]],[[9438,9438],"mapped",[111]],[[9439,9439],"mapped",[112]],[[9440,9440],"mapped",[113]],[[9441,9441],"mapped",[114]],[[9442,9442],"mapped",[115]],[[9443,9443],"mapped",[116]],[[9444,9444],"mapped",[117]],[[9445,9445],"mapped",[118]],[[9446,9446],"mapped",[119]],[[9447,9447],"mapped",[120]],[[9448,9448],"mapped",[121]],[[9449,9449],"mapped",[122]],[[9450,9450],"mapped",[48]],[[9451,9470],"valid",[],"NV8"],[[9471,9471],"valid",[],"NV8"],[[9472,9621],"valid",[],"NV8"],[[9622,9631],"valid",[],"NV8"],[[9632,9711],"valid",[],"NV8"],[[9712,9719],"valid",[],"NV8"],[[9720,9727],"valid",[],"NV8"],[[9728,9747],"valid",[],"NV8"],[[9748,9749],"valid",[],"NV8"],[[9750,9751],"valid",[],"NV8"],[[9752,9752],"valid",[],"NV8"],[[9753,9753],"valid",[],"NV8"],[[9754,9839],"valid",[],"NV8"],[[9840,9841],"valid",[],"NV8"],[[9842,9853],"valid",[],"NV8"],[[9854,9855],"valid",[],"NV8"],[[9856,9865],"valid",[],"NV8"],[[9866,9873],"valid",[],"NV8"],[[9874,9884],"valid",[],"NV8"],[[9885,9885],"valid",[],"NV8"],[[9886,9887],"valid",[],"NV8"],[[9888,9889],"valid",[],"NV8"],[[9890,9905],"valid",[],"NV8"],[[9906,9906],"valid",[],"NV8"],[[9907,9916],"valid",[],"NV8"],[[9917,9919],"valid",[],"NV8"],[[9920,9923],"valid",[],"NV8"],[[9924,9933],"valid",[],"NV8"],[[9934,9934],"valid",[],"NV8"],[[9935,9953],"valid",[],"NV8"],[[9954,9954],"valid",[],"NV8"],[[9955,9955],"valid",[],"NV8"],[[9956,9959],"valid",[],"NV8"],[[9960,9983],"valid",[],"NV8"],[[9984,9984],"valid",[],"NV8"],[[9985,9988],"valid",[],"NV8"],[[9989,9989],"valid",[],"NV8"],[[9990,9993],"valid",[],"NV8"],[[9994,9995],"valid",[],"NV8"],[[9996,10023],"valid",[],"NV8"],[[10024,10024],"valid",[],"NV8"],[[10025,10059],"valid",[],"NV8"],[[10060,10060],"valid",[],"NV8"],[[10061,10061],"valid",[],"NV8"],[[10062,10062],"valid",[],"NV8"],[[10063,10066],"valid",[],"NV8"],[[10067,10069],"valid",[],"NV8"],[[10070,10070],"valid",[],"NV8"],[[10071,10071],"valid",[],"NV8"],[[10072,10078],"valid",[],"NV8"],[[10079,10080],"valid",[],"NV8"],[[10081,10087],"valid",[],"NV8"],[[10088,10101],"valid",[],"NV8"],[[10102,10132],"valid",[],"NV8"],[[10133,10135],"valid",[],"NV8"],[[10136,10159],"valid",[],"NV8"],[[10160,10160],"valid",[],"NV8"],[[10161,10174],"valid",[],"NV8"],[[10175,10175],"valid",[],"NV8"],[[10176,10182],"valid",[],"NV8"],[[10183,10186],"valid",[],"NV8"],[[10187,10187],"valid",[],"NV8"],[[10188,10188],"valid",[],"NV8"],[[10189,10189],"valid",[],"NV8"],[[10190,10191],"valid",[],"NV8"],[[10192,10219],"valid",[],"NV8"],[[10220,10223],"valid",[],"NV8"],[[10224,10239],"valid",[],"NV8"],[[10240,10495],"valid",[],"NV8"],[[10496,10763],"valid",[],"NV8"],[[10764,10764],"mapped",[8747,8747,8747,8747]],[[10765,10867],"valid",[],"NV8"],[[10868,10868],"disallowed_STD3_mapped",[58,58,61]],[[10869,10869],"disallowed_STD3_mapped",[61,61]],[[10870,10870],"disallowed_STD3_mapped",[61,61,61]],[[10871,10971],"valid",[],"NV8"],[[10972,10972],"mapped",[10973,824]],[[10973,11007],"valid",[],"NV8"],[[11008,11021],"valid",[],"NV8"],[[11022,11027],"valid",[],"NV8"],[[11028,11034],"valid",[],"NV8"],[[11035,11039],"valid",[],"NV8"],[[11040,11043],"valid",[],"NV8"],[[11044,11084],"valid",[],"NV8"],[[11085,11087],"valid",[],"NV8"],[[11088,11092],"valid",[],"NV8"],[[11093,11097],"valid",[],"NV8"],[[11098,11123],"valid",[],"NV8"],[[11124,11125],"disallowed"],[[11126,11157],"valid",[],"NV8"],[[11158,11159],"disallowed"],[[11160,11193],"valid",[],"NV8"],[[11194,11196],"disallowed"],[[11197,11208],"valid",[],"NV8"],[[11209,11209],"disallowed"],[[11210,11217],"valid",[],"NV8"],[[11218,11243],"disallowed"],[[11244,11247],"valid",[],"NV8"],[[11248,11263],"disallowed"],[[11264,11264],"mapped",[11312]],[[11265,11265],"mapped",[11313]],[[11266,11266],"mapped",[11314]],[[11267,11267],"mapped",[11315]],[[11268,11268],"mapped",[11316]],[[11269,11269],"mapped",[11317]],[[11270,11270],"mapped",[11318]],[[11271,11271],"mapped",[11319]],[[11272,11272],"mapped",[11320]],[[11273,11273],"mapped",[11321]],[[11274,11274],"mapped",[11322]],[[11275,11275],"mapped",[11323]],[[11276,11276],"mapped",[11324]],[[11277,11277],"mapped",[11325]],[[11278,11278],"mapped",[11326]],[[11279,11279],"mapped",[11327]],[[11280,11280],"mapped",[11328]],[[11281,11281],"mapped",[11329]],[[11282,11282],"mapped",[11330]],[[11283,11283],"mapped",[11331]],[[11284,11284],"mapped",[11332]],[[11285,11285],"mapped",[11333]],[[11286,11286],"mapped",[11334]],[[11287,11287],"mapped",[11335]],[[11288,11288],"mapped",[11336]],[[11289,11289],"mapped",[11337]],[[11290,11290],"mapped",[11338]],[[11291,11291],"mapped",[11339]],[[11292,11292],"mapped",[11340]],[[11293,11293],"mapped",[11341]],[[11294,11294],"mapped",[11342]],[[11295,11295],"mapped",[11343]],[[11296,11296],"mapped",[11344]],[[11297,11297],"mapped",[11345]],[[11298,11298],"mapped",[11346]],[[11299,11299],"mapped",[11347]],[[11300,11300],"mapped",[11348]],[[11301,11301],"mapped",[11349]],[[11302,11302],"mapped",[11350]],[[11303,11303],"mapped",[11351]],[[11304,11304],"mapped",[11352]],[[11305,11305],"mapped",[11353]],[[11306,11306],"mapped",[11354]],[[11307,11307],"mapped",[11355]],[[11308,11308],"mapped",[11356]],[[11309,11309],"mapped",[11357]],[[11310,11310],"mapped",[11358]],[[11311,11311],"disallowed"],[[11312,11358],"valid"],[[11359,11359],"disallowed"],[[11360,11360],"mapped",[11361]],[[11361,11361],"valid"],[[11362,11362],"mapped",[619]],[[11363,11363],"mapped",[7549]],[[11364,11364],"mapped",[637]],[[11365,11366],"valid"],[[11367,11367],"mapped",[11368]],[[11368,11368],"valid"],[[11369,11369],"mapped",[11370]],[[11370,11370],"valid"],[[11371,11371],"mapped",[11372]],[[11372,11372],"valid"],[[11373,11373],"mapped",[593]],[[11374,11374],"mapped",[625]],[[11375,11375],"mapped",[592]],[[11376,11376],"mapped",[594]],[[11377,11377],"valid"],[[11378,11378],"mapped",[11379]],[[11379,11379],"valid"],[[11380,11380],"valid"],[[11381,11381],"mapped",[11382]],[[11382,11383],"valid"],[[11384,11387],"valid"],[[11388,11388],"mapped",[106]],[[11389,11389],"mapped",[118]],[[11390,11390],"mapped",[575]],[[11391,11391],"mapped",[576]],[[11392,11392],"mapped",[11393]],[[11393,11393],"valid"],[[11394,11394],"mapped",[11395]],[[11395,11395],"valid"],[[11396,11396],"mapped",[11397]],[[11397,11397],"valid"],[[11398,11398],"mapped",[11399]],[[11399,11399],"valid"],[[11400,11400],"mapped",[11401]],[[11401,11401],"valid"],[[11402,11402],"mapped",[11403]],[[11403,11403],"valid"],[[11404,11404],"mapped",[11405]],[[11405,11405],"valid"],[[11406,11406],"mapped",[11407]],[[11407,11407],"valid"],[[11408,11408],"mapped",[11409]],[[11409,11409],"valid"],[[11410,11410],"mapped",[11411]],[[11411,11411],"valid"],[[11412,11412],"mapped",[11413]],[[11413,11413],"valid"],[[11414,11414],"mapped",[11415]],[[11415,11415],"valid"],[[11416,11416],"mapped",[11417]],[[11417,11417],"valid"],[[11418,11418],"mapped",[11419]],[[11419,11419],"valid"],[[11420,11420],"mapped",[11421]],[[11421,11421],"valid"],[[11422,11422],"mapped",[11423]],[[11423,11423],"valid"],[[11424,11424],"mapped",[11425]],[[11425,11425],"valid"],[[11426,11426],"mapped",[11427]],[[11427,11427],"valid"],[[11428,11428],"mapped",[11429]],[[11429,11429],"valid"],[[11430,11430],"mapped",[11431]],[[11431,11431],"valid"],[[11432,11432],"mapped",[11433]],[[11433,11433],"valid"],[[11434,11434],"mapped",[11435]],[[11435,11435],"valid"],[[11436,11436],"mapped",[11437]],[[11437,11437],"valid"],[[11438,11438],"mapped",[11439]],[[11439,11439],"valid"],[[11440,11440],"mapped",[11441]],[[11441,11441],"valid"],[[11442,11442],"mapped",[11443]],[[11443,11443],"valid"],[[11444,11444],"mapped",[11445]],[[11445,11445],"valid"],[[11446,11446],"mapped",[11447]],[[11447,11447],"valid"],[[11448,11448],"mapped",[11449]],[[11449,11449],"valid"],[[11450,11450],"mapped",[11451]],[[11451,11451],"valid"],[[11452,11452],"mapped",[11453]],[[11453,11453],"valid"],[[11454,11454],"mapped",[11455]],[[11455,11455],"valid"],[[11456,11456],"mapped",[11457]],[[11457,11457],"valid"],[[11458,11458],"mapped",[11459]],[[11459,11459],"valid"],[[11460,11460],"mapped",[11461]],[[11461,11461],"valid"],[[11462,11462],"mapped",[11463]],[[11463,11463],"valid"],[[11464,11464],"mapped",[11465]],[[11465,11465],"valid"],[[11466,11466],"mapped",[11467]],[[11467,11467],"valid"],[[11468,11468],"mapped",[11469]],[[11469,11469],"valid"],[[11470,11470],"mapped",[11471]],[[11471,11471],"valid"],[[11472,11472],"mapped",[11473]],[[11473,11473],"valid"],[[11474,11474],"mapped",[11475]],[[11475,11475],"valid"],[[11476,11476],"mapped",[11477]],[[11477,11477],"valid"],[[11478,11478],"mapped",[11479]],[[11479,11479],"valid"],[[11480,11480],"mapped",[11481]],[[11481,11481],"valid"],[[11482,11482],"mapped",[11483]],[[11483,11483],"valid"],[[11484,11484],"mapped",[11485]],[[11485,11485],"valid"],[[11486,11486],"mapped",[11487]],[[11487,11487],"valid"],[[11488,11488],"mapped",[11489]],[[11489,11489],"valid"],[[11490,11490],"mapped",[11491]],[[11491,11492],"valid"],[[11493,11498],"valid",[],"NV8"],[[11499,11499],"mapped",[11500]],[[11500,11500],"valid"],[[11501,11501],"mapped",[11502]],[[11502,11505],"valid"],[[11506,11506],"mapped",[11507]],[[11507,11507],"valid"],[[11508,11512],"disallowed"],[[11513,11519],"valid",[],"NV8"],[[11520,11557],"valid"],[[11558,11558],"disallowed"],[[11559,11559],"valid"],[[11560,11564],"disallowed"],[[11565,11565],"valid"],[[11566,11567],"disallowed"],[[11568,11621],"valid"],[[11622,11623],"valid"],[[11624,11630],"disallowed"],[[11631,11631],"mapped",[11617]],[[11632,11632],"valid",[],"NV8"],[[11633,11646],"disallowed"],[[11647,11647],"valid"],[[11648,11670],"valid"],[[11671,11679],"disallowed"],[[11680,11686],"valid"],[[11687,11687],"disallowed"],[[11688,11694],"valid"],[[11695,11695],"disallowed"],[[11696,11702],"valid"],[[11703,11703],"disallowed"],[[11704,11710],"valid"],[[11711,11711],"disallowed"],[[11712,11718],"valid"],[[11719,11719],"disallowed"],[[11720,11726],"valid"],[[11727,11727],"disallowed"],[[11728,11734],"valid"],[[11735,11735],"disallowed"],[[11736,11742],"valid"],[[11743,11743],"disallowed"],[[11744,11775],"valid"],[[11776,11799],"valid",[],"NV8"],[[11800,11803],"valid",[],"NV8"],[[11804,11805],"valid",[],"NV8"],[[11806,11822],"valid",[],"NV8"],[[11823,11823],"valid"],[[11824,11824],"valid",[],"NV8"],[[11825,11825],"valid",[],"NV8"],[[11826,11835],"valid",[],"NV8"],[[11836,11842],"valid",[],"NV8"],[[11843,11903],"disallowed"],[[11904,11929],"valid",[],"NV8"],[[11930,11930],"disallowed"],[[11931,11934],"valid",[],"NV8"],[[11935,11935],"mapped",[27597]],[[11936,12018],"valid",[],"NV8"],[[12019,12019],"mapped",[40863]],[[12020,12031],"disallowed"],[[12032,12032],"mapped",[19968]],[[12033,12033],"mapped",[20008]],[[12034,12034],"mapped",[20022]],[[12035,12035],"mapped",[20031]],[[12036,12036],"mapped",[20057]],[[12037,12037],"mapped",[20101]],[[12038,12038],"mapped",[20108]],[[12039,12039],"mapped",[20128]],[[12040,12040],"mapped",[20154]],[[12041,12041],"mapped",[20799]],[[12042,12042],"mapped",[20837]],[[12043,12043],"mapped",[20843]],[[12044,12044],"mapped",[20866]],[[12045,12045],"mapped",[20886]],[[12046,12046],"mapped",[20907]],[[12047,12047],"mapped",[20960]],[[12048,12048],"mapped",[20981]],[[12049,12049],"mapped",[20992]],[[12050,12050],"mapped",[21147]],[[12051,12051],"mapped",[21241]],[[12052,12052],"mapped",[21269]],[[12053,12053],"mapped",[21274]],[[12054,12054],"mapped",[21304]],[[12055,12055],"mapped",[21313]],[[12056,12056],"mapped",[21340]],[[12057,12057],"mapped",[21353]],[[12058,12058],"mapped",[21378]],[[12059,12059],"mapped",[21430]],[[12060,12060],"mapped",[21448]],[[12061,12061],"mapped",[21475]],[[12062,12062],"mapped",[22231]],[[12063,12063],"mapped",[22303]],[[12064,12064],"mapped",[22763]],[[12065,12065],"mapped",[22786]],[[12066,12066],"mapped",[22794]],[[12067,12067],"mapped",[22805]],[[12068,12068],"mapped",[22823]],[[12069,12069],"mapped",[22899]],[[12070,12070],"mapped",[23376]],[[12071,12071],"mapped",[23424]],[[12072,12072],"mapped",[23544]],[[12073,12073],"mapped",[23567]],[[12074,12074],"mapped",[23586]],[[12075,12075],"mapped",[23608]],[[12076,12076],"mapped",[23662]],[[12077,12077],"mapped",[23665]],[[12078,12078],"mapped",[24027]],[[12079,12079],"mapped",[24037]],[[12080,12080],"mapped",[24049]],[[12081,12081],"mapped",[24062]],[[12082,12082],"mapped",[24178]],[[12083,12083],"mapped",[24186]],[[12084,12084],"mapped",[24191]],[[12085,12085],"mapped",[24308]],[[12086,12086],"mapped",[24318]],[[12087,12087],"mapped",[24331]],[[12088,12088],"mapped",[24339]],[[12089,12089],"mapped",[24400]],[[12090,12090],"mapped",[24417]],[[12091,12091],"mapped",[24435]],[[12092,12092],"mapped",[24515]],[[12093,12093],"mapped",[25096]],[[12094,12094],"mapped",[25142]],[[12095,12095],"mapped",[25163]],[[12096,12096],"mapped",[25903]],[[12097,12097],"mapped",[25908]],[[12098,12098],"mapped",[25991]],[[12099,12099],"mapped",[26007]],[[12100,12100],"mapped",[26020]],[[12101,12101],"mapped",[26041]],[[12102,12102],"mapped",[26080]],[[12103,12103],"mapped",[26085]],[[12104,12104],"mapped",[26352]],[[12105,12105],"mapped",[26376]],[[12106,12106],"mapped",[26408]],[[12107,12107],"mapped",[27424]],[[12108,12108],"mapped",[27490]],[[12109,12109],"mapped",[27513]],[[12110,12110],"mapped",[27571]],[[12111,12111],"mapped",[27595]],[[12112,12112],"mapped",[27604]],[[12113,12113],"mapped",[27611]],[[12114,12114],"mapped",[27663]],[[12115,12115],"mapped",[27668]],[[12116,12116],"mapped",[27700]],[[12117,12117],"mapped",[28779]],[[12118,12118],"mapped",[29226]],[[12119,12119],"mapped",[29238]],[[12120,12120],"mapped",[29243]],[[12121,12121],"mapped",[29247]],[[12122,12122],"mapped",[29255]],[[12123,12123],"mapped",[29273]],[[12124,12124],"mapped",[29275]],[[12125,12125],"mapped",[29356]],[[12126,12126],"mapped",[29572]],[[12127,12127],"mapped",[29577]],[[12128,12128],"mapped",[29916]],[[12129,12129],"mapped",[29926]],[[12130,12130],"mapped",[29976]],[[12131,12131],"mapped",[29983]],[[12132,12132],"mapped",[29992]],[[12133,12133],"mapped",[30000]],[[12134,12134],"mapped",[30091]],[[12135,12135],"mapped",[30098]],[[12136,12136],"mapped",[30326]],[[12137,12137],"mapped",[30333]],[[12138,12138],"mapped",[30382]],[[12139,12139],"mapped",[30399]],[[12140,12140],"mapped",[30446]],[[12141,12141],"mapped",[30683]],[[12142,12142],"mapped",[30690]],[[12143,12143],"mapped",[30707]],[[12144,12144],"mapped",[31034]],[[12145,12145],"mapped",[31160]],[[12146,12146],"mapped",[31166]],[[12147,12147],"mapped",[31348]],[[12148,12148],"mapped",[31435]],[[12149,12149],"mapped",[31481]],[[12150,12150],"mapped",[31859]],[[12151,12151],"mapped",[31992]],[[12152,12152],"mapped",[32566]],[[12153,12153],"mapped",[32593]],[[12154,12154],"mapped",[32650]],[[12155,12155],"mapped",[32701]],[[12156,12156],"mapped",[32769]],[[12157,12157],"mapped",[32780]],[[12158,12158],"mapped",[32786]],[[12159,12159],"mapped",[32819]],[[12160,12160],"mapped",[32895]],[[12161,12161],"mapped",[32905]],[[12162,12162],"mapped",[33251]],[[12163,12163],"mapped",[33258]],[[12164,12164],"mapped",[33267]],[[12165,12165],"mapped",[33276]],[[12166,12166],"mapped",[33292]],[[12167,12167],"mapped",[33307]],[[12168,12168],"mapped",[33311]],[[12169,12169],"mapped",[33390]],[[12170,12170],"mapped",[33394]],[[12171,12171],"mapped",[33400]],[[12172,12172],"mapped",[34381]],[[12173,12173],"mapped",[34411]],[[12174,12174],"mapped",[34880]],[[12175,12175],"mapped",[34892]],[[12176,12176],"mapped",[34915]],[[12177,12177],"mapped",[35198]],[[12178,12178],"mapped",[35211]],[[12179,12179],"mapped",[35282]],[[12180,12180],"mapped",[35328]],[[12181,12181],"mapped",[35895]],[[12182,12182],"mapped",[35910]],[[12183,12183],"mapped",[35925]],[[12184,12184],"mapped",[35960]],[[12185,12185],"mapped",[35997]],[[12186,12186],"mapped",[36196]],[[12187,12187],"mapped",[36208]],[[12188,12188],"mapped",[36275]],[[12189,12189],"mapped",[36523]],[[12190,12190],"mapped",[36554]],[[12191,12191],"mapped",[36763]],[[12192,12192],"mapped",[36784]],[[12193,12193],"mapped",[36789]],[[12194,12194],"mapped",[37009]],[[12195,12195],"mapped",[37193]],[[12196,12196],"mapped",[37318]],[[12197,12197],"mapped",[37324]],[[12198,12198],"mapped",[37329]],[[12199,12199],"mapped",[38263]],[[12200,12200],"mapped",[38272]],[[12201,12201],"mapped",[38428]],[[12202,12202],"mapped",[38582]],[[12203,12203],"mapped",[38585]],[[12204,12204],"mapped",[38632]],[[12205,12205],"mapped",[38737]],[[12206,12206],"mapped",[38750]],[[12207,12207],"mapped",[38754]],[[12208,12208],"mapped",[38761]],[[12209,12209],"mapped",[38859]],[[12210,12210],"mapped",[38893]],[[12211,12211],"mapped",[38899]],[[12212,12212],"mapped",[38913]],[[12213,12213],"mapped",[39080]],[[12214,12214],"mapped",[39131]],[[12215,12215],"mapped",[39135]],[[12216,12216],"mapped",[39318]],[[12217,12217],"mapped",[39321]],[[12218,12218],"mapped",[39340]],[[12219,12219],"mapped",[39592]],[[12220,12220],"mapped",[39640]],[[12221,12221],"mapped",[39647]],[[12222,12222],"mapped",[39717]],[[12223,12223],"mapped",[39727]],[[12224,12224],"mapped",[39730]],[[12225,12225],"mapped",[39740]],[[12226,12226],"mapped",[39770]],[[12227,12227],"mapped",[40165]],[[12228,12228],"mapped",[40565]],[[12229,12229],"mapped",[40575]],[[12230,12230],"mapped",[40613]],[[12231,12231],"mapped",[40635]],[[12232,12232],"mapped",[40643]],[[12233,12233],"mapped",[40653]],[[12234,12234],"mapped",[40657]],[[12235,12235],"mapped",[40697]],[[12236,12236],"mapped",[40701]],[[12237,12237],"mapped",[40718]],[[12238,12238],"mapped",[40723]],[[12239,12239],"mapped",[40736]],[[12240,12240],"mapped",[40763]],[[12241,12241],"mapped",[40778]],[[12242,12242],"mapped",[40786]],[[12243,12243],"mapped",[40845]],[[12244,12244],"mapped",[40860]],[[12245,12245],"mapped",[40864]],[[12246,12271],"disallowed"],[[12272,12283],"disallowed"],[[12284,12287],"disallowed"],[[12288,12288],"disallowed_STD3_mapped",[32]],[[12289,12289],"valid",[],"NV8"],[[12290,12290],"mapped",[46]],[[12291,12292],"valid",[],"NV8"],[[12293,12295],"valid"],[[12296,12329],"valid",[],"NV8"],[[12330,12333],"valid"],[[12334,12341],"valid",[],"NV8"],[[12342,12342],"mapped",[12306]],[[12343,12343],"valid",[],"NV8"],[[12344,12344],"mapped",[21313]],[[12345,12345],"mapped",[21316]],[[12346,12346],"mapped",[21317]],[[12347,12347],"valid",[],"NV8"],[[12348,12348],"valid"],[[12349,12349],"valid",[],"NV8"],[[12350,12350],"valid",[],"NV8"],[[12351,12351],"valid",[],"NV8"],[[12352,12352],"disallowed"],[[12353,12436],"valid"],[[12437,12438],"valid"],[[12439,12440],"disallowed"],[[12441,12442],"valid"],[[12443,12443],"disallowed_STD3_mapped",[32,12441]],[[12444,12444],"disallowed_STD3_mapped",[32,12442]],[[12445,12446],"valid"],[[12447,12447],"mapped",[12424,12426]],[[12448,12448],"valid",[],"NV8"],[[12449,12542],"valid"],[[12543,12543],"mapped",[12467,12488]],[[12544,12548],"disallowed"],[[12549,12588],"valid"],[[12589,12589],"valid"],[[12590,12592],"disallowed"],[[12593,12593],"mapped",[4352]],[[12594,12594],"mapped",[4353]],[[12595,12595],"mapped",[4522]],[[12596,12596],"mapped",[4354]],[[12597,12597],"mapped",[4524]],[[12598,12598],"mapped",[4525]],[[12599,12599],"mapped",[4355]],[[12600,12600],"mapped",[4356]],[[12601,12601],"mapped",[4357]],[[12602,12602],"mapped",[4528]],[[12603,12603],"mapped",[4529]],[[12604,12604],"mapped",[4530]],[[12605,12605],"mapped",[4531]],[[12606,12606],"mapped",[4532]],[[12607,12607],"mapped",[4533]],[[12608,12608],"mapped",[4378]],[[12609,12609],"mapped",[4358]],[[12610,12610],"mapped",[4359]],[[12611,12611],"mapped",[4360]],[[12612,12612],"mapped",[4385]],[[12613,12613],"mapped",[4361]],[[12614,12614],"mapped",[4362]],[[12615,12615],"mapped",[4363]],[[12616,12616],"mapped",[4364]],[[12617,12617],"mapped",[4365]],[[12618,12618],"mapped",[4366]],[[12619,12619],"mapped",[4367]],[[12620,12620],"mapped",[4368]],[[12621,12621],"mapped",[4369]],[[12622,12622],"mapped",[4370]],[[12623,12623],"mapped",[4449]],[[12624,12624],"mapped",[4450]],[[12625,12625],"mapped",[4451]],[[12626,12626],"mapped",[4452]],[[12627,12627],"mapped",[4453]],[[12628,12628],"mapped",[4454]],[[12629,12629],"mapped",[4455]],[[12630,12630],"mapped",[4456]],[[12631,12631],"mapped",[4457]],[[12632,12632],"mapped",[4458]],[[12633,12633],"mapped",[4459]],[[12634,12634],"mapped",[4460]],[[12635,12635],"mapped",[4461]],[[12636,12636],"mapped",[4462]],[[12637,12637],"mapped",[4463]],[[12638,12638],"mapped",[4464]],[[12639,12639],"mapped",[4465]],[[12640,12640],"mapped",[4466]],[[12641,12641],"mapped",[4467]],[[12642,12642],"mapped",[4468]],[[12643,12643],"mapped",[4469]],[[12644,12644],"disallowed"],[[12645,12645],"mapped",[4372]],[[12646,12646],"mapped",[4373]],[[12647,12647],"mapped",[4551]],[[12648,12648],"mapped",[4552]],[[12649,12649],"mapped",[4556]],[[12650,12650],"mapped",[4558]],[[12651,12651],"mapped",[4563]],[[12652,12652],"mapped",[4567]],[[12653,12653],"mapped",[4569]],[[12654,12654],"mapped",[4380]],[[12655,12655],"mapped",[4573]],[[12656,12656],"mapped",[4575]],[[12657,12657],"mapped",[4381]],[[12658,12658],"mapped",[4382]],[[12659,12659],"mapped",[4384]],[[12660,12660],"mapped",[4386]],[[12661,12661],"mapped",[4387]],[[12662,12662],"mapped",[4391]],[[12663,12663],"mapped",[4393]],[[12664,12664],"mapped",[4395]],[[12665,12665],"mapped",[4396]],[[12666,12666],"mapped",[4397]],[[12667,12667],"mapped",[4398]],[[12668,12668],"mapped",[4399]],[[12669,12669],"mapped",[4402]],[[12670,12670],"mapped",[4406]],[[12671,12671],"mapped",[4416]],[[12672,12672],"mapped",[4423]],[[12673,12673],"mapped",[4428]],[[12674,12674],"mapped",[4593]],[[12675,12675],"mapped",[4594]],[[12676,12676],"mapped",[4439]],[[12677,12677],"mapped",[4440]],[[12678,12678],"mapped",[4441]],[[12679,12679],"mapped",[4484]],[[12680,12680],"mapped",[4485]],[[12681,12681],"mapped",[4488]],[[12682,12682],"mapped",[4497]],[[12683,12683],"mapped",[4498]],[[12684,12684],"mapped",[4500]],[[12685,12685],"mapped",[4510]],[[12686,12686],"mapped",[4513]],[[12687,12687],"disallowed"],[[12688,12689],"valid",[],"NV8"],[[12690,12690],"mapped",[19968]],[[12691,12691],"mapped",[20108]],[[12692,12692],"mapped",[19977]],[[12693,12693],"mapped",[22235]],[[12694,12694],"mapped",[19978]],[[12695,12695],"mapped",[20013]],[[12696,12696],"mapped",[19979]],[[12697,12697],"mapped",[30002]],[[12698,12698],"mapped",[20057]],[[12699,12699],"mapped",[19993]],[[12700,12700],"mapped",[19969]],[[12701,12701],"mapped",[22825]],[[12702,12702],"mapped",[22320]],[[12703,12703],"mapped",[20154]],[[12704,12727],"valid"],[[12728,12730],"valid"],[[12731,12735],"disallowed"],[[12736,12751],"valid",[],"NV8"],[[12752,12771],"valid",[],"NV8"],[[12772,12783],"disallowed"],[[12784,12799],"valid"],[[12800,12800],"disallowed_STD3_mapped",[40,4352,41]],[[12801,12801],"disallowed_STD3_mapped",[40,4354,41]],[[12802,12802],"disallowed_STD3_mapped",[40,4355,41]],[[12803,12803],"disallowed_STD3_mapped",[40,4357,41]],[[12804,12804],"disallowed_STD3_mapped",[40,4358,41]],[[12805,12805],"disallowed_STD3_mapped",[40,4359,41]],[[12806,12806],"disallowed_STD3_mapped",[40,4361,41]],[[12807,12807],"disallowed_STD3_mapped",[40,4363,41]],[[12808,12808],"disallowed_STD3_mapped",[40,4364,41]],[[12809,12809],"disallowed_STD3_mapped",[40,4366,41]],[[12810,12810],"disallowed_STD3_mapped",[40,4367,41]],[[12811,12811],"disallowed_STD3_mapped",[40,4368,41]],[[12812,12812],"disallowed_STD3_mapped",[40,4369,41]],[[12813,12813],"disallowed_STD3_mapped",[40,4370,41]],[[12814,12814],"disallowed_STD3_mapped",[40,44032,41]],[[12815,12815],"disallowed_STD3_mapped",[40,45208,41]],[[12816,12816],"disallowed_STD3_mapped",[40,45796,41]],[[12817,12817],"disallowed_STD3_mapped",[40,46972,41]],[[12818,12818],"disallowed_STD3_mapped",[40,47560,41]],[[12819,12819],"disallowed_STD3_mapped",[40,48148,41]],[[12820,12820],"disallowed_STD3_mapped",[40,49324,41]],[[12821,12821],"disallowed_STD3_mapped",[40,50500,41]],[[12822,12822],"disallowed_STD3_mapped",[40,51088,41]],[[12823,12823],"disallowed_STD3_mapped",[40,52264,41]],[[12824,12824],"disallowed_STD3_mapped",[40,52852,41]],[[12825,12825],"disallowed_STD3_mapped",[40,53440,41]],[[12826,12826],"disallowed_STD3_mapped",[40,54028,41]],[[12827,12827],"disallowed_STD3_mapped",[40,54616,41]],[[12828,12828],"disallowed_STD3_mapped",[40,51452,41]],[[12829,12829],"disallowed_STD3_mapped",[40,50724,51204,41]],[[12830,12830],"disallowed_STD3_mapped",[40,50724,54980,41]],[[12831,12831],"disallowed"],[[12832,12832],"disallowed_STD3_mapped",[40,19968,41]],[[12833,12833],"disallowed_STD3_mapped",[40,20108,41]],[[12834,12834],"disallowed_STD3_mapped",[40,19977,41]],[[12835,12835],"disallowed_STD3_mapped",[40,22235,41]],[[12836,12836],"disallowed_STD3_mapped",[40,20116,41]],[[12837,12837],"disallowed_STD3_mapped",[40,20845,41]],[[12838,12838],"disallowed_STD3_mapped",[40,19971,41]],[[12839,12839],"disallowed_STD3_mapped",[40,20843,41]],[[12840,12840],"disallowed_STD3_mapped",[40,20061,41]],[[12841,12841],"disallowed_STD3_mapped",[40,21313,41]],[[12842,12842],"disallowed_STD3_mapped",[40,26376,41]],[[12843,12843],"disallowed_STD3_mapped",[40,28779,41]],[[12844,12844],"disallowed_STD3_mapped",[40,27700,41]],[[12845,12845],"disallowed_STD3_mapped",[40,26408,41]],[[12846,12846],"disallowed_STD3_mapped",[40,37329,41]],[[12847,12847],"disallowed_STD3_mapped",[40,22303,41]],[[12848,12848],"disallowed_STD3_mapped",[40,26085,41]],[[12849,12849],"disallowed_STD3_mapped",[40,26666,41]],[[12850,12850],"disallowed_STD3_mapped",[40,26377,41]],[[12851,12851],"disallowed_STD3_mapped",[40,31038,41]],[[12852,12852],"disallowed_STD3_mapped",[40,21517,41]],[[12853,12853],"disallowed_STD3_mapped",[40,29305,41]],[[12854,12854],"disallowed_STD3_mapped",[40,36001,41]],[[12855,12855],"disallowed_STD3_mapped",[40,31069,41]],[[12856,12856],"disallowed_STD3_mapped",[40,21172,41]],[[12857,12857],"disallowed_STD3_mapped",[40,20195,41]],[[12858,12858],"disallowed_STD3_mapped",[40,21628,41]],[[12859,12859],"disallowed_STD3_mapped",[40,23398,41]],[[12860,12860],"disallowed_STD3_mapped",[40,30435,41]],[[12861,12861],"disallowed_STD3_mapped",[40,20225,41]],[[12862,12862],"disallowed_STD3_mapped",[40,36039,41]],[[12863,12863],"disallowed_STD3_mapped",[40,21332,41]],[[12864,12864],"disallowed_STD3_mapped",[40,31085,41]],[[12865,12865],"disallowed_STD3_mapped",[40,20241,41]],[[12866,12866],"disallowed_STD3_mapped",[40,33258,41]],[[12867,12867],"disallowed_STD3_mapped",[40,33267,41]],[[12868,12868],"mapped",[21839]],[[12869,12869],"mapped",[24188]],[[12870,12870],"mapped",[25991]],[[12871,12871],"mapped",[31631]],[[12872,12879],"valid",[],"NV8"],[[12880,12880],"mapped",[112,116,101]],[[12881,12881],"mapped",[50,49]],[[12882,12882],"mapped",[50,50]],[[12883,12883],"mapped",[50,51]],[[12884,12884],"mapped",[50,52]],[[12885,12885],"mapped",[50,53]],[[12886,12886],"mapped",[50,54]],[[12887,12887],"mapped",[50,55]],[[12888,12888],"mapped",[50,56]],[[12889,12889],"mapped",[50,57]],[[12890,12890],"mapped",[51,48]],[[12891,12891],"mapped",[51,49]],[[12892,12892],"mapped",[51,50]],[[12893,12893],"mapped",[51,51]],[[12894,12894],"mapped",[51,52]],[[12895,12895],"mapped",[51,53]],[[12896,12896],"mapped",[4352]],[[12897,12897],"mapped",[4354]],[[12898,12898],"mapped",[4355]],[[12899,12899],"mapped",[4357]],[[12900,12900],"mapped",[4358]],[[12901,12901],"mapped",[4359]],[[12902,12902],"mapped",[4361]],[[12903,12903],"mapped",[4363]],[[12904,12904],"mapped",[4364]],[[12905,12905],"mapped",[4366]],[[12906,12906],"mapped",[4367]],[[12907,12907],"mapped",[4368]],[[12908,12908],"mapped",[4369]],[[12909,12909],"mapped",[4370]],[[12910,12910],"mapped",[44032]],[[12911,12911],"mapped",[45208]],[[12912,12912],"mapped",[45796]],[[12913,12913],"mapped",[46972]],[[12914,12914],"mapped",[47560]],[[12915,12915],"mapped",[48148]],[[12916,12916],"mapped",[49324]],[[12917,12917],"mapped",[50500]],[[12918,12918],"mapped",[51088]],[[12919,12919],"mapped",[52264]],[[12920,12920],"mapped",[52852]],[[12921,12921],"mapped",[53440]],[[12922,12922],"mapped",[54028]],[[12923,12923],"mapped",[54616]],[[12924,12924],"mapped",[52280,44256]],[[12925,12925],"mapped",[51452,51032]],[[12926,12926],"mapped",[50864]],[[12927,12927],"valid",[],"NV8"],[[12928,12928],"mapped",[19968]],[[12929,12929],"mapped",[20108]],[[12930,12930],"mapped",[19977]],[[12931,12931],"mapped",[22235]],[[12932,12932],"mapped",[20116]],[[12933,12933],"mapped",[20845]],[[12934,12934],"mapped",[19971]],[[12935,12935],"mapped",[20843]],[[12936,12936],"mapped",[20061]],[[12937,12937],"mapped",[21313]],[[12938,12938],"mapped",[26376]],[[12939,12939],"mapped",[28779]],[[12940,12940],"mapped",[27700]],[[12941,12941],"mapped",[26408]],[[12942,12942],"mapped",[37329]],[[12943,12943],"mapped",[22303]],[[12944,12944],"mapped",[26085]],[[12945,12945],"mapped",[26666]],[[12946,12946],"mapped",[26377]],[[12947,12947],"mapped",[31038]],[[12948,12948],"mapped",[21517]],[[12949,12949],"mapped",[29305]],[[12950,12950],"mapped",[36001]],[[12951,12951],"mapped",[31069]],[[12952,12952],"mapped",[21172]],[[12953,12953],"mapped",[31192]],[[12954,12954],"mapped",[30007]],[[12955,12955],"mapped",[22899]],[[12956,12956],"mapped",[36969]],[[12957,12957],"mapped",[20778]],[[12958,12958],"mapped",[21360]],[[12959,12959],"mapped",[27880]],[[12960,12960],"mapped",[38917]],[[12961,12961],"mapped",[20241]],[[12962,12962],"mapped",[20889]],[[12963,12963],"mapped",[27491]],[[12964,12964],"mapped",[19978]],[[12965,12965],"mapped",[20013]],[[12966,12966],"mapped",[19979]],[[12967,12967],"mapped",[24038]],[[12968,12968],"mapped",[21491]],[[12969,12969],"mapped",[21307]],[[12970,12970],"mapped",[23447]],[[12971,12971],"mapped",[23398]],[[12972,12972],"mapped",[30435]],[[12973,12973],"mapped",[20225]],[[12974,12974],"mapped",[36039]],[[12975,12975],"mapped",[21332]],[[12976,12976],"mapped",[22812]],[[12977,12977],"mapped",[51,54]],[[12978,12978],"mapped",[51,55]],[[12979,12979],"mapped",[51,56]],[[12980,12980],"mapped",[51,57]],[[12981,12981],"mapped",[52,48]],[[12982,12982],"mapped",[52,49]],[[12983,12983],"mapped",[52,50]],[[12984,12984],"mapped",[52,51]],[[12985,12985],"mapped",[52,52]],[[12986,12986],"mapped",[52,53]],[[12987,12987],"mapped",[52,54]],[[12988,12988],"mapped",[52,55]],[[12989,12989],"mapped",[52,56]],[[12990,12990],"mapped",[52,57]],[[12991,12991],"mapped",[53,48]],[[12992,12992],"mapped",[49,26376]],[[12993,12993],"mapped",[50,26376]],[[12994,12994],"mapped",[51,26376]],[[12995,12995],"mapped",[52,26376]],[[12996,12996],"mapped",[53,26376]],[[12997,12997],"mapped",[54,26376]],[[12998,12998],"mapped",[55,26376]],[[12999,12999],"mapped",[56,26376]],[[13000,13000],"mapped",[57,26376]],[[13001,13001],"mapped",[49,48,26376]],[[13002,13002],"mapped",[49,49,26376]],[[13003,13003],"mapped",[49,50,26376]],[[13004,13004],"mapped",[104,103]],[[13005,13005],"mapped",[101,114,103]],[[13006,13006],"mapped",[101,118]],[[13007,13007],"mapped",[108,116,100]],[[13008,13008],"mapped",[12450]],[[13009,13009],"mapped",[12452]],[[13010,13010],"mapped",[12454]],[[13011,13011],"mapped",[12456]],[[13012,13012],"mapped",[12458]],[[13013,13013],"mapped",[12459]],[[13014,13014],"mapped",[12461]],[[13015,13015],"mapped",[12463]],[[13016,13016],"mapped",[12465]],[[13017,13017],"mapped",[12467]],[[13018,13018],"mapped",[12469]],[[13019,13019],"mapped",[12471]],[[13020,13020],"mapped",[12473]],[[13021,13021],"mapped",[12475]],[[13022,13022],"mapped",[12477]],[[13023,13023],"mapped",[12479]],[[13024,13024],"mapped",[12481]],[[13025,13025],"mapped",[12484]],[[13026,13026],"mapped",[12486]],[[13027,13027],"mapped",[12488]],[[13028,13028],"mapped",[12490]],[[13029,13029],"mapped",[12491]],[[13030,13030],"mapped",[12492]],[[13031,13031],"mapped",[12493]],[[13032,13032],"mapped",[12494]],[[13033,13033],"mapped",[12495]],[[13034,13034],"mapped",[12498]],[[13035,13035],"mapped",[12501]],[[13036,13036],"mapped",[12504]],[[13037,13037],"mapped",[12507]],[[13038,13038],"mapped",[12510]],[[13039,13039],"mapped",[12511]],[[13040,13040],"mapped",[12512]],[[13041,13041],"mapped",[12513]],[[13042,13042],"mapped",[12514]],[[13043,13043],"mapped",[12516]],[[13044,13044],"mapped",[12518]],[[13045,13045],"mapped",[12520]],[[13046,13046],"mapped",[12521]],[[13047,13047],"mapped",[12522]],[[13048,13048],"mapped",[12523]],[[13049,13049],"mapped",[12524]],[[13050,13050],"mapped",[12525]],[[13051,13051],"mapped",[12527]],[[13052,13052],"mapped",[12528]],[[13053,13053],"mapped",[12529]],[[13054,13054],"mapped",[12530]],[[13055,13055],"disallowed"],[[13056,13056],"mapped",[12450,12497,12540,12488]],[[13057,13057],"mapped",[12450,12523,12501,12449]],[[13058,13058],"mapped",[12450,12531,12506,12450]],[[13059,13059],"mapped",[12450,12540,12523]],[[13060,13060],"mapped",[12452,12491,12531,12464]],[[13061,13061],"mapped",[12452,12531,12481]],[[13062,13062],"mapped",[12454,12457,12531]],[[13063,13063],"mapped",[12456,12473,12463,12540,12489]],[[13064,13064],"mapped",[12456,12540,12459,12540]],[[13065,13065],"mapped",[12458,12531,12473]],[[13066,13066],"mapped",[12458,12540,12512]],[[13067,13067],"mapped",[12459,12452,12522]],[[13068,13068],"mapped",[12459,12521,12483,12488]],[[13069,13069],"mapped",[12459,12525,12522,12540]],[[13070,13070],"mapped",[12460,12525,12531]],[[13071,13071],"mapped",[12460,12531,12510]],[[13072,13072],"mapped",[12462,12460]],[[13073,13073],"mapped",[12462,12491,12540]],[[13074,13074],"mapped",[12461,12517,12522,12540]],[[13075,13075],"mapped",[12462,12523,12480,12540]],[[13076,13076],"mapped",[12461,12525]],[[13077,13077],"mapped",[12461,12525,12464,12521,12512]],[[13078,13078],"mapped",[12461,12525,12513,12540,12488,12523]],[[13079,13079],"mapped",[12461,12525,12527,12483,12488]],[[13080,13080],"mapped",[12464,12521,12512]],[[13081,13081],"mapped",[12464,12521,12512,12488,12531]],[[13082,13082],"mapped",[12463,12523,12476,12452,12525]],[[13083,13083],"mapped",[12463,12525,12540,12493]],[[13084,13084],"mapped",[12465,12540,12473]],[[13085,13085],"mapped",[12467,12523,12490]],[[13086,13086],"mapped",[12467,12540,12509]],[[13087,13087],"mapped",[12469,12452,12463,12523]],[[13088,13088],"mapped",[12469,12531,12481,12540,12512]],[[13089,13089],"mapped",[12471,12522,12531,12464]],[[13090,13090],"mapped",[12475,12531,12481]],[[13091,13091],"mapped",[12475,12531,12488]],[[13092,13092],"mapped",[12480,12540,12473]],[[13093,13093],"mapped",[12487,12471]],[[13094,13094],"mapped",[12489,12523]],[[13095,13095],"mapped",[12488,12531]],[[13096,13096],"mapped",[12490,12494]],[[13097,13097],"mapped",[12494,12483,12488]],[[13098,13098],"mapped",[12495,12452,12484]],[[13099,13099],"mapped",[12497,12540,12475,12531,12488]],[[13100,13100],"mapped",[12497,12540,12484]],[[13101,13101],"mapped",[12496,12540,12524,12523]],[[13102,13102],"mapped",[12500,12450,12473,12488,12523]],[[13103,13103],"mapped",[12500,12463,12523]],[[13104,13104],"mapped",[12500,12467]],[[13105,13105],"mapped",[12499,12523]],[[13106,13106],"mapped",[12501,12449,12521,12483,12489]],[[13107,13107],"mapped",[12501,12451,12540,12488]],[[13108,13108],"mapped",[12502,12483,12471,12455,12523]],[[13109,13109],"mapped",[12501,12521,12531]],[[13110,13110],"mapped",[12504,12463,12479,12540,12523]],[[13111,13111],"mapped",[12506,12477]],[[13112,13112],"mapped",[12506,12491,12498]],[[13113,13113],"mapped",[12504,12523,12484]],[[13114,13114],"mapped",[12506,12531,12473]],[[13115,13115],"mapped",[12506,12540,12472]],[[13116,13116],"mapped",[12505,12540,12479]],[[13117,13117],"mapped",[12509,12452,12531,12488]],[[13118,13118],"mapped",[12508,12523,12488]],[[13119,13119],"mapped",[12507,12531]],[[13120,13120],"mapped",[12509,12531,12489]],[[13121,13121],"mapped",[12507,12540,12523]],[[13122,13122],"mapped",[12507,12540,12531]],[[13123,13123],"mapped",[12510,12452,12463,12525]],[[13124,13124],"mapped",[12510,12452,12523]],[[13125,13125],"mapped",[12510,12483,12495]],[[13126,13126],"mapped",[12510,12523,12463]],[[13127,13127],"mapped",[12510,12531,12471,12519,12531]],[[13128,13128],"mapped",[12511,12463,12525,12531]],[[13129,13129],"mapped",[12511,12522]],[[13130,13130],"mapped",[12511,12522,12496,12540,12523]],[[13131,13131],"mapped",[12513,12460]],[[13132,13132],"mapped",[12513,12460,12488,12531]],[[13133,13133],"mapped",[12513,12540,12488,12523]],[[13134,13134],"mapped",[12516,12540,12489]],[[13135,13135],"mapped",[12516,12540,12523]],[[13136,13136],"mapped",[12518,12450,12531]],[[13137,13137],"mapped",[12522,12483,12488,12523]],[[13138,13138],"mapped",[12522,12521]],[[13139,13139],"mapped",[12523,12500,12540]],[[13140,13140],"mapped",[12523,12540,12502,12523]],[[13141,13141],"mapped",[12524,12512]],[[13142,13142],"mapped",[12524,12531,12488,12466,12531]],[[13143,13143],"mapped",[12527,12483,12488]],[[13144,13144],"mapped",[48,28857]],[[13145,13145],"mapped",[49,28857]],[[13146,13146],"mapped",[50,28857]],[[13147,13147],"mapped",[51,28857]],[[13148,13148],"mapped",[52,28857]],[[13149,13149],"mapped",[53,28857]],[[13150,13150],"mapped",[54,28857]],[[13151,13151],"mapped",[55,28857]],[[13152,13152],"mapped",[56,28857]],[[13153,13153],"mapped",[57,28857]],[[13154,13154],"mapped",[49,48,28857]],[[13155,13155],"mapped",[49,49,28857]],[[13156,13156],"mapped",[49,50,28857]],[[13157,13157],"mapped",[49,51,28857]],[[13158,13158],"mapped",[49,52,28857]],[[13159,13159],"mapped",[49,53,28857]],[[13160,13160],"mapped",[49,54,28857]],[[13161,13161],"mapped",[49,55,28857]],[[13162,13162],"mapped",[49,56,28857]],[[13163,13163],"mapped",[49,57,28857]],[[13164,13164],"mapped",[50,48,28857]],[[13165,13165],"mapped",[50,49,28857]],[[13166,13166],"mapped",[50,50,28857]],[[13167,13167],"mapped",[50,51,28857]],[[13168,13168],"mapped",[50,52,28857]],[[13169,13169],"mapped",[104,112,97]],[[13170,13170],"mapped",[100,97]],[[13171,13171],"mapped",[97,117]],[[13172,13172],"mapped",[98,97,114]],[[13173,13173],"mapped",[111,118]],[[13174,13174],"mapped",[112,99]],[[13175,13175],"mapped",[100,109]],[[13176,13176],"mapped",[100,109,50]],[[13177,13177],"mapped",[100,109,51]],[[13178,13178],"mapped",[105,117]],[[13179,13179],"mapped",[24179,25104]],[[13180,13180],"mapped",[26157,21644]],[[13181,13181],"mapped",[22823,27491]],[[13182,13182],"mapped",[26126,27835]],[[13183,13183],"mapped",[26666,24335,20250,31038]],[[13184,13184],"mapped",[112,97]],[[13185,13185],"mapped",[110,97]],[[13186,13186],"mapped",[956,97]],[[13187,13187],"mapped",[109,97]],[[13188,13188],"mapped",[107,97]],[[13189,13189],"mapped",[107,98]],[[13190,13190],"mapped",[109,98]],[[13191,13191],"mapped",[103,98]],[[13192,13192],"mapped",[99,97,108]],[[13193,13193],"mapped",[107,99,97,108]],[[13194,13194],"mapped",[112,102]],[[13195,13195],"mapped",[110,102]],[[13196,13196],"mapped",[956,102]],[[13197,13197],"mapped",[956,103]],[[13198,13198],"mapped",[109,103]],[[13199,13199],"mapped",[107,103]],[[13200,13200],"mapped",[104,122]],[[13201,13201],"mapped",[107,104,122]],[[13202,13202],"mapped",[109,104,122]],[[13203,13203],"mapped",[103,104,122]],[[13204,13204],"mapped",[116,104,122]],[[13205,13205],"mapped",[956,108]],[[13206,13206],"mapped",[109,108]],[[13207,13207],"mapped",[100,108]],[[13208,13208],"mapped",[107,108]],[[13209,13209],"mapped",[102,109]],[[13210,13210],"mapped",[110,109]],[[13211,13211],"mapped",[956,109]],[[13212,13212],"mapped",[109,109]],[[13213,13213],"mapped",[99,109]],[[13214,13214],"mapped",[107,109]],[[13215,13215],"mapped",[109,109,50]],[[13216,13216],"mapped",[99,109,50]],[[13217,13217],"mapped",[109,50]],[[13218,13218],"mapped",[107,109,50]],[[13219,13219],"mapped",[109,109,51]],[[13220,13220],"mapped",[99,109,51]],[[13221,13221],"mapped",[109,51]],[[13222,13222],"mapped",[107,109,51]],[[13223,13223],"mapped",[109,8725,115]],[[13224,13224],"mapped",[109,8725,115,50]],[[13225,13225],"mapped",[112,97]],[[13226,13226],"mapped",[107,112,97]],[[13227,13227],"mapped",[109,112,97]],[[13228,13228],"mapped",[103,112,97]],[[13229,13229],"mapped",[114,97,100]],[[13230,13230],"mapped",[114,97,100,8725,115]],[[13231,13231],"mapped",[114,97,100,8725,115,50]],[[13232,13232],"mapped",[112,115]],[[13233,13233],"mapped",[110,115]],[[13234,13234],"mapped",[956,115]],[[13235,13235],"mapped",[109,115]],[[13236,13236],"mapped",[112,118]],[[13237,13237],"mapped",[110,118]],[[13238,13238],"mapped",[956,118]],[[13239,13239],"mapped",[109,118]],[[13240,13240],"mapped",[107,118]],[[13241,13241],"mapped",[109,118]],[[13242,13242],"mapped",[112,119]],[[13243,13243],"mapped",[110,119]],[[13244,13244],"mapped",[956,119]],[[13245,13245],"mapped",[109,119]],[[13246,13246],"mapped",[107,119]],[[13247,13247],"mapped",[109,119]],[[13248,13248],"mapped",[107,969]],[[13249,13249],"mapped",[109,969]],[[13250,13250],"disallowed"],[[13251,13251],"mapped",[98,113]],[[13252,13252],"mapped",[99,99]],[[13253,13253],"mapped",[99,100]],[[13254,13254],"mapped",[99,8725,107,103]],[[13255,13255],"disallowed"],[[13256,13256],"mapped",[100,98]],[[13257,13257],"mapped",[103,121]],[[13258,13258],"mapped",[104,97]],[[13259,13259],"mapped",[104,112]],[[13260,13260],"mapped",[105,110]],[[13261,13261],"mapped",[107,107]],[[13262,13262],"mapped",[107,109]],[[13263,13263],"mapped",[107,116]],[[13264,13264],"mapped",[108,109]],[[13265,13265],"mapped",[108,110]],[[13266,13266],"mapped",[108,111,103]],[[13267,13267],"mapped",[108,120]],[[13268,13268],"mapped",[109,98]],[[13269,13269],"mapped",[109,105,108]],[[13270,13270],"mapped",[109,111,108]],[[13271,13271],"mapped",[112,104]],[[13272,13272],"disallowed"],[[13273,13273],"mapped",[112,112,109]],[[13274,13274],"mapped",[112,114]],[[13275,13275],"mapped",[115,114]],[[13276,13276],"mapped",[115,118]],[[13277,13277],"mapped",[119,98]],[[13278,13278],"mapped",[118,8725,109]],[[13279,13279],"mapped",[97,8725,109]],[[13280,13280],"mapped",[49,26085]],[[13281,13281],"mapped",[50,26085]],[[13282,13282],"mapped",[51,26085]],[[13283,13283],"mapped",[52,26085]],[[13284,13284],"mapped",[53,26085]],[[13285,13285],"mapped",[54,26085]],[[13286,13286],"mapped",[55,26085]],[[13287,13287],"mapped",[56,26085]],[[13288,13288],"mapped",[57,26085]],[[13289,13289],"mapped",[49,48,26085]],[[13290,13290],"mapped",[49,49,26085]],[[13291,13291],"mapped",[49,50,26085]],[[13292,13292],"mapped",[49,51,26085]],[[13293,13293],"mapped",[49,52,26085]],[[13294,13294],"mapped",[49,53,26085]],[[13295,13295],"mapped",[49,54,26085]],[[13296,13296],"mapped",[49,55,26085]],[[13297,13297],"mapped",[49,56,26085]],[[13298,13298],"mapped",[49,57,26085]],[[13299,13299],"mapped",[50,48,26085]],[[13300,13300],"mapped",[50,49,26085]],[[13301,13301],"mapped",[50,50,26085]],[[13302,13302],"mapped",[50,51,26085]],[[13303,13303],"mapped",[50,52,26085]],[[13304,13304],"mapped",[50,53,26085]],[[13305,13305],"mapped",[50,54,26085]],[[13306,13306],"mapped",[50,55,26085]],[[13307,13307],"mapped",[50,56,26085]],[[13308,13308],"mapped",[50,57,26085]],[[13309,13309],"mapped",[51,48,26085]],[[13310,13310],"mapped",[51,49,26085]],[[13311,13311],"mapped",[103,97,108]],[[13312,19893],"valid"],[[19894,19903],"disallowed"],[[19904,19967],"valid",[],"NV8"],[[19968,40869],"valid"],[[40870,40891],"valid"],[[40892,40899],"valid"],[[40900,40907],"valid"],[[40908,40908],"valid"],[[40909,40917],"valid"],[[40918,40959],"disallowed"],[[40960,42124],"valid"],[[42125,42127],"disallowed"],[[42128,42145],"valid",[],"NV8"],[[42146,42147],"valid",[],"NV8"],[[42148,42163],"valid",[],"NV8"],[[42164,42164],"valid",[],"NV8"],[[42165,42176],"valid",[],"NV8"],[[42177,42177],"valid",[],"NV8"],[[42178,42180],"valid",[],"NV8"],[[42181,42181],"valid",[],"NV8"],[[42182,42182],"valid",[],"NV8"],[[42183,42191],"disallowed"],[[42192,42237],"valid"],[[42238,42239],"valid",[],"NV8"],[[42240,42508],"valid"],[[42509,42511],"valid",[],"NV8"],[[42512,42539],"valid"],[[42540,42559],"disallowed"],[[42560,42560],"mapped",[42561]],[[42561,42561],"valid"],[[42562,42562],"mapped",[42563]],[[42563,42563],"valid"],[[42564,42564],"mapped",[42565]],[[42565,42565],"valid"],[[42566,42566],"mapped",[42567]],[[42567,42567],"valid"],[[42568,42568],"mapped",[42569]],[[42569,42569],"valid"],[[42570,42570],"mapped",[42571]],[[42571,42571],"valid"],[[42572,42572],"mapped",[42573]],[[42573,42573],"valid"],[[42574,42574],"mapped",[42575]],[[42575,42575],"valid"],[[42576,42576],"mapped",[42577]],[[42577,42577],"valid"],[[42578,42578],"mapped",[42579]],[[42579,42579],"valid"],[[42580,42580],"mapped",[42581]],[[42581,42581],"valid"],[[42582,42582],"mapped",[42583]],[[42583,42583],"valid"],[[42584,42584],"mapped",[42585]],[[42585,42585],"valid"],[[42586,42586],"mapped",[42587]],[[42587,42587],"valid"],[[42588,42588],"mapped",[42589]],[[42589,42589],"valid"],[[42590,42590],"mapped",[42591]],[[42591,42591],"valid"],[[42592,42592],"mapped",[42593]],[[42593,42593],"valid"],[[42594,42594],"mapped",[42595]],[[42595,42595],"valid"],[[42596,42596],"mapped",[42597]],[[42597,42597],"valid"],[[42598,42598],"mapped",[42599]],[[42599,42599],"valid"],[[42600,42600],"mapped",[42601]],[[42601,42601],"valid"],[[42602,42602],"mapped",[42603]],[[42603,42603],"valid"],[[42604,42604],"mapped",[42605]],[[42605,42607],"valid"],[[42608,42611],"valid",[],"NV8"],[[42612,42619],"valid"],[[42620,42621],"valid"],[[42622,42622],"valid",[],"NV8"],[[42623,42623],"valid"],[[42624,42624],"mapped",[42625]],[[42625,42625],"valid"],[[42626,42626],"mapped",[42627]],[[42627,42627],"valid"],[[42628,42628],"mapped",[42629]],[[42629,42629],"valid"],[[42630,42630],"mapped",[42631]],[[42631,42631],"valid"],[[42632,42632],"mapped",[42633]],[[42633,42633],"valid"],[[42634,42634],"mapped",[42635]],[[42635,42635],"valid"],[[42636,42636],"mapped",[42637]],[[42637,42637],"valid"],[[42638,42638],"mapped",[42639]],[[42639,42639],"valid"],[[42640,42640],"mapped",[42641]],[[42641,42641],"valid"],[[42642,42642],"mapped",[42643]],[[42643,42643],"valid"],[[42644,42644],"mapped",[42645]],[[42645,42645],"valid"],[[42646,42646],"mapped",[42647]],[[42647,42647],"valid"],[[42648,42648],"mapped",[42649]],[[42649,42649],"valid"],[[42650,42650],"mapped",[42651]],[[42651,42651],"valid"],[[42652,42652],"mapped",[1098]],[[42653,42653],"mapped",[1100]],[[42654,42654],"valid"],[[42655,42655],"valid"],[[42656,42725],"valid"],[[42726,42735],"valid",[],"NV8"],[[42736,42737],"valid"],[[42738,42743],"valid",[],"NV8"],[[42744,42751],"disallowed"],[[42752,42774],"valid",[],"NV8"],[[42775,42778],"valid"],[[42779,42783],"valid"],[[42784,42785],"valid",[],"NV8"],[[42786,42786],"mapped",[42787]],[[42787,42787],"valid"],[[42788,42788],"mapped",[42789]],[[42789,42789],"valid"],[[42790,42790],"mapped",[42791]],[[42791,42791],"valid"],[[42792,42792],"mapped",[42793]],[[42793,42793],"valid"],[[42794,42794],"mapped",[42795]],[[42795,42795],"valid"],[[42796,42796],"mapped",[42797]],[[42797,42797],"valid"],[[42798,42798],"mapped",[42799]],[[42799,42801],"valid"],[[42802,42802],"mapped",[42803]],[[42803,42803],"valid"],[[42804,42804],"mapped",[42805]],[[42805,42805],"valid"],[[42806,42806],"mapped",[42807]],[[42807,42807],"valid"],[[42808,42808],"mapped",[42809]],[[42809,42809],"valid"],[[42810,42810],"mapped",[42811]],[[42811,42811],"valid"],[[42812,42812],"mapped",[42813]],[[42813,42813],"valid"],[[42814,42814],"mapped",[42815]],[[42815,42815],"valid"],[[42816,42816],"mapped",[42817]],[[42817,42817],"valid"],[[42818,42818],"mapped",[42819]],[[42819,42819],"valid"],[[42820,42820],"mapped",[42821]],[[42821,42821],"valid"],[[42822,42822],"mapped",[42823]],[[42823,42823],"valid"],[[42824,42824],"mapped",[42825]],[[42825,42825],"valid"],[[42826,42826],"mapped",[42827]],[[42827,42827],"valid"],[[42828,42828],"mapped",[42829]],[[42829,42829],"valid"],[[42830,42830],"mapped",[42831]],[[42831,42831],"valid"],[[42832,42832],"mapped",[42833]],[[42833,42833],"valid"],[[42834,42834],"mapped",[42835]],[[42835,42835],"valid"],[[42836,42836],"mapped",[42837]],[[42837,42837],"valid"],[[42838,42838],"mapped",[42839]],[[42839,42839],"valid"],[[42840,42840],"mapped",[42841]],[[42841,42841],"valid"],[[42842,42842],"mapped",[42843]],[[42843,42843],"valid"],[[42844,42844],"mapped",[42845]],[[42845,42845],"valid"],[[42846,42846],"mapped",[42847]],[[42847,42847],"valid"],[[42848,42848],"mapped",[42849]],[[42849,42849],"valid"],[[42850,42850],"mapped",[42851]],[[42851,42851],"valid"],[[42852,42852],"mapped",[42853]],[[42853,42853],"valid"],[[42854,42854],"mapped",[42855]],[[42855,42855],"valid"],[[42856,42856],"mapped",[42857]],[[42857,42857],"valid"],[[42858,42858],"mapped",[42859]],[[42859,42859],"valid"],[[42860,42860],"mapped",[42861]],[[42861,42861],"valid"],[[42862,42862],"mapped",[42863]],[[42863,42863],"valid"],[[42864,42864],"mapped",[42863]],[[42865,42872],"valid"],[[42873,42873],"mapped",[42874]],[[42874,42874],"valid"],[[42875,42875],"mapped",[42876]],[[42876,42876],"valid"],[[42877,42877],"mapped",[7545]],[[42878,42878],"mapped",[42879]],[[42879,42879],"valid"],[[42880,42880],"mapped",[42881]],[[42881,42881],"valid"],[[42882,42882],"mapped",[42883]],[[42883,42883],"valid"],[[42884,42884],"mapped",[42885]],[[42885,42885],"valid"],[[42886,42886],"mapped",[42887]],[[42887,42888],"valid"],[[42889,42890],"valid",[],"NV8"],[[42891,42891],"mapped",[42892]],[[42892,42892],"valid"],[[42893,42893],"mapped",[613]],[[42894,42894],"valid"],[[42895,42895],"valid"],[[42896,42896],"mapped",[42897]],[[42897,42897],"valid"],[[42898,42898],"mapped",[42899]],[[42899,42899],"valid"],[[42900,42901],"valid"],[[42902,42902],"mapped",[42903]],[[42903,42903],"valid"],[[42904,42904],"mapped",[42905]],[[42905,42905],"valid"],[[42906,42906],"mapped",[42907]],[[42907,42907],"valid"],[[42908,42908],"mapped",[42909]],[[42909,42909],"valid"],[[42910,42910],"mapped",[42911]],[[42911,42911],"valid"],[[42912,42912],"mapped",[42913]],[[42913,42913],"valid"],[[42914,42914],"mapped",[42915]],[[42915,42915],"valid"],[[42916,42916],"mapped",[42917]],[[42917,42917],"valid"],[[42918,42918],"mapped",[42919]],[[42919,42919],"valid"],[[42920,42920],"mapped",[42921]],[[42921,42921],"valid"],[[42922,42922],"mapped",[614]],[[42923,42923],"mapped",[604]],[[42924,42924],"mapped",[609]],[[42925,42925],"mapped",[620]],[[42926,42927],"disallowed"],[[42928,42928],"mapped",[670]],[[42929,42929],"mapped",[647]],[[42930,42930],"mapped",[669]],[[42931,42931],"mapped",[43859]],[[42932,42932],"mapped",[42933]],[[42933,42933],"valid"],[[42934,42934],"mapped",[42935]],[[42935,42935],"valid"],[[42936,42998],"disallowed"],[[42999,42999],"valid"],[[43000,43000],"mapped",[295]],[[43001,43001],"mapped",[339]],[[43002,43002],"valid"],[[43003,43007],"valid"],[[43008,43047],"valid"],[[43048,43051],"valid",[],"NV8"],[[43052,43055],"disallowed"],[[43056,43065],"valid",[],"NV8"],[[43066,43071],"disallowed"],[[43072,43123],"valid"],[[43124,43127],"valid",[],"NV8"],[[43128,43135],"disallowed"],[[43136,43204],"valid"],[[43205,43213],"disallowed"],[[43214,43215],"valid",[],"NV8"],[[43216,43225],"valid"],[[43226,43231],"disallowed"],[[43232,43255],"valid"],[[43256,43258],"valid",[],"NV8"],[[43259,43259],"valid"],[[43260,43260],"valid",[],"NV8"],[[43261,43261],"valid"],[[43262,43263],"disallowed"],[[43264,43309],"valid"],[[43310,43311],"valid",[],"NV8"],[[43312,43347],"valid"],[[43348,43358],"disallowed"],[[43359,43359],"valid",[],"NV8"],[[43360,43388],"valid",[],"NV8"],[[43389,43391],"disallowed"],[[43392,43456],"valid"],[[43457,43469],"valid",[],"NV8"],[[43470,43470],"disallowed"],[[43471,43481],"valid"],[[43482,43485],"disallowed"],[[43486,43487],"valid",[],"NV8"],[[43488,43518],"valid"],[[43519,43519],"disallowed"],[[43520,43574],"valid"],[[43575,43583],"disallowed"],[[43584,43597],"valid"],[[43598,43599],"disallowed"],[[43600,43609],"valid"],[[43610,43611],"disallowed"],[[43612,43615],"valid",[],"NV8"],[[43616,43638],"valid"],[[43639,43641],"valid",[],"NV8"],[[43642,43643],"valid"],[[43644,43647],"valid"],[[43648,43714],"valid"],[[43715,43738],"disallowed"],[[43739,43741],"valid"],[[43742,43743],"valid",[],"NV8"],[[43744,43759],"valid"],[[43760,43761],"valid",[],"NV8"],[[43762,43766],"valid"],[[43767,43776],"disallowed"],[[43777,43782],"valid"],[[43783,43784],"disallowed"],[[43785,43790],"valid"],[[43791,43792],"disallowed"],[[43793,43798],"valid"],[[43799,43807],"disallowed"],[[43808,43814],"valid"],[[43815,43815],"disallowed"],[[43816,43822],"valid"],[[43823,43823],"disallowed"],[[43824,43866],"valid"],[[43867,43867],"valid",[],"NV8"],[[43868,43868],"mapped",[42791]],[[43869,43869],"mapped",[43831]],[[43870,43870],"mapped",[619]],[[43871,43871],"mapped",[43858]],[[43872,43875],"valid"],[[43876,43877],"valid"],[[43878,43887],"disallowed"],[[43888,43888],"mapped",[5024]],[[43889,43889],"mapped",[5025]],[[43890,43890],"mapped",[5026]],[[43891,43891],"mapped",[5027]],[[43892,43892],"mapped",[5028]],[[43893,43893],"mapped",[5029]],[[43894,43894],"mapped",[5030]],[[43895,43895],"mapped",[5031]],[[43896,43896],"mapped",[5032]],[[43897,43897],"mapped",[5033]],[[43898,43898],"mapped",[5034]],[[43899,43899],"mapped",[5035]],[[43900,43900],"mapped",[5036]],[[43901,43901],"mapped",[5037]],[[43902,43902],"mapped",[5038]],[[43903,43903],"mapped",[5039]],[[43904,43904],"mapped",[5040]],[[43905,43905],"mapped",[5041]],[[43906,43906],"mapped",[5042]],[[43907,43907],"mapped",[5043]],[[43908,43908],"mapped",[5044]],[[43909,43909],"mapped",[5045]],[[43910,43910],"mapped",[5046]],[[43911,43911],"mapped",[5047]],[[43912,43912],"mapped",[5048]],[[43913,43913],"mapped",[5049]],[[43914,43914],"mapped",[5050]],[[43915,43915],"mapped",[5051]],[[43916,43916],"mapped",[5052]],[[43917,43917],"mapped",[5053]],[[43918,43918],"mapped",[5054]],[[43919,43919],"mapped",[5055]],[[43920,43920],"mapped",[5056]],[[43921,43921],"mapped",[5057]],[[43922,43922],"mapped",[5058]],[[43923,43923],"mapped",[5059]],[[43924,43924],"mapped",[5060]],[[43925,43925],"mapped",[5061]],[[43926,43926],"mapped",[5062]],[[43927,43927],"mapped",[5063]],[[43928,43928],"mapped",[5064]],[[43929,43929],"mapped",[5065]],[[43930,43930],"mapped",[5066]],[[43931,43931],"mapped",[5067]],[[43932,43932],"mapped",[5068]],[[43933,43933],"mapped",[5069]],[[43934,43934],"mapped",[5070]],[[43935,43935],"mapped",[5071]],[[43936,43936],"mapped",[5072]],[[43937,43937],"mapped",[5073]],[[43938,43938],"mapped",[5074]],[[43939,43939],"mapped",[5075]],[[43940,43940],"mapped",[5076]],[[43941,43941],"mapped",[5077]],[[43942,43942],"mapped",[5078]],[[43943,43943],"mapped",[5079]],[[43944,43944],"mapped",[5080]],[[43945,43945],"mapped",[5081]],[[43946,43946],"mapped",[5082]],[[43947,43947],"mapped",[5083]],[[43948,43948],"mapped",[5084]],[[43949,43949],"mapped",[5085]],[[43950,43950],"mapped",[5086]],[[43951,43951],"mapped",[5087]],[[43952,43952],"mapped",[5088]],[[43953,43953],"mapped",[5089]],[[43954,43954],"mapped",[5090]],[[43955,43955],"mapped",[5091]],[[43956,43956],"mapped",[5092]],[[43957,43957],"mapped",[5093]],[[43958,43958],"mapped",[5094]],[[43959,43959],"mapped",[5095]],[[43960,43960],"mapped",[5096]],[[43961,43961],"mapped",[5097]],[[43962,43962],"mapped",[5098]],[[43963,43963],"mapped",[5099]],[[43964,43964],"mapped",[5100]],[[43965,43965],"mapped",[5101]],[[43966,43966],"mapped",[5102]],[[43967,43967],"mapped",[5103]],[[43968,44010],"valid"],[[44011,44011],"valid",[],"NV8"],[[44012,44013],"valid"],[[44014,44015],"disallowed"],[[44016,44025],"valid"],[[44026,44031],"disallowed"],[[44032,55203],"valid"],[[55204,55215],"disallowed"],[[55216,55238],"valid",[],"NV8"],[[55239,55242],"disallowed"],[[55243,55291],"valid",[],"NV8"],[[55292,55295],"disallowed"],[[55296,57343],"disallowed"],[[57344,63743],"disallowed"],[[63744,63744],"mapped",[35912]],[[63745,63745],"mapped",[26356]],[[63746,63746],"mapped",[36554]],[[63747,63747],"mapped",[36040]],[[63748,63748],"mapped",[28369]],[[63749,63749],"mapped",[20018]],[[63750,63750],"mapped",[21477]],[[63751,63752],"mapped",[40860]],[[63753,63753],"mapped",[22865]],[[63754,63754],"mapped",[37329]],[[63755,63755],"mapped",[21895]],[[63756,63756],"mapped",[22856]],[[63757,63757],"mapped",[25078]],[[63758,63758],"mapped",[30313]],[[63759,63759],"mapped",[32645]],[[63760,63760],"mapped",[34367]],[[63761,63761],"mapped",[34746]],[[63762,63762],"mapped",[35064]],[[63763,63763],"mapped",[37007]],[[63764,63764],"mapped",[27138]],[[63765,63765],"mapped",[27931]],[[63766,63766],"mapped",[28889]],[[63767,63767],"mapped",[29662]],[[63768,63768],"mapped",[33853]],[[63769,63769],"mapped",[37226]],[[63770,63770],"mapped",[39409]],[[63771,63771],"mapped",[20098]],[[63772,63772],"mapped",[21365]],[[63773,63773],"mapped",[27396]],[[63774,63774],"mapped",[29211]],[[63775,63775],"mapped",[34349]],[[63776,63776],"mapped",[40478]],[[63777,63777],"mapped",[23888]],[[63778,63778],"mapped",[28651]],[[63779,63779],"mapped",[34253]],[[63780,63780],"mapped",[35172]],[[63781,63781],"mapped",[25289]],[[63782,63782],"mapped",[33240]],[[63783,63783],"mapped",[34847]],[[63784,63784],"mapped",[24266]],[[63785,63785],"mapped",[26391]],[[63786,63786],"mapped",[28010]],[[63787,63787],"mapped",[29436]],[[63788,63788],"mapped",[37070]],[[63789,63789],"mapped",[20358]],[[63790,63790],"mapped",[20919]],[[63791,63791],"mapped",[21214]],[[63792,63792],"mapped",[25796]],[[63793,63793],"mapped",[27347]],[[63794,63794],"mapped",[29200]],[[63795,63795],"mapped",[30439]],[[63796,63796],"mapped",[32769]],[[63797,63797],"mapped",[34310]],[[63798,63798],"mapped",[34396]],[[63799,63799],"mapped",[36335]],[[63800,63800],"mapped",[38706]],[[63801,63801],"mapped",[39791]],[[63802,63802],"mapped",[40442]],[[63803,63803],"mapped",[30860]],[[63804,63804],"mapped",[31103]],[[63805,63805],"mapped",[32160]],[[63806,63806],"mapped",[33737]],[[63807,63807],"mapped",[37636]],[[63808,63808],"mapped",[40575]],[[63809,63809],"mapped",[35542]],[[63810,63810],"mapped",[22751]],[[63811,63811],"mapped",[24324]],[[63812,63812],"mapped",[31840]],[[63813,63813],"mapped",[32894]],[[63814,63814],"mapped",[29282]],[[63815,63815],"mapped",[30922]],[[63816,63816],"mapped",[36034]],[[63817,63817],"mapped",[38647]],[[63818,63818],"mapped",[22744]],[[63819,63819],"mapped",[23650]],[[63820,63820],"mapped",[27155]],[[63821,63821],"mapped",[28122]],[[63822,63822],"mapped",[28431]],[[63823,63823],"mapped",[32047]],[[63824,63824],"mapped",[32311]],[[63825,63825],"mapped",[38475]],[[63826,63826],"mapped",[21202]],[[63827,63827],"mapped",[32907]],[[63828,63828],"mapped",[20956]],[[63829,63829],"mapped",[20940]],[[63830,63830],"mapped",[31260]],[[63831,63831],"mapped",[32190]],[[63832,63832],"mapped",[33777]],[[63833,63833],"mapped",[38517]],[[63834,63834],"mapped",[35712]],[[63835,63835],"mapped",[25295]],[[63836,63836],"mapped",[27138]],[[63837,63837],"mapped",[35582]],[[63838,63838],"mapped",[20025]],[[63839,63839],"mapped",[23527]],[[63840,63840],"mapped",[24594]],[[63841,63841],"mapped",[29575]],[[63842,63842],"mapped",[30064]],[[63843,63843],"mapped",[21271]],[[63844,63844],"mapped",[30971]],[[63845,63845],"mapped",[20415]],[[63846,63846],"mapped",[24489]],[[63847,63847],"mapped",[19981]],[[63848,63848],"mapped",[27852]],[[63849,63849],"mapped",[25976]],[[63850,63850],"mapped",[32034]],[[63851,63851],"mapped",[21443]],[[63852,63852],"mapped",[22622]],[[63853,63853],"mapped",[30465]],[[63854,63854],"mapped",[33865]],[[63855,63855],"mapped",[35498]],[[63856,63856],"mapped",[27578]],[[63857,63857],"mapped",[36784]],[[63858,63858],"mapped",[27784]],[[63859,63859],"mapped",[25342]],[[63860,63860],"mapped",[33509]],[[63861,63861],"mapped",[25504]],[[63862,63862],"mapped",[30053]],[[63863,63863],"mapped",[20142]],[[63864,63864],"mapped",[20841]],[[63865,63865],"mapped",[20937]],[[63866,63866],"mapped",[26753]],[[63867,63867],"mapped",[31975]],[[63868,63868],"mapped",[33391]],[[63869,63869],"mapped",[35538]],[[63870,63870],"mapped",[37327]],[[63871,63871],"mapped",[21237]],[[63872,63872],"mapped",[21570]],[[63873,63873],"mapped",[22899]],[[63874,63874],"mapped",[24300]],[[63875,63875],"mapped",[26053]],[[63876,63876],"mapped",[28670]],[[63877,63877],"mapped",[31018]],[[63878,63878],"mapped",[38317]],[[63879,63879],"mapped",[39530]],[[63880,63880],"mapped",[40599]],[[63881,63881],"mapped",[40654]],[[63882,63882],"mapped",[21147]],[[63883,63883],"mapped",[26310]],[[63884,63884],"mapped",[27511]],[[63885,63885],"mapped",[36706]],[[63886,63886],"mapped",[24180]],[[63887,63887],"mapped",[24976]],[[63888,63888],"mapped",[25088]],[[63889,63889],"mapped",[25754]],[[63890,63890],"mapped",[28451]],[[63891,63891],"mapped",[29001]],[[63892,63892],"mapped",[29833]],[[63893,63893],"mapped",[31178]],[[63894,63894],"mapped",[32244]],[[63895,63895],"mapped",[32879]],[[63896,63896],"mapped",[36646]],[[63897,63897],"mapped",[34030]],[[63898,63898],"mapped",[36899]],[[63899,63899],"mapped",[37706]],[[63900,63900],"mapped",[21015]],[[63901,63901],"mapped",[21155]],[[63902,63902],"mapped",[21693]],[[63903,63903],"mapped",[28872]],[[63904,63904],"mapped",[35010]],[[63905,63905],"mapped",[35498]],[[63906,63906],"mapped",[24265]],[[63907,63907],"mapped",[24565]],[[63908,63908],"mapped",[25467]],[[63909,63909],"mapped",[27566]],[[63910,63910],"mapped",[31806]],[[63911,63911],"mapped",[29557]],[[63912,63912],"mapped",[20196]],[[63913,63913],"mapped",[22265]],[[63914,63914],"mapped",[23527]],[[63915,63915],"mapped",[23994]],[[63916,63916],"mapped",[24604]],[[63917,63917],"mapped",[29618]],[[63918,63918],"mapped",[29801]],[[63919,63919],"mapped",[32666]],[[63920,63920],"mapped",[32838]],[[63921,63921],"mapped",[37428]],[[63922,63922],"mapped",[38646]],[[63923,63923],"mapped",[38728]],[[63924,63924],"mapped",[38936]],[[63925,63925],"mapped",[20363]],[[63926,63926],"mapped",[31150]],[[63927,63927],"mapped",[37300]],[[63928,63928],"mapped",[38584]],[[63929,63929],"mapped",[24801]],[[63930,63930],"mapped",[20102]],[[63931,63931],"mapped",[20698]],[[63932,63932],"mapped",[23534]],[[63933,63933],"mapped",[23615]],[[63934,63934],"mapped",[26009]],[[63935,63935],"mapped",[27138]],[[63936,63936],"mapped",[29134]],[[63937,63937],"mapped",[30274]],[[63938,63938],"mapped",[34044]],[[63939,63939],"mapped",[36988]],[[63940,63940],"mapped",[40845]],[[63941,63941],"mapped",[26248]],[[63942,63942],"mapped",[38446]],[[63943,63943],"mapped",[21129]],[[63944,63944],"mapped",[26491]],[[63945,63945],"mapped",[26611]],[[63946,63946],"mapped",[27969]],[[63947,63947],"mapped",[28316]],[[63948,63948],"mapped",[29705]],[[63949,63949],"mapped",[30041]],[[63950,63950],"mapped",[30827]],[[63951,63951],"mapped",[32016]],[[63952,63952],"mapped",[39006]],[[63953,63953],"mapped",[20845]],[[63954,63954],"mapped",[25134]],[[63955,63955],"mapped",[38520]],[[63956,63956],"mapped",[20523]],[[63957,63957],"mapped",[23833]],[[63958,63958],"mapped",[28138]],[[63959,63959],"mapped",[36650]],[[63960,63960],"mapped",[24459]],[[63961,63961],"mapped",[24900]],[[63962,63962],"mapped",[26647]],[[63963,63963],"mapped",[29575]],[[63964,63964],"mapped",[38534]],[[63965,63965],"mapped",[21033]],[[63966,63966],"mapped",[21519]],[[63967,63967],"mapped",[23653]],[[63968,63968],"mapped",[26131]],[[63969,63969],"mapped",[26446]],[[63970,63970],"mapped",[26792]],[[63971,63971],"mapped",[27877]],[[63972,63972],"mapped",[29702]],[[63973,63973],"mapped",[30178]],[[63974,63974],"mapped",[32633]],[[63975,63975],"mapped",[35023]],[[63976,63976],"mapped",[35041]],[[63977,63977],"mapped",[37324]],[[63978,63978],"mapped",[38626]],[[63979,63979],"mapped",[21311]],[[63980,63980],"mapped",[28346]],[[63981,63981],"mapped",[21533]],[[63982,63982],"mapped",[29136]],[[63983,63983],"mapped",[29848]],[[63984,63984],"mapped",[34298]],[[63985,63985],"mapped",[38563]],[[63986,63986],"mapped",[40023]],[[63987,63987],"mapped",[40607]],[[63988,63988],"mapped",[26519]],[[63989,63989],"mapped",[28107]],[[63990,63990],"mapped",[33256]],[[63991,63991],"mapped",[31435]],[[63992,63992],"mapped",[31520]],[[63993,63993],"mapped",[31890]],[[63994,63994],"mapped",[29376]],[[63995,63995],"mapped",[28825]],[[63996,63996],"mapped",[35672]],[[63997,63997],"mapped",[20160]],[[63998,63998],"mapped",[33590]],[[63999,63999],"mapped",[21050]],[[64000,64000],"mapped",[20999]],[[64001,64001],"mapped",[24230]],[[64002,64002],"mapped",[25299]],[[64003,64003],"mapped",[31958]],[[64004,64004],"mapped",[23429]],[[64005,64005],"mapped",[27934]],[[64006,64006],"mapped",[26292]],[[64007,64007],"mapped",[36667]],[[64008,64008],"mapped",[34892]],[[64009,64009],"mapped",[38477]],[[64010,64010],"mapped",[35211]],[[64011,64011],"mapped",[24275]],[[64012,64012],"mapped",[20800]],[[64013,64013],"mapped",[21952]],[[64014,64015],"valid"],[[64016,64016],"mapped",[22618]],[[64017,64017],"valid"],[[64018,64018],"mapped",[26228]],[[64019,64020],"valid"],[[64021,64021],"mapped",[20958]],[[64022,64022],"mapped",[29482]],[[64023,64023],"mapped",[30410]],[[64024,64024],"mapped",[31036]],[[64025,64025],"mapped",[31070]],[[64026,64026],"mapped",[31077]],[[64027,64027],"mapped",[31119]],[[64028,64028],"mapped",[38742]],[[64029,64029],"mapped",[31934]],[[64030,64030],"mapped",[32701]],[[64031,64031],"valid"],[[64032,64032],"mapped",[34322]],[[64033,64033],"valid"],[[64034,64034],"mapped",[35576]],[[64035,64036],"valid"],[[64037,64037],"mapped",[36920]],[[64038,64038],"mapped",[37117]],[[64039,64041],"valid"],[[64042,64042],"mapped",[39151]],[[64043,64043],"mapped",[39164]],[[64044,64044],"mapped",[39208]],[[64045,64045],"mapped",[40372]],[[64046,64046],"mapped",[37086]],[[64047,64047],"mapped",[38583]],[[64048,64048],"mapped",[20398]],[[64049,64049],"mapped",[20711]],[[64050,64050],"mapped",[20813]],[[64051,64051],"mapped",[21193]],[[64052,64052],"mapped",[21220]],[[64053,64053],"mapped",[21329]],[[64054,64054],"mapped",[21917]],[[64055,64055],"mapped",[22022]],[[64056,64056],"mapped",[22120]],[[64057,64057],"mapped",[22592]],[[64058,64058],"mapped",[22696]],[[64059,64059],"mapped",[23652]],[[64060,64060],"mapped",[23662]],[[64061,64061],"mapped",[24724]],[[64062,64062],"mapped",[24936]],[[64063,64063],"mapped",[24974]],[[64064,64064],"mapped",[25074]],[[64065,64065],"mapped",[25935]],[[64066,64066],"mapped",[26082]],[[64067,64067],"mapped",[26257]],[[64068,64068],"mapped",[26757]],[[64069,64069],"mapped",[28023]],[[64070,64070],"mapped",[28186]],[[64071,64071],"mapped",[28450]],[[64072,64072],"mapped",[29038]],[[64073,64073],"mapped",[29227]],[[64074,64074],"mapped",[29730]],[[64075,64075],"mapped",[30865]],[[64076,64076],"mapped",[31038]],[[64077,64077],"mapped",[31049]],[[64078,64078],"mapped",[31048]],[[64079,64079],"mapped",[31056]],[[64080,64080],"mapped",[31062]],[[64081,64081],"mapped",[31069]],[[64082,64082],"mapped",[31117]],[[64083,64083],"mapped",[31118]],[[64084,64084],"mapped",[31296]],[[64085,64085],"mapped",[31361]],[[64086,64086],"mapped",[31680]],[[64087,64087],"mapped",[32244]],[[64088,64088],"mapped",[32265]],[[64089,64089],"mapped",[32321]],[[64090,64090],"mapped",[32626]],[[64091,64091],"mapped",[32773]],[[64092,64092],"mapped",[33261]],[[64093,64094],"mapped",[33401]],[[64095,64095],"mapped",[33879]],[[64096,64096],"mapped",[35088]],[[64097,64097],"mapped",[35222]],[[64098,64098],"mapped",[35585]],[[64099,64099],"mapped",[35641]],[[64100,64100],"mapped",[36051]],[[64101,64101],"mapped",[36104]],[[64102,64102],"mapped",[36790]],[[64103,64103],"mapped",[36920]],[[64104,64104],"mapped",[38627]],[[64105,64105],"mapped",[38911]],[[64106,64106],"mapped",[38971]],[[64107,64107],"mapped",[24693]],[[64108,64108],"mapped",[148206]],[[64109,64109],"mapped",[33304]],[[64110,64111],"disallowed"],[[64112,64112],"mapped",[20006]],[[64113,64113],"mapped",[20917]],[[64114,64114],"mapped",[20840]],[[64115,64115],"mapped",[20352]],[[64116,64116],"mapped",[20805]],[[64117,64117],"mapped",[20864]],[[64118,64118],"mapped",[21191]],[[64119,64119],"mapped",[21242]],[[64120,64120],"mapped",[21917]],[[64121,64121],"mapped",[21845]],[[64122,64122],"mapped",[21913]],[[64123,64123],"mapped",[21986]],[[64124,64124],"mapped",[22618]],[[64125,64125],"mapped",[22707]],[[64126,64126],"mapped",[22852]],[[64127,64127],"mapped",[22868]],[[64128,64128],"mapped",[23138]],[[64129,64129],"mapped",[23336]],[[64130,64130],"mapped",[24274]],[[64131,64131],"mapped",[24281]],[[64132,64132],"mapped",[24425]],[[64133,64133],"mapped",[24493]],[[64134,64134],"mapped",[24792]],[[64135,64135],"mapped",[24910]],[[64136,64136],"mapped",[24840]],[[64137,64137],"mapped",[24974]],[[64138,64138],"mapped",[24928]],[[64139,64139],"mapped",[25074]],[[64140,64140],"mapped",[25140]],[[64141,64141],"mapped",[25540]],[[64142,64142],"mapped",[25628]],[[64143,64143],"mapped",[25682]],[[64144,64144],"mapped",[25942]],[[64145,64145],"mapped",[26228]],[[64146,64146],"mapped",[26391]],[[64147,64147],"mapped",[26395]],[[64148,64148],"mapped",[26454]],[[64149,64149],"mapped",[27513]],[[64150,64150],"mapped",[27578]],[[64151,64151],"mapped",[27969]],[[64152,64152],"mapped",[28379]],[[64153,64153],"mapped",[28363]],[[64154,64154],"mapped",[28450]],[[64155,64155],"mapped",[28702]],[[64156,64156],"mapped",[29038]],[[64157,64157],"mapped",[30631]],[[64158,64158],"mapped",[29237]],[[64159,64159],"mapped",[29359]],[[64160,64160],"mapped",[29482]],[[64161,64161],"mapped",[29809]],[[64162,64162],"mapped",[29958]],[[64163,64163],"mapped",[30011]],[[64164,64164],"mapped",[30237]],[[64165,64165],"mapped",[30239]],[[64166,64166],"mapped",[30410]],[[64167,64167],"mapped",[30427]],[[64168,64168],"mapped",[30452]],[[64169,64169],"mapped",[30538]],[[64170,64170],"mapped",[30528]],[[64171,64171],"mapped",[30924]],[[64172,64172],"mapped",[31409]],[[64173,64173],"mapped",[31680]],[[64174,64174],"mapped",[31867]],[[64175,64175],"mapped",[32091]],[[64176,64176],"mapped",[32244]],[[64177,64177],"mapped",[32574]],[[64178,64178],"mapped",[32773]],[[64179,64179],"mapped",[33618]],[[64180,64180],"mapped",[33775]],[[64181,64181],"mapped",[34681]],[[64182,64182],"mapped",[35137]],[[64183,64183],"mapped",[35206]],[[64184,64184],"mapped",[35222]],[[64185,64185],"mapped",[35519]],[[64186,64186],"mapped",[35576]],[[64187,64187],"mapped",[35531]],[[64188,64188],"mapped",[35585]],[[64189,64189],"mapped",[35582]],[[64190,64190],"mapped",[35565]],[[64191,64191],"mapped",[35641]],[[64192,64192],"mapped",[35722]],[[64193,64193],"mapped",[36104]],[[64194,64194],"mapped",[36664]],[[64195,64195],"mapped",[36978]],[[64196,64196],"mapped",[37273]],[[64197,64197],"mapped",[37494]],[[64198,64198],"mapped",[38524]],[[64199,64199],"mapped",[38627]],[[64200,64200],"mapped",[38742]],[[64201,64201],"mapped",[38875]],[[64202,64202],"mapped",[38911]],[[64203,64203],"mapped",[38923]],[[64204,64204],"mapped",[38971]],[[64205,64205],"mapped",[39698]],[[64206,64206],"mapped",[40860]],[[64207,64207],"mapped",[141386]],[[64208,64208],"mapped",[141380]],[[64209,64209],"mapped",[144341]],[[64210,64210],"mapped",[15261]],[[64211,64211],"mapped",[16408]],[[64212,64212],"mapped",[16441]],[[64213,64213],"mapped",[152137]],[[64214,64214],"mapped",[154832]],[[64215,64215],"mapped",[163539]],[[64216,64216],"mapped",[40771]],[[64217,64217],"mapped",[40846]],[[64218,64255],"disallowed"],[[64256,64256],"mapped",[102,102]],[[64257,64257],"mapped",[102,105]],[[64258,64258],"mapped",[102,108]],[[64259,64259],"mapped",[102,102,105]],[[64260,64260],"mapped",[102,102,108]],[[64261,64262],"mapped",[115,116]],[[64263,64274],"disallowed"],[[64275,64275],"mapped",[1396,1398]],[[64276,64276],"mapped",[1396,1381]],[[64277,64277],"mapped",[1396,1387]],[[64278,64278],"mapped",[1406,1398]],[[64279,64279],"mapped",[1396,1389]],[[64280,64284],"disallowed"],[[64285,64285],"mapped",[1497,1460]],[[64286,64286],"valid"],[[64287,64287],"mapped",[1522,1463]],[[64288,64288],"mapped",[1506]],[[64289,64289],"mapped",[1488]],[[64290,64290],"mapped",[1491]],[[64291,64291],"mapped",[1492]],[[64292,64292],"mapped",[1499]],[[64293,64293],"mapped",[1500]],[[64294,64294],"mapped",[1501]],[[64295,64295],"mapped",[1512]],[[64296,64296],"mapped",[1514]],[[64297,64297],"disallowed_STD3_mapped",[43]],[[64298,64298],"mapped",[1513,1473]],[[64299,64299],"mapped",[1513,1474]],[[64300,64300],"mapped",[1513,1468,1473]],[[64301,64301],"mapped",[1513,1468,1474]],[[64302,64302],"mapped",[1488,1463]],[[64303,64303],"mapped",[1488,1464]],[[64304,64304],"mapped",[1488,1468]],[[64305,64305],"mapped",[1489,1468]],[[64306,64306],"mapped",[1490,1468]],[[64307,64307],"mapped",[1491,1468]],[[64308,64308],"mapped",[1492,1468]],[[64309,64309],"mapped",[1493,1468]],[[64310,64310],"mapped",[1494,1468]],[[64311,64311],"disallowed"],[[64312,64312],"mapped",[1496,1468]],[[64313,64313],"mapped",[1497,1468]],[[64314,64314],"mapped",[1498,1468]],[[64315,64315],"mapped",[1499,1468]],[[64316,64316],"mapped",[1500,1468]],[[64317,64317],"disallowed"],[[64318,64318],"mapped",[1502,1468]],[[64319,64319],"disallowed"],[[64320,64320],"mapped",[1504,1468]],[[64321,64321],"mapped",[1505,1468]],[[64322,64322],"disallowed"],[[64323,64323],"mapped",[1507,1468]],[[64324,64324],"mapped",[1508,1468]],[[64325,64325],"disallowed"],[[64326,64326],"mapped",[1510,1468]],[[64327,64327],"mapped",[1511,1468]],[[64328,64328],"mapped",[1512,1468]],[[64329,64329],"mapped",[1513,1468]],[[64330,64330],"mapped",[1514,1468]],[[64331,64331],"mapped",[1493,1465]],[[64332,64332],"mapped",[1489,1471]],[[64333,64333],"mapped",[1499,1471]],[[64334,64334],"mapped",[1508,1471]],[[64335,64335],"mapped",[1488,1500]],[[64336,64337],"mapped",[1649]],[[64338,64341],"mapped",[1659]],[[64342,64345],"mapped",[1662]],[[64346,64349],"mapped",[1664]],[[64350,64353],"mapped",[1658]],[[64354,64357],"mapped",[1663]],[[64358,64361],"mapped",[1657]],[[64362,64365],"mapped",[1700]],[[64366,64369],"mapped",[1702]],[[64370,64373],"mapped",[1668]],[[64374,64377],"mapped",[1667]],[[64378,64381],"mapped",[1670]],[[64382,64385],"mapped",[1671]],[[64386,64387],"mapped",[1677]],[[64388,64389],"mapped",[1676]],[[64390,64391],"mapped",[1678]],[[64392,64393],"mapped",[1672]],[[64394,64395],"mapped",[1688]],[[64396,64397],"mapped",[1681]],[[64398,64401],"mapped",[1705]],[[64402,64405],"mapped",[1711]],[[64406,64409],"mapped",[1715]],[[64410,64413],"mapped",[1713]],[[64414,64415],"mapped",[1722]],[[64416,64419],"mapped",[1723]],[[64420,64421],"mapped",[1728]],[[64422,64425],"mapped",[1729]],[[64426,64429],"mapped",[1726]],[[64430,64431],"mapped",[1746]],[[64432,64433],"mapped",[1747]],[[64434,64449],"valid",[],"NV8"],[[64450,64466],"disallowed"],[[64467,64470],"mapped",[1709]],[[64471,64472],"mapped",[1735]],[[64473,64474],"mapped",[1734]],[[64475,64476],"mapped",[1736]],[[64477,64477],"mapped",[1735,1652]],[[64478,64479],"mapped",[1739]],[[64480,64481],"mapped",[1733]],[[64482,64483],"mapped",[1737]],[[64484,64487],"mapped",[1744]],[[64488,64489],"mapped",[1609]],[[64490,64491],"mapped",[1574,1575]],[[64492,64493],"mapped",[1574,1749]],[[64494,64495],"mapped",[1574,1608]],[[64496,64497],"mapped",[1574,1735]],[[64498,64499],"mapped",[1574,1734]],[[64500,64501],"mapped",[1574,1736]],[[64502,64504],"mapped",[1574,1744]],[[64505,64507],"mapped",[1574,1609]],[[64508,64511],"mapped",[1740]],[[64512,64512],"mapped",[1574,1580]],[[64513,64513],"mapped",[1574,1581]],[[64514,64514],"mapped",[1574,1605]],[[64515,64515],"mapped",[1574,1609]],[[64516,64516],"mapped",[1574,1610]],[[64517,64517],"mapped",[1576,1580]],[[64518,64518],"mapped",[1576,1581]],[[64519,64519],"mapped",[1576,1582]],[[64520,64520],"mapped",[1576,1605]],[[64521,64521],"mapped",[1576,1609]],[[64522,64522],"mapped",[1576,1610]],[[64523,64523],"mapped",[1578,1580]],[[64524,64524],"mapped",[1578,1581]],[[64525,64525],"mapped",[1578,1582]],[[64526,64526],"mapped",[1578,1605]],[[64527,64527],"mapped",[1578,1609]],[[64528,64528],"mapped",[1578,1610]],[[64529,64529],"mapped",[1579,1580]],[[64530,64530],"mapped",[1579,1605]],[[64531,64531],"mapped",[1579,1609]],[[64532,64532],"mapped",[1579,1610]],[[64533,64533],"mapped",[1580,1581]],[[64534,64534],"mapped",[1580,1605]],[[64535,64535],"mapped",[1581,1580]],[[64536,64536],"mapped",[1581,1605]],[[64537,64537],"mapped",[1582,1580]],[[64538,64538],"mapped",[1582,1581]],[[64539,64539],"mapped",[1582,1605]],[[64540,64540],"mapped",[1587,1580]],[[64541,64541],"mapped",[1587,1581]],[[64542,64542],"mapped",[1587,1582]],[[64543,64543],"mapped",[1587,1605]],[[64544,64544],"mapped",[1589,1581]],[[64545,64545],"mapped",[1589,1605]],[[64546,64546],"mapped",[1590,1580]],[[64547,64547],"mapped",[1590,1581]],[[64548,64548],"mapped",[1590,1582]],[[64549,64549],"mapped",[1590,1605]],[[64550,64550],"mapped",[1591,1581]],[[64551,64551],"mapped",[1591,1605]],[[64552,64552],"mapped",[1592,1605]],[[64553,64553],"mapped",[1593,1580]],[[64554,64554],"mapped",[1593,1605]],[[64555,64555],"mapped",[1594,1580]],[[64556,64556],"mapped",[1594,1605]],[[64557,64557],"mapped",[1601,1580]],[[64558,64558],"mapped",[1601,1581]],[[64559,64559],"mapped",[1601,1582]],[[64560,64560],"mapped",[1601,1605]],[[64561,64561],"mapped",[1601,1609]],[[64562,64562],"mapped",[1601,1610]],[[64563,64563],"mapped",[1602,1581]],[[64564,64564],"mapped",[1602,1605]],[[64565,64565],"mapped",[1602,1609]],[[64566,64566],"mapped",[1602,1610]],[[64567,64567],"mapped",[1603,1575]],[[64568,64568],"mapped",[1603,1580]],[[64569,64569],"mapped",[1603,1581]],[[64570,64570],"mapped",[1603,1582]],[[64571,64571],"mapped",[1603,1604]],[[64572,64572],"mapped",[1603,1605]],[[64573,64573],"mapped",[1603,1609]],[[64574,64574],"mapped",[1603,1610]],[[64575,64575],"mapped",[1604,1580]],[[64576,64576],"mapped",[1604,1581]],[[64577,64577],"mapped",[1604,1582]],[[64578,64578],"mapped",[1604,1605]],[[64579,64579],"mapped",[1604,1609]],[[64580,64580],"mapped",[1604,1610]],[[64581,64581],"mapped",[1605,1580]],[[64582,64582],"mapped",[1605,1581]],[[64583,64583],"mapped",[1605,1582]],[[64584,64584],"mapped",[1605,1605]],[[64585,64585],"mapped",[1605,1609]],[[64586,64586],"mapped",[1605,1610]],[[64587,64587],"mapped",[1606,1580]],[[64588,64588],"mapped",[1606,1581]],[[64589,64589],"mapped",[1606,1582]],[[64590,64590],"mapped",[1606,1605]],[[64591,64591],"mapped",[1606,1609]],[[64592,64592],"mapped",[1606,1610]],[[64593,64593],"mapped",[1607,1580]],[[64594,64594],"mapped",[1607,1605]],[[64595,64595],"mapped",[1607,1609]],[[64596,64596],"mapped",[1607,1610]],[[64597,64597],"mapped",[1610,1580]],[[64598,64598],"mapped",[1610,1581]],[[64599,64599],"mapped",[1610,1582]],[[64600,64600],"mapped",[1610,1605]],[[64601,64601],"mapped",[1610,1609]],[[64602,64602],"mapped",[1610,1610]],[[64603,64603],"mapped",[1584,1648]],[[64604,64604],"mapped",[1585,1648]],[[64605,64605],"mapped",[1609,1648]],[[64606,64606],"disallowed_STD3_mapped",[32,1612,1617]],[[64607,64607],"disallowed_STD3_mapped",[32,1613,1617]],[[64608,64608],"disallowed_STD3_mapped",[32,1614,1617]],[[64609,64609],"disallowed_STD3_mapped",[32,1615,1617]],[[64610,64610],"disallowed_STD3_mapped",[32,1616,1617]],[[64611,64611],"disallowed_STD3_mapped",[32,1617,1648]],[[64612,64612],"mapped",[1574,1585]],[[64613,64613],"mapped",[1574,1586]],[[64614,64614],"mapped",[1574,1605]],[[64615,64615],"mapped",[1574,1606]],[[64616,64616],"mapped",[1574,1609]],[[64617,64617],"mapped",[1574,1610]],[[64618,64618],"mapped",[1576,1585]],[[64619,64619],"mapped",[1576,1586]],[[64620,64620],"mapped",[1576,1605]],[[64621,64621],"mapped",[1576,1606]],[[64622,64622],"mapped",[1576,1609]],[[64623,64623],"mapped",[1576,1610]],[[64624,64624],"mapped",[1578,1585]],[[64625,64625],"mapped",[1578,1586]],[[64626,64626],"mapped",[1578,1605]],[[64627,64627],"mapped",[1578,1606]],[[64628,64628],"mapped",[1578,1609]],[[64629,64629],"mapped",[1578,1610]],[[64630,64630],"mapped",[1579,1585]],[[64631,64631],"mapped",[1579,1586]],[[64632,64632],"mapped",[1579,1605]],[[64633,64633],"mapped",[1579,1606]],[[64634,64634],"mapped",[1579,1609]],[[64635,64635],"mapped",[1579,1610]],[[64636,64636],"mapped",[1601,1609]],[[64637,64637],"mapped",[1601,1610]],[[64638,64638],"mapped",[1602,1609]],[[64639,64639],"mapped",[1602,1610]],[[64640,64640],"mapped",[1603,1575]],[[64641,64641],"mapped",[1603,1604]],[[64642,64642],"mapped",[1603,1605]],[[64643,64643],"mapped",[1603,1609]],[[64644,64644],"mapped",[1603,1610]],[[64645,64645],"mapped",[1604,1605]],[[64646,64646],"mapped",[1604,1609]],[[64647,64647],"mapped",[1604,1610]],[[64648,64648],"mapped",[1605,1575]],[[64649,64649],"mapped",[1605,1605]],[[64650,64650],"mapped",[1606,1585]],[[64651,64651],"mapped",[1606,1586]],[[64652,64652],"mapped",[1606,1605]],[[64653,64653],"mapped",[1606,1606]],[[64654,64654],"mapped",[1606,1609]],[[64655,64655],"mapped",[1606,1610]],[[64656,64656],"mapped",[1609,1648]],[[64657,64657],"mapped",[1610,1585]],[[64658,64658],"mapped",[1610,1586]],[[64659,64659],"mapped",[1610,1605]],[[64660,64660],"mapped",[1610,1606]],[[64661,64661],"mapped",[1610,1609]],[[64662,64662],"mapped",[1610,1610]],[[64663,64663],"mapped",[1574,1580]],[[64664,64664],"mapped",[1574,1581]],[[64665,64665],"mapped",[1574,1582]],[[64666,64666],"mapped",[1574,1605]],[[64667,64667],"mapped",[1574,1607]],[[64668,64668],"mapped",[1576,1580]],[[64669,64669],"mapped",[1576,1581]],[[64670,64670],"mapped",[1576,1582]],[[64671,64671],"mapped",[1576,1605]],[[64672,64672],"mapped",[1576,1607]],[[64673,64673],"mapped",[1578,1580]],[[64674,64674],"mapped",[1578,1581]],[[64675,64675],"mapped",[1578,1582]],[[64676,64676],"mapped",[1578,1605]],[[64677,64677],"mapped",[1578,1607]],[[64678,64678],"mapped",[1579,1605]],[[64679,64679],"mapped",[1580,1581]],[[64680,64680],"mapped",[1580,1605]],[[64681,64681],"mapped",[1581,1580]],[[64682,64682],"mapped",[1581,1605]],[[64683,64683],"mapped",[1582,1580]],[[64684,64684],"mapped",[1582,1605]],[[64685,64685],"mapped",[1587,1580]],[[64686,64686],"mapped",[1587,1581]],[[64687,64687],"mapped",[1587,1582]],[[64688,64688],"mapped",[1587,1605]],[[64689,64689],"mapped",[1589,1581]],[[64690,64690],"mapped",[1589,1582]],[[64691,64691],"mapped",[1589,1605]],[[64692,64692],"mapped",[1590,1580]],[[64693,64693],"mapped",[1590,1581]],[[64694,64694],"mapped",[1590,1582]],[[64695,64695],"mapped",[1590,1605]],[[64696,64696],"mapped",[1591,1581]],[[64697,64697],"mapped",[1592,1605]],[[64698,64698],"mapped",[1593,1580]],[[64699,64699],"mapped",[1593,1605]],[[64700,64700],"mapped",[1594,1580]],[[64701,64701],"mapped",[1594,1605]],[[64702,64702],"mapped",[1601,1580]],[[64703,64703],"mapped",[1601,1581]],[[64704,64704],"mapped",[1601,1582]],[[64705,64705],"mapped",[1601,1605]],[[64706,64706],"mapped",[1602,1581]],[[64707,64707],"mapped",[1602,1605]],[[64708,64708],"mapped",[1603,1580]],[[64709,64709],"mapped",[1603,1581]],[[64710,64710],"mapped",[1603,1582]],[[64711,64711],"mapped",[1603,1604]],[[64712,64712],"mapped",[1603,1605]],[[64713,64713],"mapped",[1604,1580]],[[64714,64714],"mapped",[1604,1581]],[[64715,64715],"mapped",[1604,1582]],[[64716,64716],"mapped",[1604,1605]],[[64717,64717],"mapped",[1604,1607]],[[64718,64718],"mapped",[1605,1580]],[[64719,64719],"mapped",[1605,1581]],[[64720,64720],"mapped",[1605,1582]],[[64721,64721],"mapped",[1605,1605]],[[64722,64722],"mapped",[1606,1580]],[[64723,64723],"mapped",[1606,1581]],[[64724,64724],"mapped",[1606,1582]],[[64725,64725],"mapped",[1606,1605]],[[64726,64726],"mapped",[1606,1607]],[[64727,64727],"mapped",[1607,1580]],[[64728,64728],"mapped",[1607,1605]],[[64729,64729],"mapped",[1607,1648]],[[64730,64730],"mapped",[1610,1580]],[[64731,64731],"mapped",[1610,1581]],[[64732,64732],"mapped",[1610,1582]],[[64733,64733],"mapped",[1610,1605]],[[64734,64734],"mapped",[1610,1607]],[[64735,64735],"mapped",[1574,1605]],[[64736,64736],"mapped",[1574,1607]],[[64737,64737],"mapped",[1576,1605]],[[64738,64738],"mapped",[1576,1607]],[[64739,64739],"mapped",[1578,1605]],[[64740,64740],"mapped",[1578,1607]],[[64741,64741],"mapped",[1579,1605]],[[64742,64742],"mapped",[1579,1607]],[[64743,64743],"mapped",[1587,1605]],[[64744,64744],"mapped",[1587,1607]],[[64745,64745],"mapped",[1588,1605]],[[64746,64746],"mapped",[1588,1607]],[[64747,64747],"mapped",[1603,1604]],[[64748,64748],"mapped",[1603,1605]],[[64749,64749],"mapped",[1604,1605]],[[64750,64750],"mapped",[1606,1605]],[[64751,64751],"mapped",[1606,1607]],[[64752,64752],"mapped",[1610,1605]],[[64753,64753],"mapped",[1610,1607]],[[64754,64754],"mapped",[1600,1614,1617]],[[64755,64755],"mapped",[1600,1615,1617]],[[64756,64756],"mapped",[1600,1616,1617]],[[64757,64757],"mapped",[1591,1609]],[[64758,64758],"mapped",[1591,1610]],[[64759,64759],"mapped",[1593,1609]],[[64760,64760],"mapped",[1593,1610]],[[64761,64761],"mapped",[1594,1609]],[[64762,64762],"mapped",[1594,1610]],[[64763,64763],"mapped",[1587,1609]],[[64764,64764],"mapped",[1587,1610]],[[64765,64765],"mapped",[1588,1609]],[[64766,64766],"mapped",[1588,1610]],[[64767,64767],"mapped",[1581,1609]],[[64768,64768],"mapped",[1581,1610]],[[64769,64769],"mapped",[1580,1609]],[[64770,64770],"mapped",[1580,1610]],[[64771,64771],"mapped",[1582,1609]],[[64772,64772],"mapped",[1582,1610]],[[64773,64773],"mapped",[1589,1609]],[[64774,64774],"mapped",[1589,1610]],[[64775,64775],"mapped",[1590,1609]],[[64776,64776],"mapped",[1590,1610]],[[64777,64777],"mapped",[1588,1580]],[[64778,64778],"mapped",[1588,1581]],[[64779,64779],"mapped",[1588,1582]],[[64780,64780],"mapped",[1588,1605]],[[64781,64781],"mapped",[1588,1585]],[[64782,64782],"mapped",[1587,1585]],[[64783,64783],"mapped",[1589,1585]],[[64784,64784],"mapped",[1590,1585]],[[64785,64785],"mapped",[1591,1609]],[[64786,64786],"mapped",[1591,1610]],[[64787,64787],"mapped",[1593,1609]],[[64788,64788],"mapped",[1593,1610]],[[64789,64789],"mapped",[1594,1609]],[[64790,64790],"mapped",[1594,1610]],[[64791,64791],"mapped",[1587,1609]],[[64792,64792],"mapped",[1587,1610]],[[64793,64793],"mapped",[1588,1609]],[[64794,64794],"mapped",[1588,1610]],[[64795,64795],"mapped",[1581,1609]],[[64796,64796],"mapped",[1581,1610]],[[64797,64797],"mapped",[1580,1609]],[[64798,64798],"mapped",[1580,1610]],[[64799,64799],"mapped",[1582,1609]],[[64800,64800],"mapped",[1582,1610]],[[64801,64801],"mapped",[1589,1609]],[[64802,64802],"mapped",[1589,1610]],[[64803,64803],"mapped",[1590,1609]],[[64804,64804],"mapped",[1590,1610]],[[64805,64805],"mapped",[1588,1580]],[[64806,64806],"mapped",[1588,1581]],[[64807,64807],"mapped",[1588,1582]],[[64808,64808],"mapped",[1588,1605]],[[64809,64809],"mapped",[1588,1585]],[[64810,64810],"mapped",[1587,1585]],[[64811,64811],"mapped",[1589,1585]],[[64812,64812],"mapped",[1590,1585]],[[64813,64813],"mapped",[1588,1580]],[[64814,64814],"mapped",[1588,1581]],[[64815,64815],"mapped",[1588,1582]],[[64816,64816],"mapped",[1588,1605]],[[64817,64817],"mapped",[1587,1607]],[[64818,64818],"mapped",[1588,1607]],[[64819,64819],"mapped",[1591,1605]],[[64820,64820],"mapped",[1587,1580]],[[64821,64821],"mapped",[1587,1581]],[[64822,64822],"mapped",[1587,1582]],[[64823,64823],"mapped",[1588,1580]],[[64824,64824],"mapped",[1588,1581]],[[64825,64825],"mapped",[1588,1582]],[[64826,64826],"mapped",[1591,1605]],[[64827,64827],"mapped",[1592,1605]],[[64828,64829],"mapped",[1575,1611]],[[64830,64831],"valid",[],"NV8"],[[64832,64847],"disallowed"],[[64848,64848],"mapped",[1578,1580,1605]],[[64849,64850],"mapped",[1578,1581,1580]],[[64851,64851],"mapped",[1578,1581,1605]],[[64852,64852],"mapped",[1578,1582,1605]],[[64853,64853],"mapped",[1578,1605,1580]],[[64854,64854],"mapped",[1578,1605,1581]],[[64855,64855],"mapped",[1578,1605,1582]],[[64856,64857],"mapped",[1580,1605,1581]],[[64858,64858],"mapped",[1581,1605,1610]],[[64859,64859],"mapped",[1581,1605,1609]],[[64860,64860],"mapped",[1587,1581,1580]],[[64861,64861],"mapped",[1587,1580,1581]],[[64862,64862],"mapped",[1587,1580,1609]],[[64863,64864],"mapped",[1587,1605,1581]],[[64865,64865],"mapped",[1587,1605,1580]],[[64866,64867],"mapped",[1587,1605,1605]],[[64868,64869],"mapped",[1589,1581,1581]],[[64870,64870],"mapped",[1589,1605,1605]],[[64871,64872],"mapped",[1588,1581,1605]],[[64873,64873],"mapped",[1588,1580,1610]],[[64874,64875],"mapped",[1588,1605,1582]],[[64876,64877],"mapped",[1588,1605,1605]],[[64878,64878],"mapped",[1590,1581,1609]],[[64879,64880],"mapped",[1590,1582,1605]],[[64881,64882],"mapped",[1591,1605,1581]],[[64883,64883],"mapped",[1591,1605,1605]],[[64884,64884],"mapped",[1591,1605,1610]],[[64885,64885],"mapped",[1593,1580,1605]],[[64886,64887],"mapped",[1593,1605,1605]],[[64888,64888],"mapped",[1593,1605,1609]],[[64889,64889],"mapped",[1594,1605,1605]],[[64890,64890],"mapped",[1594,1605,1610]],[[64891,64891],"mapped",[1594,1605,1609]],[[64892,64893],"mapped",[1601,1582,1605]],[[64894,64894],"mapped",[1602,1605,1581]],[[64895,64895],"mapped",[1602,1605,1605]],[[64896,64896],"mapped",[1604,1581,1605]],[[64897,64897],"mapped",[1604,1581,1610]],[[64898,64898],"mapped",[1604,1581,1609]],[[64899,64900],"mapped",[1604,1580,1580]],[[64901,64902],"mapped",[1604,1582,1605]],[[64903,64904],"mapped",[1604,1605,1581]],[[64905,64905],"mapped",[1605,1581,1580]],[[64906,64906],"mapped",[1605,1581,1605]],[[64907,64907],"mapped",[1605,1581,1610]],[[64908,64908],"mapped",[1605,1580,1581]],[[64909,64909],"mapped",[1605,1580,1605]],[[64910,64910],"mapped",[1605,1582,1580]],[[64911,64911],"mapped",[1605,1582,1605]],[[64912,64913],"disallowed"],[[64914,64914],"mapped",[1605,1580,1582]],[[64915,64915],"mapped",[1607,1605,1580]],[[64916,64916],"mapped",[1607,1605,1605]],[[64917,64917],"mapped",[1606,1581,1605]],[[64918,64918],"mapped",[1606,1581,1609]],[[64919,64920],"mapped",[1606,1580,1605]],[[64921,64921],"mapped",[1606,1580,1609]],[[64922,64922],"mapped",[1606,1605,1610]],[[64923,64923],"mapped",[1606,1605,1609]],[[64924,64925],"mapped",[1610,1605,1605]],[[64926,64926],"mapped",[1576,1582,1610]],[[64927,64927],"mapped",[1578,1580,1610]],[[64928,64928],"mapped",[1578,1580,1609]],[[64929,64929],"mapped",[1578,1582,1610]],[[64930,64930],"mapped",[1578,1582,1609]],[[64931,64931],"mapped",[1578,1605,1610]],[[64932,64932],"mapped",[1578,1605,1609]],[[64933,64933],"mapped",[1580,1605,1610]],[[64934,64934],"mapped",[1580,1581,1609]],[[64935,64935],"mapped",[1580,1605,1609]],[[64936,64936],"mapped",[1587,1582,1609]],[[64937,64937],"mapped",[1589,1581,1610]],[[64938,64938],"mapped",[1588,1581,1610]],[[64939,64939],"mapped",[1590,1581,1610]],[[64940,64940],"mapped",[1604,1580,1610]],[[64941,64941],"mapped",[1604,1605,1610]],[[64942,64942],"mapped",[1610,1581,1610]],[[64943,64943],"mapped",[1610,1580,1610]],[[64944,64944],"mapped",[1610,1605,1610]],[[64945,64945],"mapped",[1605,1605,1610]],[[64946,64946],"mapped",[1602,1605,1610]],[[64947,64947],"mapped",[1606,1581,1610]],[[64948,64948],"mapped",[1602,1605,1581]],[[64949,64949],"mapped",[1604,1581,1605]],[[64950,64950],"mapped",[1593,1605,1610]],[[64951,64951],"mapped",[1603,1605,1610]],[[64952,64952],"mapped",[1606,1580,1581]],[[64953,64953],"mapped",[1605,1582,1610]],[[64954,64954],"mapped",[1604,1580,1605]],[[64955,64955],"mapped",[1603,1605,1605]],[[64956,64956],"mapped",[1604,1580,1605]],[[64957,64957],"mapped",[1606,1580,1581]],[[64958,64958],"mapped",[1580,1581,1610]],[[64959,64959],"mapped",[1581,1580,1610]],[[64960,64960],"mapped",[1605,1580,1610]],[[64961,64961],"mapped",[1601,1605,1610]],[[64962,64962],"mapped",[1576,1581,1610]],[[64963,64963],"mapped",[1603,1605,1605]],[[64964,64964],"mapped",[1593,1580,1605]],[[64965,64965],"mapped",[1589,1605,1605]],[[64966,64966],"mapped",[1587,1582,1610]],[[64967,64967],"mapped",[1606,1580,1610]],[[64968,64975],"disallowed"],[[64976,65007],"disallowed"],[[65008,65008],"mapped",[1589,1604,1746]],[[65009,65009],"mapped",[1602,1604,1746]],[[65010,65010],"mapped",[1575,1604,1604,1607]],[[65011,65011],"mapped",[1575,1603,1576,1585]],[[65012,65012],"mapped",[1605,1581,1605,1583]],[[65013,65013],"mapped",[1589,1604,1593,1605]],[[65014,65014],"mapped",[1585,1587,1608,1604]],[[65015,65015],"mapped",[1593,1604,1610,1607]],[[65016,65016],"mapped",[1608,1587,1604,1605]],[[65017,65017],"mapped",[1589,1604,1609]],[[65018,65018],"disallowed_STD3_mapped",[1589,1604,1609,32,1575,1604,1604,1607,32,1593,1604,1610,1607,32,1608,1587,1604,1605]],[[65019,65019],"disallowed_STD3_mapped",[1580,1604,32,1580,1604,1575,1604,1607]],[[65020,65020],"mapped",[1585,1740,1575,1604]],[[65021,65021],"valid",[],"NV8"],[[65022,65023],"disallowed"],[[65024,65039],"ignored"],[[65040,65040],"disallowed_STD3_mapped",[44]],[[65041,65041],"mapped",[12289]],[[65042,65042],"disallowed"],[[65043,65043],"disallowed_STD3_mapped",[58]],[[65044,65044],"disallowed_STD3_mapped",[59]],[[65045,65045],"disallowed_STD3_mapped",[33]],[[65046,65046],"disallowed_STD3_mapped",[63]],[[65047,65047],"mapped",[12310]],[[65048,65048],"mapped",[12311]],[[65049,65049],"disallowed"],[[65050,65055],"disallowed"],[[65056,65059],"valid"],[[65060,65062],"valid"],[[65063,65069],"valid"],[[65070,65071],"valid"],[[65072,65072],"disallowed"],[[65073,65073],"mapped",[8212]],[[65074,65074],"mapped",[8211]],[[65075,65076],"disallowed_STD3_mapped",[95]],[[65077,65077],"disallowed_STD3_mapped",[40]],[[65078,65078],"disallowed_STD3_mapped",[41]],[[65079,65079],"disallowed_STD3_mapped",[123]],[[65080,65080],"disallowed_STD3_mapped",[125]],[[65081,65081],"mapped",[12308]],[[65082,65082],"mapped",[12309]],[[65083,65083],"mapped",[12304]],[[65084,65084],"mapped",[12305]],[[65085,65085],"mapped",[12298]],[[65086,65086],"mapped",[12299]],[[65087,65087],"mapped",[12296]],[[65088,65088],"mapped",[12297]],[[65089,65089],"mapped",[12300]],[[65090,65090],"mapped",[12301]],[[65091,65091],"mapped",[12302]],[[65092,65092],"mapped",[12303]],[[65093,65094],"valid",[],"NV8"],[[65095,65095],"disallowed_STD3_mapped",[91]],[[65096,65096],"disallowed_STD3_mapped",[93]],[[65097,65100],"disallowed_STD3_mapped",[32,773]],[[65101,65103],"disallowed_STD3_mapped",[95]],[[65104,65104],"disallowed_STD3_mapped",[44]],[[65105,65105],"mapped",[12289]],[[65106,65106],"disallowed"],[[65107,65107],"disallowed"],[[65108,65108],"disallowed_STD3_mapped",[59]],[[65109,65109],"disallowed_STD3_mapped",[58]],[[65110,65110],"disallowed_STD3_mapped",[63]],[[65111,65111],"disallowed_STD3_mapped",[33]],[[65112,65112],"mapped",[8212]],[[65113,65113],"disallowed_STD3_mapped",[40]],[[65114,65114],"disallowed_STD3_mapped",[41]],[[65115,65115],"disallowed_STD3_mapped",[123]],[[65116,65116],"disallowed_STD3_mapped",[125]],[[65117,65117],"mapped",[12308]],[[65118,65118],"mapped",[12309]],[[65119,65119],"disallowed_STD3_mapped",[35]],[[65120,65120],"disallowed_STD3_mapped",[38]],[[65121,65121],"disallowed_STD3_mapped",[42]],[[65122,65122],"disallowed_STD3_mapped",[43]],[[65123,65123],"mapped",[45]],[[65124,65124],"disallowed_STD3_mapped",[60]],[[65125,65125],"disallowed_STD3_mapped",[62]],[[65126,65126],"disallowed_STD3_mapped",[61]],[[65127,65127],"disallowed"],[[65128,65128],"disallowed_STD3_mapped",[92]],[[65129,65129],"disallowed_STD3_mapped",[36]],[[65130,65130],"disallowed_STD3_mapped",[37]],[[65131,65131],"disallowed_STD3_mapped",[64]],[[65132,65135],"disallowed"],[[65136,65136],"disallowed_STD3_mapped",[32,1611]],[[65137,65137],"mapped",[1600,1611]],[[65138,65138],"disallowed_STD3_mapped",[32,1612]],[[65139,65139],"valid"],[[65140,65140],"disallowed_STD3_mapped",[32,1613]],[[65141,65141],"disallowed"],[[65142,65142],"disallowed_STD3_mapped",[32,1614]],[[65143,65143],"mapped",[1600,1614]],[[65144,65144],"disallowed_STD3_mapped",[32,1615]],[[65145,65145],"mapped",[1600,1615]],[[65146,65146],"disallowed_STD3_mapped",[32,1616]],[[65147,65147],"mapped",[1600,1616]],[[65148,65148],"disallowed_STD3_mapped",[32,1617]],[[65149,65149],"mapped",[1600,1617]],[[65150,65150],"disallowed_STD3_mapped",[32,1618]],[[65151,65151],"mapped",[1600,1618]],[[65152,65152],"mapped",[1569]],[[65153,65154],"mapped",[1570]],[[65155,65156],"mapped",[1571]],[[65157,65158],"mapped",[1572]],[[65159,65160],"mapped",[1573]],[[65161,65164],"mapped",[1574]],[[65165,65166],"mapped",[1575]],[[65167,65170],"mapped",[1576]],[[65171,65172],"mapped",[1577]],[[65173,65176],"mapped",[1578]],[[65177,65180],"mapped",[1579]],[[65181,65184],"mapped",[1580]],[[65185,65188],"mapped",[1581]],[[65189,65192],"mapped",[1582]],[[65193,65194],"mapped",[1583]],[[65195,65196],"mapped",[1584]],[[65197,65198],"mapped",[1585]],[[65199,65200],"mapped",[1586]],[[65201,65204],"mapped",[1587]],[[65205,65208],"mapped",[1588]],[[65209,65212],"mapped",[1589]],[[65213,65216],"mapped",[1590]],[[65217,65220],"mapped",[1591]],[[65221,65224],"mapped",[1592]],[[65225,65228],"mapped",[1593]],[[65229,65232],"mapped",[1594]],[[65233,65236],"mapped",[1601]],[[65237,65240],"mapped",[1602]],[[65241,65244],"mapped",[1603]],[[65245,65248],"mapped",[1604]],[[65249,65252],"mapped",[1605]],[[65253,65256],"mapped",[1606]],[[65257,65260],"mapped",[1607]],[[65261,65262],"mapped",[1608]],[[65263,65264],"mapped",[1609]],[[65265,65268],"mapped",[1610]],[[65269,65270],"mapped",[1604,1570]],[[65271,65272],"mapped",[1604,1571]],[[65273,65274],"mapped",[1604,1573]],[[65275,65276],"mapped",[1604,1575]],[[65277,65278],"disallowed"],[[65279,65279],"ignored"],[[65280,65280],"disallowed"],[[65281,65281],"disallowed_STD3_mapped",[33]],[[65282,65282],"disallowed_STD3_mapped",[34]],[[65283,65283],"disallowed_STD3_mapped",[35]],[[65284,65284],"disallowed_STD3_mapped",[36]],[[65285,65285],"disallowed_STD3_mapped",[37]],[[65286,65286],"disallowed_STD3_mapped",[38]],[[65287,65287],"disallowed_STD3_mapped",[39]],[[65288,65288],"disallowed_STD3_mapped",[40]],[[65289,65289],"disallowed_STD3_mapped",[41]],[[65290,65290],"disallowed_STD3_mapped",[42]],[[65291,65291],"disallowed_STD3_mapped",[43]],[[65292,65292],"disallowed_STD3_mapped",[44]],[[65293,65293],"mapped",[45]],[[65294,65294],"mapped",[46]],[[65295,65295],"disallowed_STD3_mapped",[47]],[[65296,65296],"mapped",[48]],[[65297,65297],"mapped",[49]],[[65298,65298],"mapped",[50]],[[65299,65299],"mapped",[51]],[[65300,65300],"mapped",[52]],[[65301,65301],"mapped",[53]],[[65302,65302],"mapped",[54]],[[65303,65303],"mapped",[55]],[[65304,65304],"mapped",[56]],[[65305,65305],"mapped",[57]],[[65306,65306],"disallowed_STD3_mapped",[58]],[[65307,65307],"disallowed_STD3_mapped",[59]],[[65308,65308],"disallowed_STD3_mapped",[60]],[[65309,65309],"disallowed_STD3_mapped",[61]],[[65310,65310],"disallowed_STD3_mapped",[62]],[[65311,65311],"disallowed_STD3_mapped",[63]],[[65312,65312],"disallowed_STD3_mapped",[64]],[[65313,65313],"mapped",[97]],[[65314,65314],"mapped",[98]],[[65315,65315],"mapped",[99]],[[65316,65316],"mapped",[100]],[[65317,65317],"mapped",[101]],[[65318,65318],"mapped",[102]],[[65319,65319],"mapped",[103]],[[65320,65320],"mapped",[104]],[[65321,65321],"mapped",[105]],[[65322,65322],"mapped",[106]],[[65323,65323],"mapped",[107]],[[65324,65324],"mapped",[108]],[[65325,65325],"mapped",[109]],[[65326,65326],"mapped",[110]],[[65327,65327],"mapped",[111]],[[65328,65328],"mapped",[112]],[[65329,65329],"mapped",[113]],[[65330,65330],"mapped",[114]],[[65331,65331],"mapped",[115]],[[65332,65332],"mapped",[116]],[[65333,65333],"mapped",[117]],[[65334,65334],"mapped",[118]],[[65335,65335],"mapped",[119]],[[65336,65336],"mapped",[120]],[[65337,65337],"mapped",[121]],[[65338,65338],"mapped",[122]],[[65339,65339],"disallowed_STD3_mapped",[91]],[[65340,65340],"disallowed_STD3_mapped",[92]],[[65341,65341],"disallowed_STD3_mapped",[93]],[[65342,65342],"disallowed_STD3_mapped",[94]],[[65343,65343],"disallowed_STD3_mapped",[95]],[[65344,65344],"disallowed_STD3_mapped",[96]],[[65345,65345],"mapped",[97]],[[65346,65346],"mapped",[98]],[[65347,65347],"mapped",[99]],[[65348,65348],"mapped",[100]],[[65349,65349],"mapped",[101]],[[65350,65350],"mapped",[102]],[[65351,65351],"mapped",[103]],[[65352,65352],"mapped",[104]],[[65353,65353],"mapped",[105]],[[65354,65354],"mapped",[106]],[[65355,65355],"mapped",[107]],[[65356,65356],"mapped",[108]],[[65357,65357],"mapped",[109]],[[65358,65358],"mapped",[110]],[[65359,65359],"mapped",[111]],[[65360,65360],"mapped",[112]],[[65361,65361],"mapped",[113]],[[65362,65362],"mapped",[114]],[[65363,65363],"mapped",[115]],[[65364,65364],"mapped",[116]],[[65365,65365],"mapped",[117]],[[65366,65366],"mapped",[118]],[[65367,65367],"mapped",[119]],[[65368,65368],"mapped",[120]],[[65369,65369],"mapped",[121]],[[65370,65370],"mapped",[122]],[[65371,65371],"disallowed_STD3_mapped",[123]],[[65372,65372],"disallowed_STD3_mapped",[124]],[[65373,65373],"disallowed_STD3_mapped",[125]],[[65374,65374],"disallowed_STD3_mapped",[126]],[[65375,65375],"mapped",[10629]],[[65376,65376],"mapped",[10630]],[[65377,65377],"mapped",[46]],[[65378,65378],"mapped",[12300]],[[65379,65379],"mapped",[12301]],[[65380,65380],"mapped",[12289]],[[65381,65381],"mapped",[12539]],[[65382,65382],"mapped",[12530]],[[65383,65383],"mapped",[12449]],[[65384,65384],"mapped",[12451]],[[65385,65385],"mapped",[12453]],[[65386,65386],"mapped",[12455]],[[65387,65387],"mapped",[12457]],[[65388,65388],"mapped",[12515]],[[65389,65389],"mapped",[12517]],[[65390,65390],"mapped",[12519]],[[65391,65391],"mapped",[12483]],[[65392,65392],"mapped",[12540]],[[65393,65393],"mapped",[12450]],[[65394,65394],"mapped",[12452]],[[65395,65395],"mapped",[12454]],[[65396,65396],"mapped",[12456]],[[65397,65397],"mapped",[12458]],[[65398,65398],"mapped",[12459]],[[65399,65399],"mapped",[12461]],[[65400,65400],"mapped",[12463]],[[65401,65401],"mapped",[12465]],[[65402,65402],"mapped",[12467]],[[65403,65403],"mapped",[12469]],[[65404,65404],"mapped",[12471]],[[65405,65405],"mapped",[12473]],[[65406,65406],"mapped",[12475]],[[65407,65407],"mapped",[12477]],[[65408,65408],"mapped",[12479]],[[65409,65409],"mapped",[12481]],[[65410,65410],"mapped",[12484]],[[65411,65411],"mapped",[12486]],[[65412,65412],"mapped",[12488]],[[65413,65413],"mapped",[12490]],[[65414,65414],"mapped",[12491]],[[65415,65415],"mapped",[12492]],[[65416,65416],"mapped",[12493]],[[65417,65417],"mapped",[12494]],[[65418,65418],"mapped",[12495]],[[65419,65419],"mapped",[12498]],[[65420,65420],"mapped",[12501]],[[65421,65421],"mapped",[12504]],[[65422,65422],"mapped",[12507]],[[65423,65423],"mapped",[12510]],[[65424,65424],"mapped",[12511]],[[65425,65425],"mapped",[12512]],[[65426,65426],"mapped",[12513]],[[65427,65427],"mapped",[12514]],[[65428,65428],"mapped",[12516]],[[65429,65429],"mapped",[12518]],[[65430,65430],"mapped",[12520]],[[65431,65431],"mapped",[12521]],[[65432,65432],"mapped",[12522]],[[65433,65433],"mapped",[12523]],[[65434,65434],"mapped",[12524]],[[65435,65435],"mapped",[12525]],[[65436,65436],"mapped",[12527]],[[65437,65437],"mapped",[12531]],[[65438,65438],"mapped",[12441]],[[65439,65439],"mapped",[12442]],[[65440,65440],"disallowed"],[[65441,65441],"mapped",[4352]],[[65442,65442],"mapped",[4353]],[[65443,65443],"mapped",[4522]],[[65444,65444],"mapped",[4354]],[[65445,65445],"mapped",[4524]],[[65446,65446],"mapped",[4525]],[[65447,65447],"mapped",[4355]],[[65448,65448],"mapped",[4356]],[[65449,65449],"mapped",[4357]],[[65450,65450],"mapped",[4528]],[[65451,65451],"mapped",[4529]],[[65452,65452],"mapped",[4530]],[[65453,65453],"mapped",[4531]],[[65454,65454],"mapped",[4532]],[[65455,65455],"mapped",[4533]],[[65456,65456],"mapped",[4378]],[[65457,65457],"mapped",[4358]],[[65458,65458],"mapped",[4359]],[[65459,65459],"mapped",[4360]],[[65460,65460],"mapped",[4385]],[[65461,65461],"mapped",[4361]],[[65462,65462],"mapped",[4362]],[[65463,65463],"mapped",[4363]],[[65464,65464],"mapped",[4364]],[[65465,65465],"mapped",[4365]],[[65466,65466],"mapped",[4366]],[[65467,65467],"mapped",[4367]],[[65468,65468],"mapped",[4368]],[[65469,65469],"mapped",[4369]],[[65470,65470],"mapped",[4370]],[[65471,65473],"disallowed"],[[65474,65474],"mapped",[4449]],[[65475,65475],"mapped",[4450]],[[65476,65476],"mapped",[4451]],[[65477,65477],"mapped",[4452]],[[65478,65478],"mapped",[4453]],[[65479,65479],"mapped",[4454]],[[65480,65481],"disallowed"],[[65482,65482],"mapped",[4455]],[[65483,65483],"mapped",[4456]],[[65484,65484],"mapped",[4457]],[[65485,65485],"mapped",[4458]],[[65486,65486],"mapped",[4459]],[[65487,65487],"mapped",[4460]],[[65488,65489],"disallowed"],[[65490,65490],"mapped",[4461]],[[65491,65491],"mapped",[4462]],[[65492,65492],"mapped",[4463]],[[65493,65493],"mapped",[4464]],[[65494,65494],"mapped",[4465]],[[65495,65495],"mapped",[4466]],[[65496,65497],"disallowed"],[[65498,65498],"mapped",[4467]],[[65499,65499],"mapped",[4468]],[[65500,65500],"mapped",[4469]],[[65501,65503],"disallowed"],[[65504,65504],"mapped",[162]],[[65505,65505],"mapped",[163]],[[65506,65506],"mapped",[172]],[[65507,65507],"disallowed_STD3_mapped",[32,772]],[[65508,65508],"mapped",[166]],[[65509,65509],"mapped",[165]],[[65510,65510],"mapped",[8361]],[[65511,65511],"disallowed"],[[65512,65512],"mapped",[9474]],[[65513,65513],"mapped",[8592]],[[65514,65514],"mapped",[8593]],[[65515,65515],"mapped",[8594]],[[65516,65516],"mapped",[8595]],[[65517,65517],"mapped",[9632]],[[65518,65518],"mapped",[9675]],[[65519,65528],"disallowed"],[[65529,65531],"disallowed"],[[65532,65532],"disallowed"],[[65533,65533],"disallowed"],[[65534,65535],"disallowed"],[[65536,65547],"valid"],[[65548,65548],"disallowed"],[[65549,65574],"valid"],[[65575,65575],"disallowed"],[[65576,65594],"valid"],[[65595,65595],"disallowed"],[[65596,65597],"valid"],[[65598,65598],"disallowed"],[[65599,65613],"valid"],[[65614,65615],"disallowed"],[[65616,65629],"valid"],[[65630,65663],"disallowed"],[[65664,65786],"valid"],[[65787,65791],"disallowed"],[[65792,65794],"valid",[],"NV8"],[[65795,65798],"disallowed"],[[65799,65843],"valid",[],"NV8"],[[65844,65846],"disallowed"],[[65847,65855],"valid",[],"NV8"],[[65856,65930],"valid",[],"NV8"],[[65931,65932],"valid",[],"NV8"],[[65933,65935],"disallowed"],[[65936,65947],"valid",[],"NV8"],[[65948,65951],"disallowed"],[[65952,65952],"valid",[],"NV8"],[[65953,65999],"disallowed"],[[66000,66044],"valid",[],"NV8"],[[66045,66045],"valid"],[[66046,66175],"disallowed"],[[66176,66204],"valid"],[[66205,66207],"disallowed"],[[66208,66256],"valid"],[[66257,66271],"disallowed"],[[66272,66272],"valid"],[[66273,66299],"valid",[],"NV8"],[[66300,66303],"disallowed"],[[66304,66334],"valid"],[[66335,66335],"valid"],[[66336,66339],"valid",[],"NV8"],[[66340,66351],"disallowed"],[[66352,66368],"valid"],[[66369,66369],"valid",[],"NV8"],[[66370,66377],"valid"],[[66378,66378],"valid",[],"NV8"],[[66379,66383],"disallowed"],[[66384,66426],"valid"],[[66427,66431],"disallowed"],[[66432,66461],"valid"],[[66462,66462],"disallowed"],[[66463,66463],"valid",[],"NV8"],[[66464,66499],"valid"],[[66500,66503],"disallowed"],[[66504,66511],"valid"],[[66512,66517],"valid",[],"NV8"],[[66518,66559],"disallowed"],[[66560,66560],"mapped",[66600]],[[66561,66561],"mapped",[66601]],[[66562,66562],"mapped",[66602]],[[66563,66563],"mapped",[66603]],[[66564,66564],"mapped",[66604]],[[66565,66565],"mapped",[66605]],[[66566,66566],"mapped",[66606]],[[66567,66567],"mapped",[66607]],[[66568,66568],"mapped",[66608]],[[66569,66569],"mapped",[66609]],[[66570,66570],"mapped",[66610]],[[66571,66571],"mapped",[66611]],[[66572,66572],"mapped",[66612]],[[66573,66573],"mapped",[66613]],[[66574,66574],"mapped",[66614]],[[66575,66575],"mapped",[66615]],[[66576,66576],"mapped",[66616]],[[66577,66577],"mapped",[66617]],[[66578,66578],"mapped",[66618]],[[66579,66579],"mapped",[66619]],[[66580,66580],"mapped",[66620]],[[66581,66581],"mapped",[66621]],[[66582,66582],"mapped",[66622]],[[66583,66583],"mapped",[66623]],[[66584,66584],"mapped",[66624]],[[66585,66585],"mapped",[66625]],[[66586,66586],"mapped",[66626]],[[66587,66587],"mapped",[66627]],[[66588,66588],"mapped",[66628]],[[66589,66589],"mapped",[66629]],[[66590,66590],"mapped",[66630]],[[66591,66591],"mapped",[66631]],[[66592,66592],"mapped",[66632]],[[66593,66593],"mapped",[66633]],[[66594,66594],"mapped",[66634]],[[66595,66595],"mapped",[66635]],[[66596,66596],"mapped",[66636]],[[66597,66597],"mapped",[66637]],[[66598,66598],"mapped",[66638]],[[66599,66599],"mapped",[66639]],[[66600,66637],"valid"],[[66638,66717],"valid"],[[66718,66719],"disallowed"],[[66720,66729],"valid"],[[66730,66815],"disallowed"],[[66816,66855],"valid"],[[66856,66863],"disallowed"],[[66864,66915],"valid"],[[66916,66926],"disallowed"],[[66927,66927],"valid",[],"NV8"],[[66928,67071],"disallowed"],[[67072,67382],"valid"],[[67383,67391],"disallowed"],[[67392,67413],"valid"],[[67414,67423],"disallowed"],[[67424,67431],"valid"],[[67432,67583],"disallowed"],[[67584,67589],"valid"],[[67590,67591],"disallowed"],[[67592,67592],"valid"],[[67593,67593],"disallowed"],[[67594,67637],"valid"],[[67638,67638],"disallowed"],[[67639,67640],"valid"],[[67641,67643],"disallowed"],[[67644,67644],"valid"],[[67645,67646],"disallowed"],[[67647,67647],"valid"],[[67648,67669],"valid"],[[67670,67670],"disallowed"],[[67671,67679],"valid",[],"NV8"],[[67680,67702],"valid"],[[67703,67711],"valid",[],"NV8"],[[67712,67742],"valid"],[[67743,67750],"disallowed"],[[67751,67759],"valid",[],"NV8"],[[67760,67807],"disallowed"],[[67808,67826],"valid"],[[67827,67827],"disallowed"],[[67828,67829],"valid"],[[67830,67834],"disallowed"],[[67835,67839],"valid",[],"NV8"],[[67840,67861],"valid"],[[67862,67865],"valid",[],"NV8"],[[67866,67867],"valid",[],"NV8"],[[67868,67870],"disallowed"],[[67871,67871],"valid",[],"NV8"],[[67872,67897],"valid"],[[67898,67902],"disallowed"],[[67903,67903],"valid",[],"NV8"],[[67904,67967],"disallowed"],[[67968,68023],"valid"],[[68024,68027],"disallowed"],[[68028,68029],"valid",[],"NV8"],[[68030,68031],"valid"],[[68032,68047],"valid",[],"NV8"],[[68048,68049],"disallowed"],[[68050,68095],"valid",[],"NV8"],[[68096,68099],"valid"],[[68100,68100],"disallowed"],[[68101,68102],"valid"],[[68103,68107],"disallowed"],[[68108,68115],"valid"],[[68116,68116],"disallowed"],[[68117,68119],"valid"],[[68120,68120],"disallowed"],[[68121,68147],"valid"],[[68148,68151],"disallowed"],[[68152,68154],"valid"],[[68155,68158],"disallowed"],[[68159,68159],"valid"],[[68160,68167],"valid",[],"NV8"],[[68168,68175],"disallowed"],[[68176,68184],"valid",[],"NV8"],[[68185,68191],"disallowed"],[[68192,68220],"valid"],[[68221,68223],"valid",[],"NV8"],[[68224,68252],"valid"],[[68253,68255],"valid",[],"NV8"],[[68256,68287],"disallowed"],[[68288,68295],"valid"],[[68296,68296],"valid",[],"NV8"],[[68297,68326],"valid"],[[68327,68330],"disallowed"],[[68331,68342],"valid",[],"NV8"],[[68343,68351],"disallowed"],[[68352,68405],"valid"],[[68406,68408],"disallowed"],[[68409,68415],"valid",[],"NV8"],[[68416,68437],"valid"],[[68438,68439],"disallowed"],[[68440,68447],"valid",[],"NV8"],[[68448,68466],"valid"],[[68467,68471],"disallowed"],[[68472,68479],"valid",[],"NV8"],[[68480,68497],"valid"],[[68498,68504],"disallowed"],[[68505,68508],"valid",[],"NV8"],[[68509,68520],"disallowed"],[[68521,68527],"valid",[],"NV8"],[[68528,68607],"disallowed"],[[68608,68680],"valid"],[[68681,68735],"disallowed"],[[68736,68736],"mapped",[68800]],[[68737,68737],"mapped",[68801]],[[68738,68738],"mapped",[68802]],[[68739,68739],"mapped",[68803]],[[68740,68740],"mapped",[68804]],[[68741,68741],"mapped",[68805]],[[68742,68742],"mapped",[68806]],[[68743,68743],"mapped",[68807]],[[68744,68744],"mapped",[68808]],[[68745,68745],"mapped",[68809]],[[68746,68746],"mapped",[68810]],[[68747,68747],"mapped",[68811]],[[68748,68748],"mapped",[68812]],[[68749,68749],"mapped",[68813]],[[68750,68750],"mapped",[68814]],[[68751,68751],"mapped",[68815]],[[68752,68752],"mapped",[68816]],[[68753,68753],"mapped",[68817]],[[68754,68754],"mapped",[68818]],[[68755,68755],"mapped",[68819]],[[68756,68756],"mapped",[68820]],[[68757,68757],"mapped",[68821]],[[68758,68758],"mapped",[68822]],[[68759,68759],"mapped",[68823]],[[68760,68760],"mapped",[68824]],[[68761,68761],"mapped",[68825]],[[68762,68762],"mapped",[68826]],[[68763,68763],"mapped",[68827]],[[68764,68764],"mapped",[68828]],[[68765,68765],"mapped",[68829]],[[68766,68766],"mapped",[68830]],[[68767,68767],"mapped",[68831]],[[68768,68768],"mapped",[68832]],[[68769,68769],"mapped",[68833]],[[68770,68770],"mapped",[68834]],[[68771,68771],"mapped",[68835]],[[68772,68772],"mapped",[68836]],[[68773,68773],"mapped",[68837]],[[68774,68774],"mapped",[68838]],[[68775,68775],"mapped",[68839]],[[68776,68776],"mapped",[68840]],[[68777,68777],"mapped",[68841]],[[68778,68778],"mapped",[68842]],[[68779,68779],"mapped",[68843]],[[68780,68780],"mapped",[68844]],[[68781,68781],"mapped",[68845]],[[68782,68782],"mapped",[68846]],[[68783,68783],"mapped",[68847]],[[68784,68784],"mapped",[68848]],[[68785,68785],"mapped",[68849]],[[68786,68786],"mapped",[68850]],[[68787,68799],"disallowed"],[[68800,68850],"valid"],[[68851,68857],"disallowed"],[[68858,68863],"valid",[],"NV8"],[[68864,69215],"disallowed"],[[69216,69246],"valid",[],"NV8"],[[69247,69631],"disallowed"],[[69632,69702],"valid"],[[69703,69709],"valid",[],"NV8"],[[69710,69713],"disallowed"],[[69714,69733],"valid",[],"NV8"],[[69734,69743],"valid"],[[69744,69758],"disallowed"],[[69759,69759],"valid"],[[69760,69818],"valid"],[[69819,69820],"valid",[],"NV8"],[[69821,69821],"disallowed"],[[69822,69825],"valid",[],"NV8"],[[69826,69839],"disallowed"],[[69840,69864],"valid"],[[69865,69871],"disallowed"],[[69872,69881],"valid"],[[69882,69887],"disallowed"],[[69888,69940],"valid"],[[69941,69941],"disallowed"],[[69942,69951],"valid"],[[69952,69955],"valid",[],"NV8"],[[69956,69967],"disallowed"],[[69968,70003],"valid"],[[70004,70005],"valid",[],"NV8"],[[70006,70006],"valid"],[[70007,70015],"disallowed"],[[70016,70084],"valid"],[[70085,70088],"valid",[],"NV8"],[[70089,70089],"valid",[],"NV8"],[[70090,70092],"valid"],[[70093,70093],"valid",[],"NV8"],[[70094,70095],"disallowed"],[[70096,70105],"valid"],[[70106,70106],"valid"],[[70107,70107],"valid",[],"NV8"],[[70108,70108],"valid"],[[70109,70111],"valid",[],"NV8"],[[70112,70112],"disallowed"],[[70113,70132],"valid",[],"NV8"],[[70133,70143],"disallowed"],[[70144,70161],"valid"],[[70162,70162],"disallowed"],[[70163,70199],"valid"],[[70200,70205],"valid",[],"NV8"],[[70206,70271],"disallowed"],[[70272,70278],"valid"],[[70279,70279],"disallowed"],[[70280,70280],"valid"],[[70281,70281],"disallowed"],[[70282,70285],"valid"],[[70286,70286],"disallowed"],[[70287,70301],"valid"],[[70302,70302],"disallowed"],[[70303,70312],"valid"],[[70313,70313],"valid",[],"NV8"],[[70314,70319],"disallowed"],[[70320,70378],"valid"],[[70379,70383],"disallowed"],[[70384,70393],"valid"],[[70394,70399],"disallowed"],[[70400,70400],"valid"],[[70401,70403],"valid"],[[70404,70404],"disallowed"],[[70405,70412],"valid"],[[70413,70414],"disallowed"],[[70415,70416],"valid"],[[70417,70418],"disallowed"],[[70419,70440],"valid"],[[70441,70441],"disallowed"],[[70442,70448],"valid"],[[70449,70449],"disallowed"],[[70450,70451],"valid"],[[70452,70452],"disallowed"],[[70453,70457],"valid"],[[70458,70459],"disallowed"],[[70460,70468],"valid"],[[70469,70470],"disallowed"],[[70471,70472],"valid"],[[70473,70474],"disallowed"],[[70475,70477],"valid"],[[70478,70479],"disallowed"],[[70480,70480],"valid"],[[70481,70486],"disallowed"],[[70487,70487],"valid"],[[70488,70492],"disallowed"],[[70493,70499],"valid"],[[70500,70501],"disallowed"],[[70502,70508],"valid"],[[70509,70511],"disallowed"],[[70512,70516],"valid"],[[70517,70783],"disallowed"],[[70784,70853],"valid"],[[70854,70854],"valid",[],"NV8"],[[70855,70855],"valid"],[[70856,70863],"disallowed"],[[70864,70873],"valid"],[[70874,71039],"disallowed"],[[71040,71093],"valid"],[[71094,71095],"disallowed"],[[71096,71104],"valid"],[[71105,71113],"valid",[],"NV8"],[[71114,71127],"valid",[],"NV8"],[[71128,71133],"valid"],[[71134,71167],"disallowed"],[[71168,71232],"valid"],[[71233,71235],"valid",[],"NV8"],[[71236,71236],"valid"],[[71237,71247],"disallowed"],[[71248,71257],"valid"],[[71258,71295],"disallowed"],[[71296,71351],"valid"],[[71352,71359],"disallowed"],[[71360,71369],"valid"],[[71370,71423],"disallowed"],[[71424,71449],"valid"],[[71450,71452],"disallowed"],[[71453,71467],"valid"],[[71468,71471],"disallowed"],[[71472,71481],"valid"],[[71482,71487],"valid",[],"NV8"],[[71488,71839],"disallowed"],[[71840,71840],"mapped",[71872]],[[71841,71841],"mapped",[71873]],[[71842,71842],"mapped",[71874]],[[71843,71843],"mapped",[71875]],[[71844,71844],"mapped",[71876]],[[71845,71845],"mapped",[71877]],[[71846,71846],"mapped",[71878]],[[71847,71847],"mapped",[71879]],[[71848,71848],"mapped",[71880]],[[71849,71849],"mapped",[71881]],[[71850,71850],"mapped",[71882]],[[71851,71851],"mapped",[71883]],[[71852,71852],"mapped",[71884]],[[71853,71853],"mapped",[71885]],[[71854,71854],"mapped",[71886]],[[71855,71855],"mapped",[71887]],[[71856,71856],"mapped",[71888]],[[71857,71857],"mapped",[71889]],[[71858,71858],"mapped",[71890]],[[71859,71859],"mapped",[71891]],[[71860,71860],"mapped",[71892]],[[71861,71861],"mapped",[71893]],[[71862,71862],"mapped",[71894]],[[71863,71863],"mapped",[71895]],[[71864,71864],"mapped",[71896]],[[71865,71865],"mapped",[71897]],[[71866,71866],"mapped",[71898]],[[71867,71867],"mapped",[71899]],[[71868,71868],"mapped",[71900]],[[71869,71869],"mapped",[71901]],[[71870,71870],"mapped",[71902]],[[71871,71871],"mapped",[71903]],[[71872,71913],"valid"],[[71914,71922],"valid",[],"NV8"],[[71923,71934],"disallowed"],[[71935,71935],"valid"],[[71936,72383],"disallowed"],[[72384,72440],"valid"],[[72441,73727],"disallowed"],[[73728,74606],"valid"],[[74607,74648],"valid"],[[74649,74649],"valid"],[[74650,74751],"disallowed"],[[74752,74850],"valid",[],"NV8"],[[74851,74862],"valid",[],"NV8"],[[74863,74863],"disallowed"],[[74864,74867],"valid",[],"NV8"],[[74868,74868],"valid",[],"NV8"],[[74869,74879],"disallowed"],[[74880,75075],"valid"],[[75076,77823],"disallowed"],[[77824,78894],"valid"],[[78895,82943],"disallowed"],[[82944,83526],"valid"],[[83527,92159],"disallowed"],[[92160,92728],"valid"],[[92729,92735],"disallowed"],[[92736,92766],"valid"],[[92767,92767],"disallowed"],[[92768,92777],"valid"],[[92778,92781],"disallowed"],[[92782,92783],"valid",[],"NV8"],[[92784,92879],"disallowed"],[[92880,92909],"valid"],[[92910,92911],"disallowed"],[[92912,92916],"valid"],[[92917,92917],"valid",[],"NV8"],[[92918,92927],"disallowed"],[[92928,92982],"valid"],[[92983,92991],"valid",[],"NV8"],[[92992,92995],"valid"],[[92996,92997],"valid",[],"NV8"],[[92998,93007],"disallowed"],[[93008,93017],"valid"],[[93018,93018],"disallowed"],[[93019,93025],"valid",[],"NV8"],[[93026,93026],"disallowed"],[[93027,93047],"valid"],[[93048,93052],"disallowed"],[[93053,93071],"valid"],[[93072,93951],"disallowed"],[[93952,94020],"valid"],[[94021,94031],"disallowed"],[[94032,94078],"valid"],[[94079,94094],"disallowed"],[[94095,94111],"valid"],[[94112,110591],"disallowed"],[[110592,110593],"valid"],[[110594,113663],"disallowed"],[[113664,113770],"valid"],[[113771,113775],"disallowed"],[[113776,113788],"valid"],[[113789,113791],"disallowed"],[[113792,113800],"valid"],[[113801,113807],"disallowed"],[[113808,113817],"valid"],[[113818,113819],"disallowed"],[[113820,113820],"valid",[],"NV8"],[[113821,113822],"valid"],[[113823,113823],"valid",[],"NV8"],[[113824,113827],"ignored"],[[113828,118783],"disallowed"],[[118784,119029],"valid",[],"NV8"],[[119030,119039],"disallowed"],[[119040,119078],"valid",[],"NV8"],[[119079,119080],"disallowed"],[[119081,119081],"valid",[],"NV8"],[[119082,119133],"valid",[],"NV8"],[[119134,119134],"mapped",[119127,119141]],[[119135,119135],"mapped",[119128,119141]],[[119136,119136],"mapped",[119128,119141,119150]],[[119137,119137],"mapped",[119128,119141,119151]],[[119138,119138],"mapped",[119128,119141,119152]],[[119139,119139],"mapped",[119128,119141,119153]],[[119140,119140],"mapped",[119128,119141,119154]],[[119141,119154],"valid",[],"NV8"],[[119155,119162],"disallowed"],[[119163,119226],"valid",[],"NV8"],[[119227,119227],"mapped",[119225,119141]],[[119228,119228],"mapped",[119226,119141]],[[119229,119229],"mapped",[119225,119141,119150]],[[119230,119230],"mapped",[119226,119141,119150]],[[119231,119231],"mapped",[119225,119141,119151]],[[119232,119232],"mapped",[119226,119141,119151]],[[119233,119261],"valid",[],"NV8"],[[119262,119272],"valid",[],"NV8"],[[119273,119295],"disallowed"],[[119296,119365],"valid",[],"NV8"],[[119366,119551],"disallowed"],[[119552,119638],"valid",[],"NV8"],[[119639,119647],"disallowed"],[[119648,119665],"valid",[],"NV8"],[[119666,119807],"disallowed"],[[119808,119808],"mapped",[97]],[[119809,119809],"mapped",[98]],[[119810,119810],"mapped",[99]],[[119811,119811],"mapped",[100]],[[119812,119812],"mapped",[101]],[[119813,119813],"mapped",[102]],[[119814,119814],"mapped",[103]],[[119815,119815],"mapped",[104]],[[119816,119816],"mapped",[105]],[[119817,119817],"mapped",[106]],[[119818,119818],"mapped",[107]],[[119819,119819],"mapped",[108]],[[119820,119820],"mapped",[109]],[[119821,119821],"mapped",[110]],[[119822,119822],"mapped",[111]],[[119823,119823],"mapped",[112]],[[119824,119824],"mapped",[113]],[[119825,119825],"mapped",[114]],[[119826,119826],"mapped",[115]],[[119827,119827],"mapped",[116]],[[119828,119828],"mapped",[117]],[[119829,119829],"mapped",[118]],[[119830,119830],"mapped",[119]],[[119831,119831],"mapped",[120]],[[119832,119832],"mapped",[121]],[[119833,119833],"mapped",[122]],[[119834,119834],"mapped",[97]],[[119835,119835],"mapped",[98]],[[119836,119836],"mapped",[99]],[[119837,119837],"mapped",[100]],[[119838,119838],"mapped",[101]],[[119839,119839],"mapped",[102]],[[119840,119840],"mapped",[103]],[[119841,119841],"mapped",[104]],[[119842,119842],"mapped",[105]],[[119843,119843],"mapped",[106]],[[119844,119844],"mapped",[107]],[[119845,119845],"mapped",[108]],[[119846,119846],"mapped",[109]],[[119847,119847],"mapped",[110]],[[119848,119848],"mapped",[111]],[[119849,119849],"mapped",[112]],[[119850,119850],"mapped",[113]],[[119851,119851],"mapped",[114]],[[119852,119852],"mapped",[115]],[[119853,119853],"mapped",[116]],[[119854,119854],"mapped",[117]],[[119855,119855],"mapped",[118]],[[119856,119856],"mapped",[119]],[[119857,119857],"mapped",[120]],[[119858,119858],"mapped",[121]],[[119859,119859],"mapped",[122]],[[119860,119860],"mapped",[97]],[[119861,119861],"mapped",[98]],[[119862,119862],"mapped",[99]],[[119863,119863],"mapped",[100]],[[119864,119864],"mapped",[101]],[[119865,119865],"mapped",[102]],[[119866,119866],"mapped",[103]],[[119867,119867],"mapped",[104]],[[119868,119868],"mapped",[105]],[[119869,119869],"mapped",[106]],[[119870,119870],"mapped",[107]],[[119871,119871],"mapped",[108]],[[119872,119872],"mapped",[109]],[[119873,119873],"mapped",[110]],[[119874,119874],"mapped",[111]],[[119875,119875],"mapped",[112]],[[119876,119876],"mapped",[113]],[[119877,119877],"mapped",[114]],[[119878,119878],"mapped",[115]],[[119879,119879],"mapped",[116]],[[119880,119880],"mapped",[117]],[[119881,119881],"mapped",[118]],[[119882,119882],"mapped",[119]],[[119883,119883],"mapped",[120]],[[119884,119884],"mapped",[121]],[[119885,119885],"mapped",[122]],[[119886,119886],"mapped",[97]],[[119887,119887],"mapped",[98]],[[119888,119888],"mapped",[99]],[[119889,119889],"mapped",[100]],[[119890,119890],"mapped",[101]],[[119891,119891],"mapped",[102]],[[119892,119892],"mapped",[103]],[[119893,119893],"disallowed"],[[119894,119894],"mapped",[105]],[[119895,119895],"mapped",[106]],[[119896,119896],"mapped",[107]],[[119897,119897],"mapped",[108]],[[119898,119898],"mapped",[109]],[[119899,119899],"mapped",[110]],[[119900,119900],"mapped",[111]],[[119901,119901],"mapped",[112]],[[119902,119902],"mapped",[113]],[[119903,119903],"mapped",[114]],[[119904,119904],"mapped",[115]],[[119905,119905],"mapped",[116]],[[119906,119906],"mapped",[117]],[[119907,119907],"mapped",[118]],[[119908,119908],"mapped",[119]],[[119909,119909],"mapped",[120]],[[119910,119910],"mapped",[121]],[[119911,119911],"mapped",[122]],[[119912,119912],"mapped",[97]],[[119913,119913],"mapped",[98]],[[119914,119914],"mapped",[99]],[[119915,119915],"mapped",[100]],[[119916,119916],"mapped",[101]],[[119917,119917],"mapped",[102]],[[119918,119918],"mapped",[103]],[[119919,119919],"mapped",[104]],[[119920,119920],"mapped",[105]],[[119921,119921],"mapped",[106]],[[119922,119922],"mapped",[107]],[[119923,119923],"mapped",[108]],[[119924,119924],"mapped",[109]],[[119925,119925],"mapped",[110]],[[119926,119926],"mapped",[111]],[[119927,119927],"mapped",[112]],[[119928,119928],"mapped",[113]],[[119929,119929],"mapped",[114]],[[119930,119930],"mapped",[115]],[[119931,119931],"mapped",[116]],[[119932,119932],"mapped",[117]],[[119933,119933],"mapped",[118]],[[119934,119934],"mapped",[119]],[[119935,119935],"mapped",[120]],[[119936,119936],"mapped",[121]],[[119937,119937],"mapped",[122]],[[119938,119938],"mapped",[97]],[[119939,119939],"mapped",[98]],[[119940,119940],"mapped",[99]],[[119941,119941],"mapped",[100]],[[119942,119942],"mapped",[101]],[[119943,119943],"mapped",[102]],[[119944,119944],"mapped",[103]],[[119945,119945],"mapped",[104]],[[119946,119946],"mapped",[105]],[[119947,119947],"mapped",[106]],[[119948,119948],"mapped",[107]],[[119949,119949],"mapped",[108]],[[119950,119950],"mapped",[109]],[[119951,119951],"mapped",[110]],[[119952,119952],"mapped",[111]],[[119953,119953],"mapped",[112]],[[119954,119954],"mapped",[113]],[[119955,119955],"mapped",[114]],[[119956,119956],"mapped",[115]],[[119957,119957],"mapped",[116]],[[119958,119958],"mapped",[117]],[[119959,119959],"mapped",[118]],[[119960,119960],"mapped",[119]],[[119961,119961],"mapped",[120]],[[119962,119962],"mapped",[121]],[[119963,119963],"mapped",[122]],[[119964,119964],"mapped",[97]],[[119965,119965],"disallowed"],[[119966,119966],"mapped",[99]],[[119967,119967],"mapped",[100]],[[119968,119969],"disallowed"],[[119970,119970],"mapped",[103]],[[119971,119972],"disallowed"],[[119973,119973],"mapped",[106]],[[119974,119974],"mapped",[107]],[[119975,119976],"disallowed"],[[119977,119977],"mapped",[110]],[[119978,119978],"mapped",[111]],[[119979,119979],"mapped",[112]],[[119980,119980],"mapped",[113]],[[119981,119981],"disallowed"],[[119982,119982],"mapped",[115]],[[119983,119983],"mapped",[116]],[[119984,119984],"mapped",[117]],[[119985,119985],"mapped",[118]],[[119986,119986],"mapped",[119]],[[119987,119987],"mapped",[120]],[[119988,119988],"mapped",[121]],[[119989,119989],"mapped",[122]],[[119990,119990],"mapped",[97]],[[119991,119991],"mapped",[98]],[[119992,119992],"mapped",[99]],[[119993,119993],"mapped",[100]],[[119994,119994],"disallowed"],[[119995,119995],"mapped",[102]],[[119996,119996],"disallowed"],[[119997,119997],"mapped",[104]],[[119998,119998],"mapped",[105]],[[119999,119999],"mapped",[106]],[[120000,120000],"mapped",[107]],[[120001,120001],"mapped",[108]],[[120002,120002],"mapped",[109]],[[120003,120003],"mapped",[110]],[[120004,120004],"disallowed"],[[120005,120005],"mapped",[112]],[[120006,120006],"mapped",[113]],[[120007,120007],"mapped",[114]],[[120008,120008],"mapped",[115]],[[120009,120009],"mapped",[116]],[[120010,120010],"mapped",[117]],[[120011,120011],"mapped",[118]],[[120012,120012],"mapped",[119]],[[120013,120013],"mapped",[120]],[[120014,120014],"mapped",[121]],[[120015,120015],"mapped",[122]],[[120016,120016],"mapped",[97]],[[120017,120017],"mapped",[98]],[[120018,120018],"mapped",[99]],[[120019,120019],"mapped",[100]],[[120020,120020],"mapped",[101]],[[120021,120021],"mapped",[102]],[[120022,120022],"mapped",[103]],[[120023,120023],"mapped",[104]],[[120024,120024],"mapped",[105]],[[120025,120025],"mapped",[106]],[[120026,120026],"mapped",[107]],[[120027,120027],"mapped",[108]],[[120028,120028],"mapped",[109]],[[120029,120029],"mapped",[110]],[[120030,120030],"mapped",[111]],[[120031,120031],"mapped",[112]],[[120032,120032],"mapped",[113]],[[120033,120033],"mapped",[114]],[[120034,120034],"mapped",[115]],[[120035,120035],"mapped",[116]],[[120036,120036],"mapped",[117]],[[120037,120037],"mapped",[118]],[[120038,120038],"mapped",[119]],[[120039,120039],"mapped",[120]],[[120040,120040],"mapped",[121]],[[120041,120041],"mapped",[122]],[[120042,120042],"mapped",[97]],[[120043,120043],"mapped",[98]],[[120044,120044],"mapped",[99]],[[120045,120045],"mapped",[100]],[[120046,120046],"mapped",[101]],[[120047,120047],"mapped",[102]],[[120048,120048],"mapped",[103]],[[120049,120049],"mapped",[104]],[[120050,120050],"mapped",[105]],[[120051,120051],"mapped",[106]],[[120052,120052],"mapped",[107]],[[120053,120053],"mapped",[108]],[[120054,120054],"mapped",[109]],[[120055,120055],"mapped",[110]],[[120056,120056],"mapped",[111]],[[120057,120057],"mapped",[112]],[[120058,120058],"mapped",[113]],[[120059,120059],"mapped",[114]],[[120060,120060],"mapped",[115]],[[120061,120061],"mapped",[116]],[[120062,120062],"mapped",[117]],[[120063,120063],"mapped",[118]],[[120064,120064],"mapped",[119]],[[120065,120065],"mapped",[120]],[[120066,120066],"mapped",[121]],[[120067,120067],"mapped",[122]],[[120068,120068],"mapped",[97]],[[120069,120069],"mapped",[98]],[[120070,120070],"disallowed"],[[120071,120071],"mapped",[100]],[[120072,120072],"mapped",[101]],[[120073,120073],"mapped",[102]],[[120074,120074],"mapped",[103]],[[120075,120076],"disallowed"],[[120077,120077],"mapped",[106]],[[120078,120078],"mapped",[107]],[[120079,120079],"mapped",[108]],[[120080,120080],"mapped",[109]],[[120081,120081],"mapped",[110]],[[120082,120082],"mapped",[111]],[[120083,120083],"mapped",[112]],[[120084,120084],"mapped",[113]],[[120085,120085],"disallowed"],[[120086,120086],"mapped",[115]],[[120087,120087],"mapped",[116]],[[120088,120088],"mapped",[117]],[[120089,120089],"mapped",[118]],[[120090,120090],"mapped",[119]],[[120091,120091],"mapped",[120]],[[120092,120092],"mapped",[121]],[[120093,120093],"disallowed"],[[120094,120094],"mapped",[97]],[[120095,120095],"mapped",[98]],[[120096,120096],"mapped",[99]],[[120097,120097],"mapped",[100]],[[120098,120098],"mapped",[101]],[[120099,120099],"mapped",[102]],[[120100,120100],"mapped",[103]],[[120101,120101],"mapped",[104]],[[120102,120102],"mapped",[105]],[[120103,120103],"mapped",[106]],[[120104,120104],"mapped",[107]],[[120105,120105],"mapped",[108]],[[120106,120106],"mapped",[109]],[[120107,120107],"mapped",[110]],[[120108,120108],"mapped",[111]],[[120109,120109],"mapped",[112]],[[120110,120110],"mapped",[113]],[[120111,120111],"mapped",[114]],[[120112,120112],"mapped",[115]],[[120113,120113],"mapped",[116]],[[120114,120114],"mapped",[117]],[[120115,120115],"mapped",[118]],[[120116,120116],"mapped",[119]],[[120117,120117],"mapped",[120]],[[120118,120118],"mapped",[121]],[[120119,120119],"mapped",[122]],[[120120,120120],"mapped",[97]],[[120121,120121],"mapped",[98]],[[120122,120122],"disallowed"],[[120123,120123],"mapped",[100]],[[120124,120124],"mapped",[101]],[[120125,120125],"mapped",[102]],[[120126,120126],"mapped",[103]],[[120127,120127],"disallowed"],[[120128,120128],"mapped",[105]],[[120129,120129],"mapped",[106]],[[120130,120130],"mapped",[107]],[[120131,120131],"mapped",[108]],[[120132,120132],"mapped",[109]],[[120133,120133],"disallowed"],[[120134,120134],"mapped",[111]],[[120135,120137],"disallowed"],[[120138,120138],"mapped",[115]],[[120139,120139],"mapped",[116]],[[120140,120140],"mapped",[117]],[[120141,120141],"mapped",[118]],[[120142,120142],"mapped",[119]],[[120143,120143],"mapped",[120]],[[120144,120144],"mapped",[121]],[[120145,120145],"disallowed"],[[120146,120146],"mapped",[97]],[[120147,120147],"mapped",[98]],[[120148,120148],"mapped",[99]],[[120149,120149],"mapped",[100]],[[120150,120150],"mapped",[101]],[[120151,120151],"mapped",[102]],[[120152,120152],"mapped",[103]],[[120153,120153],"mapped",[104]],[[120154,120154],"mapped",[105]],[[120155,120155],"mapped",[106]],[[120156,120156],"mapped",[107]],[[120157,120157],"mapped",[108]],[[120158,120158],"mapped",[109]],[[120159,120159],"mapped",[110]],[[120160,120160],"mapped",[111]],[[120161,120161],"mapped",[112]],[[120162,120162],"mapped",[113]],[[120163,120163],"mapped",[114]],[[120164,120164],"mapped",[115]],[[120165,120165],"mapped",[116]],[[120166,120166],"mapped",[117]],[[120167,120167],"mapped",[118]],[[120168,120168],"mapped",[119]],[[120169,120169],"mapped",[120]],[[120170,120170],"mapped",[121]],[[120171,120171],"mapped",[122]],[[120172,120172],"mapped",[97]],[[120173,120173],"mapped",[98]],[[120174,120174],"mapped",[99]],[[120175,120175],"mapped",[100]],[[120176,120176],"mapped",[101]],[[120177,120177],"mapped",[102]],[[120178,120178],"mapped",[103]],[[120179,120179],"mapped",[104]],[[120180,120180],"mapped",[105]],[[120181,120181],"mapped",[106]],[[120182,120182],"mapped",[107]],[[120183,120183],"mapped",[108]],[[120184,120184],"mapped",[109]],[[120185,120185],"mapped",[110]],[[120186,120186],"mapped",[111]],[[120187,120187],"mapped",[112]],[[120188,120188],"mapped",[113]],[[120189,120189],"mapped",[114]],[[120190,120190],"mapped",[115]],[[120191,120191],"mapped",[116]],[[120192,120192],"mapped",[117]],[[120193,120193],"mapped",[118]],[[120194,120194],"mapped",[119]],[[120195,120195],"mapped",[120]],[[120196,120196],"mapped",[121]],[[120197,120197],"mapped",[122]],[[120198,120198],"mapped",[97]],[[120199,120199],"mapped",[98]],[[120200,120200],"mapped",[99]],[[120201,120201],"mapped",[100]],[[120202,120202],"mapped",[101]],[[120203,120203],"mapped",[102]],[[120204,120204],"mapped",[103]],[[120205,120205],"mapped",[104]],[[120206,120206],"mapped",[105]],[[120207,120207],"mapped",[106]],[[120208,120208],"mapped",[107]],[[120209,120209],"mapped",[108]],[[120210,120210],"mapped",[109]],[[120211,120211],"mapped",[110]],[[120212,120212],"mapped",[111]],[[120213,120213],"mapped",[112]],[[120214,120214],"mapped",[113]],[[120215,120215],"mapped",[114]],[[120216,120216],"mapped",[115]],[[120217,120217],"mapped",[116]],[[120218,120218],"mapped",[117]],[[120219,120219],"mapped",[118]],[[120220,120220],"mapped",[119]],[[120221,120221],"mapped",[120]],[[120222,120222],"mapped",[121]],[[120223,120223],"mapped",[122]],[[120224,120224],"mapped",[97]],[[120225,120225],"mapped",[98]],[[120226,120226],"mapped",[99]],[[120227,120227],"mapped",[100]],[[120228,120228],"mapped",[101]],[[120229,120229],"mapped",[102]],[[120230,120230],"mapped",[103]],[[120231,120231],"mapped",[104]],[[120232,120232],"mapped",[105]],[[120233,120233],"mapped",[106]],[[120234,120234],"mapped",[107]],[[120235,120235],"mapped",[108]],[[120236,120236],"mapped",[109]],[[120237,120237],"mapped",[110]],[[120238,120238],"mapped",[111]],[[120239,120239],"mapped",[112]],[[120240,120240],"mapped",[113]],[[120241,120241],"mapped",[114]],[[120242,120242],"mapped",[115]],[[120243,120243],"mapped",[116]],[[120244,120244],"mapped",[117]],[[120245,120245],"mapped",[118]],[[120246,120246],"mapped",[119]],[[120247,120247],"mapped",[120]],[[120248,120248],"mapped",[121]],[[120249,120249],"mapped",[122]],[[120250,120250],"mapped",[97]],[[120251,120251],"mapped",[98]],[[120252,120252],"mapped",[99]],[[120253,120253],"mapped",[100]],[[120254,120254],"mapped",[101]],[[120255,120255],"mapped",[102]],[[120256,120256],"mapped",[103]],[[120257,120257],"mapped",[104]],[[120258,120258],"mapped",[105]],[[120259,120259],"mapped",[106]],[[120260,120260],"mapped",[107]],[[120261,120261],"mapped",[108]],[[120262,120262],"mapped",[109]],[[120263,120263],"mapped",[110]],[[120264,120264],"mapped",[111]],[[120265,120265],"mapped",[112]],[[120266,120266],"mapped",[113]],[[120267,120267],"mapped",[114]],[[120268,120268],"mapped",[115]],[[120269,120269],"mapped",[116]],[[120270,120270],"mapped",[117]],[[120271,120271],"mapped",[118]],[[120272,120272],"mapped",[119]],[[120273,120273],"mapped",[120]],[[120274,120274],"mapped",[121]],[[120275,120275],"mapped",[122]],[[120276,120276],"mapped",[97]],[[120277,120277],"mapped",[98]],[[120278,120278],"mapped",[99]],[[120279,120279],"mapped",[100]],[[120280,120280],"mapped",[101]],[[120281,120281],"mapped",[102]],[[120282,120282],"mapped",[103]],[[120283,120283],"mapped",[104]],[[120284,120284],"mapped",[105]],[[120285,120285],"mapped",[106]],[[120286,120286],"mapped",[107]],[[120287,120287],"mapped",[108]],[[120288,120288],"mapped",[109]],[[120289,120289],"mapped",[110]],[[120290,120290],"mapped",[111]],[[120291,120291],"mapped",[112]],[[120292,120292],"mapped",[113]],[[120293,120293],"mapped",[114]],[[120294,120294],"mapped",[115]],[[120295,120295],"mapped",[116]],[[120296,120296],"mapped",[117]],[[120297,120297],"mapped",[118]],[[120298,120298],"mapped",[119]],[[120299,120299],"mapped",[120]],[[120300,120300],"mapped",[121]],[[120301,120301],"mapped",[122]],[[120302,120302],"mapped",[97]],[[120303,120303],"mapped",[98]],[[120304,120304],"mapped",[99]],[[120305,120305],"mapped",[100]],[[120306,120306],"mapped",[101]],[[120307,120307],"mapped",[102]],[[120308,120308],"mapped",[103]],[[120309,120309],"mapped",[104]],[[120310,120310],"mapped",[105]],[[120311,120311],"mapped",[106]],[[120312,120312],"mapped",[107]],[[120313,120313],"mapped",[108]],[[120314,120314],"mapped",[109]],[[120315,120315],"mapped",[110]],[[120316,120316],"mapped",[111]],[[120317,120317],"mapped",[112]],[[120318,120318],"mapped",[113]],[[120319,120319],"mapped",[114]],[[120320,120320],"mapped",[115]],[[120321,120321],"mapped",[116]],[[120322,120322],"mapped",[117]],[[120323,120323],"mapped",[118]],[[120324,120324],"mapped",[119]],[[120325,120325],"mapped",[120]],[[120326,120326],"mapped",[121]],[[120327,120327],"mapped",[122]],[[120328,120328],"mapped",[97]],[[120329,120329],"mapped",[98]],[[120330,120330],"mapped",[99]],[[120331,120331],"mapped",[100]],[[120332,120332],"mapped",[101]],[[120333,120333],"mapped",[102]],[[120334,120334],"mapped",[103]],[[120335,120335],"mapped",[104]],[[120336,120336],"mapped",[105]],[[120337,120337],"mapped",[106]],[[120338,120338],"mapped",[107]],[[120339,120339],"mapped",[108]],[[120340,120340],"mapped",[109]],[[120341,120341],"mapped",[110]],[[120342,120342],"mapped",[111]],[[120343,120343],"mapped",[112]],[[120344,120344],"mapped",[113]],[[120345,120345],"mapped",[114]],[[120346,120346],"mapped",[115]],[[120347,120347],"mapped",[116]],[[120348,120348],"mapped",[117]],[[120349,120349],"mapped",[118]],[[120350,120350],"mapped",[119]],[[120351,120351],"mapped",[120]],[[120352,120352],"mapped",[121]],[[120353,120353],"mapped",[122]],[[120354,120354],"mapped",[97]],[[120355,120355],"mapped",[98]],[[120356,120356],"mapped",[99]],[[120357,120357],"mapped",[100]],[[120358,120358],"mapped",[101]],[[120359,120359],"mapped",[102]],[[120360,120360],"mapped",[103]],[[120361,120361],"mapped",[104]],[[120362,120362],"mapped",[105]],[[120363,120363],"mapped",[106]],[[120364,120364],"mapped",[107]],[[120365,120365],"mapped",[108]],[[120366,120366],"mapped",[109]],[[120367,120367],"mapped",[110]],[[120368,120368],"mapped",[111]],[[120369,120369],"mapped",[112]],[[120370,120370],"mapped",[113]],[[120371,120371],"mapped",[114]],[[120372,120372],"mapped",[115]],[[120373,120373],"mapped",[116]],[[120374,120374],"mapped",[117]],[[120375,120375],"mapped",[118]],[[120376,120376],"mapped",[119]],[[120377,120377],"mapped",[120]],[[120378,120378],"mapped",[121]],[[120379,120379],"mapped",[122]],[[120380,120380],"mapped",[97]],[[120381,120381],"mapped",[98]],[[120382,120382],"mapped",[99]],[[120383,120383],"mapped",[100]],[[120384,120384],"mapped",[101]],[[120385,120385],"mapped",[102]],[[120386,120386],"mapped",[103]],[[120387,120387],"mapped",[104]],[[120388,120388],"mapped",[105]],[[120389,120389],"mapped",[106]],[[120390,120390],"mapped",[107]],[[120391,120391],"mapped",[108]],[[120392,120392],"mapped",[109]],[[120393,120393],"mapped",[110]],[[120394,120394],"mapped",[111]],[[120395,120395],"mapped",[112]],[[120396,120396],"mapped",[113]],[[120397,120397],"mapped",[114]],[[120398,120398],"mapped",[115]],[[120399,120399],"mapped",[116]],[[120400,120400],"mapped",[117]],[[120401,120401],"mapped",[118]],[[120402,120402],"mapped",[119]],[[120403,120403],"mapped",[120]],[[120404,120404],"mapped",[121]],[[120405,120405],"mapped",[122]],[[120406,120406],"mapped",[97]],[[120407,120407],"mapped",[98]],[[120408,120408],"mapped",[99]],[[120409,120409],"mapped",[100]],[[120410,120410],"mapped",[101]],[[120411,120411],"mapped",[102]],[[120412,120412],"mapped",[103]],[[120413,120413],"mapped",[104]],[[120414,120414],"mapped",[105]],[[120415,120415],"mapped",[106]],[[120416,120416],"mapped",[107]],[[120417,120417],"mapped",[108]],[[120418,120418],"mapped",[109]],[[120419,120419],"mapped",[110]],[[120420,120420],"mapped",[111]],[[120421,120421],"mapped",[112]],[[120422,120422],"mapped",[113]],[[120423,120423],"mapped",[114]],[[120424,120424],"mapped",[115]],[[120425,120425],"mapped",[116]],[[120426,120426],"mapped",[117]],[[120427,120427],"mapped",[118]],[[120428,120428],"mapped",[119]],[[120429,120429],"mapped",[120]],[[120430,120430],"mapped",[121]],[[120431,120431],"mapped",[122]],[[120432,120432],"mapped",[97]],[[120433,120433],"mapped",[98]],[[120434,120434],"mapped",[99]],[[120435,120435],"mapped",[100]],[[120436,120436],"mapped",[101]],[[120437,120437],"mapped",[102]],[[120438,120438],"mapped",[103]],[[120439,120439],"mapped",[104]],[[120440,120440],"mapped",[105]],[[120441,120441],"mapped",[106]],[[120442,120442],"mapped",[107]],[[120443,120443],"mapped",[108]],[[120444,120444],"mapped",[109]],[[120445,120445],"mapped",[110]],[[120446,120446],"mapped",[111]],[[120447,120447],"mapped",[112]],[[120448,120448],"mapped",[113]],[[120449,120449],"mapped",[114]],[[120450,120450],"mapped",[115]],[[120451,120451],"mapped",[116]],[[120452,120452],"mapped",[117]],[[120453,120453],"mapped",[118]],[[120454,120454],"mapped",[119]],[[120455,120455],"mapped",[120]],[[120456,120456],"mapped",[121]],[[120457,120457],"mapped",[122]],[[120458,120458],"mapped",[97]],[[120459,120459],"mapped",[98]],[[120460,120460],"mapped",[99]],[[120461,120461],"mapped",[100]],[[120462,120462],"mapped",[101]],[[120463,120463],"mapped",[102]],[[120464,120464],"mapped",[103]],[[120465,120465],"mapped",[104]],[[120466,120466],"mapped",[105]],[[120467,120467],"mapped",[106]],[[120468,120468],"mapped",[107]],[[120469,120469],"mapped",[108]],[[120470,120470],"mapped",[109]],[[120471,120471],"mapped",[110]],[[120472,120472],"mapped",[111]],[[120473,120473],"mapped",[112]],[[120474,120474],"mapped",[113]],[[120475,120475],"mapped",[114]],[[120476,120476],"mapped",[115]],[[120477,120477],"mapped",[116]],[[120478,120478],"mapped",[117]],[[120479,120479],"mapped",[118]],[[120480,120480],"mapped",[119]],[[120481,120481],"mapped",[120]],[[120482,120482],"mapped",[121]],[[120483,120483],"mapped",[122]],[[120484,120484],"mapped",[305]],[[120485,120485],"mapped",[567]],[[120486,120487],"disallowed"],[[120488,120488],"mapped",[945]],[[120489,120489],"mapped",[946]],[[120490,120490],"mapped",[947]],[[120491,120491],"mapped",[948]],[[120492,120492],"mapped",[949]],[[120493,120493],"mapped",[950]],[[120494,120494],"mapped",[951]],[[120495,120495],"mapped",[952]],[[120496,120496],"mapped",[953]],[[120497,120497],"mapped",[954]],[[120498,120498],"mapped",[955]],[[120499,120499],"mapped",[956]],[[120500,120500],"mapped",[957]],[[120501,120501],"mapped",[958]],[[120502,120502],"mapped",[959]],[[120503,120503],"mapped",[960]],[[120504,120504],"mapped",[961]],[[120505,120505],"mapped",[952]],[[120506,120506],"mapped",[963]],[[120507,120507],"mapped",[964]],[[120508,120508],"mapped",[965]],[[120509,120509],"mapped",[966]],[[120510,120510],"mapped",[967]],[[120511,120511],"mapped",[968]],[[120512,120512],"mapped",[969]],[[120513,120513],"mapped",[8711]],[[120514,120514],"mapped",[945]],[[120515,120515],"mapped",[946]],[[120516,120516],"mapped",[947]],[[120517,120517],"mapped",[948]],[[120518,120518],"mapped",[949]],[[120519,120519],"mapped",[950]],[[120520,120520],"mapped",[951]],[[120521,120521],"mapped",[952]],[[120522,120522],"mapped",[953]],[[120523,120523],"mapped",[954]],[[120524,120524],"mapped",[955]],[[120525,120525],"mapped",[956]],[[120526,120526],"mapped",[957]],[[120527,120527],"mapped",[958]],[[120528,120528],"mapped",[959]],[[120529,120529],"mapped",[960]],[[120530,120530],"mapped",[961]],[[120531,120532],"mapped",[963]],[[120533,120533],"mapped",[964]],[[120534,120534],"mapped",[965]],[[120535,120535],"mapped",[966]],[[120536,120536],"mapped",[967]],[[120537,120537],"mapped",[968]],[[120538,120538],"mapped",[969]],[[120539,120539],"mapped",[8706]],[[120540,120540],"mapped",[949]],[[120541,120541],"mapped",[952]],[[120542,120542],"mapped",[954]],[[120543,120543],"mapped",[966]],[[120544,120544],"mapped",[961]],[[120545,120545],"mapped",[960]],[[120546,120546],"mapped",[945]],[[120547,120547],"mapped",[946]],[[120548,120548],"mapped",[947]],[[120549,120549],"mapped",[948]],[[120550,120550],"mapped",[949]],[[120551,120551],"mapped",[950]],[[120552,120552],"mapped",[951]],[[120553,120553],"mapped",[952]],[[120554,120554],"mapped",[953]],[[120555,120555],"mapped",[954]],[[120556,120556],"mapped",[955]],[[120557,120557],"mapped",[956]],[[120558,120558],"mapped",[957]],[[120559,120559],"mapped",[958]],[[120560,120560],"mapped",[959]],[[120561,120561],"mapped",[960]],[[120562,120562],"mapped",[961]],[[120563,120563],"mapped",[952]],[[120564,120564],"mapped",[963]],[[120565,120565],"mapped",[964]],[[120566,120566],"mapped",[965]],[[120567,120567],"mapped",[966]],[[120568,120568],"mapped",[967]],[[120569,120569],"mapped",[968]],[[120570,120570],"mapped",[969]],[[120571,120571],"mapped",[8711]],[[120572,120572],"mapped",[945]],[[120573,120573],"mapped",[946]],[[120574,120574],"mapped",[947]],[[120575,120575],"mapped",[948]],[[120576,120576],"mapped",[949]],[[120577,120577],"mapped",[950]],[[120578,120578],"mapped",[951]],[[120579,120579],"mapped",[952]],[[120580,120580],"mapped",[953]],[[120581,120581],"mapped",[954]],[[120582,120582],"mapped",[955]],[[120583,120583],"mapped",[956]],[[120584,120584],"mapped",[957]],[[120585,120585],"mapped",[958]],[[120586,120586],"mapped",[959]],[[120587,120587],"mapped",[960]],[[120588,120588],"mapped",[961]],[[120589,120590],"mapped",[963]],[[120591,120591],"mapped",[964]],[[120592,120592],"mapped",[965]],[[120593,120593],"mapped",[966]],[[120594,120594],"mapped",[967]],[[120595,120595],"mapped",[968]],[[120596,120596],"mapped",[969]],[[120597,120597],"mapped",[8706]],[[120598,120598],"mapped",[949]],[[120599,120599],"mapped",[952]],[[120600,120600],"mapped",[954]],[[120601,120601],"mapped",[966]],[[120602,120602],"mapped",[961]],[[120603,120603],"mapped",[960]],[[120604,120604],"mapped",[945]],[[120605,120605],"mapped",[946]],[[120606,120606],"mapped",[947]],[[120607,120607],"mapped",[948]],[[120608,120608],"mapped",[949]],[[120609,120609],"mapped",[950]],[[120610,120610],"mapped",[951]],[[120611,120611],"mapped",[952]],[[120612,120612],"mapped",[953]],[[120613,120613],"mapped",[954]],[[120614,120614],"mapped",[955]],[[120615,120615],"mapped",[956]],[[120616,120616],"mapped",[957]],[[120617,120617],"mapped",[958]],[[120618,120618],"mapped",[959]],[[120619,120619],"mapped",[960]],[[120620,120620],"mapped",[961]],[[120621,120621],"mapped",[952]],[[120622,120622],"mapped",[963]],[[120623,120623],"mapped",[964]],[[120624,120624],"mapped",[965]],[[120625,120625],"mapped",[966]],[[120626,120626],"mapped",[967]],[[120627,120627],"mapped",[968]],[[120628,120628],"mapped",[969]],[[120629,120629],"mapped",[8711]],[[120630,120630],"mapped",[945]],[[120631,120631],"mapped",[946]],[[120632,120632],"mapped",[947]],[[120633,120633],"mapped",[948]],[[120634,120634],"mapped",[949]],[[120635,120635],"mapped",[950]],[[120636,120636],"mapped",[951]],[[120637,120637],"mapped",[952]],[[120638,120638],"mapped",[953]],[[120639,120639],"mapped",[954]],[[120640,120640],"mapped",[955]],[[120641,120641],"mapped",[956]],[[120642,120642],"mapped",[957]],[[120643,120643],"mapped",[958]],[[120644,120644],"mapped",[959]],[[120645,120645],"mapped",[960]],[[120646,120646],"mapped",[961]],[[120647,120648],"mapped",[963]],[[120649,120649],"mapped",[964]],[[120650,120650],"mapped",[965]],[[120651,120651],"mapped",[966]],[[120652,120652],"mapped",[967]],[[120653,120653],"mapped",[968]],[[120654,120654],"mapped",[969]],[[120655,120655],"mapped",[8706]],[[120656,120656],"mapped",[949]],[[120657,120657],"mapped",[952]],[[120658,120658],"mapped",[954]],[[120659,120659],"mapped",[966]],[[120660,120660],"mapped",[961]],[[120661,120661],"mapped",[960]],[[120662,120662],"mapped",[945]],[[120663,120663],"mapped",[946]],[[120664,120664],"mapped",[947]],[[120665,120665],"mapped",[948]],[[120666,120666],"mapped",[949]],[[120667,120667],"mapped",[950]],[[120668,120668],"mapped",[951]],[[120669,120669],"mapped",[952]],[[120670,120670],"mapped",[953]],[[120671,120671],"mapped",[954]],[[120672,120672],"mapped",[955]],[[120673,120673],"mapped",[956]],[[120674,120674],"mapped",[957]],[[120675,120675],"mapped",[958]],[[120676,120676],"mapped",[959]],[[120677,120677],"mapped",[960]],[[120678,120678],"mapped",[961]],[[120679,120679],"mapped",[952]],[[120680,120680],"mapped",[963]],[[120681,120681],"mapped",[964]],[[120682,120682],"mapped",[965]],[[120683,120683],"mapped",[966]],[[120684,120684],"mapped",[967]],[[120685,120685],"mapped",[968]],[[120686,120686],"mapped",[969]],[[120687,120687],"mapped",[8711]],[[120688,120688],"mapped",[945]],[[120689,120689],"mapped",[946]],[[120690,120690],"mapped",[947]],[[120691,120691],"mapped",[948]],[[120692,120692],"mapped",[949]],[[120693,120693],"mapped",[950]],[[120694,120694],"mapped",[951]],[[120695,120695],"mapped",[952]],[[120696,120696],"mapped",[953]],[[120697,120697],"mapped",[954]],[[120698,120698],"mapped",[955]],[[120699,120699],"mapped",[956]],[[120700,120700],"mapped",[957]],[[120701,120701],"mapped",[958]],[[120702,120702],"mapped",[959]],[[120703,120703],"mapped",[960]],[[120704,120704],"mapped",[961]],[[120705,120706],"mapped",[963]],[[120707,120707],"mapped",[964]],[[120708,120708],"mapped",[965]],[[120709,120709],"mapped",[966]],[[120710,120710],"mapped",[967]],[[120711,120711],"mapped",[968]],[[120712,120712],"mapped",[969]],[[120713,120713],"mapped",[8706]],[[120714,120714],"mapped",[949]],[[120715,120715],"mapped",[952]],[[120716,120716],"mapped",[954]],[[120717,120717],"mapped",[966]],[[120718,120718],"mapped",[961]],[[120719,120719],"mapped",[960]],[[120720,120720],"mapped",[945]],[[120721,120721],"mapped",[946]],[[120722,120722],"mapped",[947]],[[120723,120723],"mapped",[948]],[[120724,120724],"mapped",[949]],[[120725,120725],"mapped",[950]],[[120726,120726],"mapped",[951]],[[120727,120727],"mapped",[952]],[[120728,120728],"mapped",[953]],[[120729,120729],"mapped",[954]],[[120730,120730],"mapped",[955]],[[120731,120731],"mapped",[956]],[[120732,120732],"mapped",[957]],[[120733,120733],"mapped",[958]],[[120734,120734],"mapped",[959]],[[120735,120735],"mapped",[960]],[[120736,120736],"mapped",[961]],[[120737,120737],"mapped",[952]],[[120738,120738],"mapped",[963]],[[120739,120739],"mapped",[964]],[[120740,120740],"mapped",[965]],[[120741,120741],"mapped",[966]],[[120742,120742],"mapped",[967]],[[120743,120743],"mapped",[968]],[[120744,120744],"mapped",[969]],[[120745,120745],"mapped",[8711]],[[120746,120746],"mapped",[945]],[[120747,120747],"mapped",[946]],[[120748,120748],"mapped",[947]],[[120749,120749],"mapped",[948]],[[120750,120750],"mapped",[949]],[[120751,120751],"mapped",[950]],[[120752,120752],"mapped",[951]],[[120753,120753],"mapped",[952]],[[120754,120754],"mapped",[953]],[[120755,120755],"mapped",[954]],[[120756,120756],"mapped",[955]],[[120757,120757],"mapped",[956]],[[120758,120758],"mapped",[957]],[[120759,120759],"mapped",[958]],[[120760,120760],"mapped",[959]],[[120761,120761],"mapped",[960]],[[120762,120762],"mapped",[961]],[[120763,120764],"mapped",[963]],[[120765,120765],"mapped",[964]],[[120766,120766],"mapped",[965]],[[120767,120767],"mapped",[966]],[[120768,120768],"mapped",[967]],[[120769,120769],"mapped",[968]],[[120770,120770],"mapped",[969]],[[120771,120771],"mapped",[8706]],[[120772,120772],"mapped",[949]],[[120773,120773],"mapped",[952]],[[120774,120774],"mapped",[954]],[[120775,120775],"mapped",[966]],[[120776,120776],"mapped",[961]],[[120777,120777],"mapped",[960]],[[120778,120779],"mapped",[989]],[[120780,120781],"disallowed"],[[120782,120782],"mapped",[48]],[[120783,120783],"mapped",[49]],[[120784,120784],"mapped",[50]],[[120785,120785],"mapped",[51]],[[120786,120786],"mapped",[52]],[[120787,120787],"mapped",[53]],[[120788,120788],"mapped",[54]],[[120789,120789],"mapped",[55]],[[120790,120790],"mapped",[56]],[[120791,120791],"mapped",[57]],[[120792,120792],"mapped",[48]],[[120793,120793],"mapped",[49]],[[120794,120794],"mapped",[50]],[[120795,120795],"mapped",[51]],[[120796,120796],"mapped",[52]],[[120797,120797],"mapped",[53]],[[120798,120798],"mapped",[54]],[[120799,120799],"mapped",[55]],[[120800,120800],"mapped",[56]],[[120801,120801],"mapped",[57]],[[120802,120802],"mapped",[48]],[[120803,120803],"mapped",[49]],[[120804,120804],"mapped",[50]],[[120805,120805],"mapped",[51]],[[120806,120806],"mapped",[52]],[[120807,120807],"mapped",[53]],[[120808,120808],"mapped",[54]],[[120809,120809],"mapped",[55]],[[120810,120810],"mapped",[56]],[[120811,120811],"mapped",[57]],[[120812,120812],"mapped",[48]],[[120813,120813],"mapped",[49]],[[120814,120814],"mapped",[50]],[[120815,120815],"mapped",[51]],[[120816,120816],"mapped",[52]],[[120817,120817],"mapped",[53]],[[120818,120818],"mapped",[54]],[[120819,120819],"mapped",[55]],[[120820,120820],"mapped",[56]],[[120821,120821],"mapped",[57]],[[120822,120822],"mapped",[48]],[[120823,120823],"mapped",[49]],[[120824,120824],"mapped",[50]],[[120825,120825],"mapped",[51]],[[120826,120826],"mapped",[52]],[[120827,120827],"mapped",[53]],[[120828,120828],"mapped",[54]],[[120829,120829],"mapped",[55]],[[120830,120830],"mapped",[56]],[[120831,120831],"mapped",[57]],[[120832,121343],"valid",[],"NV8"],[[121344,121398],"valid"],[[121399,121402],"valid",[],"NV8"],[[121403,121452],"valid"],[[121453,121460],"valid",[],"NV8"],[[121461,121461],"valid"],[[121462,121475],"valid",[],"NV8"],[[121476,121476],"valid"],[[121477,121483],"valid",[],"NV8"],[[121484,121498],"disallowed"],[[121499,121503],"valid"],[[121504,121504],"disallowed"],[[121505,121519],"valid"],[[121520,124927],"disallowed"],[[124928,125124],"valid"],[[125125,125126],"disallowed"],[[125127,125135],"valid",[],"NV8"],[[125136,125142],"valid"],[[125143,126463],"disallowed"],[[126464,126464],"mapped",[1575]],[[126465,126465],"mapped",[1576]],[[126466,126466],"mapped",[1580]],[[126467,126467],"mapped",[1583]],[[126468,126468],"disallowed"],[[126469,126469],"mapped",[1608]],[[126470,126470],"mapped",[1586]],[[126471,126471],"mapped",[1581]],[[126472,126472],"mapped",[1591]],[[126473,126473],"mapped",[1610]],[[126474,126474],"mapped",[1603]],[[126475,126475],"mapped",[1604]],[[126476,126476],"mapped",[1605]],[[126477,126477],"mapped",[1606]],[[126478,126478],"mapped",[1587]],[[126479,126479],"mapped",[1593]],[[126480,126480],"mapped",[1601]],[[126481,126481],"mapped",[1589]],[[126482,126482],"mapped",[1602]],[[126483,126483],"mapped",[1585]],[[126484,126484],"mapped",[1588]],[[126485,126485],"mapped",[1578]],[[126486,126486],"mapped",[1579]],[[126487,126487],"mapped",[1582]],[[126488,126488],"mapped",[1584]],[[126489,126489],"mapped",[1590]],[[126490,126490],"mapped",[1592]],[[126491,126491],"mapped",[1594]],[[126492,126492],"mapped",[1646]],[[126493,126493],"mapped",[1722]],[[126494,126494],"mapped",[1697]],[[126495,126495],"mapped",[1647]],[[126496,126496],"disallowed"],[[126497,126497],"mapped",[1576]],[[126498,126498],"mapped",[1580]],[[126499,126499],"disallowed"],[[126500,126500],"mapped",[1607]],[[126501,126502],"disallowed"],[[126503,126503],"mapped",[1581]],[[126504,126504],"disallowed"],[[126505,126505],"mapped",[1610]],[[126506,126506],"mapped",[1603]],[[126507,126507],"mapped",[1604]],[[126508,126508],"mapped",[1605]],[[126509,126509],"mapped",[1606]],[[126510,126510],"mapped",[1587]],[[126511,126511],"mapped",[1593]],[[126512,126512],"mapped",[1601]],[[126513,126513],"mapped",[1589]],[[126514,126514],"mapped",[1602]],[[126515,126515],"disallowed"],[[126516,126516],"mapped",[1588]],[[126517,126517],"mapped",[1578]],[[126518,126518],"mapped",[1579]],[[126519,126519],"mapped",[1582]],[[126520,126520],"disallowed"],[[126521,126521],"mapped",[1590]],[[126522,126522],"disallowed"],[[126523,126523],"mapped",[1594]],[[126524,126529],"disallowed"],[[126530,126530],"mapped",[1580]],[[126531,126534],"disallowed"],[[126535,126535],"mapped",[1581]],[[126536,126536],"disallowed"],[[126537,126537],"mapped",[1610]],[[126538,126538],"disallowed"],[[126539,126539],"mapped",[1604]],[[126540,126540],"disallowed"],[[126541,126541],"mapped",[1606]],[[126542,126542],"mapped",[1587]],[[126543,126543],"mapped",[1593]],[[126544,126544],"disallowed"],[[126545,126545],"mapped",[1589]],[[126546,126546],"mapped",[1602]],[[126547,126547],"disallowed"],[[126548,126548],"mapped",[1588]],[[126549,126550],"disallowed"],[[126551,126551],"mapped",[1582]],[[126552,126552],"disallowed"],[[126553,126553],"mapped",[1590]],[[126554,126554],"disallowed"],[[126555,126555],"mapped",[1594]],[[126556,126556],"disallowed"],[[126557,126557],"mapped",[1722]],[[126558,126558],"disallowed"],[[126559,126559],"mapped",[1647]],[[126560,126560],"disallowed"],[[126561,126561],"mapped",[1576]],[[126562,126562],"mapped",[1580]],[[126563,126563],"disallowed"],[[126564,126564],"mapped",[1607]],[[126565,126566],"disallowed"],[[126567,126567],"mapped",[1581]],[[126568,126568],"mapped",[1591]],[[126569,126569],"mapped",[1610]],[[126570,126570],"mapped",[1603]],[[126571,126571],"disallowed"],[[126572,126572],"mapped",[1605]],[[126573,126573],"mapped",[1606]],[[126574,126574],"mapped",[1587]],[[126575,126575],"mapped",[1593]],[[126576,126576],"mapped",[1601]],[[126577,126577],"mapped",[1589]],[[126578,126578],"mapped",[1602]],[[126579,126579],"disallowed"],[[126580,126580],"mapped",[1588]],[[126581,126581],"mapped",[1578]],[[126582,126582],"mapped",[1579]],[[126583,126583],"mapped",[1582]],[[126584,126584],"disallowed"],[[126585,126585],"mapped",[1590]],[[126586,126586],"mapped",[1592]],[[126587,126587],"mapped",[1594]],[[126588,126588],"mapped",[1646]],[[126589,126589],"disallowed"],[[126590,126590],"mapped",[1697]],[[126591,126591],"disallowed"],[[126592,126592],"mapped",[1575]],[[126593,126593],"mapped",[1576]],[[126594,126594],"mapped",[1580]],[[126595,126595],"mapped",[1583]],[[126596,126596],"mapped",[1607]],[[126597,126597],"mapped",[1608]],[[126598,126598],"mapped",[1586]],[[126599,126599],"mapped",[1581]],[[126600,126600],"mapped",[1591]],[[126601,126601],"mapped",[1610]],[[126602,126602],"disallowed"],[[126603,126603],"mapped",[1604]],[[126604,126604],"mapped",[1605]],[[126605,126605],"mapped",[1606]],[[126606,126606],"mapped",[1587]],[[126607,126607],"mapped",[1593]],[[126608,126608],"mapped",[1601]],[[126609,126609],"mapped",[1589]],[[126610,126610],"mapped",[1602]],[[126611,126611],"mapped",[1585]],[[126612,126612],"mapped",[1588]],[[126613,126613],"mapped",[1578]],[[126614,126614],"mapped",[1579]],[[126615,126615],"mapped",[1582]],[[126616,126616],"mapped",[1584]],[[126617,126617],"mapped",[1590]],[[126618,126618],"mapped",[1592]],[[126619,126619],"mapped",[1594]],[[126620,126624],"disallowed"],[[126625,126625],"mapped",[1576]],[[126626,126626],"mapped",[1580]],[[126627,126627],"mapped",[1583]],[[126628,126628],"disallowed"],[[126629,126629],"mapped",[1608]],[[126630,126630],"mapped",[1586]],[[126631,126631],"mapped",[1581]],[[126632,126632],"mapped",[1591]],[[126633,126633],"mapped",[1610]],[[126634,126634],"disallowed"],[[126635,126635],"mapped",[1604]],[[126636,126636],"mapped",[1605]],[[126637,126637],"mapped",[1606]],[[126638,126638],"mapped",[1587]],[[126639,126639],"mapped",[1593]],[[126640,126640],"mapped",[1601]],[[126641,126641],"mapped",[1589]],[[126642,126642],"mapped",[1602]],[[126643,126643],"mapped",[1585]],[[126644,126644],"mapped",[1588]],[[126645,126645],"mapped",[1578]],[[126646,126646],"mapped",[1579]],[[126647,126647],"mapped",[1582]],[[126648,126648],"mapped",[1584]],[[126649,126649],"mapped",[1590]],[[126650,126650],"mapped",[1592]],[[126651,126651],"mapped",[1594]],[[126652,126703],"disallowed"],[[126704,126705],"valid",[],"NV8"],[[126706,126975],"disallowed"],[[126976,127019],"valid",[],"NV8"],[[127020,127023],"disallowed"],[[127024,127123],"valid",[],"NV8"],[[127124,127135],"disallowed"],[[127136,127150],"valid",[],"NV8"],[[127151,127152],"disallowed"],[[127153,127166],"valid",[],"NV8"],[[127167,127167],"valid",[],"NV8"],[[127168,127168],"disallowed"],[[127169,127183],"valid",[],"NV8"],[[127184,127184],"disallowed"],[[127185,127199],"valid",[],"NV8"],[[127200,127221],"valid",[],"NV8"],[[127222,127231],"disallowed"],[[127232,127232],"disallowed"],[[127233,127233],"disallowed_STD3_mapped",[48,44]],[[127234,127234],"disallowed_STD3_mapped",[49,44]],[[127235,127235],"disallowed_STD3_mapped",[50,44]],[[127236,127236],"disallowed_STD3_mapped",[51,44]],[[127237,127237],"disallowed_STD3_mapped",[52,44]],[[127238,127238],"disallowed_STD3_mapped",[53,44]],[[127239,127239],"disallowed_STD3_mapped",[54,44]],[[127240,127240],"disallowed_STD3_mapped",[55,44]],[[127241,127241],"disallowed_STD3_mapped",[56,44]],[[127242,127242],"disallowed_STD3_mapped",[57,44]],[[127243,127244],"valid",[],"NV8"],[[127245,127247],"disallowed"],[[127248,127248],"disallowed_STD3_mapped",[40,97,41]],[[127249,127249],"disallowed_STD3_mapped",[40,98,41]],[[127250,127250],"disallowed_STD3_mapped",[40,99,41]],[[127251,127251],"disallowed_STD3_mapped",[40,100,41]],[[127252,127252],"disallowed_STD3_mapped",[40,101,41]],[[127253,127253],"disallowed_STD3_mapped",[40,102,41]],[[127254,127254],"disallowed_STD3_mapped",[40,103,41]],[[127255,127255],"disallowed_STD3_mapped",[40,104,41]],[[127256,127256],"disallowed_STD3_mapped",[40,105,41]],[[127257,127257],"disallowed_STD3_mapped",[40,106,41]],[[127258,127258],"disallowed_STD3_mapped",[40,107,41]],[[127259,127259],"disallowed_STD3_mapped",[40,108,41]],[[127260,127260],"disallowed_STD3_mapped",[40,109,41]],[[127261,127261],"disallowed_STD3_mapped",[40,110,41]],[[127262,127262],"disallowed_STD3_mapped",[40,111,41]],[[127263,127263],"disallowed_STD3_mapped",[40,112,41]],[[127264,127264],"disallowed_STD3_mapped",[40,113,41]],[[127265,127265],"disallowed_STD3_mapped",[40,114,41]],[[127266,127266],"disallowed_STD3_mapped",[40,115,41]],[[127267,127267],"disallowed_STD3_mapped",[40,116,41]],[[127268,127268],"disallowed_STD3_mapped",[40,117,41]],[[127269,127269],"disallowed_STD3_mapped",[40,118,41]],[[127270,127270],"disallowed_STD3_mapped",[40,119,41]],[[127271,127271],"disallowed_STD3_mapped",[40,120,41]],[[127272,127272],"disallowed_STD3_mapped",[40,121,41]],[[127273,127273],"disallowed_STD3_mapped",[40,122,41]],[[127274,127274],"mapped",[12308,115,12309]],[[127275,127275],"mapped",[99]],[[127276,127276],"mapped",[114]],[[127277,127277],"mapped",[99,100]],[[127278,127278],"mapped",[119,122]],[[127279,127279],"disallowed"],[[127280,127280],"mapped",[97]],[[127281,127281],"mapped",[98]],[[127282,127282],"mapped",[99]],[[127283,127283],"mapped",[100]],[[127284,127284],"mapped",[101]],[[127285,127285],"mapped",[102]],[[127286,127286],"mapped",[103]],[[127287,127287],"mapped",[104]],[[127288,127288],"mapped",[105]],[[127289,127289],"mapped",[106]],[[127290,127290],"mapped",[107]],[[127291,127291],"mapped",[108]],[[127292,127292],"mapped",[109]],[[127293,127293],"mapped",[110]],[[127294,127294],"mapped",[111]],[[127295,127295],"mapped",[112]],[[127296,127296],"mapped",[113]],[[127297,127297],"mapped",[114]],[[127298,127298],"mapped",[115]],[[127299,127299],"mapped",[116]],[[127300,127300],"mapped",[117]],[[127301,127301],"mapped",[118]],[[127302,127302],"mapped",[119]],[[127303,127303],"mapped",[120]],[[127304,127304],"mapped",[121]],[[127305,127305],"mapped",[122]],[[127306,127306],"mapped",[104,118]],[[127307,127307],"mapped",[109,118]],[[127308,127308],"mapped",[115,100]],[[127309,127309],"mapped",[115,115]],[[127310,127310],"mapped",[112,112,118]],[[127311,127311],"mapped",[119,99]],[[127312,127318],"valid",[],"NV8"],[[127319,127319],"valid",[],"NV8"],[[127320,127326],"valid",[],"NV8"],[[127327,127327],"valid",[],"NV8"],[[127328,127337],"valid",[],"NV8"],[[127338,127338],"mapped",[109,99]],[[127339,127339],"mapped",[109,100]],[[127340,127343],"disallowed"],[[127344,127352],"valid",[],"NV8"],[[127353,127353],"valid",[],"NV8"],[[127354,127354],"valid",[],"NV8"],[[127355,127356],"valid",[],"NV8"],[[127357,127358],"valid",[],"NV8"],[[127359,127359],"valid",[],"NV8"],[[127360,127369],"valid",[],"NV8"],[[127370,127373],"valid",[],"NV8"],[[127374,127375],"valid",[],"NV8"],[[127376,127376],"mapped",[100,106]],[[127377,127386],"valid",[],"NV8"],[[127387,127461],"disallowed"],[[127462,127487],"valid",[],"NV8"],[[127488,127488],"mapped",[12411,12363]],[[127489,127489],"mapped",[12467,12467]],[[127490,127490],"mapped",[12469]],[[127491,127503],"disallowed"],[[127504,127504],"mapped",[25163]],[[127505,127505],"mapped",[23383]],[[127506,127506],"mapped",[21452]],[[127507,127507],"mapped",[12487]],[[127508,127508],"mapped",[20108]],[[127509,127509],"mapped",[22810]],[[127510,127510],"mapped",[35299]],[[127511,127511],"mapped",[22825]],[[127512,127512],"mapped",[20132]],[[127513,127513],"mapped",[26144]],[[127514,127514],"mapped",[28961]],[[127515,127515],"mapped",[26009]],[[127516,127516],"mapped",[21069]],[[127517,127517],"mapped",[24460]],[[127518,127518],"mapped",[20877]],[[127519,127519],"mapped",[26032]],[[127520,127520],"mapped",[21021]],[[127521,127521],"mapped",[32066]],[[127522,127522],"mapped",[29983]],[[127523,127523],"mapped",[36009]],[[127524,127524],"mapped",[22768]],[[127525,127525],"mapped",[21561]],[[127526,127526],"mapped",[28436]],[[127527,127527],"mapped",[25237]],[[127528,127528],"mapped",[25429]],[[127529,127529],"mapped",[19968]],[[127530,127530],"mapped",[19977]],[[127531,127531],"mapped",[36938]],[[127532,127532],"mapped",[24038]],[[127533,127533],"mapped",[20013]],[[127534,127534],"mapped",[21491]],[[127535,127535],"mapped",[25351]],[[127536,127536],"mapped",[36208]],[[127537,127537],"mapped",[25171]],[[127538,127538],"mapped",[31105]],[[127539,127539],"mapped",[31354]],[[127540,127540],"mapped",[21512]],[[127541,127541],"mapped",[28288]],[[127542,127542],"mapped",[26377]],[[127543,127543],"mapped",[26376]],[[127544,127544],"mapped",[30003]],[[127545,127545],"mapped",[21106]],[[127546,127546],"mapped",[21942]],[[127547,127551],"disallowed"],[[127552,127552],"mapped",[12308,26412,12309]],[[127553,127553],"mapped",[12308,19977,12309]],[[127554,127554],"mapped",[12308,20108,12309]],[[127555,127555],"mapped",[12308,23433,12309]],[[127556,127556],"mapped",[12308,28857,12309]],[[127557,127557],"mapped",[12308,25171,12309]],[[127558,127558],"mapped",[12308,30423,12309]],[[127559,127559],"mapped",[12308,21213,12309]],[[127560,127560],"mapped",[12308,25943,12309]],[[127561,127567],"disallowed"],[[127568,127568],"mapped",[24471]],[[127569,127569],"mapped",[21487]],[[127570,127743],"disallowed"],[[127744,127776],"valid",[],"NV8"],[[127777,127788],"valid",[],"NV8"],[[127789,127791],"valid",[],"NV8"],[[127792,127797],"valid",[],"NV8"],[[127798,127798],"valid",[],"NV8"],[[127799,127868],"valid",[],"NV8"],[[127869,127869],"valid",[],"NV8"],[[127870,127871],"valid",[],"NV8"],[[127872,127891],"valid",[],"NV8"],[[127892,127903],"valid",[],"NV8"],[[127904,127940],"valid",[],"NV8"],[[127941,127941],"valid",[],"NV8"],[[127942,127946],"valid",[],"NV8"],[[127947,127950],"valid",[],"NV8"],[[127951,127955],"valid",[],"NV8"],[[127956,127967],"valid",[],"NV8"],[[127968,127984],"valid",[],"NV8"],[[127985,127991],"valid",[],"NV8"],[[127992,127999],"valid",[],"NV8"],[[128000,128062],"valid",[],"NV8"],[[128063,128063],"valid",[],"NV8"],[[128064,128064],"valid",[],"NV8"],[[128065,128065],"valid",[],"NV8"],[[128066,128247],"valid",[],"NV8"],[[128248,128248],"valid",[],"NV8"],[[128249,128252],"valid",[],"NV8"],[[128253,128254],"valid",[],"NV8"],[[128255,128255],"valid",[],"NV8"],[[128256,128317],"valid",[],"NV8"],[[128318,128319],"valid",[],"NV8"],[[128320,128323],"valid",[],"NV8"],[[128324,128330],"valid",[],"NV8"],[[128331,128335],"valid",[],"NV8"],[[128336,128359],"valid",[],"NV8"],[[128360,128377],"valid",[],"NV8"],[[128378,128378],"disallowed"],[[128379,128419],"valid",[],"NV8"],[[128420,128420],"disallowed"],[[128421,128506],"valid",[],"NV8"],[[128507,128511],"valid",[],"NV8"],[[128512,128512],"valid",[],"NV8"],[[128513,128528],"valid",[],"NV8"],[[128529,128529],"valid",[],"NV8"],[[128530,128532],"valid",[],"NV8"],[[128533,128533],"valid",[],"NV8"],[[128534,128534],"valid",[],"NV8"],[[128535,128535],"valid",[],"NV8"],[[128536,128536],"valid",[],"NV8"],[[128537,128537],"valid",[],"NV8"],[[128538,128538],"valid",[],"NV8"],[[128539,128539],"valid",[],"NV8"],[[128540,128542],"valid",[],"NV8"],[[128543,128543],"valid",[],"NV8"],[[128544,128549],"valid",[],"NV8"],[[128550,128551],"valid",[],"NV8"],[[128552,128555],"valid",[],"NV8"],[[128556,128556],"valid",[],"NV8"],[[128557,128557],"valid",[],"NV8"],[[128558,128559],"valid",[],"NV8"],[[128560,128563],"valid",[],"NV8"],[[128564,128564],"valid",[],"NV8"],[[128565,128576],"valid",[],"NV8"],[[128577,128578],"valid",[],"NV8"],[[128579,128580],"valid",[],"NV8"],[[128581,128591],"valid",[],"NV8"],[[128592,128639],"valid",[],"NV8"],[[128640,128709],"valid",[],"NV8"],[[128710,128719],"valid",[],"NV8"],[[128720,128720],"valid",[],"NV8"],[[128721,128735],"disallowed"],[[128736,128748],"valid",[],"NV8"],[[128749,128751],"disallowed"],[[128752,128755],"valid",[],"NV8"],[[128756,128767],"disallowed"],[[128768,128883],"valid",[],"NV8"],[[128884,128895],"disallowed"],[[128896,128980],"valid",[],"NV8"],[[128981,129023],"disallowed"],[[129024,129035],"valid",[],"NV8"],[[129036,129039],"disallowed"],[[129040,129095],"valid",[],"NV8"],[[129096,129103],"disallowed"],[[129104,129113],"valid",[],"NV8"],[[129114,129119],"disallowed"],[[129120,129159],"valid",[],"NV8"],[[129160,129167],"disallowed"],[[129168,129197],"valid",[],"NV8"],[[129198,129295],"disallowed"],[[129296,129304],"valid",[],"NV8"],[[129305,129407],"disallowed"],[[129408,129412],"valid",[],"NV8"],[[129413,129471],"disallowed"],[[129472,129472],"valid",[],"NV8"],[[129473,131069],"disallowed"],[[131070,131071],"disallowed"],[[131072,173782],"valid"],[[173783,173823],"disallowed"],[[173824,177972],"valid"],[[177973,177983],"disallowed"],[[177984,178205],"valid"],[[178206,178207],"disallowed"],[[178208,183969],"valid"],[[183970,194559],"disallowed"],[[194560,194560],"mapped",[20029]],[[194561,194561],"mapped",[20024]],[[194562,194562],"mapped",[20033]],[[194563,194563],"mapped",[131362]],[[194564,194564],"mapped",[20320]],[[194565,194565],"mapped",[20398]],[[194566,194566],"mapped",[20411]],[[194567,194567],"mapped",[20482]],[[194568,194568],"mapped",[20602]],[[194569,194569],"mapped",[20633]],[[194570,194570],"mapped",[20711]],[[194571,194571],"mapped",[20687]],[[194572,194572],"mapped",[13470]],[[194573,194573],"mapped",[132666]],[[194574,194574],"mapped",[20813]],[[194575,194575],"mapped",[20820]],[[194576,194576],"mapped",[20836]],[[194577,194577],"mapped",[20855]],[[194578,194578],"mapped",[132380]],[[194579,194579],"mapped",[13497]],[[194580,194580],"mapped",[20839]],[[194581,194581],"mapped",[20877]],[[194582,194582],"mapped",[132427]],[[194583,194583],"mapped",[20887]],[[194584,194584],"mapped",[20900]],[[194585,194585],"mapped",[20172]],[[194586,194586],"mapped",[20908]],[[194587,194587],"mapped",[20917]],[[194588,194588],"mapped",[168415]],[[194589,194589],"mapped",[20981]],[[194590,194590],"mapped",[20995]],[[194591,194591],"mapped",[13535]],[[194592,194592],"mapped",[21051]],[[194593,194593],"mapped",[21062]],[[194594,194594],"mapped",[21106]],[[194595,194595],"mapped",[21111]],[[194596,194596],"mapped",[13589]],[[194597,194597],"mapped",[21191]],[[194598,194598],"mapped",[21193]],[[194599,194599],"mapped",[21220]],[[194600,194600],"mapped",[21242]],[[194601,194601],"mapped",[21253]],[[194602,194602],"mapped",[21254]],[[194603,194603],"mapped",[21271]],[[194604,194604],"mapped",[21321]],[[194605,194605],"mapped",[21329]],[[194606,194606],"mapped",[21338]],[[194607,194607],"mapped",[21363]],[[194608,194608],"mapped",[21373]],[[194609,194611],"mapped",[21375]],[[194612,194612],"mapped",[133676]],[[194613,194613],"mapped",[28784]],[[194614,194614],"mapped",[21450]],[[194615,194615],"mapped",[21471]],[[194616,194616],"mapped",[133987]],[[194617,194617],"mapped",[21483]],[[194618,194618],"mapped",[21489]],[[194619,194619],"mapped",[21510]],[[194620,194620],"mapped",[21662]],[[194621,194621],"mapped",[21560]],[[194622,194622],"mapped",[21576]],[[194623,194623],"mapped",[21608]],[[194624,194624],"mapped",[21666]],[[194625,194625],"mapped",[21750]],[[194626,194626],"mapped",[21776]],[[194627,194627],"mapped",[21843]],[[194628,194628],"mapped",[21859]],[[194629,194630],"mapped",[21892]],[[194631,194631],"mapped",[21913]],[[194632,194632],"mapped",[21931]],[[194633,194633],"mapped",[21939]],[[194634,194634],"mapped",[21954]],[[194635,194635],"mapped",[22294]],[[194636,194636],"mapped",[22022]],[[194637,194637],"mapped",[22295]],[[194638,194638],"mapped",[22097]],[[194639,194639],"mapped",[22132]],[[194640,194640],"mapped",[20999]],[[194641,194641],"mapped",[22766]],[[194642,194642],"mapped",[22478]],[[194643,194643],"mapped",[22516]],[[194644,194644],"mapped",[22541]],[[194645,194645],"mapped",[22411]],[[194646,194646],"mapped",[22578]],[[194647,194647],"mapped",[22577]],[[194648,194648],"mapped",[22700]],[[194649,194649],"mapped",[136420]],[[194650,194650],"mapped",[22770]],[[194651,194651],"mapped",[22775]],[[194652,194652],"mapped",[22790]],[[194653,194653],"mapped",[22810]],[[194654,194654],"mapped",[22818]],[[194655,194655],"mapped",[22882]],[[194656,194656],"mapped",[136872]],[[194657,194657],"mapped",[136938]],[[194658,194658],"mapped",[23020]],[[194659,194659],"mapped",[23067]],[[194660,194660],"mapped",[23079]],[[194661,194661],"mapped",[23000]],[[194662,194662],"mapped",[23142]],[[194663,194663],"mapped",[14062]],[[194664,194664],"disallowed"],[[194665,194665],"mapped",[23304]],[[194666,194667],"mapped",[23358]],[[194668,194668],"mapped",[137672]],[[194669,194669],"mapped",[23491]],[[194670,194670],"mapped",[23512]],[[194671,194671],"mapped",[23527]],[[194672,194672],"mapped",[23539]],[[194673,194673],"mapped",[138008]],[[194674,194674],"mapped",[23551]],[[194675,194675],"mapped",[23558]],[[194676,194676],"disallowed"],[[194677,194677],"mapped",[23586]],[[194678,194678],"mapped",[14209]],[[194679,194679],"mapped",[23648]],[[194680,194680],"mapped",[23662]],[[194681,194681],"mapped",[23744]],[[194682,194682],"mapped",[23693]],[[194683,194683],"mapped",[138724]],[[194684,194684],"mapped",[23875]],[[194685,194685],"mapped",[138726]],[[194686,194686],"mapped",[23918]],[[194687,194687],"mapped",[23915]],[[194688,194688],"mapped",[23932]],[[194689,194689],"mapped",[24033]],[[194690,194690],"mapped",[24034]],[[194691,194691],"mapped",[14383]],[[194692,194692],"mapped",[24061]],[[194693,194693],"mapped",[24104]],[[194694,194694],"mapped",[24125]],[[194695,194695],"mapped",[24169]],[[194696,194696],"mapped",[14434]],[[194697,194697],"mapped",[139651]],[[194698,194698],"mapped",[14460]],[[194699,194699],"mapped",[24240]],[[194700,194700],"mapped",[24243]],[[194701,194701],"mapped",[24246]],[[194702,194702],"mapped",[24266]],[[194703,194703],"mapped",[172946]],[[194704,194704],"mapped",[24318]],[[194705,194706],"mapped",[140081]],[[194707,194707],"mapped",[33281]],[[194708,194709],"mapped",[24354]],[[194710,194710],"mapped",[14535]],[[194711,194711],"mapped",[144056]],[[194712,194712],"mapped",[156122]],[[194713,194713],"mapped",[24418]],[[194714,194714],"mapped",[24427]],[[194715,194715],"mapped",[14563]],[[194716,194716],"mapped",[24474]],[[194717,194717],"mapped",[24525]],[[194718,194718],"mapped",[24535]],[[194719,194719],"mapped",[24569]],[[194720,194720],"mapped",[24705]],[[194721,194721],"mapped",[14650]],[[194722,194722],"mapped",[14620]],[[194723,194723],"mapped",[24724]],[[194724,194724],"mapped",[141012]],[[194725,194725],"mapped",[24775]],[[194726,194726],"mapped",[24904]],[[194727,194727],"mapped",[24908]],[[194728,194728],"mapped",[24910]],[[194729,194729],"mapped",[24908]],[[194730,194730],"mapped",[24954]],[[194731,194731],"mapped",[24974]],[[194732,194732],"mapped",[25010]],[[194733,194733],"mapped",[24996]],[[194734,194734],"mapped",[25007]],[[194735,194735],"mapped",[25054]],[[194736,194736],"mapped",[25074]],[[194737,194737],"mapped",[25078]],[[194738,194738],"mapped",[25104]],[[194739,194739],"mapped",[25115]],[[194740,194740],"mapped",[25181]],[[194741,194741],"mapped",[25265]],[[194742,194742],"mapped",[25300]],[[194743,194743],"mapped",[25424]],[[194744,194744],"mapped",[142092]],[[194745,194745],"mapped",[25405]],[[194746,194746],"mapped",[25340]],[[194747,194747],"mapped",[25448]],[[194748,194748],"mapped",[25475]],[[194749,194749],"mapped",[25572]],[[194750,194750],"mapped",[142321]],[[194751,194751],"mapped",[25634]],[[194752,194752],"mapped",[25541]],[[194753,194753],"mapped",[25513]],[[194754,194754],"mapped",[14894]],[[194755,194755],"mapped",[25705]],[[194756,194756],"mapped",[25726]],[[194757,194757],"mapped",[25757]],[[194758,194758],"mapped",[25719]],[[194759,194759],"mapped",[14956]],[[194760,194760],"mapped",[25935]],[[194761,194761],"mapped",[25964]],[[194762,194762],"mapped",[143370]],[[194763,194763],"mapped",[26083]],[[194764,194764],"mapped",[26360]],[[194765,194765],"mapped",[26185]],[[194766,194766],"mapped",[15129]],[[194767,194767],"mapped",[26257]],[[194768,194768],"mapped",[15112]],[[194769,194769],"mapped",[15076]],[[194770,194770],"mapped",[20882]],[[194771,194771],"mapped",[20885]],[[194772,194772],"mapped",[26368]],[[194773,194773],"mapped",[26268]],[[194774,194774],"mapped",[32941]],[[194775,194775],"mapped",[17369]],[[194776,194776],"mapped",[26391]],[[194777,194777],"mapped",[26395]],[[194778,194778],"mapped",[26401]],[[194779,194779],"mapped",[26462]],[[194780,194780],"mapped",[26451]],[[194781,194781],"mapped",[144323]],[[194782,194782],"mapped",[15177]],[[194783,194783],"mapped",[26618]],[[194784,194784],"mapped",[26501]],[[194785,194785],"mapped",[26706]],[[194786,194786],"mapped",[26757]],[[194787,194787],"mapped",[144493]],[[194788,194788],"mapped",[26766]],[[194789,194789],"mapped",[26655]],[[194790,194790],"mapped",[26900]],[[194791,194791],"mapped",[15261]],[[194792,194792],"mapped",[26946]],[[194793,194793],"mapped",[27043]],[[194794,194794],"mapped",[27114]],[[194795,194795],"mapped",[27304]],[[194796,194796],"mapped",[145059]],[[194797,194797],"mapped",[27355]],[[194798,194798],"mapped",[15384]],[[194799,194799],"mapped",[27425]],[[194800,194800],"mapped",[145575]],[[194801,194801],"mapped",[27476]],[[194802,194802],"mapped",[15438]],[[194803,194803],"mapped",[27506]],[[194804,194804],"mapped",[27551]],[[194805,194805],"mapped",[27578]],[[194806,194806],"mapped",[27579]],[[194807,194807],"mapped",[146061]],[[194808,194808],"mapped",[138507]],[[194809,194809],"mapped",[146170]],[[194810,194810],"mapped",[27726]],[[194811,194811],"mapped",[146620]],[[194812,194812],"mapped",[27839]],[[194813,194813],"mapped",[27853]],[[194814,194814],"mapped",[27751]],[[194815,194815],"mapped",[27926]],[[194816,194816],"mapped",[27966]],[[194817,194817],"mapped",[28023]],[[194818,194818],"mapped",[27969]],[[194819,194819],"mapped",[28009]],[[194820,194820],"mapped",[28024]],[[194821,194821],"mapped",[28037]],[[194822,194822],"mapped",[146718]],[[194823,194823],"mapped",[27956]],[[194824,194824],"mapped",[28207]],[[194825,194825],"mapped",[28270]],[[194826,194826],"mapped",[15667]],[[194827,194827],"mapped",[28363]],[[194828,194828],"mapped",[28359]],[[194829,194829],"mapped",[147153]],[[194830,194830],"mapped",[28153]],[[194831,194831],"mapped",[28526]],[[194832,194832],"mapped",[147294]],[[194833,194833],"mapped",[147342]],[[194834,194834],"mapped",[28614]],[[194835,194835],"mapped",[28729]],[[194836,194836],"mapped",[28702]],[[194837,194837],"mapped",[28699]],[[194838,194838],"mapped",[15766]],[[194839,194839],"mapped",[28746]],[[194840,194840],"mapped",[28797]],[[194841,194841],"mapped",[28791]],[[194842,194842],"mapped",[28845]],[[194843,194843],"mapped",[132389]],[[194844,194844],"mapped",[28997]],[[194845,194845],"mapped",[148067]],[[194846,194846],"mapped",[29084]],[[194847,194847],"disallowed"],[[194848,194848],"mapped",[29224]],[[194849,194849],"mapped",[29237]],[[194850,194850],"mapped",[29264]],[[194851,194851],"mapped",[149000]],[[194852,194852],"mapped",[29312]],[[194853,194853],"mapped",[29333]],[[194854,194854],"mapped",[149301]],[[194855,194855],"mapped",[149524]],[[194856,194856],"mapped",[29562]],[[194857,194857],"mapped",[29579]],[[194858,194858],"mapped",[16044]],[[194859,194859],"mapped",[29605]],[[194860,194861],"mapped",[16056]],[[194862,194862],"mapped",[29767]],[[194863,194863],"mapped",[29788]],[[194864,194864],"mapped",[29809]],[[194865,194865],"mapped",[29829]],[[194866,194866],"mapped",[29898]],[[194867,194867],"mapped",[16155]],[[194868,194868],"mapped",[29988]],[[194869,194869],"mapped",[150582]],[[194870,194870],"mapped",[30014]],[[194871,194871],"mapped",[150674]],[[194872,194872],"mapped",[30064]],[[194873,194873],"mapped",[139679]],[[194874,194874],"mapped",[30224]],[[194875,194875],"mapped",[151457]],[[194876,194876],"mapped",[151480]],[[194877,194877],"mapped",[151620]],[[194878,194878],"mapped",[16380]],[[194879,194879],"mapped",[16392]],[[194880,194880],"mapped",[30452]],[[194881,194881],"mapped",[151795]],[[194882,194882],"mapped",[151794]],[[194883,194883],"mapped",[151833]],[[194884,194884],"mapped",[151859]],[[194885,194885],"mapped",[30494]],[[194886,194887],"mapped",[30495]],[[194888,194888],"mapped",[30538]],[[194889,194889],"mapped",[16441]],[[194890,194890],"mapped",[30603]],[[194891,194891],"mapped",[16454]],[[194892,194892],"mapped",[16534]],[[194893,194893],"mapped",[152605]],[[194894,194894],"mapped",[30798]],[[194895,194895],"mapped",[30860]],[[194896,194896],"mapped",[30924]],[[194897,194897],"mapped",[16611]],[[194898,194898],"mapped",[153126]],[[194899,194899],"mapped",[31062]],[[194900,194900],"mapped",[153242]],[[194901,194901],"mapped",[153285]],[[194902,194902],"mapped",[31119]],[[194903,194903],"mapped",[31211]],[[194904,194904],"mapped",[16687]],[[194905,194905],"mapped",[31296]],[[194906,194906],"mapped",[31306]],[[194907,194907],"mapped",[31311]],[[194908,194908],"mapped",[153980]],[[194909,194910],"mapped",[154279]],[[194911,194911],"disallowed"],[[194912,194912],"mapped",[16898]],[[194913,194913],"mapped",[154539]],[[194914,194914],"mapped",[31686]],[[194915,194915],"mapped",[31689]],[[194916,194916],"mapped",[16935]],[[194917,194917],"mapped",[154752]],[[194918,194918],"mapped",[31954]],[[194919,194919],"mapped",[17056]],[[194920,194920],"mapped",[31976]],[[194921,194921],"mapped",[31971]],[[194922,194922],"mapped",[32000]],[[194923,194923],"mapped",[155526]],[[194924,194924],"mapped",[32099]],[[194925,194925],"mapped",[17153]],[[194926,194926],"mapped",[32199]],[[194927,194927],"mapped",[32258]],[[194928,194928],"mapped",[32325]],[[194929,194929],"mapped",[17204]],[[194930,194930],"mapped",[156200]],[[194931,194931],"mapped",[156231]],[[194932,194932],"mapped",[17241]],[[194933,194933],"mapped",[156377]],[[194934,194934],"mapped",[32634]],[[194935,194935],"mapped",[156478]],[[194936,194936],"mapped",[32661]],[[194937,194937],"mapped",[32762]],[[194938,194938],"mapped",[32773]],[[194939,194939],"mapped",[156890]],[[194940,194940],"mapped",[156963]],[[194941,194941],"mapped",[32864]],[[194942,194942],"mapped",[157096]],[[194943,194943],"mapped",[32880]],[[194944,194944],"mapped",[144223]],[[194945,194945],"mapped",[17365]],[[194946,194946],"mapped",[32946]],[[194947,194947],"mapped",[33027]],[[194948,194948],"mapped",[17419]],[[194949,194949],"mapped",[33086]],[[194950,194950],"mapped",[23221]],[[194951,194951],"mapped",[157607]],[[194952,194952],"mapped",[157621]],[[194953,194953],"mapped",[144275]],[[194954,194954],"mapped",[144284]],[[194955,194955],"mapped",[33281]],[[194956,194956],"mapped",[33284]],[[194957,194957],"mapped",[36766]],[[194958,194958],"mapped",[17515]],[[194959,194959],"mapped",[33425]],[[194960,194960],"mapped",[33419]],[[194961,194961],"mapped",[33437]],[[194962,194962],"mapped",[21171]],[[194963,194963],"mapped",[33457]],[[194964,194964],"mapped",[33459]],[[194965,194965],"mapped",[33469]],[[194966,194966],"mapped",[33510]],[[194967,194967],"mapped",[158524]],[[194968,194968],"mapped",[33509]],[[194969,194969],"mapped",[33565]],[[194970,194970],"mapped",[33635]],[[194971,194971],"mapped",[33709]],[[194972,194972],"mapped",[33571]],[[194973,194973],"mapped",[33725]],[[194974,194974],"mapped",[33767]],[[194975,194975],"mapped",[33879]],[[194976,194976],"mapped",[33619]],[[194977,194977],"mapped",[33738]],[[194978,194978],"mapped",[33740]],[[194979,194979],"mapped",[33756]],[[194980,194980],"mapped",[158774]],[[194981,194981],"mapped",[159083]],[[194982,194982],"mapped",[158933]],[[194983,194983],"mapped",[17707]],[[194984,194984],"mapped",[34033]],[[194985,194985],"mapped",[34035]],[[194986,194986],"mapped",[34070]],[[194987,194987],"mapped",[160714]],[[194988,194988],"mapped",[34148]],[[194989,194989],"mapped",[159532]],[[194990,194990],"mapped",[17757]],[[194991,194991],"mapped",[17761]],[[194992,194992],"mapped",[159665]],[[194993,194993],"mapped",[159954]],[[194994,194994],"mapped",[17771]],[[194995,194995],"mapped",[34384]],[[194996,194996],"mapped",[34396]],[[194997,194997],"mapped",[34407]],[[194998,194998],"mapped",[34409]],[[194999,194999],"mapped",[34473]],[[195000,195000],"mapped",[34440]],[[195001,195001],"mapped",[34574]],[[195002,195002],"mapped",[34530]],[[195003,195003],"mapped",[34681]],[[195004,195004],"mapped",[34600]],[[195005,195005],"mapped",[34667]],[[195006,195006],"mapped",[34694]],[[195007,195007],"disallowed"],[[195008,195008],"mapped",[34785]],[[195009,195009],"mapped",[34817]],[[195010,195010],"mapped",[17913]],[[195011,195011],"mapped",[34912]],[[195012,195012],"mapped",[34915]],[[195013,195013],"mapped",[161383]],[[195014,195014],"mapped",[35031]],[[195015,195015],"mapped",[35038]],[[195016,195016],"mapped",[17973]],[[195017,195017],"mapped",[35066]],[[195018,195018],"mapped",[13499]],[[195019,195019],"mapped",[161966]],[[195020,195020],"mapped",[162150]],[[195021,195021],"mapped",[18110]],[[195022,195022],"mapped",[18119]],[[195023,195023],"mapped",[35488]],[[195024,195024],"mapped",[35565]],[[195025,195025],"mapped",[35722]],[[195026,195026],"mapped",[35925]],[[195027,195027],"mapped",[162984]],[[195028,195028],"mapped",[36011]],[[195029,195029],"mapped",[36033]],[[195030,195030],"mapped",[36123]],[[195031,195031],"mapped",[36215]],[[195032,195032],"mapped",[163631]],[[195033,195033],"mapped",[133124]],[[195034,195034],"mapped",[36299]],[[195035,195035],"mapped",[36284]],[[195036,195036],"mapped",[36336]],[[195037,195037],"mapped",[133342]],[[195038,195038],"mapped",[36564]],[[195039,195039],"mapped",[36664]],[[195040,195040],"mapped",[165330]],[[195041,195041],"mapped",[165357]],[[195042,195042],"mapped",[37012]],[[195043,195043],"mapped",[37105]],[[195044,195044],"mapped",[37137]],[[195045,195045],"mapped",[165678]],[[195046,195046],"mapped",[37147]],[[195047,195047],"mapped",[37432]],[[195048,195048],"mapped",[37591]],[[195049,195049],"mapped",[37592]],[[195050,195050],"mapped",[37500]],[[195051,195051],"mapped",[37881]],[[195052,195052],"mapped",[37909]],[[195053,195053],"mapped",[166906]],[[195054,195054],"mapped",[38283]],[[195055,195055],"mapped",[18837]],[[195056,195056],"mapped",[38327]],[[195057,195057],"mapped",[167287]],[[195058,195058],"mapped",[18918]],[[195059,195059],"mapped",[38595]],[[195060,195060],"mapped",[23986]],[[195061,195061],"mapped",[38691]],[[195062,195062],"mapped",[168261]],[[195063,195063],"mapped",[168474]],[[195064,195064],"mapped",[19054]],[[195065,195065],"mapped",[19062]],[[195066,195066],"mapped",[38880]],[[195067,195067],"mapped",[168970]],[[195068,195068],"mapped",[19122]],[[195069,195069],"mapped",[169110]],[[195070,195071],"mapped",[38923]],[[195072,195072],"mapped",[38953]],[[195073,195073],"mapped",[169398]],[[195074,195074],"mapped",[39138]],[[195075,195075],"mapped",[19251]],[[195076,195076],"mapped",[39209]],[[195077,195077],"mapped",[39335]],[[195078,195078],"mapped",[39362]],[[195079,195079],"mapped",[39422]],[[195080,195080],"mapped",[19406]],[[195081,195081],"mapped",[170800]],[[195082,195082],"mapped",[39698]],[[195083,195083],"mapped",[40000]],[[195084,195084],"mapped",[40189]],[[195085,195085],"mapped",[19662]],[[195086,195086],"mapped",[19693]],[[195087,195087],"mapped",[40295]],[[195088,195088],"mapped",[172238]],[[195089,195089],"mapped",[19704]],[[195090,195090],"mapped",[172293]],[[195091,195091],"mapped",[172558]],[[195092,195092],"mapped",[172689]],[[195093,195093],"mapped",[40635]],[[195094,195094],"mapped",[19798]],[[195095,195095],"mapped",[40697]],[[195096,195096],"mapped",[40702]],[[195097,195097],"mapped",[40709]],[[195098,195098],"mapped",[40719]],[[195099,195099],"mapped",[40726]],[[195100,195100],"mapped",[40763]],[[195101,195101],"mapped",[173568]],[[195102,196605],"disallowed"],[[196606,196607],"disallowed"],[[196608,262141],"disallowed"],[[262142,262143],"disallowed"],[[262144,327677],"disallowed"],[[327678,327679],"disallowed"],[[327680,393213],"disallowed"],[[393214,393215],"disallowed"],[[393216,458749],"disallowed"],[[458750,458751],"disallowed"],[[458752,524285],"disallowed"],[[524286,524287],"disallowed"],[[524288,589821],"disallowed"],[[589822,589823],"disallowed"],[[589824,655357],"disallowed"],[[655358,655359],"disallowed"],[[655360,720893],"disallowed"],[[720894,720895],"disallowed"],[[720896,786429],"disallowed"],[[786430,786431],"disallowed"],[[786432,851965],"disallowed"],[[851966,851967],"disallowed"],[[851968,917501],"disallowed"],[[917502,917503],"disallowed"],[[917504,917504],"disallowed"],[[917505,917505],"disallowed"],[[917506,917535],"disallowed"],[[917536,917631],"disallowed"],[[917632,917759],"disallowed"],[[917760,917999],"ignored"],[[918000,983037],"disallowed"],[[983038,983039],"disallowed"],[[983040,1048573],"disallowed"],[[1048574,1048575],"disallowed"],[[1048576,1114109],"disallowed"],[[1114110,1114111],"disallowed"]]')}};var __webpack_module_cache__={};function __nccwpck_require__(e){var p=__webpack_module_cache__[e];if(p!==undefined){return p.exports}var a=__webpack_module_cache__[e]={exports:{}};var d=true;try{__webpack_modules__[e].call(a.exports,a,a.exports,__nccwpck_require__);d=false}finally{if(d)delete __webpack_module_cache__[e]}return a.exports}(()=>{__nccwpck_require__.n=e=>{var p=e&&e.__esModule?()=>e["default"]:()=>e;__nccwpck_require__.d(p,{a:p});return p}})();(()=>{__nccwpck_require__.d=(e,p)=>{for(var a in p){if(__nccwpck_require__.o(p,a)&&!__nccwpck_require__.o(e,a)){Object.defineProperty(e,a,{enumerable:true,get:p[a]})}}}})();(()=>{__nccwpck_require__.o=(e,p)=>Object.prototype.hasOwnProperty.call(e,p)})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=new URL(".",import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/)?1:0,-1)+"/";var __webpack_exports__={};(()=>{var e=__nccwpck_require__(2186);var p=__nccwpck_require__.n(e);var a=__nccwpck_require__(5438);var d=__nccwpck_require__.n(a);async function run(){const p=process.env.GITHUB_TOKEN;if(!p)throw new Error("No GITHUB_TOKEN provided");const{issue:d}=a.context.payload;if(!d)return console.log("Not an issue, exiting");const{body:t,number:r,title:s}=d;if(!r)return console.log("Could not get issue number, exiting");if(!t)return console.log("Could not get issue body, exiting");if(!s)return console.log("Could not get issue title, exiting");const{rest:i}=(0,a.getOctokit)(p);const o=await loadAreaLabels(i);(0,e.debug)(`Loaded labels: ${Array.from(o.keys()).join(", ")}`);const n=[];const l=t.split("Which area(s) of Next.js are affected? (leave empty if unsure)")[1]?.split("Link to the code that reproduces this issue")[0];if(!l){console.log(`Issue #${r} does not contain a match section, likely not a bug template, exiting`);return}(0,e.debug)(`Match section: ${l}`);for(const[e,p]of o.entries()){if(l.includes(p)){n.push(e)}}(0,e.debug)(`Labels to add: ${n.join(", ")}`);if(!n.length)return console.log("No labels to add, exiting");await addLabels(i,r,n);(0,e.debug)(`Added labels to issue #${r}: ${n.join(", ")}`)}async function loadAreaLabels(e){try{const{data:p}=await e.issues.listLabelsForRepo({owner:a.context.repo.owner,repo:a.context.repo.repo,per_page:100});const d=new Map;for(const e of p){if(e.name.startsWith("area:")&&e.description){d.set(e.name,e.description)}}return d}catch(e){console.error("Error loading labels: "+e);throw e}}async function addLabels(p,d,t){try{const r=t.map((e=>`"${e}"`)).join(", ");(0,e.debug)(`Adding label(s) (${r}) to issue #${d}`);return await p.issues.addLabels({owner:a.context.repo.owner,repo:a.context.repo.repo,issue_number:d,labels:t})}catch(e){console.error(`Could not add label(s) ${t} to issue #${d}`);throw e}}run().catch(e.setFailed)})(); \ No newline at end of file +import { createRequire as __WEBPACK_EXTERNAL_createRequire } from 'module' +var __webpack_modules__ = { + 7351: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + Object.defineProperty(p, '__esModule', { value: true }) + p.issue = p.issueCommand = void 0 + const s = r(a(2037)) + const i = a(5278) + function issueCommand(e, p, a) { + const d = new Command(e, p, a) + process.stdout.write(d.toString() + s.EOL) + } + p.issueCommand = issueCommand + function issue(e, p = '') { + issueCommand(e, {}, p) + } + p.issue = issue + const o = '::' + class Command { + constructor(e, p, a) { + if (!e) { + e = 'missing.command' + } + this.command = e + this.properties = p + this.message = a + } + toString() { + let e = o + this.command + if (this.properties && Object.keys(this.properties).length > 0) { + e += ' ' + let p = true + for (const a in this.properties) { + if (this.properties.hasOwnProperty(a)) { + const d = this.properties[a] + if (d) { + if (p) { + p = false + } else { + e += ',' + } + e += `${a}=${escapeProperty(d)}` + } + } + } + } + e += `${o}${escapeData(this.message)}` + return e + } + } + function escapeData(e) { + return i + .toCommandValue(e) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A') + } + function escapeProperty(e) { + return i + .toCommandValue(e) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A') + .replace(/:/g, '%3A') + .replace(/,/g, '%2C') + } + }, + 2186: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + var s = + (this && this.__awaiter) || + function (e, p, a, d) { + function adopt(e) { + return e instanceof a + ? e + : new a(function (p) { + p(e) + }) + } + return new (a || (a = Promise))(function (a, t) { + function fulfilled(e) { + try { + step(d.next(e)) + } catch (e) { + t(e) + } + } + function rejected(e) { + try { + step(d['throw'](e)) + } catch (e) { + t(e) + } + } + function step(e) { + e.done ? a(e.value) : adopt(e.value).then(fulfilled, rejected) + } + step((d = d.apply(e, p || [])).next()) + }) + } + Object.defineProperty(p, '__esModule', { value: true }) + p.getIDToken = + p.getState = + p.saveState = + p.group = + p.endGroup = + p.startGroup = + p.info = + p.notice = + p.warning = + p.error = + p.debug = + p.isDebug = + p.setFailed = + p.setCommandEcho = + p.setOutput = + p.getBooleanInput = + p.getMultilineInput = + p.getInput = + p.addPath = + p.setSecret = + p.exportVariable = + p.ExitCode = + void 0 + const i = a(7351) + const o = a(717) + const n = a(5278) + const l = r(a(2037)) + const m = r(a(1017)) + const u = a(8041) + var c + ;(function (e) { + e[(e['Success'] = 0)] = 'Success' + e[(e['Failure'] = 1)] = 'Failure' + })((c = p.ExitCode || (p.ExitCode = {}))) + function exportVariable(e, p) { + const a = n.toCommandValue(p) + process.env[e] = a + const d = process.env['GITHUB_ENV'] || '' + if (d) { + return o.issueFileCommand('ENV', o.prepareKeyValueMessage(e, p)) + } + i.issueCommand('set-env', { name: e }, a) + } + p.exportVariable = exportVariable + function setSecret(e) { + i.issueCommand('add-mask', {}, e) + } + p.setSecret = setSecret + function addPath(e) { + const p = process.env['GITHUB_PATH'] || '' + if (p) { + o.issueFileCommand('PATH', e) + } else { + i.issueCommand('add-path', {}, e) + } + process.env['PATH'] = `${e}${m.delimiter}${process.env['PATH']}` + } + p.addPath = addPath + function getInput(e, p) { + const a = process.env[`INPUT_${e.replace(/ /g, '_').toUpperCase()}`] || '' + if (p && p.required && !a) { + throw new Error(`Input required and not supplied: ${e}`) + } + if (p && p.trimWhitespace === false) { + return a + } + return a.trim() + } + p.getInput = getInput + function getMultilineInput(e, p) { + const a = getInput(e, p) + .split('\n') + .filter((e) => e !== '') + if (p && p.trimWhitespace === false) { + return a + } + return a.map((e) => e.trim()) + } + p.getMultilineInput = getMultilineInput + function getBooleanInput(e, p) { + const a = ['true', 'True', 'TRUE'] + const d = ['false', 'False', 'FALSE'] + const t = getInput(e, p) + if (a.includes(t)) return true + if (d.includes(t)) return false + throw new TypeError( + `Input does not meet YAML 1.2 "Core Schema" specification: ${e}\n` + + `Support boolean input list: \`true | True | TRUE | false | False | FALSE\`` + ) + } + p.getBooleanInput = getBooleanInput + function setOutput(e, p) { + const a = process.env['GITHUB_OUTPUT'] || '' + if (a) { + return o.issueFileCommand('OUTPUT', o.prepareKeyValueMessage(e, p)) + } + process.stdout.write(l.EOL) + i.issueCommand('set-output', { name: e }, n.toCommandValue(p)) + } + p.setOutput = setOutput + function setCommandEcho(e) { + i.issue('echo', e ? 'on' : 'off') + } + p.setCommandEcho = setCommandEcho + function setFailed(e) { + process.exitCode = c.Failure + error(e) + } + p.setFailed = setFailed + function isDebug() { + return process.env['RUNNER_DEBUG'] === '1' + } + p.isDebug = isDebug + function debug(e) { + i.issueCommand('debug', {}, e) + } + p.debug = debug + function error(e, p = {}) { + i.issueCommand( + 'error', + n.toCommandProperties(p), + e instanceof Error ? e.toString() : e + ) + } + p.error = error + function warning(e, p = {}) { + i.issueCommand( + 'warning', + n.toCommandProperties(p), + e instanceof Error ? e.toString() : e + ) + } + p.warning = warning + function notice(e, p = {}) { + i.issueCommand( + 'notice', + n.toCommandProperties(p), + e instanceof Error ? e.toString() : e + ) + } + p.notice = notice + function info(e) { + process.stdout.write(e + l.EOL) + } + p.info = info + function startGroup(e) { + i.issue('group', e) + } + p.startGroup = startGroup + function endGroup() { + i.issue('endgroup') + } + p.endGroup = endGroup + function group(e, p) { + return s(this, void 0, void 0, function* () { + startGroup(e) + let a + try { + a = yield p() + } finally { + endGroup() + } + return a + }) + } + p.group = group + function saveState(e, p) { + const a = process.env['GITHUB_STATE'] || '' + if (a) { + return o.issueFileCommand('STATE', o.prepareKeyValueMessage(e, p)) + } + i.issueCommand('save-state', { name: e }, n.toCommandValue(p)) + } + p.saveState = saveState + function getState(e) { + return process.env[`STATE_${e}`] || '' + } + p.getState = getState + function getIDToken(e) { + return s(this, void 0, void 0, function* () { + return yield u.OidcClient.getIDToken(e) + }) + } + p.getIDToken = getIDToken + var v = a(1327) + Object.defineProperty(p, 'summary', { + enumerable: true, + get: function () { + return v.summary + }, + }) + var h = a(1327) + Object.defineProperty(p, 'markdownSummary', { + enumerable: true, + get: function () { + return h.markdownSummary + }, + }) + var g = a(2981) + Object.defineProperty(p, 'toPosixPath', { + enumerable: true, + get: function () { + return g.toPosixPath + }, + }) + Object.defineProperty(p, 'toWin32Path', { + enumerable: true, + get: function () { + return g.toWin32Path + }, + }) + Object.defineProperty(p, 'toPlatformPath', { + enumerable: true, + get: function () { + return g.toPlatformPath + }, + }) + }, + 717: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + Object.defineProperty(p, '__esModule', { value: true }) + p.prepareKeyValueMessage = p.issueFileCommand = void 0 + const s = r(a(7147)) + const i = r(a(2037)) + const o = a(5840) + const n = a(5278) + function issueFileCommand(e, p) { + const a = process.env[`GITHUB_${e}`] + if (!a) { + throw new Error( + `Unable to find environment variable for file command ${e}` + ) + } + if (!s.existsSync(a)) { + throw new Error(`Missing file at path: ${a}`) + } + s.appendFileSync(a, `${n.toCommandValue(p)}${i.EOL}`, { + encoding: 'utf8', + }) + } + p.issueFileCommand = issueFileCommand + function prepareKeyValueMessage(e, p) { + const a = `ghadelimiter_${o.v4()}` + const d = n.toCommandValue(p) + if (e.includes(a)) { + throw new Error( + `Unexpected input: name should not contain the delimiter "${a}"` + ) + } + if (d.includes(a)) { + throw new Error( + `Unexpected input: value should not contain the delimiter "${a}"` + ) + } + return `${e}<<${a}${i.EOL}${d}${i.EOL}${a}` + } + p.prepareKeyValueMessage = prepareKeyValueMessage + }, + 8041: function (e, p, a) { + var d = + (this && this.__awaiter) || + function (e, p, a, d) { + function adopt(e) { + return e instanceof a + ? e + : new a(function (p) { + p(e) + }) + } + return new (a || (a = Promise))(function (a, t) { + function fulfilled(e) { + try { + step(d.next(e)) + } catch (e) { + t(e) + } + } + function rejected(e) { + try { + step(d['throw'](e)) + } catch (e) { + t(e) + } + } + function step(e) { + e.done ? a(e.value) : adopt(e.value).then(fulfilled, rejected) + } + step((d = d.apply(e, p || [])).next()) + }) + } + Object.defineProperty(p, '__esModule', { value: true }) + p.OidcClient = void 0 + const t = a(6255) + const r = a(5526) + const s = a(2186) + class OidcClient { + static createHttpClient(e = true, p = 10) { + const a = { allowRetries: e, maxRetries: p } + return new t.HttpClient( + 'actions/oidc-client', + [new r.BearerCredentialHandler(OidcClient.getRequestToken())], + a + ) + } + static getRequestToken() { + const e = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] + if (!e) { + throw new Error( + 'Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable' + ) + } + return e + } + static getIDTokenUrl() { + const e = process.env['ACTIONS_ID_TOKEN_REQUEST_URL'] + if (!e) { + throw new Error( + 'Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable' + ) + } + return e + } + static getCall(e) { + var p + return d(this, void 0, void 0, function* () { + const a = OidcClient.createHttpClient() + const d = yield a.getJson(e).catch((e) => { + throw new Error( + `Failed to get ID Token. \n \n Error Code : ${e.statusCode}\n \n Error Message: ${e.result.message}` + ) + }) + const t = (p = d.result) === null || p === void 0 ? void 0 : p.value + if (!t) { + throw new Error('Response json body do not have ID Token field') + } + return t + }) + } + static getIDToken(e) { + return d(this, void 0, void 0, function* () { + try { + let p = OidcClient.getIDTokenUrl() + if (e) { + const a = encodeURIComponent(e) + p = `${p}&audience=${a}` + } + s.debug(`ID token url is ${p}`) + const a = yield OidcClient.getCall(p) + s.setSecret(a) + return a + } catch (e) { + throw new Error(`Error message: ${e.message}`) + } + }) + } + } + p.OidcClient = OidcClient + }, + 2981: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + Object.defineProperty(p, '__esModule', { value: true }) + p.toPlatformPath = p.toWin32Path = p.toPosixPath = void 0 + const s = r(a(1017)) + function toPosixPath(e) { + return e.replace(/[\\]/g, '/') + } + p.toPosixPath = toPosixPath + function toWin32Path(e) { + return e.replace(/[/]/g, '\\') + } + p.toWin32Path = toWin32Path + function toPlatformPath(e) { + return e.replace(/[/\\]/g, s.sep) + } + p.toPlatformPath = toPlatformPath + }, + 1327: function (e, p, a) { + var d = + (this && this.__awaiter) || + function (e, p, a, d) { + function adopt(e) { + return e instanceof a + ? e + : new a(function (p) { + p(e) + }) + } + return new (a || (a = Promise))(function (a, t) { + function fulfilled(e) { + try { + step(d.next(e)) + } catch (e) { + t(e) + } + } + function rejected(e) { + try { + step(d['throw'](e)) + } catch (e) { + t(e) + } + } + function step(e) { + e.done ? a(e.value) : adopt(e.value).then(fulfilled, rejected) + } + step((d = d.apply(e, p || [])).next()) + }) + } + Object.defineProperty(p, '__esModule', { value: true }) + p.summary = + p.markdownSummary = + p.SUMMARY_DOCS_URL = + p.SUMMARY_ENV_VAR = + void 0 + const t = a(2037) + const r = a(7147) + const { access: s, appendFile: i, writeFile: o } = r.promises + p.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY' + p.SUMMARY_DOCS_URL = + 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary' + class Summary { + constructor() { + this._buffer = '' + } + filePath() { + return d(this, void 0, void 0, function* () { + if (this._filePath) { + return this._filePath + } + const e = process.env[p.SUMMARY_ENV_VAR] + if (!e) { + throw new Error( + `Unable to find environment variable for $${p.SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.` + ) + } + try { + yield s(e, r.constants.R_OK | r.constants.W_OK) + } catch (p) { + throw new Error( + `Unable to access summary file: '${e}'. Check if the file has correct read/write permissions.` + ) + } + this._filePath = e + return this._filePath + }) + } + wrap(e, p, a = {}) { + const d = Object.entries(a) + .map(([e, p]) => ` ${e}="${p}"`) + .join('') + if (!p) { + return `<${e}${d}>` + } + return `<${e}${d}>${p}` + } + write(e) { + return d(this, void 0, void 0, function* () { + const p = !!(e === null || e === void 0 ? void 0 : e.overwrite) + const a = yield this.filePath() + const d = p ? o : i + yield d(a, this._buffer, { encoding: 'utf8' }) + return this.emptyBuffer() + }) + } + clear() { + return d(this, void 0, void 0, function* () { + return this.emptyBuffer().write({ overwrite: true }) + }) + } + stringify() { + return this._buffer + } + isEmptyBuffer() { + return this._buffer.length === 0 + } + emptyBuffer() { + this._buffer = '' + return this + } + addRaw(e, p = false) { + this._buffer += e + return p ? this.addEOL() : this + } + addEOL() { + return this.addRaw(t.EOL) + } + addCodeBlock(e, p) { + const a = Object.assign({}, p && { lang: p }) + const d = this.wrap('pre', this.wrap('code', e), a) + return this.addRaw(d).addEOL() + } + addList(e, p = false) { + const a = p ? 'ol' : 'ul' + const d = e.map((e) => this.wrap('li', e)).join('') + const t = this.wrap(a, d) + return this.addRaw(t).addEOL() + } + addTable(e) { + const p = e + .map((e) => { + const p = e + .map((e) => { + if (typeof e === 'string') { + return this.wrap('td', e) + } + const { header: p, data: a, colspan: d, rowspan: t } = e + const r = p ? 'th' : 'td' + const s = Object.assign( + Object.assign({}, d && { colspan: d }), + t && { rowspan: t } + ) + return this.wrap(r, a, s) + }) + .join('') + return this.wrap('tr', p) + }) + .join('') + const a = this.wrap('table', p) + return this.addRaw(a).addEOL() + } + addDetails(e, p) { + const a = this.wrap('details', this.wrap('summary', e) + p) + return this.addRaw(a).addEOL() + } + addImage(e, p, a) { + const { width: d, height: t } = a || {} + const r = Object.assign( + Object.assign({}, d && { width: d }), + t && { height: t } + ) + const s = this.wrap('img', null, Object.assign({ src: e, alt: p }, r)) + return this.addRaw(s).addEOL() + } + addHeading(e, p) { + const a = `h${p}` + const d = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(a) ? a : 'h1' + const t = this.wrap(d, e) + return this.addRaw(t).addEOL() + } + addSeparator() { + const e = this.wrap('hr', null) + return this.addRaw(e).addEOL() + } + addBreak() { + const e = this.wrap('br', null) + return this.addRaw(e).addEOL() + } + addQuote(e, p) { + const a = Object.assign({}, p && { cite: p }) + const d = this.wrap('blockquote', e, a) + return this.addRaw(d).addEOL() + } + addLink(e, p) { + const a = this.wrap('a', e, { href: p }) + return this.addRaw(a).addEOL() + } + } + const n = new Summary() + p.markdownSummary = n + p.summary = n + }, + 5278: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + p.toCommandProperties = p.toCommandValue = void 0 + function toCommandValue(e) { + if (e === null || e === undefined) { + return '' + } else if (typeof e === 'string' || e instanceof String) { + return e + } + return JSON.stringify(e) + } + p.toCommandValue = toCommandValue + function toCommandProperties(e) { + if (!Object.keys(e).length) { + return {} + } + return { + title: e.title, + file: e.file, + line: e.startLine, + endLine: e.endLine, + col: e.startColumn, + endColumn: e.endColumn, + } + } + p.toCommandProperties = toCommandProperties + }, + 4087: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p.Context = void 0 + const d = a(7147) + const t = a(2037) + class Context { + constructor() { + var e, p, a + this.payload = {} + if (process.env.GITHUB_EVENT_PATH) { + if (d.existsSync(process.env.GITHUB_EVENT_PATH)) { + this.payload = JSON.parse( + d.readFileSync(process.env.GITHUB_EVENT_PATH, { + encoding: 'utf8', + }) + ) + } else { + const e = process.env.GITHUB_EVENT_PATH + process.stdout.write( + `GITHUB_EVENT_PATH ${e} does not exist${t.EOL}` + ) + } + } + this.eventName = process.env.GITHUB_EVENT_NAME + this.sha = process.env.GITHUB_SHA + this.ref = process.env.GITHUB_REF + this.workflow = process.env.GITHUB_WORKFLOW + this.action = process.env.GITHUB_ACTION + this.actor = process.env.GITHUB_ACTOR + this.job = process.env.GITHUB_JOB + this.runNumber = parseInt(process.env.GITHUB_RUN_NUMBER, 10) + this.runId = parseInt(process.env.GITHUB_RUN_ID, 10) + this.apiUrl = + (e = process.env.GITHUB_API_URL) !== null && e !== void 0 + ? e + : `https://api.github.com` + this.serverUrl = + (p = process.env.GITHUB_SERVER_URL) !== null && p !== void 0 + ? p + : `https://github.com` + this.graphqlUrl = + (a = process.env.GITHUB_GRAPHQL_URL) !== null && a !== void 0 + ? a + : `https://api.github.com/graphql` + } + get issue() { + const e = this.payload + return Object.assign(Object.assign({}, this.repo), { + number: (e.issue || e.pull_request || e).number, + }) + } + get repo() { + if (process.env.GITHUB_REPOSITORY) { + const [e, p] = process.env.GITHUB_REPOSITORY.split('/') + return { owner: e, repo: p } + } + if (this.payload.repository) { + return { + owner: this.payload.repository.owner.login, + repo: this.payload.repository.name, + } + } + throw new Error( + "context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'" + ) + } + } + p.Context = Context + }, + 5438: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + Object.defineProperty(p, '__esModule', { value: true }) + p.getOctokit = p.context = void 0 + const s = r(a(4087)) + const i = a(3030) + p.context = new s.Context() + function getOctokit(e, p, ...a) { + const d = i.GitHub.plugin(...a) + return new d(i.getOctokitOptions(e, p)) + } + p.getOctokit = getOctokit + }, + 7914: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + Object.defineProperty(p, '__esModule', { value: true }) + p.getApiBaseUrl = p.getProxyAgent = p.getAuthString = void 0 + const s = r(a(6255)) + function getAuthString(e, p) { + if (!e && !p.auth) { + throw new Error('Parameter token or opts.auth is required') + } else if (e && p.auth) { + throw new Error( + 'Parameters token and opts.auth may not both be specified' + ) + } + return typeof p.auth === 'string' ? p.auth : `token ${e}` + } + p.getAuthString = getAuthString + function getProxyAgent(e) { + const p = new s.HttpClient() + return p.getAgent(e) + } + p.getProxyAgent = getProxyAgent + function getApiBaseUrl() { + return process.env['GITHUB_API_URL'] || 'https://api.github.com' + } + p.getApiBaseUrl = getApiBaseUrl + }, + 3030: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + Object.defineProperty(p, '__esModule', { value: true }) + p.getOctokitOptions = p.GitHub = p.defaults = p.context = void 0 + const s = r(a(4087)) + const i = r(a(7914)) + const o = a(6762) + const n = a(3044) + const l = a(4193) + p.context = new s.Context() + const m = i.getApiBaseUrl() + p.defaults = { baseUrl: m, request: { agent: i.getProxyAgent(m) } } + p.GitHub = o.Octokit.plugin(n.restEndpointMethods, l.paginateRest).defaults( + p.defaults + ) + function getOctokitOptions(e, p) { + const a = Object.assign({}, p || {}) + const d = i.getAuthString(e, a) + if (d) { + a.auth = d + } + return a + } + p.getOctokitOptions = getOctokitOptions + }, + 5526: function (e, p) { + var a = + (this && this.__awaiter) || + function (e, p, a, d) { + function adopt(e) { + return e instanceof a + ? e + : new a(function (p) { + p(e) + }) + } + return new (a || (a = Promise))(function (a, t) { + function fulfilled(e) { + try { + step(d.next(e)) + } catch (e) { + t(e) + } + } + function rejected(e) { + try { + step(d['throw'](e)) + } catch (e) { + t(e) + } + } + function step(e) { + e.done ? a(e.value) : adopt(e.value).then(fulfilled, rejected) + } + step((d = d.apply(e, p || [])).next()) + }) + } + Object.defineProperty(p, '__esModule', { value: true }) + p.PersonalAccessTokenCredentialHandler = + p.BearerCredentialHandler = + p.BasicCredentialHandler = + void 0 + class BasicCredentialHandler { + constructor(e, p) { + this.username = e + this.password = p + } + prepareRequest(e) { + if (!e.headers) { + throw Error('The request has no headers') + } + e.headers['Authorization'] = `Basic ${Buffer.from( + `${this.username}:${this.password}` + ).toString('base64')}` + } + canHandleAuthentication() { + return false + } + handleAuthentication() { + return a(this, void 0, void 0, function* () { + throw new Error('not implemented') + }) + } + } + p.BasicCredentialHandler = BasicCredentialHandler + class BearerCredentialHandler { + constructor(e) { + this.token = e + } + prepareRequest(e) { + if (!e.headers) { + throw Error('The request has no headers') + } + e.headers['Authorization'] = `Bearer ${this.token}` + } + canHandleAuthentication() { + return false + } + handleAuthentication() { + return a(this, void 0, void 0, function* () { + throw new Error('not implemented') + }) + } + } + p.BearerCredentialHandler = BearerCredentialHandler + class PersonalAccessTokenCredentialHandler { + constructor(e) { + this.token = e + } + prepareRequest(e) { + if (!e.headers) { + throw Error('The request has no headers') + } + e.headers['Authorization'] = `Basic ${Buffer.from( + `PAT:${this.token}` + ).toString('base64')}` + } + canHandleAuthentication() { + return false + } + handleAuthentication() { + return a(this, void 0, void 0, function* () { + throw new Error('not implemented') + }) + } + } + p.PersonalAccessTokenCredentialHandler = + PersonalAccessTokenCredentialHandler + }, + 6255: function (e, p, a) { + var d = + (this && this.__createBinding) || + (Object.create + ? function (e, p, a, d) { + if (d === undefined) d = a + Object.defineProperty(e, d, { + enumerable: true, + get: function () { + return p[a] + }, + }) + } + : function (e, p, a, d) { + if (d === undefined) d = a + e[d] = p[a] + }) + var t = + (this && this.__setModuleDefault) || + (Object.create + ? function (e, p) { + Object.defineProperty(e, 'default', { enumerable: true, value: p }) + } + : function (e, p) { + e['default'] = p + }) + var r = + (this && this.__importStar) || + function (e) { + if (e && e.__esModule) return e + var p = {} + if (e != null) + for (var a in e) + if (a !== 'default' && Object.hasOwnProperty.call(e, a)) d(p, e, a) + t(p, e) + return p + } + var s = + (this && this.__awaiter) || + function (e, p, a, d) { + function adopt(e) { + return e instanceof a + ? e + : new a(function (p) { + p(e) + }) + } + return new (a || (a = Promise))(function (a, t) { + function fulfilled(e) { + try { + step(d.next(e)) + } catch (e) { + t(e) + } + } + function rejected(e) { + try { + step(d['throw'](e)) + } catch (e) { + t(e) + } + } + function step(e) { + e.done ? a(e.value) : adopt(e.value).then(fulfilled, rejected) + } + step((d = d.apply(e, p || [])).next()) + }) + } + Object.defineProperty(p, '__esModule', { value: true }) + p.HttpClient = + p.isHttps = + p.HttpClientResponse = + p.HttpClientError = + p.getProxyUrl = + p.MediaTypes = + p.Headers = + p.HttpCodes = + void 0 + const i = r(a(3685)) + const o = r(a(5687)) + const n = r(a(9835)) + const l = r(a(4294)) + var m + ;(function (e) { + e[(e['OK'] = 200)] = 'OK' + e[(e['MultipleChoices'] = 300)] = 'MultipleChoices' + e[(e['MovedPermanently'] = 301)] = 'MovedPermanently' + e[(e['ResourceMoved'] = 302)] = 'ResourceMoved' + e[(e['SeeOther'] = 303)] = 'SeeOther' + e[(e['NotModified'] = 304)] = 'NotModified' + e[(e['UseProxy'] = 305)] = 'UseProxy' + e[(e['SwitchProxy'] = 306)] = 'SwitchProxy' + e[(e['TemporaryRedirect'] = 307)] = 'TemporaryRedirect' + e[(e['PermanentRedirect'] = 308)] = 'PermanentRedirect' + e[(e['BadRequest'] = 400)] = 'BadRequest' + e[(e['Unauthorized'] = 401)] = 'Unauthorized' + e[(e['PaymentRequired'] = 402)] = 'PaymentRequired' + e[(e['Forbidden'] = 403)] = 'Forbidden' + e[(e['NotFound'] = 404)] = 'NotFound' + e[(e['MethodNotAllowed'] = 405)] = 'MethodNotAllowed' + e[(e['NotAcceptable'] = 406)] = 'NotAcceptable' + e[(e['ProxyAuthenticationRequired'] = 407)] = + 'ProxyAuthenticationRequired' + e[(e['RequestTimeout'] = 408)] = 'RequestTimeout' + e[(e['Conflict'] = 409)] = 'Conflict' + e[(e['Gone'] = 410)] = 'Gone' + e[(e['TooManyRequests'] = 429)] = 'TooManyRequests' + e[(e['InternalServerError'] = 500)] = 'InternalServerError' + e[(e['NotImplemented'] = 501)] = 'NotImplemented' + e[(e['BadGateway'] = 502)] = 'BadGateway' + e[(e['ServiceUnavailable'] = 503)] = 'ServiceUnavailable' + e[(e['GatewayTimeout'] = 504)] = 'GatewayTimeout' + })((m = p.HttpCodes || (p.HttpCodes = {}))) + var u + ;(function (e) { + e['Accept'] = 'accept' + e['ContentType'] = 'content-type' + })((u = p.Headers || (p.Headers = {}))) + var c + ;(function (e) { + e['ApplicationJson'] = 'application/json' + })((c = p.MediaTypes || (p.MediaTypes = {}))) + function getProxyUrl(e) { + const p = n.getProxyUrl(new URL(e)) + return p ? p.href : '' + } + p.getProxyUrl = getProxyUrl + const v = [ + m.MovedPermanently, + m.ResourceMoved, + m.SeeOther, + m.TemporaryRedirect, + m.PermanentRedirect, + ] + const h = [m.BadGateway, m.ServiceUnavailable, m.GatewayTimeout] + const g = ['OPTIONS', 'GET', 'DELETE', 'HEAD'] + const w = 10 + const _ = 5 + class HttpClientError extends Error { + constructor(e, p) { + super(e) + this.name = 'HttpClientError' + this.statusCode = p + Object.setPrototypeOf(this, HttpClientError.prototype) + } + } + p.HttpClientError = HttpClientError + class HttpClientResponse { + constructor(e) { + this.message = e + } + readBody() { + return s(this, void 0, void 0, function* () { + return new Promise((e) => + s(this, void 0, void 0, function* () { + let p = Buffer.alloc(0) + this.message.on('data', (e) => { + p = Buffer.concat([p, e]) + }) + this.message.on('end', () => { + e(p.toString()) + }) + }) + ) + }) + } + } + p.HttpClientResponse = HttpClientResponse + function isHttps(e) { + const p = new URL(e) + return p.protocol === 'https:' + } + p.isHttps = isHttps + class HttpClient { + constructor(e, p, a) { + this._ignoreSslError = false + this._allowRedirects = true + this._allowRedirectDowngrade = false + this._maxRedirects = 50 + this._allowRetries = false + this._maxRetries = 1 + this._keepAlive = false + this._disposed = false + this.userAgent = e + this.handlers = p || [] + this.requestOptions = a + if (a) { + if (a.ignoreSslError != null) { + this._ignoreSslError = a.ignoreSslError + } + this._socketTimeout = a.socketTimeout + if (a.allowRedirects != null) { + this._allowRedirects = a.allowRedirects + } + if (a.allowRedirectDowngrade != null) { + this._allowRedirectDowngrade = a.allowRedirectDowngrade + } + if (a.maxRedirects != null) { + this._maxRedirects = Math.max(a.maxRedirects, 0) + } + if (a.keepAlive != null) { + this._keepAlive = a.keepAlive + } + if (a.allowRetries != null) { + this._allowRetries = a.allowRetries + } + if (a.maxRetries != null) { + this._maxRetries = a.maxRetries + } + } + } + options(e, p) { + return s(this, void 0, void 0, function* () { + return this.request('OPTIONS', e, null, p || {}) + }) + } + get(e, p) { + return s(this, void 0, void 0, function* () { + return this.request('GET', e, null, p || {}) + }) + } + del(e, p) { + return s(this, void 0, void 0, function* () { + return this.request('DELETE', e, null, p || {}) + }) + } + post(e, p, a) { + return s(this, void 0, void 0, function* () { + return this.request('POST', e, p, a || {}) + }) + } + patch(e, p, a) { + return s(this, void 0, void 0, function* () { + return this.request('PATCH', e, p, a || {}) + }) + } + put(e, p, a) { + return s(this, void 0, void 0, function* () { + return this.request('PUT', e, p, a || {}) + }) + } + head(e, p) { + return s(this, void 0, void 0, function* () { + return this.request('HEAD', e, null, p || {}) + }) + } + sendStream(e, p, a, d) { + return s(this, void 0, void 0, function* () { + return this.request(e, p, a, d) + }) + } + getJson(e, p = {}) { + return s(this, void 0, void 0, function* () { + p[u.Accept] = this._getExistingOrDefaultHeader( + p, + u.Accept, + c.ApplicationJson + ) + const a = yield this.get(e, p) + return this._processResponse(a, this.requestOptions) + }) + } + postJson(e, p, a = {}) { + return s(this, void 0, void 0, function* () { + const d = JSON.stringify(p, null, 2) + a[u.Accept] = this._getExistingOrDefaultHeader( + a, + u.Accept, + c.ApplicationJson + ) + a[u.ContentType] = this._getExistingOrDefaultHeader( + a, + u.ContentType, + c.ApplicationJson + ) + const t = yield this.post(e, d, a) + return this._processResponse(t, this.requestOptions) + }) + } + putJson(e, p, a = {}) { + return s(this, void 0, void 0, function* () { + const d = JSON.stringify(p, null, 2) + a[u.Accept] = this._getExistingOrDefaultHeader( + a, + u.Accept, + c.ApplicationJson + ) + a[u.ContentType] = this._getExistingOrDefaultHeader( + a, + u.ContentType, + c.ApplicationJson + ) + const t = yield this.put(e, d, a) + return this._processResponse(t, this.requestOptions) + }) + } + patchJson(e, p, a = {}) { + return s(this, void 0, void 0, function* () { + const d = JSON.stringify(p, null, 2) + a[u.Accept] = this._getExistingOrDefaultHeader( + a, + u.Accept, + c.ApplicationJson + ) + a[u.ContentType] = this._getExistingOrDefaultHeader( + a, + u.ContentType, + c.ApplicationJson + ) + const t = yield this.patch(e, d, a) + return this._processResponse(t, this.requestOptions) + }) + } + request(e, p, a, d) { + return s(this, void 0, void 0, function* () { + if (this._disposed) { + throw new Error('Client has already been disposed.') + } + const t = new URL(p) + let r = this._prepareRequest(e, t, d) + const s = + this._allowRetries && g.includes(e) ? this._maxRetries + 1 : 1 + let i = 0 + let o + do { + o = yield this.requestRaw(r, a) + if (o && o.message && o.message.statusCode === m.Unauthorized) { + let e + for (const p of this.handlers) { + if (p.canHandleAuthentication(o)) { + e = p + break + } + } + if (e) { + return e.handleAuthentication(this, r, a) + } else { + return o + } + } + let p = this._maxRedirects + while ( + o.message.statusCode && + v.includes(o.message.statusCode) && + this._allowRedirects && + p > 0 + ) { + const s = o.message.headers['location'] + if (!s) { + break + } + const i = new URL(s) + if ( + t.protocol === 'https:' && + t.protocol !== i.protocol && + !this._allowRedirectDowngrade + ) { + throw new Error( + 'Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.' + ) + } + yield o.readBody() + if (i.hostname !== t.hostname) { + for (const e in d) { + if (e.toLowerCase() === 'authorization') { + delete d[e] + } + } + } + r = this._prepareRequest(e, i, d) + o = yield this.requestRaw(r, a) + p-- + } + if (!o.message.statusCode || !h.includes(o.message.statusCode)) { + return o + } + i += 1 + if (i < s) { + yield o.readBody() + yield this._performExponentialBackoff(i) + } + } while (i < s) + return o + }) + } + dispose() { + if (this._agent) { + this._agent.destroy() + } + this._disposed = true + } + requestRaw(e, p) { + return s(this, void 0, void 0, function* () { + return new Promise((a, d) => { + function callbackForResult(e, p) { + if (e) { + d(e) + } else if (!p) { + d(new Error('Unknown error')) + } else { + a(p) + } + } + this.requestRawWithCallback(e, p, callbackForResult) + }) + }) + } + requestRawWithCallback(e, p, a) { + if (typeof p === 'string') { + if (!e.options.headers) { + e.options.headers = {} + } + e.options.headers['Content-Length'] = Buffer.byteLength(p, 'utf8') + } + let d = false + function handleResult(e, p) { + if (!d) { + d = true + a(e, p) + } + } + const t = e.httpModule.request(e.options, (e) => { + const p = new HttpClientResponse(e) + handleResult(undefined, p) + }) + let r + t.on('socket', (e) => { + r = e + }) + t.setTimeout(this._socketTimeout || 3 * 6e4, () => { + if (r) { + r.end() + } + handleResult(new Error(`Request timeout: ${e.options.path}`)) + }) + t.on('error', function (e) { + handleResult(e) + }) + if (p && typeof p === 'string') { + t.write(p, 'utf8') + } + if (p && typeof p !== 'string') { + p.on('close', function () { + t.end() + }) + p.pipe(t) + } else { + t.end() + } + } + getAgent(e) { + const p = new URL(e) + return this._getAgent(p) + } + _prepareRequest(e, p, a) { + const d = {} + d.parsedUrl = p + const t = d.parsedUrl.protocol === 'https:' + d.httpModule = t ? o : i + const r = t ? 443 : 80 + d.options = {} + d.options.host = d.parsedUrl.hostname + d.options.port = d.parsedUrl.port ? parseInt(d.parsedUrl.port) : r + d.options.path = + (d.parsedUrl.pathname || '') + (d.parsedUrl.search || '') + d.options.method = e + d.options.headers = this._mergeHeaders(a) + if (this.userAgent != null) { + d.options.headers['user-agent'] = this.userAgent + } + d.options.agent = this._getAgent(d.parsedUrl) + if (this.handlers) { + for (const e of this.handlers) { + e.prepareRequest(d.options) + } + } + return d + } + _mergeHeaders(e) { + if (this.requestOptions && this.requestOptions.headers) { + return Object.assign( + {}, + lowercaseKeys(this.requestOptions.headers), + lowercaseKeys(e || {}) + ) + } + return lowercaseKeys(e || {}) + } + _getExistingOrDefaultHeader(e, p, a) { + let d + if (this.requestOptions && this.requestOptions.headers) { + d = lowercaseKeys(this.requestOptions.headers)[p] + } + return e[p] || d || a + } + _getAgent(e) { + let p + const a = n.getProxyUrl(e) + const d = a && a.hostname + if (this._keepAlive && d) { + p = this._proxyAgent + } + if (this._keepAlive && !d) { + p = this._agent + } + if (p) { + return p + } + const t = e.protocol === 'https:' + let r = 100 + if (this.requestOptions) { + r = this.requestOptions.maxSockets || i.globalAgent.maxSockets + } + if (a && a.hostname) { + const e = { + maxSockets: r, + keepAlive: this._keepAlive, + proxy: Object.assign( + Object.assign( + {}, + (a.username || a.password) && { + proxyAuth: `${a.username}:${a.password}`, + } + ), + { host: a.hostname, port: a.port } + ), + } + let d + const s = a.protocol === 'https:' + if (t) { + d = s ? l.httpsOverHttps : l.httpsOverHttp + } else { + d = s ? l.httpOverHttps : l.httpOverHttp + } + p = d(e) + this._proxyAgent = p + } + if (this._keepAlive && !p) { + const e = { keepAlive: this._keepAlive, maxSockets: r } + p = t ? new o.Agent(e) : new i.Agent(e) + this._agent = p + } + if (!p) { + p = t ? o.globalAgent : i.globalAgent + } + if (t && this._ignoreSslError) { + p.options = Object.assign(p.options || {}, { + rejectUnauthorized: false, + }) + } + return p + } + _performExponentialBackoff(e) { + return s(this, void 0, void 0, function* () { + e = Math.min(w, e) + const p = _ * Math.pow(2, e) + return new Promise((e) => setTimeout(() => e(), p)) + }) + } + _processResponse(e, p) { + return s(this, void 0, void 0, function* () { + return new Promise((a, d) => + s(this, void 0, void 0, function* () { + const t = e.message.statusCode || 0 + const r = { statusCode: t, result: null, headers: {} } + if (t === m.NotFound) { + a(r) + } + function dateTimeDeserializer(e, p) { + if (typeof p === 'string') { + const e = new Date(p) + if (!isNaN(e.valueOf())) { + return e + } + } + return p + } + let s + let i + try { + i = yield e.readBody() + if (i && i.length > 0) { + if (p && p.deserializeDates) { + s = JSON.parse(i, dateTimeDeserializer) + } else { + s = JSON.parse(i) + } + r.result = s + } + r.headers = e.message.headers + } catch (e) {} + if (t > 299) { + let e + if (s && s.message) { + e = s.message + } else if (i && i.length > 0) { + e = i + } else { + e = `Failed request: (${t})` + } + const p = new HttpClientError(e, t) + p.result = r.result + d(p) + } else { + a(r) + } + }) + ) + }) + } + } + p.HttpClient = HttpClient + const lowercaseKeys = (e) => + Object.keys(e).reduce((p, a) => ((p[a.toLowerCase()] = e[a]), p), {}) + }, + 9835: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + p.checkBypass = p.getProxyUrl = void 0 + function getProxyUrl(e) { + const p = e.protocol === 'https:' + if (checkBypass(e)) { + return undefined + } + const a = (() => { + if (p) { + return process.env['https_proxy'] || process.env['HTTPS_PROXY'] + } else { + return process.env['http_proxy'] || process.env['HTTP_PROXY'] + } + })() + if (a) { + return new URL(a) + } else { + return undefined + } + } + p.getProxyUrl = getProxyUrl + function checkBypass(e) { + if (!e.hostname) { + return false + } + const p = e.hostname + if (isLoopbackAddress(p)) { + return true + } + const a = process.env['no_proxy'] || process.env['NO_PROXY'] || '' + if (!a) { + return false + } + let d + if (e.port) { + d = Number(e.port) + } else if (e.protocol === 'http:') { + d = 80 + } else if (e.protocol === 'https:') { + d = 443 + } + const t = [e.hostname.toUpperCase()] + if (typeof d === 'number') { + t.push(`${t[0]}:${d}`) + } + for (const e of a + .split(',') + .map((e) => e.trim().toUpperCase()) + .filter((e) => e)) { + if ( + e === '*' || + t.some( + (p) => + p === e || + p.endsWith(`.${e}`) || + (e.startsWith('.') && p.endsWith(`${e}`)) + ) + ) { + return true + } + } + return false + } + p.checkBypass = checkBypass + function isLoopbackAddress(e) { + const p = e.toLowerCase() + return ( + p === 'localhost' || + p.startsWith('127.') || + p.startsWith('[::1]') || + p.startsWith('[0:0:0:0:0:0:0:1]') + ) + } + }, + 334: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + const a = /^v1\./ + const d = /^ghs_/ + const t = /^ghu_/ + async function auth(e) { + const p = e.split(/\./).length === 3 + const r = a.test(e) || d.test(e) + const s = t.test(e) + const i = p ? 'app' : r ? 'installation' : s ? 'user-to-server' : 'oauth' + return { type: 'token', token: e, tokenType: i } + } + function withAuthorizationPrefix(e) { + if (e.split(/\./).length === 3) { + return `bearer ${e}` + } + return `token ${e}` + } + async function hook(e, p, a, d) { + const t = p.endpoint.merge(a, d) + t.headers.authorization = withAuthorizationPrefix(e) + return p(t) + } + const r = function createTokenAuth(e) { + if (!e) { + throw new Error( + '[@octokit/auth-token] No token passed to createTokenAuth' + ) + } + if (typeof e !== 'string') { + throw new Error( + '[@octokit/auth-token] Token passed to createTokenAuth is not a string' + ) + } + e = e.replace(/^(token|bearer) +/i, '') + return Object.assign(auth.bind(null, e), { hook: hook.bind(null, e) }) + } + p.createTokenAuth = r + }, + 6762: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + var d = a(5030) + var t = a(3682) + var r = a(6234) + var s = a(8467) + var i = a(334) + function _objectWithoutPropertiesLoose(e, p) { + if (e == null) return {} + var a = {} + var d = Object.keys(e) + var t, r + for (r = 0; r < d.length; r++) { + t = d[r] + if (p.indexOf(t) >= 0) continue + a[t] = e[t] + } + return a + } + function _objectWithoutProperties(e, p) { + if (e == null) return {} + var a = _objectWithoutPropertiesLoose(e, p) + var d, t + if (Object.getOwnPropertySymbols) { + var r = Object.getOwnPropertySymbols(e) + for (t = 0; t < r.length; t++) { + d = r[t] + if (p.indexOf(d) >= 0) continue + if (!Object.prototype.propertyIsEnumerable.call(e, d)) continue + a[d] = e[d] + } + } + return a + } + const o = '3.6.0' + const n = ['authStrategy'] + class Octokit { + constructor(e = {}) { + const p = new t.Collection() + const a = { + baseUrl: r.request.endpoint.DEFAULTS.baseUrl, + headers: {}, + request: Object.assign({}, e.request, { + hook: p.bind(null, 'request'), + }), + mediaType: { previews: [], format: '' }, + } + a.headers['user-agent'] = [ + e.userAgent, + `octokit-core.js/${o} ${d.getUserAgent()}`, + ] + .filter(Boolean) + .join(' ') + if (e.baseUrl) { + a.baseUrl = e.baseUrl + } + if (e.previews) { + a.mediaType.previews = e.previews + } + if (e.timeZone) { + a.headers['time-zone'] = e.timeZone + } + this.request = r.request.defaults(a) + this.graphql = s.withCustomRequest(this.request).defaults(a) + this.log = Object.assign( + { + debug: () => {}, + info: () => {}, + warn: console.warn.bind(console), + error: console.error.bind(console), + }, + e.log + ) + this.hook = p + if (!e.authStrategy) { + if (!e.auth) { + this.auth = async () => ({ type: 'unauthenticated' }) + } else { + const a = i.createTokenAuth(e.auth) + p.wrap('request', a.hook) + this.auth = a + } + } else { + const { authStrategy: a } = e, + d = _objectWithoutProperties(e, n) + const t = a( + Object.assign( + { + request: this.request, + log: this.log, + octokit: this, + octokitOptions: d, + }, + e.auth + ) + ) + p.wrap('request', t.hook) + this.auth = t + } + const l = this.constructor + l.plugins.forEach((p) => { + Object.assign(this, p(this, e)) + }) + } + static defaults(e) { + const p = class extends this { + constructor(...p) { + const a = p[0] || {} + if (typeof e === 'function') { + super(e(a)) + return + } + super( + Object.assign( + {}, + e, + a, + a.userAgent && e.userAgent + ? { userAgent: `${a.userAgent} ${e.userAgent}` } + : null + ) + ) + } + } + return p + } + static plugin(...e) { + var p + const a = this.plugins + const d = + ((p = class extends this {}), + (p.plugins = a.concat(e.filter((e) => !a.includes(e)))), + p) + return d + } + } + Octokit.VERSION = o + Octokit.plugins = [] + p.Octokit = Octokit + }, + 9440: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + var d = a(3287) + var t = a(5030) + function lowercaseKeys(e) { + if (!e) { + return {} + } + return Object.keys(e).reduce((p, a) => { + p[a.toLowerCase()] = e[a] + return p + }, {}) + } + function mergeDeep(e, p) { + const a = Object.assign({}, e) + Object.keys(p).forEach((t) => { + if (d.isPlainObject(p[t])) { + if (!(t in e)) Object.assign(a, { [t]: p[t] }) + else a[t] = mergeDeep(e[t], p[t]) + } else { + Object.assign(a, { [t]: p[t] }) + } + }) + return a + } + function removeUndefinedProperties(e) { + for (const p in e) { + if (e[p] === undefined) { + delete e[p] + } + } + return e + } + function merge(e, p, a) { + if (typeof p === 'string') { + let [e, d] = p.split(' ') + a = Object.assign(d ? { method: e, url: d } : { url: e }, a) + } else { + a = Object.assign({}, p) + } + a.headers = lowercaseKeys(a.headers) + removeUndefinedProperties(a) + removeUndefinedProperties(a.headers) + const d = mergeDeep(e || {}, a) + if (e && e.mediaType.previews.length) { + d.mediaType.previews = e.mediaType.previews + .filter((e) => !d.mediaType.previews.includes(e)) + .concat(d.mediaType.previews) + } + d.mediaType.previews = d.mediaType.previews.map((e) => + e.replace(/-preview/, '') + ) + return d + } + function addQueryParameters(e, p) { + const a = /\?/.test(e) ? '&' : '?' + const d = Object.keys(p) + if (d.length === 0) { + return e + } + return ( + e + + a + + d + .map((e) => { + if (e === 'q') { + return 'q=' + p.q.split('+').map(encodeURIComponent).join('+') + } + return `${e}=${encodeURIComponent(p[e])}` + }) + .join('&') + ) + } + const r = /\{[^}]+\}/g + function removeNonChars(e) { + return e.replace(/^\W+|\W+$/g, '').split(/,/) + } + function extractUrlVariableNames(e) { + const p = e.match(r) + if (!p) { + return [] + } + return p.map(removeNonChars).reduce((e, p) => e.concat(p), []) + } + function omit(e, p) { + return Object.keys(e) + .filter((e) => !p.includes(e)) + .reduce((p, a) => { + p[a] = e[a] + return p + }, {}) + } + function encodeReserved(e) { + return e + .split(/(%[0-9A-Fa-f]{2})/g) + .map(function (e) { + if (!/%[0-9A-Fa-f]/.test(e)) { + e = encodeURI(e).replace(/%5B/g, '[').replace(/%5D/g, ']') + } + return e + }) + .join('') + } + function encodeUnreserved(e) { + return encodeURIComponent(e).replace(/[!'()*]/g, function (e) { + return '%' + e.charCodeAt(0).toString(16).toUpperCase() + }) + } + function encodeValue(e, p, a) { + p = e === '+' || e === '#' ? encodeReserved(p) : encodeUnreserved(p) + if (a) { + return encodeUnreserved(a) + '=' + p + } else { + return p + } + } + function isDefined(e) { + return e !== undefined && e !== null + } + function isKeyOperator(e) { + return e === ';' || e === '&' || e === '?' + } + function getValues(e, p, a, d) { + var t = e[a], + r = [] + if (isDefined(t) && t !== '') { + if ( + typeof t === 'string' || + typeof t === 'number' || + typeof t === 'boolean' + ) { + t = t.toString() + if (d && d !== '*') { + t = t.substring(0, parseInt(d, 10)) + } + r.push(encodeValue(p, t, isKeyOperator(p) ? a : '')) + } else { + if (d === '*') { + if (Array.isArray(t)) { + t.filter(isDefined).forEach(function (e) { + r.push(encodeValue(p, e, isKeyOperator(p) ? a : '')) + }) + } else { + Object.keys(t).forEach(function (e) { + if (isDefined(t[e])) { + r.push(encodeValue(p, t[e], e)) + } + }) + } + } else { + const e = [] + if (Array.isArray(t)) { + t.filter(isDefined).forEach(function (a) { + e.push(encodeValue(p, a)) + }) + } else { + Object.keys(t).forEach(function (a) { + if (isDefined(t[a])) { + e.push(encodeUnreserved(a)) + e.push(encodeValue(p, t[a].toString())) + } + }) + } + if (isKeyOperator(p)) { + r.push(encodeUnreserved(a) + '=' + e.join(',')) + } else if (e.length !== 0) { + r.push(e.join(',')) + } + } + } + } else { + if (p === ';') { + if (isDefined(t)) { + r.push(encodeUnreserved(a)) + } + } else if (t === '' && (p === '&' || p === '?')) { + r.push(encodeUnreserved(a) + '=') + } else if (t === '') { + r.push('') + } + } + return r + } + function parseUrl(e) { + return { expand: expand.bind(null, e) } + } + function expand(e, p) { + var a = ['+', '#', '.', '/', ';', '?', '&'] + return e.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (e, d, t) { + if (d) { + let e = '' + const t = [] + if (a.indexOf(d.charAt(0)) !== -1) { + e = d.charAt(0) + d = d.substr(1) + } + d.split(/,/g).forEach(function (a) { + var d = /([^:\*]*)(?::(\d+)|(\*))?/.exec(a) + t.push(getValues(p, e, d[1], d[2] || d[3])) + }) + if (e && e !== '+') { + var r = ',' + if (e === '?') { + r = '&' + } else if (e !== '#') { + r = e + } + return (t.length !== 0 ? e : '') + t.join(r) + } else { + return t.join(',') + } + } else { + return encodeReserved(t) + } + }) + } + function parse(e) { + let p = e.method.toUpperCase() + let a = (e.url || '/').replace(/:([a-z]\w+)/g, '{$1}') + let d = Object.assign({}, e.headers) + let t + let r = omit(e, [ + 'method', + 'baseUrl', + 'url', + 'headers', + 'request', + 'mediaType', + ]) + const s = extractUrlVariableNames(a) + a = parseUrl(a).expand(r) + if (!/^http/.test(a)) { + a = e.baseUrl + a + } + const i = Object.keys(e) + .filter((e) => s.includes(e)) + .concat('baseUrl') + const o = omit(r, i) + const n = /application\/octet-stream/i.test(d.accept) + if (!n) { + if (e.mediaType.format) { + d.accept = d.accept + .split(/,/) + .map((p) => + p.replace( + /application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, + `application/vnd$1$2.${e.mediaType.format}` + ) + ) + .join(',') + } + if (e.mediaType.previews.length) { + const p = d.accept.match(/[\w-]+(?=-preview)/g) || [] + d.accept = p + .concat(e.mediaType.previews) + .map((p) => { + const a = e.mediaType.format ? `.${e.mediaType.format}` : '+json' + return `application/vnd.github.${p}-preview${a}` + }) + .join(',') + } + } + if (['GET', 'HEAD'].includes(p)) { + a = addQueryParameters(a, o) + } else { + if ('data' in o) { + t = o.data + } else { + if (Object.keys(o).length) { + t = o + } else { + d['content-length'] = 0 + } + } + } + if (!d['content-type'] && typeof t !== 'undefined') { + d['content-type'] = 'application/json; charset=utf-8' + } + if (['PATCH', 'PUT'].includes(p) && typeof t === 'undefined') { + t = '' + } + return Object.assign( + { method: p, url: a, headers: d }, + typeof t !== 'undefined' ? { body: t } : null, + e.request ? { request: e.request } : null + ) + } + function endpointWithDefaults(e, p, a) { + return parse(merge(e, p, a)) + } + function withDefaults(e, p) { + const a = merge(e, p) + const d = endpointWithDefaults.bind(null, a) + return Object.assign(d, { + DEFAULTS: a, + defaults: withDefaults.bind(null, a), + merge: merge.bind(null, a), + parse: parse, + }) + } + const s = '6.0.12' + const i = `octokit-endpoint.js/${s} ${t.getUserAgent()}` + const o = { + method: 'GET', + baseUrl: 'https://api.github.com', + headers: { accept: 'application/vnd.github.v3+json', 'user-agent': i }, + mediaType: { format: '', previews: [] }, + } + const n = withDefaults(null, o) + p.endpoint = n + }, + 8467: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + var d = a(6234) + var t = a(5030) + const r = '4.8.0' + function _buildMessageForResponseErrors(e) { + return ( + `Request failed due to following response errors:\n` + + e.errors.map((e) => ` - ${e.message}`).join('\n') + ) + } + class GraphqlResponseError extends Error { + constructor(e, p, a) { + super(_buildMessageForResponseErrors(a)) + this.request = e + this.headers = p + this.response = a + this.name = 'GraphqlResponseError' + this.errors = a.errors + this.data = a.data + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor) + } + } + } + const s = [ + 'method', + 'baseUrl', + 'url', + 'headers', + 'request', + 'query', + 'mediaType', + ] + const i = ['query', 'method', 'url'] + const o = /\/api\/v3\/?$/ + function graphql(e, p, a) { + if (a) { + if (typeof p === 'string' && 'query' in a) { + return Promise.reject( + new Error( + `[@octokit/graphql] "query" cannot be used as variable name` + ) + ) + } + for (const e in a) { + if (!i.includes(e)) continue + return Promise.reject( + new Error( + `[@octokit/graphql] "${e}" cannot be used as variable name` + ) + ) + } + } + const d = typeof p === 'string' ? Object.assign({ query: p }, a) : p + const t = Object.keys(d).reduce((e, p) => { + if (s.includes(p)) { + e[p] = d[p] + return e + } + if (!e.variables) { + e.variables = {} + } + e.variables[p] = d[p] + return e + }, {}) + const r = d.baseUrl || e.endpoint.DEFAULTS.baseUrl + if (o.test(r)) { + t.url = r.replace(o, '/api/graphql') + } + return e(t).then((e) => { + if (e.data.errors) { + const p = {} + for (const a of Object.keys(e.headers)) { + p[a] = e.headers[a] + } + throw new GraphqlResponseError(t, p, e.data) + } + return e.data.data + }) + } + function withDefaults(e, p) { + const a = e.defaults(p) + const newApi = (e, p) => graphql(a, e, p) + return Object.assign(newApi, { + defaults: withDefaults.bind(null, a), + endpoint: d.request.endpoint, + }) + } + const n = withDefaults(d.request, { + headers: { 'user-agent': `octokit-graphql.js/${r} ${t.getUserAgent()}` }, + method: 'POST', + url: '/graphql', + }) + function withCustomRequest(e) { + return withDefaults(e, { method: 'POST', url: '/graphql' }) + } + p.GraphqlResponseError = GraphqlResponseError + p.graphql = n + p.withCustomRequest = withCustomRequest + }, + 4193: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + const a = '2.21.3' + function ownKeys(e, p) { + var a = Object.keys(e) + if (Object.getOwnPropertySymbols) { + var d = Object.getOwnPropertySymbols(e) + p && + (d = d.filter(function (p) { + return Object.getOwnPropertyDescriptor(e, p).enumerable + })), + a.push.apply(a, d) + } + return a + } + function _objectSpread2(e) { + for (var p = 1; p < arguments.length; p++) { + var a = null != arguments[p] ? arguments[p] : {} + p % 2 + ? ownKeys(Object(a), !0).forEach(function (p) { + _defineProperty(e, p, a[p]) + }) + : Object.getOwnPropertyDescriptors + ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(a)) + : ownKeys(Object(a)).forEach(function (p) { + Object.defineProperty(e, p, Object.getOwnPropertyDescriptor(a, p)) + }) + } + return e + } + function _defineProperty(e, p, a) { + if (p in e) { + Object.defineProperty(e, p, { + value: a, + enumerable: true, + configurable: true, + writable: true, + }) + } else { + e[p] = a + } + return e + } + function normalizePaginatedListResponse(e) { + if (!e.data) { + return _objectSpread2(_objectSpread2({}, e), {}, { data: [] }) + } + const p = 'total_count' in e.data && !('url' in e.data) + if (!p) return e + const a = e.data.incomplete_results + const d = e.data.repository_selection + const t = e.data.total_count + delete e.data.incomplete_results + delete e.data.repository_selection + delete e.data.total_count + const r = Object.keys(e.data)[0] + const s = e.data[r] + e.data = s + if (typeof a !== 'undefined') { + e.data.incomplete_results = a + } + if (typeof d !== 'undefined') { + e.data.repository_selection = d + } + e.data.total_count = t + return e + } + function iterator(e, p, a) { + const d = + typeof p === 'function' ? p.endpoint(a) : e.request.endpoint(p, a) + const t = typeof p === 'function' ? p : e.request + const r = d.method + const s = d.headers + let i = d.url + return { + [Symbol.asyncIterator]: () => ({ + async next() { + if (!i) return { done: true } + try { + const e = await t({ method: r, url: i, headers: s }) + const p = normalizePaginatedListResponse(e) + i = ((p.headers.link || '').match(/<([^>]+)>;\s*rel="next"/) || + [])[1] + return { value: p } + } catch (e) { + if (e.status !== 409) throw e + i = '' + return { value: { status: 200, headers: {}, data: [] } } + } + }, + }), + } + } + function paginate(e, p, a, d) { + if (typeof a === 'function') { + d = a + a = undefined + } + return gather(e, [], iterator(e, p, a)[Symbol.asyncIterator](), d) + } + function gather(e, p, a, d) { + return a.next().then((t) => { + if (t.done) { + return p + } + let r = false + function done() { + r = true + } + p = p.concat(d ? d(t.value, done) : t.value.data) + if (r) { + return p + } + return gather(e, p, a, d) + }) + } + const d = Object.assign(paginate, { iterator: iterator }) + const t = [ + 'GET /app/hook/deliveries', + 'GET /app/installations', + 'GET /applications/grants', + 'GET /authorizations', + 'GET /enterprises/{enterprise}/actions/permissions/organizations', + 'GET /enterprises/{enterprise}/actions/runner-groups', + 'GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/organizations', + 'GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/runners', + 'GET /enterprises/{enterprise}/actions/runners', + 'GET /enterprises/{enterprise}/audit-log', + 'GET /enterprises/{enterprise}/secret-scanning/alerts', + 'GET /enterprises/{enterprise}/settings/billing/advanced-security', + 'GET /events', + 'GET /gists', + 'GET /gists/public', + 'GET /gists/starred', + 'GET /gists/{gist_id}/comments', + 'GET /gists/{gist_id}/commits', + 'GET /gists/{gist_id}/forks', + 'GET /installation/repositories', + 'GET /issues', + 'GET /licenses', + 'GET /marketplace_listing/plans', + 'GET /marketplace_listing/plans/{plan_id}/accounts', + 'GET /marketplace_listing/stubbed/plans', + 'GET /marketplace_listing/stubbed/plans/{plan_id}/accounts', + 'GET /networks/{owner}/{repo}/events', + 'GET /notifications', + 'GET /organizations', + 'GET /orgs/{org}/actions/cache/usage-by-repository', + 'GET /orgs/{org}/actions/permissions/repositories', + 'GET /orgs/{org}/actions/runner-groups', + 'GET /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories', + 'GET /orgs/{org}/actions/runner-groups/{runner_group_id}/runners', + 'GET /orgs/{org}/actions/runners', + 'GET /orgs/{org}/actions/secrets', + 'GET /orgs/{org}/actions/secrets/{secret_name}/repositories', + 'GET /orgs/{org}/audit-log', + 'GET /orgs/{org}/blocks', + 'GET /orgs/{org}/code-scanning/alerts', + 'GET /orgs/{org}/codespaces', + 'GET /orgs/{org}/credential-authorizations', + 'GET /orgs/{org}/dependabot/secrets', + 'GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories', + 'GET /orgs/{org}/events', + 'GET /orgs/{org}/external-groups', + 'GET /orgs/{org}/failed_invitations', + 'GET /orgs/{org}/hooks', + 'GET /orgs/{org}/hooks/{hook_id}/deliveries', + 'GET /orgs/{org}/installations', + 'GET /orgs/{org}/invitations', + 'GET /orgs/{org}/invitations/{invitation_id}/teams', + 'GET /orgs/{org}/issues', + 'GET /orgs/{org}/members', + 'GET /orgs/{org}/migrations', + 'GET /orgs/{org}/migrations/{migration_id}/repositories', + 'GET /orgs/{org}/outside_collaborators', + 'GET /orgs/{org}/packages', + 'GET /orgs/{org}/packages/{package_type}/{package_name}/versions', + 'GET /orgs/{org}/projects', + 'GET /orgs/{org}/public_members', + 'GET /orgs/{org}/repos', + 'GET /orgs/{org}/secret-scanning/alerts', + 'GET /orgs/{org}/settings/billing/advanced-security', + 'GET /orgs/{org}/team-sync/groups', + 'GET /orgs/{org}/teams', + 'GET /orgs/{org}/teams/{team_slug}/discussions', + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments', + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions', + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions', + 'GET /orgs/{org}/teams/{team_slug}/invitations', + 'GET /orgs/{org}/teams/{team_slug}/members', + 'GET /orgs/{org}/teams/{team_slug}/projects', + 'GET /orgs/{org}/teams/{team_slug}/repos', + 'GET /orgs/{org}/teams/{team_slug}/teams', + 'GET /projects/columns/{column_id}/cards', + 'GET /projects/{project_id}/collaborators', + 'GET /projects/{project_id}/columns', + 'GET /repos/{owner}/{repo}/actions/artifacts', + 'GET /repos/{owner}/{repo}/actions/caches', + 'GET /repos/{owner}/{repo}/actions/runners', + 'GET /repos/{owner}/{repo}/actions/runs', + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs', + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs', + 'GET /repos/{owner}/{repo}/actions/secrets', + 'GET /repos/{owner}/{repo}/actions/workflows', + 'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs', + 'GET /repos/{owner}/{repo}/assignees', + 'GET /repos/{owner}/{repo}/branches', + 'GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations', + 'GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs', + 'GET /repos/{owner}/{repo}/code-scanning/alerts', + 'GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances', + 'GET /repos/{owner}/{repo}/code-scanning/analyses', + 'GET /repos/{owner}/{repo}/codespaces', + 'GET /repos/{owner}/{repo}/codespaces/devcontainers', + 'GET /repos/{owner}/{repo}/codespaces/secrets', + 'GET /repos/{owner}/{repo}/collaborators', + 'GET /repos/{owner}/{repo}/comments', + 'GET /repos/{owner}/{repo}/comments/{comment_id}/reactions', + 'GET /repos/{owner}/{repo}/commits', + 'GET /repos/{owner}/{repo}/commits/{commit_sha}/comments', + 'GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls', + 'GET /repos/{owner}/{repo}/commits/{ref}/check-runs', + 'GET /repos/{owner}/{repo}/commits/{ref}/check-suites', + 'GET /repos/{owner}/{repo}/commits/{ref}/status', + 'GET /repos/{owner}/{repo}/commits/{ref}/statuses', + 'GET /repos/{owner}/{repo}/contributors', + 'GET /repos/{owner}/{repo}/dependabot/secrets', + 'GET /repos/{owner}/{repo}/deployments', + 'GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses', + 'GET /repos/{owner}/{repo}/environments', + 'GET /repos/{owner}/{repo}/events', + 'GET /repos/{owner}/{repo}/forks', + 'GET /repos/{owner}/{repo}/git/matching-refs/{ref}', + 'GET /repos/{owner}/{repo}/hooks', + 'GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries', + 'GET /repos/{owner}/{repo}/invitations', + 'GET /repos/{owner}/{repo}/issues', + 'GET /repos/{owner}/{repo}/issues/comments', + 'GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions', + 'GET /repos/{owner}/{repo}/issues/events', + 'GET /repos/{owner}/{repo}/issues/{issue_number}/comments', + 'GET /repos/{owner}/{repo}/issues/{issue_number}/events', + 'GET /repos/{owner}/{repo}/issues/{issue_number}/labels', + 'GET /repos/{owner}/{repo}/issues/{issue_number}/reactions', + 'GET /repos/{owner}/{repo}/issues/{issue_number}/timeline', + 'GET /repos/{owner}/{repo}/keys', + 'GET /repos/{owner}/{repo}/labels', + 'GET /repos/{owner}/{repo}/milestones', + 'GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels', + 'GET /repos/{owner}/{repo}/notifications', + 'GET /repos/{owner}/{repo}/pages/builds', + 'GET /repos/{owner}/{repo}/projects', + 'GET /repos/{owner}/{repo}/pulls', + 'GET /repos/{owner}/{repo}/pulls/comments', + 'GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions', + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/comments', + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/commits', + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/files', + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers', + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews', + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments', + 'GET /repos/{owner}/{repo}/releases', + 'GET /repos/{owner}/{repo}/releases/{release_id}/assets', + 'GET /repos/{owner}/{repo}/releases/{release_id}/reactions', + 'GET /repos/{owner}/{repo}/secret-scanning/alerts', + 'GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations', + 'GET /repos/{owner}/{repo}/stargazers', + 'GET /repos/{owner}/{repo}/subscribers', + 'GET /repos/{owner}/{repo}/tags', + 'GET /repos/{owner}/{repo}/teams', + 'GET /repos/{owner}/{repo}/topics', + 'GET /repositories', + 'GET /repositories/{repository_id}/environments/{environment_name}/secrets', + 'GET /search/code', + 'GET /search/commits', + 'GET /search/issues', + 'GET /search/labels', + 'GET /search/repositories', + 'GET /search/topics', + 'GET /search/users', + 'GET /teams/{team_id}/discussions', + 'GET /teams/{team_id}/discussions/{discussion_number}/comments', + 'GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions', + 'GET /teams/{team_id}/discussions/{discussion_number}/reactions', + 'GET /teams/{team_id}/invitations', + 'GET /teams/{team_id}/members', + 'GET /teams/{team_id}/projects', + 'GET /teams/{team_id}/repos', + 'GET /teams/{team_id}/teams', + 'GET /user/blocks', + 'GET /user/codespaces', + 'GET /user/codespaces/secrets', + 'GET /user/emails', + 'GET /user/followers', + 'GET /user/following', + 'GET /user/gpg_keys', + 'GET /user/installations', + 'GET /user/installations/{installation_id}/repositories', + 'GET /user/issues', + 'GET /user/keys', + 'GET /user/marketplace_purchases', + 'GET /user/marketplace_purchases/stubbed', + 'GET /user/memberships/orgs', + 'GET /user/migrations', + 'GET /user/migrations/{migration_id}/repositories', + 'GET /user/orgs', + 'GET /user/packages', + 'GET /user/packages/{package_type}/{package_name}/versions', + 'GET /user/public_emails', + 'GET /user/repos', + 'GET /user/repository_invitations', + 'GET /user/starred', + 'GET /user/subscriptions', + 'GET /user/teams', + 'GET /users', + 'GET /users/{username}/events', + 'GET /users/{username}/events/orgs/{org}', + 'GET /users/{username}/events/public', + 'GET /users/{username}/followers', + 'GET /users/{username}/following', + 'GET /users/{username}/gists', + 'GET /users/{username}/gpg_keys', + 'GET /users/{username}/keys', + 'GET /users/{username}/orgs', + 'GET /users/{username}/packages', + 'GET /users/{username}/projects', + 'GET /users/{username}/received_events', + 'GET /users/{username}/received_events/public', + 'GET /users/{username}/repos', + 'GET /users/{username}/starred', + 'GET /users/{username}/subscriptions', + ] + function isPaginatingEndpoint(e) { + if (typeof e === 'string') { + return t.includes(e) + } else { + return false + } + } + function paginateRest(e) { + return { + paginate: Object.assign(paginate.bind(null, e), { + iterator: iterator.bind(null, e), + }), + } + } + paginateRest.VERSION = a + p.composePaginateRest = d + p.isPaginatingEndpoint = isPaginatingEndpoint + p.paginateRest = paginateRest + p.paginatingEndpoints = t + }, + 3044: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + function ownKeys(e, p) { + var a = Object.keys(e) + if (Object.getOwnPropertySymbols) { + var d = Object.getOwnPropertySymbols(e) + if (p) { + d = d.filter(function (p) { + return Object.getOwnPropertyDescriptor(e, p).enumerable + }) + } + a.push.apply(a, d) + } + return a + } + function _objectSpread2(e) { + for (var p = 1; p < arguments.length; p++) { + var a = arguments[p] != null ? arguments[p] : {} + if (p % 2) { + ownKeys(Object(a), true).forEach(function (p) { + _defineProperty(e, p, a[p]) + }) + } else if (Object.getOwnPropertyDescriptors) { + Object.defineProperties(e, Object.getOwnPropertyDescriptors(a)) + } else { + ownKeys(Object(a)).forEach(function (p) { + Object.defineProperty(e, p, Object.getOwnPropertyDescriptor(a, p)) + }) + } + } + return e + } + function _defineProperty(e, p, a) { + if (p in e) { + Object.defineProperty(e, p, { + value: a, + enumerable: true, + configurable: true, + writable: true, + }) + } else { + e[p] = a + } + return e + } + const a = { + actions: { + addCustomLabelsToSelfHostedRunnerForOrg: [ + 'POST /orgs/{org}/actions/runners/{runner_id}/labels', + ], + addCustomLabelsToSelfHostedRunnerForRepo: [ + 'POST /repos/{owner}/{repo}/actions/runners/{runner_id}/labels', + ], + addSelectedRepoToOrgSecret: [ + 'PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}', + ], + approveWorkflowRun: [ + 'POST /repos/{owner}/{repo}/actions/runs/{run_id}/approve', + ], + cancelWorkflowRun: [ + 'POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel', + ], + createOrUpdateEnvironmentSecret: [ + 'PUT /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}', + ], + createOrUpdateOrgSecret: [ + 'PUT /orgs/{org}/actions/secrets/{secret_name}', + ], + createOrUpdateRepoSecret: [ + 'PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}', + ], + createRegistrationTokenForOrg: [ + 'POST /orgs/{org}/actions/runners/registration-token', + ], + createRegistrationTokenForRepo: [ + 'POST /repos/{owner}/{repo}/actions/runners/registration-token', + ], + createRemoveTokenForOrg: [ + 'POST /orgs/{org}/actions/runners/remove-token', + ], + createRemoveTokenForRepo: [ + 'POST /repos/{owner}/{repo}/actions/runners/remove-token', + ], + createWorkflowDispatch: [ + 'POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches', + ], + deleteActionsCacheById: [ + 'DELETE /repos/{owner}/{repo}/actions/caches/{cache_id}', + ], + deleteActionsCacheByKey: [ + 'DELETE /repos/{owner}/{repo}/actions/caches{?key,ref}', + ], + deleteArtifact: [ + 'DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}', + ], + deleteEnvironmentSecret: [ + 'DELETE /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}', + ], + deleteOrgSecret: ['DELETE /orgs/{org}/actions/secrets/{secret_name}'], + deleteRepoSecret: [ + 'DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}', + ], + deleteSelfHostedRunnerFromOrg: [ + 'DELETE /orgs/{org}/actions/runners/{runner_id}', + ], + deleteSelfHostedRunnerFromRepo: [ + 'DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}', + ], + deleteWorkflowRun: [ + 'DELETE /repos/{owner}/{repo}/actions/runs/{run_id}', + ], + deleteWorkflowRunLogs: [ + 'DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs', + ], + disableSelectedRepositoryGithubActionsOrganization: [ + 'DELETE /orgs/{org}/actions/permissions/repositories/{repository_id}', + ], + disableWorkflow: [ + 'PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/disable', + ], + downloadArtifact: [ + 'GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}', + ], + downloadJobLogsForWorkflowRun: [ + 'GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs', + ], + downloadWorkflowRunAttemptLogs: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/logs', + ], + downloadWorkflowRunLogs: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs', + ], + enableSelectedRepositoryGithubActionsOrganization: [ + 'PUT /orgs/{org}/actions/permissions/repositories/{repository_id}', + ], + enableWorkflow: [ + 'PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable', + ], + getActionsCacheList: ['GET /repos/{owner}/{repo}/actions/caches'], + getActionsCacheUsage: ['GET /repos/{owner}/{repo}/actions/cache/usage'], + getActionsCacheUsageByRepoForOrg: [ + 'GET /orgs/{org}/actions/cache/usage-by-repository', + ], + getActionsCacheUsageForEnterprise: [ + 'GET /enterprises/{enterprise}/actions/cache/usage', + ], + getActionsCacheUsageForOrg: ['GET /orgs/{org}/actions/cache/usage'], + getAllowedActionsOrganization: [ + 'GET /orgs/{org}/actions/permissions/selected-actions', + ], + getAllowedActionsRepository: [ + 'GET /repos/{owner}/{repo}/actions/permissions/selected-actions', + ], + getArtifact: [ + 'GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}', + ], + getEnvironmentPublicKey: [ + 'GET /repositories/{repository_id}/environments/{environment_name}/secrets/public-key', + ], + getEnvironmentSecret: [ + 'GET /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}', + ], + getGithubActionsDefaultWorkflowPermissionsEnterprise: [ + 'GET /enterprises/{enterprise}/actions/permissions/workflow', + ], + getGithubActionsDefaultWorkflowPermissionsOrganization: [ + 'GET /orgs/{org}/actions/permissions/workflow', + ], + getGithubActionsDefaultWorkflowPermissionsRepository: [ + 'GET /repos/{owner}/{repo}/actions/permissions/workflow', + ], + getGithubActionsPermissionsOrganization: [ + 'GET /orgs/{org}/actions/permissions', + ], + getGithubActionsPermissionsRepository: [ + 'GET /repos/{owner}/{repo}/actions/permissions', + ], + getJobForWorkflowRun: [ + 'GET /repos/{owner}/{repo}/actions/jobs/{job_id}', + ], + getOrgPublicKey: ['GET /orgs/{org}/actions/secrets/public-key'], + getOrgSecret: ['GET /orgs/{org}/actions/secrets/{secret_name}'], + getPendingDeploymentsForRun: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments', + ], + getRepoPermissions: [ + 'GET /repos/{owner}/{repo}/actions/permissions', + {}, + { renamed: ['actions', 'getGithubActionsPermissionsRepository'] }, + ], + getRepoPublicKey: [ + 'GET /repos/{owner}/{repo}/actions/secrets/public-key', + ], + getRepoSecret: [ + 'GET /repos/{owner}/{repo}/actions/secrets/{secret_name}', + ], + getReviewsForRun: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/approvals', + ], + getSelfHostedRunnerForOrg: [ + 'GET /orgs/{org}/actions/runners/{runner_id}', + ], + getSelfHostedRunnerForRepo: [ + 'GET /repos/{owner}/{repo}/actions/runners/{runner_id}', + ], + getWorkflow: [ + 'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}', + ], + getWorkflowAccessToRepository: [ + 'GET /repos/{owner}/{repo}/actions/permissions/access', + ], + getWorkflowRun: ['GET /repos/{owner}/{repo}/actions/runs/{run_id}'], + getWorkflowRunAttempt: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}', + ], + getWorkflowRunUsage: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing', + ], + getWorkflowUsage: [ + 'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/timing', + ], + listArtifactsForRepo: ['GET /repos/{owner}/{repo}/actions/artifacts'], + listEnvironmentSecrets: [ + 'GET /repositories/{repository_id}/environments/{environment_name}/secrets', + ], + listJobsForWorkflowRun: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs', + ], + listJobsForWorkflowRunAttempt: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs', + ], + listLabelsForSelfHostedRunnerForOrg: [ + 'GET /orgs/{org}/actions/runners/{runner_id}/labels', + ], + listLabelsForSelfHostedRunnerForRepo: [ + 'GET /repos/{owner}/{repo}/actions/runners/{runner_id}/labels', + ], + listOrgSecrets: ['GET /orgs/{org}/actions/secrets'], + listRepoSecrets: ['GET /repos/{owner}/{repo}/actions/secrets'], + listRepoWorkflows: ['GET /repos/{owner}/{repo}/actions/workflows'], + listRunnerApplicationsForOrg: [ + 'GET /orgs/{org}/actions/runners/downloads', + ], + listRunnerApplicationsForRepo: [ + 'GET /repos/{owner}/{repo}/actions/runners/downloads', + ], + listSelectedReposForOrgSecret: [ + 'GET /orgs/{org}/actions/secrets/{secret_name}/repositories', + ], + listSelectedRepositoriesEnabledGithubActionsOrganization: [ + 'GET /orgs/{org}/actions/permissions/repositories', + ], + listSelfHostedRunnersForOrg: ['GET /orgs/{org}/actions/runners'], + listSelfHostedRunnersForRepo: [ + 'GET /repos/{owner}/{repo}/actions/runners', + ], + listWorkflowRunArtifacts: [ + 'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', + ], + listWorkflowRuns: [ + 'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs', + ], + listWorkflowRunsForRepo: ['GET /repos/{owner}/{repo}/actions/runs'], + reRunJobForWorkflowRun: [ + 'POST /repos/{owner}/{repo}/actions/jobs/{job_id}/rerun', + ], + reRunWorkflow: [ + 'POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun', + ], + reRunWorkflowFailedJobs: [ + 'POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun-failed-jobs', + ], + removeAllCustomLabelsFromSelfHostedRunnerForOrg: [ + 'DELETE /orgs/{org}/actions/runners/{runner_id}/labels', + ], + removeAllCustomLabelsFromSelfHostedRunnerForRepo: [ + 'DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels', + ], + removeCustomLabelFromSelfHostedRunnerForOrg: [ + 'DELETE /orgs/{org}/actions/runners/{runner_id}/labels/{name}', + ], + removeCustomLabelFromSelfHostedRunnerForRepo: [ + 'DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels/{name}', + ], + removeSelectedRepoFromOrgSecret: [ + 'DELETE /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}', + ], + reviewPendingDeploymentsForRun: [ + 'POST /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments', + ], + setAllowedActionsOrganization: [ + 'PUT /orgs/{org}/actions/permissions/selected-actions', + ], + setAllowedActionsRepository: [ + 'PUT /repos/{owner}/{repo}/actions/permissions/selected-actions', + ], + setCustomLabelsForSelfHostedRunnerForOrg: [ + 'PUT /orgs/{org}/actions/runners/{runner_id}/labels', + ], + setCustomLabelsForSelfHostedRunnerForRepo: [ + 'PUT /repos/{owner}/{repo}/actions/runners/{runner_id}/labels', + ], + setGithubActionsDefaultWorkflowPermissionsEnterprise: [ + 'PUT /enterprises/{enterprise}/actions/permissions/workflow', + ], + setGithubActionsDefaultWorkflowPermissionsOrganization: [ + 'PUT /orgs/{org}/actions/permissions/workflow', + ], + setGithubActionsDefaultWorkflowPermissionsRepository: [ + 'PUT /repos/{owner}/{repo}/actions/permissions/workflow', + ], + setGithubActionsPermissionsOrganization: [ + 'PUT /orgs/{org}/actions/permissions', + ], + setGithubActionsPermissionsRepository: [ + 'PUT /repos/{owner}/{repo}/actions/permissions', + ], + setSelectedReposForOrgSecret: [ + 'PUT /orgs/{org}/actions/secrets/{secret_name}/repositories', + ], + setSelectedRepositoriesEnabledGithubActionsOrganization: [ + 'PUT /orgs/{org}/actions/permissions/repositories', + ], + setWorkflowAccessToRepository: [ + 'PUT /repos/{owner}/{repo}/actions/permissions/access', + ], + }, + activity: { + checkRepoIsStarredByAuthenticatedUser: [ + 'GET /user/starred/{owner}/{repo}', + ], + deleteRepoSubscription: ['DELETE /repos/{owner}/{repo}/subscription'], + deleteThreadSubscription: [ + 'DELETE /notifications/threads/{thread_id}/subscription', + ], + getFeeds: ['GET /feeds'], + getRepoSubscription: ['GET /repos/{owner}/{repo}/subscription'], + getThread: ['GET /notifications/threads/{thread_id}'], + getThreadSubscriptionForAuthenticatedUser: [ + 'GET /notifications/threads/{thread_id}/subscription', + ], + listEventsForAuthenticatedUser: ['GET /users/{username}/events'], + listNotificationsForAuthenticatedUser: ['GET /notifications'], + listOrgEventsForAuthenticatedUser: [ + 'GET /users/{username}/events/orgs/{org}', + ], + listPublicEvents: ['GET /events'], + listPublicEventsForRepoNetwork: ['GET /networks/{owner}/{repo}/events'], + listPublicEventsForUser: ['GET /users/{username}/events/public'], + listPublicOrgEvents: ['GET /orgs/{org}/events'], + listReceivedEventsForUser: ['GET /users/{username}/received_events'], + listReceivedPublicEventsForUser: [ + 'GET /users/{username}/received_events/public', + ], + listRepoEvents: ['GET /repos/{owner}/{repo}/events'], + listRepoNotificationsForAuthenticatedUser: [ + 'GET /repos/{owner}/{repo}/notifications', + ], + listReposStarredByAuthenticatedUser: ['GET /user/starred'], + listReposStarredByUser: ['GET /users/{username}/starred'], + listReposWatchedByUser: ['GET /users/{username}/subscriptions'], + listStargazersForRepo: ['GET /repos/{owner}/{repo}/stargazers'], + listWatchedReposForAuthenticatedUser: ['GET /user/subscriptions'], + listWatchersForRepo: ['GET /repos/{owner}/{repo}/subscribers'], + markNotificationsAsRead: ['PUT /notifications'], + markRepoNotificationsAsRead: [ + 'PUT /repos/{owner}/{repo}/notifications', + ], + markThreadAsRead: ['PATCH /notifications/threads/{thread_id}'], + setRepoSubscription: ['PUT /repos/{owner}/{repo}/subscription'], + setThreadSubscription: [ + 'PUT /notifications/threads/{thread_id}/subscription', + ], + starRepoForAuthenticatedUser: ['PUT /user/starred/{owner}/{repo}'], + unstarRepoForAuthenticatedUser: ['DELETE /user/starred/{owner}/{repo}'], + }, + apps: { + addRepoToInstallation: [ + 'PUT /user/installations/{installation_id}/repositories/{repository_id}', + {}, + { renamed: ['apps', 'addRepoToInstallationForAuthenticatedUser'] }, + ], + addRepoToInstallationForAuthenticatedUser: [ + 'PUT /user/installations/{installation_id}/repositories/{repository_id}', + ], + checkToken: ['POST /applications/{client_id}/token'], + createFromManifest: ['POST /app-manifests/{code}/conversions'], + createInstallationAccessToken: [ + 'POST /app/installations/{installation_id}/access_tokens', + ], + deleteAuthorization: ['DELETE /applications/{client_id}/grant'], + deleteInstallation: ['DELETE /app/installations/{installation_id}'], + deleteToken: ['DELETE /applications/{client_id}/token'], + getAuthenticated: ['GET /app'], + getBySlug: ['GET /apps/{app_slug}'], + getInstallation: ['GET /app/installations/{installation_id}'], + getOrgInstallation: ['GET /orgs/{org}/installation'], + getRepoInstallation: ['GET /repos/{owner}/{repo}/installation'], + getSubscriptionPlanForAccount: [ + 'GET /marketplace_listing/accounts/{account_id}', + ], + getSubscriptionPlanForAccountStubbed: [ + 'GET /marketplace_listing/stubbed/accounts/{account_id}', + ], + getUserInstallation: ['GET /users/{username}/installation'], + getWebhookConfigForApp: ['GET /app/hook/config'], + getWebhookDelivery: ['GET /app/hook/deliveries/{delivery_id}'], + listAccountsForPlan: [ + 'GET /marketplace_listing/plans/{plan_id}/accounts', + ], + listAccountsForPlanStubbed: [ + 'GET /marketplace_listing/stubbed/plans/{plan_id}/accounts', + ], + listInstallationReposForAuthenticatedUser: [ + 'GET /user/installations/{installation_id}/repositories', + ], + listInstallations: ['GET /app/installations'], + listInstallationsForAuthenticatedUser: ['GET /user/installations'], + listPlans: ['GET /marketplace_listing/plans'], + listPlansStubbed: ['GET /marketplace_listing/stubbed/plans'], + listReposAccessibleToInstallation: ['GET /installation/repositories'], + listSubscriptionsForAuthenticatedUser: [ + 'GET /user/marketplace_purchases', + ], + listSubscriptionsForAuthenticatedUserStubbed: [ + 'GET /user/marketplace_purchases/stubbed', + ], + listWebhookDeliveries: ['GET /app/hook/deliveries'], + redeliverWebhookDelivery: [ + 'POST /app/hook/deliveries/{delivery_id}/attempts', + ], + removeRepoFromInstallation: [ + 'DELETE /user/installations/{installation_id}/repositories/{repository_id}', + {}, + { + renamed: ['apps', 'removeRepoFromInstallationForAuthenticatedUser'], + }, + ], + removeRepoFromInstallationForAuthenticatedUser: [ + 'DELETE /user/installations/{installation_id}/repositories/{repository_id}', + ], + resetToken: ['PATCH /applications/{client_id}/token'], + revokeInstallationAccessToken: ['DELETE /installation/token'], + scopeToken: ['POST /applications/{client_id}/token/scoped'], + suspendInstallation: [ + 'PUT /app/installations/{installation_id}/suspended', + ], + unsuspendInstallation: [ + 'DELETE /app/installations/{installation_id}/suspended', + ], + updateWebhookConfigForApp: ['PATCH /app/hook/config'], + }, + billing: { + getGithubActionsBillingOrg: [ + 'GET /orgs/{org}/settings/billing/actions', + ], + getGithubActionsBillingUser: [ + 'GET /users/{username}/settings/billing/actions', + ], + getGithubAdvancedSecurityBillingGhe: [ + 'GET /enterprises/{enterprise}/settings/billing/advanced-security', + ], + getGithubAdvancedSecurityBillingOrg: [ + 'GET /orgs/{org}/settings/billing/advanced-security', + ], + getGithubPackagesBillingOrg: [ + 'GET /orgs/{org}/settings/billing/packages', + ], + getGithubPackagesBillingUser: [ + 'GET /users/{username}/settings/billing/packages', + ], + getSharedStorageBillingOrg: [ + 'GET /orgs/{org}/settings/billing/shared-storage', + ], + getSharedStorageBillingUser: [ + 'GET /users/{username}/settings/billing/shared-storage', + ], + }, + checks: { + create: ['POST /repos/{owner}/{repo}/check-runs'], + createSuite: ['POST /repos/{owner}/{repo}/check-suites'], + get: ['GET /repos/{owner}/{repo}/check-runs/{check_run_id}'], + getSuite: ['GET /repos/{owner}/{repo}/check-suites/{check_suite_id}'], + listAnnotations: [ + 'GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations', + ], + listForRef: ['GET /repos/{owner}/{repo}/commits/{ref}/check-runs'], + listForSuite: [ + 'GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs', + ], + listSuitesForRef: [ + 'GET /repos/{owner}/{repo}/commits/{ref}/check-suites', + ], + rerequestRun: [ + 'POST /repos/{owner}/{repo}/check-runs/{check_run_id}/rerequest', + ], + rerequestSuite: [ + 'POST /repos/{owner}/{repo}/check-suites/{check_suite_id}/rerequest', + ], + setSuitesPreferences: [ + 'PATCH /repos/{owner}/{repo}/check-suites/preferences', + ], + update: ['PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}'], + }, + codeScanning: { + deleteAnalysis: [ + 'DELETE /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}{?confirm_delete}', + ], + getAlert: [ + 'GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}', + {}, + { renamedParameters: { alert_id: 'alert_number' } }, + ], + getAnalysis: [ + 'GET /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}', + ], + getSarif: ['GET /repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}'], + listAlertInstances: [ + 'GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances', + ], + listAlertsForOrg: ['GET /orgs/{org}/code-scanning/alerts'], + listAlertsForRepo: ['GET /repos/{owner}/{repo}/code-scanning/alerts'], + listAlertsInstances: [ + 'GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances', + {}, + { renamed: ['codeScanning', 'listAlertInstances'] }, + ], + listRecentAnalyses: [ + 'GET /repos/{owner}/{repo}/code-scanning/analyses', + ], + updateAlert: [ + 'PATCH /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}', + ], + uploadSarif: ['POST /repos/{owner}/{repo}/code-scanning/sarifs'], + }, + codesOfConduct: { + getAllCodesOfConduct: ['GET /codes_of_conduct'], + getConductCode: ['GET /codes_of_conduct/{key}'], + }, + codespaces: { + addRepositoryForSecretForAuthenticatedUser: [ + 'PUT /user/codespaces/secrets/{secret_name}/repositories/{repository_id}', + ], + codespaceMachinesForAuthenticatedUser: [ + 'GET /user/codespaces/{codespace_name}/machines', + ], + createForAuthenticatedUser: ['POST /user/codespaces'], + createOrUpdateRepoSecret: [ + 'PUT /repos/{owner}/{repo}/codespaces/secrets/{secret_name}', + ], + createOrUpdateSecretForAuthenticatedUser: [ + 'PUT /user/codespaces/secrets/{secret_name}', + ], + createWithPrForAuthenticatedUser: [ + 'POST /repos/{owner}/{repo}/pulls/{pull_number}/codespaces', + ], + createWithRepoForAuthenticatedUser: [ + 'POST /repos/{owner}/{repo}/codespaces', + ], + deleteForAuthenticatedUser: [ + 'DELETE /user/codespaces/{codespace_name}', + ], + deleteFromOrganization: [ + 'DELETE /orgs/{org}/members/{username}/codespaces/{codespace_name}', + ], + deleteRepoSecret: [ + 'DELETE /repos/{owner}/{repo}/codespaces/secrets/{secret_name}', + ], + deleteSecretForAuthenticatedUser: [ + 'DELETE /user/codespaces/secrets/{secret_name}', + ], + exportForAuthenticatedUser: [ + 'POST /user/codespaces/{codespace_name}/exports', + ], + getExportDetailsForAuthenticatedUser: [ + 'GET /user/codespaces/{codespace_name}/exports/{export_id}', + ], + getForAuthenticatedUser: ['GET /user/codespaces/{codespace_name}'], + getPublicKeyForAuthenticatedUser: [ + 'GET /user/codespaces/secrets/public-key', + ], + getRepoPublicKey: [ + 'GET /repos/{owner}/{repo}/codespaces/secrets/public-key', + ], + getRepoSecret: [ + 'GET /repos/{owner}/{repo}/codespaces/secrets/{secret_name}', + ], + getSecretForAuthenticatedUser: [ + 'GET /user/codespaces/secrets/{secret_name}', + ], + listDevcontainersInRepositoryForAuthenticatedUser: [ + 'GET /repos/{owner}/{repo}/codespaces/devcontainers', + ], + listForAuthenticatedUser: ['GET /user/codespaces'], + listInOrganization: [ + 'GET /orgs/{org}/codespaces', + {}, + { renamedParameters: { org_id: 'org' } }, + ], + listInRepositoryForAuthenticatedUser: [ + 'GET /repos/{owner}/{repo}/codespaces', + ], + listRepoSecrets: ['GET /repos/{owner}/{repo}/codespaces/secrets'], + listRepositoriesForSecretForAuthenticatedUser: [ + 'GET /user/codespaces/secrets/{secret_name}/repositories', + ], + listSecretsForAuthenticatedUser: ['GET /user/codespaces/secrets'], + removeRepositoryForSecretForAuthenticatedUser: [ + 'DELETE /user/codespaces/secrets/{secret_name}/repositories/{repository_id}', + ], + repoMachinesForAuthenticatedUser: [ + 'GET /repos/{owner}/{repo}/codespaces/machines', + ], + setRepositoriesForSecretForAuthenticatedUser: [ + 'PUT /user/codespaces/secrets/{secret_name}/repositories', + ], + startForAuthenticatedUser: [ + 'POST /user/codespaces/{codespace_name}/start', + ], + stopForAuthenticatedUser: [ + 'POST /user/codespaces/{codespace_name}/stop', + ], + stopInOrganization: [ + 'POST /orgs/{org}/members/{username}/codespaces/{codespace_name}/stop', + ], + updateForAuthenticatedUser: ['PATCH /user/codespaces/{codespace_name}'], + }, + dependabot: { + addSelectedRepoToOrgSecret: [ + 'PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}', + ], + createOrUpdateOrgSecret: [ + 'PUT /orgs/{org}/dependabot/secrets/{secret_name}', + ], + createOrUpdateRepoSecret: [ + 'PUT /repos/{owner}/{repo}/dependabot/secrets/{secret_name}', + ], + deleteOrgSecret: [ + 'DELETE /orgs/{org}/dependabot/secrets/{secret_name}', + ], + deleteRepoSecret: [ + 'DELETE /repos/{owner}/{repo}/dependabot/secrets/{secret_name}', + ], + getOrgPublicKey: ['GET /orgs/{org}/dependabot/secrets/public-key'], + getOrgSecret: ['GET /orgs/{org}/dependabot/secrets/{secret_name}'], + getRepoPublicKey: [ + 'GET /repos/{owner}/{repo}/dependabot/secrets/public-key', + ], + getRepoSecret: [ + 'GET /repos/{owner}/{repo}/dependabot/secrets/{secret_name}', + ], + listOrgSecrets: ['GET /orgs/{org}/dependabot/secrets'], + listRepoSecrets: ['GET /repos/{owner}/{repo}/dependabot/secrets'], + listSelectedReposForOrgSecret: [ + 'GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories', + ], + removeSelectedRepoFromOrgSecret: [ + 'DELETE /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}', + ], + setSelectedReposForOrgSecret: [ + 'PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories', + ], + }, + dependencyGraph: { + createRepositorySnapshot: [ + 'POST /repos/{owner}/{repo}/dependency-graph/snapshots', + ], + diffRange: [ + 'GET /repos/{owner}/{repo}/dependency-graph/compare/{basehead}', + ], + }, + emojis: { get: ['GET /emojis'] }, + enterpriseAdmin: { + addCustomLabelsToSelfHostedRunnerForEnterprise: [ + 'POST /enterprises/{enterprise}/actions/runners/{runner_id}/labels', + ], + disableSelectedOrganizationGithubActionsEnterprise: [ + 'DELETE /enterprises/{enterprise}/actions/permissions/organizations/{org_id}', + ], + enableSelectedOrganizationGithubActionsEnterprise: [ + 'PUT /enterprises/{enterprise}/actions/permissions/organizations/{org_id}', + ], + getAllowedActionsEnterprise: [ + 'GET /enterprises/{enterprise}/actions/permissions/selected-actions', + ], + getGithubActionsPermissionsEnterprise: [ + 'GET /enterprises/{enterprise}/actions/permissions', + ], + getServerStatistics: [ + 'GET /enterprise-installation/{enterprise_or_org}/server-statistics', + ], + listLabelsForSelfHostedRunnerForEnterprise: [ + 'GET /enterprises/{enterprise}/actions/runners/{runner_id}/labels', + ], + listSelectedOrganizationsEnabledGithubActionsEnterprise: [ + 'GET /enterprises/{enterprise}/actions/permissions/organizations', + ], + removeAllCustomLabelsFromSelfHostedRunnerForEnterprise: [ + 'DELETE /enterprises/{enterprise}/actions/runners/{runner_id}/labels', + ], + removeCustomLabelFromSelfHostedRunnerForEnterprise: [ + 'DELETE /enterprises/{enterprise}/actions/runners/{runner_id}/labels/{name}', + ], + setAllowedActionsEnterprise: [ + 'PUT /enterprises/{enterprise}/actions/permissions/selected-actions', + ], + setCustomLabelsForSelfHostedRunnerForEnterprise: [ + 'PUT /enterprises/{enterprise}/actions/runners/{runner_id}/labels', + ], + setGithubActionsPermissionsEnterprise: [ + 'PUT /enterprises/{enterprise}/actions/permissions', + ], + setSelectedOrganizationsEnabledGithubActionsEnterprise: [ + 'PUT /enterprises/{enterprise}/actions/permissions/organizations', + ], + }, + gists: { + checkIsStarred: ['GET /gists/{gist_id}/star'], + create: ['POST /gists'], + createComment: ['POST /gists/{gist_id}/comments'], + delete: ['DELETE /gists/{gist_id}'], + deleteComment: ['DELETE /gists/{gist_id}/comments/{comment_id}'], + fork: ['POST /gists/{gist_id}/forks'], + get: ['GET /gists/{gist_id}'], + getComment: ['GET /gists/{gist_id}/comments/{comment_id}'], + getRevision: ['GET /gists/{gist_id}/{sha}'], + list: ['GET /gists'], + listComments: ['GET /gists/{gist_id}/comments'], + listCommits: ['GET /gists/{gist_id}/commits'], + listForUser: ['GET /users/{username}/gists'], + listForks: ['GET /gists/{gist_id}/forks'], + listPublic: ['GET /gists/public'], + listStarred: ['GET /gists/starred'], + star: ['PUT /gists/{gist_id}/star'], + unstar: ['DELETE /gists/{gist_id}/star'], + update: ['PATCH /gists/{gist_id}'], + updateComment: ['PATCH /gists/{gist_id}/comments/{comment_id}'], + }, + git: { + createBlob: ['POST /repos/{owner}/{repo}/git/blobs'], + createCommit: ['POST /repos/{owner}/{repo}/git/commits'], + createRef: ['POST /repos/{owner}/{repo}/git/refs'], + createTag: ['POST /repos/{owner}/{repo}/git/tags'], + createTree: ['POST /repos/{owner}/{repo}/git/trees'], + deleteRef: ['DELETE /repos/{owner}/{repo}/git/refs/{ref}'], + getBlob: ['GET /repos/{owner}/{repo}/git/blobs/{file_sha}'], + getCommit: ['GET /repos/{owner}/{repo}/git/commits/{commit_sha}'], + getRef: ['GET /repos/{owner}/{repo}/git/ref/{ref}'], + getTag: ['GET /repos/{owner}/{repo}/git/tags/{tag_sha}'], + getTree: ['GET /repos/{owner}/{repo}/git/trees/{tree_sha}'], + listMatchingRefs: ['GET /repos/{owner}/{repo}/git/matching-refs/{ref}'], + updateRef: ['PATCH /repos/{owner}/{repo}/git/refs/{ref}'], + }, + gitignore: { + getAllTemplates: ['GET /gitignore/templates'], + getTemplate: ['GET /gitignore/templates/{name}'], + }, + interactions: { + getRestrictionsForAuthenticatedUser: ['GET /user/interaction-limits'], + getRestrictionsForOrg: ['GET /orgs/{org}/interaction-limits'], + getRestrictionsForRepo: [ + 'GET /repos/{owner}/{repo}/interaction-limits', + ], + getRestrictionsForYourPublicRepos: [ + 'GET /user/interaction-limits', + {}, + { renamed: ['interactions', 'getRestrictionsForAuthenticatedUser'] }, + ], + removeRestrictionsForAuthenticatedUser: [ + 'DELETE /user/interaction-limits', + ], + removeRestrictionsForOrg: ['DELETE /orgs/{org}/interaction-limits'], + removeRestrictionsForRepo: [ + 'DELETE /repos/{owner}/{repo}/interaction-limits', + ], + removeRestrictionsForYourPublicRepos: [ + 'DELETE /user/interaction-limits', + {}, + { + renamed: ['interactions', 'removeRestrictionsForAuthenticatedUser'], + }, + ], + setRestrictionsForAuthenticatedUser: ['PUT /user/interaction-limits'], + setRestrictionsForOrg: ['PUT /orgs/{org}/interaction-limits'], + setRestrictionsForRepo: [ + 'PUT /repos/{owner}/{repo}/interaction-limits', + ], + setRestrictionsForYourPublicRepos: [ + 'PUT /user/interaction-limits', + {}, + { renamed: ['interactions', 'setRestrictionsForAuthenticatedUser'] }, + ], + }, + issues: { + addAssignees: [ + 'POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', + ], + addLabels: ['POST /repos/{owner}/{repo}/issues/{issue_number}/labels'], + checkUserCanBeAssigned: [ + 'GET /repos/{owner}/{repo}/assignees/{assignee}', + ], + create: ['POST /repos/{owner}/{repo}/issues'], + createComment: [ + 'POST /repos/{owner}/{repo}/issues/{issue_number}/comments', + ], + createLabel: ['POST /repos/{owner}/{repo}/labels'], + createMilestone: ['POST /repos/{owner}/{repo}/milestones'], + deleteComment: [ + 'DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}', + ], + deleteLabel: ['DELETE /repos/{owner}/{repo}/labels/{name}'], + deleteMilestone: [ + 'DELETE /repos/{owner}/{repo}/milestones/{milestone_number}', + ], + get: ['GET /repos/{owner}/{repo}/issues/{issue_number}'], + getComment: ['GET /repos/{owner}/{repo}/issues/comments/{comment_id}'], + getEvent: ['GET /repos/{owner}/{repo}/issues/events/{event_id}'], + getLabel: ['GET /repos/{owner}/{repo}/labels/{name}'], + getMilestone: [ + 'GET /repos/{owner}/{repo}/milestones/{milestone_number}', + ], + list: ['GET /issues'], + listAssignees: ['GET /repos/{owner}/{repo}/assignees'], + listComments: [ + 'GET /repos/{owner}/{repo}/issues/{issue_number}/comments', + ], + listCommentsForRepo: ['GET /repos/{owner}/{repo}/issues/comments'], + listEvents: ['GET /repos/{owner}/{repo}/issues/{issue_number}/events'], + listEventsForRepo: ['GET /repos/{owner}/{repo}/issues/events'], + listEventsForTimeline: [ + 'GET /repos/{owner}/{repo}/issues/{issue_number}/timeline', + ], + listForAuthenticatedUser: ['GET /user/issues'], + listForOrg: ['GET /orgs/{org}/issues'], + listForRepo: ['GET /repos/{owner}/{repo}/issues'], + listLabelsForMilestone: [ + 'GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels', + ], + listLabelsForRepo: ['GET /repos/{owner}/{repo}/labels'], + listLabelsOnIssue: [ + 'GET /repos/{owner}/{repo}/issues/{issue_number}/labels', + ], + listMilestones: ['GET /repos/{owner}/{repo}/milestones'], + lock: ['PUT /repos/{owner}/{repo}/issues/{issue_number}/lock'], + removeAllLabels: [ + 'DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels', + ], + removeAssignees: [ + 'DELETE /repos/{owner}/{repo}/issues/{issue_number}/assignees', + ], + removeLabel: [ + 'DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}', + ], + setLabels: ['PUT /repos/{owner}/{repo}/issues/{issue_number}/labels'], + unlock: ['DELETE /repos/{owner}/{repo}/issues/{issue_number}/lock'], + update: ['PATCH /repos/{owner}/{repo}/issues/{issue_number}'], + updateComment: [ + 'PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}', + ], + updateLabel: ['PATCH /repos/{owner}/{repo}/labels/{name}'], + updateMilestone: [ + 'PATCH /repos/{owner}/{repo}/milestones/{milestone_number}', + ], + }, + licenses: { + get: ['GET /licenses/{license}'], + getAllCommonlyUsed: ['GET /licenses'], + getForRepo: ['GET /repos/{owner}/{repo}/license'], + }, + markdown: { + render: ['POST /markdown'], + renderRaw: [ + 'POST /markdown/raw', + { headers: { 'content-type': 'text/plain; charset=utf-8' } }, + ], + }, + meta: { + get: ['GET /meta'], + getOctocat: ['GET /octocat'], + getZen: ['GET /zen'], + root: ['GET /'], + }, + migrations: { + cancelImport: ['DELETE /repos/{owner}/{repo}/import'], + deleteArchiveForAuthenticatedUser: [ + 'DELETE /user/migrations/{migration_id}/archive', + ], + deleteArchiveForOrg: [ + 'DELETE /orgs/{org}/migrations/{migration_id}/archive', + ], + downloadArchiveForOrg: [ + 'GET /orgs/{org}/migrations/{migration_id}/archive', + ], + getArchiveForAuthenticatedUser: [ + 'GET /user/migrations/{migration_id}/archive', + ], + getCommitAuthors: ['GET /repos/{owner}/{repo}/import/authors'], + getImportStatus: ['GET /repos/{owner}/{repo}/import'], + getLargeFiles: ['GET /repos/{owner}/{repo}/import/large_files'], + getStatusForAuthenticatedUser: ['GET /user/migrations/{migration_id}'], + getStatusForOrg: ['GET /orgs/{org}/migrations/{migration_id}'], + listForAuthenticatedUser: ['GET /user/migrations'], + listForOrg: ['GET /orgs/{org}/migrations'], + listReposForAuthenticatedUser: [ + 'GET /user/migrations/{migration_id}/repositories', + ], + listReposForOrg: [ + 'GET /orgs/{org}/migrations/{migration_id}/repositories', + ], + listReposForUser: [ + 'GET /user/migrations/{migration_id}/repositories', + {}, + { renamed: ['migrations', 'listReposForAuthenticatedUser'] }, + ], + mapCommitAuthor: [ + 'PATCH /repos/{owner}/{repo}/import/authors/{author_id}', + ], + setLfsPreference: ['PATCH /repos/{owner}/{repo}/import/lfs'], + startForAuthenticatedUser: ['POST /user/migrations'], + startForOrg: ['POST /orgs/{org}/migrations'], + startImport: ['PUT /repos/{owner}/{repo}/import'], + unlockRepoForAuthenticatedUser: [ + 'DELETE /user/migrations/{migration_id}/repos/{repo_name}/lock', + ], + unlockRepoForOrg: [ + 'DELETE /orgs/{org}/migrations/{migration_id}/repos/{repo_name}/lock', + ], + updateImport: ['PATCH /repos/{owner}/{repo}/import'], + }, + orgs: { + blockUser: ['PUT /orgs/{org}/blocks/{username}'], + cancelInvitation: ['DELETE /orgs/{org}/invitations/{invitation_id}'], + checkBlockedUser: ['GET /orgs/{org}/blocks/{username}'], + checkMembershipForUser: ['GET /orgs/{org}/members/{username}'], + checkPublicMembershipForUser: [ + 'GET /orgs/{org}/public_members/{username}', + ], + convertMemberToOutsideCollaborator: [ + 'PUT /orgs/{org}/outside_collaborators/{username}', + ], + createInvitation: ['POST /orgs/{org}/invitations'], + createWebhook: ['POST /orgs/{org}/hooks'], + deleteWebhook: ['DELETE /orgs/{org}/hooks/{hook_id}'], + get: ['GET /orgs/{org}'], + getMembershipForAuthenticatedUser: ['GET /user/memberships/orgs/{org}'], + getMembershipForUser: ['GET /orgs/{org}/memberships/{username}'], + getWebhook: ['GET /orgs/{org}/hooks/{hook_id}'], + getWebhookConfigForOrg: ['GET /orgs/{org}/hooks/{hook_id}/config'], + getWebhookDelivery: [ + 'GET /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}', + ], + list: ['GET /organizations'], + listAppInstallations: ['GET /orgs/{org}/installations'], + listBlockedUsers: ['GET /orgs/{org}/blocks'], + listCustomRoles: ['GET /organizations/{organization_id}/custom_roles'], + listFailedInvitations: ['GET /orgs/{org}/failed_invitations'], + listForAuthenticatedUser: ['GET /user/orgs'], + listForUser: ['GET /users/{username}/orgs'], + listInvitationTeams: [ + 'GET /orgs/{org}/invitations/{invitation_id}/teams', + ], + listMembers: ['GET /orgs/{org}/members'], + listMembershipsForAuthenticatedUser: ['GET /user/memberships/orgs'], + listOutsideCollaborators: ['GET /orgs/{org}/outside_collaborators'], + listPendingInvitations: ['GET /orgs/{org}/invitations'], + listPublicMembers: ['GET /orgs/{org}/public_members'], + listWebhookDeliveries: ['GET /orgs/{org}/hooks/{hook_id}/deliveries'], + listWebhooks: ['GET /orgs/{org}/hooks'], + pingWebhook: ['POST /orgs/{org}/hooks/{hook_id}/pings'], + redeliverWebhookDelivery: [ + 'POST /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts', + ], + removeMember: ['DELETE /orgs/{org}/members/{username}'], + removeMembershipForUser: ['DELETE /orgs/{org}/memberships/{username}'], + removeOutsideCollaborator: [ + 'DELETE /orgs/{org}/outside_collaborators/{username}', + ], + removePublicMembershipForAuthenticatedUser: [ + 'DELETE /orgs/{org}/public_members/{username}', + ], + setMembershipForUser: ['PUT /orgs/{org}/memberships/{username}'], + setPublicMembershipForAuthenticatedUser: [ + 'PUT /orgs/{org}/public_members/{username}', + ], + unblockUser: ['DELETE /orgs/{org}/blocks/{username}'], + update: ['PATCH /orgs/{org}'], + updateMembershipForAuthenticatedUser: [ + 'PATCH /user/memberships/orgs/{org}', + ], + updateWebhook: ['PATCH /orgs/{org}/hooks/{hook_id}'], + updateWebhookConfigForOrg: ['PATCH /orgs/{org}/hooks/{hook_id}/config'], + }, + packages: { + deletePackageForAuthenticatedUser: [ + 'DELETE /user/packages/{package_type}/{package_name}', + ], + deletePackageForOrg: [ + 'DELETE /orgs/{org}/packages/{package_type}/{package_name}', + ], + deletePackageForUser: [ + 'DELETE /users/{username}/packages/{package_type}/{package_name}', + ], + deletePackageVersionForAuthenticatedUser: [ + 'DELETE /user/packages/{package_type}/{package_name}/versions/{package_version_id}', + ], + deletePackageVersionForOrg: [ + 'DELETE /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}', + ], + deletePackageVersionForUser: [ + 'DELETE /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}', + ], + getAllPackageVersionsForAPackageOwnedByAnOrg: [ + 'GET /orgs/{org}/packages/{package_type}/{package_name}/versions', + {}, + { + renamed: ['packages', 'getAllPackageVersionsForPackageOwnedByOrg'], + }, + ], + getAllPackageVersionsForAPackageOwnedByTheAuthenticatedUser: [ + 'GET /user/packages/{package_type}/{package_name}/versions', + {}, + { + renamed: [ + 'packages', + 'getAllPackageVersionsForPackageOwnedByAuthenticatedUser', + ], + }, + ], + getAllPackageVersionsForPackageOwnedByAuthenticatedUser: [ + 'GET /user/packages/{package_type}/{package_name}/versions', + ], + getAllPackageVersionsForPackageOwnedByOrg: [ + 'GET /orgs/{org}/packages/{package_type}/{package_name}/versions', + ], + getAllPackageVersionsForPackageOwnedByUser: [ + 'GET /users/{username}/packages/{package_type}/{package_name}/versions', + ], + getPackageForAuthenticatedUser: [ + 'GET /user/packages/{package_type}/{package_name}', + ], + getPackageForOrganization: [ + 'GET /orgs/{org}/packages/{package_type}/{package_name}', + ], + getPackageForUser: [ + 'GET /users/{username}/packages/{package_type}/{package_name}', + ], + getPackageVersionForAuthenticatedUser: [ + 'GET /user/packages/{package_type}/{package_name}/versions/{package_version_id}', + ], + getPackageVersionForOrganization: [ + 'GET /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}', + ], + getPackageVersionForUser: [ + 'GET /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}', + ], + listPackagesForAuthenticatedUser: ['GET /user/packages'], + listPackagesForOrganization: ['GET /orgs/{org}/packages'], + listPackagesForUser: ['GET /users/{username}/packages'], + restorePackageForAuthenticatedUser: [ + 'POST /user/packages/{package_type}/{package_name}/restore{?token}', + ], + restorePackageForOrg: [ + 'POST /orgs/{org}/packages/{package_type}/{package_name}/restore{?token}', + ], + restorePackageForUser: [ + 'POST /users/{username}/packages/{package_type}/{package_name}/restore{?token}', + ], + restorePackageVersionForAuthenticatedUser: [ + 'POST /user/packages/{package_type}/{package_name}/versions/{package_version_id}/restore', + ], + restorePackageVersionForOrg: [ + 'POST /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore', + ], + restorePackageVersionForUser: [ + 'POST /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore', + ], + }, + projects: { + addCollaborator: [ + 'PUT /projects/{project_id}/collaborators/{username}', + ], + createCard: ['POST /projects/columns/{column_id}/cards'], + createColumn: ['POST /projects/{project_id}/columns'], + createForAuthenticatedUser: ['POST /user/projects'], + createForOrg: ['POST /orgs/{org}/projects'], + createForRepo: ['POST /repos/{owner}/{repo}/projects'], + delete: ['DELETE /projects/{project_id}'], + deleteCard: ['DELETE /projects/columns/cards/{card_id}'], + deleteColumn: ['DELETE /projects/columns/{column_id}'], + get: ['GET /projects/{project_id}'], + getCard: ['GET /projects/columns/cards/{card_id}'], + getColumn: ['GET /projects/columns/{column_id}'], + getPermissionForUser: [ + 'GET /projects/{project_id}/collaborators/{username}/permission', + ], + listCards: ['GET /projects/columns/{column_id}/cards'], + listCollaborators: ['GET /projects/{project_id}/collaborators'], + listColumns: ['GET /projects/{project_id}/columns'], + listForOrg: ['GET /orgs/{org}/projects'], + listForRepo: ['GET /repos/{owner}/{repo}/projects'], + listForUser: ['GET /users/{username}/projects'], + moveCard: ['POST /projects/columns/cards/{card_id}/moves'], + moveColumn: ['POST /projects/columns/{column_id}/moves'], + removeCollaborator: [ + 'DELETE /projects/{project_id}/collaborators/{username}', + ], + update: ['PATCH /projects/{project_id}'], + updateCard: ['PATCH /projects/columns/cards/{card_id}'], + updateColumn: ['PATCH /projects/columns/{column_id}'], + }, + pulls: { + checkIfMerged: ['GET /repos/{owner}/{repo}/pulls/{pull_number}/merge'], + create: ['POST /repos/{owner}/{repo}/pulls'], + createReplyForReviewComment: [ + 'POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies', + ], + createReview: [ + 'POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews', + ], + createReviewComment: [ + 'POST /repos/{owner}/{repo}/pulls/{pull_number}/comments', + ], + deletePendingReview: [ + 'DELETE /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}', + ], + deleteReviewComment: [ + 'DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}', + ], + dismissReview: [ + 'PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/dismissals', + ], + get: ['GET /repos/{owner}/{repo}/pulls/{pull_number}'], + getReview: [ + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}', + ], + getReviewComment: [ + 'GET /repos/{owner}/{repo}/pulls/comments/{comment_id}', + ], + list: ['GET /repos/{owner}/{repo}/pulls'], + listCommentsForReview: [ + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments', + ], + listCommits: ['GET /repos/{owner}/{repo}/pulls/{pull_number}/commits'], + listFiles: ['GET /repos/{owner}/{repo}/pulls/{pull_number}/files'], + listRequestedReviewers: [ + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers', + ], + listReviewComments: [ + 'GET /repos/{owner}/{repo}/pulls/{pull_number}/comments', + ], + listReviewCommentsForRepo: ['GET /repos/{owner}/{repo}/pulls/comments'], + listReviews: ['GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews'], + merge: ['PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge'], + removeRequestedReviewers: [ + 'DELETE /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers', + ], + requestReviewers: [ + 'POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers', + ], + submitReview: [ + 'POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/events', + ], + update: ['PATCH /repos/{owner}/{repo}/pulls/{pull_number}'], + updateBranch: [ + 'PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch', + ], + updateReview: [ + 'PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}', + ], + updateReviewComment: [ + 'PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}', + ], + }, + rateLimit: { get: ['GET /rate_limit'] }, + reactions: { + createForCommitComment: [ + 'POST /repos/{owner}/{repo}/comments/{comment_id}/reactions', + ], + createForIssue: [ + 'POST /repos/{owner}/{repo}/issues/{issue_number}/reactions', + ], + createForIssueComment: [ + 'POST /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions', + ], + createForPullRequestReviewComment: [ + 'POST /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions', + ], + createForRelease: [ + 'POST /repos/{owner}/{repo}/releases/{release_id}/reactions', + ], + createForTeamDiscussionCommentInOrg: [ + 'POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions', + ], + createForTeamDiscussionInOrg: [ + 'POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions', + ], + deleteForCommitComment: [ + 'DELETE /repos/{owner}/{repo}/comments/{comment_id}/reactions/{reaction_id}', + ], + deleteForIssue: [ + 'DELETE /repos/{owner}/{repo}/issues/{issue_number}/reactions/{reaction_id}', + ], + deleteForIssueComment: [ + 'DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions/{reaction_id}', + ], + deleteForPullRequestComment: [ + 'DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions/{reaction_id}', + ], + deleteForRelease: [ + 'DELETE /repos/{owner}/{repo}/releases/{release_id}/reactions/{reaction_id}', + ], + deleteForTeamDiscussion: [ + 'DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions/{reaction_id}', + ], + deleteForTeamDiscussionComment: [ + 'DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions/{reaction_id}', + ], + listForCommitComment: [ + 'GET /repos/{owner}/{repo}/comments/{comment_id}/reactions', + ], + listForIssue: [ + 'GET /repos/{owner}/{repo}/issues/{issue_number}/reactions', + ], + listForIssueComment: [ + 'GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions', + ], + listForPullRequestReviewComment: [ + 'GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions', + ], + listForRelease: [ + 'GET /repos/{owner}/{repo}/releases/{release_id}/reactions', + ], + listForTeamDiscussionCommentInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions', + ], + listForTeamDiscussionInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions', + ], + }, + repos: { + acceptInvitation: [ + 'PATCH /user/repository_invitations/{invitation_id}', + {}, + { renamed: ['repos', 'acceptInvitationForAuthenticatedUser'] }, + ], + acceptInvitationForAuthenticatedUser: [ + 'PATCH /user/repository_invitations/{invitation_id}', + ], + addAppAccessRestrictions: [ + 'POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps', + {}, + { mapToData: 'apps' }, + ], + addCollaborator: ['PUT /repos/{owner}/{repo}/collaborators/{username}'], + addStatusCheckContexts: [ + 'POST /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts', + {}, + { mapToData: 'contexts' }, + ], + addTeamAccessRestrictions: [ + 'POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams', + {}, + { mapToData: 'teams' }, + ], + addUserAccessRestrictions: [ + 'POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users', + {}, + { mapToData: 'users' }, + ], + checkCollaborator: [ + 'GET /repos/{owner}/{repo}/collaborators/{username}', + ], + checkVulnerabilityAlerts: [ + 'GET /repos/{owner}/{repo}/vulnerability-alerts', + ], + codeownersErrors: ['GET /repos/{owner}/{repo}/codeowners/errors'], + compareCommits: ['GET /repos/{owner}/{repo}/compare/{base}...{head}'], + compareCommitsWithBasehead: [ + 'GET /repos/{owner}/{repo}/compare/{basehead}', + ], + createAutolink: ['POST /repos/{owner}/{repo}/autolinks'], + createCommitComment: [ + 'POST /repos/{owner}/{repo}/commits/{commit_sha}/comments', + ], + createCommitSignatureProtection: [ + 'POST /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures', + ], + createCommitStatus: ['POST /repos/{owner}/{repo}/statuses/{sha}'], + createDeployKey: ['POST /repos/{owner}/{repo}/keys'], + createDeployment: ['POST /repos/{owner}/{repo}/deployments'], + createDeploymentStatus: [ + 'POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses', + ], + createDispatchEvent: ['POST /repos/{owner}/{repo}/dispatches'], + createForAuthenticatedUser: ['POST /user/repos'], + createFork: ['POST /repos/{owner}/{repo}/forks'], + createInOrg: ['POST /orgs/{org}/repos'], + createOrUpdateEnvironment: [ + 'PUT /repos/{owner}/{repo}/environments/{environment_name}', + ], + createOrUpdateFileContents: [ + 'PUT /repos/{owner}/{repo}/contents/{path}', + ], + createPagesSite: ['POST /repos/{owner}/{repo}/pages'], + createRelease: ['POST /repos/{owner}/{repo}/releases'], + createTagProtection: ['POST /repos/{owner}/{repo}/tags/protection'], + createUsingTemplate: [ + 'POST /repos/{template_owner}/{template_repo}/generate', + ], + createWebhook: ['POST /repos/{owner}/{repo}/hooks'], + declineInvitation: [ + 'DELETE /user/repository_invitations/{invitation_id}', + {}, + { renamed: ['repos', 'declineInvitationForAuthenticatedUser'] }, + ], + declineInvitationForAuthenticatedUser: [ + 'DELETE /user/repository_invitations/{invitation_id}', + ], + delete: ['DELETE /repos/{owner}/{repo}'], + deleteAccessRestrictions: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions', + ], + deleteAdminBranchProtection: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins', + ], + deleteAnEnvironment: [ + 'DELETE /repos/{owner}/{repo}/environments/{environment_name}', + ], + deleteAutolink: [ + 'DELETE /repos/{owner}/{repo}/autolinks/{autolink_id}', + ], + deleteBranchProtection: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection', + ], + deleteCommitComment: [ + 'DELETE /repos/{owner}/{repo}/comments/{comment_id}', + ], + deleteCommitSignatureProtection: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures', + ], + deleteDeployKey: ['DELETE /repos/{owner}/{repo}/keys/{key_id}'], + deleteDeployment: [ + 'DELETE /repos/{owner}/{repo}/deployments/{deployment_id}', + ], + deleteFile: ['DELETE /repos/{owner}/{repo}/contents/{path}'], + deleteInvitation: [ + 'DELETE /repos/{owner}/{repo}/invitations/{invitation_id}', + ], + deletePagesSite: ['DELETE /repos/{owner}/{repo}/pages'], + deletePullRequestReviewProtection: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews', + ], + deleteRelease: ['DELETE /repos/{owner}/{repo}/releases/{release_id}'], + deleteReleaseAsset: [ + 'DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}', + ], + deleteTagProtection: [ + 'DELETE /repos/{owner}/{repo}/tags/protection/{tag_protection_id}', + ], + deleteWebhook: ['DELETE /repos/{owner}/{repo}/hooks/{hook_id}'], + disableAutomatedSecurityFixes: [ + 'DELETE /repos/{owner}/{repo}/automated-security-fixes', + ], + disableLfsForRepo: ['DELETE /repos/{owner}/{repo}/lfs'], + disableVulnerabilityAlerts: [ + 'DELETE /repos/{owner}/{repo}/vulnerability-alerts', + ], + downloadArchive: [ + 'GET /repos/{owner}/{repo}/zipball/{ref}', + {}, + { renamed: ['repos', 'downloadZipballArchive'] }, + ], + downloadTarballArchive: ['GET /repos/{owner}/{repo}/tarball/{ref}'], + downloadZipballArchive: ['GET /repos/{owner}/{repo}/zipball/{ref}'], + enableAutomatedSecurityFixes: [ + 'PUT /repos/{owner}/{repo}/automated-security-fixes', + ], + enableLfsForRepo: ['PUT /repos/{owner}/{repo}/lfs'], + enableVulnerabilityAlerts: [ + 'PUT /repos/{owner}/{repo}/vulnerability-alerts', + ], + generateReleaseNotes: [ + 'POST /repos/{owner}/{repo}/releases/generate-notes', + ], + get: ['GET /repos/{owner}/{repo}'], + getAccessRestrictions: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions', + ], + getAdminBranchProtection: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins', + ], + getAllEnvironments: ['GET /repos/{owner}/{repo}/environments'], + getAllStatusCheckContexts: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts', + ], + getAllTopics: ['GET /repos/{owner}/{repo}/topics'], + getAppsWithAccessToProtectedBranch: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps', + ], + getAutolink: ['GET /repos/{owner}/{repo}/autolinks/{autolink_id}'], + getBranch: ['GET /repos/{owner}/{repo}/branches/{branch}'], + getBranchProtection: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection', + ], + getClones: ['GET /repos/{owner}/{repo}/traffic/clones'], + getCodeFrequencyStats: [ + 'GET /repos/{owner}/{repo}/stats/code_frequency', + ], + getCollaboratorPermissionLevel: [ + 'GET /repos/{owner}/{repo}/collaborators/{username}/permission', + ], + getCombinedStatusForRef: [ + 'GET /repos/{owner}/{repo}/commits/{ref}/status', + ], + getCommit: ['GET /repos/{owner}/{repo}/commits/{ref}'], + getCommitActivityStats: [ + 'GET /repos/{owner}/{repo}/stats/commit_activity', + ], + getCommitComment: ['GET /repos/{owner}/{repo}/comments/{comment_id}'], + getCommitSignatureProtection: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures', + ], + getCommunityProfileMetrics: [ + 'GET /repos/{owner}/{repo}/community/profile', + ], + getContent: ['GET /repos/{owner}/{repo}/contents/{path}'], + getContributorsStats: ['GET /repos/{owner}/{repo}/stats/contributors'], + getDeployKey: ['GET /repos/{owner}/{repo}/keys/{key_id}'], + getDeployment: [ + 'GET /repos/{owner}/{repo}/deployments/{deployment_id}', + ], + getDeploymentStatus: [ + 'GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id}', + ], + getEnvironment: [ + 'GET /repos/{owner}/{repo}/environments/{environment_name}', + ], + getLatestPagesBuild: ['GET /repos/{owner}/{repo}/pages/builds/latest'], + getLatestRelease: ['GET /repos/{owner}/{repo}/releases/latest'], + getPages: ['GET /repos/{owner}/{repo}/pages'], + getPagesBuild: ['GET /repos/{owner}/{repo}/pages/builds/{build_id}'], + getPagesHealthCheck: ['GET /repos/{owner}/{repo}/pages/health'], + getParticipationStats: [ + 'GET /repos/{owner}/{repo}/stats/participation', + ], + getPullRequestReviewProtection: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews', + ], + getPunchCardStats: ['GET /repos/{owner}/{repo}/stats/punch_card'], + getReadme: ['GET /repos/{owner}/{repo}/readme'], + getReadmeInDirectory: ['GET /repos/{owner}/{repo}/readme/{dir}'], + getRelease: ['GET /repos/{owner}/{repo}/releases/{release_id}'], + getReleaseAsset: [ + 'GET /repos/{owner}/{repo}/releases/assets/{asset_id}', + ], + getReleaseByTag: ['GET /repos/{owner}/{repo}/releases/tags/{tag}'], + getStatusChecksProtection: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks', + ], + getTeamsWithAccessToProtectedBranch: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams', + ], + getTopPaths: ['GET /repos/{owner}/{repo}/traffic/popular/paths'], + getTopReferrers: [ + 'GET /repos/{owner}/{repo}/traffic/popular/referrers', + ], + getUsersWithAccessToProtectedBranch: [ + 'GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users', + ], + getViews: ['GET /repos/{owner}/{repo}/traffic/views'], + getWebhook: ['GET /repos/{owner}/{repo}/hooks/{hook_id}'], + getWebhookConfigForRepo: [ + 'GET /repos/{owner}/{repo}/hooks/{hook_id}/config', + ], + getWebhookDelivery: [ + 'GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}', + ], + listAutolinks: ['GET /repos/{owner}/{repo}/autolinks'], + listBranches: ['GET /repos/{owner}/{repo}/branches'], + listBranchesForHeadCommit: [ + 'GET /repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head', + ], + listCollaborators: ['GET /repos/{owner}/{repo}/collaborators'], + listCommentsForCommit: [ + 'GET /repos/{owner}/{repo}/commits/{commit_sha}/comments', + ], + listCommitCommentsForRepo: ['GET /repos/{owner}/{repo}/comments'], + listCommitStatusesForRef: [ + 'GET /repos/{owner}/{repo}/commits/{ref}/statuses', + ], + listCommits: ['GET /repos/{owner}/{repo}/commits'], + listContributors: ['GET /repos/{owner}/{repo}/contributors'], + listDeployKeys: ['GET /repos/{owner}/{repo}/keys'], + listDeploymentStatuses: [ + 'GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses', + ], + listDeployments: ['GET /repos/{owner}/{repo}/deployments'], + listForAuthenticatedUser: ['GET /user/repos'], + listForOrg: ['GET /orgs/{org}/repos'], + listForUser: ['GET /users/{username}/repos'], + listForks: ['GET /repos/{owner}/{repo}/forks'], + listInvitations: ['GET /repos/{owner}/{repo}/invitations'], + listInvitationsForAuthenticatedUser: [ + 'GET /user/repository_invitations', + ], + listLanguages: ['GET /repos/{owner}/{repo}/languages'], + listPagesBuilds: ['GET /repos/{owner}/{repo}/pages/builds'], + listPublic: ['GET /repositories'], + listPullRequestsAssociatedWithCommit: [ + 'GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls', + ], + listReleaseAssets: [ + 'GET /repos/{owner}/{repo}/releases/{release_id}/assets', + ], + listReleases: ['GET /repos/{owner}/{repo}/releases'], + listTagProtection: ['GET /repos/{owner}/{repo}/tags/protection'], + listTags: ['GET /repos/{owner}/{repo}/tags'], + listTeams: ['GET /repos/{owner}/{repo}/teams'], + listWebhookDeliveries: [ + 'GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries', + ], + listWebhooks: ['GET /repos/{owner}/{repo}/hooks'], + merge: ['POST /repos/{owner}/{repo}/merges'], + mergeUpstream: ['POST /repos/{owner}/{repo}/merge-upstream'], + pingWebhook: ['POST /repos/{owner}/{repo}/hooks/{hook_id}/pings'], + redeliverWebhookDelivery: [ + 'POST /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}/attempts', + ], + removeAppAccessRestrictions: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps', + {}, + { mapToData: 'apps' }, + ], + removeCollaborator: [ + 'DELETE /repos/{owner}/{repo}/collaborators/{username}', + ], + removeStatusCheckContexts: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts', + {}, + { mapToData: 'contexts' }, + ], + removeStatusCheckProtection: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks', + ], + removeTeamAccessRestrictions: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams', + {}, + { mapToData: 'teams' }, + ], + removeUserAccessRestrictions: [ + 'DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users', + {}, + { mapToData: 'users' }, + ], + renameBranch: ['POST /repos/{owner}/{repo}/branches/{branch}/rename'], + replaceAllTopics: ['PUT /repos/{owner}/{repo}/topics'], + requestPagesBuild: ['POST /repos/{owner}/{repo}/pages/builds'], + setAdminBranchProtection: [ + 'POST /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins', + ], + setAppAccessRestrictions: [ + 'PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps', + {}, + { mapToData: 'apps' }, + ], + setStatusCheckContexts: [ + 'PUT /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts', + {}, + { mapToData: 'contexts' }, + ], + setTeamAccessRestrictions: [ + 'PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams', + {}, + { mapToData: 'teams' }, + ], + setUserAccessRestrictions: [ + 'PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users', + {}, + { mapToData: 'users' }, + ], + testPushWebhook: ['POST /repos/{owner}/{repo}/hooks/{hook_id}/tests'], + transfer: ['POST /repos/{owner}/{repo}/transfer'], + update: ['PATCH /repos/{owner}/{repo}'], + updateBranchProtection: [ + 'PUT /repos/{owner}/{repo}/branches/{branch}/protection', + ], + updateCommitComment: [ + 'PATCH /repos/{owner}/{repo}/comments/{comment_id}', + ], + updateInformationAboutPagesSite: ['PUT /repos/{owner}/{repo}/pages'], + updateInvitation: [ + 'PATCH /repos/{owner}/{repo}/invitations/{invitation_id}', + ], + updatePullRequestReviewProtection: [ + 'PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews', + ], + updateRelease: ['PATCH /repos/{owner}/{repo}/releases/{release_id}'], + updateReleaseAsset: [ + 'PATCH /repos/{owner}/{repo}/releases/assets/{asset_id}', + ], + updateStatusCheckPotection: [ + 'PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks', + {}, + { renamed: ['repos', 'updateStatusCheckProtection'] }, + ], + updateStatusCheckProtection: [ + 'PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks', + ], + updateWebhook: ['PATCH /repos/{owner}/{repo}/hooks/{hook_id}'], + updateWebhookConfigForRepo: [ + 'PATCH /repos/{owner}/{repo}/hooks/{hook_id}/config', + ], + uploadReleaseAsset: [ + 'POST /repos/{owner}/{repo}/releases/{release_id}/assets{?name,label}', + { baseUrl: 'https://uploads.github.com' }, + ], + }, + search: { + code: ['GET /search/code'], + commits: ['GET /search/commits'], + issuesAndPullRequests: ['GET /search/issues'], + labels: ['GET /search/labels'], + repos: ['GET /search/repositories'], + topics: ['GET /search/topics'], + users: ['GET /search/users'], + }, + secretScanning: { + getAlert: [ + 'GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}', + ], + listAlertsForEnterprise: [ + 'GET /enterprises/{enterprise}/secret-scanning/alerts', + ], + listAlertsForOrg: ['GET /orgs/{org}/secret-scanning/alerts'], + listAlertsForRepo: ['GET /repos/{owner}/{repo}/secret-scanning/alerts'], + listLocationsForAlert: [ + 'GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations', + ], + updateAlert: [ + 'PATCH /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}', + ], + }, + teams: { + addOrUpdateMembershipForUserInOrg: [ + 'PUT /orgs/{org}/teams/{team_slug}/memberships/{username}', + ], + addOrUpdateProjectPermissionsInOrg: [ + 'PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}', + ], + addOrUpdateRepoPermissionsInOrg: [ + 'PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}', + ], + checkPermissionsForProjectInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/projects/{project_id}', + ], + checkPermissionsForRepoInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}', + ], + create: ['POST /orgs/{org}/teams'], + createDiscussionCommentInOrg: [ + 'POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments', + ], + createDiscussionInOrg: [ + 'POST /orgs/{org}/teams/{team_slug}/discussions', + ], + deleteDiscussionCommentInOrg: [ + 'DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}', + ], + deleteDiscussionInOrg: [ + 'DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}', + ], + deleteInOrg: ['DELETE /orgs/{org}/teams/{team_slug}'], + getByName: ['GET /orgs/{org}/teams/{team_slug}'], + getDiscussionCommentInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}', + ], + getDiscussionInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}', + ], + getMembershipForUserInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/memberships/{username}', + ], + list: ['GET /orgs/{org}/teams'], + listChildInOrg: ['GET /orgs/{org}/teams/{team_slug}/teams'], + listDiscussionCommentsInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments', + ], + listDiscussionsInOrg: ['GET /orgs/{org}/teams/{team_slug}/discussions'], + listForAuthenticatedUser: ['GET /user/teams'], + listMembersInOrg: ['GET /orgs/{org}/teams/{team_slug}/members'], + listPendingInvitationsInOrg: [ + 'GET /orgs/{org}/teams/{team_slug}/invitations', + ], + listProjectsInOrg: ['GET /orgs/{org}/teams/{team_slug}/projects'], + listReposInOrg: ['GET /orgs/{org}/teams/{team_slug}/repos'], + removeMembershipForUserInOrg: [ + 'DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}', + ], + removeProjectInOrg: [ + 'DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}', + ], + removeRepoInOrg: [ + 'DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}', + ], + updateDiscussionCommentInOrg: [ + 'PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}', + ], + updateDiscussionInOrg: [ + 'PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}', + ], + updateInOrg: ['PATCH /orgs/{org}/teams/{team_slug}'], + }, + users: { + addEmailForAuthenticated: [ + 'POST /user/emails', + {}, + { renamed: ['users', 'addEmailForAuthenticatedUser'] }, + ], + addEmailForAuthenticatedUser: ['POST /user/emails'], + block: ['PUT /user/blocks/{username}'], + checkBlocked: ['GET /user/blocks/{username}'], + checkFollowingForUser: [ + 'GET /users/{username}/following/{target_user}', + ], + checkPersonIsFollowedByAuthenticated: [ + 'GET /user/following/{username}', + ], + createGpgKeyForAuthenticated: [ + 'POST /user/gpg_keys', + {}, + { renamed: ['users', 'createGpgKeyForAuthenticatedUser'] }, + ], + createGpgKeyForAuthenticatedUser: ['POST /user/gpg_keys'], + createPublicSshKeyForAuthenticated: [ + 'POST /user/keys', + {}, + { renamed: ['users', 'createPublicSshKeyForAuthenticatedUser'] }, + ], + createPublicSshKeyForAuthenticatedUser: ['POST /user/keys'], + deleteEmailForAuthenticated: [ + 'DELETE /user/emails', + {}, + { renamed: ['users', 'deleteEmailForAuthenticatedUser'] }, + ], + deleteEmailForAuthenticatedUser: ['DELETE /user/emails'], + deleteGpgKeyForAuthenticated: [ + 'DELETE /user/gpg_keys/{gpg_key_id}', + {}, + { renamed: ['users', 'deleteGpgKeyForAuthenticatedUser'] }, + ], + deleteGpgKeyForAuthenticatedUser: [ + 'DELETE /user/gpg_keys/{gpg_key_id}', + ], + deletePublicSshKeyForAuthenticated: [ + 'DELETE /user/keys/{key_id}', + {}, + { renamed: ['users', 'deletePublicSshKeyForAuthenticatedUser'] }, + ], + deletePublicSshKeyForAuthenticatedUser: ['DELETE /user/keys/{key_id}'], + follow: ['PUT /user/following/{username}'], + getAuthenticated: ['GET /user'], + getByUsername: ['GET /users/{username}'], + getContextForUser: ['GET /users/{username}/hovercard'], + getGpgKeyForAuthenticated: [ + 'GET /user/gpg_keys/{gpg_key_id}', + {}, + { renamed: ['users', 'getGpgKeyForAuthenticatedUser'] }, + ], + getGpgKeyForAuthenticatedUser: ['GET /user/gpg_keys/{gpg_key_id}'], + getPublicSshKeyForAuthenticated: [ + 'GET /user/keys/{key_id}', + {}, + { renamed: ['users', 'getPublicSshKeyForAuthenticatedUser'] }, + ], + getPublicSshKeyForAuthenticatedUser: ['GET /user/keys/{key_id}'], + list: ['GET /users'], + listBlockedByAuthenticated: [ + 'GET /user/blocks', + {}, + { renamed: ['users', 'listBlockedByAuthenticatedUser'] }, + ], + listBlockedByAuthenticatedUser: ['GET /user/blocks'], + listEmailsForAuthenticated: [ + 'GET /user/emails', + {}, + { renamed: ['users', 'listEmailsForAuthenticatedUser'] }, + ], + listEmailsForAuthenticatedUser: ['GET /user/emails'], + listFollowedByAuthenticated: [ + 'GET /user/following', + {}, + { renamed: ['users', 'listFollowedByAuthenticatedUser'] }, + ], + listFollowedByAuthenticatedUser: ['GET /user/following'], + listFollowersForAuthenticatedUser: ['GET /user/followers'], + listFollowersForUser: ['GET /users/{username}/followers'], + listFollowingForUser: ['GET /users/{username}/following'], + listGpgKeysForAuthenticated: [ + 'GET /user/gpg_keys', + {}, + { renamed: ['users', 'listGpgKeysForAuthenticatedUser'] }, + ], + listGpgKeysForAuthenticatedUser: ['GET /user/gpg_keys'], + listGpgKeysForUser: ['GET /users/{username}/gpg_keys'], + listPublicEmailsForAuthenticated: [ + 'GET /user/public_emails', + {}, + { renamed: ['users', 'listPublicEmailsForAuthenticatedUser'] }, + ], + listPublicEmailsForAuthenticatedUser: ['GET /user/public_emails'], + listPublicKeysForUser: ['GET /users/{username}/keys'], + listPublicSshKeysForAuthenticated: [ + 'GET /user/keys', + {}, + { renamed: ['users', 'listPublicSshKeysForAuthenticatedUser'] }, + ], + listPublicSshKeysForAuthenticatedUser: ['GET /user/keys'], + setPrimaryEmailVisibilityForAuthenticated: [ + 'PATCH /user/email/visibility', + {}, + { + renamed: ['users', 'setPrimaryEmailVisibilityForAuthenticatedUser'], + }, + ], + setPrimaryEmailVisibilityForAuthenticatedUser: [ + 'PATCH /user/email/visibility', + ], + unblock: ['DELETE /user/blocks/{username}'], + unfollow: ['DELETE /user/following/{username}'], + updateAuthenticated: ['PATCH /user'], + }, + } + const d = '5.16.2' + function endpointsToMethods(e, p) { + const a = {} + for (const [d, t] of Object.entries(p)) { + for (const [p, r] of Object.entries(t)) { + const [t, s, i] = r + const [o, n] = t.split(/ /) + const l = Object.assign({ method: o, url: n }, s) + if (!a[d]) { + a[d] = {} + } + const m = a[d] + if (i) { + m[p] = decorate(e, d, p, l, i) + continue + } + m[p] = e.request.defaults(l) + } + } + return a + } + function decorate(e, p, a, d, t) { + const r = e.request.defaults(d) + function withDecorations(...d) { + let s = r.endpoint.merge(...d) + if (t.mapToData) { + s = Object.assign({}, s, { + data: s[t.mapToData], + [t.mapToData]: undefined, + }) + return r(s) + } + if (t.renamed) { + const [d, r] = t.renamed + e.log.warn( + `octokit.${p}.${a}() has been renamed to octokit.${d}.${r}()` + ) + } + if (t.deprecated) { + e.log.warn(t.deprecated) + } + if (t.renamedParameters) { + const s = r.endpoint.merge(...d) + for (const [d, r] of Object.entries(t.renamedParameters)) { + if (d in s) { + e.log.warn( + `"${d}" parameter is deprecated for "octokit.${p}.${a}()". Use "${r}" instead` + ) + if (!(r in s)) { + s[r] = s[d] + } + delete s[d] + } + } + return r(s) + } + return r(...d) + } + return Object.assign(withDecorations, r) + } + function restEndpointMethods(e) { + const p = endpointsToMethods(e, a) + return { rest: p } + } + restEndpointMethods.VERSION = d + function legacyRestEndpointMethods(e) { + const p = endpointsToMethods(e, a) + return _objectSpread2(_objectSpread2({}, p), {}, { rest: p }) + } + legacyRestEndpointMethods.VERSION = d + p.legacyRestEndpointMethods = legacyRestEndpointMethods + p.restEndpointMethods = restEndpointMethods + }, + 537: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + function _interopDefault(e) { + return e && typeof e === 'object' && 'default' in e ? e['default'] : e + } + var d = a(8932) + var t = _interopDefault(a(1223)) + const r = t((e) => console.warn(e)) + const s = t((e) => console.warn(e)) + class RequestError extends Error { + constructor(e, p, a) { + super(e) + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor) + } + this.name = 'HttpError' + this.status = p + let t + if ('headers' in a && typeof a.headers !== 'undefined') { + t = a.headers + } + if ('response' in a) { + this.response = a.response + t = a.response.headers + } + const i = Object.assign({}, a.request) + if (a.request.headers.authorization) { + i.headers = Object.assign({}, a.request.headers, { + authorization: a.request.headers.authorization.replace( + / .*$/, + ' [REDACTED]' + ), + }) + } + i.url = i.url + .replace(/\bclient_secret=\w+/g, 'client_secret=[REDACTED]') + .replace(/\baccess_token=\w+/g, 'access_token=[REDACTED]') + this.request = i + Object.defineProperty(this, 'code', { + get() { + r( + new d.Deprecation( + '[@octokit/request-error] `error.code` is deprecated, use `error.status`.' + ) + ) + return p + }, + }) + Object.defineProperty(this, 'headers', { + get() { + s( + new d.Deprecation( + '[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`.' + ) + ) + return t || {} + }, + }) + } + } + p.RequestError = RequestError + }, + 6234: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + function _interopDefault(e) { + return e && typeof e === 'object' && 'default' in e ? e['default'] : e + } + var d = a(9440) + var t = a(5030) + var r = a(3287) + var s = _interopDefault(a(467)) + var i = a(537) + const o = '5.6.3' + function getBufferResponse(e) { + return e.arrayBuffer() + } + function fetchWrapper(e) { + const p = e.request && e.request.log ? e.request.log : console + if (r.isPlainObject(e.body) || Array.isArray(e.body)) { + e.body = JSON.stringify(e.body) + } + let a = {} + let d + let t + const o = (e.request && e.request.fetch) || s + return o( + e.url, + Object.assign( + { + method: e.method, + body: e.body, + headers: e.headers, + redirect: e.redirect, + }, + e.request + ) + ) + .then(async (r) => { + t = r.url + d = r.status + for (const e of r.headers) { + a[e[0]] = e[1] + } + if ('deprecation' in a) { + const d = a.link && a.link.match(/<([^>]+)>; rel="deprecation"/) + const t = d && d.pop() + p.warn( + `[@octokit/request] "${e.method} ${ + e.url + }" is deprecated. It is scheduled to be removed on ${a.sunset}${ + t ? `. See ${t}` : '' + }` + ) + } + if (d === 204 || d === 205) { + return + } + if (e.method === 'HEAD') { + if (d < 400) { + return + } + throw new i.RequestError(r.statusText, d, { + response: { url: t, status: d, headers: a, data: undefined }, + request: e, + }) + } + if (d === 304) { + throw new i.RequestError('Not modified', d, { + response: { + url: t, + status: d, + headers: a, + data: await getResponseData(r), + }, + request: e, + }) + } + if (d >= 400) { + const p = await getResponseData(r) + const s = new i.RequestError(toErrorMessage(p), d, { + response: { url: t, status: d, headers: a, data: p }, + request: e, + }) + throw s + } + return getResponseData(r) + }) + .then((e) => ({ status: d, url: t, headers: a, data: e })) + .catch((p) => { + if (p instanceof i.RequestError) throw p + throw new i.RequestError(p.message, 500, { request: e }) + }) + } + async function getResponseData(e) { + const p = e.headers.get('content-type') + if (/application\/json/.test(p)) { + return e.json() + } + if (!p || /^text\/|charset=utf-8$/.test(p)) { + return e.text() + } + return getBufferResponse(e) + } + function toErrorMessage(e) { + if (typeof e === 'string') return e + if ('message' in e) { + if (Array.isArray(e.errors)) { + return `${e.message}: ${e.errors.map(JSON.stringify).join(', ')}` + } + return e.message + } + return `Unknown error: ${JSON.stringify(e)}` + } + function withDefaults(e, p) { + const a = e.defaults(p) + const newApi = function (e, p) { + const d = a.merge(e, p) + if (!d.request || !d.request.hook) { + return fetchWrapper(a.parse(d)) + } + const request = (e, p) => fetchWrapper(a.parse(a.merge(e, p))) + Object.assign(request, { + endpoint: a, + defaults: withDefaults.bind(null, a), + }) + return d.request.hook(request, d) + } + return Object.assign(newApi, { + endpoint: a, + defaults: withDefaults.bind(null, a), + }) + } + const n = withDefaults(d.endpoint, { + headers: { 'user-agent': `octokit-request.js/${o} ${t.getUserAgent()}` }, + }) + p.request = n + }, + 3682: (e, p, a) => { + var d = a(4670) + var t = a(5549) + var r = a(6819) + var s = Function.bind + var i = s.bind(s) + function bindApi(e, p, a) { + var d = i(r, null).apply(null, a ? [p, a] : [p]) + e.api = { remove: d } + e.remove = d + ;['before', 'error', 'after', 'wrap'].forEach(function (d) { + var r = a ? [p, d, a] : [p, d] + e[d] = e.api[d] = i(t, null).apply(null, r) + }) + } + function HookSingular() { + var e = 'h' + var p = { registry: {} } + var a = d.bind(null, p, e) + bindApi(a, p, e) + return a + } + function HookCollection() { + var e = { registry: {} } + var p = d.bind(null, e) + bindApi(p, e) + return p + } + var o = false + function Hook() { + if (!o) { + console.warn( + '[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4' + ) + o = true + } + return HookCollection() + } + Hook.Singular = HookSingular.bind() + Hook.Collection = HookCollection.bind() + e.exports = Hook + e.exports.Hook = Hook + e.exports.Singular = Hook.Singular + e.exports.Collection = Hook.Collection + }, + 5549: (e) => { + e.exports = addHook + function addHook(e, p, a, d) { + var t = d + if (!e.registry[a]) { + e.registry[a] = [] + } + if (p === 'before') { + d = function (e, p) { + return Promise.resolve().then(t.bind(null, p)).then(e.bind(null, p)) + } + } + if (p === 'after') { + d = function (e, p) { + var a + return Promise.resolve() + .then(e.bind(null, p)) + .then(function (e) { + a = e + return t(a, p) + }) + .then(function () { + return a + }) + } + } + if (p === 'error') { + d = function (e, p) { + return Promise.resolve() + .then(e.bind(null, p)) + .catch(function (e) { + return t(e, p) + }) + } + } + e.registry[a].push({ hook: d, orig: t }) + } + }, + 4670: (e) => { + e.exports = register + function register(e, p, a, d) { + if (typeof a !== 'function') { + throw new Error('method for before hook must be a function') + } + if (!d) { + d = {} + } + if (Array.isArray(p)) { + return p.reverse().reduce(function (p, a) { + return register.bind(null, e, a, p, d) + }, a)() + } + return Promise.resolve().then(function () { + if (!e.registry[p]) { + return a(d) + } + return e.registry[p].reduce(function (e, p) { + return p.hook.bind(null, e, d) + }, a)() + }) + } + }, + 6819: (e) => { + e.exports = removeHook + function removeHook(e, p, a) { + if (!e.registry[p]) { + return + } + var d = e.registry[p] + .map(function (e) { + return e.orig + }) + .indexOf(a) + if (d === -1) { + return + } + e.registry[p].splice(d, 1) + } + }, + 8932: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + class Deprecation extends Error { + constructor(e) { + super(e) + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor) + } + this.name = 'Deprecation' + } + } + p.Deprecation = Deprecation + }, + 3287: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + /*! + * is-plain-object + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ function isObject(e) { + return Object.prototype.toString.call(e) === '[object Object]' + } + function isPlainObject(e) { + var p, a + if (isObject(e) === false) return false + p = e.constructor + if (p === undefined) return true + a = p.prototype + if (isObject(a) === false) return false + if (a.hasOwnProperty('isPrototypeOf') === false) { + return false + } + return true + } + p.isPlainObject = isPlainObject + }, + 467: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + function _interopDefault(e) { + return e && typeof e === 'object' && 'default' in e ? e['default'] : e + } + var d = _interopDefault(a(2781)) + var t = _interopDefault(a(3685)) + var r = _interopDefault(a(7310)) + var s = _interopDefault(a(8665)) + var i = _interopDefault(a(5687)) + var o = _interopDefault(a(9796)) + const n = d.Readable + const l = Symbol('buffer') + const m = Symbol('type') + class Blob { + constructor() { + this[m] = '' + const e = arguments[0] + const p = arguments[1] + const a = [] + let d = 0 + if (e) { + const p = e + const t = Number(p.length) + for (let e = 0; e < t; e++) { + const t = p[e] + let r + if (t instanceof Buffer) { + r = t + } else if (ArrayBuffer.isView(t)) { + r = Buffer.from(t.buffer, t.byteOffset, t.byteLength) + } else if (t instanceof ArrayBuffer) { + r = Buffer.from(t) + } else if (t instanceof Blob) { + r = t[l] + } else { + r = Buffer.from(typeof t === 'string' ? t : String(t)) + } + d += r.length + a.push(r) + } + } + this[l] = Buffer.concat(a) + let t = p && p.type !== undefined && String(p.type).toLowerCase() + if (t && !/[^\u0020-\u007E]/.test(t)) { + this[m] = t + } + } + get size() { + return this[l].length + } + get type() { + return this[m] + } + text() { + return Promise.resolve(this[l].toString()) + } + arrayBuffer() { + const e = this[l] + const p = e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength) + return Promise.resolve(p) + } + stream() { + const e = new n() + e._read = function () {} + e.push(this[l]) + e.push(null) + return e + } + toString() { + return '[object Blob]' + } + slice() { + const e = this.size + const p = arguments[0] + const a = arguments[1] + let d, t + if (p === undefined) { + d = 0 + } else if (p < 0) { + d = Math.max(e + p, 0) + } else { + d = Math.min(p, e) + } + if (a === undefined) { + t = e + } else if (a < 0) { + t = Math.max(e + a, 0) + } else { + t = Math.min(a, e) + } + const r = Math.max(t - d, 0) + const s = this[l] + const i = s.slice(d, d + r) + const o = new Blob([], { type: arguments[2] }) + o[l] = i + return o + } + } + Object.defineProperties(Blob.prototype, { + size: { enumerable: true }, + type: { enumerable: true }, + slice: { enumerable: true }, + }) + Object.defineProperty(Blob.prototype, Symbol.toStringTag, { + value: 'Blob', + writable: false, + enumerable: false, + configurable: true, + }) + function FetchError(e, p, a) { + Error.call(this, e) + this.message = e + this.type = p + if (a) { + this.code = this.errno = a.code + } + Error.captureStackTrace(this, this.constructor) + } + FetchError.prototype = Object.create(Error.prototype) + FetchError.prototype.constructor = FetchError + FetchError.prototype.name = 'FetchError' + let u + try { + u = a(2877).convert + } catch (e) {} + const c = Symbol('Body internals') + const v = d.PassThrough + function Body(e) { + var p = this + var a = + arguments.length > 1 && arguments[1] !== undefined + ? arguments[1] + : {}, + t = a.size + let r = t === undefined ? 0 : t + var s = a.timeout + let i = s === undefined ? 0 : s + if (e == null) { + e = null + } else if (isURLSearchParams(e)) { + e = Buffer.from(e.toString()) + } else if (isBlob(e)); + else if (Buffer.isBuffer(e)); + else if (Object.prototype.toString.call(e) === '[object ArrayBuffer]') { + e = Buffer.from(e) + } else if (ArrayBuffer.isView(e)) { + e = Buffer.from(e.buffer, e.byteOffset, e.byteLength) + } else if (e instanceof d); + else { + e = Buffer.from(String(e)) + } + this[c] = { body: e, disturbed: false, error: null } + this.size = r + this.timeout = i + if (e instanceof d) { + e.on('error', function (e) { + const a = + e.name === 'AbortError' + ? e + : new FetchError( + `Invalid response body while trying to fetch ${p.url}: ${e.message}`, + 'system', + e + ) + p[c].error = a + }) + } + } + Body.prototype = { + get body() { + return this[c].body + }, + get bodyUsed() { + return this[c].disturbed + }, + arrayBuffer() { + return consumeBody.call(this).then(function (e) { + return e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength) + }) + }, + blob() { + let e = (this.headers && this.headers.get('content-type')) || '' + return consumeBody.call(this).then(function (p) { + return Object.assign(new Blob([], { type: e.toLowerCase() }), { + [l]: p, + }) + }) + }, + json() { + var e = this + return consumeBody.call(this).then(function (p) { + try { + return JSON.parse(p.toString()) + } catch (p) { + return Body.Promise.reject( + new FetchError( + `invalid json response body at ${e.url} reason: ${p.message}`, + 'invalid-json' + ) + ) + } + }) + }, + text() { + return consumeBody.call(this).then(function (e) { + return e.toString() + }) + }, + buffer() { + return consumeBody.call(this) + }, + textConverted() { + var e = this + return consumeBody.call(this).then(function (p) { + return convertBody(p, e.headers) + }) + }, + } + Object.defineProperties(Body.prototype, { + body: { enumerable: true }, + bodyUsed: { enumerable: true }, + arrayBuffer: { enumerable: true }, + blob: { enumerable: true }, + json: { enumerable: true }, + text: { enumerable: true }, + }) + Body.mixIn = function (e) { + for (const p of Object.getOwnPropertyNames(Body.prototype)) { + if (!(p in e)) { + const a = Object.getOwnPropertyDescriptor(Body.prototype, p) + Object.defineProperty(e, p, a) + } + } + } + function consumeBody() { + var e = this + if (this[c].disturbed) { + return Body.Promise.reject( + new TypeError(`body used already for: ${this.url}`) + ) + } + this[c].disturbed = true + if (this[c].error) { + return Body.Promise.reject(this[c].error) + } + let p = this.body + if (p === null) { + return Body.Promise.resolve(Buffer.alloc(0)) + } + if (isBlob(p)) { + p = p.stream() + } + if (Buffer.isBuffer(p)) { + return Body.Promise.resolve(p) + } + if (!(p instanceof d)) { + return Body.Promise.resolve(Buffer.alloc(0)) + } + let a = [] + let t = 0 + let r = false + return new Body.Promise(function (d, s) { + let i + if (e.timeout) { + i = setTimeout(function () { + r = true + s( + new FetchError( + `Response timeout while trying to fetch ${e.url} (over ${e.timeout}ms)`, + 'body-timeout' + ) + ) + }, e.timeout) + } + p.on('error', function (p) { + if (p.name === 'AbortError') { + r = true + s(p) + } else { + s( + new FetchError( + `Invalid response body while trying to fetch ${e.url}: ${p.message}`, + 'system', + p + ) + ) + } + }) + p.on('data', function (p) { + if (r || p === null) { + return + } + if (e.size && t + p.length > e.size) { + r = true + s( + new FetchError( + `content size at ${e.url} over limit: ${e.size}`, + 'max-size' + ) + ) + return + } + t += p.length + a.push(p) + }) + p.on('end', function () { + if (r) { + return + } + clearTimeout(i) + try { + d(Buffer.concat(a, t)) + } catch (p) { + s( + new FetchError( + `Could not create Buffer from response body for ${e.url}: ${p.message}`, + 'system', + p + ) + ) + } + }) + }) + } + function convertBody(e, p) { + if (typeof u !== 'function') { + throw new Error( + 'The package `encoding` must be installed to use the textConverted() function' + ) + } + const a = p.get('content-type') + let d = 'utf-8' + let t, r + if (a) { + t = /charset=([^;]*)/i.exec(a) + } + r = e.slice(0, 1024).toString() + if (!t && r) { + t = / 0 && arguments[0] !== undefined + ? arguments[0] + : undefined + this[w] = Object.create(null) + if (e instanceof Headers) { + const p = e.raw() + const a = Object.keys(p) + for (const e of a) { + for (const a of p[e]) { + this.append(e, a) + } + } + return + } + if (e == null); + else if (typeof e === 'object') { + const p = e[Symbol.iterator] + if (p != null) { + if (typeof p !== 'function') { + throw new TypeError('Header pairs must be iterable') + } + const a = [] + for (const p of e) { + if ( + typeof p !== 'object' || + typeof p[Symbol.iterator] !== 'function' + ) { + throw new TypeError('Each header pair must be iterable') + } + a.push(Array.from(p)) + } + for (const e of a) { + if (e.length !== 2) { + throw new TypeError( + 'Each header pair must be a name/value tuple' + ) + } + this.append(e[0], e[1]) + } + } else { + for (const p of Object.keys(e)) { + const a = e[p] + this.append(p, a) + } + } + } else { + throw new TypeError('Provided initializer must be an object') + } + } + get(e) { + e = `${e}` + validateName(e) + const p = find(this[w], e) + if (p === undefined) { + return null + } + return this[w][p].join(', ') + } + forEach(e) { + let p = + arguments.length > 1 && arguments[1] !== undefined + ? arguments[1] + : undefined + let a = getHeaders(this) + let d = 0 + while (d < a.length) { + var t = a[d] + const r = t[0], + s = t[1] + e.call(p, s, r, this) + a = getHeaders(this) + d++ + } + } + set(e, p) { + e = `${e}` + p = `${p}` + validateName(e) + validateValue(p) + const a = find(this[w], e) + this[w][a !== undefined ? a : e] = [p] + } + append(e, p) { + e = `${e}` + p = `${p}` + validateName(e) + validateValue(p) + const a = find(this[w], e) + if (a !== undefined) { + this[w][a].push(p) + } else { + this[w][e] = [p] + } + } + has(e) { + e = `${e}` + validateName(e) + return find(this[w], e) !== undefined + } + delete(e) { + e = `${e}` + validateName(e) + const p = find(this[w], e) + if (p !== undefined) { + delete this[w][p] + } + } + raw() { + return this[w] + } + keys() { + return createHeadersIterator(this, 'key') + } + values() { + return createHeadersIterator(this, 'value') + } + [Symbol.iterator]() { + return createHeadersIterator(this, 'key+value') + } + } + Headers.prototype.entries = Headers.prototype[Symbol.iterator] + Object.defineProperty(Headers.prototype, Symbol.toStringTag, { + value: 'Headers', + writable: false, + enumerable: false, + configurable: true, + }) + Object.defineProperties(Headers.prototype, { + get: { enumerable: true }, + forEach: { enumerable: true }, + set: { enumerable: true }, + append: { enumerable: true }, + has: { enumerable: true }, + delete: { enumerable: true }, + keys: { enumerable: true }, + values: { enumerable: true }, + entries: { enumerable: true }, + }) + function getHeaders(e) { + let p = + arguments.length > 1 && arguments[1] !== undefined + ? arguments[1] + : 'key+value' + const a = Object.keys(e[w]).sort() + return a.map( + p === 'key' + ? function (e) { + return e.toLowerCase() + } + : p === 'value' + ? function (p) { + return e[w][p].join(', ') + } + : function (p) { + return [p.toLowerCase(), e[w][p].join(', ')] + } + ) + } + const _ = Symbol('internal') + function createHeadersIterator(e, p) { + const a = Object.create(T) + a[_] = { target: e, kind: p, index: 0 } + return a + } + const T = Object.setPrototypeOf( + { + next() { + if (!this || Object.getPrototypeOf(this) !== T) { + throw new TypeError('Value of `this` is not a HeadersIterator') + } + var e = this[_] + const p = e.target, + a = e.kind, + d = e.index + const t = getHeaders(p, a) + const r = t.length + if (d >= r) { + return { value: undefined, done: true } + } + this[_].index = d + 1 + return { value: t[d], done: false } + }, + }, + Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())) + ) + Object.defineProperty(T, Symbol.toStringTag, { + value: 'HeadersIterator', + writable: false, + enumerable: false, + configurable: true, + }) + function exportNodeCompatibleHeaders(e) { + const p = Object.assign({ __proto__: null }, e[w]) + const a = find(e[w], 'Host') + if (a !== undefined) { + p[a] = p[a][0] + } + return p + } + function createHeadersLenient(e) { + const p = new Headers() + for (const a of Object.keys(e)) { + if (h.test(a)) { + continue + } + if (Array.isArray(e[a])) { + for (const d of e[a]) { + if (g.test(d)) { + continue + } + if (p[w][a] === undefined) { + p[w][a] = [d] + } else { + p[w][a].push(d) + } + } + } else if (!g.test(e[a])) { + p[w][a] = [e[a]] + } + } + return p + } + const E = Symbol('Response internals') + const b = t.STATUS_CODES + class Response { + constructor() { + let e = + arguments.length > 0 && arguments[0] !== undefined + ? arguments[0] + : null + let p = + arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {} + Body.call(this, e, p) + const a = p.status || 200 + const d = new Headers(p.headers) + if (e != null && !d.has('Content-Type')) { + const p = extractContentType(e) + if (p) { + d.append('Content-Type', p) + } + } + this[E] = { + url: p.url, + status: a, + statusText: p.statusText || b[a], + headers: d, + counter: p.counter, + } + } + get url() { + return this[E].url || '' + } + get status() { + return this[E].status + } + get ok() { + return this[E].status >= 200 && this[E].status < 300 + } + get redirected() { + return this[E].counter > 0 + } + get statusText() { + return this[E].statusText + } + get headers() { + return this[E].headers + } + clone() { + return new Response(clone(this), { + url: this.url, + status: this.status, + statusText: this.statusText, + headers: this.headers, + ok: this.ok, + redirected: this.redirected, + }) + } + } + Body.mixIn(Response.prototype) + Object.defineProperties(Response.prototype, { + url: { enumerable: true }, + status: { enumerable: true }, + ok: { enumerable: true }, + redirected: { enumerable: true }, + statusText: { enumerable: true }, + headers: { enumerable: true }, + clone: { enumerable: true }, + }) + Object.defineProperty(Response.prototype, Symbol.toStringTag, { + value: 'Response', + writable: false, + enumerable: false, + configurable: true, + }) + const y = Symbol('Request internals') + const S = r.URL || s.URL + const D = r.parse + const P = r.format + function parseURL(e) { + if (/^[a-zA-Z][a-zA-Z\d+\-.]*:/.exec(e)) { + e = new S(e).toString() + } + return D(e) + } + const A = 'destroy' in d.Readable.prototype + function isRequest(e) { + return typeof e === 'object' && typeof e[y] === 'object' + } + function isAbortSignal(e) { + const p = e && typeof e === 'object' && Object.getPrototypeOf(e) + return !!(p && p.constructor.name === 'AbortSignal') + } + class Request { + constructor(e) { + let p = + arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {} + let a + if (!isRequest(e)) { + if (e && e.href) { + a = parseURL(e.href) + } else { + a = parseURL(`${e}`) + } + e = {} + } else { + a = parseURL(e.url) + } + let d = p.method || e.method || 'GET' + d = d.toUpperCase() + if ( + (p.body != null || (isRequest(e) && e.body !== null)) && + (d === 'GET' || d === 'HEAD') + ) { + throw new TypeError('Request with GET/HEAD method cannot have body') + } + let t = + p.body != null + ? p.body + : isRequest(e) && e.body !== null + ? clone(e) + : null + Body.call(this, t, { + timeout: p.timeout || e.timeout || 0, + size: p.size || e.size || 0, + }) + const r = new Headers(p.headers || e.headers || {}) + if (t != null && !r.has('Content-Type')) { + const e = extractContentType(t) + if (e) { + r.append('Content-Type', e) + } + } + let s = isRequest(e) ? e.signal : null + if ('signal' in p) s = p.signal + if (s != null && !isAbortSignal(s)) { + throw new TypeError('Expected signal to be an instanceof AbortSignal') + } + this[y] = { + method: d, + redirect: p.redirect || e.redirect || 'follow', + headers: r, + parsedURL: a, + signal: s, + } + this.follow = + p.follow !== undefined + ? p.follow + : e.follow !== undefined + ? e.follow + : 20 + this.compress = + p.compress !== undefined + ? p.compress + : e.compress !== undefined + ? e.compress + : true + this.counter = p.counter || e.counter || 0 + this.agent = p.agent || e.agent + } + get method() { + return this[y].method + } + get url() { + return P(this[y].parsedURL) + } + get headers() { + return this[y].headers + } + get redirect() { + return this[y].redirect + } + get signal() { + return this[y].signal + } + clone() { + return new Request(this) + } + } + Body.mixIn(Request.prototype) + Object.defineProperty(Request.prototype, Symbol.toStringTag, { + value: 'Request', + writable: false, + enumerable: false, + configurable: true, + }) + Object.defineProperties(Request.prototype, { + method: { enumerable: true }, + url: { enumerable: true }, + headers: { enumerable: true }, + redirect: { enumerable: true }, + clone: { enumerable: true }, + signal: { enumerable: true }, + }) + function getNodeRequestOptions(e) { + const p = e[y].parsedURL + const a = new Headers(e[y].headers) + if (!a.has('Accept')) { + a.set('Accept', '*/*') + } + if (!p.protocol || !p.hostname) { + throw new TypeError('Only absolute URLs are supported') + } + if (!/^https?:$/.test(p.protocol)) { + throw new TypeError('Only HTTP(S) protocols are supported') + } + if (e.signal && e.body instanceof d.Readable && !A) { + throw new Error( + 'Cancellation of streamed requests with AbortSignal is not supported in node < 8' + ) + } + let t = null + if (e.body == null && /^(POST|PUT)$/i.test(e.method)) { + t = '0' + } + if (e.body != null) { + const p = getTotalBytes(e) + if (typeof p === 'number') { + t = String(p) + } + } + if (t) { + a.set('Content-Length', t) + } + if (!a.has('User-Agent')) { + a.set( + 'User-Agent', + 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)' + ) + } + if (e.compress && !a.has('Accept-Encoding')) { + a.set('Accept-Encoding', 'gzip,deflate') + } + let r = e.agent + if (typeof r === 'function') { + r = r(p) + } + if (!a.has('Connection') && !r) { + a.set('Connection', 'close') + } + return Object.assign({}, p, { + method: e.method, + headers: exportNodeCompatibleHeaders(a), + agent: r, + }) + } + function AbortError(e) { + Error.call(this, e) + this.type = 'aborted' + this.message = e + Error.captureStackTrace(this, this.constructor) + } + AbortError.prototype = Object.create(Error.prototype) + AbortError.prototype.constructor = AbortError + AbortError.prototype.name = 'AbortError' + const O = r.URL || s.URL + const k = d.PassThrough + const N = function isDomainOrSubdomain(e, p) { + const a = new O(p).hostname + const d = new O(e).hostname + return a === d || (a[a.length - d.length - 1] === '.' && a.endsWith(d)) + } + const R = function isSameProtocol(e, p) { + const a = new O(p).protocol + const d = new O(e).protocol + return a === d + } + function fetch(e, p) { + if (!fetch.Promise) { + throw new Error( + 'native promise missing, set fetch.Promise to your favorite alternative' + ) + } + Body.Promise = fetch.Promise + return new fetch.Promise(function (a, r) { + const s = new Request(e, p) + const n = getNodeRequestOptions(s) + const l = (n.protocol === 'https:' ? i : t).request + const m = s.signal + let u = null + const c = function abort() { + let e = new AbortError('The user aborted a request.') + r(e) + if (s.body && s.body instanceof d.Readable) { + destroyStream(s.body, e) + } + if (!u || !u.body) return + u.body.emit('error', e) + } + if (m && m.aborted) { + c() + return + } + const v = function abortAndFinalize() { + c() + finalize() + } + const h = l(n) + let g + if (m) { + m.addEventListener('abort', v) + } + function finalize() { + h.abort() + if (m) m.removeEventListener('abort', v) + clearTimeout(g) + } + if (s.timeout) { + h.once('socket', function (e) { + g = setTimeout(function () { + r( + new FetchError( + `network timeout at: ${s.url}`, + 'request-timeout' + ) + ) + finalize() + }, s.timeout) + }) + } + h.on('error', function (e) { + r( + new FetchError( + `request to ${s.url} failed, reason: ${e.message}`, + 'system', + e + ) + ) + if (u && u.body) { + destroyStream(u.body, e) + } + finalize() + }) + fixResponseChunkedTransferBadEnding(h, function (e) { + if (m && m.aborted) { + return + } + if (u && u.body) { + destroyStream(u.body, e) + } + }) + if (parseInt(process.version.substring(1)) < 14) { + h.on('socket', function (e) { + e.addListener('close', function (p) { + const a = e.listenerCount('data') > 0 + if (u && a && !p && !(m && m.aborted)) { + const e = new Error('Premature close') + e.code = 'ERR_STREAM_PREMATURE_CLOSE' + u.body.emit('error', e) + } + }) + }) + } + h.on('response', function (e) { + clearTimeout(g) + const p = createHeadersLenient(e.headers) + if (fetch.isRedirect(e.statusCode)) { + const d = p.get('Location') + let t = null + try { + t = d === null ? null : new O(d, s.url).toString() + } catch (e) { + if (s.redirect !== 'manual') { + r( + new FetchError( + `uri requested responds with an invalid redirect URL: ${d}`, + 'invalid-redirect' + ) + ) + finalize() + return + } + } + switch (s.redirect) { + case 'error': + r( + new FetchError( + `uri requested responds with a redirect, redirect mode is set to error: ${s.url}`, + 'no-redirect' + ) + ) + finalize() + return + case 'manual': + if (t !== null) { + try { + p.set('Location', t) + } catch (e) { + r(e) + } + } + break + case 'follow': + if (t === null) { + break + } + if (s.counter >= s.follow) { + r( + new FetchError( + `maximum redirect reached at: ${s.url}`, + 'max-redirect' + ) + ) + finalize() + return + } + const d = { + headers: new Headers(s.headers), + follow: s.follow, + counter: s.counter + 1, + agent: s.agent, + compress: s.compress, + method: s.method, + body: s.body, + signal: s.signal, + timeout: s.timeout, + size: s.size, + } + if (!N(s.url, t) || !R(s.url, t)) { + for (const e of [ + 'authorization', + 'www-authenticate', + 'cookie', + 'cookie2', + ]) { + d.headers.delete(e) + } + } + if ( + e.statusCode !== 303 && + s.body && + getTotalBytes(s) === null + ) { + r( + new FetchError( + 'Cannot follow redirect with body being a readable stream', + 'unsupported-redirect' + ) + ) + finalize() + return + } + if ( + e.statusCode === 303 || + ((e.statusCode === 301 || e.statusCode === 302) && + s.method === 'POST') + ) { + d.method = 'GET' + d.body = undefined + d.headers.delete('content-length') + } + a(fetch(new Request(t, d))) + finalize() + return + } + } + e.once('end', function () { + if (m) m.removeEventListener('abort', v) + }) + let d = e.pipe(new k()) + const t = { + url: s.url, + status: e.statusCode, + statusText: e.statusMessage, + headers: p, + size: s.size, + timeout: s.timeout, + counter: s.counter, + } + const i = p.get('Content-Encoding') + if ( + !s.compress || + s.method === 'HEAD' || + i === null || + e.statusCode === 204 || + e.statusCode === 304 + ) { + u = new Response(d, t) + a(u) + return + } + const n = { flush: o.Z_SYNC_FLUSH, finishFlush: o.Z_SYNC_FLUSH } + if (i == 'gzip' || i == 'x-gzip') { + d = d.pipe(o.createGunzip(n)) + u = new Response(d, t) + a(u) + return + } + if (i == 'deflate' || i == 'x-deflate') { + const p = e.pipe(new k()) + p.once('data', function (e) { + if ((e[0] & 15) === 8) { + d = d.pipe(o.createInflate()) + } else { + d = d.pipe(o.createInflateRaw()) + } + u = new Response(d, t) + a(u) + }) + p.on('end', function () { + if (!u) { + u = new Response(d, t) + a(u) + } + }) + return + } + if (i == 'br' && typeof o.createBrotliDecompress === 'function') { + d = d.pipe(o.createBrotliDecompress()) + u = new Response(d, t) + a(u) + return + } + u = new Response(d, t) + a(u) + }) + writeToStream(h, s) + }) + } + function fixResponseChunkedTransferBadEnding(e, p) { + let a + e.on('socket', function (e) { + a = e + }) + e.on('response', function (e) { + const d = e.headers + if (d['transfer-encoding'] === 'chunked' && !d['content-length']) { + e.once('close', function (e) { + const d = a.listenerCount('data') > 0 + if (d && !e) { + const e = new Error('Premature close') + e.code = 'ERR_STREAM_PREMATURE_CLOSE' + p(e) + } + }) + } + }) + } + function destroyStream(e, p) { + if (e.destroy) { + e.destroy(p) + } else { + e.emit('error', p) + e.end() + } + } + fetch.isRedirect = function (e) { + return e === 301 || e === 302 || e === 303 || e === 307 || e === 308 + } + fetch.Promise = global.Promise + e.exports = p = fetch + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = p + p.Headers = Headers + p.Request = Request + p.Response = Response + p.FetchError = FetchError + }, + 1223: (e, p, a) => { + var d = a(2940) + e.exports = d(once) + e.exports.strict = d(onceStrict) + once.proto = once(function () { + Object.defineProperty(Function.prototype, 'once', { + value: function () { + return once(this) + }, + configurable: true, + }) + Object.defineProperty(Function.prototype, 'onceStrict', { + value: function () { + return onceStrict(this) + }, + configurable: true, + }) + }) + function once(e) { + var f = function () { + if (f.called) return f.value + f.called = true + return (f.value = e.apply(this, arguments)) + } + f.called = false + return f + } + function onceStrict(e) { + var f = function () { + if (f.called) throw new Error(f.onceError) + f.called = true + return (f.value = e.apply(this, arguments)) + } + var p = e.name || 'Function wrapped with `once`' + f.onceError = p + " shouldn't be called more than once" + f.called = false + return f + } + }, + 4256: (e, p, a) => { + var d = a(5477) + var t = a(2020) + var r = { TRANSITIONAL: 0, NONTRANSITIONAL: 1 } + function normalize(e) { + return e + .split('\0') + .map(function (e) { + return e.normalize('NFC') + }) + .join('\0') + } + function findStatus(e) { + var p = 0 + var a = t.length - 1 + while (p <= a) { + var d = Math.floor((p + a) / 2) + var r = t[d] + if (r[0][0] <= e && r[0][1] >= e) { + return r + } else if (r[0][0] > e) { + a = d - 1 + } else { + p = d + 1 + } + } + return null + } + var s = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g + function countSymbols(e) { + return e.replace(s, '_').length + } + function mapChars(e, p, a) { + var d = false + var t = '' + var s = countSymbols(e) + for (var i = 0; i < s; ++i) { + var o = e.codePointAt(i) + var n = findStatus(o) + switch (n[1]) { + case 'disallowed': + d = true + t += String.fromCodePoint(o) + break + case 'ignored': + break + case 'mapped': + t += String.fromCodePoint.apply(String, n[2]) + break + case 'deviation': + if (a === r.TRANSITIONAL) { + t += String.fromCodePoint.apply(String, n[2]) + } else { + t += String.fromCodePoint(o) + } + break + case 'valid': + t += String.fromCodePoint(o) + break + case 'disallowed_STD3_mapped': + if (p) { + d = true + t += String.fromCodePoint(o) + } else { + t += String.fromCodePoint.apply(String, n[2]) + } + break + case 'disallowed_STD3_valid': + if (p) { + d = true + } + t += String.fromCodePoint(o) + break + } + } + return { string: t, error: d } + } + var i = + /[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E4-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D01-\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u18A9\u1920-\u192B\u1930-\u193B\u19B0-\u19C0\u19C8\u19C9\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF5\u1DFC-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2D]|\uD800[\uDDFD\uDEE0\uDF76-\uDF7A]|\uD802[\uDE01-\uDE03\uDE05\uDE06\uDE0C-\uDE0F\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD804[\uDC00-\uDC02\uDC38-\uDC46\uDC7F-\uDC82\uDCB0-\uDCBA\uDD00-\uDD02\uDD27-\uDD34\uDD73\uDD80-\uDD82\uDDB3-\uDDC0\uDE2C-\uDE37\uDEDF-\uDEEA\uDF01-\uDF03\uDF3C\uDF3E-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF62\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDCB0-\uDCC3\uDDAF-\uDDB5\uDDB8-\uDDC0\uDE30-\uDE40\uDEAB-\uDEB7]|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDF51-\uDF7E\uDF8F-\uDF92]|\uD82F[\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD83A[\uDCD0-\uDCD6]|\uDB40[\uDD00-\uDDEF]/ + function validateLabel(e, p) { + if (e.substr(0, 4) === 'xn--') { + e = d.toUnicode(e) + p = r.NONTRANSITIONAL + } + var a = false + if ( + normalize(e) !== e || + (e[3] === '-' && e[4] === '-') || + e[0] === '-' || + e[e.length - 1] === '-' || + e.indexOf('.') !== -1 || + e.search(i) === 0 + ) { + a = true + } + var t = countSymbols(e) + for (var s = 0; s < t; ++s) { + var o = findStatus(e.codePointAt(s)) + if ( + (processing === r.TRANSITIONAL && o[1] !== 'valid') || + (processing === r.NONTRANSITIONAL && + o[1] !== 'valid' && + o[1] !== 'deviation') + ) { + a = true + break + } + } + return { label: e, error: a } + } + function processing(e, p, a) { + var d = mapChars(e, p, a) + d.string = normalize(d.string) + var t = d.string.split('.') + for (var r = 0; r < t.length; ++r) { + try { + var s = validateLabel(t[r]) + t[r] = s.label + d.error = d.error || s.error + } catch (e) { + d.error = true + } + } + return { string: t.join('.'), error: d.error } + } + e.exports.toASCII = function (e, p, a, t) { + var r = processing(e, p, a) + var s = r.string.split('.') + s = s.map(function (e) { + try { + return d.toASCII(e) + } catch (p) { + r.error = true + return e + } + }) + if (t) { + var i = s.slice(0, s.length - 1).join('.').length + if (i.length > 253 || i.length === 0) { + r.error = true + } + for (var o = 0; o < s.length; ++o) { + if (s.length > 63 || s.length === 0) { + r.error = true + break + } + } + } + if (r.error) return null + return s.join('.') + } + e.exports.toUnicode = function (e, p) { + var a = processing(e, p, r.NONTRANSITIONAL) + return { domain: a.string, error: a.error } + } + e.exports.PROCESSING_OPTIONS = r + }, + 4294: (e, p, a) => { + e.exports = a(4219) + }, + 4219: (e, p, a) => { + var d = a(1808) + var t = a(4404) + var r = a(3685) + var s = a(5687) + var i = a(2361) + var o = a(9491) + var n = a(3837) + p.httpOverHttp = httpOverHttp + p.httpsOverHttp = httpsOverHttp + p.httpOverHttps = httpOverHttps + p.httpsOverHttps = httpsOverHttps + function httpOverHttp(e) { + var p = new TunnelingAgent(e) + p.request = r.request + return p + } + function httpsOverHttp(e) { + var p = new TunnelingAgent(e) + p.request = r.request + p.createSocket = createSecureSocket + p.defaultPort = 443 + return p + } + function httpOverHttps(e) { + var p = new TunnelingAgent(e) + p.request = s.request + return p + } + function httpsOverHttps(e) { + var p = new TunnelingAgent(e) + p.request = s.request + p.createSocket = createSecureSocket + p.defaultPort = 443 + return p + } + function TunnelingAgent(e) { + var p = this + p.options = e || {} + p.proxyOptions = p.options.proxy || {} + p.maxSockets = p.options.maxSockets || r.Agent.defaultMaxSockets + p.requests = [] + p.sockets = [] + p.on('free', function onFree(e, a, d, t) { + var r = toOptions(a, d, t) + for (var s = 0, i = p.requests.length; s < i; ++s) { + var o = p.requests[s] + if (o.host === r.host && o.port === r.port) { + p.requests.splice(s, 1) + o.request.onSocket(e) + return + } + } + e.destroy() + p.removeSocket(e) + }) + } + n.inherits(TunnelingAgent, i.EventEmitter) + TunnelingAgent.prototype.addRequest = function addRequest(e, p, a, d) { + var t = this + var r = mergeOptions({ request: e }, t.options, toOptions(p, a, d)) + if (t.sockets.length >= this.maxSockets) { + t.requests.push(r) + return + } + t.createSocket(r, function (p) { + p.on('free', onFree) + p.on('close', onCloseOrRemove) + p.on('agentRemove', onCloseOrRemove) + e.onSocket(p) + function onFree() { + t.emit('free', p, r) + } + function onCloseOrRemove(e) { + t.removeSocket(p) + p.removeListener('free', onFree) + p.removeListener('close', onCloseOrRemove) + p.removeListener('agentRemove', onCloseOrRemove) + } + }) + } + TunnelingAgent.prototype.createSocket = function createSocket(e, p) { + var a = this + var d = {} + a.sockets.push(d) + var t = mergeOptions({}, a.proxyOptions, { + method: 'CONNECT', + path: e.host + ':' + e.port, + agent: false, + headers: { host: e.host + ':' + e.port }, + }) + if (e.localAddress) { + t.localAddress = e.localAddress + } + if (t.proxyAuth) { + t.headers = t.headers || {} + t.headers['Proxy-Authorization'] = + 'Basic ' + new Buffer(t.proxyAuth).toString('base64') + } + l('making CONNECT request') + var r = a.request(t) + r.useChunkedEncodingByDefault = false + r.once('response', onResponse) + r.once('upgrade', onUpgrade) + r.once('connect', onConnect) + r.once('error', onError) + r.end() + function onResponse(e) { + e.upgrade = true + } + function onUpgrade(e, p, a) { + process.nextTick(function () { + onConnect(e, p, a) + }) + } + function onConnect(t, s, i) { + r.removeAllListeners() + s.removeAllListeners() + if (t.statusCode !== 200) { + l( + 'tunneling socket could not be established, statusCode=%d', + t.statusCode + ) + s.destroy() + var o = new Error( + 'tunneling socket could not be established, ' + + 'statusCode=' + + t.statusCode + ) + o.code = 'ECONNRESET' + e.request.emit('error', o) + a.removeSocket(d) + return + } + if (i.length > 0) { + l('got illegal response body from proxy') + s.destroy() + var o = new Error('got illegal response body from proxy') + o.code = 'ECONNRESET' + e.request.emit('error', o) + a.removeSocket(d) + return + } + l('tunneling connection has established') + a.sockets[a.sockets.indexOf(d)] = s + return p(s) + } + function onError(p) { + r.removeAllListeners() + l( + 'tunneling socket could not be established, cause=%s\n', + p.message, + p.stack + ) + var t = new Error( + 'tunneling socket could not be established, ' + 'cause=' + p.message + ) + t.code = 'ECONNRESET' + e.request.emit('error', t) + a.removeSocket(d) + } + } + TunnelingAgent.prototype.removeSocket = function removeSocket(e) { + var p = this.sockets.indexOf(e) + if (p === -1) { + return + } + this.sockets.splice(p, 1) + var a = this.requests.shift() + if (a) { + this.createSocket(a, function (e) { + a.request.onSocket(e) + }) + } + } + function createSecureSocket(e, p) { + var a = this + TunnelingAgent.prototype.createSocket.call(a, e, function (d) { + var r = e.request.getHeader('host') + var s = mergeOptions({}, a.options, { + socket: d, + servername: r ? r.replace(/:.*$/, '') : e.host, + }) + var i = t.connect(0, s) + a.sockets[a.sockets.indexOf(d)] = i + p(i) + }) + } + function toOptions(e, p, a) { + if (typeof e === 'string') { + return { host: e, port: p, localAddress: a } + } + return e + } + function mergeOptions(e) { + for (var p = 1, a = arguments.length; p < a; ++p) { + var d = arguments[p] + if (typeof d === 'object') { + var t = Object.keys(d) + for (var r = 0, s = t.length; r < s; ++r) { + var i = t[r] + if (d[i] !== undefined) { + e[i] = d[i] + } + } + } + } + return e + } + var l + if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { + l = function () { + var e = Array.prototype.slice.call(arguments) + if (typeof e[0] === 'string') { + e[0] = 'TUNNEL: ' + e[0] + } else { + e.unshift('TUNNEL:') + } + console.error.apply(console, e) + } + } else { + l = function () {} + } + p.debug = l + }, + 5030: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + function getUserAgent() { + if (typeof navigator === 'object' && 'userAgent' in navigator) { + return navigator.userAgent + } + if (typeof process === 'object' && 'version' in process) { + return `Node.js/${process.version.substr(1)} (${process.platform}; ${ + process.arch + })` + } + return '' + } + p.getUserAgent = getUserAgent + }, + 5840: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + Object.defineProperty(p, 'v1', { + enumerable: true, + get: function () { + return d.default + }, + }) + Object.defineProperty(p, 'v3', { + enumerable: true, + get: function () { + return t.default + }, + }) + Object.defineProperty(p, 'v4', { + enumerable: true, + get: function () { + return r.default + }, + }) + Object.defineProperty(p, 'v5', { + enumerable: true, + get: function () { + return s.default + }, + }) + Object.defineProperty(p, 'NIL', { + enumerable: true, + get: function () { + return i.default + }, + }) + Object.defineProperty(p, 'version', { + enumerable: true, + get: function () { + return o.default + }, + }) + Object.defineProperty(p, 'validate', { + enumerable: true, + get: function () { + return n.default + }, + }) + Object.defineProperty(p, 'stringify', { + enumerable: true, + get: function () { + return l.default + }, + }) + Object.defineProperty(p, 'parse', { + enumerable: true, + get: function () { + return m.default + }, + }) + var d = _interopRequireDefault(a(8628)) + var t = _interopRequireDefault(a(6409)) + var r = _interopRequireDefault(a(5122)) + var s = _interopRequireDefault(a(9120)) + var i = _interopRequireDefault(a(5332)) + var o = _interopRequireDefault(a(1595)) + var n = _interopRequireDefault(a(6900)) + var l = _interopRequireDefault(a(8950)) + var m = _interopRequireDefault(a(2746)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + }, + 4569: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(6113)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + function md5(e) { + if (Array.isArray(e)) { + e = Buffer.from(e) + } else if (typeof e === 'string') { + e = Buffer.from(e, 'utf8') + } + return d.default.createHash('md5').update(e).digest() + } + var t = md5 + p['default'] = t + }, + 5332: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var a = '00000000-0000-0000-0000-000000000000' + p['default'] = a + }, + 2746: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(6900)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + function parse(e) { + if (!(0, d.default)(e)) { + throw TypeError('Invalid UUID') + } + let p + const a = new Uint8Array(16) + a[0] = (p = parseInt(e.slice(0, 8), 16)) >>> 24 + a[1] = (p >>> 16) & 255 + a[2] = (p >>> 8) & 255 + a[3] = p & 255 + a[4] = (p = parseInt(e.slice(9, 13), 16)) >>> 8 + a[5] = p & 255 + a[6] = (p = parseInt(e.slice(14, 18), 16)) >>> 8 + a[7] = p & 255 + a[8] = (p = parseInt(e.slice(19, 23), 16)) >>> 8 + a[9] = p & 255 + a[10] = ((p = parseInt(e.slice(24, 36), 16)) / 1099511627776) & 255 + a[11] = (p / 4294967296) & 255 + a[12] = (p >>> 24) & 255 + a[13] = (p >>> 16) & 255 + a[14] = (p >>> 8) & 255 + a[15] = p & 255 + return a + } + var t = parse + p['default'] = t + }, + 814: (e, p) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var a = + /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i + p['default'] = a + }, + 807: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = rng + var d = _interopRequireDefault(a(6113)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + const t = new Uint8Array(256) + let r = t.length + function rng() { + if (r > t.length - 16) { + d.default.randomFillSync(t) + r = 0 + } + return t.slice(r, (r += 16)) + } + }, + 5274: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(6113)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + function sha1(e) { + if (Array.isArray(e)) { + e = Buffer.from(e) + } else if (typeof e === 'string') { + e = Buffer.from(e, 'utf8') + } + return d.default.createHash('sha1').update(e).digest() + } + var t = sha1 + p['default'] = t + }, + 8950: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(6900)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + const t = [] + for (let e = 0; e < 256; ++e) { + t.push((e + 256).toString(16).substr(1)) + } + function stringify(e, p = 0) { + const a = ( + t[e[p + 0]] + + t[e[p + 1]] + + t[e[p + 2]] + + t[e[p + 3]] + + '-' + + t[e[p + 4]] + + t[e[p + 5]] + + '-' + + t[e[p + 6]] + + t[e[p + 7]] + + '-' + + t[e[p + 8]] + + t[e[p + 9]] + + '-' + + t[e[p + 10]] + + t[e[p + 11]] + + t[e[p + 12]] + + t[e[p + 13]] + + t[e[p + 14]] + + t[e[p + 15]] + ).toLowerCase() + if (!(0, d.default)(a)) { + throw TypeError('Stringified UUID is invalid') + } + return a + } + var r = stringify + p['default'] = r + }, + 8628: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(807)) + var t = _interopRequireDefault(a(8950)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + let r + let s + let i = 0 + let o = 0 + function v1(e, p, a) { + let n = (p && a) || 0 + const l = p || new Array(16) + e = e || {} + let m = e.node || r + let u = e.clockseq !== undefined ? e.clockseq : s + if (m == null || u == null) { + const p = e.random || (e.rng || d.default)() + if (m == null) { + m = r = [p[0] | 1, p[1], p[2], p[3], p[4], p[5]] + } + if (u == null) { + u = s = ((p[6] << 8) | p[7]) & 16383 + } + } + let c = e.msecs !== undefined ? e.msecs : Date.now() + let v = e.nsecs !== undefined ? e.nsecs : o + 1 + const h = c - i + (v - o) / 1e4 + if (h < 0 && e.clockseq === undefined) { + u = (u + 1) & 16383 + } + if ((h < 0 || c > i) && e.nsecs === undefined) { + v = 0 + } + if (v >= 1e4) { + throw new Error("uuid.v1(): Can't create more than 10M uuids/sec") + } + i = c + o = v + s = u + c += 122192928e5 + const g = ((c & 268435455) * 1e4 + v) % 4294967296 + l[n++] = (g >>> 24) & 255 + l[n++] = (g >>> 16) & 255 + l[n++] = (g >>> 8) & 255 + l[n++] = g & 255 + const w = ((c / 4294967296) * 1e4) & 268435455 + l[n++] = (w >>> 8) & 255 + l[n++] = w & 255 + l[n++] = ((w >>> 24) & 15) | 16 + l[n++] = (w >>> 16) & 255 + l[n++] = (u >>> 8) | 128 + l[n++] = u & 255 + for (let e = 0; e < 6; ++e) { + l[n + e] = m[e] + } + return p || (0, t.default)(l) + } + var n = v1 + p['default'] = n + }, + 6409: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(5998)) + var t = _interopRequireDefault(a(4569)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + const r = (0, d.default)('v3', 48, t.default) + var s = r + p['default'] = s + }, + 5998: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = _default + p.URL = p.DNS = void 0 + var d = _interopRequireDefault(a(8950)) + var t = _interopRequireDefault(a(2746)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + function stringToBytes(e) { + e = unescape(encodeURIComponent(e)) + const p = [] + for (let a = 0; a < e.length; ++a) { + p.push(e.charCodeAt(a)) + } + return p + } + const r = '6ba7b810-9dad-11d1-80b4-00c04fd430c8' + p.DNS = r + const s = '6ba7b811-9dad-11d1-80b4-00c04fd430c8' + p.URL = s + function _default(e, p, a) { + function generateUUID(e, r, s, i) { + if (typeof e === 'string') { + e = stringToBytes(e) + } + if (typeof r === 'string') { + r = (0, t.default)(r) + } + if (r.length !== 16) { + throw TypeError( + 'Namespace must be array-like (16 iterable integer values, 0-255)' + ) + } + let o = new Uint8Array(16 + e.length) + o.set(r) + o.set(e, r.length) + o = a(o) + o[6] = (o[6] & 15) | p + o[8] = (o[8] & 63) | 128 + if (s) { + i = i || 0 + for (let e = 0; e < 16; ++e) { + s[i + e] = o[e] + } + return s + } + return (0, d.default)(o) + } + try { + generateUUID.name = e + } catch (e) {} + generateUUID.DNS = r + generateUUID.URL = s + return generateUUID + } + }, + 5122: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(807)) + var t = _interopRequireDefault(a(8950)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + function v4(e, p, a) { + e = e || {} + const r = e.random || (e.rng || d.default)() + r[6] = (r[6] & 15) | 64 + r[8] = (r[8] & 63) | 128 + if (p) { + a = a || 0 + for (let e = 0; e < 16; ++e) { + p[a + e] = r[e] + } + return p + } + return (0, t.default)(r) + } + var r = v4 + p['default'] = r + }, + 9120: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(5998)) + var t = _interopRequireDefault(a(5274)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + const r = (0, d.default)('v5', 80, t.default) + var s = r + p['default'] = s + }, + 6900: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(814)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + function validate(e) { + return typeof e === 'string' && d.default.test(e) + } + var t = validate + p['default'] = t + }, + 1595: (e, p, a) => { + Object.defineProperty(p, '__esModule', { value: true }) + p['default'] = void 0 + var d = _interopRequireDefault(a(6900)) + function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e } + } + function version(e) { + if (!(0, d.default)(e)) { + throw TypeError('Invalid UUID') + } + return parseInt(e.substr(14, 1), 16) + } + var t = version + p['default'] = t + }, + 4886: (e) => { + var p = {} + e.exports = p + function sign(e) { + return e < 0 ? -1 : 1 + } + function evenRound(e) { + if (e % 1 === 0.5 && (e & 1) === 0) { + return Math.floor(e) + } else { + return Math.round(e) + } + } + function createNumberConversion(e, p) { + if (!p.unsigned) { + --e + } + const a = p.unsigned ? 0 : -Math.pow(2, e) + const d = Math.pow(2, e) - 1 + const t = p.moduloBitLength + ? Math.pow(2, p.moduloBitLength) + : Math.pow(2, e) + const r = p.moduloBitLength + ? Math.pow(2, p.moduloBitLength - 1) + : Math.pow(2, e - 1) + return function (e, s) { + if (!s) s = {} + let i = +e + if (s.enforceRange) { + if (!Number.isFinite(i)) { + throw new TypeError('Argument is not a finite number') + } + i = sign(i) * Math.floor(Math.abs(i)) + if (i < a || i > d) { + throw new TypeError('Argument is not in byte range') + } + return i + } + if (!isNaN(i) && s.clamp) { + i = evenRound(i) + if (i < a) i = a + if (i > d) i = d + return i + } + if (!Number.isFinite(i) || i === 0) { + return 0 + } + i = sign(i) * Math.floor(Math.abs(i)) + i = i % t + if (!p.unsigned && i >= r) { + return i - t + } else if (p.unsigned) { + if (i < 0) { + i += t + } else if (i === -0) { + return 0 + } + } + return i + } + } + p['void'] = function () { + return undefined + } + p['boolean'] = function (e) { + return !!e + } + p['byte'] = createNumberConversion(8, { unsigned: false }) + p['octet'] = createNumberConversion(8, { unsigned: true }) + p['short'] = createNumberConversion(16, { unsigned: false }) + p['unsigned short'] = createNumberConversion(16, { unsigned: true }) + p['long'] = createNumberConversion(32, { unsigned: false }) + p['unsigned long'] = createNumberConversion(32, { unsigned: true }) + p['long long'] = createNumberConversion(32, { + unsigned: false, + moduloBitLength: 64, + }) + p['unsigned long long'] = createNumberConversion(32, { + unsigned: true, + moduloBitLength: 64, + }) + p['double'] = function (e) { + const p = +e + if (!Number.isFinite(p)) { + throw new TypeError('Argument is not a finite floating-point value') + } + return p + } + p['unrestricted double'] = function (e) { + const p = +e + if (isNaN(p)) { + throw new TypeError('Argument is NaN') + } + return p + } + p['float'] = p['double'] + p['unrestricted float'] = p['unrestricted double'] + p['DOMString'] = function (e, p) { + if (!p) p = {} + if (p.treatNullAsEmptyString && e === null) { + return '' + } + return String(e) + } + p['ByteString'] = function (e, p) { + const a = String(e) + let d = undefined + for (let e = 0; (d = a.codePointAt(e)) !== undefined; ++e) { + if (d > 255) { + throw new TypeError('Argument is not a valid bytestring') + } + } + return a + } + p['USVString'] = function (e) { + const p = String(e) + const a = p.length + const d = [] + for (let e = 0; e < a; ++e) { + const t = p.charCodeAt(e) + if (t < 55296 || t > 57343) { + d.push(String.fromCodePoint(t)) + } else if (56320 <= t && t <= 57343) { + d.push(String.fromCodePoint(65533)) + } else { + if (e === a - 1) { + d.push(String.fromCodePoint(65533)) + } else { + const a = p.charCodeAt(e + 1) + if (56320 <= a && a <= 57343) { + const p = t & 1023 + const r = a & 1023 + d.push(String.fromCodePoint((2 << 15) + (2 << 9) * p + r)) + ++e + } else { + d.push(String.fromCodePoint(65533)) + } + } + } + } + return d.join('') + } + p['Date'] = function (e, p) { + if (!(e instanceof Date)) { + throw new TypeError('Argument is not a Date object') + } + if (isNaN(e)) { + return undefined + } + return e + } + p['RegExp'] = function (e, p) { + if (!(e instanceof RegExp)) { + e = new RegExp(e) + } + return e + } + }, + 7537: (e, p, a) => { + const d = a(2158) + p.implementation = class URLImpl { + constructor(e) { + const p = e[0] + const a = e[1] + let t = null + if (a !== undefined) { + t = d.basicURLParse(a) + if (t === 'failure') { + throw new TypeError('Invalid base URL') + } + } + const r = d.basicURLParse(p, { baseURL: t }) + if (r === 'failure') { + throw new TypeError('Invalid URL') + } + this._url = r + } + get href() { + return d.serializeURL(this._url) + } + set href(e) { + const p = d.basicURLParse(e) + if (p === 'failure') { + throw new TypeError('Invalid URL') + } + this._url = p + } + get origin() { + return d.serializeURLOrigin(this._url) + } + get protocol() { + return this._url.scheme + ':' + } + set protocol(e) { + d.basicURLParse(e + ':', { + url: this._url, + stateOverride: 'scheme start', + }) + } + get username() { + return this._url.username + } + set username(e) { + if (d.cannotHaveAUsernamePasswordPort(this._url)) { + return + } + d.setTheUsername(this._url, e) + } + get password() { + return this._url.password + } + set password(e) { + if (d.cannotHaveAUsernamePasswordPort(this._url)) { + return + } + d.setThePassword(this._url, e) + } + get host() { + const e = this._url + if (e.host === null) { + return '' + } + if (e.port === null) { + return d.serializeHost(e.host) + } + return d.serializeHost(e.host) + ':' + d.serializeInteger(e.port) + } + set host(e) { + if (this._url.cannotBeABaseURL) { + return + } + d.basicURLParse(e, { url: this._url, stateOverride: 'host' }) + } + get hostname() { + if (this._url.host === null) { + return '' + } + return d.serializeHost(this._url.host) + } + set hostname(e) { + if (this._url.cannotBeABaseURL) { + return + } + d.basicURLParse(e, { url: this._url, stateOverride: 'hostname' }) + } + get port() { + if (this._url.port === null) { + return '' + } + return d.serializeInteger(this._url.port) + } + set port(e) { + if (d.cannotHaveAUsernamePasswordPort(this._url)) { + return + } + if (e === '') { + this._url.port = null + } else { + d.basicURLParse(e, { url: this._url, stateOverride: 'port' }) + } + } + get pathname() { + if (this._url.cannotBeABaseURL) { + return this._url.path[0] + } + if (this._url.path.length === 0) { + return '' + } + return '/' + this._url.path.join('/') + } + set pathname(e) { + if (this._url.cannotBeABaseURL) { + return + } + this._url.path = [] + d.basicURLParse(e, { url: this._url, stateOverride: 'path start' }) + } + get search() { + if (this._url.query === null || this._url.query === '') { + return '' + } + return '?' + this._url.query + } + set search(e) { + const p = this._url + if (e === '') { + p.query = null + return + } + const a = e[0] === '?' ? e.substring(1) : e + p.query = '' + d.basicURLParse(a, { url: p, stateOverride: 'query' }) + } + get hash() { + if (this._url.fragment === null || this._url.fragment === '') { + return '' + } + return '#' + this._url.fragment + } + set hash(e) { + if (e === '') { + this._url.fragment = null + return + } + const p = e[0] === '#' ? e.substring(1) : e + this._url.fragment = '' + d.basicURLParse(p, { url: this._url, stateOverride: 'fragment' }) + } + toJSON() { + return this.href + } + } + }, + 3394: (e, p, a) => { + const d = a(4886) + const t = a(3185) + const r = a(7537) + const s = t.implSymbol + function URL(p) { + if (!this || this[s] || !(this instanceof URL)) { + throw new TypeError( + "Failed to construct 'URL': Please use the 'new' operator, this DOM object constructor cannot be called as a function." + ) + } + if (arguments.length < 1) { + throw new TypeError( + "Failed to construct 'URL': 1 argument required, but only " + + arguments.length + + ' present.' + ) + } + const a = [] + for (let e = 0; e < arguments.length && e < 2; ++e) { + a[e] = arguments[e] + } + a[0] = d['USVString'](a[0]) + if (a[1] !== undefined) { + a[1] = d['USVString'](a[1]) + } + e.exports.setup(this, a) + } + URL.prototype.toJSON = function toJSON() { + if (!this || !e.exports.is(this)) { + throw new TypeError('Illegal invocation') + } + const p = [] + for (let e = 0; e < arguments.length && e < 0; ++e) { + p[e] = arguments[e] + } + return this[s].toJSON.apply(this[s], p) + } + Object.defineProperty(URL.prototype, 'href', { + get() { + return this[s].href + }, + set(e) { + e = d['USVString'](e) + this[s].href = e + }, + enumerable: true, + configurable: true, + }) + URL.prototype.toString = function () { + if (!this || !e.exports.is(this)) { + throw new TypeError('Illegal invocation') + } + return this.href + } + Object.defineProperty(URL.prototype, 'origin', { + get() { + return this[s].origin + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'protocol', { + get() { + return this[s].protocol + }, + set(e) { + e = d['USVString'](e) + this[s].protocol = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'username', { + get() { + return this[s].username + }, + set(e) { + e = d['USVString'](e) + this[s].username = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'password', { + get() { + return this[s].password + }, + set(e) { + e = d['USVString'](e) + this[s].password = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'host', { + get() { + return this[s].host + }, + set(e) { + e = d['USVString'](e) + this[s].host = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'hostname', { + get() { + return this[s].hostname + }, + set(e) { + e = d['USVString'](e) + this[s].hostname = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'port', { + get() { + return this[s].port + }, + set(e) { + e = d['USVString'](e) + this[s].port = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'pathname', { + get() { + return this[s].pathname + }, + set(e) { + e = d['USVString'](e) + this[s].pathname = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'search', { + get() { + return this[s].search + }, + set(e) { + e = d['USVString'](e) + this[s].search = e + }, + enumerable: true, + configurable: true, + }) + Object.defineProperty(URL.prototype, 'hash', { + get() { + return this[s].hash + }, + set(e) { + e = d['USVString'](e) + this[s].hash = e + }, + enumerable: true, + configurable: true, + }) + e.exports = { + is(e) { + return !!e && e[s] instanceof r.implementation + }, + create(e, p) { + let a = Object.create(URL.prototype) + this.setup(a, e, p) + return a + }, + setup(e, p, a) { + if (!a) a = {} + a.wrapper = e + e[s] = new r.implementation(p, a) + e[s][t.wrapperSymbol] = e + }, + interface: URL, + expose: { Window: { URL: URL }, Worker: { URL: URL } }, + } + }, + 8665: (e, p, a) => { + p.URL = a(3394)['interface'] + p.serializeURL = a(2158).serializeURL + p.serializeURLOrigin = a(2158).serializeURLOrigin + p.basicURLParse = a(2158).basicURLParse + p.setTheUsername = a(2158).setTheUsername + p.setThePassword = a(2158).setThePassword + p.serializeHost = a(2158).serializeHost + p.serializeInteger = a(2158).serializeInteger + p.parseURL = a(2158).parseURL + }, + 2158: (e, p, a) => { + const d = a(5477) + const t = a(4256) + const r = { + ftp: 21, + file: null, + gopher: 70, + http: 80, + https: 443, + ws: 80, + wss: 443, + } + const s = Symbol('failure') + function countSymbols(e) { + return d.ucs2.decode(e).length + } + function at(e, p) { + const a = e[p] + return isNaN(a) ? undefined : String.fromCodePoint(a) + } + function isASCIIDigit(e) { + return e >= 48 && e <= 57 + } + function isASCIIAlpha(e) { + return (e >= 65 && e <= 90) || (e >= 97 && e <= 122) + } + function isASCIIAlphanumeric(e) { + return isASCIIAlpha(e) || isASCIIDigit(e) + } + function isASCIIHex(e) { + return isASCIIDigit(e) || (e >= 65 && e <= 70) || (e >= 97 && e <= 102) + } + function isSingleDot(e) { + return e === '.' || e.toLowerCase() === '%2e' + } + function isDoubleDot(e) { + e = e.toLowerCase() + return e === '..' || e === '%2e.' || e === '.%2e' || e === '%2e%2e' + } + function isWindowsDriveLetterCodePoints(e, p) { + return isASCIIAlpha(e) && (p === 58 || p === 124) + } + function isWindowsDriveLetterString(e) { + return ( + e.length === 2 && + isASCIIAlpha(e.codePointAt(0)) && + (e[1] === ':' || e[1] === '|') + ) + } + function isNormalizedWindowsDriveLetterString(e) { + return e.length === 2 && isASCIIAlpha(e.codePointAt(0)) && e[1] === ':' + } + function containsForbiddenHostCodePoint(e) { + return ( + e.search( + /\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/ + ) !== -1 + ) + } + function containsForbiddenHostCodePointExcludingPercent(e) { + return ( + e.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== + -1 + ) + } + function isSpecialScheme(e) { + return r[e] !== undefined + } + function isSpecial(e) { + return isSpecialScheme(e.scheme) + } + function defaultPort(e) { + return r[e] + } + function percentEncode(e) { + let p = e.toString(16).toUpperCase() + if (p.length === 1) { + p = '0' + p + } + return '%' + p + } + function utf8PercentEncode(e) { + const p = new Buffer(e) + let a = '' + for (let e = 0; e < p.length; ++e) { + a += percentEncode(p[e]) + } + return a + } + function utf8PercentDecode(e) { + const p = new Buffer(e) + const a = [] + for (let e = 0; e < p.length; ++e) { + if (p[e] !== 37) { + a.push(p[e]) + } else if ( + p[e] === 37 && + isASCIIHex(p[e + 1]) && + isASCIIHex(p[e + 2]) + ) { + a.push(parseInt(p.slice(e + 1, e + 3).toString(), 16)) + e += 2 + } else { + a.push(p[e]) + } + } + return new Buffer(a).toString() + } + function isC0ControlPercentEncode(e) { + return e <= 31 || e > 126 + } + const i = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]) + function isPathPercentEncode(e) { + return isC0ControlPercentEncode(e) || i.has(e) + } + const o = new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]) + function isUserinfoPercentEncode(e) { + return isPathPercentEncode(e) || o.has(e) + } + function percentEncodeChar(e, p) { + const a = String.fromCodePoint(e) + if (p(e)) { + return utf8PercentEncode(a) + } + return a + } + function parseIPv4Number(e) { + let p = 10 + if ( + e.length >= 2 && + e.charAt(0) === '0' && + e.charAt(1).toLowerCase() === 'x' + ) { + e = e.substring(2) + p = 16 + } else if (e.length >= 2 && e.charAt(0) === '0') { + e = e.substring(1) + p = 8 + } + if (e === '') { + return 0 + } + const a = p === 10 ? /[^0-9]/ : p === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/ + if (a.test(e)) { + return s + } + return parseInt(e, p) + } + function parseIPv4(e) { + const p = e.split('.') + if (p[p.length - 1] === '') { + if (p.length > 1) { + p.pop() + } + } + if (p.length > 4) { + return e + } + const a = [] + for (const d of p) { + if (d === '') { + return e + } + const p = parseIPv4Number(d) + if (p === s) { + return e + } + a.push(p) + } + for (let e = 0; e < a.length - 1; ++e) { + if (a[e] > 255) { + return s + } + } + if (a[a.length - 1] >= Math.pow(256, 5 - a.length)) { + return s + } + let d = a.pop() + let t = 0 + for (const e of a) { + d += e * Math.pow(256, 3 - t) + ++t + } + return d + } + function serializeIPv4(e) { + let p = '' + let a = e + for (let e = 1; e <= 4; ++e) { + p = String(a % 256) + p + if (e !== 4) { + p = '.' + p + } + a = Math.floor(a / 256) + } + return p + } + function parseIPv6(e) { + const p = [0, 0, 0, 0, 0, 0, 0, 0] + let a = 0 + let t = null + let r = 0 + e = d.ucs2.decode(e) + if (e[r] === 58) { + if (e[r + 1] !== 58) { + return s + } + r += 2 + ++a + t = a + } + while (r < e.length) { + if (a === 8) { + return s + } + if (e[r] === 58) { + if (t !== null) { + return s + } + ++r + ++a + t = a + continue + } + let d = 0 + let i = 0 + while (i < 4 && isASCIIHex(e[r])) { + d = d * 16 + parseInt(at(e, r), 16) + ++r + ++i + } + if (e[r] === 46) { + if (i === 0) { + return s + } + r -= i + if (a > 6) { + return s + } + let d = 0 + while (e[r] !== undefined) { + let t = null + if (d > 0) { + if (e[r] === 46 && d < 4) { + ++r + } else { + return s + } + } + if (!isASCIIDigit(e[r])) { + return s + } + while (isASCIIDigit(e[r])) { + const p = parseInt(at(e, r)) + if (t === null) { + t = p + } else if (t === 0) { + return s + } else { + t = t * 10 + p + } + if (t > 255) { + return s + } + ++r + } + p[a] = p[a] * 256 + t + ++d + if (d === 2 || d === 4) { + ++a + } + } + if (d !== 4) { + return s + } + break + } else if (e[r] === 58) { + ++r + if (e[r] === undefined) { + return s + } + } else if (e[r] !== undefined) { + return s + } + p[a] = d + ++a + } + if (t !== null) { + let e = a - t + a = 7 + while (a !== 0 && e > 0) { + const d = p[t + e - 1] + p[t + e - 1] = p[a] + p[a] = d + --a + --e + } + } else if (t === null && a !== 8) { + return s + } + return p + } + function serializeIPv6(e) { + let p = '' + const a = findLongestZeroSequence(e) + const d = a.idx + let t = false + for (let a = 0; a <= 7; ++a) { + if (t && e[a] === 0) { + continue + } else if (t) { + t = false + } + if (d === a) { + const e = a === 0 ? '::' : ':' + p += e + t = true + continue + } + p += e[a].toString(16) + if (a !== 7) { + p += ':' + } + } + return p + } + function parseHost(e, p) { + if (e[0] === '[') { + if (e[e.length - 1] !== ']') { + return s + } + return parseIPv6(e.substring(1, e.length - 1)) + } + if (!p) { + return parseOpaqueHost(e) + } + const a = utf8PercentDecode(e) + const d = t.toASCII(a, false, t.PROCESSING_OPTIONS.NONTRANSITIONAL, false) + if (d === null) { + return s + } + if (containsForbiddenHostCodePoint(d)) { + return s + } + const r = parseIPv4(d) + if (typeof r === 'number' || r === s) { + return r + } + return d + } + function parseOpaqueHost(e) { + if (containsForbiddenHostCodePointExcludingPercent(e)) { + return s + } + let p = '' + const a = d.ucs2.decode(e) + for (let e = 0; e < a.length; ++e) { + p += percentEncodeChar(a[e], isC0ControlPercentEncode) + } + return p + } + function findLongestZeroSequence(e) { + let p = null + let a = 1 + let d = null + let t = 0 + for (let r = 0; r < e.length; ++r) { + if (e[r] !== 0) { + if (t > a) { + p = d + a = t + } + d = null + t = 0 + } else { + if (d === null) { + d = r + } + ++t + } + } + if (t > a) { + p = d + a = t + } + return { idx: p, len: a } + } + function serializeHost(e) { + if (typeof e === 'number') { + return serializeIPv4(e) + } + if (e instanceof Array) { + return '[' + serializeIPv6(e) + ']' + } + return e + } + function trimControlChars(e) { + return e.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, '') + } + function trimTabAndNewline(e) { + return e.replace(/\u0009|\u000A|\u000D/g, '') + } + function shortenPath(e) { + const p = e.path + if (p.length === 0) { + return + } + if ( + e.scheme === 'file' && + p.length === 1 && + isNormalizedWindowsDriveLetter(p[0]) + ) { + return + } + p.pop() + } + function includesCredentials(e) { + return e.username !== '' || e.password !== '' + } + function cannotHaveAUsernamePasswordPort(e) { + return ( + e.host === null || + e.host === '' || + e.cannotBeABaseURL || + e.scheme === 'file' + ) + } + function isNormalizedWindowsDriveLetter(e) { + return /^[A-Za-z]:$/.test(e) + } + function URLStateMachine(e, p, a, t, r) { + this.pointer = 0 + this.input = e + this.base = p || null + this.encodingOverride = a || 'utf-8' + this.stateOverride = r + this.url = t + this.failure = false + this.parseError = false + if (!this.url) { + this.url = { + scheme: '', + username: '', + password: '', + host: null, + port: null, + path: [], + query: null, + fragment: null, + cannotBeABaseURL: false, + } + const e = trimControlChars(this.input) + if (e !== this.input) { + this.parseError = true + } + this.input = e + } + const i = trimTabAndNewline(this.input) + if (i !== this.input) { + this.parseError = true + } + this.input = i + this.state = r || 'scheme start' + this.buffer = '' + this.atFlag = false + this.arrFlag = false + this.passwordTokenSeenFlag = false + this.input = d.ucs2.decode(this.input) + for (; this.pointer <= this.input.length; ++this.pointer) { + const e = this.input[this.pointer] + const p = isNaN(e) ? undefined : String.fromCodePoint(e) + const a = this['parse ' + this.state](e, p) + if (!a) { + break + } else if (a === s) { + this.failure = true + break + } + } + } + URLStateMachine.prototype['parse scheme start'] = function parseSchemeStart( + e, + p + ) { + if (isASCIIAlpha(e)) { + this.buffer += p.toLowerCase() + this.state = 'scheme' + } else if (!this.stateOverride) { + this.state = 'no scheme' + --this.pointer + } else { + this.parseError = true + return s + } + return true + } + URLStateMachine.prototype['parse scheme'] = function parseScheme(e, p) { + if (isASCIIAlphanumeric(e) || e === 43 || e === 45 || e === 46) { + this.buffer += p.toLowerCase() + } else if (e === 58) { + if (this.stateOverride) { + if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) { + return false + } + if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) { + return false + } + if ( + (includesCredentials(this.url) || this.url.port !== null) && + this.buffer === 'file' + ) { + return false + } + if ( + this.url.scheme === 'file' && + (this.url.host === '' || this.url.host === null) + ) { + return false + } + } + this.url.scheme = this.buffer + this.buffer = '' + if (this.stateOverride) { + return false + } + if (this.url.scheme === 'file') { + if ( + this.input[this.pointer + 1] !== 47 || + this.input[this.pointer + 2] !== 47 + ) { + this.parseError = true + } + this.state = 'file' + } else if ( + isSpecial(this.url) && + this.base !== null && + this.base.scheme === this.url.scheme + ) { + this.state = 'special relative or authority' + } else if (isSpecial(this.url)) { + this.state = 'special authority slashes' + } else if (this.input[this.pointer + 1] === 47) { + this.state = 'path or authority' + ++this.pointer + } else { + this.url.cannotBeABaseURL = true + this.url.path.push('') + this.state = 'cannot-be-a-base-URL path' + } + } else if (!this.stateOverride) { + this.buffer = '' + this.state = 'no scheme' + this.pointer = -1 + } else { + this.parseError = true + return s + } + return true + } + URLStateMachine.prototype['parse no scheme'] = function parseNoScheme(e) { + if (this.base === null || (this.base.cannotBeABaseURL && e !== 35)) { + return s + } else if (this.base.cannotBeABaseURL && e === 35) { + this.url.scheme = this.base.scheme + this.url.path = this.base.path.slice() + this.url.query = this.base.query + this.url.fragment = '' + this.url.cannotBeABaseURL = true + this.state = 'fragment' + } else if (this.base.scheme === 'file') { + this.state = 'file' + --this.pointer + } else { + this.state = 'relative' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse special relative or authority'] = + function parseSpecialRelativeOrAuthority(e) { + if (e === 47 && this.input[this.pointer + 1] === 47) { + this.state = 'special authority ignore slashes' + ++this.pointer + } else { + this.parseError = true + this.state = 'relative' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse path or authority'] = + function parsePathOrAuthority(e) { + if (e === 47) { + this.state = 'authority' + } else { + this.state = 'path' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse relative'] = function parseRelative(e) { + this.url.scheme = this.base.scheme + if (isNaN(e)) { + this.url.username = this.base.username + this.url.password = this.base.password + this.url.host = this.base.host + this.url.port = this.base.port + this.url.path = this.base.path.slice() + this.url.query = this.base.query + } else if (e === 47) { + this.state = 'relative slash' + } else if (e === 63) { + this.url.username = this.base.username + this.url.password = this.base.password + this.url.host = this.base.host + this.url.port = this.base.port + this.url.path = this.base.path.slice() + this.url.query = '' + this.state = 'query' + } else if (e === 35) { + this.url.username = this.base.username + this.url.password = this.base.password + this.url.host = this.base.host + this.url.port = this.base.port + this.url.path = this.base.path.slice() + this.url.query = this.base.query + this.url.fragment = '' + this.state = 'fragment' + } else if (isSpecial(this.url) && e === 92) { + this.parseError = true + this.state = 'relative slash' + } else { + this.url.username = this.base.username + this.url.password = this.base.password + this.url.host = this.base.host + this.url.port = this.base.port + this.url.path = this.base.path.slice(0, this.base.path.length - 1) + this.state = 'path' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse relative slash'] = + function parseRelativeSlash(e) { + if (isSpecial(this.url) && (e === 47 || e === 92)) { + if (e === 92) { + this.parseError = true + } + this.state = 'special authority ignore slashes' + } else if (e === 47) { + this.state = 'authority' + } else { + this.url.username = this.base.username + this.url.password = this.base.password + this.url.host = this.base.host + this.url.port = this.base.port + this.state = 'path' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse special authority slashes'] = + function parseSpecialAuthoritySlashes(e) { + if (e === 47 && this.input[this.pointer + 1] === 47) { + this.state = 'special authority ignore slashes' + ++this.pointer + } else { + this.parseError = true + this.state = 'special authority ignore slashes' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse special authority ignore slashes'] = + function parseSpecialAuthorityIgnoreSlashes(e) { + if (e !== 47 && e !== 92) { + this.state = 'authority' + --this.pointer + } else { + this.parseError = true + } + return true + } + URLStateMachine.prototype['parse authority'] = function parseAuthority( + e, + p + ) { + if (e === 64) { + this.parseError = true + if (this.atFlag) { + this.buffer = '%40' + this.buffer + } + this.atFlag = true + const e = countSymbols(this.buffer) + for (let p = 0; p < e; ++p) { + const e = this.buffer.codePointAt(p) + if (e === 58 && !this.passwordTokenSeenFlag) { + this.passwordTokenSeenFlag = true + continue + } + const a = percentEncodeChar(e, isUserinfoPercentEncode) + if (this.passwordTokenSeenFlag) { + this.url.password += a + } else { + this.url.username += a + } + } + this.buffer = '' + } else if ( + isNaN(e) || + e === 47 || + e === 63 || + e === 35 || + (isSpecial(this.url) && e === 92) + ) { + if (this.atFlag && this.buffer === '') { + this.parseError = true + return s + } + this.pointer -= countSymbols(this.buffer) + 1 + this.buffer = '' + this.state = 'host' + } else { + this.buffer += p + } + return true + } + URLStateMachine.prototype['parse hostname'] = URLStateMachine.prototype[ + 'parse host' + ] = function parseHostName(e, p) { + if (this.stateOverride && this.url.scheme === 'file') { + --this.pointer + this.state = 'file host' + } else if (e === 58 && !this.arrFlag) { + if (this.buffer === '') { + this.parseError = true + return s + } + const e = parseHost(this.buffer, isSpecial(this.url)) + if (e === s) { + return s + } + this.url.host = e + this.buffer = '' + this.state = 'port' + if (this.stateOverride === 'hostname') { + return false + } + } else if ( + isNaN(e) || + e === 47 || + e === 63 || + e === 35 || + (isSpecial(this.url) && e === 92) + ) { + --this.pointer + if (isSpecial(this.url) && this.buffer === '') { + this.parseError = true + return s + } else if ( + this.stateOverride && + this.buffer === '' && + (includesCredentials(this.url) || this.url.port !== null) + ) { + this.parseError = true + return false + } + const e = parseHost(this.buffer, isSpecial(this.url)) + if (e === s) { + return s + } + this.url.host = e + this.buffer = '' + this.state = 'path start' + if (this.stateOverride) { + return false + } + } else { + if (e === 91) { + this.arrFlag = true + } else if (e === 93) { + this.arrFlag = false + } + this.buffer += p + } + return true + } + URLStateMachine.prototype['parse port'] = function parsePort(e, p) { + if (isASCIIDigit(e)) { + this.buffer += p + } else if ( + isNaN(e) || + e === 47 || + e === 63 || + e === 35 || + (isSpecial(this.url) && e === 92) || + this.stateOverride + ) { + if (this.buffer !== '') { + const e = parseInt(this.buffer) + if (e > Math.pow(2, 16) - 1) { + this.parseError = true + return s + } + this.url.port = e === defaultPort(this.url.scheme) ? null : e + this.buffer = '' + } + if (this.stateOverride) { + return false + } + this.state = 'path start' + --this.pointer + } else { + this.parseError = true + return s + } + return true + } + const n = new Set([47, 92, 63, 35]) + URLStateMachine.prototype['parse file'] = function parseFile(e) { + this.url.scheme = 'file' + if (e === 47 || e === 92) { + if (e === 92) { + this.parseError = true + } + this.state = 'file slash' + } else if (this.base !== null && this.base.scheme === 'file') { + if (isNaN(e)) { + this.url.host = this.base.host + this.url.path = this.base.path.slice() + this.url.query = this.base.query + } else if (e === 63) { + this.url.host = this.base.host + this.url.path = this.base.path.slice() + this.url.query = '' + this.state = 'query' + } else if (e === 35) { + this.url.host = this.base.host + this.url.path = this.base.path.slice() + this.url.query = this.base.query + this.url.fragment = '' + this.state = 'fragment' + } else { + if ( + this.input.length - this.pointer - 1 === 0 || + !isWindowsDriveLetterCodePoints(e, this.input[this.pointer + 1]) || + (this.input.length - this.pointer - 1 >= 2 && + !n.has(this.input[this.pointer + 2])) + ) { + this.url.host = this.base.host + this.url.path = this.base.path.slice() + shortenPath(this.url) + } else { + this.parseError = true + } + this.state = 'path' + --this.pointer + } + } else { + this.state = 'path' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse file slash'] = function parseFileSlash(e) { + if (e === 47 || e === 92) { + if (e === 92) { + this.parseError = true + } + this.state = 'file host' + } else { + if (this.base !== null && this.base.scheme === 'file') { + if (isNormalizedWindowsDriveLetterString(this.base.path[0])) { + this.url.path.push(this.base.path[0]) + } else { + this.url.host = this.base.host + } + } + this.state = 'path' + --this.pointer + } + return true + } + URLStateMachine.prototype['parse file host'] = function parseFileHost( + e, + p + ) { + if (isNaN(e) || e === 47 || e === 92 || e === 63 || e === 35) { + --this.pointer + if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) { + this.parseError = true + this.state = 'path' + } else if (this.buffer === '') { + this.url.host = '' + if (this.stateOverride) { + return false + } + this.state = 'path start' + } else { + let e = parseHost(this.buffer, isSpecial(this.url)) + if (e === s) { + return s + } + if (e === 'localhost') { + e = '' + } + this.url.host = e + if (this.stateOverride) { + return false + } + this.buffer = '' + this.state = 'path start' + } + } else { + this.buffer += p + } + return true + } + URLStateMachine.prototype['parse path start'] = function parsePathStart(e) { + if (isSpecial(this.url)) { + if (e === 92) { + this.parseError = true + } + this.state = 'path' + if (e !== 47 && e !== 92) { + --this.pointer + } + } else if (!this.stateOverride && e === 63) { + this.url.query = '' + this.state = 'query' + } else if (!this.stateOverride && e === 35) { + this.url.fragment = '' + this.state = 'fragment' + } else if (e !== undefined) { + this.state = 'path' + if (e !== 47) { + --this.pointer + } + } + return true + } + URLStateMachine.prototype['parse path'] = function parsePath(e) { + if ( + isNaN(e) || + e === 47 || + (isSpecial(this.url) && e === 92) || + (!this.stateOverride && (e === 63 || e === 35)) + ) { + if (isSpecial(this.url) && e === 92) { + this.parseError = true + } + if (isDoubleDot(this.buffer)) { + shortenPath(this.url) + if (e !== 47 && !(isSpecial(this.url) && e === 92)) { + this.url.path.push('') + } + } else if ( + isSingleDot(this.buffer) && + e !== 47 && + !(isSpecial(this.url) && e === 92) + ) { + this.url.path.push('') + } else if (!isSingleDot(this.buffer)) { + if ( + this.url.scheme === 'file' && + this.url.path.length === 0 && + isWindowsDriveLetterString(this.buffer) + ) { + if (this.url.host !== '' && this.url.host !== null) { + this.parseError = true + this.url.host = '' + } + this.buffer = this.buffer[0] + ':' + } + this.url.path.push(this.buffer) + } + this.buffer = '' + if ( + this.url.scheme === 'file' && + (e === undefined || e === 63 || e === 35) + ) { + while (this.url.path.length > 1 && this.url.path[0] === '') { + this.parseError = true + this.url.path.shift() + } + } + if (e === 63) { + this.url.query = '' + this.state = 'query' + } + if (e === 35) { + this.url.fragment = '' + this.state = 'fragment' + } + } else { + if ( + e === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2])) + ) { + this.parseError = true + } + this.buffer += percentEncodeChar(e, isPathPercentEncode) + } + return true + } + URLStateMachine.prototype['parse cannot-be-a-base-URL path'] = + function parseCannotBeABaseURLPath(e) { + if (e === 63) { + this.url.query = '' + this.state = 'query' + } else if (e === 35) { + this.url.fragment = '' + this.state = 'fragment' + } else { + if (!isNaN(e) && e !== 37) { + this.parseError = true + } + if ( + e === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2])) + ) { + this.parseError = true + } + if (!isNaN(e)) { + this.url.path[0] = + this.url.path[0] + percentEncodeChar(e, isC0ControlPercentEncode) + } + } + return true + } + URLStateMachine.prototype['parse query'] = function parseQuery(e, p) { + if (isNaN(e) || (!this.stateOverride && e === 35)) { + if ( + !isSpecial(this.url) || + this.url.scheme === 'ws' || + this.url.scheme === 'wss' + ) { + this.encodingOverride = 'utf-8' + } + const p = new Buffer(this.buffer) + for (let e = 0; e < p.length; ++e) { + if ( + p[e] < 33 || + p[e] > 126 || + p[e] === 34 || + p[e] === 35 || + p[e] === 60 || + p[e] === 62 + ) { + this.url.query += percentEncode(p[e]) + } else { + this.url.query += String.fromCodePoint(p[e]) + } + } + this.buffer = '' + if (e === 35) { + this.url.fragment = '' + this.state = 'fragment' + } + } else { + if ( + e === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2])) + ) { + this.parseError = true + } + this.buffer += p + } + return true + } + URLStateMachine.prototype['parse fragment'] = function parseFragment(e) { + if (isNaN(e)) { + } else if (e === 0) { + this.parseError = true + } else { + if ( + e === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2])) + ) { + this.parseError = true + } + this.url.fragment += percentEncodeChar(e, isC0ControlPercentEncode) + } + return true + } + function serializeURL(e, p) { + let a = e.scheme + ':' + if (e.host !== null) { + a += '//' + if (e.username !== '' || e.password !== '') { + a += e.username + if (e.password !== '') { + a += ':' + e.password + } + a += '@' + } + a += serializeHost(e.host) + if (e.port !== null) { + a += ':' + e.port + } + } else if (e.host === null && e.scheme === 'file') { + a += '//' + } + if (e.cannotBeABaseURL) { + a += e.path[0] + } else { + for (const p of e.path) { + a += '/' + p + } + } + if (e.query !== null) { + a += '?' + e.query + } + if (!p && e.fragment !== null) { + a += '#' + e.fragment + } + return a + } + function serializeOrigin(e) { + let p = e.scheme + '://' + p += serializeHost(e.host) + if (e.port !== null) { + p += ':' + e.port + } + return p + } + e.exports.serializeURL = serializeURL + e.exports.serializeURLOrigin = function (p) { + switch (p.scheme) { + case 'blob': + try { + return e.exports.serializeURLOrigin(e.exports.parseURL(p.path[0])) + } catch (e) { + return 'null' + } + case 'ftp': + case 'gopher': + case 'http': + case 'https': + case 'ws': + case 'wss': + return serializeOrigin({ + scheme: p.scheme, + host: p.host, + port: p.port, + }) + case 'file': + return 'file://' + default: + return 'null' + } + } + e.exports.basicURLParse = function (e, p) { + if (p === undefined) { + p = {} + } + const a = new URLStateMachine( + e, + p.baseURL, + p.encodingOverride, + p.url, + p.stateOverride + ) + if (a.failure) { + return 'failure' + } + return a.url + } + e.exports.setTheUsername = function (e, p) { + e.username = '' + const a = d.ucs2.decode(p) + for (let p = 0; p < a.length; ++p) { + e.username += percentEncodeChar(a[p], isUserinfoPercentEncode) + } + } + e.exports.setThePassword = function (e, p) { + e.password = '' + const a = d.ucs2.decode(p) + for (let p = 0; p < a.length; ++p) { + e.password += percentEncodeChar(a[p], isUserinfoPercentEncode) + } + } + e.exports.serializeHost = serializeHost + e.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort + e.exports.serializeInteger = function (e) { + return String(e) + } + e.exports.parseURL = function (p, a) { + if (a === undefined) { + a = {} + } + return e.exports.basicURLParse(p, { + baseURL: a.baseURL, + encodingOverride: a.encodingOverride, + }) + } + }, + 3185: (e) => { + e.exports.mixin = function mixin(e, p) { + const a = Object.getOwnPropertyNames(p) + for (let d = 0; d < a.length; ++d) { + Object.defineProperty(e, a[d], Object.getOwnPropertyDescriptor(p, a[d])) + } + } + e.exports.wrapperSymbol = Symbol('wrapper') + e.exports.implSymbol = Symbol('impl') + e.exports.wrapperForImpl = function (p) { + return p[e.exports.wrapperSymbol] + } + e.exports.implForWrapper = function (p) { + return p[e.exports.implSymbol] + } + }, + 2940: (e) => { + e.exports = wrappy + function wrappy(e, p) { + if (e && p) return wrappy(e)(p) + if (typeof e !== 'function') throw new TypeError('need wrapper function') + Object.keys(e).forEach(function (p) { + wrapper[p] = e[p] + }) + return wrapper + function wrapper() { + var p = new Array(arguments.length) + for (var a = 0; a < p.length; a++) { + p[a] = arguments[a] + } + var d = e.apply(this, p) + var t = p[p.length - 1] + if (typeof d === 'function' && d !== t) { + Object.keys(t).forEach(function (e) { + d[e] = t[e] + }) + } + return d + } + } + }, + 2877: (module) => { + module.exports = eval('require')('encoding') + }, + 9491: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('assert') + }, + 6113: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('crypto') + }, + 2361: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('events') + }, + 7147: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('fs') + }, + 3685: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('http') + }, + 5687: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('https') + }, + 1808: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('net') + }, + 2037: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('os') + }, + 1017: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('path') + }, + 5477: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('punycode') + }, + 2781: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('stream') + }, + 4404: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('tls') + }, + 7310: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('url') + }, + 3837: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('util') + }, + 9796: (e) => { + e.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)('zlib') + }, + 2020: (e) => { + e.exports = JSON.parse( + '[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"],[[47,47],"disallowed_STD3_valid"],[[48,57],"valid"],[[58,64],"disallowed_STD3_valid"],[[65,65],"mapped",[97]],[[66,66],"mapped",[98]],[[67,67],"mapped",[99]],[[68,68],"mapped",[100]],[[69,69],"mapped",[101]],[[70,70],"mapped",[102]],[[71,71],"mapped",[103]],[[72,72],"mapped",[104]],[[73,73],"mapped",[105]],[[74,74],"mapped",[106]],[[75,75],"mapped",[107]],[[76,76],"mapped",[108]],[[77,77],"mapped",[109]],[[78,78],"mapped",[110]],[[79,79],"mapped",[111]],[[80,80],"mapped",[112]],[[81,81],"mapped",[113]],[[82,82],"mapped",[114]],[[83,83],"mapped",[115]],[[84,84],"mapped",[116]],[[85,85],"mapped",[117]],[[86,86],"mapped",[118]],[[87,87],"mapped",[119]],[[88,88],"mapped",[120]],[[89,89],"mapped",[121]],[[90,90],"mapped",[122]],[[91,96],"disallowed_STD3_valid"],[[97,122],"valid"],[[123,127],"disallowed_STD3_valid"],[[128,159],"disallowed"],[[160,160],"disallowed_STD3_mapped",[32]],[[161,167],"valid",[],"NV8"],[[168,168],"disallowed_STD3_mapped",[32,776]],[[169,169],"valid",[],"NV8"],[[170,170],"mapped",[97]],[[171,172],"valid",[],"NV8"],[[173,173],"ignored"],[[174,174],"valid",[],"NV8"],[[175,175],"disallowed_STD3_mapped",[32,772]],[[176,177],"valid",[],"NV8"],[[178,178],"mapped",[50]],[[179,179],"mapped",[51]],[[180,180],"disallowed_STD3_mapped",[32,769]],[[181,181],"mapped",[956]],[[182,182],"valid",[],"NV8"],[[183,183],"valid"],[[184,184],"disallowed_STD3_mapped",[32,807]],[[185,185],"mapped",[49]],[[186,186],"mapped",[111]],[[187,187],"valid",[],"NV8"],[[188,188],"mapped",[49,8260,52]],[[189,189],"mapped",[49,8260,50]],[[190,190],"mapped",[51,8260,52]],[[191,191],"valid",[],"NV8"],[[192,192],"mapped",[224]],[[193,193],"mapped",[225]],[[194,194],"mapped",[226]],[[195,195],"mapped",[227]],[[196,196],"mapped",[228]],[[197,197],"mapped",[229]],[[198,198],"mapped",[230]],[[199,199],"mapped",[231]],[[200,200],"mapped",[232]],[[201,201],"mapped",[233]],[[202,202],"mapped",[234]],[[203,203],"mapped",[235]],[[204,204],"mapped",[236]],[[205,205],"mapped",[237]],[[206,206],"mapped",[238]],[[207,207],"mapped",[239]],[[208,208],"mapped",[240]],[[209,209],"mapped",[241]],[[210,210],"mapped",[242]],[[211,211],"mapped",[243]],[[212,212],"mapped",[244]],[[213,213],"mapped",[245]],[[214,214],"mapped",[246]],[[215,215],"valid",[],"NV8"],[[216,216],"mapped",[248]],[[217,217],"mapped",[249]],[[218,218],"mapped",[250]],[[219,219],"mapped",[251]],[[220,220],"mapped",[252]],[[221,221],"mapped",[253]],[[222,222],"mapped",[254]],[[223,223],"deviation",[115,115]],[[224,246],"valid"],[[247,247],"valid",[],"NV8"],[[248,255],"valid"],[[256,256],"mapped",[257]],[[257,257],"valid"],[[258,258],"mapped",[259]],[[259,259],"valid"],[[260,260],"mapped",[261]],[[261,261],"valid"],[[262,262],"mapped",[263]],[[263,263],"valid"],[[264,264],"mapped",[265]],[[265,265],"valid"],[[266,266],"mapped",[267]],[[267,267],"valid"],[[268,268],"mapped",[269]],[[269,269],"valid"],[[270,270],"mapped",[271]],[[271,271],"valid"],[[272,272],"mapped",[273]],[[273,273],"valid"],[[274,274],"mapped",[275]],[[275,275],"valid"],[[276,276],"mapped",[277]],[[277,277],"valid"],[[278,278],"mapped",[279]],[[279,279],"valid"],[[280,280],"mapped",[281]],[[281,281],"valid"],[[282,282],"mapped",[283]],[[283,283],"valid"],[[284,284],"mapped",[285]],[[285,285],"valid"],[[286,286],"mapped",[287]],[[287,287],"valid"],[[288,288],"mapped",[289]],[[289,289],"valid"],[[290,290],"mapped",[291]],[[291,291],"valid"],[[292,292],"mapped",[293]],[[293,293],"valid"],[[294,294],"mapped",[295]],[[295,295],"valid"],[[296,296],"mapped",[297]],[[297,297],"valid"],[[298,298],"mapped",[299]],[[299,299],"valid"],[[300,300],"mapped",[301]],[[301,301],"valid"],[[302,302],"mapped",[303]],[[303,303],"valid"],[[304,304],"mapped",[105,775]],[[305,305],"valid"],[[306,307],"mapped",[105,106]],[[308,308],"mapped",[309]],[[309,309],"valid"],[[310,310],"mapped",[311]],[[311,312],"valid"],[[313,313],"mapped",[314]],[[314,314],"valid"],[[315,315],"mapped",[316]],[[316,316],"valid"],[[317,317],"mapped",[318]],[[318,318],"valid"],[[319,320],"mapped",[108,183]],[[321,321],"mapped",[322]],[[322,322],"valid"],[[323,323],"mapped",[324]],[[324,324],"valid"],[[325,325],"mapped",[326]],[[326,326],"valid"],[[327,327],"mapped",[328]],[[328,328],"valid"],[[329,329],"mapped",[700,110]],[[330,330],"mapped",[331]],[[331,331],"valid"],[[332,332],"mapped",[333]],[[333,333],"valid"],[[334,334],"mapped",[335]],[[335,335],"valid"],[[336,336],"mapped",[337]],[[337,337],"valid"],[[338,338],"mapped",[339]],[[339,339],"valid"],[[340,340],"mapped",[341]],[[341,341],"valid"],[[342,342],"mapped",[343]],[[343,343],"valid"],[[344,344],"mapped",[345]],[[345,345],"valid"],[[346,346],"mapped",[347]],[[347,347],"valid"],[[348,348],"mapped",[349]],[[349,349],"valid"],[[350,350],"mapped",[351]],[[351,351],"valid"],[[352,352],"mapped",[353]],[[353,353],"valid"],[[354,354],"mapped",[355]],[[355,355],"valid"],[[356,356],"mapped",[357]],[[357,357],"valid"],[[358,358],"mapped",[359]],[[359,359],"valid"],[[360,360],"mapped",[361]],[[361,361],"valid"],[[362,362],"mapped",[363]],[[363,363],"valid"],[[364,364],"mapped",[365]],[[365,365],"valid"],[[366,366],"mapped",[367]],[[367,367],"valid"],[[368,368],"mapped",[369]],[[369,369],"valid"],[[370,370],"mapped",[371]],[[371,371],"valid"],[[372,372],"mapped",[373]],[[373,373],"valid"],[[374,374],"mapped",[375]],[[375,375],"valid"],[[376,376],"mapped",[255]],[[377,377],"mapped",[378]],[[378,378],"valid"],[[379,379],"mapped",[380]],[[380,380],"valid"],[[381,381],"mapped",[382]],[[382,382],"valid"],[[383,383],"mapped",[115]],[[384,384],"valid"],[[385,385],"mapped",[595]],[[386,386],"mapped",[387]],[[387,387],"valid"],[[388,388],"mapped",[389]],[[389,389],"valid"],[[390,390],"mapped",[596]],[[391,391],"mapped",[392]],[[392,392],"valid"],[[393,393],"mapped",[598]],[[394,394],"mapped",[599]],[[395,395],"mapped",[396]],[[396,397],"valid"],[[398,398],"mapped",[477]],[[399,399],"mapped",[601]],[[400,400],"mapped",[603]],[[401,401],"mapped",[402]],[[402,402],"valid"],[[403,403],"mapped",[608]],[[404,404],"mapped",[611]],[[405,405],"valid"],[[406,406],"mapped",[617]],[[407,407],"mapped",[616]],[[408,408],"mapped",[409]],[[409,411],"valid"],[[412,412],"mapped",[623]],[[413,413],"mapped",[626]],[[414,414],"valid"],[[415,415],"mapped",[629]],[[416,416],"mapped",[417]],[[417,417],"valid"],[[418,418],"mapped",[419]],[[419,419],"valid"],[[420,420],"mapped",[421]],[[421,421],"valid"],[[422,422],"mapped",[640]],[[423,423],"mapped",[424]],[[424,424],"valid"],[[425,425],"mapped",[643]],[[426,427],"valid"],[[428,428],"mapped",[429]],[[429,429],"valid"],[[430,430],"mapped",[648]],[[431,431],"mapped",[432]],[[432,432],"valid"],[[433,433],"mapped",[650]],[[434,434],"mapped",[651]],[[435,435],"mapped",[436]],[[436,436],"valid"],[[437,437],"mapped",[438]],[[438,438],"valid"],[[439,439],"mapped",[658]],[[440,440],"mapped",[441]],[[441,443],"valid"],[[444,444],"mapped",[445]],[[445,451],"valid"],[[452,454],"mapped",[100,382]],[[455,457],"mapped",[108,106]],[[458,460],"mapped",[110,106]],[[461,461],"mapped",[462]],[[462,462],"valid"],[[463,463],"mapped",[464]],[[464,464],"valid"],[[465,465],"mapped",[466]],[[466,466],"valid"],[[467,467],"mapped",[468]],[[468,468],"valid"],[[469,469],"mapped",[470]],[[470,470],"valid"],[[471,471],"mapped",[472]],[[472,472],"valid"],[[473,473],"mapped",[474]],[[474,474],"valid"],[[475,475],"mapped",[476]],[[476,477],"valid"],[[478,478],"mapped",[479]],[[479,479],"valid"],[[480,480],"mapped",[481]],[[481,481],"valid"],[[482,482],"mapped",[483]],[[483,483],"valid"],[[484,484],"mapped",[485]],[[485,485],"valid"],[[486,486],"mapped",[487]],[[487,487],"valid"],[[488,488],"mapped",[489]],[[489,489],"valid"],[[490,490],"mapped",[491]],[[491,491],"valid"],[[492,492],"mapped",[493]],[[493,493],"valid"],[[494,494],"mapped",[495]],[[495,496],"valid"],[[497,499],"mapped",[100,122]],[[500,500],"mapped",[501]],[[501,501],"valid"],[[502,502],"mapped",[405]],[[503,503],"mapped",[447]],[[504,504],"mapped",[505]],[[505,505],"valid"],[[506,506],"mapped",[507]],[[507,507],"valid"],[[508,508],"mapped",[509]],[[509,509],"valid"],[[510,510],"mapped",[511]],[[511,511],"valid"],[[512,512],"mapped",[513]],[[513,513],"valid"],[[514,514],"mapped",[515]],[[515,515],"valid"],[[516,516],"mapped",[517]],[[517,517],"valid"],[[518,518],"mapped",[519]],[[519,519],"valid"],[[520,520],"mapped",[521]],[[521,521],"valid"],[[522,522],"mapped",[523]],[[523,523],"valid"],[[524,524],"mapped",[525]],[[525,525],"valid"],[[526,526],"mapped",[527]],[[527,527],"valid"],[[528,528],"mapped",[529]],[[529,529],"valid"],[[530,530],"mapped",[531]],[[531,531],"valid"],[[532,532],"mapped",[533]],[[533,533],"valid"],[[534,534],"mapped",[535]],[[535,535],"valid"],[[536,536],"mapped",[537]],[[537,537],"valid"],[[538,538],"mapped",[539]],[[539,539],"valid"],[[540,540],"mapped",[541]],[[541,541],"valid"],[[542,542],"mapped",[543]],[[543,543],"valid"],[[544,544],"mapped",[414]],[[545,545],"valid"],[[546,546],"mapped",[547]],[[547,547],"valid"],[[548,548],"mapped",[549]],[[549,549],"valid"],[[550,550],"mapped",[551]],[[551,551],"valid"],[[552,552],"mapped",[553]],[[553,553],"valid"],[[554,554],"mapped",[555]],[[555,555],"valid"],[[556,556],"mapped",[557]],[[557,557],"valid"],[[558,558],"mapped",[559]],[[559,559],"valid"],[[560,560],"mapped",[561]],[[561,561],"valid"],[[562,562],"mapped",[563]],[[563,563],"valid"],[[564,566],"valid"],[[567,569],"valid"],[[570,570],"mapped",[11365]],[[571,571],"mapped",[572]],[[572,572],"valid"],[[573,573],"mapped",[410]],[[574,574],"mapped",[11366]],[[575,576],"valid"],[[577,577],"mapped",[578]],[[578,578],"valid"],[[579,579],"mapped",[384]],[[580,580],"mapped",[649]],[[581,581],"mapped",[652]],[[582,582],"mapped",[583]],[[583,583],"valid"],[[584,584],"mapped",[585]],[[585,585],"valid"],[[586,586],"mapped",[587]],[[587,587],"valid"],[[588,588],"mapped",[589]],[[589,589],"valid"],[[590,590],"mapped",[591]],[[591,591],"valid"],[[592,680],"valid"],[[681,685],"valid"],[[686,687],"valid"],[[688,688],"mapped",[104]],[[689,689],"mapped",[614]],[[690,690],"mapped",[106]],[[691,691],"mapped",[114]],[[692,692],"mapped",[633]],[[693,693],"mapped",[635]],[[694,694],"mapped",[641]],[[695,695],"mapped",[119]],[[696,696],"mapped",[121]],[[697,705],"valid"],[[706,709],"valid",[],"NV8"],[[710,721],"valid"],[[722,727],"valid",[],"NV8"],[[728,728],"disallowed_STD3_mapped",[32,774]],[[729,729],"disallowed_STD3_mapped",[32,775]],[[730,730],"disallowed_STD3_mapped",[32,778]],[[731,731],"disallowed_STD3_mapped",[32,808]],[[732,732],"disallowed_STD3_mapped",[32,771]],[[733,733],"disallowed_STD3_mapped",[32,779]],[[734,734],"valid",[],"NV8"],[[735,735],"valid",[],"NV8"],[[736,736],"mapped",[611]],[[737,737],"mapped",[108]],[[738,738],"mapped",[115]],[[739,739],"mapped",[120]],[[740,740],"mapped",[661]],[[741,745],"valid",[],"NV8"],[[746,747],"valid",[],"NV8"],[[748,748],"valid"],[[749,749],"valid",[],"NV8"],[[750,750],"valid"],[[751,767],"valid",[],"NV8"],[[768,831],"valid"],[[832,832],"mapped",[768]],[[833,833],"mapped",[769]],[[834,834],"valid"],[[835,835],"mapped",[787]],[[836,836],"mapped",[776,769]],[[837,837],"mapped",[953]],[[838,846],"valid"],[[847,847],"ignored"],[[848,855],"valid"],[[856,860],"valid"],[[861,863],"valid"],[[864,865],"valid"],[[866,866],"valid"],[[867,879],"valid"],[[880,880],"mapped",[881]],[[881,881],"valid"],[[882,882],"mapped",[883]],[[883,883],"valid"],[[884,884],"mapped",[697]],[[885,885],"valid"],[[886,886],"mapped",[887]],[[887,887],"valid"],[[888,889],"disallowed"],[[890,890],"disallowed_STD3_mapped",[32,953]],[[891,893],"valid"],[[894,894],"disallowed_STD3_mapped",[59]],[[895,895],"mapped",[1011]],[[896,899],"disallowed"],[[900,900],"disallowed_STD3_mapped",[32,769]],[[901,901],"disallowed_STD3_mapped",[32,776,769]],[[902,902],"mapped",[940]],[[903,903],"mapped",[183]],[[904,904],"mapped",[941]],[[905,905],"mapped",[942]],[[906,906],"mapped",[943]],[[907,907],"disallowed"],[[908,908],"mapped",[972]],[[909,909],"disallowed"],[[910,910],"mapped",[973]],[[911,911],"mapped",[974]],[[912,912],"valid"],[[913,913],"mapped",[945]],[[914,914],"mapped",[946]],[[915,915],"mapped",[947]],[[916,916],"mapped",[948]],[[917,917],"mapped",[949]],[[918,918],"mapped",[950]],[[919,919],"mapped",[951]],[[920,920],"mapped",[952]],[[921,921],"mapped",[953]],[[922,922],"mapped",[954]],[[923,923],"mapped",[955]],[[924,924],"mapped",[956]],[[925,925],"mapped",[957]],[[926,926],"mapped",[958]],[[927,927],"mapped",[959]],[[928,928],"mapped",[960]],[[929,929],"mapped",[961]],[[930,930],"disallowed"],[[931,931],"mapped",[963]],[[932,932],"mapped",[964]],[[933,933],"mapped",[965]],[[934,934],"mapped",[966]],[[935,935],"mapped",[967]],[[936,936],"mapped",[968]],[[937,937],"mapped",[969]],[[938,938],"mapped",[970]],[[939,939],"mapped",[971]],[[940,961],"valid"],[[962,962],"deviation",[963]],[[963,974],"valid"],[[975,975],"mapped",[983]],[[976,976],"mapped",[946]],[[977,977],"mapped",[952]],[[978,978],"mapped",[965]],[[979,979],"mapped",[973]],[[980,980],"mapped",[971]],[[981,981],"mapped",[966]],[[982,982],"mapped",[960]],[[983,983],"valid"],[[984,984],"mapped",[985]],[[985,985],"valid"],[[986,986],"mapped",[987]],[[987,987],"valid"],[[988,988],"mapped",[989]],[[989,989],"valid"],[[990,990],"mapped",[991]],[[991,991],"valid"],[[992,992],"mapped",[993]],[[993,993],"valid"],[[994,994],"mapped",[995]],[[995,995],"valid"],[[996,996],"mapped",[997]],[[997,997],"valid"],[[998,998],"mapped",[999]],[[999,999],"valid"],[[1000,1000],"mapped",[1001]],[[1001,1001],"valid"],[[1002,1002],"mapped",[1003]],[[1003,1003],"valid"],[[1004,1004],"mapped",[1005]],[[1005,1005],"valid"],[[1006,1006],"mapped",[1007]],[[1007,1007],"valid"],[[1008,1008],"mapped",[954]],[[1009,1009],"mapped",[961]],[[1010,1010],"mapped",[963]],[[1011,1011],"valid"],[[1012,1012],"mapped",[952]],[[1013,1013],"mapped",[949]],[[1014,1014],"valid",[],"NV8"],[[1015,1015],"mapped",[1016]],[[1016,1016],"valid"],[[1017,1017],"mapped",[963]],[[1018,1018],"mapped",[1019]],[[1019,1019],"valid"],[[1020,1020],"valid"],[[1021,1021],"mapped",[891]],[[1022,1022],"mapped",[892]],[[1023,1023],"mapped",[893]],[[1024,1024],"mapped",[1104]],[[1025,1025],"mapped",[1105]],[[1026,1026],"mapped",[1106]],[[1027,1027],"mapped",[1107]],[[1028,1028],"mapped",[1108]],[[1029,1029],"mapped",[1109]],[[1030,1030],"mapped",[1110]],[[1031,1031],"mapped",[1111]],[[1032,1032],"mapped",[1112]],[[1033,1033],"mapped",[1113]],[[1034,1034],"mapped",[1114]],[[1035,1035],"mapped",[1115]],[[1036,1036],"mapped",[1116]],[[1037,1037],"mapped",[1117]],[[1038,1038],"mapped",[1118]],[[1039,1039],"mapped",[1119]],[[1040,1040],"mapped",[1072]],[[1041,1041],"mapped",[1073]],[[1042,1042],"mapped",[1074]],[[1043,1043],"mapped",[1075]],[[1044,1044],"mapped",[1076]],[[1045,1045],"mapped",[1077]],[[1046,1046],"mapped",[1078]],[[1047,1047],"mapped",[1079]],[[1048,1048],"mapped",[1080]],[[1049,1049],"mapped",[1081]],[[1050,1050],"mapped",[1082]],[[1051,1051],"mapped",[1083]],[[1052,1052],"mapped",[1084]],[[1053,1053],"mapped",[1085]],[[1054,1054],"mapped",[1086]],[[1055,1055],"mapped",[1087]],[[1056,1056],"mapped",[1088]],[[1057,1057],"mapped",[1089]],[[1058,1058],"mapped",[1090]],[[1059,1059],"mapped",[1091]],[[1060,1060],"mapped",[1092]],[[1061,1061],"mapped",[1093]],[[1062,1062],"mapped",[1094]],[[1063,1063],"mapped",[1095]],[[1064,1064],"mapped",[1096]],[[1065,1065],"mapped",[1097]],[[1066,1066],"mapped",[1098]],[[1067,1067],"mapped",[1099]],[[1068,1068],"mapped",[1100]],[[1069,1069],"mapped",[1101]],[[1070,1070],"mapped",[1102]],[[1071,1071],"mapped",[1103]],[[1072,1103],"valid"],[[1104,1104],"valid"],[[1105,1116],"valid"],[[1117,1117],"valid"],[[1118,1119],"valid"],[[1120,1120],"mapped",[1121]],[[1121,1121],"valid"],[[1122,1122],"mapped",[1123]],[[1123,1123],"valid"],[[1124,1124],"mapped",[1125]],[[1125,1125],"valid"],[[1126,1126],"mapped",[1127]],[[1127,1127],"valid"],[[1128,1128],"mapped",[1129]],[[1129,1129],"valid"],[[1130,1130],"mapped",[1131]],[[1131,1131],"valid"],[[1132,1132],"mapped",[1133]],[[1133,1133],"valid"],[[1134,1134],"mapped",[1135]],[[1135,1135],"valid"],[[1136,1136],"mapped",[1137]],[[1137,1137],"valid"],[[1138,1138],"mapped",[1139]],[[1139,1139],"valid"],[[1140,1140],"mapped",[1141]],[[1141,1141],"valid"],[[1142,1142],"mapped",[1143]],[[1143,1143],"valid"],[[1144,1144],"mapped",[1145]],[[1145,1145],"valid"],[[1146,1146],"mapped",[1147]],[[1147,1147],"valid"],[[1148,1148],"mapped",[1149]],[[1149,1149],"valid"],[[1150,1150],"mapped",[1151]],[[1151,1151],"valid"],[[1152,1152],"mapped",[1153]],[[1153,1153],"valid"],[[1154,1154],"valid",[],"NV8"],[[1155,1158],"valid"],[[1159,1159],"valid"],[[1160,1161],"valid",[],"NV8"],[[1162,1162],"mapped",[1163]],[[1163,1163],"valid"],[[1164,1164],"mapped",[1165]],[[1165,1165],"valid"],[[1166,1166],"mapped",[1167]],[[1167,1167],"valid"],[[1168,1168],"mapped",[1169]],[[1169,1169],"valid"],[[1170,1170],"mapped",[1171]],[[1171,1171],"valid"],[[1172,1172],"mapped",[1173]],[[1173,1173],"valid"],[[1174,1174],"mapped",[1175]],[[1175,1175],"valid"],[[1176,1176],"mapped",[1177]],[[1177,1177],"valid"],[[1178,1178],"mapped",[1179]],[[1179,1179],"valid"],[[1180,1180],"mapped",[1181]],[[1181,1181],"valid"],[[1182,1182],"mapped",[1183]],[[1183,1183],"valid"],[[1184,1184],"mapped",[1185]],[[1185,1185],"valid"],[[1186,1186],"mapped",[1187]],[[1187,1187],"valid"],[[1188,1188],"mapped",[1189]],[[1189,1189],"valid"],[[1190,1190],"mapped",[1191]],[[1191,1191],"valid"],[[1192,1192],"mapped",[1193]],[[1193,1193],"valid"],[[1194,1194],"mapped",[1195]],[[1195,1195],"valid"],[[1196,1196],"mapped",[1197]],[[1197,1197],"valid"],[[1198,1198],"mapped",[1199]],[[1199,1199],"valid"],[[1200,1200],"mapped",[1201]],[[1201,1201],"valid"],[[1202,1202],"mapped",[1203]],[[1203,1203],"valid"],[[1204,1204],"mapped",[1205]],[[1205,1205],"valid"],[[1206,1206],"mapped",[1207]],[[1207,1207],"valid"],[[1208,1208],"mapped",[1209]],[[1209,1209],"valid"],[[1210,1210],"mapped",[1211]],[[1211,1211],"valid"],[[1212,1212],"mapped",[1213]],[[1213,1213],"valid"],[[1214,1214],"mapped",[1215]],[[1215,1215],"valid"],[[1216,1216],"disallowed"],[[1217,1217],"mapped",[1218]],[[1218,1218],"valid"],[[1219,1219],"mapped",[1220]],[[1220,1220],"valid"],[[1221,1221],"mapped",[1222]],[[1222,1222],"valid"],[[1223,1223],"mapped",[1224]],[[1224,1224],"valid"],[[1225,1225],"mapped",[1226]],[[1226,1226],"valid"],[[1227,1227],"mapped",[1228]],[[1228,1228],"valid"],[[1229,1229],"mapped",[1230]],[[1230,1230],"valid"],[[1231,1231],"valid"],[[1232,1232],"mapped",[1233]],[[1233,1233],"valid"],[[1234,1234],"mapped",[1235]],[[1235,1235],"valid"],[[1236,1236],"mapped",[1237]],[[1237,1237],"valid"],[[1238,1238],"mapped",[1239]],[[1239,1239],"valid"],[[1240,1240],"mapped",[1241]],[[1241,1241],"valid"],[[1242,1242],"mapped",[1243]],[[1243,1243],"valid"],[[1244,1244],"mapped",[1245]],[[1245,1245],"valid"],[[1246,1246],"mapped",[1247]],[[1247,1247],"valid"],[[1248,1248],"mapped",[1249]],[[1249,1249],"valid"],[[1250,1250],"mapped",[1251]],[[1251,1251],"valid"],[[1252,1252],"mapped",[1253]],[[1253,1253],"valid"],[[1254,1254],"mapped",[1255]],[[1255,1255],"valid"],[[1256,1256],"mapped",[1257]],[[1257,1257],"valid"],[[1258,1258],"mapped",[1259]],[[1259,1259],"valid"],[[1260,1260],"mapped",[1261]],[[1261,1261],"valid"],[[1262,1262],"mapped",[1263]],[[1263,1263],"valid"],[[1264,1264],"mapped",[1265]],[[1265,1265],"valid"],[[1266,1266],"mapped",[1267]],[[1267,1267],"valid"],[[1268,1268],"mapped",[1269]],[[1269,1269],"valid"],[[1270,1270],"mapped",[1271]],[[1271,1271],"valid"],[[1272,1272],"mapped",[1273]],[[1273,1273],"valid"],[[1274,1274],"mapped",[1275]],[[1275,1275],"valid"],[[1276,1276],"mapped",[1277]],[[1277,1277],"valid"],[[1278,1278],"mapped",[1279]],[[1279,1279],"valid"],[[1280,1280],"mapped",[1281]],[[1281,1281],"valid"],[[1282,1282],"mapped",[1283]],[[1283,1283],"valid"],[[1284,1284],"mapped",[1285]],[[1285,1285],"valid"],[[1286,1286],"mapped",[1287]],[[1287,1287],"valid"],[[1288,1288],"mapped",[1289]],[[1289,1289],"valid"],[[1290,1290],"mapped",[1291]],[[1291,1291],"valid"],[[1292,1292],"mapped",[1293]],[[1293,1293],"valid"],[[1294,1294],"mapped",[1295]],[[1295,1295],"valid"],[[1296,1296],"mapped",[1297]],[[1297,1297],"valid"],[[1298,1298],"mapped",[1299]],[[1299,1299],"valid"],[[1300,1300],"mapped",[1301]],[[1301,1301],"valid"],[[1302,1302],"mapped",[1303]],[[1303,1303],"valid"],[[1304,1304],"mapped",[1305]],[[1305,1305],"valid"],[[1306,1306],"mapped",[1307]],[[1307,1307],"valid"],[[1308,1308],"mapped",[1309]],[[1309,1309],"valid"],[[1310,1310],"mapped",[1311]],[[1311,1311],"valid"],[[1312,1312],"mapped",[1313]],[[1313,1313],"valid"],[[1314,1314],"mapped",[1315]],[[1315,1315],"valid"],[[1316,1316],"mapped",[1317]],[[1317,1317],"valid"],[[1318,1318],"mapped",[1319]],[[1319,1319],"valid"],[[1320,1320],"mapped",[1321]],[[1321,1321],"valid"],[[1322,1322],"mapped",[1323]],[[1323,1323],"valid"],[[1324,1324],"mapped",[1325]],[[1325,1325],"valid"],[[1326,1326],"mapped",[1327]],[[1327,1327],"valid"],[[1328,1328],"disallowed"],[[1329,1329],"mapped",[1377]],[[1330,1330],"mapped",[1378]],[[1331,1331],"mapped",[1379]],[[1332,1332],"mapped",[1380]],[[1333,1333],"mapped",[1381]],[[1334,1334],"mapped",[1382]],[[1335,1335],"mapped",[1383]],[[1336,1336],"mapped",[1384]],[[1337,1337],"mapped",[1385]],[[1338,1338],"mapped",[1386]],[[1339,1339],"mapped",[1387]],[[1340,1340],"mapped",[1388]],[[1341,1341],"mapped",[1389]],[[1342,1342],"mapped",[1390]],[[1343,1343],"mapped",[1391]],[[1344,1344],"mapped",[1392]],[[1345,1345],"mapped",[1393]],[[1346,1346],"mapped",[1394]],[[1347,1347],"mapped",[1395]],[[1348,1348],"mapped",[1396]],[[1349,1349],"mapped",[1397]],[[1350,1350],"mapped",[1398]],[[1351,1351],"mapped",[1399]],[[1352,1352],"mapped",[1400]],[[1353,1353],"mapped",[1401]],[[1354,1354],"mapped",[1402]],[[1355,1355],"mapped",[1403]],[[1356,1356],"mapped",[1404]],[[1357,1357],"mapped",[1405]],[[1358,1358],"mapped",[1406]],[[1359,1359],"mapped",[1407]],[[1360,1360],"mapped",[1408]],[[1361,1361],"mapped",[1409]],[[1362,1362],"mapped",[1410]],[[1363,1363],"mapped",[1411]],[[1364,1364],"mapped",[1412]],[[1365,1365],"mapped",[1413]],[[1366,1366],"mapped",[1414]],[[1367,1368],"disallowed"],[[1369,1369],"valid"],[[1370,1375],"valid",[],"NV8"],[[1376,1376],"disallowed"],[[1377,1414],"valid"],[[1415,1415],"mapped",[1381,1410]],[[1416,1416],"disallowed"],[[1417,1417],"valid",[],"NV8"],[[1418,1418],"valid",[],"NV8"],[[1419,1420],"disallowed"],[[1421,1422],"valid",[],"NV8"],[[1423,1423],"valid",[],"NV8"],[[1424,1424],"disallowed"],[[1425,1441],"valid"],[[1442,1442],"valid"],[[1443,1455],"valid"],[[1456,1465],"valid"],[[1466,1466],"valid"],[[1467,1469],"valid"],[[1470,1470],"valid",[],"NV8"],[[1471,1471],"valid"],[[1472,1472],"valid",[],"NV8"],[[1473,1474],"valid"],[[1475,1475],"valid",[],"NV8"],[[1476,1476],"valid"],[[1477,1477],"valid"],[[1478,1478],"valid",[],"NV8"],[[1479,1479],"valid"],[[1480,1487],"disallowed"],[[1488,1514],"valid"],[[1515,1519],"disallowed"],[[1520,1524],"valid"],[[1525,1535],"disallowed"],[[1536,1539],"disallowed"],[[1540,1540],"disallowed"],[[1541,1541],"disallowed"],[[1542,1546],"valid",[],"NV8"],[[1547,1547],"valid",[],"NV8"],[[1548,1548],"valid",[],"NV8"],[[1549,1551],"valid",[],"NV8"],[[1552,1557],"valid"],[[1558,1562],"valid"],[[1563,1563],"valid",[],"NV8"],[[1564,1564],"disallowed"],[[1565,1565],"disallowed"],[[1566,1566],"valid",[],"NV8"],[[1567,1567],"valid",[],"NV8"],[[1568,1568],"valid"],[[1569,1594],"valid"],[[1595,1599],"valid"],[[1600,1600],"valid",[],"NV8"],[[1601,1618],"valid"],[[1619,1621],"valid"],[[1622,1624],"valid"],[[1625,1630],"valid"],[[1631,1631],"valid"],[[1632,1641],"valid"],[[1642,1645],"valid",[],"NV8"],[[1646,1647],"valid"],[[1648,1652],"valid"],[[1653,1653],"mapped",[1575,1652]],[[1654,1654],"mapped",[1608,1652]],[[1655,1655],"mapped",[1735,1652]],[[1656,1656],"mapped",[1610,1652]],[[1657,1719],"valid"],[[1720,1721],"valid"],[[1722,1726],"valid"],[[1727,1727],"valid"],[[1728,1742],"valid"],[[1743,1743],"valid"],[[1744,1747],"valid"],[[1748,1748],"valid",[],"NV8"],[[1749,1756],"valid"],[[1757,1757],"disallowed"],[[1758,1758],"valid",[],"NV8"],[[1759,1768],"valid"],[[1769,1769],"valid",[],"NV8"],[[1770,1773],"valid"],[[1774,1775],"valid"],[[1776,1785],"valid"],[[1786,1790],"valid"],[[1791,1791],"valid"],[[1792,1805],"valid",[],"NV8"],[[1806,1806],"disallowed"],[[1807,1807],"disallowed"],[[1808,1836],"valid"],[[1837,1839],"valid"],[[1840,1866],"valid"],[[1867,1868],"disallowed"],[[1869,1871],"valid"],[[1872,1901],"valid"],[[1902,1919],"valid"],[[1920,1968],"valid"],[[1969,1969],"valid"],[[1970,1983],"disallowed"],[[1984,2037],"valid"],[[2038,2042],"valid",[],"NV8"],[[2043,2047],"disallowed"],[[2048,2093],"valid"],[[2094,2095],"disallowed"],[[2096,2110],"valid",[],"NV8"],[[2111,2111],"disallowed"],[[2112,2139],"valid"],[[2140,2141],"disallowed"],[[2142,2142],"valid",[],"NV8"],[[2143,2207],"disallowed"],[[2208,2208],"valid"],[[2209,2209],"valid"],[[2210,2220],"valid"],[[2221,2226],"valid"],[[2227,2228],"valid"],[[2229,2274],"disallowed"],[[2275,2275],"valid"],[[2276,2302],"valid"],[[2303,2303],"valid"],[[2304,2304],"valid"],[[2305,2307],"valid"],[[2308,2308],"valid"],[[2309,2361],"valid"],[[2362,2363],"valid"],[[2364,2381],"valid"],[[2382,2382],"valid"],[[2383,2383],"valid"],[[2384,2388],"valid"],[[2389,2389],"valid"],[[2390,2391],"valid"],[[2392,2392],"mapped",[2325,2364]],[[2393,2393],"mapped",[2326,2364]],[[2394,2394],"mapped",[2327,2364]],[[2395,2395],"mapped",[2332,2364]],[[2396,2396],"mapped",[2337,2364]],[[2397,2397],"mapped",[2338,2364]],[[2398,2398],"mapped",[2347,2364]],[[2399,2399],"mapped",[2351,2364]],[[2400,2403],"valid"],[[2404,2405],"valid",[],"NV8"],[[2406,2415],"valid"],[[2416,2416],"valid",[],"NV8"],[[2417,2418],"valid"],[[2419,2423],"valid"],[[2424,2424],"valid"],[[2425,2426],"valid"],[[2427,2428],"valid"],[[2429,2429],"valid"],[[2430,2431],"valid"],[[2432,2432],"valid"],[[2433,2435],"valid"],[[2436,2436],"disallowed"],[[2437,2444],"valid"],[[2445,2446],"disallowed"],[[2447,2448],"valid"],[[2449,2450],"disallowed"],[[2451,2472],"valid"],[[2473,2473],"disallowed"],[[2474,2480],"valid"],[[2481,2481],"disallowed"],[[2482,2482],"valid"],[[2483,2485],"disallowed"],[[2486,2489],"valid"],[[2490,2491],"disallowed"],[[2492,2492],"valid"],[[2493,2493],"valid"],[[2494,2500],"valid"],[[2501,2502],"disallowed"],[[2503,2504],"valid"],[[2505,2506],"disallowed"],[[2507,2509],"valid"],[[2510,2510],"valid"],[[2511,2518],"disallowed"],[[2519,2519],"valid"],[[2520,2523],"disallowed"],[[2524,2524],"mapped",[2465,2492]],[[2525,2525],"mapped",[2466,2492]],[[2526,2526],"disallowed"],[[2527,2527],"mapped",[2479,2492]],[[2528,2531],"valid"],[[2532,2533],"disallowed"],[[2534,2545],"valid"],[[2546,2554],"valid",[],"NV8"],[[2555,2555],"valid",[],"NV8"],[[2556,2560],"disallowed"],[[2561,2561],"valid"],[[2562,2562],"valid"],[[2563,2563],"valid"],[[2564,2564],"disallowed"],[[2565,2570],"valid"],[[2571,2574],"disallowed"],[[2575,2576],"valid"],[[2577,2578],"disallowed"],[[2579,2600],"valid"],[[2601,2601],"disallowed"],[[2602,2608],"valid"],[[2609,2609],"disallowed"],[[2610,2610],"valid"],[[2611,2611],"mapped",[2610,2620]],[[2612,2612],"disallowed"],[[2613,2613],"valid"],[[2614,2614],"mapped",[2616,2620]],[[2615,2615],"disallowed"],[[2616,2617],"valid"],[[2618,2619],"disallowed"],[[2620,2620],"valid"],[[2621,2621],"disallowed"],[[2622,2626],"valid"],[[2627,2630],"disallowed"],[[2631,2632],"valid"],[[2633,2634],"disallowed"],[[2635,2637],"valid"],[[2638,2640],"disallowed"],[[2641,2641],"valid"],[[2642,2648],"disallowed"],[[2649,2649],"mapped",[2582,2620]],[[2650,2650],"mapped",[2583,2620]],[[2651,2651],"mapped",[2588,2620]],[[2652,2652],"valid"],[[2653,2653],"disallowed"],[[2654,2654],"mapped",[2603,2620]],[[2655,2661],"disallowed"],[[2662,2676],"valid"],[[2677,2677],"valid"],[[2678,2688],"disallowed"],[[2689,2691],"valid"],[[2692,2692],"disallowed"],[[2693,2699],"valid"],[[2700,2700],"valid"],[[2701,2701],"valid"],[[2702,2702],"disallowed"],[[2703,2705],"valid"],[[2706,2706],"disallowed"],[[2707,2728],"valid"],[[2729,2729],"disallowed"],[[2730,2736],"valid"],[[2737,2737],"disallowed"],[[2738,2739],"valid"],[[2740,2740],"disallowed"],[[2741,2745],"valid"],[[2746,2747],"disallowed"],[[2748,2757],"valid"],[[2758,2758],"disallowed"],[[2759,2761],"valid"],[[2762,2762],"disallowed"],[[2763,2765],"valid"],[[2766,2767],"disallowed"],[[2768,2768],"valid"],[[2769,2783],"disallowed"],[[2784,2784],"valid"],[[2785,2787],"valid"],[[2788,2789],"disallowed"],[[2790,2799],"valid"],[[2800,2800],"valid",[],"NV8"],[[2801,2801],"valid",[],"NV8"],[[2802,2808],"disallowed"],[[2809,2809],"valid"],[[2810,2816],"disallowed"],[[2817,2819],"valid"],[[2820,2820],"disallowed"],[[2821,2828],"valid"],[[2829,2830],"disallowed"],[[2831,2832],"valid"],[[2833,2834],"disallowed"],[[2835,2856],"valid"],[[2857,2857],"disallowed"],[[2858,2864],"valid"],[[2865,2865],"disallowed"],[[2866,2867],"valid"],[[2868,2868],"disallowed"],[[2869,2869],"valid"],[[2870,2873],"valid"],[[2874,2875],"disallowed"],[[2876,2883],"valid"],[[2884,2884],"valid"],[[2885,2886],"disallowed"],[[2887,2888],"valid"],[[2889,2890],"disallowed"],[[2891,2893],"valid"],[[2894,2901],"disallowed"],[[2902,2903],"valid"],[[2904,2907],"disallowed"],[[2908,2908],"mapped",[2849,2876]],[[2909,2909],"mapped",[2850,2876]],[[2910,2910],"disallowed"],[[2911,2913],"valid"],[[2914,2915],"valid"],[[2916,2917],"disallowed"],[[2918,2927],"valid"],[[2928,2928],"valid",[],"NV8"],[[2929,2929],"valid"],[[2930,2935],"valid",[],"NV8"],[[2936,2945],"disallowed"],[[2946,2947],"valid"],[[2948,2948],"disallowed"],[[2949,2954],"valid"],[[2955,2957],"disallowed"],[[2958,2960],"valid"],[[2961,2961],"disallowed"],[[2962,2965],"valid"],[[2966,2968],"disallowed"],[[2969,2970],"valid"],[[2971,2971],"disallowed"],[[2972,2972],"valid"],[[2973,2973],"disallowed"],[[2974,2975],"valid"],[[2976,2978],"disallowed"],[[2979,2980],"valid"],[[2981,2983],"disallowed"],[[2984,2986],"valid"],[[2987,2989],"disallowed"],[[2990,2997],"valid"],[[2998,2998],"valid"],[[2999,3001],"valid"],[[3002,3005],"disallowed"],[[3006,3010],"valid"],[[3011,3013],"disallowed"],[[3014,3016],"valid"],[[3017,3017],"disallowed"],[[3018,3021],"valid"],[[3022,3023],"disallowed"],[[3024,3024],"valid"],[[3025,3030],"disallowed"],[[3031,3031],"valid"],[[3032,3045],"disallowed"],[[3046,3046],"valid"],[[3047,3055],"valid"],[[3056,3058],"valid",[],"NV8"],[[3059,3066],"valid",[],"NV8"],[[3067,3071],"disallowed"],[[3072,3072],"valid"],[[3073,3075],"valid"],[[3076,3076],"disallowed"],[[3077,3084],"valid"],[[3085,3085],"disallowed"],[[3086,3088],"valid"],[[3089,3089],"disallowed"],[[3090,3112],"valid"],[[3113,3113],"disallowed"],[[3114,3123],"valid"],[[3124,3124],"valid"],[[3125,3129],"valid"],[[3130,3132],"disallowed"],[[3133,3133],"valid"],[[3134,3140],"valid"],[[3141,3141],"disallowed"],[[3142,3144],"valid"],[[3145,3145],"disallowed"],[[3146,3149],"valid"],[[3150,3156],"disallowed"],[[3157,3158],"valid"],[[3159,3159],"disallowed"],[[3160,3161],"valid"],[[3162,3162],"valid"],[[3163,3167],"disallowed"],[[3168,3169],"valid"],[[3170,3171],"valid"],[[3172,3173],"disallowed"],[[3174,3183],"valid"],[[3184,3191],"disallowed"],[[3192,3199],"valid",[],"NV8"],[[3200,3200],"disallowed"],[[3201,3201],"valid"],[[3202,3203],"valid"],[[3204,3204],"disallowed"],[[3205,3212],"valid"],[[3213,3213],"disallowed"],[[3214,3216],"valid"],[[3217,3217],"disallowed"],[[3218,3240],"valid"],[[3241,3241],"disallowed"],[[3242,3251],"valid"],[[3252,3252],"disallowed"],[[3253,3257],"valid"],[[3258,3259],"disallowed"],[[3260,3261],"valid"],[[3262,3268],"valid"],[[3269,3269],"disallowed"],[[3270,3272],"valid"],[[3273,3273],"disallowed"],[[3274,3277],"valid"],[[3278,3284],"disallowed"],[[3285,3286],"valid"],[[3287,3293],"disallowed"],[[3294,3294],"valid"],[[3295,3295],"disallowed"],[[3296,3297],"valid"],[[3298,3299],"valid"],[[3300,3301],"disallowed"],[[3302,3311],"valid"],[[3312,3312],"disallowed"],[[3313,3314],"valid"],[[3315,3328],"disallowed"],[[3329,3329],"valid"],[[3330,3331],"valid"],[[3332,3332],"disallowed"],[[3333,3340],"valid"],[[3341,3341],"disallowed"],[[3342,3344],"valid"],[[3345,3345],"disallowed"],[[3346,3368],"valid"],[[3369,3369],"valid"],[[3370,3385],"valid"],[[3386,3386],"valid"],[[3387,3388],"disallowed"],[[3389,3389],"valid"],[[3390,3395],"valid"],[[3396,3396],"valid"],[[3397,3397],"disallowed"],[[3398,3400],"valid"],[[3401,3401],"disallowed"],[[3402,3405],"valid"],[[3406,3406],"valid"],[[3407,3414],"disallowed"],[[3415,3415],"valid"],[[3416,3422],"disallowed"],[[3423,3423],"valid"],[[3424,3425],"valid"],[[3426,3427],"valid"],[[3428,3429],"disallowed"],[[3430,3439],"valid"],[[3440,3445],"valid",[],"NV8"],[[3446,3448],"disallowed"],[[3449,3449],"valid",[],"NV8"],[[3450,3455],"valid"],[[3456,3457],"disallowed"],[[3458,3459],"valid"],[[3460,3460],"disallowed"],[[3461,3478],"valid"],[[3479,3481],"disallowed"],[[3482,3505],"valid"],[[3506,3506],"disallowed"],[[3507,3515],"valid"],[[3516,3516],"disallowed"],[[3517,3517],"valid"],[[3518,3519],"disallowed"],[[3520,3526],"valid"],[[3527,3529],"disallowed"],[[3530,3530],"valid"],[[3531,3534],"disallowed"],[[3535,3540],"valid"],[[3541,3541],"disallowed"],[[3542,3542],"valid"],[[3543,3543],"disallowed"],[[3544,3551],"valid"],[[3552,3557],"disallowed"],[[3558,3567],"valid"],[[3568,3569],"disallowed"],[[3570,3571],"valid"],[[3572,3572],"valid",[],"NV8"],[[3573,3584],"disallowed"],[[3585,3634],"valid"],[[3635,3635],"mapped",[3661,3634]],[[3636,3642],"valid"],[[3643,3646],"disallowed"],[[3647,3647],"valid",[],"NV8"],[[3648,3662],"valid"],[[3663,3663],"valid",[],"NV8"],[[3664,3673],"valid"],[[3674,3675],"valid",[],"NV8"],[[3676,3712],"disallowed"],[[3713,3714],"valid"],[[3715,3715],"disallowed"],[[3716,3716],"valid"],[[3717,3718],"disallowed"],[[3719,3720],"valid"],[[3721,3721],"disallowed"],[[3722,3722],"valid"],[[3723,3724],"disallowed"],[[3725,3725],"valid"],[[3726,3731],"disallowed"],[[3732,3735],"valid"],[[3736,3736],"disallowed"],[[3737,3743],"valid"],[[3744,3744],"disallowed"],[[3745,3747],"valid"],[[3748,3748],"disallowed"],[[3749,3749],"valid"],[[3750,3750],"disallowed"],[[3751,3751],"valid"],[[3752,3753],"disallowed"],[[3754,3755],"valid"],[[3756,3756],"disallowed"],[[3757,3762],"valid"],[[3763,3763],"mapped",[3789,3762]],[[3764,3769],"valid"],[[3770,3770],"disallowed"],[[3771,3773],"valid"],[[3774,3775],"disallowed"],[[3776,3780],"valid"],[[3781,3781],"disallowed"],[[3782,3782],"valid"],[[3783,3783],"disallowed"],[[3784,3789],"valid"],[[3790,3791],"disallowed"],[[3792,3801],"valid"],[[3802,3803],"disallowed"],[[3804,3804],"mapped",[3755,3737]],[[3805,3805],"mapped",[3755,3745]],[[3806,3807],"valid"],[[3808,3839],"disallowed"],[[3840,3840],"valid"],[[3841,3850],"valid",[],"NV8"],[[3851,3851],"valid"],[[3852,3852],"mapped",[3851]],[[3853,3863],"valid",[],"NV8"],[[3864,3865],"valid"],[[3866,3871],"valid",[],"NV8"],[[3872,3881],"valid"],[[3882,3892],"valid",[],"NV8"],[[3893,3893],"valid"],[[3894,3894],"valid",[],"NV8"],[[3895,3895],"valid"],[[3896,3896],"valid",[],"NV8"],[[3897,3897],"valid"],[[3898,3901],"valid",[],"NV8"],[[3902,3906],"valid"],[[3907,3907],"mapped",[3906,4023]],[[3908,3911],"valid"],[[3912,3912],"disallowed"],[[3913,3916],"valid"],[[3917,3917],"mapped",[3916,4023]],[[3918,3921],"valid"],[[3922,3922],"mapped",[3921,4023]],[[3923,3926],"valid"],[[3927,3927],"mapped",[3926,4023]],[[3928,3931],"valid"],[[3932,3932],"mapped",[3931,4023]],[[3933,3944],"valid"],[[3945,3945],"mapped",[3904,4021]],[[3946,3946],"valid"],[[3947,3948],"valid"],[[3949,3952],"disallowed"],[[3953,3954],"valid"],[[3955,3955],"mapped",[3953,3954]],[[3956,3956],"valid"],[[3957,3957],"mapped",[3953,3956]],[[3958,3958],"mapped",[4018,3968]],[[3959,3959],"mapped",[4018,3953,3968]],[[3960,3960],"mapped",[4019,3968]],[[3961,3961],"mapped",[4019,3953,3968]],[[3962,3968],"valid"],[[3969,3969],"mapped",[3953,3968]],[[3970,3972],"valid"],[[3973,3973],"valid",[],"NV8"],[[3974,3979],"valid"],[[3980,3983],"valid"],[[3984,3986],"valid"],[[3987,3987],"mapped",[3986,4023]],[[3988,3989],"valid"],[[3990,3990],"valid"],[[3991,3991],"valid"],[[3992,3992],"disallowed"],[[3993,3996],"valid"],[[3997,3997],"mapped",[3996,4023]],[[3998,4001],"valid"],[[4002,4002],"mapped",[4001,4023]],[[4003,4006],"valid"],[[4007,4007],"mapped",[4006,4023]],[[4008,4011],"valid"],[[4012,4012],"mapped",[4011,4023]],[[4013,4013],"valid"],[[4014,4016],"valid"],[[4017,4023],"valid"],[[4024,4024],"valid"],[[4025,4025],"mapped",[3984,4021]],[[4026,4028],"valid"],[[4029,4029],"disallowed"],[[4030,4037],"valid",[],"NV8"],[[4038,4038],"valid"],[[4039,4044],"valid",[],"NV8"],[[4045,4045],"disallowed"],[[4046,4046],"valid",[],"NV8"],[[4047,4047],"valid",[],"NV8"],[[4048,4049],"valid",[],"NV8"],[[4050,4052],"valid",[],"NV8"],[[4053,4056],"valid",[],"NV8"],[[4057,4058],"valid",[],"NV8"],[[4059,4095],"disallowed"],[[4096,4129],"valid"],[[4130,4130],"valid"],[[4131,4135],"valid"],[[4136,4136],"valid"],[[4137,4138],"valid"],[[4139,4139],"valid"],[[4140,4146],"valid"],[[4147,4149],"valid"],[[4150,4153],"valid"],[[4154,4159],"valid"],[[4160,4169],"valid"],[[4170,4175],"valid",[],"NV8"],[[4176,4185],"valid"],[[4186,4249],"valid"],[[4250,4253],"valid"],[[4254,4255],"valid",[],"NV8"],[[4256,4293],"disallowed"],[[4294,4294],"disallowed"],[[4295,4295],"mapped",[11559]],[[4296,4300],"disallowed"],[[4301,4301],"mapped",[11565]],[[4302,4303],"disallowed"],[[4304,4342],"valid"],[[4343,4344],"valid"],[[4345,4346],"valid"],[[4347,4347],"valid",[],"NV8"],[[4348,4348],"mapped",[4316]],[[4349,4351],"valid"],[[4352,4441],"valid",[],"NV8"],[[4442,4446],"valid",[],"NV8"],[[4447,4448],"disallowed"],[[4449,4514],"valid",[],"NV8"],[[4515,4519],"valid",[],"NV8"],[[4520,4601],"valid",[],"NV8"],[[4602,4607],"valid",[],"NV8"],[[4608,4614],"valid"],[[4615,4615],"valid"],[[4616,4678],"valid"],[[4679,4679],"valid"],[[4680,4680],"valid"],[[4681,4681],"disallowed"],[[4682,4685],"valid"],[[4686,4687],"disallowed"],[[4688,4694],"valid"],[[4695,4695],"disallowed"],[[4696,4696],"valid"],[[4697,4697],"disallowed"],[[4698,4701],"valid"],[[4702,4703],"disallowed"],[[4704,4742],"valid"],[[4743,4743],"valid"],[[4744,4744],"valid"],[[4745,4745],"disallowed"],[[4746,4749],"valid"],[[4750,4751],"disallowed"],[[4752,4782],"valid"],[[4783,4783],"valid"],[[4784,4784],"valid"],[[4785,4785],"disallowed"],[[4786,4789],"valid"],[[4790,4791],"disallowed"],[[4792,4798],"valid"],[[4799,4799],"disallowed"],[[4800,4800],"valid"],[[4801,4801],"disallowed"],[[4802,4805],"valid"],[[4806,4807],"disallowed"],[[4808,4814],"valid"],[[4815,4815],"valid"],[[4816,4822],"valid"],[[4823,4823],"disallowed"],[[4824,4846],"valid"],[[4847,4847],"valid"],[[4848,4878],"valid"],[[4879,4879],"valid"],[[4880,4880],"valid"],[[4881,4881],"disallowed"],[[4882,4885],"valid"],[[4886,4887],"disallowed"],[[4888,4894],"valid"],[[4895,4895],"valid"],[[4896,4934],"valid"],[[4935,4935],"valid"],[[4936,4954],"valid"],[[4955,4956],"disallowed"],[[4957,4958],"valid"],[[4959,4959],"valid"],[[4960,4960],"valid",[],"NV8"],[[4961,4988],"valid",[],"NV8"],[[4989,4991],"disallowed"],[[4992,5007],"valid"],[[5008,5017],"valid",[],"NV8"],[[5018,5023],"disallowed"],[[5024,5108],"valid"],[[5109,5109],"valid"],[[5110,5111],"disallowed"],[[5112,5112],"mapped",[5104]],[[5113,5113],"mapped",[5105]],[[5114,5114],"mapped",[5106]],[[5115,5115],"mapped",[5107]],[[5116,5116],"mapped",[5108]],[[5117,5117],"mapped",[5109]],[[5118,5119],"disallowed"],[[5120,5120],"valid",[],"NV8"],[[5121,5740],"valid"],[[5741,5742],"valid",[],"NV8"],[[5743,5750],"valid"],[[5751,5759],"valid"],[[5760,5760],"disallowed"],[[5761,5786],"valid"],[[5787,5788],"valid",[],"NV8"],[[5789,5791],"disallowed"],[[5792,5866],"valid"],[[5867,5872],"valid",[],"NV8"],[[5873,5880],"valid"],[[5881,5887],"disallowed"],[[5888,5900],"valid"],[[5901,5901],"disallowed"],[[5902,5908],"valid"],[[5909,5919],"disallowed"],[[5920,5940],"valid"],[[5941,5942],"valid",[],"NV8"],[[5943,5951],"disallowed"],[[5952,5971],"valid"],[[5972,5983],"disallowed"],[[5984,5996],"valid"],[[5997,5997],"disallowed"],[[5998,6000],"valid"],[[6001,6001],"disallowed"],[[6002,6003],"valid"],[[6004,6015],"disallowed"],[[6016,6067],"valid"],[[6068,6069],"disallowed"],[[6070,6099],"valid"],[[6100,6102],"valid",[],"NV8"],[[6103,6103],"valid"],[[6104,6107],"valid",[],"NV8"],[[6108,6108],"valid"],[[6109,6109],"valid"],[[6110,6111],"disallowed"],[[6112,6121],"valid"],[[6122,6127],"disallowed"],[[6128,6137],"valid",[],"NV8"],[[6138,6143],"disallowed"],[[6144,6149],"valid",[],"NV8"],[[6150,6150],"disallowed"],[[6151,6154],"valid",[],"NV8"],[[6155,6157],"ignored"],[[6158,6158],"disallowed"],[[6159,6159],"disallowed"],[[6160,6169],"valid"],[[6170,6175],"disallowed"],[[6176,6263],"valid"],[[6264,6271],"disallowed"],[[6272,6313],"valid"],[[6314,6314],"valid"],[[6315,6319],"disallowed"],[[6320,6389],"valid"],[[6390,6399],"disallowed"],[[6400,6428],"valid"],[[6429,6430],"valid"],[[6431,6431],"disallowed"],[[6432,6443],"valid"],[[6444,6447],"disallowed"],[[6448,6459],"valid"],[[6460,6463],"disallowed"],[[6464,6464],"valid",[],"NV8"],[[6465,6467],"disallowed"],[[6468,6469],"valid",[],"NV8"],[[6470,6509],"valid"],[[6510,6511],"disallowed"],[[6512,6516],"valid"],[[6517,6527],"disallowed"],[[6528,6569],"valid"],[[6570,6571],"valid"],[[6572,6575],"disallowed"],[[6576,6601],"valid"],[[6602,6607],"disallowed"],[[6608,6617],"valid"],[[6618,6618],"valid",[],"XV8"],[[6619,6621],"disallowed"],[[6622,6623],"valid",[],"NV8"],[[6624,6655],"valid",[],"NV8"],[[6656,6683],"valid"],[[6684,6685],"disallowed"],[[6686,6687],"valid",[],"NV8"],[[6688,6750],"valid"],[[6751,6751],"disallowed"],[[6752,6780],"valid"],[[6781,6782],"disallowed"],[[6783,6793],"valid"],[[6794,6799],"disallowed"],[[6800,6809],"valid"],[[6810,6815],"disallowed"],[[6816,6822],"valid",[],"NV8"],[[6823,6823],"valid"],[[6824,6829],"valid",[],"NV8"],[[6830,6831],"disallowed"],[[6832,6845],"valid"],[[6846,6846],"valid",[],"NV8"],[[6847,6911],"disallowed"],[[6912,6987],"valid"],[[6988,6991],"disallowed"],[[6992,7001],"valid"],[[7002,7018],"valid",[],"NV8"],[[7019,7027],"valid"],[[7028,7036],"valid",[],"NV8"],[[7037,7039],"disallowed"],[[7040,7082],"valid"],[[7083,7085],"valid"],[[7086,7097],"valid"],[[7098,7103],"valid"],[[7104,7155],"valid"],[[7156,7163],"disallowed"],[[7164,7167],"valid",[],"NV8"],[[7168,7223],"valid"],[[7224,7226],"disallowed"],[[7227,7231],"valid",[],"NV8"],[[7232,7241],"valid"],[[7242,7244],"disallowed"],[[7245,7293],"valid"],[[7294,7295],"valid",[],"NV8"],[[7296,7359],"disallowed"],[[7360,7367],"valid",[],"NV8"],[[7368,7375],"disallowed"],[[7376,7378],"valid"],[[7379,7379],"valid",[],"NV8"],[[7380,7410],"valid"],[[7411,7414],"valid"],[[7415,7415],"disallowed"],[[7416,7417],"valid"],[[7418,7423],"disallowed"],[[7424,7467],"valid"],[[7468,7468],"mapped",[97]],[[7469,7469],"mapped",[230]],[[7470,7470],"mapped",[98]],[[7471,7471],"valid"],[[7472,7472],"mapped",[100]],[[7473,7473],"mapped",[101]],[[7474,7474],"mapped",[477]],[[7475,7475],"mapped",[103]],[[7476,7476],"mapped",[104]],[[7477,7477],"mapped",[105]],[[7478,7478],"mapped",[106]],[[7479,7479],"mapped",[107]],[[7480,7480],"mapped",[108]],[[7481,7481],"mapped",[109]],[[7482,7482],"mapped",[110]],[[7483,7483],"valid"],[[7484,7484],"mapped",[111]],[[7485,7485],"mapped",[547]],[[7486,7486],"mapped",[112]],[[7487,7487],"mapped",[114]],[[7488,7488],"mapped",[116]],[[7489,7489],"mapped",[117]],[[7490,7490],"mapped",[119]],[[7491,7491],"mapped",[97]],[[7492,7492],"mapped",[592]],[[7493,7493],"mapped",[593]],[[7494,7494],"mapped",[7426]],[[7495,7495],"mapped",[98]],[[7496,7496],"mapped",[100]],[[7497,7497],"mapped",[101]],[[7498,7498],"mapped",[601]],[[7499,7499],"mapped",[603]],[[7500,7500],"mapped",[604]],[[7501,7501],"mapped",[103]],[[7502,7502],"valid"],[[7503,7503],"mapped",[107]],[[7504,7504],"mapped",[109]],[[7505,7505],"mapped",[331]],[[7506,7506],"mapped",[111]],[[7507,7507],"mapped",[596]],[[7508,7508],"mapped",[7446]],[[7509,7509],"mapped",[7447]],[[7510,7510],"mapped",[112]],[[7511,7511],"mapped",[116]],[[7512,7512],"mapped",[117]],[[7513,7513],"mapped",[7453]],[[7514,7514],"mapped",[623]],[[7515,7515],"mapped",[118]],[[7516,7516],"mapped",[7461]],[[7517,7517],"mapped",[946]],[[7518,7518],"mapped",[947]],[[7519,7519],"mapped",[948]],[[7520,7520],"mapped",[966]],[[7521,7521],"mapped",[967]],[[7522,7522],"mapped",[105]],[[7523,7523],"mapped",[114]],[[7524,7524],"mapped",[117]],[[7525,7525],"mapped",[118]],[[7526,7526],"mapped",[946]],[[7527,7527],"mapped",[947]],[[7528,7528],"mapped",[961]],[[7529,7529],"mapped",[966]],[[7530,7530],"mapped",[967]],[[7531,7531],"valid"],[[7532,7543],"valid"],[[7544,7544],"mapped",[1085]],[[7545,7578],"valid"],[[7579,7579],"mapped",[594]],[[7580,7580],"mapped",[99]],[[7581,7581],"mapped",[597]],[[7582,7582],"mapped",[240]],[[7583,7583],"mapped",[604]],[[7584,7584],"mapped",[102]],[[7585,7585],"mapped",[607]],[[7586,7586],"mapped",[609]],[[7587,7587],"mapped",[613]],[[7588,7588],"mapped",[616]],[[7589,7589],"mapped",[617]],[[7590,7590],"mapped",[618]],[[7591,7591],"mapped",[7547]],[[7592,7592],"mapped",[669]],[[7593,7593],"mapped",[621]],[[7594,7594],"mapped",[7557]],[[7595,7595],"mapped",[671]],[[7596,7596],"mapped",[625]],[[7597,7597],"mapped",[624]],[[7598,7598],"mapped",[626]],[[7599,7599],"mapped",[627]],[[7600,7600],"mapped",[628]],[[7601,7601],"mapped",[629]],[[7602,7602],"mapped",[632]],[[7603,7603],"mapped",[642]],[[7604,7604],"mapped",[643]],[[7605,7605],"mapped",[427]],[[7606,7606],"mapped",[649]],[[7607,7607],"mapped",[650]],[[7608,7608],"mapped",[7452]],[[7609,7609],"mapped",[651]],[[7610,7610],"mapped",[652]],[[7611,7611],"mapped",[122]],[[7612,7612],"mapped",[656]],[[7613,7613],"mapped",[657]],[[7614,7614],"mapped",[658]],[[7615,7615],"mapped",[952]],[[7616,7619],"valid"],[[7620,7626],"valid"],[[7627,7654],"valid"],[[7655,7669],"valid"],[[7670,7675],"disallowed"],[[7676,7676],"valid"],[[7677,7677],"valid"],[[7678,7679],"valid"],[[7680,7680],"mapped",[7681]],[[7681,7681],"valid"],[[7682,7682],"mapped",[7683]],[[7683,7683],"valid"],[[7684,7684],"mapped",[7685]],[[7685,7685],"valid"],[[7686,7686],"mapped",[7687]],[[7687,7687],"valid"],[[7688,7688],"mapped",[7689]],[[7689,7689],"valid"],[[7690,7690],"mapped",[7691]],[[7691,7691],"valid"],[[7692,7692],"mapped",[7693]],[[7693,7693],"valid"],[[7694,7694],"mapped",[7695]],[[7695,7695],"valid"],[[7696,7696],"mapped",[7697]],[[7697,7697],"valid"],[[7698,7698],"mapped",[7699]],[[7699,7699],"valid"],[[7700,7700],"mapped",[7701]],[[7701,7701],"valid"],[[7702,7702],"mapped",[7703]],[[7703,7703],"valid"],[[7704,7704],"mapped",[7705]],[[7705,7705],"valid"],[[7706,7706],"mapped",[7707]],[[7707,7707],"valid"],[[7708,7708],"mapped",[7709]],[[7709,7709],"valid"],[[7710,7710],"mapped",[7711]],[[7711,7711],"valid"],[[7712,7712],"mapped",[7713]],[[7713,7713],"valid"],[[7714,7714],"mapped",[7715]],[[7715,7715],"valid"],[[7716,7716],"mapped",[7717]],[[7717,7717],"valid"],[[7718,7718],"mapped",[7719]],[[7719,7719],"valid"],[[7720,7720],"mapped",[7721]],[[7721,7721],"valid"],[[7722,7722],"mapped",[7723]],[[7723,7723],"valid"],[[7724,7724],"mapped",[7725]],[[7725,7725],"valid"],[[7726,7726],"mapped",[7727]],[[7727,7727],"valid"],[[7728,7728],"mapped",[7729]],[[7729,7729],"valid"],[[7730,7730],"mapped",[7731]],[[7731,7731],"valid"],[[7732,7732],"mapped",[7733]],[[7733,7733],"valid"],[[7734,7734],"mapped",[7735]],[[7735,7735],"valid"],[[7736,7736],"mapped",[7737]],[[7737,7737],"valid"],[[7738,7738],"mapped",[7739]],[[7739,7739],"valid"],[[7740,7740],"mapped",[7741]],[[7741,7741],"valid"],[[7742,7742],"mapped",[7743]],[[7743,7743],"valid"],[[7744,7744],"mapped",[7745]],[[7745,7745],"valid"],[[7746,7746],"mapped",[7747]],[[7747,7747],"valid"],[[7748,7748],"mapped",[7749]],[[7749,7749],"valid"],[[7750,7750],"mapped",[7751]],[[7751,7751],"valid"],[[7752,7752],"mapped",[7753]],[[7753,7753],"valid"],[[7754,7754],"mapped",[7755]],[[7755,7755],"valid"],[[7756,7756],"mapped",[7757]],[[7757,7757],"valid"],[[7758,7758],"mapped",[7759]],[[7759,7759],"valid"],[[7760,7760],"mapped",[7761]],[[7761,7761],"valid"],[[7762,7762],"mapped",[7763]],[[7763,7763],"valid"],[[7764,7764],"mapped",[7765]],[[7765,7765],"valid"],[[7766,7766],"mapped",[7767]],[[7767,7767],"valid"],[[7768,7768],"mapped",[7769]],[[7769,7769],"valid"],[[7770,7770],"mapped",[7771]],[[7771,7771],"valid"],[[7772,7772],"mapped",[7773]],[[7773,7773],"valid"],[[7774,7774],"mapped",[7775]],[[7775,7775],"valid"],[[7776,7776],"mapped",[7777]],[[7777,7777],"valid"],[[7778,7778],"mapped",[7779]],[[7779,7779],"valid"],[[7780,7780],"mapped",[7781]],[[7781,7781],"valid"],[[7782,7782],"mapped",[7783]],[[7783,7783],"valid"],[[7784,7784],"mapped",[7785]],[[7785,7785],"valid"],[[7786,7786],"mapped",[7787]],[[7787,7787],"valid"],[[7788,7788],"mapped",[7789]],[[7789,7789],"valid"],[[7790,7790],"mapped",[7791]],[[7791,7791],"valid"],[[7792,7792],"mapped",[7793]],[[7793,7793],"valid"],[[7794,7794],"mapped",[7795]],[[7795,7795],"valid"],[[7796,7796],"mapped",[7797]],[[7797,7797],"valid"],[[7798,7798],"mapped",[7799]],[[7799,7799],"valid"],[[7800,7800],"mapped",[7801]],[[7801,7801],"valid"],[[7802,7802],"mapped",[7803]],[[7803,7803],"valid"],[[7804,7804],"mapped",[7805]],[[7805,7805],"valid"],[[7806,7806],"mapped",[7807]],[[7807,7807],"valid"],[[7808,7808],"mapped",[7809]],[[7809,7809],"valid"],[[7810,7810],"mapped",[7811]],[[7811,7811],"valid"],[[7812,7812],"mapped",[7813]],[[7813,7813],"valid"],[[7814,7814],"mapped",[7815]],[[7815,7815],"valid"],[[7816,7816],"mapped",[7817]],[[7817,7817],"valid"],[[7818,7818],"mapped",[7819]],[[7819,7819],"valid"],[[7820,7820],"mapped",[7821]],[[7821,7821],"valid"],[[7822,7822],"mapped",[7823]],[[7823,7823],"valid"],[[7824,7824],"mapped",[7825]],[[7825,7825],"valid"],[[7826,7826],"mapped",[7827]],[[7827,7827],"valid"],[[7828,7828],"mapped",[7829]],[[7829,7833],"valid"],[[7834,7834],"mapped",[97,702]],[[7835,7835],"mapped",[7777]],[[7836,7837],"valid"],[[7838,7838],"mapped",[115,115]],[[7839,7839],"valid"],[[7840,7840],"mapped",[7841]],[[7841,7841],"valid"],[[7842,7842],"mapped",[7843]],[[7843,7843],"valid"],[[7844,7844],"mapped",[7845]],[[7845,7845],"valid"],[[7846,7846],"mapped",[7847]],[[7847,7847],"valid"],[[7848,7848],"mapped",[7849]],[[7849,7849],"valid"],[[7850,7850],"mapped",[7851]],[[7851,7851],"valid"],[[7852,7852],"mapped",[7853]],[[7853,7853],"valid"],[[7854,7854],"mapped",[7855]],[[7855,7855],"valid"],[[7856,7856],"mapped",[7857]],[[7857,7857],"valid"],[[7858,7858],"mapped",[7859]],[[7859,7859],"valid"],[[7860,7860],"mapped",[7861]],[[7861,7861],"valid"],[[7862,7862],"mapped",[7863]],[[7863,7863],"valid"],[[7864,7864],"mapped",[7865]],[[7865,7865],"valid"],[[7866,7866],"mapped",[7867]],[[7867,7867],"valid"],[[7868,7868],"mapped",[7869]],[[7869,7869],"valid"],[[7870,7870],"mapped",[7871]],[[7871,7871],"valid"],[[7872,7872],"mapped",[7873]],[[7873,7873],"valid"],[[7874,7874],"mapped",[7875]],[[7875,7875],"valid"],[[7876,7876],"mapped",[7877]],[[7877,7877],"valid"],[[7878,7878],"mapped",[7879]],[[7879,7879],"valid"],[[7880,7880],"mapped",[7881]],[[7881,7881],"valid"],[[7882,7882],"mapped",[7883]],[[7883,7883],"valid"],[[7884,7884],"mapped",[7885]],[[7885,7885],"valid"],[[7886,7886],"mapped",[7887]],[[7887,7887],"valid"],[[7888,7888],"mapped",[7889]],[[7889,7889],"valid"],[[7890,7890],"mapped",[7891]],[[7891,7891],"valid"],[[7892,7892],"mapped",[7893]],[[7893,7893],"valid"],[[7894,7894],"mapped",[7895]],[[7895,7895],"valid"],[[7896,7896],"mapped",[7897]],[[7897,7897],"valid"],[[7898,7898],"mapped",[7899]],[[7899,7899],"valid"],[[7900,7900],"mapped",[7901]],[[7901,7901],"valid"],[[7902,7902],"mapped",[7903]],[[7903,7903],"valid"],[[7904,7904],"mapped",[7905]],[[7905,7905],"valid"],[[7906,7906],"mapped",[7907]],[[7907,7907],"valid"],[[7908,7908],"mapped",[7909]],[[7909,7909],"valid"],[[7910,7910],"mapped",[7911]],[[7911,7911],"valid"],[[7912,7912],"mapped",[7913]],[[7913,7913],"valid"],[[7914,7914],"mapped",[7915]],[[7915,7915],"valid"],[[7916,7916],"mapped",[7917]],[[7917,7917],"valid"],[[7918,7918],"mapped",[7919]],[[7919,7919],"valid"],[[7920,7920],"mapped",[7921]],[[7921,7921],"valid"],[[7922,7922],"mapped",[7923]],[[7923,7923],"valid"],[[7924,7924],"mapped",[7925]],[[7925,7925],"valid"],[[7926,7926],"mapped",[7927]],[[7927,7927],"valid"],[[7928,7928],"mapped",[7929]],[[7929,7929],"valid"],[[7930,7930],"mapped",[7931]],[[7931,7931],"valid"],[[7932,7932],"mapped",[7933]],[[7933,7933],"valid"],[[7934,7934],"mapped",[7935]],[[7935,7935],"valid"],[[7936,7943],"valid"],[[7944,7944],"mapped",[7936]],[[7945,7945],"mapped",[7937]],[[7946,7946],"mapped",[7938]],[[7947,7947],"mapped",[7939]],[[7948,7948],"mapped",[7940]],[[7949,7949],"mapped",[7941]],[[7950,7950],"mapped",[7942]],[[7951,7951],"mapped",[7943]],[[7952,7957],"valid"],[[7958,7959],"disallowed"],[[7960,7960],"mapped",[7952]],[[7961,7961],"mapped",[7953]],[[7962,7962],"mapped",[7954]],[[7963,7963],"mapped",[7955]],[[7964,7964],"mapped",[7956]],[[7965,7965],"mapped",[7957]],[[7966,7967],"disallowed"],[[7968,7975],"valid"],[[7976,7976],"mapped",[7968]],[[7977,7977],"mapped",[7969]],[[7978,7978],"mapped",[7970]],[[7979,7979],"mapped",[7971]],[[7980,7980],"mapped",[7972]],[[7981,7981],"mapped",[7973]],[[7982,7982],"mapped",[7974]],[[7983,7983],"mapped",[7975]],[[7984,7991],"valid"],[[7992,7992],"mapped",[7984]],[[7993,7993],"mapped",[7985]],[[7994,7994],"mapped",[7986]],[[7995,7995],"mapped",[7987]],[[7996,7996],"mapped",[7988]],[[7997,7997],"mapped",[7989]],[[7998,7998],"mapped",[7990]],[[7999,7999],"mapped",[7991]],[[8000,8005],"valid"],[[8006,8007],"disallowed"],[[8008,8008],"mapped",[8000]],[[8009,8009],"mapped",[8001]],[[8010,8010],"mapped",[8002]],[[8011,8011],"mapped",[8003]],[[8012,8012],"mapped",[8004]],[[8013,8013],"mapped",[8005]],[[8014,8015],"disallowed"],[[8016,8023],"valid"],[[8024,8024],"disallowed"],[[8025,8025],"mapped",[8017]],[[8026,8026],"disallowed"],[[8027,8027],"mapped",[8019]],[[8028,8028],"disallowed"],[[8029,8029],"mapped",[8021]],[[8030,8030],"disallowed"],[[8031,8031],"mapped",[8023]],[[8032,8039],"valid"],[[8040,8040],"mapped",[8032]],[[8041,8041],"mapped",[8033]],[[8042,8042],"mapped",[8034]],[[8043,8043],"mapped",[8035]],[[8044,8044],"mapped",[8036]],[[8045,8045],"mapped",[8037]],[[8046,8046],"mapped",[8038]],[[8047,8047],"mapped",[8039]],[[8048,8048],"valid"],[[8049,8049],"mapped",[940]],[[8050,8050],"valid"],[[8051,8051],"mapped",[941]],[[8052,8052],"valid"],[[8053,8053],"mapped",[942]],[[8054,8054],"valid"],[[8055,8055],"mapped",[943]],[[8056,8056],"valid"],[[8057,8057],"mapped",[972]],[[8058,8058],"valid"],[[8059,8059],"mapped",[973]],[[8060,8060],"valid"],[[8061,8061],"mapped",[974]],[[8062,8063],"disallowed"],[[8064,8064],"mapped",[7936,953]],[[8065,8065],"mapped",[7937,953]],[[8066,8066],"mapped",[7938,953]],[[8067,8067],"mapped",[7939,953]],[[8068,8068],"mapped",[7940,953]],[[8069,8069],"mapped",[7941,953]],[[8070,8070],"mapped",[7942,953]],[[8071,8071],"mapped",[7943,953]],[[8072,8072],"mapped",[7936,953]],[[8073,8073],"mapped",[7937,953]],[[8074,8074],"mapped",[7938,953]],[[8075,8075],"mapped",[7939,953]],[[8076,8076],"mapped",[7940,953]],[[8077,8077],"mapped",[7941,953]],[[8078,8078],"mapped",[7942,953]],[[8079,8079],"mapped",[7943,953]],[[8080,8080],"mapped",[7968,953]],[[8081,8081],"mapped",[7969,953]],[[8082,8082],"mapped",[7970,953]],[[8083,8083],"mapped",[7971,953]],[[8084,8084],"mapped",[7972,953]],[[8085,8085],"mapped",[7973,953]],[[8086,8086],"mapped",[7974,953]],[[8087,8087],"mapped",[7975,953]],[[8088,8088],"mapped",[7968,953]],[[8089,8089],"mapped",[7969,953]],[[8090,8090],"mapped",[7970,953]],[[8091,8091],"mapped",[7971,953]],[[8092,8092],"mapped",[7972,953]],[[8093,8093],"mapped",[7973,953]],[[8094,8094],"mapped",[7974,953]],[[8095,8095],"mapped",[7975,953]],[[8096,8096],"mapped",[8032,953]],[[8097,8097],"mapped",[8033,953]],[[8098,8098],"mapped",[8034,953]],[[8099,8099],"mapped",[8035,953]],[[8100,8100],"mapped",[8036,953]],[[8101,8101],"mapped",[8037,953]],[[8102,8102],"mapped",[8038,953]],[[8103,8103],"mapped",[8039,953]],[[8104,8104],"mapped",[8032,953]],[[8105,8105],"mapped",[8033,953]],[[8106,8106],"mapped",[8034,953]],[[8107,8107],"mapped",[8035,953]],[[8108,8108],"mapped",[8036,953]],[[8109,8109],"mapped",[8037,953]],[[8110,8110],"mapped",[8038,953]],[[8111,8111],"mapped",[8039,953]],[[8112,8113],"valid"],[[8114,8114],"mapped",[8048,953]],[[8115,8115],"mapped",[945,953]],[[8116,8116],"mapped",[940,953]],[[8117,8117],"disallowed"],[[8118,8118],"valid"],[[8119,8119],"mapped",[8118,953]],[[8120,8120],"mapped",[8112]],[[8121,8121],"mapped",[8113]],[[8122,8122],"mapped",[8048]],[[8123,8123],"mapped",[940]],[[8124,8124],"mapped",[945,953]],[[8125,8125],"disallowed_STD3_mapped",[32,787]],[[8126,8126],"mapped",[953]],[[8127,8127],"disallowed_STD3_mapped",[32,787]],[[8128,8128],"disallowed_STD3_mapped",[32,834]],[[8129,8129],"disallowed_STD3_mapped",[32,776,834]],[[8130,8130],"mapped",[8052,953]],[[8131,8131],"mapped",[951,953]],[[8132,8132],"mapped",[942,953]],[[8133,8133],"disallowed"],[[8134,8134],"valid"],[[8135,8135],"mapped",[8134,953]],[[8136,8136],"mapped",[8050]],[[8137,8137],"mapped",[941]],[[8138,8138],"mapped",[8052]],[[8139,8139],"mapped",[942]],[[8140,8140],"mapped",[951,953]],[[8141,8141],"disallowed_STD3_mapped",[32,787,768]],[[8142,8142],"disallowed_STD3_mapped",[32,787,769]],[[8143,8143],"disallowed_STD3_mapped",[32,787,834]],[[8144,8146],"valid"],[[8147,8147],"mapped",[912]],[[8148,8149],"disallowed"],[[8150,8151],"valid"],[[8152,8152],"mapped",[8144]],[[8153,8153],"mapped",[8145]],[[8154,8154],"mapped",[8054]],[[8155,8155],"mapped",[943]],[[8156,8156],"disallowed"],[[8157,8157],"disallowed_STD3_mapped",[32,788,768]],[[8158,8158],"disallowed_STD3_mapped",[32,788,769]],[[8159,8159],"disallowed_STD3_mapped",[32,788,834]],[[8160,8162],"valid"],[[8163,8163],"mapped",[944]],[[8164,8167],"valid"],[[8168,8168],"mapped",[8160]],[[8169,8169],"mapped",[8161]],[[8170,8170],"mapped",[8058]],[[8171,8171],"mapped",[973]],[[8172,8172],"mapped",[8165]],[[8173,8173],"disallowed_STD3_mapped",[32,776,768]],[[8174,8174],"disallowed_STD3_mapped",[32,776,769]],[[8175,8175],"disallowed_STD3_mapped",[96]],[[8176,8177],"disallowed"],[[8178,8178],"mapped",[8060,953]],[[8179,8179],"mapped",[969,953]],[[8180,8180],"mapped",[974,953]],[[8181,8181],"disallowed"],[[8182,8182],"valid"],[[8183,8183],"mapped",[8182,953]],[[8184,8184],"mapped",[8056]],[[8185,8185],"mapped",[972]],[[8186,8186],"mapped",[8060]],[[8187,8187],"mapped",[974]],[[8188,8188],"mapped",[969,953]],[[8189,8189],"disallowed_STD3_mapped",[32,769]],[[8190,8190],"disallowed_STD3_mapped",[32,788]],[[8191,8191],"disallowed"],[[8192,8202],"disallowed_STD3_mapped",[32]],[[8203,8203],"ignored"],[[8204,8205],"deviation",[]],[[8206,8207],"disallowed"],[[8208,8208],"valid",[],"NV8"],[[8209,8209],"mapped",[8208]],[[8210,8214],"valid",[],"NV8"],[[8215,8215],"disallowed_STD3_mapped",[32,819]],[[8216,8227],"valid",[],"NV8"],[[8228,8230],"disallowed"],[[8231,8231],"valid",[],"NV8"],[[8232,8238],"disallowed"],[[8239,8239],"disallowed_STD3_mapped",[32]],[[8240,8242],"valid",[],"NV8"],[[8243,8243],"mapped",[8242,8242]],[[8244,8244],"mapped",[8242,8242,8242]],[[8245,8245],"valid",[],"NV8"],[[8246,8246],"mapped",[8245,8245]],[[8247,8247],"mapped",[8245,8245,8245]],[[8248,8251],"valid",[],"NV8"],[[8252,8252],"disallowed_STD3_mapped",[33,33]],[[8253,8253],"valid",[],"NV8"],[[8254,8254],"disallowed_STD3_mapped",[32,773]],[[8255,8262],"valid",[],"NV8"],[[8263,8263],"disallowed_STD3_mapped",[63,63]],[[8264,8264],"disallowed_STD3_mapped",[63,33]],[[8265,8265],"disallowed_STD3_mapped",[33,63]],[[8266,8269],"valid",[],"NV8"],[[8270,8274],"valid",[],"NV8"],[[8275,8276],"valid",[],"NV8"],[[8277,8278],"valid",[],"NV8"],[[8279,8279],"mapped",[8242,8242,8242,8242]],[[8280,8286],"valid",[],"NV8"],[[8287,8287],"disallowed_STD3_mapped",[32]],[[8288,8288],"ignored"],[[8289,8291],"disallowed"],[[8292,8292],"ignored"],[[8293,8293],"disallowed"],[[8294,8297],"disallowed"],[[8298,8303],"disallowed"],[[8304,8304],"mapped",[48]],[[8305,8305],"mapped",[105]],[[8306,8307],"disallowed"],[[8308,8308],"mapped",[52]],[[8309,8309],"mapped",[53]],[[8310,8310],"mapped",[54]],[[8311,8311],"mapped",[55]],[[8312,8312],"mapped",[56]],[[8313,8313],"mapped",[57]],[[8314,8314],"disallowed_STD3_mapped",[43]],[[8315,8315],"mapped",[8722]],[[8316,8316],"disallowed_STD3_mapped",[61]],[[8317,8317],"disallowed_STD3_mapped",[40]],[[8318,8318],"disallowed_STD3_mapped",[41]],[[8319,8319],"mapped",[110]],[[8320,8320],"mapped",[48]],[[8321,8321],"mapped",[49]],[[8322,8322],"mapped",[50]],[[8323,8323],"mapped",[51]],[[8324,8324],"mapped",[52]],[[8325,8325],"mapped",[53]],[[8326,8326],"mapped",[54]],[[8327,8327],"mapped",[55]],[[8328,8328],"mapped",[56]],[[8329,8329],"mapped",[57]],[[8330,8330],"disallowed_STD3_mapped",[43]],[[8331,8331],"mapped",[8722]],[[8332,8332],"disallowed_STD3_mapped",[61]],[[8333,8333],"disallowed_STD3_mapped",[40]],[[8334,8334],"disallowed_STD3_mapped",[41]],[[8335,8335],"disallowed"],[[8336,8336],"mapped",[97]],[[8337,8337],"mapped",[101]],[[8338,8338],"mapped",[111]],[[8339,8339],"mapped",[120]],[[8340,8340],"mapped",[601]],[[8341,8341],"mapped",[104]],[[8342,8342],"mapped",[107]],[[8343,8343],"mapped",[108]],[[8344,8344],"mapped",[109]],[[8345,8345],"mapped",[110]],[[8346,8346],"mapped",[112]],[[8347,8347],"mapped",[115]],[[8348,8348],"mapped",[116]],[[8349,8351],"disallowed"],[[8352,8359],"valid",[],"NV8"],[[8360,8360],"mapped",[114,115]],[[8361,8362],"valid",[],"NV8"],[[8363,8363],"valid",[],"NV8"],[[8364,8364],"valid",[],"NV8"],[[8365,8367],"valid",[],"NV8"],[[8368,8369],"valid",[],"NV8"],[[8370,8373],"valid",[],"NV8"],[[8374,8376],"valid",[],"NV8"],[[8377,8377],"valid",[],"NV8"],[[8378,8378],"valid",[],"NV8"],[[8379,8381],"valid",[],"NV8"],[[8382,8382],"valid",[],"NV8"],[[8383,8399],"disallowed"],[[8400,8417],"valid",[],"NV8"],[[8418,8419],"valid",[],"NV8"],[[8420,8426],"valid",[],"NV8"],[[8427,8427],"valid",[],"NV8"],[[8428,8431],"valid",[],"NV8"],[[8432,8432],"valid",[],"NV8"],[[8433,8447],"disallowed"],[[8448,8448],"disallowed_STD3_mapped",[97,47,99]],[[8449,8449],"disallowed_STD3_mapped",[97,47,115]],[[8450,8450],"mapped",[99]],[[8451,8451],"mapped",[176,99]],[[8452,8452],"valid",[],"NV8"],[[8453,8453],"disallowed_STD3_mapped",[99,47,111]],[[8454,8454],"disallowed_STD3_mapped",[99,47,117]],[[8455,8455],"mapped",[603]],[[8456,8456],"valid",[],"NV8"],[[8457,8457],"mapped",[176,102]],[[8458,8458],"mapped",[103]],[[8459,8462],"mapped",[104]],[[8463,8463],"mapped",[295]],[[8464,8465],"mapped",[105]],[[8466,8467],"mapped",[108]],[[8468,8468],"valid",[],"NV8"],[[8469,8469],"mapped",[110]],[[8470,8470],"mapped",[110,111]],[[8471,8472],"valid",[],"NV8"],[[8473,8473],"mapped",[112]],[[8474,8474],"mapped",[113]],[[8475,8477],"mapped",[114]],[[8478,8479],"valid",[],"NV8"],[[8480,8480],"mapped",[115,109]],[[8481,8481],"mapped",[116,101,108]],[[8482,8482],"mapped",[116,109]],[[8483,8483],"valid",[],"NV8"],[[8484,8484],"mapped",[122]],[[8485,8485],"valid",[],"NV8"],[[8486,8486],"mapped",[969]],[[8487,8487],"valid",[],"NV8"],[[8488,8488],"mapped",[122]],[[8489,8489],"valid",[],"NV8"],[[8490,8490],"mapped",[107]],[[8491,8491],"mapped",[229]],[[8492,8492],"mapped",[98]],[[8493,8493],"mapped",[99]],[[8494,8494],"valid",[],"NV8"],[[8495,8496],"mapped",[101]],[[8497,8497],"mapped",[102]],[[8498,8498],"disallowed"],[[8499,8499],"mapped",[109]],[[8500,8500],"mapped",[111]],[[8501,8501],"mapped",[1488]],[[8502,8502],"mapped",[1489]],[[8503,8503],"mapped",[1490]],[[8504,8504],"mapped",[1491]],[[8505,8505],"mapped",[105]],[[8506,8506],"valid",[],"NV8"],[[8507,8507],"mapped",[102,97,120]],[[8508,8508],"mapped",[960]],[[8509,8510],"mapped",[947]],[[8511,8511],"mapped",[960]],[[8512,8512],"mapped",[8721]],[[8513,8516],"valid",[],"NV8"],[[8517,8518],"mapped",[100]],[[8519,8519],"mapped",[101]],[[8520,8520],"mapped",[105]],[[8521,8521],"mapped",[106]],[[8522,8523],"valid",[],"NV8"],[[8524,8524],"valid",[],"NV8"],[[8525,8525],"valid",[],"NV8"],[[8526,8526],"valid"],[[8527,8527],"valid",[],"NV8"],[[8528,8528],"mapped",[49,8260,55]],[[8529,8529],"mapped",[49,8260,57]],[[8530,8530],"mapped",[49,8260,49,48]],[[8531,8531],"mapped",[49,8260,51]],[[8532,8532],"mapped",[50,8260,51]],[[8533,8533],"mapped",[49,8260,53]],[[8534,8534],"mapped",[50,8260,53]],[[8535,8535],"mapped",[51,8260,53]],[[8536,8536],"mapped",[52,8260,53]],[[8537,8537],"mapped",[49,8260,54]],[[8538,8538],"mapped",[53,8260,54]],[[8539,8539],"mapped",[49,8260,56]],[[8540,8540],"mapped",[51,8260,56]],[[8541,8541],"mapped",[53,8260,56]],[[8542,8542],"mapped",[55,8260,56]],[[8543,8543],"mapped",[49,8260]],[[8544,8544],"mapped",[105]],[[8545,8545],"mapped",[105,105]],[[8546,8546],"mapped",[105,105,105]],[[8547,8547],"mapped",[105,118]],[[8548,8548],"mapped",[118]],[[8549,8549],"mapped",[118,105]],[[8550,8550],"mapped",[118,105,105]],[[8551,8551],"mapped",[118,105,105,105]],[[8552,8552],"mapped",[105,120]],[[8553,8553],"mapped",[120]],[[8554,8554],"mapped",[120,105]],[[8555,8555],"mapped",[120,105,105]],[[8556,8556],"mapped",[108]],[[8557,8557],"mapped",[99]],[[8558,8558],"mapped",[100]],[[8559,8559],"mapped",[109]],[[8560,8560],"mapped",[105]],[[8561,8561],"mapped",[105,105]],[[8562,8562],"mapped",[105,105,105]],[[8563,8563],"mapped",[105,118]],[[8564,8564],"mapped",[118]],[[8565,8565],"mapped",[118,105]],[[8566,8566],"mapped",[118,105,105]],[[8567,8567],"mapped",[118,105,105,105]],[[8568,8568],"mapped",[105,120]],[[8569,8569],"mapped",[120]],[[8570,8570],"mapped",[120,105]],[[8571,8571],"mapped",[120,105,105]],[[8572,8572],"mapped",[108]],[[8573,8573],"mapped",[99]],[[8574,8574],"mapped",[100]],[[8575,8575],"mapped",[109]],[[8576,8578],"valid",[],"NV8"],[[8579,8579],"disallowed"],[[8580,8580],"valid"],[[8581,8584],"valid",[],"NV8"],[[8585,8585],"mapped",[48,8260,51]],[[8586,8587],"valid",[],"NV8"],[[8588,8591],"disallowed"],[[8592,8682],"valid",[],"NV8"],[[8683,8691],"valid",[],"NV8"],[[8692,8703],"valid",[],"NV8"],[[8704,8747],"valid",[],"NV8"],[[8748,8748],"mapped",[8747,8747]],[[8749,8749],"mapped",[8747,8747,8747]],[[8750,8750],"valid",[],"NV8"],[[8751,8751],"mapped",[8750,8750]],[[8752,8752],"mapped",[8750,8750,8750]],[[8753,8799],"valid",[],"NV8"],[[8800,8800],"disallowed_STD3_valid"],[[8801,8813],"valid",[],"NV8"],[[8814,8815],"disallowed_STD3_valid"],[[8816,8945],"valid",[],"NV8"],[[8946,8959],"valid",[],"NV8"],[[8960,8960],"valid",[],"NV8"],[[8961,8961],"valid",[],"NV8"],[[8962,9000],"valid",[],"NV8"],[[9001,9001],"mapped",[12296]],[[9002,9002],"mapped",[12297]],[[9003,9082],"valid",[],"NV8"],[[9083,9083],"valid",[],"NV8"],[[9084,9084],"valid",[],"NV8"],[[9085,9114],"valid",[],"NV8"],[[9115,9166],"valid",[],"NV8"],[[9167,9168],"valid",[],"NV8"],[[9169,9179],"valid",[],"NV8"],[[9180,9191],"valid",[],"NV8"],[[9192,9192],"valid",[],"NV8"],[[9193,9203],"valid",[],"NV8"],[[9204,9210],"valid",[],"NV8"],[[9211,9215],"disallowed"],[[9216,9252],"valid",[],"NV8"],[[9253,9254],"valid",[],"NV8"],[[9255,9279],"disallowed"],[[9280,9290],"valid",[],"NV8"],[[9291,9311],"disallowed"],[[9312,9312],"mapped",[49]],[[9313,9313],"mapped",[50]],[[9314,9314],"mapped",[51]],[[9315,9315],"mapped",[52]],[[9316,9316],"mapped",[53]],[[9317,9317],"mapped",[54]],[[9318,9318],"mapped",[55]],[[9319,9319],"mapped",[56]],[[9320,9320],"mapped",[57]],[[9321,9321],"mapped",[49,48]],[[9322,9322],"mapped",[49,49]],[[9323,9323],"mapped",[49,50]],[[9324,9324],"mapped",[49,51]],[[9325,9325],"mapped",[49,52]],[[9326,9326],"mapped",[49,53]],[[9327,9327],"mapped",[49,54]],[[9328,9328],"mapped",[49,55]],[[9329,9329],"mapped",[49,56]],[[9330,9330],"mapped",[49,57]],[[9331,9331],"mapped",[50,48]],[[9332,9332],"disallowed_STD3_mapped",[40,49,41]],[[9333,9333],"disallowed_STD3_mapped",[40,50,41]],[[9334,9334],"disallowed_STD3_mapped",[40,51,41]],[[9335,9335],"disallowed_STD3_mapped",[40,52,41]],[[9336,9336],"disallowed_STD3_mapped",[40,53,41]],[[9337,9337],"disallowed_STD3_mapped",[40,54,41]],[[9338,9338],"disallowed_STD3_mapped",[40,55,41]],[[9339,9339],"disallowed_STD3_mapped",[40,56,41]],[[9340,9340],"disallowed_STD3_mapped",[40,57,41]],[[9341,9341],"disallowed_STD3_mapped",[40,49,48,41]],[[9342,9342],"disallowed_STD3_mapped",[40,49,49,41]],[[9343,9343],"disallowed_STD3_mapped",[40,49,50,41]],[[9344,9344],"disallowed_STD3_mapped",[40,49,51,41]],[[9345,9345],"disallowed_STD3_mapped",[40,49,52,41]],[[9346,9346],"disallowed_STD3_mapped",[40,49,53,41]],[[9347,9347],"disallowed_STD3_mapped",[40,49,54,41]],[[9348,9348],"disallowed_STD3_mapped",[40,49,55,41]],[[9349,9349],"disallowed_STD3_mapped",[40,49,56,41]],[[9350,9350],"disallowed_STD3_mapped",[40,49,57,41]],[[9351,9351],"disallowed_STD3_mapped",[40,50,48,41]],[[9352,9371],"disallowed"],[[9372,9372],"disallowed_STD3_mapped",[40,97,41]],[[9373,9373],"disallowed_STD3_mapped",[40,98,41]],[[9374,9374],"disallowed_STD3_mapped",[40,99,41]],[[9375,9375],"disallowed_STD3_mapped",[40,100,41]],[[9376,9376],"disallowed_STD3_mapped",[40,101,41]],[[9377,9377],"disallowed_STD3_mapped",[40,102,41]],[[9378,9378],"disallowed_STD3_mapped",[40,103,41]],[[9379,9379],"disallowed_STD3_mapped",[40,104,41]],[[9380,9380],"disallowed_STD3_mapped",[40,105,41]],[[9381,9381],"disallowed_STD3_mapped",[40,106,41]],[[9382,9382],"disallowed_STD3_mapped",[40,107,41]],[[9383,9383],"disallowed_STD3_mapped",[40,108,41]],[[9384,9384],"disallowed_STD3_mapped",[40,109,41]],[[9385,9385],"disallowed_STD3_mapped",[40,110,41]],[[9386,9386],"disallowed_STD3_mapped",[40,111,41]],[[9387,9387],"disallowed_STD3_mapped",[40,112,41]],[[9388,9388],"disallowed_STD3_mapped",[40,113,41]],[[9389,9389],"disallowed_STD3_mapped",[40,114,41]],[[9390,9390],"disallowed_STD3_mapped",[40,115,41]],[[9391,9391],"disallowed_STD3_mapped",[40,116,41]],[[9392,9392],"disallowed_STD3_mapped",[40,117,41]],[[9393,9393],"disallowed_STD3_mapped",[40,118,41]],[[9394,9394],"disallowed_STD3_mapped",[40,119,41]],[[9395,9395],"disallowed_STD3_mapped",[40,120,41]],[[9396,9396],"disallowed_STD3_mapped",[40,121,41]],[[9397,9397],"disallowed_STD3_mapped",[40,122,41]],[[9398,9398],"mapped",[97]],[[9399,9399],"mapped",[98]],[[9400,9400],"mapped",[99]],[[9401,9401],"mapped",[100]],[[9402,9402],"mapped",[101]],[[9403,9403],"mapped",[102]],[[9404,9404],"mapped",[103]],[[9405,9405],"mapped",[104]],[[9406,9406],"mapped",[105]],[[9407,9407],"mapped",[106]],[[9408,9408],"mapped",[107]],[[9409,9409],"mapped",[108]],[[9410,9410],"mapped",[109]],[[9411,9411],"mapped",[110]],[[9412,9412],"mapped",[111]],[[9413,9413],"mapped",[112]],[[9414,9414],"mapped",[113]],[[9415,9415],"mapped",[114]],[[9416,9416],"mapped",[115]],[[9417,9417],"mapped",[116]],[[9418,9418],"mapped",[117]],[[9419,9419],"mapped",[118]],[[9420,9420],"mapped",[119]],[[9421,9421],"mapped",[120]],[[9422,9422],"mapped",[121]],[[9423,9423],"mapped",[122]],[[9424,9424],"mapped",[97]],[[9425,9425],"mapped",[98]],[[9426,9426],"mapped",[99]],[[9427,9427],"mapped",[100]],[[9428,9428],"mapped",[101]],[[9429,9429],"mapped",[102]],[[9430,9430],"mapped",[103]],[[9431,9431],"mapped",[104]],[[9432,9432],"mapped",[105]],[[9433,9433],"mapped",[106]],[[9434,9434],"mapped",[107]],[[9435,9435],"mapped",[108]],[[9436,9436],"mapped",[109]],[[9437,9437],"mapped",[110]],[[9438,9438],"mapped",[111]],[[9439,9439],"mapped",[112]],[[9440,9440],"mapped",[113]],[[9441,9441],"mapped",[114]],[[9442,9442],"mapped",[115]],[[9443,9443],"mapped",[116]],[[9444,9444],"mapped",[117]],[[9445,9445],"mapped",[118]],[[9446,9446],"mapped",[119]],[[9447,9447],"mapped",[120]],[[9448,9448],"mapped",[121]],[[9449,9449],"mapped",[122]],[[9450,9450],"mapped",[48]],[[9451,9470],"valid",[],"NV8"],[[9471,9471],"valid",[],"NV8"],[[9472,9621],"valid",[],"NV8"],[[9622,9631],"valid",[],"NV8"],[[9632,9711],"valid",[],"NV8"],[[9712,9719],"valid",[],"NV8"],[[9720,9727],"valid",[],"NV8"],[[9728,9747],"valid",[],"NV8"],[[9748,9749],"valid",[],"NV8"],[[9750,9751],"valid",[],"NV8"],[[9752,9752],"valid",[],"NV8"],[[9753,9753],"valid",[],"NV8"],[[9754,9839],"valid",[],"NV8"],[[9840,9841],"valid",[],"NV8"],[[9842,9853],"valid",[],"NV8"],[[9854,9855],"valid",[],"NV8"],[[9856,9865],"valid",[],"NV8"],[[9866,9873],"valid",[],"NV8"],[[9874,9884],"valid",[],"NV8"],[[9885,9885],"valid",[],"NV8"],[[9886,9887],"valid",[],"NV8"],[[9888,9889],"valid",[],"NV8"],[[9890,9905],"valid",[],"NV8"],[[9906,9906],"valid",[],"NV8"],[[9907,9916],"valid",[],"NV8"],[[9917,9919],"valid",[],"NV8"],[[9920,9923],"valid",[],"NV8"],[[9924,9933],"valid",[],"NV8"],[[9934,9934],"valid",[],"NV8"],[[9935,9953],"valid",[],"NV8"],[[9954,9954],"valid",[],"NV8"],[[9955,9955],"valid",[],"NV8"],[[9956,9959],"valid",[],"NV8"],[[9960,9983],"valid",[],"NV8"],[[9984,9984],"valid",[],"NV8"],[[9985,9988],"valid",[],"NV8"],[[9989,9989],"valid",[],"NV8"],[[9990,9993],"valid",[],"NV8"],[[9994,9995],"valid",[],"NV8"],[[9996,10023],"valid",[],"NV8"],[[10024,10024],"valid",[],"NV8"],[[10025,10059],"valid",[],"NV8"],[[10060,10060],"valid",[],"NV8"],[[10061,10061],"valid",[],"NV8"],[[10062,10062],"valid",[],"NV8"],[[10063,10066],"valid",[],"NV8"],[[10067,10069],"valid",[],"NV8"],[[10070,10070],"valid",[],"NV8"],[[10071,10071],"valid",[],"NV8"],[[10072,10078],"valid",[],"NV8"],[[10079,10080],"valid",[],"NV8"],[[10081,10087],"valid",[],"NV8"],[[10088,10101],"valid",[],"NV8"],[[10102,10132],"valid",[],"NV8"],[[10133,10135],"valid",[],"NV8"],[[10136,10159],"valid",[],"NV8"],[[10160,10160],"valid",[],"NV8"],[[10161,10174],"valid",[],"NV8"],[[10175,10175],"valid",[],"NV8"],[[10176,10182],"valid",[],"NV8"],[[10183,10186],"valid",[],"NV8"],[[10187,10187],"valid",[],"NV8"],[[10188,10188],"valid",[],"NV8"],[[10189,10189],"valid",[],"NV8"],[[10190,10191],"valid",[],"NV8"],[[10192,10219],"valid",[],"NV8"],[[10220,10223],"valid",[],"NV8"],[[10224,10239],"valid",[],"NV8"],[[10240,10495],"valid",[],"NV8"],[[10496,10763],"valid",[],"NV8"],[[10764,10764],"mapped",[8747,8747,8747,8747]],[[10765,10867],"valid",[],"NV8"],[[10868,10868],"disallowed_STD3_mapped",[58,58,61]],[[10869,10869],"disallowed_STD3_mapped",[61,61]],[[10870,10870],"disallowed_STD3_mapped",[61,61,61]],[[10871,10971],"valid",[],"NV8"],[[10972,10972],"mapped",[10973,824]],[[10973,11007],"valid",[],"NV8"],[[11008,11021],"valid",[],"NV8"],[[11022,11027],"valid",[],"NV8"],[[11028,11034],"valid",[],"NV8"],[[11035,11039],"valid",[],"NV8"],[[11040,11043],"valid",[],"NV8"],[[11044,11084],"valid",[],"NV8"],[[11085,11087],"valid",[],"NV8"],[[11088,11092],"valid",[],"NV8"],[[11093,11097],"valid",[],"NV8"],[[11098,11123],"valid",[],"NV8"],[[11124,11125],"disallowed"],[[11126,11157],"valid",[],"NV8"],[[11158,11159],"disallowed"],[[11160,11193],"valid",[],"NV8"],[[11194,11196],"disallowed"],[[11197,11208],"valid",[],"NV8"],[[11209,11209],"disallowed"],[[11210,11217],"valid",[],"NV8"],[[11218,11243],"disallowed"],[[11244,11247],"valid",[],"NV8"],[[11248,11263],"disallowed"],[[11264,11264],"mapped",[11312]],[[11265,11265],"mapped",[11313]],[[11266,11266],"mapped",[11314]],[[11267,11267],"mapped",[11315]],[[11268,11268],"mapped",[11316]],[[11269,11269],"mapped",[11317]],[[11270,11270],"mapped",[11318]],[[11271,11271],"mapped",[11319]],[[11272,11272],"mapped",[11320]],[[11273,11273],"mapped",[11321]],[[11274,11274],"mapped",[11322]],[[11275,11275],"mapped",[11323]],[[11276,11276],"mapped",[11324]],[[11277,11277],"mapped",[11325]],[[11278,11278],"mapped",[11326]],[[11279,11279],"mapped",[11327]],[[11280,11280],"mapped",[11328]],[[11281,11281],"mapped",[11329]],[[11282,11282],"mapped",[11330]],[[11283,11283],"mapped",[11331]],[[11284,11284],"mapped",[11332]],[[11285,11285],"mapped",[11333]],[[11286,11286],"mapped",[11334]],[[11287,11287],"mapped",[11335]],[[11288,11288],"mapped",[11336]],[[11289,11289],"mapped",[11337]],[[11290,11290],"mapped",[11338]],[[11291,11291],"mapped",[11339]],[[11292,11292],"mapped",[11340]],[[11293,11293],"mapped",[11341]],[[11294,11294],"mapped",[11342]],[[11295,11295],"mapped",[11343]],[[11296,11296],"mapped",[11344]],[[11297,11297],"mapped",[11345]],[[11298,11298],"mapped",[11346]],[[11299,11299],"mapped",[11347]],[[11300,11300],"mapped",[11348]],[[11301,11301],"mapped",[11349]],[[11302,11302],"mapped",[11350]],[[11303,11303],"mapped",[11351]],[[11304,11304],"mapped",[11352]],[[11305,11305],"mapped",[11353]],[[11306,11306],"mapped",[11354]],[[11307,11307],"mapped",[11355]],[[11308,11308],"mapped",[11356]],[[11309,11309],"mapped",[11357]],[[11310,11310],"mapped",[11358]],[[11311,11311],"disallowed"],[[11312,11358],"valid"],[[11359,11359],"disallowed"],[[11360,11360],"mapped",[11361]],[[11361,11361],"valid"],[[11362,11362],"mapped",[619]],[[11363,11363],"mapped",[7549]],[[11364,11364],"mapped",[637]],[[11365,11366],"valid"],[[11367,11367],"mapped",[11368]],[[11368,11368],"valid"],[[11369,11369],"mapped",[11370]],[[11370,11370],"valid"],[[11371,11371],"mapped",[11372]],[[11372,11372],"valid"],[[11373,11373],"mapped",[593]],[[11374,11374],"mapped",[625]],[[11375,11375],"mapped",[592]],[[11376,11376],"mapped",[594]],[[11377,11377],"valid"],[[11378,11378],"mapped",[11379]],[[11379,11379],"valid"],[[11380,11380],"valid"],[[11381,11381],"mapped",[11382]],[[11382,11383],"valid"],[[11384,11387],"valid"],[[11388,11388],"mapped",[106]],[[11389,11389],"mapped",[118]],[[11390,11390],"mapped",[575]],[[11391,11391],"mapped",[576]],[[11392,11392],"mapped",[11393]],[[11393,11393],"valid"],[[11394,11394],"mapped",[11395]],[[11395,11395],"valid"],[[11396,11396],"mapped",[11397]],[[11397,11397],"valid"],[[11398,11398],"mapped",[11399]],[[11399,11399],"valid"],[[11400,11400],"mapped",[11401]],[[11401,11401],"valid"],[[11402,11402],"mapped",[11403]],[[11403,11403],"valid"],[[11404,11404],"mapped",[11405]],[[11405,11405],"valid"],[[11406,11406],"mapped",[11407]],[[11407,11407],"valid"],[[11408,11408],"mapped",[11409]],[[11409,11409],"valid"],[[11410,11410],"mapped",[11411]],[[11411,11411],"valid"],[[11412,11412],"mapped",[11413]],[[11413,11413],"valid"],[[11414,11414],"mapped",[11415]],[[11415,11415],"valid"],[[11416,11416],"mapped",[11417]],[[11417,11417],"valid"],[[11418,11418],"mapped",[11419]],[[11419,11419],"valid"],[[11420,11420],"mapped",[11421]],[[11421,11421],"valid"],[[11422,11422],"mapped",[11423]],[[11423,11423],"valid"],[[11424,11424],"mapped",[11425]],[[11425,11425],"valid"],[[11426,11426],"mapped",[11427]],[[11427,11427],"valid"],[[11428,11428],"mapped",[11429]],[[11429,11429],"valid"],[[11430,11430],"mapped",[11431]],[[11431,11431],"valid"],[[11432,11432],"mapped",[11433]],[[11433,11433],"valid"],[[11434,11434],"mapped",[11435]],[[11435,11435],"valid"],[[11436,11436],"mapped",[11437]],[[11437,11437],"valid"],[[11438,11438],"mapped",[11439]],[[11439,11439],"valid"],[[11440,11440],"mapped",[11441]],[[11441,11441],"valid"],[[11442,11442],"mapped",[11443]],[[11443,11443],"valid"],[[11444,11444],"mapped",[11445]],[[11445,11445],"valid"],[[11446,11446],"mapped",[11447]],[[11447,11447],"valid"],[[11448,11448],"mapped",[11449]],[[11449,11449],"valid"],[[11450,11450],"mapped",[11451]],[[11451,11451],"valid"],[[11452,11452],"mapped",[11453]],[[11453,11453],"valid"],[[11454,11454],"mapped",[11455]],[[11455,11455],"valid"],[[11456,11456],"mapped",[11457]],[[11457,11457],"valid"],[[11458,11458],"mapped",[11459]],[[11459,11459],"valid"],[[11460,11460],"mapped",[11461]],[[11461,11461],"valid"],[[11462,11462],"mapped",[11463]],[[11463,11463],"valid"],[[11464,11464],"mapped",[11465]],[[11465,11465],"valid"],[[11466,11466],"mapped",[11467]],[[11467,11467],"valid"],[[11468,11468],"mapped",[11469]],[[11469,11469],"valid"],[[11470,11470],"mapped",[11471]],[[11471,11471],"valid"],[[11472,11472],"mapped",[11473]],[[11473,11473],"valid"],[[11474,11474],"mapped",[11475]],[[11475,11475],"valid"],[[11476,11476],"mapped",[11477]],[[11477,11477],"valid"],[[11478,11478],"mapped",[11479]],[[11479,11479],"valid"],[[11480,11480],"mapped",[11481]],[[11481,11481],"valid"],[[11482,11482],"mapped",[11483]],[[11483,11483],"valid"],[[11484,11484],"mapped",[11485]],[[11485,11485],"valid"],[[11486,11486],"mapped",[11487]],[[11487,11487],"valid"],[[11488,11488],"mapped",[11489]],[[11489,11489],"valid"],[[11490,11490],"mapped",[11491]],[[11491,11492],"valid"],[[11493,11498],"valid",[],"NV8"],[[11499,11499],"mapped",[11500]],[[11500,11500],"valid"],[[11501,11501],"mapped",[11502]],[[11502,11505],"valid"],[[11506,11506],"mapped",[11507]],[[11507,11507],"valid"],[[11508,11512],"disallowed"],[[11513,11519],"valid",[],"NV8"],[[11520,11557],"valid"],[[11558,11558],"disallowed"],[[11559,11559],"valid"],[[11560,11564],"disallowed"],[[11565,11565],"valid"],[[11566,11567],"disallowed"],[[11568,11621],"valid"],[[11622,11623],"valid"],[[11624,11630],"disallowed"],[[11631,11631],"mapped",[11617]],[[11632,11632],"valid",[],"NV8"],[[11633,11646],"disallowed"],[[11647,11647],"valid"],[[11648,11670],"valid"],[[11671,11679],"disallowed"],[[11680,11686],"valid"],[[11687,11687],"disallowed"],[[11688,11694],"valid"],[[11695,11695],"disallowed"],[[11696,11702],"valid"],[[11703,11703],"disallowed"],[[11704,11710],"valid"],[[11711,11711],"disallowed"],[[11712,11718],"valid"],[[11719,11719],"disallowed"],[[11720,11726],"valid"],[[11727,11727],"disallowed"],[[11728,11734],"valid"],[[11735,11735],"disallowed"],[[11736,11742],"valid"],[[11743,11743],"disallowed"],[[11744,11775],"valid"],[[11776,11799],"valid",[],"NV8"],[[11800,11803],"valid",[],"NV8"],[[11804,11805],"valid",[],"NV8"],[[11806,11822],"valid",[],"NV8"],[[11823,11823],"valid"],[[11824,11824],"valid",[],"NV8"],[[11825,11825],"valid",[],"NV8"],[[11826,11835],"valid",[],"NV8"],[[11836,11842],"valid",[],"NV8"],[[11843,11903],"disallowed"],[[11904,11929],"valid",[],"NV8"],[[11930,11930],"disallowed"],[[11931,11934],"valid",[],"NV8"],[[11935,11935],"mapped",[27597]],[[11936,12018],"valid",[],"NV8"],[[12019,12019],"mapped",[40863]],[[12020,12031],"disallowed"],[[12032,12032],"mapped",[19968]],[[12033,12033],"mapped",[20008]],[[12034,12034],"mapped",[20022]],[[12035,12035],"mapped",[20031]],[[12036,12036],"mapped",[20057]],[[12037,12037],"mapped",[20101]],[[12038,12038],"mapped",[20108]],[[12039,12039],"mapped",[20128]],[[12040,12040],"mapped",[20154]],[[12041,12041],"mapped",[20799]],[[12042,12042],"mapped",[20837]],[[12043,12043],"mapped",[20843]],[[12044,12044],"mapped",[20866]],[[12045,12045],"mapped",[20886]],[[12046,12046],"mapped",[20907]],[[12047,12047],"mapped",[20960]],[[12048,12048],"mapped",[20981]],[[12049,12049],"mapped",[20992]],[[12050,12050],"mapped",[21147]],[[12051,12051],"mapped",[21241]],[[12052,12052],"mapped",[21269]],[[12053,12053],"mapped",[21274]],[[12054,12054],"mapped",[21304]],[[12055,12055],"mapped",[21313]],[[12056,12056],"mapped",[21340]],[[12057,12057],"mapped",[21353]],[[12058,12058],"mapped",[21378]],[[12059,12059],"mapped",[21430]],[[12060,12060],"mapped",[21448]],[[12061,12061],"mapped",[21475]],[[12062,12062],"mapped",[22231]],[[12063,12063],"mapped",[22303]],[[12064,12064],"mapped",[22763]],[[12065,12065],"mapped",[22786]],[[12066,12066],"mapped",[22794]],[[12067,12067],"mapped",[22805]],[[12068,12068],"mapped",[22823]],[[12069,12069],"mapped",[22899]],[[12070,12070],"mapped",[23376]],[[12071,12071],"mapped",[23424]],[[12072,12072],"mapped",[23544]],[[12073,12073],"mapped",[23567]],[[12074,12074],"mapped",[23586]],[[12075,12075],"mapped",[23608]],[[12076,12076],"mapped",[23662]],[[12077,12077],"mapped",[23665]],[[12078,12078],"mapped",[24027]],[[12079,12079],"mapped",[24037]],[[12080,12080],"mapped",[24049]],[[12081,12081],"mapped",[24062]],[[12082,12082],"mapped",[24178]],[[12083,12083],"mapped",[24186]],[[12084,12084],"mapped",[24191]],[[12085,12085],"mapped",[24308]],[[12086,12086],"mapped",[24318]],[[12087,12087],"mapped",[24331]],[[12088,12088],"mapped",[24339]],[[12089,12089],"mapped",[24400]],[[12090,12090],"mapped",[24417]],[[12091,12091],"mapped",[24435]],[[12092,12092],"mapped",[24515]],[[12093,12093],"mapped",[25096]],[[12094,12094],"mapped",[25142]],[[12095,12095],"mapped",[25163]],[[12096,12096],"mapped",[25903]],[[12097,12097],"mapped",[25908]],[[12098,12098],"mapped",[25991]],[[12099,12099],"mapped",[26007]],[[12100,12100],"mapped",[26020]],[[12101,12101],"mapped",[26041]],[[12102,12102],"mapped",[26080]],[[12103,12103],"mapped",[26085]],[[12104,12104],"mapped",[26352]],[[12105,12105],"mapped",[26376]],[[12106,12106],"mapped",[26408]],[[12107,12107],"mapped",[27424]],[[12108,12108],"mapped",[27490]],[[12109,12109],"mapped",[27513]],[[12110,12110],"mapped",[27571]],[[12111,12111],"mapped",[27595]],[[12112,12112],"mapped",[27604]],[[12113,12113],"mapped",[27611]],[[12114,12114],"mapped",[27663]],[[12115,12115],"mapped",[27668]],[[12116,12116],"mapped",[27700]],[[12117,12117],"mapped",[28779]],[[12118,12118],"mapped",[29226]],[[12119,12119],"mapped",[29238]],[[12120,12120],"mapped",[29243]],[[12121,12121],"mapped",[29247]],[[12122,12122],"mapped",[29255]],[[12123,12123],"mapped",[29273]],[[12124,12124],"mapped",[29275]],[[12125,12125],"mapped",[29356]],[[12126,12126],"mapped",[29572]],[[12127,12127],"mapped",[29577]],[[12128,12128],"mapped",[29916]],[[12129,12129],"mapped",[29926]],[[12130,12130],"mapped",[29976]],[[12131,12131],"mapped",[29983]],[[12132,12132],"mapped",[29992]],[[12133,12133],"mapped",[30000]],[[12134,12134],"mapped",[30091]],[[12135,12135],"mapped",[30098]],[[12136,12136],"mapped",[30326]],[[12137,12137],"mapped",[30333]],[[12138,12138],"mapped",[30382]],[[12139,12139],"mapped",[30399]],[[12140,12140],"mapped",[30446]],[[12141,12141],"mapped",[30683]],[[12142,12142],"mapped",[30690]],[[12143,12143],"mapped",[30707]],[[12144,12144],"mapped",[31034]],[[12145,12145],"mapped",[31160]],[[12146,12146],"mapped",[31166]],[[12147,12147],"mapped",[31348]],[[12148,12148],"mapped",[31435]],[[12149,12149],"mapped",[31481]],[[12150,12150],"mapped",[31859]],[[12151,12151],"mapped",[31992]],[[12152,12152],"mapped",[32566]],[[12153,12153],"mapped",[32593]],[[12154,12154],"mapped",[32650]],[[12155,12155],"mapped",[32701]],[[12156,12156],"mapped",[32769]],[[12157,12157],"mapped",[32780]],[[12158,12158],"mapped",[32786]],[[12159,12159],"mapped",[32819]],[[12160,12160],"mapped",[32895]],[[12161,12161],"mapped",[32905]],[[12162,12162],"mapped",[33251]],[[12163,12163],"mapped",[33258]],[[12164,12164],"mapped",[33267]],[[12165,12165],"mapped",[33276]],[[12166,12166],"mapped",[33292]],[[12167,12167],"mapped",[33307]],[[12168,12168],"mapped",[33311]],[[12169,12169],"mapped",[33390]],[[12170,12170],"mapped",[33394]],[[12171,12171],"mapped",[33400]],[[12172,12172],"mapped",[34381]],[[12173,12173],"mapped",[34411]],[[12174,12174],"mapped",[34880]],[[12175,12175],"mapped",[34892]],[[12176,12176],"mapped",[34915]],[[12177,12177],"mapped",[35198]],[[12178,12178],"mapped",[35211]],[[12179,12179],"mapped",[35282]],[[12180,12180],"mapped",[35328]],[[12181,12181],"mapped",[35895]],[[12182,12182],"mapped",[35910]],[[12183,12183],"mapped",[35925]],[[12184,12184],"mapped",[35960]],[[12185,12185],"mapped",[35997]],[[12186,12186],"mapped",[36196]],[[12187,12187],"mapped",[36208]],[[12188,12188],"mapped",[36275]],[[12189,12189],"mapped",[36523]],[[12190,12190],"mapped",[36554]],[[12191,12191],"mapped",[36763]],[[12192,12192],"mapped",[36784]],[[12193,12193],"mapped",[36789]],[[12194,12194],"mapped",[37009]],[[12195,12195],"mapped",[37193]],[[12196,12196],"mapped",[37318]],[[12197,12197],"mapped",[37324]],[[12198,12198],"mapped",[37329]],[[12199,12199],"mapped",[38263]],[[12200,12200],"mapped",[38272]],[[12201,12201],"mapped",[38428]],[[12202,12202],"mapped",[38582]],[[12203,12203],"mapped",[38585]],[[12204,12204],"mapped",[38632]],[[12205,12205],"mapped",[38737]],[[12206,12206],"mapped",[38750]],[[12207,12207],"mapped",[38754]],[[12208,12208],"mapped",[38761]],[[12209,12209],"mapped",[38859]],[[12210,12210],"mapped",[38893]],[[12211,12211],"mapped",[38899]],[[12212,12212],"mapped",[38913]],[[12213,12213],"mapped",[39080]],[[12214,12214],"mapped",[39131]],[[12215,12215],"mapped",[39135]],[[12216,12216],"mapped",[39318]],[[12217,12217],"mapped",[39321]],[[12218,12218],"mapped",[39340]],[[12219,12219],"mapped",[39592]],[[12220,12220],"mapped",[39640]],[[12221,12221],"mapped",[39647]],[[12222,12222],"mapped",[39717]],[[12223,12223],"mapped",[39727]],[[12224,12224],"mapped",[39730]],[[12225,12225],"mapped",[39740]],[[12226,12226],"mapped",[39770]],[[12227,12227],"mapped",[40165]],[[12228,12228],"mapped",[40565]],[[12229,12229],"mapped",[40575]],[[12230,12230],"mapped",[40613]],[[12231,12231],"mapped",[40635]],[[12232,12232],"mapped",[40643]],[[12233,12233],"mapped",[40653]],[[12234,12234],"mapped",[40657]],[[12235,12235],"mapped",[40697]],[[12236,12236],"mapped",[40701]],[[12237,12237],"mapped",[40718]],[[12238,12238],"mapped",[40723]],[[12239,12239],"mapped",[40736]],[[12240,12240],"mapped",[40763]],[[12241,12241],"mapped",[40778]],[[12242,12242],"mapped",[40786]],[[12243,12243],"mapped",[40845]],[[12244,12244],"mapped",[40860]],[[12245,12245],"mapped",[40864]],[[12246,12271],"disallowed"],[[12272,12283],"disallowed"],[[12284,12287],"disallowed"],[[12288,12288],"disallowed_STD3_mapped",[32]],[[12289,12289],"valid",[],"NV8"],[[12290,12290],"mapped",[46]],[[12291,12292],"valid",[],"NV8"],[[12293,12295],"valid"],[[12296,12329],"valid",[],"NV8"],[[12330,12333],"valid"],[[12334,12341],"valid",[],"NV8"],[[12342,12342],"mapped",[12306]],[[12343,12343],"valid",[],"NV8"],[[12344,12344],"mapped",[21313]],[[12345,12345],"mapped",[21316]],[[12346,12346],"mapped",[21317]],[[12347,12347],"valid",[],"NV8"],[[12348,12348],"valid"],[[12349,12349],"valid",[],"NV8"],[[12350,12350],"valid",[],"NV8"],[[12351,12351],"valid",[],"NV8"],[[12352,12352],"disallowed"],[[12353,12436],"valid"],[[12437,12438],"valid"],[[12439,12440],"disallowed"],[[12441,12442],"valid"],[[12443,12443],"disallowed_STD3_mapped",[32,12441]],[[12444,12444],"disallowed_STD3_mapped",[32,12442]],[[12445,12446],"valid"],[[12447,12447],"mapped",[12424,12426]],[[12448,12448],"valid",[],"NV8"],[[12449,12542],"valid"],[[12543,12543],"mapped",[12467,12488]],[[12544,12548],"disallowed"],[[12549,12588],"valid"],[[12589,12589],"valid"],[[12590,12592],"disallowed"],[[12593,12593],"mapped",[4352]],[[12594,12594],"mapped",[4353]],[[12595,12595],"mapped",[4522]],[[12596,12596],"mapped",[4354]],[[12597,12597],"mapped",[4524]],[[12598,12598],"mapped",[4525]],[[12599,12599],"mapped",[4355]],[[12600,12600],"mapped",[4356]],[[12601,12601],"mapped",[4357]],[[12602,12602],"mapped",[4528]],[[12603,12603],"mapped",[4529]],[[12604,12604],"mapped",[4530]],[[12605,12605],"mapped",[4531]],[[12606,12606],"mapped",[4532]],[[12607,12607],"mapped",[4533]],[[12608,12608],"mapped",[4378]],[[12609,12609],"mapped",[4358]],[[12610,12610],"mapped",[4359]],[[12611,12611],"mapped",[4360]],[[12612,12612],"mapped",[4385]],[[12613,12613],"mapped",[4361]],[[12614,12614],"mapped",[4362]],[[12615,12615],"mapped",[4363]],[[12616,12616],"mapped",[4364]],[[12617,12617],"mapped",[4365]],[[12618,12618],"mapped",[4366]],[[12619,12619],"mapped",[4367]],[[12620,12620],"mapped",[4368]],[[12621,12621],"mapped",[4369]],[[12622,12622],"mapped",[4370]],[[12623,12623],"mapped",[4449]],[[12624,12624],"mapped",[4450]],[[12625,12625],"mapped",[4451]],[[12626,12626],"mapped",[4452]],[[12627,12627],"mapped",[4453]],[[12628,12628],"mapped",[4454]],[[12629,12629],"mapped",[4455]],[[12630,12630],"mapped",[4456]],[[12631,12631],"mapped",[4457]],[[12632,12632],"mapped",[4458]],[[12633,12633],"mapped",[4459]],[[12634,12634],"mapped",[4460]],[[12635,12635],"mapped",[4461]],[[12636,12636],"mapped",[4462]],[[12637,12637],"mapped",[4463]],[[12638,12638],"mapped",[4464]],[[12639,12639],"mapped",[4465]],[[12640,12640],"mapped",[4466]],[[12641,12641],"mapped",[4467]],[[12642,12642],"mapped",[4468]],[[12643,12643],"mapped",[4469]],[[12644,12644],"disallowed"],[[12645,12645],"mapped",[4372]],[[12646,12646],"mapped",[4373]],[[12647,12647],"mapped",[4551]],[[12648,12648],"mapped",[4552]],[[12649,12649],"mapped",[4556]],[[12650,12650],"mapped",[4558]],[[12651,12651],"mapped",[4563]],[[12652,12652],"mapped",[4567]],[[12653,12653],"mapped",[4569]],[[12654,12654],"mapped",[4380]],[[12655,12655],"mapped",[4573]],[[12656,12656],"mapped",[4575]],[[12657,12657],"mapped",[4381]],[[12658,12658],"mapped",[4382]],[[12659,12659],"mapped",[4384]],[[12660,12660],"mapped",[4386]],[[12661,12661],"mapped",[4387]],[[12662,12662],"mapped",[4391]],[[12663,12663],"mapped",[4393]],[[12664,12664],"mapped",[4395]],[[12665,12665],"mapped",[4396]],[[12666,12666],"mapped",[4397]],[[12667,12667],"mapped",[4398]],[[12668,12668],"mapped",[4399]],[[12669,12669],"mapped",[4402]],[[12670,12670],"mapped",[4406]],[[12671,12671],"mapped",[4416]],[[12672,12672],"mapped",[4423]],[[12673,12673],"mapped",[4428]],[[12674,12674],"mapped",[4593]],[[12675,12675],"mapped",[4594]],[[12676,12676],"mapped",[4439]],[[12677,12677],"mapped",[4440]],[[12678,12678],"mapped",[4441]],[[12679,12679],"mapped",[4484]],[[12680,12680],"mapped",[4485]],[[12681,12681],"mapped",[4488]],[[12682,12682],"mapped",[4497]],[[12683,12683],"mapped",[4498]],[[12684,12684],"mapped",[4500]],[[12685,12685],"mapped",[4510]],[[12686,12686],"mapped",[4513]],[[12687,12687],"disallowed"],[[12688,12689],"valid",[],"NV8"],[[12690,12690],"mapped",[19968]],[[12691,12691],"mapped",[20108]],[[12692,12692],"mapped",[19977]],[[12693,12693],"mapped",[22235]],[[12694,12694],"mapped",[19978]],[[12695,12695],"mapped",[20013]],[[12696,12696],"mapped",[19979]],[[12697,12697],"mapped",[30002]],[[12698,12698],"mapped",[20057]],[[12699,12699],"mapped",[19993]],[[12700,12700],"mapped",[19969]],[[12701,12701],"mapped",[22825]],[[12702,12702],"mapped",[22320]],[[12703,12703],"mapped",[20154]],[[12704,12727],"valid"],[[12728,12730],"valid"],[[12731,12735],"disallowed"],[[12736,12751],"valid",[],"NV8"],[[12752,12771],"valid",[],"NV8"],[[12772,12783],"disallowed"],[[12784,12799],"valid"],[[12800,12800],"disallowed_STD3_mapped",[40,4352,41]],[[12801,12801],"disallowed_STD3_mapped",[40,4354,41]],[[12802,12802],"disallowed_STD3_mapped",[40,4355,41]],[[12803,12803],"disallowed_STD3_mapped",[40,4357,41]],[[12804,12804],"disallowed_STD3_mapped",[40,4358,41]],[[12805,12805],"disallowed_STD3_mapped",[40,4359,41]],[[12806,12806],"disallowed_STD3_mapped",[40,4361,41]],[[12807,12807],"disallowed_STD3_mapped",[40,4363,41]],[[12808,12808],"disallowed_STD3_mapped",[40,4364,41]],[[12809,12809],"disallowed_STD3_mapped",[40,4366,41]],[[12810,12810],"disallowed_STD3_mapped",[40,4367,41]],[[12811,12811],"disallowed_STD3_mapped",[40,4368,41]],[[12812,12812],"disallowed_STD3_mapped",[40,4369,41]],[[12813,12813],"disallowed_STD3_mapped",[40,4370,41]],[[12814,12814],"disallowed_STD3_mapped",[40,44032,41]],[[12815,12815],"disallowed_STD3_mapped",[40,45208,41]],[[12816,12816],"disallowed_STD3_mapped",[40,45796,41]],[[12817,12817],"disallowed_STD3_mapped",[40,46972,41]],[[12818,12818],"disallowed_STD3_mapped",[40,47560,41]],[[12819,12819],"disallowed_STD3_mapped",[40,48148,41]],[[12820,12820],"disallowed_STD3_mapped",[40,49324,41]],[[12821,12821],"disallowed_STD3_mapped",[40,50500,41]],[[12822,12822],"disallowed_STD3_mapped",[40,51088,41]],[[12823,12823],"disallowed_STD3_mapped",[40,52264,41]],[[12824,12824],"disallowed_STD3_mapped",[40,52852,41]],[[12825,12825],"disallowed_STD3_mapped",[40,53440,41]],[[12826,12826],"disallowed_STD3_mapped",[40,54028,41]],[[12827,12827],"disallowed_STD3_mapped",[40,54616,41]],[[12828,12828],"disallowed_STD3_mapped",[40,51452,41]],[[12829,12829],"disallowed_STD3_mapped",[40,50724,51204,41]],[[12830,12830],"disallowed_STD3_mapped",[40,50724,54980,41]],[[12831,12831],"disallowed"],[[12832,12832],"disallowed_STD3_mapped",[40,19968,41]],[[12833,12833],"disallowed_STD3_mapped",[40,20108,41]],[[12834,12834],"disallowed_STD3_mapped",[40,19977,41]],[[12835,12835],"disallowed_STD3_mapped",[40,22235,41]],[[12836,12836],"disallowed_STD3_mapped",[40,20116,41]],[[12837,12837],"disallowed_STD3_mapped",[40,20845,41]],[[12838,12838],"disallowed_STD3_mapped",[40,19971,41]],[[12839,12839],"disallowed_STD3_mapped",[40,20843,41]],[[12840,12840],"disallowed_STD3_mapped",[40,20061,41]],[[12841,12841],"disallowed_STD3_mapped",[40,21313,41]],[[12842,12842],"disallowed_STD3_mapped",[40,26376,41]],[[12843,12843],"disallowed_STD3_mapped",[40,28779,41]],[[12844,12844],"disallowed_STD3_mapped",[40,27700,41]],[[12845,12845],"disallowed_STD3_mapped",[40,26408,41]],[[12846,12846],"disallowed_STD3_mapped",[40,37329,41]],[[12847,12847],"disallowed_STD3_mapped",[40,22303,41]],[[12848,12848],"disallowed_STD3_mapped",[40,26085,41]],[[12849,12849],"disallowed_STD3_mapped",[40,26666,41]],[[12850,12850],"disallowed_STD3_mapped",[40,26377,41]],[[12851,12851],"disallowed_STD3_mapped",[40,31038,41]],[[12852,12852],"disallowed_STD3_mapped",[40,21517,41]],[[12853,12853],"disallowed_STD3_mapped",[40,29305,41]],[[12854,12854],"disallowed_STD3_mapped",[40,36001,41]],[[12855,12855],"disallowed_STD3_mapped",[40,31069,41]],[[12856,12856],"disallowed_STD3_mapped",[40,21172,41]],[[12857,12857],"disallowed_STD3_mapped",[40,20195,41]],[[12858,12858],"disallowed_STD3_mapped",[40,21628,41]],[[12859,12859],"disallowed_STD3_mapped",[40,23398,41]],[[12860,12860],"disallowed_STD3_mapped",[40,30435,41]],[[12861,12861],"disallowed_STD3_mapped",[40,20225,41]],[[12862,12862],"disallowed_STD3_mapped",[40,36039,41]],[[12863,12863],"disallowed_STD3_mapped",[40,21332,41]],[[12864,12864],"disallowed_STD3_mapped",[40,31085,41]],[[12865,12865],"disallowed_STD3_mapped",[40,20241,41]],[[12866,12866],"disallowed_STD3_mapped",[40,33258,41]],[[12867,12867],"disallowed_STD3_mapped",[40,33267,41]],[[12868,12868],"mapped",[21839]],[[12869,12869],"mapped",[24188]],[[12870,12870],"mapped",[25991]],[[12871,12871],"mapped",[31631]],[[12872,12879],"valid",[],"NV8"],[[12880,12880],"mapped",[112,116,101]],[[12881,12881],"mapped",[50,49]],[[12882,12882],"mapped",[50,50]],[[12883,12883],"mapped",[50,51]],[[12884,12884],"mapped",[50,52]],[[12885,12885],"mapped",[50,53]],[[12886,12886],"mapped",[50,54]],[[12887,12887],"mapped",[50,55]],[[12888,12888],"mapped",[50,56]],[[12889,12889],"mapped",[50,57]],[[12890,12890],"mapped",[51,48]],[[12891,12891],"mapped",[51,49]],[[12892,12892],"mapped",[51,50]],[[12893,12893],"mapped",[51,51]],[[12894,12894],"mapped",[51,52]],[[12895,12895],"mapped",[51,53]],[[12896,12896],"mapped",[4352]],[[12897,12897],"mapped",[4354]],[[12898,12898],"mapped",[4355]],[[12899,12899],"mapped",[4357]],[[12900,12900],"mapped",[4358]],[[12901,12901],"mapped",[4359]],[[12902,12902],"mapped",[4361]],[[12903,12903],"mapped",[4363]],[[12904,12904],"mapped",[4364]],[[12905,12905],"mapped",[4366]],[[12906,12906],"mapped",[4367]],[[12907,12907],"mapped",[4368]],[[12908,12908],"mapped",[4369]],[[12909,12909],"mapped",[4370]],[[12910,12910],"mapped",[44032]],[[12911,12911],"mapped",[45208]],[[12912,12912],"mapped",[45796]],[[12913,12913],"mapped",[46972]],[[12914,12914],"mapped",[47560]],[[12915,12915],"mapped",[48148]],[[12916,12916],"mapped",[49324]],[[12917,12917],"mapped",[50500]],[[12918,12918],"mapped",[51088]],[[12919,12919],"mapped",[52264]],[[12920,12920],"mapped",[52852]],[[12921,12921],"mapped",[53440]],[[12922,12922],"mapped",[54028]],[[12923,12923],"mapped",[54616]],[[12924,12924],"mapped",[52280,44256]],[[12925,12925],"mapped",[51452,51032]],[[12926,12926],"mapped",[50864]],[[12927,12927],"valid",[],"NV8"],[[12928,12928],"mapped",[19968]],[[12929,12929],"mapped",[20108]],[[12930,12930],"mapped",[19977]],[[12931,12931],"mapped",[22235]],[[12932,12932],"mapped",[20116]],[[12933,12933],"mapped",[20845]],[[12934,12934],"mapped",[19971]],[[12935,12935],"mapped",[20843]],[[12936,12936],"mapped",[20061]],[[12937,12937],"mapped",[21313]],[[12938,12938],"mapped",[26376]],[[12939,12939],"mapped",[28779]],[[12940,12940],"mapped",[27700]],[[12941,12941],"mapped",[26408]],[[12942,12942],"mapped",[37329]],[[12943,12943],"mapped",[22303]],[[12944,12944],"mapped",[26085]],[[12945,12945],"mapped",[26666]],[[12946,12946],"mapped",[26377]],[[12947,12947],"mapped",[31038]],[[12948,12948],"mapped",[21517]],[[12949,12949],"mapped",[29305]],[[12950,12950],"mapped",[36001]],[[12951,12951],"mapped",[31069]],[[12952,12952],"mapped",[21172]],[[12953,12953],"mapped",[31192]],[[12954,12954],"mapped",[30007]],[[12955,12955],"mapped",[22899]],[[12956,12956],"mapped",[36969]],[[12957,12957],"mapped",[20778]],[[12958,12958],"mapped",[21360]],[[12959,12959],"mapped",[27880]],[[12960,12960],"mapped",[38917]],[[12961,12961],"mapped",[20241]],[[12962,12962],"mapped",[20889]],[[12963,12963],"mapped",[27491]],[[12964,12964],"mapped",[19978]],[[12965,12965],"mapped",[20013]],[[12966,12966],"mapped",[19979]],[[12967,12967],"mapped",[24038]],[[12968,12968],"mapped",[21491]],[[12969,12969],"mapped",[21307]],[[12970,12970],"mapped",[23447]],[[12971,12971],"mapped",[23398]],[[12972,12972],"mapped",[30435]],[[12973,12973],"mapped",[20225]],[[12974,12974],"mapped",[36039]],[[12975,12975],"mapped",[21332]],[[12976,12976],"mapped",[22812]],[[12977,12977],"mapped",[51,54]],[[12978,12978],"mapped",[51,55]],[[12979,12979],"mapped",[51,56]],[[12980,12980],"mapped",[51,57]],[[12981,12981],"mapped",[52,48]],[[12982,12982],"mapped",[52,49]],[[12983,12983],"mapped",[52,50]],[[12984,12984],"mapped",[52,51]],[[12985,12985],"mapped",[52,52]],[[12986,12986],"mapped",[52,53]],[[12987,12987],"mapped",[52,54]],[[12988,12988],"mapped",[52,55]],[[12989,12989],"mapped",[52,56]],[[12990,12990],"mapped",[52,57]],[[12991,12991],"mapped",[53,48]],[[12992,12992],"mapped",[49,26376]],[[12993,12993],"mapped",[50,26376]],[[12994,12994],"mapped",[51,26376]],[[12995,12995],"mapped",[52,26376]],[[12996,12996],"mapped",[53,26376]],[[12997,12997],"mapped",[54,26376]],[[12998,12998],"mapped",[55,26376]],[[12999,12999],"mapped",[56,26376]],[[13000,13000],"mapped",[57,26376]],[[13001,13001],"mapped",[49,48,26376]],[[13002,13002],"mapped",[49,49,26376]],[[13003,13003],"mapped",[49,50,26376]],[[13004,13004],"mapped",[104,103]],[[13005,13005],"mapped",[101,114,103]],[[13006,13006],"mapped",[101,118]],[[13007,13007],"mapped",[108,116,100]],[[13008,13008],"mapped",[12450]],[[13009,13009],"mapped",[12452]],[[13010,13010],"mapped",[12454]],[[13011,13011],"mapped",[12456]],[[13012,13012],"mapped",[12458]],[[13013,13013],"mapped",[12459]],[[13014,13014],"mapped",[12461]],[[13015,13015],"mapped",[12463]],[[13016,13016],"mapped",[12465]],[[13017,13017],"mapped",[12467]],[[13018,13018],"mapped",[12469]],[[13019,13019],"mapped",[12471]],[[13020,13020],"mapped",[12473]],[[13021,13021],"mapped",[12475]],[[13022,13022],"mapped",[12477]],[[13023,13023],"mapped",[12479]],[[13024,13024],"mapped",[12481]],[[13025,13025],"mapped",[12484]],[[13026,13026],"mapped",[12486]],[[13027,13027],"mapped",[12488]],[[13028,13028],"mapped",[12490]],[[13029,13029],"mapped",[12491]],[[13030,13030],"mapped",[12492]],[[13031,13031],"mapped",[12493]],[[13032,13032],"mapped",[12494]],[[13033,13033],"mapped",[12495]],[[13034,13034],"mapped",[12498]],[[13035,13035],"mapped",[12501]],[[13036,13036],"mapped",[12504]],[[13037,13037],"mapped",[12507]],[[13038,13038],"mapped",[12510]],[[13039,13039],"mapped",[12511]],[[13040,13040],"mapped",[12512]],[[13041,13041],"mapped",[12513]],[[13042,13042],"mapped",[12514]],[[13043,13043],"mapped",[12516]],[[13044,13044],"mapped",[12518]],[[13045,13045],"mapped",[12520]],[[13046,13046],"mapped",[12521]],[[13047,13047],"mapped",[12522]],[[13048,13048],"mapped",[12523]],[[13049,13049],"mapped",[12524]],[[13050,13050],"mapped",[12525]],[[13051,13051],"mapped",[12527]],[[13052,13052],"mapped",[12528]],[[13053,13053],"mapped",[12529]],[[13054,13054],"mapped",[12530]],[[13055,13055],"disallowed"],[[13056,13056],"mapped",[12450,12497,12540,12488]],[[13057,13057],"mapped",[12450,12523,12501,12449]],[[13058,13058],"mapped",[12450,12531,12506,12450]],[[13059,13059],"mapped",[12450,12540,12523]],[[13060,13060],"mapped",[12452,12491,12531,12464]],[[13061,13061],"mapped",[12452,12531,12481]],[[13062,13062],"mapped",[12454,12457,12531]],[[13063,13063],"mapped",[12456,12473,12463,12540,12489]],[[13064,13064],"mapped",[12456,12540,12459,12540]],[[13065,13065],"mapped",[12458,12531,12473]],[[13066,13066],"mapped",[12458,12540,12512]],[[13067,13067],"mapped",[12459,12452,12522]],[[13068,13068],"mapped",[12459,12521,12483,12488]],[[13069,13069],"mapped",[12459,12525,12522,12540]],[[13070,13070],"mapped",[12460,12525,12531]],[[13071,13071],"mapped",[12460,12531,12510]],[[13072,13072],"mapped",[12462,12460]],[[13073,13073],"mapped",[12462,12491,12540]],[[13074,13074],"mapped",[12461,12517,12522,12540]],[[13075,13075],"mapped",[12462,12523,12480,12540]],[[13076,13076],"mapped",[12461,12525]],[[13077,13077],"mapped",[12461,12525,12464,12521,12512]],[[13078,13078],"mapped",[12461,12525,12513,12540,12488,12523]],[[13079,13079],"mapped",[12461,12525,12527,12483,12488]],[[13080,13080],"mapped",[12464,12521,12512]],[[13081,13081],"mapped",[12464,12521,12512,12488,12531]],[[13082,13082],"mapped",[12463,12523,12476,12452,12525]],[[13083,13083],"mapped",[12463,12525,12540,12493]],[[13084,13084],"mapped",[12465,12540,12473]],[[13085,13085],"mapped",[12467,12523,12490]],[[13086,13086],"mapped",[12467,12540,12509]],[[13087,13087],"mapped",[12469,12452,12463,12523]],[[13088,13088],"mapped",[12469,12531,12481,12540,12512]],[[13089,13089],"mapped",[12471,12522,12531,12464]],[[13090,13090],"mapped",[12475,12531,12481]],[[13091,13091],"mapped",[12475,12531,12488]],[[13092,13092],"mapped",[12480,12540,12473]],[[13093,13093],"mapped",[12487,12471]],[[13094,13094],"mapped",[12489,12523]],[[13095,13095],"mapped",[12488,12531]],[[13096,13096],"mapped",[12490,12494]],[[13097,13097],"mapped",[12494,12483,12488]],[[13098,13098],"mapped",[12495,12452,12484]],[[13099,13099],"mapped",[12497,12540,12475,12531,12488]],[[13100,13100],"mapped",[12497,12540,12484]],[[13101,13101],"mapped",[12496,12540,12524,12523]],[[13102,13102],"mapped",[12500,12450,12473,12488,12523]],[[13103,13103],"mapped",[12500,12463,12523]],[[13104,13104],"mapped",[12500,12467]],[[13105,13105],"mapped",[12499,12523]],[[13106,13106],"mapped",[12501,12449,12521,12483,12489]],[[13107,13107],"mapped",[12501,12451,12540,12488]],[[13108,13108],"mapped",[12502,12483,12471,12455,12523]],[[13109,13109],"mapped",[12501,12521,12531]],[[13110,13110],"mapped",[12504,12463,12479,12540,12523]],[[13111,13111],"mapped",[12506,12477]],[[13112,13112],"mapped",[12506,12491,12498]],[[13113,13113],"mapped",[12504,12523,12484]],[[13114,13114],"mapped",[12506,12531,12473]],[[13115,13115],"mapped",[12506,12540,12472]],[[13116,13116],"mapped",[12505,12540,12479]],[[13117,13117],"mapped",[12509,12452,12531,12488]],[[13118,13118],"mapped",[12508,12523,12488]],[[13119,13119],"mapped",[12507,12531]],[[13120,13120],"mapped",[12509,12531,12489]],[[13121,13121],"mapped",[12507,12540,12523]],[[13122,13122],"mapped",[12507,12540,12531]],[[13123,13123],"mapped",[12510,12452,12463,12525]],[[13124,13124],"mapped",[12510,12452,12523]],[[13125,13125],"mapped",[12510,12483,12495]],[[13126,13126],"mapped",[12510,12523,12463]],[[13127,13127],"mapped",[12510,12531,12471,12519,12531]],[[13128,13128],"mapped",[12511,12463,12525,12531]],[[13129,13129],"mapped",[12511,12522]],[[13130,13130],"mapped",[12511,12522,12496,12540,12523]],[[13131,13131],"mapped",[12513,12460]],[[13132,13132],"mapped",[12513,12460,12488,12531]],[[13133,13133],"mapped",[12513,12540,12488,12523]],[[13134,13134],"mapped",[12516,12540,12489]],[[13135,13135],"mapped",[12516,12540,12523]],[[13136,13136],"mapped",[12518,12450,12531]],[[13137,13137],"mapped",[12522,12483,12488,12523]],[[13138,13138],"mapped",[12522,12521]],[[13139,13139],"mapped",[12523,12500,12540]],[[13140,13140],"mapped",[12523,12540,12502,12523]],[[13141,13141],"mapped",[12524,12512]],[[13142,13142],"mapped",[12524,12531,12488,12466,12531]],[[13143,13143],"mapped",[12527,12483,12488]],[[13144,13144],"mapped",[48,28857]],[[13145,13145],"mapped",[49,28857]],[[13146,13146],"mapped",[50,28857]],[[13147,13147],"mapped",[51,28857]],[[13148,13148],"mapped",[52,28857]],[[13149,13149],"mapped",[53,28857]],[[13150,13150],"mapped",[54,28857]],[[13151,13151],"mapped",[55,28857]],[[13152,13152],"mapped",[56,28857]],[[13153,13153],"mapped",[57,28857]],[[13154,13154],"mapped",[49,48,28857]],[[13155,13155],"mapped",[49,49,28857]],[[13156,13156],"mapped",[49,50,28857]],[[13157,13157],"mapped",[49,51,28857]],[[13158,13158],"mapped",[49,52,28857]],[[13159,13159],"mapped",[49,53,28857]],[[13160,13160],"mapped",[49,54,28857]],[[13161,13161],"mapped",[49,55,28857]],[[13162,13162],"mapped",[49,56,28857]],[[13163,13163],"mapped",[49,57,28857]],[[13164,13164],"mapped",[50,48,28857]],[[13165,13165],"mapped",[50,49,28857]],[[13166,13166],"mapped",[50,50,28857]],[[13167,13167],"mapped",[50,51,28857]],[[13168,13168],"mapped",[50,52,28857]],[[13169,13169],"mapped",[104,112,97]],[[13170,13170],"mapped",[100,97]],[[13171,13171],"mapped",[97,117]],[[13172,13172],"mapped",[98,97,114]],[[13173,13173],"mapped",[111,118]],[[13174,13174],"mapped",[112,99]],[[13175,13175],"mapped",[100,109]],[[13176,13176],"mapped",[100,109,50]],[[13177,13177],"mapped",[100,109,51]],[[13178,13178],"mapped",[105,117]],[[13179,13179],"mapped",[24179,25104]],[[13180,13180],"mapped",[26157,21644]],[[13181,13181],"mapped",[22823,27491]],[[13182,13182],"mapped",[26126,27835]],[[13183,13183],"mapped",[26666,24335,20250,31038]],[[13184,13184],"mapped",[112,97]],[[13185,13185],"mapped",[110,97]],[[13186,13186],"mapped",[956,97]],[[13187,13187],"mapped",[109,97]],[[13188,13188],"mapped",[107,97]],[[13189,13189],"mapped",[107,98]],[[13190,13190],"mapped",[109,98]],[[13191,13191],"mapped",[103,98]],[[13192,13192],"mapped",[99,97,108]],[[13193,13193],"mapped",[107,99,97,108]],[[13194,13194],"mapped",[112,102]],[[13195,13195],"mapped",[110,102]],[[13196,13196],"mapped",[956,102]],[[13197,13197],"mapped",[956,103]],[[13198,13198],"mapped",[109,103]],[[13199,13199],"mapped",[107,103]],[[13200,13200],"mapped",[104,122]],[[13201,13201],"mapped",[107,104,122]],[[13202,13202],"mapped",[109,104,122]],[[13203,13203],"mapped",[103,104,122]],[[13204,13204],"mapped",[116,104,122]],[[13205,13205],"mapped",[956,108]],[[13206,13206],"mapped",[109,108]],[[13207,13207],"mapped",[100,108]],[[13208,13208],"mapped",[107,108]],[[13209,13209],"mapped",[102,109]],[[13210,13210],"mapped",[110,109]],[[13211,13211],"mapped",[956,109]],[[13212,13212],"mapped",[109,109]],[[13213,13213],"mapped",[99,109]],[[13214,13214],"mapped",[107,109]],[[13215,13215],"mapped",[109,109,50]],[[13216,13216],"mapped",[99,109,50]],[[13217,13217],"mapped",[109,50]],[[13218,13218],"mapped",[107,109,50]],[[13219,13219],"mapped",[109,109,51]],[[13220,13220],"mapped",[99,109,51]],[[13221,13221],"mapped",[109,51]],[[13222,13222],"mapped",[107,109,51]],[[13223,13223],"mapped",[109,8725,115]],[[13224,13224],"mapped",[109,8725,115,50]],[[13225,13225],"mapped",[112,97]],[[13226,13226],"mapped",[107,112,97]],[[13227,13227],"mapped",[109,112,97]],[[13228,13228],"mapped",[103,112,97]],[[13229,13229],"mapped",[114,97,100]],[[13230,13230],"mapped",[114,97,100,8725,115]],[[13231,13231],"mapped",[114,97,100,8725,115,50]],[[13232,13232],"mapped",[112,115]],[[13233,13233],"mapped",[110,115]],[[13234,13234],"mapped",[956,115]],[[13235,13235],"mapped",[109,115]],[[13236,13236],"mapped",[112,118]],[[13237,13237],"mapped",[110,118]],[[13238,13238],"mapped",[956,118]],[[13239,13239],"mapped",[109,118]],[[13240,13240],"mapped",[107,118]],[[13241,13241],"mapped",[109,118]],[[13242,13242],"mapped",[112,119]],[[13243,13243],"mapped",[110,119]],[[13244,13244],"mapped",[956,119]],[[13245,13245],"mapped",[109,119]],[[13246,13246],"mapped",[107,119]],[[13247,13247],"mapped",[109,119]],[[13248,13248],"mapped",[107,969]],[[13249,13249],"mapped",[109,969]],[[13250,13250],"disallowed"],[[13251,13251],"mapped",[98,113]],[[13252,13252],"mapped",[99,99]],[[13253,13253],"mapped",[99,100]],[[13254,13254],"mapped",[99,8725,107,103]],[[13255,13255],"disallowed"],[[13256,13256],"mapped",[100,98]],[[13257,13257],"mapped",[103,121]],[[13258,13258],"mapped",[104,97]],[[13259,13259],"mapped",[104,112]],[[13260,13260],"mapped",[105,110]],[[13261,13261],"mapped",[107,107]],[[13262,13262],"mapped",[107,109]],[[13263,13263],"mapped",[107,116]],[[13264,13264],"mapped",[108,109]],[[13265,13265],"mapped",[108,110]],[[13266,13266],"mapped",[108,111,103]],[[13267,13267],"mapped",[108,120]],[[13268,13268],"mapped",[109,98]],[[13269,13269],"mapped",[109,105,108]],[[13270,13270],"mapped",[109,111,108]],[[13271,13271],"mapped",[112,104]],[[13272,13272],"disallowed"],[[13273,13273],"mapped",[112,112,109]],[[13274,13274],"mapped",[112,114]],[[13275,13275],"mapped",[115,114]],[[13276,13276],"mapped",[115,118]],[[13277,13277],"mapped",[119,98]],[[13278,13278],"mapped",[118,8725,109]],[[13279,13279],"mapped",[97,8725,109]],[[13280,13280],"mapped",[49,26085]],[[13281,13281],"mapped",[50,26085]],[[13282,13282],"mapped",[51,26085]],[[13283,13283],"mapped",[52,26085]],[[13284,13284],"mapped",[53,26085]],[[13285,13285],"mapped",[54,26085]],[[13286,13286],"mapped",[55,26085]],[[13287,13287],"mapped",[56,26085]],[[13288,13288],"mapped",[57,26085]],[[13289,13289],"mapped",[49,48,26085]],[[13290,13290],"mapped",[49,49,26085]],[[13291,13291],"mapped",[49,50,26085]],[[13292,13292],"mapped",[49,51,26085]],[[13293,13293],"mapped",[49,52,26085]],[[13294,13294],"mapped",[49,53,26085]],[[13295,13295],"mapped",[49,54,26085]],[[13296,13296],"mapped",[49,55,26085]],[[13297,13297],"mapped",[49,56,26085]],[[13298,13298],"mapped",[49,57,26085]],[[13299,13299],"mapped",[50,48,26085]],[[13300,13300],"mapped",[50,49,26085]],[[13301,13301],"mapped",[50,50,26085]],[[13302,13302],"mapped",[50,51,26085]],[[13303,13303],"mapped",[50,52,26085]],[[13304,13304],"mapped",[50,53,26085]],[[13305,13305],"mapped",[50,54,26085]],[[13306,13306],"mapped",[50,55,26085]],[[13307,13307],"mapped",[50,56,26085]],[[13308,13308],"mapped",[50,57,26085]],[[13309,13309],"mapped",[51,48,26085]],[[13310,13310],"mapped",[51,49,26085]],[[13311,13311],"mapped",[103,97,108]],[[13312,19893],"valid"],[[19894,19903],"disallowed"],[[19904,19967],"valid",[],"NV8"],[[19968,40869],"valid"],[[40870,40891],"valid"],[[40892,40899],"valid"],[[40900,40907],"valid"],[[40908,40908],"valid"],[[40909,40917],"valid"],[[40918,40959],"disallowed"],[[40960,42124],"valid"],[[42125,42127],"disallowed"],[[42128,42145],"valid",[],"NV8"],[[42146,42147],"valid",[],"NV8"],[[42148,42163],"valid",[],"NV8"],[[42164,42164],"valid",[],"NV8"],[[42165,42176],"valid",[],"NV8"],[[42177,42177],"valid",[],"NV8"],[[42178,42180],"valid",[],"NV8"],[[42181,42181],"valid",[],"NV8"],[[42182,42182],"valid",[],"NV8"],[[42183,42191],"disallowed"],[[42192,42237],"valid"],[[42238,42239],"valid",[],"NV8"],[[42240,42508],"valid"],[[42509,42511],"valid",[],"NV8"],[[42512,42539],"valid"],[[42540,42559],"disallowed"],[[42560,42560],"mapped",[42561]],[[42561,42561],"valid"],[[42562,42562],"mapped",[42563]],[[42563,42563],"valid"],[[42564,42564],"mapped",[42565]],[[42565,42565],"valid"],[[42566,42566],"mapped",[42567]],[[42567,42567],"valid"],[[42568,42568],"mapped",[42569]],[[42569,42569],"valid"],[[42570,42570],"mapped",[42571]],[[42571,42571],"valid"],[[42572,42572],"mapped",[42573]],[[42573,42573],"valid"],[[42574,42574],"mapped",[42575]],[[42575,42575],"valid"],[[42576,42576],"mapped",[42577]],[[42577,42577],"valid"],[[42578,42578],"mapped",[42579]],[[42579,42579],"valid"],[[42580,42580],"mapped",[42581]],[[42581,42581],"valid"],[[42582,42582],"mapped",[42583]],[[42583,42583],"valid"],[[42584,42584],"mapped",[42585]],[[42585,42585],"valid"],[[42586,42586],"mapped",[42587]],[[42587,42587],"valid"],[[42588,42588],"mapped",[42589]],[[42589,42589],"valid"],[[42590,42590],"mapped",[42591]],[[42591,42591],"valid"],[[42592,42592],"mapped",[42593]],[[42593,42593],"valid"],[[42594,42594],"mapped",[42595]],[[42595,42595],"valid"],[[42596,42596],"mapped",[42597]],[[42597,42597],"valid"],[[42598,42598],"mapped",[42599]],[[42599,42599],"valid"],[[42600,42600],"mapped",[42601]],[[42601,42601],"valid"],[[42602,42602],"mapped",[42603]],[[42603,42603],"valid"],[[42604,42604],"mapped",[42605]],[[42605,42607],"valid"],[[42608,42611],"valid",[],"NV8"],[[42612,42619],"valid"],[[42620,42621],"valid"],[[42622,42622],"valid",[],"NV8"],[[42623,42623],"valid"],[[42624,42624],"mapped",[42625]],[[42625,42625],"valid"],[[42626,42626],"mapped",[42627]],[[42627,42627],"valid"],[[42628,42628],"mapped",[42629]],[[42629,42629],"valid"],[[42630,42630],"mapped",[42631]],[[42631,42631],"valid"],[[42632,42632],"mapped",[42633]],[[42633,42633],"valid"],[[42634,42634],"mapped",[42635]],[[42635,42635],"valid"],[[42636,42636],"mapped",[42637]],[[42637,42637],"valid"],[[42638,42638],"mapped",[42639]],[[42639,42639],"valid"],[[42640,42640],"mapped",[42641]],[[42641,42641],"valid"],[[42642,42642],"mapped",[42643]],[[42643,42643],"valid"],[[42644,42644],"mapped",[42645]],[[42645,42645],"valid"],[[42646,42646],"mapped",[42647]],[[42647,42647],"valid"],[[42648,42648],"mapped",[42649]],[[42649,42649],"valid"],[[42650,42650],"mapped",[42651]],[[42651,42651],"valid"],[[42652,42652],"mapped",[1098]],[[42653,42653],"mapped",[1100]],[[42654,42654],"valid"],[[42655,42655],"valid"],[[42656,42725],"valid"],[[42726,42735],"valid",[],"NV8"],[[42736,42737],"valid"],[[42738,42743],"valid",[],"NV8"],[[42744,42751],"disallowed"],[[42752,42774],"valid",[],"NV8"],[[42775,42778],"valid"],[[42779,42783],"valid"],[[42784,42785],"valid",[],"NV8"],[[42786,42786],"mapped",[42787]],[[42787,42787],"valid"],[[42788,42788],"mapped",[42789]],[[42789,42789],"valid"],[[42790,42790],"mapped",[42791]],[[42791,42791],"valid"],[[42792,42792],"mapped",[42793]],[[42793,42793],"valid"],[[42794,42794],"mapped",[42795]],[[42795,42795],"valid"],[[42796,42796],"mapped",[42797]],[[42797,42797],"valid"],[[42798,42798],"mapped",[42799]],[[42799,42801],"valid"],[[42802,42802],"mapped",[42803]],[[42803,42803],"valid"],[[42804,42804],"mapped",[42805]],[[42805,42805],"valid"],[[42806,42806],"mapped",[42807]],[[42807,42807],"valid"],[[42808,42808],"mapped",[42809]],[[42809,42809],"valid"],[[42810,42810],"mapped",[42811]],[[42811,42811],"valid"],[[42812,42812],"mapped",[42813]],[[42813,42813],"valid"],[[42814,42814],"mapped",[42815]],[[42815,42815],"valid"],[[42816,42816],"mapped",[42817]],[[42817,42817],"valid"],[[42818,42818],"mapped",[42819]],[[42819,42819],"valid"],[[42820,42820],"mapped",[42821]],[[42821,42821],"valid"],[[42822,42822],"mapped",[42823]],[[42823,42823],"valid"],[[42824,42824],"mapped",[42825]],[[42825,42825],"valid"],[[42826,42826],"mapped",[42827]],[[42827,42827],"valid"],[[42828,42828],"mapped",[42829]],[[42829,42829],"valid"],[[42830,42830],"mapped",[42831]],[[42831,42831],"valid"],[[42832,42832],"mapped",[42833]],[[42833,42833],"valid"],[[42834,42834],"mapped",[42835]],[[42835,42835],"valid"],[[42836,42836],"mapped",[42837]],[[42837,42837],"valid"],[[42838,42838],"mapped",[42839]],[[42839,42839],"valid"],[[42840,42840],"mapped",[42841]],[[42841,42841],"valid"],[[42842,42842],"mapped",[42843]],[[42843,42843],"valid"],[[42844,42844],"mapped",[42845]],[[42845,42845],"valid"],[[42846,42846],"mapped",[42847]],[[42847,42847],"valid"],[[42848,42848],"mapped",[42849]],[[42849,42849],"valid"],[[42850,42850],"mapped",[42851]],[[42851,42851],"valid"],[[42852,42852],"mapped",[42853]],[[42853,42853],"valid"],[[42854,42854],"mapped",[42855]],[[42855,42855],"valid"],[[42856,42856],"mapped",[42857]],[[42857,42857],"valid"],[[42858,42858],"mapped",[42859]],[[42859,42859],"valid"],[[42860,42860],"mapped",[42861]],[[42861,42861],"valid"],[[42862,42862],"mapped",[42863]],[[42863,42863],"valid"],[[42864,42864],"mapped",[42863]],[[42865,42872],"valid"],[[42873,42873],"mapped",[42874]],[[42874,42874],"valid"],[[42875,42875],"mapped",[42876]],[[42876,42876],"valid"],[[42877,42877],"mapped",[7545]],[[42878,42878],"mapped",[42879]],[[42879,42879],"valid"],[[42880,42880],"mapped",[42881]],[[42881,42881],"valid"],[[42882,42882],"mapped",[42883]],[[42883,42883],"valid"],[[42884,42884],"mapped",[42885]],[[42885,42885],"valid"],[[42886,42886],"mapped",[42887]],[[42887,42888],"valid"],[[42889,42890],"valid",[],"NV8"],[[42891,42891],"mapped",[42892]],[[42892,42892],"valid"],[[42893,42893],"mapped",[613]],[[42894,42894],"valid"],[[42895,42895],"valid"],[[42896,42896],"mapped",[42897]],[[42897,42897],"valid"],[[42898,42898],"mapped",[42899]],[[42899,42899],"valid"],[[42900,42901],"valid"],[[42902,42902],"mapped",[42903]],[[42903,42903],"valid"],[[42904,42904],"mapped",[42905]],[[42905,42905],"valid"],[[42906,42906],"mapped",[42907]],[[42907,42907],"valid"],[[42908,42908],"mapped",[42909]],[[42909,42909],"valid"],[[42910,42910],"mapped",[42911]],[[42911,42911],"valid"],[[42912,42912],"mapped",[42913]],[[42913,42913],"valid"],[[42914,42914],"mapped",[42915]],[[42915,42915],"valid"],[[42916,42916],"mapped",[42917]],[[42917,42917],"valid"],[[42918,42918],"mapped",[42919]],[[42919,42919],"valid"],[[42920,42920],"mapped",[42921]],[[42921,42921],"valid"],[[42922,42922],"mapped",[614]],[[42923,42923],"mapped",[604]],[[42924,42924],"mapped",[609]],[[42925,42925],"mapped",[620]],[[42926,42927],"disallowed"],[[42928,42928],"mapped",[670]],[[42929,42929],"mapped",[647]],[[42930,42930],"mapped",[669]],[[42931,42931],"mapped",[43859]],[[42932,42932],"mapped",[42933]],[[42933,42933],"valid"],[[42934,42934],"mapped",[42935]],[[42935,42935],"valid"],[[42936,42998],"disallowed"],[[42999,42999],"valid"],[[43000,43000],"mapped",[295]],[[43001,43001],"mapped",[339]],[[43002,43002],"valid"],[[43003,43007],"valid"],[[43008,43047],"valid"],[[43048,43051],"valid",[],"NV8"],[[43052,43055],"disallowed"],[[43056,43065],"valid",[],"NV8"],[[43066,43071],"disallowed"],[[43072,43123],"valid"],[[43124,43127],"valid",[],"NV8"],[[43128,43135],"disallowed"],[[43136,43204],"valid"],[[43205,43213],"disallowed"],[[43214,43215],"valid",[],"NV8"],[[43216,43225],"valid"],[[43226,43231],"disallowed"],[[43232,43255],"valid"],[[43256,43258],"valid",[],"NV8"],[[43259,43259],"valid"],[[43260,43260],"valid",[],"NV8"],[[43261,43261],"valid"],[[43262,43263],"disallowed"],[[43264,43309],"valid"],[[43310,43311],"valid",[],"NV8"],[[43312,43347],"valid"],[[43348,43358],"disallowed"],[[43359,43359],"valid",[],"NV8"],[[43360,43388],"valid",[],"NV8"],[[43389,43391],"disallowed"],[[43392,43456],"valid"],[[43457,43469],"valid",[],"NV8"],[[43470,43470],"disallowed"],[[43471,43481],"valid"],[[43482,43485],"disallowed"],[[43486,43487],"valid",[],"NV8"],[[43488,43518],"valid"],[[43519,43519],"disallowed"],[[43520,43574],"valid"],[[43575,43583],"disallowed"],[[43584,43597],"valid"],[[43598,43599],"disallowed"],[[43600,43609],"valid"],[[43610,43611],"disallowed"],[[43612,43615],"valid",[],"NV8"],[[43616,43638],"valid"],[[43639,43641],"valid",[],"NV8"],[[43642,43643],"valid"],[[43644,43647],"valid"],[[43648,43714],"valid"],[[43715,43738],"disallowed"],[[43739,43741],"valid"],[[43742,43743],"valid",[],"NV8"],[[43744,43759],"valid"],[[43760,43761],"valid",[],"NV8"],[[43762,43766],"valid"],[[43767,43776],"disallowed"],[[43777,43782],"valid"],[[43783,43784],"disallowed"],[[43785,43790],"valid"],[[43791,43792],"disallowed"],[[43793,43798],"valid"],[[43799,43807],"disallowed"],[[43808,43814],"valid"],[[43815,43815],"disallowed"],[[43816,43822],"valid"],[[43823,43823],"disallowed"],[[43824,43866],"valid"],[[43867,43867],"valid",[],"NV8"],[[43868,43868],"mapped",[42791]],[[43869,43869],"mapped",[43831]],[[43870,43870],"mapped",[619]],[[43871,43871],"mapped",[43858]],[[43872,43875],"valid"],[[43876,43877],"valid"],[[43878,43887],"disallowed"],[[43888,43888],"mapped",[5024]],[[43889,43889],"mapped",[5025]],[[43890,43890],"mapped",[5026]],[[43891,43891],"mapped",[5027]],[[43892,43892],"mapped",[5028]],[[43893,43893],"mapped",[5029]],[[43894,43894],"mapped",[5030]],[[43895,43895],"mapped",[5031]],[[43896,43896],"mapped",[5032]],[[43897,43897],"mapped",[5033]],[[43898,43898],"mapped",[5034]],[[43899,43899],"mapped",[5035]],[[43900,43900],"mapped",[5036]],[[43901,43901],"mapped",[5037]],[[43902,43902],"mapped",[5038]],[[43903,43903],"mapped",[5039]],[[43904,43904],"mapped",[5040]],[[43905,43905],"mapped",[5041]],[[43906,43906],"mapped",[5042]],[[43907,43907],"mapped",[5043]],[[43908,43908],"mapped",[5044]],[[43909,43909],"mapped",[5045]],[[43910,43910],"mapped",[5046]],[[43911,43911],"mapped",[5047]],[[43912,43912],"mapped",[5048]],[[43913,43913],"mapped",[5049]],[[43914,43914],"mapped",[5050]],[[43915,43915],"mapped",[5051]],[[43916,43916],"mapped",[5052]],[[43917,43917],"mapped",[5053]],[[43918,43918],"mapped",[5054]],[[43919,43919],"mapped",[5055]],[[43920,43920],"mapped",[5056]],[[43921,43921],"mapped",[5057]],[[43922,43922],"mapped",[5058]],[[43923,43923],"mapped",[5059]],[[43924,43924],"mapped",[5060]],[[43925,43925],"mapped",[5061]],[[43926,43926],"mapped",[5062]],[[43927,43927],"mapped",[5063]],[[43928,43928],"mapped",[5064]],[[43929,43929],"mapped",[5065]],[[43930,43930],"mapped",[5066]],[[43931,43931],"mapped",[5067]],[[43932,43932],"mapped",[5068]],[[43933,43933],"mapped",[5069]],[[43934,43934],"mapped",[5070]],[[43935,43935],"mapped",[5071]],[[43936,43936],"mapped",[5072]],[[43937,43937],"mapped",[5073]],[[43938,43938],"mapped",[5074]],[[43939,43939],"mapped",[5075]],[[43940,43940],"mapped",[5076]],[[43941,43941],"mapped",[5077]],[[43942,43942],"mapped",[5078]],[[43943,43943],"mapped",[5079]],[[43944,43944],"mapped",[5080]],[[43945,43945],"mapped",[5081]],[[43946,43946],"mapped",[5082]],[[43947,43947],"mapped",[5083]],[[43948,43948],"mapped",[5084]],[[43949,43949],"mapped",[5085]],[[43950,43950],"mapped",[5086]],[[43951,43951],"mapped",[5087]],[[43952,43952],"mapped",[5088]],[[43953,43953],"mapped",[5089]],[[43954,43954],"mapped",[5090]],[[43955,43955],"mapped",[5091]],[[43956,43956],"mapped",[5092]],[[43957,43957],"mapped",[5093]],[[43958,43958],"mapped",[5094]],[[43959,43959],"mapped",[5095]],[[43960,43960],"mapped",[5096]],[[43961,43961],"mapped",[5097]],[[43962,43962],"mapped",[5098]],[[43963,43963],"mapped",[5099]],[[43964,43964],"mapped",[5100]],[[43965,43965],"mapped",[5101]],[[43966,43966],"mapped",[5102]],[[43967,43967],"mapped",[5103]],[[43968,44010],"valid"],[[44011,44011],"valid",[],"NV8"],[[44012,44013],"valid"],[[44014,44015],"disallowed"],[[44016,44025],"valid"],[[44026,44031],"disallowed"],[[44032,55203],"valid"],[[55204,55215],"disallowed"],[[55216,55238],"valid",[],"NV8"],[[55239,55242],"disallowed"],[[55243,55291],"valid",[],"NV8"],[[55292,55295],"disallowed"],[[55296,57343],"disallowed"],[[57344,63743],"disallowed"],[[63744,63744],"mapped",[35912]],[[63745,63745],"mapped",[26356]],[[63746,63746],"mapped",[36554]],[[63747,63747],"mapped",[36040]],[[63748,63748],"mapped",[28369]],[[63749,63749],"mapped",[20018]],[[63750,63750],"mapped",[21477]],[[63751,63752],"mapped",[40860]],[[63753,63753],"mapped",[22865]],[[63754,63754],"mapped",[37329]],[[63755,63755],"mapped",[21895]],[[63756,63756],"mapped",[22856]],[[63757,63757],"mapped",[25078]],[[63758,63758],"mapped",[30313]],[[63759,63759],"mapped",[32645]],[[63760,63760],"mapped",[34367]],[[63761,63761],"mapped",[34746]],[[63762,63762],"mapped",[35064]],[[63763,63763],"mapped",[37007]],[[63764,63764],"mapped",[27138]],[[63765,63765],"mapped",[27931]],[[63766,63766],"mapped",[28889]],[[63767,63767],"mapped",[29662]],[[63768,63768],"mapped",[33853]],[[63769,63769],"mapped",[37226]],[[63770,63770],"mapped",[39409]],[[63771,63771],"mapped",[20098]],[[63772,63772],"mapped",[21365]],[[63773,63773],"mapped",[27396]],[[63774,63774],"mapped",[29211]],[[63775,63775],"mapped",[34349]],[[63776,63776],"mapped",[40478]],[[63777,63777],"mapped",[23888]],[[63778,63778],"mapped",[28651]],[[63779,63779],"mapped",[34253]],[[63780,63780],"mapped",[35172]],[[63781,63781],"mapped",[25289]],[[63782,63782],"mapped",[33240]],[[63783,63783],"mapped",[34847]],[[63784,63784],"mapped",[24266]],[[63785,63785],"mapped",[26391]],[[63786,63786],"mapped",[28010]],[[63787,63787],"mapped",[29436]],[[63788,63788],"mapped",[37070]],[[63789,63789],"mapped",[20358]],[[63790,63790],"mapped",[20919]],[[63791,63791],"mapped",[21214]],[[63792,63792],"mapped",[25796]],[[63793,63793],"mapped",[27347]],[[63794,63794],"mapped",[29200]],[[63795,63795],"mapped",[30439]],[[63796,63796],"mapped",[32769]],[[63797,63797],"mapped",[34310]],[[63798,63798],"mapped",[34396]],[[63799,63799],"mapped",[36335]],[[63800,63800],"mapped",[38706]],[[63801,63801],"mapped",[39791]],[[63802,63802],"mapped",[40442]],[[63803,63803],"mapped",[30860]],[[63804,63804],"mapped",[31103]],[[63805,63805],"mapped",[32160]],[[63806,63806],"mapped",[33737]],[[63807,63807],"mapped",[37636]],[[63808,63808],"mapped",[40575]],[[63809,63809],"mapped",[35542]],[[63810,63810],"mapped",[22751]],[[63811,63811],"mapped",[24324]],[[63812,63812],"mapped",[31840]],[[63813,63813],"mapped",[32894]],[[63814,63814],"mapped",[29282]],[[63815,63815],"mapped",[30922]],[[63816,63816],"mapped",[36034]],[[63817,63817],"mapped",[38647]],[[63818,63818],"mapped",[22744]],[[63819,63819],"mapped",[23650]],[[63820,63820],"mapped",[27155]],[[63821,63821],"mapped",[28122]],[[63822,63822],"mapped",[28431]],[[63823,63823],"mapped",[32047]],[[63824,63824],"mapped",[32311]],[[63825,63825],"mapped",[38475]],[[63826,63826],"mapped",[21202]],[[63827,63827],"mapped",[32907]],[[63828,63828],"mapped",[20956]],[[63829,63829],"mapped",[20940]],[[63830,63830],"mapped",[31260]],[[63831,63831],"mapped",[32190]],[[63832,63832],"mapped",[33777]],[[63833,63833],"mapped",[38517]],[[63834,63834],"mapped",[35712]],[[63835,63835],"mapped",[25295]],[[63836,63836],"mapped",[27138]],[[63837,63837],"mapped",[35582]],[[63838,63838],"mapped",[20025]],[[63839,63839],"mapped",[23527]],[[63840,63840],"mapped",[24594]],[[63841,63841],"mapped",[29575]],[[63842,63842],"mapped",[30064]],[[63843,63843],"mapped",[21271]],[[63844,63844],"mapped",[30971]],[[63845,63845],"mapped",[20415]],[[63846,63846],"mapped",[24489]],[[63847,63847],"mapped",[19981]],[[63848,63848],"mapped",[27852]],[[63849,63849],"mapped",[25976]],[[63850,63850],"mapped",[32034]],[[63851,63851],"mapped",[21443]],[[63852,63852],"mapped",[22622]],[[63853,63853],"mapped",[30465]],[[63854,63854],"mapped",[33865]],[[63855,63855],"mapped",[35498]],[[63856,63856],"mapped",[27578]],[[63857,63857],"mapped",[36784]],[[63858,63858],"mapped",[27784]],[[63859,63859],"mapped",[25342]],[[63860,63860],"mapped",[33509]],[[63861,63861],"mapped",[25504]],[[63862,63862],"mapped",[30053]],[[63863,63863],"mapped",[20142]],[[63864,63864],"mapped",[20841]],[[63865,63865],"mapped",[20937]],[[63866,63866],"mapped",[26753]],[[63867,63867],"mapped",[31975]],[[63868,63868],"mapped",[33391]],[[63869,63869],"mapped",[35538]],[[63870,63870],"mapped",[37327]],[[63871,63871],"mapped",[21237]],[[63872,63872],"mapped",[21570]],[[63873,63873],"mapped",[22899]],[[63874,63874],"mapped",[24300]],[[63875,63875],"mapped",[26053]],[[63876,63876],"mapped",[28670]],[[63877,63877],"mapped",[31018]],[[63878,63878],"mapped",[38317]],[[63879,63879],"mapped",[39530]],[[63880,63880],"mapped",[40599]],[[63881,63881],"mapped",[40654]],[[63882,63882],"mapped",[21147]],[[63883,63883],"mapped",[26310]],[[63884,63884],"mapped",[27511]],[[63885,63885],"mapped",[36706]],[[63886,63886],"mapped",[24180]],[[63887,63887],"mapped",[24976]],[[63888,63888],"mapped",[25088]],[[63889,63889],"mapped",[25754]],[[63890,63890],"mapped",[28451]],[[63891,63891],"mapped",[29001]],[[63892,63892],"mapped",[29833]],[[63893,63893],"mapped",[31178]],[[63894,63894],"mapped",[32244]],[[63895,63895],"mapped",[32879]],[[63896,63896],"mapped",[36646]],[[63897,63897],"mapped",[34030]],[[63898,63898],"mapped",[36899]],[[63899,63899],"mapped",[37706]],[[63900,63900],"mapped",[21015]],[[63901,63901],"mapped",[21155]],[[63902,63902],"mapped",[21693]],[[63903,63903],"mapped",[28872]],[[63904,63904],"mapped",[35010]],[[63905,63905],"mapped",[35498]],[[63906,63906],"mapped",[24265]],[[63907,63907],"mapped",[24565]],[[63908,63908],"mapped",[25467]],[[63909,63909],"mapped",[27566]],[[63910,63910],"mapped",[31806]],[[63911,63911],"mapped",[29557]],[[63912,63912],"mapped",[20196]],[[63913,63913],"mapped",[22265]],[[63914,63914],"mapped",[23527]],[[63915,63915],"mapped",[23994]],[[63916,63916],"mapped",[24604]],[[63917,63917],"mapped",[29618]],[[63918,63918],"mapped",[29801]],[[63919,63919],"mapped",[32666]],[[63920,63920],"mapped",[32838]],[[63921,63921],"mapped",[37428]],[[63922,63922],"mapped",[38646]],[[63923,63923],"mapped",[38728]],[[63924,63924],"mapped",[38936]],[[63925,63925],"mapped",[20363]],[[63926,63926],"mapped",[31150]],[[63927,63927],"mapped",[37300]],[[63928,63928],"mapped",[38584]],[[63929,63929],"mapped",[24801]],[[63930,63930],"mapped",[20102]],[[63931,63931],"mapped",[20698]],[[63932,63932],"mapped",[23534]],[[63933,63933],"mapped",[23615]],[[63934,63934],"mapped",[26009]],[[63935,63935],"mapped",[27138]],[[63936,63936],"mapped",[29134]],[[63937,63937],"mapped",[30274]],[[63938,63938],"mapped",[34044]],[[63939,63939],"mapped",[36988]],[[63940,63940],"mapped",[40845]],[[63941,63941],"mapped",[26248]],[[63942,63942],"mapped",[38446]],[[63943,63943],"mapped",[21129]],[[63944,63944],"mapped",[26491]],[[63945,63945],"mapped",[26611]],[[63946,63946],"mapped",[27969]],[[63947,63947],"mapped",[28316]],[[63948,63948],"mapped",[29705]],[[63949,63949],"mapped",[30041]],[[63950,63950],"mapped",[30827]],[[63951,63951],"mapped",[32016]],[[63952,63952],"mapped",[39006]],[[63953,63953],"mapped",[20845]],[[63954,63954],"mapped",[25134]],[[63955,63955],"mapped",[38520]],[[63956,63956],"mapped",[20523]],[[63957,63957],"mapped",[23833]],[[63958,63958],"mapped",[28138]],[[63959,63959],"mapped",[36650]],[[63960,63960],"mapped",[24459]],[[63961,63961],"mapped",[24900]],[[63962,63962],"mapped",[26647]],[[63963,63963],"mapped",[29575]],[[63964,63964],"mapped",[38534]],[[63965,63965],"mapped",[21033]],[[63966,63966],"mapped",[21519]],[[63967,63967],"mapped",[23653]],[[63968,63968],"mapped",[26131]],[[63969,63969],"mapped",[26446]],[[63970,63970],"mapped",[26792]],[[63971,63971],"mapped",[27877]],[[63972,63972],"mapped",[29702]],[[63973,63973],"mapped",[30178]],[[63974,63974],"mapped",[32633]],[[63975,63975],"mapped",[35023]],[[63976,63976],"mapped",[35041]],[[63977,63977],"mapped",[37324]],[[63978,63978],"mapped",[38626]],[[63979,63979],"mapped",[21311]],[[63980,63980],"mapped",[28346]],[[63981,63981],"mapped",[21533]],[[63982,63982],"mapped",[29136]],[[63983,63983],"mapped",[29848]],[[63984,63984],"mapped",[34298]],[[63985,63985],"mapped",[38563]],[[63986,63986],"mapped",[40023]],[[63987,63987],"mapped",[40607]],[[63988,63988],"mapped",[26519]],[[63989,63989],"mapped",[28107]],[[63990,63990],"mapped",[33256]],[[63991,63991],"mapped",[31435]],[[63992,63992],"mapped",[31520]],[[63993,63993],"mapped",[31890]],[[63994,63994],"mapped",[29376]],[[63995,63995],"mapped",[28825]],[[63996,63996],"mapped",[35672]],[[63997,63997],"mapped",[20160]],[[63998,63998],"mapped",[33590]],[[63999,63999],"mapped",[21050]],[[64000,64000],"mapped",[20999]],[[64001,64001],"mapped",[24230]],[[64002,64002],"mapped",[25299]],[[64003,64003],"mapped",[31958]],[[64004,64004],"mapped",[23429]],[[64005,64005],"mapped",[27934]],[[64006,64006],"mapped",[26292]],[[64007,64007],"mapped",[36667]],[[64008,64008],"mapped",[34892]],[[64009,64009],"mapped",[38477]],[[64010,64010],"mapped",[35211]],[[64011,64011],"mapped",[24275]],[[64012,64012],"mapped",[20800]],[[64013,64013],"mapped",[21952]],[[64014,64015],"valid"],[[64016,64016],"mapped",[22618]],[[64017,64017],"valid"],[[64018,64018],"mapped",[26228]],[[64019,64020],"valid"],[[64021,64021],"mapped",[20958]],[[64022,64022],"mapped",[29482]],[[64023,64023],"mapped",[30410]],[[64024,64024],"mapped",[31036]],[[64025,64025],"mapped",[31070]],[[64026,64026],"mapped",[31077]],[[64027,64027],"mapped",[31119]],[[64028,64028],"mapped",[38742]],[[64029,64029],"mapped",[31934]],[[64030,64030],"mapped",[32701]],[[64031,64031],"valid"],[[64032,64032],"mapped",[34322]],[[64033,64033],"valid"],[[64034,64034],"mapped",[35576]],[[64035,64036],"valid"],[[64037,64037],"mapped",[36920]],[[64038,64038],"mapped",[37117]],[[64039,64041],"valid"],[[64042,64042],"mapped",[39151]],[[64043,64043],"mapped",[39164]],[[64044,64044],"mapped",[39208]],[[64045,64045],"mapped",[40372]],[[64046,64046],"mapped",[37086]],[[64047,64047],"mapped",[38583]],[[64048,64048],"mapped",[20398]],[[64049,64049],"mapped",[20711]],[[64050,64050],"mapped",[20813]],[[64051,64051],"mapped",[21193]],[[64052,64052],"mapped",[21220]],[[64053,64053],"mapped",[21329]],[[64054,64054],"mapped",[21917]],[[64055,64055],"mapped",[22022]],[[64056,64056],"mapped",[22120]],[[64057,64057],"mapped",[22592]],[[64058,64058],"mapped",[22696]],[[64059,64059],"mapped",[23652]],[[64060,64060],"mapped",[23662]],[[64061,64061],"mapped",[24724]],[[64062,64062],"mapped",[24936]],[[64063,64063],"mapped",[24974]],[[64064,64064],"mapped",[25074]],[[64065,64065],"mapped",[25935]],[[64066,64066],"mapped",[26082]],[[64067,64067],"mapped",[26257]],[[64068,64068],"mapped",[26757]],[[64069,64069],"mapped",[28023]],[[64070,64070],"mapped",[28186]],[[64071,64071],"mapped",[28450]],[[64072,64072],"mapped",[29038]],[[64073,64073],"mapped",[29227]],[[64074,64074],"mapped",[29730]],[[64075,64075],"mapped",[30865]],[[64076,64076],"mapped",[31038]],[[64077,64077],"mapped",[31049]],[[64078,64078],"mapped",[31048]],[[64079,64079],"mapped",[31056]],[[64080,64080],"mapped",[31062]],[[64081,64081],"mapped",[31069]],[[64082,64082],"mapped",[31117]],[[64083,64083],"mapped",[31118]],[[64084,64084],"mapped",[31296]],[[64085,64085],"mapped",[31361]],[[64086,64086],"mapped",[31680]],[[64087,64087],"mapped",[32244]],[[64088,64088],"mapped",[32265]],[[64089,64089],"mapped",[32321]],[[64090,64090],"mapped",[32626]],[[64091,64091],"mapped",[32773]],[[64092,64092],"mapped",[33261]],[[64093,64094],"mapped",[33401]],[[64095,64095],"mapped",[33879]],[[64096,64096],"mapped",[35088]],[[64097,64097],"mapped",[35222]],[[64098,64098],"mapped",[35585]],[[64099,64099],"mapped",[35641]],[[64100,64100],"mapped",[36051]],[[64101,64101],"mapped",[36104]],[[64102,64102],"mapped",[36790]],[[64103,64103],"mapped",[36920]],[[64104,64104],"mapped",[38627]],[[64105,64105],"mapped",[38911]],[[64106,64106],"mapped",[38971]],[[64107,64107],"mapped",[24693]],[[64108,64108],"mapped",[148206]],[[64109,64109],"mapped",[33304]],[[64110,64111],"disallowed"],[[64112,64112],"mapped",[20006]],[[64113,64113],"mapped",[20917]],[[64114,64114],"mapped",[20840]],[[64115,64115],"mapped",[20352]],[[64116,64116],"mapped",[20805]],[[64117,64117],"mapped",[20864]],[[64118,64118],"mapped",[21191]],[[64119,64119],"mapped",[21242]],[[64120,64120],"mapped",[21917]],[[64121,64121],"mapped",[21845]],[[64122,64122],"mapped",[21913]],[[64123,64123],"mapped",[21986]],[[64124,64124],"mapped",[22618]],[[64125,64125],"mapped",[22707]],[[64126,64126],"mapped",[22852]],[[64127,64127],"mapped",[22868]],[[64128,64128],"mapped",[23138]],[[64129,64129],"mapped",[23336]],[[64130,64130],"mapped",[24274]],[[64131,64131],"mapped",[24281]],[[64132,64132],"mapped",[24425]],[[64133,64133],"mapped",[24493]],[[64134,64134],"mapped",[24792]],[[64135,64135],"mapped",[24910]],[[64136,64136],"mapped",[24840]],[[64137,64137],"mapped",[24974]],[[64138,64138],"mapped",[24928]],[[64139,64139],"mapped",[25074]],[[64140,64140],"mapped",[25140]],[[64141,64141],"mapped",[25540]],[[64142,64142],"mapped",[25628]],[[64143,64143],"mapped",[25682]],[[64144,64144],"mapped",[25942]],[[64145,64145],"mapped",[26228]],[[64146,64146],"mapped",[26391]],[[64147,64147],"mapped",[26395]],[[64148,64148],"mapped",[26454]],[[64149,64149],"mapped",[27513]],[[64150,64150],"mapped",[27578]],[[64151,64151],"mapped",[27969]],[[64152,64152],"mapped",[28379]],[[64153,64153],"mapped",[28363]],[[64154,64154],"mapped",[28450]],[[64155,64155],"mapped",[28702]],[[64156,64156],"mapped",[29038]],[[64157,64157],"mapped",[30631]],[[64158,64158],"mapped",[29237]],[[64159,64159],"mapped",[29359]],[[64160,64160],"mapped",[29482]],[[64161,64161],"mapped",[29809]],[[64162,64162],"mapped",[29958]],[[64163,64163],"mapped",[30011]],[[64164,64164],"mapped",[30237]],[[64165,64165],"mapped",[30239]],[[64166,64166],"mapped",[30410]],[[64167,64167],"mapped",[30427]],[[64168,64168],"mapped",[30452]],[[64169,64169],"mapped",[30538]],[[64170,64170],"mapped",[30528]],[[64171,64171],"mapped",[30924]],[[64172,64172],"mapped",[31409]],[[64173,64173],"mapped",[31680]],[[64174,64174],"mapped",[31867]],[[64175,64175],"mapped",[32091]],[[64176,64176],"mapped",[32244]],[[64177,64177],"mapped",[32574]],[[64178,64178],"mapped",[32773]],[[64179,64179],"mapped",[33618]],[[64180,64180],"mapped",[33775]],[[64181,64181],"mapped",[34681]],[[64182,64182],"mapped",[35137]],[[64183,64183],"mapped",[35206]],[[64184,64184],"mapped",[35222]],[[64185,64185],"mapped",[35519]],[[64186,64186],"mapped",[35576]],[[64187,64187],"mapped",[35531]],[[64188,64188],"mapped",[35585]],[[64189,64189],"mapped",[35582]],[[64190,64190],"mapped",[35565]],[[64191,64191],"mapped",[35641]],[[64192,64192],"mapped",[35722]],[[64193,64193],"mapped",[36104]],[[64194,64194],"mapped",[36664]],[[64195,64195],"mapped",[36978]],[[64196,64196],"mapped",[37273]],[[64197,64197],"mapped",[37494]],[[64198,64198],"mapped",[38524]],[[64199,64199],"mapped",[38627]],[[64200,64200],"mapped",[38742]],[[64201,64201],"mapped",[38875]],[[64202,64202],"mapped",[38911]],[[64203,64203],"mapped",[38923]],[[64204,64204],"mapped",[38971]],[[64205,64205],"mapped",[39698]],[[64206,64206],"mapped",[40860]],[[64207,64207],"mapped",[141386]],[[64208,64208],"mapped",[141380]],[[64209,64209],"mapped",[144341]],[[64210,64210],"mapped",[15261]],[[64211,64211],"mapped",[16408]],[[64212,64212],"mapped",[16441]],[[64213,64213],"mapped",[152137]],[[64214,64214],"mapped",[154832]],[[64215,64215],"mapped",[163539]],[[64216,64216],"mapped",[40771]],[[64217,64217],"mapped",[40846]],[[64218,64255],"disallowed"],[[64256,64256],"mapped",[102,102]],[[64257,64257],"mapped",[102,105]],[[64258,64258],"mapped",[102,108]],[[64259,64259],"mapped",[102,102,105]],[[64260,64260],"mapped",[102,102,108]],[[64261,64262],"mapped",[115,116]],[[64263,64274],"disallowed"],[[64275,64275],"mapped",[1396,1398]],[[64276,64276],"mapped",[1396,1381]],[[64277,64277],"mapped",[1396,1387]],[[64278,64278],"mapped",[1406,1398]],[[64279,64279],"mapped",[1396,1389]],[[64280,64284],"disallowed"],[[64285,64285],"mapped",[1497,1460]],[[64286,64286],"valid"],[[64287,64287],"mapped",[1522,1463]],[[64288,64288],"mapped",[1506]],[[64289,64289],"mapped",[1488]],[[64290,64290],"mapped",[1491]],[[64291,64291],"mapped",[1492]],[[64292,64292],"mapped",[1499]],[[64293,64293],"mapped",[1500]],[[64294,64294],"mapped",[1501]],[[64295,64295],"mapped",[1512]],[[64296,64296],"mapped",[1514]],[[64297,64297],"disallowed_STD3_mapped",[43]],[[64298,64298],"mapped",[1513,1473]],[[64299,64299],"mapped",[1513,1474]],[[64300,64300],"mapped",[1513,1468,1473]],[[64301,64301],"mapped",[1513,1468,1474]],[[64302,64302],"mapped",[1488,1463]],[[64303,64303],"mapped",[1488,1464]],[[64304,64304],"mapped",[1488,1468]],[[64305,64305],"mapped",[1489,1468]],[[64306,64306],"mapped",[1490,1468]],[[64307,64307],"mapped",[1491,1468]],[[64308,64308],"mapped",[1492,1468]],[[64309,64309],"mapped",[1493,1468]],[[64310,64310],"mapped",[1494,1468]],[[64311,64311],"disallowed"],[[64312,64312],"mapped",[1496,1468]],[[64313,64313],"mapped",[1497,1468]],[[64314,64314],"mapped",[1498,1468]],[[64315,64315],"mapped",[1499,1468]],[[64316,64316],"mapped",[1500,1468]],[[64317,64317],"disallowed"],[[64318,64318],"mapped",[1502,1468]],[[64319,64319],"disallowed"],[[64320,64320],"mapped",[1504,1468]],[[64321,64321],"mapped",[1505,1468]],[[64322,64322],"disallowed"],[[64323,64323],"mapped",[1507,1468]],[[64324,64324],"mapped",[1508,1468]],[[64325,64325],"disallowed"],[[64326,64326],"mapped",[1510,1468]],[[64327,64327],"mapped",[1511,1468]],[[64328,64328],"mapped",[1512,1468]],[[64329,64329],"mapped",[1513,1468]],[[64330,64330],"mapped",[1514,1468]],[[64331,64331],"mapped",[1493,1465]],[[64332,64332],"mapped",[1489,1471]],[[64333,64333],"mapped",[1499,1471]],[[64334,64334],"mapped",[1508,1471]],[[64335,64335],"mapped",[1488,1500]],[[64336,64337],"mapped",[1649]],[[64338,64341],"mapped",[1659]],[[64342,64345],"mapped",[1662]],[[64346,64349],"mapped",[1664]],[[64350,64353],"mapped",[1658]],[[64354,64357],"mapped",[1663]],[[64358,64361],"mapped",[1657]],[[64362,64365],"mapped",[1700]],[[64366,64369],"mapped",[1702]],[[64370,64373],"mapped",[1668]],[[64374,64377],"mapped",[1667]],[[64378,64381],"mapped",[1670]],[[64382,64385],"mapped",[1671]],[[64386,64387],"mapped",[1677]],[[64388,64389],"mapped",[1676]],[[64390,64391],"mapped",[1678]],[[64392,64393],"mapped",[1672]],[[64394,64395],"mapped",[1688]],[[64396,64397],"mapped",[1681]],[[64398,64401],"mapped",[1705]],[[64402,64405],"mapped",[1711]],[[64406,64409],"mapped",[1715]],[[64410,64413],"mapped",[1713]],[[64414,64415],"mapped",[1722]],[[64416,64419],"mapped",[1723]],[[64420,64421],"mapped",[1728]],[[64422,64425],"mapped",[1729]],[[64426,64429],"mapped",[1726]],[[64430,64431],"mapped",[1746]],[[64432,64433],"mapped",[1747]],[[64434,64449],"valid",[],"NV8"],[[64450,64466],"disallowed"],[[64467,64470],"mapped",[1709]],[[64471,64472],"mapped",[1735]],[[64473,64474],"mapped",[1734]],[[64475,64476],"mapped",[1736]],[[64477,64477],"mapped",[1735,1652]],[[64478,64479],"mapped",[1739]],[[64480,64481],"mapped",[1733]],[[64482,64483],"mapped",[1737]],[[64484,64487],"mapped",[1744]],[[64488,64489],"mapped",[1609]],[[64490,64491],"mapped",[1574,1575]],[[64492,64493],"mapped",[1574,1749]],[[64494,64495],"mapped",[1574,1608]],[[64496,64497],"mapped",[1574,1735]],[[64498,64499],"mapped",[1574,1734]],[[64500,64501],"mapped",[1574,1736]],[[64502,64504],"mapped",[1574,1744]],[[64505,64507],"mapped",[1574,1609]],[[64508,64511],"mapped",[1740]],[[64512,64512],"mapped",[1574,1580]],[[64513,64513],"mapped",[1574,1581]],[[64514,64514],"mapped",[1574,1605]],[[64515,64515],"mapped",[1574,1609]],[[64516,64516],"mapped",[1574,1610]],[[64517,64517],"mapped",[1576,1580]],[[64518,64518],"mapped",[1576,1581]],[[64519,64519],"mapped",[1576,1582]],[[64520,64520],"mapped",[1576,1605]],[[64521,64521],"mapped",[1576,1609]],[[64522,64522],"mapped",[1576,1610]],[[64523,64523],"mapped",[1578,1580]],[[64524,64524],"mapped",[1578,1581]],[[64525,64525],"mapped",[1578,1582]],[[64526,64526],"mapped",[1578,1605]],[[64527,64527],"mapped",[1578,1609]],[[64528,64528],"mapped",[1578,1610]],[[64529,64529],"mapped",[1579,1580]],[[64530,64530],"mapped",[1579,1605]],[[64531,64531],"mapped",[1579,1609]],[[64532,64532],"mapped",[1579,1610]],[[64533,64533],"mapped",[1580,1581]],[[64534,64534],"mapped",[1580,1605]],[[64535,64535],"mapped",[1581,1580]],[[64536,64536],"mapped",[1581,1605]],[[64537,64537],"mapped",[1582,1580]],[[64538,64538],"mapped",[1582,1581]],[[64539,64539],"mapped",[1582,1605]],[[64540,64540],"mapped",[1587,1580]],[[64541,64541],"mapped",[1587,1581]],[[64542,64542],"mapped",[1587,1582]],[[64543,64543],"mapped",[1587,1605]],[[64544,64544],"mapped",[1589,1581]],[[64545,64545],"mapped",[1589,1605]],[[64546,64546],"mapped",[1590,1580]],[[64547,64547],"mapped",[1590,1581]],[[64548,64548],"mapped",[1590,1582]],[[64549,64549],"mapped",[1590,1605]],[[64550,64550],"mapped",[1591,1581]],[[64551,64551],"mapped",[1591,1605]],[[64552,64552],"mapped",[1592,1605]],[[64553,64553],"mapped",[1593,1580]],[[64554,64554],"mapped",[1593,1605]],[[64555,64555],"mapped",[1594,1580]],[[64556,64556],"mapped",[1594,1605]],[[64557,64557],"mapped",[1601,1580]],[[64558,64558],"mapped",[1601,1581]],[[64559,64559],"mapped",[1601,1582]],[[64560,64560],"mapped",[1601,1605]],[[64561,64561],"mapped",[1601,1609]],[[64562,64562],"mapped",[1601,1610]],[[64563,64563],"mapped",[1602,1581]],[[64564,64564],"mapped",[1602,1605]],[[64565,64565],"mapped",[1602,1609]],[[64566,64566],"mapped",[1602,1610]],[[64567,64567],"mapped",[1603,1575]],[[64568,64568],"mapped",[1603,1580]],[[64569,64569],"mapped",[1603,1581]],[[64570,64570],"mapped",[1603,1582]],[[64571,64571],"mapped",[1603,1604]],[[64572,64572],"mapped",[1603,1605]],[[64573,64573],"mapped",[1603,1609]],[[64574,64574],"mapped",[1603,1610]],[[64575,64575],"mapped",[1604,1580]],[[64576,64576],"mapped",[1604,1581]],[[64577,64577],"mapped",[1604,1582]],[[64578,64578],"mapped",[1604,1605]],[[64579,64579],"mapped",[1604,1609]],[[64580,64580],"mapped",[1604,1610]],[[64581,64581],"mapped",[1605,1580]],[[64582,64582],"mapped",[1605,1581]],[[64583,64583],"mapped",[1605,1582]],[[64584,64584],"mapped",[1605,1605]],[[64585,64585],"mapped",[1605,1609]],[[64586,64586],"mapped",[1605,1610]],[[64587,64587],"mapped",[1606,1580]],[[64588,64588],"mapped",[1606,1581]],[[64589,64589],"mapped",[1606,1582]],[[64590,64590],"mapped",[1606,1605]],[[64591,64591],"mapped",[1606,1609]],[[64592,64592],"mapped",[1606,1610]],[[64593,64593],"mapped",[1607,1580]],[[64594,64594],"mapped",[1607,1605]],[[64595,64595],"mapped",[1607,1609]],[[64596,64596],"mapped",[1607,1610]],[[64597,64597],"mapped",[1610,1580]],[[64598,64598],"mapped",[1610,1581]],[[64599,64599],"mapped",[1610,1582]],[[64600,64600],"mapped",[1610,1605]],[[64601,64601],"mapped",[1610,1609]],[[64602,64602],"mapped",[1610,1610]],[[64603,64603],"mapped",[1584,1648]],[[64604,64604],"mapped",[1585,1648]],[[64605,64605],"mapped",[1609,1648]],[[64606,64606],"disallowed_STD3_mapped",[32,1612,1617]],[[64607,64607],"disallowed_STD3_mapped",[32,1613,1617]],[[64608,64608],"disallowed_STD3_mapped",[32,1614,1617]],[[64609,64609],"disallowed_STD3_mapped",[32,1615,1617]],[[64610,64610],"disallowed_STD3_mapped",[32,1616,1617]],[[64611,64611],"disallowed_STD3_mapped",[32,1617,1648]],[[64612,64612],"mapped",[1574,1585]],[[64613,64613],"mapped",[1574,1586]],[[64614,64614],"mapped",[1574,1605]],[[64615,64615],"mapped",[1574,1606]],[[64616,64616],"mapped",[1574,1609]],[[64617,64617],"mapped",[1574,1610]],[[64618,64618],"mapped",[1576,1585]],[[64619,64619],"mapped",[1576,1586]],[[64620,64620],"mapped",[1576,1605]],[[64621,64621],"mapped",[1576,1606]],[[64622,64622],"mapped",[1576,1609]],[[64623,64623],"mapped",[1576,1610]],[[64624,64624],"mapped",[1578,1585]],[[64625,64625],"mapped",[1578,1586]],[[64626,64626],"mapped",[1578,1605]],[[64627,64627],"mapped",[1578,1606]],[[64628,64628],"mapped",[1578,1609]],[[64629,64629],"mapped",[1578,1610]],[[64630,64630],"mapped",[1579,1585]],[[64631,64631],"mapped",[1579,1586]],[[64632,64632],"mapped",[1579,1605]],[[64633,64633],"mapped",[1579,1606]],[[64634,64634],"mapped",[1579,1609]],[[64635,64635],"mapped",[1579,1610]],[[64636,64636],"mapped",[1601,1609]],[[64637,64637],"mapped",[1601,1610]],[[64638,64638],"mapped",[1602,1609]],[[64639,64639],"mapped",[1602,1610]],[[64640,64640],"mapped",[1603,1575]],[[64641,64641],"mapped",[1603,1604]],[[64642,64642],"mapped",[1603,1605]],[[64643,64643],"mapped",[1603,1609]],[[64644,64644],"mapped",[1603,1610]],[[64645,64645],"mapped",[1604,1605]],[[64646,64646],"mapped",[1604,1609]],[[64647,64647],"mapped",[1604,1610]],[[64648,64648],"mapped",[1605,1575]],[[64649,64649],"mapped",[1605,1605]],[[64650,64650],"mapped",[1606,1585]],[[64651,64651],"mapped",[1606,1586]],[[64652,64652],"mapped",[1606,1605]],[[64653,64653],"mapped",[1606,1606]],[[64654,64654],"mapped",[1606,1609]],[[64655,64655],"mapped",[1606,1610]],[[64656,64656],"mapped",[1609,1648]],[[64657,64657],"mapped",[1610,1585]],[[64658,64658],"mapped",[1610,1586]],[[64659,64659],"mapped",[1610,1605]],[[64660,64660],"mapped",[1610,1606]],[[64661,64661],"mapped",[1610,1609]],[[64662,64662],"mapped",[1610,1610]],[[64663,64663],"mapped",[1574,1580]],[[64664,64664],"mapped",[1574,1581]],[[64665,64665],"mapped",[1574,1582]],[[64666,64666],"mapped",[1574,1605]],[[64667,64667],"mapped",[1574,1607]],[[64668,64668],"mapped",[1576,1580]],[[64669,64669],"mapped",[1576,1581]],[[64670,64670],"mapped",[1576,1582]],[[64671,64671],"mapped",[1576,1605]],[[64672,64672],"mapped",[1576,1607]],[[64673,64673],"mapped",[1578,1580]],[[64674,64674],"mapped",[1578,1581]],[[64675,64675],"mapped",[1578,1582]],[[64676,64676],"mapped",[1578,1605]],[[64677,64677],"mapped",[1578,1607]],[[64678,64678],"mapped",[1579,1605]],[[64679,64679],"mapped",[1580,1581]],[[64680,64680],"mapped",[1580,1605]],[[64681,64681],"mapped",[1581,1580]],[[64682,64682],"mapped",[1581,1605]],[[64683,64683],"mapped",[1582,1580]],[[64684,64684],"mapped",[1582,1605]],[[64685,64685],"mapped",[1587,1580]],[[64686,64686],"mapped",[1587,1581]],[[64687,64687],"mapped",[1587,1582]],[[64688,64688],"mapped",[1587,1605]],[[64689,64689],"mapped",[1589,1581]],[[64690,64690],"mapped",[1589,1582]],[[64691,64691],"mapped",[1589,1605]],[[64692,64692],"mapped",[1590,1580]],[[64693,64693],"mapped",[1590,1581]],[[64694,64694],"mapped",[1590,1582]],[[64695,64695],"mapped",[1590,1605]],[[64696,64696],"mapped",[1591,1581]],[[64697,64697],"mapped",[1592,1605]],[[64698,64698],"mapped",[1593,1580]],[[64699,64699],"mapped",[1593,1605]],[[64700,64700],"mapped",[1594,1580]],[[64701,64701],"mapped",[1594,1605]],[[64702,64702],"mapped",[1601,1580]],[[64703,64703],"mapped",[1601,1581]],[[64704,64704],"mapped",[1601,1582]],[[64705,64705],"mapped",[1601,1605]],[[64706,64706],"mapped",[1602,1581]],[[64707,64707],"mapped",[1602,1605]],[[64708,64708],"mapped",[1603,1580]],[[64709,64709],"mapped",[1603,1581]],[[64710,64710],"mapped",[1603,1582]],[[64711,64711],"mapped",[1603,1604]],[[64712,64712],"mapped",[1603,1605]],[[64713,64713],"mapped",[1604,1580]],[[64714,64714],"mapped",[1604,1581]],[[64715,64715],"mapped",[1604,1582]],[[64716,64716],"mapped",[1604,1605]],[[64717,64717],"mapped",[1604,1607]],[[64718,64718],"mapped",[1605,1580]],[[64719,64719],"mapped",[1605,1581]],[[64720,64720],"mapped",[1605,1582]],[[64721,64721],"mapped",[1605,1605]],[[64722,64722],"mapped",[1606,1580]],[[64723,64723],"mapped",[1606,1581]],[[64724,64724],"mapped",[1606,1582]],[[64725,64725],"mapped",[1606,1605]],[[64726,64726],"mapped",[1606,1607]],[[64727,64727],"mapped",[1607,1580]],[[64728,64728],"mapped",[1607,1605]],[[64729,64729],"mapped",[1607,1648]],[[64730,64730],"mapped",[1610,1580]],[[64731,64731],"mapped",[1610,1581]],[[64732,64732],"mapped",[1610,1582]],[[64733,64733],"mapped",[1610,1605]],[[64734,64734],"mapped",[1610,1607]],[[64735,64735],"mapped",[1574,1605]],[[64736,64736],"mapped",[1574,1607]],[[64737,64737],"mapped",[1576,1605]],[[64738,64738],"mapped",[1576,1607]],[[64739,64739],"mapped",[1578,1605]],[[64740,64740],"mapped",[1578,1607]],[[64741,64741],"mapped",[1579,1605]],[[64742,64742],"mapped",[1579,1607]],[[64743,64743],"mapped",[1587,1605]],[[64744,64744],"mapped",[1587,1607]],[[64745,64745],"mapped",[1588,1605]],[[64746,64746],"mapped",[1588,1607]],[[64747,64747],"mapped",[1603,1604]],[[64748,64748],"mapped",[1603,1605]],[[64749,64749],"mapped",[1604,1605]],[[64750,64750],"mapped",[1606,1605]],[[64751,64751],"mapped",[1606,1607]],[[64752,64752],"mapped",[1610,1605]],[[64753,64753],"mapped",[1610,1607]],[[64754,64754],"mapped",[1600,1614,1617]],[[64755,64755],"mapped",[1600,1615,1617]],[[64756,64756],"mapped",[1600,1616,1617]],[[64757,64757],"mapped",[1591,1609]],[[64758,64758],"mapped",[1591,1610]],[[64759,64759],"mapped",[1593,1609]],[[64760,64760],"mapped",[1593,1610]],[[64761,64761],"mapped",[1594,1609]],[[64762,64762],"mapped",[1594,1610]],[[64763,64763],"mapped",[1587,1609]],[[64764,64764],"mapped",[1587,1610]],[[64765,64765],"mapped",[1588,1609]],[[64766,64766],"mapped",[1588,1610]],[[64767,64767],"mapped",[1581,1609]],[[64768,64768],"mapped",[1581,1610]],[[64769,64769],"mapped",[1580,1609]],[[64770,64770],"mapped",[1580,1610]],[[64771,64771],"mapped",[1582,1609]],[[64772,64772],"mapped",[1582,1610]],[[64773,64773],"mapped",[1589,1609]],[[64774,64774],"mapped",[1589,1610]],[[64775,64775],"mapped",[1590,1609]],[[64776,64776],"mapped",[1590,1610]],[[64777,64777],"mapped",[1588,1580]],[[64778,64778],"mapped",[1588,1581]],[[64779,64779],"mapped",[1588,1582]],[[64780,64780],"mapped",[1588,1605]],[[64781,64781],"mapped",[1588,1585]],[[64782,64782],"mapped",[1587,1585]],[[64783,64783],"mapped",[1589,1585]],[[64784,64784],"mapped",[1590,1585]],[[64785,64785],"mapped",[1591,1609]],[[64786,64786],"mapped",[1591,1610]],[[64787,64787],"mapped",[1593,1609]],[[64788,64788],"mapped",[1593,1610]],[[64789,64789],"mapped",[1594,1609]],[[64790,64790],"mapped",[1594,1610]],[[64791,64791],"mapped",[1587,1609]],[[64792,64792],"mapped",[1587,1610]],[[64793,64793],"mapped",[1588,1609]],[[64794,64794],"mapped",[1588,1610]],[[64795,64795],"mapped",[1581,1609]],[[64796,64796],"mapped",[1581,1610]],[[64797,64797],"mapped",[1580,1609]],[[64798,64798],"mapped",[1580,1610]],[[64799,64799],"mapped",[1582,1609]],[[64800,64800],"mapped",[1582,1610]],[[64801,64801],"mapped",[1589,1609]],[[64802,64802],"mapped",[1589,1610]],[[64803,64803],"mapped",[1590,1609]],[[64804,64804],"mapped",[1590,1610]],[[64805,64805],"mapped",[1588,1580]],[[64806,64806],"mapped",[1588,1581]],[[64807,64807],"mapped",[1588,1582]],[[64808,64808],"mapped",[1588,1605]],[[64809,64809],"mapped",[1588,1585]],[[64810,64810],"mapped",[1587,1585]],[[64811,64811],"mapped",[1589,1585]],[[64812,64812],"mapped",[1590,1585]],[[64813,64813],"mapped",[1588,1580]],[[64814,64814],"mapped",[1588,1581]],[[64815,64815],"mapped",[1588,1582]],[[64816,64816],"mapped",[1588,1605]],[[64817,64817],"mapped",[1587,1607]],[[64818,64818],"mapped",[1588,1607]],[[64819,64819],"mapped",[1591,1605]],[[64820,64820],"mapped",[1587,1580]],[[64821,64821],"mapped",[1587,1581]],[[64822,64822],"mapped",[1587,1582]],[[64823,64823],"mapped",[1588,1580]],[[64824,64824],"mapped",[1588,1581]],[[64825,64825],"mapped",[1588,1582]],[[64826,64826],"mapped",[1591,1605]],[[64827,64827],"mapped",[1592,1605]],[[64828,64829],"mapped",[1575,1611]],[[64830,64831],"valid",[],"NV8"],[[64832,64847],"disallowed"],[[64848,64848],"mapped",[1578,1580,1605]],[[64849,64850],"mapped",[1578,1581,1580]],[[64851,64851],"mapped",[1578,1581,1605]],[[64852,64852],"mapped",[1578,1582,1605]],[[64853,64853],"mapped",[1578,1605,1580]],[[64854,64854],"mapped",[1578,1605,1581]],[[64855,64855],"mapped",[1578,1605,1582]],[[64856,64857],"mapped",[1580,1605,1581]],[[64858,64858],"mapped",[1581,1605,1610]],[[64859,64859],"mapped",[1581,1605,1609]],[[64860,64860],"mapped",[1587,1581,1580]],[[64861,64861],"mapped",[1587,1580,1581]],[[64862,64862],"mapped",[1587,1580,1609]],[[64863,64864],"mapped",[1587,1605,1581]],[[64865,64865],"mapped",[1587,1605,1580]],[[64866,64867],"mapped",[1587,1605,1605]],[[64868,64869],"mapped",[1589,1581,1581]],[[64870,64870],"mapped",[1589,1605,1605]],[[64871,64872],"mapped",[1588,1581,1605]],[[64873,64873],"mapped",[1588,1580,1610]],[[64874,64875],"mapped",[1588,1605,1582]],[[64876,64877],"mapped",[1588,1605,1605]],[[64878,64878],"mapped",[1590,1581,1609]],[[64879,64880],"mapped",[1590,1582,1605]],[[64881,64882],"mapped",[1591,1605,1581]],[[64883,64883],"mapped",[1591,1605,1605]],[[64884,64884],"mapped",[1591,1605,1610]],[[64885,64885],"mapped",[1593,1580,1605]],[[64886,64887],"mapped",[1593,1605,1605]],[[64888,64888],"mapped",[1593,1605,1609]],[[64889,64889],"mapped",[1594,1605,1605]],[[64890,64890],"mapped",[1594,1605,1610]],[[64891,64891],"mapped",[1594,1605,1609]],[[64892,64893],"mapped",[1601,1582,1605]],[[64894,64894],"mapped",[1602,1605,1581]],[[64895,64895],"mapped",[1602,1605,1605]],[[64896,64896],"mapped",[1604,1581,1605]],[[64897,64897],"mapped",[1604,1581,1610]],[[64898,64898],"mapped",[1604,1581,1609]],[[64899,64900],"mapped",[1604,1580,1580]],[[64901,64902],"mapped",[1604,1582,1605]],[[64903,64904],"mapped",[1604,1605,1581]],[[64905,64905],"mapped",[1605,1581,1580]],[[64906,64906],"mapped",[1605,1581,1605]],[[64907,64907],"mapped",[1605,1581,1610]],[[64908,64908],"mapped",[1605,1580,1581]],[[64909,64909],"mapped",[1605,1580,1605]],[[64910,64910],"mapped",[1605,1582,1580]],[[64911,64911],"mapped",[1605,1582,1605]],[[64912,64913],"disallowed"],[[64914,64914],"mapped",[1605,1580,1582]],[[64915,64915],"mapped",[1607,1605,1580]],[[64916,64916],"mapped",[1607,1605,1605]],[[64917,64917],"mapped",[1606,1581,1605]],[[64918,64918],"mapped",[1606,1581,1609]],[[64919,64920],"mapped",[1606,1580,1605]],[[64921,64921],"mapped",[1606,1580,1609]],[[64922,64922],"mapped",[1606,1605,1610]],[[64923,64923],"mapped",[1606,1605,1609]],[[64924,64925],"mapped",[1610,1605,1605]],[[64926,64926],"mapped",[1576,1582,1610]],[[64927,64927],"mapped",[1578,1580,1610]],[[64928,64928],"mapped",[1578,1580,1609]],[[64929,64929],"mapped",[1578,1582,1610]],[[64930,64930],"mapped",[1578,1582,1609]],[[64931,64931],"mapped",[1578,1605,1610]],[[64932,64932],"mapped",[1578,1605,1609]],[[64933,64933],"mapped",[1580,1605,1610]],[[64934,64934],"mapped",[1580,1581,1609]],[[64935,64935],"mapped",[1580,1605,1609]],[[64936,64936],"mapped",[1587,1582,1609]],[[64937,64937],"mapped",[1589,1581,1610]],[[64938,64938],"mapped",[1588,1581,1610]],[[64939,64939],"mapped",[1590,1581,1610]],[[64940,64940],"mapped",[1604,1580,1610]],[[64941,64941],"mapped",[1604,1605,1610]],[[64942,64942],"mapped",[1610,1581,1610]],[[64943,64943],"mapped",[1610,1580,1610]],[[64944,64944],"mapped",[1610,1605,1610]],[[64945,64945],"mapped",[1605,1605,1610]],[[64946,64946],"mapped",[1602,1605,1610]],[[64947,64947],"mapped",[1606,1581,1610]],[[64948,64948],"mapped",[1602,1605,1581]],[[64949,64949],"mapped",[1604,1581,1605]],[[64950,64950],"mapped",[1593,1605,1610]],[[64951,64951],"mapped",[1603,1605,1610]],[[64952,64952],"mapped",[1606,1580,1581]],[[64953,64953],"mapped",[1605,1582,1610]],[[64954,64954],"mapped",[1604,1580,1605]],[[64955,64955],"mapped",[1603,1605,1605]],[[64956,64956],"mapped",[1604,1580,1605]],[[64957,64957],"mapped",[1606,1580,1581]],[[64958,64958],"mapped",[1580,1581,1610]],[[64959,64959],"mapped",[1581,1580,1610]],[[64960,64960],"mapped",[1605,1580,1610]],[[64961,64961],"mapped",[1601,1605,1610]],[[64962,64962],"mapped",[1576,1581,1610]],[[64963,64963],"mapped",[1603,1605,1605]],[[64964,64964],"mapped",[1593,1580,1605]],[[64965,64965],"mapped",[1589,1605,1605]],[[64966,64966],"mapped",[1587,1582,1610]],[[64967,64967],"mapped",[1606,1580,1610]],[[64968,64975],"disallowed"],[[64976,65007],"disallowed"],[[65008,65008],"mapped",[1589,1604,1746]],[[65009,65009],"mapped",[1602,1604,1746]],[[65010,65010],"mapped",[1575,1604,1604,1607]],[[65011,65011],"mapped",[1575,1603,1576,1585]],[[65012,65012],"mapped",[1605,1581,1605,1583]],[[65013,65013],"mapped",[1589,1604,1593,1605]],[[65014,65014],"mapped",[1585,1587,1608,1604]],[[65015,65015],"mapped",[1593,1604,1610,1607]],[[65016,65016],"mapped",[1608,1587,1604,1605]],[[65017,65017],"mapped",[1589,1604,1609]],[[65018,65018],"disallowed_STD3_mapped",[1589,1604,1609,32,1575,1604,1604,1607,32,1593,1604,1610,1607,32,1608,1587,1604,1605]],[[65019,65019],"disallowed_STD3_mapped",[1580,1604,32,1580,1604,1575,1604,1607]],[[65020,65020],"mapped",[1585,1740,1575,1604]],[[65021,65021],"valid",[],"NV8"],[[65022,65023],"disallowed"],[[65024,65039],"ignored"],[[65040,65040],"disallowed_STD3_mapped",[44]],[[65041,65041],"mapped",[12289]],[[65042,65042],"disallowed"],[[65043,65043],"disallowed_STD3_mapped",[58]],[[65044,65044],"disallowed_STD3_mapped",[59]],[[65045,65045],"disallowed_STD3_mapped",[33]],[[65046,65046],"disallowed_STD3_mapped",[63]],[[65047,65047],"mapped",[12310]],[[65048,65048],"mapped",[12311]],[[65049,65049],"disallowed"],[[65050,65055],"disallowed"],[[65056,65059],"valid"],[[65060,65062],"valid"],[[65063,65069],"valid"],[[65070,65071],"valid"],[[65072,65072],"disallowed"],[[65073,65073],"mapped",[8212]],[[65074,65074],"mapped",[8211]],[[65075,65076],"disallowed_STD3_mapped",[95]],[[65077,65077],"disallowed_STD3_mapped",[40]],[[65078,65078],"disallowed_STD3_mapped",[41]],[[65079,65079],"disallowed_STD3_mapped",[123]],[[65080,65080],"disallowed_STD3_mapped",[125]],[[65081,65081],"mapped",[12308]],[[65082,65082],"mapped",[12309]],[[65083,65083],"mapped",[12304]],[[65084,65084],"mapped",[12305]],[[65085,65085],"mapped",[12298]],[[65086,65086],"mapped",[12299]],[[65087,65087],"mapped",[12296]],[[65088,65088],"mapped",[12297]],[[65089,65089],"mapped",[12300]],[[65090,65090],"mapped",[12301]],[[65091,65091],"mapped",[12302]],[[65092,65092],"mapped",[12303]],[[65093,65094],"valid",[],"NV8"],[[65095,65095],"disallowed_STD3_mapped",[91]],[[65096,65096],"disallowed_STD3_mapped",[93]],[[65097,65100],"disallowed_STD3_mapped",[32,773]],[[65101,65103],"disallowed_STD3_mapped",[95]],[[65104,65104],"disallowed_STD3_mapped",[44]],[[65105,65105],"mapped",[12289]],[[65106,65106],"disallowed"],[[65107,65107],"disallowed"],[[65108,65108],"disallowed_STD3_mapped",[59]],[[65109,65109],"disallowed_STD3_mapped",[58]],[[65110,65110],"disallowed_STD3_mapped",[63]],[[65111,65111],"disallowed_STD3_mapped",[33]],[[65112,65112],"mapped",[8212]],[[65113,65113],"disallowed_STD3_mapped",[40]],[[65114,65114],"disallowed_STD3_mapped",[41]],[[65115,65115],"disallowed_STD3_mapped",[123]],[[65116,65116],"disallowed_STD3_mapped",[125]],[[65117,65117],"mapped",[12308]],[[65118,65118],"mapped",[12309]],[[65119,65119],"disallowed_STD3_mapped",[35]],[[65120,65120],"disallowed_STD3_mapped",[38]],[[65121,65121],"disallowed_STD3_mapped",[42]],[[65122,65122],"disallowed_STD3_mapped",[43]],[[65123,65123],"mapped",[45]],[[65124,65124],"disallowed_STD3_mapped",[60]],[[65125,65125],"disallowed_STD3_mapped",[62]],[[65126,65126],"disallowed_STD3_mapped",[61]],[[65127,65127],"disallowed"],[[65128,65128],"disallowed_STD3_mapped",[92]],[[65129,65129],"disallowed_STD3_mapped",[36]],[[65130,65130],"disallowed_STD3_mapped",[37]],[[65131,65131],"disallowed_STD3_mapped",[64]],[[65132,65135],"disallowed"],[[65136,65136],"disallowed_STD3_mapped",[32,1611]],[[65137,65137],"mapped",[1600,1611]],[[65138,65138],"disallowed_STD3_mapped",[32,1612]],[[65139,65139],"valid"],[[65140,65140],"disallowed_STD3_mapped",[32,1613]],[[65141,65141],"disallowed"],[[65142,65142],"disallowed_STD3_mapped",[32,1614]],[[65143,65143],"mapped",[1600,1614]],[[65144,65144],"disallowed_STD3_mapped",[32,1615]],[[65145,65145],"mapped",[1600,1615]],[[65146,65146],"disallowed_STD3_mapped",[32,1616]],[[65147,65147],"mapped",[1600,1616]],[[65148,65148],"disallowed_STD3_mapped",[32,1617]],[[65149,65149],"mapped",[1600,1617]],[[65150,65150],"disallowed_STD3_mapped",[32,1618]],[[65151,65151],"mapped",[1600,1618]],[[65152,65152],"mapped",[1569]],[[65153,65154],"mapped",[1570]],[[65155,65156],"mapped",[1571]],[[65157,65158],"mapped",[1572]],[[65159,65160],"mapped",[1573]],[[65161,65164],"mapped",[1574]],[[65165,65166],"mapped",[1575]],[[65167,65170],"mapped",[1576]],[[65171,65172],"mapped",[1577]],[[65173,65176],"mapped",[1578]],[[65177,65180],"mapped",[1579]],[[65181,65184],"mapped",[1580]],[[65185,65188],"mapped",[1581]],[[65189,65192],"mapped",[1582]],[[65193,65194],"mapped",[1583]],[[65195,65196],"mapped",[1584]],[[65197,65198],"mapped",[1585]],[[65199,65200],"mapped",[1586]],[[65201,65204],"mapped",[1587]],[[65205,65208],"mapped",[1588]],[[65209,65212],"mapped",[1589]],[[65213,65216],"mapped",[1590]],[[65217,65220],"mapped",[1591]],[[65221,65224],"mapped",[1592]],[[65225,65228],"mapped",[1593]],[[65229,65232],"mapped",[1594]],[[65233,65236],"mapped",[1601]],[[65237,65240],"mapped",[1602]],[[65241,65244],"mapped",[1603]],[[65245,65248],"mapped",[1604]],[[65249,65252],"mapped",[1605]],[[65253,65256],"mapped",[1606]],[[65257,65260],"mapped",[1607]],[[65261,65262],"mapped",[1608]],[[65263,65264],"mapped",[1609]],[[65265,65268],"mapped",[1610]],[[65269,65270],"mapped",[1604,1570]],[[65271,65272],"mapped",[1604,1571]],[[65273,65274],"mapped",[1604,1573]],[[65275,65276],"mapped",[1604,1575]],[[65277,65278],"disallowed"],[[65279,65279],"ignored"],[[65280,65280],"disallowed"],[[65281,65281],"disallowed_STD3_mapped",[33]],[[65282,65282],"disallowed_STD3_mapped",[34]],[[65283,65283],"disallowed_STD3_mapped",[35]],[[65284,65284],"disallowed_STD3_mapped",[36]],[[65285,65285],"disallowed_STD3_mapped",[37]],[[65286,65286],"disallowed_STD3_mapped",[38]],[[65287,65287],"disallowed_STD3_mapped",[39]],[[65288,65288],"disallowed_STD3_mapped",[40]],[[65289,65289],"disallowed_STD3_mapped",[41]],[[65290,65290],"disallowed_STD3_mapped",[42]],[[65291,65291],"disallowed_STD3_mapped",[43]],[[65292,65292],"disallowed_STD3_mapped",[44]],[[65293,65293],"mapped",[45]],[[65294,65294],"mapped",[46]],[[65295,65295],"disallowed_STD3_mapped",[47]],[[65296,65296],"mapped",[48]],[[65297,65297],"mapped",[49]],[[65298,65298],"mapped",[50]],[[65299,65299],"mapped",[51]],[[65300,65300],"mapped",[52]],[[65301,65301],"mapped",[53]],[[65302,65302],"mapped",[54]],[[65303,65303],"mapped",[55]],[[65304,65304],"mapped",[56]],[[65305,65305],"mapped",[57]],[[65306,65306],"disallowed_STD3_mapped",[58]],[[65307,65307],"disallowed_STD3_mapped",[59]],[[65308,65308],"disallowed_STD3_mapped",[60]],[[65309,65309],"disallowed_STD3_mapped",[61]],[[65310,65310],"disallowed_STD3_mapped",[62]],[[65311,65311],"disallowed_STD3_mapped",[63]],[[65312,65312],"disallowed_STD3_mapped",[64]],[[65313,65313],"mapped",[97]],[[65314,65314],"mapped",[98]],[[65315,65315],"mapped",[99]],[[65316,65316],"mapped",[100]],[[65317,65317],"mapped",[101]],[[65318,65318],"mapped",[102]],[[65319,65319],"mapped",[103]],[[65320,65320],"mapped",[104]],[[65321,65321],"mapped",[105]],[[65322,65322],"mapped",[106]],[[65323,65323],"mapped",[107]],[[65324,65324],"mapped",[108]],[[65325,65325],"mapped",[109]],[[65326,65326],"mapped",[110]],[[65327,65327],"mapped",[111]],[[65328,65328],"mapped",[112]],[[65329,65329],"mapped",[113]],[[65330,65330],"mapped",[114]],[[65331,65331],"mapped",[115]],[[65332,65332],"mapped",[116]],[[65333,65333],"mapped",[117]],[[65334,65334],"mapped",[118]],[[65335,65335],"mapped",[119]],[[65336,65336],"mapped",[120]],[[65337,65337],"mapped",[121]],[[65338,65338],"mapped",[122]],[[65339,65339],"disallowed_STD3_mapped",[91]],[[65340,65340],"disallowed_STD3_mapped",[92]],[[65341,65341],"disallowed_STD3_mapped",[93]],[[65342,65342],"disallowed_STD3_mapped",[94]],[[65343,65343],"disallowed_STD3_mapped",[95]],[[65344,65344],"disallowed_STD3_mapped",[96]],[[65345,65345],"mapped",[97]],[[65346,65346],"mapped",[98]],[[65347,65347],"mapped",[99]],[[65348,65348],"mapped",[100]],[[65349,65349],"mapped",[101]],[[65350,65350],"mapped",[102]],[[65351,65351],"mapped",[103]],[[65352,65352],"mapped",[104]],[[65353,65353],"mapped",[105]],[[65354,65354],"mapped",[106]],[[65355,65355],"mapped",[107]],[[65356,65356],"mapped",[108]],[[65357,65357],"mapped",[109]],[[65358,65358],"mapped",[110]],[[65359,65359],"mapped",[111]],[[65360,65360],"mapped",[112]],[[65361,65361],"mapped",[113]],[[65362,65362],"mapped",[114]],[[65363,65363],"mapped",[115]],[[65364,65364],"mapped",[116]],[[65365,65365],"mapped",[117]],[[65366,65366],"mapped",[118]],[[65367,65367],"mapped",[119]],[[65368,65368],"mapped",[120]],[[65369,65369],"mapped",[121]],[[65370,65370],"mapped",[122]],[[65371,65371],"disallowed_STD3_mapped",[123]],[[65372,65372],"disallowed_STD3_mapped",[124]],[[65373,65373],"disallowed_STD3_mapped",[125]],[[65374,65374],"disallowed_STD3_mapped",[126]],[[65375,65375],"mapped",[10629]],[[65376,65376],"mapped",[10630]],[[65377,65377],"mapped",[46]],[[65378,65378],"mapped",[12300]],[[65379,65379],"mapped",[12301]],[[65380,65380],"mapped",[12289]],[[65381,65381],"mapped",[12539]],[[65382,65382],"mapped",[12530]],[[65383,65383],"mapped",[12449]],[[65384,65384],"mapped",[12451]],[[65385,65385],"mapped",[12453]],[[65386,65386],"mapped",[12455]],[[65387,65387],"mapped",[12457]],[[65388,65388],"mapped",[12515]],[[65389,65389],"mapped",[12517]],[[65390,65390],"mapped",[12519]],[[65391,65391],"mapped",[12483]],[[65392,65392],"mapped",[12540]],[[65393,65393],"mapped",[12450]],[[65394,65394],"mapped",[12452]],[[65395,65395],"mapped",[12454]],[[65396,65396],"mapped",[12456]],[[65397,65397],"mapped",[12458]],[[65398,65398],"mapped",[12459]],[[65399,65399],"mapped",[12461]],[[65400,65400],"mapped",[12463]],[[65401,65401],"mapped",[12465]],[[65402,65402],"mapped",[12467]],[[65403,65403],"mapped",[12469]],[[65404,65404],"mapped",[12471]],[[65405,65405],"mapped",[12473]],[[65406,65406],"mapped",[12475]],[[65407,65407],"mapped",[12477]],[[65408,65408],"mapped",[12479]],[[65409,65409],"mapped",[12481]],[[65410,65410],"mapped",[12484]],[[65411,65411],"mapped",[12486]],[[65412,65412],"mapped",[12488]],[[65413,65413],"mapped",[12490]],[[65414,65414],"mapped",[12491]],[[65415,65415],"mapped",[12492]],[[65416,65416],"mapped",[12493]],[[65417,65417],"mapped",[12494]],[[65418,65418],"mapped",[12495]],[[65419,65419],"mapped",[12498]],[[65420,65420],"mapped",[12501]],[[65421,65421],"mapped",[12504]],[[65422,65422],"mapped",[12507]],[[65423,65423],"mapped",[12510]],[[65424,65424],"mapped",[12511]],[[65425,65425],"mapped",[12512]],[[65426,65426],"mapped",[12513]],[[65427,65427],"mapped",[12514]],[[65428,65428],"mapped",[12516]],[[65429,65429],"mapped",[12518]],[[65430,65430],"mapped",[12520]],[[65431,65431],"mapped",[12521]],[[65432,65432],"mapped",[12522]],[[65433,65433],"mapped",[12523]],[[65434,65434],"mapped",[12524]],[[65435,65435],"mapped",[12525]],[[65436,65436],"mapped",[12527]],[[65437,65437],"mapped",[12531]],[[65438,65438],"mapped",[12441]],[[65439,65439],"mapped",[12442]],[[65440,65440],"disallowed"],[[65441,65441],"mapped",[4352]],[[65442,65442],"mapped",[4353]],[[65443,65443],"mapped",[4522]],[[65444,65444],"mapped",[4354]],[[65445,65445],"mapped",[4524]],[[65446,65446],"mapped",[4525]],[[65447,65447],"mapped",[4355]],[[65448,65448],"mapped",[4356]],[[65449,65449],"mapped",[4357]],[[65450,65450],"mapped",[4528]],[[65451,65451],"mapped",[4529]],[[65452,65452],"mapped",[4530]],[[65453,65453],"mapped",[4531]],[[65454,65454],"mapped",[4532]],[[65455,65455],"mapped",[4533]],[[65456,65456],"mapped",[4378]],[[65457,65457],"mapped",[4358]],[[65458,65458],"mapped",[4359]],[[65459,65459],"mapped",[4360]],[[65460,65460],"mapped",[4385]],[[65461,65461],"mapped",[4361]],[[65462,65462],"mapped",[4362]],[[65463,65463],"mapped",[4363]],[[65464,65464],"mapped",[4364]],[[65465,65465],"mapped",[4365]],[[65466,65466],"mapped",[4366]],[[65467,65467],"mapped",[4367]],[[65468,65468],"mapped",[4368]],[[65469,65469],"mapped",[4369]],[[65470,65470],"mapped",[4370]],[[65471,65473],"disallowed"],[[65474,65474],"mapped",[4449]],[[65475,65475],"mapped",[4450]],[[65476,65476],"mapped",[4451]],[[65477,65477],"mapped",[4452]],[[65478,65478],"mapped",[4453]],[[65479,65479],"mapped",[4454]],[[65480,65481],"disallowed"],[[65482,65482],"mapped",[4455]],[[65483,65483],"mapped",[4456]],[[65484,65484],"mapped",[4457]],[[65485,65485],"mapped",[4458]],[[65486,65486],"mapped",[4459]],[[65487,65487],"mapped",[4460]],[[65488,65489],"disallowed"],[[65490,65490],"mapped",[4461]],[[65491,65491],"mapped",[4462]],[[65492,65492],"mapped",[4463]],[[65493,65493],"mapped",[4464]],[[65494,65494],"mapped",[4465]],[[65495,65495],"mapped",[4466]],[[65496,65497],"disallowed"],[[65498,65498],"mapped",[4467]],[[65499,65499],"mapped",[4468]],[[65500,65500],"mapped",[4469]],[[65501,65503],"disallowed"],[[65504,65504],"mapped",[162]],[[65505,65505],"mapped",[163]],[[65506,65506],"mapped",[172]],[[65507,65507],"disallowed_STD3_mapped",[32,772]],[[65508,65508],"mapped",[166]],[[65509,65509],"mapped",[165]],[[65510,65510],"mapped",[8361]],[[65511,65511],"disallowed"],[[65512,65512],"mapped",[9474]],[[65513,65513],"mapped",[8592]],[[65514,65514],"mapped",[8593]],[[65515,65515],"mapped",[8594]],[[65516,65516],"mapped",[8595]],[[65517,65517],"mapped",[9632]],[[65518,65518],"mapped",[9675]],[[65519,65528],"disallowed"],[[65529,65531],"disallowed"],[[65532,65532],"disallowed"],[[65533,65533],"disallowed"],[[65534,65535],"disallowed"],[[65536,65547],"valid"],[[65548,65548],"disallowed"],[[65549,65574],"valid"],[[65575,65575],"disallowed"],[[65576,65594],"valid"],[[65595,65595],"disallowed"],[[65596,65597],"valid"],[[65598,65598],"disallowed"],[[65599,65613],"valid"],[[65614,65615],"disallowed"],[[65616,65629],"valid"],[[65630,65663],"disallowed"],[[65664,65786],"valid"],[[65787,65791],"disallowed"],[[65792,65794],"valid",[],"NV8"],[[65795,65798],"disallowed"],[[65799,65843],"valid",[],"NV8"],[[65844,65846],"disallowed"],[[65847,65855],"valid",[],"NV8"],[[65856,65930],"valid",[],"NV8"],[[65931,65932],"valid",[],"NV8"],[[65933,65935],"disallowed"],[[65936,65947],"valid",[],"NV8"],[[65948,65951],"disallowed"],[[65952,65952],"valid",[],"NV8"],[[65953,65999],"disallowed"],[[66000,66044],"valid",[],"NV8"],[[66045,66045],"valid"],[[66046,66175],"disallowed"],[[66176,66204],"valid"],[[66205,66207],"disallowed"],[[66208,66256],"valid"],[[66257,66271],"disallowed"],[[66272,66272],"valid"],[[66273,66299],"valid",[],"NV8"],[[66300,66303],"disallowed"],[[66304,66334],"valid"],[[66335,66335],"valid"],[[66336,66339],"valid",[],"NV8"],[[66340,66351],"disallowed"],[[66352,66368],"valid"],[[66369,66369],"valid",[],"NV8"],[[66370,66377],"valid"],[[66378,66378],"valid",[],"NV8"],[[66379,66383],"disallowed"],[[66384,66426],"valid"],[[66427,66431],"disallowed"],[[66432,66461],"valid"],[[66462,66462],"disallowed"],[[66463,66463],"valid",[],"NV8"],[[66464,66499],"valid"],[[66500,66503],"disallowed"],[[66504,66511],"valid"],[[66512,66517],"valid",[],"NV8"],[[66518,66559],"disallowed"],[[66560,66560],"mapped",[66600]],[[66561,66561],"mapped",[66601]],[[66562,66562],"mapped",[66602]],[[66563,66563],"mapped",[66603]],[[66564,66564],"mapped",[66604]],[[66565,66565],"mapped",[66605]],[[66566,66566],"mapped",[66606]],[[66567,66567],"mapped",[66607]],[[66568,66568],"mapped",[66608]],[[66569,66569],"mapped",[66609]],[[66570,66570],"mapped",[66610]],[[66571,66571],"mapped",[66611]],[[66572,66572],"mapped",[66612]],[[66573,66573],"mapped",[66613]],[[66574,66574],"mapped",[66614]],[[66575,66575],"mapped",[66615]],[[66576,66576],"mapped",[66616]],[[66577,66577],"mapped",[66617]],[[66578,66578],"mapped",[66618]],[[66579,66579],"mapped",[66619]],[[66580,66580],"mapped",[66620]],[[66581,66581],"mapped",[66621]],[[66582,66582],"mapped",[66622]],[[66583,66583],"mapped",[66623]],[[66584,66584],"mapped",[66624]],[[66585,66585],"mapped",[66625]],[[66586,66586],"mapped",[66626]],[[66587,66587],"mapped",[66627]],[[66588,66588],"mapped",[66628]],[[66589,66589],"mapped",[66629]],[[66590,66590],"mapped",[66630]],[[66591,66591],"mapped",[66631]],[[66592,66592],"mapped",[66632]],[[66593,66593],"mapped",[66633]],[[66594,66594],"mapped",[66634]],[[66595,66595],"mapped",[66635]],[[66596,66596],"mapped",[66636]],[[66597,66597],"mapped",[66637]],[[66598,66598],"mapped",[66638]],[[66599,66599],"mapped",[66639]],[[66600,66637],"valid"],[[66638,66717],"valid"],[[66718,66719],"disallowed"],[[66720,66729],"valid"],[[66730,66815],"disallowed"],[[66816,66855],"valid"],[[66856,66863],"disallowed"],[[66864,66915],"valid"],[[66916,66926],"disallowed"],[[66927,66927],"valid",[],"NV8"],[[66928,67071],"disallowed"],[[67072,67382],"valid"],[[67383,67391],"disallowed"],[[67392,67413],"valid"],[[67414,67423],"disallowed"],[[67424,67431],"valid"],[[67432,67583],"disallowed"],[[67584,67589],"valid"],[[67590,67591],"disallowed"],[[67592,67592],"valid"],[[67593,67593],"disallowed"],[[67594,67637],"valid"],[[67638,67638],"disallowed"],[[67639,67640],"valid"],[[67641,67643],"disallowed"],[[67644,67644],"valid"],[[67645,67646],"disallowed"],[[67647,67647],"valid"],[[67648,67669],"valid"],[[67670,67670],"disallowed"],[[67671,67679],"valid",[],"NV8"],[[67680,67702],"valid"],[[67703,67711],"valid",[],"NV8"],[[67712,67742],"valid"],[[67743,67750],"disallowed"],[[67751,67759],"valid",[],"NV8"],[[67760,67807],"disallowed"],[[67808,67826],"valid"],[[67827,67827],"disallowed"],[[67828,67829],"valid"],[[67830,67834],"disallowed"],[[67835,67839],"valid",[],"NV8"],[[67840,67861],"valid"],[[67862,67865],"valid",[],"NV8"],[[67866,67867],"valid",[],"NV8"],[[67868,67870],"disallowed"],[[67871,67871],"valid",[],"NV8"],[[67872,67897],"valid"],[[67898,67902],"disallowed"],[[67903,67903],"valid",[],"NV8"],[[67904,67967],"disallowed"],[[67968,68023],"valid"],[[68024,68027],"disallowed"],[[68028,68029],"valid",[],"NV8"],[[68030,68031],"valid"],[[68032,68047],"valid",[],"NV8"],[[68048,68049],"disallowed"],[[68050,68095],"valid",[],"NV8"],[[68096,68099],"valid"],[[68100,68100],"disallowed"],[[68101,68102],"valid"],[[68103,68107],"disallowed"],[[68108,68115],"valid"],[[68116,68116],"disallowed"],[[68117,68119],"valid"],[[68120,68120],"disallowed"],[[68121,68147],"valid"],[[68148,68151],"disallowed"],[[68152,68154],"valid"],[[68155,68158],"disallowed"],[[68159,68159],"valid"],[[68160,68167],"valid",[],"NV8"],[[68168,68175],"disallowed"],[[68176,68184],"valid",[],"NV8"],[[68185,68191],"disallowed"],[[68192,68220],"valid"],[[68221,68223],"valid",[],"NV8"],[[68224,68252],"valid"],[[68253,68255],"valid",[],"NV8"],[[68256,68287],"disallowed"],[[68288,68295],"valid"],[[68296,68296],"valid",[],"NV8"],[[68297,68326],"valid"],[[68327,68330],"disallowed"],[[68331,68342],"valid",[],"NV8"],[[68343,68351],"disallowed"],[[68352,68405],"valid"],[[68406,68408],"disallowed"],[[68409,68415],"valid",[],"NV8"],[[68416,68437],"valid"],[[68438,68439],"disallowed"],[[68440,68447],"valid",[],"NV8"],[[68448,68466],"valid"],[[68467,68471],"disallowed"],[[68472,68479],"valid",[],"NV8"],[[68480,68497],"valid"],[[68498,68504],"disallowed"],[[68505,68508],"valid",[],"NV8"],[[68509,68520],"disallowed"],[[68521,68527],"valid",[],"NV8"],[[68528,68607],"disallowed"],[[68608,68680],"valid"],[[68681,68735],"disallowed"],[[68736,68736],"mapped",[68800]],[[68737,68737],"mapped",[68801]],[[68738,68738],"mapped",[68802]],[[68739,68739],"mapped",[68803]],[[68740,68740],"mapped",[68804]],[[68741,68741],"mapped",[68805]],[[68742,68742],"mapped",[68806]],[[68743,68743],"mapped",[68807]],[[68744,68744],"mapped",[68808]],[[68745,68745],"mapped",[68809]],[[68746,68746],"mapped",[68810]],[[68747,68747],"mapped",[68811]],[[68748,68748],"mapped",[68812]],[[68749,68749],"mapped",[68813]],[[68750,68750],"mapped",[68814]],[[68751,68751],"mapped",[68815]],[[68752,68752],"mapped",[68816]],[[68753,68753],"mapped",[68817]],[[68754,68754],"mapped",[68818]],[[68755,68755],"mapped",[68819]],[[68756,68756],"mapped",[68820]],[[68757,68757],"mapped",[68821]],[[68758,68758],"mapped",[68822]],[[68759,68759],"mapped",[68823]],[[68760,68760],"mapped",[68824]],[[68761,68761],"mapped",[68825]],[[68762,68762],"mapped",[68826]],[[68763,68763],"mapped",[68827]],[[68764,68764],"mapped",[68828]],[[68765,68765],"mapped",[68829]],[[68766,68766],"mapped",[68830]],[[68767,68767],"mapped",[68831]],[[68768,68768],"mapped",[68832]],[[68769,68769],"mapped",[68833]],[[68770,68770],"mapped",[68834]],[[68771,68771],"mapped",[68835]],[[68772,68772],"mapped",[68836]],[[68773,68773],"mapped",[68837]],[[68774,68774],"mapped",[68838]],[[68775,68775],"mapped",[68839]],[[68776,68776],"mapped",[68840]],[[68777,68777],"mapped",[68841]],[[68778,68778],"mapped",[68842]],[[68779,68779],"mapped",[68843]],[[68780,68780],"mapped",[68844]],[[68781,68781],"mapped",[68845]],[[68782,68782],"mapped",[68846]],[[68783,68783],"mapped",[68847]],[[68784,68784],"mapped",[68848]],[[68785,68785],"mapped",[68849]],[[68786,68786],"mapped",[68850]],[[68787,68799],"disallowed"],[[68800,68850],"valid"],[[68851,68857],"disallowed"],[[68858,68863],"valid",[],"NV8"],[[68864,69215],"disallowed"],[[69216,69246],"valid",[],"NV8"],[[69247,69631],"disallowed"],[[69632,69702],"valid"],[[69703,69709],"valid",[],"NV8"],[[69710,69713],"disallowed"],[[69714,69733],"valid",[],"NV8"],[[69734,69743],"valid"],[[69744,69758],"disallowed"],[[69759,69759],"valid"],[[69760,69818],"valid"],[[69819,69820],"valid",[],"NV8"],[[69821,69821],"disallowed"],[[69822,69825],"valid",[],"NV8"],[[69826,69839],"disallowed"],[[69840,69864],"valid"],[[69865,69871],"disallowed"],[[69872,69881],"valid"],[[69882,69887],"disallowed"],[[69888,69940],"valid"],[[69941,69941],"disallowed"],[[69942,69951],"valid"],[[69952,69955],"valid",[],"NV8"],[[69956,69967],"disallowed"],[[69968,70003],"valid"],[[70004,70005],"valid",[],"NV8"],[[70006,70006],"valid"],[[70007,70015],"disallowed"],[[70016,70084],"valid"],[[70085,70088],"valid",[],"NV8"],[[70089,70089],"valid",[],"NV8"],[[70090,70092],"valid"],[[70093,70093],"valid",[],"NV8"],[[70094,70095],"disallowed"],[[70096,70105],"valid"],[[70106,70106],"valid"],[[70107,70107],"valid",[],"NV8"],[[70108,70108],"valid"],[[70109,70111],"valid",[],"NV8"],[[70112,70112],"disallowed"],[[70113,70132],"valid",[],"NV8"],[[70133,70143],"disallowed"],[[70144,70161],"valid"],[[70162,70162],"disallowed"],[[70163,70199],"valid"],[[70200,70205],"valid",[],"NV8"],[[70206,70271],"disallowed"],[[70272,70278],"valid"],[[70279,70279],"disallowed"],[[70280,70280],"valid"],[[70281,70281],"disallowed"],[[70282,70285],"valid"],[[70286,70286],"disallowed"],[[70287,70301],"valid"],[[70302,70302],"disallowed"],[[70303,70312],"valid"],[[70313,70313],"valid",[],"NV8"],[[70314,70319],"disallowed"],[[70320,70378],"valid"],[[70379,70383],"disallowed"],[[70384,70393],"valid"],[[70394,70399],"disallowed"],[[70400,70400],"valid"],[[70401,70403],"valid"],[[70404,70404],"disallowed"],[[70405,70412],"valid"],[[70413,70414],"disallowed"],[[70415,70416],"valid"],[[70417,70418],"disallowed"],[[70419,70440],"valid"],[[70441,70441],"disallowed"],[[70442,70448],"valid"],[[70449,70449],"disallowed"],[[70450,70451],"valid"],[[70452,70452],"disallowed"],[[70453,70457],"valid"],[[70458,70459],"disallowed"],[[70460,70468],"valid"],[[70469,70470],"disallowed"],[[70471,70472],"valid"],[[70473,70474],"disallowed"],[[70475,70477],"valid"],[[70478,70479],"disallowed"],[[70480,70480],"valid"],[[70481,70486],"disallowed"],[[70487,70487],"valid"],[[70488,70492],"disallowed"],[[70493,70499],"valid"],[[70500,70501],"disallowed"],[[70502,70508],"valid"],[[70509,70511],"disallowed"],[[70512,70516],"valid"],[[70517,70783],"disallowed"],[[70784,70853],"valid"],[[70854,70854],"valid",[],"NV8"],[[70855,70855],"valid"],[[70856,70863],"disallowed"],[[70864,70873],"valid"],[[70874,71039],"disallowed"],[[71040,71093],"valid"],[[71094,71095],"disallowed"],[[71096,71104],"valid"],[[71105,71113],"valid",[],"NV8"],[[71114,71127],"valid",[],"NV8"],[[71128,71133],"valid"],[[71134,71167],"disallowed"],[[71168,71232],"valid"],[[71233,71235],"valid",[],"NV8"],[[71236,71236],"valid"],[[71237,71247],"disallowed"],[[71248,71257],"valid"],[[71258,71295],"disallowed"],[[71296,71351],"valid"],[[71352,71359],"disallowed"],[[71360,71369],"valid"],[[71370,71423],"disallowed"],[[71424,71449],"valid"],[[71450,71452],"disallowed"],[[71453,71467],"valid"],[[71468,71471],"disallowed"],[[71472,71481],"valid"],[[71482,71487],"valid",[],"NV8"],[[71488,71839],"disallowed"],[[71840,71840],"mapped",[71872]],[[71841,71841],"mapped",[71873]],[[71842,71842],"mapped",[71874]],[[71843,71843],"mapped",[71875]],[[71844,71844],"mapped",[71876]],[[71845,71845],"mapped",[71877]],[[71846,71846],"mapped",[71878]],[[71847,71847],"mapped",[71879]],[[71848,71848],"mapped",[71880]],[[71849,71849],"mapped",[71881]],[[71850,71850],"mapped",[71882]],[[71851,71851],"mapped",[71883]],[[71852,71852],"mapped",[71884]],[[71853,71853],"mapped",[71885]],[[71854,71854],"mapped",[71886]],[[71855,71855],"mapped",[71887]],[[71856,71856],"mapped",[71888]],[[71857,71857],"mapped",[71889]],[[71858,71858],"mapped",[71890]],[[71859,71859],"mapped",[71891]],[[71860,71860],"mapped",[71892]],[[71861,71861],"mapped",[71893]],[[71862,71862],"mapped",[71894]],[[71863,71863],"mapped",[71895]],[[71864,71864],"mapped",[71896]],[[71865,71865],"mapped",[71897]],[[71866,71866],"mapped",[71898]],[[71867,71867],"mapped",[71899]],[[71868,71868],"mapped",[71900]],[[71869,71869],"mapped",[71901]],[[71870,71870],"mapped",[71902]],[[71871,71871],"mapped",[71903]],[[71872,71913],"valid"],[[71914,71922],"valid",[],"NV8"],[[71923,71934],"disallowed"],[[71935,71935],"valid"],[[71936,72383],"disallowed"],[[72384,72440],"valid"],[[72441,73727],"disallowed"],[[73728,74606],"valid"],[[74607,74648],"valid"],[[74649,74649],"valid"],[[74650,74751],"disallowed"],[[74752,74850],"valid",[],"NV8"],[[74851,74862],"valid",[],"NV8"],[[74863,74863],"disallowed"],[[74864,74867],"valid",[],"NV8"],[[74868,74868],"valid",[],"NV8"],[[74869,74879],"disallowed"],[[74880,75075],"valid"],[[75076,77823],"disallowed"],[[77824,78894],"valid"],[[78895,82943],"disallowed"],[[82944,83526],"valid"],[[83527,92159],"disallowed"],[[92160,92728],"valid"],[[92729,92735],"disallowed"],[[92736,92766],"valid"],[[92767,92767],"disallowed"],[[92768,92777],"valid"],[[92778,92781],"disallowed"],[[92782,92783],"valid",[],"NV8"],[[92784,92879],"disallowed"],[[92880,92909],"valid"],[[92910,92911],"disallowed"],[[92912,92916],"valid"],[[92917,92917],"valid",[],"NV8"],[[92918,92927],"disallowed"],[[92928,92982],"valid"],[[92983,92991],"valid",[],"NV8"],[[92992,92995],"valid"],[[92996,92997],"valid",[],"NV8"],[[92998,93007],"disallowed"],[[93008,93017],"valid"],[[93018,93018],"disallowed"],[[93019,93025],"valid",[],"NV8"],[[93026,93026],"disallowed"],[[93027,93047],"valid"],[[93048,93052],"disallowed"],[[93053,93071],"valid"],[[93072,93951],"disallowed"],[[93952,94020],"valid"],[[94021,94031],"disallowed"],[[94032,94078],"valid"],[[94079,94094],"disallowed"],[[94095,94111],"valid"],[[94112,110591],"disallowed"],[[110592,110593],"valid"],[[110594,113663],"disallowed"],[[113664,113770],"valid"],[[113771,113775],"disallowed"],[[113776,113788],"valid"],[[113789,113791],"disallowed"],[[113792,113800],"valid"],[[113801,113807],"disallowed"],[[113808,113817],"valid"],[[113818,113819],"disallowed"],[[113820,113820],"valid",[],"NV8"],[[113821,113822],"valid"],[[113823,113823],"valid",[],"NV8"],[[113824,113827],"ignored"],[[113828,118783],"disallowed"],[[118784,119029],"valid",[],"NV8"],[[119030,119039],"disallowed"],[[119040,119078],"valid",[],"NV8"],[[119079,119080],"disallowed"],[[119081,119081],"valid",[],"NV8"],[[119082,119133],"valid",[],"NV8"],[[119134,119134],"mapped",[119127,119141]],[[119135,119135],"mapped",[119128,119141]],[[119136,119136],"mapped",[119128,119141,119150]],[[119137,119137],"mapped",[119128,119141,119151]],[[119138,119138],"mapped",[119128,119141,119152]],[[119139,119139],"mapped",[119128,119141,119153]],[[119140,119140],"mapped",[119128,119141,119154]],[[119141,119154],"valid",[],"NV8"],[[119155,119162],"disallowed"],[[119163,119226],"valid",[],"NV8"],[[119227,119227],"mapped",[119225,119141]],[[119228,119228],"mapped",[119226,119141]],[[119229,119229],"mapped",[119225,119141,119150]],[[119230,119230],"mapped",[119226,119141,119150]],[[119231,119231],"mapped",[119225,119141,119151]],[[119232,119232],"mapped",[119226,119141,119151]],[[119233,119261],"valid",[],"NV8"],[[119262,119272],"valid",[],"NV8"],[[119273,119295],"disallowed"],[[119296,119365],"valid",[],"NV8"],[[119366,119551],"disallowed"],[[119552,119638],"valid",[],"NV8"],[[119639,119647],"disallowed"],[[119648,119665],"valid",[],"NV8"],[[119666,119807],"disallowed"],[[119808,119808],"mapped",[97]],[[119809,119809],"mapped",[98]],[[119810,119810],"mapped",[99]],[[119811,119811],"mapped",[100]],[[119812,119812],"mapped",[101]],[[119813,119813],"mapped",[102]],[[119814,119814],"mapped",[103]],[[119815,119815],"mapped",[104]],[[119816,119816],"mapped",[105]],[[119817,119817],"mapped",[106]],[[119818,119818],"mapped",[107]],[[119819,119819],"mapped",[108]],[[119820,119820],"mapped",[109]],[[119821,119821],"mapped",[110]],[[119822,119822],"mapped",[111]],[[119823,119823],"mapped",[112]],[[119824,119824],"mapped",[113]],[[119825,119825],"mapped",[114]],[[119826,119826],"mapped",[115]],[[119827,119827],"mapped",[116]],[[119828,119828],"mapped",[117]],[[119829,119829],"mapped",[118]],[[119830,119830],"mapped",[119]],[[119831,119831],"mapped",[120]],[[119832,119832],"mapped",[121]],[[119833,119833],"mapped",[122]],[[119834,119834],"mapped",[97]],[[119835,119835],"mapped",[98]],[[119836,119836],"mapped",[99]],[[119837,119837],"mapped",[100]],[[119838,119838],"mapped",[101]],[[119839,119839],"mapped",[102]],[[119840,119840],"mapped",[103]],[[119841,119841],"mapped",[104]],[[119842,119842],"mapped",[105]],[[119843,119843],"mapped",[106]],[[119844,119844],"mapped",[107]],[[119845,119845],"mapped",[108]],[[119846,119846],"mapped",[109]],[[119847,119847],"mapped",[110]],[[119848,119848],"mapped",[111]],[[119849,119849],"mapped",[112]],[[119850,119850],"mapped",[113]],[[119851,119851],"mapped",[114]],[[119852,119852],"mapped",[115]],[[119853,119853],"mapped",[116]],[[119854,119854],"mapped",[117]],[[119855,119855],"mapped",[118]],[[119856,119856],"mapped",[119]],[[119857,119857],"mapped",[120]],[[119858,119858],"mapped",[121]],[[119859,119859],"mapped",[122]],[[119860,119860],"mapped",[97]],[[119861,119861],"mapped",[98]],[[119862,119862],"mapped",[99]],[[119863,119863],"mapped",[100]],[[119864,119864],"mapped",[101]],[[119865,119865],"mapped",[102]],[[119866,119866],"mapped",[103]],[[119867,119867],"mapped",[104]],[[119868,119868],"mapped",[105]],[[119869,119869],"mapped",[106]],[[119870,119870],"mapped",[107]],[[119871,119871],"mapped",[108]],[[119872,119872],"mapped",[109]],[[119873,119873],"mapped",[110]],[[119874,119874],"mapped",[111]],[[119875,119875],"mapped",[112]],[[119876,119876],"mapped",[113]],[[119877,119877],"mapped",[114]],[[119878,119878],"mapped",[115]],[[119879,119879],"mapped",[116]],[[119880,119880],"mapped",[117]],[[119881,119881],"mapped",[118]],[[119882,119882],"mapped",[119]],[[119883,119883],"mapped",[120]],[[119884,119884],"mapped",[121]],[[119885,119885],"mapped",[122]],[[119886,119886],"mapped",[97]],[[119887,119887],"mapped",[98]],[[119888,119888],"mapped",[99]],[[119889,119889],"mapped",[100]],[[119890,119890],"mapped",[101]],[[119891,119891],"mapped",[102]],[[119892,119892],"mapped",[103]],[[119893,119893],"disallowed"],[[119894,119894],"mapped",[105]],[[119895,119895],"mapped",[106]],[[119896,119896],"mapped",[107]],[[119897,119897],"mapped",[108]],[[119898,119898],"mapped",[109]],[[119899,119899],"mapped",[110]],[[119900,119900],"mapped",[111]],[[119901,119901],"mapped",[112]],[[119902,119902],"mapped",[113]],[[119903,119903],"mapped",[114]],[[119904,119904],"mapped",[115]],[[119905,119905],"mapped",[116]],[[119906,119906],"mapped",[117]],[[119907,119907],"mapped",[118]],[[119908,119908],"mapped",[119]],[[119909,119909],"mapped",[120]],[[119910,119910],"mapped",[121]],[[119911,119911],"mapped",[122]],[[119912,119912],"mapped",[97]],[[119913,119913],"mapped",[98]],[[119914,119914],"mapped",[99]],[[119915,119915],"mapped",[100]],[[119916,119916],"mapped",[101]],[[119917,119917],"mapped",[102]],[[119918,119918],"mapped",[103]],[[119919,119919],"mapped",[104]],[[119920,119920],"mapped",[105]],[[119921,119921],"mapped",[106]],[[119922,119922],"mapped",[107]],[[119923,119923],"mapped",[108]],[[119924,119924],"mapped",[109]],[[119925,119925],"mapped",[110]],[[119926,119926],"mapped",[111]],[[119927,119927],"mapped",[112]],[[119928,119928],"mapped",[113]],[[119929,119929],"mapped",[114]],[[119930,119930],"mapped",[115]],[[119931,119931],"mapped",[116]],[[119932,119932],"mapped",[117]],[[119933,119933],"mapped",[118]],[[119934,119934],"mapped",[119]],[[119935,119935],"mapped",[120]],[[119936,119936],"mapped",[121]],[[119937,119937],"mapped",[122]],[[119938,119938],"mapped",[97]],[[119939,119939],"mapped",[98]],[[119940,119940],"mapped",[99]],[[119941,119941],"mapped",[100]],[[119942,119942],"mapped",[101]],[[119943,119943],"mapped",[102]],[[119944,119944],"mapped",[103]],[[119945,119945],"mapped",[104]],[[119946,119946],"mapped",[105]],[[119947,119947],"mapped",[106]],[[119948,119948],"mapped",[107]],[[119949,119949],"mapped",[108]],[[119950,119950],"mapped",[109]],[[119951,119951],"mapped",[110]],[[119952,119952],"mapped",[111]],[[119953,119953],"mapped",[112]],[[119954,119954],"mapped",[113]],[[119955,119955],"mapped",[114]],[[119956,119956],"mapped",[115]],[[119957,119957],"mapped",[116]],[[119958,119958],"mapped",[117]],[[119959,119959],"mapped",[118]],[[119960,119960],"mapped",[119]],[[119961,119961],"mapped",[120]],[[119962,119962],"mapped",[121]],[[119963,119963],"mapped",[122]],[[119964,119964],"mapped",[97]],[[119965,119965],"disallowed"],[[119966,119966],"mapped",[99]],[[119967,119967],"mapped",[100]],[[119968,119969],"disallowed"],[[119970,119970],"mapped",[103]],[[119971,119972],"disallowed"],[[119973,119973],"mapped",[106]],[[119974,119974],"mapped",[107]],[[119975,119976],"disallowed"],[[119977,119977],"mapped",[110]],[[119978,119978],"mapped",[111]],[[119979,119979],"mapped",[112]],[[119980,119980],"mapped",[113]],[[119981,119981],"disallowed"],[[119982,119982],"mapped",[115]],[[119983,119983],"mapped",[116]],[[119984,119984],"mapped",[117]],[[119985,119985],"mapped",[118]],[[119986,119986],"mapped",[119]],[[119987,119987],"mapped",[120]],[[119988,119988],"mapped",[121]],[[119989,119989],"mapped",[122]],[[119990,119990],"mapped",[97]],[[119991,119991],"mapped",[98]],[[119992,119992],"mapped",[99]],[[119993,119993],"mapped",[100]],[[119994,119994],"disallowed"],[[119995,119995],"mapped",[102]],[[119996,119996],"disallowed"],[[119997,119997],"mapped",[104]],[[119998,119998],"mapped",[105]],[[119999,119999],"mapped",[106]],[[120000,120000],"mapped",[107]],[[120001,120001],"mapped",[108]],[[120002,120002],"mapped",[109]],[[120003,120003],"mapped",[110]],[[120004,120004],"disallowed"],[[120005,120005],"mapped",[112]],[[120006,120006],"mapped",[113]],[[120007,120007],"mapped",[114]],[[120008,120008],"mapped",[115]],[[120009,120009],"mapped",[116]],[[120010,120010],"mapped",[117]],[[120011,120011],"mapped",[118]],[[120012,120012],"mapped",[119]],[[120013,120013],"mapped",[120]],[[120014,120014],"mapped",[121]],[[120015,120015],"mapped",[122]],[[120016,120016],"mapped",[97]],[[120017,120017],"mapped",[98]],[[120018,120018],"mapped",[99]],[[120019,120019],"mapped",[100]],[[120020,120020],"mapped",[101]],[[120021,120021],"mapped",[102]],[[120022,120022],"mapped",[103]],[[120023,120023],"mapped",[104]],[[120024,120024],"mapped",[105]],[[120025,120025],"mapped",[106]],[[120026,120026],"mapped",[107]],[[120027,120027],"mapped",[108]],[[120028,120028],"mapped",[109]],[[120029,120029],"mapped",[110]],[[120030,120030],"mapped",[111]],[[120031,120031],"mapped",[112]],[[120032,120032],"mapped",[113]],[[120033,120033],"mapped",[114]],[[120034,120034],"mapped",[115]],[[120035,120035],"mapped",[116]],[[120036,120036],"mapped",[117]],[[120037,120037],"mapped",[118]],[[120038,120038],"mapped",[119]],[[120039,120039],"mapped",[120]],[[120040,120040],"mapped",[121]],[[120041,120041],"mapped",[122]],[[120042,120042],"mapped",[97]],[[120043,120043],"mapped",[98]],[[120044,120044],"mapped",[99]],[[120045,120045],"mapped",[100]],[[120046,120046],"mapped",[101]],[[120047,120047],"mapped",[102]],[[120048,120048],"mapped",[103]],[[120049,120049],"mapped",[104]],[[120050,120050],"mapped",[105]],[[120051,120051],"mapped",[106]],[[120052,120052],"mapped",[107]],[[120053,120053],"mapped",[108]],[[120054,120054],"mapped",[109]],[[120055,120055],"mapped",[110]],[[120056,120056],"mapped",[111]],[[120057,120057],"mapped",[112]],[[120058,120058],"mapped",[113]],[[120059,120059],"mapped",[114]],[[120060,120060],"mapped",[115]],[[120061,120061],"mapped",[116]],[[120062,120062],"mapped",[117]],[[120063,120063],"mapped",[118]],[[120064,120064],"mapped",[119]],[[120065,120065],"mapped",[120]],[[120066,120066],"mapped",[121]],[[120067,120067],"mapped",[122]],[[120068,120068],"mapped",[97]],[[120069,120069],"mapped",[98]],[[120070,120070],"disallowed"],[[120071,120071],"mapped",[100]],[[120072,120072],"mapped",[101]],[[120073,120073],"mapped",[102]],[[120074,120074],"mapped",[103]],[[120075,120076],"disallowed"],[[120077,120077],"mapped",[106]],[[120078,120078],"mapped",[107]],[[120079,120079],"mapped",[108]],[[120080,120080],"mapped",[109]],[[120081,120081],"mapped",[110]],[[120082,120082],"mapped",[111]],[[120083,120083],"mapped",[112]],[[120084,120084],"mapped",[113]],[[120085,120085],"disallowed"],[[120086,120086],"mapped",[115]],[[120087,120087],"mapped",[116]],[[120088,120088],"mapped",[117]],[[120089,120089],"mapped",[118]],[[120090,120090],"mapped",[119]],[[120091,120091],"mapped",[120]],[[120092,120092],"mapped",[121]],[[120093,120093],"disallowed"],[[120094,120094],"mapped",[97]],[[120095,120095],"mapped",[98]],[[120096,120096],"mapped",[99]],[[120097,120097],"mapped",[100]],[[120098,120098],"mapped",[101]],[[120099,120099],"mapped",[102]],[[120100,120100],"mapped",[103]],[[120101,120101],"mapped",[104]],[[120102,120102],"mapped",[105]],[[120103,120103],"mapped",[106]],[[120104,120104],"mapped",[107]],[[120105,120105],"mapped",[108]],[[120106,120106],"mapped",[109]],[[120107,120107],"mapped",[110]],[[120108,120108],"mapped",[111]],[[120109,120109],"mapped",[112]],[[120110,120110],"mapped",[113]],[[120111,120111],"mapped",[114]],[[120112,120112],"mapped",[115]],[[120113,120113],"mapped",[116]],[[120114,120114],"mapped",[117]],[[120115,120115],"mapped",[118]],[[120116,120116],"mapped",[119]],[[120117,120117],"mapped",[120]],[[120118,120118],"mapped",[121]],[[120119,120119],"mapped",[122]],[[120120,120120],"mapped",[97]],[[120121,120121],"mapped",[98]],[[120122,120122],"disallowed"],[[120123,120123],"mapped",[100]],[[120124,120124],"mapped",[101]],[[120125,120125],"mapped",[102]],[[120126,120126],"mapped",[103]],[[120127,120127],"disallowed"],[[120128,120128],"mapped",[105]],[[120129,120129],"mapped",[106]],[[120130,120130],"mapped",[107]],[[120131,120131],"mapped",[108]],[[120132,120132],"mapped",[109]],[[120133,120133],"disallowed"],[[120134,120134],"mapped",[111]],[[120135,120137],"disallowed"],[[120138,120138],"mapped",[115]],[[120139,120139],"mapped",[116]],[[120140,120140],"mapped",[117]],[[120141,120141],"mapped",[118]],[[120142,120142],"mapped",[119]],[[120143,120143],"mapped",[120]],[[120144,120144],"mapped",[121]],[[120145,120145],"disallowed"],[[120146,120146],"mapped",[97]],[[120147,120147],"mapped",[98]],[[120148,120148],"mapped",[99]],[[120149,120149],"mapped",[100]],[[120150,120150],"mapped",[101]],[[120151,120151],"mapped",[102]],[[120152,120152],"mapped",[103]],[[120153,120153],"mapped",[104]],[[120154,120154],"mapped",[105]],[[120155,120155],"mapped",[106]],[[120156,120156],"mapped",[107]],[[120157,120157],"mapped",[108]],[[120158,120158],"mapped",[109]],[[120159,120159],"mapped",[110]],[[120160,120160],"mapped",[111]],[[120161,120161],"mapped",[112]],[[120162,120162],"mapped",[113]],[[120163,120163],"mapped",[114]],[[120164,120164],"mapped",[115]],[[120165,120165],"mapped",[116]],[[120166,120166],"mapped",[117]],[[120167,120167],"mapped",[118]],[[120168,120168],"mapped",[119]],[[120169,120169],"mapped",[120]],[[120170,120170],"mapped",[121]],[[120171,120171],"mapped",[122]],[[120172,120172],"mapped",[97]],[[120173,120173],"mapped",[98]],[[120174,120174],"mapped",[99]],[[120175,120175],"mapped",[100]],[[120176,120176],"mapped",[101]],[[120177,120177],"mapped",[102]],[[120178,120178],"mapped",[103]],[[120179,120179],"mapped",[104]],[[120180,120180],"mapped",[105]],[[120181,120181],"mapped",[106]],[[120182,120182],"mapped",[107]],[[120183,120183],"mapped",[108]],[[120184,120184],"mapped",[109]],[[120185,120185],"mapped",[110]],[[120186,120186],"mapped",[111]],[[120187,120187],"mapped",[112]],[[120188,120188],"mapped",[113]],[[120189,120189],"mapped",[114]],[[120190,120190],"mapped",[115]],[[120191,120191],"mapped",[116]],[[120192,120192],"mapped",[117]],[[120193,120193],"mapped",[118]],[[120194,120194],"mapped",[119]],[[120195,120195],"mapped",[120]],[[120196,120196],"mapped",[121]],[[120197,120197],"mapped",[122]],[[120198,120198],"mapped",[97]],[[120199,120199],"mapped",[98]],[[120200,120200],"mapped",[99]],[[120201,120201],"mapped",[100]],[[120202,120202],"mapped",[101]],[[120203,120203],"mapped",[102]],[[120204,120204],"mapped",[103]],[[120205,120205],"mapped",[104]],[[120206,120206],"mapped",[105]],[[120207,120207],"mapped",[106]],[[120208,120208],"mapped",[107]],[[120209,120209],"mapped",[108]],[[120210,120210],"mapped",[109]],[[120211,120211],"mapped",[110]],[[120212,120212],"mapped",[111]],[[120213,120213],"mapped",[112]],[[120214,120214],"mapped",[113]],[[120215,120215],"mapped",[114]],[[120216,120216],"mapped",[115]],[[120217,120217],"mapped",[116]],[[120218,120218],"mapped",[117]],[[120219,120219],"mapped",[118]],[[120220,120220],"mapped",[119]],[[120221,120221],"mapped",[120]],[[120222,120222],"mapped",[121]],[[120223,120223],"mapped",[122]],[[120224,120224],"mapped",[97]],[[120225,120225],"mapped",[98]],[[120226,120226],"mapped",[99]],[[120227,120227],"mapped",[100]],[[120228,120228],"mapped",[101]],[[120229,120229],"mapped",[102]],[[120230,120230],"mapped",[103]],[[120231,120231],"mapped",[104]],[[120232,120232],"mapped",[105]],[[120233,120233],"mapped",[106]],[[120234,120234],"mapped",[107]],[[120235,120235],"mapped",[108]],[[120236,120236],"mapped",[109]],[[120237,120237],"mapped",[110]],[[120238,120238],"mapped",[111]],[[120239,120239],"mapped",[112]],[[120240,120240],"mapped",[113]],[[120241,120241],"mapped",[114]],[[120242,120242],"mapped",[115]],[[120243,120243],"mapped",[116]],[[120244,120244],"mapped",[117]],[[120245,120245],"mapped",[118]],[[120246,120246],"mapped",[119]],[[120247,120247],"mapped",[120]],[[120248,120248],"mapped",[121]],[[120249,120249],"mapped",[122]],[[120250,120250],"mapped",[97]],[[120251,120251],"mapped",[98]],[[120252,120252],"mapped",[99]],[[120253,120253],"mapped",[100]],[[120254,120254],"mapped",[101]],[[120255,120255],"mapped",[102]],[[120256,120256],"mapped",[103]],[[120257,120257],"mapped",[104]],[[120258,120258],"mapped",[105]],[[120259,120259],"mapped",[106]],[[120260,120260],"mapped",[107]],[[120261,120261],"mapped",[108]],[[120262,120262],"mapped",[109]],[[120263,120263],"mapped",[110]],[[120264,120264],"mapped",[111]],[[120265,120265],"mapped",[112]],[[120266,120266],"mapped",[113]],[[120267,120267],"mapped",[114]],[[120268,120268],"mapped",[115]],[[120269,120269],"mapped",[116]],[[120270,120270],"mapped",[117]],[[120271,120271],"mapped",[118]],[[120272,120272],"mapped",[119]],[[120273,120273],"mapped",[120]],[[120274,120274],"mapped",[121]],[[120275,120275],"mapped",[122]],[[120276,120276],"mapped",[97]],[[120277,120277],"mapped",[98]],[[120278,120278],"mapped",[99]],[[120279,120279],"mapped",[100]],[[120280,120280],"mapped",[101]],[[120281,120281],"mapped",[102]],[[120282,120282],"mapped",[103]],[[120283,120283],"mapped",[104]],[[120284,120284],"mapped",[105]],[[120285,120285],"mapped",[106]],[[120286,120286],"mapped",[107]],[[120287,120287],"mapped",[108]],[[120288,120288],"mapped",[109]],[[120289,120289],"mapped",[110]],[[120290,120290],"mapped",[111]],[[120291,120291],"mapped",[112]],[[120292,120292],"mapped",[113]],[[120293,120293],"mapped",[114]],[[120294,120294],"mapped",[115]],[[120295,120295],"mapped",[116]],[[120296,120296],"mapped",[117]],[[120297,120297],"mapped",[118]],[[120298,120298],"mapped",[119]],[[120299,120299],"mapped",[120]],[[120300,120300],"mapped",[121]],[[120301,120301],"mapped",[122]],[[120302,120302],"mapped",[97]],[[120303,120303],"mapped",[98]],[[120304,120304],"mapped",[99]],[[120305,120305],"mapped",[100]],[[120306,120306],"mapped",[101]],[[120307,120307],"mapped",[102]],[[120308,120308],"mapped",[103]],[[120309,120309],"mapped",[104]],[[120310,120310],"mapped",[105]],[[120311,120311],"mapped",[106]],[[120312,120312],"mapped",[107]],[[120313,120313],"mapped",[108]],[[120314,120314],"mapped",[109]],[[120315,120315],"mapped",[110]],[[120316,120316],"mapped",[111]],[[120317,120317],"mapped",[112]],[[120318,120318],"mapped",[113]],[[120319,120319],"mapped",[114]],[[120320,120320],"mapped",[115]],[[120321,120321],"mapped",[116]],[[120322,120322],"mapped",[117]],[[120323,120323],"mapped",[118]],[[120324,120324],"mapped",[119]],[[120325,120325],"mapped",[120]],[[120326,120326],"mapped",[121]],[[120327,120327],"mapped",[122]],[[120328,120328],"mapped",[97]],[[120329,120329],"mapped",[98]],[[120330,120330],"mapped",[99]],[[120331,120331],"mapped",[100]],[[120332,120332],"mapped",[101]],[[120333,120333],"mapped",[102]],[[120334,120334],"mapped",[103]],[[120335,120335],"mapped",[104]],[[120336,120336],"mapped",[105]],[[120337,120337],"mapped",[106]],[[120338,120338],"mapped",[107]],[[120339,120339],"mapped",[108]],[[120340,120340],"mapped",[109]],[[120341,120341],"mapped",[110]],[[120342,120342],"mapped",[111]],[[120343,120343],"mapped",[112]],[[120344,120344],"mapped",[113]],[[120345,120345],"mapped",[114]],[[120346,120346],"mapped",[115]],[[120347,120347],"mapped",[116]],[[120348,120348],"mapped",[117]],[[120349,120349],"mapped",[118]],[[120350,120350],"mapped",[119]],[[120351,120351],"mapped",[120]],[[120352,120352],"mapped",[121]],[[120353,120353],"mapped",[122]],[[120354,120354],"mapped",[97]],[[120355,120355],"mapped",[98]],[[120356,120356],"mapped",[99]],[[120357,120357],"mapped",[100]],[[120358,120358],"mapped",[101]],[[120359,120359],"mapped",[102]],[[120360,120360],"mapped",[103]],[[120361,120361],"mapped",[104]],[[120362,120362],"mapped",[105]],[[120363,120363],"mapped",[106]],[[120364,120364],"mapped",[107]],[[120365,120365],"mapped",[108]],[[120366,120366],"mapped",[109]],[[120367,120367],"mapped",[110]],[[120368,120368],"mapped",[111]],[[120369,120369],"mapped",[112]],[[120370,120370],"mapped",[113]],[[120371,120371],"mapped",[114]],[[120372,120372],"mapped",[115]],[[120373,120373],"mapped",[116]],[[120374,120374],"mapped",[117]],[[120375,120375],"mapped",[118]],[[120376,120376],"mapped",[119]],[[120377,120377],"mapped",[120]],[[120378,120378],"mapped",[121]],[[120379,120379],"mapped",[122]],[[120380,120380],"mapped",[97]],[[120381,120381],"mapped",[98]],[[120382,120382],"mapped",[99]],[[120383,120383],"mapped",[100]],[[120384,120384],"mapped",[101]],[[120385,120385],"mapped",[102]],[[120386,120386],"mapped",[103]],[[120387,120387],"mapped",[104]],[[120388,120388],"mapped",[105]],[[120389,120389],"mapped",[106]],[[120390,120390],"mapped",[107]],[[120391,120391],"mapped",[108]],[[120392,120392],"mapped",[109]],[[120393,120393],"mapped",[110]],[[120394,120394],"mapped",[111]],[[120395,120395],"mapped",[112]],[[120396,120396],"mapped",[113]],[[120397,120397],"mapped",[114]],[[120398,120398],"mapped",[115]],[[120399,120399],"mapped",[116]],[[120400,120400],"mapped",[117]],[[120401,120401],"mapped",[118]],[[120402,120402],"mapped",[119]],[[120403,120403],"mapped",[120]],[[120404,120404],"mapped",[121]],[[120405,120405],"mapped",[122]],[[120406,120406],"mapped",[97]],[[120407,120407],"mapped",[98]],[[120408,120408],"mapped",[99]],[[120409,120409],"mapped",[100]],[[120410,120410],"mapped",[101]],[[120411,120411],"mapped",[102]],[[120412,120412],"mapped",[103]],[[120413,120413],"mapped",[104]],[[120414,120414],"mapped",[105]],[[120415,120415],"mapped",[106]],[[120416,120416],"mapped",[107]],[[120417,120417],"mapped",[108]],[[120418,120418],"mapped",[109]],[[120419,120419],"mapped",[110]],[[120420,120420],"mapped",[111]],[[120421,120421],"mapped",[112]],[[120422,120422],"mapped",[113]],[[120423,120423],"mapped",[114]],[[120424,120424],"mapped",[115]],[[120425,120425],"mapped",[116]],[[120426,120426],"mapped",[117]],[[120427,120427],"mapped",[118]],[[120428,120428],"mapped",[119]],[[120429,120429],"mapped",[120]],[[120430,120430],"mapped",[121]],[[120431,120431],"mapped",[122]],[[120432,120432],"mapped",[97]],[[120433,120433],"mapped",[98]],[[120434,120434],"mapped",[99]],[[120435,120435],"mapped",[100]],[[120436,120436],"mapped",[101]],[[120437,120437],"mapped",[102]],[[120438,120438],"mapped",[103]],[[120439,120439],"mapped",[104]],[[120440,120440],"mapped",[105]],[[120441,120441],"mapped",[106]],[[120442,120442],"mapped",[107]],[[120443,120443],"mapped",[108]],[[120444,120444],"mapped",[109]],[[120445,120445],"mapped",[110]],[[120446,120446],"mapped",[111]],[[120447,120447],"mapped",[112]],[[120448,120448],"mapped",[113]],[[120449,120449],"mapped",[114]],[[120450,120450],"mapped",[115]],[[120451,120451],"mapped",[116]],[[120452,120452],"mapped",[117]],[[120453,120453],"mapped",[118]],[[120454,120454],"mapped",[119]],[[120455,120455],"mapped",[120]],[[120456,120456],"mapped",[121]],[[120457,120457],"mapped",[122]],[[120458,120458],"mapped",[97]],[[120459,120459],"mapped",[98]],[[120460,120460],"mapped",[99]],[[120461,120461],"mapped",[100]],[[120462,120462],"mapped",[101]],[[120463,120463],"mapped",[102]],[[120464,120464],"mapped",[103]],[[120465,120465],"mapped",[104]],[[120466,120466],"mapped",[105]],[[120467,120467],"mapped",[106]],[[120468,120468],"mapped",[107]],[[120469,120469],"mapped",[108]],[[120470,120470],"mapped",[109]],[[120471,120471],"mapped",[110]],[[120472,120472],"mapped",[111]],[[120473,120473],"mapped",[112]],[[120474,120474],"mapped",[113]],[[120475,120475],"mapped",[114]],[[120476,120476],"mapped",[115]],[[120477,120477],"mapped",[116]],[[120478,120478],"mapped",[117]],[[120479,120479],"mapped",[118]],[[120480,120480],"mapped",[119]],[[120481,120481],"mapped",[120]],[[120482,120482],"mapped",[121]],[[120483,120483],"mapped",[122]],[[120484,120484],"mapped",[305]],[[120485,120485],"mapped",[567]],[[120486,120487],"disallowed"],[[120488,120488],"mapped",[945]],[[120489,120489],"mapped",[946]],[[120490,120490],"mapped",[947]],[[120491,120491],"mapped",[948]],[[120492,120492],"mapped",[949]],[[120493,120493],"mapped",[950]],[[120494,120494],"mapped",[951]],[[120495,120495],"mapped",[952]],[[120496,120496],"mapped",[953]],[[120497,120497],"mapped",[954]],[[120498,120498],"mapped",[955]],[[120499,120499],"mapped",[956]],[[120500,120500],"mapped",[957]],[[120501,120501],"mapped",[958]],[[120502,120502],"mapped",[959]],[[120503,120503],"mapped",[960]],[[120504,120504],"mapped",[961]],[[120505,120505],"mapped",[952]],[[120506,120506],"mapped",[963]],[[120507,120507],"mapped",[964]],[[120508,120508],"mapped",[965]],[[120509,120509],"mapped",[966]],[[120510,120510],"mapped",[967]],[[120511,120511],"mapped",[968]],[[120512,120512],"mapped",[969]],[[120513,120513],"mapped",[8711]],[[120514,120514],"mapped",[945]],[[120515,120515],"mapped",[946]],[[120516,120516],"mapped",[947]],[[120517,120517],"mapped",[948]],[[120518,120518],"mapped",[949]],[[120519,120519],"mapped",[950]],[[120520,120520],"mapped",[951]],[[120521,120521],"mapped",[952]],[[120522,120522],"mapped",[953]],[[120523,120523],"mapped",[954]],[[120524,120524],"mapped",[955]],[[120525,120525],"mapped",[956]],[[120526,120526],"mapped",[957]],[[120527,120527],"mapped",[958]],[[120528,120528],"mapped",[959]],[[120529,120529],"mapped",[960]],[[120530,120530],"mapped",[961]],[[120531,120532],"mapped",[963]],[[120533,120533],"mapped",[964]],[[120534,120534],"mapped",[965]],[[120535,120535],"mapped",[966]],[[120536,120536],"mapped",[967]],[[120537,120537],"mapped",[968]],[[120538,120538],"mapped",[969]],[[120539,120539],"mapped",[8706]],[[120540,120540],"mapped",[949]],[[120541,120541],"mapped",[952]],[[120542,120542],"mapped",[954]],[[120543,120543],"mapped",[966]],[[120544,120544],"mapped",[961]],[[120545,120545],"mapped",[960]],[[120546,120546],"mapped",[945]],[[120547,120547],"mapped",[946]],[[120548,120548],"mapped",[947]],[[120549,120549],"mapped",[948]],[[120550,120550],"mapped",[949]],[[120551,120551],"mapped",[950]],[[120552,120552],"mapped",[951]],[[120553,120553],"mapped",[952]],[[120554,120554],"mapped",[953]],[[120555,120555],"mapped",[954]],[[120556,120556],"mapped",[955]],[[120557,120557],"mapped",[956]],[[120558,120558],"mapped",[957]],[[120559,120559],"mapped",[958]],[[120560,120560],"mapped",[959]],[[120561,120561],"mapped",[960]],[[120562,120562],"mapped",[961]],[[120563,120563],"mapped",[952]],[[120564,120564],"mapped",[963]],[[120565,120565],"mapped",[964]],[[120566,120566],"mapped",[965]],[[120567,120567],"mapped",[966]],[[120568,120568],"mapped",[967]],[[120569,120569],"mapped",[968]],[[120570,120570],"mapped",[969]],[[120571,120571],"mapped",[8711]],[[120572,120572],"mapped",[945]],[[120573,120573],"mapped",[946]],[[120574,120574],"mapped",[947]],[[120575,120575],"mapped",[948]],[[120576,120576],"mapped",[949]],[[120577,120577],"mapped",[950]],[[120578,120578],"mapped",[951]],[[120579,120579],"mapped",[952]],[[120580,120580],"mapped",[953]],[[120581,120581],"mapped",[954]],[[120582,120582],"mapped",[955]],[[120583,120583],"mapped",[956]],[[120584,120584],"mapped",[957]],[[120585,120585],"mapped",[958]],[[120586,120586],"mapped",[959]],[[120587,120587],"mapped",[960]],[[120588,120588],"mapped",[961]],[[120589,120590],"mapped",[963]],[[120591,120591],"mapped",[964]],[[120592,120592],"mapped",[965]],[[120593,120593],"mapped",[966]],[[120594,120594],"mapped",[967]],[[120595,120595],"mapped",[968]],[[120596,120596],"mapped",[969]],[[120597,120597],"mapped",[8706]],[[120598,120598],"mapped",[949]],[[120599,120599],"mapped",[952]],[[120600,120600],"mapped",[954]],[[120601,120601],"mapped",[966]],[[120602,120602],"mapped",[961]],[[120603,120603],"mapped",[960]],[[120604,120604],"mapped",[945]],[[120605,120605],"mapped",[946]],[[120606,120606],"mapped",[947]],[[120607,120607],"mapped",[948]],[[120608,120608],"mapped",[949]],[[120609,120609],"mapped",[950]],[[120610,120610],"mapped",[951]],[[120611,120611],"mapped",[952]],[[120612,120612],"mapped",[953]],[[120613,120613],"mapped",[954]],[[120614,120614],"mapped",[955]],[[120615,120615],"mapped",[956]],[[120616,120616],"mapped",[957]],[[120617,120617],"mapped",[958]],[[120618,120618],"mapped",[959]],[[120619,120619],"mapped",[960]],[[120620,120620],"mapped",[961]],[[120621,120621],"mapped",[952]],[[120622,120622],"mapped",[963]],[[120623,120623],"mapped",[964]],[[120624,120624],"mapped",[965]],[[120625,120625],"mapped",[966]],[[120626,120626],"mapped",[967]],[[120627,120627],"mapped",[968]],[[120628,120628],"mapped",[969]],[[120629,120629],"mapped",[8711]],[[120630,120630],"mapped",[945]],[[120631,120631],"mapped",[946]],[[120632,120632],"mapped",[947]],[[120633,120633],"mapped",[948]],[[120634,120634],"mapped",[949]],[[120635,120635],"mapped",[950]],[[120636,120636],"mapped",[951]],[[120637,120637],"mapped",[952]],[[120638,120638],"mapped",[953]],[[120639,120639],"mapped",[954]],[[120640,120640],"mapped",[955]],[[120641,120641],"mapped",[956]],[[120642,120642],"mapped",[957]],[[120643,120643],"mapped",[958]],[[120644,120644],"mapped",[959]],[[120645,120645],"mapped",[960]],[[120646,120646],"mapped",[961]],[[120647,120648],"mapped",[963]],[[120649,120649],"mapped",[964]],[[120650,120650],"mapped",[965]],[[120651,120651],"mapped",[966]],[[120652,120652],"mapped",[967]],[[120653,120653],"mapped",[968]],[[120654,120654],"mapped",[969]],[[120655,120655],"mapped",[8706]],[[120656,120656],"mapped",[949]],[[120657,120657],"mapped",[952]],[[120658,120658],"mapped",[954]],[[120659,120659],"mapped",[966]],[[120660,120660],"mapped",[961]],[[120661,120661],"mapped",[960]],[[120662,120662],"mapped",[945]],[[120663,120663],"mapped",[946]],[[120664,120664],"mapped",[947]],[[120665,120665],"mapped",[948]],[[120666,120666],"mapped",[949]],[[120667,120667],"mapped",[950]],[[120668,120668],"mapped",[951]],[[120669,120669],"mapped",[952]],[[120670,120670],"mapped",[953]],[[120671,120671],"mapped",[954]],[[120672,120672],"mapped",[955]],[[120673,120673],"mapped",[956]],[[120674,120674],"mapped",[957]],[[120675,120675],"mapped",[958]],[[120676,120676],"mapped",[959]],[[120677,120677],"mapped",[960]],[[120678,120678],"mapped",[961]],[[120679,120679],"mapped",[952]],[[120680,120680],"mapped",[963]],[[120681,120681],"mapped",[964]],[[120682,120682],"mapped",[965]],[[120683,120683],"mapped",[966]],[[120684,120684],"mapped",[967]],[[120685,120685],"mapped",[968]],[[120686,120686],"mapped",[969]],[[120687,120687],"mapped",[8711]],[[120688,120688],"mapped",[945]],[[120689,120689],"mapped",[946]],[[120690,120690],"mapped",[947]],[[120691,120691],"mapped",[948]],[[120692,120692],"mapped",[949]],[[120693,120693],"mapped",[950]],[[120694,120694],"mapped",[951]],[[120695,120695],"mapped",[952]],[[120696,120696],"mapped",[953]],[[120697,120697],"mapped",[954]],[[120698,120698],"mapped",[955]],[[120699,120699],"mapped",[956]],[[120700,120700],"mapped",[957]],[[120701,120701],"mapped",[958]],[[120702,120702],"mapped",[959]],[[120703,120703],"mapped",[960]],[[120704,120704],"mapped",[961]],[[120705,120706],"mapped",[963]],[[120707,120707],"mapped",[964]],[[120708,120708],"mapped",[965]],[[120709,120709],"mapped",[966]],[[120710,120710],"mapped",[967]],[[120711,120711],"mapped",[968]],[[120712,120712],"mapped",[969]],[[120713,120713],"mapped",[8706]],[[120714,120714],"mapped",[949]],[[120715,120715],"mapped",[952]],[[120716,120716],"mapped",[954]],[[120717,120717],"mapped",[966]],[[120718,120718],"mapped",[961]],[[120719,120719],"mapped",[960]],[[120720,120720],"mapped",[945]],[[120721,120721],"mapped",[946]],[[120722,120722],"mapped",[947]],[[120723,120723],"mapped",[948]],[[120724,120724],"mapped",[949]],[[120725,120725],"mapped",[950]],[[120726,120726],"mapped",[951]],[[120727,120727],"mapped",[952]],[[120728,120728],"mapped",[953]],[[120729,120729],"mapped",[954]],[[120730,120730],"mapped",[955]],[[120731,120731],"mapped",[956]],[[120732,120732],"mapped",[957]],[[120733,120733],"mapped",[958]],[[120734,120734],"mapped",[959]],[[120735,120735],"mapped",[960]],[[120736,120736],"mapped",[961]],[[120737,120737],"mapped",[952]],[[120738,120738],"mapped",[963]],[[120739,120739],"mapped",[964]],[[120740,120740],"mapped",[965]],[[120741,120741],"mapped",[966]],[[120742,120742],"mapped",[967]],[[120743,120743],"mapped",[968]],[[120744,120744],"mapped",[969]],[[120745,120745],"mapped",[8711]],[[120746,120746],"mapped",[945]],[[120747,120747],"mapped",[946]],[[120748,120748],"mapped",[947]],[[120749,120749],"mapped",[948]],[[120750,120750],"mapped",[949]],[[120751,120751],"mapped",[950]],[[120752,120752],"mapped",[951]],[[120753,120753],"mapped",[952]],[[120754,120754],"mapped",[953]],[[120755,120755],"mapped",[954]],[[120756,120756],"mapped",[955]],[[120757,120757],"mapped",[956]],[[120758,120758],"mapped",[957]],[[120759,120759],"mapped",[958]],[[120760,120760],"mapped",[959]],[[120761,120761],"mapped",[960]],[[120762,120762],"mapped",[961]],[[120763,120764],"mapped",[963]],[[120765,120765],"mapped",[964]],[[120766,120766],"mapped",[965]],[[120767,120767],"mapped",[966]],[[120768,120768],"mapped",[967]],[[120769,120769],"mapped",[968]],[[120770,120770],"mapped",[969]],[[120771,120771],"mapped",[8706]],[[120772,120772],"mapped",[949]],[[120773,120773],"mapped",[952]],[[120774,120774],"mapped",[954]],[[120775,120775],"mapped",[966]],[[120776,120776],"mapped",[961]],[[120777,120777],"mapped",[960]],[[120778,120779],"mapped",[989]],[[120780,120781],"disallowed"],[[120782,120782],"mapped",[48]],[[120783,120783],"mapped",[49]],[[120784,120784],"mapped",[50]],[[120785,120785],"mapped",[51]],[[120786,120786],"mapped",[52]],[[120787,120787],"mapped",[53]],[[120788,120788],"mapped",[54]],[[120789,120789],"mapped",[55]],[[120790,120790],"mapped",[56]],[[120791,120791],"mapped",[57]],[[120792,120792],"mapped",[48]],[[120793,120793],"mapped",[49]],[[120794,120794],"mapped",[50]],[[120795,120795],"mapped",[51]],[[120796,120796],"mapped",[52]],[[120797,120797],"mapped",[53]],[[120798,120798],"mapped",[54]],[[120799,120799],"mapped",[55]],[[120800,120800],"mapped",[56]],[[120801,120801],"mapped",[57]],[[120802,120802],"mapped",[48]],[[120803,120803],"mapped",[49]],[[120804,120804],"mapped",[50]],[[120805,120805],"mapped",[51]],[[120806,120806],"mapped",[52]],[[120807,120807],"mapped",[53]],[[120808,120808],"mapped",[54]],[[120809,120809],"mapped",[55]],[[120810,120810],"mapped",[56]],[[120811,120811],"mapped",[57]],[[120812,120812],"mapped",[48]],[[120813,120813],"mapped",[49]],[[120814,120814],"mapped",[50]],[[120815,120815],"mapped",[51]],[[120816,120816],"mapped",[52]],[[120817,120817],"mapped",[53]],[[120818,120818],"mapped",[54]],[[120819,120819],"mapped",[55]],[[120820,120820],"mapped",[56]],[[120821,120821],"mapped",[57]],[[120822,120822],"mapped",[48]],[[120823,120823],"mapped",[49]],[[120824,120824],"mapped",[50]],[[120825,120825],"mapped",[51]],[[120826,120826],"mapped",[52]],[[120827,120827],"mapped",[53]],[[120828,120828],"mapped",[54]],[[120829,120829],"mapped",[55]],[[120830,120830],"mapped",[56]],[[120831,120831],"mapped",[57]],[[120832,121343],"valid",[],"NV8"],[[121344,121398],"valid"],[[121399,121402],"valid",[],"NV8"],[[121403,121452],"valid"],[[121453,121460],"valid",[],"NV8"],[[121461,121461],"valid"],[[121462,121475],"valid",[],"NV8"],[[121476,121476],"valid"],[[121477,121483],"valid",[],"NV8"],[[121484,121498],"disallowed"],[[121499,121503],"valid"],[[121504,121504],"disallowed"],[[121505,121519],"valid"],[[121520,124927],"disallowed"],[[124928,125124],"valid"],[[125125,125126],"disallowed"],[[125127,125135],"valid",[],"NV8"],[[125136,125142],"valid"],[[125143,126463],"disallowed"],[[126464,126464],"mapped",[1575]],[[126465,126465],"mapped",[1576]],[[126466,126466],"mapped",[1580]],[[126467,126467],"mapped",[1583]],[[126468,126468],"disallowed"],[[126469,126469],"mapped",[1608]],[[126470,126470],"mapped",[1586]],[[126471,126471],"mapped",[1581]],[[126472,126472],"mapped",[1591]],[[126473,126473],"mapped",[1610]],[[126474,126474],"mapped",[1603]],[[126475,126475],"mapped",[1604]],[[126476,126476],"mapped",[1605]],[[126477,126477],"mapped",[1606]],[[126478,126478],"mapped",[1587]],[[126479,126479],"mapped",[1593]],[[126480,126480],"mapped",[1601]],[[126481,126481],"mapped",[1589]],[[126482,126482],"mapped",[1602]],[[126483,126483],"mapped",[1585]],[[126484,126484],"mapped",[1588]],[[126485,126485],"mapped",[1578]],[[126486,126486],"mapped",[1579]],[[126487,126487],"mapped",[1582]],[[126488,126488],"mapped",[1584]],[[126489,126489],"mapped",[1590]],[[126490,126490],"mapped",[1592]],[[126491,126491],"mapped",[1594]],[[126492,126492],"mapped",[1646]],[[126493,126493],"mapped",[1722]],[[126494,126494],"mapped",[1697]],[[126495,126495],"mapped",[1647]],[[126496,126496],"disallowed"],[[126497,126497],"mapped",[1576]],[[126498,126498],"mapped",[1580]],[[126499,126499],"disallowed"],[[126500,126500],"mapped",[1607]],[[126501,126502],"disallowed"],[[126503,126503],"mapped",[1581]],[[126504,126504],"disallowed"],[[126505,126505],"mapped",[1610]],[[126506,126506],"mapped",[1603]],[[126507,126507],"mapped",[1604]],[[126508,126508],"mapped",[1605]],[[126509,126509],"mapped",[1606]],[[126510,126510],"mapped",[1587]],[[126511,126511],"mapped",[1593]],[[126512,126512],"mapped",[1601]],[[126513,126513],"mapped",[1589]],[[126514,126514],"mapped",[1602]],[[126515,126515],"disallowed"],[[126516,126516],"mapped",[1588]],[[126517,126517],"mapped",[1578]],[[126518,126518],"mapped",[1579]],[[126519,126519],"mapped",[1582]],[[126520,126520],"disallowed"],[[126521,126521],"mapped",[1590]],[[126522,126522],"disallowed"],[[126523,126523],"mapped",[1594]],[[126524,126529],"disallowed"],[[126530,126530],"mapped",[1580]],[[126531,126534],"disallowed"],[[126535,126535],"mapped",[1581]],[[126536,126536],"disallowed"],[[126537,126537],"mapped",[1610]],[[126538,126538],"disallowed"],[[126539,126539],"mapped",[1604]],[[126540,126540],"disallowed"],[[126541,126541],"mapped",[1606]],[[126542,126542],"mapped",[1587]],[[126543,126543],"mapped",[1593]],[[126544,126544],"disallowed"],[[126545,126545],"mapped",[1589]],[[126546,126546],"mapped",[1602]],[[126547,126547],"disallowed"],[[126548,126548],"mapped",[1588]],[[126549,126550],"disallowed"],[[126551,126551],"mapped",[1582]],[[126552,126552],"disallowed"],[[126553,126553],"mapped",[1590]],[[126554,126554],"disallowed"],[[126555,126555],"mapped",[1594]],[[126556,126556],"disallowed"],[[126557,126557],"mapped",[1722]],[[126558,126558],"disallowed"],[[126559,126559],"mapped",[1647]],[[126560,126560],"disallowed"],[[126561,126561],"mapped",[1576]],[[126562,126562],"mapped",[1580]],[[126563,126563],"disallowed"],[[126564,126564],"mapped",[1607]],[[126565,126566],"disallowed"],[[126567,126567],"mapped",[1581]],[[126568,126568],"mapped",[1591]],[[126569,126569],"mapped",[1610]],[[126570,126570],"mapped",[1603]],[[126571,126571],"disallowed"],[[126572,126572],"mapped",[1605]],[[126573,126573],"mapped",[1606]],[[126574,126574],"mapped",[1587]],[[126575,126575],"mapped",[1593]],[[126576,126576],"mapped",[1601]],[[126577,126577],"mapped",[1589]],[[126578,126578],"mapped",[1602]],[[126579,126579],"disallowed"],[[126580,126580],"mapped",[1588]],[[126581,126581],"mapped",[1578]],[[126582,126582],"mapped",[1579]],[[126583,126583],"mapped",[1582]],[[126584,126584],"disallowed"],[[126585,126585],"mapped",[1590]],[[126586,126586],"mapped",[1592]],[[126587,126587],"mapped",[1594]],[[126588,126588],"mapped",[1646]],[[126589,126589],"disallowed"],[[126590,126590],"mapped",[1697]],[[126591,126591],"disallowed"],[[126592,126592],"mapped",[1575]],[[126593,126593],"mapped",[1576]],[[126594,126594],"mapped",[1580]],[[126595,126595],"mapped",[1583]],[[126596,126596],"mapped",[1607]],[[126597,126597],"mapped",[1608]],[[126598,126598],"mapped",[1586]],[[126599,126599],"mapped",[1581]],[[126600,126600],"mapped",[1591]],[[126601,126601],"mapped",[1610]],[[126602,126602],"disallowed"],[[126603,126603],"mapped",[1604]],[[126604,126604],"mapped",[1605]],[[126605,126605],"mapped",[1606]],[[126606,126606],"mapped",[1587]],[[126607,126607],"mapped",[1593]],[[126608,126608],"mapped",[1601]],[[126609,126609],"mapped",[1589]],[[126610,126610],"mapped",[1602]],[[126611,126611],"mapped",[1585]],[[126612,126612],"mapped",[1588]],[[126613,126613],"mapped",[1578]],[[126614,126614],"mapped",[1579]],[[126615,126615],"mapped",[1582]],[[126616,126616],"mapped",[1584]],[[126617,126617],"mapped",[1590]],[[126618,126618],"mapped",[1592]],[[126619,126619],"mapped",[1594]],[[126620,126624],"disallowed"],[[126625,126625],"mapped",[1576]],[[126626,126626],"mapped",[1580]],[[126627,126627],"mapped",[1583]],[[126628,126628],"disallowed"],[[126629,126629],"mapped",[1608]],[[126630,126630],"mapped",[1586]],[[126631,126631],"mapped",[1581]],[[126632,126632],"mapped",[1591]],[[126633,126633],"mapped",[1610]],[[126634,126634],"disallowed"],[[126635,126635],"mapped",[1604]],[[126636,126636],"mapped",[1605]],[[126637,126637],"mapped",[1606]],[[126638,126638],"mapped",[1587]],[[126639,126639],"mapped",[1593]],[[126640,126640],"mapped",[1601]],[[126641,126641],"mapped",[1589]],[[126642,126642],"mapped",[1602]],[[126643,126643],"mapped",[1585]],[[126644,126644],"mapped",[1588]],[[126645,126645],"mapped",[1578]],[[126646,126646],"mapped",[1579]],[[126647,126647],"mapped",[1582]],[[126648,126648],"mapped",[1584]],[[126649,126649],"mapped",[1590]],[[126650,126650],"mapped",[1592]],[[126651,126651],"mapped",[1594]],[[126652,126703],"disallowed"],[[126704,126705],"valid",[],"NV8"],[[126706,126975],"disallowed"],[[126976,127019],"valid",[],"NV8"],[[127020,127023],"disallowed"],[[127024,127123],"valid",[],"NV8"],[[127124,127135],"disallowed"],[[127136,127150],"valid",[],"NV8"],[[127151,127152],"disallowed"],[[127153,127166],"valid",[],"NV8"],[[127167,127167],"valid",[],"NV8"],[[127168,127168],"disallowed"],[[127169,127183],"valid",[],"NV8"],[[127184,127184],"disallowed"],[[127185,127199],"valid",[],"NV8"],[[127200,127221],"valid",[],"NV8"],[[127222,127231],"disallowed"],[[127232,127232],"disallowed"],[[127233,127233],"disallowed_STD3_mapped",[48,44]],[[127234,127234],"disallowed_STD3_mapped",[49,44]],[[127235,127235],"disallowed_STD3_mapped",[50,44]],[[127236,127236],"disallowed_STD3_mapped",[51,44]],[[127237,127237],"disallowed_STD3_mapped",[52,44]],[[127238,127238],"disallowed_STD3_mapped",[53,44]],[[127239,127239],"disallowed_STD3_mapped",[54,44]],[[127240,127240],"disallowed_STD3_mapped",[55,44]],[[127241,127241],"disallowed_STD3_mapped",[56,44]],[[127242,127242],"disallowed_STD3_mapped",[57,44]],[[127243,127244],"valid",[],"NV8"],[[127245,127247],"disallowed"],[[127248,127248],"disallowed_STD3_mapped",[40,97,41]],[[127249,127249],"disallowed_STD3_mapped",[40,98,41]],[[127250,127250],"disallowed_STD3_mapped",[40,99,41]],[[127251,127251],"disallowed_STD3_mapped",[40,100,41]],[[127252,127252],"disallowed_STD3_mapped",[40,101,41]],[[127253,127253],"disallowed_STD3_mapped",[40,102,41]],[[127254,127254],"disallowed_STD3_mapped",[40,103,41]],[[127255,127255],"disallowed_STD3_mapped",[40,104,41]],[[127256,127256],"disallowed_STD3_mapped",[40,105,41]],[[127257,127257],"disallowed_STD3_mapped",[40,106,41]],[[127258,127258],"disallowed_STD3_mapped",[40,107,41]],[[127259,127259],"disallowed_STD3_mapped",[40,108,41]],[[127260,127260],"disallowed_STD3_mapped",[40,109,41]],[[127261,127261],"disallowed_STD3_mapped",[40,110,41]],[[127262,127262],"disallowed_STD3_mapped",[40,111,41]],[[127263,127263],"disallowed_STD3_mapped",[40,112,41]],[[127264,127264],"disallowed_STD3_mapped",[40,113,41]],[[127265,127265],"disallowed_STD3_mapped",[40,114,41]],[[127266,127266],"disallowed_STD3_mapped",[40,115,41]],[[127267,127267],"disallowed_STD3_mapped",[40,116,41]],[[127268,127268],"disallowed_STD3_mapped",[40,117,41]],[[127269,127269],"disallowed_STD3_mapped",[40,118,41]],[[127270,127270],"disallowed_STD3_mapped",[40,119,41]],[[127271,127271],"disallowed_STD3_mapped",[40,120,41]],[[127272,127272],"disallowed_STD3_mapped",[40,121,41]],[[127273,127273],"disallowed_STD3_mapped",[40,122,41]],[[127274,127274],"mapped",[12308,115,12309]],[[127275,127275],"mapped",[99]],[[127276,127276],"mapped",[114]],[[127277,127277],"mapped",[99,100]],[[127278,127278],"mapped",[119,122]],[[127279,127279],"disallowed"],[[127280,127280],"mapped",[97]],[[127281,127281],"mapped",[98]],[[127282,127282],"mapped",[99]],[[127283,127283],"mapped",[100]],[[127284,127284],"mapped",[101]],[[127285,127285],"mapped",[102]],[[127286,127286],"mapped",[103]],[[127287,127287],"mapped",[104]],[[127288,127288],"mapped",[105]],[[127289,127289],"mapped",[106]],[[127290,127290],"mapped",[107]],[[127291,127291],"mapped",[108]],[[127292,127292],"mapped",[109]],[[127293,127293],"mapped",[110]],[[127294,127294],"mapped",[111]],[[127295,127295],"mapped",[112]],[[127296,127296],"mapped",[113]],[[127297,127297],"mapped",[114]],[[127298,127298],"mapped",[115]],[[127299,127299],"mapped",[116]],[[127300,127300],"mapped",[117]],[[127301,127301],"mapped",[118]],[[127302,127302],"mapped",[119]],[[127303,127303],"mapped",[120]],[[127304,127304],"mapped",[121]],[[127305,127305],"mapped",[122]],[[127306,127306],"mapped",[104,118]],[[127307,127307],"mapped",[109,118]],[[127308,127308],"mapped",[115,100]],[[127309,127309],"mapped",[115,115]],[[127310,127310],"mapped",[112,112,118]],[[127311,127311],"mapped",[119,99]],[[127312,127318],"valid",[],"NV8"],[[127319,127319],"valid",[],"NV8"],[[127320,127326],"valid",[],"NV8"],[[127327,127327],"valid",[],"NV8"],[[127328,127337],"valid",[],"NV8"],[[127338,127338],"mapped",[109,99]],[[127339,127339],"mapped",[109,100]],[[127340,127343],"disallowed"],[[127344,127352],"valid",[],"NV8"],[[127353,127353],"valid",[],"NV8"],[[127354,127354],"valid",[],"NV8"],[[127355,127356],"valid",[],"NV8"],[[127357,127358],"valid",[],"NV8"],[[127359,127359],"valid",[],"NV8"],[[127360,127369],"valid",[],"NV8"],[[127370,127373],"valid",[],"NV8"],[[127374,127375],"valid",[],"NV8"],[[127376,127376],"mapped",[100,106]],[[127377,127386],"valid",[],"NV8"],[[127387,127461],"disallowed"],[[127462,127487],"valid",[],"NV8"],[[127488,127488],"mapped",[12411,12363]],[[127489,127489],"mapped",[12467,12467]],[[127490,127490],"mapped",[12469]],[[127491,127503],"disallowed"],[[127504,127504],"mapped",[25163]],[[127505,127505],"mapped",[23383]],[[127506,127506],"mapped",[21452]],[[127507,127507],"mapped",[12487]],[[127508,127508],"mapped",[20108]],[[127509,127509],"mapped",[22810]],[[127510,127510],"mapped",[35299]],[[127511,127511],"mapped",[22825]],[[127512,127512],"mapped",[20132]],[[127513,127513],"mapped",[26144]],[[127514,127514],"mapped",[28961]],[[127515,127515],"mapped",[26009]],[[127516,127516],"mapped",[21069]],[[127517,127517],"mapped",[24460]],[[127518,127518],"mapped",[20877]],[[127519,127519],"mapped",[26032]],[[127520,127520],"mapped",[21021]],[[127521,127521],"mapped",[32066]],[[127522,127522],"mapped",[29983]],[[127523,127523],"mapped",[36009]],[[127524,127524],"mapped",[22768]],[[127525,127525],"mapped",[21561]],[[127526,127526],"mapped",[28436]],[[127527,127527],"mapped",[25237]],[[127528,127528],"mapped",[25429]],[[127529,127529],"mapped",[19968]],[[127530,127530],"mapped",[19977]],[[127531,127531],"mapped",[36938]],[[127532,127532],"mapped",[24038]],[[127533,127533],"mapped",[20013]],[[127534,127534],"mapped",[21491]],[[127535,127535],"mapped",[25351]],[[127536,127536],"mapped",[36208]],[[127537,127537],"mapped",[25171]],[[127538,127538],"mapped",[31105]],[[127539,127539],"mapped",[31354]],[[127540,127540],"mapped",[21512]],[[127541,127541],"mapped",[28288]],[[127542,127542],"mapped",[26377]],[[127543,127543],"mapped",[26376]],[[127544,127544],"mapped",[30003]],[[127545,127545],"mapped",[21106]],[[127546,127546],"mapped",[21942]],[[127547,127551],"disallowed"],[[127552,127552],"mapped",[12308,26412,12309]],[[127553,127553],"mapped",[12308,19977,12309]],[[127554,127554],"mapped",[12308,20108,12309]],[[127555,127555],"mapped",[12308,23433,12309]],[[127556,127556],"mapped",[12308,28857,12309]],[[127557,127557],"mapped",[12308,25171,12309]],[[127558,127558],"mapped",[12308,30423,12309]],[[127559,127559],"mapped",[12308,21213,12309]],[[127560,127560],"mapped",[12308,25943,12309]],[[127561,127567],"disallowed"],[[127568,127568],"mapped",[24471]],[[127569,127569],"mapped",[21487]],[[127570,127743],"disallowed"],[[127744,127776],"valid",[],"NV8"],[[127777,127788],"valid",[],"NV8"],[[127789,127791],"valid",[],"NV8"],[[127792,127797],"valid",[],"NV8"],[[127798,127798],"valid",[],"NV8"],[[127799,127868],"valid",[],"NV8"],[[127869,127869],"valid",[],"NV8"],[[127870,127871],"valid",[],"NV8"],[[127872,127891],"valid",[],"NV8"],[[127892,127903],"valid",[],"NV8"],[[127904,127940],"valid",[],"NV8"],[[127941,127941],"valid",[],"NV8"],[[127942,127946],"valid",[],"NV8"],[[127947,127950],"valid",[],"NV8"],[[127951,127955],"valid",[],"NV8"],[[127956,127967],"valid",[],"NV8"],[[127968,127984],"valid",[],"NV8"],[[127985,127991],"valid",[],"NV8"],[[127992,127999],"valid",[],"NV8"],[[128000,128062],"valid",[],"NV8"],[[128063,128063],"valid",[],"NV8"],[[128064,128064],"valid",[],"NV8"],[[128065,128065],"valid",[],"NV8"],[[128066,128247],"valid",[],"NV8"],[[128248,128248],"valid",[],"NV8"],[[128249,128252],"valid",[],"NV8"],[[128253,128254],"valid",[],"NV8"],[[128255,128255],"valid",[],"NV8"],[[128256,128317],"valid",[],"NV8"],[[128318,128319],"valid",[],"NV8"],[[128320,128323],"valid",[],"NV8"],[[128324,128330],"valid",[],"NV8"],[[128331,128335],"valid",[],"NV8"],[[128336,128359],"valid",[],"NV8"],[[128360,128377],"valid",[],"NV8"],[[128378,128378],"disallowed"],[[128379,128419],"valid",[],"NV8"],[[128420,128420],"disallowed"],[[128421,128506],"valid",[],"NV8"],[[128507,128511],"valid",[],"NV8"],[[128512,128512],"valid",[],"NV8"],[[128513,128528],"valid",[],"NV8"],[[128529,128529],"valid",[],"NV8"],[[128530,128532],"valid",[],"NV8"],[[128533,128533],"valid",[],"NV8"],[[128534,128534],"valid",[],"NV8"],[[128535,128535],"valid",[],"NV8"],[[128536,128536],"valid",[],"NV8"],[[128537,128537],"valid",[],"NV8"],[[128538,128538],"valid",[],"NV8"],[[128539,128539],"valid",[],"NV8"],[[128540,128542],"valid",[],"NV8"],[[128543,128543],"valid",[],"NV8"],[[128544,128549],"valid",[],"NV8"],[[128550,128551],"valid",[],"NV8"],[[128552,128555],"valid",[],"NV8"],[[128556,128556],"valid",[],"NV8"],[[128557,128557],"valid",[],"NV8"],[[128558,128559],"valid",[],"NV8"],[[128560,128563],"valid",[],"NV8"],[[128564,128564],"valid",[],"NV8"],[[128565,128576],"valid",[],"NV8"],[[128577,128578],"valid",[],"NV8"],[[128579,128580],"valid",[],"NV8"],[[128581,128591],"valid",[],"NV8"],[[128592,128639],"valid",[],"NV8"],[[128640,128709],"valid",[],"NV8"],[[128710,128719],"valid",[],"NV8"],[[128720,128720],"valid",[],"NV8"],[[128721,128735],"disallowed"],[[128736,128748],"valid",[],"NV8"],[[128749,128751],"disallowed"],[[128752,128755],"valid",[],"NV8"],[[128756,128767],"disallowed"],[[128768,128883],"valid",[],"NV8"],[[128884,128895],"disallowed"],[[128896,128980],"valid",[],"NV8"],[[128981,129023],"disallowed"],[[129024,129035],"valid",[],"NV8"],[[129036,129039],"disallowed"],[[129040,129095],"valid",[],"NV8"],[[129096,129103],"disallowed"],[[129104,129113],"valid",[],"NV8"],[[129114,129119],"disallowed"],[[129120,129159],"valid",[],"NV8"],[[129160,129167],"disallowed"],[[129168,129197],"valid",[],"NV8"],[[129198,129295],"disallowed"],[[129296,129304],"valid",[],"NV8"],[[129305,129407],"disallowed"],[[129408,129412],"valid",[],"NV8"],[[129413,129471],"disallowed"],[[129472,129472],"valid",[],"NV8"],[[129473,131069],"disallowed"],[[131070,131071],"disallowed"],[[131072,173782],"valid"],[[173783,173823],"disallowed"],[[173824,177972],"valid"],[[177973,177983],"disallowed"],[[177984,178205],"valid"],[[178206,178207],"disallowed"],[[178208,183969],"valid"],[[183970,194559],"disallowed"],[[194560,194560],"mapped",[20029]],[[194561,194561],"mapped",[20024]],[[194562,194562],"mapped",[20033]],[[194563,194563],"mapped",[131362]],[[194564,194564],"mapped",[20320]],[[194565,194565],"mapped",[20398]],[[194566,194566],"mapped",[20411]],[[194567,194567],"mapped",[20482]],[[194568,194568],"mapped",[20602]],[[194569,194569],"mapped",[20633]],[[194570,194570],"mapped",[20711]],[[194571,194571],"mapped",[20687]],[[194572,194572],"mapped",[13470]],[[194573,194573],"mapped",[132666]],[[194574,194574],"mapped",[20813]],[[194575,194575],"mapped",[20820]],[[194576,194576],"mapped",[20836]],[[194577,194577],"mapped",[20855]],[[194578,194578],"mapped",[132380]],[[194579,194579],"mapped",[13497]],[[194580,194580],"mapped",[20839]],[[194581,194581],"mapped",[20877]],[[194582,194582],"mapped",[132427]],[[194583,194583],"mapped",[20887]],[[194584,194584],"mapped",[20900]],[[194585,194585],"mapped",[20172]],[[194586,194586],"mapped",[20908]],[[194587,194587],"mapped",[20917]],[[194588,194588],"mapped",[168415]],[[194589,194589],"mapped",[20981]],[[194590,194590],"mapped",[20995]],[[194591,194591],"mapped",[13535]],[[194592,194592],"mapped",[21051]],[[194593,194593],"mapped",[21062]],[[194594,194594],"mapped",[21106]],[[194595,194595],"mapped",[21111]],[[194596,194596],"mapped",[13589]],[[194597,194597],"mapped",[21191]],[[194598,194598],"mapped",[21193]],[[194599,194599],"mapped",[21220]],[[194600,194600],"mapped",[21242]],[[194601,194601],"mapped",[21253]],[[194602,194602],"mapped",[21254]],[[194603,194603],"mapped",[21271]],[[194604,194604],"mapped",[21321]],[[194605,194605],"mapped",[21329]],[[194606,194606],"mapped",[21338]],[[194607,194607],"mapped",[21363]],[[194608,194608],"mapped",[21373]],[[194609,194611],"mapped",[21375]],[[194612,194612],"mapped",[133676]],[[194613,194613],"mapped",[28784]],[[194614,194614],"mapped",[21450]],[[194615,194615],"mapped",[21471]],[[194616,194616],"mapped",[133987]],[[194617,194617],"mapped",[21483]],[[194618,194618],"mapped",[21489]],[[194619,194619],"mapped",[21510]],[[194620,194620],"mapped",[21662]],[[194621,194621],"mapped",[21560]],[[194622,194622],"mapped",[21576]],[[194623,194623],"mapped",[21608]],[[194624,194624],"mapped",[21666]],[[194625,194625],"mapped",[21750]],[[194626,194626],"mapped",[21776]],[[194627,194627],"mapped",[21843]],[[194628,194628],"mapped",[21859]],[[194629,194630],"mapped",[21892]],[[194631,194631],"mapped",[21913]],[[194632,194632],"mapped",[21931]],[[194633,194633],"mapped",[21939]],[[194634,194634],"mapped",[21954]],[[194635,194635],"mapped",[22294]],[[194636,194636],"mapped",[22022]],[[194637,194637],"mapped",[22295]],[[194638,194638],"mapped",[22097]],[[194639,194639],"mapped",[22132]],[[194640,194640],"mapped",[20999]],[[194641,194641],"mapped",[22766]],[[194642,194642],"mapped",[22478]],[[194643,194643],"mapped",[22516]],[[194644,194644],"mapped",[22541]],[[194645,194645],"mapped",[22411]],[[194646,194646],"mapped",[22578]],[[194647,194647],"mapped",[22577]],[[194648,194648],"mapped",[22700]],[[194649,194649],"mapped",[136420]],[[194650,194650],"mapped",[22770]],[[194651,194651],"mapped",[22775]],[[194652,194652],"mapped",[22790]],[[194653,194653],"mapped",[22810]],[[194654,194654],"mapped",[22818]],[[194655,194655],"mapped",[22882]],[[194656,194656],"mapped",[136872]],[[194657,194657],"mapped",[136938]],[[194658,194658],"mapped",[23020]],[[194659,194659],"mapped",[23067]],[[194660,194660],"mapped",[23079]],[[194661,194661],"mapped",[23000]],[[194662,194662],"mapped",[23142]],[[194663,194663],"mapped",[14062]],[[194664,194664],"disallowed"],[[194665,194665],"mapped",[23304]],[[194666,194667],"mapped",[23358]],[[194668,194668],"mapped",[137672]],[[194669,194669],"mapped",[23491]],[[194670,194670],"mapped",[23512]],[[194671,194671],"mapped",[23527]],[[194672,194672],"mapped",[23539]],[[194673,194673],"mapped",[138008]],[[194674,194674],"mapped",[23551]],[[194675,194675],"mapped",[23558]],[[194676,194676],"disallowed"],[[194677,194677],"mapped",[23586]],[[194678,194678],"mapped",[14209]],[[194679,194679],"mapped",[23648]],[[194680,194680],"mapped",[23662]],[[194681,194681],"mapped",[23744]],[[194682,194682],"mapped",[23693]],[[194683,194683],"mapped",[138724]],[[194684,194684],"mapped",[23875]],[[194685,194685],"mapped",[138726]],[[194686,194686],"mapped",[23918]],[[194687,194687],"mapped",[23915]],[[194688,194688],"mapped",[23932]],[[194689,194689],"mapped",[24033]],[[194690,194690],"mapped",[24034]],[[194691,194691],"mapped",[14383]],[[194692,194692],"mapped",[24061]],[[194693,194693],"mapped",[24104]],[[194694,194694],"mapped",[24125]],[[194695,194695],"mapped",[24169]],[[194696,194696],"mapped",[14434]],[[194697,194697],"mapped",[139651]],[[194698,194698],"mapped",[14460]],[[194699,194699],"mapped",[24240]],[[194700,194700],"mapped",[24243]],[[194701,194701],"mapped",[24246]],[[194702,194702],"mapped",[24266]],[[194703,194703],"mapped",[172946]],[[194704,194704],"mapped",[24318]],[[194705,194706],"mapped",[140081]],[[194707,194707],"mapped",[33281]],[[194708,194709],"mapped",[24354]],[[194710,194710],"mapped",[14535]],[[194711,194711],"mapped",[144056]],[[194712,194712],"mapped",[156122]],[[194713,194713],"mapped",[24418]],[[194714,194714],"mapped",[24427]],[[194715,194715],"mapped",[14563]],[[194716,194716],"mapped",[24474]],[[194717,194717],"mapped",[24525]],[[194718,194718],"mapped",[24535]],[[194719,194719],"mapped",[24569]],[[194720,194720],"mapped",[24705]],[[194721,194721],"mapped",[14650]],[[194722,194722],"mapped",[14620]],[[194723,194723],"mapped",[24724]],[[194724,194724],"mapped",[141012]],[[194725,194725],"mapped",[24775]],[[194726,194726],"mapped",[24904]],[[194727,194727],"mapped",[24908]],[[194728,194728],"mapped",[24910]],[[194729,194729],"mapped",[24908]],[[194730,194730],"mapped",[24954]],[[194731,194731],"mapped",[24974]],[[194732,194732],"mapped",[25010]],[[194733,194733],"mapped",[24996]],[[194734,194734],"mapped",[25007]],[[194735,194735],"mapped",[25054]],[[194736,194736],"mapped",[25074]],[[194737,194737],"mapped",[25078]],[[194738,194738],"mapped",[25104]],[[194739,194739],"mapped",[25115]],[[194740,194740],"mapped",[25181]],[[194741,194741],"mapped",[25265]],[[194742,194742],"mapped",[25300]],[[194743,194743],"mapped",[25424]],[[194744,194744],"mapped",[142092]],[[194745,194745],"mapped",[25405]],[[194746,194746],"mapped",[25340]],[[194747,194747],"mapped",[25448]],[[194748,194748],"mapped",[25475]],[[194749,194749],"mapped",[25572]],[[194750,194750],"mapped",[142321]],[[194751,194751],"mapped",[25634]],[[194752,194752],"mapped",[25541]],[[194753,194753],"mapped",[25513]],[[194754,194754],"mapped",[14894]],[[194755,194755],"mapped",[25705]],[[194756,194756],"mapped",[25726]],[[194757,194757],"mapped",[25757]],[[194758,194758],"mapped",[25719]],[[194759,194759],"mapped",[14956]],[[194760,194760],"mapped",[25935]],[[194761,194761],"mapped",[25964]],[[194762,194762],"mapped",[143370]],[[194763,194763],"mapped",[26083]],[[194764,194764],"mapped",[26360]],[[194765,194765],"mapped",[26185]],[[194766,194766],"mapped",[15129]],[[194767,194767],"mapped",[26257]],[[194768,194768],"mapped",[15112]],[[194769,194769],"mapped",[15076]],[[194770,194770],"mapped",[20882]],[[194771,194771],"mapped",[20885]],[[194772,194772],"mapped",[26368]],[[194773,194773],"mapped",[26268]],[[194774,194774],"mapped",[32941]],[[194775,194775],"mapped",[17369]],[[194776,194776],"mapped",[26391]],[[194777,194777],"mapped",[26395]],[[194778,194778],"mapped",[26401]],[[194779,194779],"mapped",[26462]],[[194780,194780],"mapped",[26451]],[[194781,194781],"mapped",[144323]],[[194782,194782],"mapped",[15177]],[[194783,194783],"mapped",[26618]],[[194784,194784],"mapped",[26501]],[[194785,194785],"mapped",[26706]],[[194786,194786],"mapped",[26757]],[[194787,194787],"mapped",[144493]],[[194788,194788],"mapped",[26766]],[[194789,194789],"mapped",[26655]],[[194790,194790],"mapped",[26900]],[[194791,194791],"mapped",[15261]],[[194792,194792],"mapped",[26946]],[[194793,194793],"mapped",[27043]],[[194794,194794],"mapped",[27114]],[[194795,194795],"mapped",[27304]],[[194796,194796],"mapped",[145059]],[[194797,194797],"mapped",[27355]],[[194798,194798],"mapped",[15384]],[[194799,194799],"mapped",[27425]],[[194800,194800],"mapped",[145575]],[[194801,194801],"mapped",[27476]],[[194802,194802],"mapped",[15438]],[[194803,194803],"mapped",[27506]],[[194804,194804],"mapped",[27551]],[[194805,194805],"mapped",[27578]],[[194806,194806],"mapped",[27579]],[[194807,194807],"mapped",[146061]],[[194808,194808],"mapped",[138507]],[[194809,194809],"mapped",[146170]],[[194810,194810],"mapped",[27726]],[[194811,194811],"mapped",[146620]],[[194812,194812],"mapped",[27839]],[[194813,194813],"mapped",[27853]],[[194814,194814],"mapped",[27751]],[[194815,194815],"mapped",[27926]],[[194816,194816],"mapped",[27966]],[[194817,194817],"mapped",[28023]],[[194818,194818],"mapped",[27969]],[[194819,194819],"mapped",[28009]],[[194820,194820],"mapped",[28024]],[[194821,194821],"mapped",[28037]],[[194822,194822],"mapped",[146718]],[[194823,194823],"mapped",[27956]],[[194824,194824],"mapped",[28207]],[[194825,194825],"mapped",[28270]],[[194826,194826],"mapped",[15667]],[[194827,194827],"mapped",[28363]],[[194828,194828],"mapped",[28359]],[[194829,194829],"mapped",[147153]],[[194830,194830],"mapped",[28153]],[[194831,194831],"mapped",[28526]],[[194832,194832],"mapped",[147294]],[[194833,194833],"mapped",[147342]],[[194834,194834],"mapped",[28614]],[[194835,194835],"mapped",[28729]],[[194836,194836],"mapped",[28702]],[[194837,194837],"mapped",[28699]],[[194838,194838],"mapped",[15766]],[[194839,194839],"mapped",[28746]],[[194840,194840],"mapped",[28797]],[[194841,194841],"mapped",[28791]],[[194842,194842],"mapped",[28845]],[[194843,194843],"mapped",[132389]],[[194844,194844],"mapped",[28997]],[[194845,194845],"mapped",[148067]],[[194846,194846],"mapped",[29084]],[[194847,194847],"disallowed"],[[194848,194848],"mapped",[29224]],[[194849,194849],"mapped",[29237]],[[194850,194850],"mapped",[29264]],[[194851,194851],"mapped",[149000]],[[194852,194852],"mapped",[29312]],[[194853,194853],"mapped",[29333]],[[194854,194854],"mapped",[149301]],[[194855,194855],"mapped",[149524]],[[194856,194856],"mapped",[29562]],[[194857,194857],"mapped",[29579]],[[194858,194858],"mapped",[16044]],[[194859,194859],"mapped",[29605]],[[194860,194861],"mapped",[16056]],[[194862,194862],"mapped",[29767]],[[194863,194863],"mapped",[29788]],[[194864,194864],"mapped",[29809]],[[194865,194865],"mapped",[29829]],[[194866,194866],"mapped",[29898]],[[194867,194867],"mapped",[16155]],[[194868,194868],"mapped",[29988]],[[194869,194869],"mapped",[150582]],[[194870,194870],"mapped",[30014]],[[194871,194871],"mapped",[150674]],[[194872,194872],"mapped",[30064]],[[194873,194873],"mapped",[139679]],[[194874,194874],"mapped",[30224]],[[194875,194875],"mapped",[151457]],[[194876,194876],"mapped",[151480]],[[194877,194877],"mapped",[151620]],[[194878,194878],"mapped",[16380]],[[194879,194879],"mapped",[16392]],[[194880,194880],"mapped",[30452]],[[194881,194881],"mapped",[151795]],[[194882,194882],"mapped",[151794]],[[194883,194883],"mapped",[151833]],[[194884,194884],"mapped",[151859]],[[194885,194885],"mapped",[30494]],[[194886,194887],"mapped",[30495]],[[194888,194888],"mapped",[30538]],[[194889,194889],"mapped",[16441]],[[194890,194890],"mapped",[30603]],[[194891,194891],"mapped",[16454]],[[194892,194892],"mapped",[16534]],[[194893,194893],"mapped",[152605]],[[194894,194894],"mapped",[30798]],[[194895,194895],"mapped",[30860]],[[194896,194896],"mapped",[30924]],[[194897,194897],"mapped",[16611]],[[194898,194898],"mapped",[153126]],[[194899,194899],"mapped",[31062]],[[194900,194900],"mapped",[153242]],[[194901,194901],"mapped",[153285]],[[194902,194902],"mapped",[31119]],[[194903,194903],"mapped",[31211]],[[194904,194904],"mapped",[16687]],[[194905,194905],"mapped",[31296]],[[194906,194906],"mapped",[31306]],[[194907,194907],"mapped",[31311]],[[194908,194908],"mapped",[153980]],[[194909,194910],"mapped",[154279]],[[194911,194911],"disallowed"],[[194912,194912],"mapped",[16898]],[[194913,194913],"mapped",[154539]],[[194914,194914],"mapped",[31686]],[[194915,194915],"mapped",[31689]],[[194916,194916],"mapped",[16935]],[[194917,194917],"mapped",[154752]],[[194918,194918],"mapped",[31954]],[[194919,194919],"mapped",[17056]],[[194920,194920],"mapped",[31976]],[[194921,194921],"mapped",[31971]],[[194922,194922],"mapped",[32000]],[[194923,194923],"mapped",[155526]],[[194924,194924],"mapped",[32099]],[[194925,194925],"mapped",[17153]],[[194926,194926],"mapped",[32199]],[[194927,194927],"mapped",[32258]],[[194928,194928],"mapped",[32325]],[[194929,194929],"mapped",[17204]],[[194930,194930],"mapped",[156200]],[[194931,194931],"mapped",[156231]],[[194932,194932],"mapped",[17241]],[[194933,194933],"mapped",[156377]],[[194934,194934],"mapped",[32634]],[[194935,194935],"mapped",[156478]],[[194936,194936],"mapped",[32661]],[[194937,194937],"mapped",[32762]],[[194938,194938],"mapped",[32773]],[[194939,194939],"mapped",[156890]],[[194940,194940],"mapped",[156963]],[[194941,194941],"mapped",[32864]],[[194942,194942],"mapped",[157096]],[[194943,194943],"mapped",[32880]],[[194944,194944],"mapped",[144223]],[[194945,194945],"mapped",[17365]],[[194946,194946],"mapped",[32946]],[[194947,194947],"mapped",[33027]],[[194948,194948],"mapped",[17419]],[[194949,194949],"mapped",[33086]],[[194950,194950],"mapped",[23221]],[[194951,194951],"mapped",[157607]],[[194952,194952],"mapped",[157621]],[[194953,194953],"mapped",[144275]],[[194954,194954],"mapped",[144284]],[[194955,194955],"mapped",[33281]],[[194956,194956],"mapped",[33284]],[[194957,194957],"mapped",[36766]],[[194958,194958],"mapped",[17515]],[[194959,194959],"mapped",[33425]],[[194960,194960],"mapped",[33419]],[[194961,194961],"mapped",[33437]],[[194962,194962],"mapped",[21171]],[[194963,194963],"mapped",[33457]],[[194964,194964],"mapped",[33459]],[[194965,194965],"mapped",[33469]],[[194966,194966],"mapped",[33510]],[[194967,194967],"mapped",[158524]],[[194968,194968],"mapped",[33509]],[[194969,194969],"mapped",[33565]],[[194970,194970],"mapped",[33635]],[[194971,194971],"mapped",[33709]],[[194972,194972],"mapped",[33571]],[[194973,194973],"mapped",[33725]],[[194974,194974],"mapped",[33767]],[[194975,194975],"mapped",[33879]],[[194976,194976],"mapped",[33619]],[[194977,194977],"mapped",[33738]],[[194978,194978],"mapped",[33740]],[[194979,194979],"mapped",[33756]],[[194980,194980],"mapped",[158774]],[[194981,194981],"mapped",[159083]],[[194982,194982],"mapped",[158933]],[[194983,194983],"mapped",[17707]],[[194984,194984],"mapped",[34033]],[[194985,194985],"mapped",[34035]],[[194986,194986],"mapped",[34070]],[[194987,194987],"mapped",[160714]],[[194988,194988],"mapped",[34148]],[[194989,194989],"mapped",[159532]],[[194990,194990],"mapped",[17757]],[[194991,194991],"mapped",[17761]],[[194992,194992],"mapped",[159665]],[[194993,194993],"mapped",[159954]],[[194994,194994],"mapped",[17771]],[[194995,194995],"mapped",[34384]],[[194996,194996],"mapped",[34396]],[[194997,194997],"mapped",[34407]],[[194998,194998],"mapped",[34409]],[[194999,194999],"mapped",[34473]],[[195000,195000],"mapped",[34440]],[[195001,195001],"mapped",[34574]],[[195002,195002],"mapped",[34530]],[[195003,195003],"mapped",[34681]],[[195004,195004],"mapped",[34600]],[[195005,195005],"mapped",[34667]],[[195006,195006],"mapped",[34694]],[[195007,195007],"disallowed"],[[195008,195008],"mapped",[34785]],[[195009,195009],"mapped",[34817]],[[195010,195010],"mapped",[17913]],[[195011,195011],"mapped",[34912]],[[195012,195012],"mapped",[34915]],[[195013,195013],"mapped",[161383]],[[195014,195014],"mapped",[35031]],[[195015,195015],"mapped",[35038]],[[195016,195016],"mapped",[17973]],[[195017,195017],"mapped",[35066]],[[195018,195018],"mapped",[13499]],[[195019,195019],"mapped",[161966]],[[195020,195020],"mapped",[162150]],[[195021,195021],"mapped",[18110]],[[195022,195022],"mapped",[18119]],[[195023,195023],"mapped",[35488]],[[195024,195024],"mapped",[35565]],[[195025,195025],"mapped",[35722]],[[195026,195026],"mapped",[35925]],[[195027,195027],"mapped",[162984]],[[195028,195028],"mapped",[36011]],[[195029,195029],"mapped",[36033]],[[195030,195030],"mapped",[36123]],[[195031,195031],"mapped",[36215]],[[195032,195032],"mapped",[163631]],[[195033,195033],"mapped",[133124]],[[195034,195034],"mapped",[36299]],[[195035,195035],"mapped",[36284]],[[195036,195036],"mapped",[36336]],[[195037,195037],"mapped",[133342]],[[195038,195038],"mapped",[36564]],[[195039,195039],"mapped",[36664]],[[195040,195040],"mapped",[165330]],[[195041,195041],"mapped",[165357]],[[195042,195042],"mapped",[37012]],[[195043,195043],"mapped",[37105]],[[195044,195044],"mapped",[37137]],[[195045,195045],"mapped",[165678]],[[195046,195046],"mapped",[37147]],[[195047,195047],"mapped",[37432]],[[195048,195048],"mapped",[37591]],[[195049,195049],"mapped",[37592]],[[195050,195050],"mapped",[37500]],[[195051,195051],"mapped",[37881]],[[195052,195052],"mapped",[37909]],[[195053,195053],"mapped",[166906]],[[195054,195054],"mapped",[38283]],[[195055,195055],"mapped",[18837]],[[195056,195056],"mapped",[38327]],[[195057,195057],"mapped",[167287]],[[195058,195058],"mapped",[18918]],[[195059,195059],"mapped",[38595]],[[195060,195060],"mapped",[23986]],[[195061,195061],"mapped",[38691]],[[195062,195062],"mapped",[168261]],[[195063,195063],"mapped",[168474]],[[195064,195064],"mapped",[19054]],[[195065,195065],"mapped",[19062]],[[195066,195066],"mapped",[38880]],[[195067,195067],"mapped",[168970]],[[195068,195068],"mapped",[19122]],[[195069,195069],"mapped",[169110]],[[195070,195071],"mapped",[38923]],[[195072,195072],"mapped",[38953]],[[195073,195073],"mapped",[169398]],[[195074,195074],"mapped",[39138]],[[195075,195075],"mapped",[19251]],[[195076,195076],"mapped",[39209]],[[195077,195077],"mapped",[39335]],[[195078,195078],"mapped",[39362]],[[195079,195079],"mapped",[39422]],[[195080,195080],"mapped",[19406]],[[195081,195081],"mapped",[170800]],[[195082,195082],"mapped",[39698]],[[195083,195083],"mapped",[40000]],[[195084,195084],"mapped",[40189]],[[195085,195085],"mapped",[19662]],[[195086,195086],"mapped",[19693]],[[195087,195087],"mapped",[40295]],[[195088,195088],"mapped",[172238]],[[195089,195089],"mapped",[19704]],[[195090,195090],"mapped",[172293]],[[195091,195091],"mapped",[172558]],[[195092,195092],"mapped",[172689]],[[195093,195093],"mapped",[40635]],[[195094,195094],"mapped",[19798]],[[195095,195095],"mapped",[40697]],[[195096,195096],"mapped",[40702]],[[195097,195097],"mapped",[40709]],[[195098,195098],"mapped",[40719]],[[195099,195099],"mapped",[40726]],[[195100,195100],"mapped",[40763]],[[195101,195101],"mapped",[173568]],[[195102,196605],"disallowed"],[[196606,196607],"disallowed"],[[196608,262141],"disallowed"],[[262142,262143],"disallowed"],[[262144,327677],"disallowed"],[[327678,327679],"disallowed"],[[327680,393213],"disallowed"],[[393214,393215],"disallowed"],[[393216,458749],"disallowed"],[[458750,458751],"disallowed"],[[458752,524285],"disallowed"],[[524286,524287],"disallowed"],[[524288,589821],"disallowed"],[[589822,589823],"disallowed"],[[589824,655357],"disallowed"],[[655358,655359],"disallowed"],[[655360,720893],"disallowed"],[[720894,720895],"disallowed"],[[720896,786429],"disallowed"],[[786430,786431],"disallowed"],[[786432,851965],"disallowed"],[[851966,851967],"disallowed"],[[851968,917501],"disallowed"],[[917502,917503],"disallowed"],[[917504,917504],"disallowed"],[[917505,917505],"disallowed"],[[917506,917535],"disallowed"],[[917536,917631],"disallowed"],[[917632,917759],"disallowed"],[[917760,917999],"ignored"],[[918000,983037],"disallowed"],[[983038,983039],"disallowed"],[[983040,1048573],"disallowed"],[[1048574,1048575],"disallowed"],[[1048576,1114109],"disallowed"],[[1114110,1114111],"disallowed"]]' + ) + }, +} +var __webpack_module_cache__ = {} +function __nccwpck_require__(e) { + var p = __webpack_module_cache__[e] + if (p !== undefined) { + return p.exports + } + var a = (__webpack_module_cache__[e] = { exports: {} }) + var d = true + try { + __webpack_modules__[e].call(a.exports, a, a.exports, __nccwpck_require__) + d = false + } finally { + if (d) delete __webpack_module_cache__[e] + } + return a.exports +} +;(() => { + __nccwpck_require__.n = (e) => { + var p = e && e.__esModule ? () => e['default'] : () => e + __nccwpck_require__.d(p, { a: p }) + return p + } +})() +;(() => { + __nccwpck_require__.d = (e, p) => { + for (var a in p) { + if (__nccwpck_require__.o(p, a) && !__nccwpck_require__.o(e, a)) { + Object.defineProperty(e, a, { enumerable: true, get: p[a] }) + } + } + } +})() +;(() => { + __nccwpck_require__.o = (e, p) => Object.prototype.hasOwnProperty.call(e, p) +})() +if (typeof __nccwpck_require__ !== 'undefined') + __nccwpck_require__.ab = + new URL('.', import.meta.url).pathname.slice( + import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, + -1 + ) + '/' +var __webpack_exports__ = {} +;(() => { + var e = __nccwpck_require__(2186) + var p = __nccwpck_require__.n(e) + var a = __nccwpck_require__(5438) + var d = __nccwpck_require__.n(a) + async function run() { + const p = process.env.GITHUB_TOKEN + if (!p) throw new Error('No GITHUB_TOKEN provided') + const { issue: d } = a.context.payload + if (!d) return console.log('Not an issue, exiting') + const { body: t, number: r, title: s } = d + if (!r) return console.log('Could not get issue number, exiting') + if (!t) return console.log('Could not get issue body, exiting') + if (!s) return console.log('Could not get issue title, exiting') + const { rest: i } = (0, a.getOctokit)(p) + const o = await loadAreaLabels(i) + ;(0, e.debug)(`Loaded labels: ${Array.from(o.keys()).join(', ')}`) + const n = [] + const l = t + .split( + 'Which area(s) of Next.js are affected? (leave empty if unsure)' + )[1] + ?.split('Link to the code that reproduces this issue')[0] + if (!l) { + console.log( + `Issue #${r} does not contain a match section, likely not a bug template, exiting` + ) + return + } + ;(0, e.debug)(`Match section: ${l}`) + for (const [e, p] of o.entries()) { + if (l.includes(p)) { + n.push(e) + } + } + ;(0, e.debug)(`Labels to add: ${n.join(', ')}`) + if (!n.length) return console.log('No labels to add, exiting') + await addLabels(i, r, n) + ;(0, e.debug)(`Added labels to issue #${r}: ${n.join(', ')}`) + } + async function loadAreaLabels(e) { + try { + const { data: p } = await e.issues.listLabelsForRepo({ + owner: a.context.repo.owner, + repo: a.context.repo.repo, + per_page: 100, + }) + const d = new Map() + for (const e of p) { + if (e.name.startsWith('area:') && e.description) { + d.set(e.name, e.description) + } + } + return d + } catch (e) { + console.error('Error loading labels: ' + e) + throw e + } + } + async function addLabels(p, d, t) { + try { + const r = t.map((e) => `"${e}"`).join(', ') + ;(0, e.debug)(`Adding label(s) (${r}) to issue #${d}`) + return await p.issues.addLabels({ + owner: a.context.repo.owner, + repo: a.context.repo.repo, + issue_number: d, + labels: t, + }) + } catch (e) { + console.error(`Could not add label(s) ${t} to issue #${d}`) + throw e + } + } + run().catch(e.setFailed) +})() diff --git a/packages/next/src/lib/metadata/resolve-metadata.ts b/packages/next/src/lib/metadata/resolve-metadata.ts index 7c8d5e97ad598e..d369bf6fc82f1d 100644 --- a/packages/next/src/lib/metadata/resolve-metadata.ts +++ b/packages/next/src/lib/metadata/resolve-metadata.ts @@ -25,6 +25,8 @@ import { resolveViewport, } from './resolvers/resolve-basics' import { resolveIcons } from './resolvers/resolve-icons' +import { getTracer } from '../../server/lib/trace/tracer' +import { ResolveMetadataSpan } from '../../server/lib/trace/constants' type StaticMetadata = Awaited> @@ -181,7 +183,8 @@ function merge( async function getDefinedMetadata( mod: any, - props: any + props: any, + route: string ): Promise { // Layer is a client component, we just skip it. It can't have metadata exported. // Return early to avoid accessing properties error for client references. @@ -190,7 +193,17 @@ async function getDefinedMetadata( } return ( (mod.generateMetadata - ? (parent: ResolvingMetadata) => mod.generateMetadata(props, parent) + ? (parent: ResolvingMetadata) => + getTracer().trace( + ResolveMetadataSpan.generateMetadata, + { + spanName: `generateMetadata ${route}`, + attributes: { + 'next.route': route, + }, + }, + () => mod.generateMetadata(props, parent) + ) : mod.metadata) || null ) } @@ -231,14 +244,27 @@ async function resolveStaticMetadata(components: ComponentsType) { } // [layout.metadata, static files metadata] -> ... -> [page.metadata, static files metadata] -export async function collectMetadata( - loaderTree: LoaderTree, - props: any, +export async function collectMetadata({ + loaderTree, + props, + array, + route, +}: { + loaderTree: LoaderTree + props: any array: MetadataItems -) { - const mod = await getLayoutOrPageModule(loaderTree) + route: string +}) { + const [mod, modType] = await getLayoutOrPageModule(loaderTree) + + if (modType) { + route += `/${modType}` + } + const staticFilesMetadata = await resolveStaticMetadata(loaderTree[2]) - const metadataExport = mod ? await getDefinedMetadata(mod, props) : null + const metadataExport = mod + ? await getDefinedMetadata(mod, props, route) + : null array.push([metadataExport, staticFilesMetadata]) } diff --git a/packages/next/src/server/api-utils/node.ts b/packages/next/src/server/api-utils/node.ts index 55dd33bc308e36..932ed5b1fa63bb 100644 --- a/packages/next/src/server/api-utils/node.ts +++ b/packages/next/src/server/api-utils/node.ts @@ -34,6 +34,8 @@ import { RESPONSE_LIMIT_DEFAULT, } from './index' import { mockRequest } from '../lib/mock-request' +import { getTracer } from '../lib/trace/tracer' +import { NodeSpan } from '../lib/trace/constants' export function tryGetPreviewData( req: IncomingMessage | BaseNextRequest, @@ -528,7 +530,13 @@ export async function apiResolver( } // Call API route method - await resolver(req, res) + await getTracer().trace( + NodeSpan.runHandler, + { + spanName: `executing api route (pages) ${page}`, + }, + () => resolver(req, res) + ) if ( process.env.NODE_ENV !== 'production' && diff --git a/packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts b/packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts index 46afe6473fe85d..959916ac488d16 100644 --- a/packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts +++ b/packages/next/src/server/app-render/create-flight-router-state-from-loader-tree.ts @@ -1,9 +1,7 @@ import { LoaderTree } from '../lib/app-dir-module' import { FlightRouterState, Segment } from './types' import { GetDynamicParamFromSegment } from './index' - -// TODO-APP: Move __PAGE__ to a shared constant -const PAGE_SEGMENT_KEY = '__PAGE__' +import { PAGE_SEGMENT_KEY } from '../../shared/lib/constants' export function addSearchParamsIfPageSegment( segment: Segment, diff --git a/packages/next/src/server/app-render/index.tsx b/packages/next/src/server/app-render/index.tsx index 26a236d3d2d819..c0915334034067 100644 --- a/packages/next/src/server/app-render/index.tsx +++ b/packages/next/src/server/app-render/index.tsx @@ -72,6 +72,7 @@ import { addSearchParamsIfPageSegment, createFlightRouterStateFromLoaderTree, } from './create-flight-router-state-from-loader-tree' +import { PAGE_SEGMENT_KEY } from '../../shared/lib/constants' export const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge' @@ -279,12 +280,20 @@ export async function renderToHTMLOrFlight( } } - async function resolveHead( - tree: LoaderTree, - parentParams: { [key: string]: any }, + async function resolveHead({ + tree, + parentParams, + metadataItems, + treePrefix = [], + }: { + tree: LoaderTree + parentParams: { [key: string]: any } metadataItems: MetadataItems - ): Promise<[React.ReactNode, MetadataItems]> { + /** Provided tree can be nested subtree, this argument says what is the path of such subtree */ + treePrefix?: string[] + }): Promise<[React.ReactNode, MetadataItems]> { const [segment, parallelRoutes, { head, page }] = tree + const currentTreePrefix = [...treePrefix, segment] const isPage = typeof page !== 'undefined' // Handle dynamic segment params. const segmentParam = getDynamicParamFromSegment(segment) @@ -306,15 +315,24 @@ export async function renderToHTMLOrFlight( ...(isPage && searchParamsProps), } - await collectMetadata(tree, layerProps, metadataItems) + await collectMetadata({ + loaderTree: tree, + props: layerProps, + array: metadataItems, + route: currentTreePrefix + // __PAGE__ shouldn't be shown in a route + .filter((s) => s !== PAGE_SEGMENT_KEY) + .join('/'), + }) for (const key in parallelRoutes) { const childTree = parallelRoutes[key] - const [returnedHead] = await resolveHead( - childTree, - currentParams, - metadataItems - ) + const [returnedHead] = await resolveHead({ + tree: childTree, + parentParams: currentParams, + metadataItems, + treePrefix: currentTreePrefix, + }) if (returnedHead) { return [returnedHead, metadataItems] } @@ -473,7 +491,7 @@ export async function renderToHTMLOrFlight( const isLayout = typeof layout !== 'undefined' const isPage = typeof page !== 'undefined' - const layoutOrPageMod = await getLayoutOrPageModule(tree) + const [layoutOrPageMod] = await getLayoutOrPageModule(tree) /** * Checks if the current segment is a root layout. @@ -979,11 +997,11 @@ export async function renderToHTMLOrFlight( return [actualSegment] } - const [resolvedHead, metadataItems] = await resolveHead( - loaderTree, - {}, - [] - ) + const [resolvedHead, metadataItems] = await resolveHead({ + tree: loaderTree, + parentParams: {}, + metadataItems: [], + }) // Flight data that is going to be passed to the browser. // Currently a single item array but in the future multiple patches might be combined in a single request. const flightData: FlightData = [ @@ -1074,7 +1092,11 @@ export async function renderToHTMLOrFlight( } : {} - const [initialHead, metadataItems] = await resolveHead(loaderTree, {}, []) + const [initialHead, metadataItems] = await resolveHead({ + tree: loaderTree, + parentParams: {}, + metadataItems: [], + }) /** * A new React Component that renders the provided React Component @@ -1156,6 +1178,9 @@ export async function renderToHTMLOrFlight( const bodyResult = getTracer().wrap( AppRenderSpan.getBodyResult, + { + spanName: `render route (app) ${pathname}`, + }, async ({ asNotFound, }: { @@ -1314,7 +1339,7 @@ export async function renderToHTMLOrFlight( } ) - // For action requests, we handle them differently with a sepcial render result. + // For action requests, we handle them differently with a special render result. let actionId = req.headers[ACTION.toLowerCase()] as string const isFormAction = req.method === 'POST' && diff --git a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts index c0732cf0560802..710d82c679207e 100644 --- a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts @@ -38,6 +38,8 @@ import { AppConfig } from '../../../build/utils' import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies' import { NextURL } from '../../web/next-url' import { NextConfig } from '../../config-shared' +import { getTracer } from '../../lib/trace/tracer' +import { AppRouteRouteHandlersSpan } from '../../lib/trace/constants' import { AppRouteRouteDefinition } from '../route-definitions/app-route-route-definition' import { WebNextRequest } from '../../base-http/web' @@ -296,6 +298,20 @@ function proxyRequest( }) } +function getPathnameFromAbsolutePath(absolutePath: string) { + // Remove prefix including app dir + let appDir = '/app/' + if (!absolutePath.includes(appDir)) { + appDir = '\\app\\' + } + const [, ...parts] = absolutePath.split(appDir) + const relativePath = appDir[0] + parts.join(appDir) + + // remove extension + const pathname = relativePath.split('.').slice(0, -1).join('.') + return pathname +} + /** * Validate that the module is exporting methods supported by the handler. * @@ -532,7 +548,16 @@ export class AppRouteRouteHandler implements RouteHandler { module ) - return handle(wrappedRequest, { params }) + return getTracer().trace( + AppRouteRouteHandlersSpan.runHandler, + { + // TODO: propagate this pathname from route matcher + spanName: `executing api route (app) ${getPathnameFromAbsolutePath( + module.resolvedPagePath + )}`, + }, + () => handle(wrappedRequest, { params }) + ) } ) ) diff --git a/packages/next/src/server/lib/app-dir-module.ts b/packages/next/src/server/lib/app-dir-module.ts index 9694fb7d4fd40d..77a35c215f25d0 100644 --- a/packages/next/src/server/lib/app-dir-module.ts +++ b/packages/next/src/server/lib/app-dir-module.ts @@ -13,5 +13,17 @@ export async function getLayoutOrPageModule(loaderTree: LoaderTree) { const { layout, page } = loaderTree[2] const isLayout = typeof layout !== 'undefined' const isPage = typeof page !== 'undefined' - return isLayout ? await layout[0]() : isPage ? await page[0]() : undefined + + let value = undefined + let modType: 'layout' | 'page' | undefined = undefined + if (isLayout) { + value = await layout[0]() + modType = 'layout' + } + if (isPage) { + value = await page[0]() + modType = 'page' + } + + return [value, modType] as const } diff --git a/packages/next/src/server/lib/trace/constants.ts b/packages/next/src/server/lib/trace/constants.ts index 312a2223f22400..a9f2681abae265 100644 --- a/packages/next/src/server/lib/trace/constants.ts +++ b/packages/next/src/server/lib/trace/constants.ts @@ -72,6 +72,7 @@ enum StartServerSpan { enum RenderSpan { getServerSideProps = 'Render.getServerSideProps', + getStaticProps = 'Render.getStaticProps', renderToString = 'Render.renderToString', renderDocument = 'Render.renderDocument', createBodyResult = 'Render.createBodyResult', @@ -88,6 +89,18 @@ enum RouterSpan { executeRoute = 'Router.executeRoute', } +enum NodeSpan { + runHandler = 'Node.runHandler', +} + +enum AppRouteRouteHandlersSpan { + runHandler = 'AppRouteRouteHandlers.runHandler', +} + +enum ResolveMetadataSpan { + generateMetadata = 'ResolveMetadata.generateMetadata', +} + type SpanTypes = | `${BaseServerSpan}` | `${LoadComponentsSpan}` @@ -97,14 +110,21 @@ type SpanTypes = | `${RenderSpan}` | `${RouterSpan}` | `${AppRenderSpan}` + | `${NodeSpan}` + | `${AppRouteRouteHandlersSpan}` + | `${ResolveMetadataSpan}` // This list is used to filter out spans that are not relevant to the user export const NextVanillaSpanAllowlist = [ BaseServerSpan.handleRequest, - NextNodeServerSpan.findPageComponents, - BaseServerSpan.renderToResponse, RenderSpan.getServerSideProps, + RenderSpan.getStaticProps, AppRenderSpan.fetch, + AppRenderSpan.getBodyResult, + RenderSpan.renderDocument, + NodeSpan.runHandler, + AppRouteRouteHandlersSpan.runHandler, + ResolveMetadataSpan.generateMetadata, ] export { @@ -117,4 +137,7 @@ export { RenderSpan, RouterSpan, AppRenderSpan, + NodeSpan, + AppRouteRouteHandlersSpan, + ResolveMetadataSpan, } diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index e6353f8e0800a6..26495dc71bf6e9 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -566,7 +566,7 @@ export async function renderToHTML( await Loadable.preloadAll() // Make sure all dynamic imports are loaded - let isPreview + let isPreview: boolean | undefined = undefined let previewData: PreviewData if ( @@ -761,15 +761,24 @@ export async function renderToHTML( let data: UnwrapPromise> try { - data = await getStaticProps!({ - ...(pageIsDynamic ? { params: query as ParsedUrlQuery } : undefined), - ...(isPreview - ? { preview: true, previewData: previewData } - : undefined), - locales: renderOpts.locales, - locale: renderOpts.locale, - defaultLocale: renderOpts.defaultLocale, - }) + data = await getTracer().trace( + RenderSpan.getStaticProps, + { + spanName: `getStaticProps ${pathname}`, + }, + () => + getStaticProps!({ + ...(pageIsDynamic + ? { params: query as ParsedUrlQuery } + : undefined), + ...(isPreview + ? { preview: true, previewData: previewData } + : undefined), + locales: renderOpts.locales, + locale: renderOpts.locale, + defaultLocale: renderOpts.defaultLocale, + }) + ) } catch (staticPropsError: any) { // remove not found error code to prevent triggering legacy // 404 rendering @@ -1324,6 +1333,9 @@ export async function renderToHTML( const documentResult = await getTracer().trace( RenderSpan.renderDocument, + { + spanName: `render route (pages) ${renderOpts.pathname}`, + }, async () => renderDocument() ) if (!documentResult) { diff --git a/packages/next/src/shared/lib/constants.ts b/packages/next/src/shared/lib/constants.ts index 8dd91173175162..ec306eb4ebafeb 100644 --- a/packages/next/src/shared/lib/constants.ts +++ b/packages/next/src/shared/lib/constants.ts @@ -96,6 +96,7 @@ export const TEMPORARY_REDIRECT_STATUS = 307 export const PERMANENT_REDIRECT_STATUS = 308 export const STATIC_PROPS_ID = '__N_SSG' export const SERVER_PROPS_ID = '__N_SSP' +export const PAGE_SEGMENT_KEY = '__PAGE__' export const GOOGLE_FONT_PROVIDER = 'https://fonts.googleapis.com/' export const OPTIMIZED_FONT_PROVIDERS = [ { url: GOOGLE_FONT_PROVIDER, preconnect: 'https://fonts.gstatic.com' }, diff --git a/test/e2e/opentelemetry/app/app/api/data/route.ts b/test/e2e/opentelemetry/app/api/app/[param]/data/route.ts similarity index 68% rename from test/e2e/opentelemetry/app/app/api/data/route.ts rename to test/e2e/opentelemetry/app/api/app/[param]/data/route.ts index f3d6d572c5a42e..f2b89ee775deef 100644 --- a/test/e2e/opentelemetry/app/app/api/data/route.ts +++ b/test/e2e/opentelemetry/app/api/app/[param]/data/route.ts @@ -1,3 +1,5 @@ export async function GET() { return new Response(JSON.stringify({ test: 'data' })) } + +export const dynamic = 'force-dynamic' diff --git a/test/e2e/opentelemetry/app/app/[param]/layout.tsx b/test/e2e/opentelemetry/app/app/[param]/layout.tsx new file mode 100644 index 00000000000000..09e4a22dda7a03 --- /dev/null +++ b/test/e2e/opentelemetry/app/app/[param]/layout.tsx @@ -0,0 +1,16 @@ +export default async function Layout({ + children, +}: { + children: React.ReactNode +}) { + await new Promise((resolve) => setTimeout(resolve, 5000)) + return ( + + {children} + + ) +} + +export async function generateMetadata() { + return {} +} diff --git a/test/e2e/opentelemetry/app/app/[param]/loading/loading.tsx b/test/e2e/opentelemetry/app/app/[param]/loading/loading.tsx new file mode 100644 index 00000000000000..e23bf121e51813 --- /dev/null +++ b/test/e2e/opentelemetry/app/app/[param]/loading/loading.tsx @@ -0,0 +1,4 @@ +export default function Loading() { + new Promise((resolve) => setTimeout(resolve, 3000)) + return
loading
+} diff --git a/test/e2e/opentelemetry/app/app/[param]/loading/page1/page.tsx b/test/e2e/opentelemetry/app/app/[param]/loading/page1/page.tsx new file mode 100644 index 00000000000000..2fbdff3f713bac --- /dev/null +++ b/test/e2e/opentelemetry/app/app/[param]/loading/page1/page.tsx @@ -0,0 +1,14 @@ +import Link from 'next/link' + +// We want to trace this fetch in runtime +export const dynamic = 'force-dynamic' + +export default async function Page() { + await new Promise((resolve) => setTimeout(resolve, 5000)) + return ( + <> +

app/loading/page1

+ Page2 + + ) +} diff --git a/test/e2e/opentelemetry/app/app/[param]/loading/page2/page.tsx b/test/e2e/opentelemetry/app/app/[param]/loading/page2/page.tsx new file mode 100644 index 00000000000000..ee2b37fe5a6ac2 --- /dev/null +++ b/test/e2e/opentelemetry/app/app/[param]/loading/page2/page.tsx @@ -0,0 +1,14 @@ +import Link from 'next/link' + +// We want to trace this fetch in runtime +export const dynamic = 'force-dynamic' + +export default async function Page() { + await new Promise((resolve) => setTimeout(resolve, 5000)) + return ( + <> +

app/loading/page2

+ Page1 + + ) +} diff --git a/test/e2e/opentelemetry/app/app/rsc-fetch/page.tsx b/test/e2e/opentelemetry/app/app/[param]/rsc-fetch/page.tsx similarity index 62% rename from test/e2e/opentelemetry/app/app/rsc-fetch/page.tsx rename to test/e2e/opentelemetry/app/app/[param]/rsc-fetch/page.tsx index 797bbd84c4a7e7..fbc402b01d6ab7 100644 --- a/test/e2e/opentelemetry/app/app/rsc-fetch/page.tsx +++ b/test/e2e/opentelemetry/app/app/[param]/rsc-fetch/page.tsx @@ -1,6 +1,10 @@ -// We are fetching our own API +// We want to trace this fetch in runtime export const dynamic = 'force-dynamic' +export async function generateMetadata() { + return {} +} + export default async function Page() { const data = await fetch('https://vercel.com') return
{await data.text()}
diff --git a/test/e2e/opentelemetry/app/app/layout.tsx b/test/e2e/opentelemetry/app/app/layout.tsx deleted file mode 100644 index c7295294439d6f..00000000000000 --- a/test/e2e/opentelemetry/app/app/layout.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function Layout({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ) -} diff --git a/test/e2e/opentelemetry/opentelemetry.test.ts b/test/e2e/opentelemetry/opentelemetry.test.ts index b7557201bbcd4d..a323ddc39db87b 100644 --- a/test/e2e/opentelemetry/opentelemetry.test.ts +++ b/test/e2e/opentelemetry/opentelemetry.test.ts @@ -8,17 +8,7 @@ createNextDescribe( { files: __dirname, skipDeployment: true, - dependencies: { - 'fs-extra': '^8.0.0', - '@types/fs-extra': '^8.0.0', - '@opentelemetry/api': '^1.0.0', - '@opentelemetry/core': '^1.0.0', - '@opentelemetry/resources': '^1.0.0', - '@opentelemetry/sdk-trace-base': '^1.0.0', - '@opentelemetry/sdk-trace-node': '^1.0.0', - '@opentelemetry/semantic-conventions': '^1.0.0', - '@opentelemetry/exporter-trace-otlp-http': '^0.34.0', - }, + dependencies: require('./package.json').dependencies, }, ({ next }) => { const getTraces = async (): Promise => { @@ -66,7 +56,11 @@ createNextDescribe( } const sanitizeSpans = (spans: SavedSpan[]) => spans - .sort((a, b) => (a.name ?? '').localeCompare(b.name ?? '')) + .sort((a, b) => + (a.attributes?.['next.span_type'] ?? '').localeCompare( + b.attributes?.['next.span_type'] ?? '' + ) + ) .map(sanitizeSpan) const getSanitizedTraces = async (numberOfRootTraces: number) => { @@ -86,255 +80,253 @@ createNextDescribe( await cleanTraces() }) - it('should have spans when accessing page', async () => { - await next.fetch('/pages') + describe('app router', () => { + it('should handle RSC with fetch', async () => { + await next.fetch('/app/param/rsc-fetch') - expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.status_code": 200, - "http.target": "/pages", - "next.span_name": "GET /pages", - "next.span_type": "BaseServer.handleRequest", + expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.url": "https://vercel.com/", + "net.peer.name": "vercel.com", + "next.span_name": "fetch GET https://vercel.com/", + "next.span_type": "AppRender.fetch", + }, + "kind": 2, + "name": "fetch GET https://vercel.com/", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - "kind": 1, - "name": "GET /pages", - "parentId": undefined, - "status": Object { - "code": 0, + Object { + "attributes": Object { + "next.span_name": "render route (app) /app/[param]/rsc-fetch", + "next.span_type": "AppRender.getBodyResult", + }, + "kind": 0, + "name": "render route (app) /app/[param]/rsc-fetch", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - }, - Object { - "attributes": Object { - "next.pathname": "/pages", - "next.span_name": "rendering page", - "next.span_type": "BaseServer.renderToResponse", + Object { + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/app/param/rsc-fetch", + "next.span_name": "GET /app/param/rsc-fetch", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /app/param/rsc-fetch", + "parentId": undefined, + "status": Object { + "code": 0, + }, }, - "kind": 0, - "name": "rendering page", - "parentId": "[parent-id]", - "status": Object { - "code": 0, + Object { + "attributes": Object { + "next.route": "/app/[param]/layout", + "next.span_name": "generateMetadata /app/[param]/layout", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "kind": 0, + "name": "generateMetadata /app/[param]/layout", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - }, - Object { - "attributes": Object { - "next.route": "/pages", - "next.span_name": "resolving page into components", - "next.span_type": "NextNodeServer.findPageComponents", + Object { + "attributes": Object { + "next.route": "/app/[param]/rsc-fetch/page", + "next.span_name": "generateMetadata /app/[param]/rsc-fetch/page", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "kind": 0, + "name": "generateMetadata /app/[param]/rsc-fetch/page", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - "kind": 0, - "name": "resolving page into components", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) - }) + ] + `) + }) - it('should handle route params', async () => { - await next.fetch('/pages/params/stuff') + it('should handle route handlers in app router', async () => { + await next.fetch('/api/app/param/data') - expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.status_code": 200, - "http.target": "/pages/params/stuff", - "next.span_name": "GET /pages/params/stuff", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /pages/params/stuff", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.pathname": "/pages/params/stuff", - "next.span_name": "rendering page", - "next.span_type": "BaseServer.renderToResponse", - }, - "kind": 0, - "name": "rendering page", - "parentId": "[parent-id]", - "status": Object { - "code": 0, + expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object { + "next.span_name": "executing api route (app) /api/app/[param]/data/route", + "next.span_type": "AppRouteRouteHandlers.runHandler", + }, + "kind": 0, + "name": "executing api route (app) /api/app/[param]/data/route", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - }, - Object { - "attributes": Object { - "next.route": "/pages/params/[param]", - "next.span_name": "resolving page into components", - "next.span_type": "NextNodeServer.findPageComponents", + Object { + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/api/app/param/data", + "next.span_name": "GET /api/app/param/data", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /api/app/param/data", + "parentId": undefined, + "status": Object { + "code": 0, + }, }, - "kind": 0, - "name": "resolving page into components", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + ] + `) + }) }) - it('should handle RSC with fetch', async () => { - await next.fetch('/app/rsc-fetch') + describe('pages', () => { + it('should handle getServerSideProps', async () => { + await next.fetch('/pages/param/getServerSideProps') - expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.url": "https://vercel.com/", - "net.peer.name": "vercel.com", - "next.span_name": "fetch GET https://vercel.com/", - "next.span_type": "AppRender.fetch", - }, - "kind": 2, - "name": "fetch GET https://vercel.com/", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "http.method": "GET", - "http.status_code": 200, - "http.target": "/app/rsc-fetch", - "next.span_name": "GET /app/rsc-fetch", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /app/rsc-fetch", - "parentId": undefined, - "status": Object { - "code": 0, + expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/pages/param/getServerSideProps", + "next.span_name": "GET /pages/param/getServerSideProps", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/param/getServerSideProps", + "parentId": undefined, + "status": Object { + "code": 0, + }, }, - }, - Object { - "attributes": Object { - "next.pathname": "/app/rsc-fetch", - "next.span_name": "rendering page", - "next.span_type": "BaseServer.renderToResponse", + Object { + "attributes": Object { + "next.span_name": "getServerSideProps /pages/[param]/getServerSideProps", + "next.span_type": "Render.getServerSideProps", + }, + "kind": 0, + "name": "getServerSideProps /pages/[param]/getServerSideProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - "kind": 0, - "name": "rendering page", - "parentId": "[parent-id]", - "status": Object { - "code": 0, + Object { + "attributes": Object { + "next.span_name": "render route (pages) /pages/[param]/getServerSideProps", + "next.span_type": "Render.renderDocument", + }, + "kind": 0, + "name": "render route (pages) /pages/[param]/getServerSideProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - }, - Object { - "attributes": Object { - "next.route": "/app/rsc-fetch/page", - "next.span_name": "resolving page into components", - "next.span_type": "NextNodeServer.findPageComponents", - }, - "kind": 0, - "name": "resolving page into components", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) - }) + ] + `) + }) - it('should handle getServerSideProps', async () => { - await next.fetch('/pages/getServerSideProps') + it("should handle getStaticProps when fallback: 'blocking'", async () => { + await next.fetch('/pages/param/getStaticProps') - expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.status_code": 200, - "http.target": "/pages/getServerSideProps", - "next.span_name": "GET /pages/getServerSideProps", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /pages/getServerSideProps", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.span_name": "getServerSideProps /pages/getServerSideProps", - "next.span_type": "Render.getServerSideProps", + expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/pages/param/getStaticProps", + "next.span_name": "GET /pages/param/getStaticProps", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/param/getStaticProps", + "parentId": undefined, + "status": Object { + "code": 0, + }, }, - "kind": 0, - "name": "getServerSideProps /pages/getServerSideProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, + Object { + "attributes": Object { + "next.span_name": "getStaticProps /pages/[param]/getStaticProps", + "next.span_type": "Render.getStaticProps", + }, + "kind": 0, + "name": "getStaticProps /pages/[param]/getStaticProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - }, - Object { - "attributes": Object { - "next.pathname": "/pages/getServerSideProps", - "next.span_name": "rendering page", - "next.span_type": "BaseServer.renderToResponse", + Object { + "attributes": Object { + "next.span_name": "render route (pages) /pages/[param]/getStaticProps", + "next.span_type": "Render.renderDocument", + }, + "kind": 0, + "name": "render route (pages) /pages/[param]/getStaticProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - "kind": 0, - "name": "rendering page", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/getServerSideProps", - "next.span_name": "resolving page into components", - "next.span_type": "NextNodeServer.findPageComponents", - }, - "kind": 0, - "name": "resolving page into components", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) - }) + ] + `) + }) - it('should handle route handlers in app router', async () => { - await next.fetch('/api/pages/basic') + it('should handle api routes in pages', async () => { + await next.fetch('/api/pages/param/basic') - expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.status_code": 200, - "http.target": "/api/pages/basic", - "next.span_name": "GET /api/pages/basic", - "next.span_type": "BaseServer.handleRequest", + expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/api/pages/param/basic", + "next.span_name": "GET /api/pages/param/basic", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /api/pages/param/basic", + "parentId": undefined, + "status": Object { + "code": 0, + }, }, - "kind": 1, - "name": "GET /api/pages/basic", - "parentId": undefined, - "status": Object { - "code": 0, + Object { + "attributes": Object { + "next.span_name": "executing api route (pages) /api/pages/[param]/basic", + "next.span_type": "Node.runHandler", + }, + "kind": 0, + "name": "executing api route (pages) /api/pages/[param]/basic", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, }, - }, - ] - `) + ] + `) + }) }) } ) diff --git a/test/e2e/opentelemetry/package.json b/test/e2e/opentelemetry/package.json new file mode 100644 index 00000000000000..a9c38e4ba3a418 --- /dev/null +++ b/test/e2e/opentelemetry/package.json @@ -0,0 +1,13 @@ +{ + "dependencies": { + "fs-extra": "^8.0.0", + "@types/fs-extra": "^8.0.0", + "@opentelemetry/api": "^1.0.0", + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/sdk-trace-base": "^1.0.0", + "@opentelemetry/sdk-trace-node": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.34.0" + } +} diff --git a/test/e2e/opentelemetry/pages/api/pages/basic.ts b/test/e2e/opentelemetry/pages/api/pages/[param]/basic.ts similarity index 100% rename from test/e2e/opentelemetry/pages/api/pages/basic.ts rename to test/e2e/opentelemetry/pages/api/pages/[param]/basic.ts diff --git a/test/e2e/opentelemetry/pages/pages/getServerSideProps.tsx b/test/e2e/opentelemetry/pages/pages/[param]/getServerSideProps.tsx similarity index 100% rename from test/e2e/opentelemetry/pages/pages/getServerSideProps.tsx rename to test/e2e/opentelemetry/pages/pages/[param]/getServerSideProps.tsx diff --git a/test/e2e/opentelemetry/pages/pages/[param]/getStaticProps.tsx b/test/e2e/opentelemetry/pages/pages/[param]/getStaticProps.tsx new file mode 100644 index 00000000000000..3ba125ed2fe9c6 --- /dev/null +++ b/test/e2e/opentelemetry/pages/pages/[param]/getStaticProps.tsx @@ -0,0 +1,17 @@ +export default function Page() { + return
Page
+} + +export function getStaticProps() { + return { + props: {}, + } +} + +// We don't want to render in build time +export async function getStaticPaths() { + return { + paths: [], + fallback: 'blocking', + } +} diff --git a/test/e2e/opentelemetry/pages/pages/index.tsx b/test/e2e/opentelemetry/pages/pages/index.tsx deleted file mode 100644 index ff7159d9149fee..00000000000000 --- a/test/e2e/opentelemetry/pages/pages/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Page() { - return

hello world

-} diff --git a/test/e2e/opentelemetry/pages/pages/params/[param].tsx b/test/e2e/opentelemetry/pages/pages/params/[param].tsx deleted file mode 100644 index ff7159d9149fee..00000000000000 --- a/test/e2e/opentelemetry/pages/pages/params/[param].tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Page() { - return

hello world

-} diff --git a/test/lib/create-next-install.js b/test/lib/create-next-install.js index 0882b5cb2e32a2..de10ba3e0f3eb7 100644 --- a/test/lib/create-next-install.js +++ b/test/lib/create-next-install.js @@ -74,6 +74,7 @@ async function createNextInstall({ filter: (item) => { return ( !item.includes('node_modules') && + !item.includes('pnpm-lock.yaml') && !item.includes('.DS_Store') && // Exclude Rust compilation files !/next[\\/]build[\\/]swc[\\/]target/.test(item) && From 6a6977cb71b6613593333eba374754d8c72bef4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Wed, 22 Mar 2023 14:39:24 +0100 Subject: [PATCH 607/672] chore: tweak PR labeler pattern (#47395) Co-authored-by: Jan Kaifer --- .github/labeler.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/labeler.json b/.github/labeler.json index 6bf909a239e2c2..364a29f3d6038d 100644 --- a/.github/labeler.json +++ b/.github/labeler.json @@ -3,13 +3,6 @@ "area: create-next-app": ["packages/create-next-app/**"], "area: documentation": ["docs/**", "errors/**"], "area: examples": ["examples/**"], - "area: next/image": [ - "**/*image*", - "**/*image*/**", - "packages/next/src/client/use-intersection.tsx", - "packages/next/src/server/lib/squoosh/", - "packages/next/src/server/serve-static.ts" - ], "area: Font Optimization": ["**/*font*"], "area: tests": ["test/**", "bench/**"], "created-by: Chrome Aurora": [ From e6a3bab489cb39753353b11cefb346ec5f18896b Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 22 Mar 2023 15:15:08 +0100 Subject: [PATCH 608/672] Support HOC cases in server entries (#47379) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../crates/core/src/server_actions.rs | 285 ++++++++++++++---- .../fixture/server-actions/server/21/input.js | 19 ++ .../server-actions/server/21/output.js | 32 ++ .../fixture/server-actions/server/22/input.js | 6 + .../server-actions/server/22/output.js | 17 ++ packages/next/src/client/app-call-server.ts | 4 + packages/next/src/server/app-render/index.tsx | 8 + test/e2e/app-dir/actions/app-action.test.ts | 19 ++ test/e2e/app-dir/actions/app/header/page.js | 12 +- test/e2e/app-dir/actions/app/header/ui.js | 15 +- .../app-dir/actions/app/header/validator.js | 11 + 11 files changed, 366 insertions(+), 62 deletions(-) create mode 100644 packages/next-swc/crates/core/tests/fixture/server-actions/server/21/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/server-actions/server/21/output.js create mode 100644 packages/next-swc/crates/core/tests/fixture/server-actions/server/22/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/server-actions/server/22/output.js create mode 100644 test/e2e/app-dir/actions/app/header/validator.js diff --git a/packages/next-swc/crates/core/src/server_actions.rs b/packages/next-swc/crates/core/src/server_actions.rs index 682be084e3b7f9..9ff89541292a2a 100644 --- a/packages/next-swc/crates/core/src/server_actions.rs +++ b/packages/next-swc/crates/core/src/server_actions.rs @@ -47,6 +47,7 @@ pub fn server_actions( closure_idents: Default::default(), action_idents: Default::default(), exported_idents: Default::default(), + inlined_action_idents: Default::default(), annotations: Default::default(), extra_items: Default::default(), @@ -73,6 +74,7 @@ struct ServerActions { in_action_closure: bool, closure_idents: Vec, action_idents: Vec, + inlined_action_idents: Vec<(Id, Id)>, // (ident, export name) exported_idents: Vec<(Id, String)>, @@ -125,11 +127,17 @@ impl ServerActions { ident: &Ident, function: Option<&mut Box>, arrow: Option<&mut ArrowExpr>, + call_expr_and_ident: Option<(&mut CallExpr, CallExpr, Ident)>, return_paren: bool, ) -> (Option>, Option>) { let action_name: JsWord = gen_ident(&mut self.ident_cnt); let action_ident = private_ident!(action_name.clone()); + if !self.in_action_file { + self.inlined_action_idents + .push((ident.to_id(), action_ident.to_id())); + } + let export_name: JsWord = if self.in_default_export_decl { "default".into() } else { @@ -140,7 +148,7 @@ impl ServerActions { self.export_actions.push(export_name.to_string()); // If it's already a top level function, we don't need to hoist it. - if self.top_level && arrow.is_none() { + if self.top_level && arrow.is_none() && call_expr_and_ident.is_none() { annotate_ident_as_action( &mut self.annotations, ident.clone(), @@ -148,6 +156,7 @@ impl ServerActions { self.file_name.to_string(), export_name.to_string(), false, + None, ); // export const $ACTION_myAction = myAction; @@ -205,6 +214,7 @@ impl ServerActions { self.file_name.to_string(), export_name.to_string(), true, + None, ); if let BlockStmtOrExpr::BlockStmt(block) = &mut *a.body { @@ -304,6 +314,7 @@ impl ServerActions { self.file_name.to_string(), export_name.to_string(), true, + None, ); f.body.visit_mut_with(&mut ClosureReplacer { @@ -391,6 +402,60 @@ impl ServerActions { } return (None, Some(Box::new(new_fn))); + } else if let Some((c, original_call, inner_action_ident)) = call_expr_and_ident { + let mut arrow_annotations = Vec::new(); + annotate_ident_as_action( + &mut arrow_annotations, + ident.clone(), + vec![], + self.file_name.to_string(), + export_name.to_string(), + true, + Some(inner_action_ident), + ); + + self.extra_items + .push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { + span: DUMMY_SP, + decl: Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + kind: VarDeclKind::Const, + declare: Default::default(), + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: action_ident.into(), + init: Some(Box::new(Expr::Call(c.clone()))), + definite: Default::default(), + }], + })), + }))); + + // Create a paren expr to wrap all annotations: + // ($ACTION = hoc(...), $ACTION.$$id = "..", .., $ACTION) + let mut exprs = vec![Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + left: PatOrExpr::Pat(Box::new(Pat::Ident(ident.clone().into()))), + op: op!("="), + right: Box::new(Expr::Call(original_call)), + }))]; + exprs.extend(arrow_annotations.into_iter().map(|a| { + if let Stmt::Expr(ExprStmt { expr, .. }) = a { + expr + } else { + unreachable!() + } + })); + exprs.push(Box::new(Expr::Ident(ident.clone()))); + + let new_paren = ParenExpr { + span: DUMMY_SP, + expr: Box::new(Expr::Seq(SeqExpr { + span: DUMMY_SP, + exprs, + })), + }; + + return (Some(Box::new(new_paren)), None); } } @@ -500,6 +565,7 @@ impl VisitMut for ServerActions { &f.ident, Some(&mut f.function), None, + None, false, ); @@ -611,73 +677,143 @@ impl VisitMut for ServerActions { n.visit_mut_children_with(self); - if !self.in_action_file { - match n { - Expr::Arrow(a) => { - let is_action_fn = self.get_action_info( - if let BlockStmtOrExpr::BlockStmt(block) = &mut *a.body { - Some(block) - } else { - None - }, - true, - ); + if self.in_action_file { + return; + } + + match n { + Expr::Arrow(a) => { + let is_action_fn = self.get_action_info( + if let BlockStmtOrExpr::BlockStmt(block) = &mut *a.body { + Some(block) + } else { + None + }, + true, + ); + + if !is_action_fn { + return; + } - if is_action_fn { - // We need to give a name to the arrow function - // action and hoist it to the top. + // We need to give a name to the arrow function + // action and hoist it to the top. + let action_name = gen_ident(&mut self.ident_cnt); + let ident = private_ident!(action_name); + + let (maybe_new_paren, _) = + self.add_action_annotations_and_maybe_hoist(&ident, None, Some(a), None, true); + + *n = attach_name_to_expr( + ident, + if let Some(new_paren) = maybe_new_paren { + Expr::Paren(*new_paren) + } else { + Expr::Arrow(a.clone()) + }, + &mut self.extra_items, + ); + } + Expr::Fn(f) => { + let is_action_fn = self.get_action_info(f.function.body.as_mut(), true); + + if !is_action_fn { + return; + } + let ident = match f.ident.as_mut() { + None => { let action_name = gen_ident(&mut self.ident_cnt); - let ident = private_ident!(action_name); - - let (maybe_new_paren, _) = self.add_action_annotations_and_maybe_hoist( - &ident, - None, - Some(a), - true, - ); - - *n = attach_name_to_expr( - ident, - if let Some(new_paren) = maybe_new_paren { - Expr::Paren(*new_paren) - } else { - Expr::Arrow(a.clone()) - }, - &mut self.extra_items, - ); + let ident = Ident::new(action_name, DUMMY_SP); + f.ident.insert(ident) } + Some(i) => i, + }; + + let (maybe_new_paren, _) = self.add_action_annotations_and_maybe_hoist( + ident, + Some(&mut f.function), + None, + None, + true, + ); + + if let Some(new_paren) = maybe_new_paren { + *n = attach_name_to_expr( + ident.clone(), + Expr::Paren(*new_paren), + &mut self.extra_items, + ); + } + } + Expr::Call(c) => { + // Here we need to handle HOCs that wrap actions, e.g.: + // withValidator(($ACTION = async function () { ... }, ...)) + + // For now, we only handle the case where the HOC has a single argument: + // the action function. + if c.args.len() != 1 { + return; } - Expr::Fn(f) => { - let is_action_fn = self.get_action_info(f.function.body.as_mut(), true); - - if is_action_fn { - let ident = match f.ident.as_mut() { - None => { - let action_name = gen_ident(&mut self.ident_cnt); - let ident = Ident::new(action_name, DUMMY_SP); - f.ident.insert(ident) - } - Some(i) => i, - }; - let (maybe_new_paren, _) = self.add_action_annotations_and_maybe_hoist( - ident, - Some(&mut f.function), - None, - true, - ); + if let Some(ExprOrSpread { + expr: + box Expr::Paren(ParenExpr { + expr: box Expr::Seq(seq_expr), + .. + }), + .. + }) = c.args.first_mut() + { + if let Some(box Expr::Assign(AssignExpr { + left: PatOrExpr::Pat(box Pat::Ident(pat_id)), + .. + })) = seq_expr.exprs.first_mut() + { + let maybe_action_ident = self + .inlined_action_idents + .iter() + .find(|id| id.0 == pat_id.id.to_id()); + if let Some(action_ident) = maybe_action_ident { + // This is a HOC that wraps an + // action. + // We need to give a name to the result + // action and hoist it to the top. + let action_name = gen_ident(&mut self.ident_cnt); + let ident = private_ident!(action_name); + + let mut new_call = CallExpr { + span: DUMMY_SP, + callee: c.callee.clone(), + args: vec![ExprOrSpread { + spread: None, + expr: Box::new(Expr::Ident(action_ident.1.clone().into())), + }], + type_args: Default::default(), + }; + + let (maybe_new_paren, _) = self.add_action_annotations_and_maybe_hoist( + &ident, + None, + None, + Some((&mut new_call, c.clone(), action_ident.0.clone().into())), + true, + ); - if let Some(new_paren) = maybe_new_paren { *n = attach_name_to_expr( - ident.clone(), - Expr::Paren(*new_paren), + ident, + if let Some(new_paren) = maybe_new_paren { + // Keep the original $$bound value. + Expr::Paren(*new_paren) + } else { + Expr::Call(c.clone()) + }, &mut self.extra_items, ); } } } - _ => {} } + _ => {} } } @@ -720,6 +856,7 @@ impl VisitMut for ServerActions { match &**init { Expr::Fn(_f) => {} Expr::Arrow(_a) => {} + Expr::Call(_c) => {} _ => { disallowed_export_span = *span; } @@ -813,6 +950,20 @@ impl VisitMut for ServerActions { // export default foo self.exported_idents.push((ident.to_id(), "default".into())); } + Expr::Call(call) => { + // export default fn() + let new_ident = + Ident::new(gen_ident(&mut self.ident_cnt), DUMMY_SP); + + self.exported_idents + .push((new_ident.to_id(), "default".into())); + + *default_expr.expr = attach_name_to_expr( + new_ident, + Expr::Call(call.clone()), + &mut self.extra_items, + ); + } _ => { disallowed_export_span = default_expr.span; } @@ -857,6 +1008,7 @@ impl VisitMut for ServerActions { self.file_name.to_string(), export_name.to_string(), false, + None, ); if !self.config.is_server { let params_ident = private_ident!("args"); @@ -1078,6 +1230,7 @@ fn annotate_ident_as_action( file_name: String, export_name: String, has_bound: bool, + re_annotate_action: Option, ) { // myAction.$$typeof = Symbol.for('react.server.reference'); annotations.push(annotate( @@ -1109,11 +1262,23 @@ fn annotate_ident_as_action( annotations.push(annotate( &ident, "$$bound", - ArrayLit { - span: DUMMY_SP, - elems: bound, - } - .into(), + if let Some(re_annotate_ident) = re_annotate_action { + Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(re_annotate_ident)), + prop: MemberProp::Ident(Ident { + sym: "$$bound".into(), + span: DUMMY_SP, + optional: false, + }), + })) + } else { + ArrayLit { + span: DUMMY_SP, + elems: bound, + } + .into() + }, )); // If an action doesn't have any bound values, we add a special property diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/21/input.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/21/input.js new file mode 100644 index 00000000000000..19b94c3e2edfb4 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/21/input.js @@ -0,0 +1,19 @@ +import { validator, another } from 'auth' + +const x = 1 + +export default function Page () { + const y = 1 + return +} + +validator(async () => { + 'use server' +}) + +another(validator(async () => { + 'use server' +})) diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/21/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/21/output.js new file mode 100644 index 00000000000000..715abd4dd14821 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/21/output.js @@ -0,0 +1,32 @@ +/* __next_internal_action_entry_do_not_use__ $$ACTION_1,$$ACTION_3,$$ACTION_5,$$ACTION_7,$$ACTION_9,$$ACTION_11,$$ACTION_13 */ import { validator, another } from 'auth'; +const x = 1; +export default function Page() { + const y = 1; + return ; +} +export async function $$ACTION_1(closure, z = closure[1]) { + return x + closure[0] + z; +} +var $$ACTION_0; +export const $$ACTION_3 = validator($$ACTION_1); +var $$ACTION_2; +$$ACTION_6 = validator(($$ACTION_4 = async ()=>$$ACTION_5($$ACTION_4.$$bound), $$ACTION_4.$$typeof = Symbol.for("react.server.reference"), $$ACTION_4.$$id = "1383664d1dc2d9cfe33b88df3fa0eaffef8b99bc", $$ACTION_4.$$bound = [ + y +], $$ACTION_4)), $$ACTION_6.$$typeof = Symbol.for("react.server.reference"), $$ACTION_6.$$id = "faf016739650cb4995340c9d9ab06ce1c9407fa0", $$ACTION_6.$$bound = $$ACTION_4.$$bound, $$ACTION_6; +export const $$ACTION_5 = async (closure)=>{}; +var $$ACTION_4; +export const $$ACTION_7 = validator($$ACTION_5); +var $$ACTION_6; +$$ACTION_12 = another(($$ACTION_10 = validator(($$ACTION_8 = async ()=>$$ACTION_9($$ACTION_8.$$bound), $$ACTION_8.$$typeof = Symbol.for("react.server.reference"), $$ACTION_8.$$id = "0d0ca9684921f1c6dc36a2ec55ce57ba31407820", $$ACTION_8.$$bound = [ + y +], $$ACTION_8)), $$ACTION_10.$$typeof = Symbol.for("react.server.reference"), $$ACTION_10.$$id = "dd70487b74c2c510c55e3e68aa3614cfa780850d", $$ACTION_10.$$bound = $$ACTION_8.$$bound, $$ACTION_10)), $$ACTION_12.$$typeof = Symbol.for("react.server.reference"), $$ACTION_12.$$id = "57cbac1f8911efd298cb885cba89919b14153dc1", $$ACTION_12.$$bound = $$ACTION_10.$$bound, $$ACTION_12; +export const $$ACTION_9 = async (closure)=>{}; +var $$ACTION_8; +export const $$ACTION_11 = validator($$ACTION_9); +var $$ACTION_10; +export const $$ACTION_13 = another($$ACTION_11); +var $$ACTION_12; diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/22/input.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/22/input.js new file mode 100644 index 00000000000000..97cc5f4aba3a25 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/22/input.js @@ -0,0 +1,6 @@ +'use server' + +import { validator } from 'auth' + +export const action = validator(async () => {}) +export default validator(async () => {}) diff --git a/packages/next-swc/crates/core/tests/fixture/server-actions/server/22/output.js b/packages/next-swc/crates/core/tests/fixture/server-actions/server/22/output.js new file mode 100644 index 00000000000000..8b8e95091bf488 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/server-actions/server/22/output.js @@ -0,0 +1,17 @@ +/* __next_internal_action_entry_do_not_use__ action,default */ import { validator } from 'auth'; +export const action = validator(async ()=>{}); +export default $$ACTION_0 = validator(async ()=>{}); +var $$ACTION_0; +import ensureServerEntryExports from "private-next-rsc-action-proxy"; +ensureServerEntryExports([ + action, + $$ACTION_0 +]); +action.$$typeof = Symbol.for("react.server.reference"); +action.$$id = "f14702b5a021dd117f7ec7a3c838f397c2046d3b"; +action.$$bound = []; +action.$$with_bound = false; +$$ACTION_0.$$typeof = Symbol.for("react.server.reference"); +$$ACTION_0.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d"; +$$ACTION_0.$$bound = []; +$$ACTION_0.$$with_bound = false; diff --git a/packages/next/src/client/app-call-server.ts b/packages/next/src/client/app-call-server.ts index 53ac4efd08d28c..3bdf12104ab92c 100644 --- a/packages/next/src/client/app-call-server.ts +++ b/packages/next/src/client/app-call-server.ts @@ -14,5 +14,9 @@ export async function callServer(id: string, bound: any[]) { }), }) + if (!res.ok) { + throw new Error(await res.text()) + } + return (await res.json())[0] } diff --git a/packages/next/src/server/app-render/index.tsx b/packages/next/src/server/app-render/index.tsx index c0915334034067..3812493f2f323e 100644 --- a/packages/next/src/server/app-render/index.tsx +++ b/packages/next/src/server/app-render/index.tsx @@ -1398,6 +1398,14 @@ export async function renderToHTMLOrFlight( res.statusCode = 404 return new RenderResult(await bodyResult({ asNotFound: true })) } + + if (isFetchAction) { + res.statusCode = 500 + return new RenderResult( + (err as Error)?.message ?? 'Internal Server Error' + ) + } + throw err } } else { diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 804e425aaad38e..629f6f580afb8c 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -65,6 +65,25 @@ createNextDescribe( }, 'my-not-found') }) + it('should support hoc auth wrappers', async () => { + const browser = await next.browser('/header') + await await browser.eval(`document.cookie = 'auth=0'`) + + await browser.elementByCss('#authed').click() + + await check(() => { + return browser.elementByCss('h1').text() + }, 'Error: Unauthorized request') + + await await browser.eval(`document.cookie = 'auth=1'`) + + await browser.elementByCss('#authed').click() + + await check(() => { + return browser.elementByCss('h1').text() + }, 'HELLO, WORLD') + }) + it('should support importing actions in client components', async () => { const browser = await next.browser('/client') diff --git a/test/e2e/app-dir/actions/app/header/page.js b/test/e2e/app-dir/actions/app/header/page.js index 264f33e0abde7d..f868c82283ff8d 100644 --- a/test/e2e/app-dir/actions/app/header/page.js +++ b/test/e2e/app-dir/actions/app/header/page.js @@ -1,7 +1,17 @@ import UI from './ui' import { getCookie, getHeader } from './actions' +import { validator } from './validator' export default function Page() { - return + return ( + { + 'use server' + return str.toUpperCase() + })} + /> + ) } diff --git a/test/e2e/app-dir/actions/app/header/ui.js b/test/e2e/app-dir/actions/app/header/ui.js index 6a8ea797779c78..2c1d0edbf871ae 100644 --- a/test/e2e/app-dir/actions/app/header/ui.js +++ b/test/e2e/app-dir/actions/app/header/ui.js @@ -2,7 +2,7 @@ import { useState } from 'react' -export default function UI({ getCookie, getHeader }) { +export default function UI({ getCookie, getHeader, getAuthedUppercase }) { const [result, setResult] = useState('') return ( @@ -29,6 +29,19 @@ export default function UI({ getCookie, getHeader }) { > getHeader +
) } diff --git a/test/e2e/app-dir/actions/app/header/validator.js b/test/e2e/app-dir/actions/app/header/validator.js new file mode 100644 index 00000000000000..3c3dc00529edf8 --- /dev/null +++ b/test/e2e/app-dir/actions/app/header/validator.js @@ -0,0 +1,11 @@ +import { cookies } from 'next/headers' + +export function validator(action) { + return async function (...args) { + const auth = cookies().get('auth') + if (auth?.value !== '1') { + throw new Error('Unauthorized request') + } + return action(...args) + } +} From bbd79ac9977e03010e09ff90d933f2ec614b031f Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 22 Mar 2023 15:19:50 +0100 Subject: [PATCH 609/672] Support dynamic routes for social images and icons (#47372) Allow image responses returning from dynamic image routes for og/twitter images, and icon/apple-icon images. This PR supports the basic functionalities for nodejs runtime of image routes. `@vercel/og` is able to be leveraged for generating dynamic image responses. Close NEXT-264 Close NEXT-266 --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- package.json | 2 +- .../webpack/loaders/metadata/discover.ts | 48 +++++++--- .../build/webpack/loaders/next-app-loader.ts | 4 + .../loaders/next-metadata-route-loader.ts | 39 ++++++-- .../webpack/plugins/middleware-plugin.ts | 2 +- .../src/lib/metadata/is-metadata-route.ts | 19 ++-- .../next/src/lib/metadata/resolve-metadata.ts | 15 +-- pnpm-lock.yaml | 52 ++++++----- .../app/apple-icon.tsx | 24 +++++ .../app/dynamic/[size]/opengraph-image.tsx | 34 +++++++ .../app/dynamic/[size]/page.tsx | 3 + .../metadata-dynamic-routes/app/icon.tsx | 25 +++++ .../app/opengraph-image.tsx | 23 +++++ .../metadata-dynamic-routes/app/page.tsx | 1 + .../app/twitter-image.tsx | 25 +++++ .../metadata-dynamic-routes/index.test.ts | 92 ++++++++++++++++++- 16 files changed, 351 insertions(+), 57 deletions(-) create mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx create mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx create mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx create mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx create mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx create mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx diff --git a/package.json b/package.json index e958e56ad6cd9c..f915d6d2fed251 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "@typescript-eslint/eslint-plugin": "4.29.1", "@typescript-eslint/parser": "4.29.1", "@vercel/fetch": "6.1.1", - "@vercel/og": "0.0.20", + "@vercel/og": "0.4.0", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/floating-point-hex-parser": "1.11.1", "@webassemblyjs/helper-api-error": "1.11.1", diff --git a/packages/next/src/build/webpack/loaders/metadata/discover.ts b/packages/next/src/build/webpack/loaders/metadata/discover.ts index 3081ded78e92c6..375d55f8add0bd 100644 --- a/packages/next/src/build/webpack/loaders/metadata/discover.ts +++ b/packages/next/src/build/webpack/loaders/metadata/discover.ts @@ -80,11 +80,13 @@ export async function createStaticMetadataFromRoute( resolvePath, isRootLayer, loaderContext, + pageExtensions, }: { route: string resolvePath: (pathname: string) => Promise isRootLayer: boolean loaderContext: webpack.LoaderContext + pageExtensions: string[] } ) { let hasStaticMetadataFiles = false @@ -106,22 +108,46 @@ export async function createStaticMetadataFromRoute( const resolvedMetadataFiles = await enumMetadataFiles( resolvedDir, STATIC_METADATA_IMAGES[type].filename, - STATIC_METADATA_IMAGES[type].extensions, + pageExtensions.concat(STATIC_METADATA_IMAGES[type].extensions), opts ) resolvedMetadataFiles .sort((a, b) => a.localeCompare(b)) .forEach((filepath) => { - const imageModule = `() => import(/* webpackMode: "eager" */ ${JSON.stringify( - `next-metadata-image-loader?${stringify({ - route, - numericSizes: - type === 'twitter' || type === 'opengraph' ? '1' : undefined, - type, - })}!` + - filepath + - METADATA_RESOURCE_QUERY - )})` + const [filename, ext] = path.basename(filepath).split('.') + const isDynamicResource = pageExtensions.includes(ext) + + // imageModule type: () => Promise + const imageModule = isDynamicResource + ? `(async () => { + let { alt, size, contentType } = await import(/* webpackMode: "lazy" */ ${JSON.stringify( + filepath + )}) + + const props = { + alt, + type: contentType, + url: ${JSON.stringify(route + '/' + filename)}, + } + if (size) { + ${ + type === 'twitter' || type === 'opengraph' + ? 'props.width = size.width; props.height = size.height;' + : 'props.sizes = size.width + "x" + size.height;' + } + } + return props + })` + : `() => import(/* webpackMode: "eager" */ ${JSON.stringify( + `next-metadata-image-loader?${stringify({ + route, + numericSizes: + type === 'twitter' || type === 'opengraph' ? '1' : undefined, + type, + })}!` + + filepath + + METADATA_RESOURCE_QUERY + )})` hasStaticMetadataFiles = true if (type === 'favicon') { diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index b32bdf0c599b41..223d49000d3322 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -111,6 +111,7 @@ async function createTreeCodeFromPath( resolvePath, resolveParallelSegments, loaderContext, + pageExtensions, }: { resolver: ( pathname: string, @@ -121,6 +122,7 @@ async function createTreeCodeFromPath( pathname: string ) => [key: string, segment: string | string[]][] loaderContext: webpack.LoaderContext + pageExtensions: string[] } ) { const splittedPath = pagePath.split(/[\\/]/) @@ -161,6 +163,7 @@ async function createTreeCodeFromPath( resolvePath, isRootLayer, loaderContext, + pageExtensions, }) } } catch (err: any) { @@ -379,6 +382,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { resolvePath: (pathname: string) => resolve(this.rootContext, pathname), resolveParallelSegments, loaderContext: this, + pageExtensions, }) if (!rootLayout) { diff --git a/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts b/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts index 6b3797e8e2b13b..a78e39bd23a35d 100644 --- a/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts @@ -42,7 +42,6 @@ const filePath = fileURLToPath(resourceUrl).replace(${JSON.stringify( )}, '') const buffer = fs.readFileSync(filePath) - export function GET() { return new NextResponse(buffer, { headers: { @@ -56,7 +55,7 @@ export const dynamic = 'force-static' ` } -function getDynamicRouteCode(resourcePath: string) { +function getDynamicTextRouteCode(resourcePath: string) { return `\ import { NextResponse } from 'next/server' import handler from ${JSON.stringify(resourcePath)} @@ -79,6 +78,19 @@ export async function GET() { ` } +function getDynamicImageRouteCode(resourcePath: string) { + return `\ +import { NextResponse } from 'next/server' +import handler from ${JSON.stringify(resourcePath)} + +export async function GET(req, ctx) { + const res = await handler({ params: ctx.params }) + res.headers.set('Cache-Control', 'public, max-age=0, must-revalidate') + return res +} +` +} + // `import.meta.url` is the resource name of the current module. // When it's static route, it could be favicon.ico, sitemap.xml, robots.txt etc. // TODO-METADATA: improve the cache control strategy @@ -87,12 +99,23 @@ const nextMetadataRouterLoader: webpack.LoaderDefinitionFunction r.test(appDirRelativePath)) } +/* + * Remove the 'app' prefix or '/route' suffix, only check the route name since they're only allowed in root app directory + * e.g. + * /app/robots -> /robots + * app/robots -> /robots + * /robots -> /robots + */ export function isMetadataRoute(route: string): boolean { - // Remove the 'app' prefix or '/route' suffix, only check the route name since they're only allowed in root app directory - const page = route.replace(/^\/?app/, '').replace(/\/route$/, '') + let page = route.replace(/^\/?app\//, '').replace(/\/route$/, '') + if (page[0] !== '/') page = '/' + page return ( !page.endsWith('/page') && diff --git a/packages/next/src/lib/metadata/resolve-metadata.ts b/packages/next/src/lib/metadata/resolve-metadata.ts index d369bf6fc82f1d..0ad2d6bcee07f3 100644 --- a/packages/next/src/lib/metadata/resolve-metadata.ts +++ b/packages/next/src/lib/metadata/resolve-metadata.ts @@ -45,9 +45,13 @@ function mergeStaticMetadata( if (!staticFilesMetadata) return const { icon, apple, opengraph, twitter } = staticFilesMetadata if (icon || apple) { - if (!metadata.icons) metadata.icons = { icon: [], apple: [] } - if (icon) metadata.icons.icon.push(...icon) - if (apple) metadata.icons.apple.push(...apple) + // if (!metadata.icons) + metadata.icons = { + icon: icon || [], + apple: apple || [], + } + // if (icon) metadata.icons.icon.push(...icon) + // if (apple) metadata.icons.apple.push(...apple) } if (twitter) { const resolvedTwitter = resolveTwitter( @@ -215,9 +219,8 @@ async function collectStaticImagesFiles( if (!metadata?.[type]) return undefined const iconPromises = metadata[type as 'icon' | 'apple'].map( - // TODO-APP: share the typing between next-metadata-image-loader and here - async (iconResolver: any) => - interopDefault(await iconResolver()) as MetadataImageModule + async (iconResolver: () => Promise) => + interopDefault(await iconResolver()) ) return iconPromises?.length > 0 ? await Promise.all(iconPromises) : undefined } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6eab37e04e64b..57be1a8553e049 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,7 +55,7 @@ importers: '@typescript-eslint/eslint-plugin': 4.29.1 '@typescript-eslint/parser': 4.29.1 '@vercel/fetch': 6.1.1 - '@vercel/og': 0.0.20 + '@vercel/og': 0.4.0 '@webassemblyjs/ast': 1.11.1 '@webassemblyjs/floating-point-hex-parser': 1.11.1 '@webassemblyjs/helper-api-error': 1.11.1 @@ -232,7 +232,7 @@ importers: '@typescript-eslint/eslint-plugin': 4.29.1_qxyn66xcaddhgaahwkbomftvi4 '@typescript-eslint/parser': 4.29.1_6x3mpmmsttbpxxsctsorxedanu '@vercel/fetch': 6.1.1_fii5qhbaymjqmfm7e2spxc5z4m - '@vercel/og': 0.0.20 + '@vercel/og': 0.4.0 '@webassemblyjs/ast': 1.11.1 '@webassemblyjs/floating-point-hex-parser': 1.11.1 '@webassemblyjs/helper-api-error': 1.11.1 @@ -6308,8 +6308,8 @@ packages: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} dev: true - /@resvg/resvg-wasm/2.0.0-alpha.4: - resolution: {integrity: sha512-pWIG9a/x1ky8gXKRhPH1OPKpHFoMN1ISLbJ+O+gPXQHIAKhNd5I28RlWf7q576hAOQA9JZTlo3p/M2uyLzJmmw==} + /@resvg/resvg-wasm/2.4.1: + resolution: {integrity: sha512-yi6R0HyHtsoWTRA06Col4WoDs7SvlXU3DLMNP2bdAgs7HK18dTEVl1weXgxRzi8gwLteGUbIg29zulxIB3GSdg==} engines: {node: '>= 10'} dev: true @@ -7494,10 +7494,6 @@ packages: '@types/yargs-parser': 13.1.0 dev: true - /@types/yoga-layout/1.9.2: - resolution: {integrity: sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==} - dev: true - /@typescript-eslint/eslint-plugin/4.29.1_qxyn66xcaddhgaahwkbomftvi4: resolution: {integrity: sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw==} engines: {node: ^10.12.0 || >=12.0.0} @@ -7735,13 +7731,13 @@ packages: - supports-color dev: true - /@vercel/og/0.0.20: - resolution: {integrity: sha512-089P+TfqWz0xBxjOvOhkZIDDtfrLcye94H4IZ+SqxoGPWpNGXaBvRJER/z5SoJxJRcCAL8tPiK5zdjRskM6tLw==} + /@vercel/og/0.4.0: + resolution: {integrity: sha512-FFjXYCD5ZM0VotC9niy11qf4m6D99JVQ73P/uCLJl/r2PeOj0l26xwTEQ4HHJ/yZ6ncByCNoWAjk+S0fjMJmwg==} engines: {node: '>=16'} dependencies: - '@resvg/resvg-wasm': 2.0.0-alpha.4 - satori: 0.0.43 - yoga-wasm-web: 0.1.2 + '@resvg/resvg-wasm': 2.4.1 + satori: 0.4.1 + yoga-wasm-web: 0.3.0 dev: true /@webassemblyjs/ast/1.11.1: @@ -8834,6 +8830,11 @@ packages: mixin-deep: 1.3.2 pascalcase: 0.1.1 + /base64-js/0.0.8: + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} + engines: {node: '>= 0.4'} + dev: true + /base64-js/1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true @@ -16408,6 +16409,13 @@ packages: resolution: {integrity: sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==} dev: true + /linebreak/1.1.0: + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} + dependencies: + base64-js: 0.0.8 + unicode-trie: 2.0.0 + dev: true + /lines-and-columns/1.1.6: resolution: {integrity: sha512-8ZmlJFVK9iCmtLz19HpSsR8HaAMWBT284VMNednLwlIMDP2hJDCIhUp0IZ2xUcZ+Ob6BM0VvCSJwzASDM45NLQ==} @@ -22269,8 +22277,8 @@ packages: immutable: 4.1.0 source-map-js: 1.0.2 - /satori/0.0.43: - resolution: {integrity: sha512-SzYwr+LsELWRJU9KMviEOE9TdShry+R5AdS54YQvgAVKFDN4yniAIzwQk1/z2TtIx0ceUT9zTeosWAoWvJBEtQ==} + /satori/0.4.1: + resolution: {integrity: sha512-uQm4+vQj57E9PO/ASAlxsRb+78fHkRUmkNLBBmfuEeGNLGqJ9ufYU7TzYP4XH60PLHYt9Wz1jSsgcAe2cz7+ng==} engines: {node: '>=16'} dependencies: '@shuding/opentype.js': 1.4.0-beta.0 @@ -22278,8 +22286,9 @@ packages: css-box-shadow: 1.0.0-3 css-to-react-native: 3.0.0 emoji-regex: 10.2.1 + linebreak: 1.1.0 postcss-value-parser: 4.2.0 - yoga-layout-prebuilt: 1.10.0 + yoga-wasm-web: 0.3.3 dev: true /sax/1.2.4: @@ -25392,15 +25401,12 @@ packages: engines: {node: '>=12.20'} dev: true - /yoga-layout-prebuilt/1.10.0: - resolution: {integrity: sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==} - engines: {node: '>=8'} - dependencies: - '@types/yoga-layout': 1.9.2 + /yoga-wasm-web/0.3.0: + resolution: {integrity: sha512-rD3L4jyMlO1m+RWU60lNwZQK5zmzglCV5fI1gTRikmpv3YzmNIZQbjyfE6cMNb9Xaly/C1SwemYGbsiOekMvnQ==} dev: true - /yoga-wasm-web/0.1.2: - resolution: {integrity: sha512-8SkgawHcA0RUbMrnhxbaQkZDBi8rMed8pQHixkFF9w32zGhAwZ9/cOHWlpYfr6RCx42Yp3siV45/jPEkJxsk6w==} + /yoga-wasm-web/0.3.3: + resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} dev: true /zod/3.21.4: diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx new file mode 100644 index 00000000000000..683dd12fcc6f14 --- /dev/null +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx @@ -0,0 +1,24 @@ +import { ImageResponse } from '@vercel/og' + +export const contentType = 'image/png' + +export default function appleIcon() { + return new ImageResponse( + ( +
+ Apple Icon +
+ ) + ) +} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx new file mode 100644 index 00000000000000..7b5859a8293ffb --- /dev/null +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx @@ -0,0 +1,34 @@ +import { ImageResponse } from '@vercel/og' + +export const alt = 'Open Graph' + +export default function og({ params }) { + const big = params.size === 'big' + const background = big ? 'orange' : '#000' + return new ImageResponse( + ( +
+
+
+ ), + { + width: big === true ? 1200 : 600, + height: big === true ? 630 : 315, + } + ) +} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx new file mode 100644 index 00000000000000..e1b5bd8f2ce11d --- /dev/null +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx @@ -0,0 +1,3 @@ +export default function page() { + return <>dynamic +} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx new file mode 100644 index 00000000000000..1205089f21319d --- /dev/null +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx @@ -0,0 +1,25 @@ +import { ImageResponse } from '@vercel/og' + +export const contentType = 'image/png' +export const size = { width: 512, height: 512 } + +export default function icon() { + return new ImageResponse( + ( +
+ Icon +
+ ) + ) +} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx new file mode 100644 index 00000000000000..fd72c819260e17 --- /dev/null +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx @@ -0,0 +1,23 @@ +import { ImageResponse } from '@vercel/og' + +export const alt = 'Open Graph' + +export default function og() { + return new ImageResponse( + ( +
+ Open Graph +
+ ) + ) +} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx index eba737535cc7e9..c2dd96ac06ceaf 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx @@ -5,5 +5,6 @@ export default function Page() { } export const metadata = { + metadataBase: new URL('https://deploy-preview-abc.vercel.app'), title: 'index page', } diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx new file mode 100644 index 00000000000000..0190d601348c94 --- /dev/null +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx @@ -0,0 +1,25 @@ +import { ImageResponse } from '@vercel/og' + +export const alt = 'Twitter' +export const size = { width: 1600, height: 900 } + +export default function twitter() { + return new ImageResponse( + ( +
+ Twitter Image +
+ ), + size + ) +} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts b/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts index 4b49a9e9e84670..644151bddd2340 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts +++ b/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts @@ -1,13 +1,17 @@ import { createNextDescribe } from 'e2e-utils' +import imageSize from 'image-size' createNextDescribe( 'app dir - metadata dynamic routes', { files: __dirname, skipDeployment: true, + dependencies: { + '@vercel/og': '0.4.0', + }, }, ({ next }) => { - describe('dynamic routes', () => { + describe('text routes', () => { it('should handle robots.[ext] dynamic routes', async () => { const res = await next.fetch('/robots.txt') const text = await res.text() @@ -56,7 +60,9 @@ createNextDescribe( " `) }) + }) + describe('social image routes', () => { it('should handle manifest.[ext] dynamic routes', async () => { const res = await next.fetch('/manifest.webmanifest') const json = await res.json() @@ -85,6 +91,90 @@ createNextDescribe( ], }) }) + + it('should render og image with opengraph-image dynamic routes', async () => { + const res = await next.fetch('/opengraph-image') + + expect(res.headers.get('content-type')).toBe('image/png') + expect(res.headers.get('cache-control')).toBe( + 'public, max-age=0, must-revalidate' + ) + }) + + it('should render og image with twitter-image dynamic routes', async () => { + const res = await next.fetch('/twitter-image') + + expect(res.headers.get('content-type')).toBe('image/png') + expect(res.headers.get('cache-control')).toBe( + 'public, max-age=0, must-revalidate' + ) + }) + + it('should support params as argument in dynamic routes', async () => { + const bufferBig = await ( + await next.fetch('/dynamic/big/opengraph-image') + ).buffer() + const bufferSmall = await ( + await next.fetch('/dynamic/small/opengraph-image') + ).buffer() + + const sizeBig = imageSize(bufferBig) + const sizeSmall = imageSize(bufferSmall) + expect([sizeBig.width, sizeBig.height]).toEqual([1200, 630]) + expect([sizeSmall.width, sizeSmall.height]).toEqual([600, 315]) + }) + }) + + describe('icon image routes', () => { + it('should render icon with dynamic routes', async () => { + const res = await next.fetch('/icon') + + expect(res.headers.get('content-type')).toBe('image/png') + expect(res.headers.get('cache-control')).toBe( + 'public, max-age=0, must-revalidate' + ) + }) + + it('should render apple icon with dynamic routes', async () => { + const res = await next.fetch('/apple-icon') + + expect(res.headers.get('content-type')).toBe('image/png') + expect(res.headers.get('cache-control')).toBe( + 'public, max-age=0, must-revalidate' + ) + }) + }) + + it('should inject dynamic metadata properly to head', async () => { + const $ = await next.render$('/') + const $icon = $('link[rel="icon"]') + const $appleIcon = $('link[rel="apple-touch-icon"]') + const ogImageUrl = $('meta[property="og:image"]').attr('content') + const twitterImageUrl = $('meta[name="twitter:image"]').attr('content') + + // non absolute urls + expect($icon.attr('href')).toBe('/icon') + expect($icon.attr('sizes')).toBe('512x512') + expect($icon.attr('type')).toBe('image/png') + expect($appleIcon.attr('href')).toBe('/apple-icon') + expect($appleIcon.attr('sizes')).toBe(undefined) + expect($appleIcon.attr('type')).toBe('image/png') + + // absolute urls + expect(ogImageUrl).toBe( + 'https://deploy-preview-abc.vercel.app/opengraph-image' + ) + expect(twitterImageUrl).toBe( + 'https://deploy-preview-abc.vercel.app/twitter-image' + ) + + // alt text + expect($('meta[property="og:image:alt"]').attr('content')).toBe( + 'Open Graph' + ) + expect($('meta[name="twitter:image:alt"]').attr('content')).toBe( + 'Twitter' + ) }) } ) From 1a85bb7c655a602eb8573f182fc54310df37558f Mon Sep 17 00:00:00 2001 From: furkan mavili Date: Wed, 22 Mar 2023 21:20:22 +0300 Subject: [PATCH 610/672] chore: fix localhost port (#47413) Development server actually running on port 3000. ![image](https://user-images.githubusercontent.com/61994117/226997492-7d61d401-bcdc-47b0-ac5b-48469c5a88b8.png) --- examples/with-static-export/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-static-export/README.md b/examples/with-static-export/README.md index 38dc481c39da4d..6191d0e88c9633 100644 --- a/examples/with-static-export/README.md +++ b/examples/with-static-export/README.md @@ -2,7 +2,7 @@ This example show how to export to static HTML files your Next.js application fetching data from an API to generate a dynamic list of pages. -When trying to run `npm start` it will build and export your pages into the `out` folder and serve them on `localhost:5000`. +When trying to run `npm start` it will build and export your pages into the `out` folder and serve them on `localhost:3000`. ## Deploy your own From 7060b8c9ef46a3395b2e44dfaa3de7635218edde Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 22 Mar 2023 15:24:09 -0400 Subject: [PATCH 611/672] Revert "Support dynamic routes for social images and icons" (#47416 Reverts vercel/next.js#47372 ``` Error occurred prerendering page "/apple-icon". Read more: https://nextjs.org/docs/messages/prerender-error Error: The `ImageResponse` API is not supported in this runtime, use the `unstable_createNodejsStream` API instead or switch to the Vercel Edge Runtime. at new ImageResponse (/tmp/next-install-db63e2a2f25e9feda48affa69456fcbdde8d89bf94645e42abd2aa522224f432/.next/server/chunks/558.js:26416:19) at appleIcon (/tmp/next-install-db63e2a2f25e9feda48affa69456fcbdde8d89bf94645e42abd2aa522224f432/.next/server/app/apple-icon/route.js:127:12) ``` https://github.com/vercel/next.js/actions/runs/4490842502/jobs/7899302486#step:6:305 --- package.json | 2 +- .../webpack/loaders/metadata/discover.ts | 48 +++------- .../build/webpack/loaders/next-app-loader.ts | 4 - .../loaders/next-metadata-route-loader.ts | 39 ++------ .../webpack/plugins/middleware-plugin.ts | 2 +- .../src/lib/metadata/is-metadata-route.ts | 19 ++-- .../next/src/lib/metadata/resolve-metadata.ts | 15 ++- pnpm-lock.yaml | 52 +++++------ .../app/apple-icon.tsx | 24 ----- .../app/dynamic/[size]/opengraph-image.tsx | 34 ------- .../app/dynamic/[size]/page.tsx | 3 - .../metadata-dynamic-routes/app/icon.tsx | 25 ----- .../app/opengraph-image.tsx | 23 ----- .../metadata-dynamic-routes/app/page.tsx | 1 - .../app/twitter-image.tsx | 25 ----- .../metadata-dynamic-routes/index.test.ts | 92 +------------------ 16 files changed, 57 insertions(+), 351 deletions(-) delete mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx delete mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx delete mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx delete mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx delete mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx delete mode 100644 test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx diff --git a/package.json b/package.json index f915d6d2fed251..e958e56ad6cd9c 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "@typescript-eslint/eslint-plugin": "4.29.1", "@typescript-eslint/parser": "4.29.1", "@vercel/fetch": "6.1.1", - "@vercel/og": "0.4.0", + "@vercel/og": "0.0.20", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/floating-point-hex-parser": "1.11.1", "@webassemblyjs/helper-api-error": "1.11.1", diff --git a/packages/next/src/build/webpack/loaders/metadata/discover.ts b/packages/next/src/build/webpack/loaders/metadata/discover.ts index 375d55f8add0bd..3081ded78e92c6 100644 --- a/packages/next/src/build/webpack/loaders/metadata/discover.ts +++ b/packages/next/src/build/webpack/loaders/metadata/discover.ts @@ -80,13 +80,11 @@ export async function createStaticMetadataFromRoute( resolvePath, isRootLayer, loaderContext, - pageExtensions, }: { route: string resolvePath: (pathname: string) => Promise isRootLayer: boolean loaderContext: webpack.LoaderContext - pageExtensions: string[] } ) { let hasStaticMetadataFiles = false @@ -108,46 +106,22 @@ export async function createStaticMetadataFromRoute( const resolvedMetadataFiles = await enumMetadataFiles( resolvedDir, STATIC_METADATA_IMAGES[type].filename, - pageExtensions.concat(STATIC_METADATA_IMAGES[type].extensions), + STATIC_METADATA_IMAGES[type].extensions, opts ) resolvedMetadataFiles .sort((a, b) => a.localeCompare(b)) .forEach((filepath) => { - const [filename, ext] = path.basename(filepath).split('.') - const isDynamicResource = pageExtensions.includes(ext) - - // imageModule type: () => Promise - const imageModule = isDynamicResource - ? `(async () => { - let { alt, size, contentType } = await import(/* webpackMode: "lazy" */ ${JSON.stringify( - filepath - )}) - - const props = { - alt, - type: contentType, - url: ${JSON.stringify(route + '/' + filename)}, - } - if (size) { - ${ - type === 'twitter' || type === 'opengraph' - ? 'props.width = size.width; props.height = size.height;' - : 'props.sizes = size.width + "x" + size.height;' - } - } - return props - })` - : `() => import(/* webpackMode: "eager" */ ${JSON.stringify( - `next-metadata-image-loader?${stringify({ - route, - numericSizes: - type === 'twitter' || type === 'opengraph' ? '1' : undefined, - type, - })}!` + - filepath + - METADATA_RESOURCE_QUERY - )})` + const imageModule = `() => import(/* webpackMode: "eager" */ ${JSON.stringify( + `next-metadata-image-loader?${stringify({ + route, + numericSizes: + type === 'twitter' || type === 'opengraph' ? '1' : undefined, + type, + })}!` + + filepath + + METADATA_RESOURCE_QUERY + )})` hasStaticMetadataFiles = true if (type === 'favicon') { diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index 223d49000d3322..b32bdf0c599b41 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -111,7 +111,6 @@ async function createTreeCodeFromPath( resolvePath, resolveParallelSegments, loaderContext, - pageExtensions, }: { resolver: ( pathname: string, @@ -122,7 +121,6 @@ async function createTreeCodeFromPath( pathname: string ) => [key: string, segment: string | string[]][] loaderContext: webpack.LoaderContext - pageExtensions: string[] } ) { const splittedPath = pagePath.split(/[\\/]/) @@ -163,7 +161,6 @@ async function createTreeCodeFromPath( resolvePath, isRootLayer, loaderContext, - pageExtensions, }) } } catch (err: any) { @@ -382,7 +379,6 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { resolvePath: (pathname: string) => resolve(this.rootContext, pathname), resolveParallelSegments, loaderContext: this, - pageExtensions, }) if (!rootLayout) { diff --git a/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts b/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts index a78e39bd23a35d..6b3797e8e2b13b 100644 --- a/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts @@ -42,6 +42,7 @@ const filePath = fileURLToPath(resourceUrl).replace(${JSON.stringify( )}, '') const buffer = fs.readFileSync(filePath) + export function GET() { return new NextResponse(buffer, { headers: { @@ -55,7 +56,7 @@ export const dynamic = 'force-static' ` } -function getDynamicTextRouteCode(resourcePath: string) { +function getDynamicRouteCode(resourcePath: string) { return `\ import { NextResponse } from 'next/server' import handler from ${JSON.stringify(resourcePath)} @@ -78,19 +79,6 @@ export async function GET() { ` } -function getDynamicImageRouteCode(resourcePath: string) { - return `\ -import { NextResponse } from 'next/server' -import handler from ${JSON.stringify(resourcePath)} - -export async function GET(req, ctx) { - const res = await handler({ params: ctx.params }) - res.headers.set('Cache-Control', 'public, max-age=0, must-revalidate') - return res -} -` -} - // `import.meta.url` is the resource name of the current module. // When it's static route, it could be favicon.ico, sitemap.xml, robots.txt etc. // TODO-METADATA: improve the cache control strategy @@ -99,23 +87,12 @@ const nextMetadataRouterLoader: webpack.LoaderDefinitionFunction r.test(appDirRelativePath)) } -/* - * Remove the 'app' prefix or '/route' suffix, only check the route name since they're only allowed in root app directory - * e.g. - * /app/robots -> /robots - * app/robots -> /robots - * /robots -> /robots - */ export function isMetadataRoute(route: string): boolean { - let page = route.replace(/^\/?app\//, '').replace(/\/route$/, '') - if (page[0] !== '/') page = '/' + page + // Remove the 'app' prefix or '/route' suffix, only check the route name since they're only allowed in root app directory + const page = route.replace(/^\/?app/, '').replace(/\/route$/, '') return ( !page.endsWith('/page') && diff --git a/packages/next/src/lib/metadata/resolve-metadata.ts b/packages/next/src/lib/metadata/resolve-metadata.ts index 0ad2d6bcee07f3..d369bf6fc82f1d 100644 --- a/packages/next/src/lib/metadata/resolve-metadata.ts +++ b/packages/next/src/lib/metadata/resolve-metadata.ts @@ -45,13 +45,9 @@ function mergeStaticMetadata( if (!staticFilesMetadata) return const { icon, apple, opengraph, twitter } = staticFilesMetadata if (icon || apple) { - // if (!metadata.icons) - metadata.icons = { - icon: icon || [], - apple: apple || [], - } - // if (icon) metadata.icons.icon.push(...icon) - // if (apple) metadata.icons.apple.push(...apple) + if (!metadata.icons) metadata.icons = { icon: [], apple: [] } + if (icon) metadata.icons.icon.push(...icon) + if (apple) metadata.icons.apple.push(...apple) } if (twitter) { const resolvedTwitter = resolveTwitter( @@ -219,8 +215,9 @@ async function collectStaticImagesFiles( if (!metadata?.[type]) return undefined const iconPromises = metadata[type as 'icon' | 'apple'].map( - async (iconResolver: () => Promise) => - interopDefault(await iconResolver()) + // TODO-APP: share the typing between next-metadata-image-loader and here + async (iconResolver: any) => + interopDefault(await iconResolver()) as MetadataImageModule ) return iconPromises?.length > 0 ? await Promise.all(iconPromises) : undefined } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57be1a8553e049..f6eab37e04e64b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,7 +55,7 @@ importers: '@typescript-eslint/eslint-plugin': 4.29.1 '@typescript-eslint/parser': 4.29.1 '@vercel/fetch': 6.1.1 - '@vercel/og': 0.4.0 + '@vercel/og': 0.0.20 '@webassemblyjs/ast': 1.11.1 '@webassemblyjs/floating-point-hex-parser': 1.11.1 '@webassemblyjs/helper-api-error': 1.11.1 @@ -232,7 +232,7 @@ importers: '@typescript-eslint/eslint-plugin': 4.29.1_qxyn66xcaddhgaahwkbomftvi4 '@typescript-eslint/parser': 4.29.1_6x3mpmmsttbpxxsctsorxedanu '@vercel/fetch': 6.1.1_fii5qhbaymjqmfm7e2spxc5z4m - '@vercel/og': 0.4.0 + '@vercel/og': 0.0.20 '@webassemblyjs/ast': 1.11.1 '@webassemblyjs/floating-point-hex-parser': 1.11.1 '@webassemblyjs/helper-api-error': 1.11.1 @@ -6308,8 +6308,8 @@ packages: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} dev: true - /@resvg/resvg-wasm/2.4.1: - resolution: {integrity: sha512-yi6R0HyHtsoWTRA06Col4WoDs7SvlXU3DLMNP2bdAgs7HK18dTEVl1weXgxRzi8gwLteGUbIg29zulxIB3GSdg==} + /@resvg/resvg-wasm/2.0.0-alpha.4: + resolution: {integrity: sha512-pWIG9a/x1ky8gXKRhPH1OPKpHFoMN1ISLbJ+O+gPXQHIAKhNd5I28RlWf7q576hAOQA9JZTlo3p/M2uyLzJmmw==} engines: {node: '>= 10'} dev: true @@ -7494,6 +7494,10 @@ packages: '@types/yargs-parser': 13.1.0 dev: true + /@types/yoga-layout/1.9.2: + resolution: {integrity: sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==} + dev: true + /@typescript-eslint/eslint-plugin/4.29.1_qxyn66xcaddhgaahwkbomftvi4: resolution: {integrity: sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw==} engines: {node: ^10.12.0 || >=12.0.0} @@ -7731,13 +7735,13 @@ packages: - supports-color dev: true - /@vercel/og/0.4.0: - resolution: {integrity: sha512-FFjXYCD5ZM0VotC9niy11qf4m6D99JVQ73P/uCLJl/r2PeOj0l26xwTEQ4HHJ/yZ6ncByCNoWAjk+S0fjMJmwg==} + /@vercel/og/0.0.20: + resolution: {integrity: sha512-089P+TfqWz0xBxjOvOhkZIDDtfrLcye94H4IZ+SqxoGPWpNGXaBvRJER/z5SoJxJRcCAL8tPiK5zdjRskM6tLw==} engines: {node: '>=16'} dependencies: - '@resvg/resvg-wasm': 2.4.1 - satori: 0.4.1 - yoga-wasm-web: 0.3.0 + '@resvg/resvg-wasm': 2.0.0-alpha.4 + satori: 0.0.43 + yoga-wasm-web: 0.1.2 dev: true /@webassemblyjs/ast/1.11.1: @@ -8830,11 +8834,6 @@ packages: mixin-deep: 1.3.2 pascalcase: 0.1.1 - /base64-js/0.0.8: - resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} - engines: {node: '>= 0.4'} - dev: true - /base64-js/1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true @@ -16409,13 +16408,6 @@ packages: resolution: {integrity: sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==} dev: true - /linebreak/1.1.0: - resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} - dependencies: - base64-js: 0.0.8 - unicode-trie: 2.0.0 - dev: true - /lines-and-columns/1.1.6: resolution: {integrity: sha512-8ZmlJFVK9iCmtLz19HpSsR8HaAMWBT284VMNednLwlIMDP2hJDCIhUp0IZ2xUcZ+Ob6BM0VvCSJwzASDM45NLQ==} @@ -22277,8 +22269,8 @@ packages: immutable: 4.1.0 source-map-js: 1.0.2 - /satori/0.4.1: - resolution: {integrity: sha512-uQm4+vQj57E9PO/ASAlxsRb+78fHkRUmkNLBBmfuEeGNLGqJ9ufYU7TzYP4XH60PLHYt9Wz1jSsgcAe2cz7+ng==} + /satori/0.0.43: + resolution: {integrity: sha512-SzYwr+LsELWRJU9KMviEOE9TdShry+R5AdS54YQvgAVKFDN4yniAIzwQk1/z2TtIx0ceUT9zTeosWAoWvJBEtQ==} engines: {node: '>=16'} dependencies: '@shuding/opentype.js': 1.4.0-beta.0 @@ -22286,9 +22278,8 @@ packages: css-box-shadow: 1.0.0-3 css-to-react-native: 3.0.0 emoji-regex: 10.2.1 - linebreak: 1.1.0 postcss-value-parser: 4.2.0 - yoga-wasm-web: 0.3.3 + yoga-layout-prebuilt: 1.10.0 dev: true /sax/1.2.4: @@ -25401,12 +25392,15 @@ packages: engines: {node: '>=12.20'} dev: true - /yoga-wasm-web/0.3.0: - resolution: {integrity: sha512-rD3L4jyMlO1m+RWU60lNwZQK5zmzglCV5fI1gTRikmpv3YzmNIZQbjyfE6cMNb9Xaly/C1SwemYGbsiOekMvnQ==} + /yoga-layout-prebuilt/1.10.0: + resolution: {integrity: sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==} + engines: {node: '>=8'} + dependencies: + '@types/yoga-layout': 1.9.2 dev: true - /yoga-wasm-web/0.3.3: - resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} + /yoga-wasm-web/0.1.2: + resolution: {integrity: sha512-8SkgawHcA0RUbMrnhxbaQkZDBi8rMed8pQHixkFF9w32zGhAwZ9/cOHWlpYfr6RCx42Yp3siV45/jPEkJxsk6w==} dev: true /zod/3.21.4: diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx deleted file mode 100644 index 683dd12fcc6f14..00000000000000 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/apple-icon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { ImageResponse } from '@vercel/og' - -export const contentType = 'image/png' - -export default function appleIcon() { - return new ImageResponse( - ( -
- Apple Icon -
- ) - ) -} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx deleted file mode 100644 index 7b5859a8293ffb..00000000000000 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/opengraph-image.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { ImageResponse } from '@vercel/og' - -export const alt = 'Open Graph' - -export default function og({ params }) { - const big = params.size === 'big' - const background = big ? 'orange' : '#000' - return new ImageResponse( - ( -
-
-
- ), - { - width: big === true ? 1200 : 600, - height: big === true ? 630 : 315, - } - ) -} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx deleted file mode 100644 index e1b5bd8f2ce11d..00000000000000 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/dynamic/[size]/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function page() { - return <>dynamic -} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx deleted file mode 100644 index 1205089f21319d..00000000000000 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/icon.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ImageResponse } from '@vercel/og' - -export const contentType = 'image/png' -export const size = { width: 512, height: 512 } - -export default function icon() { - return new ImageResponse( - ( -
- Icon -
- ) - ) -} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx deleted file mode 100644 index fd72c819260e17..00000000000000 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/opengraph-image.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { ImageResponse } from '@vercel/og' - -export const alt = 'Open Graph' - -export default function og() { - return new ImageResponse( - ( -
- Open Graph -
- ) - ) -} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx index c2dd96ac06ceaf..eba737535cc7e9 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/page.tsx @@ -5,6 +5,5 @@ export default function Page() { } export const metadata = { - metadataBase: new URL('https://deploy-preview-abc.vercel.app'), title: 'index page', } diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx b/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx deleted file mode 100644 index 0190d601348c94..00000000000000 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/twitter-image.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ImageResponse } from '@vercel/og' - -export const alt = 'Twitter' -export const size = { width: 1600, height: 900 } - -export default function twitter() { - return new ImageResponse( - ( -
- Twitter Image -
- ), - size - ) -} diff --git a/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts b/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts index 644151bddd2340..4b49a9e9e84670 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts +++ b/test/e2e/app-dir/metadata-dynamic-routes/index.test.ts @@ -1,17 +1,13 @@ import { createNextDescribe } from 'e2e-utils' -import imageSize from 'image-size' createNextDescribe( 'app dir - metadata dynamic routes', { files: __dirname, skipDeployment: true, - dependencies: { - '@vercel/og': '0.4.0', - }, }, ({ next }) => { - describe('text routes', () => { + describe('dynamic routes', () => { it('should handle robots.[ext] dynamic routes', async () => { const res = await next.fetch('/robots.txt') const text = await res.text() @@ -60,9 +56,7 @@ createNextDescribe( " `) }) - }) - describe('social image routes', () => { it('should handle manifest.[ext] dynamic routes', async () => { const res = await next.fetch('/manifest.webmanifest') const json = await res.json() @@ -91,90 +85,6 @@ createNextDescribe( ], }) }) - - it('should render og image with opengraph-image dynamic routes', async () => { - const res = await next.fetch('/opengraph-image') - - expect(res.headers.get('content-type')).toBe('image/png') - expect(res.headers.get('cache-control')).toBe( - 'public, max-age=0, must-revalidate' - ) - }) - - it('should render og image with twitter-image dynamic routes', async () => { - const res = await next.fetch('/twitter-image') - - expect(res.headers.get('content-type')).toBe('image/png') - expect(res.headers.get('cache-control')).toBe( - 'public, max-age=0, must-revalidate' - ) - }) - - it('should support params as argument in dynamic routes', async () => { - const bufferBig = await ( - await next.fetch('/dynamic/big/opengraph-image') - ).buffer() - const bufferSmall = await ( - await next.fetch('/dynamic/small/opengraph-image') - ).buffer() - - const sizeBig = imageSize(bufferBig) - const sizeSmall = imageSize(bufferSmall) - expect([sizeBig.width, sizeBig.height]).toEqual([1200, 630]) - expect([sizeSmall.width, sizeSmall.height]).toEqual([600, 315]) - }) - }) - - describe('icon image routes', () => { - it('should render icon with dynamic routes', async () => { - const res = await next.fetch('/icon') - - expect(res.headers.get('content-type')).toBe('image/png') - expect(res.headers.get('cache-control')).toBe( - 'public, max-age=0, must-revalidate' - ) - }) - - it('should render apple icon with dynamic routes', async () => { - const res = await next.fetch('/apple-icon') - - expect(res.headers.get('content-type')).toBe('image/png') - expect(res.headers.get('cache-control')).toBe( - 'public, max-age=0, must-revalidate' - ) - }) - }) - - it('should inject dynamic metadata properly to head', async () => { - const $ = await next.render$('/') - const $icon = $('link[rel="icon"]') - const $appleIcon = $('link[rel="apple-touch-icon"]') - const ogImageUrl = $('meta[property="og:image"]').attr('content') - const twitterImageUrl = $('meta[name="twitter:image"]').attr('content') - - // non absolute urls - expect($icon.attr('href')).toBe('/icon') - expect($icon.attr('sizes')).toBe('512x512') - expect($icon.attr('type')).toBe('image/png') - expect($appleIcon.attr('href')).toBe('/apple-icon') - expect($appleIcon.attr('sizes')).toBe(undefined) - expect($appleIcon.attr('type')).toBe('image/png') - - // absolute urls - expect(ogImageUrl).toBe( - 'https://deploy-preview-abc.vercel.app/opengraph-image' - ) - expect(twitterImageUrl).toBe( - 'https://deploy-preview-abc.vercel.app/twitter-image' - ) - - // alt text - expect($('meta[property="og:image:alt"]').attr('content')).toBe( - 'Open Graph' - ) - expect($('meta[name="twitter:image:alt"]').attr('content')).toBe( - 'Twitter' - ) }) } ) From 84a416b5e115f5b622d3cfab2d747dfe64a12e7d Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 22 Mar 2023 12:56:39 -0700 Subject: [PATCH 612/672] Fix build spinner in TTY env (#47383) This ensures the build spinner is correctly stopped in a TTY environment and also adds regression tests for `app` and `pages` to ensure this behaves as expected. This updates our docker image to use the `jammy` tag instead of `focal` to match the Ubuntu version to our CI. --- .github/workflows/build_test_deploy.yml | 32 +-- package.json | 1 + packages/next/src/build/webpack-build.ts | 1 + pnpm-lock.yaml | 9 + test/integration/build-spinners/index.test.ts | 187 ++++++++++++++++++ 5 files changed, 214 insertions(+), 16 deletions(-) create mode 100644 test/integration/build-spinners/index.test.ts diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 3695eb96e5f7b6..8bcff220a51345 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -301,7 +301,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type development --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type development --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" name: Run test/development if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -352,7 +352,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type development --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type development --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" name: Run test/development if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -400,7 +400,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" name: Run test/e2e (dev) if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -449,7 +449,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=dev TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" name: Run test/e2e (dev) if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -497,7 +497,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type production --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type production --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" name: Run test/production if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -536,7 +536,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type production --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type production --timings -g ${{ matrix.group }}/5 >> /proc/1/fd/1" name: Run test/production if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -574,7 +574,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" name: Run test/e2e (production) if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -614,7 +614,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e --timings -g ${{ matrix.group }}/8 >> /proc/1/fd/1" name: Run test/e2e (production) if: ${{needs.build.outputs.docsChange == 'nope'}} @@ -650,7 +650,7 @@ jobs: - run: echo "CNA_CHANGE<> $GITHUB_OUTPUT; echo "$(node scripts/run-for-change.js --type cna --always-canary --exec echo 'yup')" >> $GITHUB_OUTPUT; echo "EOF" >> $GITHUB_OUTPUT id: cna-change - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_CNA=1 xvfb-run node run-tests.js test/integration/create-next-app/index.test.ts test/integration/create-next-app/templates.test.ts >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_CNA=1 xvfb-run node run-tests.js test/integration/create-next-app/index.test.ts test/integration/create-next-app/templates.test.ts >> /proc/1/fd/1" if: ${{ needs.build.outputs.docsChange == 'nope' && steps.cna-change.outputs.CNA_CHANGE == 'yup' }} - name: Upload test trace @@ -690,7 +690,7 @@ jobs: - run: echo "CODEMOD_CHANGE<> $GITHUB_OUTPUT; echo "$(node scripts/run-for-change.js --type next-codemod --always-canary --exec echo 'yup')" >> $GITHUB_OUTPUT; echo "EOF" >> $GITHUB_OUTPUT id: codemodChange - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && cd ./packages/next-codemod && pnpm build && pnpm test >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && cd ./packages/next-codemod && pnpm build && pnpm test >> /proc/1/fd/1" if: ${{ needs.build.outputs.docsChange == 'nope' && steps.codemodChange.outputs.CODEMOD_CHANGE == 'yup' }} testIntegration: @@ -756,7 +756,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --timings -g ${{ matrix.group }}/28 >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --timings -g ${{ matrix.group }}/28 >> /proc/1/fd/1" if: ${{needs.build.outputs.docsChange == 'nope'}} - name: Upload test trace @@ -850,7 +850,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_MAINTENANCE_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && BROWSERNAME=firefox NEXT_TEST_JOB=1 TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js test/integration/production/test/index.test.js >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_MAINTENANCE_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && BROWSERNAME=firefox NEXT_TEST_JOB=1 TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js test/integration/production/test/index.test.js >> /proc/1/fd/1" if: ${{needs.build.outputs.docsChange == 'nope'}} testSafari: @@ -879,7 +879,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v{{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start BROWSER_NAME=safari node run-tests.js -c 1 test/integration/production/test/index.test.js test/e2e/basepath.test.ts && DEVICE_NAME='iPhone XR' node run-tests.js -c 1 test/production/prerender-prefetch/index.test.ts >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v{{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start BROWSER_NAME=safari node run-tests.js -c 1 test/integration/production/test/index.test.js test/e2e/basepath.test.ts && DEVICE_NAME='iPhone XR' node run-tests.js -c 1 test/production/prerender-prefetch/index.test.ts >> /proc/1/fd/1" if: ${{needs.build.outputs.docsChange == 'nope'}} testFirefoxNodeLTS: @@ -904,7 +904,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && BROWSER_NAME=firefox NEXT_TEST_JOB=1 TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js test/integration/production/test/index.test.js >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && BROWSER_NAME=firefox NEXT_TEST_JOB=1 TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js test/integration/production/test/index.test.js >> /proc/1/fd/1" if: ${{needs.build.outputs.docsChange == 'nope'}} publishRelease: @@ -999,7 +999,7 @@ jobs: - run: RESET_VC_PROJECT=true node scripts/reset-vercel-project.mjs name: Reset test project - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && VERCEL_TEST_TOKEN=${{ secrets.VERCEL_TEST_TOKEN }} VERCEL_TEST_TEAM=vtest314-next-e2e-tests NEXT_TEST_JOB=1 NEXT_TEST_MODE=deploy TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && npm i -g pnpm@${PNPM_VERSION} > /dev/null && VERCEL_TEST_TOKEN=${{ secrets.VERCEL_TEST_TOKEN }} VERCEL_TEST_TEAM=vtest314-next-e2e-tests NEXT_TEST_JOB=1 NEXT_TEST_MODE=deploy TEST_TIMINGS_TOKEN=${{ secrets.TEST_TIMINGS_TOKEN }} xvfb-run node run-tests.js --type e2e >> /proc/1/fd/1" name: Run test/e2e (deploy) - name: Upload test trace @@ -1224,7 +1224,7 @@ jobs: name: next-swc-test-binary path: packages/next-swc/native - - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && node -v && node ./scripts/setup-wasm.mjs && npm i -g pnpm@${PNPM_VERSION} > /dev/null && TEST_WASM=true xvfb-run node run-tests.js test/integration/production/test/index.test.js test/e2e/streaming-ssr/index.test.ts >> /proc/1/fd/1" + - run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-jammy /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ env.NODE_LTS_VERSION }} | FORCE=1 bash && node -v && node ./scripts/setup-wasm.mjs && npm i -g pnpm@${PNPM_VERSION} > /dev/null && TEST_WASM=true xvfb-run node run-tests.js test/integration/production/test/index.test.js test/e2e/streaming-ssr/index.test.ts >> /proc/1/fd/1" if: ${{needs.build.outputs.docsChange == 'nope'}} # Build binaries for publishing diff --git a/package.json b/package.json index e958e56ad6cd9c..b115f94ce749f8 100644 --- a/package.json +++ b/package.json @@ -176,6 +176,7 @@ "nanoid": "3.1.30", "next": "workspace:*", "node-fetch": "2.6.7", + "node-pty": "0.10.1", "npm-run-all": "4.1.5", "nprogress": "0.2.0", "pixrem": "5.0.0", diff --git a/packages/next/src/build/webpack-build.ts b/packages/next/src/build/webpack-build.ts index f2832bed8d64ef..2bb71491ab6edf 100644 --- a/packages/next/src/build/webpack-build.ts +++ b/packages/next/src/build/webpack-build.ts @@ -304,6 +304,7 @@ async function webpackBuildImpl( console.warn(result.warnings.filter(Boolean).join('\n\n')) console.warn() } else if (!compilerName) { + NextBuildContext.buildSpinner?.stopAndPersist() Log.info('Compiled successfully') } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6eab37e04e64b..3cd3955c6a0877 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -136,6 +136,7 @@ importers: nanoid: 3.1.30 next: workspace:* node-fetch: 2.6.7 + node-pty: 0.10.1 npm-run-all: 4.1.5 nprogress: 0.2.0 pixrem: 5.0.0 @@ -313,6 +314,7 @@ importers: nanoid: 3.1.30 next: link:packages/next node-fetch: 2.6.7 + node-pty: 0.10.1 npm-run-all: 4.1.5 nprogress: 0.2.0 pixrem: 5.0.0 @@ -18201,6 +18203,13 @@ packages: upper-case: 2.0.2 dev: true + /node-pty/0.10.1: + resolution: {integrity: sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg==} + requiresBuild: true + dependencies: + nan: 2.15.0 + dev: true + /node-releases/2.0.3: resolution: {integrity: sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==} diff --git a/test/integration/build-spinners/index.test.ts b/test/integration/build-spinners/index.test.ts new file mode 100644 index 00000000000000..6a02fc8b333bef --- /dev/null +++ b/test/integration/build-spinners/index.test.ts @@ -0,0 +1,187 @@ +import * as pty from 'node-pty' +import fs from 'fs-extra' +import path from 'path' +import stripAnsi from 'strip-ansi' + +type File = { + filename: string + content: string +} + +const appDirFiles: File[] = [ + { + filename: 'app/page.js', + content: ` + export default function Page() { + return

hello world

+ } + `, + }, + { + filename: 'app/layout.js', + content: ` + export default function Layout({ children }) { + return ( + + + {children} + + ) + } + `, + }, + { + filename: 'next.config.js', + content: ` + module.exports = { + experimental: { + appDir: true + } + } + `, + }, +] +const pagesFiles: File[] = [ + { + filename: 'pages/another.js', + content: ` + export default function Page() { + return ( +

another page

+ ) + } + `, + }, +] + +it.each([ + { name: 'app dir', files: appDirFiles }, + { + name: 'app dir (compile workers)', + files: [ + ...appDirFiles, + { + filename: 'next.config.js', + content: ` + module.exports = { + experimental: { + appDir: true, + webpackBuildWorker: true, + } + } + `, + }, + ], + }, + { + name: 'page dir', + files: [ + ...pagesFiles, + { + filename: 'next.config.js', + content: ` + module.exports = { + experimental: { + webpackBuildWorker: true, + } + } + `, + }, + ], + }, + { name: 'page dir (compile workers)', files: pagesFiles }, + { name: 'app and pages', files: [...appDirFiles, ...pagesFiles] }, +])('should handle build spinners correctly $name', async ({ files }) => { + const appDir = path.join(__dirname, 'app') + await fs.remove(appDir) + + try { + for (const file of files) { + await fs.ensureDir(path.dirname(path.join(appDir, file.filename))) + await fs.writeFile(path.join(appDir, file.filename), file.content) + } + + const nextBin = require.resolve('next/dist/bin/next') + + const output = [] + const ptyProcess = pty.spawn(process.execPath, [nextBin, 'build'], { + name: 'xterm-color', + cols: 80, + rows: 30, + cwd: appDir, + env: process.env, + }) + + ptyProcess.onData(function (data) { + stripAnsi(data) + .split('\n') + .forEach((line) => output.push(line)) + process.stdout.write(data) + }) + + await new Promise((resolve, reject) => { + ptyProcess.onExit(({ exitCode, signal }) => { + if (exitCode) { + return reject(`failed with code ${exitCode}`) + } + resolve() + }) + }) + + let compiledIdx = -1 + let optimizedBuildIdx = -1 + let collectingPageDataIdx = -1 + let generatingStaticIdx = -1 + let finalizingOptimization = -1 + + // order matters so we check output from end to start + for (let i = output.length - 1; i--; i >= 0) { + const line = output[i] + + if (compiledIdx === -1 && line.includes('Compiled successfully')) { + compiledIdx = i + } + + if ( + optimizedBuildIdx === -1 && + line.includes('Creating an optimized production build') + ) { + optimizedBuildIdx = i + } + + if ( + collectingPageDataIdx === -1 && + line.includes('Collecting page data') + ) { + collectingPageDataIdx = i + } + + if ( + generatingStaticIdx === -1 && + line.includes('Generating static pages') + ) { + generatingStaticIdx = i + } + + if ( + finalizingOptimization === -1 && + line.includes('Finalizing page optimization') + ) { + finalizingOptimization = i + } + } + + expect(compiledIdx).not.toBe(-1) + expect(optimizedBuildIdx).not.toBe(-1) + expect(collectingPageDataIdx).not.toBe(-1) + expect(generatingStaticIdx).not.toBe(-1) + expect(finalizingOptimization).not.toBe(-1) + + expect(optimizedBuildIdx).toBeLessThan(compiledIdx) + expect(compiledIdx).toBeLessThan(collectingPageDataIdx) + expect(collectingPageDataIdx).toBeLessThan(generatingStaticIdx) + expect(generatingStaticIdx).toBeLessThan(finalizingOptimization) + } finally { + await fs.remove(appDir) + } +}) From 1d407f27a5283c3991f5b520b9be72ec6cc4aaa9 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 22 Mar 2023 21:26:46 +0100 Subject: [PATCH 613/672] upgrade vendored React to `18.3.0-next-12a1d140e-20230321` (#47405) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Includes the following upstream changes: - 12a1d140e Don't prerender siblings of suspended component (#26380) (Andrew Clark) - 77ba1618a Bugfix: Remove extra render pass when reverting to client render (#26445) (Andrew Clark) - 520f7f3ed Refactor ReactDOMComponent to use flatter property operations (#26433) (Sebastian Markbåge) - 0131d0cff Check if suspensey instance resolves in immediate task (#26427) (Andrew Clark) - 3554c8852 Clean interface for public instances between React and React Native (#26416) (Rubén Norte) - c57b90f50 [DiffTrain] Add artifacts for React Native to compiled (#26204) (Samuel Susla) - 842bd787a Fix sizebot not working due to missing auth token (#26423) (Andrew Clark) - db281b3d9 Feature: Suspend commit without blocking render (#26398) (Andrew Clark) - 6310087f0 [ci] Fix download_base_build_for_sizebot (#26422) (lauren) - 6854a3cf6 [difftrain] Fix broken workflow (#26421) (lauren) - 55308554e [www] enable enableFilterEmptyStringAttributesDOM flag (#26410) (Jan Kassens) - 163d86e19 Updated comment message (#26158) (Ibrahim Amin) - 108aed083 Fix use of stale props in Fabric events (#26408) (Rubén Norte) - 8fa41ffa2 Don't "fix up" mismatched text content with suppressedHydrationWarning (#26391) (Sebastian Markbåge) - 87c803d1d Fix a test case in ReactUpdates-test (#26399) (Tianyu Yao) - eaccf27c2 Revert "Remove hydrate entry point from www builds" (#26413) (Jan Kassens) - 480aa7785 Remove hydrate entry point from www builds (#26400) (Sebastian Markbåge) - 9941cbaca Fix devtools tests after internal test changes (#26405) (Ricky) - e4606c1e0 Add missing `"react-dom/server.bun"` entry in package.json `"exports"` (#26402) (Jarred Sumner) - 05777ffb0 Setting transition pending flag shouldn't be part of a surrounding transition (#26243) (Sophie Alpert) - 21f6dba6a Sync from oss-experimental, not oss-stable (#26401) (Ricky) - 99aa082be Remove unstable_flushControlled (#26397) (Jan Kassens) - 47cf4e578 Restore some guards in ReactFabricGlobalResponderHandler after refactor (#26394) (Rubén Norte) - cfc1274e3 Disable IE innerHTML workaround behind a flag (#26390) (Sebastian Markbåge) - a57f40d83 Undo dependency injection of batching (#26389) (Sebastian Markbåge) - d310d654a Avoid meta programming to initialize functions in module scope (#26388) (Sebastian Markbåge) - 21aee59e4 Delete unused DOM files (#26387) (Sebastian Markbåge) - 56a3c18e5 [Flight fixture] Remove redundant `use` (#26373) (Andrew Clark) - 6bd53a5bd Remove FeatureFlags fork for `react-dom/unstable_testing` (#26383) (Sebastian Markbåge) - 2788d0d8d Allow empty string to be passed to formAction (#26379) (Sebastian Markbåge) - f828bad38 Extracted definition and access to public instances to a separate module in Fabric (#26321) (Rubén Norte) - cd20376f0 Remove internal `act` from DevTools e2e test (#26376) (Andrew Clark) - 131768166 Support Context as renderable node (#25641) (Andrew Clark) - d4f58c3b8 Support Promise as a renderable node (#25634) (Andrew Clark) - f411e8990 Remote `.internal` override from untrusted URL tests (#26372) (Andrew Clark) - 633461486 Add disableLegacyContext test gates where needed (#26371) (Andrew Clark) - 432ffc9d0 Convert more Scheduler.unstable_flushAll in tests to new test utils (#26369) (Tianyu Yao) - 774111855 [Flight Fixture] Fix proxying with compression (#26368) (Sebastian Markbåge) - 69fd78fe3 Update Float tests to check for specific errors (#26367) (Andrew Clark) - 93c10dfa6 flushSync: Exhaust queue even if something throws (#26366) (Andrew Clark) - a22bd995c [DevTools] prevent StyleX plugin from throwing when inspecting CSS (#26364) (Mengdi Chen) - be353d251 [Flight Reply] Add undefined and Iterable Support (#26365) (Sebastian Markbåge) - ef8bdbecb [Flight Reply] Add Reply Encoding (#26360) (Sebastian Markbåge) - a8875eab7 Update more tests to not rely on sync queuing (#26358) (Andrew Clark) - d1ad984db [Flight] Add support for returning `undefined` from render (#26349) (Sebastian Silbermann) - 39d4b9365 [Internal tests] Close MessageChannel port to prevent leak (#26357) (Andrew Clark) --- package.json | 6 +- ...t-dom-server-legacy.browser.development.js | 271 +- ...om-server-legacy.browser.production.min.js | 121 +- ...eact-dom-server-legacy.node.development.js | 271 +- ...t-dom-server-legacy.node.production.min.js | 117 +- ...t-dom-server-rendering-stub.development.js | 2 +- ...om-server-rendering-stub.production.min.js | 2 +- .../react-dom-server.browser.development.js | 271 +- ...react-dom-server.browser.production.min.js | 115 +- .../cjs/react-dom-server.edge.development.js | 271 +- .../react-dom-server.edge.production.min.js | 129 +- .../cjs/react-dom-server.node.development.js | 271 +- .../react-dom-server.node.production.min.js | 103 +- .../react-dom/cjs/react-dom.development.js | 46932 ++++++++-------- .../react-dom/cjs/react-dom.production.min.js | 732 +- .../react-dom/cjs/react-dom.profiling.min.js | 778 +- .../next/src/compiled/react-dom/package.json | 7 +- ...-dom-webpack-client.browser.development.js | 590 +- ...m-webpack-client.browser.production.min.js | 41 +- ...ver-dom-webpack-client.edge.development.js | 12 +- ...-dom-webpack-client.edge.production.min.js | 32 +- ...ver-dom-webpack-client.node.development.js | 12 +- ...-dom-webpack-client.node.production.min.js | 36 +- ...bpack-client.node.unbundled.development.js | 10 + ...ck-client.node.unbundled.production.min.js | 30 +- ...-dom-webpack-server.browser.development.js | 1780 +- ...m-webpack-server.browser.production.min.js | 102 +- ...ver-dom-webpack-server.edge.development.js | 1780 +- ...-dom-webpack-server.edge.production.min.js | 104 +- ...ver-dom-webpack-server.node.development.js | 1815 +- ...-dom-webpack-server.node.production.min.js | 107 +- ...bpack-server.node.unbundled.development.js | 1779 +- ...ck-server.node.unbundled.production.min.js | 100 +- .../react-server-dom-webpack/package.json | 6 +- .../cjs/react-jsx-dev-runtime.development.js | 4 +- .../cjs/react-jsx-runtime.development.js | 4 +- .../compiled/react/cjs/react.development.js | 6 +- .../react/cjs/react.production.min.js | 2 +- .../cjs/react.shared-subset.development.js | 6 +- .../cjs/react.shared-subset.production.min.js | 2 +- packages/next/src/compiled/react/package.json | 2 +- pnpm-lock.yaml | 36 +- 42 files changed, 31228 insertions(+), 27569 deletions(-) diff --git a/package.json b/package.json index b115f94ce749f8..0bd34354f344cf 100644 --- a/package.json +++ b/package.json @@ -193,11 +193,11 @@ "random-seed": "0.3.0", "react": "18.2.0", "react-17": "npm:react@17.0.2", - "react-builtin": "npm:react@18.3.0-next-3706edb81-20230308", + "react-builtin": "npm:react@18.3.0-next-12a1d140e-20230321", "react-dom": "18.2.0", "react-dom-17": "npm:react-dom@17.0.2", - "react-dom-builtin": "npm:react-dom@18.3.0-next-3706edb81-20230308", - "react-server-dom-webpack": "18.3.0-next-3706edb81-20230308", + "react-dom-builtin": "npm:react-dom@18.3.0-next-12a1d140e-20230321", + "react-server-dom-webpack": "18.3.0-next-12a1d140e-20230321", "react-ssr-prepass": "1.0.8", "react-virtualized": "9.22.3", "relay-compiler": "13.0.2", diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js index 7e11e4a1e9ca11..fe87fba5392d6f 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js @@ -17,7 +17,7 @@ if (process.env.NODE_ENV !== "production") { var React = require('react'); var ReactDOM = require('react-dom'); -var ReactVersion = '18.3.0-next-3706edb81-20230308'; +var ReactVersion = '18.3.0-next-12a1d140e-20230321'; var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; @@ -212,9 +212,6 @@ var enableFloat = true; // $FlowFixMe[method-unbinding] var hasOwnProperty = Object.prototype.hasOwnProperty; -// It is handled by React separately and shouldn't be written to the DOM. - -var RESERVED = 0; // A simple string attribute. // Attributes that aren't in the filter are presumed to have this type. var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called @@ -269,35 +266,6 @@ function isAttributeNameSafe(attributeName) { return false; } -function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { - if (propertyInfo !== null && propertyInfo.type === RESERVED) { - return false; - } - - switch (typeof value) { - case 'function': - case 'symbol': - // eslint-disable-line - return true; - - case 'boolean': - { - if (isCustomComponentTag) { - return false; - } - - if (propertyInfo !== null) { - return !propertyInfo.acceptsBooleans; - } else { - var prefix = name.toLowerCase().slice(0, 5); - return prefix !== 'data-' && prefix !== 'aria-'; - } - } - - default: - return false; - } -} function getPropertyInfo(name) { return properties.hasOwnProperty(name) ? properties[name] : null; } // $FlowFixMe[missing-this-annot] @@ -316,21 +284,7 @@ function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attribut // name warnings. -var properties = {}; // These props are reserved by React. They shouldn't be written to the DOM. - -var reservedProps = ['children', 'dangerouslySetInnerHTML', // TODO: This prevents the assignment of defaultValue to regular -// elements (not just inputs). Now that ReactDOMInput assigns to the -// defaultValue property -- do we need this? -'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style']; - -reservedProps.forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty - name, // attributeName - null, // attributeNamespace - false, // sanitizeURL - false); -}); // A few React string attributes have a different name. +var properties = {}; // A few React string attributes have a different name. // This is a mapping from React prop names to the attribute names. [['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { @@ -489,7 +443,14 @@ var xlinkHref = 'xlinkHref'; // $FlowFixMe[invalid-constructor] Flow no longer s properties[xlinkHref] = new PropertyInfoRecord('xlinkHref', STRING, false, // mustUseProperty 'xlink:href', 'http://www.w3.org/1999/xlink', true, // sanitizeURL false); -['src', 'href', 'action', 'formAction'].forEach(function (attributeName) { +var formAction = 'formAction'; // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + +properties[formAction] = new PropertyInfoRecord('formAction', STRING, false, // mustUseProperty +'formaction', // attributeName +null, // attributeNamespace +true, // sanitizeURL +false); +['src', 'href', 'action'].forEach(function (attributeName) { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty attributeName.toLowerCase(), // attributeName @@ -1280,16 +1241,14 @@ var possibleStandardNames = { zoomandpan: 'zoomAndPan' }; -var validateProperty = function () {}; +var warnedProperties = {}; +var EVENT_NAME_REGEX = /^on./; +var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/; +var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$') ; +var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$') ; -{ - var warnedProperties = {}; - var EVENT_NAME_REGEX = /^on./; - var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/; - var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); - var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); - - validateProperty = function (tagName, name, value, eventRegistry) { +function validateProperty(tagName, name, value, eventRegistry) { + { if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) { return true; } @@ -1372,8 +1331,7 @@ var validateProperty = function () {}; return true; } - var propertyInfo = getPropertyInfo(name); - var isReserved = propertyInfo !== null && propertyInfo.type === RESERVED; // Known attributes should match the casing specified in the property config. + var propertyInfo = getPropertyInfo(name); // Known attributes should match the casing specified in the property config. if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { var standardName = possibleStandardNames[lowerCasedName]; @@ -1384,36 +1342,56 @@ var validateProperty = function () {}; warnedProperties[name] = true; return true; } - } else if (!isReserved && name !== lowerCasedName) { + } else if (name !== lowerCasedName) { // Unknown attributes should have lowercase casing since that's how they // will be cased anyway with server rendering. error('React does not recognize the `%s` prop on a DOM element. If you ' + 'intentionally want it to appear in the DOM as a custom ' + 'attribute, spell it as lowercase `%s` instead. ' + 'If you accidentally passed it from a parent component, remove ' + 'it from the DOM element.', name, lowerCasedName); warnedProperties[name] = true; return true; + } // Now that we've validated casing, do not validate + // data types for reserved props + + + switch (name) { + case 'dangerouslySetInnerHTML': + case 'children': + case 'style': + case 'suppressContentEditableWarning': + case 'suppressHydrationWarning': + case 'defaultValue': // Reserved + + case 'defaultChecked': + case 'innerHTML': + { + return true; + } + } - if (typeof value === 'boolean' && shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { - if (value) { - error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.', value, name, name, value, name); - } else { - error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.\n\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.', value, name, name, value, name, name, name); + if (typeof value === 'boolean') { + var prefix = name.toLowerCase().slice(0, 5); + var acceptsBooleans = propertyInfo !== null ? propertyInfo.acceptsBooleans : prefix === 'data-' || prefix === 'aria-'; + + if (!acceptsBooleans) { + if (value) { + error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.', value, name, name, value, name); + } else { + error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.\n\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.', value, name, name, value, name, name, name); + } } warnedProperties[name] = true; return true; - } // Now that we've validated casing, do not validate - // data types for reserved props - - - if (isReserved) { - return true; } // Warn when a known attribute is a bad type - if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { - warnedProperties[name] = true; - return false; + switch (typeof value) { + case 'function': + case 'symbol': + // eslint-disable-line + warnedProperties[name] = true; + return false; } // Warn when passing the strings 'false' or 'true' into a boolean prop @@ -1425,10 +1403,10 @@ var validateProperty = function () {}; } return true; - }; + } } -var warnUnknownProperties = function (type, props, eventRegistry) { +function warnUnknownProperties(type, props, eventRegistry) { { var unknownProps = []; @@ -1450,7 +1428,7 @@ var warnUnknownProperties = function (type, props, eventRegistry) { error('Invalid values for props %s on <%s> tag. Either remove them from the element, ' + 'or pass a string or number value to keep them in the DOM. ' + 'For details, see https://reactjs.org/link/attribute-behavior ', unknownPropString, type); } } -}; +} function validateProperties(type, props, eventRegistry) { if (isCustomComponent(type, props)) { @@ -1460,27 +1438,25 @@ function validateProperties(type, props, eventRegistry) { warnUnknownProperties(type, props, eventRegistry); } -var warnValidStyle = function () {}; +// 'msTransform' is correct, but the other prefixes should be capitalized +var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; +var msPattern$1 = /^-ms-/; +var hyphenPattern = /-(.)/g; // style values shouldn't contain a semicolon -{ - // 'msTransform' is correct, but the other prefixes should be capitalized - var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; - var msPattern$1 = /^-ms-/; - var hyphenPattern = /-(.)/g; // style values shouldn't contain a semicolon - - var badStyleValueWithSemicolonPattern = /;\s*$/; - var warnedStyleNames = {}; - var warnedStyleValues = {}; - var warnedForNaNValue = false; - var warnedForInfinityValue = false; - - var camelize = function (string) { - return string.replace(hyphenPattern, function (_, character) { - return character.toUpperCase(); - }); - }; +var badStyleValueWithSemicolonPattern = /;\s*$/; +var warnedStyleNames = {}; +var warnedStyleValues = {}; +var warnedForNaNValue = false; +var warnedForInfinityValue = false; - var warnHyphenatedStyleName = function (name) { +function camelize(string) { + return string.replace(hyphenPattern, function (_, character) { + return character.toUpperCase(); + }); +} + +function warnHyphenatedStyleName(name) { + { if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { return; } @@ -1491,9 +1467,11 @@ var warnValidStyle = function () {}; // (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix // is converted to lowercase `ms`. camelize(name.replace(msPattern$1, 'ms-'))); - }; + } +} - var warnBadVendoredStyleName = function (name) { +function warnBadVendoredStyleName(name) { + { if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { return; } @@ -1501,9 +1479,11 @@ var warnValidStyle = function () {}; warnedStyleNames[name] = true; error('Unsupported vendor-prefixed style property %s. Did you mean %s?', name, name.charAt(0).toUpperCase() + name.slice(1)); - }; + } +} - var warnStyleValueWithSemicolon = function (name, value) { +function warnStyleValueWithSemicolon(name, value) { + { if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { return; } @@ -1511,9 +1491,11 @@ var warnValidStyle = function () {}; warnedStyleValues[value] = true; error("Style property values shouldn't contain a semicolon. " + 'Try "%s: %s" instead.', name, value.replace(badStyleValueWithSemicolonPattern, '')); - }; + } +} - var warnStyleValueIsNaN = function (name, value) { +function warnStyleValueIsNaN(name, value) { + { if (warnedForNaNValue) { return; } @@ -1521,9 +1503,11 @@ var warnValidStyle = function () {}; warnedForNaNValue = true; error('`NaN` is an invalid value for the `%s` css style property.', name); - }; + } +} - var warnStyleValueIsInfinity = function (name, value) { +function warnStyleValueIsInfinity(name, value) { + { if (warnedForInfinityValue) { return; } @@ -1531,9 +1515,11 @@ var warnValidStyle = function () {}; warnedForInfinityValue = true; error('`Infinity` is an invalid value for the `%s` css style property.', name); - }; + } +} - warnValidStyle = function (name, value) { +function warnValidStyle(name, value) { + { if (name.indexOf('-') > -1) { warnHyphenatedStyleName(name); } else if (badVendoredStyleNamePattern.test(name)) { @@ -1544,16 +1530,14 @@ var warnValidStyle = function () {}; if (typeof value === 'number') { if (isNaN(value)) { - warnStyleValueIsNaN(name, value); + warnStyleValueIsNaN(name); } else if (!isFinite(value)) { - warnStyleValueIsInfinity(name, value); + warnStyleValueIsInfinity(name); } } - }; + } } -var warnValidStyle$1 = warnValidStyle; - // code copied and modified from escape-html var matchHtmlRegExp = /["'&<>]/; /** @@ -2341,7 +2325,7 @@ function pushStyleAttribute(target, style) { valueChunk = stringToChunk(escapeTextForBrowser(('' + styleValue).trim())); } else { { - warnValidStyle$1(styleName, styleValue); + warnValidStyle(styleName, styleValue); } nameChunk = processStyleName(styleName); @@ -6757,11 +6741,10 @@ var didWarnAboutUninitializedState; var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; var didWarnAboutLegacyLifecyclesAndDerivedState; var didWarnAboutUndefinedDerivedState; -var warnOnUndefinedDerivedState; -var warnOnInvalidCallback; var didWarnAboutDirectlyAssigningPropsToState; var didWarnAboutContextTypeAndContextTypes; var didWarnAboutInvalidateContextType; +var didWarnOnInvalidCallback; { didWarnAboutUninitializedState = new Set(); @@ -6771,9 +6754,11 @@ var didWarnAboutInvalidateContextType; didWarnAboutUndefinedDerivedState = new Set(); didWarnAboutContextTypeAndContextTypes = new Set(); didWarnAboutInvalidateContextType = new Set(); - var didWarnOnInvalidCallback = new Set(); + didWarnOnInvalidCallback = new Set(); +} - warnOnInvalidCallback = function (callback, callerName) { +function warnOnInvalidCallback(callback, callerName) { + { if (callback === null || typeof callback === 'function') { return; } @@ -6785,9 +6770,11 @@ var didWarnAboutInvalidateContextType; error('%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); } - }; + } +} - warnOnUndefinedDerivedState = function (type, partialState) { +function warnOnUndefinedDerivedState(type, partialState) { + { if (partialState === undefined) { var componentName = getComponentNameFromType(type) || 'Component'; @@ -6797,7 +6784,7 @@ var didWarnAboutInvalidateContextType; error('%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName); } } - }; + } } function warnNoop(publicInstance, callerName) { @@ -7906,16 +7893,8 @@ function use(usable) { // $FlowFixMe[method-unbinding] if (typeof usable.then === 'function') { // This is a thenable. - var thenable = usable; // Track the position of the thenable within this fiber. - - var index = thenableIndexCounter; - thenableIndexCounter += 1; - - if (thenableState === null) { - thenableState = createThenableState(); - } - - return trackUsedThenable(thenableState, thenable, index); + var thenable = usable; + return unwrapThenable(thenable); } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) { var context = usable; return readContext(context); @@ -7926,6 +7905,17 @@ function use(usable) { throw new Error('An unsupported type was passed to use(): ' + String(usable)); } +function unwrapThenable(thenable) { + var index = thenableIndexCounter; + thenableIndexCounter += 1; + + if (thenableState === null) { + thenableState = createThenableState(); + } + + return trackUsedThenable(thenableState, thenable, index); +} + function unsupportedRefresh() { throw new Error('Cache cannot be refreshed during server rendering.'); } @@ -8929,6 +8919,27 @@ function renderNodeDestructiveImpl(request, task, prevThenableState, node) { return; } + } // Usables are a valid React node type. When React encounters a Usable in + // a child position, it unwraps it using the same algorithm as `use`. For + // example, for promises, React will throw an exception to unwind the + // stack, then replay the component once the promise resolves. + // + // A difference from `use` is that React will keep unwrapping the value + // until it reaches a non-Usable type. + // + // e.g. Usable>> should resolve to T + + + var maybeUsable = node; + + if (typeof maybeUsable.then === 'function') { + var thenable = maybeUsable; + return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable)); + } + + if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) { + var context = maybeUsable; + return renderNodeDestructiveImpl(request, task, null, readContext$1(context)); } // $FlowFixMe[method-unbinding] diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js index 860636f976d7cd..31f03fba7605fe 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js @@ -10,46 +10,46 @@ 'use strict';var aa=require("react"),ba=require("react-dom");function m(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c