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/esm/core.js
CHANGED
|
@@ -582,12 +582,40 @@ const patternProperties = {
|
|
|
582
582
|
},
|
|
583
583
|
implicitClosed: {
|
|
584
584
|
title: "List of elements which implicitly closes this element",
|
|
585
|
-
description: "Some elements are automatically closed when another start tag occurs",
|
|
585
|
+
description: "Some elements are automatically closed when another start tag occurs. Entries may be explicit tag names or @category strings (e.g. \"@flow\").",
|
|
586
586
|
type: "array",
|
|
587
587
|
items: {
|
|
588
588
|
type: "string"
|
|
589
589
|
}
|
|
590
590
|
},
|
|
591
|
+
implicitOpen: {
|
|
592
|
+
title: "Implicit-open rules for child elements",
|
|
593
|
+
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.",
|
|
594
|
+
type: "array",
|
|
595
|
+
items: {
|
|
596
|
+
type: "object",
|
|
597
|
+
required: [
|
|
598
|
+
"for",
|
|
599
|
+
"open"
|
|
600
|
+
],
|
|
601
|
+
additionalProperties: false,
|
|
602
|
+
properties: {
|
|
603
|
+
"for": {
|
|
604
|
+
title: "Selector list",
|
|
605
|
+
description: "Tag names or @category strings (e.g. \"@flow\") that trigger the implicit open.",
|
|
606
|
+
type: "array",
|
|
607
|
+
items: {
|
|
608
|
+
type: "string"
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
open: {
|
|
612
|
+
title: "Element to open",
|
|
613
|
+
description: "Tag name of the element to implicitly open.",
|
|
614
|
+
type: "string"
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
},
|
|
591
619
|
optionalEnd: {
|
|
592
620
|
title: "Mark element as having an optional end tag",
|
|
593
621
|
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.",
|
|
@@ -12476,7 +12504,7 @@ class EventHandler {
|
|
|
12476
12504
|
}
|
|
12477
12505
|
|
|
12478
12506
|
const name = "html-validate";
|
|
12479
|
-
const version = "10.13.
|
|
12507
|
+
const version = "10.13.1";
|
|
12480
12508
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12481
12509
|
|
|
12482
12510
|
function freeze(src) {
|
|
@@ -12665,6 +12693,31 @@ class ParserError extends Error {
|
|
|
12665
12693
|
}
|
|
12666
12694
|
}
|
|
12667
12695
|
|
|
12696
|
+
function isStaticTrue(value) {
|
|
12697
|
+
return value === true;
|
|
12698
|
+
}
|
|
12699
|
+
function matchesContentCategory(meta, category) {
|
|
12700
|
+
switch (category) {
|
|
12701
|
+
case "@meta":
|
|
12702
|
+
return isStaticTrue(meta.metadata);
|
|
12703
|
+
case "@flow":
|
|
12704
|
+
return isStaticTrue(meta.flow);
|
|
12705
|
+
case "@flow-not-meta":
|
|
12706
|
+
return isStaticTrue(meta.flow) && !isStaticTrue(meta.metadata);
|
|
12707
|
+
case "@sectioning":
|
|
12708
|
+
return isStaticTrue(meta.sectioning);
|
|
12709
|
+
case "@heading":
|
|
12710
|
+
return isStaticTrue(meta.heading);
|
|
12711
|
+
case "@phrasing":
|
|
12712
|
+
return isStaticTrue(meta.phrasing);
|
|
12713
|
+
case "@embedded":
|
|
12714
|
+
return isStaticTrue(meta.embedded);
|
|
12715
|
+
case "@interactive":
|
|
12716
|
+
return isStaticTrue(meta.interactive);
|
|
12717
|
+
default:
|
|
12718
|
+
return false;
|
|
12719
|
+
}
|
|
12720
|
+
}
|
|
12668
12721
|
function isAttrValueToken(token) {
|
|
12669
12722
|
return token?.type === TokenType.ATTR_VALUE;
|
|
12670
12723
|
}
|
|
@@ -12760,7 +12813,16 @@ class Parser {
|
|
|
12760
12813
|
const open = !token.data[1];
|
|
12761
12814
|
const implicitClosed = active.meta.implicitClosed;
|
|
12762
12815
|
if (open) {
|
|
12763
|
-
|
|
12816
|
+
if (!implicitClosed) {
|
|
12817
|
+
return false;
|
|
12818
|
+
}
|
|
12819
|
+
const incomingMeta = this.metaTable.getMetaFor(tagName);
|
|
12820
|
+
return implicitClosed.some((entry) => {
|
|
12821
|
+
if (!entry.startsWith("@")) {
|
|
12822
|
+
return entry === tagName;
|
|
12823
|
+
}
|
|
12824
|
+
return incomingMeta ? matchesContentCategory(incomingMeta, entry) : false;
|
|
12825
|
+
});
|
|
12764
12826
|
} else {
|
|
12765
12827
|
if (active.is(tagName)) {
|
|
12766
12828
|
return false;
|
|
@@ -12769,6 +12831,42 @@ class Parser {
|
|
|
12769
12831
|
return Boolean(active.parent && active.parent.is(tagName) && canOmitEnd);
|
|
12770
12832
|
}
|
|
12771
12833
|
}
|
|
12834
|
+
/**
|
|
12835
|
+
* Check whether an intermediary element (e.g. `<head>` or `<body>`) should
|
|
12836
|
+
* be implicitly opened before the incoming element is inserted under
|
|
12837
|
+
* `parent`.
|
|
12838
|
+
*
|
|
12839
|
+
* If the parent's metadata defines an `implicitOpen` rule that matches the
|
|
12840
|
+
* incoming element, a new `HtmlElement` for the intermediary is created and
|
|
12841
|
+
* returned (with `parent` as its parent). The caller is responsible for
|
|
12842
|
+
* pushing it onto the active stack and firing the relevant events.
|
|
12843
|
+
*
|
|
12844
|
+
* Returns `null` when no implicit open is required.
|
|
12845
|
+
*/
|
|
12846
|
+
peekImplicitOpen(token, parent) {
|
|
12847
|
+
if (!parent?.meta?.implicitOpen) {
|
|
12848
|
+
return null;
|
|
12849
|
+
}
|
|
12850
|
+
const tagName = token.data[2];
|
|
12851
|
+
const incomingMeta = this.metaTable.getMetaFor(tagName);
|
|
12852
|
+
for (const entry of parent.meta.implicitOpen) {
|
|
12853
|
+
const matches = entry.for.some((selector) => {
|
|
12854
|
+
if (!selector.startsWith("@")) {
|
|
12855
|
+
return selector === tagName;
|
|
12856
|
+
}
|
|
12857
|
+
return incomingMeta ? matchesContentCategory(incomingMeta, selector) : false;
|
|
12858
|
+
});
|
|
12859
|
+
if (matches) {
|
|
12860
|
+
const intermediaryMeta = this.metaTable.getMetaFor(entry.open);
|
|
12861
|
+
return HtmlElement.createElement(entry.open, token.location, {
|
|
12862
|
+
closed: NodeClosed.Open,
|
|
12863
|
+
meta: intermediaryMeta,
|
|
12864
|
+
parent
|
|
12865
|
+
});
|
|
12866
|
+
}
|
|
12867
|
+
}
|
|
12868
|
+
return null;
|
|
12869
|
+
}
|
|
12772
12870
|
/**
|
|
12773
12871
|
* @internal
|
|
12774
12872
|
*/
|
|
@@ -12819,8 +12917,11 @@ class Parser {
|
|
|
12819
12917
|
this.consumeUntil(tokenStream, TokenType.TAG_CLOSE, startToken.location)
|
|
12820
12918
|
);
|
|
12821
12919
|
const endToken = tokens.at(-1);
|
|
12920
|
+
const isStartTag = !startToken.data[1];
|
|
12822
12921
|
const closeOptional = this.closeOptional(startToken);
|
|
12823
|
-
const
|
|
12922
|
+
const baseParent = closeOptional ? this.dom.getActive().parent : this.dom.getActive();
|
|
12923
|
+
const implicitParent = isStartTag ? this.peekImplicitOpen(startToken, baseParent) : null;
|
|
12924
|
+
const parent = implicitParent ?? baseParent;
|
|
12824
12925
|
const node = HtmlElement.fromTokens(
|
|
12825
12926
|
startToken,
|
|
12826
12927
|
endToken,
|
|
@@ -12828,7 +12929,6 @@ class Parser {
|
|
|
12828
12929
|
this.metaTable,
|
|
12829
12930
|
this.currentNamespace
|
|
12830
12931
|
);
|
|
12831
|
-
const isStartTag = !startToken.data[1];
|
|
12832
12932
|
const isClosing = !isStartTag || node.closed !== NodeClosed.Open;
|
|
12833
12933
|
const isForeign = node.meta?.foreign;
|
|
12834
12934
|
if (closeOptional) {
|
|
@@ -12838,6 +12938,17 @@ class Parser {
|
|
|
12838
12938
|
this.dom.popActive();
|
|
12839
12939
|
}
|
|
12840
12940
|
if (isStartTag) {
|
|
12941
|
+
if (implicitParent) {
|
|
12942
|
+
this.dom.pushActive(implicitParent);
|
|
12943
|
+
this.trigger("tag:start", {
|
|
12944
|
+
target: implicitParent,
|
|
12945
|
+
location: startToken.location
|
|
12946
|
+
});
|
|
12947
|
+
this.trigger("tag:ready", {
|
|
12948
|
+
target: implicitParent,
|
|
12949
|
+
location: startToken.location
|
|
12950
|
+
});
|
|
12951
|
+
}
|
|
12841
12952
|
this.dom.pushActive(node);
|
|
12842
12953
|
this.trigger("tag:start", {
|
|
12843
12954
|
target: node,
|