mirror of
https://github.com/theoludwig/html-w3c-validator.git
synced 2025-05-21 23:21:29 +02:00
@ -4,7 +4,10 @@ import fs from 'node:fs'
|
||||
import { Command } from 'clipanion'
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import validateHTML, { ValidationMessageLocationObject } from 'html-validator'
|
||||
import validateHTML, {
|
||||
ValidationMessageLocationObject,
|
||||
ParsedJsonAsValidationResults
|
||||
} from 'html-validator'
|
||||
import { table } from 'table'
|
||||
|
||||
import { isExistingPath } from './utils/isExistingPath.js'
|
||||
@ -13,11 +16,12 @@ const CURRENT_DIRECTORY = process.cwd()
|
||||
const CONFIG_FILE_NAME = '.html-w3c-validatorrc.json'
|
||||
|
||||
interface Config {
|
||||
urls: string[]
|
||||
urls?: string[]
|
||||
files?: string[]
|
||||
}
|
||||
|
||||
interface Error {
|
||||
url: string
|
||||
data: string
|
||||
messagesTable: string[][]
|
||||
}
|
||||
|
||||
@ -39,59 +43,104 @@ export class HTMLValidatorCommand extends Command {
|
||||
const configData = await fs.promises.readFile(configPath, {
|
||||
encoding: 'utf-8'
|
||||
})
|
||||
let config: Config = { urls: [] }
|
||||
let config: Config = { urls: [], files: [] }
|
||||
let isValidConfig = true
|
||||
try {
|
||||
config = JSON.parse(configData)
|
||||
} catch {
|
||||
isValidConfig = false
|
||||
}
|
||||
isValidConfig = isValidConfig && Array.isArray(config.urls)
|
||||
isValidConfig =
|
||||
isValidConfig &&
|
||||
(Array.isArray(config.urls) || Array.isArray(config.urls))
|
||||
if (!isValidConfig) {
|
||||
throw new Error(
|
||||
`Invalid config file at ${configPath}. Please check the syntax.`
|
||||
)
|
||||
}
|
||||
|
||||
const urls =
|
||||
config.urls == null
|
||||
? []
|
||||
: config.urls.map((url) => {
|
||||
return { type: 'url', data: url }
|
||||
})
|
||||
const files =
|
||||
config.files == null
|
||||
? []
|
||||
: config.files.map((file) => {
|
||||
return { type: 'file', data: file }
|
||||
})
|
||||
const dataToValidate = [...urls, ...files]
|
||||
const errors: Error[] = []
|
||||
let isValid = true
|
||||
for (const url of config.urls) {
|
||||
const loader = ora(`Validating ${url}`).start()
|
||||
const result = await validateHTML({
|
||||
url,
|
||||
format: 'json',
|
||||
isLocal: true
|
||||
})
|
||||
const isValidHTML = result.messages.length === 0
|
||||
if (isValidHTML) {
|
||||
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}`
|
||||
for (const { data, type } of dataToValidate) {
|
||||
const loader = ora(`Validating ${data}`).start()
|
||||
try {
|
||||
const options = {
|
||||
format: 'json' as 'json' | undefined
|
||||
}
|
||||
let result: ParsedJsonAsValidationResults | 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.`
|
||||
)
|
||||
}
|
||||
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({ url, messagesTable })
|
||||
const isValidHTML = result.messages.length === 0
|
||||
if (isValidHTML) {
|
||||
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)
|
||||
}
|
||||
errors.push({ data, messagesTable })
|
||||
isValid = false
|
||||
}
|
||||
} catch (error) {
|
||||
loader.fail()
|
||||
isValid = false
|
||||
if (error instanceof Error) {
|
||||
const messagesTable: string[][] = [[error.message]]
|
||||
errors.push({ data, messagesTable })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
for (const error of errors) {
|
||||
console.error(`\n${error.url}`)
|
||||
console.error(`\n${error.data}`)
|
||||
console.error(table(error.messagesTable))
|
||||
console.error('------------------------------')
|
||||
}
|
||||
|
Reference in New Issue
Block a user