diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59aac2709..1bf425aaa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,9 @@ jobs: run: cargo build --all-targets --tests working-directory: api + - name: Check uncommitted changes + run: git diff --exit-code + - name: Test run: cargo test working-directory: api diff --git a/Cargo.lock b/Cargo.lock index 1df9671a5..6cf023394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -908,6 +908,41 @@ dependencies = [ "uuid", ] +[[package]] +name = "deno_ast" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59d2c5dcead329b1382472f0ca026839f33a86d897b47cf6d9cfa21c520b69c6" +dependencies = [ + "base64 0.22.1", + "capacity_builder", + "deno_error 0.5.7", + "deno_media_type", + "deno_terminal", + "dprint-swc-ext", + "percent-encoding", + "serde", + "sourcemap", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_codegen_macros", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_eq_ignore_macros", + "swc_macros_common 1.0.0", + "swc_visit", + "swc_visit_macros", + "text_lines", + "thiserror 2.0.12", + "unicode-width 0.2.0", + "url", +] + [[package]] name = "deno_ast" version = "0.48.0" @@ -916,7 +951,7 @@ checksum = "0f883bd8eae4dfc8019d925ec3dd04b634b6af9346a5168acc259d55f5f5021d" dependencies = [ "base64 0.22.1", "capacity_builder", - "deno_error", + "deno_error 0.6.1", "deno_media_type", "deno_terminal", "dprint-swc-ext", @@ -950,6 +985,36 @@ dependencies = [ "url", ] +[[package]] +name = "deno_doc" +version = "0.174.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc305e5fe22a3b14705964daef6fb2dd328345cce92d785a6f629d222590e11" +dependencies = [ + "anyhow", + "cfg-if", + "comrak", + "deno_ast 0.47.0", + "deno_graph 0.91.0", + "deno_path_util 0.3.3", + "deno_terminal", + "handlebars 6.1.0", + "html-escape", + "import_map 0.21.0", + "indexmap 2.5.0", + "itoa", + "js-sys", + "lazy_static", + "percent-encoding", + "regex", + "serde", + "serde-wasm-bindgen", + "serde_json", + "termcolor", + "url", + "wasm-bindgen", +] + [[package]] name = "deno_doc" version = "0.178.1" @@ -959,13 +1024,13 @@ dependencies = [ "anyhow", "cfg-if", "comrak", - "deno_ast", - "deno_graph", - "deno_path_util", + "deno_ast 0.48.0", + "deno_graph 0.95.1", + "deno_path_util 0.4.0", "deno_terminal", "handlebars 6.1.0", "html-escape", - "import_map", + "import_map 0.22.0", "indexmap 2.5.0", "itoa", "js-sys", @@ -980,19 +1045,43 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "deno_error" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e983933fb4958fbe1e0a63c1e89a2af72b12c409e86404e547955564e6e217b8" +dependencies = [ + "deno_error_macro 0.5.7", + "libc", + "serde", + "serde_json", + "url", +] + [[package]] name = "deno_error" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612ec3fc481fea759141b0c57810889b0a4fb6fee8f10748677bfe492fd30486" dependencies = [ - "deno_error_macro", + "deno_error_macro 0.6.1", "libc", "serde", "serde_json", "url", ] +[[package]] +name = "deno_error_macro" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ad5ae3ef15db33e917d6ed54b53d0a98d068c4d1217eb35a4997423203c3ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "deno_error_macro" version = "0.6.1" @@ -1004,6 +1093,39 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "deno_graph" +version = "0.91.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d54da704eeea3a15a23eb929f93914d833a2a2858c1aaec220097343445ca04" +dependencies = [ + "async-trait", + "capacity_builder", + "data-url", + "deno_ast 0.47.0", + "deno_error 0.5.7", + "deno_media_type", + "deno_path_util 0.3.3", + "deno_semver 0.7.1", + "deno_unsync", + "encoding_rs", + "futures", + "import_map 0.21.0", + "indexmap 2.5.0", + "log", + "monch", + "once_cell", + "parking_lot", + "regex", + "serde", + "serde_json", + "sha2", + "sys_traits", + "thiserror 2.0.12", + "url", + "wasm_dep_analyzer 0.2.0", +] + [[package]] name = "deno_graph" version = "0.95.1" @@ -1013,15 +1135,15 @@ dependencies = [ "async-trait", "capacity_builder", "data-url", - "deno_ast", - "deno_error", + "deno_ast 0.48.0", + "deno_error 0.6.1", "deno_media_type", - "deno_path_util", - "deno_semver", + "deno_path_util 0.4.0", + "deno_semver 0.8.0", "deno_unsync", "encoding_rs", "futures", - "import_map", + "import_map 0.22.0", "indexmap 2.5.0", "log", "monch", @@ -1035,7 +1157,7 @@ dependencies = [ "thiserror 2.0.12", "twox-hash", "url", - "wasm_dep_analyzer", + "wasm_dep_analyzer 0.3.0", ] [[package]] @@ -1050,19 +1172,49 @@ dependencies = [ "url", ] +[[package]] +name = "deno_path_util" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8850326ea9cb786aafd938f3de9866432904c0bae3aa0139a7a4e570b0174f6" +dependencies = [ + "deno_error 0.5.7", + "percent-encoding", + "sys_traits", + "thiserror 2.0.12", + "url", +] + [[package]] name = "deno_path_util" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "516f813389095889776b81cc9108ff6f336fd9409b4b12fc0138aea23d2708e1" dependencies = [ - "deno_error", + "deno_error 0.6.1", "percent-encoding", "sys_traits", "thiserror 2.0.12", "url", ] +[[package]] +name = "deno_semver" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4775271f9b5602482698f76d24ea9ed8ba27af7f587a7e9a876916300c542435" +dependencies = [ + "capacity_builder", + "deno_error 0.5.7", + "ecow", + "hipstr", + "monch", + "once_cell", + "serde", + "thiserror 2.0.12", + "url", +] + [[package]] name = "deno_semver" version = "0.8.0" @@ -1070,7 +1222,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d807160e754edb1989b4a19cac1ac5299065a7a89ff98682a2366cbaa25795" dependencies = [ "capacity_builder", - "deno_error", + "deno_error 0.6.1", "ecow", "hipstr", "monch", @@ -2027,6 +2179,23 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" +[[package]] +name = "import_map" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1215d4d92511fbbdaea50e750e91f2429598ef817f02b579158e92803b52c00a" +dependencies = [ + "boxed_error", + "deno_error 0.5.7", + "indexmap 2.5.0", + "log", + "percent-encoding", + "serde", + "serde_json", + "thiserror 2.0.12", + "url", +] + [[package]] name = "import_map" version = "0.22.0" @@ -2034,7 +2203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f315e535cb94a0e80704278d630990bb48834c8c8d976acf0a2f6bc8fede7c38" dependencies = [ "boxed_error", - "deno_error", + "deno_error 0.6.1", "indexmap 2.5.0", "log", "percent-encoding", @@ -3212,11 +3381,12 @@ dependencies = [ "comrak", "const_format", "crc32fast", - "deno_ast", - "deno_doc", - "deno_error", - "deno_graph", - "deno_semver", + "deno_ast 0.48.0", + "deno_doc 0.174.0", + "deno_doc 0.178.1", + "deno_error 0.6.1", + "deno_graph 0.95.1", + "deno_semver 0.8.0", "dotenvy", "flate2", "futures", @@ -5552,13 +5722,23 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm_dep_analyzer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eeee3bdea6257cc36d756fa745a70f9d393571e47d69e0ed97581676a5369ca" +dependencies = [ + "deno_error 0.5.7", + "thiserror 2.0.12", +] + [[package]] name = "wasm_dep_analyzer" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51cf5f08b357e64cd7642ab4bbeb11aecab9e15520692129624fb9908b8df2c" dependencies = [ - "deno_error", + "deno_error 0.6.1", "thiserror 2.0.12", ] diff --git a/api/Cargo.toml b/api/Cargo.toml index 94ec7f870..68fceda9e 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -115,3 +115,6 @@ lazy_static = "1.5.0" flate2 = "1" deno_semver = "0.8.0" pretty_assertions = "1.4.0" + +[build-dependencies] +deno_doc = { version = "0.174.0", features = ["comrak"] } \ No newline at end of file diff --git a/api/build.rs b/api/build.rs new file mode 100644 index 000000000..fe6eb4c2b --- /dev/null +++ b/api/build.rs @@ -0,0 +1,18 @@ +// Copyright 2024 the JSR authors. All rights reserved. MIT license. +use std::fs; +use std::path::Path; + +fn main() { + let static_dir = Path::new("../frontend/static/ddoc"); + fs::create_dir_all(static_dir).unwrap(); + + fs::write(static_dir.join("style.css"), deno_doc::html::STYLESHEET).unwrap(); + + fs::write( + static_dir.join("comrak.css"), + deno_doc::html::comrak::COMRAK_STYLESHEET, + ) + .unwrap(); + + fs::write(static_dir.join("script.js"), deno_doc::html::SCRIPT_JS).unwrap(); +} diff --git a/api/src/analysis.rs b/api/src/analysis.rs index 561866d22..d3117e3ca 100644 --- a/api/src/analysis.rs +++ b/api/src/analysis.rs @@ -11,6 +11,7 @@ use deno_ast::ModuleSpecifier; use deno_ast::ParsedSource; use deno_ast::SourceRange; use deno_ast::SourceRangedForSpanned; +use deno_doc::html::search::SearchIndexNode; use deno_ast::swc::common::Span; use deno_ast::swc::common::comments::CommentKind; use deno_doc::DocNodeDef; @@ -68,7 +69,7 @@ pub struct PackageAnalysisOutput { pub data: PackageAnalysisData, pub module_graph_2: HashMap, pub doc_nodes_json: Bytes, - pub doc_search_json: serde_json::Value, + pub doc_search: Vec, pub dependencies: HashSet<(DependencyKind, PackageReqReference)>, pub npm_tarball: NpmTarball, pub readme_path: Option, @@ -252,8 +253,8 @@ async fn analyze_package_inner( doc_nodes, main_entrypoint, info.rewrite_map, - scope, - name, + scope.clone(), + name.clone(), version, true, None, @@ -266,20 +267,41 @@ async fn analyze_package_inner( bun: None, }, registry_url.to_string(), + Some(format!("{scope}/{name}/")), ); - let search_index = deno_doc::html::generate_search_index(&ctx); - let doc_search_json = if let serde_json::Value::Object(mut obj) = search_index - { - obj.remove("nodes").unwrap() - } else { - unreachable!() - }; + + let doc_nodes = ctx + .doc_nodes + .values() + .flatten() + .map(std::borrow::Cow::Borrowed); + let partitions = + deno_doc::html::partition::partition_nodes_by_name(&ctx, doc_nodes, true); + let render_ctx = deno_doc::html::RenderContext::new( + &ctx, + &[], + deno_doc::html::UrlResolveKind::AllSymbols, + ); + + let mut doc_search = partitions + .into_iter() + .flat_map(|(name, nodes)| { + deno_doc::html::search::doc_nodes_into_search_index_node( + &render_ctx, + nodes, + name, + None, + ) + }) + .collect::>(); + + doc_search.sort_by(|a, b| a.file.cmp(&b.file)); Ok(PackageAnalysisOutput { data: PackageAnalysisData { exports, files }, module_graph_2, doc_nodes_json, - doc_search_json, + doc_search, dependencies, npm_tarball, readme_path, diff --git a/api/src/api/package.rs b/api/src/api/package.rs index fb426fd26..f29f99826 100644 --- a/api/src/api/package.rs +++ b/api/src/api/package.rs @@ -33,7 +33,6 @@ use routerify_query::RequestQueryExt; use serde::Deserialize; use serde::Serialize; use sha2::Digest; -use std::borrow::Cow; use std::io; use std::sync::Arc; use std::sync::Mutex; @@ -1261,6 +1260,8 @@ pub async fn get_docs_handler( package.runtime_compat, registry_url, package.readme_source, + None, + None, ) .map_err(|e| { error!("failed to generate docs: {}", e); @@ -1270,9 +1271,6 @@ pub async fn get_docs_handler( match docs { GeneratedDocsOutput::Docs(docs) => Ok(ApiPackageVersionDocs::Content { - css: Cow::Borrowed(deno_doc::html::STYLESHEET), - comrak_css: Cow::Borrowed(deno_doc::html::comrak::COMRAK_STYLESHEET), - script: Cow::Borrowed(deno_doc::html::SCRIPT_JS), breadcrumbs: docs.breadcrumbs, toc: docs.toc, main: docs.main, @@ -1348,9 +1346,10 @@ pub async fn get_docs_search_handler( false, package.runtime_compat, registry_url, + Some(format!("{scope}/{package_name}/")), ); - let search_index = deno_doc::html::generate_search_index(&ctx); + let search_index = deno_doc::html::search::generate_search_index(&ctx); Ok(search_index) } @@ -1421,6 +1420,8 @@ pub async fn get_docs_search_html_handler( package.runtime_compat, registry_url, package.readme_source, + Some(format!("{}/{}/", scope, package_name)), + None, ) .map_err(|e| { error!("failed to generate docs: {}", e); @@ -1589,9 +1590,6 @@ pub async fn get_source_handler( Ok(ApiPackageVersionSource { version: ApiPackageVersion::from(version), - css: Cow::Borrowed(deno_doc::html::STYLESHEET), - comrak_css: Cow::Borrowed(deno_doc::html::comrak::COMRAK_STYLESHEET), - script: Cow::Borrowed(deno_doc::html::SCRIPT_JS), source, }) } @@ -3536,15 +3534,11 @@ ggHohNAjhbzDaY2iBW/m3NC5dehGUP4T2GBo/cwGhg== match docs { ApiPackageVersionDocs::Content { version, - css, - comrak_css: _, - script: _, breadcrumbs, toc, main: _, } => { assert_eq!(version.version, task.package_version); - assert!(css.contains("{max-width:"), "{}", css); assert!(breadcrumbs.is_none(), "{:?}", breadcrumbs); assert!(toc.is_some(), "{:?}", toc) } @@ -3562,15 +3556,11 @@ ggHohNAjhbzDaY2iBW/m3NC5dehGUP4T2GBo/cwGhg== match docs { ApiPackageVersionDocs::Content { version, - css, - comrak_css: _, - script: _, breadcrumbs, toc, main: _, } => { assert_eq!(version.version, task.package_version); - assert!(css.contains("{max-width:"), "{}", css); assert!( breadcrumbs.as_ref().unwrap().contains("all symbols"), "{:?}", @@ -3592,15 +3582,11 @@ ggHohNAjhbzDaY2iBW/m3NC5dehGUP4T2GBo/cwGhg== match docs { ApiPackageVersionDocs::Content { version, - css, - comrak_css: _, - script: _, breadcrumbs, toc, main: _, } => { assert_eq!(version.version, task.package_version); - assert!(css.contains("{max-width:"), "{}", css); assert!( breadcrumbs.as_ref().unwrap().contains("hello"), "{:?}", @@ -3625,15 +3611,11 @@ ggHohNAjhbzDaY2iBW/m3NC5dehGUP4T2GBo/cwGhg== match docs { ApiPackageVersionDocs::Content { version, - css, - comrak_css: _, - script: _, breadcrumbs, toc, main: _, } => { assert_eq!(version.version, task.package_version); - assert!(css.contains("{max-width:"), "{}", css); assert!( breadcrumbs.as_ref().unwrap().contains("读取多键1"), "{:?}", @@ -3654,7 +3636,7 @@ ggHohNAjhbzDaY2iBW/m3NC5dehGUP4T2GBo/cwGhg== let search: serde_json::Value = resp.expect_ok().await; assert_eq!( search, - json!({"kind":"search","nodes":[{"id":"namespace_hello","kind":[{"kind":"Variable","char":"v","title":"Variable"}],"name":"hello","file":".","doc":"This is a test constant.","url":"/@scope/foo@1.2.3/doc/~/hello","deprecated":false},{"id":"namespace_读取多键1","kind":[{"kind":"Variable","char":"v","title":"Variable"}],"name":"读取多键1","file":".","doc":"","url":"/@scope/foo@1.2.3/doc/~/读取多键1","deprecated":false}]}), + json!({"kind":"search","nodes":[{"id":"scope/foo/_namespace_hello","kind":[{"kind":"Variable","char":"v","title":"Variable"}],"name":"hello","file":".","doc":"This is a test constant.","url":"/@scope/foo@1.2.3/doc/~/hello","deprecated":false},{"id":"scope/foo/_namespace_读取多键1","kind":[{"kind":"Variable","char":"v","title":"Variable"}],"name":"读取多键1","file":".","doc":"","url":"/@scope/foo@1.2.3/doc/~/读取多键1","deprecated":false}]}), ); // symbol doesn't exist diff --git a/api/src/api/scope.rs b/api/src/api/scope.rs index 83219729a..546287c1b 100644 --- a/api/src/api/scope.rs +++ b/api/src/api/scope.rs @@ -1,12 +1,10 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. -use std::borrow::Cow; -use std::sync::OnceLock; - -use crate::RegistryUrl; use crate::api::package::package_router; use crate::emails::EmailArgs; use crate::emails::EmailSender; use crate::iam::ReqIamExt; +use crate::RegistryUrl; +use anyhow::Context; use hyper::Body; use hyper::Request; use hyper::Response; @@ -14,6 +12,9 @@ use hyper::StatusCode; use routerify::Router; use routerify::ext::RequestExt; use tracing::Span; +use std::borrow::Cow; +use std::sync::OnceLock; +use tracing::error; use tracing::field; use tracing::instrument; @@ -21,11 +22,16 @@ use super::errors::ApiError; use super::errors::map_unique_violation; use super::types::*; -use crate::auth::GithubOauth2Client; use crate::auth::lookup_user_by_github_login; +use crate::auth::GithubOauth2Client; +use crate::buckets::Buckets; use crate::db::*; +use crate::docs::DocNodesByUrl; +use crate::docs::DocsRequest; +use crate::docs::GeneratedDocsOutput; use crate::util; use crate::util::ApiResult; +use crate::util::CacheDuration; use crate::util::RequestIdExt; use crate::util::decode_json; @@ -54,6 +60,13 @@ pub fn scope_router() -> Router { "/:scope/invites/:user_id", util::auth(delete_invite_handler), ) + .get( + "/:scope/search_html", + util::cache( + CacheDuration::ONE_MINUTE, + util::json(get_docs_search_html_handler), + ), + ) .build() .unwrap() } @@ -497,6 +510,88 @@ pub async fn delete_invite_handler( Ok(resp) } +#[instrument( + name = "GET /api/scopes/:scope/search_html", + skip(req), + err, + fields(scope, user_id) +)] +pub async fn get_docs_search_html_handler( + req: Request, +) -> ApiResult { + let scope = req.param_scope()?; + Span::current().record("scope", field::display(&scope)); + + let db = req.data::().unwrap(); + let buckets = req.data::().unwrap(); + + let (_, packages) = db.list_packages_by_scope(&scope, false, 0, 100).await?; + + let registry_url = req.data::().unwrap().0.to_string(); + + let mut outsearch = String::new(); + for (package, _, _) in packages { + let (package, repo, _) = db + .get_package(&scope, &package.name) + .await? + .ok_or(ApiError::PackageNotFound)?; + + let Some(version) = db + .get_latest_unyanked_version_for_package(&scope, &package.name) + .await? + else { + continue; + }; + + let docs_path = + crate::gcs_paths::docs_v1_path(&scope, &package.name, &version.version); + let docs = buckets.docs_bucket.download(docs_path.into()).await?; + let docs = docs.ok_or_else(|| { + error!( + "docs not found for {}/{}/{}", + scope, package.name, version.version + ); + ApiError::InternalServerError + })?; + + let doc_nodes: DocNodesByUrl = + serde_json::from_slice(&docs).context("failed to parse doc nodes")?; + let docs_info = crate::docs::get_docs_info(&version.exports, None); + + let docs = crate::docs::generate_docs_html( + doc_nodes, + docs_info.main_entrypoint, + docs_info.rewrite_map, + DocsRequest::AllSymbols, + scope.clone(), + package.name.clone(), + version.version.clone(), + true, + repo, + None, + package.runtime_compat, + registry_url.clone(), + package.readme_source, + Some(format!("{}/{}/", scope, package.name)), + Some(format!("@{}/{}/", scope, package.name)), + ) + .map_err(|e| { + error!("failed to generate docs: {}", e); + ApiError::InternalServerError + })? + .unwrap(); + + let search = match docs { + GeneratedDocsOutput::Docs(docs) => docs.main, + GeneratedDocsOutput::Redirect(_) => unreachable!(), + }; + + outsearch.push_str(&search); + } + + Ok(outsearch) +} + #[cfg(test)] pub mod tests { use super::*; diff --git a/api/src/api/types.rs b/api/src/api/types.rs index 0bc776a2b..fd278fa2a 100644 --- a/api/src/api/types.rs +++ b/api/src/api/types.rs @@ -1,6 +1,4 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. -use std::borrow::Cow; - use crate::db::*; use crate::ids::PackageName; use crate::ids::PackagePath; @@ -631,9 +629,6 @@ pub enum ApiPackageVersionDocs { #[serde(rename_all = "camelCase")] Content { version: ApiPackageVersion, - css: Cow<'static, str>, - comrak_css: Cow<'static, str>, - script: Cow<'static, str>, breadcrumbs: Option, toc: Option, main: String, @@ -687,9 +682,6 @@ pub enum ApiSource { #[serde(rename_all = "camelCase")] pub struct ApiPackageVersionSource { pub version: ApiPackageVersion, - pub css: Cow<'static, str>, - pub comrak_css: Cow<'static, str>, - pub script: Cow<'static, str>, pub source: ApiSource, } diff --git a/api/src/docs.rs b/api/src/docs.rs index d6749f132..18787b15a 100644 --- a/api/src/docs.rs +++ b/api/src/docs.rs @@ -22,7 +22,6 @@ use deno_doc::html::ShortPath; use deno_doc::html::UrlResolveKind; use deno_doc::html::UsageComposerEntry; use deno_doc::html::pages::SymbolPage; -use deno_doc::html::util::Id; use deno_semver::RangeSetOrTag; use indexmap::IndexMap; use std::borrow::Cow; @@ -440,6 +439,7 @@ pub fn get_generate_ctx<'a>( has_readme: bool, runtime_compat: RuntimeCompat, registry_url: String, + id_prefix: Option, ) -> GenerateCtx { let package_name = format!("@{scope}/{package}"); let url_rewriter_base = format!("/{package_name}/{version}"); @@ -515,7 +515,7 @@ pub fn get_generate_ctx<'a>( markdown_renderer, markdown_stripper: Rc::new(deno_doc::html::comrak::strip), head_inject: None, - id_prefix: None, + id_prefix, }, None, deno_doc::html::FileMode::Normal, @@ -544,6 +544,8 @@ pub fn generate_docs_html( runtime_compat: RuntimeCompat, registry_url: String, readme_source: ReadmeSource, + id_prefix: Option, + all_symbols_section_prefix: Option, ) -> Result, anyhow::Error> { let ctx = get_generate_ctx( doc_nodes_by_url, @@ -557,6 +559,7 @@ pub fn generate_docs_html( readme.is_some(), runtime_compat, registry_url, + id_prefix, ); match req { @@ -577,10 +580,24 @@ pub fn generate_docs_html( partitions_by_kind.into_iter().map(|(path, nodes)| { ( render_ctx.clone(), - deno_doc::html::SectionHeaderCtx::new_for_all_symbols( - &render_ctx, - &path, - ), + { + let mut header = + deno_doc::html::SectionHeaderCtx::new_for_all_symbols( + &render_ctx, + &path, + ); + + if let Some(header) = &mut header { + if let Some(all_symbols_section_prefix) = + &all_symbols_section_prefix + { + header.title = + format!("{all_symbols_section_prefix}{}", header.title); + } + } + + header + }, nodes, ) }), @@ -593,7 +610,7 @@ pub fn generate_docs_html( .render( "symbol_content", &deno_doc::html::SymbolContentCtx { - id: Id::empty(), + id: deno_doc::html::util::Id::empty(), sections, docs: None, }, diff --git a/api/src/orama.rs b/api/src/orama.rs index efb3ce861..055f49e00 100644 --- a/api/src/orama.rs +++ b/api/src/orama.rs @@ -1,18 +1,18 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. // Copyright Deno Land Inc. All Rights Reserved. Proprietary and confidential. -use std::sync::Arc; - use crate::api::ApiPackageScore; use crate::db::Package; use crate::db::PackageVersionMeta; use crate::ids::PackageName; use crate::ids::ScopeName; use crate::util::USER_AGENT; -use tracing::Instrument; -use tracing::Span; +use deno_doc::html::search::SearchIndexNode; +use std::sync::Arc; use tracing::error; use tracing::instrument; +use tracing::Instrument; +use tracing::Span; const MAX_ORAMA_INSERT_SIZE: f64 = 3f64 * 1024f64 * 1024f64; @@ -138,7 +138,7 @@ impl OramaClient { &self, scope_name: &ScopeName, package_name: &PackageName, - search: serde_json::Value, + search: &[SearchIndexNode], ) { let package = format!("{scope_name}/{package_name}"); let body = serde_json::json!({ @@ -172,17 +172,21 @@ impl OramaClient { .instrument(span), ); - let search = if let serde_json::Value::Array(mut array) = search { - for entry in &mut array { - let obj = entry.as_object_mut().unwrap(); - obj.insert("scope".to_string(), scope_name.to_string().into()); - obj.insert("package".to_string(), package_name.to_string().into()); - } - - array - } else { - unreachable!() - }; + let search = search + .iter() + .map(|node| { + serde_json::json!({ + "target_id": node.id, + "name": node.name, + "file": node.file, + "doc": node.doc, + "url": node.url, + "deprecated": node.deprecated, + "scope": scope_name.to_string(), + "package": package_name.to_string(), + }) + }) + .collect::>(); let chunks = { let str_data = serde_json::to_string(&search).unwrap(); diff --git a/api/src/publish.rs b/api/src/publish.rs index fa8bd9bbd..8028b9552 100644 --- a/api/src/publish.rs +++ b/api/src/publish.rs @@ -206,7 +206,7 @@ async fn process_publishing_task( npm_tarball_info, readme_path, meta, - doc_search_json, + doc_search, } = output; upload_version_manifest( @@ -234,7 +234,7 @@ async fn process_publishing_task( orama_client.upsert_symbols( &publishing_task.package_scope, &publishing_task.package_name, - doc_search_json, + &doc_search, ); } diff --git a/api/src/tarball.rs b/api/src/tarball.rs index 63cb59c95..566a735b5 100644 --- a/api/src/tarball.rs +++ b/api/src/tarball.rs @@ -7,6 +7,7 @@ use std::sync::OnceLock; use async_tar::EntryType; use bytes::Bytes; use deno_ast::MediaType; +use deno_doc::html::search::SearchIndexNode; use deno_graph::ModuleGraphError; use deno_semver::jsr::JsrPackageReqReference; use deno_semver::npm::NpmPackageReqReference; @@ -66,7 +67,7 @@ pub struct ProcessTarballOutput { pub npm_tarball_info: NpmTarballInfo, pub readme_path: Option, pub meta: PackageVersionMeta, - pub doc_search_json: serde_json::Value, + pub doc_search: Vec, } pub struct NpmTarballInfo { @@ -283,7 +284,7 @@ pub async fn process_tarball( data: PackageAnalysisData { exports, files }, module_graph_2, doc_nodes_json, - doc_search_json, + doc_search, dependencies, npm_tarball, readme_path, @@ -460,7 +461,7 @@ pub async fn process_tarball( npm_tarball_info, readme_path, meta, - doc_search_json, + doc_search, }) } diff --git a/deno.json b/deno.json index fc784d351..4634f22f5 100644 --- a/deno.json +++ b/deno.json @@ -36,6 +36,7 @@ "api/testdata/", ".gcs/", "frontend/_fresh", + "frontend/static/ddoc/*", "e2e/vendor" ], "imports": { diff --git a/frontend/components/List.tsx b/frontend/components/List.tsx index 12bfcbb26..1996ab65e 100644 --- a/frontend/components/List.tsx +++ b/frontend/components/List.tsx @@ -10,15 +10,19 @@ export interface ListDisplayItem { } export function ListDisplay( - { title, pagination, currentUrl, children }: { + { title, pagination, currentUrl, children, id }: { title?: string; pagination?: PaginationData; currentUrl?: URL; children: ListDisplayItem[]; + id?: string; }, ) { return ( -
+
{title && (
diff --git a/frontend/components/Nav.tsx b/frontend/components/Nav.tsx index 34a14da23..b1e63a4ab 100644 --- a/frontend/components/Nav.tsx +++ b/frontend/components/Nav.tsx @@ -4,21 +4,17 @@ import { NavOverflow } from "./NavOverflow.tsx"; export interface NavProps { children?: ComponentChildren; + end?: ComponentChildren; noTopMargin?: boolean; } export function Nav(props: NavProps) { return ( -