ass_core/analysis/
construction.rs1use super::{
8 linting, AnalysisConfig, DialogueInfo, LintConfig, ScriptAnalysis, ScriptAnalysisOptions,
9 StyleAnalyzer,
10};
11#[cfg(feature = "plugins")]
12use crate::plugin::ExtensionRegistry;
13use crate::{
14 parser::{Script, Section},
15 Result,
16};
17use alloc::vec::Vec;
18
19impl<'a> ScriptAnalysis<'a> {
20 pub fn analyze(script: &'a Script<'a>) -> Result<Self> {
35 #[cfg(feature = "plugins")]
36 return Self::analyze_with_registry(script, None, AnalysisConfig::default());
37 #[cfg(not(feature = "plugins"))]
38 return Self::analyze_with_config(script, AnalysisConfig::default());
39 }
40
41 #[cfg(feature = "plugins")]
55 pub fn analyze_with_registry(
56 script: &'a Script<'a>,
57 registry: Option<&'a ExtensionRegistry>,
58 config: AnalysisConfig,
59 ) -> Result<Self> {
60 Ok(Self::analyze_impl(script, registry, config))
61 }
62
63 pub fn analyze_with_config(script: &'a Script<'a>, config: AnalysisConfig) -> Result<Self> {
71 #[cfg(feature = "plugins")]
72 return Ok(Self::analyze_impl(script, None, config));
73 #[cfg(not(feature = "plugins"))]
74 return Ok(Self::analyze_impl_no_plugins(script, config));
75 }
76
77 #[cfg(feature = "plugins")]
79 fn analyze_impl(
80 script: &'a Script<'a>,
81 registry: Option<&'a ExtensionRegistry>,
82 config: AnalysisConfig,
83 ) -> Self {
84 let mut analysis = Self {
85 script,
86 lint_issues: Vec::new(),
87 resolved_styles: Vec::new(),
88 dialogue_info: Vec::new(),
89 config,
90 registry,
91 };
92
93 analysis.resolve_all_styles();
94 analysis.analyze_events();
95 analysis.run_linting();
96
97 analysis
98 }
99
100 #[cfg(not(feature = "plugins"))]
102 fn analyze_impl_no_plugins(script: &'a Script<'a>, config: AnalysisConfig) -> Self {
103 let mut analysis = Self {
104 script,
105 lint_issues: Vec::new(),
106 resolved_styles: Vec::new(),
107 dialogue_info: Vec::new(),
108 config,
109 };
110
111 analysis.resolve_all_styles();
112 analysis.analyze_events();
113 analysis.run_linting();
114
115 analysis
116 }
117
118 fn run_linting(&mut self) {
120 let lint_config = LintConfig::default().with_strict_compliance(
121 self.config
122 .options
123 .contains(ScriptAnalysisOptions::STRICT_COMPLIANCE),
124 );
125
126 let mut issues = Vec::new();
127 let rules = linting::rules::BuiltinRules::all_rules();
128
129 for rule in rules {
130 if !lint_config.is_rule_enabled(rule.id()) {
131 continue;
132 }
133
134 let mut rule_issues = rule.check_script(self);
135 rule_issues.retain(|issue| lint_config.should_report_severity(issue.severity()));
136
137 issues.extend(rule_issues);
138
139 if lint_config.max_issues > 0 && issues.len() >= lint_config.max_issues {
140 issues.truncate(lint_config.max_issues);
141 break;
142 }
143 }
144
145 self.lint_issues = issues;
146 }
147
148 pub(super) fn resolve_all_styles(&mut self) {
150 let analyzer = StyleAnalyzer::new(self.script);
151 self.resolved_styles = analyzer.resolved_styles().values().cloned().collect();
152 }
153
154 pub(super) fn analyze_events(&mut self) {
156 if let Some(Section::Events(events)) = self
157 .script
158 .sections()
159 .iter()
160 .find(|s| matches!(s, Section::Events(_)))
161 {
162 for event in events {
163 #[cfg(feature = "plugins")]
164 let info_result = self.registry.map_or_else(
165 || DialogueInfo::analyze(event),
166 |registry| DialogueInfo::analyze_with_registry(event, Some(registry)),
167 );
168
169 #[cfg(not(feature = "plugins"))]
170 let info_result = DialogueInfo::analyze(event);
171
172 if let Ok(info) = info_result {
173 self.dialogue_info.push(info);
174 }
175 }
176 }
177 }
178}