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.
Files changed (41) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/dist/cjs/browser.js +2 -6
  3. package/dist/cjs/browser.js.map +1 -1
  4. package/dist/cjs/cli.js +53 -28
  5. package/dist/cjs/cli.js.map +1 -1
  6. package/dist/cjs/core.d.ts +21 -7
  7. package/dist/cjs/core.js +618 -351
  8. package/dist/cjs/core.js.map +1 -1
  9. package/dist/cjs/html-validate.js +9 -9
  10. package/dist/cjs/html-validate.js.map +1 -1
  11. package/dist/cjs/index.d.ts +15 -2
  12. package/dist/cjs/index.js +2 -6
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/{matchers.d.ts → jest-lib.d.ts} +2 -4
  15. package/dist/cjs/{matchers.js → jest-lib.js} +125 -87
  16. package/dist/cjs/jest-lib.js.map +1 -0
  17. package/dist/cjs/jest.d.ts +4 -0
  18. package/dist/cjs/jest.js +17 -0
  19. package/dist/cjs/jest.js.map +1 -0
  20. package/dist/cjs/test-utils.js +1 -1
  21. package/dist/es/cli.js +34 -9
  22. package/dist/es/cli.js.map +1 -1
  23. package/dist/es/core.d.ts +21 -7
  24. package/dist/es/core.js +582 -315
  25. package/dist/es/core.js.map +1 -1
  26. package/dist/es/html-validate.js +1 -1
  27. package/dist/es/html-validate.js.map +1 -1
  28. package/dist/es/index.d.ts +15 -2
  29. package/dist/es/{matchers.d.ts → jest-lib.d.ts} +2 -4
  30. package/dist/es/{matchers.js → jest-lib.js} +120 -82
  31. package/dist/es/jest-lib.js.map +1 -0
  32. package/dist/es/jest.d.ts +4 -0
  33. package/dist/es/jest.js +16 -0
  34. package/dist/es/jest.js.map +1 -0
  35. package/dist/schema/elements.json +43 -5
  36. package/elements/html5.json +940 -290
  37. package/jest.d.ts +1 -1
  38. package/jest.js +1 -1
  39. package/package.json +30 -28
  40. package/dist/cjs/matchers.js.map +0 -1
  41. package/dist/es/matchers.js.map +0 -1
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['default'](schema, obj, errors, {
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['default'](this.schema, this.obj, this.errors, {
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['default'].existsSync(this.filename)) {
296
- return fs__default['default'].readFileSync(this.filename, "utf-8");
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['default'].resolve(__dirname, "../../");
304
+ const projectRoot = path__default["default"].resolve(__dirname, "../../");
305
305
  const legacyRequire = require;
306
- const distFolder = path__default['default'].resolve(projectRoot, "dist/cjs");
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
- type: "array",
590
- uniqueItems: true,
591
- items: {
592
- anyOf: [
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['default'].apply(this.schema, {
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['default'].apply(this.schema, {
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] ? Object.assign({}, this.elements[tagName]) : null;
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 = deepmerge__default['default'](parent, Object.assign(Object.assign({}, entry), { tagName }), { arrayMerge: overwriteMerge$1 });
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['default']({ strict: true, strictTuples: true, strictTypes: true });
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" });
@@ -832,11 +982,20 @@ class MetaTable {
832
982
  delete global.void;
833
983
  /* merge elements */
834
984
  for (const [tagName, entry] of Object.entries(this.elements)) {
835
- this.elements[tagName] = this.mergeElement(entry, global);
985
+ this.elements[tagName] = this.mergeElement(global, entry);
836
986
  }
837
987
  }
838
988
  mergeElement(a, b) {
839
- return deepmerge__default['default'](a, b);
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[key] = evaluateProperty(node, property);
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;
@@ -1342,6 +1461,15 @@ class DOMTokenList extends Array {
1342
1461
  contains(token) {
1343
1462
  return this.includes(token);
1344
1463
  }
1464
+ *iterator() {
1465
+ for (let index = 0; index < this.length; index++) {
1466
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
1467
+ const item = this.item(index);
1468
+ const location = this.location(index);
1469
+ /* eslint-enable @typescript-eslint/no-non-null-assertion */
1470
+ yield { index, item, location };
1471
+ }
1472
+ }
1345
1473
  }
1346
1474
 
1347
1475
  var Combinator;
@@ -1814,8 +1942,9 @@ class HtmlElement extends DOMNode {
1814
1942
  this.metaElement = {};
1815
1943
  }
1816
1944
  for (const key of MetaCopyableProperty) {
1817
- if (typeof meta[key] !== "undefined") {
1818
- this.metaElement[key] = meta[key];
1945
+ const value = meta[key];
1946
+ if (typeof value !== "undefined") {
1947
+ setMetaProperty(this.metaElement, key, value);
1819
1948
  }
1820
1949
  else {
1821
1950
  delete this.metaElement[key];
@@ -2231,6 +2360,7 @@ class Validator {
2231
2360
  * @param rules - Element attribute metadta.
2232
2361
  * @returns `true` if attribute passes all tests.
2233
2362
  */
2363
+ /* eslint-disable-next-line complexity */
2234
2364
  static validateAttribute(attr, rules) {
2235
2365
  const rule = rules[attr.key];
2236
2366
  if (!rule) {
@@ -2244,19 +2374,34 @@ class Validator {
2244
2374
  return true;
2245
2375
  }
2246
2376
  const empty = value === null || value === "";
2247
- /* consider an empty array as being a boolean attribute */
2248
- if (rule.length === 0) {
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) {
2249
2380
  return empty || value === attr.key;
2250
2381
  }
2251
- /* if the empty string is present allow both "" and null
2252
- * (boolean-attribute-style will regulate which is allowed) */
2253
- if (rule.includes("") && empty) {
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) {
2254
2399
  return true;
2255
2400
  }
2256
2401
  if (value === null || value === undefined) {
2257
2402
  return false;
2258
2403
  }
2259
- return rule.some((entry) => {
2404
+ return rule.enum.some((entry) => {
2260
2405
  if (entry instanceof RegExp) {
2261
2406
  return !!value.match(entry);
2262
2407
  }
@@ -2522,12 +2667,12 @@ var configurationSchema = {
2522
2667
  const espree = legacyRequire("espree");
2523
2668
  const walk = legacyRequire("acorn-walk");
2524
2669
  function joinTemplateLiteral(nodes) {
2525
- let offset = nodes[0].start;
2670
+ let offset = nodes[0].start + 1;
2526
2671
  let output = "";
2527
2672
  for (const node of nodes) {
2528
- output += " ".repeat(node.start - offset);
2673
+ output += " ".repeat(node.start + 1 - offset);
2529
2674
  output += node.value.raw;
2530
- offset = node.end;
2675
+ offset = node.end - 2;
2531
2676
  }
2532
2677
  return output;
2533
2678
  }
@@ -2632,7 +2777,7 @@ class TemplateExtractor {
2632
2777
  this.data = data;
2633
2778
  }
2634
2779
  static fromFilename(filename) {
2635
- const source = fs__default['default'].readFileSync(filename, "utf-8");
2780
+ const source = fs__default["default"].readFileSync(filename, "utf-8");
2636
2781
  const ast = espree.parse(source, {
2637
2782
  ecmaVersion: 2017,
2638
2783
  sourceType: "module",
@@ -2668,7 +2813,7 @@ class TemplateExtractor {
2668
2813
  * functions.
2669
2814
  */
2670
2815
  static createSource(filename) {
2671
- const data = fs__default['default'].readFileSync(filename, "utf-8");
2816
+ const data = fs__default["default"].readFileSync(filename, "utf-8");
2672
2817
  return [
2673
2818
  {
2674
2819
  column: 1,
@@ -2719,7 +2864,7 @@ var TRANSFORMER_API;
2719
2864
  })(TRANSFORMER_API || (TRANSFORMER_API = {}));
2720
2865
 
2721
2866
  const name = "html-validate";
2722
- const version = "5.3.0";
2867
+ const version = "6.0.0";
2723
2868
  const homepage = "https://html-validate.org";
2724
2869
  const bugs = {
2725
2870
  url: "https://gitlab.com/html-validate/html-validate/issues/new"
@@ -2756,7 +2901,7 @@ const remapEvents = {
2756
2901
  "tag:open": "tag:start",
2757
2902
  "tag:close": "tag:end",
2758
2903
  };
2759
- const ajv$1 = new Ajv__default['default']({ strict: true, strictTuples: true, strictTypes: true });
2904
+ const ajv$1 = new Ajv__default["default"]({ strict: true, strictTuples: true, strictTypes: true });
2760
2905
  ajv$1.addMetaSchema(ajvSchemaDraft);
2761
2906
  /**
2762
2907
  * Get (cached) schema validator for rule options.
@@ -2984,9 +3129,9 @@ function ruleDocumentationUrl(filename) {
2984
3129
  * folder and with the @/ prefix, by replacing the @ with the dist folder we
2985
3130
  * can resolve the path properly */
2986
3131
  filename = filename.replace("@", distFolder);
2987
- const p = path__default['default'].parse(filename);
2988
- const root = path__default['default'].join(distFolder, "rules");
2989
- const rel = path__default['default'].relative(root, path__default['default'].join(p.dir, p.name));
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));
2990
3135
  return `${homepage}/rules/${rel}.html`;
2991
3136
  }
2992
3137
 
@@ -3011,7 +3156,7 @@ const description = {
3011
3156
  };
3012
3157
  class AllowedLinks extends Rule {
3013
3158
  constructor(options) {
3014
- super(Object.assign(Object.assign({}, defaults$p), options));
3159
+ super({ ...defaults$p, ...options });
3015
3160
  }
3016
3161
  static schema() {
3017
3162
  return {
@@ -3259,7 +3404,7 @@ const defaults$o = {
3259
3404
  };
3260
3405
  class AttrCase extends Rule {
3261
3406
  constructor(options) {
3262
- super(Object.assign(Object.assign({}, defaults$o), options));
3407
+ super({ ...defaults$o, ...options });
3263
3408
  this.style = new CaseStyle(this.options.style, "attr-case");
3264
3409
  }
3265
3410
  static schema() {
@@ -3612,7 +3757,7 @@ function generateDescription(name, pattern) {
3612
3757
  }
3613
3758
  class AttrPattern extends Rule {
3614
3759
  constructor(options) {
3615
- super(Object.assign(Object.assign({}, defaults$n), options));
3760
+ super({ ...defaults$n, ...options });
3616
3761
  this.pattern = generateRegexp(this.options.pattern);
3617
3762
  }
3618
3763
  static schema() {
@@ -3678,7 +3823,7 @@ const defaults$m = {
3678
3823
  };
3679
3824
  class AttrQuotes extends Rule {
3680
3825
  constructor(options) {
3681
- super(Object.assign(Object.assign({}, defaults$m), options));
3826
+ super({ ...defaults$m, ...options });
3682
3827
  this.style = parseStyle$4(this.options.style);
3683
3828
  }
3684
3829
  static schema() {
@@ -3774,11 +3919,11 @@ class AttributeAllowedValues extends Rule {
3774
3919
  if (!context) {
3775
3920
  return docs;
3776
3921
  }
3777
- if (context.allowed.length > 0) {
3778
- const allowed = context.allowed.map((val) => `- \`${val}\``);
3922
+ if (context.allowed.enum) {
3923
+ const allowed = context.allowed.enum.map((val) => `- \`${val}\``);
3779
3924
  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")}`;
3780
3925
  }
3781
- else {
3926
+ else if (context.allowed.boolean) {
3782
3927
  docs.description = `Element <${context.element}> attribute \`${context.attribute}\` must be a boolean attribute, e.g. \`<${context.element} ${context.attribute}>\``;
3783
3928
  }
3784
3929
  return docs;
@@ -3834,7 +3979,7 @@ const defaults$l = {
3834
3979
  };
3835
3980
  class AttributeBooleanStyle extends Rule {
3836
3981
  constructor(options) {
3837
- super(Object.assign(Object.assign({}, defaults$l), options));
3982
+ super({ ...defaults$l, ...options });
3838
3983
  this.hasInvalidStyle = parseStyle$3(this.options.style);
3839
3984
  }
3840
3985
  static schema() {
@@ -3879,7 +4024,8 @@ class AttributeBooleanStyle extends Rule {
3879
4024
  });
3880
4025
  }
3881
4026
  isBoolean(attr, rules) {
3882
- return rules[attr.key] && rules[attr.key].length === 0;
4027
+ var _a;
4028
+ return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.boolean);
3883
4029
  }
3884
4030
  }
3885
4031
  function parseStyle$3(style) {
@@ -3914,7 +4060,7 @@ const defaults$k = {
3914
4060
  };
3915
4061
  class AttributeEmptyStyle extends Rule {
3916
4062
  constructor(options) {
3917
- super(Object.assign(Object.assign({}, defaults$k), options));
4063
+ super({ ...defaults$k, ...options });
3918
4064
  this.hasInvalidStyle = parseStyle$2(this.options.style);
3919
4065
  }
3920
4066
  static schema() {
@@ -3963,7 +4109,8 @@ class AttributeEmptyStyle extends Rule {
3963
4109
  }
3964
4110
  }
3965
4111
  function allowsEmpty(attr, rules) {
3966
- return rules[attr.key] && rules[attr.key].includes("");
4112
+ var _a;
4113
+ return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.omit);
3967
4114
  }
3968
4115
  function isEmptyValue(attr) {
3969
4116
  /* dynamic values are ignored, assumed to contain a value */
@@ -4026,7 +4173,7 @@ const defaults$j = {
4026
4173
  };
4027
4174
  class ClassPattern extends Rule {
4028
4175
  constructor(options) {
4029
- super(Object.assign(Object.assign({}, defaults$j), options));
4176
+ super({ ...defaults$j, ...options });
4030
4177
  this.pattern = parsePattern(this.options.pattern);
4031
4178
  }
4032
4179
  static schema() {
@@ -4139,7 +4286,7 @@ const defaults$i = {
4139
4286
  };
4140
4287
  class Deprecated extends Rule {
4141
4288
  constructor(options) {
4142
- super(Object.assign(Object.assign({}, defaults$i), options));
4289
+ super({ ...defaults$i, ...options });
4143
4290
  }
4144
4291
  static schema() {
4145
4292
  return {
@@ -4233,7 +4380,7 @@ class Deprecated extends Rule {
4233
4380
  this.report(node, message, location, context);
4234
4381
  }
4235
4382
  reportObject(deprecated, node, location) {
4236
- const context = Object.assign(Object.assign({}, deprecated), { tagName: node.tagName });
4383
+ const context = { ...deprecated, tagName: node.tagName };
4237
4384
  const notice = deprecated.message ? `: ${deprecated.message}` : "";
4238
4385
  const message = `<${node.tagName}> is deprecated${notice}`;
4239
4386
  this.report(node, message, location, context);
@@ -4307,7 +4454,7 @@ const defaults$h = {
4307
4454
  };
4308
4455
  class DoctypeStyle extends Rule {
4309
4456
  constructor(options) {
4310
- super(Object.assign(Object.assign({}, defaults$h), options));
4457
+ super({ ...defaults$h, ...options });
4311
4458
  }
4312
4459
  static schema() {
4313
4460
  return {
@@ -4344,7 +4491,7 @@ const defaults$g = {
4344
4491
  };
4345
4492
  class ElementCase extends Rule {
4346
4493
  constructor(options) {
4347
- super(Object.assign(Object.assign({}, defaults$g), options));
4494
+ super({ ...defaults$g, ...options });
4348
4495
  this.style = new CaseStyle(this.options.style, "element-case");
4349
4496
  }
4350
4497
  static schema() {
@@ -4414,7 +4561,7 @@ const defaults$f = {
4414
4561
  };
4415
4562
  class ElementName extends Rule {
4416
4563
  constructor(options) {
4417
- super(Object.assign(Object.assign({}, defaults$f), options));
4564
+ super({ ...defaults$f, ...options });
4418
4565
  // eslint-disable-next-line security/detect-non-literal-regexp
4419
4566
  this.pattern = new RegExp(this.options.pattern);
4420
4567
  }
@@ -4686,9 +4833,14 @@ class ElementRequiredAttributes extends Rule {
4686
4833
  this.on("tag:end", (event) => {
4687
4834
  const node = event.previous;
4688
4835
  const meta = node.meta;
4689
- if (!meta || !meta.requiredAttributes)
4836
+ /* handle missing metadata and missing attributes */
4837
+ if (!meta || !meta.attributes) {
4690
4838
  return;
4691
- for (const key of meta.requiredAttributes) {
4839
+ }
4840
+ for (const [key, attr] of Object.entries(meta.attributes)) {
4841
+ if (!attr.required) {
4842
+ continue;
4843
+ }
4692
4844
  if (node.hasAttribute(key))
4693
4845
  continue;
4694
4846
  const context = {
@@ -4842,6 +4994,7 @@ class EmptyTitle extends Rule {
4842
4994
 
4843
4995
  const defaults$e = {
4844
4996
  allowMultipleH1: false,
4997
+ minInitialRank: "h1",
4845
4998
  sectioningRoots: ["dialog", '[role="dialog"]'],
4846
4999
  };
4847
5000
  function isRelevant$2(event) {
@@ -4857,10 +5010,22 @@ function extractLevel(node) {
4857
5010
  return null;
4858
5011
  }
4859
5012
  }
5013
+ function parseMaxInitial(value) {
5014
+ if (value === false || value === "any") {
5015
+ return 6;
5016
+ }
5017
+ const match = value.match(/^h(\d)$/);
5018
+ /* istanbul ignore next: should never happen, schema validation should catch invalid values */
5019
+ if (!match) {
5020
+ return 1;
5021
+ }
5022
+ return parseInt(match[1], 10);
5023
+ }
4860
5024
  class HeadingLevel extends Rule {
4861
5025
  constructor(options) {
4862
- super(Object.assign(Object.assign({}, defaults$e), options));
5026
+ super({ ...defaults$e, ...options });
4863
5027
  this.stack = [];
5028
+ this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
4864
5029
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
4865
5030
  /* add a global sectioning root used by default */
4866
5031
  this.stack.push({
@@ -4874,6 +5039,9 @@ class HeadingLevel extends Rule {
4874
5039
  allowMultipleH1: {
4875
5040
  type: "boolean",
4876
5041
  },
5042
+ minInitialRank: {
5043
+ enum: ["h1", "h2", "h3", "h4", "h5", "h6", "any", false],
5044
+ },
4877
5045
  sectioningRoots: {
4878
5046
  items: {
4879
5047
  type: "string",
@@ -4884,7 +5052,8 @@ class HeadingLevel extends Rule {
4884
5052
  }
4885
5053
  documentation() {
4886
5054
  const text = [];
4887
- text.push("Headings must start at <h1> and can only increase one level at a time.");
5055
+ const modality = this.minInitialRank > 1 ? "should" : "must";
5056
+ text.push(`Headings ${modality} start at <h1> and can only increase one level at a time.`);
4888
5057
  text.push("The headings should form a table of contents and make sense on its own.");
4889
5058
  if (!this.options.allowMultipleH1) {
4890
5059
  text.push("");
@@ -4929,20 +5098,32 @@ class HeadingLevel extends Rule {
4929
5098
  */
4930
5099
  checkLevelIncrementation(root, event, level) {
4931
5100
  const expected = root.current + 1;
4932
- if (level !== expected) {
4933
- const location = sliceLocation(event.location, 1);
4934
- if (root.current > 0) {
4935
- const msg = `Heading level can only increase by one, expected <h${expected}> but got <h${level}>`;
4936
- this.report(event.target, msg, location);
4937
- }
4938
- else {
4939
- this.checkInitialLevel(event, location, level, expected);
4940
- }
5101
+ /* check if the new level is the expected one (headings with higher ranks
5102
+ * are skipped already) */
5103
+ if (level === expected) {
5104
+ return;
5105
+ }
5106
+ /* if this is the initial heading of the document it is compared to the
5107
+ * minimal allowed (default h1) */
5108
+ const isInitial = this.stack.length === 1 && expected === 1;
5109
+ if (isInitial && level <= this.minInitialRank) {
5110
+ return;
5111
+ }
5112
+ /* if we reach this far the heading level is not accepted */
5113
+ const location = sliceLocation(event.location, 1);
5114
+ if (root.current > 0) {
5115
+ const msg = `Heading level can only increase by one, expected <h${expected}> but got <h${level}>`;
5116
+ this.report(event.target, msg, location);
5117
+ }
5118
+ else {
5119
+ this.checkInitialLevel(event, location, level, expected);
4941
5120
  }
4942
5121
  }
4943
5122
  checkInitialLevel(event, location, level, expected) {
4944
5123
  if (this.stack.length === 1) {
4945
- const msg = `Initial heading level must be <h${expected}> but got <h${level}>`;
5124
+ const msg = this.minInitialRank > 1
5125
+ ? `Initial heading level must be <h${this.minInitialRank}> or higher rank but got <h${level}>`
5126
+ : `Initial heading level must be <h${expected}> but got <h${level}>`;
4946
5127
  this.report(event.target, msg, location);
4947
5128
  }
4948
5129
  else {
@@ -5005,7 +5186,7 @@ const defaults$d = {
5005
5186
  };
5006
5187
  class IdPattern extends Rule {
5007
5188
  constructor(options) {
5008
- super(Object.assign(Object.assign({}, defaults$d), options));
5189
+ super({ ...defaults$d, ...options });
5009
5190
  this.pattern = parsePattern(this.options.pattern);
5010
5191
  }
5011
5192
  static schema() {
@@ -5357,7 +5538,7 @@ const defaults$c = {
5357
5538
  };
5358
5539
  class LongTitle extends Rule {
5359
5540
  constructor(options) {
5360
- super(Object.assign(Object.assign({}, defaults$c), options));
5541
+ super({ ...defaults$c, ...options });
5361
5542
  this.maxlength = this.options.maxlength;
5362
5543
  }
5363
5544
  static schema() {
@@ -5510,7 +5691,7 @@ const defaults$b = {
5510
5691
  };
5511
5692
  class NoAutoplay extends Rule {
5512
5693
  constructor(options) {
5513
- super(Object.assign(Object.assign({}, defaults$b), options));
5694
+ super({ ...defaults$b, ...options });
5514
5695
  }
5515
5696
  documentation(context) {
5516
5697
  const tagName = context ? ` on <${context.tagName}>` : "";
@@ -5606,8 +5787,12 @@ class NoDeprecatedAttr extends Rule {
5606
5787
  if (meta === null) {
5607
5788
  return;
5608
5789
  }
5609
- const deprecated = meta.deprecatedAttributes || [];
5610
- if (deprecated.includes(attr)) {
5790
+ const metaAttribute = meta.attributes && meta.attributes[attr];
5791
+ if (!metaAttribute) {
5792
+ return;
5793
+ }
5794
+ const deprecated = metaAttribute.deprecated;
5795
+ if (deprecated) {
5611
5796
  this.report(node, `Attribute "${event.key}" is deprecated on <${node.tagName}> element`, event.keyLocation);
5612
5797
  }
5613
5798
  });
@@ -5764,7 +5949,7 @@ function getCSSDeclarations(value) {
5764
5949
  }
5765
5950
  class NoInlineStyle extends Rule {
5766
5951
  constructor(options) {
5767
- super(Object.assign(Object.assign({}, defaults$a), options));
5952
+ super({ ...defaults$a, ...options });
5768
5953
  }
5769
5954
  static schema() {
5770
5955
  return {
@@ -5858,7 +6043,20 @@ class NoInlineStyle extends Rule {
5858
6043
  }
5859
6044
  }
5860
6045
 
5861
- const ARIA = ["aria-controls", "aria-describedby", "aria-labelledby"];
6046
+ const ARIA = [
6047
+ { property: "aria-activedescendant", isList: false },
6048
+ { property: "aria-controls", isList: true },
6049
+ { property: "aria-describedby", isList: true },
6050
+ { property: "aria-details", isList: false },
6051
+ { property: "aria-errormessage", isList: false },
6052
+ { property: "aria-flowto", isList: true },
6053
+ { property: "aria-labelledby", isList: true },
6054
+ { property: "aria-owns", isList: true },
6055
+ ];
6056
+ function idMissing(document, id) {
6057
+ const nodes = document.querySelectorAll(`[id="${id}"]`);
6058
+ return nodes.length === 0;
6059
+ }
5862
6060
  class NoMissingReferences extends Rule {
5863
6061
  documentation(context) {
5864
6062
  if (context) {
@@ -5880,38 +6078,56 @@ class NoMissingReferences extends Rule {
5880
6078
  /* verify <label for=".."> */
5881
6079
  for (const node of document.querySelectorAll("label[for]")) {
5882
6080
  const attr = node.getAttribute("for");
5883
- this.validateReference(document, node, attr);
6081
+ this.validateReference(document, node, attr, false);
5884
6082
  }
5885
6083
  /* verify <input list=".."> */
5886
6084
  for (const node of document.querySelectorAll("input[list]")) {
5887
6085
  const attr = node.getAttribute("list");
5888
- this.validateReference(document, node, attr);
6086
+ this.validateReference(document, node, attr, false);
5889
6087
  }
5890
6088
  /* verify WAI-ARIA properties */
5891
- for (const property of ARIA) {
6089
+ for (const { property, isList } of ARIA) {
5892
6090
  for (const node of document.querySelectorAll(`[${property}]`)) {
5893
6091
  const attr = node.getAttribute(property);
5894
- this.validateReference(document, node, attr);
6092
+ this.validateReference(document, node, attr, isList);
5895
6093
  }
5896
6094
  }
5897
6095
  });
5898
6096
  }
5899
- validateReference(document, node, attr) {
6097
+ validateReference(document, node, attr, isList) {
5900
6098
  /* sanity check: querySelector should never return elements without the attribute */
5901
6099
  /* istanbul ignore next */
5902
6100
  if (!attr) {
5903
6101
  return;
5904
6102
  }
5905
- const id = attr.value;
5906
- if (id instanceof DynamicValue || id === null || id === "") {
6103
+ /* skip dynamic and empty values */
6104
+ const value = attr.value;
6105
+ if (value instanceof DynamicValue || value === null || value === "") {
5907
6106
  return;
5908
6107
  }
5909
- const nodes = document.querySelectorAll(`[id="${id}"]`);
5910
- if (nodes.length === 0) {
6108
+ if (isList) {
6109
+ this.validateList(document, node, attr, value);
6110
+ }
6111
+ else {
6112
+ this.validateSingle(document, node, attr, value);
6113
+ }
6114
+ }
6115
+ validateSingle(document, node, attr, id) {
6116
+ if (idMissing(document, id)) {
5911
6117
  const context = { key: attr.key, value: id };
5912
6118
  this.report(node, `Element references missing id "${id}"`, attr.valueLocation, context);
5913
6119
  }
5914
6120
  }
6121
+ validateList(document, node, attr, values) {
6122
+ const parsed = new DOMTokenList(values, attr.valueLocation);
6123
+ for (const entry of parsed.iterator()) {
6124
+ const id = entry.item;
6125
+ if (idMissing(document, id)) {
6126
+ const context = { key: attr.key, value: id };
6127
+ this.report(node, `Element references missing id "${id}"`, entry.location, context);
6128
+ }
6129
+ }
6130
+ }
5915
6131
  }
5916
6132
 
5917
6133
  class NoMultipleMain extends Rule {
@@ -5955,7 +6171,7 @@ const replacementTable = new Map([
5955
6171
  ]);
5956
6172
  class NoRawCharacters extends Rule {
5957
6173
  constructor(options) {
5958
- super(Object.assign(Object.assign({}, defaults$9), options));
6174
+ super({ ...defaults$9, ...options });
5959
6175
  this.relaxed = this.options.relaxed;
5960
6176
  }
5961
6177
  static schema() {
@@ -6140,7 +6356,7 @@ const defaults$8 = {
6140
6356
  };
6141
6357
  class NoSelfClosing extends Rule {
6142
6358
  constructor(options) {
6143
- super(Object.assign(Object.assign({}, defaults$8), options));
6359
+ super({ ...defaults$8, ...options });
6144
6360
  }
6145
6361
  static schema() {
6146
6362
  return {
@@ -6279,7 +6495,7 @@ const defaults$7 = {
6279
6495
  };
6280
6496
  class PreferButton extends Rule {
6281
6497
  constructor(options) {
6282
- super(Object.assign(Object.assign({}, defaults$7), options));
6498
+ super({ ...defaults$7, ...options });
6283
6499
  }
6284
6500
  static schema() {
6285
6501
  return {
@@ -6384,7 +6600,7 @@ const defaults$6 = {
6384
6600
  };
6385
6601
  class PreferNativeElement extends Rule {
6386
6602
  constructor(options) {
6387
- super(Object.assign(Object.assign({}, defaults$6), options));
6603
+ super({ ...defaults$6, ...options });
6388
6604
  }
6389
6605
  static schema() {
6390
6606
  return {
@@ -6514,7 +6730,7 @@ const supportSri = {
6514
6730
  };
6515
6731
  class RequireSri extends Rule {
6516
6732
  constructor(options) {
6517
- super(Object.assign(Object.assign({}, defaults$5), options));
6733
+ super({ ...defaults$5, ...options });
6518
6734
  this.target = this.options.target;
6519
6735
  }
6520
6736
  static schema() {
@@ -8609,7 +8825,7 @@ const defaults$4 = {
8609
8825
  };
8610
8826
  class Void extends Rule {
8611
8827
  constructor(options) {
8612
- super(Object.assign(Object.assign({}, defaults$4), options));
8828
+ super({ ...defaults$4, ...options });
8613
8829
  this.style = parseStyle$1(this.options.style);
8614
8830
  }
8615
8831
  get deprecated() {
@@ -8718,7 +8934,7 @@ const defaults$3 = {
8718
8934
  };
8719
8935
  class VoidStyle extends Rule {
8720
8936
  constructor(options) {
8721
- super(Object.assign(Object.assign({}, defaults$3), options));
8937
+ super({ ...defaults$3, ...options });
8722
8938
  this.style = parseStyle(this.options.style);
8723
8939
  }
8724
8940
  static schema() {
@@ -8921,7 +9137,7 @@ const defaults$2 = {
8921
9137
  };
8922
9138
  class H37 extends Rule {
8923
9139
  constructor(options) {
8924
- super(Object.assign(Object.assign({}, defaults$2), options));
9140
+ super({ ...defaults$2, ...options });
8925
9141
  /* ensure alias is array */
8926
9142
  if (!Array.isArray(this.options.alias)) {
8927
9143
  this.options.alias = [this.options.alias];
@@ -9048,7 +9264,73 @@ const bundledRules$1 = {
9048
9264
  "wcag/h71": H71,
9049
9265
  };
9050
9266
 
9051
- const bundledRules = Object.assign({ "allowed-links": AllowedLinks, "aria-label-misuse": AriaLabelMisuse, "attr-case": AttrCase, "attr-delimiter": AttrDelimiter, "attr-pattern": AttrPattern, "attr-quotes": AttrQuotes, "attr-spacing": AttrSpacing, "attribute-allowed-values": AttributeAllowedValues, "attribute-boolean-style": AttributeBooleanStyle, "attribute-empty-style": AttributeEmptyStyle, "class-pattern": ClassPattern, "close-attr": CloseAttr, "close-order": CloseOrder, deprecated: Deprecated, "deprecated-rule": DeprecatedRule, "doctype-html": NoStyleTag$1, "doctype-style": DoctypeStyle, "element-case": ElementCase, "element-name": ElementName, "element-permitted-content": ElementPermittedContent, "element-permitted-occurrences": ElementPermittedOccurrences, "element-permitted-order": ElementPermittedOrder, "element-required-attributes": ElementRequiredAttributes, "element-required-content": ElementRequiredContent, "empty-heading": EmptyHeading, "empty-title": EmptyTitle, "heading-level": HeadingLevel, "id-pattern": IdPattern, "input-attributes": InputAttributes, "input-missing-label": InputMissingLabel, "long-title": LongTitle, "meta-refresh": MetaRefresh, "missing-doctype": MissingDoctype, "multiple-labeled-controls": MultipleLabeledControls, "no-autoplay": NoAutoplay, "no-conditional-comment": NoConditionalComment, "no-deprecated-attr": NoDeprecatedAttr, "no-dup-attr": NoDupAttr, "no-dup-class": NoDupClass, "no-dup-id": NoDupID, "no-implicit-close": NoImplicitClose, "no-inline-style": NoInlineStyle, "no-missing-references": NoMissingReferences, "no-multiple-main": NoMultipleMain, "no-raw-characters": NoRawCharacters, "no-redundant-for": NoRedundantFor, "no-redundant-role": NoRedundantRole, "no-self-closing": NoSelfClosing, "no-style-tag": NoStyleTag, "no-trailing-whitespace": NoTrailingWhitespace, "no-unknown-elements": NoUnknownElements, "no-utf8-bom": NoUtf8Bom, "prefer-button": PreferButton, "prefer-native-element": PreferNativeElement, "prefer-tbody": PreferTbody, "require-sri": RequireSri, "script-element": ScriptElement, "script-type": ScriptType, "svg-focusable": SvgFocusable, "text-content": TextContent, "unrecognized-char-ref": UnknownCharReference, void: Void, "void-content": VoidContent, "void-style": VoidStyle }, bundledRules$1);
9267
+ const bundledRules = {
9268
+ "allowed-links": AllowedLinks,
9269
+ "aria-label-misuse": AriaLabelMisuse,
9270
+ "attr-case": AttrCase,
9271
+ "attr-delimiter": AttrDelimiter,
9272
+ "attr-pattern": AttrPattern,
9273
+ "attr-quotes": AttrQuotes,
9274
+ "attr-spacing": AttrSpacing,
9275
+ "attribute-allowed-values": AttributeAllowedValues,
9276
+ "attribute-boolean-style": AttributeBooleanStyle,
9277
+ "attribute-empty-style": AttributeEmptyStyle,
9278
+ "class-pattern": ClassPattern,
9279
+ "close-attr": CloseAttr,
9280
+ "close-order": CloseOrder,
9281
+ deprecated: Deprecated,
9282
+ "deprecated-rule": DeprecatedRule,
9283
+ "doctype-html": NoStyleTag$1,
9284
+ "doctype-style": DoctypeStyle,
9285
+ "element-case": ElementCase,
9286
+ "element-name": ElementName,
9287
+ "element-permitted-content": ElementPermittedContent,
9288
+ "element-permitted-occurrences": ElementPermittedOccurrences,
9289
+ "element-permitted-order": ElementPermittedOrder,
9290
+ "element-required-attributes": ElementRequiredAttributes,
9291
+ "element-required-content": ElementRequiredContent,
9292
+ "empty-heading": EmptyHeading,
9293
+ "empty-title": EmptyTitle,
9294
+ "heading-level": HeadingLevel,
9295
+ "id-pattern": IdPattern,
9296
+ "input-attributes": InputAttributes,
9297
+ "input-missing-label": InputMissingLabel,
9298
+ "long-title": LongTitle,
9299
+ "meta-refresh": MetaRefresh,
9300
+ "missing-doctype": MissingDoctype,
9301
+ "multiple-labeled-controls": MultipleLabeledControls,
9302
+ "no-autoplay": NoAutoplay,
9303
+ "no-conditional-comment": NoConditionalComment,
9304
+ "no-deprecated-attr": NoDeprecatedAttr,
9305
+ "no-dup-attr": NoDupAttr,
9306
+ "no-dup-class": NoDupClass,
9307
+ "no-dup-id": NoDupID,
9308
+ "no-implicit-close": NoImplicitClose,
9309
+ "no-inline-style": NoInlineStyle,
9310
+ "no-missing-references": NoMissingReferences,
9311
+ "no-multiple-main": NoMultipleMain,
9312
+ "no-raw-characters": NoRawCharacters,
9313
+ "no-redundant-for": NoRedundantFor,
9314
+ "no-redundant-role": NoRedundantRole,
9315
+ "no-self-closing": NoSelfClosing,
9316
+ "no-style-tag": NoStyleTag,
9317
+ "no-trailing-whitespace": NoTrailingWhitespace,
9318
+ "no-unknown-elements": NoUnknownElements,
9319
+ "no-utf8-bom": NoUtf8Bom,
9320
+ "prefer-button": PreferButton,
9321
+ "prefer-native-element": PreferNativeElement,
9322
+ "prefer-tbody": PreferTbody,
9323
+ "require-sri": RequireSri,
9324
+ "script-element": ScriptElement,
9325
+ "script-type": ScriptType,
9326
+ "svg-focusable": SvgFocusable,
9327
+ "text-content": TextContent,
9328
+ "unrecognized-char-ref": UnknownCharReference,
9329
+ void: Void,
9330
+ "void-content": VoidContent,
9331
+ "void-style": VoidStyle,
9332
+ ...bundledRules$1,
9333
+ };
9052
9334
 
9053
9335
  var defaultConfig = {};
9054
9336
 
@@ -9254,7 +9536,7 @@ class ResolvedConfig {
9254
9536
  * @returns A list of transformed sources ready for validation.
9255
9537
  */
9256
9538
  transformFilename(filename) {
9257
- const data = fs__default['default'].readFileSync(filename, { encoding: "utf8" });
9539
+ const data = fs__default["default"].readFileSync(filename, { encoding: "utf8" });
9258
9540
  const source = {
9259
9541
  data,
9260
9542
  filename,
@@ -9279,19 +9561,19 @@ class ResolvedConfig {
9279
9561
  }
9280
9562
 
9281
9563
  let rootDirCache = null;
9282
- const ajv = new Ajv__default['default']({ strict: true, strictTuples: true, strictTypes: true });
9564
+ const ajv = new Ajv__default["default"]({ strict: true, strictTuples: true, strictTypes: true });
9283
9565
  ajv.addMetaSchema(ajvSchemaDraft);
9284
9566
  const validator = ajv.compile(configurationSchema);
9285
9567
  function overwriteMerge(a, b) {
9286
9568
  return b;
9287
9569
  }
9288
9570
  function mergeInternal(base, rhs) {
9289
- const dst = deepmerge__default['default'](base, Object.assign(Object.assign({}, rhs), { rules: {} }));
9571
+ const dst = deepmerge__default["default"](base, { ...rhs, rules: {} });
9290
9572
  /* rules need some special care, should overwrite arrays instead of
9291
9573
  * concaternation, i.e. ["error", {...options}] should not be merged by
9292
9574
  * appending to old value */
9293
9575
  if (rhs.rules) {
9294
- dst.rules = deepmerge__default['default'](dst.rules, rhs.rules, { arrayMerge: overwriteMerge });
9576
+ dst.rules = deepmerge__default["default"](dst.rules, rhs.rules, { arrayMerge: overwriteMerge });
9295
9577
  }
9296
9578
  /* root property is merged with boolean "or" since it should always be truthy
9297
9579
  * if any config has it set. */
@@ -9315,7 +9597,7 @@ function loadFromFile(filename) {
9315
9597
  if (!json[key])
9316
9598
  continue;
9317
9599
  json[key] = json[key].map((ref) => {
9318
- return Config.expandRelative(ref, path__default['default'].dirname(filename));
9600
+ return Config.expandRelative(ref, path__default["default"].dirname(filename));
9319
9601
  });
9320
9602
  }
9321
9603
  return json;
@@ -9474,14 +9756,14 @@ class Config {
9474
9756
  }
9475
9757
  let filename;
9476
9758
  /* try searching builtin metadata */
9477
- filename = path__default['default'].join(projectRoot, "elements", `${entry}.json`);
9478
- if (fs__default['default'].existsSync(filename)) {
9759
+ filename = path__default["default"].join(projectRoot, "elements", `${entry}.json`);
9760
+ if (fs__default["default"].existsSync(filename)) {
9479
9761
  metaTable.loadFromFile(filename);
9480
9762
  continue;
9481
9763
  }
9482
9764
  /* try as regular file */
9483
9765
  filename = entry.replace("<rootDir>", this.rootDir);
9484
- if (fs__default['default'].existsSync(filename)) {
9766
+ if (fs__default["default"].existsSync(filename)) {
9485
9767
  metaTable.loadFromFile(filename);
9486
9768
  continue;
9487
9769
  }
@@ -9501,7 +9783,7 @@ class Config {
9501
9783
  */
9502
9784
  static expandRelative(src, currentPath) {
9503
9785
  if (src[0] === ".") {
9504
- return path__default['default'].normalize(`${currentPath}/${src}`);
9786
+ return path__default["default"].normalize(`${currentPath}/${src}`);
9505
9787
  }
9506
9788
  return src;
9507
9789
  }
@@ -9511,7 +9793,7 @@ class Config {
9511
9793
  * @internal primary purpose is unittests
9512
9794
  */
9513
9795
  get() {
9514
- const config = Object.assign({}, this.config);
9796
+ const config = { ...this.config };
9515
9797
  if (config.elements) {
9516
9798
  config.elements = config.elements.map((cur) => {
9517
9799
  if (typeof cur === "string") {
@@ -9597,7 +9879,11 @@ class Config {
9597
9879
  if (!properties) {
9598
9880
  continue;
9599
9881
  }
9600
- for (const [key, schema] of Object.entries(properties)) {
9882
+ for (const [raw, schema] of Object.entries(properties)) {
9883
+ /* at compile time this is a fixed list but the point of this method is
9884
+ * to augment the runtime with additional keys so it is a bit of lying
9885
+ * to typescript */
9886
+ const key = raw;
9601
9887
  if (schema.copyable && !MetaCopyableProperty.includes(key)) {
9602
9888
  MetaCopyableProperty.push(key);
9603
9889
  }
@@ -9751,13 +10037,13 @@ class Config {
9751
10037
  let current = process.cwd();
9752
10038
  // eslint-disable-next-line no-constant-condition
9753
10039
  while (true) {
9754
- const search = path__default['default'].join(current, "package.json");
9755
- if (fs__default['default'].existsSync(search)) {
10040
+ const search = path__default["default"].join(current, "package.json");
10041
+ if (fs__default["default"].existsSync(search)) {
9756
10042
  return (this.rootDirCache = current);
9757
10043
  }
9758
10044
  /* get the parent directory */
9759
10045
  const child = current;
9760
- current = path__default['default'].dirname(current);
10046
+ current = path__default["default"].dirname(current);
9761
10047
  /* stop if this is the root directory */
9762
10048
  if (current === child) {
9763
10049
  break;
@@ -9793,31 +10079,6 @@ class ConfigLoader {
9793
10079
  }
9794
10080
  }
9795
10081
 
9796
- /*! *****************************************************************************
9797
- Copyright (c) Microsoft Corporation. All rights reserved.
9798
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
9799
- this file except in compliance with the License. You may obtain a copy of the
9800
- License at http://www.apache.org/licenses/LICENSE-2.0
9801
-
9802
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9803
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
9804
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
9805
- MERCHANTABLITY OR NON-INFRINGEMENT.
9806
-
9807
- See the Apache Version 2.0 License for specific language governing permissions
9808
- and limitations under the License.
9809
- ***************************************************************************** */
9810
-
9811
- function __rest(s, e) {
9812
- var t = {};
9813
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
9814
- t[p] = s[p];
9815
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
9816
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
9817
- t[p[i]] = s[p[i]];
9818
- return t;
9819
- }
9820
-
9821
10082
  class EventHandler {
9822
10083
  constructor() {
9823
10084
  this.listeners = {};
@@ -10391,7 +10652,7 @@ class Reporter {
10391
10652
  merged[key].messages = [...merged[key].messages, ...result.messages];
10392
10653
  }
10393
10654
  else {
10394
- merged[key] = Object.assign({}, result);
10655
+ merged[key] = { ...result };
10395
10656
  }
10396
10657
  });
10397
10658
  });
@@ -10493,14 +10754,16 @@ function messageSort(a, b) {
10493
10754
  }
10494
10755
 
10495
10756
  class Engine {
10496
- constructor(config, configData, ParserClass) {
10757
+ constructor(config, ParserClass) {
10497
10758
  this.report = new Reporter();
10498
- this.configData = configData;
10499
10759
  this.config = config;
10500
10760
  this.ParserClass = ParserClass;
10501
10761
  /* initialize plugins and rules */
10502
10762
  const result = this.initPlugins(this.config);
10503
- this.availableRules = Object.assign(Object.assign({}, bundledRules), result.availableRules);
10763
+ this.availableRules = {
10764
+ ...bundledRules,
10765
+ ...result.availableRules,
10766
+ };
10504
10767
  }
10505
10768
  /**
10506
10769
  * Lint sources and return report
@@ -10525,13 +10788,13 @@ class Engine {
10525
10788
  /* trigger configuration ready event */
10526
10789
  const configEvent = {
10527
10790
  location,
10528
- config: this.configData,
10791
+ config: this.config,
10529
10792
  rules,
10530
10793
  };
10531
10794
  parser.trigger("config:ready", configEvent);
10532
10795
  /* trigger source ready event */
10533
10796
  /* eslint-disable-next-line @typescript-eslint/no-unused-vars -- object destructured on purpose to remove property */
10534
- const sourceData = __rest(source, ["hooks"]);
10797
+ const { hooks: _, ...sourceData } = source;
10535
10798
  const sourceEvent = {
10536
10799
  location,
10537
10800
  source: sourceData,
@@ -10838,133 +11101,31 @@ class Engine {
10838
11101
  }
10839
11102
 
10840
11103
  /**
10841
- * @internal
10842
- */
10843
- function findConfigurationFiles(directory) {
10844
- return ["json", "cjs", "js"]
10845
- .map((extension) => path__default['default'].join(directory, `.htmlvalidate.${extension}`))
10846
- .filter((filePath) => fs__default['default'].existsSync(filePath));
10847
- }
10848
- /**
10849
- * Loads configuration by traversing filesystem.
10850
- *
10851
- * Configuration is read from three sources and in the following order:
10852
- *
10853
- * 1. Global configuration passed to constructor.
10854
- * 2. Configuration files found when traversing the directory structure.
10855
- * 3. Override passed to this function.
10856
- *
10857
- * The following configuration filenames are searched:
10858
- *
10859
- * - `.htmlvalidate.json`
10860
- * - `.htmlvalidate.js`
10861
- * - `.htmlvalidate.cjs`
10862
- *
10863
- * Global configuration is used when no configuration file is found. The
10864
- * result is always merged with override if present.
10865
- *
10866
- * The `root` property set to `true` affects the configuration as following:
11104
+ * The static configuration loader does not do any per-handle lookup. Only the
11105
+ * global or per-call configuration is used.
10867
11106
  *
10868
- * 1. If set in override the override is returned as-is.
10869
- * 2. If set in the global config the override is merged into global and
10870
- * returned. No configuration files are searched.
10871
- * 3. Setting `root` in configuration file only stops directory traversal.
11107
+ * In practice this means no configuration is fetch by traversing the
11108
+ * filesystem.
10872
11109
  */
10873
- class FileSystemConfigLoader extends ConfigLoader {
10874
- /**
10875
- * @param config - Global configuration
10876
- * @param configFactory - Optional configuration factory
10877
- */
10878
- constructor(config, configFactory = Config) {
10879
- super(config, configFactory);
10880
- this.cache = new Map();
10881
- }
10882
- /**
10883
- * Get configuration for given filename.
10884
- *
10885
- * @param filename - Filename to get configuration for.
10886
- * @param configOverride - Configuration to merge final result with.
10887
- */
10888
- getConfigFor(filename, configOverride) {
10889
- /* special case when the overridden configuration is marked as root, should
10890
- * not try to load any more configuration files */
11110
+ class StaticConfigLoader extends ConfigLoader {
11111
+ getConfigFor(handle, configOverride) {
10891
11112
  const override = this.loadFromObject(configOverride || {});
10892
11113
  if (override.isRootFound()) {
10893
11114
  override.init();
10894
11115
  return override;
10895
11116
  }
10896
- /* special case when the global configuration is marked as root, should not
10897
- * try to load and more configuration files */
10898
- if (this.globalConfig.isRootFound()) {
10899
- const merged = this.globalConfig.merge(override);
10900
- merged.init();
10901
- return merged;
10902
- }
10903
- const config = this.fromFilename(filename);
10904
- const merged = config ? config.merge(override) : this.globalConfig.merge(override);
11117
+ const merged = this.globalConfig.merge(override);
10905
11118
  merged.init();
10906
11119
  return merged;
10907
11120
  }
10908
- /**
10909
- * Flush configuration cache.
10910
- *
10911
- * @param filename - If given only the cache for that file is flushed.
10912
- */
10913
- flushCache(filename) {
10914
- if (filename) {
10915
- this.cache.delete(filename);
10916
- }
10917
- else {
10918
- this.cache.clear();
10919
- }
10920
- }
10921
- /**
10922
- * Load raw configuration from directory traversal.
10923
- *
10924
- * This configuration is not merged with global configuration and may return
10925
- * `null` if no configuration files are found.
10926
- */
10927
- fromFilename(filename) {
10928
- var _a;
10929
- if (filename === "inline") {
10930
- return null;
10931
- }
10932
- if (this.cache.has(filename)) {
10933
- return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
10934
- }
10935
- let found = false;
10936
- let current = path__default['default'].resolve(path__default['default'].dirname(filename));
10937
- let config = this.empty();
10938
- // eslint-disable-next-line no-constant-condition
10939
- while (true) {
10940
- /* search configuration files in current directory */
10941
- for (const configFile of findConfigurationFiles(current)) {
10942
- const local = this.loadFromFile(configFile);
10943
- found = true;
10944
- config = local.merge(config);
10945
- }
10946
- /* stop if a configuration with "root" is set to true */
10947
- if (config.isRootFound()) {
10948
- break;
10949
- }
10950
- /* get the parent directory */
10951
- const child = current;
10952
- current = path__default['default'].dirname(current);
10953
- /* stop if this is the root directory */
10954
- if (current === child) {
10955
- break;
10956
- }
10957
- }
10958
- /* no config was found by loader, return null and let caller decide what to do */
10959
- if (!found) {
10960
- this.cache.set(filename, null);
10961
- return null;
10962
- }
10963
- this.cache.set(filename, config);
10964
- return config;
11121
+ flushCache() {
11122
+ /* do nothing */
10965
11123
  }
10966
11124
  defaultConfig() {
10967
- return this.configFactory.defaultConfig();
11125
+ return this.loadFromObject({
11126
+ extends: ["html-validate:recommended"],
11127
+ elements: ["html5"],
11128
+ });
10968
11129
  }
10969
11130
  }
10970
11131
 
@@ -10988,7 +11149,7 @@ function isConfigData(value) {
10988
11149
  class HtmlValidate {
10989
11150
  constructor(arg) {
10990
11151
  const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
10991
- this.configLoader = loader !== null && loader !== void 0 ? loader : new FileSystemConfigLoader(config);
11152
+ this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
10992
11153
  }
10993
11154
  validateString(str, arg1, arg2, arg3) {
10994
11155
  const filename = typeof arg1 === "string" ? arg1 : "inline";
@@ -11015,7 +11176,7 @@ class HtmlValidate {
11015
11176
  const config = this.getConfigFor(input.filename, configOverride);
11016
11177
  const resolved = config.resolve();
11017
11178
  const source = resolved.transformSource(input);
11018
- const engine = new Engine(resolved, config.get(), Parser);
11179
+ const engine = new Engine(resolved, Parser);
11019
11180
  return engine.lint(source);
11020
11181
  }
11021
11182
  /**
@@ -11029,7 +11190,7 @@ class HtmlValidate {
11029
11190
  const config = this.getConfigFor(filename);
11030
11191
  const resolved = config.resolve();
11031
11192
  const source = resolved.transformFilename(filename);
11032
- const engine = new Engine(resolved, config.get(), Parser);
11193
+ const engine = new Engine(resolved, Parser);
11033
11194
  return engine.lint(source);
11034
11195
  }
11035
11196
  /**
@@ -11053,7 +11214,7 @@ class HtmlValidate {
11053
11214
  */
11054
11215
  canValidate(filename) {
11055
11216
  /* .html is always supported */
11056
- const extension = path__default['default'].extname(filename).toLowerCase();
11217
+ const extension = path__default["default"].extname(filename).toLowerCase();
11057
11218
  if (extension === ".html") {
11058
11219
  return true;
11059
11220
  }
@@ -11074,7 +11235,7 @@ class HtmlValidate {
11074
11235
  const config = this.getConfigFor(filename);
11075
11236
  const resolved = config.resolve();
11076
11237
  const source = resolved.transformFilename(filename);
11077
- const engine = new Engine(resolved, config.get(), Parser);
11238
+ const engine = new Engine(resolved, Parser);
11078
11239
  return engine.dumpTokens(source);
11079
11240
  }
11080
11241
  /**
@@ -11089,7 +11250,7 @@ class HtmlValidate {
11089
11250
  const config = this.getConfigFor(filename);
11090
11251
  const resolved = config.resolve();
11091
11252
  const source = resolved.transformFilename(filename);
11092
- const engine = new Engine(resolved, config.get(), Parser);
11253
+ const engine = new Engine(resolved, Parser);
11093
11254
  return engine.dumpEvents(source);
11094
11255
  }
11095
11256
  /**
@@ -11104,7 +11265,7 @@ class HtmlValidate {
11104
11265
  const config = this.getConfigFor(filename);
11105
11266
  const resolved = config.resolve();
11106
11267
  const source = resolved.transformFilename(filename);
11107
- const engine = new Engine(resolved, config.get(), Parser);
11268
+ const engine = new Engine(resolved, Parser);
11108
11269
  return engine.dumpTree(source);
11109
11270
  }
11110
11271
  /**
@@ -11182,7 +11343,7 @@ class HtmlValidate {
11182
11343
  */
11183
11344
  getRuleDocumentation(ruleId, config = null, context = null) {
11184
11345
  const c = config || this.getConfigFor("inline");
11185
- const engine = new Engine(c.resolve(), c.get(), Parser);
11346
+ const engine = new Engine(c.resolve(), Parser);
11186
11347
  return engine.getRuleDocumentation(ruleId, context);
11187
11348
  }
11188
11349
  /**
@@ -11219,41 +11380,12 @@ class HtmlValidate {
11219
11380
  }
11220
11381
  }
11221
11382
 
11222
- /**
11223
- * The static configuration loader does not do any per-handle lookup. Only the
11224
- * global or per-call configuration is used.
11225
- *
11226
- * In practice this means no configuration is fetch by traversing the
11227
- * filesystem.
11228
- */
11229
- class StaticConfigLoader extends ConfigLoader {
11230
- getConfigFor(handle, configOverride) {
11231
- const override = this.loadFromObject(configOverride || {});
11232
- if (override.isRootFound()) {
11233
- override.init();
11234
- return override;
11235
- }
11236
- const merged = this.globalConfig.merge(override);
11237
- merged.init();
11238
- return merged;
11239
- }
11240
- flushCache() {
11241
- /* do nothing */
11242
- }
11243
- defaultConfig() {
11244
- return this.loadFromObject({
11245
- extends: ["html-validate:recommended"],
11246
- elements: ["html5"],
11247
- });
11248
- }
11249
- }
11250
-
11251
11383
  const defaults$1 = {
11252
11384
  silent: false,
11253
11385
  version,
11254
11386
  logger(text) {
11255
11387
  /* eslint-disable-next-line no-console */
11256
- console.error(kleur__default['default'].red(text));
11388
+ console.error(kleur__default["default"].red(text));
11257
11389
  },
11258
11390
  };
11259
11391
  /**
@@ -11265,8 +11397,8 @@ const defaults$1 = {
11265
11397
  * @returns - `true` if version is compatible
11266
11398
  */
11267
11399
  function compatibilityCheck(name, declared, options) {
11268
- const { silent, version: current, logger } = Object.assign(Object.assign({}, defaults$1), options);
11269
- const valid = semver__default['default'].satisfies(current, declared);
11400
+ const { silent, version: current, logger } = { ...defaults$1, ...options };
11401
+ const valid = semver__default["default"].satisfies(current, declared);
11270
11402
  if (valid || silent) {
11271
11403
  return valid;
11272
11404
  }
@@ -11295,6 +11427,137 @@ function ruleExists(ruleId) {
11295
11427
  return ruleIds.has(ruleId);
11296
11428
  }
11297
11429
 
11430
+ /**
11431
+ * @internal
11432
+ */
11433
+ function findConfigurationFiles(directory) {
11434
+ return ["json", "cjs", "js"]
11435
+ .map((extension) => path__default["default"].join(directory, `.htmlvalidate.${extension}`))
11436
+ .filter((filePath) => fs__default["default"].existsSync(filePath));
11437
+ }
11438
+ /**
11439
+ * Loads configuration by traversing filesystem.
11440
+ *
11441
+ * Configuration is read from three sources and in the following order:
11442
+ *
11443
+ * 1. Global configuration passed to constructor.
11444
+ * 2. Configuration files found when traversing the directory structure.
11445
+ * 3. Override passed to this function.
11446
+ *
11447
+ * The following configuration filenames are searched:
11448
+ *
11449
+ * - `.htmlvalidate.json`
11450
+ * - `.htmlvalidate.js`
11451
+ * - `.htmlvalidate.cjs`
11452
+ *
11453
+ * Global configuration is used when no configuration file is found. The
11454
+ * result is always merged with override if present.
11455
+ *
11456
+ * The `root` property set to `true` affects the configuration as following:
11457
+ *
11458
+ * 1. If set in override the override is returned as-is.
11459
+ * 2. If set in the global config the override is merged into global and
11460
+ * returned. No configuration files are searched.
11461
+ * 3. Setting `root` in configuration file only stops directory traversal.
11462
+ */
11463
+ class FileSystemConfigLoader extends ConfigLoader {
11464
+ /**
11465
+ * @param config - Global configuration
11466
+ * @param configFactory - Optional configuration factory
11467
+ */
11468
+ constructor(config, configFactory = Config) {
11469
+ super(config, configFactory);
11470
+ this.cache = new Map();
11471
+ }
11472
+ /**
11473
+ * Get configuration for given filename.
11474
+ *
11475
+ * @param filename - Filename to get configuration for.
11476
+ * @param configOverride - Configuration to merge final result with.
11477
+ */
11478
+ getConfigFor(filename, configOverride) {
11479
+ /* special case when the overridden configuration is marked as root, should
11480
+ * not try to load any more configuration files */
11481
+ const override = this.loadFromObject(configOverride || {});
11482
+ if (override.isRootFound()) {
11483
+ override.init();
11484
+ return override;
11485
+ }
11486
+ /* special case when the global configuration is marked as root, should not
11487
+ * try to load and more configuration files */
11488
+ if (this.globalConfig.isRootFound()) {
11489
+ const merged = this.globalConfig.merge(override);
11490
+ merged.init();
11491
+ return merged;
11492
+ }
11493
+ const config = this.fromFilename(filename);
11494
+ const merged = config ? config.merge(override) : this.globalConfig.merge(override);
11495
+ merged.init();
11496
+ return merged;
11497
+ }
11498
+ /**
11499
+ * Flush configuration cache.
11500
+ *
11501
+ * @param filename - If given only the cache for that file is flushed.
11502
+ */
11503
+ flushCache(filename) {
11504
+ if (filename) {
11505
+ this.cache.delete(filename);
11506
+ }
11507
+ else {
11508
+ this.cache.clear();
11509
+ }
11510
+ }
11511
+ /**
11512
+ * Load raw configuration from directory traversal.
11513
+ *
11514
+ * This configuration is not merged with global configuration and may return
11515
+ * `null` if no configuration files are found.
11516
+ */
11517
+ fromFilename(filename) {
11518
+ var _a;
11519
+ if (filename === "inline") {
11520
+ return null;
11521
+ }
11522
+ if (this.cache.has(filename)) {
11523
+ return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
11524
+ }
11525
+ let found = false;
11526
+ let current = path__default["default"].resolve(path__default["default"].dirname(filename));
11527
+ let config = this.empty();
11528
+ // eslint-disable-next-line no-constant-condition
11529
+ while (true) {
11530
+ /* search configuration files in current directory */
11531
+ for (const configFile of findConfigurationFiles(current)) {
11532
+ const local = this.loadFromFile(configFile);
11533
+ found = true;
11534
+ config = local.merge(config);
11535
+ }
11536
+ /* stop if a configuration with "root" is set to true */
11537
+ if (config.isRootFound()) {
11538
+ break;
11539
+ }
11540
+ /* get the parent directory */
11541
+ const child = current;
11542
+ current = path__default["default"].dirname(current);
11543
+ /* stop if this is the root directory */
11544
+ if (current === child) {
11545
+ break;
11546
+ }
11547
+ }
11548
+ /* no config was found by loader, return null and let caller decide what to do */
11549
+ if (!found) {
11550
+ this.cache.set(filename, null);
11551
+ return null;
11552
+ }
11553
+ this.cache.set(filename, config);
11554
+ return config;
11555
+ }
11556
+ defaultConfig() {
11557
+ return this.configFactory.defaultConfig();
11558
+ }
11559
+ }
11560
+
11298
11561
  const entities = {
11299
11562
  ">": "&gt;",
11300
11563
  "<": "&lt;",
@@ -11366,12 +11629,12 @@ function pluralize(word, count) {
11366
11629
  * @returns The formatted file path.
11367
11630
  */
11368
11631
  function formatFilePath(filePath, line, column) {
11369
- let relPath = path__default['default'].relative(process.cwd(), filePath);
11632
+ let relPath = path__default["default"].relative(process.cwd(), filePath);
11370
11633
  /* istanbul ignore next: safety check from original implementation */
11371
11634
  if (line && column) {
11372
11635
  relPath += `:${line}:${column}`;
11373
11636
  }
11374
- return kleur__default['default'].green(relPath);
11637
+ return kleur__default["default"].green(relPath);
11375
11638
  }
11376
11639
  function getStartLocation(message) {
11377
11640
  return {
@@ -11400,9 +11663,9 @@ function getEndLocation(message, source) {
11400
11663
  * @returns The formatted output.
11401
11664
  */
11402
11665
  function formatMessage(message, parentResult, options) {
11403
- const type = message.severity === 2 ? kleur__default['default'].red("error") : kleur__default['default'].yellow("warning");
11404
- const msg = `${kleur__default['default'].bold(message.message.replace(/([^ ])\.$/, "$1"))}`;
11405
- const ruleId = kleur__default['default'].dim(`(${message.ruleId})`);
11666
+ const type = message.severity === 2 ? kleur__default["default"].red("error") : kleur__default["default"].yellow("warning");
11667
+ const msg = `${kleur__default["default"].bold(message.message.replace(/([^ ])\.$/, "$1"))}`;
11668
+ const ruleId = kleur__default["default"].dim(`(${message.ruleId})`);
11406
11669
  const filePath = formatFilePath(parentResult.filePath, message.line, message.column);
11407
11670
  const sourceCode = parentResult.source;
11408
11671
  /* istanbul ignore next: safety check from original implementation */
@@ -11423,7 +11686,7 @@ function formatMessage(message, parentResult, options) {
11423
11686
  }, { highlightCode: false }));
11424
11687
  }
11425
11688
  if (options.showLink && message.ruleUrl) {
11426
- result.push(`${kleur__default['default'].bold("Details:")} ${message.ruleUrl}`);
11689
+ result.push(`${kleur__default["default"].bold("Details:")} ${message.ruleUrl}`);
11427
11690
  }
11428
11691
  return result.join("\n");
11429
11692
  }
@@ -11442,10 +11705,10 @@ function formatSummary(errors, warnings) {
11442
11705
  if (warnings > 0) {
11443
11706
  summary.push(`${warnings} ${pluralize("warning", warnings)}`);
11444
11707
  }
11445
- return kleur__default['default'][summaryColor]().bold(`${summary.join(" and ")} found.`);
11708
+ return kleur__default["default"][summaryColor]().bold(`${summary.join(" and ")} found.`);
11446
11709
  }
11447
11710
  function codeframe(results, options) {
11448
- const merged = Object.assign(Object.assign({}, defaults), options);
11711
+ const merged = { ...defaults, ...options };
11449
11712
  let errors = 0;
11450
11713
  let warnings = 0;
11451
11714
  const resultsWithMessages = results.filter((result) => result.messages.length > 0);
@@ -11483,10 +11746,14 @@ function linkSummary(results) {
11483
11746
  return "";
11484
11747
  }
11485
11748
  const lines = unique.map((url) => ` ${url}\n`);
11486
- return `\n${kleur__default['default'].bold("More information")}:\n${lines.join("")}\n`;
11749
+ return `\n${kleur__default["default"].bold("More information")}:\n${lines.join("")}\n`;
11487
11750
  }
11488
11751
  function stylish(results) {
11489
- const errors = stylishImpl__default['default'](results.map((it) => (Object.assign(Object.assign({}, it), { fixableErrorCount: 0, fixableWarningCount: 0 }))));
11752
+ const errors = stylishImpl__default["default"](results.map((it) => ({
11753
+ ...it,
11754
+ fixableErrorCount: 0,
11755
+ fixableWarningCount: 0,
11756
+ })));
11490
11757
  const links = linkSummary(results);
11491
11758
  return `${errors}${links}`;
11492
11759
  }