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