From a24d6e2f148417b32188cd1e643439a2858f4eac Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 4 May 2026 14:41:59 +0900 Subject: feat(validate): port ValidatingArrayLoader license checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror Composer's Package\Loader\ValidatingArrayLoader::load() license block: warn on non-string/wrong-shape values, validate the SPDX expression with proprietary→MIT substitution, and surface "extra spaces" diagnostics. Validity is gated on the manifest's `time` field (checked only for releases without a date or within the last 8 days), mirroring Composer's strtotime('-8days') window. --- crates/mozart-spdx-licenses/Cargo.toml | 3 --- crates/mozart-spdx-licenses/src/lib.rs | 29 +++++++++++++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'crates/mozart-spdx-licenses') diff --git a/crates/mozart-spdx-licenses/Cargo.toml b/crates/mozart-spdx-licenses/Cargo.toml index 1500932..7361c93 100644 --- a/crates/mozart-spdx-licenses/Cargo.toml +++ b/crates/mozart-spdx-licenses/Cargo.toml @@ -3,9 +3,6 @@ name = "mozart-spdx-licenses" version.workspace = true edition.workspace = true -[dependencies] -indexmap.workspace = true - [build-dependencies] serde.workspace = true serde_json.workspace = true diff --git a/crates/mozart-spdx-licenses/src/lib.rs b/crates/mozart-spdx-licenses/src/lib.rs index 668270f..a551988 100644 --- a/crates/mozart-spdx-licenses/src/lib.rs +++ b/crates/mozart-spdx-licenses/src/lib.rs @@ -1,4 +1,4 @@ -use indexmap::IndexMap; +use std::collections::HashMap; use std::sync::LazyLock; include!(concat!(env!("OUT_DIR"), "/spdx_data.rs")); @@ -21,16 +21,16 @@ pub struct ExceptionInfo { /// SPDX license database with expression validation. pub struct SpdxLicenses { - licenses: IndexMap<&'static str, LicenseInfo>, - exceptions: IndexMap<&'static str, ExceptionInfo>, - name_to_id: IndexMap<&'static str, &'static str>, + licenses: HashMap<&'static str, LicenseInfo>, + exceptions: HashMap<&'static str, ExceptionInfo>, + name_to_id: HashMap<&'static str, &'static str>, } impl SpdxLicenses { /// Build the license database from generated data. pub fn new() -> Self { - let mut licenses = IndexMap::with_capacity(LICENSES.len()); - let mut name_to_id = IndexMap::with_capacity(LICENSES.len()); + let mut licenses = HashMap::with_capacity(LICENSES.len()); + let mut name_to_id = HashMap::with_capacity(LICENSES.len()); for &(lower, id, full_name, osi, deprecated) in LICENSES { licenses.insert( lower, @@ -44,7 +44,7 @@ impl SpdxLicenses { name_to_id.insert(full_name, id); } - let mut exceptions = IndexMap::with_capacity(EXCEPTIONS.len()); + let mut exceptions = HashMap::with_capacity(EXCEPTIONS.len()); for &(lower, id, full_name) in EXCEPTIONS { exceptions.insert( lower, @@ -95,7 +95,6 @@ impl SpdxLicenses { /// exceptions, the `+` (or-later) operator, LicenseRef, and the special /// values `NONE` and `NOASSERTION`. pub fn validate(&self, license: &str) -> bool { - let license = license.trim(); if license.is_empty() { return false; } @@ -417,6 +416,20 @@ mod tests { assert!(!db.validate("MIT WITH not-an-exception")); } + #[test] + fn no_edge_whitespace_allowed() { + // Composer's `^(NONE|NOASSERTION|...)$` (with `x` flag) admits no + // leading or trailing whitespace; mirror that. + let db = spdx(); + assert!(db.validate("MIT")); + assert!(!db.validate(" MIT")); + assert!(!db.validate("MIT ")); + assert!(!db.validate(" MIT ")); + assert!(!db.validate("\tMIT")); + assert!(!db.validate("MIT\t")); + assert!(!db.validate("\nMIT")); + } + #[test] fn validate_list() { let db = spdx(); -- cgit v1.3.1