135 lines
3.3 KiB
JavaScript
135 lines
3.3 KiB
JavaScript
'use strict'
|
|
const Joi = require('@hapi/joi')
|
|
const { optionalUrl } = require('../validators')
|
|
const { BaseJsonService, NotFound } = require('..')
|
|
const {
|
|
documentation,
|
|
presetRegex,
|
|
getColor,
|
|
getMessage,
|
|
getSchema,
|
|
} = require('./w3c-validation-helper')
|
|
|
|
const schema = Joi.object({
|
|
url: Joi.string().optional(),
|
|
messages: Joi.array()
|
|
.required()
|
|
.items(
|
|
Joi.object({
|
|
type: Joi.string()
|
|
.allow('info', 'error', 'non-document-error')
|
|
.required(),
|
|
subType: Joi.string().optional(),
|
|
message: Joi.string().required(),
|
|
})
|
|
),
|
|
}).required()
|
|
|
|
const queryParamSchema = Joi.object({
|
|
targetUrl: optionalUrl.required(),
|
|
preset: Joi.string().regex(presetRegex).allow(''),
|
|
}).required()
|
|
|
|
module.exports = class W3cValidation extends BaseJsonService {
|
|
static get category() {
|
|
return 'analysis'
|
|
}
|
|
|
|
static get route() {
|
|
return {
|
|
base: 'w3c-validation',
|
|
pattern: ':parser(default|html|xml|xmldtd)',
|
|
queryParamSchema,
|
|
}
|
|
}
|
|
|
|
static get examples() {
|
|
return [
|
|
{
|
|
title: 'W3C Validation',
|
|
namedParams: { parser: 'html' },
|
|
queryParams: {
|
|
targetUrl: 'https://validator.nu/',
|
|
preset: 'HTML, SVG 1.1, MathML 3.0',
|
|
},
|
|
staticPreview: this.render({ messageTypes: {} }),
|
|
documentation,
|
|
},
|
|
]
|
|
}
|
|
|
|
static get defaultBadgeData() {
|
|
return {
|
|
label: 'w3c',
|
|
}
|
|
}
|
|
|
|
static render({ messageTypes }) {
|
|
return {
|
|
message: getMessage(messageTypes),
|
|
color: getColor(messageTypes),
|
|
}
|
|
}
|
|
|
|
async fetch(targetUrl, preset, parser) {
|
|
return this._requestJson({
|
|
url: 'https://validator.nu/',
|
|
schema,
|
|
options: {
|
|
qs: {
|
|
schema: getSchema(preset),
|
|
parser: parser === 'default' ? undefined : parser,
|
|
doc: encodeURI(targetUrl),
|
|
out: 'json',
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
transform(url, messages) {
|
|
if (messages.length === 1) {
|
|
const { subType, type, message } = messages[0]
|
|
if (type === 'non-document-error' && subType === 'io') {
|
|
let notFound = false
|
|
if (
|
|
message ===
|
|
'HTTP resource not retrievable. The HTTP status from the remote server was: 404.'
|
|
) {
|
|
notFound = true
|
|
} else if (message.endsWith('Name or service not known')) {
|
|
const domain = message.split(':')[0].trim()
|
|
notFound = url.indexOf(domain) !== -1
|
|
}
|
|
|
|
if (notFound) {
|
|
throw new NotFound({ prettyMessage: 'target url not found' })
|
|
}
|
|
}
|
|
}
|
|
|
|
return messages.reduce((accumulator, message) => {
|
|
let { type } = message
|
|
if (type === 'info') {
|
|
type = 'warning'
|
|
} else {
|
|
// All messages are suppose to have a type and there can only be info, error or non-document
|
|
// If a new type gets introduce this will flag them as errors
|
|
type = 'error'
|
|
}
|
|
|
|
if (!(type in accumulator)) {
|
|
accumulator[type] = 0
|
|
}
|
|
accumulator[type] += 1
|
|
return accumulator
|
|
}, {})
|
|
}
|
|
|
|
async handle({ parser }, { targetUrl, preset }) {
|
|
const { url, messages } = await this.fetch(targetUrl, preset, parser)
|
|
return this.constructor.render({
|
|
messageTypes: this.transform(url, messages),
|
|
})
|
|
}
|
|
}
|