html-validate 10.14.0 → 10.15.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 +1 -0
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/cli.js +50 -4
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core-browser.js +60 -11
- package/dist/cjs/core-browser.js.map +1 -1
- package/dist/cjs/core-nodejs.js +60 -11
- package/dist/cjs/core-nodejs.js.map +1 -1
- package/dist/cjs/core.js +306 -176
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/html-validate.js +4 -1
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/browser.js +1 -1
- package/dist/esm/cli.js +51 -5
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/core-browser.js +61 -12
- package/dist/esm/core-browser.js.map +1 -1
- package/dist/esm/core-nodejs.js +61 -12
- package/dist/esm/core-nodejs.js.map +1 -1
- package/dist/esm/core.js +306 -177
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/html-validate.js +5 -2
- package/dist/esm/html-validate.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/matcher-utils.js +1 -1
- package/dist/esm/matchers.js +1 -1
- package/dist/types/browser.d.ts +15 -0
- package/dist/types/index.d.ts +15 -0
- package/package.json +1 -1
package/dist/esm/core.js
CHANGED
|
@@ -1195,9 +1195,6 @@ function clone(value) {
|
|
|
1195
1195
|
return JSON.parse(JSON.stringify(value));
|
|
1196
1196
|
}
|
|
1197
1197
|
}
|
|
1198
|
-
function overwriteMerge$1(_a, b) {
|
|
1199
|
-
return b;
|
|
1200
|
-
}
|
|
1201
1198
|
class MetaTable {
|
|
1202
1199
|
elements;
|
|
1203
1200
|
schema;
|
|
@@ -1370,15 +1367,22 @@ class MetaTable {
|
|
|
1370
1367
|
}
|
|
1371
1368
|
}
|
|
1372
1369
|
mergeElement(a, b) {
|
|
1373
|
-
const merged =
|
|
1374
|
-
const
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1370
|
+
const merged = { ...a, ...b };
|
|
1371
|
+
const mergedAttrs = {
|
|
1372
|
+
...a.attributes,
|
|
1373
|
+
...b.attributes
|
|
1374
|
+
};
|
|
1375
|
+
for (const [name, attr] of Object.entries(mergedAttrs)) {
|
|
1376
|
+
if (attr.delete) {
|
|
1377
|
+
delete mergedAttrs[name];
|
|
1378
|
+
} else {
|
|
1379
|
+
delete attr.delete;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
merged.attributes = mergedAttrs;
|
|
1383
|
+
if (a.aria) {
|
|
1384
|
+
merged.aria = { ...a.aria, ...b.aria };
|
|
1385
|
+
}
|
|
1382
1386
|
return merged;
|
|
1383
1387
|
}
|
|
1384
1388
|
/**
|
|
@@ -1959,71 +1963,68 @@ function factory(name, context) {
|
|
|
1959
1963
|
function stripslashes(value) {
|
|
1960
1964
|
return value.replaceAll(/\\(.)/g, "$1");
|
|
1961
1965
|
}
|
|
1962
|
-
|
|
1966
|
+
function createClassCondition(classname) {
|
|
1967
|
+
return {
|
|
1968
|
+
kind: "class",
|
|
1969
|
+
classname,
|
|
1970
|
+
match(node) {
|
|
1971
|
+
return node.classList.contains(classname);
|
|
1972
|
+
}
|
|
1973
|
+
};
|
|
1963
1974
|
}
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
}
|
|
1975
|
+
function createIdCondition(raw) {
|
|
1976
|
+
const id = stripslashes(raw);
|
|
1977
|
+
return {
|
|
1978
|
+
kind: "id",
|
|
1979
|
+
id,
|
|
1980
|
+
match(node) {
|
|
1981
|
+
return node.id === id;
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1973
1984
|
}
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1985
|
+
function createAttributeCondition(attr) {
|
|
1986
|
+
const match = /^(.+?)(?:([$*^|~]?=)"([^"]+?)")?$/.exec(attr);
|
|
1987
|
+
const key = match[1];
|
|
1988
|
+
const op = match[2];
|
|
1989
|
+
const rawValue = match[3];
|
|
1990
|
+
const value = typeof rawValue === "string" ? stripslashes(rawValue) : rawValue;
|
|
1991
|
+
return {
|
|
1992
|
+
kind: "attribute",
|
|
1993
|
+
key,
|
|
1994
|
+
op,
|
|
1995
|
+
value,
|
|
1996
|
+
match(node) {
|
|
1997
|
+
const attrs = node.getAttribute(key, true);
|
|
1998
|
+
return attrs.some((cur) => {
|
|
1999
|
+
switch (op) {
|
|
2000
|
+
case void 0:
|
|
2001
|
+
return true;
|
|
2002
|
+
/* attribute exists */
|
|
2003
|
+
case "=":
|
|
2004
|
+
return cur.value === value;
|
|
2005
|
+
default:
|
|
2006
|
+
throw new Error(`Attribute selector operator ${op} is not implemented yet`);
|
|
2007
|
+
}
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
1983
2011
|
}
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
constructor(attr) {
|
|
1989
|
-
super();
|
|
1990
|
-
const [, key, op, value] = /^(.+?)(?:([$*^|~]?=)"([^"]+?)")?$/.exec(attr);
|
|
1991
|
-
this.key = key;
|
|
1992
|
-
this.op = op;
|
|
1993
|
-
this.value = typeof value === "string" ? stripslashes(value) : value;
|
|
1994
|
-
}
|
|
1995
|
-
match(node) {
|
|
1996
|
-
const attr = node.getAttribute(this.key, true);
|
|
1997
|
-
return attr.some((cur) => {
|
|
1998
|
-
switch (this.op) {
|
|
1999
|
-
case void 0:
|
|
2000
|
-
return true;
|
|
2001
|
-
/* attribute exists */
|
|
2002
|
-
case "=":
|
|
2003
|
-
return cur.value === this.value;
|
|
2004
|
-
default:
|
|
2005
|
-
throw new Error(`Attribute selector operator ${this.op} is not implemented yet`);
|
|
2006
|
-
}
|
|
2007
|
-
});
|
|
2012
|
+
function createPseudoClassCondition(pseudoclass, context) {
|
|
2013
|
+
const match = /^([^(]+)(?:\((.*)\))?$/.exec(pseudoclass);
|
|
2014
|
+
if (!match) {
|
|
2015
|
+
throw new Error(`Missing pseudo-class after colon in selector pattern "${context}"`);
|
|
2008
2016
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2017
|
+
const name = match[1];
|
|
2018
|
+
const args = match[2];
|
|
2019
|
+
return {
|
|
2020
|
+
kind: "pseudo",
|
|
2021
|
+
name,
|
|
2022
|
+
args,
|
|
2023
|
+
match(node, selectorContext) {
|
|
2024
|
+
const fn = factory(name, selectorContext);
|
|
2025
|
+
return fn(node, args);
|
|
2018
2026
|
}
|
|
2019
|
-
|
|
2020
|
-
this.name = name;
|
|
2021
|
-
this.args = args;
|
|
2022
|
-
}
|
|
2023
|
-
match(node, context) {
|
|
2024
|
-
const fn = factory(this.name, context);
|
|
2025
|
-
return fn(node, this.args);
|
|
2026
|
-
}
|
|
2027
|
+
};
|
|
2027
2028
|
}
|
|
2028
2029
|
|
|
2029
2030
|
function isDelimiter(ch) {
|
|
@@ -2098,37 +2099,84 @@ class Compound {
|
|
|
2098
2099
|
createCondition(pattern) {
|
|
2099
2100
|
switch (pattern[0]) {
|
|
2100
2101
|
case ".":
|
|
2101
|
-
return
|
|
2102
|
+
return createClassCondition(pattern.slice(1));
|
|
2102
2103
|
case "#":
|
|
2103
|
-
return
|
|
2104
|
+
return createIdCondition(pattern.slice(1));
|
|
2104
2105
|
case "[":
|
|
2105
|
-
return
|
|
2106
|
+
return createAttributeCondition(pattern.slice(1, -1));
|
|
2106
2107
|
case ":":
|
|
2107
|
-
return
|
|
2108
|
+
return createPseudoClassCondition(pattern.slice(1), this.selector);
|
|
2108
2109
|
default:
|
|
2109
2110
|
throw new Error(`Failed to create selector condition for "${pattern}"`);
|
|
2110
2111
|
}
|
|
2111
2112
|
}
|
|
2112
2113
|
}
|
|
2113
2114
|
|
|
2114
|
-
const
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
if (codepoints[ch]) {
|
|
2122
|
-
return codepoints[ch];
|
|
2123
|
-
} else {
|
|
2124
|
-
return `\\${ch}`;
|
|
2115
|
+
const escapedCodepoints = /* @__PURE__ */ new Set(["9", "a", "d"]);
|
|
2116
|
+
function* splitSelectorElements(selector) {
|
|
2117
|
+
let begin = 0;
|
|
2118
|
+
let end = 0;
|
|
2119
|
+
function initialState(ch, p) {
|
|
2120
|
+
if (ch === "\\") {
|
|
2121
|
+
return 1 /* ESCAPED */;
|
|
2125
2122
|
}
|
|
2126
|
-
|
|
2123
|
+
if (ch === " ") {
|
|
2124
|
+
end = p;
|
|
2125
|
+
return 2 /* WHITESPACE */;
|
|
2126
|
+
}
|
|
2127
|
+
return 0 /* INITIAL */;
|
|
2128
|
+
}
|
|
2129
|
+
function escapedState(ch) {
|
|
2130
|
+
if (escapedCodepoints.has(ch)) {
|
|
2131
|
+
return 1 /* ESCAPED */;
|
|
2132
|
+
}
|
|
2133
|
+
return 0 /* INITIAL */;
|
|
2134
|
+
}
|
|
2135
|
+
function* whitespaceState(ch, p) {
|
|
2136
|
+
if (ch === " ") {
|
|
2137
|
+
return 2 /* WHITESPACE */;
|
|
2138
|
+
}
|
|
2139
|
+
yield selector.slice(begin, end);
|
|
2140
|
+
begin = p;
|
|
2141
|
+
end = p;
|
|
2142
|
+
return 0 /* INITIAL */;
|
|
2143
|
+
}
|
|
2144
|
+
let state = 0 /* INITIAL */;
|
|
2145
|
+
for (let p = 0; p < selector.length; p++) {
|
|
2146
|
+
const ch = selector[p];
|
|
2147
|
+
switch (state) {
|
|
2148
|
+
case 0 /* INITIAL */:
|
|
2149
|
+
state = initialState(ch, p);
|
|
2150
|
+
break;
|
|
2151
|
+
case 1 /* ESCAPED */:
|
|
2152
|
+
state = escapedState(ch);
|
|
2153
|
+
break;
|
|
2154
|
+
case 2 /* WHITESPACE */:
|
|
2155
|
+
state = yield* whitespaceState(ch, p);
|
|
2156
|
+
break;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
if (begin !== selector.length) {
|
|
2160
|
+
yield selector.slice(begin);
|
|
2161
|
+
}
|
|
2127
2162
|
}
|
|
2128
2163
|
|
|
2129
|
-
function
|
|
2130
|
-
const
|
|
2131
|
-
|
|
2164
|
+
function unescapeCodepoint(value) {
|
|
2165
|
+
const replacement = {
|
|
2166
|
+
"\\9 ": " ",
|
|
2167
|
+
"\\a ": "\n",
|
|
2168
|
+
"\\d ": "\r"
|
|
2169
|
+
};
|
|
2170
|
+
return value.replaceAll(
|
|
2171
|
+
/(\\[9ad] )/g,
|
|
2172
|
+
(_, codepoint) => replacement[codepoint]
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
function getCompounds(selector) {
|
|
2176
|
+
selector = selector.replaceAll(/([+>~]) /g, "$1");
|
|
2177
|
+
return Array.from(splitSelectorElements(selector), (element) => {
|
|
2178
|
+
return new Compound(unescapeCodepoint(element));
|
|
2179
|
+
});
|
|
2132
2180
|
}
|
|
2133
2181
|
|
|
2134
2182
|
function* ancestors$1(element) {
|
|
@@ -2193,70 +2241,16 @@ function matchElement(element, compounds, context) {
|
|
|
2193
2241
|
return false;
|
|
2194
2242
|
}
|
|
2195
2243
|
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
function initialState(ch, p) {
|
|
2201
|
-
if (ch === "\\") {
|
|
2202
|
-
return 1 /* ESCAPED */;
|
|
2203
|
-
}
|
|
2204
|
-
if (ch === " ") {
|
|
2205
|
-
end = p;
|
|
2206
|
-
return 2 /* WHITESPACE */;
|
|
2207
|
-
}
|
|
2208
|
-
return 0 /* INITIAL */;
|
|
2244
|
+
class ComplexSelector {
|
|
2245
|
+
compounds;
|
|
2246
|
+
constructor(compounds) {
|
|
2247
|
+
this.compounds = compounds;
|
|
2209
2248
|
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
return 1 /* ESCAPED */;
|
|
2213
|
-
}
|
|
2214
|
-
return 0 /* INITIAL */;
|
|
2249
|
+
static fromString(selector) {
|
|
2250
|
+
return new ComplexSelector(getCompounds(selector));
|
|
2215
2251
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
return 2 /* WHITESPACE */;
|
|
2219
|
-
}
|
|
2220
|
-
yield selector.slice(begin, end);
|
|
2221
|
-
begin = p;
|
|
2222
|
-
end = p;
|
|
2223
|
-
return 0 /* INITIAL */;
|
|
2224
|
-
}
|
|
2225
|
-
let state = 0 /* INITIAL */;
|
|
2226
|
-
for (let p = 0; p < selector.length; p++) {
|
|
2227
|
-
const ch = selector[p];
|
|
2228
|
-
switch (state) {
|
|
2229
|
-
case 0 /* INITIAL */:
|
|
2230
|
-
state = initialState(ch, p);
|
|
2231
|
-
break;
|
|
2232
|
-
case 1 /* ESCAPED */:
|
|
2233
|
-
state = escapedState(ch);
|
|
2234
|
-
break;
|
|
2235
|
-
case 2 /* WHITESPACE */:
|
|
2236
|
-
state = yield* whitespaceState(ch, p);
|
|
2237
|
-
break;
|
|
2238
|
-
}
|
|
2239
|
-
}
|
|
2240
|
-
if (begin !== selector.length) {
|
|
2241
|
-
yield selector.slice(begin);
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
|
|
2245
|
-
function unescapeCodepoint(value) {
|
|
2246
|
-
const replacement = {
|
|
2247
|
-
"\\9 ": " ",
|
|
2248
|
-
"\\a ": "\n",
|
|
2249
|
-
"\\d ": "\r"
|
|
2250
|
-
};
|
|
2251
|
-
return value.replaceAll(
|
|
2252
|
-
/(\\[9ad] )/g,
|
|
2253
|
-
(_, codepoint) => replacement[codepoint]
|
|
2254
|
-
);
|
|
2255
|
-
}
|
|
2256
|
-
class Selector {
|
|
2257
|
-
pattern;
|
|
2258
|
-
constructor(selector) {
|
|
2259
|
-
this.pattern = Selector.parse(selector);
|
|
2252
|
+
static fromCompounds(compounds) {
|
|
2253
|
+
return new ComplexSelector(compounds);
|
|
2260
2254
|
}
|
|
2261
2255
|
/**
|
|
2262
2256
|
* Match this selector against a HtmlElement.
|
|
@@ -2273,15 +2267,15 @@ class Selector {
|
|
|
2273
2267
|
*/
|
|
2274
2268
|
matchElement(element) {
|
|
2275
2269
|
const context = { scope: null };
|
|
2276
|
-
return matchElement(element, this.
|
|
2270
|
+
return matchElement(element, this.compounds, context);
|
|
2277
2271
|
}
|
|
2278
2272
|
*matchInternal(root, level, context) {
|
|
2279
|
-
if (level >= this.
|
|
2273
|
+
if (level >= this.compounds.length) {
|
|
2280
2274
|
yield root;
|
|
2281
2275
|
return;
|
|
2282
2276
|
}
|
|
2283
|
-
const pattern = this.
|
|
2284
|
-
const matches =
|
|
2277
|
+
const pattern = this.compounds[level];
|
|
2278
|
+
const matches = ComplexSelector.findCandidates(root, pattern);
|
|
2285
2279
|
for (const node of matches) {
|
|
2286
2280
|
if (!pattern.match(node, context)) {
|
|
2287
2281
|
continue;
|
|
@@ -2289,12 +2283,6 @@ class Selector {
|
|
|
2289
2283
|
yield* this.matchInternal(node, level + 1, context);
|
|
2290
2284
|
}
|
|
2291
2285
|
}
|
|
2292
|
-
static parse(selector) {
|
|
2293
|
-
selector = selector.replaceAll(/([+>~]) /g, "$1");
|
|
2294
|
-
return Array.from(splitSelectorElements(selector), (element) => {
|
|
2295
|
-
return new Compound(unescapeCodepoint(element));
|
|
2296
|
-
});
|
|
2297
|
-
}
|
|
2298
2286
|
static findCandidates(root, pattern) {
|
|
2299
2287
|
switch (pattern.combinator) {
|
|
2300
2288
|
case Combinator.DESCENDANT:
|
|
@@ -2302,9 +2290,9 @@ class Selector {
|
|
|
2302
2290
|
case Combinator.CHILD:
|
|
2303
2291
|
return root.childElements.filter((node) => node.is(pattern.tagName));
|
|
2304
2292
|
case Combinator.ADJACENT_SIBLING:
|
|
2305
|
-
return
|
|
2293
|
+
return ComplexSelector.findAdjacentSibling(root);
|
|
2306
2294
|
case Combinator.GENERAL_SIBLING:
|
|
2307
|
-
return
|
|
2295
|
+
return ComplexSelector.findGeneralSibling(root);
|
|
2308
2296
|
case Combinator.SCOPE:
|
|
2309
2297
|
return [root];
|
|
2310
2298
|
}
|
|
@@ -2316,7 +2304,7 @@ class Selector {
|
|
|
2316
2304
|
adjacent = false;
|
|
2317
2305
|
return true;
|
|
2318
2306
|
}
|
|
2319
|
-
if (cur
|
|
2307
|
+
if (cur.isSameNode(node)) {
|
|
2320
2308
|
adjacent = true;
|
|
2321
2309
|
}
|
|
2322
2310
|
return false;
|
|
@@ -2328,7 +2316,7 @@ class Selector {
|
|
|
2328
2316
|
if (after) {
|
|
2329
2317
|
return true;
|
|
2330
2318
|
}
|
|
2331
|
-
if (cur
|
|
2319
|
+
if (cur.isSameNode(node)) {
|
|
2332
2320
|
after = true;
|
|
2333
2321
|
}
|
|
2334
2322
|
return false;
|
|
@@ -2336,6 +2324,31 @@ class Selector {
|
|
|
2336
2324
|
}
|
|
2337
2325
|
}
|
|
2338
2326
|
|
|
2327
|
+
const codepoints = {
|
|
2328
|
+
" ": "\\9 ",
|
|
2329
|
+
"\n": "\\a ",
|
|
2330
|
+
"\r": "\\d "
|
|
2331
|
+
};
|
|
2332
|
+
function escapeSelectorComponent(text) {
|
|
2333
|
+
return text.toString().replaceAll(/([\t\n\r]|[^\w-])/gi, (_, ch) => {
|
|
2334
|
+
if (codepoints[ch]) {
|
|
2335
|
+
return codepoints[ch];
|
|
2336
|
+
} else {
|
|
2337
|
+
return `\\${ch}`;
|
|
2338
|
+
}
|
|
2339
|
+
});
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
function generateIdSelector(id) {
|
|
2343
|
+
const escaped = escapeSelectorComponent(id);
|
|
2344
|
+
return /^\d/.test(escaped) ? `[id="${escaped}"]` : `#${escaped}`;
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
function parseSelector(selector) {
|
|
2348
|
+
const compounds = getCompounds(selector);
|
|
2349
|
+
return ComplexSelector.fromCompounds(compounds);
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2339
2352
|
const TEXT_NODE_NAME = "#text";
|
|
2340
2353
|
function isTextNode(node) {
|
|
2341
2354
|
return node?.nodeType === NodeType.TEXT_NODE;
|
|
@@ -2649,7 +2662,7 @@ class HtmlElement extends DOMNode {
|
|
|
2649
2662
|
*/
|
|
2650
2663
|
matches(selectorList) {
|
|
2651
2664
|
return selectorList.split(",").some((it) => {
|
|
2652
|
-
const selector =
|
|
2665
|
+
const selector = parseSelector(it.trim());
|
|
2653
2666
|
return selector.matchElement(this);
|
|
2654
2667
|
});
|
|
2655
2668
|
}
|
|
@@ -2882,9 +2895,9 @@ class HtmlElement extends DOMNode {
|
|
|
2882
2895
|
if (!selectorList) {
|
|
2883
2896
|
return;
|
|
2884
2897
|
}
|
|
2885
|
-
for (const
|
|
2886
|
-
const
|
|
2887
|
-
yield*
|
|
2898
|
+
for (const selectorString of selectorList.split(/(?<!\\),\s*/)) {
|
|
2899
|
+
const selector = parseSelector(selectorString);
|
|
2900
|
+
yield* selector.match(this);
|
|
2888
2901
|
}
|
|
2889
2902
|
}
|
|
2890
2903
|
/**
|
|
@@ -3737,6 +3750,7 @@ class Rule {
|
|
|
3737
3750
|
severity;
|
|
3738
3751
|
// rule severity
|
|
3739
3752
|
event;
|
|
3753
|
+
tracker;
|
|
3740
3754
|
/**
|
|
3741
3755
|
* Rule name. Defaults to filename without extension but can be overwritten by
|
|
3742
3756
|
* subclasses.
|
|
@@ -3756,6 +3770,7 @@ class Rule {
|
|
|
3756
3770
|
this.blockers = [];
|
|
3757
3771
|
this.severity = Severity.DISABLED;
|
|
3758
3772
|
this.name = "";
|
|
3773
|
+
this.tracker = null;
|
|
3759
3774
|
}
|
|
3760
3775
|
getSeverity() {
|
|
3761
3776
|
return this.severity;
|
|
@@ -3931,7 +3946,15 @@ class Rule {
|
|
|
3931
3946
|
return this.parser.on(event, (_event, data) => {
|
|
3932
3947
|
if (this.isEnabled() && filter(data)) {
|
|
3933
3948
|
this.event = data;
|
|
3934
|
-
|
|
3949
|
+
const { tracker } = this;
|
|
3950
|
+
if (tracker) {
|
|
3951
|
+
const start = performance.now();
|
|
3952
|
+
callback(data);
|
|
3953
|
+
const end = performance.now();
|
|
3954
|
+
tracker.trackRule(this.name, end - start);
|
|
3955
|
+
} else {
|
|
3956
|
+
callback(data);
|
|
3957
|
+
}
|
|
3935
3958
|
}
|
|
3936
3959
|
});
|
|
3937
3960
|
}
|
|
@@ -3948,6 +3971,14 @@ class Rule {
|
|
|
3948
3971
|
this.severity = severity;
|
|
3949
3972
|
this.meta = meta;
|
|
3950
3973
|
}
|
|
3974
|
+
/**
|
|
3975
|
+
* Set (or clear) the performance tracker.
|
|
3976
|
+
*
|
|
3977
|
+
* @internal
|
|
3978
|
+
*/
|
|
3979
|
+
setTracker(tracker) {
|
|
3980
|
+
this.tracker = tracker;
|
|
3981
|
+
}
|
|
3951
3982
|
/**
|
|
3952
3983
|
* Validate rule options against schema. Throws error if object does not validate.
|
|
3953
3984
|
*
|
|
@@ -12462,8 +12493,10 @@ class StaticConfigLoader extends ConfigLoader {
|
|
|
12462
12493
|
|
|
12463
12494
|
class EventHandler {
|
|
12464
12495
|
listeners;
|
|
12496
|
+
tracker;
|
|
12465
12497
|
constructor() {
|
|
12466
12498
|
this.listeners = {};
|
|
12499
|
+
this.tracker = null;
|
|
12467
12500
|
}
|
|
12468
12501
|
/**
|
|
12469
12502
|
* Add an event listener.
|
|
@@ -12502,6 +12535,14 @@ class EventHandler {
|
|
|
12502
12535
|
});
|
|
12503
12536
|
return deregister;
|
|
12504
12537
|
}
|
|
12538
|
+
/**
|
|
12539
|
+
* Set (or clear) the performance tracker.
|
|
12540
|
+
*
|
|
12541
|
+
* @internal
|
|
12542
|
+
*/
|
|
12543
|
+
setTracker(tracker) {
|
|
12544
|
+
this.tracker = tracker;
|
|
12545
|
+
}
|
|
12505
12546
|
/**
|
|
12506
12547
|
* Trigger event causing all listeners to be called.
|
|
12507
12548
|
*
|
|
@@ -12510,8 +12551,18 @@ class EventHandler {
|
|
|
12510
12551
|
*/
|
|
12511
12552
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any -- technical debt, should be made typesafe */
|
|
12512
12553
|
trigger(event, data) {
|
|
12513
|
-
|
|
12514
|
-
|
|
12554
|
+
const { tracker } = this;
|
|
12555
|
+
if (tracker) {
|
|
12556
|
+
const start = performance.now();
|
|
12557
|
+
for (const listener of this.getCallbacks(event)) {
|
|
12558
|
+
listener.call(null, event, data);
|
|
12559
|
+
}
|
|
12560
|
+
const end = performance.now();
|
|
12561
|
+
tracker.trackEvent(event, end - start);
|
|
12562
|
+
} else {
|
|
12563
|
+
for (const listener of this.getCallbacks(event)) {
|
|
12564
|
+
listener.call(null, event, data);
|
|
12565
|
+
}
|
|
12515
12566
|
}
|
|
12516
12567
|
}
|
|
12517
12568
|
getCallbacks(event) {
|
|
@@ -12523,7 +12574,7 @@ class EventHandler {
|
|
|
12523
12574
|
}
|
|
12524
12575
|
|
|
12525
12576
|
const name = "html-validate";
|
|
12526
|
-
const version = "10.
|
|
12577
|
+
const version = "10.15.0";
|
|
12527
12578
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12528
12579
|
|
|
12529
12580
|
function freeze(src) {
|
|
@@ -13457,6 +13508,78 @@ class Parser {
|
|
|
13457
13508
|
}
|
|
13458
13509
|
}
|
|
13459
13510
|
|
|
13511
|
+
class PerformanceTracker {
|
|
13512
|
+
eventData;
|
|
13513
|
+
ruleData;
|
|
13514
|
+
startTime;
|
|
13515
|
+
accConfigTime;
|
|
13516
|
+
accTransformTime;
|
|
13517
|
+
constructor() {
|
|
13518
|
+
this.eventData = /* @__PURE__ */ new Map();
|
|
13519
|
+
this.ruleData = /* @__PURE__ */ new Map();
|
|
13520
|
+
this.startTime = performance.now();
|
|
13521
|
+
this.accConfigTime = 0;
|
|
13522
|
+
this.accTransformTime = 0;
|
|
13523
|
+
}
|
|
13524
|
+
/**
|
|
13525
|
+
* Record a single event trigger with the time it took to run all listeners.
|
|
13526
|
+
*/
|
|
13527
|
+
trackEvent(name, time) {
|
|
13528
|
+
const existing = this.eventData.get(name);
|
|
13529
|
+
if (existing) {
|
|
13530
|
+
existing.count += 1;
|
|
13531
|
+
existing.time += time;
|
|
13532
|
+
} else {
|
|
13533
|
+
this.eventData.set(name, { count: 1, time });
|
|
13534
|
+
}
|
|
13535
|
+
}
|
|
13536
|
+
/**
|
|
13537
|
+
* Record time spent loading configuration.
|
|
13538
|
+
*/
|
|
13539
|
+
trackConfig(time) {
|
|
13540
|
+
this.accConfigTime += time;
|
|
13541
|
+
}
|
|
13542
|
+
/**
|
|
13543
|
+
* Record time spent in transformers.
|
|
13544
|
+
*/
|
|
13545
|
+
trackTransform(time) {
|
|
13546
|
+
this.accTransformTime += time;
|
|
13547
|
+
}
|
|
13548
|
+
/**
|
|
13549
|
+
* Record a single rule callback invocation with its execution time.
|
|
13550
|
+
*/
|
|
13551
|
+
trackRule(ruleName, time) {
|
|
13552
|
+
const existing = this.ruleData.get(ruleName);
|
|
13553
|
+
if (existing) {
|
|
13554
|
+
existing.count += 1;
|
|
13555
|
+
existing.time += time;
|
|
13556
|
+
} else {
|
|
13557
|
+
this.ruleData.set(ruleName, { count: 1, time });
|
|
13558
|
+
}
|
|
13559
|
+
}
|
|
13560
|
+
/**
|
|
13561
|
+
* Returns a snapshot of the recorded performance data, with both arrays
|
|
13562
|
+
* sorted by time (descending).
|
|
13563
|
+
*/
|
|
13564
|
+
getResult() {
|
|
13565
|
+
const events = Array.from(
|
|
13566
|
+
this.eventData.entries(),
|
|
13567
|
+
([event, { count, time }]) => ({ event, count, time })
|
|
13568
|
+
).toSorted((a, b) => b.time - a.time);
|
|
13569
|
+
const rules = Array.from(
|
|
13570
|
+
this.ruleData.entries(),
|
|
13571
|
+
([rule, { count, time }]) => ({ rule, count, time })
|
|
13572
|
+
).toSorted((a, b) => b.time - a.time);
|
|
13573
|
+
return {
|
|
13574
|
+
events,
|
|
13575
|
+
rules,
|
|
13576
|
+
configTime: this.accConfigTime,
|
|
13577
|
+
transformTime: this.accTransformTime,
|
|
13578
|
+
totalTime: performance.now() - this.startTime
|
|
13579
|
+
};
|
|
13580
|
+
}
|
|
13581
|
+
}
|
|
13582
|
+
|
|
13460
13583
|
const ruleIds = new Set(Object.keys(bundledRules));
|
|
13461
13584
|
function ruleExists(ruleId) {
|
|
13462
13585
|
return ruleIds.has(ruleId);
|
|
@@ -13504,10 +13627,12 @@ class Engine {
|
|
|
13504
13627
|
config;
|
|
13505
13628
|
ParserClass;
|
|
13506
13629
|
availableRules;
|
|
13507
|
-
|
|
13630
|
+
tracker;
|
|
13631
|
+
constructor(config, ParserClass, options) {
|
|
13508
13632
|
this.report = new Reporter();
|
|
13509
13633
|
this.config = config;
|
|
13510
13634
|
this.ParserClass = ParserClass;
|
|
13635
|
+
this.tracker = options.tracker;
|
|
13511
13636
|
const result = this.initPlugins(this.config);
|
|
13512
13637
|
this.availableRules = {
|
|
13513
13638
|
...bundledRules,
|
|
@@ -13523,6 +13648,9 @@ class Engine {
|
|
|
13523
13648
|
lint(sources) {
|
|
13524
13649
|
for (const source of sources) {
|
|
13525
13650
|
const parser = this.instantiateParser();
|
|
13651
|
+
if (this.tracker) {
|
|
13652
|
+
parser.getEventHandler().setTracker(this.tracker);
|
|
13653
|
+
}
|
|
13526
13654
|
const { rules } = this.setupPlugins(source, this.config, parser);
|
|
13527
13655
|
const noUnusedDisable = rules["no-unused-disable"];
|
|
13528
13656
|
const directiveContext = {
|
|
@@ -13799,6 +13927,7 @@ class Engine {
|
|
|
13799
13927
|
const rule = this.instantiateRule(ruleId, options);
|
|
13800
13928
|
rule.name = ruleId;
|
|
13801
13929
|
rule.init(parser, report, severity, meta);
|
|
13930
|
+
rule.setTracker(this.tracker);
|
|
13802
13931
|
if (rule.setup) {
|
|
13803
13932
|
rule.setup();
|
|
13804
13933
|
}
|
|
@@ -15157,5 +15286,5 @@ const engines = {
|
|
|
15157
15286
|
|
|
15158
15287
|
var workerPath = "./jest-worker.js";
|
|
15159
15288
|
|
|
15160
|
-
export {
|
|
15289
|
+
export { walk as $, Attribute as A, Severity as B, ConfigLoader as C, DOMNode as D, Engine as E, TextContent$1 as F, TextNode as G, HtmlElement as H, ariaNaming as I, classifyNodeText as J, presets as K, defineConfig as L, MetaCopyableProperty as M, NestedError as N, definePlugin as O, PerformanceTracker as P, isUserError as Q, Reporter as R, StaticConfigLoader as S, TextClassification as T, UserError as U, Validator as V, WrappedError as W, keywordPatternMatcher as X, ruleExists as Y, sliceLocation as Z, staticResolver as _, Parser as a, engines as a0, codeFrameColumns as a1, getEndLocation as a2, getStartLocation as a3, workerPath as a4, name as a5, bugs as a6, transformSourceSync as b, transformFilename as c, transformFilenameSync as d, configurationSchema as e, ConfigError as f, Config as g, compatibilityCheckImpl as h, isThenable as i, ensureError as j, getFormatter as k, deepmerge as l, ignore as m, normalizeSource as n, DOMTokenList as o, DOMTree as p, DynamicValue as q, EventHandler as r, MetaTable as s, transformSource as t, NodeClosed as u, version as v, NodeType as w, ResolvedConfig as x, Rule as y, SchemaValidationError as z };
|
|
15161
15290
|
//# sourceMappingURL=core.js.map
|