html-validate 8.7.3 → 8.8.0
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/dist/cjs/browser.js +7 -21
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/cli.js +468 -451
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core-browser.js +9 -20
- package/dist/cjs/core-browser.js.map +1 -1
- package/dist/cjs/core-nodejs.js +203 -297
- package/dist/cjs/core-nodejs.js.map +1 -1
- package/dist/cjs/core.js +9511 -10450
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js +2293 -2296
- package/dist/cjs/elements.js.map +1 -1
- package/dist/cjs/html-validate.js +148 -169
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/html5.js.map +1 -1
- package/dist/cjs/index.js +8 -21
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/jest-diff.js +26 -36
- package/dist/cjs/jest-diff.js.map +1 -1
- package/dist/cjs/jest.js +8 -8
- package/dist/cjs/jest.js.map +1 -1
- package/dist/cjs/matcher-utils.js +12 -28
- package/dist/cjs/matcher-utils.js.map +1 -1
- package/dist/cjs/matchers-jestonly.js +38 -47
- package/dist/cjs/matchers-jestonly.js.map +1 -1
- package/dist/cjs/matchers.js +196 -196
- package/dist/cjs/matchers.js.map +1 -1
- package/dist/cjs/meta-helper.js +40 -60
- package/dist/cjs/meta-helper.js.map +1 -1
- package/dist/cjs/test-utils.js +26 -47
- package/dist/cjs/test-utils.js.map +1 -1
- package/dist/cjs/tsdoc-metadata.json +1 -1
- package/dist/cjs/utils/natural-join.js +10 -23
- package/dist/cjs/utils/natural-join.js.map +1 -1
- package/dist/cjs/vitest.js +6 -6
- package/dist/cjs/vitest.js.map +1 -1
- package/dist/es/browser.js +2 -2
- package/dist/es/cli.js +467 -454
- package/dist/es/cli.js.map +1 -1
- package/dist/es/core-browser.js +10 -21
- package/dist/es/core-browser.js.map +1 -1
- package/dist/es/core-nodejs.js +204 -299
- package/dist/es/core-nodejs.js.map +1 -1
- package/dist/es/core.js +9506 -10451
- package/dist/es/core.js.map +1 -1
- package/dist/es/elements.js +2293 -2296
- package/dist/es/elements.js.map +1 -1
- package/dist/es/html-validate.js +150 -171
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/html5.js.map +1 -1
- package/dist/es/index.js +3 -3
- package/dist/es/jest-diff.js +11 -21
- package/dist/es/jest-diff.js.map +1 -1
- package/dist/es/jest.js +8 -8
- package/dist/es/jest.js.map +1 -1
- package/dist/es/matcher-utils.js +12 -28
- package/dist/es/matcher-utils.js.map +1 -1
- package/dist/es/matchers-jestonly.js +39 -48
- package/dist/es/matchers-jestonly.js.map +1 -1
- package/dist/es/matchers.js +196 -196
- package/dist/es/matchers.js.map +1 -1
- package/dist/es/meta-helper.js +40 -60
- package/dist/es/meta-helper.js.map +1 -1
- package/dist/es/test-utils.js +26 -47
- package/dist/es/test-utils.js.map +1 -1
- package/dist/es/utils/natural-join.js +10 -23
- package/dist/es/utils/natural-join.js.map +1 -1
- package/dist/es/vitest.js +6 -6
- package/dist/es/vitest.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types/browser.d.ts +62 -30
- package/dist/types/index.d.ts +89 -32
- package/package.json +22 -18
package/dist/cjs/cli.js
CHANGED
|
@@ -7,6 +7,8 @@ var fs = require('fs');
|
|
|
7
7
|
var glob = require('glob');
|
|
8
8
|
var prompts = require('prompts');
|
|
9
9
|
require('./meta-helper.js');
|
|
10
|
+
var fs$1 = require('node:fs');
|
|
11
|
+
var betterAjvErrors = require('@sidvind/better-ajv-errors');
|
|
10
12
|
var kleur = require('kleur');
|
|
11
13
|
|
|
12
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -14,531 +16,546 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
14
16
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
15
17
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
16
18
|
var prompts__default = /*#__PURE__*/_interopDefault(prompts);
|
|
19
|
+
var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
|
|
20
|
+
var betterAjvErrors__default = /*#__PURE__*/_interopDefault(betterAjvErrors);
|
|
17
21
|
var kleur__default = /*#__PURE__*/_interopDefault(kleur);
|
|
18
22
|
|
|
19
23
|
const DEFAULT_EXTENSIONS = ["html"];
|
|
20
24
|
function isDirectory(filename) {
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
const st = fs__default.default.statSync(filename);
|
|
26
|
+
return st.isDirectory();
|
|
23
27
|
}
|
|
24
28
|
function join(stem, filename) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
29
|
+
if (path__default.default.isAbsolute(filename)) {
|
|
30
|
+
return path__default.default.normalize(filename);
|
|
31
|
+
} else {
|
|
32
|
+
return path__default.default.normalize(path__default.default.join(stem, filename));
|
|
33
|
+
}
|
|
31
34
|
}
|
|
32
35
|
function directoryPattern(extensions) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
switch (extensions.length) {
|
|
37
|
+
case 0:
|
|
38
|
+
return "**/*";
|
|
39
|
+
case 1:
|
|
40
|
+
return `**/*.${extensions[0]}`;
|
|
41
|
+
default:
|
|
42
|
+
return `**/*.{${extensions.join(",")}}`;
|
|
43
|
+
}
|
|
41
44
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Takes a number of file patterns (globs) and returns array of expanded
|
|
44
|
-
* filenames.
|
|
45
|
-
*/
|
|
46
45
|
function expandFiles(patterns, options) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}, []);
|
|
77
|
-
/* only return unique matches */
|
|
78
|
-
return Array.from(new Set(files));
|
|
46
|
+
const cwd = options.cwd ?? process.cwd();
|
|
47
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
48
|
+
const files = patterns.reduce((result, pattern) => {
|
|
49
|
+
if (pattern === "-") {
|
|
50
|
+
result.push("/dev/stdin");
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
for (const filename of glob.globSync(pattern, { cwd })) {
|
|
54
|
+
const fullpath = join(cwd, filename);
|
|
55
|
+
if (isDirectory(fullpath)) {
|
|
56
|
+
const dir = expandFiles([directoryPattern(extensions)], { ...options, cwd: fullpath });
|
|
57
|
+
result = result.concat(dir.map((cur) => join(filename, cur)));
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
result.push(fullpath);
|
|
61
|
+
}
|
|
62
|
+
return result.sort((a, b) => {
|
|
63
|
+
const pa = a.split("/").length;
|
|
64
|
+
const pb = b.split("/").length;
|
|
65
|
+
if (pa !== pb) {
|
|
66
|
+
return pa - pb;
|
|
67
|
+
} else {
|
|
68
|
+
return a > b ? 1 : -1;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}, []);
|
|
72
|
+
return Array.from(new Set(files));
|
|
79
73
|
}
|
|
80
74
|
|
|
81
75
|
function wrap(formatter, dst) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
};
|
|
76
|
+
return (results) => {
|
|
77
|
+
const output = formatter(results);
|
|
78
|
+
if (dst) {
|
|
79
|
+
const dir = path__default.default.dirname(dst);
|
|
80
|
+
if (!fs__default.default.existsSync(dir)) {
|
|
81
|
+
fs__default.default.mkdirSync(dir, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
fs__default.default.writeFileSync(dst, output, "utf-8");
|
|
84
|
+
return "";
|
|
85
|
+
} else {
|
|
86
|
+
return output;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
96
89
|
}
|
|
97
90
|
function loadFormatter(name) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
91
|
+
const fn = core.getFormatter(name);
|
|
92
|
+
if (fn) {
|
|
93
|
+
return fn;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
return coreNodejs.legacyRequire(name);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw new core.UserError(`No formatter named "${name}"`, core.ensureError(error));
|
|
99
|
+
}
|
|
108
100
|
}
|
|
109
101
|
function getFormatter(formatters) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.filter(Boolean)
|
|
119
|
-
.join("\n");
|
|
120
|
-
};
|
|
102
|
+
const fn = formatters.split(",").map((cur) => {
|
|
103
|
+
const [name, dst] = cur.split("=", 2);
|
|
104
|
+
const fn2 = loadFormatter(name);
|
|
105
|
+
return wrap(fn2, dst);
|
|
106
|
+
});
|
|
107
|
+
return (report) => {
|
|
108
|
+
return fn.map((formatter) => formatter(report.results)).filter(Boolean).join("\n");
|
|
109
|
+
};
|
|
121
110
|
}
|
|
122
111
|
|
|
123
112
|
class IsIgnored {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const ig = core.ignore().add(content);
|
|
171
|
-
this.cacheIgnore.set(filename, ig);
|
|
172
|
-
return ig;
|
|
173
|
-
}
|
|
113
|
+
constructor() {
|
|
114
|
+
this.cacheIgnore = /* @__PURE__ */ new Map();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Searches ".htmlvalidateignore" files from filesystem and returns `true` if
|
|
118
|
+
* one of them contains a pattern matching given filename.
|
|
119
|
+
*/
|
|
120
|
+
isIgnored(filename) {
|
|
121
|
+
return this.match(filename);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Clear cache
|
|
125
|
+
*/
|
|
126
|
+
clearCache() {
|
|
127
|
+
this.cacheIgnore.clear();
|
|
128
|
+
}
|
|
129
|
+
match(target) {
|
|
130
|
+
let current = path__default.default.dirname(target);
|
|
131
|
+
while (true) {
|
|
132
|
+
const relative = path__default.default.relative(current, target);
|
|
133
|
+
const filename = path__default.default.join(current, ".htmlvalidateignore");
|
|
134
|
+
const ig = this.parseFile(filename);
|
|
135
|
+
if (ig && ig.ignores(relative)) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
const child = current;
|
|
139
|
+
current = path__default.default.dirname(current);
|
|
140
|
+
if (current === child) {
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
parseFile(filename) {
|
|
147
|
+
if (this.cacheIgnore.has(filename)) {
|
|
148
|
+
return this.cacheIgnore.get(filename);
|
|
149
|
+
}
|
|
150
|
+
if (!fs__default.default.existsSync(filename)) {
|
|
151
|
+
this.cacheIgnore.set(filename, void 0);
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
const content = fs__default.default.readFileSync(filename, "utf-8");
|
|
155
|
+
const ig = core.ignore().add(content);
|
|
156
|
+
this.cacheIgnore.set(filename, ig);
|
|
157
|
+
return ig;
|
|
158
|
+
}
|
|
174
159
|
}
|
|
175
160
|
|
|
176
|
-
var Frameworks;
|
|
177
|
-
(function (Frameworks) {
|
|
178
|
-
Frameworks["angularjs"] = "AngularJS";
|
|
179
|
-
Frameworks["vuejs"] = "Vue.js";
|
|
180
|
-
Frameworks["markdown"] = "Markdown";
|
|
181
|
-
})(Frameworks || (Frameworks = {}));
|
|
182
161
|
const frameworkConfig = {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
162
|
+
["AngularJS" /* angularjs */]: {
|
|
163
|
+
transform: {
|
|
164
|
+
"^.*\\.js$": "html-validate-angular/js",
|
|
165
|
+
"^.*\\.html$": "html-validate-angular/html"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
["Vue.js" /* vuejs */]: {
|
|
169
|
+
plugins: ["html-validate-vue"],
|
|
170
|
+
extends: ["html-validate-vue:recommended"],
|
|
171
|
+
transform: {
|
|
172
|
+
"^.*\\.vue$": "html-validate-vue"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
["Markdown" /* markdown */]: {
|
|
176
|
+
transform: {
|
|
177
|
+
"^.*\\.md$": "html-validate-markdown"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
201
180
|
};
|
|
202
181
|
function addFrameworks(src, frameworks) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
182
|
+
let config = src;
|
|
183
|
+
for (const framework of frameworks) {
|
|
184
|
+
config = core.deepmerge(config, frameworkConfig[framework]);
|
|
185
|
+
}
|
|
186
|
+
return config;
|
|
208
187
|
}
|
|
209
188
|
function writeConfig(dst, config) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
});
|
|
189
|
+
return new Promise((resolve, reject) => {
|
|
190
|
+
fs__default.default.writeFile(dst, JSON.stringify(config, null, 2), (err) => {
|
|
191
|
+
if (err)
|
|
192
|
+
reject(err);
|
|
193
|
+
resolve();
|
|
216
194
|
});
|
|
195
|
+
});
|
|
217
196
|
}
|
|
218
197
|
async function init$1(cwd) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return {
|
|
255
|
-
filename,
|
|
256
|
-
};
|
|
198
|
+
const filename = `${cwd}/.htmlvalidate.json`;
|
|
199
|
+
const exists = fs__default.default.existsSync(filename);
|
|
200
|
+
const initialConfig = {
|
|
201
|
+
elements: ["html5"],
|
|
202
|
+
extends: ["html-validate:recommended"]
|
|
203
|
+
};
|
|
204
|
+
if (exists) {
|
|
205
|
+
const result = await prompts__default.default({
|
|
206
|
+
name: "overwrite",
|
|
207
|
+
type: "confirm",
|
|
208
|
+
message: "A .htmlvalidate.json file already exists, do you want to overwrite it?"
|
|
209
|
+
});
|
|
210
|
+
if (!result.overwrite) {
|
|
211
|
+
return Promise.reject();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const questions = [
|
|
215
|
+
{
|
|
216
|
+
name: "frameworks",
|
|
217
|
+
type: "multiselect",
|
|
218
|
+
choices: [
|
|
219
|
+
{ title: "AngularJS" /* angularjs */, value: "AngularJS" /* angularjs */ },
|
|
220
|
+
{ title: "Vue.js" /* vuejs */, value: "Vue.js" /* vuejs */ },
|
|
221
|
+
{ title: "Markdown" /* markdown */, value: "Markdown" /* markdown */ }
|
|
222
|
+
],
|
|
223
|
+
message: "Support additional frameworks?"
|
|
224
|
+
}
|
|
225
|
+
];
|
|
226
|
+
const answers = await prompts__default.default(questions);
|
|
227
|
+
let config = initialConfig;
|
|
228
|
+
config = addFrameworks(config, answers.frameworks);
|
|
229
|
+
await writeConfig(filename, config);
|
|
230
|
+
return {
|
|
231
|
+
filename
|
|
232
|
+
};
|
|
257
233
|
}
|
|
258
234
|
|
|
259
235
|
const defaultConfig = {
|
|
260
|
-
|
|
236
|
+
extends: ["html-validate:recommended"]
|
|
261
237
|
};
|
|
262
238
|
function getBaseConfig(filename) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
239
|
+
if (filename) {
|
|
240
|
+
const resolver = coreNodejs.cjsResolver();
|
|
241
|
+
const configData = resolver.resolveConfig(path__default.default.resolve(filename), { cache: false });
|
|
242
|
+
if (!configData) {
|
|
243
|
+
throw new core.UserError(`Failed to read configuration from "${filename}"`);
|
|
244
|
+
}
|
|
245
|
+
return configData;
|
|
246
|
+
} else {
|
|
247
|
+
return defaultConfig;
|
|
248
|
+
}
|
|
274
249
|
}
|
|
275
|
-
/**
|
|
276
|
-
* @public
|
|
277
|
-
*/
|
|
278
250
|
class CLI {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Create new CLI helper.
|
|
253
|
+
*
|
|
254
|
+
* Can be used to create tooling with similar properties to bundled CLI
|
|
255
|
+
* script.
|
|
256
|
+
*/
|
|
257
|
+
constructor(options) {
|
|
258
|
+
this.options = options ?? {};
|
|
259
|
+
this.config = null;
|
|
260
|
+
this.loader = null;
|
|
261
|
+
this.ignored = new IsIgnored();
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Returns list of files matching patterns and are not ignored. Filenames will
|
|
265
|
+
* have absolute paths.
|
|
266
|
+
*
|
|
267
|
+
* @public
|
|
268
|
+
*/
|
|
269
|
+
expandFiles(patterns, options = {}) {
|
|
270
|
+
return expandFiles(patterns, options).filter((filename) => !this.isIgnored(filename));
|
|
271
|
+
}
|
|
272
|
+
getFormatter(formatters) {
|
|
273
|
+
return getFormatter(formatters);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Initialize project with a new configuration.
|
|
277
|
+
*
|
|
278
|
+
* A new `.htmlvalidate.json` file will be placed in the path provided by
|
|
279
|
+
* `cwd`.
|
|
280
|
+
*/
|
|
281
|
+
init(cwd) {
|
|
282
|
+
return init$1(cwd);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Searches ".htmlvalidateignore" files from filesystem and returns `true` if
|
|
286
|
+
* one of them contains a pattern matching given filename.
|
|
287
|
+
*/
|
|
288
|
+
isIgnored(filename) {
|
|
289
|
+
return this.ignored.isIgnored(filename);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Clear cache.
|
|
293
|
+
*
|
|
294
|
+
* Previously fetched [[HtmlValidate]] instances must either be fetched again
|
|
295
|
+
* or call [[HtmlValidate.flushConfigCache]].
|
|
296
|
+
*/
|
|
297
|
+
/* istanbul ignore next: each method is tested separately */
|
|
298
|
+
clearCache() {
|
|
299
|
+
if (this.loader) {
|
|
300
|
+
this.loader.flushCache();
|
|
301
|
+
}
|
|
302
|
+
this.ignored.clearCache();
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get HtmlValidate instance with configuration based on options passed to the
|
|
306
|
+
* constructor.
|
|
307
|
+
*
|
|
308
|
+
* @internal
|
|
309
|
+
*/
|
|
310
|
+
getLoader() {
|
|
311
|
+
if (!this.loader) {
|
|
312
|
+
this.loader = new coreNodejs.FileSystemConfigLoader(this.getConfig());
|
|
313
|
+
}
|
|
314
|
+
return this.loader;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get HtmlValidate instance with configuration based on options passed to the
|
|
318
|
+
* constructor.
|
|
319
|
+
*
|
|
320
|
+
* @public
|
|
321
|
+
*/
|
|
322
|
+
getValidator() {
|
|
323
|
+
const loader = this.getLoader();
|
|
324
|
+
return new core.HtmlValidate(loader);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* @internal
|
|
328
|
+
*/
|
|
329
|
+
getConfig() {
|
|
330
|
+
if (!this.config) {
|
|
331
|
+
this.config = this.resolveConfig();
|
|
332
|
+
}
|
|
333
|
+
return this.config;
|
|
334
|
+
}
|
|
335
|
+
resolveConfig() {
|
|
336
|
+
const { options } = this;
|
|
337
|
+
const config = getBaseConfig(options.configFile);
|
|
338
|
+
if (options.rules) {
|
|
339
|
+
const rules = Array.isArray(options.rules) ? options.rules : [options.rules];
|
|
340
|
+
try {
|
|
341
|
+
const severityMap = { off: 0, warn: 1, error: 2 };
|
|
342
|
+
const ruleConfig = rules.reduce((parsedRules, rule) => {
|
|
343
|
+
const [ruleName, ruleSeverity] = rule.trim().split(":");
|
|
344
|
+
const severityValue = severityMap[ruleSeverity] ?? parseInt(ruleSeverity, 10);
|
|
345
|
+
if (!Object.values(severityMap).includes(severityValue)) {
|
|
346
|
+
throw new Error(`Invalid severity value for rule "${ruleName}": ${ruleSeverity}`);
|
|
347
|
+
}
|
|
348
|
+
parsedRules[ruleName] = severityValue;
|
|
349
|
+
return parsedRules;
|
|
350
|
+
}, {});
|
|
351
|
+
config.extends = [];
|
|
352
|
+
config.rules = ruleConfig;
|
|
353
|
+
} catch (err) {
|
|
354
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
355
|
+
throw new core.UserError(
|
|
356
|
+
`Error while parsing --rule option "{${rules.join(",")}": ${message}.
|
|
357
|
+
`
|
|
358
|
+
);
|
|
359
|
+
}
|
|
381
360
|
}
|
|
361
|
+
return config;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function prettyError(err) {
|
|
366
|
+
let json;
|
|
367
|
+
if (err.filename && fs__default$1.default.existsSync(err.filename)) {
|
|
368
|
+
json = fs__default$1.default.readFileSync(err.filename, "utf-8");
|
|
369
|
+
}
|
|
370
|
+
return betterAjvErrors__default.default(err.schema, err.obj, err.errors, {
|
|
371
|
+
format: "cli",
|
|
372
|
+
indent: 2,
|
|
373
|
+
json
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
function handleSchemaValidationError(console, err) {
|
|
377
|
+
if (err.filename) {
|
|
378
|
+
const filename = path__default.default.relative(process.cwd(), err.filename);
|
|
379
|
+
console.error(kleur__default.default.red(`A configuration error was found in "${filename}":`));
|
|
380
|
+
} else {
|
|
381
|
+
console.error(kleur__default.default.red(`A configuration error was found:`));
|
|
382
|
+
}
|
|
383
|
+
console.group();
|
|
384
|
+
{
|
|
385
|
+
console.error(prettyError(err));
|
|
386
|
+
}
|
|
387
|
+
console.groupEnd();
|
|
382
388
|
}
|
|
383
389
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
Mode[Mode["DUMP_SOURCE"] = 5] = "DUMP_SOURCE";
|
|
395
|
-
Mode[Mode["PRINT_CONFIG"] = 6] = "PRINT_CONFIG";
|
|
396
|
-
})(exports.Mode || (exports.Mode = {}));
|
|
390
|
+
var Mode = /* @__PURE__ */ ((Mode2) => {
|
|
391
|
+
Mode2[Mode2["LINT"] = 0] = "LINT";
|
|
392
|
+
Mode2[Mode2["INIT"] = 1] = "INIT";
|
|
393
|
+
Mode2[Mode2["DUMP_EVENTS"] = 2] = "DUMP_EVENTS";
|
|
394
|
+
Mode2[Mode2["DUMP_TOKENS"] = 3] = "DUMP_TOKENS";
|
|
395
|
+
Mode2[Mode2["DUMP_TREE"] = 4] = "DUMP_TREE";
|
|
396
|
+
Mode2[Mode2["DUMP_SOURCE"] = 5] = "DUMP_SOURCE";
|
|
397
|
+
Mode2[Mode2["PRINT_CONFIG"] = 6] = "PRINT_CONFIG";
|
|
398
|
+
return Mode2;
|
|
399
|
+
})(Mode || {});
|
|
397
400
|
function modeToFlag(mode) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
401
|
+
switch (mode) {
|
|
402
|
+
case 0 /* LINT */:
|
|
403
|
+
return null;
|
|
404
|
+
case 1 /* INIT */:
|
|
405
|
+
return "--init";
|
|
406
|
+
case 2 /* DUMP_EVENTS */:
|
|
407
|
+
return "--dump-events";
|
|
408
|
+
case 3 /* DUMP_TOKENS */:
|
|
409
|
+
return "--dump-tokens";
|
|
410
|
+
case 4 /* DUMP_TREE */:
|
|
411
|
+
return "--dump-tree";
|
|
412
|
+
case 5 /* DUMP_SOURCE */:
|
|
413
|
+
return "--dump-source";
|
|
414
|
+
case 6 /* PRINT_CONFIG */:
|
|
415
|
+
return "--print-config";
|
|
416
|
+
}
|
|
414
417
|
}
|
|
415
418
|
|
|
416
419
|
function renameStdin(report, filename) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
420
|
+
const stdin = report.results.find((cur) => cur.filePath === "/dev/stdin");
|
|
421
|
+
if (stdin) {
|
|
422
|
+
stdin.filePath = filename;
|
|
423
|
+
}
|
|
421
424
|
}
|
|
422
|
-
function lint(htmlvalidate, output, files, options) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
425
|
+
async function lint(htmlvalidate, output, files, options) {
|
|
426
|
+
const reports = files.map(async (filename) => {
|
|
427
|
+
try {
|
|
428
|
+
return await htmlvalidate.validateFile(filename);
|
|
429
|
+
} catch (err) {
|
|
430
|
+
const message = kleur__default.default.red(`Validator crashed when parsing "${filename}"`);
|
|
431
|
+
output.write(`${message}
|
|
432
|
+
`);
|
|
433
|
+
throw err;
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
const merged = await core.Reporter.merge(reports);
|
|
437
|
+
if (options.stdinFilename) {
|
|
438
|
+
renameStdin(merged, options.stdinFilename);
|
|
439
|
+
}
|
|
440
|
+
output.write(options.formatter(merged));
|
|
441
|
+
if (options.maxWarnings >= 0 && merged.warningCount > options.maxWarnings) {
|
|
442
|
+
output.write(`
|
|
443
|
+
html-validate found too many warnings (maximum: ${options.maxWarnings}).
|
|
444
|
+
`);
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
return merged.valid;
|
|
444
448
|
}
|
|
445
449
|
|
|
446
450
|
async function init(cli, output, options) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
451
|
+
const result = await cli.init(options.cwd);
|
|
452
|
+
output.write(`Configuration written to "${result.filename}"
|
|
453
|
+
`);
|
|
454
|
+
return true;
|
|
450
455
|
}
|
|
451
456
|
|
|
452
457
|
async function printConfig(htmlvalidate, output, files) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
if (files.length > 1) {
|
|
459
|
+
output.write(`\`--print-config\` expected a single filename but got multiple:
|
|
460
|
+
|
|
461
|
+
`);
|
|
462
|
+
for (const filename of files) {
|
|
463
|
+
output.write(` - ${filename}
|
|
464
|
+
`);
|
|
460
465
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
466
|
+
output.write("\n");
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
const config = await htmlvalidate.getConfigFor(files[0]);
|
|
470
|
+
const json = JSON.stringify(config.getConfigData(), null, 2);
|
|
471
|
+
output.write(`${json}
|
|
472
|
+
`);
|
|
473
|
+
return true;
|
|
465
474
|
}
|
|
466
475
|
|
|
467
476
|
const jsonIgnored = [
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
+
"annotation",
|
|
478
|
+
"blockedRules",
|
|
479
|
+
"cache",
|
|
480
|
+
"closed",
|
|
481
|
+
"depth",
|
|
482
|
+
"disabledRules",
|
|
483
|
+
"nodeType",
|
|
484
|
+
"unique",
|
|
485
|
+
"voidElement"
|
|
477
486
|
];
|
|
478
487
|
const jsonFiltered = [
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
488
|
+
"childNodes",
|
|
489
|
+
"children",
|
|
490
|
+
"data",
|
|
491
|
+
"meta",
|
|
492
|
+
"metaElement",
|
|
493
|
+
"originalData",
|
|
494
|
+
"parent"
|
|
486
495
|
];
|
|
487
496
|
function isLocation(key, value) {
|
|
488
|
-
|
|
497
|
+
return Boolean(value && (key === "location" || key.endsWith("Location")));
|
|
489
498
|
}
|
|
490
499
|
function isIgnored(key) {
|
|
491
|
-
|
|
500
|
+
return Boolean(key.startsWith("_") || jsonIgnored.includes(key));
|
|
492
501
|
}
|
|
493
502
|
function isFiltered(key, value) {
|
|
494
|
-
|
|
503
|
+
return Boolean(value && jsonFiltered.includes(key));
|
|
495
504
|
}
|
|
496
505
|
function eventReplacer(key, value) {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
506
|
+
if (isLocation(key, value)) {
|
|
507
|
+
return `${value.filename}:${value.line}:${value.column}`;
|
|
508
|
+
}
|
|
509
|
+
if (isIgnored(key)) {
|
|
510
|
+
return void 0;
|
|
511
|
+
}
|
|
512
|
+
if (isFiltered(key, value)) {
|
|
513
|
+
return "[truncated]";
|
|
514
|
+
}
|
|
515
|
+
return value;
|
|
507
516
|
}
|
|
508
517
|
function eventFormatter(entry) {
|
|
509
|
-
|
|
510
|
-
|
|
518
|
+
const strdata = JSON.stringify(entry.data, eventReplacer, 2);
|
|
519
|
+
return `${entry.event}: ${strdata}`;
|
|
511
520
|
}
|
|
512
521
|
|
|
513
522
|
function dump(htmlvalidate, output, files, mode) {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
523
|
+
let lines = [];
|
|
524
|
+
switch (mode) {
|
|
525
|
+
case Mode.DUMP_EVENTS:
|
|
526
|
+
lines = files.map(
|
|
527
|
+
(filename) => htmlvalidate.dumpEvents(filename).map(eventFormatter)
|
|
528
|
+
);
|
|
529
|
+
break;
|
|
530
|
+
case Mode.DUMP_TOKENS:
|
|
531
|
+
lines = files.map(
|
|
532
|
+
(filename) => htmlvalidate.dumpTokens(filename).map((entry) => {
|
|
533
|
+
const data = JSON.stringify(entry.data);
|
|
534
|
+
return `TOKEN: ${entry.token}
|
|
535
|
+
Data: ${data}
|
|
536
|
+
Location: ${entry.location}`;
|
|
537
|
+
})
|
|
538
|
+
);
|
|
539
|
+
break;
|
|
540
|
+
case Mode.DUMP_TREE:
|
|
541
|
+
lines = files.map((filename) => htmlvalidate.dumpTree(filename));
|
|
542
|
+
break;
|
|
543
|
+
case Mode.DUMP_SOURCE:
|
|
544
|
+
lines = files.map((filename) => htmlvalidate.dumpSource(filename));
|
|
545
|
+
break;
|
|
546
|
+
default:
|
|
547
|
+
throw new Error(`Unknown mode "${mode}"`);
|
|
548
|
+
}
|
|
549
|
+
const flat = lines.reduce((s, c) => s.concat(c), []);
|
|
550
|
+
output.write(flat.join("\n"));
|
|
551
|
+
output.write("\n");
|
|
552
|
+
return Promise.resolve(true);
|
|
538
553
|
}
|
|
539
554
|
|
|
540
555
|
exports.CLI = CLI;
|
|
556
|
+
exports.Mode = Mode;
|
|
541
557
|
exports.dump = dump;
|
|
558
|
+
exports.handleSchemaValidationError = handleSchemaValidationError;
|
|
542
559
|
exports.init = init;
|
|
543
560
|
exports.lint = lint;
|
|
544
561
|
exports.modeToFlag = modeToFlag;
|