html-validate 5.3.0 → 6.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/CHANGELOG.md +71 -0
- package/dist/cjs/browser.js +2 -6
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/cli.js +53 -28
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core.d.ts +21 -7
- package/dist/cjs/core.js +618 -351
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/html-validate.js +9 -9
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/index.d.ts +15 -2
- package/dist/cjs/index.js +2 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/{matchers.d.ts → jest-lib.d.ts} +2 -4
- package/dist/cjs/{matchers.js → jest-lib.js} +125 -87
- package/dist/cjs/jest-lib.js.map +1 -0
- package/dist/cjs/jest.d.ts +4 -0
- package/dist/cjs/jest.js +17 -0
- package/dist/cjs/jest.js.map +1 -0
- package/dist/cjs/test-utils.js +1 -1
- package/dist/es/cli.js +34 -9
- package/dist/es/cli.js.map +1 -1
- package/dist/es/core.d.ts +21 -7
- package/dist/es/core.js +582 -315
- package/dist/es/core.js.map +1 -1
- package/dist/es/html-validate.js +1 -1
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/index.d.ts +15 -2
- package/dist/es/{matchers.d.ts → jest-lib.d.ts} +2 -4
- package/dist/es/{matchers.js → jest-lib.js} +120 -82
- package/dist/es/jest-lib.js.map +1 -0
- package/dist/es/jest.d.ts +4 -0
- package/dist/es/jest.js +16 -0
- package/dist/es/jest.js.map +1 -0
- package/dist/schema/elements.json +43 -5
- package/elements/html5.json +940 -290
- package/jest.d.ts +1 -1
- package/jest.js +1 -1
- package/package.json +30 -28
- package/dist/cjs/matchers.js.map +0 -1
- package/dist/es/matchers.js.map +0 -1
package/dist/es/core.js
CHANGED
|
@@ -574,18 +574,63 @@ const definitions = {
|
|
|
574
574
|
type: "object",
|
|
575
575
|
patternProperties: {
|
|
576
576
|
"^.*$": {
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
{
|
|
577
|
+
anyOf: [
|
|
578
|
+
{
|
|
579
|
+
type: "object",
|
|
580
|
+
additionalProperties: false,
|
|
581
|
+
properties: {
|
|
582
|
+
boolean: {
|
|
583
|
+
type: "boolean",
|
|
584
|
+
title: "Set to true if this is a boolean attribute"
|
|
585
|
+
},
|
|
586
|
+
deprecated: {
|
|
587
|
+
title: "Set to true or string if this attribute is deprecated",
|
|
588
|
+
oneOf: [
|
|
589
|
+
{
|
|
590
|
+
type: "boolean"
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
type: "string"
|
|
594
|
+
}
|
|
595
|
+
]
|
|
596
|
+
},
|
|
597
|
+
list: {
|
|
598
|
+
type: "boolean",
|
|
599
|
+
title: "Set to true if this attribute is a list of space-separated tokens, each which must be valid by itself"
|
|
600
|
+
},
|
|
601
|
+
"enum": {
|
|
602
|
+
type: "array",
|
|
603
|
+
title: "Exhaustive list of values (string or regex) this attribute accepts",
|
|
604
|
+
uniqueItems: true,
|
|
605
|
+
items: {
|
|
606
|
+
anyOf: [
|
|
607
|
+
{
|
|
608
|
+
type: "string"
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
regexp: true
|
|
612
|
+
}
|
|
613
|
+
]
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
omit: {
|
|
617
|
+
type: "boolean",
|
|
618
|
+
title: "Set to true if this attribute can optionally omit its value"
|
|
619
|
+
},
|
|
620
|
+
required: {
|
|
621
|
+
type: "boolean",
|
|
622
|
+
title: "Set to true if this attribute is required"
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
type: "array",
|
|
628
|
+
uniqueItems: true,
|
|
629
|
+
items: {
|
|
582
630
|
type: "string"
|
|
583
|
-
},
|
|
584
|
-
{
|
|
585
|
-
regexp: true
|
|
586
631
|
}
|
|
587
|
-
|
|
588
|
-
|
|
632
|
+
}
|
|
633
|
+
]
|
|
589
634
|
}
|
|
590
635
|
}
|
|
591
636
|
},
|
|
@@ -636,6 +681,111 @@ var schema = {
|
|
|
636
681
|
definitions: definitions
|
|
637
682
|
};
|
|
638
683
|
|
|
684
|
+
var TextContent$1;
|
|
685
|
+
(function (TextContent) {
|
|
686
|
+
/* forbid node to have text content, inter-element whitespace is ignored */
|
|
687
|
+
TextContent["NONE"] = "none";
|
|
688
|
+
/* node can have text but not required too */
|
|
689
|
+
TextContent["DEFAULT"] = "default";
|
|
690
|
+
/* node requires text-nodes to be present (direct or by descendant) */
|
|
691
|
+
TextContent["REQUIRED"] = "required";
|
|
692
|
+
/* node requires accessible text (hidden text is ignored, tries to get text from accessibility tree) */
|
|
693
|
+
TextContent["ACCESSIBLE"] = "accessible";
|
|
694
|
+
})(TextContent$1 || (TextContent$1 = {}));
|
|
695
|
+
/**
|
|
696
|
+
* Properties listed here can be copied (loaded) onto another element using
|
|
697
|
+
* [[HtmlElement.loadMeta]].
|
|
698
|
+
*/
|
|
699
|
+
const MetaCopyableProperty = [
|
|
700
|
+
"metadata",
|
|
701
|
+
"flow",
|
|
702
|
+
"sectioning",
|
|
703
|
+
"heading",
|
|
704
|
+
"phrasing",
|
|
705
|
+
"embedded",
|
|
706
|
+
"interactive",
|
|
707
|
+
"transparent",
|
|
708
|
+
"form",
|
|
709
|
+
"labelable",
|
|
710
|
+
"attributes",
|
|
711
|
+
"permittedContent",
|
|
712
|
+
"permittedDescendants",
|
|
713
|
+
"permittedOrder",
|
|
714
|
+
"requiredAncestors",
|
|
715
|
+
"requiredContent",
|
|
716
|
+
];
|
|
717
|
+
/**
|
|
718
|
+
* @internal
|
|
719
|
+
*/
|
|
720
|
+
function setMetaProperty(dst, key, value) {
|
|
721
|
+
dst[key] = value;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function isSet(value) {
|
|
725
|
+
return typeof value !== "undefined";
|
|
726
|
+
}
|
|
727
|
+
function flag(value) {
|
|
728
|
+
return value ? true : undefined;
|
|
729
|
+
}
|
|
730
|
+
function stripUndefined(src) {
|
|
731
|
+
const entries = Object.entries(src).filter(([, value]) => isSet(value));
|
|
732
|
+
return Object.fromEntries(entries);
|
|
733
|
+
}
|
|
734
|
+
function migrateSingleAttribute(src, key) {
|
|
735
|
+
var _a, _b;
|
|
736
|
+
const result = {};
|
|
737
|
+
result.deprecated = flag((_a = src.deprecatedAttributes) === null || _a === void 0 ? void 0 : _a.includes(key));
|
|
738
|
+
result.required = flag((_b = src.requiredAttributes) === null || _b === void 0 ? void 0 : _b.includes(key));
|
|
739
|
+
result.omit = undefined;
|
|
740
|
+
const attr = src.attributes ? src.attributes[key] : undefined;
|
|
741
|
+
if (typeof attr === "undefined") {
|
|
742
|
+
return stripUndefined(result);
|
|
743
|
+
}
|
|
744
|
+
/* when the attribute is set to null we use a special property "delete" to
|
|
745
|
+
* flag it, if it is still set during merge (inheritance, overwriting, etc) the attribute will be removed */
|
|
746
|
+
if (attr === null) {
|
|
747
|
+
result.delete = true;
|
|
748
|
+
return stripUndefined(result);
|
|
749
|
+
}
|
|
750
|
+
if (Array.isArray(attr)) {
|
|
751
|
+
if (attr.length === 0) {
|
|
752
|
+
result.boolean = true;
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
result.enum = attr.filter((it) => it !== "");
|
|
756
|
+
if (attr.includes("")) {
|
|
757
|
+
result.omit = true;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return stripUndefined(result);
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
return stripUndefined({ ...result, ...attr });
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function migrateAttributes(src) {
|
|
767
|
+
var _a, _b, _c;
|
|
768
|
+
const keys = [
|
|
769
|
+
...Object.keys((_a = src.attributes) !== null && _a !== void 0 ? _a : {}),
|
|
770
|
+
...((_b = src.requiredAttributes) !== null && _b !== void 0 ? _b : []),
|
|
771
|
+
...((_c = src.deprecatedAttributes) !== null && _c !== void 0 ? _c : []),
|
|
772
|
+
].sort();
|
|
773
|
+
const entries = keys.map((key) => {
|
|
774
|
+
return [key, migrateSingleAttribute(src, key)];
|
|
775
|
+
});
|
|
776
|
+
return Object.fromEntries(entries);
|
|
777
|
+
}
|
|
778
|
+
function migrateElement(src) {
|
|
779
|
+
const result = {
|
|
780
|
+
...src,
|
|
781
|
+
attributes: migrateAttributes(src),
|
|
782
|
+
};
|
|
783
|
+
/* removed properties */
|
|
784
|
+
delete result.deprecatedAttributes;
|
|
785
|
+
delete result.requiredAttributes;
|
|
786
|
+
return result;
|
|
787
|
+
}
|
|
788
|
+
|
|
639
789
|
const dynamicKeys = [
|
|
640
790
|
"metadata",
|
|
641
791
|
"flow",
|
|
@@ -729,7 +879,7 @@ class MetaTable {
|
|
|
729
879
|
for (const [key, value] of Object.entries(obj)) {
|
|
730
880
|
if (key === "$schema")
|
|
731
881
|
continue;
|
|
732
|
-
this.addEntry(key, value);
|
|
882
|
+
this.addEntry(key, migrateElement(value));
|
|
733
883
|
}
|
|
734
884
|
}
|
|
735
885
|
/**
|
|
@@ -757,7 +907,7 @@ class MetaTable {
|
|
|
757
907
|
*/
|
|
758
908
|
getMetaFor(tagName) {
|
|
759
909
|
tagName = tagName.toLowerCase();
|
|
760
|
-
return this.elements[tagName] ?
|
|
910
|
+
return this.elements[tagName] ? { ...this.elements[tagName] } : null;
|
|
761
911
|
}
|
|
762
912
|
/**
|
|
763
913
|
* Find all tags which has enabled given property.
|
|
@@ -786,7 +936,7 @@ class MetaTable {
|
|
|
786
936
|
}
|
|
787
937
|
}
|
|
788
938
|
/* merge all sources together */
|
|
789
|
-
const expanded =
|
|
939
|
+
const expanded = this.mergeElement(parent, { ...entry, tagName });
|
|
790
940
|
expandRegex(expanded);
|
|
791
941
|
this.elements[tagName] = expanded;
|
|
792
942
|
}
|
|
@@ -820,11 +970,20 @@ class MetaTable {
|
|
|
820
970
|
delete global.void;
|
|
821
971
|
/* merge elements */
|
|
822
972
|
for (const [tagName, entry] of Object.entries(this.elements)) {
|
|
823
|
-
this.elements[tagName] = this.mergeElement(
|
|
973
|
+
this.elements[tagName] = this.mergeElement(global, entry);
|
|
824
974
|
}
|
|
825
975
|
}
|
|
826
976
|
mergeElement(a, b) {
|
|
827
|
-
|
|
977
|
+
const merged = deepmerge(a, b, { arrayMerge: overwriteMerge$1 });
|
|
978
|
+
/* special handling when removing attributes by setting them to null
|
|
979
|
+
* resulting in the deletion flag being set */
|
|
980
|
+
const filteredAttrs = Object.entries(merged.attributes).filter(([, attr]) => {
|
|
981
|
+
const val = !attr.delete;
|
|
982
|
+
delete attr.delete;
|
|
983
|
+
return val;
|
|
984
|
+
});
|
|
985
|
+
merged.attributes = Object.fromEntries(filteredAttrs);
|
|
986
|
+
return merged;
|
|
828
987
|
}
|
|
829
988
|
resolve(node) {
|
|
830
989
|
if (node.meta) {
|
|
@@ -836,7 +995,7 @@ function expandProperties(node, entry) {
|
|
|
836
995
|
for (const key of dynamicKeys) {
|
|
837
996
|
const property = entry[key];
|
|
838
997
|
if (property && typeof property !== "boolean") {
|
|
839
|
-
entry
|
|
998
|
+
setMetaProperty(entry, key, evaluateProperty(node, property));
|
|
840
999
|
}
|
|
841
1000
|
}
|
|
842
1001
|
}
|
|
@@ -862,14 +1021,9 @@ function expandRegexValue(value) {
|
|
|
862
1021
|
* Expand all regular expressions in strings ("/../"). This mutates the object.
|
|
863
1022
|
*/
|
|
864
1023
|
function expandRegex(entry) {
|
|
865
|
-
if (!entry.attributes)
|
|
866
|
-
return;
|
|
867
1024
|
for (const [name, values] of Object.entries(entry.attributes)) {
|
|
868
|
-
if (values) {
|
|
869
|
-
entry.attributes[name] = values.map(expandRegexValue);
|
|
870
|
-
}
|
|
871
|
-
else {
|
|
872
|
-
delete entry.attributes[name];
|
|
1025
|
+
if (values.enum) {
|
|
1026
|
+
entry.attributes[name].enum = values.enum.map(expandRegexValue);
|
|
873
1027
|
}
|
|
874
1028
|
}
|
|
875
1029
|
}
|
|
@@ -925,41 +1079,6 @@ function matchAttribute(node, match) {
|
|
|
925
1079
|
}
|
|
926
1080
|
}
|
|
927
1081
|
|
|
928
|
-
var TextContent$1;
|
|
929
|
-
(function (TextContent) {
|
|
930
|
-
/* forbid node to have text content, inter-element whitespace is ignored */
|
|
931
|
-
TextContent["NONE"] = "none";
|
|
932
|
-
/* node can have text but not required too */
|
|
933
|
-
TextContent["DEFAULT"] = "default";
|
|
934
|
-
/* node requires text-nodes to be present (direct or by descendant) */
|
|
935
|
-
TextContent["REQUIRED"] = "required";
|
|
936
|
-
/* node requires accessible text (hidden text is ignored, tries to get text from accessibility tree) */
|
|
937
|
-
TextContent["ACCESSIBLE"] = "accessible";
|
|
938
|
-
})(TextContent$1 || (TextContent$1 = {}));
|
|
939
|
-
/**
|
|
940
|
-
* Properties listed here can be copied (loaded) onto another element using
|
|
941
|
-
* [[HtmlElement.loadMeta]].
|
|
942
|
-
*/
|
|
943
|
-
const MetaCopyableProperty = [
|
|
944
|
-
"metadata",
|
|
945
|
-
"flow",
|
|
946
|
-
"sectioning",
|
|
947
|
-
"heading",
|
|
948
|
-
"phrasing",
|
|
949
|
-
"embedded",
|
|
950
|
-
"interactive",
|
|
951
|
-
"transparent",
|
|
952
|
-
"form",
|
|
953
|
-
"labelable",
|
|
954
|
-
"requiredAttributes",
|
|
955
|
-
"attributes",
|
|
956
|
-
"permittedContent",
|
|
957
|
-
"permittedDescendants",
|
|
958
|
-
"permittedOrder",
|
|
959
|
-
"requiredAncestors",
|
|
960
|
-
"requiredContent",
|
|
961
|
-
];
|
|
962
|
-
|
|
963
1082
|
class DynamicValue {
|
|
964
1083
|
constructor(expr) {
|
|
965
1084
|
this.expr = expr;
|
|
@@ -1330,6 +1449,15 @@ class DOMTokenList extends Array {
|
|
|
1330
1449
|
contains(token) {
|
|
1331
1450
|
return this.includes(token);
|
|
1332
1451
|
}
|
|
1452
|
+
*iterator() {
|
|
1453
|
+
for (let index = 0; index < this.length; index++) {
|
|
1454
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
1455
|
+
const item = this.item(index);
|
|
1456
|
+
const location = this.location(index);
|
|
1457
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
1458
|
+
yield { index, item, location };
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1333
1461
|
}
|
|
1334
1462
|
|
|
1335
1463
|
var Combinator;
|
|
@@ -1802,8 +1930,9 @@ class HtmlElement extends DOMNode {
|
|
|
1802
1930
|
this.metaElement = {};
|
|
1803
1931
|
}
|
|
1804
1932
|
for (const key of MetaCopyableProperty) {
|
|
1805
|
-
|
|
1806
|
-
|
|
1933
|
+
const value = meta[key];
|
|
1934
|
+
if (typeof value !== "undefined") {
|
|
1935
|
+
setMetaProperty(this.metaElement, key, value);
|
|
1807
1936
|
}
|
|
1808
1937
|
else {
|
|
1809
1938
|
delete this.metaElement[key];
|
|
@@ -2219,6 +2348,7 @@ class Validator {
|
|
|
2219
2348
|
* @param rules - Element attribute metadta.
|
|
2220
2349
|
* @returns `true` if attribute passes all tests.
|
|
2221
2350
|
*/
|
|
2351
|
+
/* eslint-disable-next-line complexity */
|
|
2222
2352
|
static validateAttribute(attr, rules) {
|
|
2223
2353
|
const rule = rules[attr.key];
|
|
2224
2354
|
if (!rule) {
|
|
@@ -2232,19 +2362,34 @@ class Validator {
|
|
|
2232
2362
|
return true;
|
|
2233
2363
|
}
|
|
2234
2364
|
const empty = value === null || value === "";
|
|
2235
|
-
/*
|
|
2236
|
-
|
|
2365
|
+
/* if boolean is set the value can be either null, empty string or the
|
|
2366
|
+
* attribute key (attribute-boolean-style regulates style) */
|
|
2367
|
+
if (rule.boolean) {
|
|
2237
2368
|
return empty || value === attr.key;
|
|
2238
2369
|
}
|
|
2239
|
-
/* if the
|
|
2240
|
-
* (
|
|
2241
|
-
if (rule.
|
|
2370
|
+
/* if omit is set the value can be either null or empty string
|
|
2371
|
+
* (attribute-empty style regulates style) */
|
|
2372
|
+
if (rule.omit && empty) {
|
|
2373
|
+
return true;
|
|
2374
|
+
}
|
|
2375
|
+
/* validate each token when using list, all tokens must be valid */
|
|
2376
|
+
if (rule.list) {
|
|
2377
|
+
const tokens = new DOMTokenList(value, attr.valueLocation);
|
|
2378
|
+
return tokens.every((token) => {
|
|
2379
|
+
return this.validateAttributeValue(token, rule);
|
|
2380
|
+
});
|
|
2381
|
+
}
|
|
2382
|
+
return this.validateAttributeValue(value, rule);
|
|
2383
|
+
}
|
|
2384
|
+
static validateAttributeValue(value, rule) {
|
|
2385
|
+
/* skip attribute if it not have enumerated list */
|
|
2386
|
+
if (!rule.enum) {
|
|
2242
2387
|
return true;
|
|
2243
2388
|
}
|
|
2244
2389
|
if (value === null || value === undefined) {
|
|
2245
2390
|
return false;
|
|
2246
2391
|
}
|
|
2247
|
-
return rule.some((entry) => {
|
|
2392
|
+
return rule.enum.some((entry) => {
|
|
2248
2393
|
if (entry instanceof RegExp) {
|
|
2249
2394
|
return !!value.match(entry);
|
|
2250
2395
|
}
|
|
@@ -2510,12 +2655,12 @@ var configurationSchema = {
|
|
|
2510
2655
|
const espree = legacyRequire("espree");
|
|
2511
2656
|
const walk = legacyRequire("acorn-walk");
|
|
2512
2657
|
function joinTemplateLiteral(nodes) {
|
|
2513
|
-
let offset = nodes[0].start;
|
|
2658
|
+
let offset = nodes[0].start + 1;
|
|
2514
2659
|
let output = "";
|
|
2515
2660
|
for (const node of nodes) {
|
|
2516
|
-
output += " ".repeat(node.start - offset);
|
|
2661
|
+
output += " ".repeat(node.start + 1 - offset);
|
|
2517
2662
|
output += node.value.raw;
|
|
2518
|
-
offset = node.end;
|
|
2663
|
+
offset = node.end - 2;
|
|
2519
2664
|
}
|
|
2520
2665
|
return output;
|
|
2521
2666
|
}
|
|
@@ -2707,7 +2852,7 @@ var TRANSFORMER_API;
|
|
|
2707
2852
|
})(TRANSFORMER_API || (TRANSFORMER_API = {}));
|
|
2708
2853
|
|
|
2709
2854
|
const name = "html-validate";
|
|
2710
|
-
const version = "
|
|
2855
|
+
const version = "6.0.0";
|
|
2711
2856
|
const homepage = "https://html-validate.org";
|
|
2712
2857
|
const bugs = {
|
|
2713
2858
|
url: "https://gitlab.com/html-validate/html-validate/issues/new"
|
|
@@ -2999,7 +3144,7 @@ const description = {
|
|
|
2999
3144
|
};
|
|
3000
3145
|
class AllowedLinks extends Rule {
|
|
3001
3146
|
constructor(options) {
|
|
3002
|
-
super(
|
|
3147
|
+
super({ ...defaults$p, ...options });
|
|
3003
3148
|
}
|
|
3004
3149
|
static schema() {
|
|
3005
3150
|
return {
|
|
@@ -3247,7 +3392,7 @@ const defaults$o = {
|
|
|
3247
3392
|
};
|
|
3248
3393
|
class AttrCase extends Rule {
|
|
3249
3394
|
constructor(options) {
|
|
3250
|
-
super(
|
|
3395
|
+
super({ ...defaults$o, ...options });
|
|
3251
3396
|
this.style = new CaseStyle(this.options.style, "attr-case");
|
|
3252
3397
|
}
|
|
3253
3398
|
static schema() {
|
|
@@ -3600,7 +3745,7 @@ function generateDescription(name, pattern) {
|
|
|
3600
3745
|
}
|
|
3601
3746
|
class AttrPattern extends Rule {
|
|
3602
3747
|
constructor(options) {
|
|
3603
|
-
super(
|
|
3748
|
+
super({ ...defaults$n, ...options });
|
|
3604
3749
|
this.pattern = generateRegexp(this.options.pattern);
|
|
3605
3750
|
}
|
|
3606
3751
|
static schema() {
|
|
@@ -3666,7 +3811,7 @@ const defaults$m = {
|
|
|
3666
3811
|
};
|
|
3667
3812
|
class AttrQuotes extends Rule {
|
|
3668
3813
|
constructor(options) {
|
|
3669
|
-
super(
|
|
3814
|
+
super({ ...defaults$m, ...options });
|
|
3670
3815
|
this.style = parseStyle$4(this.options.style);
|
|
3671
3816
|
}
|
|
3672
3817
|
static schema() {
|
|
@@ -3762,11 +3907,11 @@ class AttributeAllowedValues extends Rule {
|
|
|
3762
3907
|
if (!context) {
|
|
3763
3908
|
return docs;
|
|
3764
3909
|
}
|
|
3765
|
-
if (context.allowed.
|
|
3766
|
-
const allowed = context.allowed.map((val) => `- \`${val}\``);
|
|
3910
|
+
if (context.allowed.enum) {
|
|
3911
|
+
const allowed = context.allowed.enum.map((val) => `- \`${val}\``);
|
|
3767
3912
|
docs.description = `Element <${context.element}> does not allow attribute \`${context.attribute}\` to have the value \`"${context.value}"\`, it must match one of the following:\n\n${allowed.join("\n")}`;
|
|
3768
3913
|
}
|
|
3769
|
-
else {
|
|
3914
|
+
else if (context.allowed.boolean) {
|
|
3770
3915
|
docs.description = `Element <${context.element}> attribute \`${context.attribute}\` must be a boolean attribute, e.g. \`<${context.element} ${context.attribute}>\``;
|
|
3771
3916
|
}
|
|
3772
3917
|
return docs;
|
|
@@ -3822,7 +3967,7 @@ const defaults$l = {
|
|
|
3822
3967
|
};
|
|
3823
3968
|
class AttributeBooleanStyle extends Rule {
|
|
3824
3969
|
constructor(options) {
|
|
3825
|
-
super(
|
|
3970
|
+
super({ ...defaults$l, ...options });
|
|
3826
3971
|
this.hasInvalidStyle = parseStyle$3(this.options.style);
|
|
3827
3972
|
}
|
|
3828
3973
|
static schema() {
|
|
@@ -3867,7 +4012,8 @@ class AttributeBooleanStyle extends Rule {
|
|
|
3867
4012
|
});
|
|
3868
4013
|
}
|
|
3869
4014
|
isBoolean(attr, rules) {
|
|
3870
|
-
|
|
4015
|
+
var _a;
|
|
4016
|
+
return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.boolean);
|
|
3871
4017
|
}
|
|
3872
4018
|
}
|
|
3873
4019
|
function parseStyle$3(style) {
|
|
@@ -3902,7 +4048,7 @@ const defaults$k = {
|
|
|
3902
4048
|
};
|
|
3903
4049
|
class AttributeEmptyStyle extends Rule {
|
|
3904
4050
|
constructor(options) {
|
|
3905
|
-
super(
|
|
4051
|
+
super({ ...defaults$k, ...options });
|
|
3906
4052
|
this.hasInvalidStyle = parseStyle$2(this.options.style);
|
|
3907
4053
|
}
|
|
3908
4054
|
static schema() {
|
|
@@ -3951,7 +4097,8 @@ class AttributeEmptyStyle extends Rule {
|
|
|
3951
4097
|
}
|
|
3952
4098
|
}
|
|
3953
4099
|
function allowsEmpty(attr, rules) {
|
|
3954
|
-
|
|
4100
|
+
var _a;
|
|
4101
|
+
return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.omit);
|
|
3955
4102
|
}
|
|
3956
4103
|
function isEmptyValue(attr) {
|
|
3957
4104
|
/* dynamic values are ignored, assumed to contain a value */
|
|
@@ -4014,7 +4161,7 @@ const defaults$j = {
|
|
|
4014
4161
|
};
|
|
4015
4162
|
class ClassPattern extends Rule {
|
|
4016
4163
|
constructor(options) {
|
|
4017
|
-
super(
|
|
4164
|
+
super({ ...defaults$j, ...options });
|
|
4018
4165
|
this.pattern = parsePattern(this.options.pattern);
|
|
4019
4166
|
}
|
|
4020
4167
|
static schema() {
|
|
@@ -4127,7 +4274,7 @@ const defaults$i = {
|
|
|
4127
4274
|
};
|
|
4128
4275
|
class Deprecated extends Rule {
|
|
4129
4276
|
constructor(options) {
|
|
4130
|
-
super(
|
|
4277
|
+
super({ ...defaults$i, ...options });
|
|
4131
4278
|
}
|
|
4132
4279
|
static schema() {
|
|
4133
4280
|
return {
|
|
@@ -4221,7 +4368,7 @@ class Deprecated extends Rule {
|
|
|
4221
4368
|
this.report(node, message, location, context);
|
|
4222
4369
|
}
|
|
4223
4370
|
reportObject(deprecated, node, location) {
|
|
4224
|
-
const context =
|
|
4371
|
+
const context = { ...deprecated, tagName: node.tagName };
|
|
4225
4372
|
const notice = deprecated.message ? `: ${deprecated.message}` : "";
|
|
4226
4373
|
const message = `<${node.tagName}> is deprecated${notice}`;
|
|
4227
4374
|
this.report(node, message, location, context);
|
|
@@ -4295,7 +4442,7 @@ const defaults$h = {
|
|
|
4295
4442
|
};
|
|
4296
4443
|
class DoctypeStyle extends Rule {
|
|
4297
4444
|
constructor(options) {
|
|
4298
|
-
super(
|
|
4445
|
+
super({ ...defaults$h, ...options });
|
|
4299
4446
|
}
|
|
4300
4447
|
static schema() {
|
|
4301
4448
|
return {
|
|
@@ -4332,7 +4479,7 @@ const defaults$g = {
|
|
|
4332
4479
|
};
|
|
4333
4480
|
class ElementCase extends Rule {
|
|
4334
4481
|
constructor(options) {
|
|
4335
|
-
super(
|
|
4482
|
+
super({ ...defaults$g, ...options });
|
|
4336
4483
|
this.style = new CaseStyle(this.options.style, "element-case");
|
|
4337
4484
|
}
|
|
4338
4485
|
static schema() {
|
|
@@ -4402,7 +4549,7 @@ const defaults$f = {
|
|
|
4402
4549
|
};
|
|
4403
4550
|
class ElementName extends Rule {
|
|
4404
4551
|
constructor(options) {
|
|
4405
|
-
super(
|
|
4552
|
+
super({ ...defaults$f, ...options });
|
|
4406
4553
|
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
4407
4554
|
this.pattern = new RegExp(this.options.pattern);
|
|
4408
4555
|
}
|
|
@@ -4674,9 +4821,14 @@ class ElementRequiredAttributes extends Rule {
|
|
|
4674
4821
|
this.on("tag:end", (event) => {
|
|
4675
4822
|
const node = event.previous;
|
|
4676
4823
|
const meta = node.meta;
|
|
4677
|
-
|
|
4824
|
+
/* handle missing metadata and missing attributes */
|
|
4825
|
+
if (!meta || !meta.attributes) {
|
|
4678
4826
|
return;
|
|
4679
|
-
|
|
4827
|
+
}
|
|
4828
|
+
for (const [key, attr] of Object.entries(meta.attributes)) {
|
|
4829
|
+
if (!attr.required) {
|
|
4830
|
+
continue;
|
|
4831
|
+
}
|
|
4680
4832
|
if (node.hasAttribute(key))
|
|
4681
4833
|
continue;
|
|
4682
4834
|
const context = {
|
|
@@ -4830,6 +4982,7 @@ class EmptyTitle extends Rule {
|
|
|
4830
4982
|
|
|
4831
4983
|
const defaults$e = {
|
|
4832
4984
|
allowMultipleH1: false,
|
|
4985
|
+
minInitialRank: "h1",
|
|
4833
4986
|
sectioningRoots: ["dialog", '[role="dialog"]'],
|
|
4834
4987
|
};
|
|
4835
4988
|
function isRelevant$2(event) {
|
|
@@ -4845,10 +4998,22 @@ function extractLevel(node) {
|
|
|
4845
4998
|
return null;
|
|
4846
4999
|
}
|
|
4847
5000
|
}
|
|
5001
|
+
function parseMaxInitial(value) {
|
|
5002
|
+
if (value === false || value === "any") {
|
|
5003
|
+
return 6;
|
|
5004
|
+
}
|
|
5005
|
+
const match = value.match(/^h(\d)$/);
|
|
5006
|
+
/* istanbul ignore next: should never happen, schema validation should catch invalid values */
|
|
5007
|
+
if (!match) {
|
|
5008
|
+
return 1;
|
|
5009
|
+
}
|
|
5010
|
+
return parseInt(match[1], 10);
|
|
5011
|
+
}
|
|
4848
5012
|
class HeadingLevel extends Rule {
|
|
4849
5013
|
constructor(options) {
|
|
4850
|
-
super(
|
|
5014
|
+
super({ ...defaults$e, ...options });
|
|
4851
5015
|
this.stack = [];
|
|
5016
|
+
this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
|
|
4852
5017
|
this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
|
|
4853
5018
|
/* add a global sectioning root used by default */
|
|
4854
5019
|
this.stack.push({
|
|
@@ -4862,6 +5027,9 @@ class HeadingLevel extends Rule {
|
|
|
4862
5027
|
allowMultipleH1: {
|
|
4863
5028
|
type: "boolean",
|
|
4864
5029
|
},
|
|
5030
|
+
minInitialRank: {
|
|
5031
|
+
enum: ["h1", "h2", "h3", "h4", "h5", "h6", "any", false],
|
|
5032
|
+
},
|
|
4865
5033
|
sectioningRoots: {
|
|
4866
5034
|
items: {
|
|
4867
5035
|
type: "string",
|
|
@@ -4872,7 +5040,8 @@ class HeadingLevel extends Rule {
|
|
|
4872
5040
|
}
|
|
4873
5041
|
documentation() {
|
|
4874
5042
|
const text = [];
|
|
4875
|
-
|
|
5043
|
+
const modality = this.minInitialRank > 1 ? "should" : "must";
|
|
5044
|
+
text.push(`Headings ${modality} start at <h1> and can only increase one level at a time.`);
|
|
4876
5045
|
text.push("The headings should form a table of contents and make sense on its own.");
|
|
4877
5046
|
if (!this.options.allowMultipleH1) {
|
|
4878
5047
|
text.push("");
|
|
@@ -4917,20 +5086,32 @@ class HeadingLevel extends Rule {
|
|
|
4917
5086
|
*/
|
|
4918
5087
|
checkLevelIncrementation(root, event, level) {
|
|
4919
5088
|
const expected = root.current + 1;
|
|
4920
|
-
if
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
5089
|
+
/* check if the new level is the expected one (headings with higher ranks
|
|
5090
|
+
* are skipped already) */
|
|
5091
|
+
if (level === expected) {
|
|
5092
|
+
return;
|
|
5093
|
+
}
|
|
5094
|
+
/* if this is the initial heading of the document it is compared to the
|
|
5095
|
+
* minimal allowed (default h1) */
|
|
5096
|
+
const isInitial = this.stack.length === 1 && expected === 1;
|
|
5097
|
+
if (isInitial && level <= this.minInitialRank) {
|
|
5098
|
+
return;
|
|
5099
|
+
}
|
|
5100
|
+
/* if we reach this far the heading level is not accepted */
|
|
5101
|
+
const location = sliceLocation(event.location, 1);
|
|
5102
|
+
if (root.current > 0) {
|
|
5103
|
+
const msg = `Heading level can only increase by one, expected <h${expected}> but got <h${level}>`;
|
|
5104
|
+
this.report(event.target, msg, location);
|
|
5105
|
+
}
|
|
5106
|
+
else {
|
|
5107
|
+
this.checkInitialLevel(event, location, level, expected);
|
|
4929
5108
|
}
|
|
4930
5109
|
}
|
|
4931
5110
|
checkInitialLevel(event, location, level, expected) {
|
|
4932
5111
|
if (this.stack.length === 1) {
|
|
4933
|
-
const msg =
|
|
5112
|
+
const msg = this.minInitialRank > 1
|
|
5113
|
+
? `Initial heading level must be <h${this.minInitialRank}> or higher rank but got <h${level}>`
|
|
5114
|
+
: `Initial heading level must be <h${expected}> but got <h${level}>`;
|
|
4934
5115
|
this.report(event.target, msg, location);
|
|
4935
5116
|
}
|
|
4936
5117
|
else {
|
|
@@ -4993,7 +5174,7 @@ const defaults$d = {
|
|
|
4993
5174
|
};
|
|
4994
5175
|
class IdPattern extends Rule {
|
|
4995
5176
|
constructor(options) {
|
|
4996
|
-
super(
|
|
5177
|
+
super({ ...defaults$d, ...options });
|
|
4997
5178
|
this.pattern = parsePattern(this.options.pattern);
|
|
4998
5179
|
}
|
|
4999
5180
|
static schema() {
|
|
@@ -5345,7 +5526,7 @@ const defaults$c = {
|
|
|
5345
5526
|
};
|
|
5346
5527
|
class LongTitle extends Rule {
|
|
5347
5528
|
constructor(options) {
|
|
5348
|
-
super(
|
|
5529
|
+
super({ ...defaults$c, ...options });
|
|
5349
5530
|
this.maxlength = this.options.maxlength;
|
|
5350
5531
|
}
|
|
5351
5532
|
static schema() {
|
|
@@ -5498,7 +5679,7 @@ const defaults$b = {
|
|
|
5498
5679
|
};
|
|
5499
5680
|
class NoAutoplay extends Rule {
|
|
5500
5681
|
constructor(options) {
|
|
5501
|
-
super(
|
|
5682
|
+
super({ ...defaults$b, ...options });
|
|
5502
5683
|
}
|
|
5503
5684
|
documentation(context) {
|
|
5504
5685
|
const tagName = context ? ` on <${context.tagName}>` : "";
|
|
@@ -5594,8 +5775,12 @@ class NoDeprecatedAttr extends Rule {
|
|
|
5594
5775
|
if (meta === null) {
|
|
5595
5776
|
return;
|
|
5596
5777
|
}
|
|
5597
|
-
const
|
|
5598
|
-
if (
|
|
5778
|
+
const metaAttribute = meta.attributes && meta.attributes[attr];
|
|
5779
|
+
if (!metaAttribute) {
|
|
5780
|
+
return;
|
|
5781
|
+
}
|
|
5782
|
+
const deprecated = metaAttribute.deprecated;
|
|
5783
|
+
if (deprecated) {
|
|
5599
5784
|
this.report(node, `Attribute "${event.key}" is deprecated on <${node.tagName}> element`, event.keyLocation);
|
|
5600
5785
|
}
|
|
5601
5786
|
});
|
|
@@ -5752,7 +5937,7 @@ function getCSSDeclarations(value) {
|
|
|
5752
5937
|
}
|
|
5753
5938
|
class NoInlineStyle extends Rule {
|
|
5754
5939
|
constructor(options) {
|
|
5755
|
-
super(
|
|
5940
|
+
super({ ...defaults$a, ...options });
|
|
5756
5941
|
}
|
|
5757
5942
|
static schema() {
|
|
5758
5943
|
return {
|
|
@@ -5846,7 +6031,20 @@ class NoInlineStyle extends Rule {
|
|
|
5846
6031
|
}
|
|
5847
6032
|
}
|
|
5848
6033
|
|
|
5849
|
-
const ARIA = [
|
|
6034
|
+
const ARIA = [
|
|
6035
|
+
{ property: "aria-activedescendant", isList: false },
|
|
6036
|
+
{ property: "aria-controls", isList: true },
|
|
6037
|
+
{ property: "aria-describedby", isList: true },
|
|
6038
|
+
{ property: "aria-details", isList: false },
|
|
6039
|
+
{ property: "aria-errormessage", isList: false },
|
|
6040
|
+
{ property: "aria-flowto", isList: true },
|
|
6041
|
+
{ property: "aria-labelledby", isList: true },
|
|
6042
|
+
{ property: "aria-owns", isList: true },
|
|
6043
|
+
];
|
|
6044
|
+
function idMissing(document, id) {
|
|
6045
|
+
const nodes = document.querySelectorAll(`[id="${id}"]`);
|
|
6046
|
+
return nodes.length === 0;
|
|
6047
|
+
}
|
|
5850
6048
|
class NoMissingReferences extends Rule {
|
|
5851
6049
|
documentation(context) {
|
|
5852
6050
|
if (context) {
|
|
@@ -5868,38 +6066,56 @@ class NoMissingReferences extends Rule {
|
|
|
5868
6066
|
/* verify <label for=".."> */
|
|
5869
6067
|
for (const node of document.querySelectorAll("label[for]")) {
|
|
5870
6068
|
const attr = node.getAttribute("for");
|
|
5871
|
-
this.validateReference(document, node, attr);
|
|
6069
|
+
this.validateReference(document, node, attr, false);
|
|
5872
6070
|
}
|
|
5873
6071
|
/* verify <input list=".."> */
|
|
5874
6072
|
for (const node of document.querySelectorAll("input[list]")) {
|
|
5875
6073
|
const attr = node.getAttribute("list");
|
|
5876
|
-
this.validateReference(document, node, attr);
|
|
6074
|
+
this.validateReference(document, node, attr, false);
|
|
5877
6075
|
}
|
|
5878
6076
|
/* verify WAI-ARIA properties */
|
|
5879
|
-
for (const property of ARIA) {
|
|
6077
|
+
for (const { property, isList } of ARIA) {
|
|
5880
6078
|
for (const node of document.querySelectorAll(`[${property}]`)) {
|
|
5881
6079
|
const attr = node.getAttribute(property);
|
|
5882
|
-
this.validateReference(document, node, attr);
|
|
6080
|
+
this.validateReference(document, node, attr, isList);
|
|
5883
6081
|
}
|
|
5884
6082
|
}
|
|
5885
6083
|
});
|
|
5886
6084
|
}
|
|
5887
|
-
validateReference(document, node, attr) {
|
|
6085
|
+
validateReference(document, node, attr, isList) {
|
|
5888
6086
|
/* sanity check: querySelector should never return elements without the attribute */
|
|
5889
6087
|
/* istanbul ignore next */
|
|
5890
6088
|
if (!attr) {
|
|
5891
6089
|
return;
|
|
5892
6090
|
}
|
|
5893
|
-
|
|
5894
|
-
|
|
6091
|
+
/* skip dynamic and empty values */
|
|
6092
|
+
const value = attr.value;
|
|
6093
|
+
if (value instanceof DynamicValue || value === null || value === "") {
|
|
5895
6094
|
return;
|
|
5896
6095
|
}
|
|
5897
|
-
|
|
5898
|
-
|
|
6096
|
+
if (isList) {
|
|
6097
|
+
this.validateList(document, node, attr, value);
|
|
6098
|
+
}
|
|
6099
|
+
else {
|
|
6100
|
+
this.validateSingle(document, node, attr, value);
|
|
6101
|
+
}
|
|
6102
|
+
}
|
|
6103
|
+
validateSingle(document, node, attr, id) {
|
|
6104
|
+
if (idMissing(document, id)) {
|
|
5899
6105
|
const context = { key: attr.key, value: id };
|
|
5900
6106
|
this.report(node, `Element references missing id "${id}"`, attr.valueLocation, context);
|
|
5901
6107
|
}
|
|
5902
6108
|
}
|
|
6109
|
+
validateList(document, node, attr, values) {
|
|
6110
|
+
const parsed = new DOMTokenList(values, attr.valueLocation);
|
|
6111
|
+
for (const entry of parsed.iterator()) {
|
|
6112
|
+
const id = entry.item;
|
|
6113
|
+
if (idMissing(document, id)) {
|
|
6114
|
+
const context = { key: attr.key, value: id };
|
|
6115
|
+
this.report(node, `Element references missing id "${id}"`, entry.location, context);
|
|
6116
|
+
}
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
5903
6119
|
}
|
|
5904
6120
|
|
|
5905
6121
|
class NoMultipleMain extends Rule {
|
|
@@ -5943,7 +6159,7 @@ const replacementTable = new Map([
|
|
|
5943
6159
|
]);
|
|
5944
6160
|
class NoRawCharacters extends Rule {
|
|
5945
6161
|
constructor(options) {
|
|
5946
|
-
super(
|
|
6162
|
+
super({ ...defaults$9, ...options });
|
|
5947
6163
|
this.relaxed = this.options.relaxed;
|
|
5948
6164
|
}
|
|
5949
6165
|
static schema() {
|
|
@@ -6128,7 +6344,7 @@ const defaults$8 = {
|
|
|
6128
6344
|
};
|
|
6129
6345
|
class NoSelfClosing extends Rule {
|
|
6130
6346
|
constructor(options) {
|
|
6131
|
-
super(
|
|
6347
|
+
super({ ...defaults$8, ...options });
|
|
6132
6348
|
}
|
|
6133
6349
|
static schema() {
|
|
6134
6350
|
return {
|
|
@@ -6267,7 +6483,7 @@ const defaults$7 = {
|
|
|
6267
6483
|
};
|
|
6268
6484
|
class PreferButton extends Rule {
|
|
6269
6485
|
constructor(options) {
|
|
6270
|
-
super(
|
|
6486
|
+
super({ ...defaults$7, ...options });
|
|
6271
6487
|
}
|
|
6272
6488
|
static schema() {
|
|
6273
6489
|
return {
|
|
@@ -6372,7 +6588,7 @@ const defaults$6 = {
|
|
|
6372
6588
|
};
|
|
6373
6589
|
class PreferNativeElement extends Rule {
|
|
6374
6590
|
constructor(options) {
|
|
6375
|
-
super(
|
|
6591
|
+
super({ ...defaults$6, ...options });
|
|
6376
6592
|
}
|
|
6377
6593
|
static schema() {
|
|
6378
6594
|
return {
|
|
@@ -6502,7 +6718,7 @@ const supportSri = {
|
|
|
6502
6718
|
};
|
|
6503
6719
|
class RequireSri extends Rule {
|
|
6504
6720
|
constructor(options) {
|
|
6505
|
-
super(
|
|
6721
|
+
super({ ...defaults$5, ...options });
|
|
6506
6722
|
this.target = this.options.target;
|
|
6507
6723
|
}
|
|
6508
6724
|
static schema() {
|
|
@@ -8597,7 +8813,7 @@ const defaults$4 = {
|
|
|
8597
8813
|
};
|
|
8598
8814
|
class Void extends Rule {
|
|
8599
8815
|
constructor(options) {
|
|
8600
|
-
super(
|
|
8816
|
+
super({ ...defaults$4, ...options });
|
|
8601
8817
|
this.style = parseStyle$1(this.options.style);
|
|
8602
8818
|
}
|
|
8603
8819
|
get deprecated() {
|
|
@@ -8706,7 +8922,7 @@ const defaults$3 = {
|
|
|
8706
8922
|
};
|
|
8707
8923
|
class VoidStyle extends Rule {
|
|
8708
8924
|
constructor(options) {
|
|
8709
|
-
super(
|
|
8925
|
+
super({ ...defaults$3, ...options });
|
|
8710
8926
|
this.style = parseStyle(this.options.style);
|
|
8711
8927
|
}
|
|
8712
8928
|
static schema() {
|
|
@@ -8909,7 +9125,7 @@ const defaults$2 = {
|
|
|
8909
9125
|
};
|
|
8910
9126
|
class H37 extends Rule {
|
|
8911
9127
|
constructor(options) {
|
|
8912
|
-
super(
|
|
9128
|
+
super({ ...defaults$2, ...options });
|
|
8913
9129
|
/* ensure alias is array */
|
|
8914
9130
|
if (!Array.isArray(this.options.alias)) {
|
|
8915
9131
|
this.options.alias = [this.options.alias];
|
|
@@ -9036,7 +9252,73 @@ const bundledRules$1 = {
|
|
|
9036
9252
|
"wcag/h71": H71,
|
|
9037
9253
|
};
|
|
9038
9254
|
|
|
9039
|
-
const bundledRules =
|
|
9255
|
+
const bundledRules = {
|
|
9256
|
+
"allowed-links": AllowedLinks,
|
|
9257
|
+
"aria-label-misuse": AriaLabelMisuse,
|
|
9258
|
+
"attr-case": AttrCase,
|
|
9259
|
+
"attr-delimiter": AttrDelimiter,
|
|
9260
|
+
"attr-pattern": AttrPattern,
|
|
9261
|
+
"attr-quotes": AttrQuotes,
|
|
9262
|
+
"attr-spacing": AttrSpacing,
|
|
9263
|
+
"attribute-allowed-values": AttributeAllowedValues,
|
|
9264
|
+
"attribute-boolean-style": AttributeBooleanStyle,
|
|
9265
|
+
"attribute-empty-style": AttributeEmptyStyle,
|
|
9266
|
+
"class-pattern": ClassPattern,
|
|
9267
|
+
"close-attr": CloseAttr,
|
|
9268
|
+
"close-order": CloseOrder,
|
|
9269
|
+
deprecated: Deprecated,
|
|
9270
|
+
"deprecated-rule": DeprecatedRule,
|
|
9271
|
+
"doctype-html": NoStyleTag$1,
|
|
9272
|
+
"doctype-style": DoctypeStyle,
|
|
9273
|
+
"element-case": ElementCase,
|
|
9274
|
+
"element-name": ElementName,
|
|
9275
|
+
"element-permitted-content": ElementPermittedContent,
|
|
9276
|
+
"element-permitted-occurrences": ElementPermittedOccurrences,
|
|
9277
|
+
"element-permitted-order": ElementPermittedOrder,
|
|
9278
|
+
"element-required-attributes": ElementRequiredAttributes,
|
|
9279
|
+
"element-required-content": ElementRequiredContent,
|
|
9280
|
+
"empty-heading": EmptyHeading,
|
|
9281
|
+
"empty-title": EmptyTitle,
|
|
9282
|
+
"heading-level": HeadingLevel,
|
|
9283
|
+
"id-pattern": IdPattern,
|
|
9284
|
+
"input-attributes": InputAttributes,
|
|
9285
|
+
"input-missing-label": InputMissingLabel,
|
|
9286
|
+
"long-title": LongTitle,
|
|
9287
|
+
"meta-refresh": MetaRefresh,
|
|
9288
|
+
"missing-doctype": MissingDoctype,
|
|
9289
|
+
"multiple-labeled-controls": MultipleLabeledControls,
|
|
9290
|
+
"no-autoplay": NoAutoplay,
|
|
9291
|
+
"no-conditional-comment": NoConditionalComment,
|
|
9292
|
+
"no-deprecated-attr": NoDeprecatedAttr,
|
|
9293
|
+
"no-dup-attr": NoDupAttr,
|
|
9294
|
+
"no-dup-class": NoDupClass,
|
|
9295
|
+
"no-dup-id": NoDupID,
|
|
9296
|
+
"no-implicit-close": NoImplicitClose,
|
|
9297
|
+
"no-inline-style": NoInlineStyle,
|
|
9298
|
+
"no-missing-references": NoMissingReferences,
|
|
9299
|
+
"no-multiple-main": NoMultipleMain,
|
|
9300
|
+
"no-raw-characters": NoRawCharacters,
|
|
9301
|
+
"no-redundant-for": NoRedundantFor,
|
|
9302
|
+
"no-redundant-role": NoRedundantRole,
|
|
9303
|
+
"no-self-closing": NoSelfClosing,
|
|
9304
|
+
"no-style-tag": NoStyleTag,
|
|
9305
|
+
"no-trailing-whitespace": NoTrailingWhitespace,
|
|
9306
|
+
"no-unknown-elements": NoUnknownElements,
|
|
9307
|
+
"no-utf8-bom": NoUtf8Bom,
|
|
9308
|
+
"prefer-button": PreferButton,
|
|
9309
|
+
"prefer-native-element": PreferNativeElement,
|
|
9310
|
+
"prefer-tbody": PreferTbody,
|
|
9311
|
+
"require-sri": RequireSri,
|
|
9312
|
+
"script-element": ScriptElement,
|
|
9313
|
+
"script-type": ScriptType,
|
|
9314
|
+
"svg-focusable": SvgFocusable,
|
|
9315
|
+
"text-content": TextContent,
|
|
9316
|
+
"unrecognized-char-ref": UnknownCharReference,
|
|
9317
|
+
void: Void,
|
|
9318
|
+
"void-content": VoidContent,
|
|
9319
|
+
"void-style": VoidStyle,
|
|
9320
|
+
...bundledRules$1,
|
|
9321
|
+
};
|
|
9040
9322
|
|
|
9041
9323
|
var defaultConfig = {};
|
|
9042
9324
|
|
|
@@ -9274,7 +9556,7 @@ function overwriteMerge(a, b) {
|
|
|
9274
9556
|
return b;
|
|
9275
9557
|
}
|
|
9276
9558
|
function mergeInternal(base, rhs) {
|
|
9277
|
-
const dst = deepmerge(base,
|
|
9559
|
+
const dst = deepmerge(base, { ...rhs, rules: {} });
|
|
9278
9560
|
/* rules need some special care, should overwrite arrays instead of
|
|
9279
9561
|
* concaternation, i.e. ["error", {...options}] should not be merged by
|
|
9280
9562
|
* appending to old value */
|
|
@@ -9499,7 +9781,7 @@ class Config {
|
|
|
9499
9781
|
* @internal primary purpose is unittests
|
|
9500
9782
|
*/
|
|
9501
9783
|
get() {
|
|
9502
|
-
const config =
|
|
9784
|
+
const config = { ...this.config };
|
|
9503
9785
|
if (config.elements) {
|
|
9504
9786
|
config.elements = config.elements.map((cur) => {
|
|
9505
9787
|
if (typeof cur === "string") {
|
|
@@ -9585,7 +9867,11 @@ class Config {
|
|
|
9585
9867
|
if (!properties) {
|
|
9586
9868
|
continue;
|
|
9587
9869
|
}
|
|
9588
|
-
for (const [
|
|
9870
|
+
for (const [raw, schema] of Object.entries(properties)) {
|
|
9871
|
+
/* at compile time this is a fixed list but the point of this method is
|
|
9872
|
+
* to augment the runtime with additional keys so it is a bit of lying
|
|
9873
|
+
* to typescript */
|
|
9874
|
+
const key = raw;
|
|
9589
9875
|
if (schema.copyable && !MetaCopyableProperty.includes(key)) {
|
|
9590
9876
|
MetaCopyableProperty.push(key);
|
|
9591
9877
|
}
|
|
@@ -9781,31 +10067,6 @@ class ConfigLoader {
|
|
|
9781
10067
|
}
|
|
9782
10068
|
}
|
|
9783
10069
|
|
|
9784
|
-
/*! *****************************************************************************
|
|
9785
|
-
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
9786
|
-
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
9787
|
-
this file except in compliance with the License. You may obtain a copy of the
|
|
9788
|
-
License at http://www.apache.org/licenses/LICENSE-2.0
|
|
9789
|
-
|
|
9790
|
-
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
9791
|
-
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
|
9792
|
-
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
|
9793
|
-
MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
9794
|
-
|
|
9795
|
-
See the Apache Version 2.0 License for specific language governing permissions
|
|
9796
|
-
and limitations under the License.
|
|
9797
|
-
***************************************************************************** */
|
|
9798
|
-
|
|
9799
|
-
function __rest(s, e) {
|
|
9800
|
-
var t = {};
|
|
9801
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
9802
|
-
t[p] = s[p];
|
|
9803
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
9804
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
|
|
9805
|
-
t[p[i]] = s[p[i]];
|
|
9806
|
-
return t;
|
|
9807
|
-
}
|
|
9808
|
-
|
|
9809
10070
|
class EventHandler {
|
|
9810
10071
|
constructor() {
|
|
9811
10072
|
this.listeners = {};
|
|
@@ -10379,7 +10640,7 @@ class Reporter {
|
|
|
10379
10640
|
merged[key].messages = [...merged[key].messages, ...result.messages];
|
|
10380
10641
|
}
|
|
10381
10642
|
else {
|
|
10382
|
-
merged[key] =
|
|
10643
|
+
merged[key] = { ...result };
|
|
10383
10644
|
}
|
|
10384
10645
|
});
|
|
10385
10646
|
});
|
|
@@ -10481,14 +10742,16 @@ function messageSort(a, b) {
|
|
|
10481
10742
|
}
|
|
10482
10743
|
|
|
10483
10744
|
class Engine {
|
|
10484
|
-
constructor(config,
|
|
10745
|
+
constructor(config, ParserClass) {
|
|
10485
10746
|
this.report = new Reporter();
|
|
10486
|
-
this.configData = configData;
|
|
10487
10747
|
this.config = config;
|
|
10488
10748
|
this.ParserClass = ParserClass;
|
|
10489
10749
|
/* initialize plugins and rules */
|
|
10490
10750
|
const result = this.initPlugins(this.config);
|
|
10491
|
-
this.availableRules =
|
|
10751
|
+
this.availableRules = {
|
|
10752
|
+
...bundledRules,
|
|
10753
|
+
...result.availableRules,
|
|
10754
|
+
};
|
|
10492
10755
|
}
|
|
10493
10756
|
/**
|
|
10494
10757
|
* Lint sources and return report
|
|
@@ -10513,13 +10776,13 @@ class Engine {
|
|
|
10513
10776
|
/* trigger configuration ready event */
|
|
10514
10777
|
const configEvent = {
|
|
10515
10778
|
location,
|
|
10516
|
-
config: this.
|
|
10779
|
+
config: this.config,
|
|
10517
10780
|
rules,
|
|
10518
10781
|
};
|
|
10519
10782
|
parser.trigger("config:ready", configEvent);
|
|
10520
10783
|
/* trigger source ready event */
|
|
10521
10784
|
/* eslint-disable-next-line @typescript-eslint/no-unused-vars -- object destructured on purpose to remove property */
|
|
10522
|
-
const sourceData =
|
|
10785
|
+
const { hooks: _, ...sourceData } = source;
|
|
10523
10786
|
const sourceEvent = {
|
|
10524
10787
|
location,
|
|
10525
10788
|
source: sourceData,
|
|
@@ -10826,133 +11089,31 @@ class Engine {
|
|
|
10826
11089
|
}
|
|
10827
11090
|
|
|
10828
11091
|
/**
|
|
10829
|
-
*
|
|
10830
|
-
|
|
10831
|
-
function findConfigurationFiles(directory) {
|
|
10832
|
-
return ["json", "cjs", "js"]
|
|
10833
|
-
.map((extension) => path.join(directory, `.htmlvalidate.${extension}`))
|
|
10834
|
-
.filter((filePath) => fs.existsSync(filePath));
|
|
10835
|
-
}
|
|
10836
|
-
/**
|
|
10837
|
-
* Loads configuration by traversing filesystem.
|
|
10838
|
-
*
|
|
10839
|
-
* Configuration is read from three sources and in the following order:
|
|
10840
|
-
*
|
|
10841
|
-
* 1. Global configuration passed to constructor.
|
|
10842
|
-
* 2. Configuration files found when traversing the directory structure.
|
|
10843
|
-
* 3. Override passed to this function.
|
|
10844
|
-
*
|
|
10845
|
-
* The following configuration filenames are searched:
|
|
10846
|
-
*
|
|
10847
|
-
* - `.htmlvalidate.json`
|
|
10848
|
-
* - `.htmlvalidate.js`
|
|
10849
|
-
* - `.htmlvalidate.cjs`
|
|
10850
|
-
*
|
|
10851
|
-
* Global configuration is used when no configuration file is found. The
|
|
10852
|
-
* result is always merged with override if present.
|
|
10853
|
-
*
|
|
10854
|
-
* The `root` property set to `true` affects the configuration as following:
|
|
11092
|
+
* The static configuration loader does not do any per-handle lookup. Only the
|
|
11093
|
+
* global or per-call configuration is used.
|
|
10855
11094
|
*
|
|
10856
|
-
*
|
|
10857
|
-
*
|
|
10858
|
-
* returned. No configuration files are searched.
|
|
10859
|
-
* 3. Setting `root` in configuration file only stops directory traversal.
|
|
11095
|
+
* In practice this means no configuration is fetch by traversing the
|
|
11096
|
+
* filesystem.
|
|
10860
11097
|
*/
|
|
10861
|
-
class
|
|
10862
|
-
|
|
10863
|
-
* @param config - Global configuration
|
|
10864
|
-
* @param configFactory - Optional configuration factory
|
|
10865
|
-
*/
|
|
10866
|
-
constructor(config, configFactory = Config) {
|
|
10867
|
-
super(config, configFactory);
|
|
10868
|
-
this.cache = new Map();
|
|
10869
|
-
}
|
|
10870
|
-
/**
|
|
10871
|
-
* Get configuration for given filename.
|
|
10872
|
-
*
|
|
10873
|
-
* @param filename - Filename to get configuration for.
|
|
10874
|
-
* @param configOverride - Configuration to merge final result with.
|
|
10875
|
-
*/
|
|
10876
|
-
getConfigFor(filename, configOverride) {
|
|
10877
|
-
/* special case when the overridden configuration is marked as root, should
|
|
10878
|
-
* not try to load any more configuration files */
|
|
11098
|
+
class StaticConfigLoader extends ConfigLoader {
|
|
11099
|
+
getConfigFor(handle, configOverride) {
|
|
10879
11100
|
const override = this.loadFromObject(configOverride || {});
|
|
10880
11101
|
if (override.isRootFound()) {
|
|
10881
11102
|
override.init();
|
|
10882
11103
|
return override;
|
|
10883
11104
|
}
|
|
10884
|
-
|
|
10885
|
-
* try to load and more configuration files */
|
|
10886
|
-
if (this.globalConfig.isRootFound()) {
|
|
10887
|
-
const merged = this.globalConfig.merge(override);
|
|
10888
|
-
merged.init();
|
|
10889
|
-
return merged;
|
|
10890
|
-
}
|
|
10891
|
-
const config = this.fromFilename(filename);
|
|
10892
|
-
const merged = config ? config.merge(override) : this.globalConfig.merge(override);
|
|
11105
|
+
const merged = this.globalConfig.merge(override);
|
|
10893
11106
|
merged.init();
|
|
10894
11107
|
return merged;
|
|
10895
11108
|
}
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
*
|
|
10899
|
-
* @param filename - If given only the cache for that file is flushed.
|
|
10900
|
-
*/
|
|
10901
|
-
flushCache(filename) {
|
|
10902
|
-
if (filename) {
|
|
10903
|
-
this.cache.delete(filename);
|
|
10904
|
-
}
|
|
10905
|
-
else {
|
|
10906
|
-
this.cache.clear();
|
|
10907
|
-
}
|
|
10908
|
-
}
|
|
10909
|
-
/**
|
|
10910
|
-
* Load raw configuration from directory traversal.
|
|
10911
|
-
*
|
|
10912
|
-
* This configuration is not merged with global configuration and may return
|
|
10913
|
-
* `null` if no configuration files are found.
|
|
10914
|
-
*/
|
|
10915
|
-
fromFilename(filename) {
|
|
10916
|
-
var _a;
|
|
10917
|
-
if (filename === "inline") {
|
|
10918
|
-
return null;
|
|
10919
|
-
}
|
|
10920
|
-
if (this.cache.has(filename)) {
|
|
10921
|
-
return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
|
|
10922
|
-
}
|
|
10923
|
-
let found = false;
|
|
10924
|
-
let current = path.resolve(path.dirname(filename));
|
|
10925
|
-
let config = this.empty();
|
|
10926
|
-
// eslint-disable-next-line no-constant-condition
|
|
10927
|
-
while (true) {
|
|
10928
|
-
/* search configuration files in current directory */
|
|
10929
|
-
for (const configFile of findConfigurationFiles(current)) {
|
|
10930
|
-
const local = this.loadFromFile(configFile);
|
|
10931
|
-
found = true;
|
|
10932
|
-
config = local.merge(config);
|
|
10933
|
-
}
|
|
10934
|
-
/* stop if a configuration with "root" is set to true */
|
|
10935
|
-
if (config.isRootFound()) {
|
|
10936
|
-
break;
|
|
10937
|
-
}
|
|
10938
|
-
/* get the parent directory */
|
|
10939
|
-
const child = current;
|
|
10940
|
-
current = path.dirname(current);
|
|
10941
|
-
/* stop if this is the root directory */
|
|
10942
|
-
if (current === child) {
|
|
10943
|
-
break;
|
|
10944
|
-
}
|
|
10945
|
-
}
|
|
10946
|
-
/* no config was found by loader, return null and let caller decide what to do */
|
|
10947
|
-
if (!found) {
|
|
10948
|
-
this.cache.set(filename, null);
|
|
10949
|
-
return null;
|
|
10950
|
-
}
|
|
10951
|
-
this.cache.set(filename, config);
|
|
10952
|
-
return config;
|
|
11109
|
+
flushCache() {
|
|
11110
|
+
/* do nothing */
|
|
10953
11111
|
}
|
|
10954
11112
|
defaultConfig() {
|
|
10955
|
-
return this.
|
|
11113
|
+
return this.loadFromObject({
|
|
11114
|
+
extends: ["html-validate:recommended"],
|
|
11115
|
+
elements: ["html5"],
|
|
11116
|
+
});
|
|
10956
11117
|
}
|
|
10957
11118
|
}
|
|
10958
11119
|
|
|
@@ -10976,7 +11137,7 @@ function isConfigData(value) {
|
|
|
10976
11137
|
class HtmlValidate {
|
|
10977
11138
|
constructor(arg) {
|
|
10978
11139
|
const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
|
|
10979
|
-
this.configLoader = loader !== null && loader !== void 0 ? loader : new
|
|
11140
|
+
this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
|
|
10980
11141
|
}
|
|
10981
11142
|
validateString(str, arg1, arg2, arg3) {
|
|
10982
11143
|
const filename = typeof arg1 === "string" ? arg1 : "inline";
|
|
@@ -11003,7 +11164,7 @@ class HtmlValidate {
|
|
|
11003
11164
|
const config = this.getConfigFor(input.filename, configOverride);
|
|
11004
11165
|
const resolved = config.resolve();
|
|
11005
11166
|
const source = resolved.transformSource(input);
|
|
11006
|
-
const engine = new Engine(resolved,
|
|
11167
|
+
const engine = new Engine(resolved, Parser);
|
|
11007
11168
|
return engine.lint(source);
|
|
11008
11169
|
}
|
|
11009
11170
|
/**
|
|
@@ -11017,7 +11178,7 @@ class HtmlValidate {
|
|
|
11017
11178
|
const config = this.getConfigFor(filename);
|
|
11018
11179
|
const resolved = config.resolve();
|
|
11019
11180
|
const source = resolved.transformFilename(filename);
|
|
11020
|
-
const engine = new Engine(resolved,
|
|
11181
|
+
const engine = new Engine(resolved, Parser);
|
|
11021
11182
|
return engine.lint(source);
|
|
11022
11183
|
}
|
|
11023
11184
|
/**
|
|
@@ -11062,7 +11223,7 @@ class HtmlValidate {
|
|
|
11062
11223
|
const config = this.getConfigFor(filename);
|
|
11063
11224
|
const resolved = config.resolve();
|
|
11064
11225
|
const source = resolved.transformFilename(filename);
|
|
11065
|
-
const engine = new Engine(resolved,
|
|
11226
|
+
const engine = new Engine(resolved, Parser);
|
|
11066
11227
|
return engine.dumpTokens(source);
|
|
11067
11228
|
}
|
|
11068
11229
|
/**
|
|
@@ -11077,7 +11238,7 @@ class HtmlValidate {
|
|
|
11077
11238
|
const config = this.getConfigFor(filename);
|
|
11078
11239
|
const resolved = config.resolve();
|
|
11079
11240
|
const source = resolved.transformFilename(filename);
|
|
11080
|
-
const engine = new Engine(resolved,
|
|
11241
|
+
const engine = new Engine(resolved, Parser);
|
|
11081
11242
|
return engine.dumpEvents(source);
|
|
11082
11243
|
}
|
|
11083
11244
|
/**
|
|
@@ -11092,7 +11253,7 @@ class HtmlValidate {
|
|
|
11092
11253
|
const config = this.getConfigFor(filename);
|
|
11093
11254
|
const resolved = config.resolve();
|
|
11094
11255
|
const source = resolved.transformFilename(filename);
|
|
11095
|
-
const engine = new Engine(resolved,
|
|
11256
|
+
const engine = new Engine(resolved, Parser);
|
|
11096
11257
|
return engine.dumpTree(source);
|
|
11097
11258
|
}
|
|
11098
11259
|
/**
|
|
@@ -11170,7 +11331,7 @@ class HtmlValidate {
|
|
|
11170
11331
|
*/
|
|
11171
11332
|
getRuleDocumentation(ruleId, config = null, context = null) {
|
|
11172
11333
|
const c = config || this.getConfigFor("inline");
|
|
11173
|
-
const engine = new Engine(c.resolve(),
|
|
11334
|
+
const engine = new Engine(c.resolve(), Parser);
|
|
11174
11335
|
return engine.getRuleDocumentation(ruleId, context);
|
|
11175
11336
|
}
|
|
11176
11337
|
/**
|
|
@@ -11207,35 +11368,6 @@ class HtmlValidate {
|
|
|
11207
11368
|
}
|
|
11208
11369
|
}
|
|
11209
11370
|
|
|
11210
|
-
/**
|
|
11211
|
-
* The static configuration loader does not do any per-handle lookup. Only the
|
|
11212
|
-
* global or per-call configuration is used.
|
|
11213
|
-
*
|
|
11214
|
-
* In practice this means no configuration is fetch by traversing the
|
|
11215
|
-
* filesystem.
|
|
11216
|
-
*/
|
|
11217
|
-
class StaticConfigLoader extends ConfigLoader {
|
|
11218
|
-
getConfigFor(handle, configOverride) {
|
|
11219
|
-
const override = this.loadFromObject(configOverride || {});
|
|
11220
|
-
if (override.isRootFound()) {
|
|
11221
|
-
override.init();
|
|
11222
|
-
return override;
|
|
11223
|
-
}
|
|
11224
|
-
const merged = this.globalConfig.merge(override);
|
|
11225
|
-
merged.init();
|
|
11226
|
-
return merged;
|
|
11227
|
-
}
|
|
11228
|
-
flushCache() {
|
|
11229
|
-
/* do nothing */
|
|
11230
|
-
}
|
|
11231
|
-
defaultConfig() {
|
|
11232
|
-
return this.loadFromObject({
|
|
11233
|
-
extends: ["html-validate:recommended"],
|
|
11234
|
-
elements: ["html5"],
|
|
11235
|
-
});
|
|
11236
|
-
}
|
|
11237
|
-
}
|
|
11238
|
-
|
|
11239
11371
|
const defaults$1 = {
|
|
11240
11372
|
silent: false,
|
|
11241
11373
|
version,
|
|
@@ -11253,7 +11385,7 @@ const defaults$1 = {
|
|
|
11253
11385
|
* @returns - `true` if version is compatible
|
|
11254
11386
|
*/
|
|
11255
11387
|
function compatibilityCheck(name, declared, options) {
|
|
11256
|
-
const { silent, version: current, logger } =
|
|
11388
|
+
const { silent, version: current, logger } = { ...defaults$1, ...options };
|
|
11257
11389
|
const valid = semver.satisfies(current, declared);
|
|
11258
11390
|
if (valid || silent) {
|
|
11259
11391
|
return valid;
|
|
@@ -11283,6 +11415,137 @@ function ruleExists(ruleId) {
|
|
|
11283
11415
|
return ruleIds.has(ruleId);
|
|
11284
11416
|
}
|
|
11285
11417
|
|
|
11418
|
+
/**
|
|
11419
|
+
* @internal
|
|
11420
|
+
*/
|
|
11421
|
+
function findConfigurationFiles(directory) {
|
|
11422
|
+
return ["json", "cjs", "js"]
|
|
11423
|
+
.map((extension) => path.join(directory, `.htmlvalidate.${extension}`))
|
|
11424
|
+
.filter((filePath) => fs.existsSync(filePath));
|
|
11425
|
+
}
|
|
11426
|
+
/**
|
|
11427
|
+
* Loads configuration by traversing filesystem.
|
|
11428
|
+
*
|
|
11429
|
+
* Configuration is read from three sources and in the following order:
|
|
11430
|
+
*
|
|
11431
|
+
* 1. Global configuration passed to constructor.
|
|
11432
|
+
* 2. Configuration files found when traversing the directory structure.
|
|
11433
|
+
* 3. Override passed to this function.
|
|
11434
|
+
*
|
|
11435
|
+
* The following configuration filenames are searched:
|
|
11436
|
+
*
|
|
11437
|
+
* - `.htmlvalidate.json`
|
|
11438
|
+
* - `.htmlvalidate.js`
|
|
11439
|
+
* - `.htmlvalidate.cjs`
|
|
11440
|
+
*
|
|
11441
|
+
* Global configuration is used when no configuration file is found. The
|
|
11442
|
+
* result is always merged with override if present.
|
|
11443
|
+
*
|
|
11444
|
+
* The `root` property set to `true` affects the configuration as following:
|
|
11445
|
+
*
|
|
11446
|
+
* 1. If set in override the override is returned as-is.
|
|
11447
|
+
* 2. If set in the global config the override is merged into global and
|
|
11448
|
+
* returned. No configuration files are searched.
|
|
11449
|
+
* 3. Setting `root` in configuration file only stops directory traversal.
|
|
11450
|
+
*/
|
|
11451
|
+
class FileSystemConfigLoader extends ConfigLoader {
|
|
11452
|
+
/**
|
|
11453
|
+
* @param config - Global configuration
|
|
11454
|
+
* @param configFactory - Optional configuration factory
|
|
11455
|
+
*/
|
|
11456
|
+
constructor(config, configFactory = Config) {
|
|
11457
|
+
super(config, configFactory);
|
|
11458
|
+
this.cache = new Map();
|
|
11459
|
+
}
|
|
11460
|
+
/**
|
|
11461
|
+
* Get configuration for given filename.
|
|
11462
|
+
*
|
|
11463
|
+
* @param filename - Filename to get configuration for.
|
|
11464
|
+
* @param configOverride - Configuration to merge final result with.
|
|
11465
|
+
*/
|
|
11466
|
+
getConfigFor(filename, configOverride) {
|
|
11467
|
+
/* special case when the overridden configuration is marked as root, should
|
|
11468
|
+
* not try to load any more configuration files */
|
|
11469
|
+
const override = this.loadFromObject(configOverride || {});
|
|
11470
|
+
if (override.isRootFound()) {
|
|
11471
|
+
override.init();
|
|
11472
|
+
return override;
|
|
11473
|
+
}
|
|
11474
|
+
/* special case when the global configuration is marked as root, should not
|
|
11475
|
+
* try to load and more configuration files */
|
|
11476
|
+
if (this.globalConfig.isRootFound()) {
|
|
11477
|
+
const merged = this.globalConfig.merge(override);
|
|
11478
|
+
merged.init();
|
|
11479
|
+
return merged;
|
|
11480
|
+
}
|
|
11481
|
+
const config = this.fromFilename(filename);
|
|
11482
|
+
const merged = config ? config.merge(override) : this.globalConfig.merge(override);
|
|
11483
|
+
merged.init();
|
|
11484
|
+
return merged;
|
|
11485
|
+
}
|
|
11486
|
+
/**
|
|
11487
|
+
* Flush configuration cache.
|
|
11488
|
+
*
|
|
11489
|
+
* @param filename - If given only the cache for that file is flushed.
|
|
11490
|
+
*/
|
|
11491
|
+
flushCache(filename) {
|
|
11492
|
+
if (filename) {
|
|
11493
|
+
this.cache.delete(filename);
|
|
11494
|
+
}
|
|
11495
|
+
else {
|
|
11496
|
+
this.cache.clear();
|
|
11497
|
+
}
|
|
11498
|
+
}
|
|
11499
|
+
/**
|
|
11500
|
+
* Load raw configuration from directory traversal.
|
|
11501
|
+
*
|
|
11502
|
+
* This configuration is not merged with global configuration and may return
|
|
11503
|
+
* `null` if no configuration files are found.
|
|
11504
|
+
*/
|
|
11505
|
+
fromFilename(filename) {
|
|
11506
|
+
var _a;
|
|
11507
|
+
if (filename === "inline") {
|
|
11508
|
+
return null;
|
|
11509
|
+
}
|
|
11510
|
+
if (this.cache.has(filename)) {
|
|
11511
|
+
return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
|
|
11512
|
+
}
|
|
11513
|
+
let found = false;
|
|
11514
|
+
let current = path.resolve(path.dirname(filename));
|
|
11515
|
+
let config = this.empty();
|
|
11516
|
+
// eslint-disable-next-line no-constant-condition
|
|
11517
|
+
while (true) {
|
|
11518
|
+
/* search configuration files in current directory */
|
|
11519
|
+
for (const configFile of findConfigurationFiles(current)) {
|
|
11520
|
+
const local = this.loadFromFile(configFile);
|
|
11521
|
+
found = true;
|
|
11522
|
+
config = local.merge(config);
|
|
11523
|
+
}
|
|
11524
|
+
/* stop if a configuration with "root" is set to true */
|
|
11525
|
+
if (config.isRootFound()) {
|
|
11526
|
+
break;
|
|
11527
|
+
}
|
|
11528
|
+
/* get the parent directory */
|
|
11529
|
+
const child = current;
|
|
11530
|
+
current = path.dirname(current);
|
|
11531
|
+
/* stop if this is the root directory */
|
|
11532
|
+
if (current === child) {
|
|
11533
|
+
break;
|
|
11534
|
+
}
|
|
11535
|
+
}
|
|
11536
|
+
/* no config was found by loader, return null and let caller decide what to do */
|
|
11537
|
+
if (!found) {
|
|
11538
|
+
this.cache.set(filename, null);
|
|
11539
|
+
return null;
|
|
11540
|
+
}
|
|
11541
|
+
this.cache.set(filename, config);
|
|
11542
|
+
return config;
|
|
11543
|
+
}
|
|
11544
|
+
defaultConfig() {
|
|
11545
|
+
return this.configFactory.defaultConfig();
|
|
11546
|
+
}
|
|
11547
|
+
}
|
|
11548
|
+
|
|
11286
11549
|
const entities = {
|
|
11287
11550
|
">": ">",
|
|
11288
11551
|
"<": "<",
|
|
@@ -11433,7 +11696,7 @@ function formatSummary(errors, warnings) {
|
|
|
11433
11696
|
return kleur[summaryColor]().bold(`${summary.join(" and ")} found.`);
|
|
11434
11697
|
}
|
|
11435
11698
|
function codeframe(results, options) {
|
|
11436
|
-
const merged =
|
|
11699
|
+
const merged = { ...defaults, ...options };
|
|
11437
11700
|
let errors = 0;
|
|
11438
11701
|
let warnings = 0;
|
|
11439
11702
|
const resultsWithMessages = results.filter((result) => result.messages.length > 0);
|
|
@@ -11474,7 +11737,11 @@ function linkSummary(results) {
|
|
|
11474
11737
|
return `\n${kleur.bold("More information")}:\n${lines.join("")}\n`;
|
|
11475
11738
|
}
|
|
11476
11739
|
function stylish(results) {
|
|
11477
|
-
const errors = stylishImpl(results.map((it) => (
|
|
11740
|
+
const errors = stylishImpl(results.map((it) => ({
|
|
11741
|
+
...it,
|
|
11742
|
+
fixableErrorCount: 0,
|
|
11743
|
+
fixableWarningCount: 0,
|
|
11744
|
+
})));
|
|
11478
11745
|
const links = linkSummary(results);
|
|
11479
11746
|
return `${errors}${links}`;
|
|
11480
11747
|
}
|
|
@@ -11525,5 +11792,5 @@ function getFormatter(name) {
|
|
|
11525
11792
|
return (_a = availableFormatters[name]) !== null && _a !== void 0 ? _a : null;
|
|
11526
11793
|
}
|
|
11527
11794
|
|
|
11528
|
-
export { Config as C, DynamicValue as D, EventHandler as E, FileSystemConfigLoader as F, HtmlValidate as H, MetaTable as M, NodeClosed as N, Parser as P, Rule as R, Severity as S, TextNode as T, UserError as U, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, HtmlElement as d, SchemaValidationError as e, MetaCopyableProperty as f, Reporter as g, TemplateExtractor as h, getFormatter as i, compatibilityCheck as j,
|
|
11795
|
+
export { Config as C, DynamicValue as D, EventHandler as E, FileSystemConfigLoader as F, HtmlValidate as H, MetaTable as M, NodeClosed as N, Parser as P, Rule as R, Severity as S, TextNode as T, UserError as U, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, HtmlElement as d, SchemaValidationError as e, MetaCopyableProperty as f, Reporter as g, TemplateExtractor as h, getFormatter as i, compatibilityCheck as j, TokenType as k, legacyRequire as l, bugs as m, name as n, presets as p, ruleExists as r, version as v };
|
|
11529
11796
|
//# sourceMappingURL=core.js.map
|