html-validate 8.10.0 → 8.11.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.
@@ -1,4 +1,4 @@
1
- import { G as compatibilityCheckImpl, v as version } from './core.js';
1
+ import { I as compatibilityCheckImpl, v as version } from './core.js';
2
2
 
3
3
  const defaults = {
4
4
  silent: false,
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { a as ConfigError, b as ConfigLoader, C as Config, G as compatibilityCheckImpl, v as version } from './core.js';
3
+ import { a as ConfigError, b as ConfigLoader, C as Config, I as compatibilityCheckImpl, v as version } from './core.js';
4
4
  import { createRequire } from 'node:module';
5
5
  import kleur from 'kleur';
6
6
 
package/dist/es/core.js CHANGED
@@ -584,8 +584,13 @@ const patternProperties = {
584
584
  implicitRole: {
585
585
  title: "Implicit ARIA role for this element",
586
586
  description: "Some elements have implicit ARIA roles.",
587
+ deprecated: true,
587
588
  "function": true
588
589
  },
590
+ aria: {
591
+ title: "WAI-ARIA properties for this element",
592
+ $ref: "#/definitions/Aria"
593
+ },
589
594
  scriptSupporting: {
590
595
  title: "Mark element as script-supporting",
591
596
  description: "Script-supporting elements are elements which can be inserted where othersise not permitted to assist in templating",
@@ -682,6 +687,39 @@ const patternProperties = {
682
687
  }
683
688
  };
684
689
  const definitions = {
690
+ Aria: {
691
+ type: "object",
692
+ additionalProperties: false,
693
+ properties: {
694
+ implicitRole: {
695
+ title: "Implicit ARIA role for this element",
696
+ description: "Some elements have implicit ARIA roles.",
697
+ anyOf: [
698
+ {
699
+ type: "string"
700
+ },
701
+ {
702
+ "function": true
703
+ }
704
+ ]
705
+ },
706
+ naming: {
707
+ title: "Prohibit or allow this element to be named by aria-label or aria-labelledby",
708
+ anyOf: [
709
+ {
710
+ type: "string",
711
+ "enum": [
712
+ "prohibited",
713
+ "allowed"
714
+ ]
715
+ },
716
+ {
717
+ "function": true
718
+ }
719
+ ]
720
+ }
721
+ }
722
+ },
685
723
  contentCategory: {
686
724
  anyOf: [
687
725
  {
@@ -982,6 +1020,7 @@ const MetaCopyableProperty = [
982
1020
  "formAssociated",
983
1021
  "labelable",
984
1022
  "attributes",
1023
+ "aria",
985
1024
  "permittedContent",
986
1025
  "permittedDescendants",
987
1026
  "permittedOrder",
@@ -1042,7 +1081,27 @@ function migrateAttributes(src) {
1042
1081
  });
1043
1082
  return Object.fromEntries(entries);
1044
1083
  }
1084
+ function normalizeAriaImplicitRole(value) {
1085
+ if (!value) {
1086
+ return () => null;
1087
+ }
1088
+ if (typeof value === "string") {
1089
+ return () => value;
1090
+ }
1091
+ return value;
1092
+ }
1093
+ function normalizeAriaNaming(value) {
1094
+ if (!value) {
1095
+ return () => "allowed";
1096
+ }
1097
+ if (typeof value === "string") {
1098
+ return () => value;
1099
+ }
1100
+ return value;
1101
+ }
1045
1102
  function migrateElement(src) {
1103
+ var _a, _b;
1104
+ const implicitRole = normalizeAriaImplicitRole(src.implicitRole ?? ((_a = src.aria) == null ? void 0 : _a.implicitRole));
1046
1105
  const result = {
1047
1106
  ...src,
1048
1107
  ...{
@@ -1051,7 +1110,11 @@ function migrateElement(src) {
1051
1110
  attributes: migrateAttributes(src),
1052
1111
  textContent: src.textContent,
1053
1112
  focusable: src.focusable ?? false,
1054
- implicitRole: src.implicitRole ?? (() => null)
1113
+ implicitRole,
1114
+ aria: {
1115
+ implicitRole,
1116
+ naming: normalizeAriaNaming((_b = src.aria) == null ? void 0 : _b.naming)
1117
+ }
1055
1118
  };
1056
1119
  delete result.deprecatedAttributes;
1057
1120
  delete result.requiredAttributes;
@@ -1893,8 +1956,30 @@ function factory$1(name, context) {
1893
1956
  function stripslashes(value) {
1894
1957
  return value.replace(/\\(.)/g, "$1");
1895
1958
  }
1959
+ function unescapeCodepoint(value) {
1960
+ const replacement = {
1961
+ "\\9 ": " ",
1962
+ "\\a ": "\n",
1963
+ "\\d ": "\r"
1964
+ };
1965
+ return value.replace(
1966
+ /(\\[\u0039\u0061\u0064] )/g,
1967
+ (_, codepoint) => replacement[codepoint]
1968
+ );
1969
+ }
1896
1970
  function escapeSelectorComponent(text) {
1897
- return text.toString().replace(/([^a-z0-9_-])/gi, "\\$1");
1971
+ const codepoints = {
1972
+ " ": "\\9 ",
1973
+ "\n": "\\a ",
1974
+ "\r": "\\d "
1975
+ };
1976
+ return text.toString().replace(/([\t\n\r]|[^a-z0-9_-])/gi, (_, ch) => {
1977
+ if (codepoints[ch]) {
1978
+ return codepoints[ch];
1979
+ } else {
1980
+ return `\\${ch}`;
1981
+ }
1982
+ });
1898
1983
  }
1899
1984
  function generateIdSelector(id) {
1900
1985
  const escaped = escapeSelectorComponent(id);
@@ -2009,7 +2094,10 @@ class PseudoClassMatcher extends Matcher {
2009
2094
  }
2010
2095
  class Pattern {
2011
2096
  constructor(pattern) {
2012
- const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/);
2097
+ const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)([^]*)$/);
2098
+ if (!match) {
2099
+ throw new Error(`Failed to create selector pattern from "${pattern}"`);
2100
+ }
2013
2101
  match.shift();
2014
2102
  this.selector = pattern;
2015
2103
  this.combinator = parseCombinator(match.shift(), pattern);
@@ -2065,10 +2153,10 @@ class Selector {
2065
2153
  static parse(selector) {
2066
2154
  selector = selector.replace(/([+~>]) /g, "$1");
2067
2155
  let begin = 0;
2068
- const delimiter = /((?:[^\\]) +|$)/g;
2156
+ const delimiter = /((?:[^\\\u0039\u0061\u0064]) +|$)/g;
2069
2157
  return Array.from(selector.matchAll(delimiter), (match) => {
2070
2158
  const end = match.index + 1;
2071
- const part = selector.slice(begin, end);
2159
+ const part = unescapeCodepoint(selector.slice(begin, end));
2072
2160
  begin = end + 1;
2073
2161
  return new Pattern(part);
2074
2162
  });
@@ -2401,7 +2489,8 @@ class HtmlElement extends DOMNode {
2401
2489
  return this.cacheSet(ROLE, role.value);
2402
2490
  }
2403
2491
  if (this.metaElement) {
2404
- const implicitRole = this.metaElement.implicitRole(this._adapter);
2492
+ const { aria } = this.metaElement;
2493
+ const implicitRole = aria.implicitRole(this._adapter);
2405
2494
  return this.cacheSet(ROLE, implicitRole);
2406
2495
  }
2407
2496
  return this.cacheSet(ROLE, null);
@@ -3143,6 +3232,48 @@ function interpolate(text, data) {
3143
3232
  });
3144
3233
  }
3145
3234
 
3235
+ const cacheKey = Symbol("aria-naming");
3236
+ const defaultValue = "allowed";
3237
+ const prohibitedRoles = [
3238
+ "caption",
3239
+ "code",
3240
+ "deletion",
3241
+ "emphasis",
3242
+ "generic",
3243
+ "insertion",
3244
+ "paragraph",
3245
+ "presentation",
3246
+ "strong",
3247
+ "subscript",
3248
+ "superscript"
3249
+ ];
3250
+ function byRole(role) {
3251
+ return prohibitedRoles.includes(role) ? "prohibited" : "allowed";
3252
+ }
3253
+ function byMeta(element, meta) {
3254
+ return meta.aria.naming(element._adapter);
3255
+ }
3256
+ function ariaNaming(element) {
3257
+ var _a;
3258
+ const cached = element.cacheGet(cacheKey);
3259
+ if (cached) {
3260
+ return cached;
3261
+ }
3262
+ const role = (_a = element.getAttribute("role")) == null ? void 0 : _a.value;
3263
+ if (role) {
3264
+ if (role instanceof DynamicValue) {
3265
+ return element.cacheSet(cacheKey, defaultValue);
3266
+ } else {
3267
+ return element.cacheSet(cacheKey, byRole(role));
3268
+ }
3269
+ }
3270
+ const meta = element.meta;
3271
+ if (!meta) {
3272
+ return element.cacheSet(cacheKey, defaultValue);
3273
+ }
3274
+ return element.cacheSet(cacheKey, byMeta(element, meta));
3275
+ }
3276
+
3146
3277
  const patternCache = /* @__PURE__ */ new Map();
3147
3278
  function compileStringPattern(pattern) {
3148
3279
  const regexp = pattern.replace(/[*]+/g, ".+");
@@ -3661,7 +3792,7 @@ class Rule {
3661
3792
  }
3662
3793
  }
3663
3794
 
3664
- const defaults$u = {
3795
+ const defaults$v = {
3665
3796
  allowExternal: true,
3666
3797
  allowRelative: true,
3667
3798
  allowAbsolute: true,
@@ -3702,7 +3833,7 @@ function matchList(value, list) {
3702
3833
  }
3703
3834
  class AllowedLinks extends Rule {
3704
3835
  constructor(options) {
3705
- super({ ...defaults$u, ...options });
3836
+ super({ ...defaults$v, ...options });
3706
3837
  this.allowExternal = parseAllow(this.options.allowExternal);
3707
3838
  this.allowRelative = parseAllow(this.options.allowRelative);
3708
3839
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -3866,7 +3997,7 @@ class AllowedLinks extends Rule {
3866
3997
  }
3867
3998
  }
3868
3999
 
3869
- const defaults$t = {
4000
+ const defaults$u = {
3870
4001
  accessible: true
3871
4002
  };
3872
4003
  function findByTarget(target, siblings) {
@@ -3896,7 +4027,7 @@ function getDescription$1(context) {
3896
4027
  }
3897
4028
  class AreaAlt extends Rule {
3898
4029
  constructor(options) {
3899
- super({ ...defaults$t, ...options });
4030
+ super({ ...defaults$u, ...options });
3900
4031
  }
3901
4032
  static schema() {
3902
4033
  return {
@@ -3975,6 +4106,9 @@ class AriaHiddenBody extends Rule {
3975
4106
  }
3976
4107
  }
3977
4108
 
4109
+ const defaults$t = {
4110
+ allowAnyNamable: false
4111
+ };
3978
4112
  const whitelisted = [
3979
4113
  "main",
3980
4114
  "nav",
@@ -4013,6 +4147,9 @@ function isValidUsage(target, meta) {
4013
4147
  return false;
4014
4148
  }
4015
4149
  class AriaLabelMisuse extends Rule {
4150
+ constructor(options) {
4151
+ super({ ...defaults$t, ...options });
4152
+ }
4016
4153
  documentation() {
4017
4154
  const valid = [
4018
4155
  "Interactive elements",
@@ -4055,6 +4192,9 @@ ${lines}`,
4055
4192
  if (isValidUsage(target, meta)) {
4056
4193
  return;
4057
4194
  }
4195
+ if (this.options.allowAnyNamable && ariaNaming(target) === "allowed") {
4196
+ return;
4197
+ }
4058
4198
  this.report(target, `"aria-label" cannot be used on this element`, attr.keyLocation);
4059
4199
  }
4060
4200
  }
@@ -7552,7 +7692,7 @@ class NoRedundantRole extends Rule {
7552
7692
  if (!meta) {
7553
7693
  return;
7554
7694
  }
7555
- const implicitRole = meta.implicitRole(target._adapter);
7695
+ const implicitRole = meta.aria.implicitRole(target._adapter);
7556
7696
  if (!implicitRole) {
7557
7697
  return;
7558
7698
  }
@@ -9334,7 +9474,7 @@ const config$4 = {
9334
9474
  rules: {
9335
9475
  "area-alt": ["error", { accessible: true }],
9336
9476
  "aria-hidden-body": "error",
9337
- "aria-label-misuse": "error",
9477
+ "aria-label-misuse": ["error", { allowAnyNamable: false }],
9338
9478
  "deprecated-rule": "warn",
9339
9479
  "empty-heading": "error",
9340
9480
  "empty-title": "error",
@@ -9386,7 +9526,7 @@ const config$1 = {
9386
9526
  rules: {
9387
9527
  "area-alt": ["error", { accessible: true }],
9388
9528
  "aria-hidden-body": "error",
9389
- "aria-label-misuse": "error",
9529
+ "aria-label-misuse": ["error", { allowAnyNamable: false }],
9390
9530
  "attr-case": "error",
9391
9531
  "attr-delimiter": "error",
9392
9532
  "attr-quotes": "error",
@@ -9467,6 +9607,7 @@ var recommended = config$1;
9467
9607
  const config = {
9468
9608
  rules: {
9469
9609
  "area-alt": ["error", { accessible: false }],
9610
+ "aria-label-misuse": ["error", { allowAnyNamable: true }],
9470
9611
  "attr-spacing": "error",
9471
9612
  "attribute-allowed-values": "error",
9472
9613
  "attribute-misuse": "error",
@@ -11719,7 +11860,7 @@ class HtmlValidate {
11719
11860
  }
11720
11861
 
11721
11862
  const name = "html-validate";
11722
- const version = "8.10.0";
11863
+ const version = "8.11.0";
11723
11864
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
11724
11865
 
11725
11866
  function definePlugin(plugin) {
@@ -12596,5 +12737,5 @@ function compatibilityCheckImpl(name, declared, options) {
12596
12737
  return false;
12597
12738
  }
12598
12739
 
12599
- export { Attribute as A, Parser as B, Config as C, DOMNode as D, ruleExists as E, EventHandler as F, compatibilityCheckImpl as G, HtmlValidate as H, codeframe as I, name as J, bugs as K, MetaCopyableProperty as M, NodeClosed as N, Presets as P, ResolvedConfig as R, Severity as S, TextNode as T, UserError as U, Validator as V, WrappedError as W, ConfigError as a, ConfigLoader as b, defineConfig as c, deepmerge$1 as d, ensureError as e, StaticConfigLoader as f, getFormatter as g, DOMTokenList as h, ignore$1 as i, DOMTree as j, DynamicValue as k, HtmlElement as l, NodeType as m, NestedError as n, SchemaValidationError as o, MetaTable as p, TextContent$1 as q, Rule as r, staticResolver as s, TextClassification as t, classifyNodeText as u, version as v, keywordPatternMatcher as w, sliceLocation as x, Reporter as y, definePlugin as z };
12740
+ export { Attribute as A, definePlugin as B, Config as C, DOMNode as D, Parser as E, ruleExists as F, EventHandler as G, HtmlValidate as H, compatibilityCheckImpl as I, codeframe as J, name as K, bugs as L, MetaCopyableProperty as M, NodeClosed as N, Presets as P, ResolvedConfig as R, Severity as S, TextNode as T, UserError as U, Validator as V, WrappedError as W, ConfigError as a, ConfigLoader as b, defineConfig as c, deepmerge$1 as d, ensureError as e, StaticConfigLoader as f, getFormatter as g, DOMTokenList as h, ignore$1 as i, DOMTree as j, DynamicValue as k, HtmlElement as l, NodeType as m, NestedError as n, SchemaValidationError as o, MetaTable as p, TextContent$1 as q, Rule as r, staticResolver as s, ariaNaming as t, TextClassification as u, version as v, classifyNodeText as w, keywordPatternMatcher as x, sliceLocation as y, Reporter as z };
12600
12741
  //# sourceMappingURL=core.js.map