html-validate 10.16.0 → 11.0.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/esm/core.js CHANGED
@@ -1146,7 +1146,7 @@ function normalizeAriaNaming(value) {
1146
1146
  return value;
1147
1147
  }
1148
1148
  function migrateElement(src) {
1149
- const implicitRole = normalizeAriaImplicitRole(src.implicitRole ?? src.aria?.implicitRole);
1149
+ const implicitRole = normalizeAriaImplicitRole(src.aria?.implicitRole);
1150
1150
  const result = {
1151
1151
  ...src,
1152
1152
  formAssociated: void 0,
@@ -1562,12 +1562,21 @@ function sliceLocation(location, begin, end, wrap) {
1562
1562
  return sliced;
1563
1563
  }
1564
1564
 
1565
- var NodeType = /* @__PURE__ */ ((NodeType2) => {
1566
- NodeType2[NodeType2["ELEMENT_NODE"] = 1] = "ELEMENT_NODE";
1567
- NodeType2[NodeType2["TEXT_NODE"] = 3] = "TEXT_NODE";
1568
- NodeType2[NodeType2["DOCUMENT_NODE"] = 9] = "DOCUMENT_NODE";
1569
- return NodeType2;
1570
- })(NodeType || {});
1565
+ const Node = {
1566
+ ELEMENT_NODE: 1,
1567
+ TEXT_NODE: 3,
1568
+ DOCUMENT_NODE: 9,
1569
+ /** element wasn't closed */
1570
+ CLOSED_OPEN: 0,
1571
+ /** element closed with end tag <p>...</p> */
1572
+ CLOSED_END_TAG: 1,
1573
+ /** void element with omitted end tag <input> */
1574
+ CLOSED_VOID_OMITTED: 2,
1575
+ /** self-closed void element <input/> */
1576
+ CLOSED_VOID_SELF_CLOSED: 3,
1577
+ /** element with optional end tag <li>foo<li>bar */
1578
+ CLOSED_IMPLICIT_CLOSED: 4
1579
+ };
1571
1580
 
1572
1581
  const DOCUMENT_NODE_NAME = "#document";
1573
1582
  const TEXT_CONTENT = /* @__PURE__ */ Symbol("textContent");
@@ -1694,7 +1703,7 @@ class DOMNode {
1694
1703
  }
1695
1704
  }
1696
1705
  isRootElement() {
1697
- return this.nodeType === NodeType.DOCUMENT_NODE;
1706
+ return this.nodeType === Node.DOCUMENT_NODE;
1698
1707
  }
1699
1708
  /**
1700
1709
  * Tests if two nodes are the same (references the same object).
@@ -2351,7 +2360,7 @@ function parseSelector(selector) {
2351
2360
 
2352
2361
  const TEXT_NODE_NAME = "#text";
2353
2362
  function isTextNode(node) {
2354
- return node?.nodeType === NodeType.TEXT_NODE;
2363
+ return node?.nodeType === Node.TEXT_NODE;
2355
2364
  }
2356
2365
  class TextNode extends DOMNode {
2357
2366
  text;
@@ -2361,7 +2370,7 @@ class TextNode extends DOMNode {
2361
2370
  * @param location - Source code location of this node.
2362
2371
  */
2363
2372
  constructor(text, location) {
2364
- super(NodeType.TEXT_NODE, TEXT_NODE_NAME, location);
2373
+ super(Node.TEXT_NODE, TEXT_NODE_NAME, location);
2365
2374
  this.text = text;
2366
2375
  }
2367
2376
  /**
@@ -2387,16 +2396,8 @@ class TextNode extends DOMNode {
2387
2396
  const CHILD_ELEMENTS = /* @__PURE__ */ Symbol("childElements");
2388
2397
  const ROLE = /* @__PURE__ */ Symbol("role");
2389
2398
  const TABINDEX = /* @__PURE__ */ Symbol("tabindex");
2390
- var NodeClosed = /* @__PURE__ */ ((NodeClosed2) => {
2391
- NodeClosed2[NodeClosed2["Open"] = 0] = "Open";
2392
- NodeClosed2[NodeClosed2["EndTag"] = 1] = "EndTag";
2393
- NodeClosed2[NodeClosed2["VoidOmitted"] = 2] = "VoidOmitted";
2394
- NodeClosed2[NodeClosed2["VoidSelfClosed"] = 3] = "VoidSelfClosed";
2395
- NodeClosed2[NodeClosed2["ImplicitClosed"] = 4] = "ImplicitClosed";
2396
- return NodeClosed2;
2397
- })(NodeClosed || {});
2398
2399
  function isElementNode(node) {
2399
- return node?.nodeType === NodeType.ELEMENT_NODE;
2400
+ return node?.nodeType === Node.ELEMENT_NODE;
2400
2401
  }
2401
2402
  function isInvalidTagName(tagName) {
2402
2403
  return tagName === "" || tagName === "*";
@@ -2430,7 +2431,7 @@ class HtmlElement extends DOMNode {
2430
2431
  nodeType,
2431
2432
  tagName,
2432
2433
  parent = null,
2433
- closed = 1 /* EndTag */,
2434
+ closed = Node.CLOSED_END_TAG,
2434
2435
  meta = null,
2435
2436
  location
2436
2437
  } = details;
@@ -2471,9 +2472,9 @@ class HtmlElement extends DOMNode {
2471
2472
  * @param details - Additional element details.
2472
2473
  */
2473
2474
  static createElement(tagName, location, details = {}) {
2474
- const { closed = 1 /* EndTag */, meta = null, parent = null } = details;
2475
+ const { closed = Node.CLOSED_END_TAG, meta = null, parent = null } = details;
2475
2476
  return new HtmlElement({
2476
- nodeType: NodeType.ELEMENT_NODE,
2477
+ nodeType: Node.ELEMENT_NODE,
2477
2478
  tagName,
2478
2479
  parent,
2479
2480
  closed,
@@ -2486,7 +2487,7 @@ class HtmlElement extends DOMNode {
2486
2487
  */
2487
2488
  static rootNode(location) {
2488
2489
  const root = new HtmlElement({
2489
- nodeType: NodeType.DOCUMENT_NODE,
2490
+ nodeType: Node.DOCUMENT_NODE,
2490
2491
  location
2491
2492
  });
2492
2493
  root.setAnnotation("#document");
@@ -2508,7 +2509,7 @@ class HtmlElement extends DOMNode {
2508
2509
  const closed = isClosed(endToken, meta);
2509
2510
  const location = sliceLocation(startToken.location, 1);
2510
2511
  return new HtmlElement({
2511
- nodeType: NodeType.ELEMENT_NODE,
2512
+ nodeType: Node.ELEMENT_NODE,
2512
2513
  tagName,
2513
2514
  parent: open ? parent : null,
2514
2515
  closed,
@@ -2973,12 +2974,12 @@ class HtmlElement extends DOMNode {
2973
2974
  }
2974
2975
  }
2975
2976
  function isClosed(endToken, meta) {
2976
- let closed = 0 /* Open */;
2977
+ let closed = Node.CLOSED_OPEN;
2977
2978
  if (meta?.void) {
2978
- closed = 2 /* VoidOmitted */;
2979
+ closed = Node.CLOSED_VOID_OMITTED;
2979
2980
  }
2980
2981
  if (endToken.data[0] === "/>") {
2981
- closed = 3 /* VoidSelfClosed */;
2982
+ closed = Node.CLOSED_VOID_SELF_CLOSED;
2982
2983
  }
2983
2984
  return closed;
2984
2985
  }
@@ -3065,18 +3066,6 @@ class DOMTree {
3065
3066
  getElementsByTagName(tagName) {
3066
3067
  return this.root.getElementsByTagName(tagName);
3067
3068
  }
3068
- /**
3069
- * @deprecated use utility function `walk.depthFirst(..)` instead (since 8.21.0).
3070
- */
3071
- visitDepthFirst(callback) {
3072
- walk.depthFirst(this, callback);
3073
- }
3074
- /**
3075
- * @deprecated use `querySelector(..)` instead (since 8.21.0)
3076
- */
3077
- find(callback) {
3078
- return this.root.find(callback);
3079
- }
3080
3069
  querySelector(selector) {
3081
3070
  return this.root.querySelector(selector);
3082
3071
  }
@@ -5728,14 +5717,12 @@ function parsePattern(pattern) {
5728
5717
  default: {
5729
5718
  if (pattern.startsWith("/") && pattern.endsWith("/")) {
5730
5719
  const regexpSource = pattern.slice(1, -1);
5731
- const regexp2 = new RegExp(regexpSource);
5732
- return { regexp: regexp2, description: regexp2.toString() };
5720
+ const regexp = new RegExp(regexpSource);
5721
+ return { regexp, description: regexp.toString() };
5733
5722
  }
5734
- console.warn(
5735
- `Custom pattern "${pattern}" should be wrapped in forward slashes, e.g., "/${pattern}/". Support for unwrapped patterns is deprecated and will be removed in a future version.`
5723
+ throw new Error(
5724
+ `Custom pattern "${pattern}" must be wrapped in forward slashes, i.e. "/${pattern}/"`
5736
5725
  );
5737
- const regexp = new RegExp(pattern);
5738
- return { regexp, description: regexp.toString() };
5739
5726
  }
5740
5727
  }
5741
5728
  }
@@ -5933,7 +5920,7 @@ class CloseOrder extends Rule {
5933
5920
  if (current.voidElement) {
5934
5921
  return;
5935
5922
  }
5936
- if (active.closed === NodeClosed.ImplicitClosed) {
5923
+ if (active.closed === Node.CLOSED_IMPLICIT_CLOSED) {
5937
5924
  return;
5938
5925
  }
5939
5926
  if (active.isRootElement()) {
@@ -8362,7 +8349,7 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
8362
8349
  if (!by) {
8363
8350
  return;
8364
8351
  }
8365
- if (closed.closed !== NodeClosed.ImplicitClosed) {
8352
+ if (closed.closed !== Node.CLOSED_IMPLICIT_CLOSED) {
8366
8353
  return;
8367
8354
  }
8368
8355
  const parent = closed.parent;
@@ -8669,7 +8656,7 @@ class NoRawCharacters extends Rule {
8669
8656
  return;
8670
8657
  }
8671
8658
  for (const child of node.childNodes) {
8672
- if (child.nodeType !== NodeType.TEXT_NODE) {
8659
+ if (child.nodeType !== Node.TEXT_NODE) {
8673
8660
  continue;
8674
8661
  }
8675
8662
  if (matchTemplate.test(child.textContent)) {
@@ -8900,7 +8887,7 @@ class NoSelfClosing extends Rule {
8900
8887
  });
8901
8888
  }
8902
8889
  validateElement(node) {
8903
- if (node.closed !== NodeClosed.VoidSelfClosed) {
8890
+ if (node.closed !== Node.CLOSED_VOID_SELF_CLOSED) {
8904
8891
  return;
8905
8892
  }
8906
8893
  this.report(node, `<${node.tagName}> must not be self-closed`, null, node.tagName);
@@ -8972,6 +8959,55 @@ class NoTrailingWhitespace extends Rule {
8972
8959
  }
8973
8960
  }
8974
8961
 
8962
+ const skipPatterns = [
8963
+ /^data-/i,
8964
+ /^aria-/i,
8965
+ /^on[a-z]/i,
8966
+ /^xml(ns)?:/i,
8967
+ /^:/,
8968
+ /^@/,
8969
+ /^ng-/i,
8970
+ /^v-/i,
8971
+ /^x-/i,
8972
+ /^\[/
8973
+ ];
8974
+ function isKnownDynamicAttr(attr) {
8975
+ return skipPatterns.some((pattern) => pattern.test(attr));
8976
+ }
8977
+ class NoUnknownAttributes extends Rule {
8978
+ documentation(context) {
8979
+ return {
8980
+ description: `The \`${context.attr}\` attribute is not a known attribute on \`<${context.tagName}>\`.`,
8981
+ url: "https://html-validate.org/rules/no-unknown-attributes.html"
8982
+ };
8983
+ }
8984
+ setup() {
8985
+ this.on("attr", (event) => {
8986
+ const node = event.target;
8987
+ const meta = node.meta;
8988
+ const attr = event.key.toLowerCase();
8989
+ if (meta === null) {
8990
+ return;
8991
+ }
8992
+ if (attr in meta.attributes) {
8993
+ return;
8994
+ }
8995
+ if (isKnownDynamicAttr(attr)) {
8996
+ return;
8997
+ }
8998
+ this.report({
8999
+ node,
9000
+ message: `Attribute "${event.key}" is not allowed on <${node.tagName}> element`,
9001
+ location: event.keyLocation,
9002
+ context: {
9003
+ tagName: node.tagName,
9004
+ attr: event.key
9005
+ }
9006
+ });
9007
+ });
9008
+ }
9009
+ }
9010
+
8975
9011
  const defaults$b = {
8976
9012
  include: null,
8977
9013
  exclude: null
@@ -9484,7 +9520,7 @@ class ScriptElement extends Rule {
9484
9520
  if (node?.tagName !== "script") {
9485
9521
  return;
9486
9522
  }
9487
- if (node.closed !== NodeClosed.EndTag) {
9523
+ if (node.closed !== Node.CLOSED_END_TAG) {
9488
9524
  this.report(node, `End tag for <${node.tagName}> must not be omitted`);
9489
9525
  }
9490
9526
  });
@@ -10027,7 +10063,7 @@ class UnknownCharReference extends Rule {
10027
10063
  return;
10028
10064
  }
10029
10065
  for (const child of node.childNodes) {
10030
- if (child.nodeType !== NodeType.TEXT_NODE) {
10066
+ if (child.nodeType !== Node.TEXT_NODE) {
10031
10067
  continue;
10032
10068
  }
10033
10069
  this.findCharacterReferences(node, child.textContent, child.location, {
@@ -10764,7 +10800,7 @@ class VoidContent extends Rule {
10764
10800
  if (!node.voidElement) {
10765
10801
  return;
10766
10802
  }
10767
- if (node.closed === NodeClosed.EndTag) {
10803
+ if (node.closed === Node.CLOSED_END_TAG) {
10768
10804
  this.report(
10769
10805
  null,
10770
10806
  `End tag for <${node.tagName}> must be omitted`,
@@ -10817,7 +10853,7 @@ class VoidStyle extends Rule {
10817
10853
  if (!node.voidElement) {
10818
10854
  return;
10819
10855
  }
10820
- if (node.closed !== NodeClosed.VoidSelfClosed) {
10856
+ if (node.closed !== Node.CLOSED_VOID_SELF_CLOSED) {
10821
10857
  return;
10822
10858
  }
10823
10859
  this.reportError(
@@ -10829,7 +10865,7 @@ class VoidStyle extends Rule {
10829
10865
  if (!node.voidElement) {
10830
10866
  return;
10831
10867
  }
10832
- if (node.closed !== NodeClosed.VoidOmitted) {
10868
+ if (node.closed !== Node.CLOSED_VOID_OMITTED) {
10833
10869
  return;
10834
10870
  }
10835
10871
  this.reportError(
@@ -11279,6 +11315,7 @@ const bundledRules = {
11279
11315
  "no-self-closing": NoSelfClosing,
11280
11316
  "no-style-tag": NoStyleTag,
11281
11317
  "no-trailing-whitespace": NoTrailingWhitespace,
11318
+ "no-unknown-attributes": NoUnknownAttributes,
11282
11319
  "no-unknown-elements": NoUnknownElements,
11283
11320
  "no-unused-disable": NoUnusedDisable,
11284
11321
  "no-utf8-bom": NoUtf8Bom,
@@ -12593,7 +12630,7 @@ class EventHandler {
12593
12630
  }
12594
12631
 
12595
12632
  const name = "html-validate";
12596
- const version = "10.16.0";
12633
+ const version = "11.0.0";
12597
12634
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
12598
12635
 
12599
12636
  function freeze(src) {
@@ -13008,7 +13045,7 @@ class Parser {
13008
13045
  if (matches) {
13009
13046
  const intermediaryMeta = this.metaTable.getMetaFor(entry.open);
13010
13047
  return HtmlElement.createElement(entry.open, token.location, {
13011
- closed: NodeClosed.Open,
13048
+ closed: Node.CLOSED_OPEN,
13012
13049
  meta: intermediaryMeta,
13013
13050
  parent
13014
13051
  });
@@ -13091,11 +13128,11 @@ class Parser {
13091
13128
  this.metaTable,
13092
13129
  this.currentNamespace
13093
13130
  );
13094
- const isClosing = !isStartTag || node.closed !== NodeClosed.Open;
13131
+ const isClosing = !isStartTag || node.closed !== Node.CLOSED_OPEN;
13095
13132
  const isForeign = node.meta?.foreign;
13096
13133
  while (this.closeOptional(startToken)) {
13097
13134
  const active = this.dom.getActive();
13098
- active.closed = NodeClosed.ImplicitClosed;
13135
+ active.closed = Node.CLOSED_IMPLICIT_CLOSED;
13099
13136
  this.closeElement(source, node, active, startToken.location);
13100
13137
  this.dom.popActive();
13101
13138
  }
@@ -13136,7 +13173,7 @@ class Parser {
13136
13173
  if (isClosing) {
13137
13174
  const active = this.dom.getActive();
13138
13175
  if (!isStartTag) {
13139
- node.closed = NodeClosed.EndTag;
13176
+ node.closed = Node.CLOSED_END_TAG;
13140
13177
  }
13141
13178
  this.closeElement(source, node, active, endToken.location);
13142
13179
  const mismatched = node.tagName !== active.tagName;
@@ -13159,7 +13196,7 @@ class Parser {
13159
13196
  location
13160
13197
  };
13161
13198
  this.trigger("tag:end", event);
13162
- if (node && node.tagName !== active.tagName && active.closed !== NodeClosed.ImplicitClosed) {
13199
+ if (node && node.tagName !== active.tagName && active.closed !== Node.CLOSED_IMPLICIT_CLOSED) {
13163
13200
  return;
13164
13201
  }
13165
13202
  if (!active.isRootElement()) {
@@ -13516,7 +13553,7 @@ class Parser {
13516
13553
  let active = this.dom.getActive();
13517
13554
  while (!active.isRootElement()) {
13518
13555
  if (active.meta?.implicitClosed || active.meta?.optionalEnd) {
13519
- active.closed = NodeClosed.ImplicitClosed;
13556
+ active.closed = Node.CLOSED_IMPLICIT_CLOSED;
13520
13557
  this.closeElement(source, documentElement, active, location);
13521
13558
  } else {
13522
13559
  this.closeElement(source, null, active, location);
@@ -15300,10 +15337,10 @@ var ignoreExports = /*@__PURE__*/ requireIgnore();
15300
15337
  var ignore = /*@__PURE__*/getDefaultExportFromCjs(ignoreExports);
15301
15338
 
15302
15339
  const engines = {
15303
- node: "^20.19.0 || ^22.16.0 || >= 24.0.0"
15340
+ node: "^22.16.0 || >= 24.0.0"
15304
15341
  };
15305
15342
 
15306
15343
  var workerPath = "./jest-worker.js";
15307
15344
 
15308
- 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 };
15345
+ export { codeFrameColumns as $, Attribute as A, TextContent$1 as B, ConfigLoader as C, DOMNode as D, Engine as E, TextNode as F, ariaNaming as G, HtmlElement as H, classifyNodeText as I, presets as J, defineConfig as K, definePlugin as L, MetaCopyableProperty as M, NestedError as N, isUserError as O, PerformanceTracker as P, keywordPatternMatcher as Q, Reporter as R, StaticConfigLoader as S, TextClassification as T, UserError as U, ruleExists as V, WrappedError as W, sliceLocation as X, staticResolver as Y, walk as Z, engines as _, Parser as a, getEndLocation as a0, getStartLocation as a1, workerPath as a2, name as a3, bugs as a4, 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, Node as u, version as v, ResolvedConfig as w, Rule as x, SchemaValidationError as y, Severity as z };
15309
15346
  //# sourceMappingURL=core.js.map