1use rules::{RuleOrigin, lookup_rule, section_for_rule_id};
2use template_model::{SourceSpan, SpanProvider, UNKNOWN_SPAN};
3
4pub fn source_for_rule(rule_id: &str) -> RuleOrigin {
8 lookup_rule(rule_id).unwrap_or_else(|| panic!("Rule '{}' not found in RULE_REGISTRY", rule_id)).origin
9}
10
11pub fn resolve_section_span(rule_id: &str, span_provider: &dyn SpanProvider) -> SourceSpan {
15 match section_for_rule_id(rule_id) {
16 Some(section) => span_provider.source_location(section).unwrap_or(UNKNOWN_SPAN),
17 None => UNKNOWN_SPAN,
18 }
19}
20
21#[cfg(test)]
22mod tests {
23 use super::*;
24
25 struct FakeSpanProvider {
26 known_section: &'static str,
27 span: SourceSpan,
28 }
29
30 impl SpanProvider for FakeSpanProvider {
31 fn source_location(&self, path: &str) -> Option<SourceSpan> {
32 if path == self.known_section { Some(self.span) } else { None }
33 }
34 }
35
36 struct EmptySpanProvider;
37 impl SpanProvider for EmptySpanProvider {
38 fn source_location(&self, _path: &str) -> Option<SourceSpan> {
39 None
40 }
41 }
42
43 #[test]
44 fn resolve_section_span_returns_span_when_section_and_provider_match() {
45 let expected = SourceSpan { start_line: 5, start_column: 0, end_line: 10, end_column: 0 };
46 let provider = FakeSpanProvider { known_section: "Resources", span: expected };
47
48 let result = resolve_section_span("F0001", &provider);
49 assert_eq!(result, expected);
50 }
51
52 #[test]
53 fn resolve_section_span_returns_unknown_when_provider_has_no_match() {
54 let provider = EmptySpanProvider;
55 let result = resolve_section_span("F0001", &provider);
56 assert_eq!(result, UNKNOWN_SPAN);
57 }
58
59 #[test]
60 fn resolve_section_span_returns_unknown_for_unmapped_rule() {
61 let provider = FakeSpanProvider {
62 known_section: "Resources",
63 span: SourceSpan { start_line: 1, start_column: 0, end_line: 1, end_column: 0 },
64 };
65 let result = resolve_section_span("ZZZZZ", &provider);
66 assert_eq!(result, UNKNOWN_SPAN);
67 }
68}