diff --git a/compiler-cli/src/publish.rs b/compiler-cli/src/publish.rs index 159454d47fc..6bba30955f5 100644 --- a/compiler-cli/src/publish.rs +++ b/compiler-cli/src/publish.rs @@ -4,7 +4,7 @@ use flate2::{Compression, write::GzEncoder}; use gleam_core::{ Error, Result, analyse::TargetSupport, - build::{Codegen, Compile, Mode, Options, Package, Target}, + build::{Codegen, Compile, Mode, Options, Origin, Package, Target}, config::{GleamVersion, PackageConfig, SpdxLicense}, docs::DocContext, error::{SmallVersion, wrap}, @@ -338,8 +338,21 @@ fn do_build_hex_tarball(paths: &ProjectPaths, config: &mut PackageConfig) -> Res // refuse to publish as the package is not yet finished. let mut modules_containing_todo = vec![]; let mut modules_containing_echo = vec![]; + let dev_dependencies: Vec<&EcoString> = config.dev_dependencies.keys().collect(); for module in built.root_package.modules.iter() { + for (imported_module, _) in &module.dependencies { + if let Some(import_info) = built.module_interfaces.get(imported_module) { + let package = &import_info.package; + if dev_dependencies.contains(&package) && module.origin == Origin::Src { + return Err(Error::CannotPublishLeakedDevDependency { + module: module.name.clone(), + package: package.clone(), + }); + } + } + } + if module.ast.type_info.contains_todo() { modules_containing_todo.push(module.name.clone()); } else if module.ast.type_info.contains_echo { diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index fd0d67019af..b08e2a69356 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -298,6 +298,12 @@ file_names.iter().map(|x| x.as_str()).join(", "))] )] CannotPublishLeakedInternalType { unfinished: Vec }, + #[error("The module imports a dev dependency")] + CannotPublishLeakedDevDependency { + module: EcoString, + package: EcoString, + }, + #[error("Publishing packages to reserve names is not permitted")] HexPackageSquatting, @@ -1083,6 +1089,17 @@ Please make sure internal types do not appear in public functions and try again. location: None, }], + Error::CannotPublishLeakedDevDependency { module, package } => { + let text = &format!("The module `{module}` is being imported from `{package}`, but package is not a direct dependency of your project.\nRun this command to add it to your dependencies:\n\tgleam add {package}"); + vec![Diagnostic { + title: "Development dependency imported".into(), + text: text.to_string(), + hint: None, + level: Level::Error, + location: None + }] + } + Error::UnableToFindProjectRoot { path } => { let text = wrap_format!( "We were unable to find gleam.toml.