html-validate 9.4.2-rc.1 → 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 +41 -30
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js.map +1 -1
- package/dist/cjs/html-validate.d.ts +1 -0
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/html5.d.ts +1 -0
- package/dist/cjs/jest-worker.d.ts +1 -0
- 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/package.json +2 -2
- 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/cjs/vitest.d.ts +1 -0
- 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 +41 -30
- package/dist/es/core.js.map +1 -1
- package/dist/es/elements.js.map +1 -1
- package/dist/es/html-validate.d.ts +1 -0
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/html5.d.ts +1 -0
- package/dist/es/jest-worker.d.ts +1 -0
- 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/package.json +2 -2
- package/dist/es/test-utils.js +7 -4
- package/dist/es/test-utils.js.map +7 -1
- package/dist/es/vitest.d.ts +1 -0
- 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/cjs/core.js
CHANGED
|
@@ -1071,6 +1071,7 @@ function migrateAttributes(src) {
|
|
|
1071
1071
|
...Object.keys(src.attributes ?? {}),
|
|
1072
1072
|
...src.requiredAttributes ?? [],
|
|
1073
1073
|
...src.deprecatedAttributes ?? []
|
|
1074
|
+
/* eslint-disable-next-line sonarjs/no-alphabetical-sort -- not really needed in this case, this is a-z anyway */
|
|
1074
1075
|
].sort();
|
|
1075
1076
|
const entries = keys.map((key) => {
|
|
1076
1077
|
return [key, migrateSingleAttribute(src, key)];
|
|
@@ -1347,7 +1348,7 @@ function expandRegexValue(value) {
|
|
|
1347
1348
|
if (value instanceof RegExp) {
|
|
1348
1349
|
return value;
|
|
1349
1350
|
}
|
|
1350
|
-
const match =
|
|
1351
|
+
const match = /^\/(.*(?=\/))\/(i?)$/.exec(value);
|
|
1351
1352
|
if (match) {
|
|
1352
1353
|
const [, expr, flags] = match;
|
|
1353
1354
|
if (expr.startsWith("^") || expr.endsWith("$")) {
|
|
@@ -1592,6 +1593,7 @@ class DOMNode {
|
|
|
1592
1593
|
* @internal
|
|
1593
1594
|
*/
|
|
1594
1595
|
unique;
|
|
1596
|
+
/* eslint-disable-next-line sonarjs/use-type-alias -- technical debt */
|
|
1595
1597
|
cache;
|
|
1596
1598
|
/**
|
|
1597
1599
|
* Set of disabled rules for this node.
|
|
@@ -1647,6 +1649,11 @@ class DOMNode {
|
|
|
1647
1649
|
}
|
|
1648
1650
|
return value;
|
|
1649
1651
|
}
|
|
1652
|
+
/**
|
|
1653
|
+
* Remove a value by key from cache.
|
|
1654
|
+
*
|
|
1655
|
+
* @returns `true` if the entry existed and has been removed.
|
|
1656
|
+
*/
|
|
1650
1657
|
cacheRemove(key) {
|
|
1651
1658
|
if (this.cache) {
|
|
1652
1659
|
return this.cache.delete(key);
|
|
@@ -1654,6 +1661,9 @@ class DOMNode {
|
|
|
1654
1661
|
return false;
|
|
1655
1662
|
}
|
|
1656
1663
|
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Check if key exists in cache.
|
|
1666
|
+
*/
|
|
1657
1667
|
cacheExists(key) {
|
|
1658
1668
|
return Boolean(this.cache?.has(key));
|
|
1659
1669
|
}
|
|
@@ -1994,7 +2004,7 @@ class AttributeCondition extends Condition {
|
|
|
1994
2004
|
value;
|
|
1995
2005
|
constructor(attr) {
|
|
1996
2006
|
super();
|
|
1997
|
-
const [, key, op, value] =
|
|
2007
|
+
const [, key, op, value] = /^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/.exec(attr);
|
|
1998
2008
|
this.key = key;
|
|
1999
2009
|
this.op = op;
|
|
2000
2010
|
this.value = value;
|
|
@@ -2003,6 +2013,7 @@ class AttributeCondition extends Condition {
|
|
|
2003
2013
|
const attr = node.getAttribute(this.key, true);
|
|
2004
2014
|
return attr.some((cur) => {
|
|
2005
2015
|
switch (this.op) {
|
|
2016
|
+
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- technical debt, the type of op should reflect this case */
|
|
2006
2017
|
case void 0:
|
|
2007
2018
|
return true;
|
|
2008
2019
|
/* attribute exists */
|
|
@@ -2019,7 +2030,7 @@ class PseudoClassCondition extends Condition {
|
|
|
2019
2030
|
args;
|
|
2020
2031
|
constructor(pseudoclass, context) {
|
|
2021
2032
|
super();
|
|
2022
|
-
const match =
|
|
2033
|
+
const match = /^([^(]+)(?:\((.*)\))?$/.exec(pseudoclass);
|
|
2023
2034
|
if (!match) {
|
|
2024
2035
|
throw new Error(`Missing pseudo-class after colon in selector pattern "${context}"`);
|
|
2025
2036
|
}
|
|
@@ -2089,7 +2100,7 @@ class Compound {
|
|
|
2089
2100
|
selector;
|
|
2090
2101
|
conditions;
|
|
2091
2102
|
constructor(pattern) {
|
|
2092
|
-
const match =
|
|
2103
|
+
const match = /^([~+\->]?)((?:[*]|[^.#[:]+)?)([^]*)$/.exec(pattern);
|
|
2093
2104
|
if (!match) {
|
|
2094
2105
|
throw new Error(`Failed to create selector pattern from "${pattern}"`);
|
|
2095
2106
|
}
|
|
@@ -2157,14 +2168,12 @@ function candidatesFromCombinator(element, combinator) {
|
|
|
2157
2168
|
return adjacentSibling(element);
|
|
2158
2169
|
case Combinator.GENERAL_SIBLING:
|
|
2159
2170
|
return generalSibling(element);
|
|
2171
|
+
/* istanbul ignore next -- cannot really happen, the selector would be malformed */
|
|
2160
2172
|
case Combinator.SCOPE:
|
|
2161
2173
|
return scope(element);
|
|
2162
2174
|
}
|
|
2163
2175
|
}
|
|
2164
2176
|
function matchElement(element, compounds, context) {
|
|
2165
|
-
if (compounds.length === 0) {
|
|
2166
|
-
return true;
|
|
2167
|
-
}
|
|
2168
2177
|
const last = compounds[compounds.length - 1];
|
|
2169
2178
|
if (!last.match(element, context)) {
|
|
2170
2179
|
return false;
|
|
@@ -2258,7 +2267,7 @@ function escapeSelectorComponent(text) {
|
|
|
2258
2267
|
}
|
|
2259
2268
|
function generateIdSelector(id) {
|
|
2260
2269
|
const escaped = escapeSelectorComponent(id);
|
|
2261
|
-
return
|
|
2270
|
+
return /^\d/.exec(escaped) ? `[id="${escaped}"]` : `#${escaped}`;
|
|
2262
2271
|
}
|
|
2263
2272
|
class Selector {
|
|
2264
2273
|
pattern;
|
|
@@ -3080,7 +3089,7 @@ class Validator {
|
|
|
3080
3089
|
if (typeof rule !== "string") {
|
|
3081
3090
|
return false;
|
|
3082
3091
|
}
|
|
3083
|
-
const [, category, quantifier] =
|
|
3092
|
+
const [, category, quantifier] = /^(@?.*?)([?*]?)$/.exec(rule);
|
|
3084
3093
|
const limit = category && quantifier && parseQuantifier(quantifier);
|
|
3085
3094
|
if (limit) {
|
|
3086
3095
|
const siblings = children.filter(
|
|
@@ -3248,7 +3257,7 @@ class Validator {
|
|
|
3248
3257
|
*/
|
|
3249
3258
|
/* eslint-disable-next-line complexity -- rule does not like switch */
|
|
3250
3259
|
static validatePermittedCategory(node, category, defaultMatch) {
|
|
3251
|
-
const [, rawCategory] =
|
|
3260
|
+
const [, rawCategory] = /^(@?.*?)([?*]?)$/.exec(category);
|
|
3252
3261
|
if (!rawCategory.startsWith("@")) {
|
|
3253
3262
|
return node.tagName === rawCategory;
|
|
3254
3263
|
}
|
|
@@ -3491,7 +3500,7 @@ function escape(value) {
|
|
|
3491
3500
|
return JSON.stringify(value);
|
|
3492
3501
|
}
|
|
3493
3502
|
function format(value, quote = false) {
|
|
3494
|
-
if (value === null) {
|
|
3503
|
+
if (value === null || value === void 0) {
|
|
3495
3504
|
return "null";
|
|
3496
3505
|
}
|
|
3497
3506
|
if (typeof value === "number") {
|
|
@@ -3570,7 +3579,7 @@ function compilePattern(pattern) {
|
|
|
3570
3579
|
if (cached) {
|
|
3571
3580
|
return cached;
|
|
3572
3581
|
}
|
|
3573
|
-
const match =
|
|
3582
|
+
const match = /^\/(.*)\/$/.exec(pattern);
|
|
3574
3583
|
const regexp = match ? compileRegExpPattern(match[1]) : compileStringPattern(pattern);
|
|
3575
3584
|
patternCache.set(pattern, regexp);
|
|
3576
3585
|
return regexp;
|
|
@@ -3755,7 +3764,7 @@ function classifyNodeText(node, options = {}) {
|
|
|
3755
3764
|
if (text.some((cur) => cur.isDynamic)) {
|
|
3756
3765
|
return node.cacheSet(cacheKey, 1 /* DYNAMIC_TEXT */);
|
|
3757
3766
|
}
|
|
3758
|
-
if (text.some((cur) => cur.textContent
|
|
3767
|
+
if (text.some((cur) => /\S/.exec(cur.textContent) !== null)) {
|
|
3759
3768
|
return node.cacheSet(cacheKey, 2 /* STATIC_TEXT */);
|
|
3760
3769
|
}
|
|
3761
3770
|
return node.cacheSet(cacheKey, 0 /* EMPTY_TEXT */);
|
|
@@ -5769,7 +5778,7 @@ class Deprecated extends Rule {
|
|
|
5769
5778
|
}
|
|
5770
5779
|
}
|
|
5771
5780
|
function prettySource(source) {
|
|
5772
|
-
const match =
|
|
5781
|
+
const match = /html(\d)(\d)?/.exec(source);
|
|
5773
5782
|
if (match) {
|
|
5774
5783
|
const [, ...parts] = match;
|
|
5775
5784
|
const version = parts.filter(Boolean).join(".");
|
|
@@ -6007,7 +6016,7 @@ class ElementName extends Rule {
|
|
|
6007
6016
|
if (target.meta) {
|
|
6008
6017
|
return;
|
|
6009
6018
|
}
|
|
6010
|
-
if (
|
|
6019
|
+
if (xmlns.exec(tagName)) {
|
|
6011
6020
|
return;
|
|
6012
6021
|
}
|
|
6013
6022
|
if (this.options.whitelist.includes(tagName)) {
|
|
@@ -6094,7 +6103,7 @@ class ElementPermittedContent extends Rule {
|
|
|
6094
6103
|
}
|
|
6095
6104
|
validatePermittedDescendant(node, parent) {
|
|
6096
6105
|
for (let cur = parent; cur && !cur.isRootElement(); cur = /* istanbul ignore next */
|
|
6097
|
-
cur
|
|
6106
|
+
cur.parent ?? null) {
|
|
6098
6107
|
const meta = cur.meta;
|
|
6099
6108
|
if (!meta) {
|
|
6100
6109
|
continue;
|
|
@@ -6265,7 +6274,7 @@ class ElementPermittedParent extends Rule {
|
|
|
6265
6274
|
}
|
|
6266
6275
|
|
|
6267
6276
|
function isTagnameOnly(value) {
|
|
6268
|
-
return Boolean(
|
|
6277
|
+
return Boolean(/^[a-zA-Z0-9-]+$/.exec(value));
|
|
6269
6278
|
}
|
|
6270
6279
|
function getRuleDescription(context) {
|
|
6271
6280
|
const escaped = context.ancestor.map((it) => `\`${it}\``);
|
|
@@ -6678,7 +6687,7 @@ function isRelevant$5(event) {
|
|
|
6678
6687
|
return Boolean(node.meta?.heading);
|
|
6679
6688
|
}
|
|
6680
6689
|
function extractLevel(node) {
|
|
6681
|
-
const match =
|
|
6690
|
+
const match = /^[hH](\d)$/.exec(node.tagName);
|
|
6682
6691
|
if (match) {
|
|
6683
6692
|
return parseInt(match[1], 10);
|
|
6684
6693
|
} else {
|
|
@@ -6689,7 +6698,7 @@ function parseMaxInitial(value) {
|
|
|
6689
6698
|
if (value === false || value === "any") {
|
|
6690
6699
|
return 6;
|
|
6691
6700
|
}
|
|
6692
|
-
const match =
|
|
6701
|
+
const match = /^h(\d)$/.exec(value);
|
|
6693
6702
|
if (!match) {
|
|
6694
6703
|
return 1;
|
|
6695
6704
|
}
|
|
@@ -7346,7 +7355,7 @@ class MetaRefresh extends Rule {
|
|
|
7346
7355
|
}
|
|
7347
7356
|
}
|
|
7348
7357
|
function parseContent(text) {
|
|
7349
|
-
const match =
|
|
7358
|
+
const match = /^(\d+)(?:\s*;\s*url=(.*))?/i.exec(text);
|
|
7350
7359
|
if (match) {
|
|
7351
7360
|
return {
|
|
7352
7361
|
delay: parseInt(match[1], 10),
|
|
@@ -8137,7 +8146,7 @@ class NoRawCharacters extends Rule {
|
|
|
8137
8146
|
if (child.nodeType !== NodeType.TEXT_NODE) {
|
|
8138
8147
|
continue;
|
|
8139
8148
|
}
|
|
8140
|
-
if (child.textContent
|
|
8149
|
+
if (matchTemplate.exec(child.textContent)) {
|
|
8141
8150
|
continue;
|
|
8142
8151
|
}
|
|
8143
8152
|
this.findRawChars(node, child.textContent, child.location, textRegexp);
|
|
@@ -8330,7 +8339,7 @@ class NoSelfClosing extends Rule {
|
|
|
8330
8339
|
}
|
|
8331
8340
|
}
|
|
8332
8341
|
function isRelevant(node, options) {
|
|
8333
|
-
if (node.tagName
|
|
8342
|
+
if (xmlns.exec(node.tagName)) {
|
|
8334
8343
|
return !options.ignoreXML;
|
|
8335
8344
|
}
|
|
8336
8345
|
if (!node.meta) {
|
|
@@ -8371,7 +8380,7 @@ class NoTrailingWhitespace extends Rule {
|
|
|
8371
8380
|
}
|
|
8372
8381
|
setup() {
|
|
8373
8382
|
this.on("whitespace", (event) => {
|
|
8374
|
-
if (
|
|
8383
|
+
if (/^[ \t]+\r?\n$/.exec(event.text)) {
|
|
8375
8384
|
this.report(null, "Trailing whitespace", event.location);
|
|
8376
8385
|
}
|
|
8377
8386
|
});
|
|
@@ -8976,7 +8985,7 @@ function constructRegex(characters) {
|
|
|
8976
8985
|
return new RegExp(pattern, "g");
|
|
8977
8986
|
}
|
|
8978
8987
|
function getText(node) {
|
|
8979
|
-
const match =
|
|
8988
|
+
const match = /^(\s*)(.*)$/.exec(node.textContent);
|
|
8980
8989
|
const [, leading, text] = match;
|
|
8981
8990
|
return [leading.length, text.trimEnd()];
|
|
8982
8991
|
}
|
|
@@ -9572,7 +9581,9 @@ const fieldNameGroup = {
|
|
|
9572
9581
|
nickname: "text",
|
|
9573
9582
|
username: "username",
|
|
9574
9583
|
"new-password": "password",
|
|
9584
|
+
// eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
|
|
9575
9585
|
"current-password": "password",
|
|
9586
|
+
// eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
|
|
9576
9587
|
"one-time-code": "password",
|
|
9577
9588
|
"organization-title": "text",
|
|
9578
9589
|
organization: "text",
|
|
@@ -10061,7 +10072,7 @@ class ValidID extends Rule {
|
|
|
10061
10072
|
this.report(event.target, this.messages[context.kind], event.location, context);
|
|
10062
10073
|
return;
|
|
10063
10074
|
}
|
|
10064
|
-
if (
|
|
10075
|
+
if (/\s/.exec(value)) {
|
|
10065
10076
|
const context = { kind: 2 /* WHITESPACE */, id: value };
|
|
10066
10077
|
this.report(event.target, this.messages[context.kind], event.valueLocation, context);
|
|
10067
10078
|
return;
|
|
@@ -10070,12 +10081,12 @@ class ValidID extends Rule {
|
|
|
10070
10081
|
if (relaxed) {
|
|
10071
10082
|
return;
|
|
10072
10083
|
}
|
|
10073
|
-
if (
|
|
10084
|
+
if (/^[^\p{L}]/u.exec(value)) {
|
|
10074
10085
|
const context = { kind: 3 /* LEADING_CHARACTER */, id: value };
|
|
10075
10086
|
this.report(event.target, this.messages[context.kind], event.valueLocation, context);
|
|
10076
10087
|
return;
|
|
10077
10088
|
}
|
|
10078
|
-
if (
|
|
10089
|
+
if (/[^\p{L}\p{N}_-]/u.exec(value)) {
|
|
10079
10090
|
const context = { kind: 4 /* DISALLOWED_CHARACTER */, id: value };
|
|
10080
10091
|
this.report(event.target, this.messages[context.kind], event.valueLocation, context);
|
|
10081
10092
|
}
|
|
@@ -11719,7 +11730,7 @@ class EventHandler {
|
|
|
11719
11730
|
}
|
|
11720
11731
|
|
|
11721
11732
|
const name = "html-validate";
|
|
11722
|
-
const version = "9.
|
|
11733
|
+
const version = "9.5.0";
|
|
11723
11734
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
11724
11735
|
|
|
11725
11736
|
function freeze(src) {
|
|
@@ -12266,7 +12277,7 @@ class Parser {
|
|
|
12266
12277
|
if (!postamble.startsWith("]")) {
|
|
12267
12278
|
throw new ParserError(token.location, `Missing end bracket "]" on directive "${text}"`);
|
|
12268
12279
|
}
|
|
12269
|
-
const match =
|
|
12280
|
+
const match = /^(.*?)(?:(\s*(?:--|:)\s*)(.*))?$/.exec(directive);
|
|
12270
12281
|
if (!match) {
|
|
12271
12282
|
throw new Error(`Failed to parse directive "${text}"`);
|
|
12272
12283
|
}
|
|
@@ -12851,7 +12862,7 @@ function validateTransformer(transformer) {
|
|
|
12851
12862
|
}
|
|
12852
12863
|
}
|
|
12853
12864
|
function loadTransformerFunction(resolvers, name, plugins) {
|
|
12854
|
-
const match =
|
|
12865
|
+
const match = /(.*):(.*)/.exec(name);
|
|
12855
12866
|
if (match) {
|
|
12856
12867
|
const [, pluginName, key] = match;
|
|
12857
12868
|
return getNamedTransformerFromPlugin(name, plugins, pluginName, key);
|