w3c-html-validator 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -7
- package/bin/cli.js +1 -75
- package/dist/w3c-html-validator.d.ts +9 -8
- package/dist/w3c-html-validator.js +75 -12
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -20,7 +20,14 @@ $ npm install --save-dev w3c-html-validator
|
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
## B) Usage
|
|
23
|
-
### 1.
|
|
23
|
+
### 1. Synopsis
|
|
24
|
+
```
|
|
25
|
+
html-validator [INPUT1] [INPUT2] [INPUT3] [...]
|
|
26
|
+
```
|
|
27
|
+
Parameters:
|
|
28
|
+
Each parameter is a folder or file to be sent to the HTML validator.
|
|
29
|
+
|
|
30
|
+
### 2. npm package.json scripts
|
|
24
31
|
Run `html-validator` from the `"scripts"` section of your **package.json** file.
|
|
25
32
|
|
|
26
33
|
The parameters are folders and files to be validated.
|
|
@@ -37,7 +44,7 @@ Example **package.json** scripts:
|
|
|
37
44
|
Passing no parameters defaults to validating all HTML files in the project (skipping the
|
|
38
45
|
**node_modules** folder).
|
|
39
46
|
|
|
40
|
-
###
|
|
47
|
+
### 3. Command-line npx
|
|
41
48
|
Example terminal commands:
|
|
42
49
|
```shell
|
|
43
50
|
$ npm install --save-dev w3c-html-validator
|
|
@@ -47,7 +54,7 @@ The above `npx` line validates all the HTML files in the **docs** folder.
|
|
|
47
54
|
|
|
48
55
|
You can also install **w3c-html-validator** globally (`--global`) and then run it anywhere directly from the terminal.
|
|
49
56
|
|
|
50
|
-
###
|
|
57
|
+
### 4. CLI flags
|
|
51
58
|
Command-line flags:
|
|
52
59
|
| Flag | Description | Value |
|
|
53
60
|
| ----------------- | ------------------------------------------------------------------- | ---------- |
|
|
@@ -62,8 +69,7 @@ Command-line flags:
|
|
|
62
69
|
| `--quiet` | Suppress messages for successful validations. | N/A |
|
|
63
70
|
| `--trim` | Truncate validation messages to not exceed a maximum length. | **number** |
|
|
64
71
|
|
|
65
|
-
###
|
|
66
|
-
Examples:
|
|
72
|
+
### 5. Examples
|
|
67
73
|
- `html-validator`<br>
|
|
68
74
|
Validates all HTML files in the project.
|
|
69
75
|
|
|
@@ -93,7 +99,7 @@ Examples:
|
|
|
93
99
|
|
|
94
100
|
_**Note:** Single quotes in commands are normalized so they work cross-platform and avoid the errors often encountered on Microsoft Windows._
|
|
95
101
|
|
|
96
|
-
###
|
|
102
|
+
### 6. Configuration File for Ignore Patterns
|
|
97
103
|
The optional `--ignore-config=FILENAME` flag specifies a configuration file with one string or regex per line.
|
|
98
104
|
HTML validation messages containing any of the strings or matching any of the regexes will be skipped.
|
|
99
105
|
Empty lines and lines starting with a hash sign (`#`) are treated as comments and do nothing.
|
|
@@ -109,7 +115,7 @@ Example configuration file with 3 regexes:
|
|
|
109
115
|
The caret (`^`) regex operator says to match from the beginning of the validation message.
|
|
110
116
|
The dot (`.`) regex operator says to match any one character, which is a handy way to avoid typing the special curly quote characters in some of the validation messages.
|
|
111
117
|
|
|
112
|
-
###
|
|
118
|
+
### 7. Default Ignore List
|
|
113
119
|
The optional `--default-rules` flag causes HTML validation messages to be skipped if they are on the opinionated pre-defined list of unhelpful messages.
|
|
114
120
|
|
|
115
121
|
Default ignore list:
|
package/bin/cli.js
CHANGED
|
@@ -4,80 +4,6 @@
|
|
|
4
4
|
// MIT License //
|
|
5
5
|
////////////////////////
|
|
6
6
|
|
|
7
|
-
// Usage in package.json:
|
|
8
|
-
// "scripts": {
|
|
9
|
-
// "validate": "html-validator docs flyer.html",
|
|
10
|
-
// "all": "html-validator"
|
|
11
|
-
// },
|
|
12
|
-
//
|
|
13
|
-
// Usage from command line:
|
|
14
|
-
// $ npm install --save-dev w3c-html-validator
|
|
15
|
-
// $ npx html-validator dist #validate all html files in the dist folder
|
|
16
|
-
// $ npx html-validator docs flyer.html
|
|
17
|
-
//
|
|
18
|
-
// Contributors to this project:
|
|
19
|
-
// $ cd w3c-html-validator
|
|
20
|
-
// $ npm install
|
|
21
|
-
// $ npm test
|
|
22
|
-
// $ node bin/cli.js spec --continue
|
|
23
|
-
|
|
24
|
-
// Imports
|
|
25
|
-
import { cliArgvUtil } from 'cli-argv-util';
|
|
26
|
-
import { globSync } from 'glob';
|
|
27
7
|
import { w3cHtmlValidator } from '../dist/w3c-html-validator.js';
|
|
28
|
-
import fs from 'fs';
|
|
29
|
-
import slash from 'slash';
|
|
30
|
-
|
|
31
|
-
// Parameters and flags
|
|
32
|
-
const validFlags = ['continue', 'default-rules', 'delay', 'dry-run', 'exclude',
|
|
33
|
-
'ignore', 'ignore-config', 'note', 'quiet', 'trim'];
|
|
34
|
-
const cli = cliArgvUtil.parse(validFlags);
|
|
35
|
-
const files = cli.params.length ? cli.params.map(cliArgvUtil.cleanPath) : ['.'];
|
|
36
|
-
const excludeList = cli.flagMap.exclude?.split(',') ?? [];
|
|
37
|
-
const ignore = cli.flagMap.ignore ?? null;
|
|
38
|
-
const ignoreConfig = cli.flagMap.ignoreConfig ?? null;
|
|
39
|
-
const defaultRules = cli.flagOn.defaultRules;
|
|
40
|
-
const delay = Number(cli.flagMap.delay) || 500; //default half second debounce pause
|
|
41
|
-
const trim = Number(cli.flagMap.trim) || null;
|
|
42
|
-
const dryRun = cli.flagOn.dryRun || process.env.w3cHtmlValidator === 'dry-run'; //bash: export w3cHtmlValidator=dry-run
|
|
43
8
|
|
|
44
|
-
|
|
45
|
-
const readFilenames = (file) => globSync(file, { ignore: '**/node_modules/**/*' }).map(slash);
|
|
46
|
-
const readHtmlFiles = (folder) => readFilenames(folder + '/**/*.html');
|
|
47
|
-
const addHtml = (file) => fs.lstatSync(file).isDirectory() ? readHtmlFiles(file) : file;
|
|
48
|
-
const keep = (file) => excludeList.every(exclude => !file.includes(exclude));
|
|
49
|
-
return files.map(readFilenames).flat().map(addHtml).flat().filter(keep).sort();
|
|
50
|
-
};
|
|
51
|
-
const filenames = getFilenames();
|
|
52
|
-
const error =
|
|
53
|
-
cli.invalidFlag ? cli.invalidFlagMsg :
|
|
54
|
-
!filenames.length ? 'No files to validate.' :
|
|
55
|
-
cli.flagOn.trim && !trim ? 'Value of "trim" must be a positive whole number.' :
|
|
56
|
-
null;
|
|
57
|
-
if (error)
|
|
58
|
-
throw new Error('[w3c-html-validator] ' + error);
|
|
59
|
-
if (dryRun)
|
|
60
|
-
w3cHtmlValidator.dryRunNotice();
|
|
61
|
-
if (filenames.length > 1 && !cli.flagOn.quiet)
|
|
62
|
-
w3cHtmlValidator.summary(filenames.length);
|
|
63
|
-
const reporterOptions = {
|
|
64
|
-
continueOnFail: cli.flagOn.continue,
|
|
65
|
-
quiet: cli.flagOn.quiet,
|
|
66
|
-
maxMessageLen: trim,
|
|
67
|
-
};
|
|
68
|
-
const getIgnoreMessages = () => {
|
|
69
|
-
const toArray = (text) => text.replace(/\r/g, '').split('\n').map(line => line.trim());
|
|
70
|
-
const notComment = (line) => line.length > 1 && !line.startsWith('#');
|
|
71
|
-
const readLines = (file) => toArray(fs.readFileSync(file).toString()).filter(notComment);
|
|
72
|
-
const rawLines = ignoreConfig ? readLines(ignoreConfig) : [];
|
|
73
|
-
if (ignore)
|
|
74
|
-
rawLines.push(ignore);
|
|
75
|
-
const isRegex = /^\/.*\/$/; //starts and ends with a slash indicating it's a regex
|
|
76
|
-
return rawLines.map(line => isRegex.test(line) ? new RegExp(line.slice(1, -1)) : line);
|
|
77
|
-
};
|
|
78
|
-
const ignoreMessages = getIgnoreMessages();
|
|
79
|
-
const options = (filename) => ({ filename, ignoreMessages, defaultRules, dryRun });
|
|
80
|
-
const handleResults = (results) => w3cHtmlValidator.reporter(results, reporterOptions);
|
|
81
|
-
const getReport = (filename) => w3cHtmlValidator.validate(options(filename)).then(handleResults);
|
|
82
|
-
const processFile = (filename, i) => globalThis.setTimeout(() => getReport(filename), i * delay);
|
|
83
|
-
filenames.forEach(processFile);
|
|
9
|
+
w3cHtmlValidator.cli();
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
//! w3c-html-validator v2.0.
|
|
1
|
+
//! w3c-html-validator v2.0.2 ~~ https://github.com/center-key/w3c-html-validator ~~ MIT License
|
|
2
2
|
|
|
3
3
|
export type ValidatorSettings = {
|
|
4
|
-
html: string;
|
|
5
|
-
filename: string;
|
|
6
|
-
website: string;
|
|
7
|
-
checkUrl: string;
|
|
8
|
-
ignoreLevel: 'info' | 'warning';
|
|
4
|
+
html: string | null;
|
|
5
|
+
filename: string | null;
|
|
6
|
+
website: string | null;
|
|
7
|
+
checkUrl: string | null;
|
|
8
|
+
ignoreLevel: 'info' | 'warning' | null;
|
|
9
9
|
ignoreMessages: ValidatorIgnorePattern[];
|
|
10
10
|
defaultRules: boolean;
|
|
11
|
-
output:
|
|
11
|
+
output: 'json' | 'html' | null;
|
|
12
12
|
dryRun: boolean;
|
|
13
13
|
};
|
|
14
14
|
export type ValidatorIgnorePattern = string | RegExp;
|
|
@@ -38,7 +38,6 @@ export type ValidatorResults = {
|
|
|
38
38
|
display: string | null;
|
|
39
39
|
dryRun: boolean;
|
|
40
40
|
};
|
|
41
|
-
export type ValidatorResultsOutput = ValidatorResults['output'];
|
|
42
41
|
export type ReporterSettings = {
|
|
43
42
|
continueOnFail: boolean;
|
|
44
43
|
maxMessageLen: number | null;
|
|
@@ -48,6 +47,8 @@ export type ReporterSettings = {
|
|
|
48
47
|
declare const w3cHtmlValidator: {
|
|
49
48
|
version: string;
|
|
50
49
|
defaultIgnoreList: string[];
|
|
50
|
+
assert(ok: unknown, message: string | null): void;
|
|
51
|
+
cli(): void;
|
|
51
52
|
validate(options: Partial<ValidatorSettings>): Promise<ValidatorResults>;
|
|
52
53
|
dryRunNotice(): void;
|
|
53
54
|
summary(numFiles: number): void;
|
|
@@ -1,31 +1,94 @@
|
|
|
1
|
-
//! w3c-html-validator v2.0.
|
|
1
|
+
//! w3c-html-validator v2.0.2 ~~ https://github.com/center-key/w3c-html-validator ~~ MIT License
|
|
2
2
|
|
|
3
|
+
import { cliArgvUtil } from 'cli-argv-util';
|
|
4
|
+
import { globSync } from 'glob';
|
|
3
5
|
import chalk from 'chalk';
|
|
4
6
|
import fs from 'fs';
|
|
5
7
|
import log from 'fancy-log';
|
|
6
8
|
import request from 'superagent';
|
|
7
9
|
import slash from 'slash';
|
|
8
10
|
const w3cHtmlValidator = {
|
|
9
|
-
version: '2.0.
|
|
11
|
+
version: '2.0.2',
|
|
10
12
|
defaultIgnoreList: [
|
|
11
13
|
'Section lacks heading.'
|
|
12
14
|
],
|
|
15
|
+
assert(ok, message) {
|
|
16
|
+
if (!ok)
|
|
17
|
+
throw new Error(`[w3c-html-validator] ${message}`);
|
|
18
|
+
},
|
|
19
|
+
cli() {
|
|
20
|
+
const validFlags = ['continue', 'default-rules', 'delay', 'dry-run', 'exclude',
|
|
21
|
+
'ignore', 'ignore-config', 'note', 'quiet', 'trim'];
|
|
22
|
+
const cli = cliArgvUtil.parse(validFlags);
|
|
23
|
+
const files = cli.params.length ? cli.params.map(cliArgvUtil.cleanPath) : ['.'];
|
|
24
|
+
const excludeList = cli.flagMap.exclude?.split(',') ?? [];
|
|
25
|
+
const ignore = cli.flagMap.ignore ?? null;
|
|
26
|
+
const ignoreConfig = cli.flagMap.ignoreConfig ?? null;
|
|
27
|
+
const defaultRules = cli.flagOn.defaultRules;
|
|
28
|
+
const delay = Number(cli.flagMap.delay) || 500;
|
|
29
|
+
const trim = Number(cli.flagMap.trim) || null;
|
|
30
|
+
const dryRun = cli.flagOn.dryRun || process.env.w3cHtmlValidator === 'dry-run';
|
|
31
|
+
const getFilenames = () => {
|
|
32
|
+
const readFilenames = (file) => globSync(file, { ignore: '**/node_modules/**/*' }).map(slash);
|
|
33
|
+
const readHtmlFiles = (folder) => readFilenames(folder + '/**/*.html');
|
|
34
|
+
const addHtml = (file) => fs.lstatSync(file).isDirectory() ? readHtmlFiles(file) : file;
|
|
35
|
+
const keep = (file) => excludeList.every(exclude => !file.includes(exclude));
|
|
36
|
+
return files.map(readFilenames).flat().map(addHtml).flat().filter(keep).sort();
|
|
37
|
+
};
|
|
38
|
+
const filenames = getFilenames();
|
|
39
|
+
const error = cli.invalidFlag ? cli.invalidFlagMsg :
|
|
40
|
+
!filenames.length ? 'No files to validate.' :
|
|
41
|
+
cli.flagOn.trim && !trim ? 'Value of "trim" must be a positive whole number.' :
|
|
42
|
+
null;
|
|
43
|
+
w3cHtmlValidator.assert(!error, error);
|
|
44
|
+
if (dryRun)
|
|
45
|
+
w3cHtmlValidator.dryRunNotice();
|
|
46
|
+
if (filenames.length > 1 && !cli.flagOn.quiet)
|
|
47
|
+
w3cHtmlValidator.summary(filenames.length);
|
|
48
|
+
const reporterOptions = {
|
|
49
|
+
continueOnFail: cli.flagOn.continue,
|
|
50
|
+
maxMessageLen: trim,
|
|
51
|
+
quiet: cli.flagOn.quiet,
|
|
52
|
+
title: null,
|
|
53
|
+
};
|
|
54
|
+
const getIgnoreMessages = () => {
|
|
55
|
+
const toArray = (text) => text.replace(/\r/g, '').split('\n').map(line => line.trim());
|
|
56
|
+
const notComment = (line) => line.length > 1 && !line.startsWith('#');
|
|
57
|
+
const readLines = (file) => toArray(fs.readFileSync(file).toString()).filter(notComment);
|
|
58
|
+
const rawLines = ignoreConfig ? readLines(ignoreConfig) : [];
|
|
59
|
+
if (ignore)
|
|
60
|
+
rawLines.push(ignore);
|
|
61
|
+
const isRegex = /^\/.*\/$/;
|
|
62
|
+
return rawLines.map(line => isRegex.test(line) ? new RegExp(line.slice(1, -1)) : line);
|
|
63
|
+
};
|
|
64
|
+
const ignoreMessages = getIgnoreMessages();
|
|
65
|
+
const options = (filename) => ({ filename, ignoreMessages, defaultRules, dryRun });
|
|
66
|
+
const handleResults = (results) => w3cHtmlValidator.reporter(results, reporterOptions);
|
|
67
|
+
const getReport = (filename) => w3cHtmlValidator.validate(options(filename)).then(handleResults);
|
|
68
|
+
const processFile = (filename, i) => globalThis.setTimeout(() => getReport(filename), i * delay);
|
|
69
|
+
filenames.forEach(processFile);
|
|
70
|
+
},
|
|
13
71
|
validate(options) {
|
|
14
72
|
const defaults = {
|
|
15
73
|
checkUrl: 'https://validator.w3.org/nu/',
|
|
16
74
|
defaultRules: false,
|
|
17
75
|
dryRun: false,
|
|
76
|
+
filename: null,
|
|
77
|
+
html: null,
|
|
18
78
|
ignoreLevel: null,
|
|
19
79
|
ignoreMessages: [],
|
|
20
80
|
output: 'json',
|
|
81
|
+
website: null,
|
|
21
82
|
};
|
|
22
83
|
const settings = { ...defaults, ...options };
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
84
|
+
const missingInput = !settings.html && !settings.filename && !settings.website;
|
|
85
|
+
const badLevel = ![null, 'info', 'warning'].includes(settings.ignoreLevel);
|
|
86
|
+
const invalidOutput = settings.output !== 'json' && settings.output !== 'html';
|
|
87
|
+
const error = missingInput ? 'Must specify the "html", "filename", or "website" option.' :
|
|
88
|
+
badLevel ? `Invalid ignoreLevel option: ${settings.ignoreLevel}` :
|
|
89
|
+
invalidOutput ? 'Option "output" must be "json" or "html".' :
|
|
90
|
+
null;
|
|
91
|
+
w3cHtmlValidator.assert(!error, error);
|
|
29
92
|
const filename = settings.filename ? slash(settings.filename) : null;
|
|
30
93
|
const mode = settings.html ? 'html' : filename ? 'filename' : 'website';
|
|
31
94
|
const unixify = (text) => text.replace(/\r/g, '');
|
|
@@ -102,8 +165,8 @@ const w3cHtmlValidator = {
|
|
|
102
165
|
title: null,
|
|
103
166
|
};
|
|
104
167
|
const settings = { ...defaults, ...options };
|
|
105
|
-
|
|
106
|
-
|
|
168
|
+
const hasResults = 'validates' in results && typeof results.validates === 'boolean';
|
|
169
|
+
w3cHtmlValidator.assert(hasResults, `Invalid results for reporter(): ${results}`);
|
|
107
170
|
const messages = results.messages ?? [];
|
|
108
171
|
const title = settings.title ?? results.title;
|
|
109
172
|
const status = results.validates ? chalk.green.bold('✔ pass') : chalk.red.bold('✘ fail');
|
|
@@ -131,8 +194,8 @@ const w3cHtmlValidator = {
|
|
|
131
194
|
const fileDetails = () => `${results.filename} -- ${results.messages.map(toString).join(', ')}`;
|
|
132
195
|
return !results.filename ? results.messages[0].message : fileDetails();
|
|
133
196
|
};
|
|
134
|
-
|
|
135
|
-
|
|
197
|
+
const failed = !settings.continueOnFail && !results.validates;
|
|
198
|
+
w3cHtmlValidator.assert(!failed, `Failed: ${failDetails()}`);
|
|
136
199
|
return results;
|
|
137
200
|
},
|
|
138
201
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "w3c-html-validator",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Check the markup validity of HTML files using the W3C validator",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -60,25 +60,25 @@
|
|
|
60
60
|
"chalk": "~5.6",
|
|
61
61
|
"cli-argv-util": "~1.3",
|
|
62
62
|
"fancy-log": "~2.0",
|
|
63
|
-
"glob": "~
|
|
63
|
+
"glob": "~12.0",
|
|
64
64
|
"slash": "~5.1",
|
|
65
65
|
"superagent": "~10.2"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@eslint/js": "~9.
|
|
68
|
+
"@eslint/js": "~9.39",
|
|
69
69
|
"@types/fancy-log": "~2.0",
|
|
70
|
-
"@types/node": "~24.
|
|
70
|
+
"@types/node": "~24.10",
|
|
71
71
|
"@types/superagent": "~8.1",
|
|
72
|
-
"add-dist-header": "~1.
|
|
72
|
+
"add-dist-header": "~1.6",
|
|
73
73
|
"assert-deep-strict-equal": "~1.2",
|
|
74
74
|
"copy-file-util": "~1.3",
|
|
75
|
-
"copy-folder-util": "~1.
|
|
76
|
-
"eslint": "~9.
|
|
75
|
+
"copy-folder-util": "~1.2",
|
|
76
|
+
"eslint": "~9.39",
|
|
77
77
|
"jshint": "~2.13",
|
|
78
78
|
"mocha": "~11.7",
|
|
79
|
-
"rimraf": "~6.
|
|
79
|
+
"rimraf": "~6.1",
|
|
80
80
|
"run-scripts-util": "~1.3",
|
|
81
81
|
"typescript": "~5.9",
|
|
82
|
-
"typescript-eslint": "~8.
|
|
82
|
+
"typescript-eslint": "~8.47"
|
|
83
83
|
}
|
|
84
84
|
}
|