html-validate 10.13.1 → 10.14.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/core.js +130 -38
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js +71 -4
- package/dist/cjs/elements.js.map +1 -1
- package/dist/cjs/tsdoc-metadata.json +1 -1
- package/dist/esm/core.js +130 -38
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/elements.js +71 -4
- package/dist/esm/elements.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types/browser.d.ts +27 -0
- package/dist/types/index.d.ts +27 -0
- package/package.json +1 -1
package/dist/cjs/core.js
CHANGED
|
@@ -2120,6 +2120,26 @@ class Compound {
|
|
|
2120
2120
|
}
|
|
2121
2121
|
}
|
|
2122
2122
|
|
|
2123
|
+
const codepoints = {
|
|
2124
|
+
" ": "\\9 ",
|
|
2125
|
+
"\n": "\\a ",
|
|
2126
|
+
"\r": "\\d "
|
|
2127
|
+
};
|
|
2128
|
+
function escapeSelectorComponent(text) {
|
|
2129
|
+
return text.toString().replaceAll(/([\t\n\r]|[^\w-])/gi, (_, ch) => {
|
|
2130
|
+
if (codepoints[ch]) {
|
|
2131
|
+
return codepoints[ch];
|
|
2132
|
+
} else {
|
|
2133
|
+
return `\\${ch}`;
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
function generateIdSelector(id) {
|
|
2139
|
+
const escaped = escapeSelectorComponent(id);
|
|
2140
|
+
return /^\d/.test(escaped) ? `[id="${escaped}"]` : `#${escaped}`;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2123
2143
|
function* ancestors$1(element) {
|
|
2124
2144
|
let current = element.parent;
|
|
2125
2145
|
while (current && !current.isRootElement()) {
|
|
@@ -2242,24 +2262,6 @@ function unescapeCodepoint(value) {
|
|
|
2242
2262
|
(_, codepoint) => replacement[codepoint]
|
|
2243
2263
|
);
|
|
2244
2264
|
}
|
|
2245
|
-
function escapeSelectorComponent(text) {
|
|
2246
|
-
const codepoints = {
|
|
2247
|
-
" ": "\\9 ",
|
|
2248
|
-
"\n": "\\a ",
|
|
2249
|
-
"\r": "\\d "
|
|
2250
|
-
};
|
|
2251
|
-
return text.toString().replaceAll(/([\t\n\r]|[^\w-])/gi, (_, ch) => {
|
|
2252
|
-
if (codepoints[ch]) {
|
|
2253
|
-
return codepoints[ch];
|
|
2254
|
-
} else {
|
|
2255
|
-
return `\\${ch}`;
|
|
2256
|
-
}
|
|
2257
|
-
});
|
|
2258
|
-
}
|
|
2259
|
-
function generateIdSelector(id) {
|
|
2260
|
-
const escaped = escapeSelectorComponent(id);
|
|
2261
|
-
return /^\d/.test(escaped) ? `[id="${escaped}"]` : `#${escaped}`;
|
|
2262
|
-
}
|
|
2263
2265
|
class Selector {
|
|
2264
2266
|
pattern;
|
|
2265
2267
|
constructor(selector) {
|
|
@@ -2378,6 +2380,7 @@ class TextNode extends DOMNode {
|
|
|
2378
2380
|
}
|
|
2379
2381
|
}
|
|
2380
2382
|
|
|
2383
|
+
const CHILD_ELEMENTS = /* @__PURE__ */ Symbol("childElements");
|
|
2381
2384
|
const ROLE = /* @__PURE__ */ Symbol("role");
|
|
2382
2385
|
const TABINDEX = /* @__PURE__ */ Symbol("tabindex");
|
|
2383
2386
|
var NodeClosed = /* @__PURE__ */ ((NodeClosed2) => {
|
|
@@ -2544,7 +2547,11 @@ class HtmlElement extends DOMNode {
|
|
|
2544
2547
|
* Similar to childNodes but only elements.
|
|
2545
2548
|
*/
|
|
2546
2549
|
get childElements() {
|
|
2547
|
-
|
|
2550
|
+
const cached = this.cacheGet(CHILD_ELEMENTS);
|
|
2551
|
+
if (cached !== void 0) {
|
|
2552
|
+
return cached;
|
|
2553
|
+
}
|
|
2554
|
+
return this.cacheSet(CHILD_ELEMENTS, this.childNodes.filter(isElementNode));
|
|
2548
2555
|
}
|
|
2549
2556
|
/**
|
|
2550
2557
|
* Find the first ancestor matching a selector.
|
|
@@ -2940,12 +2947,24 @@ class HtmlElement extends DOMNode {
|
|
|
2940
2947
|
}
|
|
2941
2948
|
return visit(this);
|
|
2942
2949
|
}
|
|
2950
|
+
append(node) {
|
|
2951
|
+
super.append(node);
|
|
2952
|
+
this.cacheRemove(CHILD_ELEMENTS);
|
|
2953
|
+
}
|
|
2954
|
+
insertBefore(node, reference) {
|
|
2955
|
+
super.insertBefore(node, reference);
|
|
2956
|
+
this.cacheRemove(CHILD_ELEMENTS);
|
|
2957
|
+
}
|
|
2958
|
+
removeChild(node) {
|
|
2959
|
+
return super.removeChild(node);
|
|
2960
|
+
}
|
|
2943
2961
|
/**
|
|
2944
2962
|
* @internal
|
|
2945
2963
|
*/
|
|
2946
2964
|
_setParent(node) {
|
|
2947
2965
|
const oldParent = this._parent;
|
|
2948
2966
|
this._parent = node instanceof HtmlElement ? node : null;
|
|
2967
|
+
oldParent?.cacheRemove(CHILD_ELEMENTS);
|
|
2949
2968
|
return oldParent;
|
|
2950
2969
|
}
|
|
2951
2970
|
}
|
|
@@ -12513,7 +12532,7 @@ class EventHandler {
|
|
|
12513
12532
|
}
|
|
12514
12533
|
|
|
12515
12534
|
const name = "html-validate";
|
|
12516
|
-
const version = "10.
|
|
12535
|
+
const version = "10.14.0";
|
|
12517
12536
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12518
12537
|
|
|
12519
12538
|
function freeze(src) {
|
|
@@ -12813,32 +12832,92 @@ class Parser {
|
|
|
12813
12832
|
* valid). The parser handles this by checking if the element on top of the
|
|
12814
12833
|
* stack when is allowed to omit.
|
|
12815
12834
|
*/
|
|
12835
|
+
/**
|
|
12836
|
+
* Check whether a given element would be implicitly closed by an incoming
|
|
12837
|
+
* start tag. Used both in `closeOptional` and in the multi-level lookahead.
|
|
12838
|
+
*/
|
|
12839
|
+
wouldCloseElement(token, element) {
|
|
12840
|
+
if (!element.meta) {
|
|
12841
|
+
return false;
|
|
12842
|
+
}
|
|
12843
|
+
const implicitClosed = element.meta.implicitClosed;
|
|
12844
|
+
if (!implicitClosed) {
|
|
12845
|
+
return false;
|
|
12846
|
+
}
|
|
12847
|
+
const tagName = token.data[2];
|
|
12848
|
+
const incomingMeta = this.metaTable.getMetaFor(tagName);
|
|
12849
|
+
return implicitClosed.some((entry) => {
|
|
12850
|
+
if (!entry.startsWith("@")) {
|
|
12851
|
+
return entry === tagName;
|
|
12852
|
+
}
|
|
12853
|
+
return incomingMeta ? matchesContentCategory(incomingMeta, entry) : false;
|
|
12854
|
+
});
|
|
12855
|
+
}
|
|
12856
|
+
/**
|
|
12857
|
+
* Walk up the active stack to find the parent element that will remain
|
|
12858
|
+
* after all multi-level implicit closes triggered by the incoming start tag.
|
|
12859
|
+
* For a single-level close this is equivalent to `getActive().parent`.
|
|
12860
|
+
*/
|
|
12861
|
+
getParentAfterImplicitClose(token) {
|
|
12862
|
+
let current = this.dom.getActive();
|
|
12863
|
+
while (!current.isRootElement() && this.wouldCloseElement(token, current)) {
|
|
12864
|
+
const { parent } = current;
|
|
12865
|
+
if (!parent) {
|
|
12866
|
+
break;
|
|
12867
|
+
}
|
|
12868
|
+
current = parent;
|
|
12869
|
+
}
|
|
12870
|
+
return current;
|
|
12871
|
+
}
|
|
12816
12872
|
closeOptional(token) {
|
|
12817
12873
|
const active = this.dom.getActive();
|
|
12818
12874
|
if (!active.meta) {
|
|
12819
12875
|
return false;
|
|
12820
12876
|
}
|
|
12821
|
-
const tagName = token.data[2];
|
|
12822
12877
|
const open = !token.data[1];
|
|
12823
|
-
const implicitClosed = active.meta.implicitClosed;
|
|
12824
12878
|
if (open) {
|
|
12825
|
-
|
|
12826
|
-
return false;
|
|
12827
|
-
}
|
|
12828
|
-
const incomingMeta = this.metaTable.getMetaFor(tagName);
|
|
12829
|
-
return implicitClosed.some((entry) => {
|
|
12830
|
-
if (!entry.startsWith("@")) {
|
|
12831
|
-
return entry === tagName;
|
|
12832
|
-
}
|
|
12833
|
-
return incomingMeta ? matchesContentCategory(incomingMeta, entry) : false;
|
|
12834
|
-
});
|
|
12879
|
+
return this.wouldCloseElement(token, active);
|
|
12835
12880
|
} else {
|
|
12836
|
-
|
|
12881
|
+
return this.closeOptionalEndTag(token, active);
|
|
12882
|
+
}
|
|
12883
|
+
}
|
|
12884
|
+
/**
|
|
12885
|
+
* Returns `true` if the element’s end tag may be omitted, either because
|
|
12886
|
+
* its `implicitClosed` list includes its own tag name (e.g. `<li>`, `<td>`)
|
|
12887
|
+
* or because `optionalEnd` is set.
|
|
12888
|
+
*/
|
|
12889
|
+
canOmitEndTag(element) {
|
|
12890
|
+
if (!element.meta) {
|
|
12891
|
+
return false;
|
|
12892
|
+
}
|
|
12893
|
+
const { implicitClosed, optionalEnd } = element.meta;
|
|
12894
|
+
return Boolean(implicitClosed?.includes(element.tagName)) || Boolean(optionalEnd);
|
|
12895
|
+
}
|
|
12896
|
+
/**
|
|
12897
|
+
* Check whether the active element can be implicitly closed by an incoming
|
|
12898
|
+
* end tag. The end tag may close a direct parent or any ancestor, as long as
|
|
12899
|
+
* every intermediate element can also have its end tag omitted.
|
|
12900
|
+
* This handles cases like `</table>` implicitly closing `<td>`, `<tr>`, `<tbody>`.
|
|
12901
|
+
*/
|
|
12902
|
+
closeOptionalEndTag(token, active) {
|
|
12903
|
+
const tagName = token.data[2];
|
|
12904
|
+
if (active.is(tagName)) {
|
|
12905
|
+
return false;
|
|
12906
|
+
}
|
|
12907
|
+
if (!this.canOmitEndTag(active)) {
|
|
12908
|
+
return false;
|
|
12909
|
+
}
|
|
12910
|
+
let ancestor = active.parent;
|
|
12911
|
+
while (ancestor && !ancestor.isRootElement()) {
|
|
12912
|
+
if (ancestor.is(tagName)) {
|
|
12913
|
+
return true;
|
|
12914
|
+
}
|
|
12915
|
+
if (!this.canOmitEndTag(ancestor)) {
|
|
12837
12916
|
return false;
|
|
12838
12917
|
}
|
|
12839
|
-
|
|
12840
|
-
return Boolean(active.parent && active.parent.is(tagName) && canOmitEnd);
|
|
12918
|
+
ancestor = ancestor.parent;
|
|
12841
12919
|
}
|
|
12920
|
+
return false;
|
|
12842
12921
|
}
|
|
12843
12922
|
/**
|
|
12844
12923
|
* Check whether an intermediary element (e.g. `<head>` or `<body>`) should
|
|
@@ -12927,8 +13006,21 @@ class Parser {
|
|
|
12927
13006
|
);
|
|
12928
13007
|
const endToken = tokens.at(-1);
|
|
12929
13008
|
const isStartTag = !startToken.data[1];
|
|
12930
|
-
|
|
12931
|
-
|
|
13009
|
+
let baseParent;
|
|
13010
|
+
if (isStartTag) {
|
|
13011
|
+
baseParent = this.getParentAfterImplicitClose(startToken);
|
|
13012
|
+
} else {
|
|
13013
|
+
const tagName = startToken.data[2];
|
|
13014
|
+
let cur = this.dom.getActive();
|
|
13015
|
+
while (!cur.isRootElement() && !cur.is(tagName)) {
|
|
13016
|
+
const { parent: parent2 } = cur;
|
|
13017
|
+
if (!parent2) {
|
|
13018
|
+
break;
|
|
13019
|
+
}
|
|
13020
|
+
cur = parent2;
|
|
13021
|
+
}
|
|
13022
|
+
baseParent = cur;
|
|
13023
|
+
}
|
|
12932
13024
|
const implicitParent = isStartTag ? this.peekImplicitOpen(startToken, baseParent) : null;
|
|
12933
13025
|
const parent = implicitParent ?? baseParent;
|
|
12934
13026
|
const node = HtmlElement.fromTokens(
|
|
@@ -12940,7 +13032,7 @@ class Parser {
|
|
|
12940
13032
|
);
|
|
12941
13033
|
const isClosing = !isStartTag || node.closed !== NodeClosed.Open;
|
|
12942
13034
|
const isForeign = node.meta?.foreign;
|
|
12943
|
-
|
|
13035
|
+
while (this.closeOptional(startToken)) {
|
|
12944
13036
|
const active = this.dom.getActive();
|
|
12945
13037
|
active.closed = NodeClosed.ImplicitClosed;
|
|
12946
13038
|
this.closeElement(source, node, active, startToken.location);
|