praxis-kit 6.2.3 → 6.5.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/vue/index.js CHANGED
@@ -975,7 +975,11 @@ var ATTRIBUTE_IGNORED_CODES = {
975
975
  max: DiagnosticCode3.HtmlInputMaxIgnoredForType,
976
976
  step: DiagnosticCode3.HtmlInputStepIgnoredForType,
977
977
  accept: DiagnosticCode3.HtmlInputAcceptIgnoredForType,
978
- capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType
978
+ capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType,
979
+ size: DiagnosticCode3.HtmlInputSizeIgnoredForType,
980
+ alt: DiagnosticCode3.HtmlInputAltIgnoredForType,
981
+ height: DiagnosticCode3.HtmlInputHeightIgnoredForType,
982
+ width: DiagnosticCode3.HtmlInputWidthIgnoredForType
979
983
  };
980
984
  var HtmlDiagnostics = {
981
985
  emptyRole(tag) {
@@ -1209,8 +1213,132 @@ var InvariantBase = class {
1209
1213
  }
1210
1214
  };
1211
1215
 
1212
- // ../../lib/contract/src/aria/polymorphic-validator.ts
1216
+ // ../../lib/contract/src/aria/spec/roles/required-properties.ts
1217
+ var REQUIRED_ARIA_PROPERTIES = {
1218
+ combobox: ["aria-expanded"],
1219
+ option: ["aria-selected"],
1220
+ slider: ["aria-valuenow"],
1221
+ scrollbar: ["aria-controls", "aria-valuenow"],
1222
+ spinbutton: ["aria-valuenow"]
1223
+ };
1224
+
1225
+ // ../../lib/contract/src/aria/spec/roles/name-required.ts
1226
+ var NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
1227
+
1228
+ // ../../lib/contract/src/aria/spec/validators/required-properties-validator.ts
1213
1229
  var NO_VIOLATIONS = [{ valid: true }];
1230
+ function requiredAttributeByRole(roles, attribute) {
1231
+ return Object.fromEntries([...roles].map((role) => [role, [attribute]]));
1232
+ }
1233
+ function checkRequiredAttributes(requirement, { props, effectiveRole }) {
1234
+ if (!effectiveRole) return NO_VIOLATIONS;
1235
+ const requiredAttributes = requirement.attributesByRole[effectiveRole];
1236
+ if (!requiredAttributes) return NO_VIOLATIONS;
1237
+ const results = [];
1238
+ for (const attribute of requiredAttributes) {
1239
+ if (attribute in props) continue;
1240
+ results.push({
1241
+ valid: false,
1242
+ fixable: false,
1243
+ severity: "warning",
1244
+ attribute,
1245
+ diagnostic: requirement.diagnosticFor(attribute, effectiveRole)
1246
+ });
1247
+ }
1248
+ return results;
1249
+ }
1250
+
1251
+ // ../../lib/contract/src/aria/spec/roles/live-region.ts
1252
+ var LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
1253
+ ["alert", "assertive"],
1254
+ ["status", "polite"],
1255
+ ["log", "polite"],
1256
+ ["timer", "off"]
1257
+ ]);
1258
+ var ATOMIC_REQUIREMENTS = requiredAttributeByRole(LIVE_REGION_ROLES.keys(), "aria-atomic");
1259
+
1260
+ // ../../lib/contract/src/aria/spec/attributes/aria-value-types.ts
1261
+ var ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
1262
+ // Boolean (true | false)
1263
+ ["aria-atomic", { kind: "boolean" }],
1264
+ ["aria-busy", { kind: "boolean" }],
1265
+ ["aria-disabled", { kind: "boolean" }],
1266
+ ["aria-expanded", { kind: "boolean" }],
1267
+ ["aria-hidden", { kind: "boolean" }],
1268
+ ["aria-modal", { kind: "boolean" }],
1269
+ ["aria-multiline", { kind: "boolean" }],
1270
+ ["aria-multiselectable", { kind: "boolean" }],
1271
+ ["aria-readonly", { kind: "boolean" }],
1272
+ ["aria-required", { kind: "boolean" }],
1273
+ ["aria-selected", { kind: "boolean" }],
1274
+ // Tristate (true | false | mixed)
1275
+ ["aria-checked", { kind: "tristate" }],
1276
+ ["aria-pressed", { kind: "tristate" }],
1277
+ // Numeric (any finite number)
1278
+ ["aria-valuenow", { kind: "number" }],
1279
+ ["aria-valuemin", { kind: "number" }],
1280
+ ["aria-valuemax", { kind: "number" }],
1281
+ // Integer with optional range
1282
+ ["aria-level", { kind: "integer", min: 1, max: 6 }],
1283
+ ["aria-posinset", { kind: "integer", min: 1 }],
1284
+ ["aria-setsize", { kind: "integer", min: -1 }],
1285
+ ["aria-rowcount", { kind: "integer", min: -1 }],
1286
+ ["aria-colcount", { kind: "integer", min: -1 }],
1287
+ ["aria-rowindex", { kind: "integer", min: 1 }],
1288
+ ["aria-colindex", { kind: "integer", min: 1 }],
1289
+ ["aria-rowspan", { kind: "integer", min: 0 }],
1290
+ ["aria-colspan", { kind: "integer", min: 0 }],
1291
+ // Enum (specific allowed tokens)
1292
+ ["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
1293
+ [
1294
+ "aria-current",
1295
+ {
1296
+ kind: "enum",
1297
+ values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
1298
+ }
1299
+ ],
1300
+ [
1301
+ "aria-haspopup",
1302
+ {
1303
+ kind: "enum",
1304
+ values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
1305
+ }
1306
+ ],
1307
+ ["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
1308
+ ["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
1309
+ ["aria-orientation", { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }],
1310
+ ["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
1311
+ ]);
1312
+
1313
+ // ../../lib/contract/src/aria/spec/attributes/aria-relevant-tokens.ts
1314
+ var VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set([
1315
+ "additions",
1316
+ "removals",
1317
+ "text",
1318
+ "all"
1319
+ ]);
1320
+
1321
+ // ../../lib/contract/src/aria/spec/elements/heading-implicit-levels.ts
1322
+ var HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
1323
+ ["h1", 1],
1324
+ ["h2", 2],
1325
+ ["h3", 3],
1326
+ ["h4", 4],
1327
+ ["h5", 5],
1328
+ ["h6", 6]
1329
+ ]);
1330
+
1331
+ // ../../lib/contract/src/aria/spec/elements/interactive-tags.ts
1332
+ var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1333
+ "a",
1334
+ "button",
1335
+ "input",
1336
+ "select",
1337
+ "textarea"
1338
+ ]);
1339
+
1340
+ // ../../lib/contract/src/aria/polymorphic-validator.ts
1341
+ var NO_VIOLATIONS2 = [{ valid: true }];
1214
1342
  function isIntrinsicTag(tag) {
1215
1343
  return isString(tag);
1216
1344
  }
@@ -1272,6 +1400,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1272
1400
  const violations = [];
1273
1401
  const fixes = [];
1274
1402
  iterate.forEach(rules, (rule) => {
1403
+ if (isNonNull(rule.tags) && !rule.tags.includes(context.tag)) return;
1275
1404
  iterate.forEach(rule(context), (result) => {
1276
1405
  if (result.valid) return;
1277
1406
  const {
@@ -1297,7 +1426,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1297
1426
  return { violations, fixes };
1298
1427
  }
1299
1428
  static #getRules(context) {
1300
- if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1429
+ if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && LIVE_REGION_ROLES.has(context.effectiveRole)) {
1301
1430
  return _AriaPolicyEngine.#pipeline;
1302
1431
  }
1303
1432
  return _AriaPolicyEngine.#implicitOnlyRules;
@@ -1499,7 +1628,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1499
1628
  implicitRole
1500
1629
  }) {
1501
1630
  const role = props.role;
1502
- if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS;
1631
+ if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS2;
1503
1632
  if (isStrongImplicitRole(tag) && role === "region") {
1504
1633
  const diagnostic = HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role);
1505
1634
  return [
@@ -1512,11 +1641,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1512
1641
  }
1513
1642
  ];
1514
1643
  }
1515
- return NO_VIOLATIONS;
1644
+ return NO_VIOLATIONS2;
1516
1645
  }
1517
1646
  static #checkRedundantRole({ tag, props, implicitRole }) {
1518
1647
  const role = props.role;
1519
- if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS;
1648
+ if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS2;
1520
1649
  const diagnostic = HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole);
1521
1650
  return [
1522
1651
  {
@@ -1530,8 +1659,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1530
1659
  }
1531
1660
  static #checkStandaloneRegion({ tag, props, implicitRole }) {
1532
1661
  const role = props.role;
1533
- if (role !== "region") return NO_VIOLATIONS;
1534
- if (!isStandaloneTag(tag)) return NO_VIOLATIONS;
1662
+ if (role !== "region") return NO_VIOLATIONS2;
1663
+ if (!isStandaloneTag(tag)) return NO_VIOLATIONS2;
1535
1664
  const diagnostic = HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag);
1536
1665
  return [
1537
1666
  {
@@ -1548,7 +1677,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1548
1677
  props,
1549
1678
  effectiveRole
1550
1679
  }) {
1551
- if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1680
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
1552
1681
  const results = [];
1553
1682
  iterate.forEachEntry(props, (key) => {
1554
1683
  if (!key.startsWith("aria-")) return;
@@ -1566,62 +1695,6 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1566
1695
  return results;
1567
1696
  }
1568
1697
  // ─── ARIA attribute value validation ──────────────────────────────────────
1569
- // Accepted value shapes for typed ARIA attributes.
1570
- // Attributes not in this map are unconstrained (arbitrary string values permitted).
1571
- static #ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
1572
- // Boolean (true | false)
1573
- ["aria-atomic", { kind: "boolean" }],
1574
- ["aria-busy", { kind: "boolean" }],
1575
- ["aria-disabled", { kind: "boolean" }],
1576
- ["aria-expanded", { kind: "boolean" }],
1577
- ["aria-hidden", { kind: "boolean" }],
1578
- ["aria-modal", { kind: "boolean" }],
1579
- ["aria-multiline", { kind: "boolean" }],
1580
- ["aria-multiselectable", { kind: "boolean" }],
1581
- ["aria-readonly", { kind: "boolean" }],
1582
- ["aria-required", { kind: "boolean" }],
1583
- ["aria-selected", { kind: "boolean" }],
1584
- // Tristate (true | false | mixed)
1585
- ["aria-checked", { kind: "tristate" }],
1586
- ["aria-pressed", { kind: "tristate" }],
1587
- // Numeric (any finite number)
1588
- ["aria-valuenow", { kind: "number" }],
1589
- ["aria-valuemin", { kind: "number" }],
1590
- ["aria-valuemax", { kind: "number" }],
1591
- // Integer with optional range
1592
- ["aria-level", { kind: "integer", min: 1, max: 6 }],
1593
- ["aria-posinset", { kind: "integer", min: 1 }],
1594
- ["aria-setsize", { kind: "integer", min: -1 }],
1595
- ["aria-rowcount", { kind: "integer", min: -1 }],
1596
- ["aria-colcount", { kind: "integer", min: -1 }],
1597
- ["aria-rowindex", { kind: "integer", min: 1 }],
1598
- ["aria-colindex", { kind: "integer", min: 1 }],
1599
- ["aria-rowspan", { kind: "integer", min: 0 }],
1600
- ["aria-colspan", { kind: "integer", min: 0 }],
1601
- // Enum (specific allowed tokens)
1602
- ["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
1603
- [
1604
- "aria-current",
1605
- {
1606
- kind: "enum",
1607
- values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
1608
- }
1609
- ],
1610
- [
1611
- "aria-haspopup",
1612
- {
1613
- kind: "enum",
1614
- values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
1615
- }
1616
- ],
1617
- ["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
1618
- ["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
1619
- [
1620
- "aria-orientation",
1621
- { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }
1622
- ],
1623
- ["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
1624
- ]);
1625
1698
  static #isValidAriaValue(value, type) {
1626
1699
  switch (type.kind) {
1627
1700
  case "boolean":
@@ -1666,11 +1739,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1666
1739
  }
1667
1740
  }
1668
1741
  static #checkAriaAttributeValues({ props, effectiveRole }) {
1669
- if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1742
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
1670
1743
  const results = [];
1671
1744
  iterate.forEachEntry(props, (key, value) => {
1672
1745
  if (!key.startsWith("aria-")) return;
1673
- const type = _AriaPolicyEngine.#ARIA_VALUE_TYPES.get(key);
1746
+ const type = ARIA_VALUE_TYPES.get(key);
1674
1747
  if (!isNonNull(type)) return;
1675
1748
  if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
1676
1749
  results.push({
@@ -1689,26 +1762,18 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1689
1762
  return results;
1690
1763
  }
1691
1764
  // ─── Heading implicit level ────────────────────────────────────────────────
1692
- static #HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
1693
- ["h1", 1],
1694
- ["h2", 2],
1695
- ["h3", 3],
1696
- ["h4", 4],
1697
- ["h5", 5],
1698
- ["h6", 6]
1699
- ]);
1700
1765
  static #checkRedundantAriaLevel({
1701
1766
  tag,
1702
1767
  props,
1703
1768
  effectiveRole
1704
1769
  }) {
1705
- if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1706
- const implicitLevel = _AriaPolicyEngine.#HEADING_IMPLICIT_LEVELS.get(tag);
1707
- if (!isNonNull(implicitLevel)) return NO_VIOLATIONS;
1770
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS2;
1771
+ const implicitLevel = HEADING_IMPLICIT_LEVELS.get(tag);
1772
+ if (!isNonNull(implicitLevel)) return NO_VIOLATIONS2;
1708
1773
  const raw = props["aria-level"];
1709
- if (!isNonNull(raw)) return NO_VIOLATIONS;
1774
+ if (!isNonNull(raw)) return NO_VIOLATIONS2;
1710
1775
  const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
1711
- if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS;
1776
+ if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS2;
1712
1777
  return [
1713
1778
  {
1714
1779
  valid: false,
@@ -1721,20 +1786,14 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1721
1786
  ];
1722
1787
  }
1723
1788
  // ─── Name-required roles ───────────────────────────────────────────────────
1724
- // Roles that always require an accessible name per WAI-ARIA APG.
1725
- // Dialog and landmark names are enforced via contracts (ariaContract) rather than
1726
- // the built-in pipeline so consumers can opt in; img is built in because role=img
1727
- // on any element (including bare <img>) is definitionally useless without a name.
1728
- static #NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
1729
1789
  static #checkNameRequiredRoles({
1730
1790
  tag,
1731
1791
  props,
1732
1792
  effectiveRole
1733
1793
  }) {
1734
- if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole))
1735
- return NO_VIOLATIONS;
1736
- if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS;
1737
- if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS;
1794
+ if (!effectiveRole || !NAME_REQUIRED_ROLES.has(effectiveRole)) return NO_VIOLATIONS2;
1795
+ if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS2;
1796
+ if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS2;
1738
1797
  return [
1739
1798
  {
1740
1799
  valid: false,
@@ -1744,51 +1803,21 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1744
1803
  }
1745
1804
  ];
1746
1805
  }
1747
- // WAI-ARIA 1.2 required states and properties, keyed by role.
1748
- // Source: https://www.w3.org/TR/wai-aria-1.2/#requiredState
1749
- static #REQUIRED_PROPERTIES = /* @__PURE__ */ new Map([
1750
- ["combobox", ["aria-expanded"]],
1751
- ["option", ["aria-selected"]],
1752
- ["slider", ["aria-valuenow"]],
1753
- ["scrollbar", ["aria-controls", "aria-valuenow"]],
1754
- ["spinbutton", ["aria-valuenow"]]
1755
- ]);
1756
- static #checkRequiredAriaProperties({
1757
- props,
1758
- effectiveRole
1759
- }) {
1760
- if (!effectiveRole) return NO_VIOLATIONS;
1761
- const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
1762
- if (!isNonNull(required)) return NO_VIOLATIONS;
1763
- const results = [];
1764
- iterate.forEach(required, (attr) => {
1765
- if (attr in props) return;
1766
- results.push({
1767
- valid: false,
1768
- fixable: false,
1769
- severity: "warning",
1770
- attribute: attr,
1771
- diagnostic: AriaDiagnostics.requiredProperty(attr, effectiveRole)
1772
- });
1773
- });
1774
- return results;
1806
+ static #requiredAriaPropertiesRule = {
1807
+ attributesByRole: REQUIRED_ARIA_PROPERTIES,
1808
+ diagnosticFor: (attribute, role) => AriaDiagnostics.requiredProperty(attribute, role)
1809
+ };
1810
+ static #checkRequiredAriaProperties(context) {
1811
+ return checkRequiredAttributes(_AriaPolicyEngine.#requiredAriaPropertiesRule, context);
1775
1812
  }
1776
- // Natively interactive HTML elements — always keyboard-reachable unless explicitly disabled.
1777
- static #INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1778
- "a",
1779
- "button",
1780
- "input",
1781
- "select",
1782
- "textarea"
1783
- ]);
1784
1813
  // WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
1785
1814
  static #checkAriaHiddenOnFocusable({ tag, props }) {
1786
- if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS;
1787
- const isInteractive = _AriaPolicyEngine.#INTERACTIVE_TAGS.has(tag);
1815
+ if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS2;
1816
+ const isInteractive = INTERACTIVE_TAGS.has(tag);
1788
1817
  if (!isInteractive) {
1789
1818
  const tabindex = props.tabindex;
1790
1819
  const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
1791
- if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS;
1820
+ if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS2;
1792
1821
  }
1793
1822
  return [
1794
1823
  {
@@ -1807,7 +1836,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1807
1836
  props,
1808
1837
  effectiveRole
1809
1838
  }) {
1810
- if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS;
1839
+ if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS2;
1811
1840
  const results = [];
1812
1841
  iterate.forEachEntry(props, (key) => {
1813
1842
  if (!key.startsWith("aria-")) return;
@@ -1823,18 +1852,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1823
1852
  });
1824
1853
  return results;
1825
1854
  }
1826
- // WAI-ARIA live region roles and their implied aria-live politeness values.
1827
- static #LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
1828
- ["alert", "assertive"],
1829
- ["status", "polite"],
1830
- ["log", "polite"],
1831
- ["timer", "off"]
1832
- ]);
1833
1855
  static #checkMissingLiveRegion({ effectiveRole, props }) {
1834
- if (!effectiveRole) return NO_VIOLATIONS;
1835
- const impliedLive = _AriaPolicyEngine.#LIVE_REGION_ROLES.get(effectiveRole);
1836
- if (!impliedLive) return NO_VIOLATIONS;
1837
- if ("aria-live" in props) return NO_VIOLATIONS;
1856
+ if (!effectiveRole) return NO_VIOLATIONS2;
1857
+ const impliedLive = LIVE_REGION_ROLES.get(effectiveRole);
1858
+ if (!impliedLive) return NO_VIOLATIONS2;
1859
+ if ("aria-live" in props) return NO_VIOLATIONS2;
1838
1860
  const injectLive = {
1839
1861
  kind: `injectLive:${effectiveRole}`,
1840
1862
  apply: (ctx) => ({
@@ -1853,20 +1875,13 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1853
1875
  }
1854
1876
  ];
1855
1877
  }
1856
- static #checkMissingAtomic({ effectiveRole, props }) {
1857
- if (!effectiveRole || !_AriaPolicyEngine.#LIVE_REGION_ROLES.has(effectiveRole))
1858
- return NO_VIOLATIONS;
1859
- if ("aria-atomic" in props) return NO_VIOLATIONS;
1860
- return [
1861
- {
1862
- valid: false,
1863
- fixable: false,
1864
- severity: "warning",
1865
- diagnostic: AriaDiagnostics.missingAtomic(effectiveRole)
1866
- }
1867
- ];
1878
+ static #missingAtomicRule = {
1879
+ attributesByRole: ATOMIC_REQUIREMENTS,
1880
+ diagnosticFor: (_attribute, role) => AriaDiagnostics.missingAtomic(role)
1881
+ };
1882
+ static #checkMissingAtomic(context) {
1883
+ return checkRequiredAttributes(_AriaPolicyEngine.#missingAtomicRule, context);
1868
1884
  }
1869
- static #VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set(["additions", "removals", "text", "all"]);
1870
1885
  // Custom fix rules passed via `options.rules` must be pure functions of (tag, props) — the cache
1871
1886
  // replays stored fixes against new prop objects, so fixes that close over external state will
1872
1887
  // produce inconsistent results on cache hits.
@@ -1880,10 +1895,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1880
1895
  };
1881
1896
  static #checkInvalidAriaRelevant({ props }) {
1882
1897
  const relevant = props["aria-relevant"];
1883
- if (relevant === void 0) return NO_VIOLATIONS;
1884
- if (typeof relevant !== "string") return NO_VIOLATIONS;
1898
+ if (relevant === void 0) return NO_VIOLATIONS2;
1899
+ if (typeof relevant !== "string") return NO_VIOLATIONS2;
1885
1900
  const tokens = relevant.trim().split(/\s+/);
1886
- const invalid = tokens.filter((t) => !_AriaPolicyEngine.#VALID_RELEVANT_TOKENS.has(t));
1901
+ const invalid = tokens.filter((t) => !VALID_RELEVANT_TOKENS.has(t));
1887
1902
  if (invalid.length > 0) {
1888
1903
  return [
1889
1904
  {
@@ -1908,7 +1923,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1908
1923
  }
1909
1924
  ];
1910
1925
  }
1911
- return NO_VIOLATIONS;
1926
+ return NO_VIOLATIONS2;
1912
1927
  }
1913
1928
  };
1914
1929
 
@@ -2228,7 +2243,59 @@ var readonlyProps = ({
2228
2243
  // ../core/src/html/evaluators.ts
2229
2244
  import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2230
2245
 
2231
- // ../core/src/html/input-rules.ts
2246
+ // ../core/src/html/spec/vocabulary/input.ts
2247
+ var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
2248
+ var NUMERIC_INPUT_TYPES = [
2249
+ "number",
2250
+ "range",
2251
+ "date",
2252
+ "month",
2253
+ "week",
2254
+ "time",
2255
+ "datetime-local"
2256
+ ];
2257
+ var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
2258
+ ...TEXT_INPUT_TYPES,
2259
+ ...NUMERIC_INPUT_TYPES,
2260
+ "checkbox",
2261
+ "radio",
2262
+ "file",
2263
+ "color",
2264
+ "hidden",
2265
+ "button",
2266
+ "submit",
2267
+ "reset",
2268
+ "image"
2269
+ ]);
2270
+
2271
+ // ../core/src/html/spec/attributes/input.ts
2272
+ var INPUT_ATTRIBUTE_TYPE_POLICIES = [
2273
+ { attribute: "checked", allowedTypes: ["checkbox", "radio"] },
2274
+ { attribute: "multiple", allowedTypes: ["email", "file"] },
2275
+ { attribute: "maxLength", allowedTypes: TEXT_INPUT_TYPES },
2276
+ { attribute: "minLength", allowedTypes: TEXT_INPUT_TYPES },
2277
+ { attribute: "pattern", allowedTypes: TEXT_INPUT_TYPES },
2278
+ { attribute: "min", allowedTypes: NUMERIC_INPUT_TYPES },
2279
+ { attribute: "max", allowedTypes: NUMERIC_INPUT_TYPES },
2280
+ { attribute: "step", allowedTypes: NUMERIC_INPUT_TYPES },
2281
+ { attribute: "accept", allowedTypes: ["file"] },
2282
+ { attribute: "capture", allowedTypes: ["file"] },
2283
+ { attribute: "size", allowedTypes: TEXT_INPUT_TYPES },
2284
+ { attribute: "alt", allowedTypes: ["image"] },
2285
+ { attribute: "height", allowedTypes: ["image"] },
2286
+ { attribute: "width", allowedTypes: ["image"] }
2287
+ ];
2288
+
2289
+ // ../core/src/html/spec/constraints/input.ts
2290
+ var REQUIRED_READONLY_CONFLICT = {
2291
+ props: ["required", "readOnly"],
2292
+ diagnostic: () => InputAccessibilityDiagnostics.requiredReadOnlyConflict()
2293
+ };
2294
+ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2295
+ REQUIRED_READONLY_CONFLICT
2296
+ ];
2297
+
2298
+ // ../core/src/html/spec/validators/attribute-type-validator.ts
2232
2299
  var DEFAULT_INPUT_TYPE = "text";
2233
2300
  function omit(props, key) {
2234
2301
  const next = { ...props };
@@ -2244,7 +2311,10 @@ function removeAttributeFix(attribute) {
2244
2311
  }
2245
2312
  };
2246
2313
  }
2247
- function inputAttributeRequiresType(attribute, allowedTypes) {
2314
+ function createInputAttributeTypeRule({
2315
+ attribute,
2316
+ allowedTypes
2317
+ }) {
2248
2318
  const rule = ({ tag, props }) => {
2249
2319
  if (tag !== "input" || !(attribute in props)) return [];
2250
2320
  const type = typeof props.type === "string" ? props.type : DEFAULT_INPUT_TYPE;
@@ -2260,31 +2330,30 @@ function inputAttributeRequiresType(attribute, allowedTypes) {
2260
2330
  }
2261
2331
  ];
2262
2332
  };
2263
- return Object.assign(rule, { readsProps: ["type", attribute] });
2333
+ return Object.assign(rule, { readsProps: ["type", attribute], tags: ["input"] });
2334
+ }
2335
+
2336
+ // ../core/src/html/spec/validators/mutually-exclusive-validator.ts
2337
+ function createMutuallyExclusiveRule({
2338
+ props: conflictingProps,
2339
+ diagnostic: createDiagnostic
2340
+ }) {
2341
+ const [first, second] = conflictingProps;
2342
+ const rule = ({ tag, props }) => {
2343
+ if (tag !== "input" || !props[first] || !props[second]) return [];
2344
+ const diagnostic = createDiagnostic();
2345
+ return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2346
+ };
2347
+ return Object.assign(rule, { readsProps: conflictingProps, tags: ["input"] });
2348
+ }
2349
+
2350
+ // ../core/src/html/input-rules.ts
2351
+ var policyByAttribute = Object.fromEntries(
2352
+ INPUT_ATTRIBUTE_TYPE_POLICIES.map((policy) => [policy.attribute, policy])
2353
+ );
2354
+ function policyFor(attribute) {
2355
+ return policyByAttribute[attribute];
2264
2356
  }
2265
- var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
2266
- var NUMERIC_INPUT_TYPES = [
2267
- "number",
2268
- "range",
2269
- "date",
2270
- "month",
2271
- "week",
2272
- "time",
2273
- "datetime-local"
2274
- ];
2275
- var HTML_INPUT_TYPES = /* @__PURE__ */ new Set([
2276
- ...TEXT_INPUT_TYPES,
2277
- ...NUMERIC_INPUT_TYPES,
2278
- "checkbox",
2279
- "radio",
2280
- "file",
2281
- "color",
2282
- "hidden",
2283
- "button",
2284
- "submit",
2285
- "reset",
2286
- "image"
2287
- ]);
2288
2357
  var supportedInputTypeRule = Object.assign(
2289
2358
  ({ tag, props }) => {
2290
2359
  if (tag !== "input" || typeof props.type !== "string") return [];
@@ -2300,30 +2369,22 @@ var supportedInputTypeRule = Object.assign(
2300
2369
  }
2301
2370
  ];
2302
2371
  },
2303
- { readsProps: ["type"] }
2372
+ { readsProps: ["type"], tags: ["input"] }
2304
2373
  );
2305
- var checkedRequiresCheckableTypeRule = inputAttributeRequiresType("checked", [
2306
- "checkbox",
2307
- "radio"
2308
- ]);
2309
- var multipleRequiresSupportedTypeRule = inputAttributeRequiresType("multiple", [
2310
- "email",
2311
- "file"
2312
- ]);
2313
- var maxLengthRequiresTextTypeRule = inputAttributeRequiresType(
2314
- "maxLength",
2315
- TEXT_INPUT_TYPES
2316
- );
2317
- var minLengthRequiresTextTypeRule = inputAttributeRequiresType(
2318
- "minLength",
2319
- TEXT_INPUT_TYPES
2320
- );
2321
- var patternRequiresTextTypeRule = inputAttributeRequiresType("pattern", TEXT_INPUT_TYPES);
2322
- var minRequiresNumericTypeRule = inputAttributeRequiresType("min", NUMERIC_INPUT_TYPES);
2323
- var maxRequiresNumericTypeRule = inputAttributeRequiresType("max", NUMERIC_INPUT_TYPES);
2324
- var stepRequiresNumericTypeRule = inputAttributeRequiresType("step", NUMERIC_INPUT_TYPES);
2325
- var acceptRequiresFileTypeRule = inputAttributeRequiresType("accept", ["file"]);
2326
- var captureRequiresFileTypeRule = inputAttributeRequiresType("capture", ["file"]);
2374
+ var checkedRequiresCheckableTypeRule = createInputAttributeTypeRule(policyFor("checked"));
2375
+ var multipleRequiresSupportedTypeRule = createInputAttributeTypeRule(policyFor("multiple"));
2376
+ var maxLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("maxLength"));
2377
+ var minLengthRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("minLength"));
2378
+ var patternRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("pattern"));
2379
+ var minRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("min"));
2380
+ var maxRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("max"));
2381
+ var stepRequiresNumericTypeRule = createInputAttributeTypeRule(policyFor("step"));
2382
+ var acceptRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("accept"));
2383
+ var captureRequiresFileTypeRule = createInputAttributeTypeRule(policyFor("capture"));
2384
+ var sizeRequiresTextTypeRule = createInputAttributeTypeRule(policyFor("size"));
2385
+ var altRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("alt"));
2386
+ var heightRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("height"));
2387
+ var widthRequiresImageTypeRule = createInputAttributeTypeRule(policyFor("width"));
2327
2388
  var inputAccessibleNameRule = Object.assign(
2328
2389
  ({ tag, props }) => {
2329
2390
  if (tag !== "input" || props.type === "hidden") return [];
@@ -2332,7 +2393,10 @@ var inputAccessibleNameRule = Object.assign(
2332
2393
  const diagnostic = hasPlaceholder ? InputAccessibilityDiagnostics.placeholderIsNotLabel() : InputAccessibilityDiagnostics.missingAccessibleName();
2333
2394
  return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2334
2395
  },
2335
- { readsProps: ["type", "aria-label", "aria-labelledby", "placeholder"] }
2396
+ {
2397
+ readsProps: ["type", "aria-label", "aria-labelledby", "placeholder"],
2398
+ tags: ["input"]
2399
+ }
2336
2400
  );
2337
2401
  var PASSWORD_AUTOCOMPLETE_VALUES = ["current-password", "new-password"];
2338
2402
  var passwordAutocompleteRule = Object.assign(
@@ -2344,16 +2408,9 @@ var passwordAutocompleteRule = Object.assign(
2344
2408
  const diagnostic = InputAccessibilityDiagnostics.passwordMissingAutocomplete();
2345
2409
  return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2346
2410
  },
2347
- { readsProps: ["type", "autoComplete"] }
2348
- );
2349
- var requiredReadOnlyConflictRule = Object.assign(
2350
- ({ tag, props }) => {
2351
- if (tag !== "input" || !props.required || !props.readOnly) return [];
2352
- const diagnostic = InputAccessibilityDiagnostics.requiredReadOnlyConflict();
2353
- return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2354
- },
2355
- { readsProps: ["required", "readOnly"] }
2411
+ { readsProps: ["type", "autoComplete"], tags: ["input"] }
2356
2412
  );
2413
+ var requiredReadOnlyConflictRule = createMutuallyExclusiveRule(REQUIRED_READONLY_CONFLICT);
2357
2414
  var INPUT_RULES = [
2358
2415
  supportedInputTypeRule,
2359
2416
  checkedRequiresCheckableTypeRule,
@@ -2366,11 +2423,132 @@ var INPUT_RULES = [
2366
2423
  stepRequiresNumericTypeRule,
2367
2424
  acceptRequiresFileTypeRule,
2368
2425
  captureRequiresFileTypeRule,
2426
+ sizeRequiresTextTypeRule,
2427
+ altRequiresImageTypeRule,
2428
+ heightRequiresImageTypeRule,
2429
+ widthRequiresImageTypeRule,
2369
2430
  inputAccessibleNameRule,
2370
2431
  passwordAutocompleteRule,
2371
2432
  requiredReadOnlyConflictRule
2372
2433
  ];
2373
2434
 
2435
+ // ../core/src/html/spec/types.ts
2436
+ function definePropRolePolicy(prop, map2, fallback) {
2437
+ return { kind: "byProp", prop, map: map2, fallback };
2438
+ }
2439
+ function resolveAllowedRoles(spec, props) {
2440
+ const policy = spec.allowedRoles;
2441
+ if (!policy) return void 0;
2442
+ switch (policy.kind) {
2443
+ case "fixed":
2444
+ return policy.roles;
2445
+ case "byProp": {
2446
+ const value = typeof props[policy.prop] === "string" ? props[policy.prop] : policy.fallback;
2447
+ return policy.map[value];
2448
+ }
2449
+ case "dynamic":
2450
+ return policy.resolve({ props });
2451
+ }
2452
+ }
2453
+
2454
+ // ../core/src/html/spec/roles/input.ts
2455
+ var ALLOWED_INPUT_ROLES = {
2456
+ checkbox: ["menuitemcheckbox", "option", "switch", "button"],
2457
+ radio: ["menuitemradio"],
2458
+ range: [],
2459
+ number: [],
2460
+ search: ["combobox"],
2461
+ text: ["combobox", "searchbox", "spinbutton"],
2462
+ email: ["combobox"],
2463
+ tel: ["combobox"],
2464
+ url: ["combobox"],
2465
+ button: [
2466
+ "link",
2467
+ "menuitem",
2468
+ "menuitemcheckbox",
2469
+ "menuitemradio",
2470
+ "option",
2471
+ "radio",
2472
+ "switch",
2473
+ "tab"
2474
+ ],
2475
+ submit: [
2476
+ "link",
2477
+ "menuitem",
2478
+ "menuitemcheckbox",
2479
+ "menuitemradio",
2480
+ "option",
2481
+ "radio",
2482
+ "switch",
2483
+ "tab"
2484
+ ],
2485
+ reset: [
2486
+ "link",
2487
+ "menuitem",
2488
+ "menuitemcheckbox",
2489
+ "menuitemradio",
2490
+ "option",
2491
+ "radio",
2492
+ "switch",
2493
+ "tab"
2494
+ ],
2495
+ image: [
2496
+ "link",
2497
+ "menuitem",
2498
+ "menuitemcheckbox",
2499
+ "menuitemradio",
2500
+ "option",
2501
+ "radio",
2502
+ "switch",
2503
+ "tab"
2504
+ ],
2505
+ hidden: []
2506
+ };
2507
+
2508
+ // ../core/src/html/spec/elements/input.ts
2509
+ var inputElementSpec = {
2510
+ tag: "input",
2511
+ allowedRoles: definePropRolePolicy("type", ALLOWED_INPUT_ROLES, "text"),
2512
+ attributes: INPUT_ATTRIBUTE_TYPE_POLICIES,
2513
+ mutuallyExclusive: INPUT_MUTUALLY_EXCLUSIVE_POLICIES
2514
+ };
2515
+
2516
+ // ../core/src/html/spec/roles/img.ts
2517
+ var IMG_NAMED_ROLES = [
2518
+ "button",
2519
+ "checkbox",
2520
+ "link",
2521
+ "menuitem",
2522
+ "menuitemcheckbox",
2523
+ "menuitemradio",
2524
+ "option",
2525
+ "progressbar",
2526
+ "scrollbar",
2527
+ "separator",
2528
+ "slider",
2529
+ "switch",
2530
+ "tab",
2531
+ "treeitem"
2532
+ ];
2533
+
2534
+ // ../core/src/html/spec/elements/img.ts
2535
+ var imgElementSpec = {
2536
+ tag: "img",
2537
+ allowedRoles: {
2538
+ kind: "dynamic",
2539
+ resolve: ({ props }) => props.alt === "" ? [] : IMG_NAMED_ROLES
2540
+ }
2541
+ };
2542
+
2543
+ // ../core/src/html/spec/roles/table.ts
2544
+ var ALLOWED_TABLE_ROLES = ["grid", "treegrid"];
2545
+
2546
+ // ../core/src/html/spec/elements/table.ts
2547
+ var tableElementSpec = {
2548
+ tag: "table",
2549
+ allowedRoles: { kind: "fixed", roles: ALLOWED_TABLE_ROLES }
2550
+ };
2551
+
2374
2552
  // ../core/src/html/role-restrictions.ts
2375
2553
  var ALLOWED_ROLES = {
2376
2554
  article: ["application", "document", "feed", "main", "none", "presentation", "region"],
@@ -2443,86 +2621,17 @@ var ALLOWED_ROLES = {
2443
2621
  "tab",
2444
2622
  "treeitem"
2445
2623
  ],
2446
- table: ["grid", "treegrid"],
2447
2624
  dialog: ["alertdialog"],
2448
2625
  fieldset: ["none", "presentation", "radiogroup"]
2449
2626
  };
2450
- var IMG_NAMED_ROLES = [
2451
- "button",
2452
- "checkbox",
2453
- "link",
2454
- "menuitem",
2455
- "menuitemcheckbox",
2456
- "menuitemradio",
2457
- "option",
2458
- "progressbar",
2459
- "scrollbar",
2460
- "separator",
2461
- "slider",
2462
- "switch",
2463
- "tab",
2464
- "treeitem"
2465
- ];
2466
- var ALLOWED_INPUT_ROLES = {
2467
- checkbox: ["menuitemcheckbox", "option", "switch", "button"],
2468
- radio: ["menuitemradio"],
2469
- range: [],
2470
- number: [],
2471
- search: ["combobox"],
2472
- text: ["combobox", "searchbox", "spinbutton"],
2473
- email: ["combobox"],
2474
- tel: ["combobox"],
2475
- url: ["combobox"],
2476
- button: [
2477
- "link",
2478
- "menuitem",
2479
- "menuitemcheckbox",
2480
- "menuitemradio",
2481
- "option",
2482
- "radio",
2483
- "switch",
2484
- "tab"
2485
- ],
2486
- submit: [
2487
- "link",
2488
- "menuitem",
2489
- "menuitemcheckbox",
2490
- "menuitemradio",
2491
- "option",
2492
- "radio",
2493
- "switch",
2494
- "tab"
2495
- ],
2496
- reset: [
2497
- "link",
2498
- "menuitem",
2499
- "menuitemcheckbox",
2500
- "menuitemradio",
2501
- "option",
2502
- "radio",
2503
- "switch",
2504
- "tab"
2505
- ],
2506
- image: [
2507
- "link",
2508
- "menuitem",
2509
- "menuitemcheckbox",
2510
- "menuitemradio",
2511
- "option",
2512
- "radio",
2513
- "switch",
2514
- "tab"
2515
- ],
2516
- hidden: []
2627
+ var ELEMENT_SPECS = {
2628
+ input: inputElementSpec,
2629
+ img: imgElementSpec,
2630
+ table: tableElementSpec
2517
2631
  };
2518
2632
  function getAllowedRoles(tag, props) {
2519
- if (tag === "input") {
2520
- const type = typeof props.type === "string" ? props.type : "text";
2521
- return ALLOWED_INPUT_ROLES[type];
2522
- }
2523
- if (tag === "img") {
2524
- return props.alt === "" ? [] : IMG_NAMED_ROLES;
2525
- }
2633
+ const spec = ELEMENT_SPECS[tag];
2634
+ if (spec) return resolveAllowedRoles(spec, props);
2526
2635
  return ALLOWED_ROLES[tag];
2527
2636
  }
2528
2637
  var removeRoleFix = {
@@ -2563,21 +2672,24 @@ var removeLandmarkRoleOverride = {
2563
2672
  return { applied: true, next: rest, previous: props };
2564
2673
  }
2565
2674
  };
2566
- function landmarkRoleRule({ tag, props, implicitRole }) {
2567
- if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
2568
- const role = props.role;
2569
- if (!role || role === implicitRole) return [];
2570
- const diagnostic = HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role);
2571
- return [
2572
- {
2573
- valid: false,
2574
- fixable: true,
2575
- severity: diagnostic.severity,
2576
- fix: removeLandmarkRoleOverride,
2577
- diagnostic
2578
- }
2579
- ];
2580
- }
2675
+ var landmarkRoleRule = Object.assign(
2676
+ ({ tag, props, implicitRole }) => {
2677
+ if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
2678
+ const role = props.role;
2679
+ if (!role || role === implicitRole) return [];
2680
+ const diagnostic = HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role);
2681
+ return [
2682
+ {
2683
+ valid: false,
2684
+ fixable: true,
2685
+ severity: diagnostic.severity,
2686
+ fix: removeLandmarkRoleOverride,
2687
+ diagnostic
2688
+ }
2689
+ ];
2690
+ },
2691
+ { tags: [...LANDMARK_TAG_SET] }
2692
+ );
2581
2693
  function requireAccessibleName({ tag, props }) {
2582
2694
  if ("aria-label" in props || "aria-labelledby" in props) return [];
2583
2695
  return [
@@ -2590,10 +2702,13 @@ function requireAccessibleName({ tag, props }) {
2590
2702
  ];
2591
2703
  }
2592
2704
  var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
2593
- function landmarkNameAdvisory(ctx) {
2594
- if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
2595
- return requireAccessibleName(ctx);
2596
- }
2705
+ var landmarkNameAdvisory = Object.assign(
2706
+ (ctx) => {
2707
+ if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
2708
+ return requireAccessibleName(ctx);
2709
+ },
2710
+ { tags: [...NAMED_LANDMARK_TAGS] }
2711
+ );
2597
2712
  var HTML_ARIA_RULES = [
2598
2713
  landmarkRoleRule,
2599
2714
  landmarkNameAdvisory,
@@ -2694,6 +2809,62 @@ var figureContract = contract([
2694
2809
  ]);
2695
2810
  var detailsContract = firstChildContract("summary", "summary");
2696
2811
  var fieldsetContract = firstChildContract("legend", "legend");
2812
+ var objectContract = contract([
2813
+ { name: "param", match: isTag("param") },
2814
+ { name: "content", match: isOpenContent("param") }
2815
+ ]);
2816
+ var INTERACTIVE_CONTENT_TAGS = ["a", "button", "input", "select", "textarea", "label"];
2817
+ var buttonContract = closedContract([
2818
+ { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2819
+ ]);
2820
+ var anchorContract = closedContract([
2821
+ { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2822
+ ]);
2823
+ var LABELABLE_TAGS = [
2824
+ "button",
2825
+ "input",
2826
+ "meter",
2827
+ "output",
2828
+ "progress",
2829
+ "select",
2830
+ "textarea"
2831
+ ];
2832
+ var labelContract = contract([
2833
+ { name: "control", match: isTag(...LABELABLE_TAGS), cardinality: { max: 1 } }
2834
+ ]);
2835
+ var P_BLOCKED_TAGS = [
2836
+ "address",
2837
+ "article",
2838
+ "aside",
2839
+ "blockquote",
2840
+ "details",
2841
+ "dialog",
2842
+ "div",
2843
+ "dl",
2844
+ "fieldset",
2845
+ "figure",
2846
+ "footer",
2847
+ "form",
2848
+ "h1",
2849
+ "h2",
2850
+ "h3",
2851
+ "h4",
2852
+ "h5",
2853
+ "h6",
2854
+ "header",
2855
+ "hr",
2856
+ "main",
2857
+ "nav",
2858
+ "ol",
2859
+ "p",
2860
+ "pre",
2861
+ "section",
2862
+ "table",
2863
+ "ul"
2864
+ ];
2865
+ var pContract = closedContract([
2866
+ { name: "content", match: isOpenContent(...P_BLOCKED_TAGS) }
2867
+ ]);
2697
2868
  var mediaContract = contract([
2698
2869
  { name: "source", match: isTag("source") },
2699
2870
  { name: "track", match: isTag("track") },
@@ -2748,6 +2919,11 @@ var htmlContracts = {
2748
2919
  details: detailsContract,
2749
2920
  fieldset: fieldsetContract,
2750
2921
  dialog: dialogContract,
2922
+ object: objectContract,
2923
+ button: buttonContract,
2924
+ a: anchorContract,
2925
+ label: labelContract,
2926
+ p: pContract,
2751
2927
  head: headContract,
2752
2928
  html: htmlContract
2753
2929
  };