html-validate 8.10.0 → 8.11.1

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;
@@ -1890,11 +1953,82 @@ function factory$1(name, context) {
1890
1953
  }
1891
1954
  }
1892
1955
 
1956
+ const escapedCodepoints = ["9", "a", "d"];
1957
+ function* splitSelectorElements(selector) {
1958
+ let begin = 0;
1959
+ let end = 0;
1960
+ function initialState(ch, p) {
1961
+ if (ch === "\\") {
1962
+ return 1 /* ESCAPED */;
1963
+ }
1964
+ if (ch === " ") {
1965
+ end = p;
1966
+ return 2 /* WHITESPACE */;
1967
+ }
1968
+ return 0 /* INITIAL */;
1969
+ }
1970
+ function escapedState(ch) {
1971
+ if (escapedCodepoints.includes(ch)) {
1972
+ return 1 /* ESCAPED */;
1973
+ }
1974
+ return 0 /* INITIAL */;
1975
+ }
1976
+ function* whitespaceState(ch, p) {
1977
+ if (ch === " ") {
1978
+ return 2 /* WHITESPACE */;
1979
+ }
1980
+ yield selector.slice(begin, end);
1981
+ begin = p;
1982
+ end = p;
1983
+ return 0 /* INITIAL */;
1984
+ }
1985
+ let state = 0 /* INITIAL */;
1986
+ for (let p = 0; p < selector.length; p++) {
1987
+ const ch = selector[p];
1988
+ switch (state) {
1989
+ case 0 /* INITIAL */:
1990
+ state = initialState(ch, p);
1991
+ break;
1992
+ case 1 /* ESCAPED */:
1993
+ state = escapedState(ch);
1994
+ break;
1995
+ case 2 /* WHITESPACE */:
1996
+ state = yield* whitespaceState(ch, p);
1997
+ break;
1998
+ }
1999
+ }
2000
+ if (begin !== selector.length) {
2001
+ yield selector.slice(begin);
2002
+ }
2003
+ }
2004
+
1893
2005
  function stripslashes(value) {
1894
2006
  return value.replace(/\\(.)/g, "$1");
1895
2007
  }
2008
+ function unescapeCodepoint(value) {
2009
+ const replacement = {
2010
+ "\\9 ": " ",
2011
+ "\\a ": "\n",
2012
+ "\\d ": "\r"
2013
+ };
2014
+ return value.replace(
2015
+ /(\\[\u0039\u0061\u0064] )/g,
2016
+ (_, codepoint) => replacement[codepoint]
2017
+ );
2018
+ }
1896
2019
  function escapeSelectorComponent(text) {
1897
- return text.toString().replace(/([^a-z0-9_-])/gi, "\\$1");
2020
+ const codepoints = {
2021
+ " ": "\\9 ",
2022
+ "\n": "\\a ",
2023
+ "\r": "\\d "
2024
+ };
2025
+ return text.toString().replace(/([\t\n\r]|[^a-z0-9_-])/gi, (_, ch) => {
2026
+ if (codepoints[ch]) {
2027
+ return codepoints[ch];
2028
+ } else {
2029
+ return `\\${ch}`;
2030
+ }
2031
+ });
1898
2032
  }
1899
2033
  function generateIdSelector(id) {
1900
2034
  const escaped = escapeSelectorComponent(id);
@@ -2009,7 +2143,10 @@ class PseudoClassMatcher extends Matcher {
2009
2143
  }
2010
2144
  class Pattern {
2011
2145
  constructor(pattern) {
2012
- const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/);
2146
+ const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)([^]*)$/);
2147
+ if (!match) {
2148
+ throw new Error(`Failed to create selector pattern from "${pattern}"`);
2149
+ }
2013
2150
  match.shift();
2014
2151
  this.selector = pattern;
2015
2152
  this.combinator = parseCombinator(match.shift(), pattern);
@@ -2064,13 +2201,8 @@ class Selector {
2064
2201
  }
2065
2202
  static parse(selector) {
2066
2203
  selector = selector.replace(/([+~>]) /g, "$1");
2067
- let begin = 0;
2068
- const delimiter = /((?:[^\\]) +|$)/g;
2069
- return Array.from(selector.matchAll(delimiter), (match) => {
2070
- const end = match.index + 1;
2071
- const part = selector.slice(begin, end);
2072
- begin = end + 1;
2073
- return new Pattern(part);
2204
+ return Array.from(splitSelectorElements(selector), (element) => {
2205
+ return new Pattern(unescapeCodepoint(element));
2074
2206
  });
2075
2207
  }
2076
2208
  static findCandidates(root, pattern) {
@@ -2401,7 +2533,8 @@ class HtmlElement extends DOMNode {
2401
2533
  return this.cacheSet(ROLE, role.value);
2402
2534
  }
2403
2535
  if (this.metaElement) {
2404
- const implicitRole = this.metaElement.implicitRole(this._adapter);
2536
+ const { aria } = this.metaElement;
2537
+ const implicitRole = aria.implicitRole(this._adapter);
2405
2538
  return this.cacheSet(ROLE, implicitRole);
2406
2539
  }
2407
2540
  return this.cacheSet(ROLE, null);
@@ -3143,6 +3276,48 @@ function interpolate(text, data) {
3143
3276
  });
3144
3277
  }
3145
3278
 
3279
+ const cacheKey = Symbol("aria-naming");
3280
+ const defaultValue = "allowed";
3281
+ const prohibitedRoles = [
3282
+ "caption",
3283
+ "code",
3284
+ "deletion",
3285
+ "emphasis",
3286
+ "generic",
3287
+ "insertion",
3288
+ "paragraph",
3289
+ "presentation",
3290
+ "strong",
3291
+ "subscript",
3292
+ "superscript"
3293
+ ];
3294
+ function byRole(role) {
3295
+ return prohibitedRoles.includes(role) ? "prohibited" : "allowed";
3296
+ }
3297
+ function byMeta(element, meta) {
3298
+ return meta.aria.naming(element._adapter);
3299
+ }
3300
+ function ariaNaming(element) {
3301
+ var _a;
3302
+ const cached = element.cacheGet(cacheKey);
3303
+ if (cached) {
3304
+ return cached;
3305
+ }
3306
+ const role = (_a = element.getAttribute("role")) == null ? void 0 : _a.value;
3307
+ if (role) {
3308
+ if (role instanceof DynamicValue) {
3309
+ return element.cacheSet(cacheKey, defaultValue);
3310
+ } else {
3311
+ return element.cacheSet(cacheKey, byRole(role));
3312
+ }
3313
+ }
3314
+ const meta = element.meta;
3315
+ if (!meta) {
3316
+ return element.cacheSet(cacheKey, defaultValue);
3317
+ }
3318
+ return element.cacheSet(cacheKey, byMeta(element, meta));
3319
+ }
3320
+
3146
3321
  const patternCache = /* @__PURE__ */ new Map();
3147
3322
  function compileStringPattern(pattern) {
3148
3323
  const regexp = pattern.replace(/[*]+/g, ".+");
@@ -3661,7 +3836,7 @@ class Rule {
3661
3836
  }
3662
3837
  }
3663
3838
 
3664
- const defaults$u = {
3839
+ const defaults$v = {
3665
3840
  allowExternal: true,
3666
3841
  allowRelative: true,
3667
3842
  allowAbsolute: true,
@@ -3702,7 +3877,7 @@ function matchList(value, list) {
3702
3877
  }
3703
3878
  class AllowedLinks extends Rule {
3704
3879
  constructor(options) {
3705
- super({ ...defaults$u, ...options });
3880
+ super({ ...defaults$v, ...options });
3706
3881
  this.allowExternal = parseAllow(this.options.allowExternal);
3707
3882
  this.allowRelative = parseAllow(this.options.allowRelative);
3708
3883
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -3866,7 +4041,7 @@ class AllowedLinks extends Rule {
3866
4041
  }
3867
4042
  }
3868
4043
 
3869
- const defaults$t = {
4044
+ const defaults$u = {
3870
4045
  accessible: true
3871
4046
  };
3872
4047
  function findByTarget(target, siblings) {
@@ -3896,7 +4071,7 @@ function getDescription$1(context) {
3896
4071
  }
3897
4072
  class AreaAlt extends Rule {
3898
4073
  constructor(options) {
3899
- super({ ...defaults$t, ...options });
4074
+ super({ ...defaults$u, ...options });
3900
4075
  }
3901
4076
  static schema() {
3902
4077
  return {
@@ -3975,6 +4150,9 @@ class AriaHiddenBody extends Rule {
3975
4150
  }
3976
4151
  }
3977
4152
 
4153
+ const defaults$t = {
4154
+ allowAnyNamable: false
4155
+ };
3978
4156
  const whitelisted = [
3979
4157
  "main",
3980
4158
  "nav",
@@ -4013,6 +4191,9 @@ function isValidUsage(target, meta) {
4013
4191
  return false;
4014
4192
  }
4015
4193
  class AriaLabelMisuse extends Rule {
4194
+ constructor(options) {
4195
+ super({ ...defaults$t, ...options });
4196
+ }
4016
4197
  documentation() {
4017
4198
  const valid = [
4018
4199
  "Interactive elements",
@@ -4055,6 +4236,9 @@ ${lines}`,
4055
4236
  if (isValidUsage(target, meta)) {
4056
4237
  return;
4057
4238
  }
4239
+ if (this.options.allowAnyNamable && ariaNaming(target) === "allowed") {
4240
+ return;
4241
+ }
4058
4242
  this.report(target, `"aria-label" cannot be used on this element`, attr.keyLocation);
4059
4243
  }
4060
4244
  }
@@ -7552,7 +7736,7 @@ class NoRedundantRole extends Rule {
7552
7736
  if (!meta) {
7553
7737
  return;
7554
7738
  }
7555
- const implicitRole = meta.implicitRole(target._adapter);
7739
+ const implicitRole = meta.aria.implicitRole(target._adapter);
7556
7740
  if (!implicitRole) {
7557
7741
  return;
7558
7742
  }
@@ -9334,7 +9518,7 @@ const config$4 = {
9334
9518
  rules: {
9335
9519
  "area-alt": ["error", { accessible: true }],
9336
9520
  "aria-hidden-body": "error",
9337
- "aria-label-misuse": "error",
9521
+ "aria-label-misuse": ["error", { allowAnyNamable: false }],
9338
9522
  "deprecated-rule": "warn",
9339
9523
  "empty-heading": "error",
9340
9524
  "empty-title": "error",
@@ -9386,7 +9570,7 @@ const config$1 = {
9386
9570
  rules: {
9387
9571
  "area-alt": ["error", { accessible: true }],
9388
9572
  "aria-hidden-body": "error",
9389
- "aria-label-misuse": "error",
9573
+ "aria-label-misuse": ["error", { allowAnyNamable: false }],
9390
9574
  "attr-case": "error",
9391
9575
  "attr-delimiter": "error",
9392
9576
  "attr-quotes": "error",
@@ -9467,6 +9651,7 @@ var recommended = config$1;
9467
9651
  const config = {
9468
9652
  rules: {
9469
9653
  "area-alt": ["error", { accessible: false }],
9654
+ "aria-label-misuse": ["error", { allowAnyNamable: true }],
9470
9655
  "attr-spacing": "error",
9471
9656
  "attribute-allowed-values": "error",
9472
9657
  "attribute-misuse": "error",
@@ -11719,7 +11904,7 @@ class HtmlValidate {
11719
11904
  }
11720
11905
 
11721
11906
  const name = "html-validate";
11722
- const version = "8.10.0";
11907
+ const version = "8.11.1";
11723
11908
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
11724
11909
 
11725
11910
  function definePlugin(plugin) {
@@ -12596,5 +12781,5 @@ function compatibilityCheckImpl(name, declared, options) {
12596
12781
  return false;
12597
12782
  }
12598
12783
 
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 };
12784
+ 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
12785
  //# sourceMappingURL=core.js.map