Skip to content

Commit 55bb36e

Browse files
committed
v1.15.3
1 parent 0fc4a4c commit 55bb36e

14 files changed

Lines changed: 150 additions & 28 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212

1313
### Bug fixes
1414

15+
## v1.15.3 - 2026-04-11
16+
17+
### Bug fixes
18+
19+
- `gleam.toml` files with invalid dependency names now raise an error
20+
immediately when the file is parsed.
21+
([Louis Pilfold](https://github.com/lpil))
22+
1523
## v1.15.2 - 2026-03-19
1624

1725
### Bug fixes

Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler-cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gleam-cli"
3-
version = "1.15.2"
3+
version = "1.15.3"
44
authors = ["Louis Pilfold <louis@lpil.uk>"]
55
edition = "2024"
66
license = "Apache-2.0"

compiler-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gleam-core"
3-
version = "1.15.2"
3+
version = "1.15.3"
44
authors = ["Louis Pilfold <louis@lpil.uk>"]
55
edition = "2024"
66
license = "Apache-2.0"

compiler-core/src/config.rs

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,18 @@ pub struct PackageConfig {
163163
pub description: EcoString,
164164
#[serde(default, alias = "docs")]
165165
pub documentation: Docs,
166-
#[serde(default, serialize_with = "ordered_map")]
166+
#[serde(
167+
default,
168+
serialize_with = "ordered_map",
169+
deserialize_with = "dependencies_map::deserialize"
170+
)]
167171
pub dependencies: Dependencies,
168-
#[serde(default, alias = "dev-dependencies", serialize_with = "ordered_map")]
172+
#[serde(
173+
default,
174+
alias = "dev-dependencies",
175+
serialize_with = "ordered_map",
176+
deserialize_with = "dependencies_map::deserialize"
177+
)]
169178
pub dev_dependencies: Dependencies,
170179
#[serde(default)]
171180
pub repository: Option<Repository>,
@@ -362,6 +371,34 @@ aide_generator = { git = "git@github.com:crowdhailer/aide.git", ref = "f559c5bc"
362371
insta::assert_snapshot!(insta::internals::AutoName, error.pretty_string());
363372
}
364373

374+
#[test]
375+
fn invalid_dependency_name() {
376+
let toml = r#"
377+
name = "wibble"
378+
version = "1.0.0"
379+
380+
[dependencies]
381+
Hello = "> 1.0.0"
382+
"#;
383+
let error = deserialise_config("gleam.toml", toml.into())
384+
.expect_err("should fail to deserialise because invalid name");
385+
insta::assert_snapshot!(insta::internals::AutoName, error.pretty_string());
386+
}
387+
388+
#[test]
389+
fn invalid_dev_dependency_name() {
390+
let toml = r#"
391+
name = "wibble"
392+
version = "1.0.0"
393+
394+
[dev_dependencies]
395+
"yes." = "> 1.0.0"
396+
"#;
397+
let error = deserialise_config("gleam.toml", toml.into())
398+
.expect_err("should fail to deserialise because invalid name");
399+
insta::assert_snapshot!(insta::internals::AutoName, error.pretty_string());
400+
}
401+
365402
#[test]
366403
fn locked_no_manifest() {
367404
let mut config = PackageConfig::default();
@@ -1065,11 +1102,8 @@ mod uri_serde_default_https {
10651102

10661103
mod package_name {
10671104
use ecow::EcoString;
1068-
use regex::Regex;
10691105
use serde::Deserializer;
1070-
use std::{fmt, sync::OnceLock};
1071-
1072-
static PACKAGE_NAME_PATTERN: OnceLock<Regex> = OnceLock::new();
1106+
use std::fmt;
10731107

10741108
pub fn deserialize<'de, D>(deserializer: D) -> Result<EcoString, D::Error>
10751109
where
@@ -1091,10 +1125,7 @@ mod package_name {
10911125
where
10921126
E: serde::de::Error,
10931127
{
1094-
if PACKAGE_NAME_PATTERN
1095-
.get_or_init(|| Regex::new("^[a-z][a-z0-9_]*$").expect("Package name regex"))
1096-
.is_match(value)
1097-
{
1128+
if super::is_valid_package_name(value) {
10981129
Ok(value.into())
10991130
} else {
11001131
let error =
@@ -1105,6 +1136,53 @@ mod package_name {
11051136
}
11061137
}
11071138

1139+
mod dependencies_map {
1140+
use ecow::EcoString;
1141+
use serde::{Deserialize, Deserializer, de};
1142+
use std::collections::HashMap;
1143+
1144+
pub fn deserialize<'de, D, V>(deserializer: D) -> Result<HashMap<EcoString, V>, D::Error>
1145+
where
1146+
D: Deserializer<'de>,
1147+
V: Deserialize<'de>,
1148+
{
1149+
struct DependenciesVisitor<V>(std::marker::PhantomData<V>);
1150+
1151+
impl<'de, V: Deserialize<'de>> de::Visitor<'de> for DependenciesVisitor<V> {
1152+
type Value = HashMap<EcoString, V>;
1153+
1154+
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1155+
write!(f, "a map with valid package name keys")
1156+
}
1157+
1158+
fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
1159+
let mut dependencies = HashMap::new();
1160+
while let Some(key) = map.next_key::<EcoString>()? {
1161+
if !super::is_valid_package_name(&key) {
1162+
return Err(de::Error::invalid_value(
1163+
de::Unexpected::Str(&key),
1164+
&"a package name containing only lowercase letter, numbers, and underscores",
1165+
));
1166+
}
1167+
let _: Option<_> = dependencies.insert(key, map.next_value()?);
1168+
}
1169+
Ok(dependencies)
1170+
}
1171+
}
1172+
1173+
deserializer.deserialize_map(DependenciesVisitor(std::marker::PhantomData))
1174+
}
1175+
}
1176+
1177+
fn is_valid_package_name(name: &str) -> bool {
1178+
use regex::Regex;
1179+
use std::sync::OnceLock;
1180+
static PACKAGE_NAME_PATTERN: OnceLock<Regex> = OnceLock::new();
1181+
PACKAGE_NAME_PATTERN
1182+
.get_or_init(|| Regex::new("^[a-z][a-z0-9_]*$").expect("Package name regex"))
1183+
.is_match(name)
1184+
}
1185+
11081186
#[test]
11091187
fn name_with_dash() {
11101188
let input = r#"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
source: compiler-core/src/config.rs
3+
assertion_line: 385
4+
expression: error.pretty_string()
5+
---
6+
error: File IO failure
7+
8+
An error occurred while trying to parse this file:
9+
10+
gleam.toml
11+
12+
The error message from the file IO library was:
13+
14+
TOML parse error at line 5, column 1
15+
|
16+
5 | [dependencies]
17+
| ^^^^^^^^^^^^^^
18+
invalid value: string "Hello", expected a package name containing only lowercase letter, numbers, and underscores
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
source: compiler-core/src/config.rs
3+
assertion_line: 399
4+
expression: error.pretty_string()
5+
---
6+
error: File IO failure
7+
8+
An error occurred while trying to parse this file:
9+
10+
gleam.toml
11+
12+
The error message from the file IO library was:
13+
14+
TOML parse error at line 5, column 1
15+
|
16+
5 | [dev_dependencies]
17+
| ^^^^^^^^^^^^^^^^^^
18+
invalid value: string "yes.", expected a package name containing only lowercase letter, numbers, and underscores

compiler-wasm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gleam-wasm"
3-
version = "1.15.2"
3+
version = "1.15.3"
44
authors = ["Louis Pilfold <louis@lpil.uk>"]
55
edition = "2024"
66
license = "Apache-2.0"

gleam-bin/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gleam"
3-
version = "1.15.2"
3+
version = "1.15.3"
44
authors = ["Louis Pilfold <louis@lpil.uk>"]
55
edition = "2024"
66
license = "Apache-2.0"

hexpm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "hexpm"
3-
version = "1.15.2"
3+
version = "1.15.3"
44
authors = ["Louis Pilfold <louis@lpil.uk>"]
55
edition = "2024"
66
license = "Apache-2.0"

0 commit comments

Comments
 (0)