html-conformv0.2.1

CASOON Open Source

HTML conformance checks inside your Rust build.

html-conform parses a document the way browsers do, then checks it against the W3C HTML schema, attribute microsyntaxes, ARIA and structural rules. It is tested against the Nu Html Checker's own test corpus and runs without a JVM, subprocess or network access.

cargo add html-conform
MITcrates.io 0.2.1Rust 1.88+no JVM
check(table-grid.html)
error   10:9   schema.html5
  invalid value `rows` for attribute `scope` at 10:9
error   10:9   assertion.tables.th-scope-enum
  A th element's scope attribute must be one of row, col,
  rowgroup, or colgroup.
error   11:23  tables.integrity
  Table cell is overlapped by later table cell.
error   12:9   tables.integrity
  Table cell overlaps an earlier table cell.

4 errors, 0 warnings
vnu test fixtures in the differential test
4,655
false positives on that corpus
0
false negative, documented: CSS inside <style>
1
finding sources in one report
6

What it does

  1. Six layers, one report

    Parser diagnostics, the RELAX NG schema with SVG and MathML, attribute microsyntaxes, Schematron co-constraints, script and CSP checks, and the table cell grid all return the same Finding: rule ID, severity, message and position.

  2. Measured against vnu

    The differential test runs every vendored vnu fixture through check() on each push and fails if false positives or false negatives rise above the recorded baseline.

  3. A library, not a service

    No JVM, no subprocess, no HTTP. The schema and the rules are embedded in the crate, so check() works the same in a test, a CLI or a server.

  4. Serializable findings

    CheckReport, Finding, Severity and SourceLocation implement serde Serialize and Deserialize. The showcase on this site is built from that JSON.

Generated at build time

All examples →
error   7:3    scripts.import-map
  A "script" element with a "type" attribute whose value is "importmap"
  must contain a JSON object with no properties other than "imports",
  "scopes", and "integrity".
error   11:3   scripts.speculation-rules
  The "urls" property in a speculation rule must be a JSON array.
warning 7:3    csp.meta-enforcement
  Inline script violates Content Security Policy (meta tag): blocked by
  "script-src" directive (missing "'unsafe-inline'" or nonce/hash).
warning 10:3   csp.meta-enforcement
  Inline script violates Content Security Policy (meta tag): blocked by
  "script-src" directive (missing "'unsafe-inline'" or nonce/hash).
warning 11:3   csp.meta-enforcement
  Inline script violates Content Security Policy (meta tag): blocked by
  "script-src" directive (missing "'unsafe-inline'" or nonce/hash).

2 errors, 3 warnings

Findings for examples/showcase/csp-and-scripts.html, written by cargo run --example findings and formatted for this page. The showcase has six more samples.

examples/showcase/csp-and-scripts.json

Quickstart

Three steps from a dependency to a failing build on invalid markup. The documentation covers options, rule IDs and the comparison with vnu.

  1. Add the crate with cargo add html-conform.
  2. Pass the document to html_conform::check().
  3. Read report.findings, or ask report.has_errors().
main.rsRust
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let html = std::fs::read_to_string("index.html")?;
    let report = html_conform::check(&html)?;

    for finding in &report.findings {
        let at = finding.location.map(|l| l.to_string()).unwrap_or_default();
        println!("{:?} {at} {} {}", finding.severity, finding.rule_id, finding.message);
    }

    if report.has_errors() {
        std::process::exit(1);
    }
    Ok(())
}