import { ConfigData, formatterFactory, HtmlValidate, Report, Reporter } from "html-validate"; import "lume/types.ts"; import { merge } from "lume/core/utils/object.ts"; import { log } from "lume/core/utils/log.ts"; // HTML Validation Plugin, by dish // version 1.0.1 export const defaults: ConfigData = { extends: ["html-validate:recommended", "html-validate:document"], rules: { "doctype-style": "off", "attr-quotes": "off", "no-trailing-whitespace": "off", "void-style": "warn", "require-sri": ["off", { target: "crossorigin" }], }, }; export default function (userOptions?: ConfigData) { const options = merge(defaults, userOptions); const htmlvalidate = new HtmlValidate(options); return (site: Lume.Site) => { site.process([".html"], validatePages); const barReport = site.debugBar?.collection("HTML Validator"); if (barReport) { barReport.icon = "shield-check"; barReport.contexts = { "error": { background: "error", }, "warning": { background: "warning", }, "success": { background: "success", }, }; } async function validatePages(pages: Lume.Page[]) { for (const page of pages) { const report = await htmlvalidate.validateString(page.content as string, page.outputPath); if (report.valid == true) { barReport?.items.push({ title: page.data.url, context: "success", text: "No errors or warnings on page", }); } else { barReport?.items.push({ title: page.data.url, details: `${report.errorCount} errors, ${report.warningCount} warnings`, items: Array.from(report.results[0].messages).map((msg) => ({ title: msg.message, context: severity(msg.severity), code: msg.ruleId, actions: [ { text: "Rule", icon: "question", href: msg.ruleUrl, target: "_blank", }, ], })), }); } } } }; } function severity(level: number) { if (level == 1) { return "warning"; } return "error"; }