Skip to content
This repository was archived by the owner on Jul 19, 2023. It is now read-only.

Commit 1d5e39f

Browse files
committed
Leverage filtering and reporting from w3c-html-validator
1 parent f9678a2 commit 1d5e39f

File tree

4 files changed

+162
-191
lines changed

4 files changed

+162
-191
lines changed

README.md

Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,38 @@ const task = {
3636
gulp.task('validate-html', task.validateHtml);
3737
```
3838

39-
## 3) Custom Reporting
40-
The results are also added onto each file object under `validationResults`, containing `success` (boolean)
41-
and `messages` (Array).
39+
## 3) Options
40+
### analyzer()
41+
| Name (key) | Type | Default | Description |
42+
| :--------------- | :---------------------- | :------------------------------- | :------------------------------------------------------------------- |
43+
| `checkUrl` | **string** | `'https://validator.w3.org/nu/'` | W3C validation API endpoint. |
44+
| `ignoreLevel` | `'info'` or `'warning'` | `null` | Skip unwanted messages.* |
45+
| `ignoreMessages` | **string** or **regex** | `null` | Skip messages containing a string or matching a regular expression.* |
46+
47+
*The `ignoreMessages` and `ignoreLevel` options only work for `'json'` output. 
48+
Option value `'warning'` also skips `'info'`.
49+
50+
Example usage of `verifyMessage` option:
51+
```javascript
52+
// Tasks
53+
const task = {
54+
validateHtml() {
55+
return gulp.src('target/**/*.html')
56+
.pipe(htmlValidator.analyzer({ ignoreMessages: /^Duplicate ID/ }))
57+
.pipe(htmlValidator.reporter());
58+
},
59+
};
60+
```
61+
62+
### reporter()
63+
| Name (key) | Type | Default | Description |
64+
| --------------- | ----------- | --------| ------------------------------------------------------------------------------------- |
65+
| `maxMessageLen` | **number** | `null` | Trim validation messages to not exceed a maximum length. |
66+
| `throwErrors` | **boolean** | `false` | Throw an [error](https://github.com/gulpjs/plugin-error) for HTTP validation failure. |
67+
68+
## 4) Custom Reporting
69+
The `analyzer()` adds the validation results onto each file object in the `w3cHtmlValidator` field,
70+
which contains a `validates` (**boolean**) field and a `messages` (**array**) field.
4271

4372
### Example usage
4473
```javascript
@@ -51,8 +80,8 @@ const task = {
5180
validateHtml() {
5281
const handleFile = (file, encoding, callback) => {
5382
callback(null, file);
54-
if (!file.validationResults.success)
55-
throw Error('HTML validation error(s) found');
83+
if (!file.w3cHtmlValidator.validates)
84+
throw Error('HTML failed validation');
5685
};
5786
return gulp.src('target/**/*.html')
5887
.pipe(htmlValidator.analyzer())
@@ -64,43 +93,6 @@ const task = {
6493
gulp.task('validate-html', task.validateHtml);
6594
```
6695

67-
### Example output
68-
```shell
69-
HTML Error: index.html Line 5, Column 19: Element title must not be empty.
70-
<title></title>
71-
.../gulpfile.js:11
72-
throw Error('HTML validation error(s) found');
73-
^
74-
Error: HTML validation error(s) found
75-
```
76-
77-
## 4) Options
78-
### analyzer()
79-
| Option | Type | Description | Default |
80-
| ----------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ------- |
81-
| **proxy** | `string` | HTTP address of the proxy server if you are running behind a firewall, e.g. `'http://proxy:8080'` | `null` |
82-
| **skipWarnings** | `boolean` | Suppress informational warning messages (`type: 'info'`). | `false` |
83-
| **url** | `string` | URL to the W3C validator. Use if you want to use a local validator. | see:&nbsp;[w3c-html-validator](https://github.com/center-key/w3c-html-validator) |
84-
| **verifyMessage** | `function` | Function to determine if a warning or error should be allowed. Return `true` to allow and `false` to skip. | `null` |
85-
86-
Example usage of `verifyMessage` option:
87-
```javascript
88-
// Tasks
89-
const task = {
90-
validateHtml() {
91-
const ignoreDuplicateIds = (type, message) => !/^Duplicate ID/.test(message);
92-
return gulp.src('target/**/*.html')
93-
.pipe(htmlValidator.analyzer({ verifyMessage: ignoreDuplicateIds })) //custom function
94-
.pipe(htmlValidator.reporter());
95-
},
96-
};
97-
```
98-
99-
### reporter()
100-
| Option | Type | Description | Default |
101-
| --------------- | --------- | ------------------------------------------------------------------------------------- | ------- |
102-
| **throwErrors** | `boolean` | Throw an [error](https://github.com/gulpjs/plugin-error) on HTTP validation failure. | `false` |
103-
10496
## 5) Deprecated CommonJS (gulp-w3c-html-validator v2.0)
10597
If your build system is using `require()` statements for CommonJS modules, install the older v2.0:
10698
```shell

html-validator.js

Lines changed: 12 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
// MIT License
55

66
// Imports
7-
import color from 'ansi-colors';
87
import PluginError from 'plugin-error';
9-
import log from 'fancy-log';
108
import through2 from 'through2';
119
import { w3cHtmlValidator } from 'w3c-html-validator';
1210

@@ -16,99 +14,35 @@ const pluginName = 'gulp-w3c-html-validator';
1614
// Gulp plugin
1715
const htmlValidator = {
1816

19-
handleMessages(file) {
20-
const text = {
21-
error: color.red.bold('HTML Error:'),
22-
info: color.yellow.bold('HTML Warning:'),
23-
};
24-
const lines = file.contents.toString().split(/\r\n|\r|\n/g);
25-
const processMessage = (message) => {
26-
// Example message object:
27-
// {
28-
// type: 'error',
29-
// message: 'Unclosed element “h1”.',
30-
// extract: '<body>\n <h1>Specif',
31-
// lastLine: 8,
32-
// firstColumn: 4,
33-
// lastColumn: 7,
34-
// hiliteStart: 10,
35-
// hiliteLength: 4,
36-
// }
37-
// See: https://github.com/validator/validator/wiki/Output-»-JSON#example
38-
const type = text[message.type] || color.cyan.bold('HTML Comment:');
39-
const line = message.lastLine || 0;
40-
const column = message.lastColumn || 0;
41-
const location = 'Line ' + line + ', Column ' + column + ':';
42-
let erroredLine = lines[line - 1];
43-
let errorColumn = message.lastColumn;
44-
const trimErrorLength = () => {
45-
erroredLine = erroredLine.slice(errorColumn - 50);
46-
errorColumn = 50;
47-
};
48-
const formatErroredLine = () => {
49-
if (errorColumn > 60)
50-
trimErrorLength();
51-
erroredLine = erroredLine.slice(0, 60); //trim after so the line is not too long
52-
erroredLine = //highlight character with error
53-
color.gray(erroredLine.substring(0, errorColumn - 1)) +
54-
color.red.bold(erroredLine[errorColumn - 1]) +
55-
color.gray(erroredLine.substring(errorColumn));
56-
};
57-
if (erroredLine) //if false, stream was changed since validation
58-
formatErroredLine();
59-
if (typeof message.lastLine !== 'undefined' || typeof lastColumn !== 'undefined')
60-
log(type, file.relative, location, message.message);
61-
else
62-
log(type, file.relative, message.message);
63-
if (erroredLine)
64-
log(erroredLine);
65-
};
66-
if (!file.validationResults || !Array.isArray(file.validationResults.messages))
67-
log(text.warning, 'Failed to run validation on', file.relative);
68-
else
69-
file.validationResults.messages.forEach(processMessage);
70-
},
71-
7217
analyzer(options) {
73-
const defaults = { proxy: null, skipWarnings: false, url: null, verifyMessage: null };
74-
const settings = { ...defaults, ...options };
75-
if (settings.proxy)
76-
throw Error('The "proxy" option is not supported at this time.');
77-
const transform = (file, encoding, done) => {
18+
const validate = (file, encoding, done) => {
7819
const handleValidation = (results) => {
79-
const worthy = (message) => !(settings.skipWarnings && message.type === 'info') &&
80-
!(settings.verifyMessage && !settings.verifyMessage(message.type, message.message));
81-
const filteredMessages = results.messages.filter(worthy);
82-
file.validationResults = {
83-
success: !filteredMessages.length,
84-
messages: filteredMessages,
85-
unfiltered: results.messages,
86-
};
87-
htmlValidator.handleMessages(file);
20+
file.w3cHtmlValidator = results;
8821
done(null, file);
8922
};
90-
const validatorOptions = { html: file.contents };
91-
if (typeof settings.url === 'string')
92-
validatorOptions.checkUrl = settings.url;
23+
const validatorOptions = { ...options, ...{ html: file.contents.toString() } };
9324
if (file.isNull())
9425
done(null, file);
9526
else if (file.isStream())
9627
done(new PluginError(pluginName, 'Streaming not supported'));
9728
else
98-
w3cHtmlValidator.validate({ html: file.contents }).then(handleValidation);
29+
w3cHtmlValidator.validate(validatorOptions).then(handleValidation);
9930
};
100-
return through2.obj(transform);
31+
return through2.obj(validate);
10132
},
10233

10334
reporter(options) {
104-
const defaults = { throwErrors: false };
35+
const defaults = { maxMessageLen: null, throwErrors: false };
10536
const settings = { ...defaults, ...options };
106-
const transform = (file, encoding, done) => {
37+
const report = (file, encoding, done) => {
38+
const options = { title: file.path, maxMessageLen: settings.maxMessageLen };
39+
if (file.w3cHtmlValidator)
40+
w3cHtmlValidator.reporter(file.w3cHtmlValidator, options);
10741
done(null, file);
108-
if (settings.throwErrors && file.validationResults && !file.validationResults.success)
42+
if (settings.throwErrors && file.w3cHtmlValidator && !file.w3cHtmlValidator.validates)
10943
throw new PluginError(pluginName, 'HTML validation failed');
11044
};
111-
return through2.obj(transform);
45+
return through2.obj(report);
11246
},
11347

11448
};

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,15 @@
4141
"test": "mocha spec --timeout 5000"
4242
},
4343
"dependencies": {
44-
"ansi-colors": "~4.1",
45-
"fancy-log": "~1.3",
4644
"plugin-error": "~1.0",
4745
"through2": "~4.0",
4846
"vinyl": "~2.2",
4947
"w3c-html-validator": "~0.7"
5048
},
5149
"devDependencies": {
50+
"assert-deep-strict-equal": "~0.0",
5251
"jshint": "~2.13",
5352
"mocha": "~9.0",
54-
"should": "~13.2"
53+
"sinon": "~11.1"
5554
}
5655
}

0 commit comments

Comments
 (0)