html-validate 5.5.0 → 6.1.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 +64 -0
- package/dist/cjs/browser.js +2 -6
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/cli.js +41 -27
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core.d.ts +16 -7
- package/dist/cjs/core.js +615 -360
- 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 +11 -1
- package/dist/cjs/index.js +2 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/jest-lib.js +7 -8
- package/dist/cjs/jest-lib.js.map +1 -1
- package/dist/cjs/test-utils.js +1 -1
- package/dist/es/cli.js +19 -5
- package/dist/es/cli.js.map +1 -1
- package/dist/es/core.d.ts +16 -7
- package/dist/es/core.js +578 -323
- package/dist/es/core.js.map +1 -1
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/index.d.ts +11 -1
- package/dist/es/jest-lib.js +3 -2
- package/dist/es/jest-lib.js.map +1 -1
- package/dist/schema/elements.json +43 -5
- package/elements/html5.json +940 -307
- package/package.json +21 -22
package/dist/cjs/core.js
CHANGED
|
@@ -268,7 +268,7 @@ class UserError extends NestedError {
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
function getSummary(schema, obj, errors) {
|
|
271
|
-
const output = betterAjvErrors__default[
|
|
271
|
+
const output = betterAjvErrors__default["default"](schema, obj, errors, {
|
|
272
272
|
format: "js",
|
|
273
273
|
});
|
|
274
274
|
// istanbul ignore next: for safety only
|
|
@@ -285,15 +285,15 @@ class SchemaValidationError extends UserError {
|
|
|
285
285
|
}
|
|
286
286
|
prettyError() {
|
|
287
287
|
const json = this.getRawJSON();
|
|
288
|
-
return betterAjvErrors__default[
|
|
288
|
+
return betterAjvErrors__default["default"](this.schema, this.obj, this.errors, {
|
|
289
289
|
format: "cli",
|
|
290
290
|
indent: 2,
|
|
291
291
|
json,
|
|
292
292
|
});
|
|
293
293
|
}
|
|
294
294
|
getRawJSON() {
|
|
295
|
-
if (this.filename && fs__default[
|
|
296
|
-
return fs__default[
|
|
295
|
+
if (this.filename && fs__default["default"].existsSync(this.filename)) {
|
|
296
|
+
return fs__default["default"].readFileSync(this.filename, "utf-8");
|
|
297
297
|
}
|
|
298
298
|
else {
|
|
299
299
|
return null;
|
|
@@ -301,9 +301,9 @@ class SchemaValidationError extends UserError {
|
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
-
const projectRoot = path__default[
|
|
304
|
+
const projectRoot = path__default["default"].resolve(__dirname, "../../");
|
|
305
305
|
const legacyRequire = require;
|
|
306
|
-
const distFolder = path__default[
|
|
306
|
+
const distFolder = path__default["default"].resolve(projectRoot, "dist/cjs");
|
|
307
307
|
|
|
308
308
|
/**
|
|
309
309
|
* Similar to `require(..)` but removes the cached copy first.
|
|
@@ -586,18 +586,63 @@ const definitions = {
|
|
|
586
586
|
type: "object",
|
|
587
587
|
patternProperties: {
|
|
588
588
|
"^.*$": {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
{
|
|
589
|
+
anyOf: [
|
|
590
|
+
{
|
|
591
|
+
type: "object",
|
|
592
|
+
additionalProperties: false,
|
|
593
|
+
properties: {
|
|
594
|
+
boolean: {
|
|
595
|
+
type: "boolean",
|
|
596
|
+
title: "Set to true if this is a boolean attribute"
|
|
597
|
+
},
|
|
598
|
+
deprecated: {
|
|
599
|
+
title: "Set to true or string if this attribute is deprecated",
|
|
600
|
+
oneOf: [
|
|
601
|
+
{
|
|
602
|
+
type: "boolean"
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
type: "string"
|
|
606
|
+
}
|
|
607
|
+
]
|
|
608
|
+
},
|
|
609
|
+
list: {
|
|
610
|
+
type: "boolean",
|
|
611
|
+
title: "Set to true if this attribute is a list of space-separated tokens, each which must be valid by itself"
|
|
612
|
+
},
|
|
613
|
+
"enum": {
|
|
614
|
+
type: "array",
|
|
615
|
+
title: "Exhaustive list of values (string or regex) this attribute accepts",
|
|
616
|
+
uniqueItems: true,
|
|
617
|
+
items: {
|
|
618
|
+
anyOf: [
|
|
619
|
+
{
|
|
620
|
+
type: "string"
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
regexp: true
|
|
624
|
+
}
|
|
625
|
+
]
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
omit: {
|
|
629
|
+
type: "boolean",
|
|
630
|
+
title: "Set to true if this attribute can optionally omit its value"
|
|
631
|
+
},
|
|
632
|
+
required: {
|
|
633
|
+
type: "boolean",
|
|
634
|
+
title: "Set to true if this attribute is required"
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
type: "array",
|
|
640
|
+
uniqueItems: true,
|
|
641
|
+
items: {
|
|
594
642
|
type: "string"
|
|
595
|
-
},
|
|
596
|
-
{
|
|
597
|
-
regexp: true
|
|
598
643
|
}
|
|
599
|
-
|
|
600
|
-
|
|
644
|
+
}
|
|
645
|
+
]
|
|
601
646
|
}
|
|
602
647
|
}
|
|
603
648
|
},
|
|
@@ -648,6 +693,111 @@ var schema = {
|
|
|
648
693
|
definitions: definitions
|
|
649
694
|
};
|
|
650
695
|
|
|
696
|
+
var TextContent$1;
|
|
697
|
+
(function (TextContent) {
|
|
698
|
+
/* forbid node to have text content, inter-element whitespace is ignored */
|
|
699
|
+
TextContent["NONE"] = "none";
|
|
700
|
+
/* node can have text but not required too */
|
|
701
|
+
TextContent["DEFAULT"] = "default";
|
|
702
|
+
/* node requires text-nodes to be present (direct or by descendant) */
|
|
703
|
+
TextContent["REQUIRED"] = "required";
|
|
704
|
+
/* node requires accessible text (hidden text is ignored, tries to get text from accessibility tree) */
|
|
705
|
+
TextContent["ACCESSIBLE"] = "accessible";
|
|
706
|
+
})(TextContent$1 || (TextContent$1 = {}));
|
|
707
|
+
/**
|
|
708
|
+
* Properties listed here can be copied (loaded) onto another element using
|
|
709
|
+
* [[HtmlElement.loadMeta]].
|
|
710
|
+
*/
|
|
711
|
+
const MetaCopyableProperty = [
|
|
712
|
+
"metadata",
|
|
713
|
+
"flow",
|
|
714
|
+
"sectioning",
|
|
715
|
+
"heading",
|
|
716
|
+
"phrasing",
|
|
717
|
+
"embedded",
|
|
718
|
+
"interactive",
|
|
719
|
+
"transparent",
|
|
720
|
+
"form",
|
|
721
|
+
"labelable",
|
|
722
|
+
"attributes",
|
|
723
|
+
"permittedContent",
|
|
724
|
+
"permittedDescendants",
|
|
725
|
+
"permittedOrder",
|
|
726
|
+
"requiredAncestors",
|
|
727
|
+
"requiredContent",
|
|
728
|
+
];
|
|
729
|
+
/**
|
|
730
|
+
* @internal
|
|
731
|
+
*/
|
|
732
|
+
function setMetaProperty(dst, key, value) {
|
|
733
|
+
dst[key] = value;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function isSet(value) {
|
|
737
|
+
return typeof value !== "undefined";
|
|
738
|
+
}
|
|
739
|
+
function flag(value) {
|
|
740
|
+
return value ? true : undefined;
|
|
741
|
+
}
|
|
742
|
+
function stripUndefined(src) {
|
|
743
|
+
const entries = Object.entries(src).filter(([, value]) => isSet(value));
|
|
744
|
+
return Object.fromEntries(entries);
|
|
745
|
+
}
|
|
746
|
+
function migrateSingleAttribute(src, key) {
|
|
747
|
+
var _a, _b;
|
|
748
|
+
const result = {};
|
|
749
|
+
result.deprecated = flag((_a = src.deprecatedAttributes) === null || _a === void 0 ? void 0 : _a.includes(key));
|
|
750
|
+
result.required = flag((_b = src.requiredAttributes) === null || _b === void 0 ? void 0 : _b.includes(key));
|
|
751
|
+
result.omit = undefined;
|
|
752
|
+
const attr = src.attributes ? src.attributes[key] : undefined;
|
|
753
|
+
if (typeof attr === "undefined") {
|
|
754
|
+
return stripUndefined(result);
|
|
755
|
+
}
|
|
756
|
+
/* when the attribute is set to null we use a special property "delete" to
|
|
757
|
+
* flag it, if it is still set during merge (inheritance, overwriting, etc) the attribute will be removed */
|
|
758
|
+
if (attr === null) {
|
|
759
|
+
result.delete = true;
|
|
760
|
+
return stripUndefined(result);
|
|
761
|
+
}
|
|
762
|
+
if (Array.isArray(attr)) {
|
|
763
|
+
if (attr.length === 0) {
|
|
764
|
+
result.boolean = true;
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
result.enum = attr.filter((it) => it !== "");
|
|
768
|
+
if (attr.includes("")) {
|
|
769
|
+
result.omit = true;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return stripUndefined(result);
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
return stripUndefined({ ...result, ...attr });
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function migrateAttributes(src) {
|
|
779
|
+
var _a, _b, _c;
|
|
780
|
+
const keys = [
|
|
781
|
+
...Object.keys((_a = src.attributes) !== null && _a !== void 0 ? _a : {}),
|
|
782
|
+
...((_b = src.requiredAttributes) !== null && _b !== void 0 ? _b : []),
|
|
783
|
+
...((_c = src.deprecatedAttributes) !== null && _c !== void 0 ? _c : []),
|
|
784
|
+
].sort();
|
|
785
|
+
const entries = keys.map((key) => {
|
|
786
|
+
return [key, migrateSingleAttribute(src, key)];
|
|
787
|
+
});
|
|
788
|
+
return Object.fromEntries(entries);
|
|
789
|
+
}
|
|
790
|
+
function migrateElement(src) {
|
|
791
|
+
const result = {
|
|
792
|
+
...src,
|
|
793
|
+
attributes: migrateAttributes(src),
|
|
794
|
+
};
|
|
795
|
+
/* removed properties */
|
|
796
|
+
delete result.deprecatedAttributes;
|
|
797
|
+
delete result.requiredAttributes;
|
|
798
|
+
return result;
|
|
799
|
+
}
|
|
800
|
+
|
|
651
801
|
const dynamicKeys = [
|
|
652
802
|
"metadata",
|
|
653
803
|
"flow",
|
|
@@ -710,7 +860,7 @@ class MetaTable {
|
|
|
710
860
|
*/
|
|
711
861
|
extendValidationSchema(patch) {
|
|
712
862
|
if (patch.properties) {
|
|
713
|
-
this.schema = jsonMergePatch__default[
|
|
863
|
+
this.schema = jsonMergePatch__default["default"].apply(this.schema, {
|
|
714
864
|
patternProperties: {
|
|
715
865
|
"^[^$].*$": {
|
|
716
866
|
properties: patch.properties,
|
|
@@ -719,7 +869,7 @@ class MetaTable {
|
|
|
719
869
|
});
|
|
720
870
|
}
|
|
721
871
|
if (patch.definitions) {
|
|
722
|
-
this.schema = jsonMergePatch__default[
|
|
872
|
+
this.schema = jsonMergePatch__default["default"].apply(this.schema, {
|
|
723
873
|
definitions: patch.definitions,
|
|
724
874
|
});
|
|
725
875
|
}
|
|
@@ -741,7 +891,7 @@ class MetaTable {
|
|
|
741
891
|
for (const [key, value] of Object.entries(obj)) {
|
|
742
892
|
if (key === "$schema")
|
|
743
893
|
continue;
|
|
744
|
-
this.addEntry(key, value);
|
|
894
|
+
this.addEntry(key, migrateElement(value));
|
|
745
895
|
}
|
|
746
896
|
}
|
|
747
897
|
/**
|
|
@@ -769,7 +919,7 @@ class MetaTable {
|
|
|
769
919
|
*/
|
|
770
920
|
getMetaFor(tagName) {
|
|
771
921
|
tagName = tagName.toLowerCase();
|
|
772
|
-
return this.elements[tagName] ?
|
|
922
|
+
return this.elements[tagName] ? { ...this.elements[tagName] } : null;
|
|
773
923
|
}
|
|
774
924
|
/**
|
|
775
925
|
* Find all tags which has enabled given property.
|
|
@@ -798,7 +948,7 @@ class MetaTable {
|
|
|
798
948
|
}
|
|
799
949
|
}
|
|
800
950
|
/* merge all sources together */
|
|
801
|
-
const expanded =
|
|
951
|
+
const expanded = this.mergeElement(parent, { ...entry, tagName });
|
|
802
952
|
expandRegex(expanded);
|
|
803
953
|
this.elements[tagName] = expanded;
|
|
804
954
|
}
|
|
@@ -806,7 +956,7 @@ class MetaTable {
|
|
|
806
956
|
* Construct a new AJV schema validator.
|
|
807
957
|
*/
|
|
808
958
|
getSchemaValidator() {
|
|
809
|
-
const ajv = new Ajv__default[
|
|
959
|
+
const ajv = new Ajv__default["default"]({ strict: true, strictTuples: true, strictTypes: true });
|
|
810
960
|
ajv.addMetaSchema(ajvSchemaDraft);
|
|
811
961
|
ajv.addKeyword(ajvRegexpKeyword);
|
|
812
962
|
ajv.addKeyword({ keyword: "copyable" });
|
|
@@ -836,7 +986,16 @@ class MetaTable {
|
|
|
836
986
|
}
|
|
837
987
|
}
|
|
838
988
|
mergeElement(a, b) {
|
|
839
|
-
|
|
989
|
+
const merged = deepmerge__default["default"](a, b, { arrayMerge: overwriteMerge$1 });
|
|
990
|
+
/* special handling when removing attributes by setting them to null
|
|
991
|
+
* resulting in the deletion flag being set */
|
|
992
|
+
const filteredAttrs = Object.entries(merged.attributes).filter(([, attr]) => {
|
|
993
|
+
const val = !attr.delete;
|
|
994
|
+
delete attr.delete;
|
|
995
|
+
return val;
|
|
996
|
+
});
|
|
997
|
+
merged.attributes = Object.fromEntries(filteredAttrs);
|
|
998
|
+
return merged;
|
|
840
999
|
}
|
|
841
1000
|
resolve(node) {
|
|
842
1001
|
if (node.meta) {
|
|
@@ -848,7 +1007,7 @@ function expandProperties(node, entry) {
|
|
|
848
1007
|
for (const key of dynamicKeys) {
|
|
849
1008
|
const property = entry[key];
|
|
850
1009
|
if (property && typeof property !== "boolean") {
|
|
851
|
-
entry
|
|
1010
|
+
setMetaProperty(entry, key, evaluateProperty(node, property));
|
|
852
1011
|
}
|
|
853
1012
|
}
|
|
854
1013
|
}
|
|
@@ -874,14 +1033,9 @@ function expandRegexValue(value) {
|
|
|
874
1033
|
* Expand all regular expressions in strings ("/../"). This mutates the object.
|
|
875
1034
|
*/
|
|
876
1035
|
function expandRegex(entry) {
|
|
877
|
-
if (!entry.attributes)
|
|
878
|
-
return;
|
|
879
1036
|
for (const [name, values] of Object.entries(entry.attributes)) {
|
|
880
|
-
if (values) {
|
|
881
|
-
entry.attributes[name] = values.map(expandRegexValue);
|
|
882
|
-
}
|
|
883
|
-
else {
|
|
884
|
-
delete entry.attributes[name];
|
|
1037
|
+
if (values.enum) {
|
|
1038
|
+
entry.attributes[name].enum = values.enum.map(expandRegexValue);
|
|
885
1039
|
}
|
|
886
1040
|
}
|
|
887
1041
|
}
|
|
@@ -937,41 +1091,6 @@ function matchAttribute(node, match) {
|
|
|
937
1091
|
}
|
|
938
1092
|
}
|
|
939
1093
|
|
|
940
|
-
var TextContent$1;
|
|
941
|
-
(function (TextContent) {
|
|
942
|
-
/* forbid node to have text content, inter-element whitespace is ignored */
|
|
943
|
-
TextContent["NONE"] = "none";
|
|
944
|
-
/* node can have text but not required too */
|
|
945
|
-
TextContent["DEFAULT"] = "default";
|
|
946
|
-
/* node requires text-nodes to be present (direct or by descendant) */
|
|
947
|
-
TextContent["REQUIRED"] = "required";
|
|
948
|
-
/* node requires accessible text (hidden text is ignored, tries to get text from accessibility tree) */
|
|
949
|
-
TextContent["ACCESSIBLE"] = "accessible";
|
|
950
|
-
})(TextContent$1 || (TextContent$1 = {}));
|
|
951
|
-
/**
|
|
952
|
-
* Properties listed here can be copied (loaded) onto another element using
|
|
953
|
-
* [[HtmlElement.loadMeta]].
|
|
954
|
-
*/
|
|
955
|
-
const MetaCopyableProperty = [
|
|
956
|
-
"metadata",
|
|
957
|
-
"flow",
|
|
958
|
-
"sectioning",
|
|
959
|
-
"heading",
|
|
960
|
-
"phrasing",
|
|
961
|
-
"embedded",
|
|
962
|
-
"interactive",
|
|
963
|
-
"transparent",
|
|
964
|
-
"form",
|
|
965
|
-
"labelable",
|
|
966
|
-
"requiredAttributes",
|
|
967
|
-
"attributes",
|
|
968
|
-
"permittedContent",
|
|
969
|
-
"permittedDescendants",
|
|
970
|
-
"permittedOrder",
|
|
971
|
-
"requiredAncestors",
|
|
972
|
-
"requiredContent",
|
|
973
|
-
];
|
|
974
|
-
|
|
975
1094
|
class DynamicValue {
|
|
976
1095
|
constructor(expr) {
|
|
977
1096
|
this.expr = expr;
|
|
@@ -1823,8 +1942,9 @@ class HtmlElement extends DOMNode {
|
|
|
1823
1942
|
this.metaElement = {};
|
|
1824
1943
|
}
|
|
1825
1944
|
for (const key of MetaCopyableProperty) {
|
|
1826
|
-
|
|
1827
|
-
|
|
1945
|
+
const value = meta[key];
|
|
1946
|
+
if (typeof value !== "undefined") {
|
|
1947
|
+
setMetaProperty(this.metaElement, key, value);
|
|
1828
1948
|
}
|
|
1829
1949
|
else {
|
|
1830
1950
|
delete this.metaElement[key];
|
|
@@ -2240,6 +2360,7 @@ class Validator {
|
|
|
2240
2360
|
* @param rules - Element attribute metadta.
|
|
2241
2361
|
* @returns `true` if attribute passes all tests.
|
|
2242
2362
|
*/
|
|
2363
|
+
/* eslint-disable-next-line complexity */
|
|
2243
2364
|
static validateAttribute(attr, rules) {
|
|
2244
2365
|
const rule = rules[attr.key];
|
|
2245
2366
|
if (!rule) {
|
|
@@ -2253,19 +2374,34 @@ class Validator {
|
|
|
2253
2374
|
return true;
|
|
2254
2375
|
}
|
|
2255
2376
|
const empty = value === null || value === "";
|
|
2256
|
-
/*
|
|
2257
|
-
|
|
2377
|
+
/* if boolean is set the value can be either null, empty string or the
|
|
2378
|
+
* attribute key (attribute-boolean-style regulates style) */
|
|
2379
|
+
if (rule.boolean) {
|
|
2258
2380
|
return empty || value === attr.key;
|
|
2259
2381
|
}
|
|
2260
|
-
/* if the
|
|
2261
|
-
* (
|
|
2262
|
-
if (rule.
|
|
2382
|
+
/* if omit is set the value can be either null or empty string
|
|
2383
|
+
* (attribute-empty style regulates style) */
|
|
2384
|
+
if (rule.omit && empty) {
|
|
2385
|
+
return true;
|
|
2386
|
+
}
|
|
2387
|
+
/* validate each token when using list, all tokens must be valid */
|
|
2388
|
+
if (rule.list) {
|
|
2389
|
+
const tokens = new DOMTokenList(value, attr.valueLocation);
|
|
2390
|
+
return tokens.every((token) => {
|
|
2391
|
+
return this.validateAttributeValue(token, rule);
|
|
2392
|
+
});
|
|
2393
|
+
}
|
|
2394
|
+
return this.validateAttributeValue(value, rule);
|
|
2395
|
+
}
|
|
2396
|
+
static validateAttributeValue(value, rule) {
|
|
2397
|
+
/* skip attribute if it not have enumerated list */
|
|
2398
|
+
if (!rule.enum) {
|
|
2263
2399
|
return true;
|
|
2264
2400
|
}
|
|
2265
2401
|
if (value === null || value === undefined) {
|
|
2266
2402
|
return false;
|
|
2267
2403
|
}
|
|
2268
|
-
return rule.some((entry) => {
|
|
2404
|
+
return rule.enum.some((entry) => {
|
|
2269
2405
|
if (entry instanceof RegExp) {
|
|
2270
2406
|
return !!value.match(entry);
|
|
2271
2407
|
}
|
|
@@ -2531,12 +2667,12 @@ var configurationSchema = {
|
|
|
2531
2667
|
const espree = legacyRequire("espree");
|
|
2532
2668
|
const walk = legacyRequire("acorn-walk");
|
|
2533
2669
|
function joinTemplateLiteral(nodes) {
|
|
2534
|
-
let offset = nodes[0].start;
|
|
2670
|
+
let offset = nodes[0].start + 1;
|
|
2535
2671
|
let output = "";
|
|
2536
2672
|
for (const node of nodes) {
|
|
2537
|
-
output += " ".repeat(node.start - offset);
|
|
2673
|
+
output += " ".repeat(node.start + 1 - offset);
|
|
2538
2674
|
output += node.value.raw;
|
|
2539
|
-
offset = node.end;
|
|
2675
|
+
offset = node.end - 2;
|
|
2540
2676
|
}
|
|
2541
2677
|
return output;
|
|
2542
2678
|
}
|
|
@@ -2641,7 +2777,7 @@ class TemplateExtractor {
|
|
|
2641
2777
|
this.data = data;
|
|
2642
2778
|
}
|
|
2643
2779
|
static fromFilename(filename) {
|
|
2644
|
-
const source = fs__default[
|
|
2780
|
+
const source = fs__default["default"].readFileSync(filename, "utf-8");
|
|
2645
2781
|
const ast = espree.parse(source, {
|
|
2646
2782
|
ecmaVersion: 2017,
|
|
2647
2783
|
sourceType: "module",
|
|
@@ -2677,7 +2813,7 @@ class TemplateExtractor {
|
|
|
2677
2813
|
* functions.
|
|
2678
2814
|
*/
|
|
2679
2815
|
static createSource(filename) {
|
|
2680
|
-
const data = fs__default[
|
|
2816
|
+
const data = fs__default["default"].readFileSync(filename, "utf-8");
|
|
2681
2817
|
return [
|
|
2682
2818
|
{
|
|
2683
2819
|
column: 1,
|
|
@@ -2728,7 +2864,7 @@ var TRANSFORMER_API;
|
|
|
2728
2864
|
})(TRANSFORMER_API || (TRANSFORMER_API = {}));
|
|
2729
2865
|
|
|
2730
2866
|
const name = "html-validate";
|
|
2731
|
-
const version = "
|
|
2867
|
+
const version = "6.1.0";
|
|
2732
2868
|
const homepage = "https://html-validate.org";
|
|
2733
2869
|
const bugs = {
|
|
2734
2870
|
url: "https://gitlab.com/html-validate/html-validate/issues/new"
|
|
@@ -2765,7 +2901,7 @@ const remapEvents = {
|
|
|
2765
2901
|
"tag:open": "tag:start",
|
|
2766
2902
|
"tag:close": "tag:end",
|
|
2767
2903
|
};
|
|
2768
|
-
const ajv$1 = new Ajv__default[
|
|
2904
|
+
const ajv$1 = new Ajv__default["default"]({ strict: true, strictTuples: true, strictTypes: true });
|
|
2769
2905
|
ajv$1.addMetaSchema(ajvSchemaDraft);
|
|
2770
2906
|
/**
|
|
2771
2907
|
* Get (cached) schema validator for rule options.
|
|
@@ -2993,9 +3129,9 @@ function ruleDocumentationUrl(filename) {
|
|
|
2993
3129
|
* folder and with the @/ prefix, by replacing the @ with the dist folder we
|
|
2994
3130
|
* can resolve the path properly */
|
|
2995
3131
|
filename = filename.replace("@", distFolder);
|
|
2996
|
-
const p = path__default[
|
|
2997
|
-
const root = path__default[
|
|
2998
|
-
const rel = path__default[
|
|
3132
|
+
const p = path__default["default"].parse(filename);
|
|
3133
|
+
const root = path__default["default"].join(distFolder, "rules");
|
|
3134
|
+
const rel = path__default["default"].relative(root, path__default["default"].join(p.dir, p.name));
|
|
2999
3135
|
return `${homepage}/rules/${rel}.html`;
|
|
3000
3136
|
}
|
|
3001
3137
|
|
|
@@ -3018,24 +3154,60 @@ const description = {
|
|
|
3018
3154
|
["absolute" /* ABSOLUTE */]: "Absolute links are not allowed by current configuration.",
|
|
3019
3155
|
["anchor" /* ANCHOR */]: null,
|
|
3020
3156
|
};
|
|
3157
|
+
function parseAllow(value) {
|
|
3158
|
+
if (typeof value === "boolean") {
|
|
3159
|
+
return value;
|
|
3160
|
+
}
|
|
3161
|
+
return {
|
|
3162
|
+
/* eslint-disable security/detect-non-literal-regexp */
|
|
3163
|
+
include: value.include ? value.include.map((it) => new RegExp(it)) : null,
|
|
3164
|
+
exclude: value.exclude ? value.exclude.map((it) => new RegExp(it)) : null,
|
|
3165
|
+
/* eslint-enable security/detect-non-literal-regexp */
|
|
3166
|
+
};
|
|
3167
|
+
}
|
|
3168
|
+
/**
|
|
3169
|
+
* @internal
|
|
3170
|
+
*/
|
|
3171
|
+
function matchList(value, list) {
|
|
3172
|
+
if (list.include && !list.include.some((it) => it.test(value))) {
|
|
3173
|
+
return false;
|
|
3174
|
+
}
|
|
3175
|
+
if (list.exclude && list.exclude.some((it) => it.test(value))) {
|
|
3176
|
+
return false;
|
|
3177
|
+
}
|
|
3178
|
+
return true;
|
|
3179
|
+
}
|
|
3021
3180
|
class AllowedLinks extends Rule {
|
|
3022
3181
|
constructor(options) {
|
|
3023
|
-
super(
|
|
3182
|
+
super({ ...defaults$p, ...options });
|
|
3183
|
+
this.allowExternal = parseAllow(this.options.allowExternal);
|
|
3184
|
+
this.allowRelative = parseAllow(this.options.allowRelative);
|
|
3185
|
+
this.allowAbsolute = parseAllow(this.options.allowAbsolute);
|
|
3024
3186
|
}
|
|
3025
3187
|
static schema() {
|
|
3188
|
+
const booleanOrObject = {
|
|
3189
|
+
anyOf: [
|
|
3190
|
+
{ type: "boolean" },
|
|
3191
|
+
{
|
|
3192
|
+
type: "object",
|
|
3193
|
+
properties: {
|
|
3194
|
+
include: {
|
|
3195
|
+
type: "array",
|
|
3196
|
+
items: { type: "string" },
|
|
3197
|
+
},
|
|
3198
|
+
exclude: {
|
|
3199
|
+
type: "array",
|
|
3200
|
+
items: { type: "string" },
|
|
3201
|
+
},
|
|
3202
|
+
},
|
|
3203
|
+
},
|
|
3204
|
+
],
|
|
3205
|
+
};
|
|
3026
3206
|
return {
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
},
|
|
3030
|
-
allowBase: {
|
|
3031
|
-
type: "boolean",
|
|
3032
|
-
},
|
|
3033
|
-
allowExternal: {
|
|
3034
|
-
type: "boolean",
|
|
3035
|
-
},
|
|
3036
|
-
allowRelative: {
|
|
3037
|
-
type: "boolean",
|
|
3038
|
-
},
|
|
3207
|
+
allowExternal: { ...booleanOrObject },
|
|
3208
|
+
allowRelative: { ...booleanOrObject },
|
|
3209
|
+
allowAbsolute: { ...booleanOrObject },
|
|
3210
|
+
allowBase: { type: "boolean" },
|
|
3039
3211
|
};
|
|
3040
3212
|
}
|
|
3041
3213
|
documentation(context) {
|
|
@@ -3057,16 +3229,16 @@ class AllowedLinks extends Rule {
|
|
|
3057
3229
|
/* anchor links are always allowed by this rule */
|
|
3058
3230
|
break;
|
|
3059
3231
|
case "absolute" /* ABSOLUTE */:
|
|
3060
|
-
this.handleAbsolute(event, style);
|
|
3232
|
+
this.handleAbsolute(link, event, style);
|
|
3061
3233
|
break;
|
|
3062
3234
|
case "external" /* EXTERNAL */:
|
|
3063
|
-
this.handleExternal(event, style);
|
|
3235
|
+
this.handleExternal(link, event, style);
|
|
3064
3236
|
break;
|
|
3065
3237
|
case "relative-base" /* RELATIVE_BASE */:
|
|
3066
|
-
this.handleRelativeBase(event, style);
|
|
3238
|
+
this.handleRelativeBase(link, event, style);
|
|
3067
3239
|
break;
|
|
3068
3240
|
case "relative-path" /* RELATIVE_PATH */:
|
|
3069
|
-
this.handleRelativePath(event, style);
|
|
3241
|
+
this.handleRelativePath(link, event, style);
|
|
3070
3242
|
break;
|
|
3071
3243
|
}
|
|
3072
3244
|
});
|
|
@@ -3100,28 +3272,49 @@ class AllowedLinks extends Rule {
|
|
|
3100
3272
|
return "relative-base" /* RELATIVE_BASE */;
|
|
3101
3273
|
}
|
|
3102
3274
|
}
|
|
3103
|
-
handleAbsolute(event, style) {
|
|
3104
|
-
const { allowAbsolute } = this
|
|
3105
|
-
if (
|
|
3275
|
+
handleAbsolute(target, event, style) {
|
|
3276
|
+
const { allowAbsolute } = this;
|
|
3277
|
+
if (allowAbsolute === true) {
|
|
3278
|
+
return;
|
|
3279
|
+
}
|
|
3280
|
+
else if (allowAbsolute === false) {
|
|
3106
3281
|
this.report(event.target, "Link destination must not be absolute url", event.valueLocation, style);
|
|
3107
3282
|
}
|
|
3283
|
+
else if (!matchList(target, allowAbsolute)) {
|
|
3284
|
+
this.report(event.target, "Absolute link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3285
|
+
}
|
|
3108
3286
|
}
|
|
3109
|
-
handleExternal(event, style) {
|
|
3110
|
-
const { allowExternal } = this
|
|
3111
|
-
if (
|
|
3287
|
+
handleExternal(target, event, style) {
|
|
3288
|
+
const { allowExternal } = this;
|
|
3289
|
+
if (allowExternal === true) {
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3292
|
+
else if (allowExternal === false) {
|
|
3112
3293
|
this.report(event.target, "Link destination must not be external url", event.valueLocation, style);
|
|
3113
3294
|
}
|
|
3295
|
+
else if (!matchList(target, allowExternal)) {
|
|
3296
|
+
this.report(event.target, "External link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3297
|
+
}
|
|
3114
3298
|
}
|
|
3115
|
-
handleRelativePath(event, style) {
|
|
3116
|
-
const { allowRelative } = this
|
|
3117
|
-
if (
|
|
3299
|
+
handleRelativePath(target, event, style) {
|
|
3300
|
+
const { allowRelative } = this;
|
|
3301
|
+
if (allowRelative === true) {
|
|
3302
|
+
return false;
|
|
3303
|
+
}
|
|
3304
|
+
else if (allowRelative === false) {
|
|
3118
3305
|
this.report(event.target, "Link destination must not be relative url", event.valueLocation, style);
|
|
3306
|
+
return true;
|
|
3307
|
+
}
|
|
3308
|
+
else if (!matchList(target, allowRelative)) {
|
|
3309
|
+
this.report(event.target, "Relative link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3310
|
+
return true;
|
|
3119
3311
|
}
|
|
3312
|
+
return false;
|
|
3120
3313
|
}
|
|
3121
|
-
handleRelativeBase(event, style) {
|
|
3122
|
-
const {
|
|
3123
|
-
if (
|
|
3124
|
-
|
|
3314
|
+
handleRelativeBase(target, event, style) {
|
|
3315
|
+
const { allowBase } = this.options;
|
|
3316
|
+
if (this.handleRelativePath(target, event, style)) {
|
|
3317
|
+
return;
|
|
3125
3318
|
}
|
|
3126
3319
|
else if (!allowBase) {
|
|
3127
3320
|
this.report(event.target, "Relative links must be relative to current folder", event.valueLocation, style);
|
|
@@ -3268,7 +3461,7 @@ const defaults$o = {
|
|
|
3268
3461
|
};
|
|
3269
3462
|
class AttrCase extends Rule {
|
|
3270
3463
|
constructor(options) {
|
|
3271
|
-
super(
|
|
3464
|
+
super({ ...defaults$o, ...options });
|
|
3272
3465
|
this.style = new CaseStyle(this.options.style, "attr-case");
|
|
3273
3466
|
}
|
|
3274
3467
|
static schema() {
|
|
@@ -3358,7 +3551,7 @@ const MATCH_XML_TAG = /^<\?xml.*?\?>\s+/;
|
|
|
3358
3551
|
const MATCH_TAG_OPEN = /^<(\/?)([a-zA-Z0-9\-:]+)/; // https://www.w3.org/TR/html/syntax.html#start-tags
|
|
3359
3552
|
const MATCH_TAG_CLOSE = /^\/?>/;
|
|
3360
3553
|
const MATCH_TEXT = /^[^]*?(?=(?:[ \t]*(?:\r\n|\r|\n)|<[^ ]|$))/;
|
|
3361
|
-
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)
|
|
3554
|
+
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)/s;
|
|
3362
3555
|
const MATCH_TAG_LOOKAHEAD = /^[^]*?(?=<|$)/;
|
|
3363
3556
|
const MATCH_ATTR_START = /^([^\t\r\n\f \/><"'=]+)/; // https://www.w3.org/TR/html/syntax.html#elements-attributes
|
|
3364
3557
|
const MATCH_ATTR_SINGLE = /^(\s*=\s*)'([^']*?)(')/;
|
|
@@ -3621,7 +3814,7 @@ function generateDescription(name, pattern) {
|
|
|
3621
3814
|
}
|
|
3622
3815
|
class AttrPattern extends Rule {
|
|
3623
3816
|
constructor(options) {
|
|
3624
|
-
super(
|
|
3817
|
+
super({ ...defaults$n, ...options });
|
|
3625
3818
|
this.pattern = generateRegexp(this.options.pattern);
|
|
3626
3819
|
}
|
|
3627
3820
|
static schema() {
|
|
@@ -3687,7 +3880,7 @@ const defaults$m = {
|
|
|
3687
3880
|
};
|
|
3688
3881
|
class AttrQuotes extends Rule {
|
|
3689
3882
|
constructor(options) {
|
|
3690
|
-
super(
|
|
3883
|
+
super({ ...defaults$m, ...options });
|
|
3691
3884
|
this.style = parseStyle$4(this.options.style);
|
|
3692
3885
|
}
|
|
3693
3886
|
static schema() {
|
|
@@ -3783,11 +3976,11 @@ class AttributeAllowedValues extends Rule {
|
|
|
3783
3976
|
if (!context) {
|
|
3784
3977
|
return docs;
|
|
3785
3978
|
}
|
|
3786
|
-
if (context.allowed.
|
|
3787
|
-
const allowed = context.allowed.map((val) => `- \`${val}\``);
|
|
3979
|
+
if (context.allowed.enum) {
|
|
3980
|
+
const allowed = context.allowed.enum.map((val) => `- \`${val}\``);
|
|
3788
3981
|
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")}`;
|
|
3789
3982
|
}
|
|
3790
|
-
else {
|
|
3983
|
+
else if (context.allowed.boolean) {
|
|
3791
3984
|
docs.description = `Element <${context.element}> attribute \`${context.attribute}\` must be a boolean attribute, e.g. \`<${context.element} ${context.attribute}>\``;
|
|
3792
3985
|
}
|
|
3793
3986
|
return docs;
|
|
@@ -3843,7 +4036,7 @@ const defaults$l = {
|
|
|
3843
4036
|
};
|
|
3844
4037
|
class AttributeBooleanStyle extends Rule {
|
|
3845
4038
|
constructor(options) {
|
|
3846
|
-
super(
|
|
4039
|
+
super({ ...defaults$l, ...options });
|
|
3847
4040
|
this.hasInvalidStyle = parseStyle$3(this.options.style);
|
|
3848
4041
|
}
|
|
3849
4042
|
static schema() {
|
|
@@ -3888,7 +4081,8 @@ class AttributeBooleanStyle extends Rule {
|
|
|
3888
4081
|
});
|
|
3889
4082
|
}
|
|
3890
4083
|
isBoolean(attr, rules) {
|
|
3891
|
-
|
|
4084
|
+
var _a;
|
|
4085
|
+
return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.boolean);
|
|
3892
4086
|
}
|
|
3893
4087
|
}
|
|
3894
4088
|
function parseStyle$3(style) {
|
|
@@ -3923,7 +4117,7 @@ const defaults$k = {
|
|
|
3923
4117
|
};
|
|
3924
4118
|
class AttributeEmptyStyle extends Rule {
|
|
3925
4119
|
constructor(options) {
|
|
3926
|
-
super(
|
|
4120
|
+
super({ ...defaults$k, ...options });
|
|
3927
4121
|
this.hasInvalidStyle = parseStyle$2(this.options.style);
|
|
3928
4122
|
}
|
|
3929
4123
|
static schema() {
|
|
@@ -3972,7 +4166,8 @@ class AttributeEmptyStyle extends Rule {
|
|
|
3972
4166
|
}
|
|
3973
4167
|
}
|
|
3974
4168
|
function allowsEmpty(attr, rules) {
|
|
3975
|
-
|
|
4169
|
+
var _a;
|
|
4170
|
+
return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.omit);
|
|
3976
4171
|
}
|
|
3977
4172
|
function isEmptyValue(attr) {
|
|
3978
4173
|
/* dynamic values are ignored, assumed to contain a value */
|
|
@@ -4035,7 +4230,7 @@ const defaults$j = {
|
|
|
4035
4230
|
};
|
|
4036
4231
|
class ClassPattern extends Rule {
|
|
4037
4232
|
constructor(options) {
|
|
4038
|
-
super(
|
|
4233
|
+
super({ ...defaults$j, ...options });
|
|
4039
4234
|
this.pattern = parsePattern(this.options.pattern);
|
|
4040
4235
|
}
|
|
4041
4236
|
static schema() {
|
|
@@ -4148,7 +4343,7 @@ const defaults$i = {
|
|
|
4148
4343
|
};
|
|
4149
4344
|
class Deprecated extends Rule {
|
|
4150
4345
|
constructor(options) {
|
|
4151
|
-
super(
|
|
4346
|
+
super({ ...defaults$i, ...options });
|
|
4152
4347
|
}
|
|
4153
4348
|
static schema() {
|
|
4154
4349
|
return {
|
|
@@ -4242,7 +4437,7 @@ class Deprecated extends Rule {
|
|
|
4242
4437
|
this.report(node, message, location, context);
|
|
4243
4438
|
}
|
|
4244
4439
|
reportObject(deprecated, node, location) {
|
|
4245
|
-
const context =
|
|
4440
|
+
const context = { ...deprecated, tagName: node.tagName };
|
|
4246
4441
|
const notice = deprecated.message ? `: ${deprecated.message}` : "";
|
|
4247
4442
|
const message = `<${node.tagName}> is deprecated${notice}`;
|
|
4248
4443
|
this.report(node, message, location, context);
|
|
@@ -4316,7 +4511,7 @@ const defaults$h = {
|
|
|
4316
4511
|
};
|
|
4317
4512
|
class DoctypeStyle extends Rule {
|
|
4318
4513
|
constructor(options) {
|
|
4319
|
-
super(
|
|
4514
|
+
super({ ...defaults$h, ...options });
|
|
4320
4515
|
}
|
|
4321
4516
|
static schema() {
|
|
4322
4517
|
return {
|
|
@@ -4353,7 +4548,7 @@ const defaults$g = {
|
|
|
4353
4548
|
};
|
|
4354
4549
|
class ElementCase extends Rule {
|
|
4355
4550
|
constructor(options) {
|
|
4356
|
-
super(
|
|
4551
|
+
super({ ...defaults$g, ...options });
|
|
4357
4552
|
this.style = new CaseStyle(this.options.style, "element-case");
|
|
4358
4553
|
}
|
|
4359
4554
|
static schema() {
|
|
@@ -4423,7 +4618,7 @@ const defaults$f = {
|
|
|
4423
4618
|
};
|
|
4424
4619
|
class ElementName extends Rule {
|
|
4425
4620
|
constructor(options) {
|
|
4426
|
-
super(
|
|
4621
|
+
super({ ...defaults$f, ...options });
|
|
4427
4622
|
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
4428
4623
|
this.pattern = new RegExp(this.options.pattern);
|
|
4429
4624
|
}
|
|
@@ -4695,9 +4890,14 @@ class ElementRequiredAttributes extends Rule {
|
|
|
4695
4890
|
this.on("tag:end", (event) => {
|
|
4696
4891
|
const node = event.previous;
|
|
4697
4892
|
const meta = node.meta;
|
|
4698
|
-
|
|
4893
|
+
/* handle missing metadata and missing attributes */
|
|
4894
|
+
if (!meta || !meta.attributes) {
|
|
4699
4895
|
return;
|
|
4700
|
-
|
|
4896
|
+
}
|
|
4897
|
+
for (const [key, attr] of Object.entries(meta.attributes)) {
|
|
4898
|
+
if (!attr.required) {
|
|
4899
|
+
continue;
|
|
4900
|
+
}
|
|
4701
4901
|
if (node.hasAttribute(key))
|
|
4702
4902
|
continue;
|
|
4703
4903
|
const context = {
|
|
@@ -4880,7 +5080,7 @@ function parseMaxInitial(value) {
|
|
|
4880
5080
|
}
|
|
4881
5081
|
class HeadingLevel extends Rule {
|
|
4882
5082
|
constructor(options) {
|
|
4883
|
-
super(
|
|
5083
|
+
super({ ...defaults$e, ...options });
|
|
4884
5084
|
this.stack = [];
|
|
4885
5085
|
this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
|
|
4886
5086
|
this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
|
|
@@ -5043,7 +5243,7 @@ const defaults$d = {
|
|
|
5043
5243
|
};
|
|
5044
5244
|
class IdPattern extends Rule {
|
|
5045
5245
|
constructor(options) {
|
|
5046
|
-
super(
|
|
5246
|
+
super({ ...defaults$d, ...options });
|
|
5047
5247
|
this.pattern = parsePattern(this.options.pattern);
|
|
5048
5248
|
}
|
|
5049
5249
|
static schema() {
|
|
@@ -5395,7 +5595,7 @@ const defaults$c = {
|
|
|
5395
5595
|
};
|
|
5396
5596
|
class LongTitle extends Rule {
|
|
5397
5597
|
constructor(options) {
|
|
5398
|
-
super(
|
|
5598
|
+
super({ ...defaults$c, ...options });
|
|
5399
5599
|
this.maxlength = this.options.maxlength;
|
|
5400
5600
|
}
|
|
5401
5601
|
static schema() {
|
|
@@ -5548,7 +5748,7 @@ const defaults$b = {
|
|
|
5548
5748
|
};
|
|
5549
5749
|
class NoAutoplay extends Rule {
|
|
5550
5750
|
constructor(options) {
|
|
5551
|
-
super(
|
|
5751
|
+
super({ ...defaults$b, ...options });
|
|
5552
5752
|
}
|
|
5553
5753
|
documentation(context) {
|
|
5554
5754
|
const tagName = context ? ` on <${context.tagName}>` : "";
|
|
@@ -5644,8 +5844,12 @@ class NoDeprecatedAttr extends Rule {
|
|
|
5644
5844
|
if (meta === null) {
|
|
5645
5845
|
return;
|
|
5646
5846
|
}
|
|
5647
|
-
const
|
|
5648
|
-
if (
|
|
5847
|
+
const metaAttribute = meta.attributes && meta.attributes[attr];
|
|
5848
|
+
if (!metaAttribute) {
|
|
5849
|
+
return;
|
|
5850
|
+
}
|
|
5851
|
+
const deprecated = metaAttribute.deprecated;
|
|
5852
|
+
if (deprecated) {
|
|
5649
5853
|
this.report(node, `Attribute "${event.key}" is deprecated on <${node.tagName}> element`, event.keyLocation);
|
|
5650
5854
|
}
|
|
5651
5855
|
});
|
|
@@ -5802,7 +6006,7 @@ function getCSSDeclarations(value) {
|
|
|
5802
6006
|
}
|
|
5803
6007
|
class NoInlineStyle extends Rule {
|
|
5804
6008
|
constructor(options) {
|
|
5805
|
-
super(
|
|
6009
|
+
super({ ...defaults$a, ...options });
|
|
5806
6010
|
}
|
|
5807
6011
|
static schema() {
|
|
5808
6012
|
return {
|
|
@@ -6012,7 +6216,7 @@ const defaults$9 = {
|
|
|
6012
6216
|
};
|
|
6013
6217
|
const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6014
6218
|
const unquotedAttrRegexp = /([<>"'=`]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6015
|
-
const matchTemplate = /^(<%.*?%>|<\?.*?\?>|<\$.*?\$>)
|
|
6219
|
+
const matchTemplate = /^(<%.*?%>|<\?.*?\?>|<\$.*?\$>)$/s;
|
|
6016
6220
|
const replacementTable = new Map([
|
|
6017
6221
|
['"', """],
|
|
6018
6222
|
["&", "&"],
|
|
@@ -6024,7 +6228,7 @@ const replacementTable = new Map([
|
|
|
6024
6228
|
]);
|
|
6025
6229
|
class NoRawCharacters extends Rule {
|
|
6026
6230
|
constructor(options) {
|
|
6027
|
-
super(
|
|
6231
|
+
super({ ...defaults$9, ...options });
|
|
6028
6232
|
this.relaxed = this.options.relaxed;
|
|
6029
6233
|
}
|
|
6030
6234
|
static schema() {
|
|
@@ -6209,7 +6413,7 @@ const defaults$8 = {
|
|
|
6209
6413
|
};
|
|
6210
6414
|
class NoSelfClosing extends Rule {
|
|
6211
6415
|
constructor(options) {
|
|
6212
|
-
super(
|
|
6416
|
+
super({ ...defaults$8, ...options });
|
|
6213
6417
|
}
|
|
6214
6418
|
static schema() {
|
|
6215
6419
|
return {
|
|
@@ -6348,7 +6552,7 @@ const defaults$7 = {
|
|
|
6348
6552
|
};
|
|
6349
6553
|
class PreferButton extends Rule {
|
|
6350
6554
|
constructor(options) {
|
|
6351
|
-
super(
|
|
6555
|
+
super({ ...defaults$7, ...options });
|
|
6352
6556
|
}
|
|
6353
6557
|
static schema() {
|
|
6354
6558
|
return {
|
|
@@ -6453,7 +6657,7 @@ const defaults$6 = {
|
|
|
6453
6657
|
};
|
|
6454
6658
|
class PreferNativeElement extends Rule {
|
|
6455
6659
|
constructor(options) {
|
|
6456
|
-
super(
|
|
6660
|
+
super({ ...defaults$6, ...options });
|
|
6457
6661
|
}
|
|
6458
6662
|
static schema() {
|
|
6459
6663
|
return {
|
|
@@ -6583,7 +6787,7 @@ const supportSri = {
|
|
|
6583
6787
|
};
|
|
6584
6788
|
class RequireSri extends Rule {
|
|
6585
6789
|
constructor(options) {
|
|
6586
|
-
super(
|
|
6790
|
+
super({ ...defaults$5, ...options });
|
|
6587
6791
|
this.target = this.options.target;
|
|
6588
6792
|
}
|
|
6589
6793
|
static schema() {
|
|
@@ -8678,7 +8882,7 @@ const defaults$4 = {
|
|
|
8678
8882
|
};
|
|
8679
8883
|
class Void extends Rule {
|
|
8680
8884
|
constructor(options) {
|
|
8681
|
-
super(
|
|
8885
|
+
super({ ...defaults$4, ...options });
|
|
8682
8886
|
this.style = parseStyle$1(this.options.style);
|
|
8683
8887
|
}
|
|
8684
8888
|
get deprecated() {
|
|
@@ -8787,7 +8991,7 @@ const defaults$3 = {
|
|
|
8787
8991
|
};
|
|
8788
8992
|
class VoidStyle extends Rule {
|
|
8789
8993
|
constructor(options) {
|
|
8790
|
-
super(
|
|
8994
|
+
super({ ...defaults$3, ...options });
|
|
8791
8995
|
this.style = parseStyle(this.options.style);
|
|
8792
8996
|
}
|
|
8793
8997
|
static schema() {
|
|
@@ -8990,7 +9194,7 @@ const defaults$2 = {
|
|
|
8990
9194
|
};
|
|
8991
9195
|
class H37 extends Rule {
|
|
8992
9196
|
constructor(options) {
|
|
8993
|
-
super(
|
|
9197
|
+
super({ ...defaults$2, ...options });
|
|
8994
9198
|
/* ensure alias is array */
|
|
8995
9199
|
if (!Array.isArray(this.options.alias)) {
|
|
8996
9200
|
this.options.alias = [this.options.alias];
|
|
@@ -9117,7 +9321,73 @@ const bundledRules$1 = {
|
|
|
9117
9321
|
"wcag/h71": H71,
|
|
9118
9322
|
};
|
|
9119
9323
|
|
|
9120
|
-
const bundledRules =
|
|
9324
|
+
const bundledRules = {
|
|
9325
|
+
"allowed-links": AllowedLinks,
|
|
9326
|
+
"aria-label-misuse": AriaLabelMisuse,
|
|
9327
|
+
"attr-case": AttrCase,
|
|
9328
|
+
"attr-delimiter": AttrDelimiter,
|
|
9329
|
+
"attr-pattern": AttrPattern,
|
|
9330
|
+
"attr-quotes": AttrQuotes,
|
|
9331
|
+
"attr-spacing": AttrSpacing,
|
|
9332
|
+
"attribute-allowed-values": AttributeAllowedValues,
|
|
9333
|
+
"attribute-boolean-style": AttributeBooleanStyle,
|
|
9334
|
+
"attribute-empty-style": AttributeEmptyStyle,
|
|
9335
|
+
"class-pattern": ClassPattern,
|
|
9336
|
+
"close-attr": CloseAttr,
|
|
9337
|
+
"close-order": CloseOrder,
|
|
9338
|
+
deprecated: Deprecated,
|
|
9339
|
+
"deprecated-rule": DeprecatedRule,
|
|
9340
|
+
"doctype-html": NoStyleTag$1,
|
|
9341
|
+
"doctype-style": DoctypeStyle,
|
|
9342
|
+
"element-case": ElementCase,
|
|
9343
|
+
"element-name": ElementName,
|
|
9344
|
+
"element-permitted-content": ElementPermittedContent,
|
|
9345
|
+
"element-permitted-occurrences": ElementPermittedOccurrences,
|
|
9346
|
+
"element-permitted-order": ElementPermittedOrder,
|
|
9347
|
+
"element-required-attributes": ElementRequiredAttributes,
|
|
9348
|
+
"element-required-content": ElementRequiredContent,
|
|
9349
|
+
"empty-heading": EmptyHeading,
|
|
9350
|
+
"empty-title": EmptyTitle,
|
|
9351
|
+
"heading-level": HeadingLevel,
|
|
9352
|
+
"id-pattern": IdPattern,
|
|
9353
|
+
"input-attributes": InputAttributes,
|
|
9354
|
+
"input-missing-label": InputMissingLabel,
|
|
9355
|
+
"long-title": LongTitle,
|
|
9356
|
+
"meta-refresh": MetaRefresh,
|
|
9357
|
+
"missing-doctype": MissingDoctype,
|
|
9358
|
+
"multiple-labeled-controls": MultipleLabeledControls,
|
|
9359
|
+
"no-autoplay": NoAutoplay,
|
|
9360
|
+
"no-conditional-comment": NoConditionalComment,
|
|
9361
|
+
"no-deprecated-attr": NoDeprecatedAttr,
|
|
9362
|
+
"no-dup-attr": NoDupAttr,
|
|
9363
|
+
"no-dup-class": NoDupClass,
|
|
9364
|
+
"no-dup-id": NoDupID,
|
|
9365
|
+
"no-implicit-close": NoImplicitClose,
|
|
9366
|
+
"no-inline-style": NoInlineStyle,
|
|
9367
|
+
"no-missing-references": NoMissingReferences,
|
|
9368
|
+
"no-multiple-main": NoMultipleMain,
|
|
9369
|
+
"no-raw-characters": NoRawCharacters,
|
|
9370
|
+
"no-redundant-for": NoRedundantFor,
|
|
9371
|
+
"no-redundant-role": NoRedundantRole,
|
|
9372
|
+
"no-self-closing": NoSelfClosing,
|
|
9373
|
+
"no-style-tag": NoStyleTag,
|
|
9374
|
+
"no-trailing-whitespace": NoTrailingWhitespace,
|
|
9375
|
+
"no-unknown-elements": NoUnknownElements,
|
|
9376
|
+
"no-utf8-bom": NoUtf8Bom,
|
|
9377
|
+
"prefer-button": PreferButton,
|
|
9378
|
+
"prefer-native-element": PreferNativeElement,
|
|
9379
|
+
"prefer-tbody": PreferTbody,
|
|
9380
|
+
"require-sri": RequireSri,
|
|
9381
|
+
"script-element": ScriptElement,
|
|
9382
|
+
"script-type": ScriptType,
|
|
9383
|
+
"svg-focusable": SvgFocusable,
|
|
9384
|
+
"text-content": TextContent,
|
|
9385
|
+
"unrecognized-char-ref": UnknownCharReference,
|
|
9386
|
+
void: Void,
|
|
9387
|
+
"void-content": VoidContent,
|
|
9388
|
+
"void-style": VoidStyle,
|
|
9389
|
+
...bundledRules$1,
|
|
9390
|
+
};
|
|
9121
9391
|
|
|
9122
9392
|
var defaultConfig = {};
|
|
9123
9393
|
|
|
@@ -9323,7 +9593,7 @@ class ResolvedConfig {
|
|
|
9323
9593
|
* @returns A list of transformed sources ready for validation.
|
|
9324
9594
|
*/
|
|
9325
9595
|
transformFilename(filename) {
|
|
9326
|
-
const data = fs__default[
|
|
9596
|
+
const data = fs__default["default"].readFileSync(filename, { encoding: "utf8" });
|
|
9327
9597
|
const source = {
|
|
9328
9598
|
data,
|
|
9329
9599
|
filename,
|
|
@@ -9348,19 +9618,19 @@ class ResolvedConfig {
|
|
|
9348
9618
|
}
|
|
9349
9619
|
|
|
9350
9620
|
let rootDirCache = null;
|
|
9351
|
-
const ajv = new Ajv__default[
|
|
9621
|
+
const ajv = new Ajv__default["default"]({ strict: true, strictTuples: true, strictTypes: true });
|
|
9352
9622
|
ajv.addMetaSchema(ajvSchemaDraft);
|
|
9353
9623
|
const validator = ajv.compile(configurationSchema);
|
|
9354
9624
|
function overwriteMerge(a, b) {
|
|
9355
9625
|
return b;
|
|
9356
9626
|
}
|
|
9357
9627
|
function mergeInternal(base, rhs) {
|
|
9358
|
-
const dst = deepmerge__default[
|
|
9628
|
+
const dst = deepmerge__default["default"](base, { ...rhs, rules: {} });
|
|
9359
9629
|
/* rules need some special care, should overwrite arrays instead of
|
|
9360
9630
|
* concaternation, i.e. ["error", {...options}] should not be merged by
|
|
9361
9631
|
* appending to old value */
|
|
9362
9632
|
if (rhs.rules) {
|
|
9363
|
-
dst.rules = deepmerge__default[
|
|
9633
|
+
dst.rules = deepmerge__default["default"](dst.rules, rhs.rules, { arrayMerge: overwriteMerge });
|
|
9364
9634
|
}
|
|
9365
9635
|
/* root property is merged with boolean "or" since it should always be truthy
|
|
9366
9636
|
* if any config has it set. */
|
|
@@ -9384,7 +9654,7 @@ function loadFromFile(filename) {
|
|
|
9384
9654
|
if (!json[key])
|
|
9385
9655
|
continue;
|
|
9386
9656
|
json[key] = json[key].map((ref) => {
|
|
9387
|
-
return Config.expandRelative(ref, path__default[
|
|
9657
|
+
return Config.expandRelative(ref, path__default["default"].dirname(filename));
|
|
9388
9658
|
});
|
|
9389
9659
|
}
|
|
9390
9660
|
return json;
|
|
@@ -9543,14 +9813,14 @@ class Config {
|
|
|
9543
9813
|
}
|
|
9544
9814
|
let filename;
|
|
9545
9815
|
/* try searching builtin metadata */
|
|
9546
|
-
filename = path__default[
|
|
9547
|
-
if (fs__default[
|
|
9816
|
+
filename = path__default["default"].join(projectRoot, "elements", `${entry}.json`);
|
|
9817
|
+
if (fs__default["default"].existsSync(filename)) {
|
|
9548
9818
|
metaTable.loadFromFile(filename);
|
|
9549
9819
|
continue;
|
|
9550
9820
|
}
|
|
9551
9821
|
/* try as regular file */
|
|
9552
9822
|
filename = entry.replace("<rootDir>", this.rootDir);
|
|
9553
|
-
if (fs__default[
|
|
9823
|
+
if (fs__default["default"].existsSync(filename)) {
|
|
9554
9824
|
metaTable.loadFromFile(filename);
|
|
9555
9825
|
continue;
|
|
9556
9826
|
}
|
|
@@ -9570,7 +9840,7 @@ class Config {
|
|
|
9570
9840
|
*/
|
|
9571
9841
|
static expandRelative(src, currentPath) {
|
|
9572
9842
|
if (src[0] === ".") {
|
|
9573
|
-
return path__default[
|
|
9843
|
+
return path__default["default"].normalize(`${currentPath}/${src}`);
|
|
9574
9844
|
}
|
|
9575
9845
|
return src;
|
|
9576
9846
|
}
|
|
@@ -9580,7 +9850,7 @@ class Config {
|
|
|
9580
9850
|
* @internal primary purpose is unittests
|
|
9581
9851
|
*/
|
|
9582
9852
|
get() {
|
|
9583
|
-
const config =
|
|
9853
|
+
const config = { ...this.config };
|
|
9584
9854
|
if (config.elements) {
|
|
9585
9855
|
config.elements = config.elements.map((cur) => {
|
|
9586
9856
|
if (typeof cur === "string") {
|
|
@@ -9666,7 +9936,11 @@ class Config {
|
|
|
9666
9936
|
if (!properties) {
|
|
9667
9937
|
continue;
|
|
9668
9938
|
}
|
|
9669
|
-
for (const [
|
|
9939
|
+
for (const [raw, schema] of Object.entries(properties)) {
|
|
9940
|
+
/* at compile time this is a fixed list but the point of this method is
|
|
9941
|
+
* to augment the runtime with additional keys so it is a bit of lying
|
|
9942
|
+
* to typescript */
|
|
9943
|
+
const key = raw;
|
|
9670
9944
|
if (schema.copyable && !MetaCopyableProperty.includes(key)) {
|
|
9671
9945
|
MetaCopyableProperty.push(key);
|
|
9672
9946
|
}
|
|
@@ -9820,13 +10094,13 @@ class Config {
|
|
|
9820
10094
|
let current = process.cwd();
|
|
9821
10095
|
// eslint-disable-next-line no-constant-condition
|
|
9822
10096
|
while (true) {
|
|
9823
|
-
const search = path__default[
|
|
9824
|
-
if (fs__default[
|
|
10097
|
+
const search = path__default["default"].join(current, "package.json");
|
|
10098
|
+
if (fs__default["default"].existsSync(search)) {
|
|
9825
10099
|
return (this.rootDirCache = current);
|
|
9826
10100
|
}
|
|
9827
10101
|
/* get the parent directory */
|
|
9828
10102
|
const child = current;
|
|
9829
|
-
current = path__default[
|
|
10103
|
+
current = path__default["default"].dirname(current);
|
|
9830
10104
|
/* stop if this is the root directory */
|
|
9831
10105
|
if (current === child) {
|
|
9832
10106
|
break;
|
|
@@ -9862,31 +10136,6 @@ class ConfigLoader {
|
|
|
9862
10136
|
}
|
|
9863
10137
|
}
|
|
9864
10138
|
|
|
9865
|
-
/*! *****************************************************************************
|
|
9866
|
-
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
9867
|
-
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
9868
|
-
this file except in compliance with the License. You may obtain a copy of the
|
|
9869
|
-
License at http://www.apache.org/licenses/LICENSE-2.0
|
|
9870
|
-
|
|
9871
|
-
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
9872
|
-
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
|
9873
|
-
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
|
9874
|
-
MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
9875
|
-
|
|
9876
|
-
See the Apache Version 2.0 License for specific language governing permissions
|
|
9877
|
-
and limitations under the License.
|
|
9878
|
-
***************************************************************************** */
|
|
9879
|
-
|
|
9880
|
-
function __rest(s, e) {
|
|
9881
|
-
var t = {};
|
|
9882
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
9883
|
-
t[p] = s[p];
|
|
9884
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
9885
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
|
|
9886
|
-
t[p[i]] = s[p[i]];
|
|
9887
|
-
return t;
|
|
9888
|
-
}
|
|
9889
|
-
|
|
9890
10139
|
class EventHandler {
|
|
9891
10140
|
constructor() {
|
|
9892
10141
|
this.listeners = {};
|
|
@@ -10460,7 +10709,7 @@ class Reporter {
|
|
|
10460
10709
|
merged[key].messages = [...merged[key].messages, ...result.messages];
|
|
10461
10710
|
}
|
|
10462
10711
|
else {
|
|
10463
|
-
merged[key] =
|
|
10712
|
+
merged[key] = { ...result };
|
|
10464
10713
|
}
|
|
10465
10714
|
});
|
|
10466
10715
|
});
|
|
@@ -10562,14 +10811,16 @@ function messageSort(a, b) {
|
|
|
10562
10811
|
}
|
|
10563
10812
|
|
|
10564
10813
|
class Engine {
|
|
10565
|
-
constructor(config,
|
|
10814
|
+
constructor(config, ParserClass) {
|
|
10566
10815
|
this.report = new Reporter();
|
|
10567
|
-
this.configData = configData;
|
|
10568
10816
|
this.config = config;
|
|
10569
10817
|
this.ParserClass = ParserClass;
|
|
10570
10818
|
/* initialize plugins and rules */
|
|
10571
10819
|
const result = this.initPlugins(this.config);
|
|
10572
|
-
this.availableRules =
|
|
10820
|
+
this.availableRules = {
|
|
10821
|
+
...bundledRules,
|
|
10822
|
+
...result.availableRules,
|
|
10823
|
+
};
|
|
10573
10824
|
}
|
|
10574
10825
|
/**
|
|
10575
10826
|
* Lint sources and return report
|
|
@@ -10594,13 +10845,13 @@ class Engine {
|
|
|
10594
10845
|
/* trigger configuration ready event */
|
|
10595
10846
|
const configEvent = {
|
|
10596
10847
|
location,
|
|
10597
|
-
config: this.
|
|
10848
|
+
config: this.config,
|
|
10598
10849
|
rules,
|
|
10599
10850
|
};
|
|
10600
10851
|
parser.trigger("config:ready", configEvent);
|
|
10601
10852
|
/* trigger source ready event */
|
|
10602
10853
|
/* eslint-disable-next-line @typescript-eslint/no-unused-vars -- object destructured on purpose to remove property */
|
|
10603
|
-
const sourceData =
|
|
10854
|
+
const { hooks: _, ...sourceData } = source;
|
|
10604
10855
|
const sourceEvent = {
|
|
10605
10856
|
location,
|
|
10606
10857
|
source: sourceData,
|
|
@@ -10907,133 +11158,31 @@ class Engine {
|
|
|
10907
11158
|
}
|
|
10908
11159
|
|
|
10909
11160
|
/**
|
|
10910
|
-
*
|
|
10911
|
-
|
|
10912
|
-
function findConfigurationFiles(directory) {
|
|
10913
|
-
return ["json", "cjs", "js"]
|
|
10914
|
-
.map((extension) => path__default['default'].join(directory, `.htmlvalidate.${extension}`))
|
|
10915
|
-
.filter((filePath) => fs__default['default'].existsSync(filePath));
|
|
10916
|
-
}
|
|
10917
|
-
/**
|
|
10918
|
-
* Loads configuration by traversing filesystem.
|
|
10919
|
-
*
|
|
10920
|
-
* Configuration is read from three sources and in the following order:
|
|
10921
|
-
*
|
|
10922
|
-
* 1. Global configuration passed to constructor.
|
|
10923
|
-
* 2. Configuration files found when traversing the directory structure.
|
|
10924
|
-
* 3. Override passed to this function.
|
|
10925
|
-
*
|
|
10926
|
-
* The following configuration filenames are searched:
|
|
10927
|
-
*
|
|
10928
|
-
* - `.htmlvalidate.json`
|
|
10929
|
-
* - `.htmlvalidate.js`
|
|
10930
|
-
* - `.htmlvalidate.cjs`
|
|
10931
|
-
*
|
|
10932
|
-
* Global configuration is used when no configuration file is found. The
|
|
10933
|
-
* result is always merged with override if present.
|
|
10934
|
-
*
|
|
10935
|
-
* The `root` property set to `true` affects the configuration as following:
|
|
11161
|
+
* The static configuration loader does not do any per-handle lookup. Only the
|
|
11162
|
+
* global or per-call configuration is used.
|
|
10936
11163
|
*
|
|
10937
|
-
*
|
|
10938
|
-
*
|
|
10939
|
-
* returned. No configuration files are searched.
|
|
10940
|
-
* 3. Setting `root` in configuration file only stops directory traversal.
|
|
11164
|
+
* In practice this means no configuration is fetch by traversing the
|
|
11165
|
+
* filesystem.
|
|
10941
11166
|
*/
|
|
10942
|
-
class
|
|
10943
|
-
|
|
10944
|
-
* @param config - Global configuration
|
|
10945
|
-
* @param configFactory - Optional configuration factory
|
|
10946
|
-
*/
|
|
10947
|
-
constructor(config, configFactory = Config) {
|
|
10948
|
-
super(config, configFactory);
|
|
10949
|
-
this.cache = new Map();
|
|
10950
|
-
}
|
|
10951
|
-
/**
|
|
10952
|
-
* Get configuration for given filename.
|
|
10953
|
-
*
|
|
10954
|
-
* @param filename - Filename to get configuration for.
|
|
10955
|
-
* @param configOverride - Configuration to merge final result with.
|
|
10956
|
-
*/
|
|
10957
|
-
getConfigFor(filename, configOverride) {
|
|
10958
|
-
/* special case when the overridden configuration is marked as root, should
|
|
10959
|
-
* not try to load any more configuration files */
|
|
11167
|
+
class StaticConfigLoader extends ConfigLoader {
|
|
11168
|
+
getConfigFor(handle, configOverride) {
|
|
10960
11169
|
const override = this.loadFromObject(configOverride || {});
|
|
10961
11170
|
if (override.isRootFound()) {
|
|
10962
11171
|
override.init();
|
|
10963
11172
|
return override;
|
|
10964
11173
|
}
|
|
10965
|
-
|
|
10966
|
-
* try to load and more configuration files */
|
|
10967
|
-
if (this.globalConfig.isRootFound()) {
|
|
10968
|
-
const merged = this.globalConfig.merge(override);
|
|
10969
|
-
merged.init();
|
|
10970
|
-
return merged;
|
|
10971
|
-
}
|
|
10972
|
-
const config = this.fromFilename(filename);
|
|
10973
|
-
const merged = config ? config.merge(override) : this.globalConfig.merge(override);
|
|
11174
|
+
const merged = this.globalConfig.merge(override);
|
|
10974
11175
|
merged.init();
|
|
10975
11176
|
return merged;
|
|
10976
11177
|
}
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
*
|
|
10980
|
-
* @param filename - If given only the cache for that file is flushed.
|
|
10981
|
-
*/
|
|
10982
|
-
flushCache(filename) {
|
|
10983
|
-
if (filename) {
|
|
10984
|
-
this.cache.delete(filename);
|
|
10985
|
-
}
|
|
10986
|
-
else {
|
|
10987
|
-
this.cache.clear();
|
|
10988
|
-
}
|
|
10989
|
-
}
|
|
10990
|
-
/**
|
|
10991
|
-
* Load raw configuration from directory traversal.
|
|
10992
|
-
*
|
|
10993
|
-
* This configuration is not merged with global configuration and may return
|
|
10994
|
-
* `null` if no configuration files are found.
|
|
10995
|
-
*/
|
|
10996
|
-
fromFilename(filename) {
|
|
10997
|
-
var _a;
|
|
10998
|
-
if (filename === "inline") {
|
|
10999
|
-
return null;
|
|
11000
|
-
}
|
|
11001
|
-
if (this.cache.has(filename)) {
|
|
11002
|
-
return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
|
|
11003
|
-
}
|
|
11004
|
-
let found = false;
|
|
11005
|
-
let current = path__default['default'].resolve(path__default['default'].dirname(filename));
|
|
11006
|
-
let config = this.empty();
|
|
11007
|
-
// eslint-disable-next-line no-constant-condition
|
|
11008
|
-
while (true) {
|
|
11009
|
-
/* search configuration files in current directory */
|
|
11010
|
-
for (const configFile of findConfigurationFiles(current)) {
|
|
11011
|
-
const local = this.loadFromFile(configFile);
|
|
11012
|
-
found = true;
|
|
11013
|
-
config = local.merge(config);
|
|
11014
|
-
}
|
|
11015
|
-
/* stop if a configuration with "root" is set to true */
|
|
11016
|
-
if (config.isRootFound()) {
|
|
11017
|
-
break;
|
|
11018
|
-
}
|
|
11019
|
-
/* get the parent directory */
|
|
11020
|
-
const child = current;
|
|
11021
|
-
current = path__default['default'].dirname(current);
|
|
11022
|
-
/* stop if this is the root directory */
|
|
11023
|
-
if (current === child) {
|
|
11024
|
-
break;
|
|
11025
|
-
}
|
|
11026
|
-
}
|
|
11027
|
-
/* no config was found by loader, return null and let caller decide what to do */
|
|
11028
|
-
if (!found) {
|
|
11029
|
-
this.cache.set(filename, null);
|
|
11030
|
-
return null;
|
|
11031
|
-
}
|
|
11032
|
-
this.cache.set(filename, config);
|
|
11033
|
-
return config;
|
|
11178
|
+
flushCache() {
|
|
11179
|
+
/* do nothing */
|
|
11034
11180
|
}
|
|
11035
11181
|
defaultConfig() {
|
|
11036
|
-
return this.
|
|
11182
|
+
return this.loadFromObject({
|
|
11183
|
+
extends: ["html-validate:recommended"],
|
|
11184
|
+
elements: ["html5"],
|
|
11185
|
+
});
|
|
11037
11186
|
}
|
|
11038
11187
|
}
|
|
11039
11188
|
|
|
@@ -11057,7 +11206,7 @@ function isConfigData(value) {
|
|
|
11057
11206
|
class HtmlValidate {
|
|
11058
11207
|
constructor(arg) {
|
|
11059
11208
|
const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
|
|
11060
|
-
this.configLoader = loader !== null && loader !== void 0 ? loader : new
|
|
11209
|
+
this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
|
|
11061
11210
|
}
|
|
11062
11211
|
validateString(str, arg1, arg2, arg3) {
|
|
11063
11212
|
const filename = typeof arg1 === "string" ? arg1 : "inline";
|
|
@@ -11084,7 +11233,7 @@ class HtmlValidate {
|
|
|
11084
11233
|
const config = this.getConfigFor(input.filename, configOverride);
|
|
11085
11234
|
const resolved = config.resolve();
|
|
11086
11235
|
const source = resolved.transformSource(input);
|
|
11087
|
-
const engine = new Engine(resolved,
|
|
11236
|
+
const engine = new Engine(resolved, Parser);
|
|
11088
11237
|
return engine.lint(source);
|
|
11089
11238
|
}
|
|
11090
11239
|
/**
|
|
@@ -11098,7 +11247,7 @@ class HtmlValidate {
|
|
|
11098
11247
|
const config = this.getConfigFor(filename);
|
|
11099
11248
|
const resolved = config.resolve();
|
|
11100
11249
|
const source = resolved.transformFilename(filename);
|
|
11101
|
-
const engine = new Engine(resolved,
|
|
11250
|
+
const engine = new Engine(resolved, Parser);
|
|
11102
11251
|
return engine.lint(source);
|
|
11103
11252
|
}
|
|
11104
11253
|
/**
|
|
@@ -11122,7 +11271,7 @@ class HtmlValidate {
|
|
|
11122
11271
|
*/
|
|
11123
11272
|
canValidate(filename) {
|
|
11124
11273
|
/* .html is always supported */
|
|
11125
|
-
const extension = path__default[
|
|
11274
|
+
const extension = path__default["default"].extname(filename).toLowerCase();
|
|
11126
11275
|
if (extension === ".html") {
|
|
11127
11276
|
return true;
|
|
11128
11277
|
}
|
|
@@ -11143,7 +11292,7 @@ class HtmlValidate {
|
|
|
11143
11292
|
const config = this.getConfigFor(filename);
|
|
11144
11293
|
const resolved = config.resolve();
|
|
11145
11294
|
const source = resolved.transformFilename(filename);
|
|
11146
|
-
const engine = new Engine(resolved,
|
|
11295
|
+
const engine = new Engine(resolved, Parser);
|
|
11147
11296
|
return engine.dumpTokens(source);
|
|
11148
11297
|
}
|
|
11149
11298
|
/**
|
|
@@ -11158,7 +11307,7 @@ class HtmlValidate {
|
|
|
11158
11307
|
const config = this.getConfigFor(filename);
|
|
11159
11308
|
const resolved = config.resolve();
|
|
11160
11309
|
const source = resolved.transformFilename(filename);
|
|
11161
|
-
const engine = new Engine(resolved,
|
|
11310
|
+
const engine = new Engine(resolved, Parser);
|
|
11162
11311
|
return engine.dumpEvents(source);
|
|
11163
11312
|
}
|
|
11164
11313
|
/**
|
|
@@ -11173,7 +11322,7 @@ class HtmlValidate {
|
|
|
11173
11322
|
const config = this.getConfigFor(filename);
|
|
11174
11323
|
const resolved = config.resolve();
|
|
11175
11324
|
const source = resolved.transformFilename(filename);
|
|
11176
|
-
const engine = new Engine(resolved,
|
|
11325
|
+
const engine = new Engine(resolved, Parser);
|
|
11177
11326
|
return engine.dumpTree(source);
|
|
11178
11327
|
}
|
|
11179
11328
|
/**
|
|
@@ -11251,7 +11400,7 @@ class HtmlValidate {
|
|
|
11251
11400
|
*/
|
|
11252
11401
|
getRuleDocumentation(ruleId, config = null, context = null) {
|
|
11253
11402
|
const c = config || this.getConfigFor("inline");
|
|
11254
|
-
const engine = new Engine(c.resolve(),
|
|
11403
|
+
const engine = new Engine(c.resolve(), Parser);
|
|
11255
11404
|
return engine.getRuleDocumentation(ruleId, context);
|
|
11256
11405
|
}
|
|
11257
11406
|
/**
|
|
@@ -11288,41 +11437,12 @@ class HtmlValidate {
|
|
|
11288
11437
|
}
|
|
11289
11438
|
}
|
|
11290
11439
|
|
|
11291
|
-
/**
|
|
11292
|
-
* The static configuration loader does not do any per-handle lookup. Only the
|
|
11293
|
-
* global or per-call configuration is used.
|
|
11294
|
-
*
|
|
11295
|
-
* In practice this means no configuration is fetch by traversing the
|
|
11296
|
-
* filesystem.
|
|
11297
|
-
*/
|
|
11298
|
-
class StaticConfigLoader extends ConfigLoader {
|
|
11299
|
-
getConfigFor(handle, configOverride) {
|
|
11300
|
-
const override = this.loadFromObject(configOverride || {});
|
|
11301
|
-
if (override.isRootFound()) {
|
|
11302
|
-
override.init();
|
|
11303
|
-
return override;
|
|
11304
|
-
}
|
|
11305
|
-
const merged = this.globalConfig.merge(override);
|
|
11306
|
-
merged.init();
|
|
11307
|
-
return merged;
|
|
11308
|
-
}
|
|
11309
|
-
flushCache() {
|
|
11310
|
-
/* do nothing */
|
|
11311
|
-
}
|
|
11312
|
-
defaultConfig() {
|
|
11313
|
-
return this.loadFromObject({
|
|
11314
|
-
extends: ["html-validate:recommended"],
|
|
11315
|
-
elements: ["html5"],
|
|
11316
|
-
});
|
|
11317
|
-
}
|
|
11318
|
-
}
|
|
11319
|
-
|
|
11320
11440
|
const defaults$1 = {
|
|
11321
11441
|
silent: false,
|
|
11322
11442
|
version,
|
|
11323
11443
|
logger(text) {
|
|
11324
11444
|
/* eslint-disable-next-line no-console */
|
|
11325
|
-
console.error(kleur__default[
|
|
11445
|
+
console.error(kleur__default["default"].red(text));
|
|
11326
11446
|
},
|
|
11327
11447
|
};
|
|
11328
11448
|
/**
|
|
@@ -11334,8 +11454,8 @@ const defaults$1 = {
|
|
|
11334
11454
|
* @returns - `true` if version is compatible
|
|
11335
11455
|
*/
|
|
11336
11456
|
function compatibilityCheck(name, declared, options) {
|
|
11337
|
-
const { silent, version: current, logger } =
|
|
11338
|
-
const valid = semver__default[
|
|
11457
|
+
const { silent, version: current, logger } = { ...defaults$1, ...options };
|
|
11458
|
+
const valid = semver__default["default"].satisfies(current, declared);
|
|
11339
11459
|
if (valid || silent) {
|
|
11340
11460
|
return valid;
|
|
11341
11461
|
}
|
|
@@ -11364,6 +11484,137 @@ function ruleExists(ruleId) {
|
|
|
11364
11484
|
return ruleIds.has(ruleId);
|
|
11365
11485
|
}
|
|
11366
11486
|
|
|
11487
|
+
/**
|
|
11488
|
+
* @internal
|
|
11489
|
+
*/
|
|
11490
|
+
function findConfigurationFiles(directory) {
|
|
11491
|
+
return ["json", "cjs", "js"]
|
|
11492
|
+
.map((extension) => path__default["default"].join(directory, `.htmlvalidate.${extension}`))
|
|
11493
|
+
.filter((filePath) => fs__default["default"].existsSync(filePath));
|
|
11494
|
+
}
|
|
11495
|
+
/**
|
|
11496
|
+
* Loads configuration by traversing filesystem.
|
|
11497
|
+
*
|
|
11498
|
+
* Configuration is read from three sources and in the following order:
|
|
11499
|
+
*
|
|
11500
|
+
* 1. Global configuration passed to constructor.
|
|
11501
|
+
* 2. Configuration files found when traversing the directory structure.
|
|
11502
|
+
* 3. Override passed to this function.
|
|
11503
|
+
*
|
|
11504
|
+
* The following configuration filenames are searched:
|
|
11505
|
+
*
|
|
11506
|
+
* - `.htmlvalidate.json`
|
|
11507
|
+
* - `.htmlvalidate.js`
|
|
11508
|
+
* - `.htmlvalidate.cjs`
|
|
11509
|
+
*
|
|
11510
|
+
* Global configuration is used when no configuration file is found. The
|
|
11511
|
+
* result is always merged with override if present.
|
|
11512
|
+
*
|
|
11513
|
+
* The `root` property set to `true` affects the configuration as following:
|
|
11514
|
+
*
|
|
11515
|
+
* 1. If set in override the override is returned as-is.
|
|
11516
|
+
* 2. If set in the global config the override is merged into global and
|
|
11517
|
+
* returned. No configuration files are searched.
|
|
11518
|
+
* 3. Setting `root` in configuration file only stops directory traversal.
|
|
11519
|
+
*/
|
|
11520
|
+
class FileSystemConfigLoader extends ConfigLoader {
|
|
11521
|
+
/**
|
|
11522
|
+
* @param config - Global configuration
|
|
11523
|
+
* @param configFactory - Optional configuration factory
|
|
11524
|
+
*/
|
|
11525
|
+
constructor(config, configFactory = Config) {
|
|
11526
|
+
super(config, configFactory);
|
|
11527
|
+
this.cache = new Map();
|
|
11528
|
+
}
|
|
11529
|
+
/**
|
|
11530
|
+
* Get configuration for given filename.
|
|
11531
|
+
*
|
|
11532
|
+
* @param filename - Filename to get configuration for.
|
|
11533
|
+
* @param configOverride - Configuration to merge final result with.
|
|
11534
|
+
*/
|
|
11535
|
+
getConfigFor(filename, configOverride) {
|
|
11536
|
+
/* special case when the overridden configuration is marked as root, should
|
|
11537
|
+
* not try to load any more configuration files */
|
|
11538
|
+
const override = this.loadFromObject(configOverride || {});
|
|
11539
|
+
if (override.isRootFound()) {
|
|
11540
|
+
override.init();
|
|
11541
|
+
return override;
|
|
11542
|
+
}
|
|
11543
|
+
/* special case when the global configuration is marked as root, should not
|
|
11544
|
+
* try to load and more configuration files */
|
|
11545
|
+
if (this.globalConfig.isRootFound()) {
|
|
11546
|
+
const merged = this.globalConfig.merge(override);
|
|
11547
|
+
merged.init();
|
|
11548
|
+
return merged;
|
|
11549
|
+
}
|
|
11550
|
+
const config = this.fromFilename(filename);
|
|
11551
|
+
const merged = config ? config.merge(override) : this.globalConfig.merge(override);
|
|
11552
|
+
merged.init();
|
|
11553
|
+
return merged;
|
|
11554
|
+
}
|
|
11555
|
+
/**
|
|
11556
|
+
* Flush configuration cache.
|
|
11557
|
+
*
|
|
11558
|
+
* @param filename - If given only the cache for that file is flushed.
|
|
11559
|
+
*/
|
|
11560
|
+
flushCache(filename) {
|
|
11561
|
+
if (filename) {
|
|
11562
|
+
this.cache.delete(filename);
|
|
11563
|
+
}
|
|
11564
|
+
else {
|
|
11565
|
+
this.cache.clear();
|
|
11566
|
+
}
|
|
11567
|
+
}
|
|
11568
|
+
/**
|
|
11569
|
+
* Load raw configuration from directory traversal.
|
|
11570
|
+
*
|
|
11571
|
+
* This configuration is not merged with global configuration and may return
|
|
11572
|
+
* `null` if no configuration files are found.
|
|
11573
|
+
*/
|
|
11574
|
+
fromFilename(filename) {
|
|
11575
|
+
var _a;
|
|
11576
|
+
if (filename === "inline") {
|
|
11577
|
+
return null;
|
|
11578
|
+
}
|
|
11579
|
+
if (this.cache.has(filename)) {
|
|
11580
|
+
return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
|
|
11581
|
+
}
|
|
11582
|
+
let found = false;
|
|
11583
|
+
let current = path__default["default"].resolve(path__default["default"].dirname(filename));
|
|
11584
|
+
let config = this.empty();
|
|
11585
|
+
// eslint-disable-next-line no-constant-condition
|
|
11586
|
+
while (true) {
|
|
11587
|
+
/* search configuration files in current directory */
|
|
11588
|
+
for (const configFile of findConfigurationFiles(current)) {
|
|
11589
|
+
const local = this.loadFromFile(configFile);
|
|
11590
|
+
found = true;
|
|
11591
|
+
config = local.merge(config);
|
|
11592
|
+
}
|
|
11593
|
+
/* stop if a configuration with "root" is set to true */
|
|
11594
|
+
if (config.isRootFound()) {
|
|
11595
|
+
break;
|
|
11596
|
+
}
|
|
11597
|
+
/* get the parent directory */
|
|
11598
|
+
const child = current;
|
|
11599
|
+
current = path__default["default"].dirname(current);
|
|
11600
|
+
/* stop if this is the root directory */
|
|
11601
|
+
if (current === child) {
|
|
11602
|
+
break;
|
|
11603
|
+
}
|
|
11604
|
+
}
|
|
11605
|
+
/* no config was found by loader, return null and let caller decide what to do */
|
|
11606
|
+
if (!found) {
|
|
11607
|
+
this.cache.set(filename, null);
|
|
11608
|
+
return null;
|
|
11609
|
+
}
|
|
11610
|
+
this.cache.set(filename, config);
|
|
11611
|
+
return config;
|
|
11612
|
+
}
|
|
11613
|
+
defaultConfig() {
|
|
11614
|
+
return this.configFactory.defaultConfig();
|
|
11615
|
+
}
|
|
11616
|
+
}
|
|
11617
|
+
|
|
11367
11618
|
const entities = {
|
|
11368
11619
|
">": ">",
|
|
11369
11620
|
"<": "<",
|
|
@@ -11435,12 +11686,12 @@ function pluralize(word, count) {
|
|
|
11435
11686
|
* @returns The formatted file path.
|
|
11436
11687
|
*/
|
|
11437
11688
|
function formatFilePath(filePath, line, column) {
|
|
11438
|
-
let relPath = path__default[
|
|
11689
|
+
let relPath = path__default["default"].relative(process.cwd(), filePath);
|
|
11439
11690
|
/* istanbul ignore next: safety check from original implementation */
|
|
11440
11691
|
if (line && column) {
|
|
11441
11692
|
relPath += `:${line}:${column}`;
|
|
11442
11693
|
}
|
|
11443
|
-
return kleur__default[
|
|
11694
|
+
return kleur__default["default"].green(relPath);
|
|
11444
11695
|
}
|
|
11445
11696
|
function getStartLocation(message) {
|
|
11446
11697
|
return {
|
|
@@ -11469,9 +11720,9 @@ function getEndLocation(message, source) {
|
|
|
11469
11720
|
* @returns The formatted output.
|
|
11470
11721
|
*/
|
|
11471
11722
|
function formatMessage(message, parentResult, options) {
|
|
11472
|
-
const type = message.severity === 2 ? kleur__default[
|
|
11473
|
-
const msg = `${kleur__default[
|
|
11474
|
-
const ruleId = kleur__default[
|
|
11723
|
+
const type = message.severity === 2 ? kleur__default["default"].red("error") : kleur__default["default"].yellow("warning");
|
|
11724
|
+
const msg = `${kleur__default["default"].bold(message.message.replace(/([^ ])\.$/, "$1"))}`;
|
|
11725
|
+
const ruleId = kleur__default["default"].dim(`(${message.ruleId})`);
|
|
11475
11726
|
const filePath = formatFilePath(parentResult.filePath, message.line, message.column);
|
|
11476
11727
|
const sourceCode = parentResult.source;
|
|
11477
11728
|
/* istanbul ignore next: safety check from original implementation */
|
|
@@ -11492,7 +11743,7 @@ function formatMessage(message, parentResult, options) {
|
|
|
11492
11743
|
}, { highlightCode: false }));
|
|
11493
11744
|
}
|
|
11494
11745
|
if (options.showLink && message.ruleUrl) {
|
|
11495
|
-
result.push(`${kleur__default[
|
|
11746
|
+
result.push(`${kleur__default["default"].bold("Details:")} ${message.ruleUrl}`);
|
|
11496
11747
|
}
|
|
11497
11748
|
return result.join("\n");
|
|
11498
11749
|
}
|
|
@@ -11511,10 +11762,10 @@ function formatSummary(errors, warnings) {
|
|
|
11511
11762
|
if (warnings > 0) {
|
|
11512
11763
|
summary.push(`${warnings} ${pluralize("warning", warnings)}`);
|
|
11513
11764
|
}
|
|
11514
|
-
return kleur__default[
|
|
11765
|
+
return kleur__default["default"][summaryColor]().bold(`${summary.join(" and ")} found.`);
|
|
11515
11766
|
}
|
|
11516
11767
|
function codeframe(results, options) {
|
|
11517
|
-
const merged =
|
|
11768
|
+
const merged = { ...defaults, ...options };
|
|
11518
11769
|
let errors = 0;
|
|
11519
11770
|
let warnings = 0;
|
|
11520
11771
|
const resultsWithMessages = results.filter((result) => result.messages.length > 0);
|
|
@@ -11552,10 +11803,14 @@ function linkSummary(results) {
|
|
|
11552
11803
|
return "";
|
|
11553
11804
|
}
|
|
11554
11805
|
const lines = unique.map((url) => ` ${url}\n`);
|
|
11555
|
-
return `\n${kleur__default[
|
|
11806
|
+
return `\n${kleur__default["default"].bold("More information")}:\n${lines.join("")}\n`;
|
|
11556
11807
|
}
|
|
11557
11808
|
function stylish(results) {
|
|
11558
|
-
const errors = stylishImpl__default[
|
|
11809
|
+
const errors = stylishImpl__default["default"](results.map((it) => ({
|
|
11810
|
+
...it,
|
|
11811
|
+
fixableErrorCount: 0,
|
|
11812
|
+
fixableWarningCount: 0,
|
|
11813
|
+
})));
|
|
11559
11814
|
const links = linkSummary(results);
|
|
11560
11815
|
return `${errors}${links}`;
|
|
11561
11816
|
}
|