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/cjs/core-browser.js.map +1 -1
- package/dist/cjs/core-nodejs.js +1 -0
- package/dist/cjs/core-nodejs.js.map +1 -1
- package/dist/cjs/core.js +39 -26
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js.map +1 -1
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/jest-worker.js.map +1 -1
- package/dist/cjs/matchers.js.map +1 -1
- package/dist/cjs/meta-helper.js +1 -1
- package/dist/cjs/meta-helper.js.map +1 -1
- package/dist/cjs/test-utils.js +45 -11
- package/dist/cjs/test-utils.js.map +7 -1
- package/dist/cjs/tsdoc-metadata.json +1 -1
- package/dist/es/core-browser.js.map +1 -1
- package/dist/es/core-nodejs.js +1 -0
- package/dist/es/core-nodejs.js.map +1 -1
- package/dist/es/core.js +39 -26
- package/dist/es/core.js.map +1 -1
- package/dist/es/elements.js.map +1 -1
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/jest-worker.js.map +1 -1
- package/dist/es/matchers.js.map +1 -1
- package/dist/es/meta-helper.js +1 -1
- package/dist/es/meta-helper.js.map +1 -1
- package/dist/es/test-utils.js +7 -4
- package/dist/es/test-utils.js.map +7 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types/browser.d.ts +6 -8
- package/dist/types/index.d.ts +6 -8
- package/package.json +2 -2
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 =
|
|
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] =
|
|
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 =
|
|
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 =
|
|
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
|
|
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] =
|
|
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] =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 (
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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.
|
|
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 =
|
|
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 =
|
|
12856
|
+
const match = /(.*):(.*)/.exec(name);
|
|
12844
12857
|
if (match) {
|
|
12845
12858
|
const [, pluginName, key] = match;
|
|
12846
12859
|
return getNamedTransformerFromPlugin(name, plugins, pluginName, key);
|