html-validate 10.12.2 → 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.
Files changed (44) hide show
  1. package/dist/cjs/browser.js +1 -0
  2. package/dist/cjs/browser.js.map +1 -1
  3. package/dist/cjs/core.js +116 -5
  4. package/dist/cjs/core.js.map +1 -1
  5. package/dist/cjs/elements.js +12 -3
  6. package/dist/cjs/elements.js.map +1 -1
  7. package/dist/cjs/html-validate.js +1 -0
  8. package/dist/cjs/html-validate.js.map +1 -1
  9. package/dist/cjs/html5.js +1 -0
  10. package/dist/cjs/html5.js.map +1 -1
  11. package/dist/cjs/index.js +1 -0
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/jest-worker.js +1 -0
  14. package/dist/cjs/jest-worker.js.map +1 -1
  15. package/dist/cjs/jest.js +1 -0
  16. package/dist/cjs/jest.js.map +1 -1
  17. package/dist/cjs/utils/parse-image-candidate-string.js +38 -0
  18. package/dist/cjs/utils/parse-image-candidate-string.js.map +1 -0
  19. package/dist/cjs/vitest.js +1 -0
  20. package/dist/cjs/vitest.js.map +1 -1
  21. package/dist/esm/browser.js +1 -0
  22. package/dist/esm/browser.js.map +1 -1
  23. package/dist/esm/core.js +116 -5
  24. package/dist/esm/core.js.map +1 -1
  25. package/dist/esm/elements.js +12 -3
  26. package/dist/esm/elements.js.map +1 -1
  27. package/dist/esm/html-validate.js +1 -0
  28. package/dist/esm/html-validate.js.map +1 -1
  29. package/dist/esm/html5.js +1 -0
  30. package/dist/esm/html5.js.map +1 -1
  31. package/dist/esm/index.js +1 -0
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/esm/jest-worker.js +1 -0
  34. package/dist/esm/jest-worker.js.map +1 -1
  35. package/dist/esm/jest.js +1 -0
  36. package/dist/esm/jest.js.map +1 -1
  37. package/dist/esm/utils/parse-image-candidate-string.js +36 -0
  38. package/dist/esm/utils/parse-image-candidate-string.js.map +1 -0
  39. package/dist/esm/vitest.js +1 -0
  40. package/dist/esm/vitest.js.map +1 -1
  41. package/dist/schema/elements.json +25 -1
  42. package/dist/types/browser.d.ts +43 -0
  43. package/dist/types/index.d.ts +43 -0
  44. package/package.json +2 -2
@@ -5,6 +5,7 @@ var core = require('./core.js');
5
5
  var metaHelper = require('./meta-helper.js');
6
6
  require('ajv');
7
7
  require('./elements.js');
8
+ require('./utils/parse-image-candidate-string.js');
8
9
  require('@sidvind/better-ajv-errors');
9
10
  require('./utils/natural-join.js');
10
11
  require('kleur');
@@ -1 +1 @@
1
- {"version":3,"file":"browser.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"browser.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
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.12.2";
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
- return Boolean(implicitClosed?.includes(tagName));
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 parent = closeOptional ? this.dom.getActive().parent : this.dom.getActive();
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,