use super::{
linting, AnalysisConfig, DialogueInfo, LintConfig, ScriptAnalysis, ScriptAnalysisOptions,
StyleAnalyzer,
};
#[cfg(feature = "plugins")]
use crate::plugin::ExtensionRegistry;
use crate::{
parser::{Script, Section},
Result,
};
use alloc::vec::Vec;
impl<'a> ScriptAnalysis<'a> {
pub fn analyze(script: &'a Script<'a>) -> Result<Self> {
#[cfg(feature = "plugins")]
return Self::analyze_with_registry(script, None, AnalysisConfig::default());
#[cfg(not(feature = "plugins"))]
return Self::analyze_with_config(script, AnalysisConfig::default());
}
#[cfg(feature = "plugins")]
pub fn analyze_with_registry(
script: &'a Script<'a>,
registry: Option<&'a ExtensionRegistry>,
config: AnalysisConfig,
) -> Result<Self> {
Ok(Self::analyze_impl(script, registry, config))
}
pub fn analyze_with_config(script: &'a Script<'a>, config: AnalysisConfig) -> Result<Self> {
#[cfg(feature = "plugins")]
return Ok(Self::analyze_impl(script, None, config));
#[cfg(not(feature = "plugins"))]
return Ok(Self::analyze_impl_no_plugins(script, config));
}
#[cfg(feature = "plugins")]
fn analyze_impl(
script: &'a Script<'a>,
registry: Option<&'a ExtensionRegistry>,
config: AnalysisConfig,
) -> Self {
let mut analysis = Self {
script,
lint_issues: Vec::new(),
resolved_styles: Vec::new(),
dialogue_info: Vec::new(),
config,
registry,
};
analysis.resolve_all_styles();
analysis.analyze_events();
analysis.run_linting();
analysis
}
#[cfg(not(feature = "plugins"))]
fn analyze_impl_no_plugins(script: &'a Script<'a>, config: AnalysisConfig) -> Self {
let mut analysis = Self {
script,
lint_issues: Vec::new(),
resolved_styles: Vec::new(),
dialogue_info: Vec::new(),
config,
};
analysis.resolve_all_styles();
analysis.analyze_events();
analysis.run_linting();
analysis
}
fn run_linting(&mut self) {
let lint_config = LintConfig::default().with_strict_compliance(
self.config
.options
.contains(ScriptAnalysisOptions::STRICT_COMPLIANCE),
);
let mut issues = Vec::new();
let rules = linting::rules::BuiltinRules::all_rules();
for rule in rules {
if !lint_config.is_rule_enabled(rule.id()) {
continue;
}
let mut rule_issues = rule.check_script(self);
rule_issues.retain(|issue| lint_config.should_report_severity(issue.severity()));
issues.extend(rule_issues);
if lint_config.max_issues > 0 && issues.len() >= lint_config.max_issues {
issues.truncate(lint_config.max_issues);
break;
}
}
self.lint_issues = issues;
}
pub(super) fn resolve_all_styles(&mut self) {
let analyzer = StyleAnalyzer::new(self.script);
self.resolved_styles = analyzer.resolved_styles().values().cloned().collect();
}
pub(super) fn analyze_events(&mut self) {
if let Some(Section::Events(events)) = self
.script
.sections()
.iter()
.find(|s| matches!(s, Section::Events(_)))
{
for event in events {
#[cfg(feature = "plugins")]
let info_result = self.registry.map_or_else(
|| DialogueInfo::analyze(event),
|registry| DialogueInfo::analyze_with_registry(event, Some(registry)),
);
#[cfg(not(feature = "plugins"))]
let info_result = DialogueInfo::analyze(event);
if let Ok(info) = info_result {
self.dialogue_info.push(info);
}
}
}
}
}