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

Configure Feed

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

1use std::time::SystemTime; 2 3use camino::Utf8PathBuf; 4use ecow::EcoString; 5use globset::GlobBuilder; 6use hexpm::version::Identifier; 7 8use crate::{ 9 analyse::TargetSupport, 10 build::{Module, Origin, Package, Target}, 11 config::{Docs, ErlangConfig, JavaScriptConfig, PackageConfig, Repository}, 12 line_numbers::LineNumbers, 13 type_::PRELUDE_MODULE_NAME, 14 uid::UniqueIdGenerator, 15 warning::{TypeWarningEmitter, WarningEmitter}, 16}; 17 18use super::PackageInterface; 19 20#[macro_export] 21macro_rules! assert_package_interface_with_name { 22 ($module_name:expr, $src:expr) => { 23 let output = 24 $crate::package_interface::tests::compile_package(Some($module_name), $src, None); 25 insta::assert_snapshot!(insta::internals::AutoName, output, $src); 26 }; 27} 28 29#[macro_export] 30macro_rules! assert_package_interface { 31 (($dep_package:expr, $dep_name:expr, $dep_src:expr), $src:expr $(,)?) => {{ 32 let output = $crate::package_interface::tests::compile_package( 33 None, 34 $src, 35 Some(($dep_package, $dep_name, $dep_src)), 36 ); 37 insta::assert_snapshot!(insta::internals::AutoName, output, $src); 38 }}; 39 40 (($dep_package:expr, $dep_name:expr, $dep_src:expr), $src:expr $(,)?) => {{ 41 let output = $crate::package_interface::tests::compile_package( 42 None, 43 $src, 44 Some(($dep_package, $dep_name, $dep_src)), 45 ); 46 insta::assert_snapshot!(insta::internals::AutoName, output, $src); 47 }}; 48 49 ($src:expr) => {{ 50 let output = $crate::package_interface::tests::compile_package(None, $src, None); 51 insta::assert_snapshot!(insta::internals::AutoName, output, $src); 52 }}; 53} 54 55pub fn compile_package( 56 module_name: Option<&str>, 57 src: &str, 58 dep: Option<(&str, &str, &str)>, 59) -> String { 60 let mut modules = im::HashMap::new(); 61 let ids = UniqueIdGenerator::new(); 62 // DUPE: preludeinsertion 63 // TODO: Currently we do this here and also in the tests. It would be better 64 // to have one place where we create all this required state for use in each 65 // place. 66 let _ = modules.insert( 67 PRELUDE_MODULE_NAME.into(), 68 crate::type_::build_prelude(&ids), 69 ); 70 let mut direct_dependencies = std::collections::HashMap::from_iter(vec![]); 71 if let Some((dep_package, dep_name, dep_src)) = dep { 72 let parsed = crate::parse::parse_module( 73 Utf8PathBuf::from("test/path"), 74 dep_src, 75 &WarningEmitter::null(), 76 ) 77 .expect("dep syntax error"); 78 let mut ast = parsed.module; 79 ast.name = dep_name.into(); 80 let line_numbers = LineNumbers::new(dep_src); 81 let mut config = PackageConfig::default(); 82 config.name = dep_package.into(); 83 84 let dep = crate::analyse::ModuleAnalyzerConstructor::<()> { 85 target: Target::Erlang, 86 ids: &ids, 87 origin: Origin::Src, 88 importable_modules: &modules, 89 warnings: &TypeWarningEmitter::null(), 90 direct_dependencies: &std::collections::HashMap::new(), 91 target_support: TargetSupport::Enforced, 92 package_config: &config, 93 } 94 .infer_module(ast, line_numbers, "".into()) 95 .expect("should successfully infer"); 96 let _ = modules.insert(dep_name.into(), dep.type_info); 97 let _ = direct_dependencies.insert(dep_package.into(), ()); 98 } 99 let parsed = 100 crate::parse::parse_module(Utf8PathBuf::from("test/path"), src, &WarningEmitter::null()) 101 .expect("syntax error"); 102 103 let mut ast = parsed.module; 104 let module_name = module_name 105 .map(EcoString::from) 106 .unwrap_or("my/module".into()); 107 108 ast.name = module_name.clone(); 109 let mut config = PackageConfig::default(); 110 config.name = "my_package".into(); 111 let ast = crate::analyse::ModuleAnalyzerConstructor { 112 target: Target::Erlang, 113 ids: &ids, 114 origin: Origin::Src, 115 importable_modules: &modules, 116 warnings: &TypeWarningEmitter::null(), 117 direct_dependencies: &direct_dependencies, 118 target_support: TargetSupport::Enforced, 119 package_config: &config, 120 } 121 .infer_module(ast, LineNumbers::new(src), "".into()) 122 .expect("should successfully infer"); 123 124 // TODO: all the bits above are basically copy pasted from the javascript 125 // and erlang test helpers. A refactor might be due here. 126 let mut module = Module { 127 name: module_name, 128 code: src.into(), 129 mtime: SystemTime::UNIX_EPOCH, 130 input_path: "wibble".into(), 131 origin: Origin::Src, 132 ast, 133 extra: parsed.extra, 134 dependencies: vec![], 135 }; 136 module.attach_doc_and_module_comments(); 137 let package: Package = package_from_module(module); 138 serde_json::to_string_pretty(&PackageInterface::from_package( 139 &package, 140 &Default::default(), 141 )) 142 .expect("to json") 143} 144 145fn package_from_module(module: Module) -> Package { 146 Package { 147 config: PackageConfig { 148 name: "my_package".into(), 149 version: hexpm::version::Version { 150 major: 11, 151 minor: 10, 152 patch: 9, 153 pre: vec![ 154 Identifier::Numeric(1), 155 Identifier::AlphaNumeric("wibble".into()), 156 ], 157 build: Some("build".into()), 158 }, 159 gleam_version: Some( 160 hexpm::version::Range::new("1.0.0".into()) 161 .to_pubgrub() 162 .unwrap(), 163 ), 164 licences: vec![], 165 description: "description".into(), 166 documentation: Docs { pages: vec![] }, 167 dependencies: std::collections::HashMap::new(), 168 dev_dependencies: std::collections::HashMap::new(), 169 repository: Repository::default(), 170 links: vec![], 171 erlang: ErlangConfig::default(), 172 javascript: JavaScriptConfig::default(), 173 target: Target::Erlang, 174 internal_modules: Some(vec![ 175 GlobBuilder::new("internals/*") 176 .build() 177 .expect("internals glob"), 178 ]), 179 }, 180 module_names: vec![module.name.clone()], 181 modules: vec![module], 182 } 183} 184 185#[test] 186pub fn package_documentation_is_included() { 187 assert_package_interface!( 188 " 189//// Some package 190//// documentation! 191 192pub fn main() { 1 } 193" 194 ); 195} 196 197#[test] 198pub fn private_definitions_are_not_included() { 199 assert_package_interface!( 200 " 201const float = 1.1 202fn main() {} 203type Wibble 204type Wob = Int 205" 206 ); 207} 208 209#[test] 210pub fn internal_definitions_are_not_included() { 211 assert_package_interface!( 212 " 213@internal pub const float = 1.1 214@internal pub fn main() {} 215@internal pub type Wibble 216@internal pub type Wobble = Int 217" 218 ); 219} 220 221#[test] 222pub fn opaque_constructors_are_not_exposed() { 223 assert_package_interface!("pub opaque type Wibble { Wob }") 224} 225 226#[test] 227pub fn type_aliases() { 228 assert_package_interface!("pub type Wibble(a) = List(a)") 229} 230 231#[test] 232pub fn type_definition() { 233 assert_package_interface!( 234 " 235/// Wibble's documentation 236pub type Wibble(a, b) { 237 Wibble 238 Wobble 239} 240" 241 ) 242} 243 244#[test] 245pub fn prelude_types() { 246 assert_package_interface!( 247 r#" 248pub const float = 1.1 249pub const string = "" 250pub const int = 1 251pub const bool = True 252"# 253 ); 254} 255 256#[test] 257pub fn generic_function() { 258 assert_package_interface!( 259 r#" 260pub type Wob(a) { Wob } 261@deprecated("deprecation message") 262pub fn main() { Wob } 263"# 264 ); 265} 266 267#[test] 268pub fn imported_type() { 269 assert_package_interface!( 270 ("other_package", "other_module", "pub type Element(a)"), 271 r#" 272import other_module.{type Element} 273pub fn main() -> Element(Int) {} 274"# 275 ); 276} 277 278#[test] 279pub fn imported_aliased_type_keeps_original_name() { 280 assert_package_interface!( 281 ("other_package", "other_module", "pub type Element(a)"), 282 r#" 283import other_module.{type Element as Alias} as module_alias 284pub fn main() -> Alias(module_alias.Element(a)) {} 285"# 286 ); 287} 288 289#[test] 290pub fn multiple_type_variables() { 291 assert_package_interface!( 292 r#" 293pub type Box(a, b) 294pub fn some_type_variables(a: a, b: b, c: Box(c, d)) -> Box(a, d) {} 295"# 296 ); 297} 298 299#[test] 300pub fn type_constructors() { 301 assert_package_interface!( 302 r#" 303pub type Box(a, b) { 304 Box(b, Int) 305 OtherBox(message: String, a: a) 306} 307"# 308 ); 309} 310 311#[test] 312pub fn internal_modules_are_not_exported() { 313 assert_package_interface_with_name!("internals/internal_module", "pub fn main() { 1 }"); 314}