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(),
default_enabled: rule.default_enabled(),
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. Each section describes
one rule, identified by its stable **rule id**. BibTeX rules share an id
namespace with the [LaTeX rules](linter-rules.md), so the same `[lint]` settings
and `--select` and `--ignore` flags select both sets.
Most rules are **on by default**. Each rule's section states whether it is
enabled by default. Use `select` to enable an opt-in rule, or use `select` and
`ignore` in the `[lint]` table to narrow the default set. See the
[Configuration reference](configuration.md#lint).
Some rules offer an **autofix** when a rewrite is unambiguous.
`badness lint --fix` applies *safe* fixes, shown below under \"After applying the
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 write suppression directives inside
structured `@comment` entries. A `skip` directive suppresses one rule on the
**next entry**:
```bib
@comment{badness-lint skip missing-required-field: publisher long gone}
@book{oldbook, title = {An Orphaned Book}}
```
The directive grammar is the same as in LaTeX. `off` and `on` delimit a
region of entries, and `skip-file` covers the whole file wherever the directive
appears:
```bib
@comment{badness-lint off missing-required-field: imported, incomplete by design}
@book{oldbook, title = {An Orphaned Book}}
@comment{badness-lint on missing-required-field}
```
The `<id>` is optional. Omitting it suppresses every rule over the same span.
Parse diagnostics (rule id `parse`) are never suppressed.
";