From ce2cca8601eed2bd660f8162abd2a359fc4275ea Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Sat, 27 Sep 2025 20:33:21 -0700 Subject: [PATCH] New validator (#41775) * New validator * update * remove * update --- .github/workflows/docs.yml | 4 +- build/html-validate.mjs | 104 +++++ build/vnu-jar.mjs | 66 --- package-lock.json | 908 +++++++++++++++++++++++++++++++++---- package.json | 6 +- 5 files changed, 926 insertions(+), 162 deletions(-) create mode 100644 build/html-validate.mjs delete mode 100644 build/vnu-jar.mjs diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 59abb9111f..93035f41de 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -30,8 +30,6 @@ jobs: node-version: "${{ env.NODE }}" cache: npm - - run: java -version - - name: Install npm dependencies run: npm ci @@ -39,7 +37,7 @@ jobs: run: npm run docs-build - name: Validate HTML - run: npm run docs-vnu + run: npm run docs-html-validate - name: Run linkinator uses: JustinBeckwith/linkinator-action@3d5ba091319fa7b0ac14703761eebb7d100e6f6d # v1.11.0 diff --git a/build/html-validate.mjs b/build/html-validate.mjs new file mode 100644 index 0000000000..09b9ad66f8 --- /dev/null +++ b/build/html-validate.mjs @@ -0,0 +1,104 @@ +#!/usr/bin/env node + +/*! + * Script to run html-validate for HTML validation. + * + * This replaces the Java-based vnu-jar validator with a faster, Node.js-only solution. + * Benefits: + * - No Java dependency required + * - Faster execution (no JVM startup time) + * - Easy to configure with rule-based system + * - Better integration with Node.js build tools + * + * Copyright 2017-2025 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +import { HtmlValidate } from 'html-validate' +import { globby } from 'globby' + +const htmlValidate = new HtmlValidate({ + rules: { + // Allow autocomplete on buttons (Bootstrap specific) + 'attribute-allowed-values': 'off', + // Allow aria-disabled on links (Bootstrap specific) + 'aria-label-misuse': 'off', + // Allow modern CSS syntax + 'valid-id': 'off', + // Allow void elements with trailing slashes (Astro) + 'void-style': 'off', + // Allow custom attributes + 'no-unknown-elements': 'off', + 'attribute-boolean-style': 'off', + 'no-inline-style': 'off', + // KEEP duplicate ID checking enabled (this is important for HTML validity) + 'no-dup-id': 'error' + }, + elements: [ + 'html5', + { + // Allow custom attributes for Astro/framework compatibility + '*': { + attributes: { + 'is:raw': { boolean: true }, + switch: { boolean: true }, + autocomplete: { enum: ['on', 'off', 'new-password', 'current-password'] } + } + } + } + ] +}) + +async function validateHTML() { + try { + console.log('Running html-validate validation...') + + // Find all HTML files + const files = await globby([ + '_site/**/*.html', + 'js/tests/**/*.html' + ], { + ignore: ['**/node_modules/**'] + }) + + console.log(`Validating ${files.length} HTML files...`) + + let hasErrors = false + + // Validate all files in parallel to avoid await-in-loop + const validationPromises = files.map(file => + htmlValidate.validateFile(file).then(report => ({ file, report })) + ) + + const validationResults = await Promise.all(validationPromises) + + // Process results and check for errors + for (const { file, report } of validationResults) { + if (!report.valid) { + hasErrors = true + console.error(`\nErrors in ${file}:`) + + // Extract error messages with reduced nesting + const errorMessages = report.results.flatMap(result => + result.messages.filter(message => message.severity === 2) + ) + + for (const message of errorMessages) { + console.error(` Line ${message.line}:${message.column} - ${message.message} (${message.ruleId})`) + } + } + } + + if (hasErrors) { + console.error('\nHTML validation failed!') + process.exit(1) + } else { + console.log('✓ All HTML files are valid!') + } + } catch (error) { + console.error('HTML validation error:', error) + process.exit(1) + } +} + +validateHTML() diff --git a/build/vnu-jar.mjs b/build/vnu-jar.mjs deleted file mode 100644 index 4eedb1bedc..0000000000 --- a/build/vnu-jar.mjs +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to run vnu-jar if Java is available. - * Copyright 2017-2025 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -import { execFile, spawn } from 'node:child_process' -import vnu from 'vnu-jar' - -execFile('java', ['-version'], (error, stdout, stderr) => { - if (error) { - console.error('Skipping vnu-jar test; Java is probably missing.') - console.error(error) - return - } - - console.log('Running vnu-jar validation...') - - const is32bitJava = !/64-Bit/.test(stderr) - - // vnu-jar accepts multiple ignores joined with a `|`. - // Also note that the ignores are string regular expressions. - const ignores = [ - // "autocomplete" is included in