html-validate 6.6.1 → 6.7.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/browser.js +2 -0
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/cli.js +9 -5
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core.d.ts +1 -3
- package/dist/cjs/core.js +273 -82
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/html-validate.js +11 -6
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/jest-lib.d.ts +2 -1
- package/dist/cjs/jest-lib.js +52 -27
- package/dist/cjs/jest-lib.js.map +1 -1
- package/dist/cjs/jest.js +2 -0
- package/dist/cjs/jest.js.map +1 -1
- package/dist/es/browser.js +2 -0
- package/dist/es/browser.js.map +1 -1
- package/dist/es/cli.js +9 -5
- package/dist/es/cli.js.map +1 -1
- package/dist/es/core.d.ts +1 -3
- package/dist/es/core.js +251 -80
- package/dist/es/core.js.map +1 -1
- package/dist/es/html-validate.js +11 -6
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/index.js +2 -0
- package/dist/es/index.js.map +1 -1
- package/dist/es/jest-lib.d.ts +2 -1
- package/dist/es/jest-lib.js +52 -27
- package/dist/es/jest-lib.js.map +1 -1
- package/dist/es/jest.js +2 -0
- package/dist/es/jest.js.map +1 -1
- package/package.json +1 -153
package/dist/es/core.js
CHANGED
|
@@ -2,6 +2,8 @@ import fs from 'fs';
|
|
|
2
2
|
import betterAjvErrors from '@sidvind/better-ajv-errors';
|
|
3
3
|
import Ajv from 'ajv';
|
|
4
4
|
import deepmerge from 'deepmerge';
|
|
5
|
+
import * as espree from 'espree';
|
|
6
|
+
import * as walk from 'acorn-walk';
|
|
5
7
|
import path from 'path';
|
|
6
8
|
import semver from 'semver';
|
|
7
9
|
import kleur from 'kleur';
|
|
@@ -245,7 +247,7 @@ class NestedError extends Error {
|
|
|
245
247
|
constructor(message, nested) {
|
|
246
248
|
super(message);
|
|
247
249
|
Error.captureStackTrace(this, NestedError);
|
|
248
|
-
if (nested) {
|
|
250
|
+
if (nested && nested.stack) {
|
|
249
251
|
this.stack += `\nCaused by: ${nested.stack}`;
|
|
250
252
|
}
|
|
251
253
|
}
|
|
@@ -1838,8 +1840,13 @@ var NodeClosed;
|
|
|
1838
1840
|
NodeClosed[NodeClosed["VoidSelfClosed"] = 3] = "VoidSelfClosed";
|
|
1839
1841
|
NodeClosed[NodeClosed["ImplicitClosed"] = 4] = "ImplicitClosed";
|
|
1840
1842
|
})(NodeClosed || (NodeClosed = {}));
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
+
/**
|
|
1844
|
+
* Returns true if the node is an element node.
|
|
1845
|
+
*
|
|
1846
|
+
* @public
|
|
1847
|
+
*/
|
|
1848
|
+
function isElementNode(node) {
|
|
1849
|
+
return Boolean(node && node.nodeType === NodeType.ELEMENT_NODE);
|
|
1843
1850
|
}
|
|
1844
1851
|
function isValidTagName(tagName) {
|
|
1845
1852
|
return Boolean(tagName !== "" && tagName !== "*");
|
|
@@ -1913,7 +1920,7 @@ class HtmlElement extends DOMNode {
|
|
|
1913
1920
|
* Similar to childNodes but only elements.
|
|
1914
1921
|
*/
|
|
1915
1922
|
get childElements() {
|
|
1916
|
-
return this.childNodes.filter(
|
|
1923
|
+
return this.childNodes.filter(isElementNode);
|
|
1917
1924
|
}
|
|
1918
1925
|
/**
|
|
1919
1926
|
* Find the first ancestor matching a selector.
|
|
@@ -2174,8 +2181,9 @@ class HtmlElement extends DOMNode {
|
|
|
2174
2181
|
}, []);
|
|
2175
2182
|
}
|
|
2176
2183
|
querySelector(selector) {
|
|
2184
|
+
var _a;
|
|
2177
2185
|
const it = this.querySelectorImpl(selector);
|
|
2178
|
-
return it.next().value
|
|
2186
|
+
return (_a = it.next().value) !== null && _a !== void 0 ? _a : null; // eslint-disable-line @typescript-eslint/no-unsafe-return
|
|
2179
2187
|
}
|
|
2180
2188
|
querySelectorAll(selector) {
|
|
2181
2189
|
const it = this.querySelectorImpl(selector);
|
|
@@ -2742,8 +2750,6 @@ var configurationSchema = {
|
|
|
2742
2750
|
};
|
|
2743
2751
|
|
|
2744
2752
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2745
|
-
const espree = legacyRequire("espree");
|
|
2746
|
-
const walk = legacyRequire("acorn-walk");
|
|
2747
2753
|
function joinTemplateLiteral(nodes) {
|
|
2748
2754
|
let offset = nodes[0].start + 1;
|
|
2749
2755
|
let output = "";
|
|
@@ -2924,7 +2930,8 @@ class TemplateExtractor {
|
|
|
2924
2930
|
extractObjectProperty(key) {
|
|
2925
2931
|
const result = [];
|
|
2926
2932
|
const { filename, data } = this;
|
|
2927
|
-
|
|
2933
|
+
const node = this.ast;
|
|
2934
|
+
walk.simple(node, {
|
|
2928
2935
|
Property(node) {
|
|
2929
2936
|
if (compareKey(node.key, key, filename)) {
|
|
2930
2937
|
const source = extractLiteral(node.value, filename, data);
|
|
@@ -2948,7 +2955,7 @@ var TRANSFORMER_API;
|
|
|
2948
2955
|
/** @public */
|
|
2949
2956
|
const name = "html-validate";
|
|
2950
2957
|
/** @public */
|
|
2951
|
-
const version = "6.
|
|
2958
|
+
const version = "6.7.0";
|
|
2952
2959
|
/** @public */
|
|
2953
2960
|
const homepage = "https://html-validate.org";
|
|
2954
2961
|
/** @public */
|
|
@@ -3269,7 +3276,7 @@ function ruleDocumentationUrl(filename) {
|
|
|
3269
3276
|
return `${homepage}/rules/${normalized}.html`;
|
|
3270
3277
|
}
|
|
3271
3278
|
|
|
3272
|
-
const defaults$
|
|
3279
|
+
const defaults$q = {
|
|
3273
3280
|
allowExternal: true,
|
|
3274
3281
|
allowRelative: true,
|
|
3275
3282
|
allowAbsolute: true,
|
|
@@ -3313,7 +3320,7 @@ function matchList(value, list) {
|
|
|
3313
3320
|
}
|
|
3314
3321
|
class AllowedLinks extends Rule {
|
|
3315
3322
|
constructor(options) {
|
|
3316
|
-
super({ ...defaults$
|
|
3323
|
+
super({ ...defaults$q, ...options });
|
|
3317
3324
|
this.allowExternal = parseAllow(this.options.allowExternal);
|
|
3318
3325
|
this.allowRelative = parseAllow(this.options.allowRelative);
|
|
3319
3326
|
this.allowAbsolute = parseAllow(this.options.allowAbsolute);
|
|
@@ -3592,7 +3599,7 @@ class CaseStyle {
|
|
|
3592
3599
|
default: {
|
|
3593
3600
|
const last = names.slice(-1);
|
|
3594
3601
|
const rest = names.slice(0, -1);
|
|
3595
|
-
return `${rest.join(", ")} or ${last}`;
|
|
3602
|
+
return `${rest.join(", ")} or ${last[0]}`;
|
|
3596
3603
|
}
|
|
3597
3604
|
}
|
|
3598
3605
|
}
|
|
@@ -3608,19 +3615,19 @@ class CaseStyle {
|
|
|
3608
3615
|
case "camelcase":
|
|
3609
3616
|
return { pattern: /^[a-z][A-Za-z]*$/, name: "camelCase" };
|
|
3610
3617
|
default:
|
|
3611
|
-
throw new ConfigError(`Invalid style "${
|
|
3618
|
+
throw new ConfigError(`Invalid style "${cur}" for ${ruleId} rule`);
|
|
3612
3619
|
}
|
|
3613
3620
|
});
|
|
3614
3621
|
}
|
|
3615
3622
|
}
|
|
3616
3623
|
|
|
3617
|
-
const defaults$
|
|
3624
|
+
const defaults$p = {
|
|
3618
3625
|
style: "lowercase",
|
|
3619
3626
|
ignoreForeign: true,
|
|
3620
3627
|
};
|
|
3621
3628
|
class AttrCase extends Rule {
|
|
3622
3629
|
constructor(options) {
|
|
3623
|
-
super({ ...defaults$
|
|
3630
|
+
super({ ...defaults$p, ...options });
|
|
3624
3631
|
this.style = new CaseStyle(this.options.style, "attr-case");
|
|
3625
3632
|
}
|
|
3626
3633
|
static schema() {
|
|
@@ -3647,8 +3654,11 @@ class AttrCase extends Rule {
|
|
|
3647
3654
|
};
|
|
3648
3655
|
}
|
|
3649
3656
|
documentation() {
|
|
3657
|
+
const { style } = this.options;
|
|
3650
3658
|
return {
|
|
3651
|
-
description:
|
|
3659
|
+
description: Array.isArray(style)
|
|
3660
|
+
? [`Attribute name must be in one of:`, "", ...style.map((it) => `- ${it}`)].join("\n")
|
|
3661
|
+
: `Attribute name must be in ${style}.`,
|
|
3652
3662
|
url: ruleDocumentationUrl("@/rules/attr-case.ts"),
|
|
3653
3663
|
};
|
|
3654
3664
|
}
|
|
@@ -3939,7 +3949,7 @@ function isRelevant$3(event) {
|
|
|
3939
3949
|
class AttrDelimiter extends Rule {
|
|
3940
3950
|
documentation() {
|
|
3941
3951
|
return {
|
|
3942
|
-
description: `Attribute value
|
|
3952
|
+
description: `Attribute value must not be separated by whitespace.`,
|
|
3943
3953
|
url: ruleDocumentationUrl("@/rules/attr-delimiter.ts"),
|
|
3944
3954
|
};
|
|
3945
3955
|
}
|
|
@@ -3956,7 +3966,7 @@ class AttrDelimiter extends Rule {
|
|
|
3956
3966
|
}
|
|
3957
3967
|
|
|
3958
3968
|
const DEFAULT_PATTERN = "[a-z0-9-:]+";
|
|
3959
|
-
const defaults$
|
|
3969
|
+
const defaults$o = {
|
|
3960
3970
|
pattern: DEFAULT_PATTERN,
|
|
3961
3971
|
ignoreForeign: true,
|
|
3962
3972
|
};
|
|
@@ -3993,7 +4003,7 @@ function generateDescription(name, pattern) {
|
|
|
3993
4003
|
}
|
|
3994
4004
|
class AttrPattern extends Rule {
|
|
3995
4005
|
constructor(options) {
|
|
3996
|
-
super({ ...defaults$
|
|
4006
|
+
super({ ...defaults$o, ...options });
|
|
3997
4007
|
this.pattern = generateRegexp(this.options.pattern);
|
|
3998
4008
|
}
|
|
3999
4009
|
static schema() {
|
|
@@ -4053,13 +4063,13 @@ var QuoteStyle;
|
|
|
4053
4063
|
QuoteStyle["DOUBLE_QUOTE"] = "\"";
|
|
4054
4064
|
QuoteStyle["AUTO_QUOTE"] = "auto";
|
|
4055
4065
|
})(QuoteStyle || (QuoteStyle = {}));
|
|
4056
|
-
const defaults$
|
|
4066
|
+
const defaults$n = {
|
|
4057
4067
|
style: "auto",
|
|
4058
4068
|
unquoted: false,
|
|
4059
4069
|
};
|
|
4060
4070
|
class AttrQuotes extends Rule {
|
|
4061
4071
|
constructor(options) {
|
|
4062
|
-
super({ ...defaults$
|
|
4072
|
+
super({ ...defaults$n, ...options });
|
|
4063
4073
|
this.style = parseStyle$4(this.options.style);
|
|
4064
4074
|
}
|
|
4065
4075
|
static schema() {
|
|
@@ -4224,12 +4234,12 @@ class AttributeAllowedValues extends Rule {
|
|
|
4224
4234
|
}
|
|
4225
4235
|
}
|
|
4226
4236
|
|
|
4227
|
-
const defaults$
|
|
4237
|
+
const defaults$m = {
|
|
4228
4238
|
style: "omit",
|
|
4229
4239
|
};
|
|
4230
4240
|
class AttributeBooleanStyle extends Rule {
|
|
4231
4241
|
constructor(options) {
|
|
4232
|
-
super({ ...defaults$
|
|
4242
|
+
super({ ...defaults$m, ...options });
|
|
4233
4243
|
this.hasInvalidStyle = parseStyle$3(this.options.style);
|
|
4234
4244
|
}
|
|
4235
4245
|
static schema() {
|
|
@@ -4305,12 +4315,12 @@ function reportMessage$1(attr, style) {
|
|
|
4305
4315
|
return "";
|
|
4306
4316
|
}
|
|
4307
4317
|
|
|
4308
|
-
const defaults$
|
|
4318
|
+
const defaults$l = {
|
|
4309
4319
|
style: "omit",
|
|
4310
4320
|
};
|
|
4311
4321
|
class AttributeEmptyStyle extends Rule {
|
|
4312
4322
|
constructor(options) {
|
|
4313
|
-
super({ ...defaults$
|
|
4323
|
+
super({ ...defaults$l, ...options });
|
|
4314
4324
|
this.hasInvalidStyle = parseStyle$2(this.options.style);
|
|
4315
4325
|
}
|
|
4316
4326
|
static schema() {
|
|
@@ -4418,12 +4428,12 @@ function describePattern(pattern) {
|
|
|
4418
4428
|
}
|
|
4419
4429
|
}
|
|
4420
4430
|
|
|
4421
|
-
const defaults$
|
|
4431
|
+
const defaults$k = {
|
|
4422
4432
|
pattern: "kebabcase",
|
|
4423
4433
|
};
|
|
4424
4434
|
class ClassPattern extends Rule {
|
|
4425
4435
|
constructor(options) {
|
|
4426
|
-
super({ ...defaults$
|
|
4436
|
+
super({ ...defaults$k, ...options });
|
|
4427
4437
|
this.pattern = parsePattern(this.options.pattern);
|
|
4428
4438
|
}
|
|
4429
4439
|
static schema() {
|
|
@@ -4449,7 +4459,9 @@ class ClassPattern extends Rule {
|
|
|
4449
4459
|
classes.forEach((cur, index) => {
|
|
4450
4460
|
if (!cur.match(this.pattern)) {
|
|
4451
4461
|
const location = classes.location(index);
|
|
4452
|
-
|
|
4462
|
+
const pattern = this.pattern.toString();
|
|
4463
|
+
const message = `Class "${cur}" does not match required pattern "${pattern}"`;
|
|
4464
|
+
this.report(event.target, message, location);
|
|
4453
4465
|
}
|
|
4454
4466
|
});
|
|
4455
4467
|
});
|
|
@@ -4530,13 +4542,13 @@ class CloseOrder extends Rule {
|
|
|
4530
4542
|
}
|
|
4531
4543
|
}
|
|
4532
4544
|
|
|
4533
|
-
const defaults$
|
|
4545
|
+
const defaults$j = {
|
|
4534
4546
|
include: null,
|
|
4535
4547
|
exclude: null,
|
|
4536
4548
|
};
|
|
4537
4549
|
class Deprecated extends Rule {
|
|
4538
4550
|
constructor(options) {
|
|
4539
|
-
super({ ...defaults$
|
|
4551
|
+
super({ ...defaults$j, ...options });
|
|
4540
4552
|
}
|
|
4541
4553
|
static schema() {
|
|
4542
4554
|
return {
|
|
@@ -4699,12 +4711,12 @@ class NoStyleTag$1 extends Rule {
|
|
|
4699
4711
|
}
|
|
4700
4712
|
}
|
|
4701
4713
|
|
|
4702
|
-
const defaults$
|
|
4714
|
+
const defaults$i = {
|
|
4703
4715
|
style: "uppercase",
|
|
4704
4716
|
};
|
|
4705
4717
|
class DoctypeStyle extends Rule {
|
|
4706
4718
|
constructor(options) {
|
|
4707
|
-
super({ ...defaults$
|
|
4719
|
+
super({ ...defaults$i, ...options });
|
|
4708
4720
|
}
|
|
4709
4721
|
static schema() {
|
|
4710
4722
|
return {
|
|
@@ -4736,12 +4748,12 @@ class DoctypeStyle extends Rule {
|
|
|
4736
4748
|
}
|
|
4737
4749
|
}
|
|
4738
4750
|
|
|
4739
|
-
const defaults$
|
|
4751
|
+
const defaults$h = {
|
|
4740
4752
|
style: "lowercase",
|
|
4741
4753
|
};
|
|
4742
4754
|
class ElementCase extends Rule {
|
|
4743
4755
|
constructor(options) {
|
|
4744
|
-
super({ ...defaults$
|
|
4756
|
+
super({ ...defaults$h, ...options });
|
|
4745
4757
|
this.style = new CaseStyle(this.options.style, "element-case");
|
|
4746
4758
|
}
|
|
4747
4759
|
static schema() {
|
|
@@ -4765,8 +4777,11 @@ class ElementCase extends Rule {
|
|
|
4765
4777
|
};
|
|
4766
4778
|
}
|
|
4767
4779
|
documentation() {
|
|
4780
|
+
const { style } = this.options;
|
|
4768
4781
|
return {
|
|
4769
|
-
description:
|
|
4782
|
+
description: Array.isArray(style)
|
|
4783
|
+
? [`Element tagname must be in one of:`, "", ...style.map((it) => `- ${it}`)].join("\n")
|
|
4784
|
+
: `Element tagname must be in ${style}.`,
|
|
4770
4785
|
url: ruleDocumentationUrl("@/rules/element-case.ts"),
|
|
4771
4786
|
};
|
|
4772
4787
|
}
|
|
@@ -4804,14 +4819,14 @@ class ElementCase extends Rule {
|
|
|
4804
4819
|
}
|
|
4805
4820
|
}
|
|
4806
4821
|
|
|
4807
|
-
const defaults$
|
|
4822
|
+
const defaults$g = {
|
|
4808
4823
|
pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
|
|
4809
4824
|
whitelist: [],
|
|
4810
4825
|
blacklist: [],
|
|
4811
4826
|
};
|
|
4812
4827
|
class ElementName extends Rule {
|
|
4813
4828
|
constructor(options) {
|
|
4814
|
-
super({ ...defaults$
|
|
4829
|
+
super({ ...defaults$g, ...options });
|
|
4815
4830
|
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
4816
4831
|
this.pattern = new RegExp(this.options.pattern);
|
|
4817
4832
|
}
|
|
@@ -4852,7 +4867,7 @@ class ElementName extends Rule {
|
|
|
4852
4867
|
...context.blacklist.map((cur) => `- ${cur}`),
|
|
4853
4868
|
];
|
|
4854
4869
|
}
|
|
4855
|
-
if (context.pattern !== defaults$
|
|
4870
|
+
if (context.pattern !== defaults$g.pattern) {
|
|
4856
4871
|
return [
|
|
4857
4872
|
`<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
|
|
4858
4873
|
"",
|
|
@@ -5254,7 +5269,7 @@ class EmptyTitle extends Rule {
|
|
|
5254
5269
|
}
|
|
5255
5270
|
}
|
|
5256
5271
|
|
|
5257
|
-
const defaults$
|
|
5272
|
+
const defaults$f = {
|
|
5258
5273
|
allowMultipleH1: false,
|
|
5259
5274
|
minInitialRank: "h1",
|
|
5260
5275
|
sectioningRoots: ["dialog", '[role="dialog"]'],
|
|
@@ -5285,7 +5300,7 @@ function parseMaxInitial(value) {
|
|
|
5285
5300
|
}
|
|
5286
5301
|
class HeadingLevel extends Rule {
|
|
5287
5302
|
constructor(options) {
|
|
5288
|
-
super({ ...defaults$
|
|
5303
|
+
super({ ...defaults$f, ...options });
|
|
5289
5304
|
this.stack = [];
|
|
5290
5305
|
this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
|
|
5291
5306
|
this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
|
|
@@ -5443,12 +5458,12 @@ class HeadingLevel extends Rule {
|
|
|
5443
5458
|
}
|
|
5444
5459
|
}
|
|
5445
5460
|
|
|
5446
|
-
const defaults$
|
|
5461
|
+
const defaults$e = {
|
|
5447
5462
|
pattern: "kebabcase",
|
|
5448
5463
|
};
|
|
5449
5464
|
class IdPattern extends Rule {
|
|
5450
5465
|
constructor(options) {
|
|
5451
|
-
super({ ...defaults$
|
|
5466
|
+
super({ ...defaults$e, ...options });
|
|
5452
5467
|
this.pattern = parsePattern(this.options.pattern);
|
|
5453
5468
|
}
|
|
5454
5469
|
static schema() {
|
|
@@ -5467,6 +5482,7 @@ class IdPattern extends Rule {
|
|
|
5467
5482
|
}
|
|
5468
5483
|
setup() {
|
|
5469
5484
|
this.on("attr", (event) => {
|
|
5485
|
+
var _a;
|
|
5470
5486
|
if (event.key.toLowerCase() !== "id") {
|
|
5471
5487
|
return;
|
|
5472
5488
|
}
|
|
@@ -5475,7 +5491,10 @@ class IdPattern extends Rule {
|
|
|
5475
5491
|
return;
|
|
5476
5492
|
}
|
|
5477
5493
|
if (!event.value || !event.value.match(this.pattern)) {
|
|
5478
|
-
|
|
5494
|
+
const value = (_a = event.value) !== null && _a !== void 0 ? _a : "";
|
|
5495
|
+
const pattern = this.pattern.toString();
|
|
5496
|
+
const message = `ID "${value}" does not match required pattern "${pattern}"`;
|
|
5497
|
+
this.report(event.target, message, event.valueLocation);
|
|
5479
5498
|
}
|
|
5480
5499
|
});
|
|
5481
5500
|
}
|
|
@@ -5795,12 +5814,12 @@ function findLabelByParent(el) {
|
|
|
5795
5814
|
return [];
|
|
5796
5815
|
}
|
|
5797
5816
|
|
|
5798
|
-
const defaults$
|
|
5817
|
+
const defaults$d = {
|
|
5799
5818
|
maxlength: 70,
|
|
5800
5819
|
};
|
|
5801
5820
|
class LongTitle extends Rule {
|
|
5802
5821
|
constructor(options) {
|
|
5803
|
-
super({ ...defaults$
|
|
5822
|
+
super({ ...defaults$d, ...options });
|
|
5804
5823
|
this.maxlength = this.options.maxlength;
|
|
5805
5824
|
}
|
|
5806
5825
|
static schema() {
|
|
@@ -5947,13 +5966,13 @@ class MultipleLabeledControls extends Rule {
|
|
|
5947
5966
|
}
|
|
5948
5967
|
}
|
|
5949
5968
|
|
|
5950
|
-
const defaults$
|
|
5969
|
+
const defaults$c = {
|
|
5951
5970
|
include: null,
|
|
5952
5971
|
exclude: null,
|
|
5953
5972
|
};
|
|
5954
5973
|
class NoAutoplay extends Rule {
|
|
5955
5974
|
constructor(options) {
|
|
5956
|
-
super({ ...defaults$
|
|
5975
|
+
super({ ...defaults$c, ...options });
|
|
5957
5976
|
}
|
|
5958
5977
|
documentation(context) {
|
|
5959
5978
|
const tagName = context ? ` on <${context.tagName}>` : "";
|
|
@@ -6194,7 +6213,7 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
|
|
|
6194
6213
|
}
|
|
6195
6214
|
}
|
|
6196
6215
|
|
|
6197
|
-
const defaults$
|
|
6216
|
+
const defaults$b = {
|
|
6198
6217
|
include: null,
|
|
6199
6218
|
exclude: null,
|
|
6200
6219
|
allowedProperties: ["display"],
|
|
@@ -6211,7 +6230,7 @@ function getCSSDeclarations(value) {
|
|
|
6211
6230
|
}
|
|
6212
6231
|
class NoInlineStyle extends Rule {
|
|
6213
6232
|
constructor(options) {
|
|
6214
|
-
super({ ...defaults$
|
|
6233
|
+
super({ ...defaults$b, ...options });
|
|
6215
6234
|
}
|
|
6216
6235
|
static schema() {
|
|
6217
6236
|
return {
|
|
@@ -6416,24 +6435,24 @@ class NoMultipleMain extends Rule {
|
|
|
6416
6435
|
}
|
|
6417
6436
|
}
|
|
6418
6437
|
|
|
6419
|
-
const defaults$
|
|
6438
|
+
const defaults$a = {
|
|
6420
6439
|
relaxed: false,
|
|
6421
6440
|
};
|
|
6422
6441
|
const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6423
6442
|
const unquotedAttrRegexp = /([<>"'=`]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6424
6443
|
const matchTemplate = /^(<%.*?%>|<\?.*?\?>|<\$.*?\$>)$/s;
|
|
6425
|
-
const replacementTable =
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6444
|
+
const replacementTable = {
|
|
6445
|
+
'"': """,
|
|
6446
|
+
"&": "&",
|
|
6447
|
+
"'": "'",
|
|
6448
|
+
"<": "<",
|
|
6449
|
+
"=": "=",
|
|
6450
|
+
">": ">",
|
|
6451
|
+
"`": "`",
|
|
6452
|
+
};
|
|
6434
6453
|
class NoRawCharacters extends Rule {
|
|
6435
6454
|
constructor(options) {
|
|
6436
|
-
super({ ...defaults$
|
|
6455
|
+
super({ ...defaults$a, ...options });
|
|
6437
6456
|
this.relaxed = this.options.relaxed;
|
|
6438
6457
|
}
|
|
6439
6458
|
static schema() {
|
|
@@ -6483,7 +6502,6 @@ class NoRawCharacters extends Rule {
|
|
|
6483
6502
|
* @param text - The full text to find unescaped raw characters in.
|
|
6484
6503
|
* @param location - Location of text.
|
|
6485
6504
|
* @param regexp - Regexp pattern to match using.
|
|
6486
|
-
* @param ignore - List of characters to ignore for this text.
|
|
6487
6505
|
*/
|
|
6488
6506
|
findRawChars(node, text, location, regexp) {
|
|
6489
6507
|
let match;
|
|
@@ -6499,7 +6517,7 @@ class NoRawCharacters extends Rule {
|
|
|
6499
6517
|
continue;
|
|
6500
6518
|
}
|
|
6501
6519
|
/* determine replacement character and location */
|
|
6502
|
-
const replacement = replacementTable
|
|
6520
|
+
const replacement = replacementTable[char];
|
|
6503
6521
|
const charLocation = sliceLocation(location, match.index, match.index + 1);
|
|
6504
6522
|
/* report as error */
|
|
6505
6523
|
this.report(node, `Raw "${char}" must be encoded as "${replacement}"`, charLocation);
|
|
@@ -6612,13 +6630,13 @@ class NoRedundantRole extends Rule {
|
|
|
6612
6630
|
}
|
|
6613
6631
|
|
|
6614
6632
|
const xmlns = /^(.+):.+$/;
|
|
6615
|
-
const defaults$
|
|
6633
|
+
const defaults$9 = {
|
|
6616
6634
|
ignoreForeign: true,
|
|
6617
6635
|
ignoreXML: true,
|
|
6618
6636
|
};
|
|
6619
6637
|
class NoSelfClosing extends Rule {
|
|
6620
6638
|
constructor(options) {
|
|
6621
|
-
super({ ...defaults$
|
|
6639
|
+
super({ ...defaults$9, ...options });
|
|
6622
6640
|
}
|
|
6623
6641
|
static schema() {
|
|
6624
6642
|
return {
|
|
@@ -6751,13 +6769,13 @@ const replacement = {
|
|
|
6751
6769
|
reset: '<button type="reset">',
|
|
6752
6770
|
image: '<button type="button">',
|
|
6753
6771
|
};
|
|
6754
|
-
const defaults$
|
|
6772
|
+
const defaults$8 = {
|
|
6755
6773
|
include: null,
|
|
6756
6774
|
exclude: null,
|
|
6757
6775
|
};
|
|
6758
6776
|
class PreferButton extends Rule {
|
|
6759
6777
|
constructor(options) {
|
|
6760
|
-
super({ ...defaults$
|
|
6778
|
+
super({ ...defaults$8, ...options });
|
|
6761
6779
|
}
|
|
6762
6780
|
static schema() {
|
|
6763
6781
|
return {
|
|
@@ -6832,7 +6850,7 @@ class PreferButton extends Rule {
|
|
|
6832
6850
|
}
|
|
6833
6851
|
}
|
|
6834
6852
|
|
|
6835
|
-
const defaults$
|
|
6853
|
+
const defaults$7 = {
|
|
6836
6854
|
mapping: {
|
|
6837
6855
|
article: "article",
|
|
6838
6856
|
banner: "header",
|
|
@@ -6862,7 +6880,7 @@ const defaults$6 = {
|
|
|
6862
6880
|
};
|
|
6863
6881
|
class PreferNativeElement extends Rule {
|
|
6864
6882
|
constructor(options) {
|
|
6865
|
-
super({ ...defaults$
|
|
6883
|
+
super({ ...defaults$7, ...options });
|
|
6866
6884
|
}
|
|
6867
6885
|
static schema() {
|
|
6868
6886
|
return {
|
|
@@ -6982,7 +7000,7 @@ class PreferTbody extends Rule {
|
|
|
6982
7000
|
}
|
|
6983
7001
|
}
|
|
6984
7002
|
|
|
6985
|
-
const defaults$
|
|
7003
|
+
const defaults$6 = {
|
|
6986
7004
|
target: "all",
|
|
6987
7005
|
};
|
|
6988
7006
|
const crossorigin = new RegExp("^(\\w+://|//)"); /* e.g. https:// or // */
|
|
@@ -6992,7 +7010,7 @@ const supportSri = {
|
|
|
6992
7010
|
};
|
|
6993
7011
|
class RequireSri extends Rule {
|
|
6994
7012
|
constructor(options) {
|
|
6995
|
-
super({ ...defaults$
|
|
7013
|
+
super({ ...defaults$6, ...options });
|
|
6996
7014
|
this.target = this.options.target;
|
|
6997
7015
|
}
|
|
6998
7016
|
static schema() {
|
|
@@ -7120,6 +7138,155 @@ class SvgFocusable extends Rule {
|
|
|
7120
7138
|
}
|
|
7121
7139
|
}
|
|
7122
7140
|
|
|
7141
|
+
const defaults$5 = {
|
|
7142
|
+
characters: [
|
|
7143
|
+
{ pattern: " ", replacement: " ", description: "non-breaking space" },
|
|
7144
|
+
{ pattern: "-", replacement: "‑", description: "non-breaking hyphen" },
|
|
7145
|
+
],
|
|
7146
|
+
ignoreClasses: [],
|
|
7147
|
+
};
|
|
7148
|
+
function constructRegex(characters) {
|
|
7149
|
+
const disallowed = characters
|
|
7150
|
+
.map((it) => {
|
|
7151
|
+
return it.pattern;
|
|
7152
|
+
})
|
|
7153
|
+
.join("|");
|
|
7154
|
+
const pattern = `(${disallowed})`;
|
|
7155
|
+
/* eslint-disable-next-line security/detect-non-literal-regexp */
|
|
7156
|
+
return new RegExp(pattern, "g");
|
|
7157
|
+
}
|
|
7158
|
+
function getText(node) {
|
|
7159
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
|
|
7160
|
+
const match = node.textContent.match(/^(\s*)(.*)$/);
|
|
7161
|
+
const [, leading, text] = match;
|
|
7162
|
+
return [leading.length, text.trimEnd()];
|
|
7163
|
+
}
|
|
7164
|
+
/**
|
|
7165
|
+
* Node 12 does not support String.matchAll, this simulates it's behavior.
|
|
7166
|
+
*/
|
|
7167
|
+
function matchAll(text, regexp) {
|
|
7168
|
+
/* eslint-disable-next-line security/detect-non-literal-regexp */
|
|
7169
|
+
const copy = new RegExp(regexp);
|
|
7170
|
+
const matches = [];
|
|
7171
|
+
/* eslint-disable-next-line no-constant-condition */
|
|
7172
|
+
while (true) {
|
|
7173
|
+
const match = copy.exec(text);
|
|
7174
|
+
if (match === null) {
|
|
7175
|
+
break;
|
|
7176
|
+
}
|
|
7177
|
+
matches.push(match);
|
|
7178
|
+
}
|
|
7179
|
+
return matches;
|
|
7180
|
+
}
|
|
7181
|
+
class TelNonBreaking extends Rule {
|
|
7182
|
+
constructor(options) {
|
|
7183
|
+
super({ ...defaults$5, ...options });
|
|
7184
|
+
this.regex = constructRegex(this.options.characters);
|
|
7185
|
+
}
|
|
7186
|
+
static schema() {
|
|
7187
|
+
return {
|
|
7188
|
+
characters: {
|
|
7189
|
+
type: "array",
|
|
7190
|
+
items: {
|
|
7191
|
+
type: "object",
|
|
7192
|
+
additionalProperties: false,
|
|
7193
|
+
properties: {
|
|
7194
|
+
pattern: {
|
|
7195
|
+
type: "string",
|
|
7196
|
+
},
|
|
7197
|
+
replacement: {
|
|
7198
|
+
type: "string",
|
|
7199
|
+
},
|
|
7200
|
+
description: {
|
|
7201
|
+
type: "string",
|
|
7202
|
+
},
|
|
7203
|
+
},
|
|
7204
|
+
},
|
|
7205
|
+
},
|
|
7206
|
+
ignoreClasses: {
|
|
7207
|
+
type: "array",
|
|
7208
|
+
items: {
|
|
7209
|
+
type: "string",
|
|
7210
|
+
},
|
|
7211
|
+
},
|
|
7212
|
+
};
|
|
7213
|
+
}
|
|
7214
|
+
documentation(context) {
|
|
7215
|
+
const { characters } = this.options;
|
|
7216
|
+
const replacements = characters.map((it) => {
|
|
7217
|
+
return ` - \`${it.pattern}\` - replace with \`${it.replacement}\` (${it.description}).`;
|
|
7218
|
+
});
|
|
7219
|
+
return {
|
|
7220
|
+
description: [
|
|
7221
|
+
context
|
|
7222
|
+
? `The \`${context.pattern}\` character should be replaced with \`${context.replacement}\` character (${context.description}) when used in a telephone number.`
|
|
7223
|
+
: `Replace this character with a non-breaking version.`,
|
|
7224
|
+
"",
|
|
7225
|
+
"Unless non-breaking characters is used there could be a line break inserted at that character.",
|
|
7226
|
+
"Line breaks make is harder to read and understand the telephone number.",
|
|
7227
|
+
"",
|
|
7228
|
+
"The following characters should be avoided:",
|
|
7229
|
+
"",
|
|
7230
|
+
...replacements,
|
|
7231
|
+
].join("\n"),
|
|
7232
|
+
url: ruleDocumentationUrl("@/rules/tel-non-breaking.ts"),
|
|
7233
|
+
};
|
|
7234
|
+
}
|
|
7235
|
+
setup() {
|
|
7236
|
+
this.on("element:ready", this.isRelevant, (event) => {
|
|
7237
|
+
const { target } = event;
|
|
7238
|
+
const { ignoreClasses } = this.options;
|
|
7239
|
+
/* skip if element has a class in the ignore list */
|
|
7240
|
+
const isIgnored = ignoreClasses.some((it) => target.classList.contains(it));
|
|
7241
|
+
if (isIgnored) {
|
|
7242
|
+
return;
|
|
7243
|
+
}
|
|
7244
|
+
this.walk(target);
|
|
7245
|
+
});
|
|
7246
|
+
}
|
|
7247
|
+
isRelevant(event) {
|
|
7248
|
+
const { target } = event;
|
|
7249
|
+
/* should only deal with anchors */
|
|
7250
|
+
if (!target.is("a")) {
|
|
7251
|
+
return false;
|
|
7252
|
+
}
|
|
7253
|
+
/* ignore if anchor does not have tel href */
|
|
7254
|
+
const attr = target.getAttribute("href");
|
|
7255
|
+
if (!attr || !attr.valueMatches(/^tel:/, false)) {
|
|
7256
|
+
return false;
|
|
7257
|
+
}
|
|
7258
|
+
return true;
|
|
7259
|
+
}
|
|
7260
|
+
walk(node) {
|
|
7261
|
+
for (const child of node.childNodes) {
|
|
7262
|
+
if (isTextNode(child)) {
|
|
7263
|
+
this.detectDisallowed(child);
|
|
7264
|
+
}
|
|
7265
|
+
else if (isElementNode(child)) {
|
|
7266
|
+
this.walk(child);
|
|
7267
|
+
}
|
|
7268
|
+
}
|
|
7269
|
+
}
|
|
7270
|
+
detectDisallowed(node) {
|
|
7271
|
+
const [offset, text] = getText(node);
|
|
7272
|
+
const matches = matchAll(text, this.regex);
|
|
7273
|
+
for (const match of matches) {
|
|
7274
|
+
const detected = match[0];
|
|
7275
|
+
const entry = this.options.characters.find((it) => it.pattern === detected);
|
|
7276
|
+
/* istanbul ignore next: should never happen and cannot be tested, just a sanity check */
|
|
7277
|
+
if (!entry) {
|
|
7278
|
+
throw new Error(`Failed to find entry for "${detected}" when searching text "${text}"`);
|
|
7279
|
+
}
|
|
7280
|
+
const message = `"${detected}" should be replaced with "${entry.replacement}" in telephone number`;
|
|
7281
|
+
const begin = offset + match.index;
|
|
7282
|
+
const end = begin + detected.length;
|
|
7283
|
+
const location = sliceLocation(node.location, begin, end);
|
|
7284
|
+
const context = entry;
|
|
7285
|
+
this.report(node, message, location, context);
|
|
7286
|
+
}
|
|
7287
|
+
}
|
|
7288
|
+
}
|
|
7289
|
+
|
|
7123
7290
|
function hasAltText(image) {
|
|
7124
7291
|
const alt = image.getAttribute("alt");
|
|
7125
7292
|
/* missing or boolean */
|
|
@@ -9150,9 +9317,6 @@ function parseStyle$1(name) {
|
|
|
9150
9317
|
case "selfclose":
|
|
9151
9318
|
case "selfclosing":
|
|
9152
9319
|
return Style$1.AlwaysSelfclose;
|
|
9153
|
-
/* istanbul ignore next: covered by schema validation */
|
|
9154
|
-
default:
|
|
9155
|
-
throw new Error(`Invalid style "${name}" for "void" rule`);
|
|
9156
9320
|
}
|
|
9157
9321
|
}
|
|
9158
9322
|
|
|
@@ -9584,6 +9748,7 @@ const bundledRules = {
|
|
|
9584
9748
|
"script-element": ScriptElement,
|
|
9585
9749
|
"script-type": ScriptType,
|
|
9586
9750
|
"svg-focusable": SvgFocusable,
|
|
9751
|
+
"tel-non-breaking": TelNonBreaking,
|
|
9587
9752
|
"text-content": TextContent,
|
|
9588
9753
|
"unrecognized-char-ref": UnknownCharReference,
|
|
9589
9754
|
void: Void,
|
|
@@ -9680,6 +9845,7 @@ const config$1 = {
|
|
|
9680
9845
|
"script-element": "error",
|
|
9681
9846
|
"script-type": "error",
|
|
9682
9847
|
"svg-focusable": "off",
|
|
9848
|
+
"tel-non-breaking": "error",
|
|
9683
9849
|
"text-content": "error",
|
|
9684
9850
|
"unrecognized-char-ref": "error",
|
|
9685
9851
|
void: "off",
|
|
@@ -9785,7 +9951,8 @@ class ResolvedConfig {
|
|
|
9785
9951
|
});
|
|
9786
9952
|
}
|
|
9787
9953
|
catch (err) {
|
|
9788
|
-
|
|
9954
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
9955
|
+
throw new NestedError(`When transforming "${source.filename}": ${message}`, err);
|
|
9789
9956
|
}
|
|
9790
9957
|
}
|
|
9791
9958
|
else {
|
|
@@ -9861,9 +10028,10 @@ function loadFromFile(filename) {
|
|
|
9861
10028
|
}
|
|
9862
10029
|
/* expand any relative paths */
|
|
9863
10030
|
for (const key of ["extends", "elements", "plugins"]) {
|
|
9864
|
-
|
|
10031
|
+
const value = json[key];
|
|
10032
|
+
if (!value)
|
|
9865
10033
|
continue;
|
|
9866
|
-
json[key] =
|
|
10034
|
+
json[key] = value.map((ref) => {
|
|
9867
10035
|
return Config.expandRelative(ref, path.dirname(filename));
|
|
9868
10036
|
});
|
|
9869
10037
|
}
|
|
@@ -10021,6 +10189,7 @@ class Config {
|
|
|
10021
10189
|
/**
|
|
10022
10190
|
* Get element metadata.
|
|
10023
10191
|
*/
|
|
10192
|
+
/* eslint-disable-next-line complexity, sonarjs/cognitive-complexity */
|
|
10024
10193
|
getMetaTable() {
|
|
10025
10194
|
/* use cached table if it exists */
|
|
10026
10195
|
if (this.metaTable) {
|
|
@@ -10059,7 +10228,8 @@ class Config {
|
|
|
10059
10228
|
metaTable.loadFromObject(legacyRequire(entry));
|
|
10060
10229
|
}
|
|
10061
10230
|
catch (err) {
|
|
10062
|
-
|
|
10231
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10232
|
+
throw new ConfigError(`Failed to load elements from "${entry}": ${message}`, err);
|
|
10063
10233
|
}
|
|
10064
10234
|
}
|
|
10065
10235
|
metaTable.init();
|
|
@@ -10135,7 +10305,8 @@ class Config {
|
|
|
10135
10305
|
return plugin;
|
|
10136
10306
|
}
|
|
10137
10307
|
catch (err) {
|
|
10138
|
-
|
|
10308
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10309
|
+
throw new ConfigError(`Failed to load plugin "${moduleName}": ${message}`, err);
|
|
10139
10310
|
}
|
|
10140
10311
|
});
|
|
10141
10312
|
}
|
|
@@ -11139,7 +11310,7 @@ class Engine {
|
|
|
11139
11310
|
/**
|
|
11140
11311
|
* Lint sources and return report
|
|
11141
11312
|
*
|
|
11142
|
-
* @param
|
|
11313
|
+
* @param sources - Sources to lint.
|
|
11143
11314
|
* @returns Report output.
|
|
11144
11315
|
*/
|
|
11145
11316
|
lint(sources) {
|
|
@@ -11233,7 +11404,7 @@ class Engine {
|
|
|
11233
11404
|
const lines = [];
|
|
11234
11405
|
function decoration(node) {
|
|
11235
11406
|
let output = "";
|
|
11236
|
-
if (node.
|
|
11407
|
+
if (node.id) {
|
|
11237
11408
|
output += `#${node.id}`;
|
|
11238
11409
|
}
|
|
11239
11410
|
if (node.hasAttribute("class")) {
|