1
1
mirror of https://github.com/theoludwig/html-w3c-validator.git synced 2025-05-21 23:21:29 +02:00

6 Commits

22 changed files with 6669 additions and 16022 deletions

View File

@ -1,6 +1,6 @@
<!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. --> <!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. -->
## What changes this PR introduce? # What changes this PR introduce?
## List any relevant issue numbers ## List any relevant issue numbers

View File

@ -10,16 +10,18 @@ jobs:
build: build:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.0.0' - uses: 'actions/checkout@v3.5.2'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.1.0' uses: 'actions/setup-node@v3.6.0'
with: with:
node-version: 'lts/*' node-version: 'lts/*'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- name: 'Build' - name: 'Build'
run: 'npm run build' run: 'npm run build'
- run: 'npm run build:typescript'

View File

@ -10,19 +10,19 @@ jobs:
lint: lint:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.0.0' - uses: 'actions/checkout@v3.5.2'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.1.0' uses: 'actions/setup-node@v3.6.0'
with: with:
node-version: 'lts/*' node-version: 'lts/*'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- run: 'npm run lint:commit -- --to "${{ github.sha }}"' - run: 'npm run lint:commit -- --to "${{ github.sha }}"'
- run: 'npm run lint:editorconfig' - run: 'npm run lint:editorconfig'
- run: 'npm run lint:markdown' - run: 'npm run lint:markdown'
- run: 'npm run lint:typescript' - run: 'npm run lint:eslint'
- run: 'npm run lint:prettier' - run: 'npm run lint:prettier'

View File

@ -7,24 +7,34 @@ on:
jobs: jobs:
release: release:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
issues: 'write'
pull-requests: 'write'
id-token: 'write'
steps: steps:
- uses: 'actions/checkout@v3.0.0' - uses: 'actions/checkout@v3.5.2'
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.1.0' uses: 'actions/setup-node@v3.6.0'
with: with:
node-version: 'lts/*' node-version: 'lts/*'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- name: 'Build' - name: 'Build'
run: 'npm run build' run: 'npm run build'
- run: 'npm run build:typescript'
- name: 'Verify the integrity of provenance attestations and registry signatures for installed dependencies'
run: 'npm audit signatures'
- name: 'Release' - name: 'Release'
run: 'npm run release' run: 'npm run release'
env: env:

View File

@ -10,16 +10,16 @@ jobs:
test: test:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.0.0' - uses: 'actions/checkout@v3.5.2'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.1.0' uses: 'actions/setup-node@v3.6.0'
with: with:
node-version: 'lts/*' node-version: 'lts/*'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- name: 'Build' - name: 'Build'
run: 'npm run build' run: 'npm run build'

View File

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint:commit -- --edit

View File

@ -1,5 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint:staged
npm run build

11
.markdownlint-cli2.jsonc Normal file
View File

@ -0,0 +1,11 @@
{
"config": {
"extends": "markdownlint/style/prettier",
"relative-links": true,
"default": true,
"MD033": false
},
"globs": ["**/*.{md,mdx}"],
"ignores": ["**/node_modules"],
"customRules": ["markdownlint-rule-relative-links"]
}

View File

@ -1,6 +0,0 @@
{
"default": true,
"MD013": false,
"MD033": false,
"MD041": false
}

1
.npmrc
View File

@ -1 +1,2 @@
save-exact=true save-exact=true
provenance=true

View File

@ -3,7 +3,6 @@
"editorconfig.editorconfig", "editorconfig.editorconfig",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"davidanson.vscode-markdownlint", "davidanson.vscode-markdownlint"
"ms-azuretools.vscode-docker"
] ]
} }

View File

@ -6,5 +6,9 @@
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll": true "source.fixAll": true
} },
"eslint.options": {
"ignorePath": ".gitignore"
},
"prettier.ignorePath": ".gitignore"
} }

View File

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at reported to the community leaders responsible for enforcement at
contact@divlo.fr. <contact@divlo.fr>.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

View File

@ -2,6 +2,14 @@
Thanks a lot for your interest in contributing to **html-w3c-validator**! 🎉 Thanks a lot for your interest in contributing to **html-w3c-validator**! 🎉
## Code of Conduct
**html-w3c-validator** adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
## Open Development
All work on **html-w3c-validator** happens directly on this repository. Both core team members and external contributors send pull requests which go through the same review process.
## Types of contributions ## Types of contributions
- Reporting a bug. - Reporting a bug.
@ -21,26 +29,4 @@ If you're adding new features to **html-w3c-validator**, please include tests.
## Commits ## Commits
The commit message guidelines respect [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) and [Semantic Versioning](https://semver.org/) for releases. The commit message guidelines adheres to [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/) for releases.
### Types
Types define which kind of changes you made to the project.
| Types | Description |
| -------- | ------------------------------------------------------------------------------------------------------------ |
| feat | A new feature. |
| fix | A bug fix. |
| docs | Documentation only changes. |
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc). |
| refactor | A code change that neither fixes a bug nor adds a feature. |
| perf | A code change that improves performance. |
| test | Adding missing tests or correcting existing tests. |
| build | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm). |
| ci | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs). |
| chore | Other changes that don't modify src or test files. |
| revert | Reverts a previous commit. |
### Scopes
Scopes define what part of the code changed.

View File

@ -59,7 +59,7 @@ npm install --save-dev html-w3c-validator start-server-and-test
"start": "serve \"./build\"", "start": "serve \"./build\"",
// Command to validate your HTML pages // Command to validate your HTML pages
"test:html-w3c-validator": "start-server-and-test \"start\" \"http://localhost:3000\" \"html-w3c-validator\"" "test:html-w3c-validator": "start-server-and-test \"start\" \"http://127.0.0.1:3000\" \"html-w3c-validator\""
} }
} }
``` ```
@ -68,7 +68,7 @@ npm install --save-dev html-w3c-validator start-server-and-test
```jsonc ```jsonc
{ {
"urls": ["http://localhost:3000/", "http://localhost:3000/about"], "urls": ["http://127.0.0.1:3000/", "http://127.0.0.1:3000/about"],
// You can also specify HTML files instead of URLs // You can also specify HTML files instead of URLs
"files": ["./index.html", "./about.html"] "files": ["./index.html", "./about.html"]
@ -84,8 +84,8 @@ npm run test:html-w3c-validator
Example of output (in case of success): Example of output (in case of success):
```txt ```txt
✔ Validating http://localhost:3000/ ✔ Validating http://127.0.0.1:3000/
✔ Validating http://localhost:3000/about ✔ Validating http://127.0.0.1:3000/about
Success: HTML validation (W3C) passed! 🎉 Success: HTML validation (W3C) passed! 🎉
``` ```

View File

@ -1,4 +1,4 @@
{ {
"urls": ["http://localhost:3000/", "http://localhost:3000/about"], "urls": ["http://127.0.0.1:3000/", "http://127.0.0.1:3000/about"],
"files": ["./build/index.html", "./build/about.html"] "files": ["./build/index.html", "./build/about.html"]
} }

2260
example/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,11 +3,11 @@
"private": true, "private": true,
"scripts": { "scripts": {
"start": "serve \"./build\"", "start": "serve \"./build\"",
"test:html-w3c-validator": "start-server-and-test \"start\" \"http://localhost:3000\" \"html-w3c-validator\"" "test:html-w3c-validator": "start-server-and-test \"start\" \"http://127.0.0.1:3000\" \"html-w3c-validator\""
}, },
"devDependencies": { "devDependencies": {
"serve": "13.0.2", "serve": "14.2.0",
"start-server-and-test": "1.14.0", "start-server-and-test": "2.0.0",
"html-w3c-validator": "file:.." "html-w3c-validator": "file:.."
} }
} }

20048
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,64 +22,67 @@
], ],
"main": "build/index.js", "main": "build/index.js",
"bin": "build/index.js", "bin": "build/index.js",
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"files": [ "files": [
"build" "build"
], ],
"publishConfig": {
"access": "public",
"provenance": true
},
"engines": {
"node": ">=16.0.0",
"npm": ">=9.0.0"
},
"scripts": { "scripts": {
"build": "rimraf ./build && swc ./src --out-dir ./build && tsc", "build": "rimraf ./build && swc ./src --out-dir ./build",
"build:typescript": "tsc",
"lint:commit": "commitlint", "lint:commit": "commitlint",
"lint:editorconfig": "editorconfig-checker", "lint:editorconfig": "editorconfig-checker",
"lint:markdown": "markdownlint \"**/*.md\" --dot --ignore-path \".gitignore\"", "lint:markdown": "markdownlint-cli2",
"lint:typescript": "eslint \"**/*.{js,jsx,ts,tsx}\" --ignore-path \".gitignore\"", "lint:eslint": "eslint \".\" --ignore-path \".gitignore\"",
"lint:prettier": "prettier \".\" --check --ignore-path \".gitignore\"", "lint:prettier": "prettier \".\" --check --ignore-path \".gitignore\"",
"lint:staged": "lint-staged", "lint:staged": "lint-staged",
"test": "tap", "test": "tap",
"release": "semantic-release", "release": "semantic-release"
"postinstall": "husky install",
"prepublishOnly": "pinst --disable",
"postpublish": "pinst --enable"
}, },
"dependencies": { "dependencies": {
"chalk": "5.0.1", "chalk": "5.2.0",
"clipanion": "3.1.0", "clipanion": "3.2.0",
"html-validator": "6.0.0", "html-validator": "6.0.1",
"ora": "6.1.0", "log-symbols": "5.1.0",
"read-pkg": "7.1.0", "ora": "6.3.0",
"table": "6.8.0" "read-pkg": "8.0.0",
"table": "6.8.1"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "16.2.3", "@commitlint/cli": "17.6.3",
"@commitlint/config-conventional": "16.2.1", "@commitlint/config-conventional": "17.6.3",
"@swc/cli": "0.1.57", "@swc/cli": "0.1.62",
"@swc/core": "1.2.163", "@swc/core": "1.3.57",
"@types/html-validator": "5.0.2", "@tsconfig/strictest": "2.0.1",
"@types/html-validator": "5.0.3",
"@types/mock-fs": "4.13.1", "@types/mock-fs": "4.13.1",
"@types/node": "17.0.23", "@types/node": "20.1.3",
"@types/tap": "15.0.6", "@types/tap": "15.0.8",
"@typescript-eslint/eslint-plugin": "5.18.0", "@typescript-eslint/eslint-plugin": "5.59.5",
"editorconfig-checker": "4.0.2", "editorconfig-checker": "5.0.1",
"eslint": "8.12.0", "eslint": "8.40.0",
"eslint-config-conventions": "2.0.0", "eslint-config-conventions": "9.0.0",
"eslint-config-prettier": "8.5.0", "eslint-config-prettier": "8.8.0",
"eslint-plugin-import": "2.26.0", "eslint-plugin-import": "2.27.5",
"eslint-plugin-prettier": "4.0.0", "eslint-plugin-prettier": "4.2.1",
"eslint-plugin-promise": "6.0.0", "eslint-plugin-promise": "6.1.1",
"eslint-plugin-unicorn": "42.0.0", "eslint-plugin-unicorn": "47.0.0",
"execa": "6.1.0", "execa": "7.1.1",
"husky": "7.0.4", "lint-staged": "13.2.2",
"lint-staged": "12.3.7", "markdownlint-cli2": "0.7.1",
"markdownlint-cli": "0.31.1", "markdownlint-rule-relative-links": "1.2.0",
"mock-fs": "5.1.2", "mock-fs": "5.2.0",
"pinst": "3.0.0", "prettier": "2.8.8",
"prettier": "2.6.2", "rimraf": "5.0.0",
"rimraf": "3.0.2", "semantic-release": "21.0.2",
"semantic-release": "19.0.2", "serve": "14.2.0",
"serve": "13.0.2", "tap": "16.3.4",
"tap": "16.0.1", "typescript": "5.0.4"
"typescript": "4.6.3"
} }
} }

View File

@ -4,10 +4,12 @@ import fs from 'node:fs'
import { Command } from 'clipanion' import { Command } from 'clipanion'
import chalk from 'chalk' import chalk from 'chalk'
import ora from 'ora' import ora from 'ora'
import validateHTML, { import logSymbols from 'log-symbols'
import type {
ValidationMessageLocationObject, ValidationMessageLocationObject,
ParsedJsonAsValidationResults ParsedJsonAsValidationResults
} from 'html-validator' } from 'html-validator'
import validateHTML from 'html-validator'
import { table } from 'table' import { table } from 'table'
import { isExistingPath } from './utils/isExistingPath.js' import { isExistingPath } from './utils/isExistingPath.js'
@ -25,13 +27,28 @@ interface Error {
messagesTable: string[][] messagesTable: string[][]
} }
interface Result {
data: string
isSuccess: boolean
}
const printResults = (results: Result[]): void => {
for (const result of results) {
if (result.isSuccess) {
console.log(logSymbols.success, result.data)
} else {
console.log(logSymbols.error, result.data)
}
}
}
export class HTMLValidatorCommand extends Command { export class HTMLValidatorCommand extends Command {
static usage = { static override usage = {
description: description:
'CLI for validating multiple html pages using <https://validator.w3.org/>.' 'CLI for validating multiple html pages using <https://validator.w3.org/>.'
} }
async execute(): Promise<number> { public async execute(): Promise<number> {
const configPath = path.join(CURRENT_DIRECTORY, CONFIG_FILE_NAME) const configPath = path.join(CURRENT_DIRECTORY, CONFIG_FILE_NAME)
try { try {
if (!(await isExistingPath(configPath))) { if (!(await isExistingPath(configPath))) {
@ -39,7 +56,6 @@ export class HTMLValidatorCommand extends Command {
`No config file found at ${configPath}. Please create ${CONFIG_FILE_NAME}.` `No config file found at ${configPath}. Please create ${CONFIG_FILE_NAME}.`
) )
} }
const configData = await fs.promises.readFile(configPath, { const configData = await fs.promises.readFile(configPath, {
encoding: 'utf-8' encoding: 'utf-8'
}) })
@ -73,8 +89,10 @@ export class HTMLValidatorCommand extends Command {
const dataToValidate = [...urls, ...files] const dataToValidate = [...urls, ...files]
const errors: Error[] = [] const errors: Error[] = []
let isValid = true let isValid = true
for (const { data, type } of dataToValidate) { const loader = ora(`Validating HTML (W3C)...`).start()
const loader = ora(`Validating ${data}`).start() const results: Result[] = []
await Promise.all(
dataToValidate.map(async ({ data, type }) => {
try { try {
const options = { const options = {
format: 'json' as 'json' | undefined format: 'json' as 'json' | undefined
@ -103,19 +121,18 @@ export class HTMLValidatorCommand extends Command {
} else { } else {
throw new Error('Invalid type') throw new Error('Invalid type')
} }
const isValidHTML = result.messages.length === 0 const hasErrors = result.messages.some((message) => {
if (isValidHTML) { return message.type === 'error'
loader.succeed() })
if (!hasErrors) {
results.push({ data, isSuccess: true })
} else { } else {
loader.fail() results.push({ data, isSuccess: false })
const messagesTable: string[][] = [] const messagesTable: string[][] = []
for (const message of result.messages) { for (const message of result.messages) {
const row: string[] = []
if (message.type === 'error') { if (message.type === 'error') {
const row: string[] = []
row.push(chalk.red(message.type)) row.push(chalk.red(message.type))
} else {
row.push(chalk.yellow(message.type))
}
row.push(message.message) row.push(message.message)
const violation = message as ValidationMessageLocationObject const violation = message as ValidationMessageLocationObject
if (violation.extract != null) { if (violation.extract != null) {
@ -125,20 +142,22 @@ export class HTMLValidatorCommand extends Command {
} }
messagesTable.push(row) messagesTable.push(row)
} }
}
errors.push({ data, messagesTable }) errors.push({ data, messagesTable })
isValid = false isValid = false
} }
} catch (error) { } catch (error) {
loader.fail()
isValid = false isValid = false
if (error instanceof Error) { if (error instanceof Error) {
const messagesTable: string[][] = [[error.message]] const messagesTable: string[][] = [[error.message]]
errors.push({ data, messagesTable }) errors.push({ data, messagesTable })
} }
} }
} })
)
if (!isValid) { if (!isValid) {
loader.fail()
printResults(results)
for (const error of errors) { for (const error of errors) {
console.error(`\n${error.data}`) console.error(`\n${error.data}`)
console.error(table(error.messagesTable)) console.error(table(error.messagesTable))
@ -147,10 +166,10 @@ export class HTMLValidatorCommand extends Command {
console.error() console.error()
throw new Error('HTML validation (W3C) failed!') throw new Error('HTML validation (W3C) failed!')
} }
console.log() loader.succeed(
console.log(
`${chalk.bold.green('Success:')} HTML validation (W3C) passed! 🎉` `${chalk.bold.green('Success:')} HTML validation (W3C) passed! 🎉`
) )
printResults(results)
return 0 return 0
} catch (error) { } catch (error) {
if (error instanceof Error) { if (error instanceof Error) {

View File

@ -1,4 +1,5 @@
{ {
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"module": "ESNext", "module": "ESNext",
@ -7,8 +8,6 @@
"outDir": "./build", "outDir": "./build",
"rootDir": "./src", "rootDir": "./src",
"noEmit": true, "noEmit": true,
"strict": true, "exactOptionalPropertyTypes": false
"skipLibCheck": true,
"esModuleInterop": true
} }
} }