Skip to content

Commit a8658f5

Browse files
committed
chore: better validation
1 parent c266d9e commit a8658f5

File tree

6 files changed

+97
-59
lines changed

6 files changed

+97
-59
lines changed

packages/cli/bin/view/render.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
const spinner = require('ora')({ text: '', color: 'gray' })
44
const indentString = require('indent-string')
5+
const cliTruncate = require('cli-truncate')
6+
const terminalSize = require('term-size')
57
const httpStatus = require('http-status')
68
const logSymbols = require('log-symbols')
79
const prettyMs = require('pretty-ms')
@@ -10,6 +12,10 @@ const { EOL } = require('os')
1012
const color = require('../color')
1113
const { pink, gray } = color
1214

15+
const { columns } = terminalSize()
16+
17+
const truncateText = text => (text.length + 50 < columns ? text : cliTruncate(text, columns - 50))
18+
1319
const renderProgress = ({ fetchingUrl, count, total, startTimestamp }) => {
1420
const timestamp = pink(prettyMs(Date.now() - startTimestamp))
1521
const spinnerFrame = spinner.frame()
@@ -26,14 +32,16 @@ const renderResume = state => {
2632
let str = `${url} ${humanStatusCode} ${EOL}`
2733
Object.keys(allRules).forEach(ruleName => {
2834
const rules = allRules[ruleName]
29-
str += `${EOL}${indentString(`${ruleName}`, 2)}${EOL}${EOL}`
35+
str += `${EOL}${indentString(`${ruleName}`, 2)}${EOL}`
36+
3037
rules.forEach(rule => {
3138
const colorize = color[rule.status]
32-
const info = rule.message ? `${EOL}${indentString(`- ${rule.message}`, 2)}${EOL}` : EOL
39+
const value = truncateText(rule.value)
40+
const info = rule.message ? `${EOL}${indentString(`- ${rule.message}`, 2)}` : ''
3341
str += indentString(
3442
`${colorize(logSymbols[rule.status])} ${colorize(rule.selector)} ${gray(
35-
rule.value
36-
)} ${colorize(info)}`,
43+
`(${rule.value.length})`
44+
)} ${gray(value)} ${colorize(info)}`,
3745
4
3846
)
3947
str += EOL

packages/cli/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"beauty-error": "~1.2.8",
3636
"chalk": "~4.1.1",
3737
"ci-env": "~1.16.0",
38+
"cli-truncate": "~2.1.0",
3839
"cosmiconfig": "~7.0.0",
3940
"github-build": "~1.2.2",
4041
"http-status": "~1.5.0",
@@ -46,6 +47,7 @@
4647
"ora": "~5.0.0",
4748
"prepend-http": "~3.0.1",
4849
"pretty-ms": "~7.0.1",
50+
"term-size": "~2.2.1",
4951
"update-notifier": "~5.1.0"
5052
},
5153
"files": [

packages/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"reachable-url": "~1.6.0",
3636
"require-one-of": "~1.0.15",
3737
"signal-exit": "~3.0.3",
38+
"whoops": "~4.1.0",
3839
"xml-urls": "~2.1.25"
3940
},
4041
"files": [

packages/core/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const evaluateRule = async ({ value, validator, el }) => {
1818
try {
1919
await validator({ value, el })
2020
} catch (error) {
21-
status = error.name === 'RangeError' ? 'warning' : 'error'
21+
status = error.status
2222
message = error.message
2323
}
2424

packages/core/src/rules.js

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,6 @@
11
'use strict'
22

3-
const isUrl = require('is-url-http/lightweight')
4-
const reachableUrl = require('reachable-url')
5-
6-
const inRange = (num, init, final) => num >= Math.min(init, final) && num < Math.max(init, final)
7-
8-
// https://moz.com/learn/seo/title-tag
9-
const VALIDATOR = {
10-
url: async ({ value }) => {
11-
if (value.toString().length === 0) {
12-
throw new TypeError('Expected to be present')
13-
}
14-
15-
if (!isUrl(value)) {
16-
throw new TypeError(`Expected an absolute WHATWG URL, got \`${value}\``)
17-
}
18-
19-
const res = await reachableUrl(value)
20-
21-
if (!reachableUrl.isReachable(res)) {
22-
throw new TypeError(`Expected a reachable URL, got ${res.statusCode} HTTP status code`)
23-
}
24-
},
25-
notEmpty: ({ value }) => {
26-
if (value.toString().length === 0) {
27-
throw new TypeError('Expected to be not empty')
28-
}
29-
},
30-
presence: ({ el }) => {
31-
if (el.length === 0) {
32-
throw new TypeError('Expected to be present')
33-
}
34-
},
35-
title: ({ value }) => {
36-
if (value.toString().length === 0) {
37-
throw new TypeError('Expected to be present')
38-
}
39-
40-
if (!inRange(value.toString().length, 50, 60)) {
41-
throw new RangeError(`Expected a value between 50 and 60 maximum length, got ${value.length}`)
42-
}
43-
},
44-
description: ({ value }) => {
45-
if (value.toString().length === 0) {
46-
throw new TypeError('Expected to be present')
47-
}
48-
49-
if (!inRange(value.toString().length, 50, 160)) {
50-
throw new RangeError(
51-
`Expected a value between 50 and 160 maximum length, got ${value.length}`
52-
)
53-
}
54-
}
55-
}
3+
const VALIDATOR = require('./validators')
564

575
module.exports = {
586
// Search Engine
@@ -70,6 +18,7 @@ module.exports = {
7018
},
7119
{
7220
selector: 'meta[charset]',
21+
attr: 'charset',
7322
validator: VALIDATOR.presence
7423
},
7524
{
@@ -85,7 +34,7 @@ module.exports = {
8534
{ selector: 'meta[itemprop="name"]', attr: 'content', validator: VALIDATOR.title },
8635
{
8736
selector: '[itemprop*="author" i] [itemprop="name"], [itemprop*="author" i]',
88-
validator: VALIDATOR.presence
37+
validator: VALIDATOR.notEmpty
8938
},
9039
{
9140
selector: 'meta[itemprop="description"]',

packages/core/src/validators.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
'use strict'
2+
3+
const isUrl = require('is-url-http/lightweight')
4+
const reachableUrl = require('reachable-url')
5+
const whoops = require('whoops')
6+
7+
const inRange = (num, init, final) => num >= Math.min(init, final) && num < Math.max(init, final)
8+
9+
const ruleError = whoops('RuleError', { status: 'error' })
10+
ruleError.warning = props => ruleError({ ...props, status: 'warning' })
11+
12+
const VALIDATOR = {
13+
url: async ({ value }) => {
14+
if (value.toString().length === 0) {
15+
throw ruleError({ message: 'Expected to be present' })
16+
}
17+
18+
if (!isUrl(value)) {
19+
throw ruleError({ message: `Expected an absolute WHATWG URL, got \`${value}\`` })
20+
}
21+
22+
const res = await reachableUrl(value)
23+
24+
if (!reachableUrl.isReachable(res)) {
25+
throw ruleError({
26+
message: `Expected a reachable URL, got ${res.statusCode} HTTP status code`
27+
})
28+
}
29+
},
30+
/* when is present, it can't be empty */
31+
notEmpty: ({ el, value }) => {
32+
if (el.length !== 0 && value.toString().length === 0) {
33+
throw ruleError.warning({
34+
message: 'Expected to be not empty'
35+
})
36+
}
37+
},
38+
/** it should be exist and no be empty */
39+
presence: ({ el, value }) => {
40+
if (el.length === 0) {
41+
throw ruleError({ message: 'Expected to be present' })
42+
}
43+
if (value.toString().length === 0) {
44+
throw ruleError.warning({
45+
message: 'Expected to be not empty'
46+
})
47+
}
48+
},
49+
title: ({ el, value }) => {
50+
if (el.length === 0) {
51+
throw ruleError({
52+
message: 'Expected to be present',
53+
link: 'https://moz.com/learn/seo/title-tag'
54+
})
55+
}
56+
57+
if (!inRange(value.toString().length, 50, 60)) {
58+
throw ruleError.warning({
59+
message: 'Recommended a value between 50 and 60 characters',
60+
link: 'https://moz.com/learn/seo/title-tag'
61+
})
62+
}
63+
},
64+
description: ({ value }) => {
65+
if (value.toString().length === 0) {
66+
throw ruleError({ message: 'Expected to be present' })
67+
}
68+
69+
if (!inRange(value.toString().length, 50, 160)) {
70+
throw ruleError.warning({
71+
message: 'Recommended a value between 50 and 160 characters',
72+
link: 'https://moz.com/learn/seo/meta-description'
73+
})
74+
}
75+
}
76+
}
77+
78+
module.exports = VALIDATOR

0 commit comments

Comments
 (0)