use std::fmt::Write;
use super::{RuleId, Severity};
pub(super) const WEAK_TERMS: &[&str] = &[
"appropriate",
"adequate",
"efficient",
"flexible",
"user friendly",
"easy",
"fast",
"seamless",
"reasonable",
"sufficient",
"robust",
"intuitive",
"timely",
"optimal",
"as soon as possible",
];
pub(super) const VAGUE_QUANTIFIERS: &[&str] = &[
"some",
"several",
"many",
"few",
"most",
"various",
"significant",
"minimal",
"frequently",
"rarely",
"regularly",
];
pub(super) const ESCAPE_CLAUSES: &[&str] = &[
"if possible",
"where appropriate",
"as appropriate",
"as required",
"as necessary",
"if needed",
"where feasible",
"to the extent practical",
"if applicable",
];
pub(super) const ABSOLUTES: &[&str] = &["all", "always", "never", "every", "any", "none"];
pub(super) const MODALS: &[&str] = &["shall", "must", "will", "should"];
pub(super) const CONJUNCTIONS: &[&str] = &["and", "or"];
pub(super) const NORMATIVE_WORDS: &[&str] = &["shall", "must"];
pub(super) enum Kind {
Lexicon(&'static [&'static str]),
Count {
default: usize,
least: usize,
expected: &'static str,
},
Millionths(u32),
Names,
}
pub(super) const OPTIONS: [(RuleId, &str, Kind); 13] = [
(RuleId::Lq001, "lexicon", Kind::Lexicon(WEAK_TERMS)),
(RuleId::Lq002, "lexicon", Kind::Lexicon(VAGUE_QUANTIFIERS)),
(RuleId::Lq003, "lexicon", Kind::Lexicon(ESCAPE_CLAUSES)),
(RuleId::Lq004, "lexicon", Kind::Lexicon(ABSOLUTES)),
(RuleId::Lq005, "modalLexicon", Kind::Lexicon(MODALS)),
(
RuleId::Lq005,
"conjunctionLexicon",
Kind::Lexicon(CONJUNCTIONS),
),
(
RuleId::Lq005,
"conjunctionThreshold",
Kind::Count {
default: 3,
least: 2,
expected: "a count of at least 2",
},
),
(
RuleId::Lq008,
"minTokens",
Kind::Count {
default: 2,
least: 1,
expected: "a count of at least 1",
},
),
(RuleId::Lq008, "threshold", Kind::Millionths(800_000)),
(
RuleId::V2006,
"maxCriteria",
Kind::Count {
default: 20,
least: 1,
expected: "a count of at least 1",
},
),
(
RuleId::V2006,
"maxBodyWords",
Kind::Count {
default: 150,
least: 1,
expected: "a count of at least 1",
},
),
(RuleId::V2007, "lexicon", Kind::Lexicon(NORMATIVE_WORDS)),
(RuleId::V2008, "properNames", Kind::Names),
];
pub(super) fn option(rule: RuleId, key: &str) -> Option<(&'static str, &'static Kind)> {
OPTIONS
.iter()
.find(|(each, name, _)| *each == rule && *name == key)
.map(|(_, name, kind)| (*name, kind))
}
impl RuleId {
#[must_use]
pub const fn enabled_by_default(self) -> bool {
!matches!(self, Self::Lq004 | Self::Lq007)
}
#[must_use]
pub const fn default_severity(self) -> Severity {
match self {
Self::Sh001
| Self::Sh003
| Self::Sh004
| Self::Sh007
| Self::Sh009
| Self::Lq001
| Self::Lq002
| Self::Lq003
| Self::Lq006
| Self::V2003
| Self::V2004
| Self::V2005
| Self::V2007 => Severity::Warning,
Self::Sh002
| Self::Sh005
| Self::Sh006
| Self::Sh008
| Self::Lq004
| Self::Lq005
| Self::Lq007
| Self::Lq008
| Self::V2001
| Self::V2002
| Self::V2006
| Self::V2008 => Severity::Info,
Self::Sh010 | Self::Lq009 => Severity::Hint,
}
}
}
#[must_use]
pub fn defaults_text() -> String {
let mut text = String::from("rules:\n");
for rule in RuleId::ALL {
let _ = write!(
text,
" - rule: {rule}\n enabled: {}\n severity: {}\n",
rule.enabled_by_default(),
rule.default_severity()
);
for (_, key, kind) in OPTIONS.iter().filter(|(each, ..)| each == rule) {
option_text(&mut text, key, kind);
}
}
text
}
fn option_text(text: &mut String, key: &str, kind: &Kind) {
match kind {
Kind::Lexicon(terms) => {
let _ = writeln!(text, " {key}:\n replace:");
for term in *terms {
let _ = writeln!(text, " - \"{term}\"");
}
}
Kind::Count { default, .. } => {
let _ = writeln!(text, " {key}: {default}");
}
Kind::Millionths(default) => {
let threshold = super::config::millionths_text(*default);
let _ = writeln!(text, " {key}: {threshold}");
}
Kind::Names => {
let _ = writeln!(text, " {key}:");
}
}
}