at main 2.3 kB view raw
1import { ConfigData, formatterFactory, HtmlValidate, Report, Reporter } from "html-validate"; 2import "lume/types.ts"; 3import { merge } from "lume/core/utils/object.ts"; 4import { log } from "lume/core/utils/log.ts"; 5 6// HTML Validation Plugin, by dish 7// version 1.0.1 8 9export const defaults: ConfigData = { 10 extends: ["html-validate:recommended", "html-validate:document"], 11 rules: { 12 "doctype-style": "off", 13 "attr-quotes": "off", 14 "no-trailing-whitespace": "off", 15 "void-style": "warn", 16 "require-sri": ["off", { target: "crossorigin" }], 17 }, 18}; 19 20export default function (userOptions?: ConfigData) { 21 const options = merge(defaults, userOptions); 22 const htmlvalidate = new HtmlValidate(options); 23 24 return (site: Lume.Site) => { 25 site.process([".html"], validatePages); 26 const barReport = site.debugBar?.collection("HTML Validator"); 27 if (barReport) { 28 barReport.icon = "shield-check"; 29 barReport.contexts = { 30 "error": { 31 background: "error", 32 }, 33 "warning": { 34 background: "warning", 35 }, 36 "success": { 37 background: "success", 38 }, 39 }; 40 } 41 42 async function validatePages(pages: Lume.Page[]) { 43 for (const page of pages) { 44 const report = await htmlvalidate.validateString(page.content as string, page.outputPath); 45 if (report.valid == true) { 46 barReport?.items.push({ 47 title: page.data.url, 48 context: "success", 49 text: "No errors or warnings on page", 50 }); 51 } else { 52 barReport?.items.push({ 53 title: page.data.url, 54 details: `${report.errorCount} errors, ${report.warningCount} warnings`, 55 items: Array.from(report.results[0].messages).map((msg) => ({ 56 title: msg.message, 57 context: severity(msg.severity), 58 code: msg.ruleId, 59 actions: [ 60 { 61 text: "Rule", 62 icon: "question", 63 href: msg.ruleUrl, 64 target: "_blank", 65 }, 66 ], 67 })), 68 }); 69 } 70 } 71 } 72 }; 73} 74 75function severity(level: number) { 76 if (level == 1) { 77 return "warning"; 78 } 79 80 return "error"; 81}