use std::path::PathBuf;
use crate::bib::linter::check::lint_document;
use crate::bib::linter::rules::{BibRule, all_rules};
use crate::bib::parse;
use crate::bib::semantic::Model;
use crate::linter::diagnostic::Diagnostic;
use crate::linter::docs::{RuleDocSection, render_rule_section};
fn example_path() -> PathBuf {
PathBuf::from("references.bib")
}
pub fn demo_diagnostics(source: &str) -> Vec<Diagnostic> {
let path = example_path();
let root = parse(source).syntax();
let model = Model::build(&root);
lint_document(&path, &root, &model)
}
pub fn render_rule_doc(rule: &dyn BibRule) -> String {
let path = example_path();
render_rule_section(
&RuleDocSection {
id: rule.id(),
description: rule.description(),
examples: rule.examples(),
companions: &[],
example_path: &path,
lang: "bib",
},
&demo_diagnostics,
)
}
pub fn explain_rule(id: &str) -> Option<String> {
all_rules()
.iter()
.find(|rule| rule.id() == id)
.map(|rule| render_rule_doc(rule.as_ref()))
}
pub fn render_reference_page() -> String {
let mut out = String::from(PREAMBLE);
for rule in all_rules() {
out.push('\n');
out.push_str(&render_rule_doc(rule.as_ref()));
}
out.push('\n');
out.push_str(FOOTER);
out
}
const PREAMBLE: &str = "\
<!-- Generated by `cargo run --example docgen`. Do not edit by hand: edit each \
rule's `description()`/`examples()` in `src/bib/linter/rules/` and regenerate. -->
# BibTeX Linter Rules
`badness lint` runs a parallel set of built-in rules over each `.bib` file's
parse tree and reports a diagnostic for every finding. This page is the
catalogue: one section per rule, keyed by its stable **rule id**. Bib rules
share one id namespace with the [LaTeX rules](linter-rules.md), so the same
`[lint]` `select`/`ignore` (and `--select`/`--ignore`) target both.
Every rule is **on by default**; narrowing happens only through `select`/`ignore`
in the `[lint]` table (see the
[Configuration reference](configuration.md#lint)). Where a rewrite is unambiguous a rule
carries an **auto-fix**: a *safe* fix (shown below as \"After applying the fix\")
is applied by `badness lint --fix`.
Each example below is linted live to produce its diagnostic and fixed output, so
this page never drifts from the rules' actual behavior.
";
const FOOTER: &str = "\
## Suppression
BibTeX has no line-comment token, so per-site suppression rides a structured
`@comment` entry instead of the LaTeX `%` directive. A plain directive
suppresses one rule on the **next entry**:
```bib
@comment{badness-ignore missing-required-field: publisher long gone}
@book{oldbook, title = {An Orphaned Book}}
```
`@comment{badness-ignore-file <id>: ...}` suppresses one rule file-wide, and
`@comment{badness-ignore-file: ...}` suppresses all rules file-wide. Parse
diagnostics (rule id `parse`) are never suppressed.
";