Skip to content

Commit 1d88612

Browse files
committed
validation
1 parent b62b0fe commit 1d88612

File tree

3 files changed

+62
-9
lines changed

3 files changed

+62
-9
lines changed

docs/book/src/forc/manifest_reference.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ The `Forc.toml` (the _manifest_ file) is a compulsory file for each package and
44

55
* [`[project]`](#the-project-section) — Defines a sway project.
66
* `name` — The name of the project.
7+
* `version` — The version of the project.
8+
* `description` — A description of the project.
79
* `authors` — The authors of the project.
810
* `organization` — The organization of the project.
9-
* `license`— The project license.
11+
* `license` — The project license.
12+
* `homepage` — URL of the project homepage.
13+
* `repository` — URL of the project source repository.
14+
* `documentation` — URL of the project documentation.
1015
* `entry` — The entry point for the compiler to start parsing from.
1116
* For the recommended way of selecting an entry point of large libraries please take a look at: [Libraries](./../sway-program-types/libraries.md)
1217
* `implicit-std` - Controls whether provided `std` version (with the current `forc` version) will get added as a dependency _implicitly_. _Unless you know what you are doing, leave this as default._
@@ -29,6 +34,11 @@ An example `Forc.toml` is shown below. Under `[project]` the following fields ar
2934

3035
* `authors`
3136
* `organization`
37+
* `version`
38+
* `description`
39+
* `homepage`
40+
* `repository`
41+
* `documentation`
3242

3343
Also for the following fields, a default value is provided so omitting them is allowed:
3444

@@ -39,6 +49,11 @@ Also for the following fields, a default value is provided so omitting them is a
3949
[project]
4050
authors = ["user"]
4151
entry = "main.sw"
52+
description = "Wallet contract"
53+
version = "1.0.0"
54+
homepage = "https://example.com/"
55+
repository = "https://example.com/"
56+
documentation = "https://example.com/"
4257
organization = "Fuel_Labs"
4358
license = "Apache-2.0"
4459
name = "wallet_contract"

forc-pkg/src/manifest/mod.rs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ pub mod build_profile;
33
use crate::pkg::{manifest_file_missing, parsing_failed, wrong_program_type};
44
use anyhow::{anyhow, bail, Context, Result};
55
use forc_tracing::println_warning;
6-
use forc_util::{validate_name, validate_project_name};
7-
use serde::{Deserialize, Serialize};
6+
use forc_util::{restricted::is_valid_package_version, validate_name, validate_project_name};
7+
use serde::{de, Deserialize, Serialize};
88
use serde_with::{serde_as, DisplayFromStr};
99
use std::{
1010
collections::{BTreeMap, HashMap},
@@ -19,6 +19,7 @@ use sway_utils::{
1919
constants, find_nested_manifest_dir, find_parent_manifest_dir,
2020
find_parent_manifest_dir_with_check,
2121
};
22+
use url::Url;
2223

2324
use self::build_profile::BuildProfile;
2425

@@ -193,14 +194,16 @@ pub struct PackageManifest {
193194
#[serde(rename_all = "kebab-case")]
194195
pub struct Project {
195196
pub authors: Option<Vec<String>>,
197+
#[serde(deserialize_with = "validate_package_name")]
196198
pub name: String,
199+
#[serde(deserialize_with = "validate_package_version")]
197200
pub version: Option<String>,
198201
pub description: Option<String>,
199202
pub organization: Option<String>,
200203
pub license: String,
201-
pub homepage: Option<String>,
202-
pub repository: Option<String>,
203-
pub documentation: Option<String>,
204+
pub homepage: Option<Url>,
205+
pub repository: Option<Url>,
206+
pub documentation: Option<Url>,
204207
#[serde(default = "default_entry")]
205208
pub entry: String,
206209
pub implicit_std: Option<bool>,
@@ -210,6 +213,35 @@ pub struct Project {
210213
pub metadata: Option<toml::Value>,
211214
}
212215

216+
// Validation function for the `name` field
217+
fn validate_package_name<'de, D>(deserializer: D) -> Result<String, D::Error>
218+
where
219+
D: de::Deserializer<'de>,
220+
{
221+
let name: String = Deserialize::deserialize(deserializer)?;
222+
match validate_project_name(&name) {
223+
Ok(_) => Ok(name),
224+
Err(e) => Err(de::Error::custom(e.to_string())),
225+
}
226+
}
227+
228+
// Validation function for `version`
229+
fn validate_package_version<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
230+
where
231+
D: de::Deserializer<'de>,
232+
{
233+
let version: Option<String> = Deserialize::deserialize(deserializer)?;
234+
if let Some(ref version_str) = version {
235+
if is_valid_package_version(version_str) {
236+
return Err(de::Error::custom(format!(
237+
"Invalid semantic version: '{}'",
238+
version_str
239+
)));
240+
}
241+
}
242+
Ok(version)
243+
}
244+
213245
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
214246
#[serde(rename_all = "kebab-case")]
215247
pub struct Network {
@@ -1394,9 +1426,9 @@ mod tests {
13941426
name: "test-project".to_string(),
13951427
version: Some("0.1.0".to_string()),
13961428
description: Some("test description".to_string()),
1397-
homepage: Some("https://example.com".to_string()),
1398-
documentation: Some("https://docs.example.com".to_string()),
1399-
repository: Some("https://example.com".to_string()),
1429+
homepage: Some(Url::parse("https://example.com").unwrap()),
1430+
documentation: Some(Url::parse("https://docs.example.com").unwrap()),
1431+
repository: Some(Url::parse("https://example.com").unwrap()),
14001432
organization: None,
14011433
license: "Apache-2.0".to_string(),
14021434
entry: "main.sw".to_string(),

forc-util/src/restricted.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ pub fn is_valid_project_name_format(name: &str) -> Result<()> {
107107
Ok(())
108108
}
109109

110+
pub fn is_valid_package_version(vers: &str) -> bool {
111+
// Must start with an alphanumeric character, can contain only letters, numbers, underscores, dots and hyphens
112+
let re = Regex::new(r"^[a-zA-Z0-9][\w.-]*$").unwrap();
113+
re.is_match(vers)
114+
}
115+
110116
#[test]
111117
fn test_invalid_char() {
112118
assert_eq!(

0 commit comments

Comments
 (0)