html-validate 9.4.2 → 9.5.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/es/core.js CHANGED
@@ -1062,6 +1062,7 @@ function migrateAttributes(src) {
1062
1062
  ...Object.keys(src.attributes ?? {}),
1063
1063
  ...src.requiredAttributes ?? [],
1064
1064
  ...src.deprecatedAttributes ?? []
1065
+ /* eslint-disable-next-line sonarjs/no-alphabetical-sort -- not really needed in this case, this is a-z anyway */
1065
1066
  ].sort();
1066
1067
  const entries = keys.map((key) => {
1067
1068
  return [key, migrateSingleAttribute(src, key)];
@@ -1338,7 +1339,7 @@ function expandRegexValue(value) {
1338
1339
  if (value instanceof RegExp) {
1339
1340
  return value;
1340
1341
  }
1341
- const match = value.match(/^\/(.*(?=\/))\/(i?)$/);
1342
+ const match = /^\/(.*(?=\/))\/(i?)$/.exec(value);
1342
1343
  if (match) {
1343
1344
  const [, expr, flags] = match;
1344
1345
  if (expr.startsWith("^") || expr.endsWith("$")) {
@@ -1583,6 +1584,7 @@ class DOMNode {
1583
1584
  * @internal
1584
1585
  */
1585
1586
  unique;
1587
+ /* eslint-disable-next-line sonarjs/use-type-alias -- technical debt */
1586
1588
  cache;
1587
1589
  /**
1588
1590
  * Set of disabled rules for this node.
@@ -1638,6 +1640,11 @@ class DOMNode {
1638
1640
  }
1639
1641
  return value;
1640
1642
  }
1643
+ /**
1644
+ * Remove a value by key from cache.
1645
+ *
1646
+ * @returns `true` if the entry existed and has been removed.
1647
+ */
1641
1648
  cacheRemove(key) {
1642
1649
  if (this.cache) {
1643
1650
  return this.cache.delete(key);
@@ -1645,6 +1652,9 @@ class DOMNode {
1645
1652
  return false;
1646
1653
  }
1647
1654
  }
1655
+ /**
1656
+ * Check if key exists in cache.
1657
+ */
1648
1658
  cacheExists(key) {
1649
1659
  return Boolean(this.cache?.has(key));
1650
1660
  }
@@ -1985,7 +1995,7 @@ class AttributeCondition extends Condition {
1985
1995
  value;
1986
1996
  constructor(attr) {
1987
1997
  super();
1988
- const [, key, op, value] = attr.match(/^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/);
1998
+ const [, key, op, value] = /^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/.exec(attr);
1989
1999
  this.key = key;
1990
2000
  this.op = op;
1991
2001
  this.value = value;
@@ -1994,6 +2004,7 @@ class AttributeCondition extends Condition {
1994
2004
  const attr = node.getAttribute(this.key, true);
1995
2005
  return attr.some((cur) => {
1996
2006
  switch (this.op) {
2007
+ /* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- technical debt, the type of op should reflect this case */
1997
2008
  case void 0:
1998
2009
  return true;
1999
2010
  /* attribute exists */
@@ -2010,7 +2021,7 @@ class PseudoClassCondition extends Condition {
2010
2021
  args;
2011
2022
  constructor(pseudoclass, context) {
2012
2023
  super();
2013
- const match = pseudoclass.match(/^([^(]+)(?:\((.*)\))?$/);
2024
+ const match = /^([^(]+)(?:\((.*)\))?$/.exec(pseudoclass);
2014
2025
  if (!match) {
2015
2026
  throw new Error(`Missing pseudo-class after colon in selector pattern "${context}"`);
2016
2027
  }
@@ -2080,7 +2091,7 @@ class Compound {
2080
2091
  selector;
2081
2092
  conditions;
2082
2093
  constructor(pattern) {
2083
- const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)([^]*)$/);
2094
+ const match = /^([~+\->]?)((?:[*]|[^.#[:]+)?)([^]*)$/.exec(pattern);
2084
2095
  if (!match) {
2085
2096
  throw new Error(`Failed to create selector pattern from "${pattern}"`);
2086
2097
  }
@@ -2247,7 +2258,7 @@ function escapeSelectorComponent(text) {
2247
2258
  }
2248
2259
  function generateIdSelector(id) {
2249
2260
  const escaped = escapeSelectorComponent(id);
2250
- return escaped.match(/^\d/) ? `[id="${escaped}"]` : `#${escaped}`;
2261
+ return /^\d/.exec(escaped) ? `[id="${escaped}"]` : `#${escaped}`;
2251
2262
  }
2252
2263
  class Selector {
2253
2264
  pattern;
@@ -3069,7 +3080,7 @@ class Validator {
3069
3080
  if (typeof rule !== "string") {
3070
3081
  return false;
3071
3082
  }
3072
- const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/);
3083
+ const [, category, quantifier] = /^(@?.*?)([?*]?)$/.exec(rule);
3073
3084
  const limit = category && quantifier && parseQuantifier(quantifier);
3074
3085
  if (limit) {
3075
3086
  const siblings = children.filter(
@@ -3237,7 +3248,7 @@ class Validator {
3237
3248
  */
3238
3249
  /* eslint-disable-next-line complexity -- rule does not like switch */
3239
3250
  static validatePermittedCategory(node, category, defaultMatch) {
3240
- const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/);
3251
+ const [, rawCategory] = /^(@?.*?)([?*]?)$/.exec(category);
3241
3252
  if (!rawCategory.startsWith("@")) {
3242
3253
  return node.tagName === rawCategory;
3243
3254
  }
@@ -3480,7 +3491,7 @@ function escape(value) {
3480
3491
  return JSON.stringify(value);
3481
3492
  }
3482
3493
  function format(value, quote = false) {
3483
- if (value === null) {
3494
+ if (value === null || value === void 0) {
3484
3495
  return "null";
3485
3496
  }
3486
3497
  if (typeof value === "number") {
@@ -3559,7 +3570,7 @@ function compilePattern(pattern) {
3559
3570
  if (cached) {
3560
3571
  return cached;
3561
3572
  }
3562
- const match = pattern.match(/^\/(.*)\/$/);
3573
+ const match = /^\/(.*)\/$/.exec(pattern);
3563
3574
  const regexp = match ? compileRegExpPattern(match[1]) : compileStringPattern(pattern);
3564
3575
  patternCache.set(pattern, regexp);
3565
3576
  return regexp;
@@ -3744,7 +3755,7 @@ function classifyNodeText(node, options = {}) {
3744
3755
  if (text.some((cur) => cur.isDynamic)) {
3745
3756
  return node.cacheSet(cacheKey, 1 /* DYNAMIC_TEXT */);
3746
3757
  }
3747
- if (text.some((cur) => cur.textContent.match(/\S/) !== null)) {
3758
+ if (text.some((cur) => /\S/.exec(cur.textContent) !== null)) {
3748
3759
  return node.cacheSet(cacheKey, 2 /* STATIC_TEXT */);
3749
3760
  }
3750
3761
  return node.cacheSet(cacheKey, 0 /* EMPTY_TEXT */);
@@ -5758,7 +5769,7 @@ class Deprecated extends Rule {
5758
5769
  }
5759
5770
  }
5760
5771
  function prettySource(source) {
5761
- const match = source.match(/html(\d)(\d)?/);
5772
+ const match = /html(\d)(\d)?/.exec(source);
5762
5773
  if (match) {
5763
5774
  const [, ...parts] = match;
5764
5775
  const version = parts.filter(Boolean).join(".");
@@ -5996,7 +6007,7 @@ class ElementName extends Rule {
5996
6007
  if (target.meta) {
5997
6008
  return;
5998
6009
  }
5999
- if (tagName.match(xmlns)) {
6010
+ if (xmlns.exec(tagName)) {
6000
6011
  return;
6001
6012
  }
6002
6013
  if (this.options.whitelist.includes(tagName)) {
@@ -6254,7 +6265,7 @@ class ElementPermittedParent extends Rule {
6254
6265
  }
6255
6266
 
6256
6267
  function isTagnameOnly(value) {
6257
- return Boolean(value.match(/^[a-zA-Z0-9-]+$/));
6268
+ return Boolean(/^[a-zA-Z0-9-]+$/.exec(value));
6258
6269
  }
6259
6270
  function getRuleDescription(context) {
6260
6271
  const escaped = context.ancestor.map((it) => `\`${it}\``);
@@ -6667,7 +6678,7 @@ function isRelevant$5(event) {
6667
6678
  return Boolean(node.meta?.heading);
6668
6679
  }
6669
6680
  function extractLevel(node) {
6670
- const match = node.tagName.match(/^[hH](\d)$/);
6681
+ const match = /^[hH](\d)$/.exec(node.tagName);
6671
6682
  if (match) {
6672
6683
  return parseInt(match[1], 10);
6673
6684
  } else {
@@ -6678,7 +6689,7 @@ function parseMaxInitial(value) {
6678
6689
  if (value === false || value === "any") {
6679
6690
  return 6;
6680
6691
  }
6681
- const match = value.match(/^h(\d)$/);
6692
+ const match = /^h(\d)$/.exec(value);
6682
6693
  if (!match) {
6683
6694
  return 1;
6684
6695
  }
@@ -7335,7 +7346,7 @@ class MetaRefresh extends Rule {
7335
7346
  }
7336
7347
  }
7337
7348
  function parseContent(text) {
7338
- const match = text.match(/^(\d+)(?:\s*;\s*url=(.*))?/i);
7349
+ const match = /^(\d+)(?:\s*;\s*url=(.*))?/i.exec(text);
7339
7350
  if (match) {
7340
7351
  return {
7341
7352
  delay: parseInt(match[1], 10),
@@ -8126,7 +8137,7 @@ class NoRawCharacters extends Rule {
8126
8137
  if (child.nodeType !== NodeType.TEXT_NODE) {
8127
8138
  continue;
8128
8139
  }
8129
- if (child.textContent.match(matchTemplate)) {
8140
+ if (matchTemplate.exec(child.textContent)) {
8130
8141
  continue;
8131
8142
  }
8132
8143
  this.findRawChars(node, child.textContent, child.location, textRegexp);
@@ -8319,7 +8330,7 @@ class NoSelfClosing extends Rule {
8319
8330
  }
8320
8331
  }
8321
8332
  function isRelevant(node, options) {
8322
- if (node.tagName.match(xmlns)) {
8333
+ if (xmlns.exec(node.tagName)) {
8323
8334
  return !options.ignoreXML;
8324
8335
  }
8325
8336
  if (!node.meta) {
@@ -8360,7 +8371,7 @@ class NoTrailingWhitespace extends Rule {
8360
8371
  }
8361
8372
  setup() {
8362
8373
  this.on("whitespace", (event) => {
8363
- if (event.text.match(/^[ \t]+\r?\n$/)) {
8374
+ if (/^[ \t]+\r?\n$/.exec(event.text)) {
8364
8375
  this.report(null, "Trailing whitespace", event.location);
8365
8376
  }
8366
8377
  });
@@ -8965,7 +8976,7 @@ function constructRegex(characters) {
8965
8976
  return new RegExp(pattern, "g");
8966
8977
  }
8967
8978
  function getText(node) {
8968
- const match = node.textContent.match(/^(\s*)(.*)$/);
8979
+ const match = /^(\s*)(.*)$/.exec(node.textContent);
8969
8980
  const [, leading, text] = match;
8970
8981
  return [leading.length, text.trimEnd()];
8971
8982
  }
@@ -9561,7 +9572,9 @@ const fieldNameGroup = {
9561
9572
  nickname: "text",
9562
9573
  username: "username",
9563
9574
  "new-password": "password",
9575
+ // eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
9564
9576
  "current-password": "password",
9577
+ // eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
9565
9578
  "one-time-code": "password",
9566
9579
  "organization-title": "text",
9567
9580
  organization: "text",
@@ -10050,7 +10063,7 @@ class ValidID extends Rule {
10050
10063
  this.report(event.target, this.messages[context.kind], event.location, context);
10051
10064
  return;
10052
10065
  }
10053
- if (value.match(/\s/)) {
10066
+ if (/\s/.exec(value)) {
10054
10067
  const context = { kind: 2 /* WHITESPACE */, id: value };
10055
10068
  this.report(event.target, this.messages[context.kind], event.valueLocation, context);
10056
10069
  return;
@@ -10059,12 +10072,12 @@ class ValidID extends Rule {
10059
10072
  if (relaxed) {
10060
10073
  return;
10061
10074
  }
10062
- if (value.match(/^[^\p{L}]/u)) {
10075
+ if (/^[^\p{L}]/u.exec(value)) {
10063
10076
  const context = { kind: 3 /* LEADING_CHARACTER */, id: value };
10064
10077
  this.report(event.target, this.messages[context.kind], event.valueLocation, context);
10065
10078
  return;
10066
10079
  }
10067
- if (value.match(/[^\p{L}\p{N}_-]/u)) {
10080
+ if (/[^\p{L}\p{N}_-]/u.exec(value)) {
10068
10081
  const context = { kind: 4 /* DISALLOWED_CHARACTER */, id: value };
10069
10082
  this.report(event.target, this.messages[context.kind], event.valueLocation, context);
10070
10083
  }
@@ -11708,7 +11721,7 @@ class EventHandler {
11708
11721
  }
11709
11722
 
11710
11723
  const name = "html-validate";
11711
- const version = "9.4.2";
11724
+ const version = "9.5.0";
11712
11725
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
11713
11726
 
11714
11727
  function freeze(src) {
@@ -12255,7 +12268,7 @@ class Parser {
12255
12268
  if (!postamble.startsWith("]")) {
12256
12269
  throw new ParserError(token.location, `Missing end bracket "]" on directive "${text}"`);
12257
12270
  }
12258
- const match = directive.match(/^(.*?)(?:(\s*(?:--|:)\s*)(.*))?$/);
12271
+ const match = /^(.*?)(?:(\s*(?:--|:)\s*)(.*))?$/.exec(directive);
12259
12272
  if (!match) {
12260
12273
  throw new Error(`Failed to parse directive "${text}"`);
12261
12274
  }
@@ -12840,7 +12853,7 @@ function validateTransformer(transformer) {
12840
12853
  }
12841
12854
  }
12842
12855
  function loadTransformerFunction(resolvers, name, plugins) {
12843
- const match = name.match(/(.*):(.*)/);
12856
+ const match = /(.*):(.*)/.exec(name);
12844
12857
  if (match) {
12845
12858
  const [, pluginName, key] = match;
12846
12859
  return getNamedTransformerFromPlugin(name, plugins, pluginName, key);