mirror of https://github.com/twbs/bootstrap.git
				
				
				
			
							parent
							
								
									f94bcbe321
								
							
						
					
					
						commit
						6b8a1bb203
					
				| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			@ -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 <button> and checkboxes and radio <input>s due to
 | 
			
		||||
    // Firefox's non-standard autocomplete behavior - see https://bugzilla.mozilla.org/show_bug.cgi?id=654072
 | 
			
		||||
    'Attribute “autocomplete” is only allowed when the input type is.*',
 | 
			
		||||
    'Attribute “autocomplete” not allowed on element “button” at this point.',
 | 
			
		||||
    // Per https://www.w3.org/TR/html-aria/#docconformance having "aria-disabled" on a link is
 | 
			
		||||
    // NOT RECOMMENDED, but it's still valid - we explain in the docs that it's not ideal,
 | 
			
		||||
    // and offer more robust alternatives, but also need to show a less-than-ideal example
 | 
			
		||||
    'An “aria-disabled” attribute whose value is “true” should not be specified on an “a” element that has an “href” attribute.',
 | 
			
		||||
    // A `code` element with the `is:raw` attribute coming from remark-prismjs (Astro upstream possible bug)
 | 
			
		||||
    'Attribute “is:raw” is not serializable as XML 1.0.',
 | 
			
		||||
    'Attribute “is:raw” not allowed on element “code” at this point.',
 | 
			
		||||
    // Astro's expecting trailing slashes on HTML tags such as <br />
 | 
			
		||||
    'Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.',
 | 
			
		||||
    // Allow `switch` attribute.
 | 
			
		||||
    'Attribute “switch” not allowed on element “input” at this point.'
 | 
			
		||||
  ].join('|')
 | 
			
		||||
 | 
			
		||||
  const args = [
 | 
			
		||||
    '-jar',
 | 
			
		||||
    `"${vnu}"`,
 | 
			
		||||
    '--asciiquotes',
 | 
			
		||||
    '--skip-non-html',
 | 
			
		||||
    '--Werror',
 | 
			
		||||
    `--filterpattern "${ignores}"`,
 | 
			
		||||
    '_site/',
 | 
			
		||||
    'js/tests/'
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  // For the 32-bit Java we need to pass `-Xss512k`
 | 
			
		||||
  if (is32bitJava) {
 | 
			
		||||
    args.splice(0, 0, '-Xss512k')
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  console.log(`command used: java ${args.join(' ')}`)
 | 
			
		||||
 | 
			
		||||
  return spawn('java', args, {
 | 
			
		||||
    shell: true,
 | 
			
		||||
    stdio: 'inherit'
 | 
			
		||||
  })
 | 
			
		||||
    .on('exit', process.exit)
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +54,7 @@
 | 
			
		|||
        "github-slugger": "^2.0.0",
 | 
			
		||||
        "globby": "^15.0.0",
 | 
			
		||||
        "hammer-simulator": "0.0.1",
 | 
			
		||||
        "html-validate": "^8.24.1",
 | 
			
		||||
        "htmlparser2": "^10.0.0",
 | 
			
		||||
        "image-size": "^2.0.2",
 | 
			
		||||
        "ip": "^2.0.1",
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +91,6 @@
 | 
			
		|||
        "stylelint-config-twbs-bootstrap": "^16.1.0",
 | 
			
		||||
        "terser": "^5.44.0",
 | 
			
		||||
        "unist-util-visit": "^5.0.0",
 | 
			
		||||
        "vnu-jar": "24.10.17",
 | 
			
		||||
        "zod": "^4.1.12"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2985,6 +2985,18 @@
 | 
			
		|||
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@html-validate/stylish": {
 | 
			
		||||
      "version": "4.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@html-validate/stylish/-/stylish-4.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-eUfvKpRJg5TvzSfTf2EovrQoTKjkRnPUOUnXVJ2cQ4GbC/bQw98oxN+DdSf+HxOBK00YOhsP52xWdJPV1o4n5w==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "kleur": "^4.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 18"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@humanwhocodes/config-array": {
 | 
			
		||||
      "version": "0.13.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -3579,7 +3591,6 @@
 | 
			
		|||
      "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -3589,22 +3600,22 @@
 | 
			
		|||
      "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@jest/schemas": {
 | 
			
		||||
      "version": "30.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
 | 
			
		||||
      "version": "29.6.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
 | 
			
		||||
      "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@sinclair/typebox": "^0.34.0"
 | 
			
		||||
        "@sinclair/typebox": "^0.27.8"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@jridgewell/gen-mapping": {
 | 
			
		||||
| 
						 | 
				
			
			@ -4651,12 +4662,28 @@
 | 
			
		|||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@sinclair/typebox": {
 | 
			
		||||
      "version": "0.34.41",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
 | 
			
		||||
      "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
 | 
			
		||||
    "node_modules/@sidvind/better-ajv-errors": {
 | 
			
		||||
      "version": "3.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@sidvind/better-ajv-errors/-/better-ajv-errors-3.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-++1mEYIeozfnwWI9P1ECvOPoacy+CgDASrmGvXPMCcqgx0YUzB01vZ78uHdQ443V6sTY+e9MzHqmN9DOls02aw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "kleur": "^4.1.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 16.14"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "ajv": "^6.12.3 || ^7.0.0 || ^8.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@sinclair/typebox": {
 | 
			
		||||
      "version": "0.27.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
 | 
			
		||||
      "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@sindresorhus/merge-streams": {
 | 
			
		||||
      "version": "4.0.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -7226,6 +7253,17 @@
 | 
			
		|||
        "node": ">=0.3.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/diff-sequences": {
 | 
			
		||||
      "version": "29.6.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
 | 
			
		||||
      "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/dir-glob": {
 | 
			
		||||
      "version": "3.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -9708,6 +9746,132 @@
 | 
			
		|||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-validate": {
 | 
			
		||||
      "version": "8.29.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/html-validate/-/html-validate-8.29.0.tgz",
 | 
			
		||||
      "integrity": "sha512-RFfFIWaUB9SN8iETL2GoPvjWEX1gcbz0+m+vao7xkPl0cnlgMDu9RcjdQz6T3n6LgT/LENPkvxHzVkqY/Qs3Tg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "funding": [
 | 
			
		||||
        {
 | 
			
		||||
          "type": "github",
 | 
			
		||||
          "url": "https://github.com/sponsors/html-validate"
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@html-validate/stylish": "^4.1.0",
 | 
			
		||||
        "@sidvind/better-ajv-errors": "3.0.1",
 | 
			
		||||
        "ajv": "^8.0.0",
 | 
			
		||||
        "glob": "^10.0.0",
 | 
			
		||||
        "kleur": "^4.1.0",
 | 
			
		||||
        "minimist": "^1.2.0",
 | 
			
		||||
        "prompts": "^2.0.0",
 | 
			
		||||
        "semver": "^7.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "html-validate": "bin/html-validate.js"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 16.14"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "jest": "^27.1 || ^28.1.3 || ^29.0.3",
 | 
			
		||||
        "jest-diff": "^27.1 || ^28.1.3 || ^29.0.3",
 | 
			
		||||
        "jest-snapshot": "^27.1 || ^28.1.3 || ^29.0.3",
 | 
			
		||||
        "vitest": "^0.34.0 || ^1.0.0 || ^2.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependenciesMeta": {
 | 
			
		||||
        "jest": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        },
 | 
			
		||||
        "jest-diff": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        },
 | 
			
		||||
        "jest-snapshot": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        },
 | 
			
		||||
        "vitest": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-validate/node_modules/ajv": {
 | 
			
		||||
      "version": "8.17.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
 | 
			
		||||
      "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "fast-deep-equal": "^3.1.3",
 | 
			
		||||
        "fast-uri": "^3.0.1",
 | 
			
		||||
        "json-schema-traverse": "^1.0.0",
 | 
			
		||||
        "require-from-string": "^2.0.2"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "type": "github",
 | 
			
		||||
        "url": "https://github.com/sponsors/epoberezkin"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-validate/node_modules/brace-expansion": {
 | 
			
		||||
      "version": "2.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "balanced-match": "^1.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-validate/node_modules/glob": {
 | 
			
		||||
      "version": "10.4.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
 | 
			
		||||
      "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "foreground-child": "^3.1.0",
 | 
			
		||||
        "jackspeak": "^3.1.2",
 | 
			
		||||
        "minimatch": "^9.0.4",
 | 
			
		||||
        "minipass": "^7.1.2",
 | 
			
		||||
        "package-json-from-dist": "^1.0.0",
 | 
			
		||||
        "path-scurry": "^1.11.1"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "glob": "dist/esm/bin.mjs"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/isaacs"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-validate/node_modules/json-schema-traverse": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-validate/node_modules/minimatch": {
 | 
			
		||||
      "version": "9.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "brace-expansion": "^2.0.1"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=16 || 14 >=14.17"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/isaacs"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-validate/node_modules/semver": {
 | 
			
		||||
      "version": "7.7.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
 | 
			
		||||
      "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "semver": "bin/semver.js"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=10"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/html-void-elements": {
 | 
			
		||||
      "version": "3.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -10853,19 +11017,20 @@
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/jest-diff": {
 | 
			
		||||
      "version": "30.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==",
 | 
			
		||||
      "version": "29.7.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
 | 
			
		||||
      "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@jest/diff-sequences": "30.0.1",
 | 
			
		||||
        "@jest/get-type": "30.1.0",
 | 
			
		||||
        "chalk": "^4.1.2",
 | 
			
		||||
        "pretty-format": "30.2.0"
 | 
			
		||||
        "chalk": "^4.0.0",
 | 
			
		||||
        "diff-sequences": "^29.6.3",
 | 
			
		||||
        "jest-get-type": "^29.6.3",
 | 
			
		||||
        "pretty-format": "^29.7.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/jest-diff/node_modules/ansi-styles": {
 | 
			
		||||
| 
						 | 
				
			
			@ -10874,6 +11039,8 @@
 | 
			
		|||
      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "color-convert": "^2.0.1"
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -10890,6 +11057,8 @@
 | 
			
		|||
      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "ansi-styles": "^4.1.0",
 | 
			
		||||
        "supports-color": "^7.1.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -10901,6 +11070,17 @@
 | 
			
		|||
        "url": "https://github.com/chalk/chalk?sponsor=1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/jest-get-type": {
 | 
			
		||||
      "version": "29.6.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
 | 
			
		||||
      "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/js-tokens": {
 | 
			
		||||
      "version": "4.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -15556,18 +15736,19 @@
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/pretty-format": {
 | 
			
		||||
      "version": "30.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
 | 
			
		||||
      "version": "29.7.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
 | 
			
		||||
      "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@jest/schemas": "30.0.5",
 | 
			
		||||
        "ansi-styles": "^5.2.0",
 | 
			
		||||
        "react-is": "^18.3.1"
 | 
			
		||||
        "@jest/schemas": "^29.6.3",
 | 
			
		||||
        "ansi-styles": "^5.0.0",
 | 
			
		||||
        "react-is": "^18.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/pretty-format/node_modules/ansi-styles": {
 | 
			
		||||
| 
						 | 
				
			
			@ -15575,7 +15756,8 @@
 | 
			
		|||
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=10"
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -15784,8 +15966,7 @@
 | 
			
		|||
      "version": "18.3.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
 | 
			
		||||
      "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/read-cache": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -16954,6 +17135,96 @@
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sass-true/node_modules/@jest/schemas": {
 | 
			
		||||
      "version": "30.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@sinclair/typebox": "^0.34.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sass-true/node_modules/@sinclair/typebox": {
 | 
			
		||||
      "version": "0.34.41",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
 | 
			
		||||
      "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sass-true/node_modules/ansi-styles": {
 | 
			
		||||
      "version": "4.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "color-convert": "^2.0.1"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=8"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sass-true/node_modules/chalk": {
 | 
			
		||||
      "version": "4.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
 | 
			
		||||
      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "ansi-styles": "^4.1.0",
 | 
			
		||||
        "supports-color": "^7.1.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=10"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/chalk/chalk?sponsor=1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sass-true/node_modules/jest-diff": {
 | 
			
		||||
      "version": "30.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.1.2.tgz",
 | 
			
		||||
      "integrity": "sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@jest/diff-sequences": "30.0.1",
 | 
			
		||||
        "@jest/get-type": "30.1.0",
 | 
			
		||||
        "chalk": "^4.1.2",
 | 
			
		||||
        "pretty-format": "30.0.5"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sass-true/node_modules/pretty-format": {
 | 
			
		||||
      "version": "30.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@jest/schemas": "30.0.5",
 | 
			
		||||
        "ansi-styles": "^5.2.0",
 | 
			
		||||
        "react-is": "^18.3.1"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sass-true/node_modules/pretty-format/node_modules/ansi-styles": {
 | 
			
		||||
      "version": "5.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=10"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/sax": {
 | 
			
		||||
      "version": "1.4.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -19499,16 +19770,6 @@
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/vnu-jar": {
 | 
			
		||||
      "version": "24.10.17",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vnu-jar/-/vnu-jar-24.10.17.tgz",
 | 
			
		||||
      "integrity": "sha512-YT7gNrRY5PiJrI1GavlWRHWIwqq2o52COc6J9QeXPfoldKRiZ9BeGP4shNLLaVfi0naA+/LMksdYWkKCr4pnVg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.10"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/void-elements": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,8 +77,8 @@
 | 
			
		|||
    "docs": "npm-run-all docs-build docs-lint",
 | 
			
		||||
    "docs-build": "npm run astro-build",
 | 
			
		||||
    "docs-compile": "npm run docs-build",
 | 
			
		||||
    "docs-vnu": "node build/vnu-jar.mjs",
 | 
			
		||||
    "docs-lint": "npm-run-all docs-prettier-check docs-vnu",
 | 
			
		||||
    "docs-html-validate": "node build/html-validate.mjs",
 | 
			
		||||
    "docs-lint": "npm-run-all docs-prettier-check docs-html-validate",
 | 
			
		||||
    "docs-prettier-check": "prettier --config site/.prettierrc.json -c --cache site",
 | 
			
		||||
    "docs-prettier-format": "prettier --config site/.prettierrc.json --write --cache site",
 | 
			
		||||
    "docs-serve": "npm run astro-dev",
 | 
			
		||||
| 
						 | 
				
			
			@ -143,6 +143,7 @@
 | 
			
		|||
    "github-slugger": "^2.0.0",
 | 
			
		||||
    "globby": "^15.0.0",
 | 
			
		||||
    "hammer-simulator": "0.0.1",
 | 
			
		||||
    "html-validate": "^8.24.1",
 | 
			
		||||
    "htmlparser2": "^10.0.0",
 | 
			
		||||
    "image-size": "^2.0.2",
 | 
			
		||||
    "ip": "^2.0.1",
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +180,6 @@
 | 
			
		|||
    "stylelint-config-twbs-bootstrap": "^16.1.0",
 | 
			
		||||
    "terser": "^5.44.0",
 | 
			
		||||
    "unist-util-visit": "^5.0.0",
 | 
			
		||||
    "vnu-jar": "24.10.17",
 | 
			
		||||
    "zod": "^4.1.12"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue