html-validate 10.13.0 → 10.13.1
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 +116 -5
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js +5 -1
- package/dist/cjs/elements.js.map +1 -1
- package/dist/esm/core.js +116 -5
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/elements.js +5 -1
- package/dist/esm/elements.js.map +1 -1
- package/dist/schema/elements.json +25 -1
- package/dist/types/browser.d.ts +43 -0
- package/dist/types/index.d.ts +43 -0
- package/package.json +1 -1
package/dist/cjs/core.js
CHANGED
|
@@ -591,12 +591,40 @@ const patternProperties = {
|
|
|
591
591
|
},
|
|
592
592
|
implicitClosed: {
|
|
593
593
|
title: "List of elements which implicitly closes this element",
|
|
594
|
-
description: "Some elements are automatically closed when another start tag occurs",
|
|
594
|
+
description: "Some elements are automatically closed when another start tag occurs. Entries may be explicit tag names or @category strings (e.g. \"@flow\").",
|
|
595
595
|
type: "array",
|
|
596
596
|
items: {
|
|
597
597
|
type: "string"
|
|
598
598
|
}
|
|
599
599
|
},
|
|
600
|
+
implicitOpen: {
|
|
601
|
+
title: "Implicit-open rules for child elements",
|
|
602
|
+
description: "Describes intermediary elements (e.g. <head> or <body>) that should be implicitly opened when a child of a given category or tag is inserted directly under this element without a matching container being present.",
|
|
603
|
+
type: "array",
|
|
604
|
+
items: {
|
|
605
|
+
type: "object",
|
|
606
|
+
required: [
|
|
607
|
+
"for",
|
|
608
|
+
"open"
|
|
609
|
+
],
|
|
610
|
+
additionalProperties: false,
|
|
611
|
+
properties: {
|
|
612
|
+
"for": {
|
|
613
|
+
title: "Selector list",
|
|
614
|
+
description: "Tag names or @category strings (e.g. \"@flow\") that trigger the implicit open.",
|
|
615
|
+
type: "array",
|
|
616
|
+
items: {
|
|
617
|
+
type: "string"
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
open: {
|
|
621
|
+
title: "Element to open",
|
|
622
|
+
description: "Tag name of the element to implicitly open.",
|
|
623
|
+
type: "string"
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
},
|
|
600
628
|
optionalEnd: {
|
|
601
629
|
title: "Mark element as having an optional end tag",
|
|
602
630
|
description: "Elements whose end tag may be omitted per the HTML spec. Such an element is treated as implicitly closed at end-of-document and when a parent’s explicit end tag is encountered while it is still open.",
|
|
@@ -12485,7 +12513,7 @@ class EventHandler {
|
|
|
12485
12513
|
}
|
|
12486
12514
|
|
|
12487
12515
|
const name = "html-validate";
|
|
12488
|
-
const version = "10.13.
|
|
12516
|
+
const version = "10.13.1";
|
|
12489
12517
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12490
12518
|
|
|
12491
12519
|
function freeze(src) {
|
|
@@ -12674,6 +12702,31 @@ class ParserError extends Error {
|
|
|
12674
12702
|
}
|
|
12675
12703
|
}
|
|
12676
12704
|
|
|
12705
|
+
function isStaticTrue(value) {
|
|
12706
|
+
return value === true;
|
|
12707
|
+
}
|
|
12708
|
+
function matchesContentCategory(meta, category) {
|
|
12709
|
+
switch (category) {
|
|
12710
|
+
case "@meta":
|
|
12711
|
+
return isStaticTrue(meta.metadata);
|
|
12712
|
+
case "@flow":
|
|
12713
|
+
return isStaticTrue(meta.flow);
|
|
12714
|
+
case "@flow-not-meta":
|
|
12715
|
+
return isStaticTrue(meta.flow) && !isStaticTrue(meta.metadata);
|
|
12716
|
+
case "@sectioning":
|
|
12717
|
+
return isStaticTrue(meta.sectioning);
|
|
12718
|
+
case "@heading":
|
|
12719
|
+
return isStaticTrue(meta.heading);
|
|
12720
|
+
case "@phrasing":
|
|
12721
|
+
return isStaticTrue(meta.phrasing);
|
|
12722
|
+
case "@embedded":
|
|
12723
|
+
return isStaticTrue(meta.embedded);
|
|
12724
|
+
case "@interactive":
|
|
12725
|
+
return isStaticTrue(meta.interactive);
|
|
12726
|
+
default:
|
|
12727
|
+
return false;
|
|
12728
|
+
}
|
|
12729
|
+
}
|
|
12677
12730
|
function isAttrValueToken(token) {
|
|
12678
12731
|
return token?.type === TokenType.ATTR_VALUE;
|
|
12679
12732
|
}
|
|
@@ -12769,7 +12822,16 @@ class Parser {
|
|
|
12769
12822
|
const open = !token.data[1];
|
|
12770
12823
|
const implicitClosed = active.meta.implicitClosed;
|
|
12771
12824
|
if (open) {
|
|
12772
|
-
|
|
12825
|
+
if (!implicitClosed) {
|
|
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
|
+
});
|
|
12773
12835
|
} else {
|
|
12774
12836
|
if (active.is(tagName)) {
|
|
12775
12837
|
return false;
|
|
@@ -12778,6 +12840,42 @@ class Parser {
|
|
|
12778
12840
|
return Boolean(active.parent && active.parent.is(tagName) && canOmitEnd);
|
|
12779
12841
|
}
|
|
12780
12842
|
}
|
|
12843
|
+
/**
|
|
12844
|
+
* Check whether an intermediary element (e.g. `<head>` or `<body>`) should
|
|
12845
|
+
* be implicitly opened before the incoming element is inserted under
|
|
12846
|
+
* `parent`.
|
|
12847
|
+
*
|
|
12848
|
+
* If the parent's metadata defines an `implicitOpen` rule that matches the
|
|
12849
|
+
* incoming element, a new `HtmlElement` for the intermediary is created and
|
|
12850
|
+
* returned (with `parent` as its parent). The caller is responsible for
|
|
12851
|
+
* pushing it onto the active stack and firing the relevant events.
|
|
12852
|
+
*
|
|
12853
|
+
* Returns `null` when no implicit open is required.
|
|
12854
|
+
*/
|
|
12855
|
+
peekImplicitOpen(token, parent) {
|
|
12856
|
+
if (!parent?.meta?.implicitOpen) {
|
|
12857
|
+
return null;
|
|
12858
|
+
}
|
|
12859
|
+
const tagName = token.data[2];
|
|
12860
|
+
const incomingMeta = this.metaTable.getMetaFor(tagName);
|
|
12861
|
+
for (const entry of parent.meta.implicitOpen) {
|
|
12862
|
+
const matches = entry.for.some((selector) => {
|
|
12863
|
+
if (!selector.startsWith("@")) {
|
|
12864
|
+
return selector === tagName;
|
|
12865
|
+
}
|
|
12866
|
+
return incomingMeta ? matchesContentCategory(incomingMeta, selector) : false;
|
|
12867
|
+
});
|
|
12868
|
+
if (matches) {
|
|
12869
|
+
const intermediaryMeta = this.metaTable.getMetaFor(entry.open);
|
|
12870
|
+
return HtmlElement.createElement(entry.open, token.location, {
|
|
12871
|
+
closed: NodeClosed.Open,
|
|
12872
|
+
meta: intermediaryMeta,
|
|
12873
|
+
parent
|
|
12874
|
+
});
|
|
12875
|
+
}
|
|
12876
|
+
}
|
|
12877
|
+
return null;
|
|
12878
|
+
}
|
|
12781
12879
|
/**
|
|
12782
12880
|
* @internal
|
|
12783
12881
|
*/
|
|
@@ -12828,8 +12926,11 @@ class Parser {
|
|
|
12828
12926
|
this.consumeUntil(tokenStream, TokenType.TAG_CLOSE, startToken.location)
|
|
12829
12927
|
);
|
|
12830
12928
|
const endToken = tokens.at(-1);
|
|
12929
|
+
const isStartTag = !startToken.data[1];
|
|
12831
12930
|
const closeOptional = this.closeOptional(startToken);
|
|
12832
|
-
const
|
|
12931
|
+
const baseParent = closeOptional ? this.dom.getActive().parent : this.dom.getActive();
|
|
12932
|
+
const implicitParent = isStartTag ? this.peekImplicitOpen(startToken, baseParent) : null;
|
|
12933
|
+
const parent = implicitParent ?? baseParent;
|
|
12833
12934
|
const node = HtmlElement.fromTokens(
|
|
12834
12935
|
startToken,
|
|
12835
12936
|
endToken,
|
|
@@ -12837,7 +12938,6 @@ class Parser {
|
|
|
12837
12938
|
this.metaTable,
|
|
12838
12939
|
this.currentNamespace
|
|
12839
12940
|
);
|
|
12840
|
-
const isStartTag = !startToken.data[1];
|
|
12841
12941
|
const isClosing = !isStartTag || node.closed !== NodeClosed.Open;
|
|
12842
12942
|
const isForeign = node.meta?.foreign;
|
|
12843
12943
|
if (closeOptional) {
|
|
@@ -12847,6 +12947,17 @@ class Parser {
|
|
|
12847
12947
|
this.dom.popActive();
|
|
12848
12948
|
}
|
|
12849
12949
|
if (isStartTag) {
|
|
12950
|
+
if (implicitParent) {
|
|
12951
|
+
this.dom.pushActive(implicitParent);
|
|
12952
|
+
this.trigger("tag:start", {
|
|
12953
|
+
target: implicitParent,
|
|
12954
|
+
location: startToken.location
|
|
12955
|
+
});
|
|
12956
|
+
this.trigger("tag:ready", {
|
|
12957
|
+
target: implicitParent,
|
|
12958
|
+
location: startToken.location
|
|
12959
|
+
});
|
|
12960
|
+
}
|
|
12850
12961
|
this.dom.pushActive(node);
|
|
12851
12962
|
this.trigger("tag:start", {
|
|
12852
12963
|
target: node,
|