Skip to main content

perl_module_import_match/
lib.rs

1//! Single-line module-import match predicates.
2//!
3//! This crate has one responsibility: determine whether a source line should
4//! be considered a target for module-import rename rewrites.
5
6#![deny(unsafe_code)]
7#![warn(rust_2018_idioms)]
8#![warn(missing_docs)]
9#![warn(clippy::all)]
10
11use perl_module_boundary::contains_standalone_module_token;
12use perl_module_import::{ModuleImportKind, parse_module_import_head};
13
14/// Return `true` when `line` references `module_name` in an import statement.
15///
16/// Matching behavior:
17/// - `use Module::Name;` and `require Module::Name;` require exact head-token match.
18/// - `use parent ...` and `use base ...` use boundary-aware token matching.
19/// - Non-import lines return `false`.
20#[must_use]
21pub fn line_references_module_import(line: &str, module_name: &str) -> bool {
22    if line.is_empty() || module_name.is_empty() {
23        return false;
24    }
25
26    let Some(parsed) = parse_module_import_head(line) else {
27        return false;
28    };
29
30    match parsed.kind {
31        ModuleImportKind::Use | ModuleImportKind::Require => parsed.token == module_name,
32        ModuleImportKind::UseParent | ModuleImportKind::UseBase => {
33            contains_standalone_module_token(line, module_name)
34        }
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::line_references_module_import;
41
42    #[test]
43    fn matches_direct_use_and_require_statements() {
44        assert!(line_references_module_import("use Foo::Bar;", "Foo::Bar"));
45        assert!(line_references_module_import("require Foo::Bar;", "Foo::Bar"));
46    }
47
48    #[test]
49    fn matches_parent_and_base_lines_with_boundary_checks() {
50        assert!(line_references_module_import("use parent qw(Foo::Bar Other::Base);", "Foo::Bar"));
51        assert!(line_references_module_import("use base 'Foo::Bar';", "Foo::Bar"));
52    }
53
54    #[test]
55    fn rejects_partial_matches_for_direct_imports() {
56        assert!(!line_references_module_import("use Foo::Barista;", "Foo::Bar"));
57        assert!(!line_references_module_import("require Foo::Barista;", "Foo::Bar"));
58    }
59
60    #[test]
61    fn rejects_non_import_contexts() {
62        assert!(!line_references_module_import("my $x = Foo::Bar->new();", "Foo::Bar"));
63        assert!(!line_references_module_import("package Foo::Bar;", "Foo::Bar"));
64    }
65
66    #[test]
67    fn rejects_empty_inputs() {
68        assert!(!line_references_module_import("", "Foo::Bar"));
69        assert!(!line_references_module_import("use Foo::Bar;", ""));
70    }
71}