aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-core/src/validation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mozart-core/src/validation.rs')
-rw-r--r--crates/mozart-core/src/validation.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/crates/mozart-core/src/validation.rs b/crates/mozart-core/src/validation.rs
index 24f1705..c27eb91 100644
--- a/crates/mozart-core/src/validation.rs
+++ b/crates/mozart-core/src/validation.rs
@@ -115,6 +115,19 @@ pub fn parse_require_string(s: &str) -> Result<(String, String), String> {
))
}
+/// Mirror of `Composer\Package\BasePackage::packageNameToRegexp`. Each
+/// character of `pattern` is `regex::escape`d, then `\*` is rewritten
+/// to `.*`, and the result is anchored and compiled case-insensitively.
+/// Used by selection commands (`reinstall`, `remove`, `update`, …) to
+/// expand `vendor/*`-style globs against installed/locked package names.
+pub fn package_name_to_regexp(pattern: &str) -> Regex {
+ let escaped = regex::escape(pattern).replace("\\*", ".*");
+ // PHP wraps with `{^...$}i`; in Rust we anchor with `\A`/`\z` and
+ // pass `(?i)` for case-insensitivity.
+ Regex::new(&format!(r"(?i)\A{escaped}\z"))
+ .expect("package_name_to_regexp pattern always compiles")
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -207,6 +220,45 @@ mod tests {
}
#[test]
+ fn test_package_name_to_regexp_exact() {
+ let re = package_name_to_regexp("monolog/monolog");
+ assert!(re.is_match("monolog/monolog"));
+ assert!(re.is_match("Monolog/Monolog"));
+ assert!(!re.is_match("psr/log"));
+ assert!(!re.is_match("monolog/monolog-extra"));
+ assert!(!re.is_match("xmonolog/monolog"));
+ }
+
+ #[test]
+ fn test_package_name_to_regexp_wildcard() {
+ let re = package_name_to_regexp("psr/*");
+ assert!(re.is_match("psr/log"));
+ assert!(re.is_match("psr/container"));
+ assert!(re.is_match("psr/log/sub"));
+ assert!(!re.is_match("monolog/monolog"));
+
+ let re = package_name_to_regexp("*/log");
+ assert!(re.is_match("psr/log"));
+ assert!(re.is_match("monolog/log"));
+ assert!(!re.is_match("psr/container"));
+
+ let re = package_name_to_regexp("symfony/*/bridge");
+ assert!(re.is_match("symfony/http/bridge"));
+ assert!(!re.is_match("symfony/bridge"));
+
+ let re = package_name_to_regexp("*");
+ assert!(re.is_match("anything/at/all"));
+ }
+
+ #[test]
+ fn test_package_name_to_regexp_escapes_metacharacters() {
+ // `.` must be literal, not "any character"
+ let re = package_name_to_regexp("foo.bar/baz");
+ assert!(re.is_match("foo.bar/baz"));
+ assert!(!re.is_match("fooXbar/baz"));
+ }
+
+ #[test]
fn test_parse_require_string() {
let (name, ver) = parse_require_string("foo/bar:^1.0").unwrap();
assert_eq!(name, "foo/bar");