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

7 Commits

37 changed files with 10573 additions and 38187 deletions

View File

@ -1,2 +0,0 @@
ARG VARIANT="16"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}

View File

@ -1,15 +0,0 @@
{
"name": "html-w3c-validator",
"dockerComposeFile": "./docker-compose.yml",
"service": "workspace",
"workspaceFolder": "/workspace",
"extensions": [
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"davidanson.vscode-markdownlint",
"ms-azuretools.vscode-docker"
],
"postAttachCommand": ["npm", "install"],
"remoteUser": "node"
}

View File

@ -1,10 +0,0 @@
version: '3.0'
services:
workspace:
build:
context: './'
dockerfile: './Dockerfile'
volumes:
- '..:/workspace:cached'
command: 'sleep infinity'

View File

@ -5,12 +5,12 @@
"project": "./tsconfig.json" "project": "./tsconfig.json"
}, },
"env": { "env": {
"node": true, "node": true
"jest": true
}, },
"rules": { "rules": {
"prettier/prettier": "error", "prettier/prettier": "error",
"import/extensions": ["error", "always"], "import/extensions": ["error", "always"],
"unicorn/prevent-abbreviations": "error" "unicorn/prevent-abbreviations": "error",
"unicorn/prefer-node-protocol": "error"
} }
} }

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@v2' - uses: 'actions/checkout@v3.5.2'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v2.5.1' 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@v2' - uses: 'actions/checkout@v3.5.2'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v2.5.1' 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@v2.3.4' - 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@v2.5.1' 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@v2' - uses: 'actions/checkout@v3.5.2'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v2.5.1' 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'

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ node_modules
# testing # testing
coverage coverage
.nyc_output
# envs # envs
.env .env

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

View File

@ -1,10 +1,6 @@
{ {
"*": ["editorconfig-checker"], "*": ["editorconfig-checker"],
"*.{js,ts,jsx,tsx}": [ "*.{js,ts,jsx,tsx}": ["prettier --write", "eslint --fix"],
"prettier --write",
"eslint --fix",
"jest --findRelatedTests"
],
"*.{yml,json}": ["prettier --write"], "*.{yml,json}": ["prettier --write"],
"*.md": ["prettier --write", "markdownlint --dot --fix"] "*.md": ["prettier --write", "markdownlint --dot --fix"]
} }

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

2
.swcrc
View File

@ -13,7 +13,7 @@
"loose": true "loose": true
}, },
"module": { "module": {
"type": "commonjs", "type": "es6",
"strict": false, "strict": false,
"strictMode": true, "strictMode": true,
"lazy": false, "lazy": false,

9
.taprc Normal file
View File

@ -0,0 +1,9 @@
ts: false
jsx: false
flow: false
check-coverage: false
coverage: false
timeout: 120000
files:
- 'build/**/*.test.js'

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"]
} }

23157
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:.."
} }
} }

View File

@ -1,9 +0,0 @@
{
"testEnvironment": "node",
"resolver": "jest-ts-webcompat-resolver",
"transform": {
"^.+\\.(t|j)sx?$": ["@swc/jest"]
},
"rootDir": "./src",
"setupFiles": ["<rootDir>/__test__/setup.ts"]
}

25074
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
"version": "0.0.0-development", "version": "0.0.0-development",
"public": true, "public": true,
"description": "CLI for validating multiple html pages using validator.w3.org.", "description": "CLI for validating multiple html pages using validator.w3.org.",
"type": "module",
"author": "Divlo <contact@divlo.fr>", "author": "Divlo <contact@divlo.fr>",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -21,67 +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": "jest", "test": "tap",
"release": "semantic-release", "release": "semantic-release"
"postinstall": "husky install",
"prepublishOnly": "pinst --disable",
"postpublish": "pinst --enable"
}, },
"dependencies": { "dependencies": {
"chalk": "4.1.2", "chalk": "5.2.0",
"clipanion": "3.1.0", "clipanion": "3.2.0",
"html-validator": "6.0.0", "html-validator": "6.0.1",
"ora": "5.4.1", "log-symbols": "5.1.0",
"read-pkg": "5.2.0", "ora": "6.3.0",
"table": "6.8.0" "read-pkg": "8.0.0",
"table": "6.8.1"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "16.2.1", "@commitlint/cli": "17.6.3",
"@commitlint/config-conventional": "16.2.1", "@commitlint/config-conventional": "17.6.3",
"@swc/cli": "0.1.55", "@swc/cli": "0.1.62",
"@swc/core": "1.2.144", "@swc/core": "1.3.57",
"@swc/jest": "0.2.17", "@tsconfig/strictest": "2.0.1",
"@types/html-validator": "5.0.2", "@types/html-validator": "5.0.3",
"@types/jest": "27.4.1",
"@types/mock-fs": "4.13.1", "@types/mock-fs": "4.13.1",
"@types/node": "17.0.21", "@types/node": "20.1.3",
"@typescript-eslint/eslint-plugin": "5.12.1", "@types/tap": "15.0.8",
"editorconfig-checker": "4.0.2", "@typescript-eslint/eslint-plugin": "5.59.5",
"eslint": "8.9.0", "editorconfig-checker": "5.0.1",
"eslint-config-conventions": "1.1.0", "eslint": "8.40.0",
"eslint-config-prettier": "8.4.0", "eslint-config-conventions": "9.0.0",
"eslint-plugin-import": "2.25.4", "eslint-config-prettier": "8.8.0",
"eslint-plugin-prettier": "4.0.0", "eslint-plugin-import": "2.27.5",
"eslint-plugin-promise": "6.0.0", "eslint-plugin-prettier": "4.2.1",
"eslint-plugin-unicorn": "41.0.0", "eslint-plugin-promise": "6.1.1",
"execa": "5.1.1", "eslint-plugin-unicorn": "47.0.0",
"husky": "7.0.4", "execa": "7.1.1",
"jest": "27.5.1", "lint-staged": "13.2.2",
"jest-mock-extended": "2.0.4", "markdownlint-cli2": "0.7.1",
"jest-ts-webcompat-resolver": "1.0.0", "markdownlint-rule-relative-links": "1.2.0",
"lint-staged": "12.3.4", "mock-fs": "5.2.0",
"markdownlint-cli": "0.31.1", "prettier": "2.8.8",
"mock-fs": "5.1.2", "rimraf": "5.0.0",
"pinst": "3.0.0", "semantic-release": "21.0.2",
"prettier": "2.5.1", "serve": "14.2.0",
"rimraf": "3.0.2", "tap": "16.3.4",
"semantic-release": "19.0.2", "typescript": "5.0.4"
"serve": "13.0.2",
"typescript": "4.5.5"
} }
} }

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,72 +89,75 @@ 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[] = []
try { await Promise.all(
const options = { dataToValidate.map(async ({ data, type }) => {
format: 'json' as 'json' | undefined try {
} const options = {
let result: ParsedJsonAsValidationResults | undefined format: 'json' as 'json' | undefined
if (type === 'url') {
result = await validateHTML({
url: data,
isLocal: true,
...options
})
} else if (type === 'file') {
const htmlPath = path.resolve(CURRENT_DIRECTORY, data)
if (!(await isExistingPath(htmlPath))) {
throw new Error(
`No file found at ${htmlPath}. Please check the path.`
)
} }
const html = await fs.promises.readFile(htmlPath, { let result: ParsedJsonAsValidationResults | undefined
encoding: 'utf-8' if (type === 'url') {
}) result = await validateHTML({
result = await validateHTML({ url: data,
data: html, isLocal: true,
...options ...options
}) })
} else { } else if (type === 'file') {
throw new Error('Invalid type') const htmlPath = path.resolve(CURRENT_DIRECTORY, data)
} if (!(await isExistingPath(htmlPath))) {
const isValidHTML = result.messages.length === 0 throw new Error(
if (isValidHTML) { `No file found at ${htmlPath}. Please check the path.`
loader.succeed()
} else {
loader.fail()
const messagesTable: string[][] = []
for (const message of result.messages) {
const row: string[] = []
if (message.type === 'error') {
row.push(chalk.red(message.type))
} else {
row.push(chalk.yellow(message.type))
}
row.push(message.message)
const violation = message as ValidationMessageLocationObject
if (violation.extract != null) {
row.push(
`line: ${violation.lastLine}, column: ${violation.firstColumn}-${violation.lastColumn}`
) )
} }
messagesTable.push(row) const html = await fs.promises.readFile(htmlPath, {
encoding: 'utf-8'
})
result = await validateHTML({
data: html,
...options
})
} else {
throw new Error('Invalid type')
} }
errors.push({ data, messagesTable }) const hasErrors = result.messages.some((message) => {
return message.type === 'error'
})
if (!hasErrors) {
results.push({ data, isSuccess: true })
} else {
results.push({ data, isSuccess: false })
const messagesTable: string[][] = []
for (const message of result.messages) {
if (message.type === 'error') {
const row: string[] = []
row.push(chalk.red(message.type))
row.push(message.message)
const violation = message as ValidationMessageLocationObject
if (violation.extract != null) {
row.push(
`line: ${violation.lastLine}, column: ${violation.firstColumn}-${violation.lastColumn}`
)
}
messagesTable.push(row)
}
}
errors.push({ data, messagesTable })
isValid = false
}
} catch (error) {
isValid = false isValid = false
if (error instanceof Error) {
const messagesTable: string[][] = [[error.message]]
errors.push({ data, messagesTable })
}
} }
} catch (error) { })
loader.fail() )
isValid = false
if (error instanceof Error) {
const messagesTable: string[][] = [[error.message]]
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,26 +1,21 @@
import path from 'node:path' import tap from 'tap'
import { execa } from 'execa'
import execa from 'execa'
import { cli } from '../cli.js' import { cli } from '../cli.js'
import { HTMLValidatorCommand } from '../HTMLValidatorCommand.js' import { HTMLValidatorCommand } from '../HTMLValidatorCommand.js'
describe('html-w3c-validator', () => { await tap.test('html-w3c-validator', async (t) => {
afterEach(() => { await t.test('should be instance of the command', async (t) => {
jest.clearAllMocks()
})
it('should be instance of the command', () => {
const command = cli.process([]) const command = cli.process([])
expect(command).toBeInstanceOf(HTMLValidatorCommand) t.equal(command instanceof HTMLValidatorCommand, true)
}) })
it('succeeds and validate the html correctly', async () => { await t.test('succeeds and validate the html correctly', async (t) => {
const examplePath = path.join(__dirname, '..', '..', 'example') const exampleURL = new URL('../../example', import.meta.url)
process.chdir(examplePath) process.chdir(exampleURL.pathname)
await execa('rimraf', ['node_modules']) await execa('rimraf', ['node_modules'])
await execa('npm', ['install']) await execa('npm', ['install'])
const { exitCode } = await execa('npm', ['run', 'test:html-w3c-validator']) const { exitCode } = await execa('npm', ['run', 'test:html-w3c-validator'])
expect(exitCode).toEqual(0) t.equal(exitCode, 0)
}) })
}) })

View File

@ -1 +0,0 @@
jest.setTimeout(60000)

View File

@ -1,11 +1,7 @@
import path from 'node:path'
import { Builtins, Cli } from 'clipanion' import { Builtins, Cli } from 'clipanion'
import readPackage from 'read-pkg'
import { HTMLValidatorCommand } from './HTMLValidatorCommand.js' import { HTMLValidatorCommand } from './HTMLValidatorCommand.js'
import { packageJSON } from './packageJSON.js'
const packageJSON = readPackage.sync({ cwd: path.join(__dirname, '..') })
export const cli = new Cli({ export const cli = new Cli({
binaryLabel: packageJSON.name, binaryLabel: packageJSON.name,

View File

@ -1,12 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
import chalk from 'chalk'
import { Cli } from 'clipanion' import { Cli } from 'clipanion'
import { cli } from './cli.js' import { cli } from './cli.js'
const [, , ...arguments_] = process.argv const [, , ...arguments_] = process.argv
cli.runExit(arguments_, Cli.defaultContext).catch(() => { await cli.runExit(arguments_, Cli.defaultContext)
console.error(chalk.red('Error occurred...'))
process.exit(1)
})

5
src/packageJSON.ts Normal file
View File

@ -0,0 +1,5 @@
import { readPackage } from 'read-pkg'
export const packageJSON = await readPackage({
cwd: new URL('..', import.meta.url)
})

View File

@ -1,29 +1,24 @@
import fsMock from 'mock-fs' import fsMock from 'mock-fs'
import tap from 'tap'
import { isExistingPath } from '../isExistingPath.js' import { isExistingPath } from '../isExistingPath.js'
describe('utils/isExistingFile', () => { await tap.test('utils/isExistingPath', async (t) => {
afterEach(() => { t.afterEach(() => {
fsMock.restore() fsMock.restore()
}) })
it('should return true if the file exists', async () => { await t.test('should return true if the file exists', async () => {
fsMock( fsMock({
{ '/file.txt': ''
'/file.txt': '' })
}, t.equal(await isExistingPath('/file.txt'), true)
{ createCwd: false }
)
expect(await isExistingPath('/file.txt')).toBeTruthy()
}) })
it("should return false if the file doesn't exists", async () => { await t.test("should return false if the file doesn't exists", async () => {
fsMock( fsMock({
{ '/file.txt': ''
'/file.txt': '' })
}, t.equal(await isExistingPath('/randomfile.txt'), false)
{ createCwd: false }
)
expect(await isExistingPath('/randomfile.txt')).toBeFalsy()
}) })
}) })

View File

@ -1,14 +1,13 @@
{ {
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"module": "commonjs", "module": "ESNext",
"lib": ["ESNext"], "lib": ["ESNext"],
"moduleResolution": "node", "moduleResolution": "node",
"outDir": "./build", "outDir": "./build",
"rootDir": "./src", "rootDir": "./src",
"noEmit": true, "noEmit": true,
"strict": true, "exactOptionalPropertyTypes": false
"skipLibCheck": true,
"esModuleInterop": true
} }
} }