html-validate 5.5.0 → 6.1.0

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