html-validate 5.5.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/core.js CHANGED
@@ -574,18 +574,63 @@ const definitions = {
574
574
  type: "object",
575
575
  patternProperties: {
576
576
  "^.*$": {
577
- type: "array",
578
- uniqueItems: true,
579
- items: {
580
- anyOf: [
581
- {
577
+ anyOf: [
578
+ {
579
+ type: "object",
580
+ additionalProperties: false,
581
+ properties: {
582
+ boolean: {
583
+ type: "boolean",
584
+ title: "Set to true if this is a boolean attribute"
585
+ },
586
+ deprecated: {
587
+ title: "Set to true or string if this attribute is deprecated",
588
+ oneOf: [
589
+ {
590
+ type: "boolean"
591
+ },
592
+ {
593
+ type: "string"
594
+ }
595
+ ]
596
+ },
597
+ list: {
598
+ type: "boolean",
599
+ title: "Set to true if this attribute is a list of space-separated tokens, each which must be valid by itself"
600
+ },
601
+ "enum": {
602
+ type: "array",
603
+ title: "Exhaustive list of values (string or regex) this attribute accepts",
604
+ uniqueItems: true,
605
+ items: {
606
+ anyOf: [
607
+ {
608
+ type: "string"
609
+ },
610
+ {
611
+ regexp: true
612
+ }
613
+ ]
614
+ }
615
+ },
616
+ omit: {
617
+ type: "boolean",
618
+ title: "Set to true if this attribute can optionally omit its value"
619
+ },
620
+ required: {
621
+ type: "boolean",
622
+ title: "Set to true if this attribute is required"
623
+ }
624
+ }
625
+ },
626
+ {
627
+ type: "array",
628
+ uniqueItems: true,
629
+ items: {
582
630
  type: "string"
583
- },
584
- {
585
- regexp: true
586
631
  }
587
- ]
588
- }
632
+ }
633
+ ]
589
634
  }
590
635
  }
591
636
  },
@@ -636,6 +681,111 @@ var schema = {
636
681
  definitions: definitions
637
682
  };
638
683
 
684
+ var TextContent$1;
685
+ (function (TextContent) {
686
+ /* forbid node to have text content, inter-element whitespace is ignored */
687
+ TextContent["NONE"] = "none";
688
+ /* node can have text but not required too */
689
+ TextContent["DEFAULT"] = "default";
690
+ /* node requires text-nodes to be present (direct or by descendant) */
691
+ TextContent["REQUIRED"] = "required";
692
+ /* node requires accessible text (hidden text is ignored, tries to get text from accessibility tree) */
693
+ TextContent["ACCESSIBLE"] = "accessible";
694
+ })(TextContent$1 || (TextContent$1 = {}));
695
+ /**
696
+ * Properties listed here can be copied (loaded) onto another element using
697
+ * [[HtmlElement.loadMeta]].
698
+ */
699
+ const MetaCopyableProperty = [
700
+ "metadata",
701
+ "flow",
702
+ "sectioning",
703
+ "heading",
704
+ "phrasing",
705
+ "embedded",
706
+ "interactive",
707
+ "transparent",
708
+ "form",
709
+ "labelable",
710
+ "attributes",
711
+ "permittedContent",
712
+ "permittedDescendants",
713
+ "permittedOrder",
714
+ "requiredAncestors",
715
+ "requiredContent",
716
+ ];
717
+ /**
718
+ * @internal
719
+ */
720
+ function setMetaProperty(dst, key, value) {
721
+ dst[key] = value;
722
+ }
723
+
724
+ function isSet(value) {
725
+ return typeof value !== "undefined";
726
+ }
727
+ function flag(value) {
728
+ return value ? true : undefined;
729
+ }
730
+ function stripUndefined(src) {
731
+ const entries = Object.entries(src).filter(([, value]) => isSet(value));
732
+ return Object.fromEntries(entries);
733
+ }
734
+ function migrateSingleAttribute(src, key) {
735
+ var _a, _b;
736
+ const result = {};
737
+ result.deprecated = flag((_a = src.deprecatedAttributes) === null || _a === void 0 ? void 0 : _a.includes(key));
738
+ result.required = flag((_b = src.requiredAttributes) === null || _b === void 0 ? void 0 : _b.includes(key));
739
+ result.omit = undefined;
740
+ const attr = src.attributes ? src.attributes[key] : undefined;
741
+ if (typeof attr === "undefined") {
742
+ return stripUndefined(result);
743
+ }
744
+ /* when the attribute is set to null we use a special property "delete" to
745
+ * flag it, if it is still set during merge (inheritance, overwriting, etc) the attribute will be removed */
746
+ if (attr === null) {
747
+ result.delete = true;
748
+ return stripUndefined(result);
749
+ }
750
+ if (Array.isArray(attr)) {
751
+ if (attr.length === 0) {
752
+ result.boolean = true;
753
+ }
754
+ else {
755
+ result.enum = attr.filter((it) => it !== "");
756
+ if (attr.includes("")) {
757
+ result.omit = true;
758
+ }
759
+ }
760
+ return stripUndefined(result);
761
+ }
762
+ else {
763
+ return stripUndefined({ ...result, ...attr });
764
+ }
765
+ }
766
+ function migrateAttributes(src) {
767
+ var _a, _b, _c;
768
+ const keys = [
769
+ ...Object.keys((_a = src.attributes) !== null && _a !== void 0 ? _a : {}),
770
+ ...((_b = src.requiredAttributes) !== null && _b !== void 0 ? _b : []),
771
+ ...((_c = src.deprecatedAttributes) !== null && _c !== void 0 ? _c : []),
772
+ ].sort();
773
+ const entries = keys.map((key) => {
774
+ return [key, migrateSingleAttribute(src, key)];
775
+ });
776
+ return Object.fromEntries(entries);
777
+ }
778
+ function migrateElement(src) {
779
+ const result = {
780
+ ...src,
781
+ attributes: migrateAttributes(src),
782
+ };
783
+ /* removed properties */
784
+ delete result.deprecatedAttributes;
785
+ delete result.requiredAttributes;
786
+ return result;
787
+ }
788
+
639
789
  const dynamicKeys = [
640
790
  "metadata",
641
791
  "flow",
@@ -729,7 +879,7 @@ class MetaTable {
729
879
  for (const [key, value] of Object.entries(obj)) {
730
880
  if (key === "$schema")
731
881
  continue;
732
- this.addEntry(key, value);
882
+ this.addEntry(key, migrateElement(value));
733
883
  }
734
884
  }
735
885
  /**
@@ -757,7 +907,7 @@ class MetaTable {
757
907
  */
758
908
  getMetaFor(tagName) {
759
909
  tagName = tagName.toLowerCase();
760
- return this.elements[tagName] ? Object.assign({}, this.elements[tagName]) : null;
910
+ return this.elements[tagName] ? { ...this.elements[tagName] } : null;
761
911
  }
762
912
  /**
763
913
  * Find all tags which has enabled given property.
@@ -786,7 +936,7 @@ class MetaTable {
786
936
  }
787
937
  }
788
938
  /* merge all sources together */
789
- const expanded = deepmerge(parent, Object.assign(Object.assign({}, entry), { tagName }), { arrayMerge: overwriteMerge$1 });
939
+ const expanded = this.mergeElement(parent, { ...entry, tagName });
790
940
  expandRegex(expanded);
791
941
  this.elements[tagName] = expanded;
792
942
  }
@@ -824,7 +974,16 @@ class MetaTable {
824
974
  }
825
975
  }
826
976
  mergeElement(a, b) {
827
- return deepmerge(a, b, { arrayMerge: overwriteMerge$1 });
977
+ const merged = deepmerge(a, b, { arrayMerge: overwriteMerge$1 });
978
+ /* special handling when removing attributes by setting them to null
979
+ * resulting in the deletion flag being set */
980
+ const filteredAttrs = Object.entries(merged.attributes).filter(([, attr]) => {
981
+ const val = !attr.delete;
982
+ delete attr.delete;
983
+ return val;
984
+ });
985
+ merged.attributes = Object.fromEntries(filteredAttrs);
986
+ return merged;
828
987
  }
829
988
  resolve(node) {
830
989
  if (node.meta) {
@@ -836,7 +995,7 @@ function expandProperties(node, entry) {
836
995
  for (const key of dynamicKeys) {
837
996
  const property = entry[key];
838
997
  if (property && typeof property !== "boolean") {
839
- entry[key] = evaluateProperty(node, property);
998
+ setMetaProperty(entry, key, evaluateProperty(node, property));
840
999
  }
841
1000
  }
842
1001
  }
@@ -862,14 +1021,9 @@ function expandRegexValue(value) {
862
1021
  * Expand all regular expressions in strings ("/../"). This mutates the object.
863
1022
  */
864
1023
  function expandRegex(entry) {
865
- if (!entry.attributes)
866
- return;
867
1024
  for (const [name, values] of Object.entries(entry.attributes)) {
868
- if (values) {
869
- entry.attributes[name] = values.map(expandRegexValue);
870
- }
871
- else {
872
- delete entry.attributes[name];
1025
+ if (values.enum) {
1026
+ entry.attributes[name].enum = values.enum.map(expandRegexValue);
873
1027
  }
874
1028
  }
875
1029
  }
@@ -925,41 +1079,6 @@ function matchAttribute(node, match) {
925
1079
  }
926
1080
  }
927
1081
 
928
- var TextContent$1;
929
- (function (TextContent) {
930
- /* forbid node to have text content, inter-element whitespace is ignored */
931
- TextContent["NONE"] = "none";
932
- /* node can have text but not required too */
933
- TextContent["DEFAULT"] = "default";
934
- /* node requires text-nodes to be present (direct or by descendant) */
935
- TextContent["REQUIRED"] = "required";
936
- /* node requires accessible text (hidden text is ignored, tries to get text from accessibility tree) */
937
- TextContent["ACCESSIBLE"] = "accessible";
938
- })(TextContent$1 || (TextContent$1 = {}));
939
- /**
940
- * Properties listed here can be copied (loaded) onto another element using
941
- * [[HtmlElement.loadMeta]].
942
- */
943
- const MetaCopyableProperty = [
944
- "metadata",
945
- "flow",
946
- "sectioning",
947
- "heading",
948
- "phrasing",
949
- "embedded",
950
- "interactive",
951
- "transparent",
952
- "form",
953
- "labelable",
954
- "requiredAttributes",
955
- "attributes",
956
- "permittedContent",
957
- "permittedDescendants",
958
- "permittedOrder",
959
- "requiredAncestors",
960
- "requiredContent",
961
- ];
962
-
963
1082
  class DynamicValue {
964
1083
  constructor(expr) {
965
1084
  this.expr = expr;
@@ -1811,8 +1930,9 @@ class HtmlElement extends DOMNode {
1811
1930
  this.metaElement = {};
1812
1931
  }
1813
1932
  for (const key of MetaCopyableProperty) {
1814
- if (typeof meta[key] !== "undefined") {
1815
- this.metaElement[key] = meta[key];
1933
+ const value = meta[key];
1934
+ if (typeof value !== "undefined") {
1935
+ setMetaProperty(this.metaElement, key, value);
1816
1936
  }
1817
1937
  else {
1818
1938
  delete this.metaElement[key];
@@ -2228,6 +2348,7 @@ class Validator {
2228
2348
  * @param rules - Element attribute metadta.
2229
2349
  * @returns `true` if attribute passes all tests.
2230
2350
  */
2351
+ /* eslint-disable-next-line complexity */
2231
2352
  static validateAttribute(attr, rules) {
2232
2353
  const rule = rules[attr.key];
2233
2354
  if (!rule) {
@@ -2241,19 +2362,34 @@ class Validator {
2241
2362
  return true;
2242
2363
  }
2243
2364
  const empty = value === null || value === "";
2244
- /* consider an empty array as being a boolean attribute */
2245
- if (rule.length === 0) {
2365
+ /* if boolean is set the value can be either null, empty string or the
2366
+ * attribute key (attribute-boolean-style regulates style) */
2367
+ if (rule.boolean) {
2246
2368
  return empty || value === attr.key;
2247
2369
  }
2248
- /* if the empty string is present allow both "" and null
2249
- * (boolean-attribute-style will regulate which is allowed) */
2250
- if (rule.includes("") && empty) {
2370
+ /* if omit is set the value can be either null or empty string
2371
+ * (attribute-empty style regulates style) */
2372
+ if (rule.omit && empty) {
2373
+ return true;
2374
+ }
2375
+ /* validate each token when using list, all tokens must be valid */
2376
+ if (rule.list) {
2377
+ const tokens = new DOMTokenList(value, attr.valueLocation);
2378
+ return tokens.every((token) => {
2379
+ return this.validateAttributeValue(token, rule);
2380
+ });
2381
+ }
2382
+ return this.validateAttributeValue(value, rule);
2383
+ }
2384
+ static validateAttributeValue(value, rule) {
2385
+ /* skip attribute if it not have enumerated list */
2386
+ if (!rule.enum) {
2251
2387
  return true;
2252
2388
  }
2253
2389
  if (value === null || value === undefined) {
2254
2390
  return false;
2255
2391
  }
2256
- return rule.some((entry) => {
2392
+ return rule.enum.some((entry) => {
2257
2393
  if (entry instanceof RegExp) {
2258
2394
  return !!value.match(entry);
2259
2395
  }
@@ -2519,12 +2655,12 @@ var configurationSchema = {
2519
2655
  const espree = legacyRequire("espree");
2520
2656
  const walk = legacyRequire("acorn-walk");
2521
2657
  function joinTemplateLiteral(nodes) {
2522
- let offset = nodes[0].start;
2658
+ let offset = nodes[0].start + 1;
2523
2659
  let output = "";
2524
2660
  for (const node of nodes) {
2525
- output += " ".repeat(node.start - offset);
2661
+ output += " ".repeat(node.start + 1 - offset);
2526
2662
  output += node.value.raw;
2527
- offset = node.end;
2663
+ offset = node.end - 2;
2528
2664
  }
2529
2665
  return output;
2530
2666
  }
@@ -2716,7 +2852,7 @@ var TRANSFORMER_API;
2716
2852
  })(TRANSFORMER_API || (TRANSFORMER_API = {}));
2717
2853
 
2718
2854
  const name = "html-validate";
2719
- const version = "5.5.0";
2855
+ const version = "6.0.0";
2720
2856
  const homepage = "https://html-validate.org";
2721
2857
  const bugs = {
2722
2858
  url: "https://gitlab.com/html-validate/html-validate/issues/new"
@@ -3008,7 +3144,7 @@ const description = {
3008
3144
  };
3009
3145
  class AllowedLinks extends Rule {
3010
3146
  constructor(options) {
3011
- super(Object.assign(Object.assign({}, defaults$p), options));
3147
+ super({ ...defaults$p, ...options });
3012
3148
  }
3013
3149
  static schema() {
3014
3150
  return {
@@ -3256,7 +3392,7 @@ const defaults$o = {
3256
3392
  };
3257
3393
  class AttrCase extends Rule {
3258
3394
  constructor(options) {
3259
- super(Object.assign(Object.assign({}, defaults$o), options));
3395
+ super({ ...defaults$o, ...options });
3260
3396
  this.style = new CaseStyle(this.options.style, "attr-case");
3261
3397
  }
3262
3398
  static schema() {
@@ -3609,7 +3745,7 @@ function generateDescription(name, pattern) {
3609
3745
  }
3610
3746
  class AttrPattern extends Rule {
3611
3747
  constructor(options) {
3612
- super(Object.assign(Object.assign({}, defaults$n), options));
3748
+ super({ ...defaults$n, ...options });
3613
3749
  this.pattern = generateRegexp(this.options.pattern);
3614
3750
  }
3615
3751
  static schema() {
@@ -3675,7 +3811,7 @@ const defaults$m = {
3675
3811
  };
3676
3812
  class AttrQuotes extends Rule {
3677
3813
  constructor(options) {
3678
- super(Object.assign(Object.assign({}, defaults$m), options));
3814
+ super({ ...defaults$m, ...options });
3679
3815
  this.style = parseStyle$4(this.options.style);
3680
3816
  }
3681
3817
  static schema() {
@@ -3771,11 +3907,11 @@ class AttributeAllowedValues extends Rule {
3771
3907
  if (!context) {
3772
3908
  return docs;
3773
3909
  }
3774
- if (context.allowed.length > 0) {
3775
- const allowed = context.allowed.map((val) => `- \`${val}\``);
3910
+ if (context.allowed.enum) {
3911
+ const allowed = context.allowed.enum.map((val) => `- \`${val}\``);
3776
3912
  docs.description = `Element <${context.element}> does not allow attribute \`${context.attribute}\` to have the value \`"${context.value}"\`, it must match one of the following:\n\n${allowed.join("\n")}`;
3777
3913
  }
3778
- else {
3914
+ else if (context.allowed.boolean) {
3779
3915
  docs.description = `Element <${context.element}> attribute \`${context.attribute}\` must be a boolean attribute, e.g. \`<${context.element} ${context.attribute}>\``;
3780
3916
  }
3781
3917
  return docs;
@@ -3831,7 +3967,7 @@ const defaults$l = {
3831
3967
  };
3832
3968
  class AttributeBooleanStyle extends Rule {
3833
3969
  constructor(options) {
3834
- super(Object.assign(Object.assign({}, defaults$l), options));
3970
+ super({ ...defaults$l, ...options });
3835
3971
  this.hasInvalidStyle = parseStyle$3(this.options.style);
3836
3972
  }
3837
3973
  static schema() {
@@ -3876,7 +4012,8 @@ class AttributeBooleanStyle extends Rule {
3876
4012
  });
3877
4013
  }
3878
4014
  isBoolean(attr, rules) {
3879
- return rules[attr.key] && rules[attr.key].length === 0;
4015
+ var _a;
4016
+ return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.boolean);
3880
4017
  }
3881
4018
  }
3882
4019
  function parseStyle$3(style) {
@@ -3911,7 +4048,7 @@ const defaults$k = {
3911
4048
  };
3912
4049
  class AttributeEmptyStyle extends Rule {
3913
4050
  constructor(options) {
3914
- super(Object.assign(Object.assign({}, defaults$k), options));
4051
+ super({ ...defaults$k, ...options });
3915
4052
  this.hasInvalidStyle = parseStyle$2(this.options.style);
3916
4053
  }
3917
4054
  static schema() {
@@ -3960,7 +4097,8 @@ class AttributeEmptyStyle extends Rule {
3960
4097
  }
3961
4098
  }
3962
4099
  function allowsEmpty(attr, rules) {
3963
- return rules[attr.key] && rules[attr.key].includes("");
4100
+ var _a;
4101
+ return Boolean((_a = rules[attr.key]) === null || _a === void 0 ? void 0 : _a.omit);
3964
4102
  }
3965
4103
  function isEmptyValue(attr) {
3966
4104
  /* dynamic values are ignored, assumed to contain a value */
@@ -4023,7 +4161,7 @@ const defaults$j = {
4023
4161
  };
4024
4162
  class ClassPattern extends Rule {
4025
4163
  constructor(options) {
4026
- super(Object.assign(Object.assign({}, defaults$j), options));
4164
+ super({ ...defaults$j, ...options });
4027
4165
  this.pattern = parsePattern(this.options.pattern);
4028
4166
  }
4029
4167
  static schema() {
@@ -4136,7 +4274,7 @@ const defaults$i = {
4136
4274
  };
4137
4275
  class Deprecated extends Rule {
4138
4276
  constructor(options) {
4139
- super(Object.assign(Object.assign({}, defaults$i), options));
4277
+ super({ ...defaults$i, ...options });
4140
4278
  }
4141
4279
  static schema() {
4142
4280
  return {
@@ -4230,7 +4368,7 @@ class Deprecated extends Rule {
4230
4368
  this.report(node, message, location, context);
4231
4369
  }
4232
4370
  reportObject(deprecated, node, location) {
4233
- const context = Object.assign(Object.assign({}, deprecated), { tagName: node.tagName });
4371
+ const context = { ...deprecated, tagName: node.tagName };
4234
4372
  const notice = deprecated.message ? `: ${deprecated.message}` : "";
4235
4373
  const message = `<${node.tagName}> is deprecated${notice}`;
4236
4374
  this.report(node, message, location, context);
@@ -4304,7 +4442,7 @@ const defaults$h = {
4304
4442
  };
4305
4443
  class DoctypeStyle extends Rule {
4306
4444
  constructor(options) {
4307
- super(Object.assign(Object.assign({}, defaults$h), options));
4445
+ super({ ...defaults$h, ...options });
4308
4446
  }
4309
4447
  static schema() {
4310
4448
  return {
@@ -4341,7 +4479,7 @@ const defaults$g = {
4341
4479
  };
4342
4480
  class ElementCase extends Rule {
4343
4481
  constructor(options) {
4344
- super(Object.assign(Object.assign({}, defaults$g), options));
4482
+ super({ ...defaults$g, ...options });
4345
4483
  this.style = new CaseStyle(this.options.style, "element-case");
4346
4484
  }
4347
4485
  static schema() {
@@ -4411,7 +4549,7 @@ const defaults$f = {
4411
4549
  };
4412
4550
  class ElementName extends Rule {
4413
4551
  constructor(options) {
4414
- super(Object.assign(Object.assign({}, defaults$f), options));
4552
+ super({ ...defaults$f, ...options });
4415
4553
  // eslint-disable-next-line security/detect-non-literal-regexp
4416
4554
  this.pattern = new RegExp(this.options.pattern);
4417
4555
  }
@@ -4683,9 +4821,14 @@ class ElementRequiredAttributes extends Rule {
4683
4821
  this.on("tag:end", (event) => {
4684
4822
  const node = event.previous;
4685
4823
  const meta = node.meta;
4686
- if (!meta || !meta.requiredAttributes)
4824
+ /* handle missing metadata and missing attributes */
4825
+ if (!meta || !meta.attributes) {
4687
4826
  return;
4688
- for (const key of meta.requiredAttributes) {
4827
+ }
4828
+ for (const [key, attr] of Object.entries(meta.attributes)) {
4829
+ if (!attr.required) {
4830
+ continue;
4831
+ }
4689
4832
  if (node.hasAttribute(key))
4690
4833
  continue;
4691
4834
  const context = {
@@ -4868,7 +5011,7 @@ function parseMaxInitial(value) {
4868
5011
  }
4869
5012
  class HeadingLevel extends Rule {
4870
5013
  constructor(options) {
4871
- super(Object.assign(Object.assign({}, defaults$e), options));
5014
+ super({ ...defaults$e, ...options });
4872
5015
  this.stack = [];
4873
5016
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
4874
5017
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
@@ -5031,7 +5174,7 @@ const defaults$d = {
5031
5174
  };
5032
5175
  class IdPattern extends Rule {
5033
5176
  constructor(options) {
5034
- super(Object.assign(Object.assign({}, defaults$d), options));
5177
+ super({ ...defaults$d, ...options });
5035
5178
  this.pattern = parsePattern(this.options.pattern);
5036
5179
  }
5037
5180
  static schema() {
@@ -5383,7 +5526,7 @@ const defaults$c = {
5383
5526
  };
5384
5527
  class LongTitle extends Rule {
5385
5528
  constructor(options) {
5386
- super(Object.assign(Object.assign({}, defaults$c), options));
5529
+ super({ ...defaults$c, ...options });
5387
5530
  this.maxlength = this.options.maxlength;
5388
5531
  }
5389
5532
  static schema() {
@@ -5536,7 +5679,7 @@ const defaults$b = {
5536
5679
  };
5537
5680
  class NoAutoplay extends Rule {
5538
5681
  constructor(options) {
5539
- super(Object.assign(Object.assign({}, defaults$b), options));
5682
+ super({ ...defaults$b, ...options });
5540
5683
  }
5541
5684
  documentation(context) {
5542
5685
  const tagName = context ? ` on <${context.tagName}>` : "";
@@ -5632,8 +5775,12 @@ class NoDeprecatedAttr extends Rule {
5632
5775
  if (meta === null) {
5633
5776
  return;
5634
5777
  }
5635
- const deprecated = meta.deprecatedAttributes || [];
5636
- if (deprecated.includes(attr)) {
5778
+ const metaAttribute = meta.attributes && meta.attributes[attr];
5779
+ if (!metaAttribute) {
5780
+ return;
5781
+ }
5782
+ const deprecated = metaAttribute.deprecated;
5783
+ if (deprecated) {
5637
5784
  this.report(node, `Attribute "${event.key}" is deprecated on <${node.tagName}> element`, event.keyLocation);
5638
5785
  }
5639
5786
  });
@@ -5790,7 +5937,7 @@ function getCSSDeclarations(value) {
5790
5937
  }
5791
5938
  class NoInlineStyle extends Rule {
5792
5939
  constructor(options) {
5793
- super(Object.assign(Object.assign({}, defaults$a), options));
5940
+ super({ ...defaults$a, ...options });
5794
5941
  }
5795
5942
  static schema() {
5796
5943
  return {
@@ -6012,7 +6159,7 @@ const replacementTable = new Map([
6012
6159
  ]);
6013
6160
  class NoRawCharacters extends Rule {
6014
6161
  constructor(options) {
6015
- super(Object.assign(Object.assign({}, defaults$9), options));
6162
+ super({ ...defaults$9, ...options });
6016
6163
  this.relaxed = this.options.relaxed;
6017
6164
  }
6018
6165
  static schema() {
@@ -6197,7 +6344,7 @@ const defaults$8 = {
6197
6344
  };
6198
6345
  class NoSelfClosing extends Rule {
6199
6346
  constructor(options) {
6200
- super(Object.assign(Object.assign({}, defaults$8), options));
6347
+ super({ ...defaults$8, ...options });
6201
6348
  }
6202
6349
  static schema() {
6203
6350
  return {
@@ -6336,7 +6483,7 @@ const defaults$7 = {
6336
6483
  };
6337
6484
  class PreferButton extends Rule {
6338
6485
  constructor(options) {
6339
- super(Object.assign(Object.assign({}, defaults$7), options));
6486
+ super({ ...defaults$7, ...options });
6340
6487
  }
6341
6488
  static schema() {
6342
6489
  return {
@@ -6441,7 +6588,7 @@ const defaults$6 = {
6441
6588
  };
6442
6589
  class PreferNativeElement extends Rule {
6443
6590
  constructor(options) {
6444
- super(Object.assign(Object.assign({}, defaults$6), options));
6591
+ super({ ...defaults$6, ...options });
6445
6592
  }
6446
6593
  static schema() {
6447
6594
  return {
@@ -6571,7 +6718,7 @@ const supportSri = {
6571
6718
  };
6572
6719
  class RequireSri extends Rule {
6573
6720
  constructor(options) {
6574
- super(Object.assign(Object.assign({}, defaults$5), options));
6721
+ super({ ...defaults$5, ...options });
6575
6722
  this.target = this.options.target;
6576
6723
  }
6577
6724
  static schema() {
@@ -8666,7 +8813,7 @@ const defaults$4 = {
8666
8813
  };
8667
8814
  class Void extends Rule {
8668
8815
  constructor(options) {
8669
- super(Object.assign(Object.assign({}, defaults$4), options));
8816
+ super({ ...defaults$4, ...options });
8670
8817
  this.style = parseStyle$1(this.options.style);
8671
8818
  }
8672
8819
  get deprecated() {
@@ -8775,7 +8922,7 @@ const defaults$3 = {
8775
8922
  };
8776
8923
  class VoidStyle extends Rule {
8777
8924
  constructor(options) {
8778
- super(Object.assign(Object.assign({}, defaults$3), options));
8925
+ super({ ...defaults$3, ...options });
8779
8926
  this.style = parseStyle(this.options.style);
8780
8927
  }
8781
8928
  static schema() {
@@ -8978,7 +9125,7 @@ const defaults$2 = {
8978
9125
  };
8979
9126
  class H37 extends Rule {
8980
9127
  constructor(options) {
8981
- super(Object.assign(Object.assign({}, defaults$2), options));
9128
+ super({ ...defaults$2, ...options });
8982
9129
  /* ensure alias is array */
8983
9130
  if (!Array.isArray(this.options.alias)) {
8984
9131
  this.options.alias = [this.options.alias];
@@ -9105,7 +9252,73 @@ const bundledRules$1 = {
9105
9252
  "wcag/h71": H71,
9106
9253
  };
9107
9254
 
9108
- 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);
9255
+ const bundledRules = {
9256
+ "allowed-links": AllowedLinks,
9257
+ "aria-label-misuse": AriaLabelMisuse,
9258
+ "attr-case": AttrCase,
9259
+ "attr-delimiter": AttrDelimiter,
9260
+ "attr-pattern": AttrPattern,
9261
+ "attr-quotes": AttrQuotes,
9262
+ "attr-spacing": AttrSpacing,
9263
+ "attribute-allowed-values": AttributeAllowedValues,
9264
+ "attribute-boolean-style": AttributeBooleanStyle,
9265
+ "attribute-empty-style": AttributeEmptyStyle,
9266
+ "class-pattern": ClassPattern,
9267
+ "close-attr": CloseAttr,
9268
+ "close-order": CloseOrder,
9269
+ deprecated: Deprecated,
9270
+ "deprecated-rule": DeprecatedRule,
9271
+ "doctype-html": NoStyleTag$1,
9272
+ "doctype-style": DoctypeStyle,
9273
+ "element-case": ElementCase,
9274
+ "element-name": ElementName,
9275
+ "element-permitted-content": ElementPermittedContent,
9276
+ "element-permitted-occurrences": ElementPermittedOccurrences,
9277
+ "element-permitted-order": ElementPermittedOrder,
9278
+ "element-required-attributes": ElementRequiredAttributes,
9279
+ "element-required-content": ElementRequiredContent,
9280
+ "empty-heading": EmptyHeading,
9281
+ "empty-title": EmptyTitle,
9282
+ "heading-level": HeadingLevel,
9283
+ "id-pattern": IdPattern,
9284
+ "input-attributes": InputAttributes,
9285
+ "input-missing-label": InputMissingLabel,
9286
+ "long-title": LongTitle,
9287
+ "meta-refresh": MetaRefresh,
9288
+ "missing-doctype": MissingDoctype,
9289
+ "multiple-labeled-controls": MultipleLabeledControls,
9290
+ "no-autoplay": NoAutoplay,
9291
+ "no-conditional-comment": NoConditionalComment,
9292
+ "no-deprecated-attr": NoDeprecatedAttr,
9293
+ "no-dup-attr": NoDupAttr,
9294
+ "no-dup-class": NoDupClass,
9295
+ "no-dup-id": NoDupID,
9296
+ "no-implicit-close": NoImplicitClose,
9297
+ "no-inline-style": NoInlineStyle,
9298
+ "no-missing-references": NoMissingReferences,
9299
+ "no-multiple-main": NoMultipleMain,
9300
+ "no-raw-characters": NoRawCharacters,
9301
+ "no-redundant-for": NoRedundantFor,
9302
+ "no-redundant-role": NoRedundantRole,
9303
+ "no-self-closing": NoSelfClosing,
9304
+ "no-style-tag": NoStyleTag,
9305
+ "no-trailing-whitespace": NoTrailingWhitespace,
9306
+ "no-unknown-elements": NoUnknownElements,
9307
+ "no-utf8-bom": NoUtf8Bom,
9308
+ "prefer-button": PreferButton,
9309
+ "prefer-native-element": PreferNativeElement,
9310
+ "prefer-tbody": PreferTbody,
9311
+ "require-sri": RequireSri,
9312
+ "script-element": ScriptElement,
9313
+ "script-type": ScriptType,
9314
+ "svg-focusable": SvgFocusable,
9315
+ "text-content": TextContent,
9316
+ "unrecognized-char-ref": UnknownCharReference,
9317
+ void: Void,
9318
+ "void-content": VoidContent,
9319
+ "void-style": VoidStyle,
9320
+ ...bundledRules$1,
9321
+ };
9109
9322
 
9110
9323
  var defaultConfig = {};
9111
9324
 
@@ -9343,7 +9556,7 @@ function overwriteMerge(a, b) {
9343
9556
  return b;
9344
9557
  }
9345
9558
  function mergeInternal(base, rhs) {
9346
- const dst = deepmerge(base, Object.assign(Object.assign({}, rhs), { rules: {} }));
9559
+ const dst = deepmerge(base, { ...rhs, rules: {} });
9347
9560
  /* rules need some special care, should overwrite arrays instead of
9348
9561
  * concaternation, i.e. ["error", {...options}] should not be merged by
9349
9562
  * appending to old value */
@@ -9568,7 +9781,7 @@ class Config {
9568
9781
  * @internal primary purpose is unittests
9569
9782
  */
9570
9783
  get() {
9571
- const config = Object.assign({}, this.config);
9784
+ const config = { ...this.config };
9572
9785
  if (config.elements) {
9573
9786
  config.elements = config.elements.map((cur) => {
9574
9787
  if (typeof cur === "string") {
@@ -9654,7 +9867,11 @@ class Config {
9654
9867
  if (!properties) {
9655
9868
  continue;
9656
9869
  }
9657
- for (const [key, schema] of Object.entries(properties)) {
9870
+ for (const [raw, schema] of Object.entries(properties)) {
9871
+ /* at compile time this is a fixed list but the point of this method is
9872
+ * to augment the runtime with additional keys so it is a bit of lying
9873
+ * to typescript */
9874
+ const key = raw;
9658
9875
  if (schema.copyable && !MetaCopyableProperty.includes(key)) {
9659
9876
  MetaCopyableProperty.push(key);
9660
9877
  }
@@ -9850,31 +10067,6 @@ class ConfigLoader {
9850
10067
  }
9851
10068
  }
9852
10069
 
9853
- /*! *****************************************************************************
9854
- Copyright (c) Microsoft Corporation. All rights reserved.
9855
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
9856
- this file except in compliance with the License. You may obtain a copy of the
9857
- License at http://www.apache.org/licenses/LICENSE-2.0
9858
-
9859
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9860
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
9861
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
9862
- MERCHANTABLITY OR NON-INFRINGEMENT.
9863
-
9864
- See the Apache Version 2.0 License for specific language governing permissions
9865
- and limitations under the License.
9866
- ***************************************************************************** */
9867
-
9868
- function __rest(s, e) {
9869
- var t = {};
9870
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
9871
- t[p] = s[p];
9872
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
9873
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
9874
- t[p[i]] = s[p[i]];
9875
- return t;
9876
- }
9877
-
9878
10070
  class EventHandler {
9879
10071
  constructor() {
9880
10072
  this.listeners = {};
@@ -10448,7 +10640,7 @@ class Reporter {
10448
10640
  merged[key].messages = [...merged[key].messages, ...result.messages];
10449
10641
  }
10450
10642
  else {
10451
- merged[key] = Object.assign({}, result);
10643
+ merged[key] = { ...result };
10452
10644
  }
10453
10645
  });
10454
10646
  });
@@ -10550,14 +10742,16 @@ function messageSort(a, b) {
10550
10742
  }
10551
10743
 
10552
10744
  class Engine {
10553
- constructor(config, configData, ParserClass) {
10745
+ constructor(config, ParserClass) {
10554
10746
  this.report = new Reporter();
10555
- this.configData = configData;
10556
10747
  this.config = config;
10557
10748
  this.ParserClass = ParserClass;
10558
10749
  /* initialize plugins and rules */
10559
10750
  const result = this.initPlugins(this.config);
10560
- this.availableRules = Object.assign(Object.assign({}, bundledRules), result.availableRules);
10751
+ this.availableRules = {
10752
+ ...bundledRules,
10753
+ ...result.availableRules,
10754
+ };
10561
10755
  }
10562
10756
  /**
10563
10757
  * Lint sources and return report
@@ -10582,13 +10776,13 @@ class Engine {
10582
10776
  /* trigger configuration ready event */
10583
10777
  const configEvent = {
10584
10778
  location,
10585
- config: this.configData,
10779
+ config: this.config,
10586
10780
  rules,
10587
10781
  };
10588
10782
  parser.trigger("config:ready", configEvent);
10589
10783
  /* trigger source ready event */
10590
10784
  /* eslint-disable-next-line @typescript-eslint/no-unused-vars -- object destructured on purpose to remove property */
10591
- const sourceData = __rest(source, ["hooks"]);
10785
+ const { hooks: _, ...sourceData } = source;
10592
10786
  const sourceEvent = {
10593
10787
  location,
10594
10788
  source: sourceData,
@@ -10895,133 +11089,31 @@ class Engine {
10895
11089
  }
10896
11090
 
10897
11091
  /**
10898
- * @internal
10899
- */
10900
- function findConfigurationFiles(directory) {
10901
- return ["json", "cjs", "js"]
10902
- .map((extension) => path.join(directory, `.htmlvalidate.${extension}`))
10903
- .filter((filePath) => fs.existsSync(filePath));
10904
- }
10905
- /**
10906
- * Loads configuration by traversing filesystem.
10907
- *
10908
- * Configuration is read from three sources and in the following order:
10909
- *
10910
- * 1. Global configuration passed to constructor.
10911
- * 2. Configuration files found when traversing the directory structure.
10912
- * 3. Override passed to this function.
10913
- *
10914
- * The following configuration filenames are searched:
10915
- *
10916
- * - `.htmlvalidate.json`
10917
- * - `.htmlvalidate.js`
10918
- * - `.htmlvalidate.cjs`
10919
- *
10920
- * Global configuration is used when no configuration file is found. The
10921
- * result is always merged with override if present.
10922
- *
10923
- * The `root` property set to `true` affects the configuration as following:
11092
+ * The static configuration loader does not do any per-handle lookup. Only the
11093
+ * global or per-call configuration is used.
10924
11094
  *
10925
- * 1. If set in override the override is returned as-is.
10926
- * 2. If set in the global config the override is merged into global and
10927
- * returned. No configuration files are searched.
10928
- * 3. Setting `root` in configuration file only stops directory traversal.
11095
+ * In practice this means no configuration is fetch by traversing the
11096
+ * filesystem.
10929
11097
  */
10930
- class FileSystemConfigLoader extends ConfigLoader {
10931
- /**
10932
- * @param config - Global configuration
10933
- * @param configFactory - Optional configuration factory
10934
- */
10935
- constructor(config, configFactory = Config) {
10936
- super(config, configFactory);
10937
- this.cache = new Map();
10938
- }
10939
- /**
10940
- * Get configuration for given filename.
10941
- *
10942
- * @param filename - Filename to get configuration for.
10943
- * @param configOverride - Configuration to merge final result with.
10944
- */
10945
- getConfigFor(filename, configOverride) {
10946
- /* special case when the overridden configuration is marked as root, should
10947
- * not try to load any more configuration files */
11098
+ class StaticConfigLoader extends ConfigLoader {
11099
+ getConfigFor(handle, configOverride) {
10948
11100
  const override = this.loadFromObject(configOverride || {});
10949
11101
  if (override.isRootFound()) {
10950
11102
  override.init();
10951
11103
  return override;
10952
11104
  }
10953
- /* special case when the global configuration is marked as root, should not
10954
- * try to load and more configuration files */
10955
- if (this.globalConfig.isRootFound()) {
10956
- const merged = this.globalConfig.merge(override);
10957
- merged.init();
10958
- return merged;
10959
- }
10960
- const config = this.fromFilename(filename);
10961
- const merged = config ? config.merge(override) : this.globalConfig.merge(override);
11105
+ const merged = this.globalConfig.merge(override);
10962
11106
  merged.init();
10963
11107
  return merged;
10964
11108
  }
10965
- /**
10966
- * Flush configuration cache.
10967
- *
10968
- * @param filename - If given only the cache for that file is flushed.
10969
- */
10970
- flushCache(filename) {
10971
- if (filename) {
10972
- this.cache.delete(filename);
10973
- }
10974
- else {
10975
- this.cache.clear();
10976
- }
10977
- }
10978
- /**
10979
- * Load raw configuration from directory traversal.
10980
- *
10981
- * This configuration is not merged with global configuration and may return
10982
- * `null` if no configuration files are found.
10983
- */
10984
- fromFilename(filename) {
10985
- var _a;
10986
- if (filename === "inline") {
10987
- return null;
10988
- }
10989
- if (this.cache.has(filename)) {
10990
- return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
10991
- }
10992
- let found = false;
10993
- let current = path.resolve(path.dirname(filename));
10994
- let config = this.empty();
10995
- // eslint-disable-next-line no-constant-condition
10996
- while (true) {
10997
- /* search configuration files in current directory */
10998
- for (const configFile of findConfigurationFiles(current)) {
10999
- const local = this.loadFromFile(configFile);
11000
- found = true;
11001
- config = local.merge(config);
11002
- }
11003
- /* stop if a configuration with "root" is set to true */
11004
- if (config.isRootFound()) {
11005
- break;
11006
- }
11007
- /* get the parent directory */
11008
- const child = current;
11009
- current = path.dirname(current);
11010
- /* stop if this is the root directory */
11011
- if (current === child) {
11012
- break;
11013
- }
11014
- }
11015
- /* no config was found by loader, return null and let caller decide what to do */
11016
- if (!found) {
11017
- this.cache.set(filename, null);
11018
- return null;
11019
- }
11020
- this.cache.set(filename, config);
11021
- return config;
11109
+ flushCache() {
11110
+ /* do nothing */
11022
11111
  }
11023
11112
  defaultConfig() {
11024
- return this.configFactory.defaultConfig();
11113
+ return this.loadFromObject({
11114
+ extends: ["html-validate:recommended"],
11115
+ elements: ["html5"],
11116
+ });
11025
11117
  }
11026
11118
  }
11027
11119
 
@@ -11045,7 +11137,7 @@ function isConfigData(value) {
11045
11137
  class HtmlValidate {
11046
11138
  constructor(arg) {
11047
11139
  const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
11048
- this.configLoader = loader !== null && loader !== void 0 ? loader : new FileSystemConfigLoader(config);
11140
+ this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
11049
11141
  }
11050
11142
  validateString(str, arg1, arg2, arg3) {
11051
11143
  const filename = typeof arg1 === "string" ? arg1 : "inline";
@@ -11072,7 +11164,7 @@ class HtmlValidate {
11072
11164
  const config = this.getConfigFor(input.filename, configOverride);
11073
11165
  const resolved = config.resolve();
11074
11166
  const source = resolved.transformSource(input);
11075
- const engine = new Engine(resolved, config.get(), Parser);
11167
+ const engine = new Engine(resolved, Parser);
11076
11168
  return engine.lint(source);
11077
11169
  }
11078
11170
  /**
@@ -11086,7 +11178,7 @@ class HtmlValidate {
11086
11178
  const config = this.getConfigFor(filename);
11087
11179
  const resolved = config.resolve();
11088
11180
  const source = resolved.transformFilename(filename);
11089
- const engine = new Engine(resolved, config.get(), Parser);
11181
+ const engine = new Engine(resolved, Parser);
11090
11182
  return engine.lint(source);
11091
11183
  }
11092
11184
  /**
@@ -11131,7 +11223,7 @@ class HtmlValidate {
11131
11223
  const config = this.getConfigFor(filename);
11132
11224
  const resolved = config.resolve();
11133
11225
  const source = resolved.transformFilename(filename);
11134
- const engine = new Engine(resolved, config.get(), Parser);
11226
+ const engine = new Engine(resolved, Parser);
11135
11227
  return engine.dumpTokens(source);
11136
11228
  }
11137
11229
  /**
@@ -11146,7 +11238,7 @@ class HtmlValidate {
11146
11238
  const config = this.getConfigFor(filename);
11147
11239
  const resolved = config.resolve();
11148
11240
  const source = resolved.transformFilename(filename);
11149
- const engine = new Engine(resolved, config.get(), Parser);
11241
+ const engine = new Engine(resolved, Parser);
11150
11242
  return engine.dumpEvents(source);
11151
11243
  }
11152
11244
  /**
@@ -11161,7 +11253,7 @@ class HtmlValidate {
11161
11253
  const config = this.getConfigFor(filename);
11162
11254
  const resolved = config.resolve();
11163
11255
  const source = resolved.transformFilename(filename);
11164
- const engine = new Engine(resolved, config.get(), Parser);
11256
+ const engine = new Engine(resolved, Parser);
11165
11257
  return engine.dumpTree(source);
11166
11258
  }
11167
11259
  /**
@@ -11239,7 +11331,7 @@ class HtmlValidate {
11239
11331
  */
11240
11332
  getRuleDocumentation(ruleId, config = null, context = null) {
11241
11333
  const c = config || this.getConfigFor("inline");
11242
- const engine = new Engine(c.resolve(), c.get(), Parser);
11334
+ const engine = new Engine(c.resolve(), Parser);
11243
11335
  return engine.getRuleDocumentation(ruleId, context);
11244
11336
  }
11245
11337
  /**
@@ -11276,35 +11368,6 @@ class HtmlValidate {
11276
11368
  }
11277
11369
  }
11278
11370
 
11279
- /**
11280
- * The static configuration loader does not do any per-handle lookup. Only the
11281
- * global or per-call configuration is used.
11282
- *
11283
- * In practice this means no configuration is fetch by traversing the
11284
- * filesystem.
11285
- */
11286
- class StaticConfigLoader extends ConfigLoader {
11287
- getConfigFor(handle, configOverride) {
11288
- const override = this.loadFromObject(configOverride || {});
11289
- if (override.isRootFound()) {
11290
- override.init();
11291
- return override;
11292
- }
11293
- const merged = this.globalConfig.merge(override);
11294
- merged.init();
11295
- return merged;
11296
- }
11297
- flushCache() {
11298
- /* do nothing */
11299
- }
11300
- defaultConfig() {
11301
- return this.loadFromObject({
11302
- extends: ["html-validate:recommended"],
11303
- elements: ["html5"],
11304
- });
11305
- }
11306
- }
11307
-
11308
11371
  const defaults$1 = {
11309
11372
  silent: false,
11310
11373
  version,
@@ -11322,7 +11385,7 @@ const defaults$1 = {
11322
11385
  * @returns - `true` if version is compatible
11323
11386
  */
11324
11387
  function compatibilityCheck(name, declared, options) {
11325
- const { silent, version: current, logger } = Object.assign(Object.assign({}, defaults$1), options);
11388
+ const { silent, version: current, logger } = { ...defaults$1, ...options };
11326
11389
  const valid = semver.satisfies(current, declared);
11327
11390
  if (valid || silent) {
11328
11391
  return valid;
@@ -11352,6 +11415,137 @@ function ruleExists(ruleId) {
11352
11415
  return ruleIds.has(ruleId);
11353
11416
  }
11354
11417
 
11418
+ /**
11419
+ * @internal
11420
+ */
11421
+ function findConfigurationFiles(directory) {
11422
+ return ["json", "cjs", "js"]
11423
+ .map((extension) => path.join(directory, `.htmlvalidate.${extension}`))
11424
+ .filter((filePath) => fs.existsSync(filePath));
11425
+ }
11426
+ /**
11427
+ * Loads configuration by traversing filesystem.
11428
+ *
11429
+ * Configuration is read from three sources and in the following order:
11430
+ *
11431
+ * 1. Global configuration passed to constructor.
11432
+ * 2. Configuration files found when traversing the directory structure.
11433
+ * 3. Override passed to this function.
11434
+ *
11435
+ * The following configuration filenames are searched:
11436
+ *
11437
+ * - `.htmlvalidate.json`
11438
+ * - `.htmlvalidate.js`
11439
+ * - `.htmlvalidate.cjs`
11440
+ *
11441
+ * Global configuration is used when no configuration file is found. The
11442
+ * result is always merged with override if present.
11443
+ *
11444
+ * The `root` property set to `true` affects the configuration as following:
11445
+ *
11446
+ * 1. If set in override the override is returned as-is.
11447
+ * 2. If set in the global config the override is merged into global and
11448
+ * returned. No configuration files are searched.
11449
+ * 3. Setting `root` in configuration file only stops directory traversal.
11450
+ */
11451
+ class FileSystemConfigLoader extends ConfigLoader {
11452
+ /**
11453
+ * @param config - Global configuration
11454
+ * @param configFactory - Optional configuration factory
11455
+ */
11456
+ constructor(config, configFactory = Config) {
11457
+ super(config, configFactory);
11458
+ this.cache = new Map();
11459
+ }
11460
+ /**
11461
+ * Get configuration for given filename.
11462
+ *
11463
+ * @param filename - Filename to get configuration for.
11464
+ * @param configOverride - Configuration to merge final result with.
11465
+ */
11466
+ getConfigFor(filename, configOverride) {
11467
+ /* special case when the overridden configuration is marked as root, should
11468
+ * not try to load any more configuration files */
11469
+ const override = this.loadFromObject(configOverride || {});
11470
+ if (override.isRootFound()) {
11471
+ override.init();
11472
+ return override;
11473
+ }
11474
+ /* special case when the global configuration is marked as root, should not
11475
+ * try to load and more configuration files */
11476
+ if (this.globalConfig.isRootFound()) {
11477
+ const merged = this.globalConfig.merge(override);
11478
+ merged.init();
11479
+ return merged;
11480
+ }
11481
+ const config = this.fromFilename(filename);
11482
+ const merged = config ? config.merge(override) : this.globalConfig.merge(override);
11483
+ merged.init();
11484
+ return merged;
11485
+ }
11486
+ /**
11487
+ * Flush configuration cache.
11488
+ *
11489
+ * @param filename - If given only the cache for that file is flushed.
11490
+ */
11491
+ flushCache(filename) {
11492
+ if (filename) {
11493
+ this.cache.delete(filename);
11494
+ }
11495
+ else {
11496
+ this.cache.clear();
11497
+ }
11498
+ }
11499
+ /**
11500
+ * Load raw configuration from directory traversal.
11501
+ *
11502
+ * This configuration is not merged with global configuration and may return
11503
+ * `null` if no configuration files are found.
11504
+ */
11505
+ fromFilename(filename) {
11506
+ var _a;
11507
+ if (filename === "inline") {
11508
+ return null;
11509
+ }
11510
+ if (this.cache.has(filename)) {
11511
+ return (_a = this.cache.get(filename)) !== null && _a !== void 0 ? _a : null;
11512
+ }
11513
+ let found = false;
11514
+ let current = path.resolve(path.dirname(filename));
11515
+ let config = this.empty();
11516
+ // eslint-disable-next-line no-constant-condition
11517
+ while (true) {
11518
+ /* search configuration files in current directory */
11519
+ for (const configFile of findConfigurationFiles(current)) {
11520
+ const local = this.loadFromFile(configFile);
11521
+ found = true;
11522
+ config = local.merge(config);
11523
+ }
11524
+ /* stop if a configuration with "root" is set to true */
11525
+ if (config.isRootFound()) {
11526
+ break;
11527
+ }
11528
+ /* get the parent directory */
11529
+ const child = current;
11530
+ current = path.dirname(current);
11531
+ /* stop if this is the root directory */
11532
+ if (current === child) {
11533
+ break;
11534
+ }
11535
+ }
11536
+ /* no config was found by loader, return null and let caller decide what to do */
11537
+ if (!found) {
11538
+ this.cache.set(filename, null);
11539
+ return null;
11540
+ }
11541
+ this.cache.set(filename, config);
11542
+ return config;
11543
+ }
11544
+ defaultConfig() {
11545
+ return this.configFactory.defaultConfig();
11546
+ }
11547
+ }
11548
+
11355
11549
  const entities = {
11356
11550
  ">": "&gt;",
11357
11551
  "<": "&lt;",
@@ -11502,7 +11696,7 @@ function formatSummary(errors, warnings) {
11502
11696
  return kleur[summaryColor]().bold(`${summary.join(" and ")} found.`);
11503
11697
  }
11504
11698
  function codeframe(results, options) {
11505
- const merged = Object.assign(Object.assign({}, defaults), options);
11699
+ const merged = { ...defaults, ...options };
11506
11700
  let errors = 0;
11507
11701
  let warnings = 0;
11508
11702
  const resultsWithMessages = results.filter((result) => result.messages.length > 0);
@@ -11543,7 +11737,11 @@ function linkSummary(results) {
11543
11737
  return `\n${kleur.bold("More information")}:\n${lines.join("")}\n`;
11544
11738
  }
11545
11739
  function stylish(results) {
11546
- const errors = stylishImpl(results.map((it) => (Object.assign(Object.assign({}, it), { fixableErrorCount: 0, fixableWarningCount: 0 }))));
11740
+ const errors = stylishImpl(results.map((it) => ({
11741
+ ...it,
11742
+ fixableErrorCount: 0,
11743
+ fixableWarningCount: 0,
11744
+ })));
11547
11745
  const links = linkSummary(results);
11548
11746
  return `${errors}${links}`;
11549
11747
  }