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 05283b76a..c37d00ca3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -448,11 +448,12 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64-simd" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" dependencies = [ - "simd-abstraction", + "outref", + "vsimd", ] [[package]] @@ -909,20 +910,19 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.46.5" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fa4986eb7deb465906266ee29faa26566d33f8b6a755ac93d49730164ae5e8" +checksum = "59d2c5dcead329b1382472f0ca026839f33a86d897b47cf6d9cfa21c520b69c6" dependencies = [ "base64 0.22.1", + "capacity_builder", "deno_error", "deno_media_type", "deno_terminal", "dprint-swc-ext", - "once_cell", "percent-encoding", "serde", "sourcemap", - "string_capacity", "swc_atoms", "swc_common", "swc_config", @@ -952,9 +952,9 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.171.1" +version = "0.174.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2586f93cf7326a45a117affbb76f1330f26cfea62cc13b91b02fce34c1d81d" +checksum = "edc305e5fe22a3b14705964daef6fb2dd328345cce92d785a6f629d222590e11" dependencies = [ "anyhow", "cfg-if", @@ -1006,9 +1006,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.89.4" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d12e08a843ed1dbef68de3720092e67dcb958eae59ec2f26a459597c2c76be0" +checksum = "0d54da704eeea3a15a23eb929f93914d833a2a2858c1aaec220097343445ca04" dependencies = [ "async-trait", "capacity_builder", @@ -1240,14 +1240,14 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "dprint-swc-ext" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "569b85f94c1e7d1065874115193cf081d658ebb01213d54fda357516837a17fc" +checksum = "9a09827d6db1a3af25e105553d674ee9019be58fa3d6745c2a2803f8ce8e3eb8" dependencies = [ "allocator-api2", "bumpalo", "num-bigint", - "rustc-hash 2.1.1", + "rustc-hash", "swc_atoms", "swc_common", "swc_ecma_ast", @@ -1774,7 +1774,7 @@ dependencies = [ "new_debug_unreachable", "once_cell", "phf", - "rustc-hash 2.1.1", + "rustc-hash", "triomphe", ] @@ -2657,9 +2657,9 @@ dependencies = [ [[package]] name = "outref" -version = "0.1.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "overload" @@ -3443,27 +3443,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - [[package]] name = "rusticata-macros" version = "4.1.0" @@ -3634,21 +3619,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.219" @@ -3774,15 +3744,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "simd-abstraction" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" -dependencies = [ - "outref", -] - [[package]] name = "simple_asn1" version = "0.6.2" @@ -3859,17 +3820,16 @@ dependencies = [ [[package]] name = "sourcemap" -version = "9.1.2" +version = "9.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c4ea7042fd1a155ad95335b5d505ab00d5124ea0332a06c8390d200bb1a76a" +checksum = "dd430118acc9fdd838557649b9b43fd0a78e3834d84a283b466f8e84720d6101" dependencies = [ "base64-simd", "bitvec", "data-encoding", "debugid", "if_chain", - "rustc-hash 1.1.0", - "rustc_version", + "rustc-hash", "serde", "serde_json", "unicode-id-start", @@ -4175,15 +4135,6 @@ dependencies = [ "quote", ] -[[package]] -name = "string_capacity" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd14cb3a5abda6d2626370785f5f788b22e95476f597159faa4a2cc2966961a" -dependencies = [ - "itoa", -] - [[package]] name = "string_enum" version = "1.0.0" @@ -4229,7 +4180,7 @@ dependencies = [ "bumpalo", "hashbrown 0.14.5", "ptr_meta", - "rustc-hash 2.1.1", + "rustc-hash", "triomphe", ] @@ -4241,29 +4192,15 @@ checksum = "9d7077ba879f95406459bc0c81f3141c529b34580bc64d7ab7bd15e7118a0391" dependencies = [ "hstr", "once_cell", - "rustc-hash 2.1.1", - "serde", -] - -[[package]] -name = "swc_cached" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7133338c3bef796430deced151b0eaa5430710a90e38da19e8e3045e8e36eeb" -dependencies = [ - "anyhow", - "dashmap", - "once_cell", - "regex", - "rustc-hash 2.1.1", + "rustc-hash", "serde", ] [[package]] name = "swc_common" -version = "8.1.0" +version = "9.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d96ac5d021c7c20acb3073940b4ee59b62989a705f855783c4a452e0737a2e6" +checksum = "a56b6f5a8e5affa271b56757a93badee6f44defcd28f3ba106bb2603afe40d3d" dependencies = [ "anyhow", "ast_node", @@ -4274,7 +4211,7 @@ dependencies = [ "new_debug_unreachable", "num-bigint", "once_cell", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "siphasher", "sourcemap", @@ -4289,15 +4226,14 @@ dependencies = [ [[package]] name = "swc_config" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb63364aebd1a8490a80fa8933825c6916d4df55d5472312d5adb62c9fb4e4ba" +checksum = "a01bfcbbdea182bdda93713aeecd997749ae324686bf7944f54d128e56be4ea9" dependencies = [ "anyhow", "indexmap 2.5.0", "serde", "serde_json", - "swc_cached", "swc_config_macro", ] @@ -4315,16 +4251,16 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "8.1.2" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4062a54522a9c02d2b68cc09282774b87121cd48693b0e67ae8c18b31b709866" +checksum = "0613d84468a6bb6d45d13c5a3368b37bd21f3067a089f69adac630dcb462a018" dependencies = [ "bitflags 2.6.0", "is-macro", "num-bigint", "once_cell", "phf", - "rustc-hash 2.1.1", + "rustc-hash", "scoped-tls", "serde", "string_enum", @@ -4336,9 +4272,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "10.0.0" +version = "11.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85453d346d0642f296c2b3aa204886a6ae2b9652262c3468d6f4556c1ed020d" +checksum = "b01b3de365a86b8f982cc162f257c82f84bda31d61084174a3be37e8ab15c0f4" dependencies = [ "ascii", "compact_str", @@ -4346,7 +4282,7 @@ dependencies = [ "num-bigint", "once_cell", "regex", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "sourcemap", "swc_allocator", @@ -4369,15 +4305,40 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "swc_ecma_lexer" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d11c8e71901401b9aae2ece4946eeb7674b14b8301a53768afbbeeb0e48b599" +dependencies = [ + "arrayvec", + "bitflags 2.6.0", + "either", + "new_debug_unreachable", + "num-bigint", + "num-traits", + "phf", + "rustc-hash", + "serde", + "smallvec", + "smartstring", + "stacker", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "tracing", + "typed-arena", +] + [[package]] name = "swc_ecma_loader" -version = "8.0.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a801462c997b71e4add7684ce4953c7d6200c75b5552b8d594783da84ad9564c" +checksum = "8eb574d660c05f3483c984107452b386e45b95531bdb1253794077edc986f413" dependencies = [ "anyhow", "pathdiff", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "swc_atoms", "swc_common", @@ -4386,9 +4347,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "11.1.2" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa942372098c7c0e7fd8c584a577378d2f659c934429b8252c4e26fae31d7ea7" +checksum = "250786944fbc05f6484eda9213df129ccfe17226ae9ad51b62fce2f72135dbee" dependencies = [ "arrayvec", "bitflags 2.6.0", @@ -4397,7 +4358,7 @@ dependencies = [ "num-bigint", "num-traits", "phf", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "smallvec", "smartstring", @@ -4405,15 +4366,16 @@ dependencies = [ "swc_atoms", "swc_common", "swc_ecma_ast", + "swc_ecma_lexer", "tracing", "typed-arena", ] [[package]] name = "swc_ecma_transforms_base" -version = "12.2.0" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46e3a36213d78fb4233e596b8a5c81c6cdafe02d03d780eed006c983aa0a724" +checksum = "6856da3da598f4da001b7e4ce225ee8970bc9d5cbaafcaf580190cf0a6031ec5" dependencies = [ "better_scoped_tls", "bitflags 2.6.0", @@ -4421,7 +4383,7 @@ dependencies = [ "once_cell", "par-core", "phf", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "smallvec", "swc_atoms", @@ -4435,9 +4397,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "12.0.0" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d871bbd46d14d032a48c14096abd778a8a87831638343f28b581c3025daa7086" +checksum = "0f84248f82bad599d250bbcd52cb4db6ff6409f48267fd6f001302a2e9716f80" dependencies = [ "swc_atoms", "swc_common", @@ -4461,12 +4423,12 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "12.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5265158f5134b7b37dd2d53e7730921b8b5f567f6baddcc52129c2eb55927214" +checksum = "193237e318421ef621c2b3958b4db174770c5280ef999f1878f2df93a2837ca6" dependencies = [ "either", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "smallvec", "swc_atoms", @@ -4481,15 +4443,15 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "13.0.1" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e7635afe1e1e798d61ff3107b8d27e437e61f243dd226a47fb10724693be66" +checksum = "baae39c70229103a72090119887922fc5e32f934f5ca45c0423a5e65dac7e549" dependencies = [ "base64 0.22.1", "dashmap", "indexmap 2.5.0", "once_cell", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "sha1", "string_enum", @@ -4507,12 +4469,12 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "13.0.0" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec3c91a2c37372746ebc5608e30b7c2c3af60216768b59ec6413ee2bfe44c29" +checksum = "a3c65e0b49f7e2a2bd92f1d89c9a404de27232ce00f6a4053f04bda446d50e5c" dependencies = [ "once_cell", - "rustc-hash 2.1.1", + "rustc-hash", "ryu-js", "serde", "swc_atoms", @@ -4526,16 +4488,16 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "12.0.0" +version = "13.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d6c8ba7d987dcc254f05ad2c23e7a6ec3f259611af2923a8c1a0602556cd21" +checksum = "7ed837406d5dbbfbf5792b1dc90964245a0cf659753d4745fe177ffebe8598b9" dependencies = [ "indexmap 2.5.0", "num_cpus", "once_cell", "par-core", "par-iter", - "rustc-hash 2.1.1", + "rustc-hash", "ryu-js", "swc_atoms", "swc_common", @@ -4547,9 +4509,9 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "8.0.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7a65fa06d0c0f709f1df4e820ccdc4eca7b3db7f9d131545e20c2ac2f1cd23" +checksum = "249dc9eede1a4ad59a038f9cfd61ce67845bd2c1392ade3586d714e7181f3c1a" dependencies = [ "new_debug_unreachable", "num-bigint", @@ -5503,6 +5465,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "want" version = "0.3.1" diff --git a/api/Cargo.toml b/api/Cargo.toml index d567d68e3..a32095cab 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -78,9 +78,9 @@ deno_semver = "0.7.1" flate2 = "1" thiserror = "2" async-tar = "0.4.2" -deno_graph = "0.89.4" -deno_ast = { version = "0.46.5", features = ["view"] } -deno_doc = { version = "0.171.1", features = ["comrak"] } +deno_graph = "0.91.0" +deno_ast = { version = "0.47.0", features = ["view"] } +deno_doc = { version = "0.174.0", features = ["comrak"] } deno_error = "0.5.5" comrak = { version = "0.29.0", default-features = false } ammonia = "4.0.0" @@ -117,3 +117,6 @@ lazy_static = "1.5.0" flate2 = "1" deno_semver = "0.7.1" 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 37af87598..55e7a884a 100644 --- a/api/src/analysis.rs +++ b/api/src/analysis.rs @@ -13,6 +13,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_doc::DocNodeDef; use deno_error::JsErrorBox; use deno_graph::source::load_data_url; @@ -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, @@ -174,7 +175,6 @@ async fn analyze_package_inner( jsr_url_provider: &PassthroughJsrUrlProvider, es_parser: Some(&module_analyzer.analyzer), resolver: Default::default(), - npm_resolver: Default::default(), workspace_fast_check: WorkspaceFastCheckOption::Enabled(&workspace_members), }); @@ -252,8 +252,8 @@ async fn analyze_package_inner( doc_nodes, main_entrypoint, info.rewrite_map, - scope, - name, + scope.clone(), + name.clone(), version, true, None, @@ -266,20 +266,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, @@ -602,7 +623,6 @@ async fn rebuild_npm_tarball_inner( jsr_url_provider: &PassthroughJsrUrlProvider, es_parser: Some(&module_analyzer.analyzer), resolver: None, - npm_resolver: None, workspace_fast_check: WorkspaceFastCheckOption::Enabled(&workspace_members), }); diff --git a/api/src/api/package.rs b/api/src/api/package.rs index cd5e8c962..94d44f18f 100644 --- a/api/src/api/package.rs +++ b/api/src/api/package.rs @@ -34,7 +34,6 @@ use routerify_query::RequestQueryExt; use serde::Deserialize; use serde::Serialize; use sha2::Digest; -use std::borrow::Cow; use std::io; use std::sync::atomic::AtomicU64; use std::sync::atomic::Ordering; @@ -847,12 +846,12 @@ pub async fn version_publish_handler( hash_.lock().unwrap().as_mut().unwrap().update(&bytes); total_size_.fetch_add(bytes.len() as u64, Ordering::SeqCst); if total_size_.load(Ordering::SeqCst) > MAX_PUBLISH_TARBALL_SIZE { - Err(io::Error::new(io::ErrorKind::Other, "Payload too large")) + Err(io::Error::other("Payload too large")) } else { Ok(bytes) } } - Err(err) => Err(io::Error::new(io::ErrorKind::Other, err)), + Err(err) => Err(io::Error::other(err)), }); let upload_result = buckets @@ -1262,6 +1261,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); @@ -1271,9 +1272,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, @@ -1349,9 +1347,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) } @@ -1422,6 +1421,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); @@ -1590,9 +1591,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, }) } @@ -1949,6 +1947,7 @@ lazy_static::lazy_static! { // We have to spawn another tokio runtime, because // `deno_graph::ModuleGraph::build` is not thread-safe. +#[allow(clippy::result_large_err)] #[tokio::main(flavor = "current_thread")] async fn analyze_deps_tree( registry_url: Url, @@ -3528,15 +3527,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) } @@ -3554,15 +3549,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"), "{:?}", @@ -3584,15 +3575,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"), "{:?}", @@ -3617,15 +3604,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"), "{:?}", @@ -3646,7 +3629,7 @@ ggHohNAjhbzDaY2iBW/m3NC5dehGUP4T2GBo/cwGhg== let search: serde_json::Value = resp.expect_ok().await; assert_eq!( search, - json!({"kind":"search","nodes":[{"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},{"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 9ecba9c22..61576924c 100644 --- a/api/src/api/scope.rs +++ b/api/src/api/scope.rs @@ -1,18 +1,19 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. -use std::borrow::Cow; -use std::sync::OnceLock; - 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; use hyper::StatusCode; use routerify::ext::RequestExt; use routerify::Router; +use std::borrow::Cow; +use std::sync::OnceLock; +use tracing::error; use tracing::field; use tracing::instrument; use tracing::Span; @@ -23,10 +24,15 @@ use super::types::*; 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::decode_json; use crate::util::ApiResult; +use crate::util::CacheDuration; use crate::util::RequestIdExt; pub fn scope_router() -> Router { @@ -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() } @@ -490,6 +503,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 aa38639fb..46eb94434 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; @@ -625,9 +623,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, @@ -681,9 +676,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 ed7e04ad1..704eb9824 100644 --- a/api/src/docs.rs +++ b/api/src/docs.rs @@ -435,6 +435,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}"); @@ -510,6 +511,7 @@ pub fn get_generate_ctx<'a>( markdown_renderer, markdown_stripper: Rc::new(deno_doc::html::comrak::strip), head_inject: None, + id_prefix, }, None, deno_doc::html::FileMode::Normal, @@ -538,6 +540,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, @@ -551,6 +555,7 @@ pub fn generate_docs_html( readme.is_some(), runtime_compat, registry_url, + id_prefix, ); match req { @@ -571,10 +576,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, ) }), @@ -587,7 +606,7 @@ pub fn generate_docs_html( .render( "symbol_content", &deno_doc::html::SymbolContentCtx { - id: String::new(), + id: deno_doc::html::util::Id::empty(), sections, docs: None, }, diff --git a/api/src/npm/specifiers.rs b/api/src/npm/specifiers.rs index a160d8e1d..2b75df417 100644 --- a/api/src/npm/specifiers.rs +++ b/api/src/npm/specifiers.rs @@ -91,7 +91,10 @@ pub fn relative_import_specifier( ) -> String { let relative = base_specifier.make_relative(specifier).unwrap(); if relative.is_empty() { - format!("./{}", specifier.path_segments().unwrap().last().unwrap()) + format!( + "./{}", + specifier.path_segments().unwrap().next_back().unwrap() + ) } else if relative.starts_with("../") { relative.to_string() } else { diff --git a/api/src/npm/tarball.rs b/api/src/npm/tarball.rs index 6523dbe1b..9e30814ac 100644 --- a/api/src/npm/tarball.rs +++ b/api/src/npm/tarball.rs @@ -731,7 +731,6 @@ mod tests { jsr_url_provider: &PassthroughJsrUrlProvider, es_parser: Some(&module_analyzer.analyzer), resolver: None, - npm_resolver: None, workspace_fast_check: WorkspaceFastCheckOption::Enabled( &workspace_members, ), diff --git a/api/src/orama.rs b/api/src/orama.rs index 99b521e48..055f49e00 100644 --- a/api/src/orama.rs +++ b/api/src/orama.rs @@ -1,14 +1,14 @@ // 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 deno_doc::html::search::SearchIndexNode; +use std::sync::Arc; use tracing::error; use tracing::instrument; use tracing::Instrument; @@ -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 3ccd835c9..634d14163 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 260ca3bc3..cc1e9484f 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 { @@ -97,7 +98,7 @@ pub async fn process_tarball( .await .map_err(PublishError::GcsDownloadError)? .ok_or(PublishError::MissingTarball)? - .map_err(|e| io::Error::new(io::ErrorKind::Other, e)); + .map_err(io::Error::other); let async_read = stream.into_async_read(); let mut tar = async_tar::Archive::new(async_read) @@ -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 ( -