Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

Fix links for external dependencies

+276 -25
+51 -4
compiler-cli/src/docs.rs
··· 1 - use std::time::{Instant, SystemTime}; 1 + use std::{ 2 + collections::HashMap, 3 + time::{Instant, SystemTime}, 4 + }; 2 5 3 6 use camino::{Utf8Path, Utf8PathBuf}; 4 7 use ecow::EcoString; ··· 9 12 analyse::TargetSupport, 10 13 build::{Codegen, Compile, Mode, Options, Package, Target}, 11 14 config::{DocsPage, PackageConfig}, 12 - docs::DocContext, 15 + docs::{Dependency, DependencyKind, DocContext}, 13 16 error::Error, 14 17 hex, 15 18 io::HttpClient as _, 19 + manifest::ManifestPackageSource, 16 20 paths::ProjectPaths, 17 21 type_, 18 22 }; ··· 49 53 crate::fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, config.target))?; 50 54 51 55 let out = paths.build_documentation_directory(&config.name); 56 + 57 + let manifest = crate::build::download_dependencies(paths, cli::Reporter::new())?; 58 + let dependencies = manifest 59 + .packages 60 + .iter() 61 + .map(|package| { 62 + ( 63 + package.name.clone(), 64 + Dependency { 65 + version: package.version.clone(), 66 + kind: match &package.source { 67 + ManifestPackageSource::Hex { .. } => DependencyKind::Hex, 68 + ManifestPackageSource::Git { .. } => DependencyKind::Git, 69 + ManifestPackageSource::Local { .. } => DependencyKind::Path, 70 + }, 71 + }, 72 + ) 73 + }) 74 + .collect(); 75 + 52 76 let mut built = crate::build::main( 53 77 paths, 54 78 Options { ··· 60 84 root_target_support: TargetSupport::Enforced, 61 85 no_print_progress: false, 62 86 }, 63 - crate::build::download_dependencies(paths, cli::Reporter::new())?, 87 + manifest, 64 88 )?; 65 89 let outputs = build_documentation( 66 90 paths, 67 91 &config, 92 + dependencies, 68 93 &mut built.root_package, 69 94 DocContext::Build, 70 95 &built.module_interfaces, ··· 106 131 pub(crate) fn build_documentation( 107 132 paths: &ProjectPaths, 108 133 config: &PackageConfig, 134 + dependencies: HashMap<EcoString, Dependency>, 109 135 compiled: &mut Package, 110 136 is_hex_publish: DocContext, 111 137 cached_modules: &im::HashMap<EcoString, type_::ModuleInterface>, ··· 121 147 let mut outputs = gleam_core::docs::generate_html( 122 148 paths, 123 149 config, 150 + dependencies, 124 151 compiled.modules.as_slice(), 125 152 &pages, 126 153 ProjectIO::new(), ··· 147 174 // Reset the build directory so we know the state of the project 148 175 crate::fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, config.target))?; 149 176 177 + let manifest = crate::build::download_dependencies(paths, cli::Reporter::new())?; 178 + let dependencies = manifest 179 + .packages 180 + .iter() 181 + .map(|package| { 182 + ( 183 + package.name.clone(), 184 + Dependency { 185 + version: package.version.clone(), 186 + kind: match &package.source { 187 + ManifestPackageSource::Hex { .. } => DependencyKind::Hex, 188 + ManifestPackageSource::Git { .. } => DependencyKind::Git, 189 + ManifestPackageSource::Local { .. } => DependencyKind::Path, 190 + }, 191 + }, 192 + ) 193 + }) 194 + .collect(); 195 + 150 196 let mut built = crate::build::main( 151 197 paths, 152 198 Options { ··· 158 204 target: None, 159 205 no_print_progress: false, 160 206 }, 161 - crate::build::download_dependencies(paths, cli::Reporter::new())?, 207 + manifest, 162 208 )?; 163 209 let outputs = build_documentation( 164 210 paths, 165 211 &config, 212 + dependencies, 166 213 &mut built.root_package, 167 214 DocContext::HexPublish, 168 215 &built.module_interfaces,
+27 -3
compiler-cli/src/publish.rs
··· 6 6 analyse::TargetSupport, 7 7 build::{Codegen, Compile, Mode, Options, Package, Target}, 8 8 config::{GleamVersion, PackageConfig, SpdxLicense}, 9 - docs::DocContext, 9 + docs::{Dependency, DependencyKind, DocContext}, 10 10 error::{SmallVersion, wrap}, 11 11 hex, 12 + manifest::ManifestPackageSource, 12 13 paths::{self, ProjectPaths}, 13 14 requirement::Requirement, 14 15 type_, ··· 16 17 use hexpm::version::{Range, Version}; 17 18 use itertools::Itertools; 18 19 use sha2::Digest; 19 - use std::{io::Write, path::PathBuf, time::Instant}; 20 + use std::{collections::HashMap, io::Write, path::PathBuf, time::Instant}; 20 21 21 22 use crate::{build, cli, docs, fs, http::HttpClient}; 22 23 ··· 38 39 data: package_tarball, 39 40 src_files_added, 40 41 generated_files_added, 42 + dependencies, 41 43 } = do_build_hex_tarball(paths, &mut config)?; 42 44 43 45 check_for_name_squatting(&compile_result)?; ··· 47 49 let docs_tarball = fs::create_tar_archive(docs::build_documentation( 48 50 paths, 49 51 &config, 52 + dependencies, 50 53 &mut compile_result, 51 54 DocContext::HexPublish, 52 55 &cached_modules, ··· 271 274 data: Vec<u8>, 272 275 src_files_added: Vec<Utf8PathBuf>, 273 276 generated_files_added: Vec<(Utf8PathBuf, String)>, 277 + dependencies: HashMap<EcoString, Dependency>, 274 278 } 275 279 276 280 pub fn build_hex_tarball(paths: &ProjectPaths, config: &mut PackageConfig) -> Result<Vec<u8>> { ··· 285 289 // Reset the build directory so we know the state of the project 286 290 fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, target))?; 287 291 292 + let manifest = build::download_dependencies(paths, cli::Reporter::new())?; 293 + let dependencies = manifest 294 + .packages 295 + .iter() 296 + .map(|package| { 297 + ( 298 + package.name.clone(), 299 + Dependency { 300 + version: package.version.clone(), 301 + kind: match &package.source { 302 + ManifestPackageSource::Hex { .. } => DependencyKind::Hex, 303 + ManifestPackageSource::Git { .. } => DependencyKind::Git, 304 + ManifestPackageSource::Local { .. } => DependencyKind::Path, 305 + }, 306 + }, 307 + ) 308 + }) 309 + .collect(); 310 + 288 311 // Build the project to check that it is valid 289 312 let built = build::main( 290 313 paths, ··· 297 320 compile: Compile::All, 298 321 no_print_progress: false, 299 322 }, 300 - build::download_dependencies(paths, cli::Reporter::new())?, 323 + manifest, 301 324 )?; 302 325 303 326 let minimum_required_version = built.minimum_required_version(); ··· 399 422 data: tarball, 400 423 src_files_added: src_files, 401 424 generated_files_added: generated_files, 425 + dependencies, 402 426 }) 403 427 } 404 428
+19 -1
compiler-core/src/docs.rs
··· 3 3 #[cfg(test)] 4 4 mod tests; 5 5 6 - use std::time::SystemTime; 6 + use std::{collections::HashMap, time::SystemTime}; 7 7 8 8 use camino::Utf8PathBuf; 9 + use hexpm::version::Version; 9 10 use printer::Printer; 10 11 11 12 use crate::{ ··· 36 37 package_config: PackageConfig, 37 38 } 38 39 40 + /// Like `ManifestPackage`, but lighter and cheaper to clone as it is all that 41 + /// we need for printing documentation. 42 + #[derive(Debug, Clone)] 43 + pub struct Dependency { 44 + pub version: Version, 45 + pub kind: DependencyKind, 46 + } 47 + 48 + #[derive(Debug, Clone, Copy)] 49 + pub enum DependencyKind { 50 + Hex, 51 + Path, 52 + Git, 53 + } 54 + 39 55 pub fn generate_html<IO: FileSystemReader>( 40 56 paths: &ProjectPaths, 41 57 config: &PackageConfig, 58 + dependencies: HashMap<EcoString, Dependency>, 42 59 analysed: &[Module], 43 60 docs_pages: &[DocsPage], 44 61 fs: IO, ··· 174 191 module.ast.type_info.package.clone(), 175 192 module.name.clone(), 176 193 &module.ast.names, 194 + &dependencies, 177 195 ); 178 196 179 197 let types: Vec<TypeDefinition<'_>> = module
+35 -8
compiler-core/src/docs/printer.rs
··· 20 20 }; 21 21 22 22 use super::{ 23 - DocsValues, TypeConstructor, TypeConstructorArg, TypeDefinition, markdown_documentation, 24 - source_links::SourceLinker, text_documentation, 23 + Dependency, DependencyKind, DocsValues, TypeConstructor, TypeConstructorArg, TypeDefinition, 24 + markdown_documentation, source_links::SourceLinker, text_documentation, 25 25 }; 26 26 27 27 #[derive(Clone, Copy)] ··· 55 55 /// An incrementing number used to generate the next type variable name. 56 56 /// `0` becomes `a`, `1` becomes `b`, etc. 57 57 next_type_variable_id: u64, 58 + 59 + dependencies: &'a HashMap<EcoString, Dependency>, 58 60 } 59 61 60 62 impl Printer<'_> { 61 - pub fn new(package: EcoString, module: EcoString, names: &Names) -> Printer<'_> { 63 + pub fn new<'a>( 64 + package: EcoString, 65 + module: EcoString, 66 + names: &'a Names, 67 + dependencies: &'a HashMap<EcoString, Dependency>, 68 + ) -> Printer<'a> { 62 69 Printer { 63 70 options: PrintOptions::all(), 64 71 names, ··· 67 74 printed_type_variables: HashMap::new(), 68 75 printed_type_variable_names: HashSet::new(), 69 76 next_type_variable_id: 0, 77 + dependencies, 70 78 } 71 79 } 72 80 ··· 521 529 ]; 522 530 let title = eco_format!("{module}.{{type {name}}}"); 523 531 524 - self.link( 525 - eco_format!("https://hexdocs.pm/{package}/{module}.html#{name}"), 526 - qualified_name, 527 - Some(title), 528 - ) 532 + // We can't reliably link to documentation if the type is from a path 533 + // or git dependency 534 + match self.dependencies.get(package) { 535 + Some(Dependency { 536 + kind: DependencyKind::Hex, 537 + version, 538 + }) => self.link( 539 + eco_format!("https://hexdocs.pm/{package}/{version}/{module}.html#{name}"), 540 + qualified_name, 541 + Some(title), 542 + ), 543 + Some(_) | None => self.span_with_title(qualified_name, title), 544 + } 529 545 } 530 546 } 531 547 ··· 624 640 name.to_doc().surround( 625 641 zero_width_string(opening_tag), 626 642 zero_width_string("</a>".into()), 643 + ) 644 + } 645 + 646 + fn span_with_title<'a>(&self, name: impl Documentable<'a>, title: EcoString) -> Document<'a> { 647 + if !self.options.print_links { 648 + return name.to_doc(); 649 + } 650 + 651 + name.to_doc().surround( 652 + zero_width_string(eco_format!(r#"<span title="{title}">"#)), 653 + zero_width_string("</span>".into()), 627 654 ) 628 655 } 629 656 }
+105 -8
compiler-core/src/docs/tests.rs
··· 1 - use std::{collections::HashSet, time::SystemTime}; 1 + use std::{ 2 + collections::{HashMap, HashSet}, 3 + time::SystemTime, 4 + }; 2 5 3 6 use super::{ 4 - SearchData, SearchItem, SearchItemType, SearchProgrammingLanguage, 7 + Dependency, DependencyKind, SearchData, SearchItem, SearchItemType, SearchProgrammingLanguage, 5 8 printer::{PrintOptions, Printer}, 6 9 source_links::SourceLinker, 7 10 }; ··· 21 24 }; 22 25 use camino::Utf8PathBuf; 23 26 use ecow::EcoString; 27 + use hexpm::version::Version; 24 28 use itertools::Itertools; 25 29 use serde_json::to_string as serde_to_string; 26 30 ··· 96 100 super::generate_html( 97 101 &paths, 98 102 &config, 103 + HashMap::new(), 99 104 &modules, 100 105 &docs_pages, 101 106 pages_fs, ··· 136 141 module_name: &str, 137 142 module_src: &str, 138 143 modules: Vec<(&str, &str, &str)>, 144 + dependency_kind: DependencyKind, 139 145 options: PrintOptions, 140 146 ) -> EcoString { 141 147 let module = type_::tests::compile_module(module_name, module_src, None, modules.clone()) ··· 158 164 let source_links = SourceLinker::new(&paths, &config, &build_module); 159 165 160 166 let module = build_module.ast; 167 + let dependencies = modules 168 + .iter() 169 + .map(|(package, _, _)| { 170 + ( 171 + EcoString::from(*package), 172 + Dependency { 173 + version: Version::new(1, 0, 0), 174 + kind: dependency_kind, 175 + }, 176 + ) 177 + }) 178 + .collect(); 161 179 162 180 let mut printer = Printer::new( 163 181 module.type_info.package.clone(), 164 182 module.name.clone(), 165 183 &module.names, 184 + &dependencies, 166 185 ); 167 186 printer.set_options(options); 168 187 ··· 251 270 }; 252 271 253 272 ($src:literal, $options:expr $(,)?) => { 254 - let output = compile_documentation("main", $src, Vec::new(), $options); 273 + let output = compile_documentation("main", $src, Vec::new(), DependencyKind::Hex, $options); 255 274 insta::assert_snapshot!(output); 256 275 }; 257 276 258 277 ($(($name:expr, $module_src:literal)),+, $src:literal $(,)?) => { 259 - let output = compile_documentation("main", $src, vec![$(("thepackage", $name, $module_src)),*], PrintOptions::all()); 278 + let output = compile_documentation( 279 + "main", 280 + $src, 281 + vec![$(("thepackage", $name, $module_src)),*], 282 + DependencyKind::Hex, 283 + PrintOptions::all(), 284 + ); 260 285 insta::assert_snapshot!(output); 261 286 }; 262 287 263 288 ($(($name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => { 264 - let output = compile_documentation("main", $src, vec![$(("thepackage", $name, $module_src)),*], $options); 289 + let output = compile_documentation( 290 + "main", 291 + $src, 292 + vec![$(("thepackage", $name, $module_src)),*], 293 + DependencyKind::Hex, 294 + $options, 295 + ); 265 296 insta::assert_snapshot!(output); 266 297 }; 267 298 268 299 ($(($name:expr, $module_src:literal)),+, $main_module:literal, $src:literal, $options:expr $(,)?) => { 269 - let output = compile_documentation($main_module, $src, vec![$(("thepackage", $name, $module_src)),*], $options); 300 + let output = compile_documentation( 301 + $main_module, 302 + $src, 303 + vec![$(("thepackage", $name, $module_src)),*], 304 + DependencyKind::Hex, 305 + $options, 306 + ); 270 307 insta::assert_snapshot!(output); 271 308 }; 272 309 273 310 ($(($package:expr, $name:expr, $module_src:literal)),+, $src:literal $(,)?) => { 274 - let output = compile_documentation("main", $src, vec![$(($package, $name, $module_src)),*], PrintOptions::all()); 311 + let output = compile_documentation( 312 + "main", 313 + $src, 314 + vec![$(($package, $name, $module_src)),*], 315 + DependencyKind::Hex, 316 + PrintOptions::all(), 317 + ); 275 318 insta::assert_snapshot!(output); 276 319 }; 277 320 278 321 ($(($package:expr, $name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => { 279 - let output = compile_documentation("main", $src, vec![$(($package, $name, $module_src)),*], $options); 322 + let output = compile_documentation( 323 + "main", 324 + $src, 325 + vec![$(($package, $name, $module_src)),*], 326 + DependencyKind::Hex, 327 + $options, 328 + ); 329 + insta::assert_snapshot!(output); 330 + }; 331 + 332 + (git: $(($package:expr, $name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => { 333 + let output = compile_documentation( 334 + "main", 335 + $src, 336 + vec![$(($package, $name, $module_src)),*], 337 + DependencyKind::Git, 338 + $options, 339 + ); 340 + insta::assert_snapshot!(output); 341 + }; 342 + 343 + (path: $(($package:expr, $name:expr, $module_src:literal)),+, $src:literal, $options:expr $(,)?) => { 344 + let output = compile_documentation( 345 + "main", 346 + $src, 347 + vec![$(($package, $name, $module_src)),*], 348 + DependencyKind::Path, 349 + $options, 350 + ); 280 351 insta::assert_snapshot!(output); 281 352 }; 282 353 } ··· 882 953 fn link_to_type_in_different_package() { 883 954 assert_documentation!( 884 955 ("gleam_stdlib", "gleam/dict", "pub type Dict(a, b)"), 956 + " 957 + import gleam/dict 958 + 959 + pub fn make_dict() -> dict.Dict(a, b) { todo } 960 + ", 961 + ONLY_LINKS 962 + ); 963 + } 964 + 965 + #[test] 966 + fn no_link_to_type_in_git_dependency() { 967 + assert_documentation!( 968 + git: ("gleam_stdlib", "gleam/dict", "pub type Dict(a, b)"), 969 + " 970 + import gleam/dict 971 + 972 + pub fn make_dict() -> dict.Dict(a, b) { todo } 973 + ", 974 + ONLY_LINKS 975 + ); 976 + } 977 + 978 + #[test] 979 + fn no_link_to_type_in_path_dependency() { 980 + assert_documentation!( 981 + path: ("gleam_stdlib", "gleam/dict", "pub type Dict(a, b)"), 885 982 " 886 983 import gleam/dict 887 984