Skip to main content

perl_source_file/
lib.rs

1//! Shared Perl source-file classification helpers.
2//!
3//! These helpers provide one canonical definition for what constitutes a Perl
4//! source file across workspace discovery and runtime file operations.
5
6use std::path::Path;
7
8/// Canonical Perl source file extensions.
9pub const PERL_SOURCE_EXTENSIONS: [&str; 4] = ["pl", "pm", "t", "psgi"];
10
11/// Returns `true` if `extension` is a recognized Perl source extension.
12///
13/// Accepts values with or without a leading dot and matches
14/// case-insensitively.
15#[must_use]
16pub fn is_perl_source_extension(extension: &str) -> bool {
17    let ext = extension.strip_prefix('.').unwrap_or(extension);
18    PERL_SOURCE_EXTENSIONS.iter().any(|candidate| candidate.eq_ignore_ascii_case(ext))
19}
20
21/// Returns `true` if `path` points to a recognized Perl source file.
22#[must_use]
23pub fn is_perl_source_path(path: &Path) -> bool {
24    path.extension().and_then(|ext| ext.to_str()).is_some_and(is_perl_source_extension)
25}
26
27/// Returns `true` if `uri` or path-like string points to a Perl source file.
28///
29/// Supports:
30/// - Plain filesystem paths
31/// - `file://` URIs
32/// - Optional query/fragment suffixes
33#[must_use]
34pub fn is_perl_source_uri(uri: &str) -> bool {
35    let without_fragment = uri.split('#').next().unwrap_or(uri);
36    let without_query = without_fragment.split('?').next().unwrap_or(without_fragment);
37    is_perl_source_path(Path::new(without_query))
38}
39
40#[cfg(test)]
41mod tests {
42    use super::{
43        PERL_SOURCE_EXTENSIONS, is_perl_source_extension, is_perl_source_path, is_perl_source_uri,
44    };
45    use std::path::Path;
46
47    #[test]
48    fn exposes_expected_extension_set() {
49        assert_eq!(PERL_SOURCE_EXTENSIONS, ["pl", "pm", "t", "psgi"]);
50    }
51
52    #[test]
53    fn classifies_extensions_case_insensitively() {
54        assert!(is_perl_source_extension("pl"));
55        assert!(is_perl_source_extension(".pm"));
56        assert!(is_perl_source_extension("T"));
57        assert!(is_perl_source_extension("PsGi"));
58        assert!(!is_perl_source_extension("txt"));
59    }
60
61    #[test]
62    fn classifies_filesystem_paths() {
63        assert!(is_perl_source_path(Path::new("/workspace/script.pl")));
64        assert!(is_perl_source_path(Path::new("/workspace/lib/Foo/Bar.PM")));
65        assert!(is_perl_source_path(Path::new("/workspace/app.psgi")));
66        assert!(!is_perl_source_path(Path::new("/workspace/README.md")));
67        assert!(!is_perl_source_path(Path::new("/workspace/no_extension")));
68    }
69
70    #[test]
71    fn classifies_uri_like_inputs() {
72        assert!(is_perl_source_uri("file:///workspace/script.pl"));
73        assert!(is_perl_source_uri("file:///workspace/lib/Foo/Bar.pm"));
74        assert!(is_perl_source_uri("file:///workspace/app.psgi"));
75        assert!(is_perl_source_uri("file:///workspace/app.psgi?version=1#section"));
76        assert!(!is_perl_source_uri("file:///workspace/README.md"));
77    }
78
79    #[test]
80    fn supports_windows_style_paths() {
81        assert!(is_perl_source_uri(r"C:\workspace\script.pl"));
82        assert!(is_perl_source_uri(r"file:///C:/workspace/lib/Foo.pm"));
83        assert!(!is_perl_source_uri(r"C:\workspace\README.txt"));
84    }
85}