Index: frontend/node_modules/eslint-plugin-jsx-a11y/.babelrc
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/.babelrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/.babelrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+{
+  "presets": [
+    [
+      "airbnb",
+      {
+        "targets": {
+          "node": 4
+        },
+        "transformRuntime": false
+      }
+    ]
+  ],
+  "plugins": [
+    "@babel/plugin-transform-flow-strip-types",
+    "add-module-exports"
+  ]
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/.eslintrc
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/.eslintrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/.eslintrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+{
+  "root": true,
+  "extends": [
+    "airbnb-base",
+    "plugin:flowtype/recommended"
+  ],
+  "ignorePatterns": [
+    "lib/",
+    "reports/",
+    "examples/",
+  ],
+  "parser": "@babel/eslint-parser",
+  "plugins": [
+    "flowtype",
+  ],
+  "rules": {
+    "max-len": "off",
+    "no-template-curly-in-string": "off",
+  },
+  "overrides": [
+    {
+      "files": ["src/rules/*"],
+      "extends": ["plugin:eslint-plugin/rules-recommended"],
+      "rules": {
+        "eslint-plugin/require-meta-docs-description": ["error", { "pattern": "^(Enforce|Require|Disallow)" }],
+        "eslint-plugin/require-meta-docs-url": [
+          "error",
+          { "pattern": "https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/{{name}}.md" },
+        ],
+        "eslint-plugin/require-meta-type": "off",
+      },
+    },
+    {
+      "files": ["__tests__/src/rules/*.js"],
+      "extends": ["plugin:eslint-plugin/tests-recommended"],
+    },
+    {
+      "files": ["__tests__/**/*"],
+      "env": {
+        "jest": true,
+      },
+    },
+  ],
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/CHANGELOG.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/CHANGELOG.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/CHANGELOG.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,774 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [v6.10.2](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.10.1...v6.10.2) - 2024-10-25
+
+### Fixed
+
+- [patch] `no-redundandant-roles`: allow `&lt;img src="*.svg" role="img" /&gt;` [`#936`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/936)
+
+### Commits
+
+- [meta] fix changelog URLs [`0d01a1a`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0d01a1aff796802bca70183b24978ffebdbef073)
+- [Refactor] remove no-longer-needed `es-iterator-helpers` [`aa075bd`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/aa075bd1897e0b0bb61683e4da68558f38511dae)
+- [Refactor] avoid spreading things that are already arrays [`d15d3ab`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/d15d3abace7afe833d0988eaf3fb7cc166c05c06)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `@babel/register` [`5dad7c4`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/5dad7c4fdfdc56c6e488fab54f25f602430dad30)
+- [Tests] `aria-role`: Add valid test for `&lt;svg role="img" /&gt;` [`daba189`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/daba18974473bce1301ffaafb822558a9e1738ae)
+- [Docs] `label-has-associated-control`: add line breaks for readability [`0bc6378`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0bc63781c8f284ac6bef00321763c13c5bea6b9f)
+- [Tests] `label-has-associated-control`: add additional test cases [`30d2318`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/30d23189d0b6354750c31a622204a9dc412dc2c1)
+- [Tests] Add tests to reinforce required attributes for role="heading" [`d92446c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/d92446c6e608617a4c75173e8b0917c06be14dc6)
+
+## [v6.10.1](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.10.0...v6.10.1) - 2024-10-20
+
+### Commits
+
+- [Fix] handle interactive/noninteractive changes from aria-query [`4925ba8`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/4925ba8d0bf80a4b1d8e8645d310590bf1b40b64)
+- [Docs] Use consistent spelling of 'screen reader' [`cb6788c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/cb6788c56d7108f2faa102d041dfa37dbc0e9f59)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `@babel/register`, `auto-changelog`, `eslint-plugin-import`, `tape` [`518a77e`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/518a77e1e23fb2b1df2e8a97d14bfdd08aded797)
+- [Deps] update `es-iterator-helpers`, `string.prototype.includes` [`eed03a3`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/eed03a31f313442158cf7d702443723ad4800dec)
+- [meta] package.json - Update jscodeshift & remove babel-jest [`2ee940c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/2ee940c5ae87bcd0d384b6dc565d630ea70e103a)
+- [Docs] Remove accidental whitespace in CONTRIBUTING.md [`a262131`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/a26213142854ffe3d931fab35f0ee4e6ae101875)
+- [Deps] unpin `aria-query` [`e517937`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/e51793729e5e366e30d2f3bf0f253f2bdb9e6523)
+
+## [v6.10.0](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.9.0...v6.10.0) - 2024-09-03
+
+### Fixed
+
+- [New] `label-has-associated-control`: add additional error message [`#1005`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/1005)
+- [Fix] `label-has-associated-control`: ignore undetermined label text [`#966`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/966)
+
+### Commits
+
+- [Tests] switch from jest to tape [`a284cbf`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/a284cbf4eb21292c4cff87f02be0bfb82764757f)
+- [New] add eslint 9 support [`deac4fd`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/deac4fd06eff4c0f5da27611c2a44a009b7e7fda)
+- [New] add `attributes` setting [`a1ee7f8`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/a1ee7f8810efafe416eb5d7f6eb0505b52873495)
+- [New] allow polymorphic linting to be restricted [`6cd1a70`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6cd1a7011446e3925f2b49c51ff26246a21491d1)
+- [Tests] remove duplicate tests [`74d5dec`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/74d5decb6f2e42c05ce40a45630041fd695a2e7f)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types` [`6eca235`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6eca2359f5457af72dbfba265b73297c9232cb3e)
+- [readme] remove deprecated travis ci badge; add github actions badge [`0be7ea9`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0be7ea95f560c6afc6817d381054d914ebd0b2ca)
+- [Tests] use `npm audit` instead of `aud` [`05a5e49`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/05a5e4992900e0d5d61e29e13046c90797b68a7c)
+- [Deps] update `axobject-query` [`912e98c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/912e98c425ef9fcc2d7d22b45b4f7e3b445112a5)
+- [Deps] unpin `axobject-query` [`75147aa`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/75147aa68888fc150a4efea5b99809969bdc32b2)
+- [Deps] update `axe-core` [`27ff7cb`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/27ff7cbf562bf2685fd5a6062e58eb4727cb85c6)
+- [readme] fix jsxA11y import name [`ce846e0`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/ce846e00414c41676a6a8601022059878bcc0b89)
+- [readme] fix typo in shareable config section in readme [`cca288b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/cca288b73a39fa0932a57c02a7a88de68fc971fc)
+
+## [v6.9.0](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.8.0...v6.9.0) - 2024-06-19
+
+### Fixed
+
+- [Fix] `img-redundant-alt`: fixed multibyte character support [`#969`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/969)
+- [meta] fix changelog links [`#960`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/960)
+
+### Commits
+
+- [New] add support for Flat Config [`6b5f096`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6b5f096f10b47326d68e2893152a48a79c8555b4)
+- Revert "[Fix] `isNonInteractiveElement`: Upgrade aria-query to 5.3.0 and axobject-query to 3.2.1" [`75d5dd7`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/75d5dd722bd67186d97afa7b151fd6fee5885c70)
+- [Robustness] use `safe-regex-test` [`4c7e781`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/4c7e7815c12a797587bb8e3cdced7f3003848964)
+- [actions] update actions/checkout [`51a1ca7`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/51a1ca7b4d83d4fbd1ea62888f7f2dc21ece6788)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `@babel/register`, `eslint-doc-generator`, `object.entries` [`1271ac1`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/1271ac1d6e5dcf9a2bc2c086faaf062335629171)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/register`, `aud`, `eslint-plugin-import`, `npmignore`, `object.assign` [`540cb7a`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/540cb7aefead582f237071d55a40f098d0885478)
+- [Deps] update `@babel/runtime`, `array-includes`, `es-iterator-helpers`, `hasown`, `object.fromentries`, `safe-regex-test` [`5d14408`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/5d1440825a8838ae10dc94cc3a4a7e1e967644b4)
+- [Deps] pin `aria-query` and `axobject-query`, add `ls-engines` test to CI [`32fd82c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/32fd82c628d7f3e4ec8c06a1994f4eca1be2be4f)
+- [Dev Deps] update `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `eslint-doc-generator` [`d1b4114`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/d1b41142248a7cca45bb5f0b96ff23ee87fb9411)
+- [Fix] ensure `summary` remains non-interactive [`6a048da`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6a048dacf2b98eaa204e2a5a70dc7e3d48d9463a)
+- [Deps] remove `@babel/runtime` [`0a98ad8`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0a98ad83ffa7f4b66458cc1c39db2ef32bb2c480)
+- [New] `no-noninteractive-element-to-interactive-role`: allow `menuitemradio` and `menuitemcheckbox` on &lt;li&gt; [`c0733f9`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/c0733f94031fe3eec6b4d54176afe47929bb0a84)
+- [Deps] update `@babel/runtime`, `safe-regex-test` [`0d5321a`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0d5321a5457c5f0da0ca216053cc5b4f571b53ae)
+- [actions] pin codecov to v3.1.5 [`961817f`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/961817f61fa56cd7815c6940c27ef08469b1516b)
+- [Deps] unpin `axe-core` [`b3559cf`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/b3559cf89be6b5352cd77ffa025831b3d793d565)
+- [Deps] move `object.entries` to dev deps [`1be7b70`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/1be7b709eececd83f1d5f67a60b2c97cfe9a561d)
+- [Deps] update `@babel/runtime` [`2a48abb`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/2a48abb5effa911e7d1a8575e1c9768c947a33f1)
+- [Deps] update `@babel/runtime` [`1adec35`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/1adec3517fc2c9797212ca4d38858deed917e7be)
+
+## [v6.8.0](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.7.1...v6.8.0) - 2023-11-01
+
+### Merged
+
+- Allow `title` attribute or `aria-label` attribute instead of accessible child in the "anchor-has-content" rule [`#727`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/727)
+
+### Fixed
+
+- [Docs] `aria-activedescendant-has-tabindex`: align with changes from #708 [`#924`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/924)
+- [Fix] `control-has-associated-label`: don't accept whitespace as an accessible label [`#918`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/918)
+
+### Commits
+
+- [Tests] migrate helper parsers function from `eslint-plugin-react` [`ce4d57f`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/ce4d57f853ce7f71bd31edaa524eeb3ff1d27cf1)
+- [Refactor] use `es-iterator-helpers` [`52de824`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/52de82403752bb2ccbcac3379925650a0112d4af)
+- [New] `mouse-events-have-key-events`: add `hoverInHandlers`/`hoverOutHandlers` config [`db64898`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/db64898fa591f17827053ad3c2ddeafdf7297dd6)
+- [New] add `polymorphicPropName` setting for polymorphic components [`fffb05b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/fffb05b38c8eee926ee758e9ceb9eae4e697fbdd)
+- [Fix] `isNonInteractiveElement`: Upgrade aria-query to 5.3.0 and axobject-query to 3.2.1 [`64bfea6`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/64bfea6352a704470a760fa6ea25cfc5a50414db)
+- [Refactor] use `hasown` instead of `has` [`9a8edde`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/9a8edde7f2e80b7d104dd576f91526c6c4cbebb9)
+- [actions] update used actions [`10c061a`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/10c061a70cac067641e3a084d0fb464960544505)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `@babel/register`, `aud`, `eslint-doc-generator`, `eslint-plugin-import`, `minimist` [`6d5022d`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6d5022d4894fa88d3c15c8b858114e8b2a8a440f)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/register`, `eslint-doc-generator`, `eslint-plugin-import` [`4dc7f1e`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/4dc7f1e5c611aeea2f81dc50d4ec0b206566181a)
+- [New] `anchor-has-content`: Allow title attribute OR aria-label attribute [`e6bfd5c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/e6bfd5cb7c060fcaf54ede85a1be74ebe2f60d1e)
+- [patch] `mouse-events-have-key-events`: rport the attribute, not the node [`eadd70c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/eadd70cb1d0478c24538ee7604cf5493a96c0715)
+- [Deps] update `@babel/runtime`, `array-includes`, `array.prototype.flatmap`, `object.entries`, `object.fromentries` [`46ffbc3`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/46ffbc38512be4ed3db2f0fcd7d21af830574f63)
+- [Deps] update `@babel/runtime`, `axobject-query`, `jsx-ast-utils`, `semver` [`5999555`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/5999555714f594c0fccfeeab2063c2658d9e4392)
+- [Fix] pin `aria-query` and `axe-core` to fix failing tests on main [`8d8f016`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/8d8f0169dbaaa28143cf936cba3046c6e53fa134)
+- [patch] move `semver` from Deps to Dev Deps [`4da13e7`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/4da13e79743ad2e1073fc2bb682197e1ba6dbea3)
+- [Deps] update `ast-types-flow` [`b755318`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/b755318e675e73a33b1bb7ee809abc88c1927408)
+- [Dev Deps] update `eslint-plugin-import` [`f1c976b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/f1c976b6af2d4f5237b481348868a5216e169296)
+- [Deps] unpin `language-tags` [`3d1d26d`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/3d1d26d89d492947cbf69f439deec9e7cfaf9867)
+- [Docs] `no-static-element-interactions`: tabIndex is written tabindex [`1271153`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/1271153653ada3f8d95b8e39f0164d5b255abea0)
+- [Deps] Upgrade ast-types-flow to mitigate Docker user namespacing problems [`f0d2ddb`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/f0d2ddb65f21278ad29be43fb167a1092287b4b1)
+- [Dev Deps] pin `jackspeak` since 2.1.2+ depends on npm aliases, which kill the install process in npm &lt; 6 [`0c278f4`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0c278f4805ec18d8ee4d3e8dfa2f603a28d7e113)
+
+## [v6.7.1](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.7.0...v6.7.1) - 2023-01-11
+
+### Commits
+
+- [Fix] `no-aria-hidden-on-focusable` rule's missing export [`b01219e`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/b01219edc2eb289c7a068b4fa195f2ac04e915fa)
+
+## [v6.7.0](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.6.1...v6.7.0) - 2023-01-09
+
+### Merged
+
+- New rule: prefer-tag-over-role [`#833`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/833)
+
+### Fixed
+
+- [Tests] `aria-role`: add now-passing test [`#756`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/756)
+- [Docs] `control-has-associated-label`: fix metadata [`#892`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/892)
+- [New] add `no-aria-hidden-on-focusable` rule [`#881`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/881)
+
+### Commits
+
+- [Docs] automate docs with `eslint-doc-generator` [`6d7a857`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6d7a857eccceb58dabfa244f6a196ad1697c01a4)
+- [Refactor] use fromEntries, flatMap, etc; better use iteration methods [`3d77c84`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/3d77c845a98b6fc8cf10c810996278c02e308f35)
+- [New] add `anchor-ambiguous-text` rule [`7f6463e`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/7f6463e5cffd1faa5cf22e3b0d33465e22bd10e1)
+- [New] add `getAccessibleChildText` util [`630116b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/630116b334e22db853a95cd64e20b7df9f2b6dc8)
+- [New] Add `isFocusable` utils method [`e199d17`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/e199d17db0b6bf1d917dab13a9690876ef6f77e3)
+- [Docs] update `eslint-doc-generator` to v1.0.0 [`6b9855b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6b9855b9c3633308004960594327a10bc2551ad2)
+- [Fix] `no-noninteractive-element-interactions`: Ignore contenteditable elements in no-noninteractive-element-interactions [`9aa878b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/9aa878bc39769f6c7b31c72bd1140c1370d202f1)
+- [New] `anchor-ambiguous-text`: ignore punctuation [`bbae2c4`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/bbae2c46ab4ae94122be6c898f2ef313c6154c27)
+- [New] `anchor-ambiguous-text`, `getAccessibleChildText`: Implements check for `alt` tags on `&lt;img /&gt;` elements [`bb84abc`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/bb84abc793435a25398160242c5f2870b83b72ca)
+- [meta] use `npmignore` to autogenerate an npmignore file [`6ad2312`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/6ad23124582741385df50e98d5ed0d070f86eafe)
+- [meta] add `auto-changelog` [`283817b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/283817b82252ef4a6395c22585d8681f97305ca0)
+- [Docs] missing descriptions in some rules [`79b975a`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/79b975ab7185cc4fbf6a3adea45c78fac2162d77)
+- [Deps] update `aria-query`, `axobject-query` [`7b3cda3`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/7b3cda3854451affe20b2e4f2dd57cf317dd7d1b)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `aud`, `object.assign` [`0852947`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0852947cfd57a34353a97c67f6de28dbcc8be0e3)
+- [meta] move `.eslintignore` to `ignorePatterns` [`65be35b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/65be35b0f6c6cf8b79e9a748cb657a64b78c6535)
+- [Dev Deps] update `@babel/cli`, `@babel/core`, `aud`, `eslint-doc-generator` [`60c2df5`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/60c2df5388a3f841a7780eafe1a0fbb44056743d)
+- [Deps] update `@babel/runtime`, `array-includes`, `axe-core` [`4abc751`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/4abc751d87a8491219a9a3d2dacd80ea8adcb79b)
+- [Deps] update `@babel/runtime`, `axe-core` [`89f766c`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/89f766cd40fd32ada2020856b251ad6e34a6f365)
+- [meta] run the build in prepack, not prepublish [`e411ce3`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/e411ce35cfa58181d375544ba5204c35db83678c)
+- [Dev Deps] update `@babel/core`, `minimist` [`cccdb62`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/cccdb625d6237538fb4443349870293e8df818eb)
+- [Dev Deps] update `markdown-magic` [`3382059`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/3382059feb5367c79e049943772e3a6e27e77609)
+- [Fix] expose `prefer-tag-over-role` [`38d52f8`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/38d52f856a18d444e6db7d16d373e0d18c5b287d)
+- [Docs] `label-has-for`: reran generate-list-of-rules [`9a2af01`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/9a2af0172cefad7fdce869401b2df42536812152)
+- [Deps] pin `language-tags` to `v1.0.5` [`f84bb74`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/f84bb746857cfbc075f8e7104b3a16dddb66be7c)
+- [Dev Deps] update `@babel/core` [`cf3f8d0`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/cf3f8d0a6bde6dc5ad39a96a6ed1912c1ad80e89)
+- [Deps] update `axe-core` [`0a73cf4`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0a73cf4ad0adca0bef0a383a10a14597acef5713)
+- [Deps] update `@babel/runtime` [`053f04d`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/053f04da8b60d259e4c92f214ffba07a14f3ec61)
+- [Deps] update `@babel/runtime` [`bccf0ae`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/bccf0aeab8dd337c5f134f892a6d3588fbc29bdf)
+- [Deps] update `jsx-ast-utils` [`c9687cc`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/c9687cc2a1b7f5f72c8181a9fd6a47f49c373240)
+- [readme] Preventing code repetition in user's eslint config file [`8b889bf`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/8b889bff2731c9db6988c88c0d76bdbff17bd3c5)
+- [Docs] `prefer-tag-over-role`: rename docs file [`0bdf95b`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/commit/0bdf95b41cce32c8b7916367e7c8c663411d881c)
+
+<!-- auto-changelog-above -->
+
+6.6.1 / 2022-07-21
+==================
+- 38405ad [Fix] `no-interactive-tabindex`: allow role assignments using a ternary with literals on both sides
+- 7524e0c [Fix] `no-static-element-interactions`: allow role assignments using a ternary with literals on both sides (#865)
+- 1c06306 [readme] properly describe rule settings in builtin configs
+- 0c19f02 [Docs] `no-noninteractive-tabindex`, `no-static-element-interactions`: document `allowExpressionValues` (#870)
+- 2362832 [readme] added link to redirect eslint to relevant docs (#862)
+- 2c6926c [Deps] unpin `axe-core`
+- b78f19d [Deps] pin `axe-core` to v4.4.1, due to a breaking change in a patch
+- 768910e [Deps] update `@babel/runtime`
+- f0e04ce [Deps] update `@babel/runtime`, `jsx-ast-utils`
+- 93b2a9d [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `@babel/register`
+- a962211 [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/plugin-transform-flow-strip-types`, `@babel/register`
+- 0d2bc43 [Tests] `no-noninteractive-element-interactions`: add passing test cases (#876)
+- ffefbad [Tests] `no-noninteractive-element-interactions`: add passing tests for form with onSubmit (#871)
+- e7d405d [Tests] `no-static-element-interactions`: add passing test cases
+
+6.6.0 / 2022-06-23
+==================
+- 566011b [New] `aria-role`: add `allowedInvalidRoles` option (#828)
+- 64dcac6 [New] Introduce a plugin-wide setting for custom components. (#844)
+- ce2c328 [Fix] `no-redundant-roles`, `role-supports-aria-props`: Remove implicit role from dl element (#848)
+- fb20bc4 [Refactor] `role-supports-aria-props`: clean up the logic a bit
+- 1826628 [Refactor] reduce egregious use of array spread, in favor of `[].concat` idiom
+- 0f1615a [Docs] `no-static-element-interactions`: Update error message (#843)
+- 9980d1d [Docs] Add infrastructure for auto-generating markdown table and list (#837)
+- f878d3b [Docs] Update project readme (#831)
+- aea7671 [Deps] update `@babel/runtime`, `array-includes`, `axe-core`, `jsx-ast-utils`
+- d74173a [Deps] update `jsx-ast-utils`
+- f6ba03c [Deps] update `@babel/runtime`, `jsx-ast-utils`
+- 547dab4 [Deps] update `@babel/runtime`, `axe-core`, `minimatch`
+- baaf791 [Deps] update `@babel/runtime`, `minimatch`, `semver`
+- c015fef [Deps] update `@babel/runtime`, `axe-core`, `damerau-levenshtein`
+- 832cbd6 [meta] add `export default` instead of `module.exports` (#861)
+- ee933a2 [meta] Add CONTRIBUTING.md to solicit contributions (#846)
+- fa3c869 [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `aud`, `eslint-plugin-eslint-plugin`, `eslint-plugin-flowtype`, `eslint-plugin-import`
+- fb3d51e [Dev Deps] update `@babel/core`, `@babel/register`, `eslint-plugin-import`, `minimist`
+- 8c1df4d [Dev Deps] pin `@technote-space/doctoc` because v2.5 is a breaking change
+- fb071ab [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `eslint-plugin-eslint-plugin`
+- 5e966e5 [Dev Deps] update `@babel/cli`
+- f597f5b [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`
+- 287854a [Tests] Fix `npm run flow` (#856)
+- 112261c [Tests] skip fragment tests in eslint < 6
+- ea877c4 [Tests] `img-redundant-alt-test`: add passing tests (#832)
+- 685426d test: align usage of jest expect across tests (#827)
+- c460a8b [Tests] move invalid test case to valid; changed in axe-core v4.4
+
+6.5.1 / 2021-11-10
+==================
+- 8f7d0b0 [Fix] properly build `module.exports` (#824)
+- 2fd2087 [Dev Deps] update `eslint-plugin-import`
+
+6.5.0 / 2021-11-09
+==================
+- 0f5f582 [New] support ESLint 8.x (#810)
+- 1dbc416 [Deps] update `@babel/runtime`, `axe-core`
+- 4043d31 [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-transform-flow-strip-types`, `eslint-config-airbnb-base`
+- d143cba [Docs] HTTP => HTTPS (#823)
+- 309b040 [Docs] `anchor-has-content`: add missing close / for jsx succeed example (#821)
+- ba1e312 [eslint] simplify eslint command
+- 0269025 [meta] change all `master` references in URLs to `HEAD`
+- f1414cf [Dev Deps] add `eslint-plugin-eslint-plugin` (#818)
+- f44fc05 [meta] update URLs
+- df34872 [Refactor] switch to `export default` syntax for exporting rules (#819)
+- ff26b82 [meta] fix prepublish scripts
+- d4a57d8 [Deps] update `@babel/runtime`, `array-includes`, `axe-core`, `jsx-ast-utils`
+- bd1dec6 [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/eslint-parser`, `eslint-plugin-import`, `estraverse`, `safe-publish-latest`
+- 434c4cf [Tests] do not test eslint 7 on node 11
+- aed7a20 [Tests] use `@babel/eslint-parser` instead of `babel-eslint` (#811)
+- 0021489 [actions] use codecov action
+- 1251088 [meta] delete FUNDING.yml in favor of `.github` repo
+- ecf7a27 [Docs] `scope`: replace duplicate `scope` word (#799)
+- 952af25 [Fix] `no-access-key`: Fix wording and grammar (#800)
+- 6cf7ac0 [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/plugin-transform-flow-strip-types`, `aud`, `eslint-plugin-flowtype`, `eslint-plugin-import`
+- 79a35d4 [Deps] update `@babel/runtime`, `axe-core`, `damerau-levenshtein`
+- 2a9ab71 [Tests] delete `src/util/getComputedRole-test.js` test in node 6
+- 0c1c587 [Tests] `autocomplete-valid`: move some failed tests to passing
+- 8830902 [Tests] fix eslint < 7 not understanding `import type`
+- d57887c [Tests] ensure all tests run
+- 55e5c11 Support img role for canvas (#796)
+- 36102cd [meta] use `prepublishOnly` script for npm 7+
+- 2501a7f Remove the link-button focus css from the anchor-is-valid doc (#662)
+- d927625 Update recommended config to allow fieldset to have the radiogroup role (#746)
+- 5aa8db9 [Docs] Clarify the title of the strictness table in the main doc (#786)
+- df3c7ad [Docs] Document the similarity between html-has-lang and lang (#778)
+- 426d4c2 Fix Flow warnings (#785)
+- ecec8e4 Fully deprecate accessible-emoji rule (#782)
+- 8a0e43c [Tests] remove .travis.yml
+- f88bf6b [Dev Deps] update `flow-bin` to support aarch64 (#784)
+- 369f9db [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/plugin-transform-flow-strip-types`, `aud`, `eslint-plugin-flowtype`, `jscodeshift`
+- ce0785f [Deps] update `@babel/runtime`, `array-includes`, `axe-core`, `emoji-regex`
+- 2c2a2ad [actions] update to use `node/install` action
+- c275964 [Docs] `anchor-is-valid`: general cleanup (#728)
+- 3df059e [Docs] `no-redundant-roles`: Adds missing closing square bracket (#775)
+- 42ce5b7 [Docs] `anchor-is-valid`: Add Next.js case (#769)
+- 2e5df91 [Tests] fix tests breaking on npm 7
+- 066ccff [Docs] `no-noninteractive-tabindex`: Add example for tabIndex on seemingly non-interactive element (#760)
+- 6b19aa5 [Tests] migrate tests to Github Actions (#764)
+- 7e158e3 [meta] run `aud` in `posttest`
+- 71f390f [Tests] stop using coveralls
+- e54b466 [meta] add Automatic Rebase and Require Allow Edits workflows
+- 7d5511d [New] `label-has-associated-control`: Add glob support (#749)
+- 854da0c Ran npm update; latest packages (#763)
+- 8637aa7 (source/pr/734, fork/pr/26) [patch] `strict` config: Turn off `label-has-for` (#734)
+- d85ce54 [doc] Add link to MDN Aria documentation (#762)
+- 20b48a4 [patch] `no-onchange`: Remove rule from recommended/strict configs, and deprecate (#757)
+
+6.4.1 / 2020-10-26
+==================
+- f8a4496 Upgrade jsx-ast-utils to v3.1.0
+
+6.4.0 / 2020-10-26
+==================
+
+- 83e4ff2 [Deps] update `axe-core`, `jsx-ast-utils`
+- eb92b07 [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/plugin-transform-flow-strip-types`, `eslint-plugin-flowtype`, `eslint-plugin-import`, `estraverse`, `expect`, `object.assign`
+- 3d98d7a [Deps] update `@babel/runtime`, `axe-core`
+- f702f62 [readme] add Spanish translation
+- c2ae092 [Docs] `no-static-element-interactions`: Fixed rule name in comments
+- b90e20d Fix screenreader -> screen reader
+- 645900a Fixed rule name in comments
+- 381b9d6 [fix:634] Ignore control elements that are hidden
+- 2c47f0a [Fix] `autocomplete-valid`: workaround for axe not being able to handle `null`
+- 00bd6d8 Add failing test for autocomplete with dynamic type
+- 3c49c9a Add WCAG guidelines to rule documentation
+- 4ecaf35 Add a testcase for tablist to interactive supports focus
+- dac6864 Deprecate the accessible-emoji rule
+- 5191053 Update to axobject-query@2.2.0
+- b315698 Allow negative tabindex in aria-activedescendant-has-tabindex
+- 8e6fcd0 docs: fix travis badge now points to correct location at travis-ci.com
+- 2234df7 Account for additional control elements in label-has-associated-control
+- 5cbb718 Adding test cases for label tests
+- 66c425c Additional test case for no-redundant-roles
+
+6.3.1 / 2020-06-19
+==================
+
+- 765da0f Update to aria-query 4.2.2
+- d528e8c Fix aria-level allowed on elements wit role heading (#704)
+- 29c6859 [meta] remove yarn registry from npmrc, so publishing works
+- f52c206 chore(package): update estraverse to version 5.0.0
+
+6.3.0 / 2020-06-18
+==================
+
+- cce838a Update aria-query to 4.2.0
+- 121e8a4 Add two test cases found while upgrading to ARIA 1.2
+- 8059f51 Fix test failures raised by the upgrade to ARIA 1.2
+- 0d24e3a Update package.json
+- b1f412a Fix test failures in role-has-required-aria-props due to ARIA 1.2 updates
+- 74cec6e Fix test failures in no-noninteractive-element-interactions due to ARIA 1.2 updates
+- 835b89e Fix test failures in role-supports-aria-props-test due to ARIA 1.2 updates
+- 730319b Account for the null semantic generic role in ARIA 1.2
+- 7dfa7c9 Update aria-query from 4.0.1 to 4.0.2
+- 42098b9 [Refactor] `img-redundant-alt`: removing a use of `some`
+- a910d83 [Tests] `label-has-associated-control`: add test for <div><label /><input /></div>
+- b273fe5 [New] Support ESLint 7.x
+- 1a97632 [Deps] update `@babel/runtime`, `array-includes`, `axe-core`, `axobject-query`, `damerau-levenshtein`, `jsx-ast-utils`
+- b36976f [Dev Deps] update `@babel/cli`, `@babel/core`, `@babel/plugin-transform-flow-types`, `babel-eslint`, `babel-jest`, `coveralls`, `eslint-config-airbnb-base`, `eslint-plugin-flowtype`, `eslint-plugin-import`, `estraverse`, `in-publish`, `jest`, `minimist`, `rimraf`, `safe-publish-latest`
+- 89acdc4 fix: removing the use of the some function
+- 410ae43 chore(package): update eslint-plugin-flowtype to version 5.0.0
+- a87f83d fix(package): update emoji-regex to version 9.0.0
+- 71940e6 chore(package): update babel-preset-airbnb to version 5.0.0
+- d471f54 docs: Fix 404 links to WAI-ARIA spec
+- 42a2016 Fixes #669: use the `language-tags` package to check the `lang` rule
+- 7bcea20 [Tests] update axe-core
+- f13dc38 [Deps] Pin axe-core version
+- 33670bb fix: require missing 'autocomplete-valid' rule
+- aca4c37 chore(mouse-event): revert unrelated formatting changes
+- df1e275 fix(mouse-event): remove check from custom elements
+- 1a16a1c chore(package): update jscodeshift to version 0.7.0
+- 7a55cdd chore(package): update flow-bin to version 0.113.0
+- 8e0d22b Update aria-query and axobject-query to the latest versions
+- dd49060 Added test cases for an empty or undefined value of aria-label and aria-labelledby in alt-text
+- 1a7b94f Updated dependencies including eslint-config-airbnb-base
+- 3aea217 chore: replace ignoreNonDOM with inputComponents
+- 1848d00 feat(autocomplete-valid): add to recommended & strict config
+- 8703840 refactor: use to axe-cre 3.4 SerialVirtualNode format
+- 3519c7b chore: Remove axe VirtualNode abstraction
+- 9ac55c4 autocomplete-valid: Add inline comment
+- 44c6098 Update axe-core to 3.3.0
+- 9916990 new autocomplete-valid rule
+- 82f598e [Docs] examples: add language in code block for syntax highlight
+- 2529ad3 fixing casing issue on aria-props
+- 00926f2 Update README.md
+- ce5d121 Update README.md
+- 031574e chore(package): update flow-bin to version 0.103.0
+- e00e1db [meta] add FUNDING.yml
+- e1e5fae Fix readme file
+
+6.2.3 / 2019-06-30
+=================
+- [617] Add @babel/runtime to the dependencies
+
+6.2.2 / 2019-06-29
+=================
+- Update jsx-ast-utils to v2.2.1
+- Add @babel/cli to the dev dependencies
+- Update ESLint to v6
+- Update jsx-ast-utils to 2.2.0
+- Update flow-bin to version 0.102.0
+- [589] Allow expression statements for attribute values in no-noninteractive-tabindexlow-bin-0.101.0
+- [583] Allow expression values in attributes by configurationrror
+- [596] Adding a test case for no-static-element-interactionseper/flow-bin-0.101.0) Merge branch 'master' into greenkeeper/flow-bin-0.101.0
+- Only run branch test coverage on the master branch
+- chore(package): update flow-bin to version 0.100.0
+- Allow select as a valid child of label.
+- Allow Node 4 / ESLint 3 failure to unblock ESLint upgrade in PR #568
+- chore(package): update flow-bin to version 0.99.0
+- Remove rootDir from Jest path configs
+- (fix) Template literals with undefined evaluate to the string undefined.
+- adds more tests to “anchor-is-valid”
+- Fixes “anchor-is-valid” false positive for hrefs starting with the word “javascript”
+- chore(package): update eslint-plugin-flowtype to version 3.5.0
+- Modified no-static-element-interactions to pass on non-literal roles.
+- Added isNonLiteralProperty util method
+- [#399] Account for spread in parser options
+- [552] control-has-associated-label should allow generic links
+- [issue 392] ul role='list' test case
+- chore(package): update eslint to version 5.15.2
+- chore(package): update flow-bin to version 0.95.0
+- chore(package): update expect to version 24.3.1
+- Fix typo: defintions > definitions
+- docs: add proper title to links to axe website for media-has-caption
+- docs: removes deprecated rule label-has-for
+- docs: fix typo and couple grammatical errors in Readme
+- Ignore null/undefined values in role-supports-aria-props rule
+- Ignore undefined values in aria-proptypes rule
+- Ignore null values in aria-proptypes rule
+- set target for node 4
+
+6.2.1 / 2019-02-03
+=================
+- 9980e45 [fix] Prevent Error when JSXSpreadAttribute is passed to isSemanticRoleElement
+
+6.2.0 / 2019-01-25
+=================
+- 5650674 [new rule] control-has-associated-label checks interactives for a label
+- f234698 [docs] add How to manage IDs
+- 9924d03 [docs] document jsx-a11y/label-has-associated-control assert option
+- 77b9870 [docs] Add newlines below headings
+- 8244e43 [docs] Add syntax highlighting to example
+- 26f41c8 [docs] Change explanation for role="presentation" escape hatch
+- 33a1f94 [fix] - Purely decorative emojis do not need descriptions.
+- 29d20f7 [fix] (package): update emoji-regex to version 7.0.2
+- 0b63f73 [chore] (package): update flow-bin to version 0.88.0
+- baa1344 [fix] Disable jsx-a11y/label-has-for in recommended
+- 2c5fb06 [chore] (package): update jscodeshift to version 0.6.0
+- 87debc0 [fix] corrected no-noninteractive-element-to-interactive-role.md file
+- d56265b [chore] (package): update flow-bin to version 0.87.0
+- 477966f [fix] Update test for implicit role of `img`
+- f484ce3 [fix] No implicit role for `<img>` with `alt=""`
+- 6c33bcb [fix] Add select to the list of default control elements in label-has-associated-control
+- 011f8d9 [fix] Dialog and Alert roles can host keyboard listeners
+- 0f6a8af [fix] More easier `plugin:jsx-a11y/{recommended,strict}` configs
+- 3844248 [fix] Mark the replacement for label-has-for
+- 93265cb [fix] normalizedValues to values
+- 651366c [fix] Make aria-role case sensitive
+- 56d3b9a [fix] [484] Fix role-has-required-aria-props for semantic elements like input[checkbox]
+- 46e9abd [fix] Handle the type={truthy} case in jsx
+
+6.1.2 / 2018-10-05
+=================
+- [fix] Add link-type styling recommendation to anchor-is-valid #486
+- [fix] `label-has-for`: `textarea`s are inputs too #470
+
+6.1.1 / 2018-07-03
+==================
+- [fix] aria-proptypes support for idlist, #454
+- [fix] Image with expanded props throws 'The prop must be a JSXAttribute collected by the AST parser.', #459
+- [fix] label-has-for: broken in v6.1.0, #455
+
+6.1.0 / 2018-06-26
+==================
+- [new] Support for eslint v5, #451
+- [new] aria-query updated to latest version
+- [new] eslint-config-airbnb-base updated to the latest version
+- [deprecate] The rule label-has-for is deprecated and replaced with label-has-associated-control
+- [fix] heading-has-content updated to work with custom components, #431
+- [fix] aria-errormessage prop is now a valid ARIA property, #424
+
+6.0.2 / 2017-06-28
+==================
+- [fix] Prefix directories in `.npmignore` with `/` so it only matches the top-level directory
+
+
+6.0.1 / 2017-06-28
+==================
+- [temporary] Remove `src` and `flow` from package to resolve flow issues for consuming packages.
+
+
+6.0.0 / 2017-06-05
+=================
+- [new] Add rule `anchor-is-valid`. See documentation for configuration options. Thanks @AlmeroSteyn.
+- [breaking] `href-no-hash` replaced with `anchor-is-valid` in the recommended and strict configs. Use the `invalidHref` aspect (active by default) in `anchor-is-valid` to continue to apply the behavior provided by `href-no-hash`.
+- [breaking] Removed support for ESLint peer dependency at version ^2.10.2.
+- [update] The rule `label-has-for` now allows inputs nested in label tags. Previously it was strict about requiring a `for` attribute. Thanks @ignatiusreza and @mjaltamirano.
+- [update] New configuration for `interactive-supports-focus`. Recommended and strict configs for now contain a trimmed-down whitelist of roles that will be checked.
+- [fix] Incompatibility between node version 4 and 5. Thanks @evilebottnawi.
+- [fix] Missing README entry for `media-has-caption`. Thanks @ismail-syed.
+- [fix] README updates explaining recommended and strict configs. Thanks @Donaldini.
+- [fix] Updated to aria-query@0.7.0, which includes new ARIA 1.1 properties. Previously, the `aria-props` rule incorrectly threw errors for these new properties.
+
+5.1.1 / 2017-07-03
+==================
+ - [fix] revert v6 breaking changes unintentionally added in v5.1 (#283)
+
+5.1.0 / 2017-06-26
+==================
+ - [new] Support eslint v4. (#267)
+ - [new] `label-has-for`: add "required" option to allow customization (#240)
+ - [new] add `anchor-is-valid` (#224)
+ - [new] `interactive-supports-focus`: Split interactive supports focus into tabbable and focusable cases (#236)
+ - [new] `anchor-is-valid`: add `aspects` option (#251)
+ - [Deps] Bump aria-query to 0.7.0
+
+5.0.3 / 2017-05-16
+==================
+- [fix] Remove `flow` directory from `.npmignore` to accommodate explicit imports from `v5.0.2`.
+
+
+5.0.2 / 2017-05-16
+==================
+- [fix] Explicitly import flow types to resolve flow failures in consuming projects.
+
+
+5.0.1 / 2017-05-07
+==================
+- [fix] Polyfill Array.includes for node < 6 support.
+
+
+5.0.0 / 2017-05-05
+==================
+- [breaking] Refactor `img-has-alt` rule into `alt-text` rule
+- [breaking] Rule `onclick-has-role` is removed. Replaced with `no-static-element-interactions` and `no-noninteractive-element-interactions`.
+- [breaking] Rule `onclick-has-focus` is removed. Replaced with `interactive-supports-focus`.
+- [new] - Add rule `media-has-caption` rule
+- [new] - Add `ignoreNonDOM` option to `no-autofocus`.
+- [new] - Add rule `no-interactive-element-to-noninteractive-role`
+- [new] - Add rule `no-noninteractive-element-to-interactive-role`
+- [new] - Add rule `no-noninteractive-tabindex`
+- [new] - Configs split into "recommended" and "strict".
+- [enhanced] - Configuration options added to `no-static-element-interactions` and `no-noninteractive-element-interactions`. Options allow for fine-tuning of elements and event handlers to check.
+
+
+4.0.0 / 2017-02-04
+==================
+Add new rules:
+- `jsx-a11y/accessible-emoji`
+- `jsx-a11y/aria-activedescendant-has-tabindex`
+- `jsx-a11y/iframe-has-title`
+- `jsx-a11y/no-autofocus`
+- `jsx-a11y/no-distracting-elements` *(breaking: consolidated no-marquee and no-blink into this rule.)*
+- `jsx-a11y/no-redundant-roles`
+- [fix] - redundant-alt to only check full words
+- [docs] - Documentation upgrades across the board.
+- [new] - Add `ignoreNonDom`
+- [dev] - Add script to scaffold new rule creation.
+
+
+3.0.2 / 2016-12-14
+==================
+- [fix] - make `aria-invalid` values true and false pass for rule `aria-proptypes`
+
+3.0.1 / 2016-10-11
+==================
+- [breaking] - Update all rule schemas to accept objects. This allows a future schema expansion to not be a breaking change.
+- [breaking] - All rules with schemas that accepted a string OR array, now only allows an array.
+- [new] - `href-no-hash` accepts new schema property `specialLink` to check for custom `href` properties on elements. (fixes [#76](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/76))
+- [breaking][fix] - `img-has-alt` now prefers `alt=""` over `role="presentation"`. You can set both, but not just `role="presentation"` by itself to ensure a11y across all devices.
+
+Note - see [rule documentation](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules) for updated schemas.
+
+2.2.3 / 2016-10-08
+==================
+- [fix] - Add `switch` aria role.
+- [devDependencies] - Updgrade dev dependencies and fix linting issues.
+
+
+2.2.2 / 2016-09-12
+==================
+- [fix] `x-has-content` rules now pass with children prop set.
+
+
+2.2.1 / 2016-08-31
+==================
+- [fix] Update `tablist` role to include missing property `aria-multiselectable`.
+
+
+2.2.0 / 2016-08-26
+==================
+- [new] Add `click-events-have-key-events` rule.
+- [new] Add `no-static-element-interactions` rule.
+- [devDependencies] Upgrade `eslint`, `eslint-config-airbnb`, `mocha` to latest.
+- [lint] Fix all new linting errors with upgrade
+- [nit] Use `error` syntax over `2` syntax in recommended config.
+
+
+2.1.0 / 2016-08-10
+==================
+- [fix] Require `aria-checked` for roles that are subclasses of `checkbox`
+- [new] Add `anchor-has-content` rule.
+- [refactor] Use new eslint rule syntax
+- [new] Add support for custom words in `img-redundant-alt` (mainly for i18n).
+
+
+2.0.1 / 2016-07-13
+==================
+- [fix] JSXElement support in expression handlers for prop types.
+- [fix] `heading-has-content`: dangerouslySetInnerHTML will pass.
+
+
+2.0.0 / 2016-07-12
+==================
+- [breaking] Scope `no-onchange` rule to select menu elements only.
+
+
+1.5.5 / 2016-07-05
+==================
+- [fix] Add `eslint` v3 as a `peerDependency`.
+
+
+1.5.4 / 2016-07-05
+==================
+- [fix] Add `eslint` as a `peerDependency`.
+
+
+1.5.3 / 2016-06-16
+==================
+- [fix] Fix crash when ``<ELEMENT role />`` for `role-supports-aria-props`.
+
+
+1.5.2 / 2016-06-16
+==================
+- [fix] Fix `img-redundant-alt` rule to use `getLiteralPropValue` from `jsx-ast-utils`.
+
+
+1.5.1 / 2016-06-16
+==================
+- [fix] Fix checking for undefined in `heading-has-content` for children content.
+
+
+1.5.0 / 2016-06-16
+==================
+- [new] Add [heading-has-content](docs/rules/heading-has-content.md) rule.
+- [new] Add [html-has-lang](docs/rules/html-has-lang.md) rule.
+- [new] Add [lang](docs/rules/lang.md) rule.
+- [new] Add [no-marquee](docs/rules/no-marquee.md) rule.
+- [new] Add [scope](docs/rules/scope.md) rule.
+
+
+1.4.2 / 2016-06-10
+==================
+- [new] Integrate with latest `jsx-ast-utils` to use `propName` function. More support for namespaced names on attributes and elements.
+
+
+1.4.1 / 2016-06-10
+==================
+- [fix] Handle spread props in `aria-unsupported-elements` and `role-supports-aria-props` when reporting.
+
+
+1.4.0 / 2016-06-10
+==================
+- [dependency] Integrate [jsx-ast-utils](https://github.com/jsx-eslint/jsx-ast-utils)
+- [fix] Better error reporting for aria-unsupported-elements indicating which prop to remove.
+
+
+1.3.0 / 2016-06-05
+==================
+- [new] Spelling suggestions for incorrect `aria-*` props
+- [fix] Ensure `role` value is a string before converting to lowercase in `img-has-alt` rule.
+
+
+1.2.3 / 2016-06-02
+==================
+- [fix] Handle dynamic `tabIndex` expression values, but still retain validation logic for literal `tabIndex` values.
+
+
+1.2.2 / 2016-05-20
+==================
+- [fix] Fix checks involving the tabIndex attribute that do not account for integer literals
+
+
+1.2.1 / 2016-05-19
+==================
+- [fix] Avoid testing interactivity of wrapper components with same name but different casing
+as DOM elements (such as `Button` vs `button`).
+
+
+1.2.0 / 2016-05-06
+==================
+- [new] Import all roles from DPUB-ARIA.
+
+
+1.1.0 / 2016-05-06
+==================
+- [new] Add expression value handler for `BinaryExpression` type.
+- [new] Add expression value handler for `NewExpression` type.
+- [new] Add expression value handler for `ObjectExpression` type.
+- [fix] Throws error when getting an expression of type without a handler function.
+	- This is for more graceful error handling and better issue reporting.
+
+
+1.0.4 / 2016-04-28
+==================
+- [fix] Add expression value handler for `ConditionalExpression` type.
+
+
+1.0.3 / 2016-04-25
+==================
+- [fix] Fix typo in recommended rules for `onclick-has-focus`.
+
+
+1.0.2 / 2016-04-20
+==================
+- [fix] Add expression value handler for `ThisExpression` type.
+
+
+1.0.1 / 2016-04-19
+==================
+- [fix] Fix build to copy source JSON files to build output.
+
+
+1.0.0 / 2016-04-19
+==================
+- [breaking] Rename `img-uses-alt` to `img-has-alt`
+- [breaking] Rename `onlick-uses-role` to `onclick-has-role`
+- [breaking] Rename `mouse-events-map-to-key-events` to `mouse-events-have-key-events`
+- [breaking] Rename `use-onblur-not-onchange` to `no-onchange`
+- [breaking] Rename `label-uses-for` to `label-has-for`
+- [breaking] Rename `redundant-alt` to `img-redundant-alt`
+- [breaking] Rename `no-hash-href` to `href-no-hash`
+- [breaking] Rename `valid-aria-role` to `aria-role`
+
+- [new] Implement `aria-props` rule
+- [new] Implement `aria-proptypes` rule
+- [new] Implement `aria-unsupported-elements` rule
+- [new] Implement `onclick-has-focus` rule
+- [new] Implement `role-has-required-aria-props` rule
+- [new] Implement `role-supports-aria-props` rule
+- [new] Implement `tabindex-no-positive` rule
+
+
+0.6.2 / 2016-04-08
+==================
+- [fix] Fix rule details for img-uses-alt: allow alt="" or role="presentation".
+
+
+0.6.1 / 2016-04-07
+==================
+- [fix] Do not infer interactivity of components that are not low-level DOM elements.
+
+
+0.6.0 / 2016-04-06
+==================
+- [breaking] Allow alt="" when role="presentation" on img-uses-alt rule.
+- [new] More descriptive error messaging for img-uses-alt rule.
+
+
+0.5.2 / 2016-04-05
+==================
+- [fix] Handle token lists for valid-aria-role.
+
+
+0.5.1 / 2016-04-05
+==================
+- [fix] Handle null valued props for valid-aria-role.
+
+
+0.5.0 / 2016-04-02
+==================
+- [new] Implement valid-aria-role rule. Based on [AX_ARIA_01](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_01)
+
+
+0.4.3 / 2016-03-29
+==================
+- [fix] Handle LogicalExpression attribute types when extracting values. LogicalExpressions are of form `<Component prop={foo || "foobar"} />`
+
+
+0.4.2 / 2016-03-24
+==================
+- [fix] Allow component names of form `Object.Property` i.e. `UX.Layout`
+
+
+0.3.0 / 2016-03-02
+==================
+- [new] Implement [no-hash-href](docs/rules/no-hash-href.md) rule.
+- [fix] Fixed TemplateLiteral AST value building to get more exact values from template strings.
+
+
+0.2.0 / 2016-03-01
+==================
+- [new] Implement [redunant-alt](docs/rules/redundant-alt.md) rule.
+
+
+0.1.2 / 2016-03-01
+==================
+- Initial pre-release.
Index: frontend/node_modules/eslint-plugin-jsx-a11y/LICENSE.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/LICENSE.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/LICENSE.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright (c) 2016 Ethan Cohen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/eslint-plugin-jsx-a11y/README.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,423 @@
+<p align="center">
+  <a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/actions">
+    <img src="https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/jsx-eslint/eslint-plugin-jsx-a11y"
+         alt="CI status" />
+  </a>
+  <a href="https://npmjs.org/package/eslint-plugin-jsx-a11y">
+    <img src="https://img.shields.io/npm/v/eslint-plugin-jsx-a11y.svg"
+         alt="npm version">
+  </a>
+  <a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/LICENSE.md">
+    <img src="https://img.shields.io/npm/l/eslint-plugin-jsx-a11y.svg"
+         alt="license">
+  </a>
+  <a href='https://coveralls.io/github/jsx-eslint/eslint-plugin-jsx-a11y?branch=master'>
+    <img src='https://coveralls.io/repos/github/jsx-eslint/eslint-plugin-jsx-a11y/badge.svg?branch=master' alt='Coverage Status' />
+  </a>
+  <a href='https://npmjs.org/package/eslint-plugin-jsx-a11y'>
+    <img src='https://img.shields.io/npm/dt/eslint-plugin-jsx-a11y.svg'
+    alt='Total npm downloads' />
+  </a>
+</p>
+
+<a href='https://tidelift.com/subscription/pkg/npm-eslint-plugin-jsx-a11y?utm_source=npm-eslint-plugin-jsx-a11y&utm_medium=referral&utm_campaign=readme'>Get professional support for eslint-plugin-jsx-a11y on Tidelift</a>
+
+# eslint-plugin-jsx-a11y
+
+Static AST checker for accessibility rules on JSX elements.
+
+#### _Read this in [other languages](https://github.com/ari-os310/eslint-plugin-jsx-a11y/blob/HEAD/translations/Translations.md)._
+
+[Mexican Spanish🇲🇽](https://github.com/ari-os310/eslint-plugin-jsx-a11y/blob/HEAD/translations/README.mx.md)
+
+## Why?
+
+This plugin does a static evaluation of the JSX to spot accessibility issues in React apps. Because it only catches errors in static code, use it in combination with [@axe-core/react](https://github.com/dequelabs/axe-core-npm/tree/develop/packages/react) to test the accessibility of the rendered DOM. Consider these tools just as one step of a larger a11y testing process and always test your apps with assistive technology.
+
+## Installation
+
+**If you are installing this plugin via `eslint-config-airbnb`, please follow [these instructions](https://github.com/airbnb/javascript/tree/HEAD/packages/eslint-config-airbnb#eslint-config-airbnb-1).**
+
+You'll first need to install [ESLint](https://eslint.org/docs/latest/user-guide/getting-started):
+
+```sh
+# npm
+npm install eslint --save-dev
+
+# yarn
+yarn add eslint --dev
+```
+
+Next, install `eslint-plugin-jsx-a11y`:
+
+```sh
+# npm
+npm install eslint-plugin-jsx-a11y --save-dev
+
+# yarn
+yarn add eslint-plugin-jsx-a11y --dev
+```
+
+**Note:** If you installed ESLint globally (using the `-g` flag in npm, or the `global` prefix in yarn) then you must also install `eslint-plugin-jsx-a11y` globally.
+
+<a id="usage"></a>
+## Usage - Legacy Config (`.eslintrc`)
+
+Add `jsx-a11y` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:
+
+```json
+{
+  "plugins": ["jsx-a11y"]
+}
+```
+
+Then configure the rules you want to use under the rules section.
+
+```json
+{
+  "rules": {
+    "jsx-a11y/rule-name": 2
+  }
+}
+```
+
+You can also enable all the recommended or strict rules at once.
+Add `plugin:jsx-a11y/recommended` or `plugin:jsx-a11y/strict` in `extends`:
+
+```json
+{
+  "extends": ["plugin:jsx-a11y/recommended"]
+}
+```
+
+### Configurations
+
+> As you are extending our configuration, you can omit `"plugins": ["jsx-a11y"]` from your `.eslintrc` configuration file.
+
+```json
+{
+  "settings": {
+    "jsx-a11y": {
+      "polymorphicPropName": "as",
+      "components": {
+        "CityInput": "input",
+        "CustomButton": "button",
+        "MyButton": "button",
+        "RoundButton": "button"
+      },
+      "attributes": {
+        "for": ["htmlFor", "for"]
+      }
+    }
+  }
+}
+```
+
+## Usage - Flat Config (`eslint.config.js`)
+
+The default export of `eslint-plugin-jsx-a11y` is a plugin object.
+
+```js
+const jsxA11y = require('eslint-plugin-jsx-a11y');
+
+module.exports = [
+  …
+  {
+    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
+    plugins: {
+      'jsx-a11y': jsxA11y,
+    },
+    languageOptions: {
+      parserOptions: {
+        ecmaFeatures: {
+          jsx: true,
+        },
+      },
+    },
+    rules: {
+      // ... any rules you want
+      'jsx-a11y/alt-text': 'error',
+    },
+    // ... others are omitted for brevity
+  },
+  …
+];
+```
+
+### Shareable Configs
+
+There are two shareable configs, provided by the plugin.
+
+- `flatConfigs.recommended`
+- `flatConfigs.strict`
+
+#### CJS
+
+```js
+const jsxA11y = require('eslint-plugin-jsx-a11y');
+
+export default [
+  jsxA11y.flatConfigs.recommended,
+  {
+    // Your additional configs and overrides
+  },
+];
+```
+
+#### ESM
+
+```js
+import jsxA11y from 'eslint-plugin-jsx-a11y';
+
+export default [
+  jsxA11y.flatConfigs.recommended,
+  {
+    // Your additional configs and overrides
+  },
+];
+```
+
+**Note**: Our shareable configs do NOT configure `files` or [`languageOptions.globals`](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new#configuration-objects).
+For most of the cases, you probably want to configure some of these properties yourself.
+
+```js
+const jsxA11y = require('eslint-plugin-jsx-a11y');
+const globals = require('globals');
+
+module.exports = [
+  …
+  {
+    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
+    ...jsxA11y.flatConfigs.recommended,
+    languageOptions: {
+      ...jsxA11y.flatConfigs.recommended.languageOptions,
+      globals: {
+        ...globals.serviceworker,
+        ...globals.browser,
+      },
+    },
+  },
+  …
+];
+```
+
+#### Component Mapping
+
+To enable your custom components to be checked as DOM elements, you can set global settings in your configuration file by mapping each custom component name to a DOM element type.
+
+#### Attribute Mapping
+
+To configure the JSX property to use for attribute checking, you can set global settings in your configuration file by mapping each DOM attribute to the JSX property you want to check.
+For example, you may want to allow the `for` attribute in addition to the `htmlFor` attribute for checking label associations.
+
+#### Polymorphic Components
+
+You can optionally use the `polymorphicPropName` setting to define the prop your code uses to create polymorphic components.
+This setting will be used determine the element type in rules that require semantic context.
+
+For example, if you set the `polymorphicPropName` setting to `as` then this element:
+
+`<Box as="h3">Configurations </Box>`
+
+will be evaluated as an `h3`. If no `polymorphicPropName` is set, then the component will be evaluated as `Box`.
+
+To restrict polymorphic linting to specified components, additionally set `polymorphicAllowList` to an array of component names.
+
+⚠️ Polymorphic components can make code harder to maintain; please use this feature with caution.
+
+## Supported Rules
+
+<!-- begin auto-generated rules list -->
+
+💼 Configurations enabled in.\
+🚫 Configurations disabled in.\
+☑️ Set in the `recommended` configuration.\
+🔒 Set in the `strict` configuration.\
+❌ Deprecated.
+
+| Name                                                                                                         | Description                                                                                                                         | 💼    | 🚫    | ❌  |
+| :----------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------- | :---- | :---- | :- |
+| [accessible-emoji](docs/rules/accessible-emoji.md)                                                           | Enforce emojis are wrapped in `<span>` and provide screen reader access.                                                            |       |       | ❌  |
+| [alt-text](docs/rules/alt-text.md)                                                                           | Enforce all elements that require alternative text have meaningful information to relay back to end user.                           | ☑️ 🔒 |       |    |
+| [anchor-ambiguous-text](docs/rules/anchor-ambiguous-text.md)                                                 | Enforce `<a>` text to not exactly match "click here", "here", "link", or "a link".                                                  |       | ☑️    |    |
+| [anchor-has-content](docs/rules/anchor-has-content.md)                                                       | Enforce all anchors to contain accessible content.                                                                                  | ☑️ 🔒 |       |    |
+| [anchor-is-valid](docs/rules/anchor-is-valid.md)                                                             | Enforce all anchors are valid, navigable elements.                                                                                  | ☑️ 🔒 |       |    |
+| [aria-activedescendant-has-tabindex](docs/rules/aria-activedescendant-has-tabindex.md)                       | Enforce elements with aria-activedescendant are tabbable.                                                                           | ☑️ 🔒 |       |    |
+| [aria-props](docs/rules/aria-props.md)                                                                       | Enforce all `aria-*` props are valid.                                                                                               | ☑️ 🔒 |       |    |
+| [aria-proptypes](docs/rules/aria-proptypes.md)                                                               | Enforce ARIA state and property values are valid.                                                                                   | ☑️ 🔒 |       |    |
+| [aria-role](docs/rules/aria-role.md)                                                                         | Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role.                                                     | ☑️ 🔒 |       |    |
+| [aria-unsupported-elements](docs/rules/aria-unsupported-elements.md)                                         | Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes.                          | ☑️ 🔒 |       |    |
+| [autocomplete-valid](docs/rules/autocomplete-valid.md)                                                       | Enforce that autocomplete attributes are used correctly.                                                                            | ☑️ 🔒 |       |    |
+| [click-events-have-key-events](docs/rules/click-events-have-key-events.md)                                   | Enforce a clickable non-interactive element has at least one keyboard event listener.                                               | ☑️ 🔒 |       |    |
+| [control-has-associated-label](docs/rules/control-has-associated-label.md)                                   | Enforce that a control (an interactive element) has a text label.                                                                   |       | ☑️ 🔒 |    |
+| [heading-has-content](docs/rules/heading-has-content.md)                                                     | Enforce heading (`h1`, `h2`, etc) elements contain accessible content.                                                              | ☑️ 🔒 |       |    |
+| [html-has-lang](docs/rules/html-has-lang.md)                                                                 | Enforce `<html>` element has `lang` prop.                                                                                           | ☑️ 🔒 |       |    |
+| [iframe-has-title](docs/rules/iframe-has-title.md)                                                           | Enforce iframe elements have a title attribute.                                                                                     | ☑️ 🔒 |       |    |
+| [img-redundant-alt](docs/rules/img-redundant-alt.md)                                                         | Enforce `<img>` alt prop does not contain the word "image", "picture", or "photo".                                                  | ☑️ 🔒 |       |    |
+| [interactive-supports-focus](docs/rules/interactive-supports-focus.md)                                       | Enforce that elements with interactive handlers like `onClick` must be focusable.                                                   | ☑️ 🔒 |       |    |
+| [label-has-associated-control](docs/rules/label-has-associated-control.md)                                   | Enforce that a `label` tag has a text label and an associated control.                                                              | ☑️ 🔒 |       |    |
+| [label-has-for](docs/rules/label-has-for.md)                                                                 | Enforce that `<label>` elements have the `htmlFor` prop.                                                                            |       | ☑️ 🔒 | ❌  |
+| [lang](docs/rules/lang.md)                                                                                   | Enforce lang attribute has a valid value.                                                                                           |       |       |    |
+| [media-has-caption](docs/rules/media-has-caption.md)                                                         | Enforces that `<audio>` and `<video>` elements must have a `<track>` for captions.                                                  | ☑️ 🔒 |       |    |
+| [mouse-events-have-key-events](docs/rules/mouse-events-have-key-events.md)                                   | Enforce that `onMouseOver`/`onMouseOut` are accompanied by `onFocus`/`onBlur` for keyboard-only users.                              | ☑️ 🔒 |       |    |
+| [no-access-key](docs/rules/no-access-key.md)                                                                 | Enforce that the `accessKey` prop is not used on any element to avoid complications with keyboard commands used by a screen reader. | ☑️ 🔒 |       |    |
+| [no-aria-hidden-on-focusable](docs/rules/no-aria-hidden-on-focusable.md)                                     | Disallow `aria-hidden="true"` from being set on focusable elements.                                                                 |       |       |    |
+| [no-autofocus](docs/rules/no-autofocus.md)                                                                   | Enforce autoFocus prop is not used.                                                                                                 | ☑️ 🔒 |       |    |
+| [no-distracting-elements](docs/rules/no-distracting-elements.md)                                             | Enforce distracting elements are not used.                                                                                          | ☑️ 🔒 |       |    |
+| [no-interactive-element-to-noninteractive-role](docs/rules/no-interactive-element-to-noninteractive-role.md) | Interactive elements should not be assigned non-interactive roles.                                                                  | ☑️ 🔒 |       |    |
+| [no-noninteractive-element-interactions](docs/rules/no-noninteractive-element-interactions.md)               | Non-interactive elements should not be assigned mouse or keyboard event listeners.                                                  | ☑️ 🔒 |       |    |
+| [no-noninteractive-element-to-interactive-role](docs/rules/no-noninteractive-element-to-interactive-role.md) | Non-interactive elements should not be assigned interactive roles.                                                                  | ☑️ 🔒 |       |    |
+| [no-noninteractive-tabindex](docs/rules/no-noninteractive-tabindex.md)                                       | `tabIndex` should only be declared on interactive elements.                                                                         | ☑️ 🔒 |       |    |
+| [no-onchange](docs/rules/no-onchange.md)                                                                     | Enforce usage of `onBlur` over `onChange` on select menus for accessibility.                                                        |       |       | ❌  |
+| [no-redundant-roles](docs/rules/no-redundant-roles.md)                                                       | Enforce explicit role property is not the same as implicit/default role property on element.                                        | ☑️ 🔒 |       |    |
+| [no-static-element-interactions](docs/rules/no-static-element-interactions.md)                               | Enforce that non-interactive, visible elements (such as `<div>`) that have click handlers use the role attribute.                   | ☑️ 🔒 |       |    |
+| [prefer-tag-over-role](docs/rules/prefer-tag-over-role.md)                                                   | Enforces using semantic DOM elements over the ARIA `role` property.                                                                 |       |       |    |
+| [role-has-required-aria-props](docs/rules/role-has-required-aria-props.md)                                   | Enforce that elements with ARIA roles must have all required attributes for that role.                                              | ☑️ 🔒 |       |    |
+| [role-supports-aria-props](docs/rules/role-supports-aria-props.md)                                           | Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`.            | ☑️ 🔒 |       |    |
+| [scope](docs/rules/scope.md)                                                                                 | Enforce `scope` prop is only used on `<th>` elements.                                                                               | ☑️ 🔒 |       |    |
+| [tabindex-no-positive](docs/rules/tabindex-no-positive.md)                                                   | Enforce `tabIndex` value is not greater than zero.                                                                                  | ☑️ 🔒 |       |    |
+
+<!-- end auto-generated rules list -->
+
+The following rules have extra options when in _recommended_ mode:
+
+### no-interactive-element-to-noninteractive-role
+
+```js
+'jsx-a11y/no-interactive-element-to-noninteractive-role': [
+  'error',
+  {
+    tr: ['none', 'presentation'],
+  },
+]
+```
+
+### no-noninteractive-element-interactions
+
+```js
+'jsx-a11y/no-noninteractive-element-interactions': [
+  'error',
+  {
+    handlers: [
+      'onClick',
+      'onMouseDown',
+      'onMouseUp',
+      'onKeyPress',
+      'onKeyDown',
+      'onKeyUp',
+    ],
+  },
+]
+```
+
+### no-noninteractive-element-to-interactive-role
+
+```js
+'jsx-a11y/no-noninteractive-element-to-interactive-role': [
+  'error',
+  {
+    ul: [
+      'listbox',
+      'menu',
+      'menubar',
+      'radiogroup',
+      'tablist',
+      'tree',
+      'treegrid',
+    ],
+    ol: [
+      'listbox',
+      'menu',
+      'menubar',
+      'radiogroup',
+      'tablist',
+      'tree',
+      'treegrid',
+    ],
+    li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
+    table: ['grid'],
+    td: ['gridcell'],
+  },
+]
+```
+
+### no-noninteractive-tabindex
+
+```js
+'jsx-a11y/no-noninteractive-tabindex': [
+  'error',
+  {
+    tags: [],
+    roles: ['tabpanel'],
+  },
+]
+```
+
+### no-static-element-interactions
+
+```js
+'jsx-a11y/no-noninteractive-element-interactions': [
+  'error',
+  {
+    handlers: [
+      'onClick',
+      'onMouseDown',
+      'onMouseUp',
+      'onKeyPress',
+      'onKeyDown',
+      'onKeyUp',
+    ],
+  },
+]
+```
+
+## Creating a new rule
+
+If you are developing new rules for this project, you can use the `create-rule`
+script to scaffold the new files.
+
+```sh
+./scripts/create-rule.js my-new-rule
+```
+
+## Some background on WAI-ARIA, the AX Tree and Browsers
+
+### Accessibility API
+
+An operating system will provide an accessibility API that maps application state and content onto input/output controllers such as a screen reader, braille device, keyboard, etc.
+
+These APIs were developed as computer interfaces shifted from buffers (which are text-based and inherently quite accessible) to graphical user interfaces (GUIs). The first attempts to make GUIs accessible involved raster image parsing to recognize characters, words, etc. This information was stored in a parallel buffer and made accessible to assistive technology (AT) devices.
+
+As GUIs became more complex, the raster parsing approach became untenable. Accessibility APIs were developed to replace them. Check out [NSAccessibility (AXAPI)](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSAccessibility_Protocol/index.html) for an example. See [Core Accessibility API Mappings 1.1](https://www.w3.org/TR/core-aam-1.1/) for more details.
+
+### Browsers
+
+Browsers support an Accessibility API on a per operating system basis. For instance, Firefox implements the MSAA accessibility API on Windows, but does not implement the AXAPI on OSX.
+
+### The Accessibility (AX) Tree & DOM
+
+From the [W3 Core Accessibility API Mappings 1.1](https://www.w3.org/TR/core-aam-1.1/#intro_treetypes)
+
+> The accessibility tree and the DOM tree are parallel structures. Roughly speaking the accessibility tree is a subset of the DOM tree. It includes the user interface objects of the user agent and the objects of the document. Accessible objects are created in the accessibility tree for every DOM element that should be exposed to assistive technology, either because it may fire an accessibility event or because it has a property, relationship or feature which needs to be exposed. Generally, if something can be trimmed out it will be, for reasons of performance and simplicity. For example, a `<span>` with just a style change and no semantics may not get its own accessible object, but the style change will be exposed by other means.
+
+Browser vendors are beginning to expose the AX Tree through inspection tools. Chrome has an experiment available to enable their inspection tool.
+
+You can also see a text-based version of the AX Tree in Chrome in the stable release version.
+
+#### Viewing the AX Tree in Chrome
+
+1. Navigate to `chrome://accessibility/` in Chrome.
+1. Toggle the `accessibility off` link for any tab that you want to inspect.
+1. A link labeled `show accessibility tree` will appear; click this link.
+1. Balk at the wall of text that gets displayed, but then regain your conviction.
+1. Use the browser's find command to locate strings and values in the wall of text.
+
+### Pulling it all together
+
+A browser constructs an AX Tree as a subset of the DOM. ARIA heavily informs the properties of this AX Tree. This AX Tree is exposed to the system level Accessibility API which mediates assistive technology agents.
+
+We model ARIA in the [aria-query](https://github.com/a11yance/aria-query) project. We model AXObjects (that comprise the AX Tree) in the [axobject-query](https://github.com/A11yance/axobject-query) project. The goal of the WAI-ARIA specification is to be a complete declarative interface to the AXObject model. The [in-draft 1.2 version](https://github.com/w3c/aria/issues?q=is%3Aissue+is%3Aopen+label%3A%22ARIA+1.2%22) is moving towards this goal. But until then, we must consider the semantics constructs afforded by ARIA as well as those afforded by the AXObject model (AXAPI) in order to determine how HTML can be used to express user interface affordances to assistive technology users.
+
+## License
+
+eslint-plugin-jsx-a11y is licensed under the [MIT License](LICENSE.md).
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/IdentifierMock.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/IdentifierMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/IdentifierMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+/**
+ * @flow
+ */
+
+export type IdentifierMockType = {|
+  type: 'Identifier',
+  name: string,
+|};
+
+export default function IdentifierMock(ident: string): IdentifierMockType {
+  return {
+    type: 'Identifier',
+    name: ident,
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXAttributeMock.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXAttributeMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXAttributeMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,39 @@
+/**
+ * @flow
+ */
+
+import toAST from 'to-ast'; // eslint-disable-line import/no-extraneous-dependencies
+import JSXExpressionContainerMock from './JSXExpressionContainerMock';
+
+export type JSXAttributeMockType = {
+  type: 'JSXAttribute',
+  name: {
+    type: 'JSXIdentifier',
+    name: string,
+  },
+  value: mixed,
+};
+
+export default function JSXAttributeMock(prop: string, value: mixed, isExpressionContainer?: boolean = false): JSXAttributeMockType {
+  let astValue;
+  if (value && value.type !== undefined) {
+    astValue = value;
+  } else {
+    astValue = toAST(value);
+  }
+  let attributeValue = astValue;
+  if (isExpressionContainer || astValue.type !== 'Literal') {
+    attributeValue = JSXExpressionContainerMock(astValue);
+  } else if (attributeValue.type === 'Literal' && !('raw' in (attributeValue: any))) {
+    (attributeValue: any).raw = JSON.stringify((attributeValue: any).value);
+  }
+
+  return {
+    type: 'JSXAttribute',
+    name: {
+      type: 'JSXIdentifier',
+      name: prop,
+    },
+    value: attributeValue,
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXElementMock.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXElementMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXElementMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+/**
+ * @flow
+ */
+
+import type { JSXAttributeMockType } from './JSXAttributeMock';
+
+export type JSXElementMockType = {
+  type: 'JSXElement',
+  openingElement: {
+    type: 'JSXOpeningElement',
+    name: {
+      type: 'JSXIdentifier',
+      name: string,
+    },
+    attributes: Array<JSXAttributeMockType>,
+  },
+  children: Array<Node>,
+};
+
+export default function JSXElementMock(
+  tagName: string,
+  attributes: Array<JSXAttributeMockType> = [],
+  children?: Array<Node> = [],
+): JSXElementMockType {
+  return {
+    type: 'JSXElement',
+    openingElement: {
+      type: 'JSXOpeningElement',
+      name: {
+        type: 'JSXIdentifier',
+        name: tagName,
+      },
+      attributes,
+    },
+    children,
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXExpressionContainerMock.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXExpressionContainerMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXExpressionContainerMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+/**
+ * @flow
+ */
+
+export type JSXExpressionContainerMockType = {
+  type: 'JSXExpressionContainer',
+  expression: mixed,
+}
+
+export default function JSXExpressionContainerMock(exp: mixed): JSXExpressionContainerMockType {
+  return {
+    type: 'JSXExpressionContainer',
+    expression: exp,
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXSpreadAttributeMock.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXSpreadAttributeMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXSpreadAttributeMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+/**
+ * @flow
+ */
+
+import IdentifierMock from './IdentifierMock';
+import type { IdentifierMockType } from './IdentifierMock';
+
+export type JSXSpreadAttributeMockType = {
+  type: 'JSXSpreadAttribute',
+  argument: IdentifierMockType,
+};
+
+export default function JSXSpreadAttributeMock(identifier: string): JSXSpreadAttributeMockType {
+  return {
+    type: 'JSXSpreadAttribute',
+    argument: IdentifierMock(identifier),
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXTextMock.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXTextMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/JSXTextMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+/**
+ * @flow
+ */
+
+export type JSXTextMockType = {|
+  type: 'JSXText',
+  value: string,
+  raw: string,
+|};
+
+export default function JSXTextMock(value: string): JSXTextMockType {
+  return {
+    type: 'JSXText',
+    value,
+    raw: value,
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/LiteralMock.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/LiteralMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/LiteralMock.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+/**
+ * @flow
+ */
+
+export type LiteralMockType = {|
+  type: 'Literal',
+  value: string,
+  raw: string,
+|};
+
+export default function LiteralMock(value: string): LiteralMockType {
+  return {
+    type: 'Literal',
+    value,
+    raw: value,
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/genInteractives.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/genInteractives.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__mocks__/genInteractives.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,218 @@
+/**
+ * @flow
+ */
+
+import { dom, roles } from 'aria-query';
+import includes from 'array-includes';
+import fromEntries from 'object.fromentries';
+
+import JSXAttributeMock from './JSXAttributeMock';
+import JSXElementMock from './JSXElementMock';
+
+import type { JSXAttributeMockType } from './JSXAttributeMock';
+import type { JSXElementMockType } from './JSXElementMock';
+
+const domElements = dom.keys();
+const roleNames = roles.keys();
+
+const interactiveElementsMap = {
+  a: [{ prop: 'href', value: '#' }],
+  area: [{ prop: 'href', value: '#' }],
+  audio: [],
+  button: [],
+  canvas: [],
+  datalist: [],
+  embed: [],
+  input: [],
+  'input[type="button"]': [{ prop: 'type', value: 'button' }],
+  'input[type="checkbox"]': [{ prop: 'type', value: 'checkbox' }],
+  'input[type="color"]': [{ prop: 'type', value: 'color' }],
+  'input[type="date"]': [{ prop: 'type', value: 'date' }],
+  'input[type="datetime"]': [{ prop: 'type', value: 'datetime' }],
+  'input[type="email"]': [{ prop: 'type', value: 'email' }],
+  'input[type="file"]': [{ prop: 'type', value: 'file' }],
+  'input[type="image"]': [{ prop: 'type', value: 'image' }],
+  'input[type="month"]': [{ prop: 'type', value: 'month' }],
+  'input[type="number"]': [{ prop: 'type', value: 'number' }],
+  'input[type="password"]': [{ prop: 'type', value: 'password' }],
+  'input[type="radio"]': [{ prop: 'type', value: 'radio' }],
+  'input[type="range"]': [{ prop: 'type', value: 'range' }],
+  'input[type="reset"]': [{ prop: 'type', value: 'reset' }],
+  'input[type="search"]': [{ prop: 'type', value: 'search' }],
+  'input[type="submit"]': [{ prop: 'type', value: 'submit' }],
+  'input[type="tel"]': [{ prop: 'type', value: 'tel' }],
+  'input[type="text"]': [{ prop: 'type', value: 'text' }],
+  'input[type="time"]': [{ prop: 'type', value: 'time' }],
+  'input[type="url"]': [{ prop: 'type', value: 'url' }],
+  'input[type="week"]': [{ prop: 'type', value: 'week' }],
+  menuitem: [],
+  option: [],
+  select: [],
+  summary: [],
+  // Whereas ARIA makes a distinction between cell and gridcell, the AXObject
+  // treats them both as CellRole and since gridcell is interactive, we consider
+  // cell interactive as well.
+  td: [],
+  th: [],
+  tr: [],
+  textarea: [],
+  video: [],
+};
+
+const nonInteractiveElementsMap: {[string]: Array<{[string]: string}>} = {
+  abbr: [],
+  address: [],
+  article: [],
+  aside: [],
+  blockquote: [],
+  br: [],
+  caption: [],
+  code: [],
+  dd: [],
+  del: [],
+  details: [],
+  dfn: [],
+  dialog: [],
+  dir: [],
+  dl: [],
+  dt: [],
+  em: [],
+  fieldset: [],
+  figcaption: [],
+  figure: [],
+  footer: [],
+  form: [],
+  h1: [],
+  h2: [],
+  h3: [],
+  h4: [],
+  h5: [],
+  h6: [],
+  hr: [],
+  html: [],
+  iframe: [],
+  img: [],
+  ins: [],
+  label: [],
+  legend: [],
+  li: [],
+  main: [],
+  mark: [],
+  marquee: [],
+  menu: [],
+  meter: [],
+  nav: [],
+  ol: [],
+  optgroup: [],
+  output: [],
+  p: [],
+  pre: [],
+  progress: [],
+  ruby: [],
+  'section[aria-label]': [{ prop: 'aria-label' }],
+  'section[aria-labelledby]': [{ prop: 'aria-labelledby' }],
+  strong: [],
+  sub: [],
+  sup: [],
+  table: [],
+  tbody: [],
+  tfoot: [],
+  thead: [],
+  time: [],
+  ul: [],
+};
+
+const indeterminantInteractiveElementsMap: { [key: string]: Array<any> } = fromEntries(domElements.map((name) => [name, []]));
+
+Object.keys(interactiveElementsMap)
+  .concat(Object.keys(nonInteractiveElementsMap))
+  .forEach((name) => delete indeterminantInteractiveElementsMap[name]);
+
+const abstractRoles = roleNames.filter((role) => roles.get(role).abstract);
+
+const nonAbstractRoles = roleNames.filter((role) => !roles.get(role).abstract);
+
+const interactiveRoles = []
+  .concat(
+    roleNames,
+    // 'toolbar' does not descend from widget, but it does support
+    // aria-activedescendant, thus in practice we treat it as a widget.
+    'toolbar',
+  )
+  .filter((role) => (
+    !roles.get(role).abstract
+    && roles.get(role).superClass.some((klasses) => includes(klasses, 'widget'))
+  ));
+
+const nonInteractiveRoles = roleNames
+  .filter((role) => (
+    !roles.get(role).abstract
+    && !roles.get(role).superClass.some((klasses) => includes(klasses, 'widget'))
+
+    // 'toolbar' does not descend from widget, but it does support
+    // aria-activedescendant, thus in practice we treat it as a widget.
+    && !includes(['toolbar'], role)
+  ));
+
+export function genElementSymbol(openingElement: Object): string {
+  return (
+    openingElement.name.name + (openingElement.attributes.length > 0
+      ? `${openingElement.attributes.map((attr) => `[${attr.name.name}="${attr.value.value}"]`).join('')}`
+      : ''
+    )
+  );
+}
+
+export function genInteractiveElements(): Array<JSXElementMockType> {
+  return Object.keys(interactiveElementsMap).map((elementSymbol: string): JSXElementMockType => {
+    const bracketIndex = elementSymbol.indexOf('[');
+    let name = elementSymbol;
+    if (bracketIndex > -1) {
+      name = elementSymbol.slice(0, bracketIndex);
+    }
+    const attributes = interactiveElementsMap[elementSymbol].map(({ prop, value }) => JSXAttributeMock(prop, value));
+    return JSXElementMock(name, attributes);
+  });
+}
+
+export function genInteractiveRoleElements(): Array<JSXElementMockType> {
+  return interactiveRoles.concat('button article', 'fakerole button article').map((value): JSXElementMockType => JSXElementMock(
+    'div',
+    [JSXAttributeMock('role', value)],
+  ));
+}
+
+export function genNonInteractiveElements(): Array<JSXElementMockType> {
+  return Object.keys(nonInteractiveElementsMap).map((elementSymbol): JSXElementMockType => {
+    const bracketIndex = elementSymbol.indexOf('[');
+    let name = elementSymbol;
+    if (bracketIndex > -1) {
+      name = elementSymbol.slice(0, bracketIndex);
+    }
+    const attributes = nonInteractiveElementsMap[elementSymbol].map(({ prop, value }) => JSXAttributeMock(prop, value));
+    return JSXElementMock(name, attributes);
+  });
+}
+
+export function genNonInteractiveRoleElements(): Array<JSXElementMockType> {
+  return [
+    ...nonInteractiveRoles,
+    'article button',
+    'fakerole article button',
+  ].map((value) => JSXElementMock('div', [JSXAttributeMock('role', value)]));
+}
+
+export function genAbstractRoleElements(): Array<JSXElementMockType> {
+  return abstractRoles.map((value) => JSXElementMock('div', [JSXAttributeMock('role', value)]));
+}
+
+export function genNonAbstractRoleElements(): Array<JSXElementMockType> {
+  return nonAbstractRoles.map((value) => JSXElementMock('div', [JSXAttributeMock('role', value)]));
+}
+
+export function genIndeterminantInteractiveElements(): Array<JSXElementMockType> {
+  return Object.keys(indeterminantInteractiveElementsMap).map((name) => {
+    const attributes = indeterminantInteractiveElementsMap[name].map(({ prop, value }): JSXAttributeMockType => JSXAttributeMock(prop, value));
+    return JSXElementMock(name, attributes);
+  });
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/axeMapping.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/axeMapping.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/axeMapping.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,6 @@
+/* eslint-disable import/prefer-default-export, no-underscore-dangle */
+import * as axe from 'axe-core';
+
+export function axeFailMessage(checkId, data) {
+  return axe.utils.getCheckMessage(checkId, 'fail', data);
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/helpers/getESLintCoreRule.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/helpers/getESLintCoreRule.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/helpers/getESLintCoreRule.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+import { version } from 'eslint/package.json';
+import semver from 'semver';
+
+const isESLintV8 = semver.major(version) >= 8;
+
+// eslint-disable-next-line global-require, import/no-dynamic-require, import/no-unresolved
+const getESLintCoreRule = (ruleId) => (isESLintV8 ? require('eslint/use-at-your-own-risk').builtinRules.get(ruleId) : require(`eslint/lib/rules/${ruleId}`));
+
+export default getESLintCoreRule;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/helpers/parsers.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/helpers/parsers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/helpers/parsers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,186 @@
+import path from 'path';
+import semver from 'semver';
+import entries from 'object.entries';
+import { version } from 'eslint/package.json';
+import flatMap from 'array.prototype.flatmap';
+
+let tsParserVersion;
+try {
+  // eslint-disable-next-line import/no-unresolved, global-require
+  tsParserVersion = require('@typescript-eslint/parser/package.json').version;
+} catch (e) { /**/ }
+
+const disableNewTS = semver.satisfies(tsParserVersion, '>= 4.1') // this rule is not useful on v4.1+ of the TS parser
+  ? (x) => ({ ...x, features: [].concat(x.features, 'no-ts-new') })
+  : (x) => x;
+
+function minEcmaVersion(features, parserOptions) {
+  const minEcmaVersionForFeatures = {
+    'class fields': 2022,
+    'optional chaining': 2020,
+    'nullish coalescing': 2020,
+  };
+  const result = Math.max(
+    ...[].concat(
+      (parserOptions && parserOptions.ecmaVersion) || [],
+      flatMap(entries(minEcmaVersionForFeatures), (entry) => {
+        const f = entry[0];
+        const y = entry[1];
+        return features.has(f) ? y : [];
+      }),
+    ).map((y) => (y > 5 && y < 2015 ? y + 2009 : y)), // normalize editions to years
+  );
+  return Number.isFinite(result) ? result : undefined;
+}
+
+const NODE_MODULES = '../../node_modules';
+
+const parsers = {
+  BABEL_ESLINT: path.join(__dirname, NODE_MODULES, 'babel-eslint'),
+  '@BABEL_ESLINT': path.join(__dirname, NODE_MODULES, '@babel/eslint-parser'),
+  TYPESCRIPT_ESLINT: path.join(__dirname, NODE_MODULES, 'typescript-eslint-parser'),
+  '@TYPESCRIPT_ESLINT': path.join(__dirname, NODE_MODULES, '@typescript-eslint/parser'),
+  disableNewTS,
+  babelParserOptions: function parserOptions(test, features) {
+    return {
+      ...test.parserOptions,
+      requireConfigFile: false,
+      babelOptions: {
+        presets: [
+          '@babel/preset-react',
+        ],
+        plugins: [
+          '@babel/plugin-syntax-do-expressions',
+          '@babel/plugin-syntax-function-bind',
+          ['@babel/plugin-syntax-decorators', { legacy: true }],
+        ],
+        parserOpts: {
+          allowSuperOutsideMethod: false,
+          allowReturnOutsideFunction: false,
+        },
+      },
+      ecmaFeatures: {
+
+        ...test.parserOptions && test.parserOptions.ecmaFeatures,
+        jsx: true,
+        modules: true,
+        legacyDecorators: features.has('decorators'),
+      },
+    };
+  },
+  all: function all(tests) {
+    const t = flatMap(tests, (test) => {
+      /* eslint no-param-reassign: 0 */
+      if (typeof test === 'string') {
+        test = { code: test };
+      }
+      if ('parser' in test) {
+        delete test.features;
+        return test;
+      }
+      const features = new Set([].concat(test.features || []));
+      delete test.features;
+
+      const es = minEcmaVersion(features, test.parserOptions);
+
+      function addComment(testObject, parser) {
+        const extras = [].concat(
+          `features: [${Array.from(features).join(',')}]`,
+          `parser: ${parser}`,
+          testObject.parserOptions ? `parserOptions: ${JSON.stringify(testObject.parserOptions)}` : [],
+          testObject.options ? `options: ${JSON.stringify(testObject.options)}` : [],
+          testObject.settings ? `settings: ${JSON.stringify(testObject.settings)}` : [],
+        );
+
+        const extraComment = `\n// ${extras.join(', ')}`;
+
+        // Augment expected fix code output with extraComment
+        const nextCode = { code: testObject.code + extraComment };
+        const nextOutput = testObject.output && { output: testObject.output + extraComment };
+
+        // Augment expected suggestion outputs with extraComment
+        // `errors` may be a number (expected number of errors) or an array of
+        // error objects.
+        const nextErrors = testObject.errors
+          && typeof testObject.errors !== 'number'
+          && {
+            errors: testObject.errors.map(
+              (errorObject) => {
+                const nextSuggestions = errorObject.suggestions && {
+                  suggestions: errorObject.suggestions.map((suggestion) => ({ ...suggestion, output: suggestion.output + extraComment })),
+                };
+
+                return { ...errorObject, ...nextSuggestions };
+              },
+            ),
+          };
+
+        return {
+
+          ...testObject,
+          ...nextCode,
+          ...nextOutput,
+          ...nextErrors,
+        };
+      }
+
+      const skipBase = (features.has('class fields') && semver.satisfies(version, '< 8'))
+        || (es >= 2020 && semver.satisfies(version, '< 6'))
+        || features.has('no-default')
+        || features.has('bind operator')
+        || features.has('do expressions')
+        || features.has('decorators')
+        || features.has('flow')
+        || features.has('ts')
+        || features.has('types')
+        || (features.has('fragment') && semver.satisfies(version, '< 5'));
+
+      const skipBabel = features.has('no-babel');
+      const skipOldBabel = skipBabel
+        || features.has('no-babel-old')
+        || features.has('optional chaining')
+        || semver.satisfies(version, '>= 8');
+      const skipNewBabel = skipBabel
+        || features.has('no-babel-new')
+        || !semver.satisfies(version, '^7.5.0') // require('@babel/eslint-parser/package.json').peerDependencies.eslint
+        || features.has('flow')
+        || features.has('types')
+        || features.has('ts');
+      const skipTS = semver.satisfies(version, '<= 5') // TODO: make these pass on eslint 5
+        || features.has('no-ts')
+        || features.has('flow')
+        || features.has('jsx namespace')
+        || features.has('bind operator')
+        || features.has('do expressions');
+      const tsOld = !skipTS && !features.has('no-ts-old');
+      const tsNew = !skipTS && !features.has('no-ts-new');
+
+      return [].concat(
+        skipBase ? [] : addComment(
+          {
+            ...test,
+            ...typeof es === 'number' && {
+              parserOptions: { ...test.parserOptions, ecmaVersion: es },
+            },
+          },
+          'default',
+        ),
+        skipOldBabel ? [] : addComment({
+          ...test,
+          parser: parsers.BABEL_ESLINT,
+          parserOptions: parsers.babelParserOptions(test, features),
+        }, 'babel-eslint'),
+        skipNewBabel ? [] : addComment({
+          ...test,
+          parser: parsers['@BABEL_ESLINT'],
+          parserOptions: parsers.babelParserOptions(test, features),
+        }, '@babel/eslint-parser'),
+        tsOld ? addComment({ ...test, parser: parsers.TYPESCRIPT_ESLINT }, 'typescript-eslint') : [],
+        tsNew ? addComment({ ...test, parser: parsers['@TYPESCRIPT_ESLINT'] }, '@typescript-eslint/parser') : [],
+      );
+    });
+    return t;
+  },
+};
+
+export default parsers;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/parserOptionsMapper.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/parserOptionsMapper.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/parserOptionsMapper.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,53 @@
+import { version as eslintVersion } from 'eslint/package.json';
+import semver from 'semver';
+
+const usingLegacy = semver.major(eslintVersion) < 9;
+
+const defaultParserOptions = {
+  ecmaFeatures: {
+    experimentalObjectRestSpread: true,
+    jsx: true,
+  },
+};
+
+const defaultLegacyParserOptions = {
+  ...defaultParserOptions,
+  ecmaVersion: 2018,
+};
+
+const defaultLanguageOptions = {
+  ecmaVersion: 'latest',
+  parserOptions: {
+    ...defaultParserOptions,
+  },
+};
+
+export default function parserOptionsMapper({
+  code,
+  errors,
+  options = [],
+  languageOptions = {},
+  settings = {},
+}) {
+  return usingLegacy
+    ? {
+      code,
+      errors,
+      options,
+      parserOptions: {
+        ...defaultLegacyParserOptions,
+        ...languageOptions,
+      },
+      settings,
+    }
+    : {
+      code,
+      errors,
+      options,
+      languageOptions: {
+        ...defaultLanguageOptions,
+        ...languageOptions,
+      },
+      settings,
+    };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/ruleOptionsMapperFactory.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/ruleOptionsMapperFactory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/__util__/ruleOptionsMapperFactory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,33 @@
+/**
+ * @flow
+ */
+
+import entries from 'object.entries';
+import flatMap from 'array.prototype.flatmap';
+import fromEntries from 'object.fromentries';
+
+type ESLintTestRunnerTestCase = {
+  code: string,
+  errors: ?Array<{ message: string, type: string }>,
+  options: ?Array<mixed>,
+  parserOptions: ?Array<mixed>,
+  settings?: {[string]: mixed},
+};
+
+type RuleOptionsMapperFactoryType = (
+  params: ESLintTestRunnerTestCase
+) => ESLintTestRunnerTestCase;
+
+export default function ruleOptionsMapperFactory(ruleOptions: Array<mixed> = []): RuleOptionsMapperFactoryType {
+  // eslint-disable-next-line
+  return ({ code, errors, options, parserOptions, settings }: ESLintTestRunnerTestCase): ESLintTestRunnerTestCase => {
+    return {
+      code,
+      errors,
+      // Flatten the array of objects in an array of one object.
+      options: [fromEntries(flatMap((options || []).concat(ruleOptions), (item) => entries(item)))],
+      parserOptions,
+      settings,
+    };
+  };
+}
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/index-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/index-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/index-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,40 @@
+/* eslint global-require: 0 */
+
+import fs from 'fs';
+import path from 'path';
+import test from 'tape';
+
+import plugin from '../src';
+
+const rules = fs.readdirSync(path.resolve(__dirname, '../src/rules/'))
+  .map((f) => path.basename(f, '.js'));
+
+test('all rule files should be exported by the plugin', (t) => {
+  rules.forEach((ruleName) => {
+    t.equal(
+      plugin.rules[ruleName],
+      require(path.join('../src/rules', ruleName)), // eslint-disable-line import/no-dynamic-require
+      `exports ${ruleName}`,
+    );
+  });
+
+  t.end();
+});
+
+test('configurations', (t) => {
+  t.notEqual(plugin.configs.recommended, undefined, 'exports a \'recommended\' configuration');
+
+  t.end();
+});
+
+test('schemas', (t) => {
+  rules.forEach((ruleName) => {
+    const rule = require(path.join('../src/rules', ruleName)); // eslint-disable-line import/no-dynamic-require
+    const schema = rule.meta && rule.meta.schema && rule.meta.schema[0];
+    const { type } = schema;
+
+    t.equal(type, 'object', `${ruleName} exports a schema with type object`);
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/accessible-emoji-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/accessible-emoji-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/accessible-emoji-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,66 @@
+/**
+ * @fileoverview Enforce <marquee> elements are not used.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import rule from '../../../src/rules/accessible-emoji';
+import parsers from '../../__util__/helpers/parsers';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'Emojis should be wrapped in <span>, have role="img", and have an accessible description with aria-label or aria-labelledby.',
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('accessible-emoji', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<span />' },
+    { code: '<span>No emoji here!</span>' },
+    { code: '<span role="img" aria-label="Panda face">🐼</span>' },
+    { code: '<span role="img" aria-label="Snowman">&#9731;</span>' },
+    { code: '<span role="img" aria-labelledby="id1">🐼</span>' },
+    { code: '<span role="img" aria-labelledby="id1">&#9731;</span>' },
+    { code: '<span role="img" aria-labelledby="id1" aria-label="Snowman">&#9731;</span>' },
+    { code: '<span>{props.emoji}</span>' },
+    { code: '<span aria-hidden>{props.emoji}</span>' },
+    { code: '<span aria-hidden="true">🐼</span>' },
+    { code: '<span aria-hidden>🐼</span>' },
+    { code: '<div aria-hidden="true">🐼</div>' },
+    { code: '<input type="hidden">🐼</input>' },
+    {
+      code: '<CustomInput type="hidden">🐼</CustomInput>',
+      settings: { 'jsx-a11y': { components: { CustomInput: 'input' } } },
+    },
+    {
+      code: '<Box as="input" type="hidden">🐼</Box>',
+      settings: { 'jsx-a11y': { polymorphicPropName: 'as' } },
+    },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<span>🐼</span>', errors: [expectedError] },
+    { code: '<span>foo🐼bar</span>', errors: [expectedError] },
+    { code: '<span>foo 🐼 bar</span>', errors: [expectedError] },
+    { code: '<i role="img" aria-label="Panda face">🐼</i>', errors: [expectedError] },
+    { code: '<i role="img" aria-labelledby="id1">🐼</i>', errors: [expectedError] },
+    { code: '<Foo>🐼</Foo>', errors: [expectedError] },
+    { code: '<span aria-hidden="false">🐼</span>', errors: [expectedError] },
+    { code: '<CustomInput type="hidden">🐼</CustomInput>', errors: [expectedError] },
+    {
+      code: '<Box as="span">🐼</Box>',
+      settings: { 'jsx-a11y': { polymorphicPropName: 'as' } },
+      errors: [expectedError],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/alt-text-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/alt-text-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/alt-text-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,291 @@
+/**
+ * @fileoverview Enforce all elements that require alternative text have it.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/alt-text';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const missingPropError = (type) => ({
+  message: `${type} elements must have an alt prop, either with meaningful text, or an empty string for decorative images.`,
+  type: 'JSXOpeningElement',
+});
+
+const altValueError = (type) => ({
+  message: `Invalid alt value for ${type}. \
+Use alt="" for presentational images.`,
+  type: 'JSXOpeningElement',
+});
+
+const ariaLabelValueError = {
+  message: 'The aria-label attribute must have a value. The alt attribute is preferred over aria-label for images.',
+};
+const ariaLabelledbyValueError = {
+  message: 'The aria-labelledby attribute must have a value. The alt attribute is preferred over aria-labelledby for images.',
+};
+
+const preferAltError = () => ({
+  message: 'Prefer alt="" over a presentational role. First rule of aria is to not use aria if it can be achieved via native HTML.',
+  type: 'JSXOpeningElement',
+});
+
+const objectError = {
+  message: 'Embedded <object> elements must have alternative text by providing inner text, aria-label or aria-labelledby props.',
+};
+
+const areaError = {
+  message: 'Each area of an image map must have a text alternative through the `alt`, `aria-label`, or `aria-labelledby` prop.',
+};
+
+const inputImageError = {
+  message: '<input> elements with type="image" must have a text alternative through the `alt`, `aria-label`, or `aria-labelledby` prop.',
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    polymorphicPropName: 'as',
+    components: {
+      Input: 'input',
+    },
+  },
+};
+
+const array = [{
+  img: ['Thumbnail', 'Image'],
+  object: ['Object'],
+  area: ['Area'],
+  'input[type="image"]': ['InputImage'],
+}];
+
+ruleTester.run('alt-text', rule, {
+  valid: parsers.all([].concat(
+    // DEFAULT ELEMENT 'img' TESTS
+    { code: '<img alt="foo" />;' },
+    { code: '<img alt={"foo"} />;' },
+    { code: '<img alt={alt} />;' },
+    { code: '<img ALT="foo" />;' },
+    { code: '<img ALT={`This is the ${alt} text`} />;' },
+    { code: '<img ALt="foo" />;' },
+    { code: '<img alt="foo" salt={undefined} />;' },
+    { code: '<img {...this.props} alt="foo" />' },
+    { code: '<a />' },
+    { code: '<div />' },
+    { code: '<img alt={function(e) {} } />' },
+    { code: '<div alt={function(e) {} } />' },
+    { code: '<img alt={() => void 0} />' },
+    { code: '<IMG />' },
+    { code: '<UX.Layout>test</UX.Layout>' },
+    { code: '<img alt={alt || "Alt text" } />' },
+    { code: '<img alt={photo.caption} />;' },
+    { code: '<img alt={bar()} />;' },
+    { code: '<img alt={foo.bar || ""} />' },
+    { code: '<img alt={bar() || ""} />' },
+    { code: '<img alt={foo.bar() || ""} />' },
+    { code: '<img alt="" />' },
+    { code: '<img alt={`${undefined}`} />' },
+    { code: '<img alt=" " />' },
+    { code: '<img alt="" role="presentation" />' },
+    { code: '<img alt="" role="none" />' },
+    { code: '<img alt="" role={`presentation`} />' },
+    { code: '<img alt="" role={"presentation"} />' },
+    { code: '<img alt="this is lit..." role="presentation" />' },
+    { code: '<img alt={error ? "not working": "working"} />' },
+    { code: '<img alt={undefined ? "working": "not working"} />' },
+    { code: '<img alt={plugin.name + " Logo"} />' },
+    { code: '<img aria-label="foo" />' },
+    { code: '<img aria-labelledby="id1" />' },
+
+    // DEFAULT <object> TESTS
+    { code: '<object aria-label="foo" />' },
+    { code: '<object aria-labelledby="id1" />' },
+    { code: '<object>Foo</object>' },
+    { code: '<object><p>This is descriptive!</p></object>' },
+    { code: '<Object />' },
+    { code: '<object title="An object" />' },
+
+    // DEFAULT <area> TESTS
+    { code: '<area aria-label="foo" />' },
+    { code: '<area aria-labelledby="id1" />' },
+    { code: '<area alt="" />' },
+    { code: '<area alt="This is descriptive!" />' },
+    { code: '<area alt={altText} />' },
+    { code: '<Area />' },
+
+    // DEFAULT <input type="image"> TESTS
+    { code: '<input />' },
+    { code: '<input type="foo" />' },
+    { code: '<input type="image" aria-label="foo" />' },
+    { code: '<input type="image" aria-labelledby="id1" />' },
+    { code: '<input type="image" alt="" />' },
+    { code: '<input type="image" alt="This is descriptive!" />' },
+    { code: '<input type="image" alt={altText} />' },
+    { code: '<InputImage />' },
+    { code: '<Input type="image" alt="" />', settings: componentsSettings },
+    { code: '<SomeComponent as="input" type="image" alt="" />', settings: componentsSettings },
+
+    // CUSTOM ELEMENT TESTS FOR ARRAY OPTION TESTS
+    { code: '<Thumbnail alt="foo" />;', options: array },
+    { code: '<Thumbnail alt={"foo"} />;', options: array },
+    { code: '<Thumbnail alt={alt} />;', options: array },
+    { code: '<Thumbnail ALT="foo" />;', options: array },
+    { code: '<Thumbnail ALT={`This is the ${alt} text`} />;', options: array },
+    { code: '<Thumbnail ALt="foo" />;', options: array },
+    { code: '<Thumbnail alt="foo" salt={undefined} />;', options: array },
+    { code: '<Thumbnail {...this.props} alt="foo" />', options: array },
+    { code: '<thumbnail />', options: array },
+    { code: '<Thumbnail alt={function(e) {} } />', options: array },
+    { code: '<div alt={function(e) {} } />', options: array },
+    { code: '<Thumbnail alt={() => void 0} />', options: array },
+    { code: '<THUMBNAIL />', options: array },
+    { code: '<Thumbnail alt={alt || "foo" } />', options: array },
+    { code: '<Image alt="foo" />;', options: array },
+    { code: '<Image alt={"foo"} />;', options: array },
+    { code: '<Image alt={alt} />;', options: array },
+    { code: '<Image ALT="foo" />;', options: array },
+    { code: '<Image ALT={`This is the ${alt} text`} />;', options: array },
+    { code: '<Image ALt="foo" />;', options: array },
+    { code: '<Image alt="foo" salt={undefined} />;', options: array },
+    { code: '<Image {...this.props} alt="foo" />', options: array },
+    { code: '<image />', options: array },
+    { code: '<Image alt={function(e) {} } />', options: array },
+    { code: '<div alt={function(e) {} } />', options: array },
+    { code: '<Image alt={() => void 0} />', options: array },
+    { code: '<IMAGE />', options: array },
+    { code: '<Image alt={alt || "foo" } />', options: array },
+    { code: '<Object aria-label="foo" />', options: array },
+    { code: '<Object aria-labelledby="id1" />', options: array },
+    { code: '<Object>Foo</Object>', options: array },
+    { code: '<Object><p>This is descriptive!</p></Object>', options: array },
+    { code: '<Object title="An object" />', options: array },
+    { code: '<Area aria-label="foo" />', options: array },
+    { code: '<Area aria-labelledby="id1" />', options: array },
+    { code: '<Area alt="" />', options: array },
+    { code: '<Area alt="This is descriptive!" />', options: array },
+    { code: '<Area alt={altText} />', options: array },
+    { code: '<InputImage aria-label="foo" />', options: array },
+    { code: '<InputImage aria-labelledby="id1" />', options: array },
+    { code: '<InputImage alt="" />', options: array },
+    { code: '<InputImage alt="This is descriptive!" />', options: array },
+    { code: '<InputImage alt={altText} />', options: array },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    // DEFAULT ELEMENT 'img' TESTS
+    { code: '<img />;', errors: [missingPropError('img')] },
+    { code: '<img alt />;', errors: [altValueError('img')] },
+    { code: '<img alt={undefined} />;', errors: [altValueError('img')] },
+    { code: '<img src="xyz" />', errors: [missingPropError('img')] },
+    { code: '<img role />', errors: [missingPropError('img')] },
+    { code: '<img {...this.props} />', errors: [missingPropError('img')] },
+    { code: '<img alt={false || false} />', errors: [altValueError('img')] },
+    { code: '<img alt={undefined} role="presentation" />;', errors: [altValueError('img')] },
+    { code: '<img alt role="presentation" />;', errors: [altValueError('img')] },
+    { code: '<img role="presentation" />;', errors: [preferAltError()] },
+    { code: '<img role="none" />;', errors: [preferAltError()] },
+    { code: '<img aria-label={undefined} />', errors: [ariaLabelValueError] },
+    { code: '<img aria-labelledby={undefined} />', errors: [ariaLabelledbyValueError] },
+    { code: '<img aria-label="" />', errors: [ariaLabelValueError] },
+    { code: '<img aria-labelledby="" />', errors: [ariaLabelledbyValueError] },
+    { code: '<SomeComponent as="img" aria-label="" />', settings: componentsSettings, errors: [ariaLabelValueError] },
+
+    // DEFAULT ELEMENT 'object' TESTS
+    { code: '<object />', errors: [objectError] },
+    { code: '<object><div aria-hidden /></object>', errors: [objectError] },
+    { code: '<object title={undefined} />', errors: [objectError] },
+    { code: '<object aria-label="" />', errors: [objectError] },
+    { code: '<object aria-labelledby="" />', errors: [objectError] },
+    { code: '<object aria-label={undefined} />', errors: [objectError] },
+    { code: '<object aria-labelledby={undefined} />', errors: [objectError] },
+
+    // DEFAULT ELEMENT 'area' TESTS
+    { code: '<area />', errors: [areaError] },
+    { code: '<area alt />', errors: [areaError] },
+    { code: '<area alt={undefined} />', errors: [areaError] },
+    { code: '<area src="xyz" />', errors: [areaError] },
+    { code: '<area {...this.props} />', errors: [areaError] },
+    { code: '<area aria-label="" />', errors: [areaError] },
+    { code: '<area aria-label={undefined} />', errors: [areaError] },
+    { code: '<area aria-labelledby="" />', errors: [areaError] },
+    { code: '<area aria-labelledby={undefined} />', errors: [areaError] },
+
+    // DEFAULT ELEMENT 'input type="image"' TESTS
+    { code: '<input type="image" />', errors: [inputImageError] },
+    { code: '<input type="image" alt />', errors: [inputImageError] },
+    { code: '<input type="image" alt={undefined} />', errors: [inputImageError] },
+    { code: '<input type="image">Foo</input>', errors: [inputImageError] },
+    { code: '<input type="image" {...this.props} />', errors: [inputImageError] },
+    { code: '<input type="image" aria-label="" />', errors: [inputImageError] },
+    { code: '<input type="image" aria-label={undefined} />', errors: [inputImageError] },
+    { code: '<input type="image" aria-labelledby="" />', errors: [inputImageError] },
+    { code: '<input type="image" aria-labelledby={undefined} />', errors: [inputImageError] },
+
+    // CUSTOM ELEMENT TESTS FOR ARRAY OPTION TESTS
+    {
+      code: '<Thumbnail />;',
+      errors: [missingPropError('Thumbnail')],
+      options: array,
+    },
+    {
+      code: '<Thumbnail alt />;',
+      errors: [altValueError('Thumbnail')],
+      options: array,
+    },
+    {
+      code: '<Thumbnail alt={undefined} />;',
+      errors: [altValueError('Thumbnail')],
+      options: array,
+    },
+    {
+      code: '<Thumbnail src="xyz" />',
+      errors: [missingPropError('Thumbnail')],
+      options: array,
+    },
+    {
+      code: '<Thumbnail {...this.props} />',
+      errors: [missingPropError('Thumbnail')],
+      options: array,
+    },
+    { code: '<Image />;', errors: [missingPropError('Image')], options: array },
+    { code: '<Image alt />;', errors: [altValueError('Image')], options: array },
+    {
+      code: '<Image alt={undefined} />;',
+      errors: [altValueError('Image')],
+      options: array,
+    },
+    {
+      code: '<Image src="xyz" />',
+      errors: [missingPropError('Image')],
+      options: array,
+    },
+    {
+      code: '<Image {...this.props} />',
+      errors: [missingPropError('Image')],
+      options: array,
+    },
+    { code: '<Object />', errors: [objectError], options: array },
+    { code: '<Object><div aria-hidden /></Object>', errors: [objectError], options: array },
+    { code: '<Object title={undefined} />', errors: [objectError], options: array },
+    { code: '<Area />', errors: [areaError], options: array },
+    { code: '<Area alt />', errors: [areaError], options: array },
+    { code: '<Area alt={undefined} />', errors: [areaError], options: array },
+    { code: '<Area src="xyz" />', errors: [areaError], options: array },
+    { code: '<Area {...this.props} />', errors: [areaError], options: array },
+    { code: '<InputImage />', errors: [inputImageError], options: array },
+    { code: '<InputImage alt />', errors: [inputImageError], options: array },
+    { code: '<InputImage alt={undefined} />', errors: [inputImageError], options: array },
+    { code: '<InputImage>Foo</InputImage>', errors: [inputImageError], options: array },
+    { code: '<InputImage {...this.props} />', errors: [inputImageError], options: array },
+    { code: '<Input type="image" />', errors: [inputImageError], settings: componentsSettings },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-ambiguous-text-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-ambiguous-text-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-ambiguous-text-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,117 @@
+/**
+ * @fileoverview Enforce `<a>` text to not exactly match "click here", "here", "link", or "a link".
+ * @author Matt Wang
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/anchor-ambiguous-text';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const DEFAULT_AMBIGUOUS_WORDS = [
+  'click here',
+  'here',
+  'link',
+  'a link',
+  'learn more',
+];
+
+const expectedErrorGenerator = (words) => ({
+  message: `Ambiguous text within anchor. Screen reader users rely on link text for context; the words "${words.join('", "')}" are ambiguous and do not provide enough context.`,
+  type: 'JSXOpeningElement',
+});
+
+const expectedError = expectedErrorGenerator(DEFAULT_AMBIGUOUS_WORDS);
+
+ruleTester.run('anchor-ambiguous-text', rule, {
+  valid: parsers.all([].concat(
+    { code: '<a>documentation</a>;' },
+    { code: '<a>${here}</a>;' },
+    { code: '<a aria-label="tutorial on using eslint-plugin-jsx-a11y">click here</a>;' },
+    { code: '<a><span aria-label="tutorial on using eslint-plugin-jsx-a11y">click here</span></a>;' },
+    { code: '<a><img alt="documentation" /></a>;' },
+    {
+      code: '<a>click here</a>',
+      options: [{
+        words: ['disabling the defaults'],
+      }],
+    },
+    {
+      code: '<Link>documentation</Link>;',
+      settings: { 'jsx-a11y': { components: { Link: 'a' } } },
+    },
+    {
+      code: '<a><Image alt="documentation" /></a>;',
+      settings: { 'jsx-a11y': { components: { Image: 'img' } } },
+    },
+    {
+      code: '<Link>${here}</Link>;',
+      settings: { 'jsx-a11y': { components: { Link: 'a' } } },
+    },
+    {
+      code: '<Link aria-label="tutorial on using eslint-plugin-jsx-a11y">click here</Link>;',
+      settings: { 'jsx-a11y': { components: { Link: 'a' } } },
+    },
+    {
+      code: '<Link>click here</Link>',
+      options: [{
+        words: ['disabling the defaults with components'],
+      }],
+      settings: { 'jsx-a11y': { components: { Link: 'a' } } },
+    },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<a>here</a>;', errors: [expectedError] },
+    { code: '<a>HERE</a>;', errors: [expectedError] },
+    { code: '<a>click here</a>;', errors: [expectedError] },
+    { code: '<a>learn more</a>;', errors: [expectedError] },
+    { code: '<a>learn      more</a>;', errors: [expectedError] },
+    { code: '<a>learn more.</a>;', errors: [expectedError] },
+    { code: '<a>learn more?</a>;', errors: [expectedError] },
+    { code: '<a>learn more,</a>;', errors: [expectedError] },
+    { code: '<a>learn more!</a>;', errors: [expectedError] },
+    { code: '<a>learn more;</a>;', errors: [expectedError] },
+    { code: '<a>learn more:</a>;', errors: [expectedError] },
+    { code: '<a>link</a>;', errors: [expectedError] },
+    { code: '<a>a link</a>;', errors: [expectedError] },
+    { code: '<a aria-label="click here">something</a>;', errors: [expectedError] },
+    { code: '<a> a link </a>;', errors: [expectedError] },
+    { code: '<a>a<i></i> link</a>;', errors: [expectedError] },
+    { code: '<a><i></i>a link</a>;', errors: [expectedError] },
+    { code: '<a><span>click</span> here</a>;', errors: [expectedError] },
+    { code: '<a><span> click </span> here</a>;', errors: [expectedError] },
+    { code: '<a><span aria-hidden>more text</span>learn more</a>;', errors: [expectedError] },
+    { code: '<a><span aria-hidden="true">more text</span>learn more</a>;', errors: [expectedError] },
+    { code: '<a><img alt="click here"/></a>;', errors: [expectedError] },
+    { code: '<a alt="tutorial on using eslint-plugin-jsx-a11y">click here</a>;', errors: [expectedError] },
+    { code: '<a><span alt="tutorial on using eslint-plugin-jsx-a11y">click here</span></a>;', errors: [expectedError] },
+    { code: '<a><CustomElement>click</CustomElement> here</a>;', errors: [expectedError] },
+    {
+      code: '<Link>here</Link>',
+      errors: [expectedError],
+      settings: { 'jsx-a11y': { components: { Link: 'a' } } },
+    },
+    {
+      code: '<a><Image alt="click here" /></a>',
+      errors: [expectedError],
+      settings: { 'jsx-a11y': { components: { Image: 'img' } } },
+    },
+    {
+      code: '<a>a disallowed word</a>',
+      errors: [expectedErrorGenerator(['a disallowed word'])],
+      options: [{
+        words: ['a disallowed word'],
+      }],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-has-content-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-has-content-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-has-content-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+/**
+ * @fileoverview Enforce anchor elements to contain accessible content.
+ * @author Lisa Ring & Niklas Holmberg
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/anchor-has-content';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'Anchors must have content and the content must be accessible by a screen reader.',
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('anchor-has-content', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<a>Foo</a>' },
+    { code: '<a><Bar /></a>' },
+    { code: '<a>{foo}</a>' },
+    { code: '<a>{foo.bar}</a>' },
+    { code: '<a dangerouslySetInnerHTML={{ __html: "foo" }} />' },
+    { code: '<a children={children} />' },
+    { code: '<Link />' },
+    {
+      code: '<Link>foo</Link>',
+      settings: { 'jsx-a11y': { components: { Link: 'a' } } },
+    },
+    { code: '<a title={title} />' },
+    { code: '<a aria-label={ariaLabel} />' },
+    { code: '<a title={title} aria-label={ariaLabel} />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<a />', errors: [expectedError] },
+    { code: '<a><Bar aria-hidden /></a>', errors: [expectedError] },
+    { code: '<a>{undefined}</a>', errors: [expectedError] },
+    {
+      code: '<Link />',
+      errors: [expectedError],
+      settings: { 'jsx-a11y': { components: { Link: 'a' } } },
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-is-valid-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-is-valid-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/anchor-is-valid-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,532 @@
+/**
+ * @fileoverview Performs validity check on anchor hrefs. Warns when anchors are used as buttons.
+ * @author Almero Steyn
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/anchor-is-valid';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const preferButtonErrorMessage = 'Anchor used as a button. Anchors are primarily expected to navigate. Use the button element instead. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md';
+
+const noHrefErrorMessage = 'The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md';
+
+const invalidHrefErrorMessage = 'The href attribute requires a valid value to be accessible. Provide a valid, navigable address as the href value. If you cannot provide a valid href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md';
+
+const preferButtonexpectedError = {
+  message: preferButtonErrorMessage,
+  type: 'JSXOpeningElement',
+};
+const noHrefexpectedError = {
+  message: noHrefErrorMessage,
+  type: 'JSXOpeningElement',
+};
+const invalidHrefexpectedError = {
+  message: invalidHrefErrorMessage,
+  type: 'JSXOpeningElement',
+};
+
+const components = [{
+  components: ['Anchor', 'Link'],
+}];
+const specialLink = [{
+  specialLink: ['hrefLeft', 'hrefRight'],
+}];
+const noHrefAspect = [{
+  aspects: ['noHref'],
+}];
+const invalidHrefAspect = [{
+  aspects: ['invalidHref'],
+}];
+const preferButtonAspect = [{
+  aspects: ['preferButton'],
+}];
+const noHrefInvalidHrefAspect = [{
+  aspects: ['noHref', 'invalidHref'],
+}];
+const noHrefPreferButtonAspect = [{
+  aspects: ['noHref', 'preferButton'],
+}];
+const preferButtonInvalidHrefAspect = [{
+  aspects: ['preferButton', 'invalidHref'],
+}];
+
+const componentsAndSpecialLink = [{
+  components: ['Anchor'],
+  specialLink: ['hrefLeft'],
+}];
+
+const componentsAndSpecialLinkAndInvalidHrefAspect = [{
+  components: ['Anchor'],
+  specialLink: ['hrefLeft'],
+  aspects: ['invalidHref'],
+}];
+
+const componentsAndSpecialLinkAndNoHrefAspect = [{
+  components: ['Anchor'],
+  specialLink: ['hrefLeft'],
+  aspects: ['noHref'],
+}];
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Anchor: 'a',
+      Link: 'a',
+    },
+  },
+};
+
+ruleTester.run('anchor-is-valid', rule, {
+  valid: parsers.all([].concat(
+    // DEFAULT ELEMENT 'a' TESTS
+    { code: '<Anchor />' },
+    { code: '<a {...props} />' },
+    { code: '<a href="foo" />' },
+    { code: '<a href={foo} />' },
+    { code: '<a href="/foo" />' },
+    { code: '<a href="https://foo.bar.com" />' },
+    { code: '<div href="foo" />' },
+    { code: '<a href="javascript" />' },
+    { code: '<a href="javascriptFoo" />' },
+    { code: '<a href={`#foo`}/>' },
+    { code: '<a href={"foo"}/>' },
+    { code: '<a href={"javascript"}/>' },
+    { code: '<a href={`#javascript`}/>' },
+    { code: '<a href="#foo" />' },
+    { code: '<a href="#javascript" />' },
+    { code: '<a href="#javascriptFoo" />' },
+    { code: '<UX.Layout>test</UX.Layout>' },
+    { code: '<a href={this} />' },
+
+    // CUSTOM ELEMENT TEST FOR ARRAY OPTION
+    { code: '<Anchor {...props} />', options: components },
+    { code: '<Anchor href="foo" />', options: components },
+    { code: '<Anchor href={foo} />', options: components },
+    { code: '<Anchor href="/foo" />', options: components },
+    { code: '<Anchor href="https://foo.bar.com" />', options: components },
+    { code: '<div href="foo" />', options: components },
+    { code: '<Anchor href={`#foo`}/>', options: components },
+    { code: '<Anchor href={"foo"}/>', options: components },
+    { code: '<Anchor href="#foo" />', options: components },
+    { code: '<Link {...props} />', options: components },
+    { code: '<Link href="foo" />', options: components },
+    { code: '<Link href={foo} />', options: components },
+    { code: '<Link href="/foo" />', options: components },
+    { code: '<Link href="https://foo.bar.com" />', options: components },
+    { code: '<div href="foo" />', options: components },
+    { code: '<Link href={`#foo`}/>', options: components },
+    { code: '<Link href={"foo"}/>', options: components },
+    { code: '<Link href="#foo" />', options: components },
+    { code: '<Link href="#foo" />', settings: componentsSettings },
+
+    // CUSTOM PROP TESTS
+    { code: '<a {...props} />', options: specialLink },
+    { code: '<a hrefLeft="foo" />', options: specialLink },
+    { code: '<a hrefLeft={foo} />', options: specialLink },
+    { code: '<a hrefLeft="/foo" />', options: specialLink },
+    { code: '<a hrefLeft="https://foo.bar.com" />', options: specialLink },
+    { code: '<div hrefLeft="foo" />', options: specialLink },
+    { code: '<a hrefLeft={`#foo`}/>', options: specialLink },
+    { code: '<a hrefLeft={"foo"}/>', options: specialLink },
+    { code: '<a hrefLeft="#foo" />', options: specialLink },
+    { code: '<UX.Layout>test</UX.Layout>', options: specialLink },
+    { code: '<a hrefRight={this} />', options: specialLink },
+    { code: '<a {...props} />', options: specialLink },
+    { code: '<a hrefRight="foo" />', options: specialLink },
+    { code: '<a hrefRight={foo} />', options: specialLink },
+    { code: '<a hrefRight="/foo" />', options: specialLink },
+    { code: '<a hrefRight="https://foo.bar.com" />', options: specialLink },
+    { code: '<div hrefRight="foo" />', options: specialLink },
+    { code: '<a hrefRight={`#foo`}/>', options: specialLink },
+    { code: '<a hrefRight={"foo"}/>', options: specialLink },
+    { code: '<a hrefRight="#foo" />', options: specialLink },
+    { code: '<UX.Layout>test</UX.Layout>', options: specialLink },
+    { code: '<a hrefRight={this} />', options: specialLink },
+
+    // CUSTOM BOTH COMPONENTS AND SPECIALLINK TESTS
+    { code: '<Anchor {...props} />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="foo" />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft={foo} />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="/foo" />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="https://foo.bar.com" />', options: componentsAndSpecialLink },
+    { code: '<div hrefLeft="foo" />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft={`#foo`}/>', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft={"foo"}/>', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="#foo" />', options: componentsAndSpecialLink },
+    { code: '<UX.Layout>test</UX.Layout>', options: componentsAndSpecialLink },
+
+    // WITH ONCLICK
+    // DEFAULT ELEMENT 'a' TESTS
+    { code: '<a {...props} onClick={() => void 0} />' },
+    { code: '<a href="foo" onClick={() => void 0} />' },
+    { code: '<a href={foo} onClick={() => void 0} />' },
+    { code: '<a href="/foo" onClick={() => void 0} />' },
+    { code: '<a href="https://foo.bar.com" onClick={() => void 0} />' },
+    { code: '<div href="foo" onClick={() => void 0} />' },
+    { code: '<a href={`#foo`} onClick={() => void 0} />' },
+    { code: '<a href={"foo"} onClick={() => void 0} />' },
+    { code: '<a href="#foo" onClick={() => void 0} />' },
+    { code: '<a href={this} onClick={() => void 0} />' },
+
+    // CUSTOM ELEMENT TEST FOR ARRAY OPTION
+    { code: '<Anchor {...props} onClick={() => void 0} />', options: components },
+    { code: '<Anchor href="foo" onClick={() => void 0} />', options: components },
+    { code: '<Anchor href={foo} onClick={() => void 0} />', options: components },
+    { code: '<Anchor href="/foo" onClick={() => void 0} />', options: components },
+    { code: '<Anchor href="https://foo.bar.com" onClick={() => void 0} />', options: components },
+    { code: '<Anchor href={`#foo`} onClick={() => void 0} />', options: components },
+    { code: '<Anchor href={"foo"} onClick={() => void 0} />', options: components },
+    { code: '<Anchor href="#foo" onClick={() => void 0} />', options: components },
+    { code: '<Link {...props} onClick={() => void 0} />', options: components },
+    { code: '<Link href="foo" onClick={() => void 0} />', options: components },
+    { code: '<Link href={foo} onClick={() => void 0} />', options: components },
+    { code: '<Link href="/foo" onClick={() => void 0} />', options: components },
+    { code: '<Link href="https://foo.bar.com" onClick={() => void 0} />', options: components },
+    { code: '<div href="foo" onClick={() => void 0} />', options: components },
+    { code: '<Link href={`#foo`} onClick={() => void 0} />', options: components },
+    { code: '<Link href={"foo"} onClick={() => void 0} />', options: components },
+    { code: '<Link href="#foo" onClick={() => void 0} />', options: components },
+
+    // CUSTOM PROP TESTS
+    { code: '<a {...props} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefLeft="foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefLeft={foo} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefLeft="/foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefLeft href="https://foo.bar.com" onClick={() => void 0} />', options: specialLink },
+    { code: '<div hrefLeft="foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefLeft={`#foo`} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefLeft={"foo"} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefLeft="#foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight={this} onClick={() => void 0} />', options: specialLink },
+    { code: '<a {...props} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight="foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight={foo} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight="/foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight href="https://foo.bar.com" onClick={() => void 0} />', options: specialLink },
+    { code: '<div hrefRight="foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight={`#foo`} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight={"foo"} onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight="#foo" onClick={() => void 0} />', options: specialLink },
+    { code: '<a hrefRight={this} onClick={() => void 0} />', options: specialLink },
+
+    // CUSTOM BOTH COMPONENTS AND SPECIALLINK TESTS
+    { code: '<Anchor {...props} onClick={() => void 0} />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="foo" onClick={() => void 0} />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft={foo} onClick={() => void 0} />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="/foo" onClick={() => void 0} />', options: componentsAndSpecialLink },
+    {
+      code: '<Anchor hrefLeft href="https://foo.bar.com" onClick={() => void 0} />',
+      options: componentsAndSpecialLink,
+    },
+    { code: '<Anchor hrefLeft={`#foo`} onClick={() => void 0} />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft={"foo"} onClick={() => void 0} />', options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="#foo" onClick={() => void 0} />', options: componentsAndSpecialLink },
+
+    // WITH ASPECTS TESTS
+    // NO HREF
+    { code: '<a />', options: invalidHrefAspect },
+    { code: '<a href={undefined} />', options: invalidHrefAspect },
+    { code: '<a href={null} />', options: invalidHrefAspect },
+    { code: '<a />', options: preferButtonAspect },
+    { code: '<a href={undefined} />', options: preferButtonAspect },
+    { code: '<a href={null} />', options: preferButtonAspect },
+    { code: '<a />', options: preferButtonInvalidHrefAspect },
+    { code: '<a href={undefined} />', options: preferButtonInvalidHrefAspect },
+    { code: '<a href={null} />', options: preferButtonInvalidHrefAspect },
+
+    // INVALID HREF
+    { code: '<a href="" />;', options: preferButtonAspect },
+    { code: '<a href="#" />', options: preferButtonAspect },
+    { code: '<a href={"#"} />', options: preferButtonAspect },
+    { code: '<a href="javascript:void(0)" />', options: preferButtonAspect },
+    { code: '<a href={"javascript:void(0)"} />', options: preferButtonAspect },
+    { code: '<a href="" />;', options: noHrefAspect },
+    { code: '<a href="#" />', options: noHrefAspect },
+    { code: '<a href={"#"} />', options: noHrefAspect },
+    { code: '<a href="javascript:void(0)" />', options: noHrefAspect },
+    { code: '<a href={"javascript:void(0)"} />', options: noHrefAspect },
+    { code: '<a href="" />;', options: noHrefPreferButtonAspect },
+    { code: '<a href="#" />', options: noHrefPreferButtonAspect },
+    { code: '<a href={"#"} />', options: noHrefPreferButtonAspect },
+    { code: '<a href="javascript:void(0)" />', options: noHrefPreferButtonAspect },
+    { code: '<a href={"javascript:void(0)"} />', options: noHrefPreferButtonAspect },
+
+    // SHOULD BE BUTTON
+    { code: '<a onClick={() => void 0} />', options: invalidHrefAspect },
+    { code: '<a href="#" onClick={() => void 0} />', options: noHrefAspect },
+    { code: '<a href="javascript:void(0)" onClick={() => void 0} />', options: noHrefAspect },
+    {
+      code: '<a href={"javascript:void(0)"} onClick={() => void 0} />',
+      options: noHrefAspect,
+    },
+
+    // CUSTOM COMPONENTS AND SPECIAL LINK AND ASPECT
+    { code: '<Anchor hrefLeft={undefined} />', options: componentsAndSpecialLinkAndInvalidHrefAspect },
+    { code: '<Anchor hrefLeft={null} />', options: componentsAndSpecialLinkAndInvalidHrefAspect },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    // DEFAULT ELEMENT 'a' TESTS
+    // NO HREF
+    { code: '<a />', errors: [noHrefexpectedError] },
+    { code: '<a href={undefined} />', errors: [noHrefexpectedError] },
+    { code: '<a href={null} />', errors: [noHrefexpectedError] },
+    // INVALID HREF
+    { code: '<a href="" />;', errors: [invalidHrefexpectedError] },
+    { code: '<a href="#" />', errors: [invalidHrefexpectedError] },
+    { code: '<a href={"#"} />', errors: [invalidHrefexpectedError] },
+    { code: '<a href="javascript:void(0)" />', errors: [invalidHrefexpectedError] },
+    { code: '<a href={"javascript:void(0)"} />', errors: [invalidHrefexpectedError] },
+    // SHOULD BE BUTTON
+    { code: '<a onClick={() => void 0} />', errors: [preferButtonexpectedError] },
+    { code: '<a href="#" onClick={() => void 0} />', errors: [preferButtonexpectedError] },
+    { code: '<a href="javascript:void(0)" onClick={() => void 0} />', errors: [preferButtonexpectedError] },
+    {
+      code: '<a href={"javascript:void(0)"} onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+    },
+
+    // CUSTOM ELEMENT TEST FOR ARRAY OPTION
+    // NO HREF
+    { code: '<Link />', errors: [noHrefexpectedError], options: components },
+    { code: '<Link href={undefined} />', errors: [noHrefexpectedError], options: components },
+    { code: '<Link href={null} />', errors: [noHrefexpectedError], options: components },
+    // INVALID HREF
+    { code: '<Link href="" />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Link href="#" />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Link href={"#"} />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Link href="javascript:void(0)" />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Link href={"javascript:void(0)"} />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Anchor href="" />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Anchor href="#" />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Anchor href={"#"} />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Anchor href="javascript:void(0)" />', errors: [invalidHrefexpectedError], options: components },
+    { code: '<Anchor href={"javascript:void(0)"} />', errors: [invalidHrefexpectedError], options: components },
+    // SHOULD BE BUTTON
+    { code: '<Link onClick={() => void 0} />', errors: [preferButtonexpectedError], options: components },
+    { code: '<Link href="#" onClick={() => void 0} />', errors: [preferButtonexpectedError], options: components },
+    {
+      code: '<Link href="javascript:void(0)" onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: components,
+    },
+    {
+      code: '<Link href={"javascript:void(0)"} onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: components,
+    },
+    { code: '<Anchor onClick={() => void 0} />', errors: [preferButtonexpectedError], options: components },
+    { code: '<Anchor href="#" onClick={() => void 0} />', errors: [preferButtonexpectedError], options: components },
+    {
+      code: '<Anchor href="javascript:void(0)" onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: components,
+    },
+    {
+      code: '<Anchor href={"javascript:void(0)"} onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: components,
+    },
+    {
+      code: '<Link href="#" onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      settings: componentsSettings,
+    },
+
+    // CUSTOM PROP TESTS
+    // NO HREF
+    { code: '<a hrefLeft={undefined} />', errors: [noHrefexpectedError], options: specialLink },
+    { code: '<a hrefLeft={null} />', errors: [noHrefexpectedError], options: specialLink },
+    // INVALID HREF
+    { code: '<a hrefLeft="" />;', errors: [invalidHrefexpectedError], options: specialLink },
+    { code: '<a hrefLeft="#" />', errors: [invalidHrefexpectedError], options: specialLink },
+    { code: '<a hrefLeft={"#"} />', errors: [invalidHrefexpectedError], options: specialLink },
+    { code: '<a hrefLeft="javascript:void(0)" />', errors: [invalidHrefexpectedError], options: specialLink },
+    { code: '<a hrefLeft={"javascript:void(0)"} />', errors: [invalidHrefexpectedError], options: specialLink },
+    // SHOULD BE BUTTON
+    { code: '<a hrefLeft="#" onClick={() => void 0} />', errors: [preferButtonexpectedError], options: specialLink },
+    {
+      code: '<a hrefLeft="javascript:void(0)" onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: specialLink,
+    },
+    {
+      code: '<a hrefLeft={"javascript:void(0)"} onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: specialLink,
+    },
+
+    // CUSTOM BOTH COMPONENTS AND SPECIAL LINK TESTS
+    // NO HREF
+    { code: '<Anchor Anchor={undefined} />', errors: [noHrefexpectedError], options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft={null} />', errors: [noHrefexpectedError], options: componentsAndSpecialLink },
+    // INVALID HREF
+    { code: '<Anchor hrefLeft="" />;', errors: [invalidHrefexpectedError], options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft="#" />', errors: [invalidHrefexpectedError], options: componentsAndSpecialLink },
+    { code: '<Anchor hrefLeft={"#"} />', errors: [invalidHrefexpectedError], options: componentsAndSpecialLink },
+    {
+      code: '<Anchor hrefLeft="javascript:void(0)" />',
+      errors: [invalidHrefexpectedError],
+      options: componentsAndSpecialLink,
+    },
+    {
+      code: '<Anchor hrefLeft={"javascript:void(0)"} />',
+      errors: [invalidHrefexpectedError],
+      options: componentsAndSpecialLink,
+    },
+    // SHOULD BE BUTTON
+    {
+      code: '<Anchor hrefLeft="#" onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: componentsAndSpecialLink,
+    },
+    {
+      code: '<Anchor hrefLeft="javascript:void(0)" onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: componentsAndSpecialLink,
+    },
+    {
+      code: '<Anchor hrefLeft={"javascript:void(0)"} onClick={() => void 0} />',
+      errors: [preferButtonexpectedError],
+      options: componentsAndSpecialLink,
+    },
+
+    // WITH ASPECTS TESTS
+    // NO HREF
+    { code: '<a />', options: noHrefAspect, errors: [noHrefexpectedError] },
+    { code: '<a />', options: noHrefPreferButtonAspect, errors: [noHrefexpectedError] },
+    { code: '<a />', options: noHrefInvalidHrefAspect, errors: [noHrefexpectedError] },
+    { code: '<a href={undefined} />', options: noHrefAspect, errors: [noHrefexpectedError] },
+    { code: '<a href={undefined} />', options: noHrefPreferButtonAspect, errors: [noHrefexpectedError] },
+    { code: '<a href={undefined} />', options: noHrefInvalidHrefAspect, errors: [noHrefexpectedError] },
+    { code: '<a href={null} />', options: noHrefAspect, errors: [noHrefexpectedError] },
+    { code: '<a href={null} />', options: noHrefPreferButtonAspect, errors: [noHrefexpectedError] },
+    { code: '<a href={null} />', options: noHrefInvalidHrefAspect, errors: [noHrefexpectedError] },
+
+    // INVALID HREF
+    { code: '<a href="" />;', options: invalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href="" />;', options: noHrefInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href="" />;', options: preferButtonInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href="#" />;', options: invalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href="#" />;', options: noHrefInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href="#" />;', options: preferButtonInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href={"#"} />;', options: invalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href={"#"} />;', options: noHrefInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href={"#"} />;', options: preferButtonInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href="javascript:void(0)" />;', options: invalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href="javascript:void(0)" />;', options: noHrefInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    {
+      code: '<a href="javascript:void(0)" />;',
+      options: preferButtonInvalidHrefAspect,
+      errors: [invalidHrefexpectedError],
+    },
+    { code: '<a href={"javascript:void(0)"} />;', options: invalidHrefAspect, errors: [invalidHrefexpectedError] },
+    { code: '<a href={"javascript:void(0)"} />;', options: noHrefInvalidHrefAspect, errors: [invalidHrefexpectedError] },
+    {
+      code: '<a href={"javascript:void(0)"} />;',
+      options: preferButtonInvalidHrefAspect,
+      errors: [invalidHrefexpectedError],
+    },
+
+    // SHOULD BE BUTTON
+    { code: '<a onClick={() => void 0} />', options: preferButtonAspect, errors: [preferButtonexpectedError] },
+    {
+      code: '<a onClick={() => void 0} />',
+      options: preferButtonInvalidHrefAspect,
+      errors: [preferButtonexpectedError],
+    },
+    { code: '<a onClick={() => void 0} />', options: noHrefPreferButtonAspect, errors: [preferButtonexpectedError] },
+    { code: '<a onClick={() => void 0} />', options: noHrefAspect, errors: [noHrefexpectedError] },
+    { code: '<a onClick={() => void 0} />', options: noHrefInvalidHrefAspect, errors: [noHrefexpectedError] },
+    { code: '<a href="#" onClick={() => void 0} />', options: preferButtonAspect, errors: [preferButtonexpectedError] },
+    {
+      code: '<a href="#" onClick={() => void 0} />',
+      options: noHrefPreferButtonAspect,
+      errors: [preferButtonexpectedError],
+    },
+    {
+      code: '<a href="#" onClick={() => void 0} />',
+      options: preferButtonInvalidHrefAspect,
+      errors: [preferButtonexpectedError],
+    },
+    { code: '<a href="#" onClick={() => void 0} />', options: invalidHrefAspect, errors: [invalidHrefexpectedError] },
+    {
+      code: '<a href="#" onClick={() => void 0} />',
+      options: noHrefInvalidHrefAspect,
+      errors: [invalidHrefexpectedError],
+    },
+    {
+      code: '<a href="javascript:void(0)" onClick={() => void 0} />',
+      options: preferButtonAspect,
+      errors: [preferButtonexpectedError],
+    },
+    {
+      code: '<a href="javascript:void(0)" onClick={() => void 0} />',
+      options: noHrefPreferButtonAspect,
+      errors: [preferButtonexpectedError],
+    },
+    {
+      code: '<a href="javascript:void(0)" onClick={() => void 0} />',
+      options: preferButtonInvalidHrefAspect,
+      errors: [preferButtonexpectedError],
+    },
+    {
+      code: '<a href="javascript:void(0)" onClick={() => void 0} />',
+      options: invalidHrefAspect,
+      errors: [invalidHrefexpectedError],
+    },
+    {
+      code: '<a href="javascript:void(0)" onClick={() => void 0} />',
+      options: noHrefInvalidHrefAspect,
+      errors: [invalidHrefexpectedError],
+    },
+    {
+      code: '<a href={"javascript:void(0)"} onClick={() => void 0} />',
+      options: preferButtonAspect,
+      errors: [preferButtonexpectedError],
+    },
+    {
+      code: '<a href={"javascript:void(0)"} onClick={() => void 0} />',
+      options: noHrefPreferButtonAspect,
+      errors: [preferButtonexpectedError],
+    },
+    {
+      code: '<a href={"javascript:void(0)"} onClick={() => void 0} />',
+      options: preferButtonInvalidHrefAspect,
+      errors: [preferButtonexpectedError],
+    },
+    {
+      code: '<a href={"javascript:void(0)"} onClick={() => void 0} />',
+      options: invalidHrefAspect,
+      errors: [invalidHrefexpectedError],
+    },
+    {
+      code: '<a href={"javascript:void(0)"} onClick={() => void 0} />',
+      options: noHrefInvalidHrefAspect,
+      errors: [invalidHrefexpectedError],
+    },
+
+    // CUSTOM COMPONENTS AND SPECIAL LINK AND ASPECT
+    {
+      code: '<Anchor hrefLeft={undefined} />',
+      options: componentsAndSpecialLinkAndNoHrefAspect,
+      errors: [noHrefexpectedError],
+    },
+    {
+      code: '<Anchor hrefLeft={null} />',
+      options: componentsAndSpecialLinkAndNoHrefAspect,
+      errors: [noHrefexpectedError],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+/**
+ * @fileoverview Enforce elements with aria-activedescendant are tabbable.
+ * @author Jesse Beach <@jessebeach>
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/aria-activedescendant-has-tabindex';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'An element that manages focus with `aria-activedescendant` must have a tabindex',
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('aria-activedescendant-has-tabindex', rule, {
+  valid: parsers.all([].concat(
+    {
+      code: '<CustomComponent />;',
+    },
+    {
+      code: '<CustomComponent aria-activedescendant={someID} />;',
+    },
+    {
+      code: '<CustomComponent aria-activedescendant={someID} tabIndex={0} />;',
+    },
+    {
+      code: '<CustomComponent aria-activedescendant={someID} tabIndex={-1} />;',
+    },
+    {
+      code: '<CustomComponent aria-activedescendant={someID} tabIndex={0} />;',
+      settings: { 'jsx-a11y': { components: { CustomComponent: 'div' } } },
+    },
+    {
+      code: '<div />;',
+    },
+    {
+      code: '<input />;',
+    },
+    {
+      code: '<div tabIndex={0} />;',
+    },
+    {
+      code: '<div aria-activedescendant={someID} tabIndex={0} />;',
+    },
+    {
+      code: '<div aria-activedescendant={someID} tabIndex="0" />;',
+    },
+    {
+      code: '<div aria-activedescendant={someID} tabIndex={1} />;',
+    },
+    {
+      code: '<input aria-activedescendant={someID} />;',
+    },
+    {
+      code: '<input aria-activedescendant={someID} tabIndex={1} />;',
+    },
+    {
+      code: '<input aria-activedescendant={someID} tabIndex={0} />;',
+    },
+    {
+      code: '<input aria-activedescendant={someID} tabIndex={-1} />;',
+    },
+    {
+      code: '<div aria-activedescendant={someID} tabIndex={-1} />;',
+    },
+    {
+      code: '<div aria-activedescendant={someID} tabIndex="-1" />;',
+    },
+    {
+      code: '<input aria-activedescendant={someID} tabIndex={-1} />;',
+    },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    {
+      code: '<div aria-activedescendant={someID} />;',
+      errors: [expectedError],
+    },
+    {
+      code: '<CustomComponent aria-activedescendant={someID} />;',
+      errors: [expectedError],
+      settings: { 'jsx-a11y': { components: { CustomComponent: 'div' } } },
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-props-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-props-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-props-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,69 @@
+/**
+ * @fileoverview Enforce all aria-* properties are valid.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { aria } from 'aria-query';
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/aria-props';
+import getSuggestion from '../../../src/util/getSuggestion';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+const ariaAttributes = aria.keys();
+
+const errorMessage = (name) => {
+  const suggestions = getSuggestion(name, ariaAttributes);
+  const message = `${name}: This attribute is an invalid ARIA attribute.`;
+
+  if (suggestions.length > 0) {
+    return {
+      type: 'JSXAttribute',
+      message: `${message} Did you mean to use ${suggestions}?`,
+    };
+  }
+
+  return {
+    type: 'JSXAttribute',
+    message,
+  };
+};
+
+// Create basic test cases using all valid role types.
+const basicValidityTests = ariaAttributes.map((prop) => ({
+  code: `<div ${prop.toLowerCase()}="foobar" />`,
+}));
+
+ruleTester.run('aria-props', rule, {
+  valid: parsers.all([].concat(
+    // Variables should pass, as we are only testing literals.
+    { code: '<div />' },
+    { code: '<div></div>' },
+    { code: '<div aria="wee"></div>' }, // Needs aria-*
+    { code: '<div abcARIAdef="true"></div>' },
+    { code: '<div fooaria-foobar="true"></div>' },
+    { code: '<div fooaria-hidden="true"></div>' },
+    { code: '<Bar baz />' },
+    { code: '<input type="text" aria-errormessage="foobar" />' },
+  )).concat(basicValidityTests).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<div aria-="foobar" />', errors: [errorMessage('aria-')] },
+    {
+      code: '<div aria-labeledby="foobar" />',
+      errors: [errorMessage('aria-labeledby')],
+    },
+    {
+      code: '<div aria-skldjfaria-klajsd="foobar" />',
+      errors: [errorMessage('aria-skldjfaria-klajsd')],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-proptypes-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-proptypes-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-proptypes-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,311 @@
+/**
+ * @fileoverview Enforce ARIA state and property values are valid.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { aria } from 'aria-query';
+import { RuleTester } from 'eslint';
+import test from 'tape';
+
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/aria-proptypes';
+
+const { validityCheck } = rule;
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = (name) => {
+  const {
+    type,
+    values: permittedValues,
+  } = aria.get(name.toLowerCase());
+
+  switch (type) {
+    case 'tristate':
+      return { message: `The value for ${name} must be a boolean or the string "mixed".` };
+    case 'token':
+      return { message: `The value for ${name} must be a single token from the following: ${permittedValues}.` };
+    case 'tokenlist':
+      return {
+        message: `The value for ${name} must be a list of one or more \
+tokens from the following: ${permittedValues}.`,
+      };
+    case 'idlist':
+      return { message: `The value for ${name} must be a list of strings that represent DOM element IDs (idlist)` };
+    case 'id':
+      return { message: `The value for ${name} must be a string that represents a DOM element ID` };
+    case 'boolean':
+    case 'string':
+    case 'integer':
+    case 'number':
+    default:
+      return { message: `The value for ${name} must be a ${type}.` };
+  }
+};
+
+test('validityCheck', (t) => {
+  t.equal(
+    validityCheck(null, null),
+    false,
+    'is false for an unknown expected type',
+  );
+
+  t.end();
+});
+
+ruleTester.run('aria-proptypes', rule, {
+  valid: parsers.all([].concat(
+    // DON'T TEST INVALID ARIA-* PROPS
+    { code: '<div aria-foo="true" />' },
+    { code: '<div abcaria-foo="true" />' },
+
+    // BOOLEAN
+    { code: '<div aria-hidden={true} />' },
+    { code: '<div aria-hidden="true" />' },
+    { code: '<div aria-hidden={"false"} />' },
+    { code: '<div aria-hidden={!false} />' },
+    { code: '<div aria-hidden />' },
+    { code: '<div aria-hidden={false} />' },
+    { code: '<div aria-hidden={!true} />' },
+    { code: '<div aria-hidden={!"yes"} />' },
+    { code: '<div aria-hidden={foo} />' },
+    { code: '<div aria-hidden={foo.bar} />' },
+    { code: '<div aria-hidden={null} />' },
+    { code: '<div aria-hidden={undefined} />' },
+    { code: '<div aria-hidden={<div />} />' },
+
+    // STRING
+    { code: '<div aria-label="Close" />' },
+    { code: '<div aria-label={`Close`} />' },
+    { code: '<div aria-label={foo} />' },
+    { code: '<div aria-label={foo.bar} />' },
+    { code: '<div aria-label={null} />' },
+    { code: '<div aria-label={undefined} />' },
+    { code: '<input aria-invalid={error ? "true" : "false"} />' },
+    { code: '<input aria-invalid={undefined ? "true" : "false"} />' },
+
+    // TRISTATE
+    { code: '<div aria-checked={true} />' },
+    { code: '<div aria-checked="true" />' },
+    { code: '<div aria-checked={"false"} />' },
+    { code: '<div aria-checked={!false} />' },
+    { code: '<div aria-checked />' },
+    { code: '<div aria-checked={false} />' },
+    { code: '<div aria-checked={!true} />' },
+    { code: '<div aria-checked={!"yes"} />' },
+    { code: '<div aria-checked={foo} />' },
+    { code: '<div aria-checked={foo.bar} />' },
+    { code: '<div aria-checked="mixed" />' },
+    { code: '<div aria-checked={`mixed`} />' },
+    { code: '<div aria-checked={null} />' },
+    { code: '<div aria-checked={undefined} />' },
+
+    // INTEGER
+    { code: '<div aria-level={123} />' },
+    { code: '<div aria-level={-123} />' },
+    { code: '<div aria-level={+123} />' },
+    { code: '<div aria-level={~123} />' },
+    { code: '<div aria-level={"123"} />' },
+    { code: '<div aria-level={`123`} />' },
+    { code: '<div aria-level="123" />' },
+    { code: '<div aria-level={foo} />' },
+    { code: '<div aria-level={foo.bar} />' },
+    { code: '<div aria-level={null} />' },
+    { code: '<div aria-level={undefined} />' },
+
+    // NUMBER
+    { code: '<div aria-valuemax={123} />' },
+    { code: '<div aria-valuemax={-123} />' },
+    { code: '<div aria-valuemax={+123} />' },
+    { code: '<div aria-valuemax={~123} />' },
+    { code: '<div aria-valuemax={"123"} />' },
+    { code: '<div aria-valuemax={`123`} />' },
+    { code: '<div aria-valuemax="123" />' },
+    { code: '<div aria-valuemax={foo} />' },
+    { code: '<div aria-valuemax={foo.bar} />' },
+    { code: '<div aria-valuemax={null} />' },
+    { code: '<div aria-valuemax={undefined} />' },
+
+    // TOKEN
+    { code: '<div aria-sort="ascending" />' },
+    { code: '<div aria-sort="ASCENDING" />' },
+    { code: '<div aria-sort={"ascending"} />' },
+    { code: '<div aria-sort={`ascending`} />' },
+    { code: '<div aria-sort="descending" />' },
+    { code: '<div aria-sort={"descending"} />' },
+    { code: '<div aria-sort={`descending`} />' },
+    { code: '<div aria-sort="none" />' },
+    { code: '<div aria-sort={"none"} />' },
+    { code: '<div aria-sort={`none`} />' },
+    { code: '<div aria-sort="other" />' },
+    { code: '<div aria-sort={"other"} />' },
+    { code: '<div aria-sort={`other`} />' },
+    { code: '<div aria-sort={foo} />' },
+    { code: '<div aria-sort={foo.bar} />' },
+    { code: '<div aria-invalid={true} />' },
+    { code: '<div aria-invalid="true" />' },
+    { code: '<div aria-invalid={false} />' },
+    { code: '<div aria-invalid="false" />' },
+    { code: '<div aria-invalid="grammar" />' },
+    { code: '<div aria-invalid="spelling" />' },
+    { code: '<div aria-invalid={null} />' },
+    { code: '<div aria-invalid={undefined} />' },
+
+    // TOKENLIST
+    { code: '<div aria-relevant="additions" />' },
+    { code: '<div aria-relevant={"additions"} />' },
+    { code: '<div aria-relevant={`additions`} />' },
+    { code: '<div aria-relevant="additions removals" />' },
+    { code: '<div aria-relevant="additions additions" />' },
+    { code: '<div aria-relevant={"additions removals"} />' },
+    { code: '<div aria-relevant={`additions removals`} />' },
+    { code: '<div aria-relevant="additions removals text" />' },
+    { code: '<div aria-relevant={"additions removals text"} />' },
+    { code: '<div aria-relevant={`additions removals text`} />' },
+    { code: '<div aria-relevant="additions removals text all" />' },
+    { code: '<div aria-relevant={"additions removals text all"} />' },
+    { code: '<div aria-relevant={`removals additions text all`} />' },
+    { code: '<div aria-relevant={foo} />' },
+    { code: '<div aria-relevant={foo.bar} />' },
+    { code: '<div aria-relevant={null} />' },
+    { code: '<div aria-relevant={undefined} />' },
+
+    // ID
+    { code: '<div aria-activedescendant="ascending" />' },
+    { code: '<div aria-activedescendant="ASCENDING" />' },
+    { code: '<div aria-activedescendant={"ascending"} />' },
+    { code: '<div aria-activedescendant={`ascending`} />' },
+    { code: '<div aria-activedescendant="descending" />' },
+    { code: '<div aria-activedescendant={"descending"} />' },
+    { code: '<div aria-activedescendant={`descending`} />' },
+    { code: '<div aria-activedescendant="none" />' },
+    { code: '<div aria-activedescendant={"none"} />' },
+    { code: '<div aria-activedescendant={`none`} />' },
+    { code: '<div aria-activedescendant="other" />' },
+    { code: '<div aria-activedescendant={"other"} />' },
+    { code: '<div aria-activedescendant={`other`} />' },
+    { code: '<div aria-activedescendant={foo} />' },
+    { code: '<div aria-activedescendant={foo.bar} />' },
+    { code: '<div aria-activedescendant={null} />' },
+    { code: '<div aria-activedescendant={undefined} />' },
+
+    // IDLIST
+    { code: '<div aria-labelledby="additions" />' },
+    { code: '<div aria-labelledby={"additions"} />' },
+    { code: '<div aria-labelledby={`additions`} />' },
+    { code: '<div aria-labelledby="additions removals" />' },
+    { code: '<div aria-labelledby="additions additions" />' },
+    { code: '<div aria-labelledby={"additions removals"} />' },
+    { code: '<div aria-labelledby={`additions removals`} />' },
+    { code: '<div aria-labelledby="additions removals text" />' },
+    { code: '<div aria-labelledby={"additions removals text"} />' },
+    { code: '<div aria-labelledby={`additions removals text`} />' },
+    { code: '<div aria-labelledby="additions removals text all" />' },
+    { code: '<div aria-labelledby={"additions removals text all"} />' },
+    { code: '<div aria-labelledby={`removals additions text all`} />' },
+    { code: '<div aria-labelledby={foo} />' },
+    { code: '<div aria-labelledby={foo.bar} />' },
+    { code: '<div aria-labelledby={null} />' },
+    { code: '<div aria-labelledby={undefined} />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    // BOOLEAN
+    { code: '<div aria-hidden="yes" />', errors: [errorMessage('aria-hidden')] },
+    { code: '<div aria-hidden="no" />', errors: [errorMessage('aria-hidden')] },
+    { code: '<div aria-hidden={1234} />', errors: [errorMessage('aria-hidden')] },
+    {
+      code: '<div aria-hidden={`${abc}`} />',
+      errors: [errorMessage('aria-hidden')],
+    },
+
+    // STRING
+    { code: '<div aria-label />', errors: [errorMessage('aria-label')] },
+    { code: '<div aria-label={true} />', errors: [errorMessage('aria-label')] },
+    { code: '<div aria-label={false} />', errors: [errorMessage('aria-label')] },
+    { code: '<div aria-label={1234} />', errors: [errorMessage('aria-label')] },
+    { code: '<div aria-label={!true} />', errors: [errorMessage('aria-label')] },
+
+    // TRISTATE
+    { code: '<div aria-checked="yes" />', errors: [errorMessage('aria-checked')] },
+    { code: '<div aria-checked="no" />', errors: [errorMessage('aria-checked')] },
+    { code: '<div aria-checked={1234} />', errors: [errorMessage('aria-checked')] },
+    {
+      code: '<div aria-checked={`${abc}`} />',
+      errors: [errorMessage('aria-checked')],
+    },
+
+    // INTEGER
+    { code: '<div aria-level="yes" />', errors: [errorMessage('aria-level')] },
+    { code: '<div aria-level="no" />', errors: [errorMessage('aria-level')] },
+    { code: '<div aria-level={`abc`} />', errors: [errorMessage('aria-level')] },
+    { code: '<div aria-level={true} />', errors: [errorMessage('aria-level')] },
+    { code: '<div aria-level />', errors: [errorMessage('aria-level')] },
+    { code: '<div aria-level={"false"} />', errors: [errorMessage('aria-level')] },
+    { code: '<div aria-level={!"false"} />', errors: [errorMessage('aria-level')] },
+
+    // NUMBER
+    { code: '<div aria-valuemax="yes" />', errors: [errorMessage('aria-valuemax')] },
+    { code: '<div aria-valuemax="no" />', errors: [errorMessage('aria-valuemax')] },
+    {
+      code: '<div aria-valuemax={`abc`} />',
+      errors: [errorMessage('aria-valuemax')],
+    },
+    {
+      code: '<div aria-valuemax={true} />',
+      errors: [errorMessage('aria-valuemax')],
+    },
+    { code: '<div aria-valuemax />', errors: [errorMessage('aria-valuemax')] },
+    {
+      code: '<div aria-valuemax={"false"} />',
+      errors: [errorMessage('aria-valuemax')],
+    },
+    {
+      code: '<div aria-valuemax={!"false"} />',
+      errors: [errorMessage('aria-valuemax')],
+    },
+
+    // TOKEN
+    { code: '<div aria-sort="" />', errors: [errorMessage('aria-sort')] },
+    { code: '<div aria-sort="descnding" />', errors: [errorMessage('aria-sort')] },
+    { code: '<div aria-sort />', errors: [errorMessage('aria-sort')] },
+    { code: '<div aria-sort={true} />', errors: [errorMessage('aria-sort')] },
+    { code: '<div aria-sort={"false"} />', errors: [errorMessage('aria-sort')] },
+    {
+      code: '<div aria-sort="ascending descending" />',
+      errors: [errorMessage('aria-sort')],
+    },
+
+    // TOKENLIST
+    { code: '<div aria-relevant="" />', errors: [errorMessage('aria-relevant')] },
+    {
+      code: '<div aria-relevant="foobar" />',
+      errors: [errorMessage('aria-relevant')],
+    },
+    { code: '<div aria-relevant />', errors: [errorMessage('aria-relevant')] },
+    {
+      code: '<div aria-relevant={true} />',
+      errors: [errorMessage('aria-relevant')],
+    },
+    {
+      code: '<div aria-relevant={"false"} />',
+      errors: [errorMessage('aria-relevant')],
+    },
+    {
+      code: '<div aria-relevant="additions removalss" />',
+      errors: [errorMessage('aria-relevant')],
+    },
+    {
+      code: '<div aria-relevant="additions removalss " />',
+      errors: [errorMessage('aria-relevant')],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-role-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,118 @@
+/**
+ * @fileoverview Enforce aria role attribute is valid.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { roles } from 'aria-query';
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/aria-role';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = {
+  message: 'Elements with ARIA roles must use a valid, non-abstract ARIA role.',
+  type: 'JSXAttribute',
+};
+
+const roleKeys = roles.keys();
+
+const validRoles = roleKeys.filter((role) => roles.get(role).abstract === false);
+const invalidRoles = roleKeys.filter((role) => roles.get(role).abstract === true);
+
+const createTests = (roleNames) => roleNames.map((role) => ({
+  code: `<div role="${role.toLowerCase()}" />`,
+}));
+
+const validTests = createTests(validRoles);
+const invalidTests = createTests(invalidRoles).map((test) => {
+  const invalidTest = { ...test };
+  invalidTest.errors = [errorMessage];
+  return invalidTest;
+});
+
+const allowedInvalidRoles = [{
+  allowedInvalidRoles: ['invalid-role', 'other-invalid-role'],
+}];
+
+const ignoreNonDOMSchema = [{
+  ignoreNonDOM: true,
+}];
+
+const customDivSettings = {
+  'jsx-a11y': {
+    polymorphicPropName: 'asChild',
+    components: {
+      Div: 'div',
+    },
+  },
+};
+
+ruleTester.run('aria-role', rule, {
+  valid: parsers.all([].concat(
+    // Variables should pass, as we are only testing literals.
+    { code: '<div />' },
+    { code: '<div></div>' },
+    { code: '<div role={role} />' },
+    { code: '<div role={role || "button"} />' },
+    { code: '<div role={role || "foobar"} />' },
+    { code: '<div role="tabpanel row" />' },
+    { code: '<div role="switch" />' },
+    { code: '<div role="doc-abstract" />' },
+    { code: '<div role="doc-appendix doc-bibliography" />' },
+    { code: '<Bar baz />' },
+    { code: '<img role="invalid-role" />', options: allowedInvalidRoles },
+    { code: '<img role="invalid-role tabpanel" />', options: allowedInvalidRoles },
+    { code: '<img role="invalid-role other-invalid-role" />', options: allowedInvalidRoles },
+    { code: '<Foo role="bar" />', options: ignoreNonDOMSchema },
+    { code: '<fakeDOM role="bar" />', options: ignoreNonDOMSchema },
+    { code: '<img role="presentation" />', options: ignoreNonDOMSchema },
+    {
+      code: '<Div role="button" />',
+      settings: customDivSettings,
+    },
+    {
+      code: '<Box asChild="div" role="button" />',
+      settings: customDivSettings,
+    },
+    { code: '<svg role="graphics-document document" />' },
+    { code: '<svg role="img" />' },
+  )).concat(validTests).map(parserOptionsMapper),
+
+  invalid: parsers.all([].concat(
+    { code: '<div role="foobar" />', errors: [errorMessage] },
+    { code: '<div role="datepicker"></div>', errors: [errorMessage] },
+    { code: '<div role="range"></div>', errors: [errorMessage] },
+    { code: '<div role="Button"></div>', errors: [errorMessage] },
+    { code: '<div role=""></div>', errors: [errorMessage] },
+    { code: '<div role="tabpanel row foobar"></div>', errors: [errorMessage] },
+    { code: '<div role="tabpanel row range"></div>', errors: [errorMessage] },
+    { code: '<div role="doc-endnotes range"></div>', errors: [errorMessage] },
+    { code: '<div role />', errors: [errorMessage] },
+    { code: '<div role="unknown-invalid-role" />', errors: [errorMessage], options: allowedInvalidRoles },
+    { code: '<div role={null}></div>', errors: [errorMessage] },
+    { code: '<Foo role="datepicker" />', errors: [errorMessage] },
+    { code: '<Foo role="Button" />', errors: [errorMessage] },
+    { code: '<Div role="Button" />', errors: [errorMessage], settings: customDivSettings },
+    {
+      code: '<Div role="Button" />',
+      errors: [errorMessage],
+      options: ignoreNonDOMSchema,
+      settings: customDivSettings,
+    },
+    {
+      code: '<Box asChild="div" role="Button" />',
+      settings: customDivSettings,
+      errors: [errorMessage],
+    },
+  )).concat(invalidTests).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-unsupported-elements-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-unsupported-elements-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/aria-unsupported-elements-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,75 @@
+/**
+ * @fileoverview Enforce that elements that do not support ARIA roles,
+ *  states and properties do not have those attributes.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { dom } from 'aria-query';
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/aria-unsupported-elements';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = (invalidProp) => ({
+  message: `This element does not support ARIA roles, states and properties. \
+Try removing the prop '${invalidProp}'.`,
+  type: 'JSXOpeningElement',
+});
+
+const domElements = dom.keys();
+// Generate valid test cases
+const roleValidityTests = domElements.map((element) => {
+  const isReserved = dom.get(element).reserved || false;
+  const role = isReserved ? '' : 'role';
+
+  return {
+    code: `<${element} ${role} />`,
+  };
+});
+
+const ariaValidityTests = domElements.map((element) => {
+  const isReserved = dom.get(element).reserved || false;
+  const aria = isReserved ? '' : 'aria-hidden';
+
+  return {
+    code: `<${element} ${aria} />`,
+  };
+}).concat({
+  code: '<fake aria-hidden />',
+  errors: [errorMessage('aria-hidden')],
+});
+
+// Generate invalid test cases.
+const invalidRoleValidityTests = domElements
+  .filter((element) => dom.get(element).reserved)
+  .map((reservedElem) => ({
+    code: `<${reservedElem} role {...props} />`,
+    errors: [errorMessage('role')],
+  })).concat({
+    code: '<Meta aria-hidden />',
+    errors: [errorMessage('aria-hidden')],
+    settings: { 'jsx-a11y': { components: { Meta: 'meta' } } },
+  });
+
+const invalidAriaValidityTests = domElements
+  .filter((element) => dom.get(element).reserved)
+  .map((reservedElem) => ({
+    code: `<${reservedElem} aria-hidden aria-role="none" {...props} />`,
+    errors: [errorMessage('aria-hidden')],
+  }));
+
+ruleTester.run('aria-unsupported-elements', rule, {
+  valid: parsers.all([].concat(roleValidityTests, ariaValidityTests)).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(invalidRoleValidityTests, invalidAriaValidityTests))
+    .map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/autocomplete-valid-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/autocomplete-valid-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/autocomplete-valid-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,77 @@
+/**
+ * @fileoverview Ensure autocomplete attribute is correct.
+ * @author Wilco Fiers
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import { axeFailMessage } from '../../__util__/axeMapping';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/autocomplete-valid';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const invalidAutocomplete = [{
+  message: axeFailMessage('autocomplete-valid'),
+  type: 'JSXOpeningElement',
+}];
+
+const inappropriateAutocomplete = [{
+  message: axeFailMessage('autocomplete-appropriate'),
+  type: 'JSXOpeningElement',
+}];
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Input: 'input',
+    },
+  },
+};
+
+ruleTester.run('autocomplete-valid', rule, {
+  valid: parsers.all([].concat(
+    // INAPPLICABLE
+    { code: '<input type="text" />;' },
+    // // PASSED AUTOCOMPLETE
+    { code: '<input type="text" autocomplete="name" />;' },
+    { code: '<input type="text" autocomplete="" />;' },
+    { code: '<input type="text" autocomplete="off" />;' },
+    { code: '<input type="text" autocomplete="on" />;' },
+    { code: '<input type="text" autocomplete="billing family-name" />;' },
+    { code: '<input type="text" autocomplete="section-blue shipping street-address" />;' },
+    { code: '<input type="text" autocomplete="section-somewhere shipping work email" />;' },
+    { code: '<input type="text" autocomplete />;' },
+    { code: '<input type="text" autocomplete={autocompl} />;' },
+    { code: '<input type="text" autocomplete={autocompl || "name"} />;' },
+    { code: '<input type="text" autocomplete={autocompl || "foo"} />;' },
+    { code: '<Foo autocomplete="bar"></Foo>;' },
+    { code: '<input type={isEmail ? "email" : "text"} autocomplete="none" />;' },
+    { code: '<Input type="text" autocomplete="name" />', settings: componentsSettings },
+    { code: '<Input type="text" autocomplete="baz" />' },
+
+    // PASSED "autocomplete-appropriate"
+    // see also: https://github.com/dequelabs/axe-core/issues/2912
+    { code: '<input type="date" autocomplete="email" />;', errors: inappropriateAutocomplete },
+    { code: '<input type="number" autocomplete="url" />;', errors: inappropriateAutocomplete },
+    { code: '<input type="month" autocomplete="tel" />;', errors: inappropriateAutocomplete },
+    { code: '<Foo type="month" autocomplete="tel"></Foo>;', errors: inappropriateAutocomplete, options: [{ inputComponents: ['Foo'] }] },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    // FAILED "autocomplete-valid"
+    { code: '<input type="text" autocomplete="foo" />;', errors: invalidAutocomplete },
+    { code: '<input type="text" autocomplete="name invalid" />;', errors: invalidAutocomplete },
+    { code: '<input type="text" autocomplete="invalid name" />;', errors: invalidAutocomplete },
+    { code: '<input type="text" autocomplete="home url" />;', errors: invalidAutocomplete },
+    { code: '<Bar autocomplete="baz"></Bar>;', errors: invalidAutocomplete, options: [{ inputComponents: ['Bar'] }] },
+    { code: '<Input type="text" autocomplete="baz" />', errors: invalidAutocomplete, settings: componentsSettings },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/click-events-have-key-events-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/click-events-have-key-events-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/click-events-have-key-events-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,77 @@
+/**
+ * @fileoverview Enforce a clickable non-interactive element has at least 1 keyboard event listener.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/click-events-have-key-events';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = 'Visible, non-interactive elements with click handlers must have at least one keyboard listener.';
+
+const expectedError = {
+  message: errorMessage,
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('click-events-have-key-events', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div onClick={() => void 0} onKeyDown={foo}/>;' },
+    { code: '<div onClick={() => void 0} onKeyUp={foo} />;' },
+    { code: '<div onClick={() => void 0} onKeyPress={foo}/>;' },
+    { code: '<div onClick={() => void 0} onKeyDown={foo} onKeyUp={bar} />;' },
+    { code: '<div onClick={() => void 0} onKeyDown={foo} {...props} />;' },
+    { code: '<div className="foo" />;' },
+    { code: '<div onClick={() => void 0} aria-hidden />;' },
+    { code: '<div onClick={() => void 0} aria-hidden={true} />;' },
+    { code: '<div onClick={() => void 0} aria-hidden={false} onKeyDown={foo} />;' },
+    {
+      code: '<div onClick={() => void 0} onKeyDown={foo} aria-hidden={undefined} />;',
+    },
+    { code: '<input type="text" onClick={() => void 0} />' },
+    { code: '<input onClick={() => void 0} />' },
+    { code: '<button onClick={() => void 0} className="foo" />' },
+    { code: '<option onClick={() => void 0} className="foo" />' },
+    { code: '<select onClick={() => void 0} className="foo" />' },
+    { code: '<textarea onClick={() => void 0} className="foo" />' },
+    { code: '<a onClick={() => void 0} href="http://x.y.z" />' },
+    { code: '<a onClick={() => void 0} href="http://x.y.z" tabIndex="0" />' },
+    { code: '<input onClick={() => void 0} type="hidden" />;' },
+    { code: '<div onClick={() => void 0} role="presentation" />;' },
+    { code: '<div onClick={() => void 0} role="none" />;' },
+    { code: '<TestComponent onClick={doFoo} />' },
+    { code: '<Button onClick={doFoo} />' },
+    { code: '<Footer onClick={doFoo} />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<div onClick={() => void 0} />;', errors: [expectedError] },
+    {
+      code: '<div onClick={() => void 0} role={undefined} />;',
+      errors: [expectedError],
+    },
+    { code: '<div onClick={() => void 0} {...props} />;', errors: [expectedError] },
+    { code: '<section onClick={() => void 0} />;', errors: [expectedError] },
+    { code: '<main onClick={() => void 0} />;', errors: [expectedError] },
+    { code: '<article onClick={() => void 0} />;', errors: [expectedError] },
+    { code: '<header onClick={() => void 0} />;', errors: [expectedError] },
+    { code: '<footer onClick={() => void 0} />;', errors: [expectedError] },
+    {
+      code: '<div onClick={() => void 0} aria-hidden={false} />;',
+      errors: [expectedError],
+    },
+    { code: '<a onClick={() => void 0} />', errors: [expectedError] },
+    { code: '<a tabIndex="0" onClick={() => void 0} />', errors: [expectedError] },
+    { code: '<Footer onClick={doFoo} />', errors: [expectedError], settings: { 'jsx-a11y': { components: { Footer: 'footer' } } } },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/control-has-associated-label-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/control-has-associated-label-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/control-has-associated-label-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,327 @@
+/**
+ * @fileoverview Control elements must be associated with a text label
+ * @author jessebeach
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import { configs } from '../../../src/index';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+import rule from '../../../src/rules/control-has-associated-label';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const ruleName = 'jsx-a11y/control-has-associated-label';
+
+const expectedError = {
+  message: 'A control must be associated with a text label.',
+  type: 'JSXOpeningElement',
+};
+
+const alwaysValid = [
+  // Custom Control Components
+  { code: '<CustomControl><span><span>Save</span></span></CustomControl>', options: [{ depth: 3, controlComponents: ['CustomControl'] }] },
+  { code: '<CustomControl><span><span label="Save"></span></span></CustomControl>', options: [{ depth: 3, controlComponents: ['CustomControl'], labelAttributes: ['label'] }] },
+  { code: '<CustomControl>Save</CustomControl>', settings: { 'jsx-a11y': { components: { CustomControl: 'button' } } } },
+  // Interactive Elements
+  { code: '<button>Save</button>' },
+  { code: '<button><span>Save</span></button>' },
+  { code: '<button><span><span>Save</span></span></button>', options: [{ depth: 3 }] },
+  { code: '<button><span><span><span><span><span><span><span><span>Save</span></span></span></span></span></span></span></span></button>', options: [{ depth: 9 }] },
+  { code: '<button><img alt="Save" /></button>' },
+  { code: '<button aria-label="Save" />' },
+  { code: '<button><span aria-label="Save" /></button>' },
+  { code: '<button aria-labelledby="js_1" />' },
+  { code: '<button><span aria-labelledby="js_1" /></button>' },
+  { code: '<button>{sureWhyNot}</button>' },
+  { code: '<button><span><span label="Save"></span></span></button>', options: [{ depth: 3, labelAttributes: ['label'] }] },
+  { code: '<a href="#">Save</a>' },
+  { code: '<area href="#">Save</area>' },
+  { code: '<link>Save</link>' },
+  { code: '<menuitem>Save</menuitem>' },
+  { code: '<option>Save</option>' },
+  { code: '<th>Save</th>' },
+  // Interactive Roles
+  { code: '<div role="button">Save</div>' },
+  { code: '<div role="checkbox">Save</div>' },
+  { code: '<div role="columnheader">Save</div>' },
+  { code: '<div role="combobox">Save</div>' },
+  { code: '<div role="gridcell">Save</div>' },
+  { code: '<div role="link">Save</div>' },
+  { code: '<div role="menuitem">Save</div>' },
+  { code: '<div role="menuitemcheckbox">Save</div>' },
+  { code: '<div role="menuitemradio">Save</div>' },
+  { code: '<div role="option">Save</div>' },
+  { code: '<div role="progressbar">Save</div>' },
+  { code: '<div role="radio">Save</div>' },
+  { code: '<div role="rowheader">Save</div>' },
+  { code: '<div role="searchbox">Save</div>' },
+  { code: '<div role="slider">Save</div>' },
+  { code: '<div role="spinbutton">Save</div>' },
+  { code: '<div role="switch">Save</div>' },
+  { code: '<div role="tab">Save</div>' },
+  { code: '<div role="textbox">Save</div>' },
+  { code: '<div role="treeitem">Save</div>' },
+  { code: '<div role="button" aria-label="Save" />' },
+  { code: '<div role="checkbox" aria-label="Save" />' },
+  { code: '<div role="columnheader" aria-label="Save" />' },
+  { code: '<div role="combobox" aria-label="Save" />' },
+  { code: '<div role="gridcell" aria-label="Save" />' },
+  { code: '<div role="link" aria-label="Save" />' },
+  { code: '<div role="menuitem" aria-label="Save" />' },
+  { code: '<div role="menuitemcheckbox" aria-label="Save" />' },
+  { code: '<div role="menuitemradio" aria-label="Save" />' },
+  { code: '<div role="option" aria-label="Save" />' },
+  { code: '<div role="progressbar" aria-label="Save" />' },
+  { code: '<div role="radio" aria-label="Save" />' },
+  { code: '<div role="rowheader" aria-label="Save" />' },
+  { code: '<div role="searchbox" aria-label="Save" />' },
+  { code: '<div role="slider" aria-label="Save" />' },
+  { code: '<div role="spinbutton" aria-label="Save" />' },
+  { code: '<div role="switch" aria-label="Save" />' },
+  { code: '<div role="tab" aria-label="Save" />' },
+  { code: '<div role="textbox" aria-label="Save" />' },
+  { code: '<div role="treeitem" aria-label="Save" />' },
+  { code: '<div role="button" aria-labelledby="js_1" />' },
+  { code: '<div role="checkbox" aria-labelledby="js_1" />' },
+  { code: '<div role="columnheader" aria-labelledby="js_1" />' },
+  { code: '<div role="combobox" aria-labelledby="js_1" />' },
+  { code: '<div role="gridcell" aria-labelledby="Save" />' },
+  { code: '<div role="link" aria-labelledby="js_1" />' },
+  { code: '<div role="menuitem" aria-labelledby="js_1" />' },
+  { code: '<div role="menuitemcheckbox" aria-labelledby="js_1" />' },
+  { code: '<div role="menuitemradio" aria-labelledby="js_1" />' },
+  { code: '<div role="option" aria-labelledby="js_1" />' },
+  { code: '<div role="progressbar" aria-labelledby="js_1" />' },
+  { code: '<div role="radio" aria-labelledby="js_1" />' },
+  { code: '<div role="rowheader" aria-labelledby="js_1" />' },
+  { code: '<div role="searchbox" aria-labelledby="js_1" />' },
+  { code: '<div role="slider" aria-labelledby="js_1" />' },
+  { code: '<div role="spinbutton" aria-labelledby="js_1" />' },
+  { code: '<div role="switch" aria-labelledby="js_1" />' },
+  { code: '<div role="tab" aria-labelledby="js_1" />' },
+  { code: '<div role="textbox" aria-labelledby="js_1" />' },
+  { code: '<div role="treeitem" aria-labelledby="js_1" />' },
+  // Non-interactive Elements
+  { code: '<abbr />' },
+  { code: '<article />' },
+  { code: '<blockquote />' },
+  { code: '<br />' },
+  { code: '<caption />' },
+  { code: '<dd />' },
+  { code: '<details />' },
+  { code: '<dfn />' },
+  { code: '<dialog />' },
+  { code: '<dir />' },
+  { code: '<dl />' },
+  { code: '<dt />' },
+  { code: '<fieldset />' },
+  { code: '<figcaption />' },
+  { code: '<figure />' },
+  { code: '<footer />' },
+  { code: '<form />' },
+  { code: '<frame />' },
+  { code: '<h1 />' },
+  { code: '<h2 />' },
+  { code: '<h3 />' },
+  { code: '<h4 />' },
+  { code: '<h5 />' },
+  { code: '<h6 />' },
+  { code: '<hr />' },
+  { code: '<iframe />' },
+  { code: '<img />' },
+  { code: '<label />' },
+  { code: '<legend />' },
+  { code: '<li />' },
+  { code: '<link />' },
+  { code: '<main />' },
+  { code: '<mark />' },
+  { code: '<marquee />' },
+  { code: '<menu />' },
+  { code: '<meter />' },
+  { code: '<nav />' },
+  { code: '<ol />' },
+  { code: '<p />' },
+  { code: '<pre />' },
+  { code: '<progress />' },
+  { code: '<ruby />' },
+  { code: '<section />' },
+  { code: '<table />' },
+  { code: '<tbody />' },
+  { code: '<tfoot />' },
+  { code: '<thead />' },
+  { code: '<time />' },
+  { code: '<ul />' },
+  // Non-interactive Roles
+  { code: '<div role="alert" />' },
+  { code: '<div role="alertdialog" />' },
+  { code: '<div role="application" />' },
+  { code: '<div role="article" />' },
+  { code: '<div role="banner" />' },
+  { code: '<div role="cell" />' },
+  { code: '<div role="complementary" />' },
+  { code: '<div role="contentinfo" />' },
+  { code: '<div role="definition" />' },
+  { code: '<div role="dialog" />' },
+  { code: '<div role="directory" />' },
+  { code: '<div role="document" />' },
+  { code: '<div role="feed" />' },
+  { code: '<div role="figure" />' },
+  { code: '<div role="form" />' },
+  { code: '<div role="group" />' },
+  { code: '<div role="heading" />' },
+  { code: '<div role="img" />' },
+  { code: '<div role="list" />' },
+  { code: '<div role="listitem" />' },
+  { code: '<div role="log" />' },
+  { code: '<div role="main" />' },
+  { code: '<div role="marquee" />' },
+  { code: '<div role="math" />' },
+  { code: '<div role="navigation" />' },
+  { code: '<div role="none" />' },
+  { code: '<div role="note" />' },
+  { code: '<div role="presentation" />' },
+  { code: '<div role="region" />' },
+  { code: '<div role="rowgroup" />' },
+  { code: '<div role="search" />' },
+  { code: '<div role="separator" />' },
+  { code: '<div role="status" />' },
+  { code: '<div role="table" />' },
+  { code: '<div role="tabpanel" />' },
+  { code: '<div role="term" />' },
+  { code: '<div role="timer" />' },
+  { code: '<div role="tooltip" />' },
+  // Via config
+  // Inputs. Ignore them because they might get a label from a wrapping label element.
+  { code: '<input />' },
+  { code: '<input type="button" />' },
+  { code: '<input type="checkbox" />' },
+  { code: '<input type="color" />' },
+  { code: '<input type="date" />' },
+  { code: '<input type="datetime" />' },
+  { code: '<input type="email" />' },
+  { code: '<input type="file" />' },
+  { code: '<input type="hidden" />' },
+  { code: '<input type="hidden" name="bot-field"/>' },
+  { code: '<input type="hidden" name="form-name" value="Contact Form"/>' },
+  { code: '<input type="image" />' },
+  { code: '<input type="month" />' },
+  { code: '<input type="number" />' },
+  { code: '<input type="password" />' },
+  { code: '<input type="radio" />' },
+  { code: '<input type="range" />' },
+  { code: '<input type="reset" />' },
+  { code: '<input type="search" />' },
+  { code: '<input type="submit" />' },
+  { code: '<input type="tel" />' },
+  { code: '<input type="text" />' },
+  { code: '<label>Foo <input type="text" /></label>' },
+  { code: '<input name={field.name} id="foo" type="text" value={field.value} disabled={isDisabled} onChange={changeText(field.onChange, field.name)} onBlur={field.onBlur} />' },
+  { code: '<input type="time" />' },
+  { code: '<input type="url" />' },
+  { code: '<input type="week" />' },
+  // Marginal interactive elements. It is difficult to insist that these
+  // elements contain a text label.
+  { code: '<audio />' },
+  { code: '<canvas />' },
+  { code: '<embed />' },
+  { code: '<textarea />' },
+  { code: '<tr />' },
+  { code: '<video />' },
+  // Interactive roles to ignore
+  { code: '<div role="grid" />' },
+  { code: '<div role="listbox" />' },
+  { code: '<div role="menu" />' },
+  { code: '<div role="menubar" />' },
+  { code: '<div role="radiogroup" />' },
+  { code: '<div role="row" />' },
+  { code: '<div role="tablist" />' },
+  { code: '<div role="toolbar" />' },
+  { code: '<div role="tree" />' },
+  { code: '<div role="treegrid" />' },
+];
+const neverValid = [
+  { code: '<button />', errors: [expectedError] },
+  { code: '<button><span /></button>', errors: [expectedError] },
+  { code: '<button><img /></button>', errors: [expectedError] },
+  { code: '<button><span title="This is not a real label" /></button>', errors: [expectedError] },
+  { code: '<button><span><span><span>Save</span></span></span></button>', options: [{ depth: 3 }], errors: [expectedError] },
+  { code: '<CustomControl><span><span></span></span></CustomControl>', options: [{ depth: 3, controlComponents: ['CustomControl'] }], errors: [expectedError] },
+  { code: '<CustomControl></CustomControl>', errors: [expectedError], settings: { 'jsx-a11y': { components: { CustomControl: 'button' } } } },
+  { code: '<a href="#" />', errors: [expectedError] },
+  { code: '<area href="#" />', errors: [expectedError] },
+  { code: '<menuitem />', errors: [expectedError] },
+  { code: '<option />', errors: [expectedError] },
+  { code: '<th />', errors: [expectedError] },
+  { code: '<td />', errors: [expectedError] },
+  // Interactive Roles
+  { code: '<div role="button" />', errors: [expectedError] },
+  { code: '<div role="checkbox" />', errors: [expectedError] },
+  { code: '<div role="columnheader" />', errors: [expectedError] },
+  { code: '<div role="combobox" />', errors: [expectedError] },
+  { code: '<div role="link" />', errors: [expectedError] },
+  { code: '<div role="gridcell" />', errors: [expectedError] },
+  { code: '<div role="menuitem" />', errors: [expectedError] },
+  { code: '<div role="menuitemcheckbox" />', errors: [expectedError] },
+  { code: '<div role="menuitemradio" />', errors: [expectedError] },
+  { code: '<div role="option" />', errors: [expectedError] },
+  { code: '<div role="progressbar" />', errors: [expectedError] },
+  { code: '<div role="radio" />', errors: [expectedError] },
+  { code: '<div role="rowheader" />', errors: [expectedError] },
+  { code: '<div role="scrollbar" />', errors: [expectedError] },
+  { code: '<div role="searchbox" />', errors: [expectedError] },
+  { code: '<div role="slider" />', errors: [expectedError] },
+  { code: '<div role="spinbutton" />', errors: [expectedError] },
+  { code: '<div role="switch" />', errors: [expectedError] },
+  { code: '<div role="tab" />', errors: [expectedError] },
+  { code: '<div role="textbox" />', errors: [expectedError] },
+];
+
+const recommendedOptions = (configs.recommended.rules[ruleName][1] || {});
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+});
+
+const strictOptions = (configs.strict.rules[ruleName][1] || {});
+ruleTester.run(`${ruleName}:strict`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+  ))
+    .map(ruleOptionsMapperFactory(strictOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  ))
+    .map(ruleOptionsMapperFactory(strictOptions))
+    .map(parserOptionsMapper),
+});
+
+ruleTester.run(`${ruleName}:no-config`, rule, {
+  valid: parsers.all([].concat(
+    { code: '<input type="hidden" />' },
+    { code: '<input type="text" aria-hidden="true" />' },
+  ))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<input type="text" />', errors: [expectedError] },
+  ))
+    .map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/heading-has-content-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/heading-has-content-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/heading-has-content-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,85 @@
+/**
+ * @fileoverview Enforce heading (h1, h2, etc) elements contain accessible content.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/heading-has-content';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'Headings must have content and the content must be accessible by a screen reader.',
+  type: 'JSXOpeningElement',
+};
+
+const components = [{
+  components: ['Heading', 'Title'],
+}];
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      CustomInput: 'input',
+      Title: 'h1',
+      Heading: 'h2',
+    },
+  },
+};
+
+ruleTester.run('heading-has-content', rule, {
+  valid: parsers.all([].concat(
+    // DEFAULT ELEMENT TESTS
+    { code: '<div />;' },
+    { code: '<h1>Foo</h1>' },
+    { code: '<h2>Foo</h2>' },
+    { code: '<h3>Foo</h3>' },
+    { code: '<h4>Foo</h4>' },
+    { code: '<h5>Foo</h5>' },
+    { code: '<h6>Foo</h6>' },
+    { code: '<h6>123</h6>' },
+    { code: '<h1><Bar /></h1>' },
+    { code: '<h1>{foo}</h1>' },
+    { code: '<h1>{foo.bar}</h1>' },
+    { code: '<h1 dangerouslySetInnerHTML={{ __html: "foo" }} />' },
+    { code: '<h1 children={children} />' },
+    // CUSTOM ELEMENT TESTS FOR COMPONENTS OPTION
+    { code: '<Heading>Foo</Heading>', options: components },
+    { code: '<Title>Foo</Title>', options: components },
+    { code: '<Heading><Bar /></Heading>', options: components },
+    { code: '<Heading>{foo}</Heading>', options: components },
+    { code: '<Heading>{foo.bar}</Heading>', options: components },
+    { code: '<Heading dangerouslySetInnerHTML={{ __html: "foo" }} />', options: components },
+    { code: '<Heading children={children} />', options: components },
+    { code: '<h1 aria-hidden />' },
+    // CUSTOM ELEMENT TESTS FOR COMPONENTS SETTINGS
+    { code: '<Heading>Foo</Heading>', settings: componentsSettings },
+    { code: '<h1><CustomInput type="hidden" /></h1>' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    // DEFAULT ELEMENT TESTS
+    { code: '<h1 />', errors: [expectedError] },
+    { code: '<h1><Bar aria-hidden /></h1>', errors: [expectedError] },
+    { code: '<h1>{undefined}</h1>', errors: [expectedError] },
+    { code: '<h1><input type="hidden" /></h1>', errors: [expectedError] },
+
+    // CUSTOM ELEMENT TESTS FOR COMPONENTS OPTION
+    { code: '<Heading />', errors: [expectedError], options: components },
+    { code: '<Heading><Bar aria-hidden /></Heading>', errors: [expectedError], options: components },
+    { code: '<Heading>{undefined}</Heading>', errors: [expectedError], options: components },
+
+    // CUSTOM ELEMENT TESTS FOR COMPONENTS SETTINGS
+    { code: '<Heading />', errors: [expectedError], settings: componentsSettings },
+    { code: '<h1><CustomInput type="hidden" /></h1>', errors: [expectedError], settings: componentsSettings },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/html-has-lang-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/html-has-lang-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/html-has-lang-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,42 @@
+/**
+ * @fileoverview Enforce html element has lang prop.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/html-has-lang';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: '<html> elements must have the lang prop.',
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('html-has-lang', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<html lang="en" />' },
+    { code: '<html lang="en-US" />' },
+    { code: '<html lang={foo} />' },
+    { code: '<html lang />' },
+    { code: '<HTML />' },
+    { code: '<HTMLTop lang="en" />', errors: [expectedError], settings: { 'jsx-a11y': { components: { HTMLTop: 'html' } } } },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<html />', errors: [expectedError] },
+    { code: '<html {...props} />', errors: [expectedError] },
+    { code: '<html lang={undefined} />', errors: [expectedError] },
+    { code: '<HTMLTop />', errors: [expectedError], settings: { 'jsx-a11y': { components: { HTMLTop: 'html' } } } },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/iframe-has-title-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/iframe-has-title-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/iframe-has-title-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,55 @@
+/**
+ * @fileoverview Enforce iframe elements have a title attribute.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/iframe-has-title';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: '<iframe> elements must have a unique title property.',
+  type: 'JSXOpeningElement',
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      FooComponent: 'iframe',
+    },
+  },
+};
+
+ruleTester.run('html-has-lang', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<iframe title="Unique title" />' },
+    { code: '<iframe title={foo} />' },
+    { code: '<FooComponent />' },
+    { code: '<FooComponent title="Unique title" />', settings: componentsSettings },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<iframe />', errors: [expectedError] },
+    { code: '<iframe {...props} />', errors: [expectedError] },
+    { code: '<iframe title={undefined} />', errors: [expectedError] },
+    { code: '<iframe title="" />', errors: [expectedError] },
+    { code: '<iframe title={false} />', errors: [expectedError] },
+    { code: '<iframe title={true} />', errors: [expectedError] },
+    { code: "<iframe title={''} />", errors: [expectedError] },
+    { code: '<iframe title={``} />', errors: [expectedError] },
+    { code: '<iframe title={""} />', errors: [expectedError] },
+    { code: '<iframe title={42} />', errors: [expectedError] },
+    { code: '<FooComponent />', errors: [expectedError], settings: componentsSettings },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/img-redundant-alt-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/img-redundant-alt-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/img-redundant-alt-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,137 @@
+/**
+ * @fileoverview Enforce img alt attribute does not have the word image, picture, or photo.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import semver from 'semver';
+import { version as eslintVersion } from 'eslint/package.json';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/img-redundant-alt';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const array = [{
+  components: ['Image'],
+  words: ['Word1', 'Word2'],
+}];
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Image: 'img',
+    },
+  },
+};
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'Redundant alt attribute. Screen-readers already announce `img` tags as an image. You don’t need to use the words `image`, `photo,` or `picture` (or any specified custom words) in the alt prop.',
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('img-redundant-alt', rule, {
+  valid: parsers.all([].concat(
+    { code: '<img alt="foo" />;' },
+    { code: '<img alt="picture of me taking a photo of an image" aria-hidden />' },
+    { code: '<img aria-hidden alt="photo of image" />' },
+    { code: '<img ALt="foo" />;' },
+    { code: '<img {...this.props} alt="foo" />' },
+    { code: '<img {...this.props} alt={"foo"} />' },
+    { code: '<img {...this.props} alt={alt} />' },
+    { code: '<a />' },
+    { code: '<img />' },
+    { code: '<IMG />' },
+    { code: '<img alt={undefined} />' },
+    { code: '<img alt={`this should pass for ${now}`} />' },
+    { code: '<img alt={`this should pass for ${photo}`} />' },
+    { code: '<img alt={`this should pass for ${image}`} />' },
+    { code: '<img alt={`this should pass for ${picture}`} />' },
+    { code: '<img alt={`${photo}`} />' },
+    { code: '<img alt={`${image}`} />' },
+    { code: '<img alt={`${picture}`} />' },
+    { code: '<img alt={"undefined"} />' },
+    { code: '<img alt={() => {}} />' },
+    { code: '<img alt={function(e){}} />' },
+    { code: '<img aria-hidden={false} alt="Doing cool things." />' },
+    { code: '<UX.Layout>test</UX.Layout>' },
+    { code: '<img alt />' },
+    { code: '<img alt={imageAlt} />' },
+    { code: '<img alt={imageAlt.name} />' },
+    semver.satisfies(eslintVersion, '>= 6') ? [
+      { code: '<img alt={imageAlt?.name} />', languageOptions: { ecmaVersion: 2020 } },
+      { code: '<img alt="Doing cool things" aria-hidden={foo?.bar}/>', languageOptions: { ecmaVersion: 2020 } },
+    ] : [],
+    { code: '<img alt="Photography" />;' },
+    { code: '<img alt="ImageMagick" />;' },
+    { code: '<Image alt="Photo of a friend" />' },
+    { code: '<Image alt="Foo" />', settings: componentsSettings },
+    { code: '<img alt="画像" />', options: [{ words: ['イメージ'] }] },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<img alt="Photo of friend." />;', errors: [expectedError] },
+    { code: '<img alt="Picture of friend." />;', errors: [expectedError] },
+    { code: '<img alt="Image of friend." />;', errors: [expectedError] },
+    { code: '<img alt="PhOtO of friend." />;', errors: [expectedError] },
+    { code: '<img alt={"photo"} />;', errors: [expectedError] },
+    { code: '<img alt="piCTUre of friend." />;', errors: [expectedError] },
+    { code: '<img alt="imAGE of friend." />;', errors: [expectedError] },
+    {
+      code: '<img alt="photo of cool person" aria-hidden={false} />',
+      errors: [expectedError],
+    },
+    {
+      code: '<img alt="picture of cool person" aria-hidden={false} />',
+      errors: [expectedError],
+    },
+    {
+      code: '<img alt="image of cool person" aria-hidden={false} />',
+      errors: [expectedError],
+    },
+    { code: '<img alt="photo" {...this.props} />', errors: [expectedError] },
+    { code: '<img alt="image" {...this.props} />', errors: [expectedError] },
+    { code: '<img alt="picture" {...this.props} />', errors: [expectedError] },
+    {
+      code: '<img alt={`picture doing ${things}`} {...this.props} />',
+      errors: [expectedError],
+    },
+    {
+      code: '<img alt={`photo doing ${things}`} {...this.props} />',
+      errors: [expectedError],
+    },
+    {
+      code: '<img alt={`image doing ${things}`} {...this.props} />',
+      errors: [expectedError],
+    },
+    {
+      code: '<img alt={`picture doing ${picture}`} {...this.props} />',
+      errors: [expectedError],
+    },
+    {
+      code: '<img alt={`photo doing ${photo}`} {...this.props} />',
+      errors: [expectedError],
+    },
+    {
+      code: '<img alt={`image doing ${image}`} {...this.props} />',
+      errors: [expectedError],
+    },
+    { code: '<Image alt="Photo of a friend" />', errors: [expectedError], settings: componentsSettings },
+
+    // TESTS FOR ARRAY OPTION TESTS
+    { code: '<img alt="Word1" />;', options: array, errors: [expectedError] },
+    { code: '<img alt="Word2" />;', options: array, errors: [expectedError] },
+    { code: '<Image alt="Word1" />;', options: array, errors: [expectedError] },
+    { code: '<Image alt="Word2" />;', options: array, errors: [expectedError] },
+
+    { code: '<img alt="イメージ" />', options: [{ words: ['イメージ'] }], errors: [expectedError] },
+    { code: '<img alt="イメージです" />', options: [{ words: ['イメージ'] }], errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/interactive-supports-focus-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/interactive-supports-focus-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/interactive-supports-focus-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,267 @@
+/**
+ * @fileoverview Enforce that elements with onClick handlers must be focusable.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import includes from 'array-includes';
+import { RuleTester } from 'eslint';
+import {
+  eventHandlers,
+  eventHandlersByType,
+} from 'jsx-ast-utils';
+import { configs } from '../../../src/index';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/interactive-supports-focus';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+function template(strings, ...keys) {
+  return (...values) => keys.reduce(
+    (acc, k, i) => acc + (values[k] || '') + strings[i + 1],
+    strings[0],
+  );
+}
+
+const ruleName = 'interactive-supports-focus';
+const type = 'JSXOpeningElement';
+const codeTemplate = template`<${0} role="${1}" ${2}={() => void 0} />`;
+const tabindexTemplate = template`<${0} role="${1}" ${2}={() => void 0} tabIndex="0" />`;
+const tabbableTemplate = template`Elements with the '${0}' interactive role must be tabbable.`;
+const focusableTemplate = template`Elements with the '${0}' interactive role must be focusable.`;
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Div: 'div',
+    },
+  },
+};
+
+const buttonError = { message: tabbableTemplate('button'), type };
+
+const recommendedOptions = configs.recommended.rules[`jsx-a11y/${ruleName}`][1] || {};
+
+const strictOptions = configs.strict.rules[`jsx-a11y/${ruleName}`][1] || {};
+
+const alwaysValid = [
+  { code: '<div />' },
+  { code: '<div aria-hidden onClick={() => void 0} />' },
+  { code: '<div aria-hidden={true == true} onClick={() => void 0} />' },
+  { code: '<div aria-hidden={true === true} onClick={() => void 0} />' },
+  { code: '<div aria-hidden={hidden !== false} onClick={() => void 0} />' },
+  { code: '<div aria-hidden={hidden != false} onClick={() => void 0} />' },
+  { code: '<div aria-hidden={1 < 2} onClick={() => void 0} />' },
+  { code: '<div aria-hidden={1 <= 2} onClick={() => void 0} />' },
+  { code: '<div aria-hidden={2 > 1} onClick={() => void 0} />' },
+  { code: '<div aria-hidden={2 >= 1} onClick={() => void 0} />' },
+  { code: '<div onClick={() => void 0} />;' },
+  { code: '<div onClick={() => void 0} tabIndex={undefined} />;' },
+  { code: '<div onClick={() => void 0} tabIndex="bad" />;' },
+  { code: '<div onClick={() => void 0} role={undefined} />;' },
+  { code: '<div role="section" onClick={() => void 0} />' },
+  { code: '<div onClick={() => void 0} aria-hidden={false} />;' },
+  { code: '<div onClick={() => void 0} {...props} />;' },
+  { code: '<input type="text" onClick={() => void 0} />' },
+  { code: '<input type="hidden" onClick={() => void 0} tabIndex="-1" />' },
+  { code: '<input type="hidden" onClick={() => void 0} tabIndex={-1} />' },
+  { code: '<input onClick={() => void 0} />' },
+  { code: '<input onClick={() => void 0} role="combobox" />' },
+  { code: '<button onClick={() => void 0} className="foo" />' },
+  { code: '<option onClick={() => void 0} className="foo" />' },
+  { code: '<select onClick={() => void 0} className="foo" />' },
+  { code: '<area href="#" onClick={() => void 0} className="foo" />' },
+  { code: '<area onClick={() => void 0} className="foo" />' },
+  { code: '<summary onClick={() => void 0} />' },
+  { code: '<textarea onClick={() => void 0} className="foo" />' },
+  { code: '<a onClick="showNextPage();">Next page</a>' },
+  { code: '<a onClick="showNextPage();" tabIndex={undefined}>Next page</a>' },
+  { code: '<a onClick="showNextPage();" tabIndex="bad">Next page</a>' },
+  { code: '<a onClick={() => void 0} />' },
+  { code: '<a tabIndex="0" onClick={() => void 0} />' },
+  { code: '<a tabIndex={dynamicTabIndex} onClick={() => void 0} />' },
+  { code: '<a tabIndex={0} onClick={() => void 0} />' },
+  { code: '<a role="button" href="#" onClick={() => void 0} />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" tabIndex="0" />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" tabIndex={0} />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" role="button" />' },
+  { code: '<TestComponent onClick={doFoo} />' },
+  { code: '<input onClick={() => void 0} type="hidden" />;' },
+  { code: '<span onClick="submitForm();">Submit</span>' },
+  { code: '<span onClick="submitForm();" tabIndex={undefined}>Submit</span>' },
+  { code: '<span onClick="submitForm();" tabIndex="bad">Submit</span>' },
+  { code: '<span onClick="doSomething();" tabIndex="0">Click me!</span>' },
+  { code: '<span onClick="doSomething();" tabIndex={0}>Click me!</span>' },
+  { code: '<span onClick="doSomething();" tabIndex="-1">Click me too!</span>' },
+  {
+    code: '<a href="javascript:void(0);" onClick="doSomething();">Click ALL the things!</a>',
+  },
+  { code: '<section onClick={() => void 0} />;' },
+  { code: '<main onClick={() => void 0} />;' },
+  { code: '<article onClick={() => void 0} />;' },
+  { code: '<header onClick={() => void 0} />;' },
+  { code: '<footer onClick={() => void 0} />;' },
+  { code: '<div role="button" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="checkbox" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="link" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="menuitem" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="menuitemcheckbox" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="menuitemradio" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="option" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="radio" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="spinbutton" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="switch" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="tablist" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="tab" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="textbox" tabIndex="0" onClick={() => void 0} />' },
+  { code: '<div role="textbox" aria-disabled="true" onClick={() => void 0} />' },
+  { code: '<Foo.Bar onClick={() => void 0} aria-hidden={false} />;' },
+  { code: '<Input onClick={() => void 0} type="hidden" />;' },
+  { code: '<Div onClick={() => void 0} role="button" tabIndex="0" />', settings: componentsSettings },
+];
+
+const neverValid = [
+  { code: '<Div onClick={() => void 0} role="button" />', errors: [buttonError], settings: componentsSettings },
+];
+
+const interactiveRoles = [
+  'button',
+  'checkbox',
+  'link',
+  'gridcell',
+  'menuitem',
+  'menuitemcheckbox',
+  'menuitemradio',
+  'option',
+  'radio',
+  'searchbox',
+  'slider',
+  'spinbutton',
+  'switch',
+  'tab',
+  'textbox',
+  'treeitem',
+];
+
+const recommendedRoles = [
+  'button',
+  'checkbox',
+  'link',
+  'searchbox',
+  'spinbutton',
+  'switch',
+  'textbox',
+];
+
+const strictRoles = [
+  'button',
+  'checkbox',
+  'link',
+  'progressbar',
+  'searchbox',
+  'slider',
+  'spinbutton',
+  'switch',
+  'textbox',
+];
+
+const staticElements = [
+  'div',
+];
+
+const triggeringHandlers = [
+  ...eventHandlersByType.mouse,
+  ...eventHandlersByType.keyboard,
+];
+
+const passReducer = (roles, handlers, messageTemplate) => (
+  staticElements.reduce((elementAcc, element) => (
+    elementAcc.concat(roles.reduce((roleAcc, role) => (
+      roleAcc.concat(handlers.map((handler) => ({
+        code: messageTemplate(element, role, handler),
+      })))
+    ), []))
+  ), [])
+);
+
+const failReducer = (roles, handlers, messageTemplate) => (
+  staticElements.reduce((elementAcc, element) => (
+    elementAcc.concat(roles.reduce((roleAcc, role) => (
+      roleAcc.concat(handlers.map((handler) => ({
+        code: codeTemplate(element, role, handler),
+        errors: [{
+          type,
+          message: messageTemplate(role),
+        }],
+      })))
+    ), []))
+  ), [])
+);
+
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    ...passReducer(
+      interactiveRoles,
+      eventHandlers.filter((handler) => !includes(triggeringHandlers, handler)),
+      codeTemplate,
+    ),
+    ...passReducer(
+      interactiveRoles.filter((role) => !includes(recommendedRoles, role)),
+      eventHandlers.filter((handler) => includes(triggeringHandlers, handler)),
+      tabindexTemplate,
+    ),
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    ...failReducer(recommendedRoles, triggeringHandlers, tabbableTemplate),
+    ...failReducer(
+      interactiveRoles.filter((role) => !includes(recommendedRoles, role)),
+      triggeringHandlers,
+      focusableTemplate,
+    ),
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+});
+
+ruleTester.run(`${ruleName}:strict`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    ...passReducer(
+      interactiveRoles,
+      eventHandlers.filter((handler) => !includes(triggeringHandlers, handler)),
+      codeTemplate,
+    ),
+    ...passReducer(
+      interactiveRoles.filter((role) => !includes(strictRoles, role)),
+      eventHandlers.filter((handler) => includes(triggeringHandlers, handler)),
+      tabindexTemplate,
+    ),
+  ))
+    .map(ruleOptionsMapperFactory(strictOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    ...failReducer(strictRoles, triggeringHandlers, tabbableTemplate),
+    ...failReducer(
+      interactiveRoles.filter((role) => !includes(strictRoles, role)),
+      triggeringHandlers,
+      focusableTemplate,
+    ),
+  ))
+    .map(ruleOptionsMapperFactory(strictOptions))
+    .map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/label-has-associated-control-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/label-has-associated-control-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/label-has-associated-control-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,243 @@
+/**
+ * @fileoverview Enforce label tags have an associated control.
+ * @author Jesse Beach
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/label-has-associated-control';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const ruleName = 'label-has-associated-control';
+
+const expectedError = {
+  message: 'A form label must be associated with a control.',
+  type: 'JSXOpeningElement',
+};
+
+const expectedErrorNoLabel = {
+  message: 'A form label must have accessible text.',
+  type: 'JSXOpeningElement',
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      CustomInput: 'input',
+      CustomLabel: 'label',
+    },
+  },
+};
+
+const attributesSettings = {
+  'jsx-a11y': {
+    attributes: {
+      for: ['htmlFor', 'for'],
+    },
+  },
+};
+
+const htmlForValid = [
+  { code: '<label htmlFor="js_id"><span><span><span>A label</span></span></span></label>', options: [{ depth: 4 }] },
+  { code: '<label htmlFor="js_id" aria-label="A label" />' },
+  { code: '<label htmlFor="js_id" aria-labelledby="A label" />' },
+  { code: '<div><label htmlFor="js_id">A label</label><input id="js_id" /></div>' },
+  { code: '<label for="js_id"><span><span><span>A label</span></span></span></label>', options: [{ depth: 4 }], settings: attributesSettings },
+  { code: '<label for="js_id" aria-label="A label" />', settings: attributesSettings },
+  { code: '<label for="js_id" aria-labelledby="A label" />', settings: attributesSettings },
+  { code: '<div><label for="js_id">A label</label><input id="js_id" /></div>', settings: attributesSettings },
+  // Custom label component.
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label" />', options: [{ labelComponents: ['CustomLabel'] }] },
+  { code: '<CustomLabel htmlFor="js_id" label="A label" />', options: [{ labelAttributes: ['label'], labelComponents: ['CustomLabel'] }] },
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label" />', settings: componentsSettings },
+  // Custom label attributes.
+  { code: '<label htmlFor="js_id" label="A label" />', options: [{ labelAttributes: ['label'] }] },
+  // Glob support for controlComponents option.
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label" />', options: [{ controlComponents: ['Custom*'] }] },
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label" />', options: [{ controlComponents: ['*Label'] }] },
+  // Rule does not error if presence of accessible label cannot be determined
+  { code: '<div><label htmlFor="js_id"><CustomText /></label><input id="js_id" /></div>' },
+];
+const nestingValid = [
+  { code: '<label>A label<input /></label>' },
+  { code: '<label>A label<textarea /></label>' },
+  { code: '<label><img alt="A label" /><input /></label>' },
+  { code: '<label><img aria-label="A label" /><input /></label>' },
+  { code: '<label><span>A label<input /></span></label>' },
+  { code: '<label><span><span>A label<input /></span></span></label>', options: [{ depth: 3 }] },
+  { code: '<label><span><span><span>A label<input /></span></span></span></label>', options: [{ depth: 4 }] },
+  { code: '<label><span><span><span><span>A label</span><input /></span></span></span></label>', options: [{ depth: 5 }] },
+  { code: '<label><span><span><span><span aria-label="A label" /><input /></span></span></span></label>', options: [{ depth: 5 }] },
+  { code: '<label><span><span><span><input aria-label="A label" /></span></span></span></label>', options: [{ depth: 5 }] },
+  // Other controls
+  { code: '<label>foo<meter /></label>' },
+  { code: '<label>foo<output /></label>' },
+  { code: '<label>foo<progress /></label>' },
+  { code: '<label>foo<textarea /></label>' },
+  // Custom controlComponents.
+  { code: '<label>A label<CustomInput /></label>', options: [{ controlComponents: ['CustomInput'] }] },
+  { code: '<label><span>A label<CustomInput /></span></label>', options: [{ controlComponents: ['CustomInput'] }] },
+  { code: '<label><span>A label<CustomInput /></span></label>', settings: componentsSettings },
+  { code: '<CustomLabel><span>A label<CustomInput /></span></CustomLabel>', options: [{ controlComponents: ['CustomInput'], labelComponents: ['CustomLabel'] }] },
+  { code: '<CustomLabel><span label="A label"><CustomInput /></span></CustomLabel>', options: [{ controlComponents: ['CustomInput'], labelComponents: ['CustomLabel'], labelAttributes: ['label'] }] },
+  // Glob support for controlComponents option.
+  { code: '<label><span>A label<CustomInput /></span></label>', options: [{ controlComponents: ['Custom*'] }] },
+  { code: '<label><span>A label<CustomInput /></span></label>', options: [{ controlComponents: ['*Input'] }] },
+  // Rule does not error if presence of accessible label cannot be determined
+  { code: '<label><CustomText /><input /></label>' },
+];
+
+const bothValid = [
+  { code: '<label htmlFor="js_id"><span><span><span>A label<input /></span></span></span></label>', options: [{ depth: 4 }] },
+  { code: '<label htmlFor="js_id" aria-label="A label"><input /></label>' },
+  { code: '<label htmlFor="js_id" aria-labelledby="A label"><input /></label>' },
+  { code: '<label htmlFor="js_id" aria-labelledby="A label"><textarea /></label>' },
+  // Custom label component.
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label"><input /></CustomLabel>', options: [{ labelComponents: ['CustomLabel'] }] },
+  { code: '<CustomLabel htmlFor="js_id" label="A label"><input /></CustomLabel>', options: [{ labelAttributes: ['label'], labelComponents: ['CustomLabel'] }] },
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label"><input /></CustomLabel>', settings: componentsSettings },
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label"><CustomInput /></CustomLabel>', settings: componentsSettings },
+  // Custom label attributes.
+  { code: '<label htmlFor="js_id" label="A label"><input /></label>', options: [{ labelAttributes: ['label'] }] },
+  { code: '<label htmlFor="selectInput">Some text<select id="selectInput" /></label>' },
+];
+
+const alwaysValid = [
+  { code: '<div />' },
+  { code: '<CustomElement />' },
+  { code: '<input type="hidden" />' },
+];
+
+const htmlForInvalid = [
+  { code: '<label htmlFor="js_id"><span><span><span>A label</span></span></span></label>', options: [{ depth: 4 }], errors: [expectedError] },
+  { code: '<label htmlFor="js_id" aria-label="A label" />', errors: [expectedError] },
+  { code: '<label htmlFor="js_id" aria-labelledby="A label" />', errors: [expectedError] },
+  // Custom label component.
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label" />', options: [{ labelComponents: ['CustomLabel'] }], errors: [expectedError] },
+  { code: '<CustomLabel htmlFor="js_id" label="A label" />', options: [{ labelAttributes: ['label'], labelComponents: ['CustomLabel'] }], errors: [expectedError] },
+  { code: '<CustomLabel htmlFor="js_id" aria-label="A label" />', settings: componentsSettings, errors: [expectedError] },
+  // Custom label attributes.
+  { code: '<label htmlFor="js_id" label="A label" />', options: [{ labelAttributes: ['label'] }], errors: [expectedError] },
+];
+const nestingInvalid = [
+  { code: '<label>A label<input /></label>', errors: [expectedError] },
+  { code: '<label>A label<textarea /></label>', errors: [expectedError] },
+  { code: '<label><img alt="A label" /><input /></label>', errors: [expectedError] },
+  { code: '<label><img aria-label="A label" /><input /></label>', errors: [expectedError] },
+  { code: '<label><span>A label<input /></span></label>', errors: [expectedError] },
+  { code: '<label><span><span>A label<input /></span></span></label>', options: [{ depth: 3 }], errors: [expectedError] },
+  { code: '<label><span><span><span>A label<input /></span></span></span></label>', options: [{ depth: 4 }], errors: [expectedError] },
+  { code: '<label><span><span><span><span>A label</span><input /></span></span></span></label>', options: [{ depth: 5 }], errors: [expectedError] },
+  { code: '<label><span><span><span><span aria-label="A label" /><input /></span></span></span></label>', options: [{ depth: 5 }], errors: [expectedError] },
+  { code: '<label><span><span><span><input aria-label="A label" /></span></span></span></label>', options: [{ depth: 5 }], errors: [expectedError] },
+  // Custom controlComponents.
+  { code: '<label>A label<OtherCustomInput /></label>', options: [{ controlComponents: ['CustomInput'] }], errors: [expectedError] },
+  { code: '<label><span>A label<CustomInput /></span></label>', options: [{ controlComponents: ['CustomInput'] }], errors: [expectedError] },
+  { code: '<CustomLabel><span>A label<CustomInput /></span></CustomLabel>', options: [{ controlComponents: ['CustomInput'], labelComponents: ['CustomLabel'] }], errors: [expectedError] },
+  { code: '<CustomLabel><span label="A label"><CustomInput /></span></CustomLabel>', options: [{ controlComponents: ['CustomInput'], labelComponents: ['CustomLabel'], labelAttributes: ['label'] }], errors: [expectedError] },
+  { code: '<label><span>A label<CustomInput /></span></label>', settings: componentsSettings, errors: [expectedError] },
+  { code: '<CustomLabel><span>A label<CustomInput /></span></CustomLabel>', settings: componentsSettings, errors: [expectedError] },
+];
+
+const neverValid = [
+  { code: '<label htmlFor="js_id" />', errors: [expectedErrorNoLabel] },
+  { code: '<label htmlFor="js_id"><input /></label>', errors: [expectedErrorNoLabel] },
+  { code: '<label htmlFor="js_id"><textarea /></label>', errors: [expectedErrorNoLabel] },
+  { code: '<label></label>', errors: [expectedErrorNoLabel] },
+  { code: '<label>A label</label>', errors: [expectedError] },
+  { code: '<div><label /><input /></div>', errors: [expectedErrorNoLabel] },
+  { code: '<div><label>A label</label><input /></div>', errors: [expectedError] },
+  // Custom label component.
+  { code: '<CustomLabel aria-label="A label" />', options: [{ labelComponents: ['CustomLabel'] }], errors: [expectedError] },
+  { code: '<CustomLabel label="A label" />', options: [{ labelAttributes: ['label'], labelComponents: ['CustomLabel'] }], errors: [expectedError] },
+  { code: '<CustomLabel aria-label="A label" />', settings: componentsSettings, errors: [expectedError] },
+  // Custom label attributes.
+  { code: '<label label="A label" />', options: [{ labelAttributes: ['label'] }], errors: [expectedError] },
+  // Custom controlComponents.
+  { code: '<label><span><CustomInput /></span></label>', options: [{ controlComponents: ['CustomInput'] }], errors: [expectedErrorNoLabel] },
+  { code: '<CustomLabel><span><CustomInput /></span></CustomLabel>', options: [{ controlComponents: ['CustomInput'], labelComponents: ['CustomLabel'] }], errors: [expectedErrorNoLabel] },
+  { code: '<CustomLabel><span><CustomInput /></span></CustomLabel>', options: [{ controlComponents: ['CustomInput'], labelComponents: ['CustomLabel'], labelAttributes: ['label'] }], errors: [expectedErrorNoLabel] },
+  { code: '<label><span><CustomInput /></span></label>', settings: componentsSettings, errors: [expectedErrorNoLabel] },
+  { code: '<CustomLabel><span><CustomInput /></span></CustomLabel>', settings: componentsSettings, errors: [expectedErrorNoLabel] },
+];
+// htmlFor valid
+ruleTester.run(ruleName, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    ...htmlForValid,
+  ))
+    .map(ruleOptionsMapperFactory({
+      assert: 'htmlFor',
+    }))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    ...nestingInvalid,
+  ))
+    .map(ruleOptionsMapperFactory({
+      assert: 'htmlFor',
+    }))
+    .map(parserOptionsMapper),
+});
+
+// nesting valid
+ruleTester.run(ruleName, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    ...nestingValid,
+  ))
+    .map(ruleOptionsMapperFactory({
+      assert: 'nesting',
+    }))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    ...htmlForInvalid,
+  ))
+    .map(ruleOptionsMapperFactory({
+      assert: 'nesting',
+    }))
+    .map(parserOptionsMapper),
+});
+
+// either valid
+ruleTester.run(ruleName, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    ...htmlForValid,
+    ...nestingValid,
+  ))
+    .map(ruleOptionsMapperFactory({
+      assert: 'either',
+    }))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  )).map(parserOptionsMapper),
+});
+
+// both valid
+ruleTester.run(ruleName, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    ...bothValid,
+  ))
+    .map(ruleOptionsMapperFactory({
+      assert: 'both',
+    }))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/label-has-for-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/label-has-for-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/label-has-for-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,235 @@
+/**
+ * @fileoverview Enforce label tags have htmlFor attribute.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import assign from 'object.assign';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/label-has-for';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedNestingError = {
+  message: 'Form label must have the following type of associated control: nesting',
+  type: 'JSXOpeningElement',
+};
+
+const expectedSomeError = {
+  message: 'Form label must have ANY of the following types of associated control: nesting, id',
+  type: 'JSXOpeningElement',
+};
+
+const expectedEveryError = {
+  message: 'Form label must have ALL of the following types of associated control: nesting, id',
+  type: 'JSXOpeningElement',
+};
+
+const optionsComponents = [{
+  components: ['Label', 'Descriptor'],
+}];
+const optionsRequiredNesting = [{
+  required: 'nesting',
+}];
+const optionsRequiredSome = [{
+  required: { some: ['nesting', 'id'] },
+}];
+const optionsRequiredEvery = [{
+  required: { every: ['nesting', 'id'] },
+}];
+const optionsChildrenAllowed = [{
+  allowChildren: true,
+}];
+
+const attributesSettings = {
+  'jsx-a11y': {
+    attributes: {
+      for: ['htmlFor', 'for'],
+    },
+  },
+};
+
+ruleTester.run('label-has-for', rule, {
+  valid: parsers.all([].concat(
+    // DEFAULT ELEMENT 'label' TESTS
+    { code: '<div />' },
+    { code: '<label htmlFor="foo"><input /></label>' },
+    { code: '<label htmlFor="foo"><textarea /></label>' },
+    { code: '<label for="foo"><input /></label>', settings: attributesSettings },
+    { code: '<label for="foo"><textarea /></label>', settings: attributesSettings },
+    { code: '<Label />' }, // lower-case convention refers to real HTML elements.
+    { code: '<Label htmlFor="foo" />' },
+    { code: '<Label for="foo" />', settings: attributesSettings },
+    { code: '<Descriptor />' },
+    { code: '<Descriptor htmlFor="foo">Test!</Descriptor>' },
+    { code: '<Descriptor for="foo">Test!</Descriptor>', settings: attributesSettings },
+    { code: '<UX.Layout>test</UX.Layout>' },
+
+    // CUSTOM ELEMENT ARRAY OPTION TESTS
+    { code: '<Label htmlFor="foo" />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Label htmlFor={"foo"} />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Label htmlFor={foo} />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Label htmlFor={`${id}`} />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<div />', options: optionsComponents },
+    { code: '<Label htmlFor="something"><input /></Label>', options: optionsComponents },
+    { code: '<Label htmlFor="foo">Test!</Label>', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Descriptor htmlFor="foo" />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Descriptor htmlFor={"foo"} />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Descriptor htmlFor={foo} />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Descriptor htmlFor={`${id}`} />', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<Descriptor htmlFor="foo">Test!</Descriptor>', options: [assign({}, optionsComponents[0], optionsRequiredSome[0])] },
+    { code: '<label htmlFor="foo" />', options: optionsRequiredSome },
+    { code: '<label htmlFor={"foo"} />', options: optionsRequiredSome },
+    { code: '<label htmlFor={foo} />', options: optionsRequiredSome },
+    { code: '<label htmlFor={`${id}`} />', options: optionsRequiredSome },
+    { code: '<label htmlFor="foo">Test!</label>', options: optionsRequiredSome },
+    { code: '<label><input /></label>', options: optionsRequiredSome },
+    { code: '<label><input /></label>', options: optionsRequiredNesting },
+    { code: '<label htmlFor="input"><input /></label>', options: optionsRequiredEvery },
+    { code: '<label><input /></label>', options: optionsChildrenAllowed },
+    { code: '<Descriptor htmlFor="foo">Test!</Descriptor>', options: [assign({}, optionsComponents, optionsChildrenAllowed)] },
+    { code: '<label>Test!</label>', options: optionsChildrenAllowed },
+    { code: '<label htmlFor="foo">Test!</label>', options: optionsChildrenAllowed },
+    { code: '<label>{children}</label>', options: optionsChildrenAllowed },
+    { code: '<label htmlFor="children">{children}</label>', options: optionsChildrenAllowed },
+    { code: '<label htmlFor={id}>{ labelText }<div><input id={id} type="checkbox" name={id} value={value} /></div></label>', options: optionsRequiredEvery },
+    { code: '<label htmlFor={id}>{ labelText }<div><div><div><div><input id={id} type="checkbox" name={id} value={value} /></div></div></div></div></label>', options: optionsRequiredEvery },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    // DEFAULT ELEMENT 'label' TESTS
+    { code: '<label id="foo" />', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor={undefined} />', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor={`${undefined}`} />', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label>First Name</label>', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label {...props}>Foo</label>', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label><input /></label>', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label><textarea /></label>', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label>{children}</label>', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor="foo" />', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor={"foo"} />', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor={foo} />', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor={`${id}`} />', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor="foo">Test!</label>', errors: [expectedEveryError], options: optionsRequiredEvery },
+    { code: '<label htmlFor={id}>{ labelText }<div><div><div><div><div id={id} type="checkbox" name={id} value={value} /></div></div></div></div></label>', errors: [expectedEveryError], options: optionsRequiredEvery },
+    //
+    // // CUSTOM ELEMENT ARRAY OPTION TESTS
+    {
+      code: '<Label></Label>',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    {
+      code: '<Label htmlFor="foo" />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Label htmlFor={"foo"} />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Label htmlFor={foo} />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Label htmlFor={`${id}`} />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Label htmlFor="foo">Test!</Label>',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Descriptor htmlFor="foo" />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Descriptor htmlFor={"foo"} />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Descriptor htmlFor={foo} />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Descriptor htmlFor={`${id}`} />',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    {
+      code: '<Descriptor htmlFor="foo">Test!</Descriptor>',
+      errors: [expectedEveryError],
+      options: [{ ...optionsComponents[0], ...optionsRequiredEvery[0] }],
+    },
+    { code: '<Label id="foo" />', errors: [expectedEveryError], options: optionsComponents },
+    {
+      code: '<Label htmlFor={undefined} />',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    {
+      code: '<Label htmlFor={`${undefined}`} />',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    { code: '<Label>First Name</Label>', errors: [expectedEveryError], options: optionsComponents },
+    {
+      code: '<Label {...props}>Foo</Label>',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    { code: '<Descriptor id="foo" />', errors: [expectedEveryError], options: optionsComponents },
+    {
+      code: '<Descriptor htmlFor={undefined} />',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    {
+      code: '<Descriptor htmlFor={`${undefined}`} />',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    {
+      code: '<Descriptor>First Name</Descriptor>',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    {
+      code: '<Descriptor {...props}>Foo</Descriptor>',
+      errors: [expectedEveryError],
+      options: optionsComponents,
+    },
+    { code: '<label>{children}</label>', errors: [expectedEveryError], options: optionsComponents },
+    { code: '<label htmlFor="foo" />', errors: [expectedNestingError], options: optionsRequiredNesting },
+    { code: '<label>First Name</label>', errors: [expectedNestingError], options: optionsRequiredNesting },
+    { code: '<label>First Name</label>', errors: [expectedSomeError], options: optionsRequiredSome },
+    { code: '<label>{children}</label>', errors: [expectedSomeError], options: optionsRequiredSome },
+    { code: '<label>{children}</label>', errors: [expectedNestingError], options: optionsRequiredNesting },
+    {
+      code: '<form><input type="text" id="howmuch" value="1" /><label htmlFor="howmuch">How much ?</label></form>',
+      errors: [expectedEveryError],
+      options: optionsRequiredEvery,
+    },
+    {
+      code: '<form><input type="text" id="howmuch" value="1" /><label htmlFor="howmuch">How much ?<span /></label></form>',
+      errors: [expectedEveryError],
+      options: optionsRequiredEvery,
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/lang-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/lang-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/lang-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+/**
+ * @fileoverview Enforce lang attribute has a valid value.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/lang';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'lang attribute must have a valid value.',
+  type: 'JSXAttribute',
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    polymorphicPropName: 'as',
+    components: {
+      Foo: 'html',
+    },
+  },
+};
+
+ruleTester.run('lang', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<div foo="bar" />;' },
+    { code: '<div lang="foo" />;' },
+    { code: '<html lang="en" />' },
+    { code: '<html lang="en-US" />' },
+    { code: '<html lang="zh-Hans" />' },
+    { code: '<html lang="zh-Hant-HK" />' },
+    { code: '<html lang="zh-yue-Hant" />' },
+    { code: '<html lang="ja-Latn" />' },
+    { code: '<html lang={foo} />' },
+    { code: '<HTML lang="foo" />' },
+    { code: '<Foo lang={undefined} />' },
+    { code: '<Foo lang="en" />', settings: componentsSettings },
+    { code: '<Box as="html" lang="en"  />', settings: componentsSettings },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<html lang="foo" />', errors: [expectedError] },
+    { code: '<html lang="zz-LL" />', errors: [expectedError] },
+    { code: '<html lang={undefined} />', errors: [expectedError] },
+    { code: '<Foo lang={undefined} />', settings: componentsSettings, errors: [expectedError] },
+    { code: '<Box as="html" lang="foo" />', settings: componentsSettings, errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/media-has-caption-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/media-has-caption-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/media-has-caption-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,220 @@
+/**
+ * @fileoverview <audio> and <video> elements must have a <track> for captions.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/media-has-caption';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'Media elements such as <audio> and <video> must have a <track> for captions.',
+  type: 'JSXOpeningElement',
+};
+
+const customSchema = [
+  {
+    audio: ['Audio'],
+    video: ['Video'],
+    track: ['Track'],
+  },
+];
+
+const componentsSettings = {
+  'jsx-a11y': {
+    polymorphicPropName: 'as',
+    components: {
+      Audio: 'audio',
+      Video: 'video',
+      Track: 'track',
+    },
+  },
+};
+
+ruleTester.run('media-has-caption', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<MyDiv />;' },
+    { code: '<audio><track kind="captions" /></audio>' },
+    { code: '<audio><track kind="Captions" /></audio>' },
+    {
+      code: '<audio><track kind="Captions" /><track kind="subtitles" /></audio>',
+    },
+    { code: '<video><track kind="captions" /></video>' },
+    { code: '<video><track kind="Captions" /></video>' },
+    {
+      code: '<video><track kind="Captions" /><track kind="subtitles" /></video>',
+    },
+    {
+      code: '<audio muted={true}></audio>',
+    },
+    {
+      code: '<video muted={true}></video>',
+    },
+    {
+      code: '<video muted></video>',
+    },
+    {
+      code: '<Audio><track kind="captions" /></Audio>',
+      options: customSchema,
+    },
+    {
+      code: '<audio><Track kind="captions" /></audio>',
+      options: customSchema,
+    },
+    {
+      code: '<Video><track kind="captions" /></Video>',
+      options: customSchema,
+    },
+    {
+      code: '<video><Track kind="captions" /></video>',
+      options: customSchema,
+    },
+    {
+      code: '<Audio><Track kind="captions" /></Audio>',
+      options: customSchema,
+    },
+    {
+      code: '<Video><Track kind="captions" /></Video>',
+      options: customSchema,
+    },
+    {
+      code: '<Video muted></Video>',
+      options: customSchema,
+    },
+    {
+      code: '<Video muted={true}></Video>',
+      options: customSchema,
+    },
+    {
+      code: '<Audio muted></Audio>',
+      options: customSchema,
+    },
+    {
+      code: '<Audio muted={true}></Audio>',
+      options: customSchema,
+    },
+    {
+      code: '<Audio><track kind="captions" /></Audio>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<audio><Track kind="captions" /></audio>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Video><track kind="captions" /></Video>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<video><Track kind="captions" /></video>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Audio><Track kind="captions" /></Audio>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Video><Track kind="captions" /></Video>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Video muted></Video>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Video muted={true}></Video>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Audio muted></Audio>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Audio muted={true}></Audio>',
+      settings: componentsSettings,
+    },
+    {
+      code: '<Box as="audio" muted={true}></Box>',
+      settings: componentsSettings,
+    },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<audio><track /></audio>', errors: [expectedError] },
+    {
+      code: '<audio><track kind="subtitles" /></audio>',
+      errors: [expectedError],
+    },
+    { code: '<audio />', errors: [expectedError] },
+    { code: '<video><track /></video>', errors: [expectedError] },
+    {
+      code: '<video><track kind="subtitles" /></video>',
+      errors: [expectedError],
+    },
+    {
+      code: '<Audio muted={false}></Audio>',
+      options: customSchema,
+      errors: [expectedError],
+    },
+    {
+      code: '<Video muted={false}></Video>',
+      options: customSchema,
+      errors: [expectedError],
+    },
+    {
+      code: '<Audio muted={false}></Audio>',
+      settings: componentsSettings,
+      errors: [expectedError],
+    },
+    {
+      code: '<Video muted={false}></Video>',
+      settings: componentsSettings,
+      errors: [expectedError],
+    },
+    { code: '<video />', errors: [expectedError] },
+    { code: '<audio>Foo</audio>', errors: [expectedError] },
+    { code: '<video>Foo</video>', errors: [expectedError] },
+    { code: '<Audio />', options: customSchema, errors: [expectedError] },
+    { code: '<Video />', options: customSchema, errors: [expectedError] },
+    { code: '<Audio />', settings: componentsSettings, errors: [expectedError] },
+    { code: '<Video />', settings: componentsSettings, errors: [expectedError] },
+    { code: '<audio><Track /></audio>', options: customSchema, errors: [expectedError] },
+    { code: '<video><Track /></video>', options: customSchema, errors: [expectedError] },
+    {
+      code: '<Audio><Track kind="subtitles" /></Audio>',
+      options: customSchema,
+      errors: [expectedError],
+    },
+    {
+      code: '<Video><Track kind="subtitles" /></Video>',
+      options: customSchema,
+      errors: [expectedError],
+    },
+    {
+      code: '<Audio><Track kind="subtitles" /></Audio>',
+      settings: componentsSettings,
+      errors: [expectedError],
+    },
+    {
+      code: '<Video><Track kind="subtitles" /></Video>',
+      settings: componentsSettings,
+      errors: [expectedError],
+    },
+    {
+      code: '<Box as="audio"><Track kind="subtitles" /></Box>',
+      settings: componentsSettings,
+      errors: [expectedError],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/mouse-events-have-key-events-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/mouse-events-have-key-events-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/mouse-events-have-key-events-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,154 @@
+/**
+ * @fileoverview Enforce onmouseover/onmouseout are accompanied
+ *  by onfocus/onblur.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/mouse-events-have-key-events';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const mouseOverError = {
+  message: 'onMouseOver must be accompanied by onFocus for accessibility.',
+  type: 'JSXAttribute',
+};
+const pointerEnterError = {
+  message: 'onPointerEnter must be accompanied by onFocus for accessibility.',
+  type: 'JSXAttribute',
+};
+const mouseOutError = {
+  message: 'onMouseOut must be accompanied by onBlur for accessibility.',
+  type: 'JSXAttribute',
+};
+const pointerLeaveError = {
+  message: 'onPointerLeave must be accompanied by onBlur for accessibility.',
+  type: 'JSXAttribute',
+};
+
+ruleTester.run('mouse-events-have-key-events', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div onMouseOver={() => void 0} onFocus={() => void 0} />;' },
+    {
+      code: '<div onMouseOver={() => void 0} onFocus={() => void 0} {...props} />;',
+    },
+    { code: '<div onMouseOver={handleMouseOver} onFocus={handleFocus} />;' },
+    {
+      code: '<div onMouseOver={handleMouseOver} onFocus={handleFocus} {...props} />;',
+    },
+    { code: '<div />;' },
+    { code: '<div onBlur={() => {}} />' },
+    { code: '<div onFocus={() => {}} />' },
+    { code: '<div onMouseOut={() => void 0} onBlur={() => void 0} />' },
+    { code: '<div onMouseOut={() => void 0} onBlur={() => void 0} {...props} />' },
+    { code: '<div onMouseOut={handleMouseOut} onBlur={handleOnBlur} />' },
+    { code: '<div onMouseOut={handleMouseOut} onBlur={handleOnBlur} {...props} />' },
+    { code: '<MyElement />' },
+    { code: '<MyElement onMouseOver={() => {}} />' },
+    { code: '<MyElement onMouseOut={() => {}} />' },
+    { code: '<MyElement onBlur={() => {}} />' },
+    { code: '<MyElement onFocus={() => {}} />' },
+    { code: '<MyElement onMouseOver={() => {}} {...props} />' },
+    { code: '<MyElement onMouseOut={() => {}} {...props} />' },
+    { code: '<MyElement onBlur={() => {}} {...props} />' },
+    { code: '<MyElement onFocus={() => {}} {...props} />' },
+    /* Passing in empty options doesn't check any event handlers */
+    {
+      code: '<div onMouseOver={() => {}} onMouseOut={() => {}} />',
+      options: [{ hoverInHandlers: [], hoverOutHandlers: [] }],
+    },
+    /* Passing in custom handlers */
+    {
+      code: '<div onMouseOver={() => {}} onFocus={() => {}} />',
+      options: [{ hoverInHandlers: ['onMouseOver'] }],
+    },
+    {
+      code: '<div onMouseEnter={() => {}} onFocus={() => {}} />',
+      options: [{ hoverInHandlers: ['onMouseEnter'] }],
+    },
+    {
+      code: '<div onMouseOut={() => {}} onBlur={() => {}} />',
+      options: [{ hoverOutHandlers: ['onMouseOut'] }],
+    },
+    {
+      code: '<div onMouseLeave={() => {}} onBlur={() => {}} />',
+      options: [{ hoverOutHandlers: ['onMouseLeave'] }],
+    },
+    {
+      code: '<div onMouseOver={() => {}} onMouseOut={() => {}} />',
+      options: [
+        { hoverInHandlers: ['onPointerEnter'], hoverOutHandlers: ['onPointerLeave'] },
+      ],
+    },
+    /* Custom options only checks the handlers passed in */
+    {
+      code: '<div onMouseLeave={() => {}} />',
+      options: [{ hoverOutHandlers: ['onPointerLeave'] }],
+    },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<div onMouseOver={() => void 0} />;', errors: [mouseOverError] },
+    { code: '<div onMouseOut={() => void 0} />', errors: [mouseOutError] },
+    {
+      code: '<div onMouseOver={() => void 0} onFocus={undefined} />;',
+      errors: [mouseOverError],
+    },
+    {
+      code: '<div onMouseOut={() => void 0} onBlur={undefined} />',
+      errors: [mouseOutError],
+    },
+    {
+      code: '<div onMouseOver={() => void 0} {...props} />',
+      errors: [mouseOverError],
+    },
+    {
+      code: '<div onMouseOut={() => void 0} {...props} />',
+      errors: [mouseOutError],
+    },
+    /* Custom options */
+    {
+      code: '<div onMouseOver={() => {}} onMouseOut={() => {}} />',
+      options: [
+        { hoverInHandlers: ['onMouseOver'], hoverOutHandlers: ['onMouseOut'] },
+      ],
+      errors: [mouseOverError, mouseOutError],
+    },
+    {
+      code: '<div onPointerEnter={() => {}} onPointerLeave={() => {}} />',
+      options: [
+        { hoverInHandlers: ['onPointerEnter'], hoverOutHandlers: ['onPointerLeave'] },
+      ],
+      errors: [pointerEnterError, pointerLeaveError],
+    },
+    {
+      code: '<div onMouseOver={() => {}} />',
+      options: [{ hoverInHandlers: ['onMouseOver'] }],
+      errors: [mouseOverError],
+    },
+    {
+      code: '<div onPointerEnter={() => {}} />',
+      options: [{ hoverInHandlers: ['onPointerEnter'] }],
+      errors: [pointerEnterError],
+    },
+    {
+      code: '<div onMouseOut={() => {}} />',
+      options: [{ hoverOutHandlers: ['onMouseOut'] }],
+      errors: [mouseOutError],
+    },
+    {
+      code: '<div onPointerLeave={() => {}} />',
+      options: [{ hoverOutHandlers: ['onPointerLeave'] }],
+      errors: [pointerLeaveError],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-access-key-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-access-key-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-access-key-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,48 @@
+/**
+ * @fileoverview Enforce no accesskey attribute on element.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-access-key';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'No access key attribute allowed. Inconsistencies between keyboard shortcuts and keyboard commands used by screen readers and keyboard-only users create a11y complications.',
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('no-access-key', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<div {...props} />' },
+    { code: '<div accessKey={undefined} />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<div accesskey="h" />', errors: [expectedError] },
+    { code: '<div accessKey="h" />', errors: [expectedError] },
+    { code: '<div accessKey="h" {...props} />', errors: [expectedError] },
+    { code: '<div acCesSKeY="y" />', errors: [expectedError] },
+    { code: '<div accessKey={"y"} />', errors: [expectedError] },
+    { code: '<div accessKey={`${y}`} />', errors: [expectedError] },
+    {
+      code: '<div accessKey={`${undefined}y${undefined}`} />',
+      errors: [expectedError],
+    },
+    { code: '<div accessKey={`This is ${bad}`} />', errors: [expectedError] },
+    { code: '<div accessKey={accessKey} />', errors: [expectedError] },
+    { code: '<div accessKey={`${undefined}`} />', errors: [expectedError] },
+    { code: '<div accessKey={`${undefined}${undefined}`} />', errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-aria-hidden-on-focusable-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-aria-hidden-on-focusable-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-aria-hidden-on-focusable-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+/**
+ * @fileoverview Enforce `aria-hidden="true"` is not used on focusable elements.
+ * @author Kate Higa
+*/
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-aria-hidden-on-focusable';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'aria-hidden="true" must not be set on focusable elements.',
+  type: 'JSXOpeningElement',
+};
+
+ruleTester.run('no-aria-hidden-on-focusable', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div aria-hidden="true" />;' },
+    { code: '<div onClick={() => void 0} aria-hidden="true" />;' },
+    { code: '<img aria-hidden="true" />' },
+    { code: '<a aria-hidden="false" href="#" />' },
+    { code: '<button aria-hidden="true" tabIndex="-1" />' },
+    { code: '<button />' },
+    { code: '<a href="/" />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<div aria-hidden="true" tabIndex="0" />;', errors: [expectedError] },
+    { code: '<input aria-hidden="true" />;', errors: [expectedError] },
+    { code: '<a href="/" aria-hidden="true" />', errors: [expectedError] },
+    { code: '<button aria-hidden="true" />', errors: [expectedError] },
+    { code: '<textarea aria-hidden="true" />', errors: [expectedError] },
+    { code: '<p tabindex="0" aria-hidden="true">text</p>;', errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-autofocus-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-autofocus-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-autofocus-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,68 @@
+/**
+ * @fileoverview Enforce autoFocus prop is not used.
+ * @author Ethan Cohen <@evcohen>
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-autofocus';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'The autoFocus prop should not be used, as it can reduce usability and accessibility for users.',
+  type: 'JSXAttribute',
+};
+
+const ignoreNonDOMSchema = [
+  {
+    ignoreNonDOM: true,
+  },
+];
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Button: 'button',
+    },
+  },
+};
+
+ruleTester.run('no-autofocus', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<div autofocus />;' },
+    { code: '<input autofocus="true" />;' },
+    { code: '<Foo bar />' },
+    { code: '<Foo autoFocus />', options: ignoreNonDOMSchema },
+    { code: '<div><div autofocus /></div>', options: ignoreNonDOMSchema },
+    { code: '<Button />', settings: componentsSettings },
+    { code: '<Button />', options: ignoreNonDOMSchema, settings: componentsSettings },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<div autoFocus />', errors: [expectedError] },
+    { code: '<div autoFocus={true} />', errors: [expectedError] },
+    { code: '<div autoFocus={false} />', errors: [expectedError] },
+    { code: '<div autoFocus={undefined} />', errors: [expectedError] },
+    { code: '<div autoFocus="true" />', errors: [expectedError] },
+    { code: '<div autoFocus="false" />', errors: [expectedError] },
+    { code: '<input autoFocus />', errors: [expectedError] },
+    { code: '<Foo autoFocus />', errors: [expectedError] },
+    { code: '<Button autoFocus />', errors: [expectedError], settings: componentsSettings },
+    {
+      code: '<Button autoFocus />',
+      errors: [expectedError],
+      options: ignoreNonDOMSchema,
+      settings: componentsSettings,
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-distracting-elements-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-distracting-elements-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-distracting-elements-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+/**
+ * @fileoverview Enforce distracting elements are not used.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-distracting-elements';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = (element) => ({
+  message: `Do not use <${element}> elements as they can create visual accessibility issues and are deprecated.`,
+  type: 'JSXOpeningElement',
+});
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Blink: 'blink',
+    },
+  },
+};
+
+ruleTester.run('no-marquee', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<Marquee />' },
+    { code: '<div marquee />' },
+    { code: '<Blink />' },
+    { code: '<div blink />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<marquee />', errors: [expectedError('marquee')] },
+    { code: '<marquee {...props} />', errors: [expectedError('marquee')] },
+    { code: '<marquee lang={undefined} />', errors: [expectedError('marquee')] },
+    { code: '<blink />', errors: [expectedError('blink')] },
+    { code: '<blink {...props} />', errors: [expectedError('blink')] },
+    { code: '<blink foo={undefined} />', errors: [expectedError('blink')] },
+    { code: '<Blink />', settings: componentsSettings, errors: [expectedError('blink')] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,405 @@
+/**
+ * @fileoverview Disallow inherently interactive elements to be assigned
+ * non-interactive roles.
+ * @author Jesse Beach
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import { configs } from '../../../src/index';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-interactive-element-to-noninteractive-role';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+const ruleTester = new RuleTester();
+
+const errorMessage = 'Interactive elements should not be assigned non-interactive roles.';
+
+const expectedError = {
+  message: errorMessage,
+  type: 'JSXAttribute',
+};
+
+const ruleName = 'jsx-a11y/no-interactive-element-to-noninteractive-role';
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Button: 'button',
+      Link: 'a',
+    },
+  },
+};
+
+const alwaysValid = [
+  { code: '<TestComponent onClick={doFoo} />' },
+  { code: '<Button onClick={doFoo} />' },
+  /* Interactive elements */
+  { code: '<a href="http://x.y.z" role="button" />' },
+  { code: '<a href="http://x.y.z" tabIndex="0" role="button" />' },
+  { code: '<button className="foo" role="button" />' },
+  /* All flavors of input */
+  { code: '<input role="button" />' },
+  { code: '<input type="button" role="button" />' },
+  { code: '<input type="checkbox" role="button" />' },
+  { code: '<input type="color" role="button" />' },
+  { code: '<input type="date" role="button" />' },
+  { code: '<input type="datetime" role="button" />' },
+  { code: '<input type="datetime-local" role="button" />' },
+  { code: '<input type="email" role="button" />' },
+  { code: '<input type="file" role="button" />' },
+  { code: '<input type="image" role="button" />' },
+  { code: '<input type="month" role="button" />' },
+  { code: '<input type="number" role="button" />' },
+  { code: '<input type="password" role="button" />' },
+  { code: '<input type="radio" role="button" />' },
+  { code: '<input type="range" role="button" />' },
+  { code: '<input type="reset" role="button" />' },
+  { code: '<input type="search" role="button" />' },
+  { code: '<input type="submit" role="button" />' },
+  { code: '<input type="tel" role="button" />' },
+  { code: '<input type="text" role="button" />' },
+  { code: '<input type="time" role="button" />' },
+  { code: '<input type="url" role="button" />' },
+  { code: '<input type="week" role="button" />' },
+  { code: '<input type="hidden" role="button" />' },
+  /* End all flavors of input */
+  { code: '<menuitem role="button" />;' },
+  { code: '<option className="foo" role="button" />' },
+  { code: '<select className="foo" role="button" />' },
+  { code: '<textarea className="foo" role="button" />' },
+  { code: '<tr role="button" />;' },
+  /* HTML elements with neither an interactive or non-interactive valence (static) */
+  { code: '<a role="button" />' },
+  { code: '<a role="img" />;' },
+  { code: '<a tabIndex="0" role="button" />' },
+  { code: '<a tabIndex="0" role="img" />' },
+  { code: '<acronym role="button" />;' },
+  { code: '<address role="button" />;' },
+  { code: '<applet role="button" />;' },
+  { code: '<aside role="button" />;' },
+  { code: '<audio role="button" />;' },
+  { code: '<b role="button" />;' },
+  { code: '<base role="button" />;' },
+  { code: '<bdi role="button" />;' },
+  { code: '<bdo role="button" />;' },
+  { code: '<big role="button" />;' },
+  { code: '<blink role="button" />;' },
+  { code: '<blockquote role="button" />;' },
+  { code: '<body role="button" />;' },
+  { code: '<br role="button" />;' },
+  { code: '<canvas role="button" />;' },
+  { code: '<caption role="button" />;' },
+  { code: '<center role="button" />;' },
+  { code: '<cite role="button" />;' },
+  { code: '<code role="button" />;' },
+  { code: '<col role="button" />;' },
+  { code: '<colgroup role="button" />;' },
+  { code: '<content role="button" />;' },
+  { code: '<data role="button" />;' },
+  { code: '<datalist role="button" />;' },
+  { code: '<del role="button" />;' },
+  { code: '<details role="button" />;' },
+  { code: '<dir role="button" />;' },
+  { code: '<div role="button" />;' },
+  { code: '<div className="foo" role="button" />;' },
+  { code: '<div className="foo" {...props} role="button" />;' },
+  { code: '<div aria-hidden role="button" />;' },
+  { code: '<div aria-hidden={true} role="button" />;' },
+  { code: '<div role="button" />;' },
+  { code: '<div role={undefined} role="button" />;' },
+  { code: '<div {...props} role="button" />;' },
+  { code: '<div onKeyUp={() => void 0} aria-hidden={false} role="button" />;' },
+  { code: '<dl role="button" />;' },
+  { code: '<em role="button" />;' },
+  { code: '<embed role="button" />;' },
+  { code: '<figcaption role="button" />;' },
+  { code: '<font role="button" />;' },
+  { code: '<footer role="button" />;' },
+  { code: '<frameset role="button" />;' },
+  { code: '<head role="button" />;' },
+  { code: '<header role="button" />;' },
+  { code: '<hgroup role="button" />;' },
+  { code: '<html role="button" />;' },
+  { code: '<i role="button" />;' },
+  { code: '<iframe role="button" />;' },
+  { code: '<ins role="button" />;' },
+  { code: '<kbd role="button" />;' },
+  { code: '<keygen role="button" />;' },
+  { code: '<label role="button" />;' },
+  { code: '<legend role="button" />;' },
+  { code: '<link role="button" />;' },
+  { code: '<map role="button" />;' },
+  { code: '<mark role="button" />;' },
+  { code: '<marquee role="button" />;' },
+  { code: '<menu role="button" />;' },
+  { code: '<meta role="button" />;' },
+  { code: '<meter role="button" />;' },
+  { code: '<noembed role="button" />;' },
+  { code: '<noscript role="button" />;' },
+  { code: '<object role="button" />;' },
+  { code: '<optgroup role="button" />;' },
+  { code: '<output role="button" />;' },
+  { code: '<p role="button" />;' },
+  { code: '<param role="button" />;' },
+  { code: '<picture role="button" />;' },
+  { code: '<pre role="button" />;' },
+  { code: '<progress role="button" />;' },
+  { code: '<q role="button" />;' },
+  { code: '<rp role="button" />;' },
+  { code: '<rt role="button" />;' },
+  { code: '<rtc role="button" />;' },
+  { code: '<ruby role="button" />;' },
+  { code: '<s role="button" />;' },
+  { code: '<samp role="button" />;' },
+  { code: '<script role="button" />;' },
+  { code: '<section role="button" />;' },
+  { code: '<small role="button" />;' },
+  { code: '<source role="button" />;' },
+  { code: '<spacer role="button" />;' },
+  { code: '<span role="button" />;' },
+  { code: '<strike role="button" />;' },
+  { code: '<strong role="button" />;' },
+  { code: '<style role="button" />;' },
+  { code: '<sub role="button" />;' },
+  { code: '<summary role="button" />;' },
+  { code: '<sup role="button" />;' },
+  { code: '<th role="button" />;' },
+  { code: '<time role="button" />;' },
+  { code: '<title role="button" />;' },
+  { code: '<track role="button" />;' },
+  { code: '<tt role="button" />;' },
+  { code: '<u role="button" />;' },
+  { code: '<var role="button" />;' },
+  { code: '<video role="button" />;' },
+  { code: '<wbr role="button" />;' },
+  { code: '<xmp role="button" />;' },
+  /* HTML elements attributed with an interactive role */
+  { code: '<div role="button" />;' },
+  { code: '<div role="checkbox" />;' },
+  { code: '<div role="columnheader" />;' },
+  { code: '<div role="combobox" />;' },
+  { code: '<div role="grid" />;' },
+  { code: '<div role="gridcell" />;' },
+  { code: '<div role="link" />;' },
+  { code: '<div role="listbox" />;' },
+  { code: '<div role="menu" />;' },
+  { code: '<div role="menubar" />;' },
+  { code: '<div role="menuitem" />;' },
+  { code: '<div role="menuitemcheckbox" />;' },
+  { code: '<div role="menuitemradio" />;' },
+  { code: '<div role="option" />;' },
+  { code: '<div role="progressbar" />;' },
+  { code: '<div role="radio" />;' },
+  { code: '<div role="radiogroup" />;' },
+  { code: '<div role="row" />;' },
+  { code: '<div role="rowheader" />;' },
+  { code: '<div role="searchbox" />;' },
+  { code: '<div role="slider" />;' },
+  { code: '<div role="spinbutton" />;' },
+  { code: '<div role="switch" />;' },
+  { code: '<div role="tab" />;' },
+  { code: '<div role="textbox" />;' },
+  { code: '<div role="treeitem" />;' },
+  /* Presentation is a special case role that indicates intentional static semantics */
+  { code: '<div role="presentation" />;' },
+  /* HTML elements attributed with an abstract role */
+  { code: '<div role="command" />;' },
+  { code: '<div role="composite" />;' },
+  { code: '<div role="input" />;' },
+  { code: '<div role="landmark" />;' },
+  { code: '<div role="range" />;' },
+  { code: '<div role="roletype" />;' },
+  { code: '<div role="section" />;' },
+  { code: '<div role="sectionhead" />;' },
+  { code: '<div role="select" />;' },
+  { code: '<div role="structure" />;' },
+  { code: '<div role="tablist" />;' },
+  { code: '<div role="toolbar" />;' },
+  { code: '<div role="tree" />;' },
+  { code: '<div role="treegrid" />;' },
+  { code: '<div role="widget" />;' },
+  { code: '<div role="window" />;' },
+  /* HTML elements with an inherent, non-interactive role, assigned an
+   * interactive role. */
+  { code: '<main role="button" />;' },
+  { code: '<area role="button" />;' },
+  { code: '<article role="button" />;' },
+  { code: '<article role="button" />;' },
+  { code: '<dd role="button" />;' },
+  { code: '<dfn role="button" />;' },
+  { code: '<dt role="button" />;' },
+  { code: '<fieldset role="button" />;' },
+  { code: '<figure role="button" />;' },
+  { code: '<form role="button" />;' },
+  { code: '<frame role="button" />;' },
+  { code: '<h1 role="button" />;' },
+  { code: '<h2 role="button" />;' },
+  { code: '<h3 role="button" />;' },
+  { code: '<h4 role="button" />;' },
+  { code: '<h5 role="button" />;' },
+  { code: '<h6 role="button" />;' },
+  { code: '<hr role="button" />;' },
+  { code: '<img role="button" />;' },
+  { code: '<li role="button" />;' },
+  { code: '<li role="presentation" />;' },
+  { code: '<nav role="button" />;' },
+  { code: '<ol role="button" />;' },
+  { code: '<table role="button" />;' },
+  { code: '<tbody role="button" />;' },
+  { code: '<td role="button" />;' },
+  { code: '<tfoot role="button" />;' },
+  { code: '<thead role="button" />;' },
+  { code: '<ul role="button" />;' },
+  /* HTML elements attributed with a non-interactive role */
+  { code: '<div role="alert" />;' },
+  { code: '<div role="alertdialog" />;' },
+  { code: '<div role="application" />;' },
+  { code: '<div role="article" />;' },
+  { code: '<div role="banner" />;' },
+  { code: '<div role="cell" />;' },
+  { code: '<div role="complementary" />;' },
+  { code: '<div role="contentinfo" />;' },
+  { code: '<div role="definition" />;' },
+  { code: '<div role="dialog" />;' },
+  { code: '<div role="directory" />;' },
+  { code: '<div role="document" />;' },
+  { code: '<div role="feed" />;' },
+  { code: '<div role="figure" />;' },
+  { code: '<div role="form" />;' },
+  { code: '<div role="group" />;' },
+  { code: '<div role="heading" />;' },
+  { code: '<div role="img" />;' },
+  { code: '<div role="list" />;' },
+  { code: '<div role="listitem" />;' },
+  { code: '<div role="log" />;' },
+  { code: '<div role="main" />;' },
+  { code: '<div role="marquee" />;' },
+  { code: '<div role="math" />;' },
+  { code: '<div role="navigation" />;' },
+  { code: '<div role="note" />;' },
+  { code: '<div role="region" />;' },
+  { code: '<div role="rowgroup" />;' },
+  { code: '<div role="search" />;' },
+  { code: '<div role="separator" />;' },
+  { code: '<div role="scrollbar" />;' },
+  { code: '<div role="status" />;' },
+  { code: '<div role="table" />;' },
+  { code: '<div role="tabpanel" />;' },
+  { code: '<div role="term" />;' },
+  { code: '<div role="timer" />;' },
+  { code: '<div role="tooltip" />;' },
+  /* Namespaced roles are not checked */
+  { code: '<div mynamespace:role="term" />' },
+  { code: '<input mynamespace:role="img" />' },
+  { code: '<Link href="http://x.y.z" role="img" />' },
+  { code: '<Link href="http://x.y.z" />', settings: componentsSettings },
+  { code: '<Button onClick={doFoo} />', settings: componentsSettings },
+];
+
+const neverValid = [
+  /* Interactive elements */
+  { code: '<a href="http://x.y.z" role="img" />', errors: [expectedError] },
+  { code: '<a href="http://x.y.z" tabIndex="0" role="img" />', errors: [expectedError] },
+  /* All flavors of input */
+  { code: '<input role="img" />', errors: [expectedError] },
+  { code: '<input type="img" role="img" />', errors: [expectedError] },
+  { code: '<input type="checkbox" role="img" />', errors: [expectedError] },
+  { code: '<input type="color" role="img" />', errors: [expectedError] },
+  { code: '<input type="date" role="img" />', errors: [expectedError] },
+  { code: '<input type="datetime" role="img" />', errors: [expectedError] },
+  { code: '<input type="datetime-local" role="img" />', errors: [expectedError] },
+  { code: '<input type="email" role="img" />', errors: [expectedError] },
+  { code: '<input type="file" role="img" />', errors: [expectedError] },
+  { code: '<input type="hidden" role="img" />', errors: [expectedError] },
+  { code: '<input type="image" role="img" />', errors: [expectedError] },
+  { code: '<input type="month" role="img" />', errors: [expectedError] },
+  { code: '<input type="number" role="img" />', errors: [expectedError] },
+  { code: '<input type="password" role="img" />', errors: [expectedError] },
+  { code: '<input type="radio" role="img" />', errors: [expectedError] },
+  { code: '<input type="range" role="img" />', errors: [expectedError] },
+  { code: '<input type="reset" role="img" />', errors: [expectedError] },
+  { code: '<input type="search" role="img" />', errors: [expectedError] },
+  { code: '<input type="submit" role="img" />', errors: [expectedError] },
+  { code: '<input type="tel" role="img" />', errors: [expectedError] },
+  { code: '<input type="text" role="img" />', errors: [expectedError] },
+  { code: '<input type="time" role="img" />', errors: [expectedError] },
+  { code: '<input type="url" role="img" />', errors: [expectedError] },
+  { code: '<input type="week" role="img" />', errors: [expectedError] },
+  /* End all flavors of input */
+  { code: '<menuitem role="img" />;', errors: [expectedError] },
+  { code: '<option className="foo" role="img" />', errors: [expectedError] },
+  { code: '<select className="foo" role="img" />', errors: [expectedError] },
+  { code: '<textarea className="foo" role="img" />', errors: [expectedError] },
+  { code: '<tr role="img" />;', errors: [expectedError] },
+  /* Interactive elements */
+  { code: '<a href="http://x.y.z" role="listitem" />', errors: [expectedError] },
+  { code: '<a href="http://x.y.z" tabIndex="0" role="listitem" />', errors: [expectedError] },
+  /* All flavors of input */
+  { code: '<input role="listitem" />', errors: [expectedError] },
+  { code: '<input type="listitem" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="checkbox" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="color" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="date" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="datetime" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="datetime-local" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="email" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="file" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="image" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="month" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="number" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="password" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="radio" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="range" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="reset" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="search" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="submit" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="tel" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="text" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="time" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="url" role="listitem" />', errors: [expectedError] },
+  { code: '<input type="week" role="listitem" />', errors: [expectedError] },
+  /* End all flavors of input */
+  { code: '<menuitem role="listitem" />;', errors: [expectedError] },
+  { code: '<option className="foo" role="listitem" />', errors: [expectedError] },
+  { code: '<select className="foo" role="listitem" />', errors: [expectedError] },
+  { code: '<textarea className="foo" role="listitem" />', errors: [expectedError] },
+  { code: '<tr role="listitem" />;', errors: [expectedError] },
+  /* Custom elements */
+  { code: '<Link href="http://x.y.z" role="img" />', errors: [expectedError], settings: componentsSettings },
+];
+
+const recommendedOptions = (configs.recommended.rules[ruleName][1] || {});
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    { code: '<tr role="presentation" />;' },
+    { code: '<canvas role="img" />;' },
+    { code: '<Component role="presentation" />;' },
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+});
+
+ruleTester.run(`${ruleName}:strict`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    { code: '<tr role="presentation" />;', errors: [expectedError] },
+    { code: '<canvas role="img" />;', errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-element-interactions-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-element-interactions-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-element-interactions-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,502 @@
+/**
+ * @fileoverview Enforce non-interactive elements have no interactive handlers.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import { configs } from '../../../src/index';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-noninteractive-element-interactions';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = 'Non-interactive elements should not be assigned mouse or keyboard event listeners.';
+
+const expectedError = {
+  message: errorMessage,
+  type: 'JSXOpeningElement',
+};
+
+const ruleName = 'no-noninteractive-element-interactions';
+
+const alwaysValid = [
+  { code: '<TestComponent onClick={doFoo} />' },
+  { code: '<Button onClick={doFoo} />' },
+  { code: '<Image onClick={() => void 0} />;' },
+  {
+    code: '<Button onClick={() => void 0} />;',
+    settings: { 'jsx-a11y': { components: { Button: 'button' } } },
+  },
+  /* All flavors of input */
+  { code: '<input onClick={() => void 0} />' },
+  { code: '<input type="button" onClick={() => void 0} />' },
+  { code: '<input type="checkbox" onClick={() => void 0} />' },
+  { code: '<input type="color" onClick={() => void 0} />' },
+  { code: '<input type="date" onClick={() => void 0} />' },
+  { code: '<input type="datetime" onClick={() => void 0} />' },
+  { code: '<input type="datetime-local" onClick={() => void 0} />' },
+  { code: '<input type="email" onClick={() => void 0} />' },
+  { code: '<input type="file" onClick={() => void 0} />' },
+  { code: '<input type="image" onClick={() => void 0} />' },
+  { code: '<input type="month" onClick={() => void 0} />' },
+  { code: '<input type="number" onClick={() => void 0} />' },
+  { code: '<input type="password" onClick={() => void 0} />' },
+  { code: '<input type="radio" onClick={() => void 0} />' },
+  { code: '<input type="range" onClick={() => void 0} />' },
+  { code: '<input type="reset" onClick={() => void 0} />' },
+  { code: '<input type="search" onClick={() => void 0} />' },
+  { code: '<input type="submit" onClick={() => void 0} />' },
+  { code: '<input type="tel" onClick={() => void 0} />' },
+  { code: '<input type="text" onClick={() => void 0} />' },
+  { code: '<input type="time" onClick={() => void 0} />' },
+  { code: '<input type="url" onClick={() => void 0} />' },
+  { code: '<input type="week" onClick={() => void 0} />' },
+  { code: '<input type="hidden" onClick={() => void 0} />' },
+  /* End all flavors of input */
+  { code: '<a onClick={() => void 0} />' },
+  { code: '<a onClick={() => {}} />;' },
+  { code: '<a tabIndex="0" onClick={() => void 0} />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" tabIndex="0" />' },
+  { code: '<area onClick={() => {}} />;' },
+  { code: '<body onClick={() => {}} />;' },
+  { code: '<button onClick={() => void 0} className="foo" />' },
+  { code: '<menuitem onClick={() => {}} />;' },
+  { code: '<option onClick={() => void 0} className="foo" />' },
+  { code: '<select onClick={() => void 0} className="foo" />' },
+  { code: '<textarea onClick={() => void 0} className="foo" />' },
+  { code: '<tr onClick={() => {}} />;' },
+  /* HTML elements with neither an interactive or non-interactive valence (static) */
+  { code: '<acronym onClick={() => {}} />;' },
+  { code: '<applet onClick={() => {}} />;' },
+  { code: '<audio onClick={() => {}} />;' },
+  { code: '<b onClick={() => {}} />;' },
+  { code: '<base onClick={() => {}} />;' },
+  { code: '<bdi onClick={() => {}} />;' },
+  { code: '<bdo onClick={() => {}} />;' },
+  { code: '<big onClick={() => {}} />;' },
+  { code: '<blink onClick={() => {}} />;' },
+  { code: '<body onLoad={() => {}} />;' },
+  { code: '<canvas onClick={() => {}} />;' },
+  { code: '<center onClick={() => {}} />;' },
+  { code: '<cite onClick={() => {}} />;' },
+  { code: '<col onClick={() => {}} />;' },
+  { code: '<colgroup onClick={() => {}} />;' },
+  { code: '<content onClick={() => {}} />;' },
+  { code: '<data onClick={() => {}} />;' },
+  { code: '<datalist onClick={() => {}} />;' },
+  { code: '<div />;' },
+  { code: '<div className="foo" />;' },
+  { code: '<div className="foo" {...props} />;' },
+  { code: '<div onClick={() => void 0} aria-hidden />;' },
+  { code: '<div onClick={() => void 0} aria-hidden={true} />;' },
+  { code: '<div onClick={() => void 0} />;' },
+  { code: '<div onClick={() => void 0} role={undefined} />;' },
+  { code: '<div onClick={() => void 0} {...props} />;' },
+  { code: '<div onClick={null} />;' },
+  { code: '<div onKeyUp={() => void 0} aria-hidden={false} />;' },
+  { code: '<embed onClick={() => {}} />;' },
+  { code: '<font onClick={() => {}} />;' },
+  { code: '<font onSubmit={() => {}} />;' },
+  { code: '<form onSubmit={() => {}} />;' },
+  {
+    code: `
+      <form onSubmit={this.handleSubmit.bind(this)} method="POST">
+        <button type="submit">
+            Save
+        </button>
+      </form>
+    `,
+  },
+  { code: '<frame onClick={() => {}} />;' },
+  { code: '<frameset onClick={() => {}} />;' },
+  { code: '<head onClick={() => {}} />;' },
+  { code: '<header onClick={() => {}} />;' },
+  { code: '<hgroup onClick={() => {}} />;' },
+  { code: '<i onClick={() => {}} />;' },
+  { code: '<iframe onLoad={() => {}} />;' },
+  {
+    code: `
+      <iframe
+        name="embeddedExternalPayment"
+        ref="embeddedExternalPayment"
+        style={iframeStyle}
+        onLoad={this.handleLoadIframe}
+      />
+    `,
+  },
+  { code: '<img {...props} onError={() => {}} />;' },
+  { code: '<img onLoad={() => {}} />;' },
+  { code: '<img src={currentPhoto.imageUrl} onLoad={this.handleImageLoad} alt="for review" />' },
+  {
+    code: `
+        <img
+        ref={this.ref}
+        className="c-responsive-image-placeholder__image"
+        src={src}
+        alt={alt}
+        data-test-id="test-id"
+        onLoad={this.fetchCompleteImage}
+      />
+    `,
+  },
+  { code: '<kbd onClick={() => {}} />;' },
+  { code: '<keygen onClick={() => {}} />;' },
+  { code: '<link onClick={() => {}} />;' },
+  { code: '<main onClick={null} />;' },
+  { code: '<map onClick={() => {}} />;' },
+  { code: '<meta onClick={() => {}} />;' },
+  { code: '<noembed onClick={() => {}} />;' },
+  { code: '<noscript onClick={() => {}} />;' },
+  { code: '<object onClick={() => {}} />;' },
+  { code: '<param onClick={() => {}} />;' },
+  { code: '<picture onClick={() => {}} />;' },
+  { code: '<q onClick={() => {}} />;' },
+  { code: '<rp onClick={() => {}} />;' },
+  { code: '<rt onClick={() => {}} />;' },
+  { code: '<rtc onClick={() => {}} />;' },
+  { code: '<s onClick={() => {}} />;' },
+  { code: '<samp onClick={() => {}} />;' },
+  { code: '<script onClick={() => {}} />;' },
+  { code: '<section onClick={() => {}} />;' },
+  { code: '<small onClick={() => {}} />;' },
+  { code: '<source onClick={() => {}} />;' },
+  { code: '<spacer onClick={() => {}} />;' },
+  { code: '<span onClick={() => {}} />;' },
+  { code: '<strike onClick={() => {}} />;' },
+  { code: '<style onClick={() => {}} />;' },
+  { code: '<summary onClick={() => {}} />;' },
+  { code: '<th onClick={() => {}} />;' },
+  { code: '<title onClick={() => {}} />;' },
+  { code: '<track onClick={() => {}} />;' },
+  { code: '<td onClick={() => {}} />;' },
+  { code: '<tt onClick={() => {}} />;' },
+  { code: '<u onClick={() => {}} />;' },
+  { code: '<var onClick={() => {}} />;' },
+  { code: '<video onClick={() => {}} />;' },
+  { code: '<wbr onClick={() => {}} />;' },
+  { code: '<xmp onClick={() => {}} />;' },
+  /* HTML elements attributed with an interactive role */
+  { code: '<div role="button" onClick={() => {}} />;' },
+  { code: '<div role="checkbox" onClick={() => {}} />;' },
+  { code: '<div role="columnheader" onClick={() => {}} />;' },
+  { code: '<div role="combobox" onClick={() => {}} />;' },
+  { code: '<div role="grid" onClick={() => {}} />;' },
+  { code: '<div role="gridcell" onClick={() => {}} />;' },
+  { code: '<div role="link" onClick={() => {}} />;' },
+  { code: '<div role="listbox" onClick={() => {}} />;' },
+  { code: '<div role="menu" onClick={() => {}} />;' },
+  { code: '<div role="menubar" onClick={() => {}} />;' },
+  { code: '<div role="menuitem" onClick={() => {}} />;' },
+  { code: '<div role="menuitemcheckbox" onClick={() => {}} />;' },
+  { code: '<div role="menuitemradio" onClick={() => {}} />;' },
+  { code: '<div role="option" onClick={() => {}} />;' },
+  { code: '<div role="progressbar" onClick={() => {}} />;' },
+  { code: '<div role="radio" onClick={() => {}} />;' },
+  { code: '<div role="radiogroup" onClick={() => {}} />;' },
+  { code: '<div role="row" onClick={() => {}} />;' },
+  { code: '<div role="rowheader" onClick={() => {}} />;' },
+  { code: '<div role="scrollbar" onClick={() => {}} />;' },
+  { code: '<div role="searchbox" onClick={() => {}} />;' },
+  { code: '<div role="slider" onClick={() => {}} />;' },
+  { code: '<div role="spinbutton" onClick={() => {}} />;' },
+  { code: '<div role="switch" onClick={() => {}} />;' },
+  { code: '<div role="tab" onClick={() => {}} />;' },
+  { code: '<div role="textbox" onClick={() => {}} />;' },
+  { code: '<div role="treeitem" onClick={() => {}} />;' },
+  /* Presentation is a special case role that indicates intentional static semantics */
+  { code: '<div role="presentation" onClick={() => {}} />;' },
+  /* HTML elements attributed with an abstract role */
+  { code: '<div role="command" onClick={() => {}} />;' },
+  { code: '<div role="composite" onClick={() => {}} />;' },
+  { code: '<div role="input" onClick={() => {}} />;' },
+  { code: '<div role="landmark" onClick={() => {}} />;' },
+  { code: '<div role="range" onClick={() => {}} />;' },
+  { code: '<div role="roletype" onClick={() => {}} />;' },
+  { code: '<div role="sectionhead" onClick={() => {}} />;' },
+  { code: '<div role="select" onClick={() => {}} />;' },
+  { code: '<div role="structure" onClick={() => {}} />;' },
+  { code: '<div role="tablist" onClick={() => {}} />;' },
+  { code: '<div role="toolbar" onClick={() => {}} />;' },
+  { code: '<div role="tree" onClick={() => {}} />;' },
+  { code: '<div role="treegrid" onClick={() => {}} />;' },
+  { code: '<div role="widget" onClick={() => {}} />;' },
+  { code: '<div role="window" onClick={() => {}} />;' },
+  // All the possible handlers
+  { code: '<div role="article" onCopy={() => {}} />;' },
+  { code: '<div role="article" onCut={() => {}} />;' },
+  { code: '<div role="article" onPaste={() => {}} />;' },
+  { code: '<div role="article" onCompositionEnd={() => {}} />;' },
+  { code: '<div role="article" onCompositionStart={() => {}} />;' },
+  { code: '<div role="article" onCompositionUpdate={() => {}} />;' },
+  { code: '<div role="article" onChange={() => {}} />;' },
+  { code: '<div role="article" onInput={() => {}} />;' },
+  { code: '<div role="article" onSubmit={() => {}} />;' },
+  { code: '<div role="article" onSelect={() => {}} />;' },
+  { code: '<div role="article" onTouchCancel={() => {}} />;' },
+  { code: '<div role="article" onTouchEnd={() => {}} />;' },
+  { code: '<div role="article" onTouchMove={() => {}} />;' },
+  { code: '<div role="article" onTouchStart={() => {}} />;' },
+  { code: '<div role="article" onScroll={() => {}} />;' },
+  { code: '<div role="article" onWheel={() => {}} />;' },
+  { code: '<div role="article" onAbort={() => {}} />;' },
+  { code: '<div role="article" onCanPlay={() => {}} />;' },
+  { code: '<div role="article" onCanPlayThrough={() => {}} />;' },
+  { code: '<div role="article" onDurationChange={() => {}} />;' },
+  { code: '<div role="article" onEmptied={() => {}} />;' },
+  { code: '<div role="article" onEncrypted={() => {}} />;' },
+  { code: '<div role="article" onEnded={() => {}} />;' },
+  { code: '<div role="article" onLoadedData={() => {}} />;' },
+  { code: '<div role="article" onLoadedMetadata={() => {}} />;' },
+  { code: '<div role="article" onLoadStart={() => {}} />;' },
+  { code: '<div role="article" onPause={() => {}} />;' },
+  { code: '<div role="article" onPlay={() => {}} />;' },
+  { code: '<div role="article" onPlaying={() => {}} />;' },
+  { code: '<div role="article" onProgress={() => {}} />;' },
+  { code: '<div role="article" onRateChange={() => {}} />;' },
+  { code: '<div role="article" onSeeked={() => {}} />;' },
+  { code: '<div role="article" onSeeking={() => {}} />;' },
+  { code: '<div role="article" onStalled={() => {}} />;' },
+  { code: '<div role="article" onSuspend={() => {}} />;' },
+  { code: '<div role="article" onTimeUpdate={() => {}} />;' },
+  { code: '<div role="article" onVolumeChange={() => {}} />;' },
+  { code: '<div role="article" onWaiting={() => {}} />;' },
+  { code: '<div role="article" onAnimationStart={() => {}} />;' },
+  { code: '<div role="article" onAnimationEnd={() => {}} />;' },
+  { code: '<div role="article" onAnimationIteration={() => {}} />;' },
+  { code: '<div role="article" onTransitionEnd={() => {}} />;' },
+];
+
+const neverValid = [
+  /* HTML elements with an inherent, non-interactive role */
+  { code: '<main onClick={() => void 0} />;', errors: [expectedError] },
+  { code: '<address onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<article onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<aside onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<blockquote onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<br onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<caption onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<code onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<dd onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<del onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<details onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<dfn onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<dl onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<dir onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<dt onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<em onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<fieldset onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<figcaption onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<figure onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<footer onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<form onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<h1 onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<h2 onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<h3 onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<h4 onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<h5 onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<h6 onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<hr onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<html onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<iframe onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<img onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<ins onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<label onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<legend onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<li onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<mark onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<marquee onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<menu onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<meter onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<nav onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<ol onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<optgroup onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<output onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<p onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<pre onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<progress onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<ruby onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<section onClick={() => {}} aria-label="Aardvark" />;', errors: [expectedError] },
+  { code: '<section onClick={() => {}} aria-labelledby="js_1" />;', errors: [expectedError] },
+  { code: '<strong onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<sub onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<sup onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<table onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<tbody onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<tfoot onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<thead onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<time onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<ul onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<ul contentEditable="false" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<article contentEditable onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div contentEditable role="article" onKeyDown={() => {}} />;', errors: [expectedError] },
+  /* HTML elements attributed with a non-interactive role */
+  { code: '<div role="alert" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="alertdialog" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="application" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="banner" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="cell" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="complementary" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="contentinfo" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="definition" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="dialog" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="directory" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="document" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="feed" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="figure" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="form" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="group" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="heading" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="img" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="list" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="listitem" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="log" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="main" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="marquee" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="math" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="navigation" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="note" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="region" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="rowgroup" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="search" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="separator" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="status" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="table" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="tabpanel" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="term" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="timer" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="tooltip" onClick={() => {}} />;', errors: [expectedError] },
+  // Handlers
+  { code: '<div role="article" onKeyDown={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="article" onKeyPress={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="article" onKeyUp={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="article" onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="article" onLoad={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="article" onError={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="article" onMouseDown={() => {}} />;', errors: [expectedError] },
+  { code: '<div role="article" onMouseUp={() => {}} />;', errors: [expectedError] },
+  // Custom component
+  {
+    code: '<Image onClick={() => void 0} />;',
+    errors: [expectedError],
+    settings: { 'jsx-a11y': { components: { Image: 'img' } } },
+  },
+];
+
+const recommendedOptions = configs.recommended.rules[`jsx-a11y/${ruleName}`][1] || {};
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    // All the possible handlers
+    { code: '<div role="article" onCopy={() => {}} />;' },
+    { code: '<div role="article" onCut={() => {}} />;' },
+    { code: '<div role="article" onPaste={() => {}} />;' },
+    { code: '<div role="article" onCompositionEnd={() => {}} />;' },
+    { code: '<div role="article" onCompositionStart={() => {}} />;' },
+    { code: '<div role="article" onCompositionUpdate={() => {}} />;' },
+    { code: '<div role="article" onFocus={() => {}} />;' },
+    { code: '<div role="article" onBlur={() => {}} />;' },
+    { code: '<div role="article" onChange={() => {}} />;' },
+    { code: '<div role="article" onInput={() => {}} />;' },
+    { code: '<div role="article" onSubmit={() => {}} />;' },
+    { code: '<div role="article" onContextMenu={() => {}} />;' },
+    { code: '<div role="article" onDblClick={() => {}} />;' },
+    { code: '<div role="article" onDoubleClick={() => {}} />;' },
+    { code: '<div role="article" onDrag={() => {}} />;' },
+    { code: '<div role="article" onDragEnd={() => {}} />;' },
+    { code: '<div role="article" onDragEnter={() => {}} />;' },
+    { code: '<div role="article" onDragExit={() => {}} />;' },
+    { code: '<div role="article" onDragLeave={() => {}} />;' },
+    { code: '<div role="article" onDragOver={() => {}} />;' },
+    { code: '<div role="article" onDragStart={() => {}} />;' },
+    { code: '<div role="article" onDrop={() => {}} />;' },
+    { code: '<div role="article" onMouseEnter={() => {}} />;' },
+    { code: '<div role="article" onMouseLeave={() => {}} />;' },
+    { code: '<div role="article" onMouseMove={() => {}} />;' },
+    { code: '<div role="article" onMouseOut={() => {}} />;' },
+    { code: '<div role="article" onMouseOver={() => {}} />;' },
+    { code: '<div role="article" onSelect={() => {}} />;' },
+    { code: '<div role="article" onTouchCancel={() => {}} />;' },
+    { code: '<div role="article" onTouchEnd={() => {}} />;' },
+    { code: '<div role="article" onTouchMove={() => {}} />;' },
+    { code: '<div role="article" onTouchStart={() => {}} />;' },
+    { code: '<div role="article" onScroll={() => {}} />;' },
+    { code: '<div role="article" onWheel={() => {}} />;' },
+    { code: '<div role="article" onAbort={() => {}} />;' },
+    { code: '<div role="article" onCanPlay={() => {}} />;' },
+    { code: '<div role="article" onCanPlayThrough={() => {}} />;' },
+    { code: '<div role="article" onDurationChange={() => {}} />;' },
+    { code: '<div role="article" onEmptied={() => {}} />;' },
+    { code: '<div role="article" onEncrypted={() => {}} />;' },
+    { code: '<div role="article" onEnded={() => {}} />;' },
+    { code: '<div role="article" onLoadedData={() => {}} />;' },
+    { code: '<div role="article" onLoadedMetadata={() => {}} />;' },
+    { code: '<div role="article" onLoadStart={() => {}} />;' },
+    { code: '<div role="article" onPause={() => {}} />;' },
+    { code: '<div role="article" onPlay={() => {}} />;' },
+    { code: '<div role="article" onPlaying={() => {}} />;' },
+    { code: '<div role="article" onProgress={() => {}} />;' },
+    { code: '<div role="article" onRateChange={() => {}} />;' },
+    { code: '<div role="article" onSeeked={() => {}} />;' },
+    { code: '<div role="article" onSeeking={() => {}} />;' },
+    { code: '<div role="article" onStalled={() => {}} />;' },
+    { code: '<div role="article" onSuspend={() => {}} />;' },
+    { code: '<div role="article" onTimeUpdate={() => {}} />;' },
+    { code: '<div role="article" onVolumeChange={() => {}} />;' },
+    { code: '<div role="article" onWaiting={() => {}} />;' },
+    { code: '<div role="article" onAnimationStart={() => {}} />;' },
+    { code: '<div role="article" onAnimationEnd={() => {}} />;' },
+    { code: '<div role="article" onAnimationIteration={() => {}} />;' },
+    { code: '<div role="article" onTransitionEnd={() => {}} />;' },
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+});
+
+const strictOptions = configs.strict.rules[`jsx-a11y/${ruleName}`][1] || {};
+ruleTester.run(`${ruleName}:strict`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+  ))
+    .map(ruleOptionsMapperFactory(strictOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    // All the possible handlers
+    { code: '<div role="article" onFocus={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onBlur={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onContextMenu={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDblClick={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDoubleClick={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDrag={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDragEnd={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDragEnter={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDragExit={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDragLeave={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDragOver={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDragStart={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onDrop={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onMouseEnter={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onMouseLeave={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onMouseMove={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onMouseOut={() => {}} />;', errors: [expectedError] },
+    { code: '<div role="article" onMouseOver={() => {}} />;', errors: [expectedError] },
+  ))
+    .map(ruleOptionsMapperFactory(strictOptions))
+    .map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,500 @@
+/**
+ * @fileoverview Disallow inherently non-interactive elements to be assigned
+ * interactive roles.
+ * @author Jesse Beach
+ * @author $AUTHOR
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import { configs } from '../../../src/index';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-noninteractive-element-to-interactive-role';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = 'Non-interactive elements should not be assigned interactive roles.';
+
+const expectedError = {
+  message: errorMessage,
+  type: 'JSXAttribute',
+};
+
+const ruleName = 'jsx-a11y/no-noninteractive-element-to-interactive-role';
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Article: 'article',
+      Input: 'input',
+    },
+  },
+};
+
+const alwaysValid = [
+  { code: '<TestComponent onClick={doFoo} />' },
+  { code: '<Button onClick={doFoo} />' },
+  /* Interactive elements */
+  { code: '<a tabIndex="0" role="button" />' },
+  { code: '<a href="http://x.y.z" role="button" />' },
+  { code: '<a href="http://x.y.z" tabIndex="0" role="button" />' },
+  { code: '<area role="button" />;' },
+  { code: '<area role="menuitem" />;' },
+  { code: '<button className="foo" role="button" />' },
+  { code: '<body role="button" />;' },
+  { code: '<frame role="button" />;' },
+  { code: '<td role="button" />;' },
+  { code: '<frame role="menuitem" />;' },
+  { code: '<td role="menuitem" />;' },
+  /* All flavors of input */
+  { code: '<input role="button" />' },
+  { code: '<input type="button" role="button" />' },
+  { code: '<input type="checkbox" role="button" />' },
+  { code: '<input type="color" role="button" />' },
+  { code: '<input type="date" role="button" />' },
+  { code: '<input type="datetime" role="button" />' },
+  { code: '<input type="datetime-local" role="button" />' },
+  { code: '<input type="email" role="button" />' },
+  { code: '<input type="file" role="button" />' },
+  { code: '<input type="hidden" role="button" />' },
+  { code: '<input type="image" role="button" />' },
+  { code: '<input type="month" role="button" />' },
+  { code: '<input type="number" role="button" />' },
+  { code: '<input type="password" role="button" />' },
+  { code: '<input type="radio" role="button" />' },
+  { code: '<input type="range" role="button" />' },
+  { code: '<input type="reset" role="button" />' },
+  { code: '<input type="search" role="button" />' },
+  { code: '<input type="submit" role="button" />' },
+  { code: '<input type="tel" role="button" />' },
+  { code: '<input type="text" role="button" />' },
+  { code: '<input type="time" role="button" />' },
+  { code: '<input type="url" role="button" />' },
+  { code: '<input type="week" role="button" />' },
+  { code: '<input type="hidden" role="img" />' },
+  /* End all flavors of input */
+  { code: '<menuitem role="button" />;' },
+  { code: '<option className="foo" role="button" />' },
+  { code: '<select className="foo" role="button" />' },
+  { code: '<textarea className="foo" role="button" />' },
+  { code: '<tr role="button" />;' },
+  { code: '<tr role="presentation" />;' },
+  /* Interactive elements */
+  { code: '<a tabIndex="0" role="img" />' },
+  { code: '<a href="http://x.y.z" role="img" />' },
+  { code: '<a href="http://x.y.z" tabIndex="0" role="img" />' },
+  /* All flavors of input */
+  { code: '<input role="img" />' },
+  { code: '<input type="img" role="img" />' },
+  { code: '<input type="checkbox" role="img" />' },
+  { code: '<input type="color" role="img" />' },
+  { code: '<input type="date" role="img" />' },
+  { code: '<input type="datetime" role="img" />' },
+  { code: '<input type="datetime-local" role="img" />' },
+  { code: '<input type="email" role="img" />' },
+  { code: '<input type="file" role="img" />' },
+  { code: '<input type="hidden" role="button" />' },
+  { code: '<input type="image" role="img" />' },
+  { code: '<input type="month" role="img" />' },
+  { code: '<input type="number" role="img" />' },
+  { code: '<input type="password" role="img" />' },
+  { code: '<input type="radio" role="img" />' },
+  { code: '<input type="range" role="img" />' },
+  { code: '<input type="reset" role="img" />' },
+  { code: '<input type="search" role="img" />' },
+  { code: '<input type="submit" role="img" />' },
+  { code: '<input type="tel" role="img" />' },
+  { code: '<input type="text" role="img" />' },
+  { code: '<input type="time" role="img" />' },
+  { code: '<input type="url" role="img" />' },
+  { code: '<input type="week" role="img" />' },
+  /* End all flavors of input */
+  { code: '<menuitem role="img" />;' },
+  { code: '<option className="foo" role="img" />' },
+  { code: '<select className="foo" role="img" />' },
+  { code: '<textarea className="foo" role="img" />' },
+  { code: '<tr role="img" />;' },
+  /* Interactive elements */
+  { code: '<a tabIndex="0" role="listitem" />' },
+  { code: '<a href="http://x.y.z" role="listitem" />' },
+  { code: '<a href="http://x.y.z" tabIndex="0" role="listitem" />' },
+  /* All flavors of input */
+  { code: '<input role="listitem" />' },
+  { code: '<input type="listitem" role="listitem" />' },
+  { code: '<input type="checkbox" role="listitem" />' },
+  { code: '<input type="color" role="listitem" />' },
+  { code: '<input type="date" role="listitem" />' },
+  { code: '<input type="datetime" role="listitem" />' },
+  { code: '<input type="datetime-local" role="listitem" />' },
+  { code: '<input type="email" role="listitem" />' },
+  { code: '<input type="file" role="listitem" />' },
+  { code: '<input type="image" role="listitem" />' },
+  { code: '<input type="month" role="listitem" />' },
+  { code: '<input type="number" role="listitem" />' },
+  { code: '<input type="password" role="listitem" />' },
+  { code: '<input type="radio" role="listitem" />' },
+  { code: '<input type="range" role="listitem" />' },
+  { code: '<input type="reset" role="listitem" />' },
+  { code: '<input type="search" role="listitem" />' },
+  { code: '<input type="submit" role="listitem" />' },
+  { code: '<input type="tel" role="listitem" />' },
+  { code: '<input type="text" role="listitem" />' },
+  { code: '<input type="time" role="listitem" />' },
+  { code: '<input type="url" role="listitem" />' },
+  { code: '<input type="week" role="listitem" />' },
+  /* End all flavors of input */
+  { code: '<menuitem role="listitem" />;' },
+  { code: '<option className="foo" role="listitem" />' },
+  { code: '<select className="foo" role="listitem" />' },
+  { code: '<textarea className="foo" role="listitem" />' },
+  { code: '<tr role="listitem" />;' },
+  /* HTML elements with neither an interactive or non-interactive valence (static) */
+  { code: '<acronym role="button" />;' },
+  { code: '<applet role="button" />;' },
+  { code: '<audio role="button" />;' },
+  { code: '<b role="button" />;' },
+  { code: '<base role="button" />;' },
+  { code: '<bdi role="button" />;' },
+  { code: '<bdo role="button" />;' },
+  { code: '<big role="button" />;' },
+  { code: '<blink role="button" />;' },
+  { code: '<canvas role="button" />;' },
+  { code: '<center role="button" />;' },
+  { code: '<cite role="button" />;' },
+  { code: '<col role="button" />;' },
+  { code: '<colgroup role="button" />;' },
+  { code: '<content role="button" />;' },
+  { code: '<data role="button" />;' },
+  { code: '<datalist role="button" />;' },
+  { code: '<div role="button" />;' },
+  { code: '<div className="foo" role="button" />;' },
+  { code: '<div className="foo" {...props} role="button" />;' },
+  { code: '<div aria-hidden role="button" />;' },
+  { code: '<div aria-hidden={true} role="button" />;' },
+  { code: '<div role="button" />;' },
+  { code: '<div role={undefined} role="button" />;' },
+  { code: '<div {...props} role="button" />;' },
+  { code: '<div onKeyUp={() => void 0} aria-hidden={false} role="button" />;' },
+  { code: '<embed role="button" />;' },
+  { code: '<font role="button" />;' },
+  { code: '<frameset role="button" />;' },
+  { code: '<head role="button" />;' },
+  { code: '<header role="button" />;' },
+  { code: '<hgroup role="button" />;' },
+  { code: '<i role="button" />;' },
+  { code: '<kbd role="button" />;' },
+  { code: '<keygen role="button" />;' },
+  { code: '<link role="button" />;' },
+  { code: '<map role="button" />;' },
+  { code: '<meta role="button" />;' },
+  { code: '<noembed role="button" />;' },
+  { code: '<noscript role="button" />;' },
+  { code: '<object role="button" />;' },
+  { code: '<param role="button" />;' },
+  { code: '<picture role="button" />;' },
+  { code: '<q role="button" />;' },
+  { code: '<rp role="button" />;' },
+  { code: '<rt role="button" />;' },
+  { code: '<rtc role="button" />;' },
+  { code: '<s role="button" />;' },
+  { code: '<samp role="button" />;' },
+  { code: '<script role="button" />;' },
+  { code: '<small role="button" />;' },
+  { code: '<source role="button" />;' },
+  { code: '<spacer role="button" />;' },
+  { code: '<span role="button" />;' },
+  { code: '<strike role="button" />;' },
+  { code: '<style role="button" />;' },
+  { code: '<summary role="button" />;' },
+  { code: '<th role="button" />;' },
+  { code: '<title role="button" />;' },
+  { code: '<track role="button" />;' },
+  { code: '<tt role="button" />;' },
+  { code: '<u role="button" />;' },
+  { code: '<var role="button" />;' },
+  { code: '<video role="button" />;' },
+  { code: '<wbr role="button" />;' },
+  { code: '<xmp role="button" />;' },
+  /* HTML elements attributed with an interactive role */
+  { code: '<div role="button" />;' },
+  { code: '<div role="checkbox" />;' },
+  { code: '<div role="columnheader" />;' },
+  { code: '<div role="combobox" />;' },
+  { code: '<div role="grid" />;' },
+  { code: '<div role="gridcell" />;' },
+  { code: '<div role="link" />;' },
+  { code: '<div role="listbox" />;' },
+  { code: '<div role="menu" />;' },
+  { code: '<div role="menubar" />;' },
+  { code: '<div role="menuitem" />;' },
+  { code: '<div role="menuitemcheckbox" />;' },
+  { code: '<div role="menuitemradio" />;' },
+  { code: '<div role="option" />;' },
+  { code: '<div role="progressbar" />;' },
+  { code: '<div role="radio" />;' },
+  { code: '<div role="radiogroup" />;' },
+  { code: '<div role="row" />;' },
+  { code: '<div role="rowheader" />;' },
+  { code: '<div role="searchbox" />;' },
+  { code: '<div role="slider" />;' },
+  { code: '<div role="spinbutton" />;' },
+  { code: '<div role="switch" />;' },
+  { code: '<div role="tab" />;' },
+  { code: '<div role="textbox" />;' },
+  { code: '<div role="treeitem" />;' },
+  /* Presentation is a special case role that indicates intentional static semantics */
+  { code: '<div role="presentation" />;' },
+  /* HTML elements attributed with an abstract role */
+  { code: '<div role="command" />;' },
+  { code: '<div role="composite" />;' },
+  { code: '<div role="input" />;' },
+  { code: '<div role="landmark" />;' },
+  { code: '<div role="range" />;' },
+  { code: '<div role="roletype" />;' },
+  { code: '<div role="section" />;' },
+  { code: '<div role="sectionhead" />;' },
+  { code: '<div role="select" />;' },
+  { code: '<div role="structure" />;' },
+  { code: '<div role="tablist" />;' },
+  { code: '<div role="toolbar" />;' },
+  { code: '<div role="tree" />;' },
+  { code: '<div role="treegrid" />;' },
+  { code: '<div role="widget" />;' },
+  { code: '<div role="window" />;' },
+  /* HTML elements with an inherent non-interactive role, assigned an
+   * interactive role. */
+  { code: '<main role="listitem" />;' },
+  { code: '<a role="listitem" />' },
+  { code: '<a role="listitem" />;' },
+  { code: '<a role="button" />' },
+  { code: '<a role="button" />;' },
+  { code: '<a role="menuitem" />' },
+  { code: '<a role="menuitem" />;' },
+  { code: '<area role="listitem" />;' },
+  { code: '<article role="listitem" />;' },
+  { code: '<article role="listitem" />;' },
+  { code: '<dd role="listitem" />;' },
+  { code: '<dfn role="listitem" />;' },
+  { code: '<dt role="listitem" />;' },
+  { code: '<fieldset role="listitem" />;' },
+  { code: '<figure role="listitem" />;' },
+  { code: '<form role="listitem" />;' },
+  { code: '<frame role="listitem" />;' },
+  { code: '<h1 role="listitem" />;' },
+  { code: '<h2 role="listitem" />;' },
+  { code: '<h3 role="listitem" />;' },
+  { code: '<h4 role="listitem" />;' },
+  { code: '<h5 role="listitem" />;' },
+  { code: '<h6 role="listitem" />;' },
+  { code: '<hr role="listitem" />;' },
+  { code: '<img role="listitem" />;' },
+  { code: '<li role="listitem" />;' },
+  { code: '<li role="presentation" />;' },
+  { code: '<nav role="listitem" />;' },
+  { code: '<ol role="listitem" />;' },
+  { code: '<table role="listitem" />;' },
+  { code: '<tbody role="listitem" />;' },
+  { code: '<td role="listitem" />;' },
+  { code: '<tfoot role="listitem" />;' },
+  { code: '<thead role="listitem" />;' },
+  { code: '<ul role="listitem" />;' },
+  /* HTML elements attributed with a non-interactive role */
+  { code: '<div role="alert" />;' },
+  { code: '<div role="alertdialog" />;' },
+  { code: '<div role="application" />;' },
+  { code: '<div role="article" />;' },
+  { code: '<div role="banner" />;' },
+  { code: '<div role="cell" />;' },
+  { code: '<div role="complementary" />;' },
+  { code: '<div role="contentinfo" />;' },
+  { code: '<div role="definition" />;' },
+  { code: '<div role="dialog" />;' },
+  { code: '<div role="directory" />;' },
+  { code: '<div role="document" />;' },
+  { code: '<div role="feed" />;' },
+  { code: '<div role="figure" />;' },
+  { code: '<div role="form" />;' },
+  { code: '<div role="group" />;' },
+  { code: '<div role="heading" />;' },
+  { code: '<div role="img" />;' },
+  { code: '<div role="list" />;' },
+  { code: '<div role="listitem" />;' },
+  { code: '<div role="log" />;' },
+  { code: '<div role="main" />;' },
+  { code: '<div role="marquee" />;' },
+  { code: '<div role="math" />;' },
+  { code: '<div role="navigation" />;' },
+  { code: '<div role="note" />;' },
+  { code: '<div role="region" />;' },
+  { code: '<div role="rowgroup" />;' },
+  { code: '<div role="search" />;' },
+  { code: '<div role="separator" />;' },
+  { code: '<div role="scrollbar" />;' },
+  { code: '<div role="status" />;' },
+  { code: '<div role="table" />;' },
+  { code: '<div role="tabpanel" />;' },
+  { code: '<div role="term" />;' },
+  { code: '<div role="timer" />;' },
+  { code: '<div role="tooltip" />;' },
+  { code: '<ul role="list" />;' },
+  /* Custom components */
+  { code: '<Article role="button" />' },
+  { code: '<Input role="button" />', settings: componentsSettings },
+];
+
+const neverValid = [
+  /* HTML elements with an inherent non-interactive role, assigned an
+   * interactive role. */
+  { code: '<address role="button" />;', errors: [expectedError] },
+  { code: '<article role="button" />;', errors: [expectedError] },
+  { code: '<aside role="button" />;', errors: [expectedError] },
+  { code: '<blockquote role="button" />;', errors: [expectedError] },
+  { code: '<br role="button" />;', errors: [expectedError] },
+  { code: '<caption role="button" />;', errors: [expectedError] },
+  { code: '<code role="button" />;', errors: [expectedError] },
+  { code: '<dd role="button" />;', errors: [expectedError] },
+  { code: '<del role="button" />;', errors: [expectedError] },
+  { code: '<details role="button" />;', errors: [expectedError] },
+  { code: '<dfn role="button" />;', errors: [expectedError] },
+  { code: '<dir role="button" />;', errors: [expectedError] },
+  { code: '<dl role="button" />;', errors: [expectedError] },
+  { code: '<dt role="button" />;', errors: [expectedError] },
+  { code: '<em role="button" />;', errors: [expectedError] },
+  { code: '<fieldset role="button" />;', errors: [expectedError] },
+  { code: '<figcaption role="button" />;', errors: [expectedError] },
+  { code: '<figure role="button" />;', errors: [expectedError] },
+  { code: '<footer role="button" />;', errors: [expectedError] },
+  { code: '<form role="button" />;', errors: [expectedError] },
+  { code: '<h1 role="button" />;', errors: [expectedError] },
+  { code: '<h2 role="button" />;', errors: [expectedError] },
+  { code: '<h3 role="button" />;', errors: [expectedError] },
+  { code: '<h4 role="button" />;', errors: [expectedError] },
+  { code: '<h5 role="button" />;', errors: [expectedError] },
+  { code: '<h6 role="button" />;', errors: [expectedError] },
+  { code: '<hr role="button" />;', errors: [expectedError] },
+  { code: '<html role="button" />;', errors: [expectedError] },
+  { code: '<iframe role="button" />;', errors: [expectedError] },
+  { code: '<img role="button" />;', errors: [expectedError] },
+  { code: '<ins role="button" />;', errors: [expectedError] },
+  { code: '<label role="button" />;', errors: [expectedError] },
+  { code: '<legend role="button" />;', errors: [expectedError] },
+  { code: '<li role="button" />;', errors: [expectedError] },
+  { code: '<main role="button" />;', errors: [expectedError] },
+  { code: '<mark role="button" />;', errors: [expectedError] },
+  { code: '<marquee role="button" />;', errors: [expectedError] },
+  { code: '<menu role="button" />;', errors: [expectedError] },
+  { code: '<meter role="button" />;', errors: [expectedError] },
+  { code: '<nav role="button" />;', errors: [expectedError] },
+  { code: '<ol role="button" />;', errors: [expectedError] },
+  { code: '<optgroup role="button" />;', errors: [expectedError] },
+  { code: '<output role="button" />;', errors: [expectedError] },
+  { code: '<pre role="button" />;', errors: [expectedError] },
+  { code: '<progress role="button" />;', errors: [expectedError] },
+  { code: '<ruby role="button" />;', errors: [expectedError] },
+  { code: '<strong role="button" />;', errors: [expectedError] },
+  { code: '<sub role="button" />;', errors: [expectedError] },
+  { code: '<sup role="button" />;', errors: [expectedError] },
+  { code: '<table role="button" />;', errors: [expectedError] },
+  { code: '<tbody role="button" />;', errors: [expectedError] },
+  { code: '<tfoot role="button" />;', errors: [expectedError] },
+  { code: '<thead role="button" />;', errors: [expectedError] },
+  { code: '<time role="button" />;', errors: [expectedError] },
+  { code: '<ul role="button" />;', errors: [expectedError] },
+  /* HTML elements with an inherent non-interactive role, assigned an
+   * interactive role. */
+  { code: '<main role="menuitem" />;', errors: [expectedError] },
+  { code: '<article role="menuitem" />;', errors: [expectedError] },
+  { code: '<dd role="menuitem" />;', errors: [expectedError] },
+  { code: '<dfn role="menuitem" />;', errors: [expectedError] },
+  { code: '<dt role="menuitem" />;', errors: [expectedError] },
+  { code: '<fieldset role="menuitem" />;', errors: [expectedError] },
+  { code: '<figure role="menuitem" />;', errors: [expectedError] },
+  { code: '<form role="menuitem" />;', errors: [expectedError] },
+  { code: '<h1 role="menuitem" />;', errors: [expectedError] },
+  { code: '<h2 role="menuitem" />;', errors: [expectedError] },
+  { code: '<h3 role="menuitem" />;', errors: [expectedError] },
+  { code: '<h4 role="menuitem" />;', errors: [expectedError] },
+  { code: '<h5 role="menuitem" />;', errors: [expectedError] },
+  { code: '<h6 role="menuitem" />;', errors: [expectedError] },
+  { code: '<hr role="menuitem" />;', errors: [expectedError] },
+  { code: '<img role="menuitem" />;', errors: [expectedError] },
+  { code: '<nav role="menuitem" />;', errors: [expectedError] },
+  { code: '<ol role="menuitem" />;', errors: [expectedError] },
+  { code: '<p role="button" />;', errors: [expectedError] },
+  { code: '<section role="button" aria-label="Aardvark" />;', errors: [expectedError] },
+  { code: '<table role="menuitem" />;', errors: [expectedError] },
+  { code: '<tbody role="menuitem" />;', errors: [expectedError] },
+  { code: '<tfoot role="menuitem" />;', errors: [expectedError] },
+  { code: '<thead role="menuitem" />;', errors: [expectedError] },
+  /* Custom components */
+  { code: '<Article role="button" />', errors: [expectedError], settings: componentsSettings },
+];
+
+const recommendedOptions = (configs.recommended.rules[ruleName][1] || {});
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    { code: '<ul role="menu" />;' },
+    { code: '<ul role="menubar" />;' },
+    { code: '<ul role="radiogroup" />;' },
+    { code: '<ul role="tablist" />;' },
+    { code: '<ul role="tree" />;' },
+    { code: '<ul role="treegrid" />;' },
+    { code: '<ol role="menu" />;' },
+    { code: '<ol role="menubar" />;' },
+    { code: '<ol role="radiogroup" />;' },
+    { code: '<ol role="tablist" />;' },
+    { code: '<ol role="tree" />;' },
+    { code: '<ol role="treegrid" />;' },
+    { code: '<li role="tab" />;' },
+    { code: '<li role="menuitem" />;' },
+    { code: '<li role="menuitemcheckbox" />;' },
+    { code: '<li role="menuitemradio" />;' },
+    { code: '<li role="row" />;' },
+    { code: '<li role="treeitem" />;' },
+    { code: '<Component role="treeitem" />;' },
+    { code: '<fieldset role="radiogroup" />;' },
+    { code: '<fieldset role="presentation" />;' },
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+});
+
+ruleTester.run(`${ruleName}:strict`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    { code: '<ul role="menu" />;', errors: [expectedError] },
+    { code: '<ul role="menubar" />;', errors: [expectedError] },
+    { code: '<ul role="radiogroup" />;', errors: [expectedError] },
+    { code: '<ul role="tablist" />;', errors: [expectedError] },
+    { code: '<ul role="tree" />;', errors: [expectedError] },
+    { code: '<ul role="treegrid" />;', errors: [expectedError] },
+    { code: '<ol role="menu" />;', errors: [expectedError] },
+    { code: '<ol role="menubar" />;', errors: [expectedError] },
+    { code: '<ol role="radiogroup" />;', errors: [expectedError] },
+    { code: '<ol role="tablist" />;', errors: [expectedError] },
+    { code: '<ol role="tree" />;', errors: [expectedError] },
+    { code: '<ol role="treegrid" />;', errors: [expectedError] },
+    { code: '<li role="tab" />;', errors: [expectedError] },
+    { code: '<li role="menuitem" />;', errors: [expectedError] },
+    { code: '<li role="row" />;', errors: [expectedError] },
+    { code: '<li role="treeitem" />;', errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-tabindex-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-tabindex-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-noninteractive-tabindex-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,123 @@
+/**
+ * @fileoverview Disallow tabindex on static and noninteractive elements
+ * @author jessebeach
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import { configs } from '../../../src/index';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-noninteractive-tabindex';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const ruleName = 'no-noninteractive-tabindex';
+
+const expectedError = {
+  message: '`tabIndex` should only be declared on interactive elements.',
+  type: 'JSXAttribute',
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Article: 'article',
+      MyButton: 'button',
+    },
+  },
+};
+
+const alwaysValid = [
+  { code: '<MyButton tabIndex={0} />' },
+  { code: '<button />' },
+  { code: '<button tabIndex="0" />' },
+  { code: '<button tabIndex={0} />' },
+  { code: '<div />' },
+  { code: '<div tabIndex="-1" />' },
+  { code: '<div role="button" tabIndex="0" />' },
+  { code: '<div role="article" tabIndex="-1" />' },
+  { code: '<article tabIndex="-1" />' },
+  { code: '<Article tabIndex="-1" />', settings: componentsSettings },
+  { code: '<MyButton tabIndex={0} />', settings: componentsSettings },
+];
+
+const neverValid = [
+  { code: '<div tabIndex="0" />', errors: [expectedError] },
+  { code: '<div role="article" tabIndex="0" />', errors: [expectedError] },
+  { code: '<article tabIndex="0" />', errors: [expectedError] },
+  { code: '<article tabIndex={0} />', errors: [expectedError] },
+  { code: '<Article tabIndex={0} />', errors: [expectedError], settings: componentsSettings },
+];
+
+const recommendedOptions = (
+  configs.recommended.rules[`jsx-a11y/${ruleName}`][1] || {}
+);
+
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    { code: '<div role="tabpanel" tabIndex="0" />' },
+    // Expressions should pass in recommended mode
+    { code: '<div role={ROLE_BUTTON} onClick={() => {}} tabIndex="0" />;' },
+    // Cases for allowExpressionValues set to true
+    {
+      code: '<div role={BUTTON} onClick={() => {}} tabIndex="0" />;',
+      options: [{ allowExpressionValues: true }],
+    },
+    // Specific case for ternary operator with literals on both side
+    {
+      code: '<div role={isButton ? "button" : "link"} onClick={() => {}} tabIndex="0" />;',
+      options: [{ allowExpressionValues: true }],
+    },
+    {
+      code: '<div role={isButton ? "button" : LINK} onClick={() => {}} tabIndex="0" />;',
+      options: [{ allowExpressionValues: true }],
+      errors: [expectedError],
+    },
+    {
+      code: '<div role={isButton ? BUTTON : LINK} onClick={() => {}} tabIndex="0"/>;',
+      options: [{ allowExpressionValues: true }],
+      errors: [expectedError],
+    },
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+});
+
+ruleTester.run(`${ruleName}:strict`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    { code: '<div role="tabpanel" tabIndex="0" />', errors: [expectedError] },
+    // Expressions should fail in strict mode
+    { code: '<div role={ROLE_BUTTON} onClick={() => {}} tabIndex="0" />;', errors: [expectedError] },
+    // Cases for allowExpressionValues set to false
+    {
+      code: '<div role={BUTTON} onClick={() => {}} tabIndex="0" />;',
+      options: [{ allowExpressionValues: false }],
+      errors: [expectedError],
+    },
+    // Specific case for ternary operator with literals on both side
+    {
+      code: '<div role={isButton ? "button" : "link"} onClick={() => {}} tabIndex="0" />;',
+      options: [{ allowExpressionValues: false }],
+      errors: [expectedError],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-onchange-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-onchange-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-onchange-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,57 @@
+/**
+ * @fileoverview Enforce usage of onBlur over onChange on select menus for accessibility.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-onchange';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'onBlur must be used instead of onchange, unless absolutely necessary and it causes no negative consequences for keyboard only or screen reader users.',
+  type: 'JSXOpeningElement',
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      CustomOption: 'option',
+      Input: 'input',
+    },
+  },
+};
+
+ruleTester.run('no-onchange', rule, {
+  valid: parsers.all([].concat(
+    { code: '<select onBlur={() => {}} />;' },
+    { code: '<select onBlur={handleOnBlur} />;' },
+    { code: '<option />;' },
+    { code: '<option onBlur={() => {}} onChange={() => {}} />;' },
+    { code: '<option {...props} />' },
+    { code: '<input onChange={() => {}} />;' },
+    { code: '<input onChange={handleOnChange} />;' },
+    { code: '<input />;' },
+    { code: '<input onChange={() => {}} onChange={() => {}} />;' },
+    { code: '<input {...props} />' },
+    { code: '<Input onChange={() => {}} />;', settings: componentsSettings },
+    { code: '<CustomOption onChange={() => {}} />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<select onChange={() => {}} />;', errors: [expectedError] },
+    { code: '<select onChange={handleOnChange} />;', errors: [expectedError] },
+    { code: '<option onChange={() => {}} />', errors: [expectedError] },
+    { code: '<option onChange={() => {}} {...props} />', errors: [expectedError] },
+    { code: '<CustomOption onChange={() => {}} />;', errors: [expectedError], settings: componentsSettings },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-redundant-roles-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-redundant-roles-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-redundant-roles-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,98 @@
+/**
+ * @fileoverview Enforce explicit role property is not the
+ * same as implicit default role property on element.
+ * @author Ethan Cohen <@evcohen>
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-redundant-roles';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = (element, implicitRole) => ({
+  message: `The element ${element} has an implicit role of ${implicitRole}. Defining this explicitly is redundant and should be avoided.`,
+  type: 'JSXOpeningElement',
+});
+
+const ruleName = 'jsx-a11y/no-redundant-roles';
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Button: 'button',
+    },
+  },
+};
+
+const alwaysValid = [
+  { code: '<div />;' },
+  { code: '<button role="main" />' },
+  { code: '<MyComponent role="button" />' },
+  { code: '<button role={`${foo}button`} />' },
+  { code: '<Button role={`${foo}button`} />', settings: componentsSettings },
+];
+
+const neverValid = [
+  { code: '<button role="button" />', errors: [expectedError('button', 'button')] },
+  { code: '<body role="DOCUMENT" />', errors: [expectedError('body', 'document')] },
+  { code: '<Button role="button" />', settings: componentsSettings, errors: [expectedError('button', 'button')] },
+];
+
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    ...alwaysValid,
+    { code: '<nav role="navigation" />' },
+  ))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    neverValid,
+  ))
+    .map(parserOptionsMapper),
+});
+
+const noNavExceptionsOptions = { nav: [] };
+const listException = { ul: ['list'], ol: ['list'] };
+
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    alwaysValid
+      .map(ruleOptionsMapperFactory(noNavExceptionsOptions)),
+  ))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    ...neverValid,
+    { code: '<nav role="navigation" />', errors: [expectedError('nav', 'navigation')] },
+  ))
+    .map(ruleOptionsMapperFactory(noNavExceptionsOptions))
+    .map(parserOptionsMapper),
+});
+
+ruleTester.run(`${ruleName}:recommended (valid list role override)`, rule, {
+  valid: parsers.all([].concat(
+    { code: '<ul role="list" />' },
+    { code: '<ol role="list" />' },
+    { code: '<dl role="list" />' },
+    { code: '<img src="example.svg" role="img" />' },
+    { code: '<svg role="img" />' },
+  ))
+    .map(ruleOptionsMapperFactory(listException))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<ul role="list" />', errors: [expectedError('ul', 'list')] },
+    { code: '<ol role="list" />', errors: [expectedError('ol', 'list')] },
+    { code: '<img role="img" />', errors: [expectedError('img', 'img')] },
+    { code: '<img src={someVariable} role="img" />', errors: [expectedError('img', 'img')] },
+  ))
+    .map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-static-element-interactions-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-static-element-interactions-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/no-static-element-interactions-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,501 @@
+/**
+ * @fileoverview Enforce static elements have no interactive handlers.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import { configs } from '../../../src/index';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/no-static-element-interactions';
+import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = 'Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive content element.';
+
+const expectedError = {
+  message: errorMessage,
+  type: 'JSXOpeningElement',
+};
+
+const ruleName = 'no-static-element-interactions';
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Button: 'button',
+      TestComponent: 'div',
+    },
+  },
+};
+
+const alwaysValid = [
+  { code: '<TestComponent onClick={doFoo} />' },
+  { code: '<Button onClick={doFoo} />' },
+  { code: '<Button onClick={doFoo} />', settings: componentsSettings },
+  { code: '<div />;' },
+  { code: '<div className="foo" />;' },
+  { code: '<div className="foo" {...props} />;' },
+  { code: '<div onClick={() => void 0} aria-hidden />;' },
+  { code: '<div onClick={() => void 0} aria-hidden={true} />;' },
+  { code: '<div onClick={null} />;' },
+  /* All flavors of input */
+  { code: '<input onClick={() => void 0} />' },
+  { code: '<input type="button" onClick={() => void 0} />' },
+  { code: '<input type="checkbox" onClick={() => void 0} />' },
+  { code: '<input type="color" onClick={() => void 0} />' },
+  { code: '<input type="date" onClick={() => void 0} />' },
+  { code: '<input type="datetime" onClick={() => void 0} />' },
+  { code: '<input type="datetime-local" onClick={() => void 0} />' },
+  { code: '<input type="email" onClick={() => void 0} />' },
+  { code: '<input type="file" onClick={() => void 0} />' },
+  { code: '<input type="hidden" onClick={() => void 0} />' },
+  { code: '<input type="image" onClick={() => void 0} />' },
+  { code: '<input type="month" onClick={() => void 0} />' },
+  { code: '<input type="number" onClick={() => void 0} />' },
+  { code: '<input type="password" onClick={() => void 0} />' },
+  { code: '<input type="radio" onClick={() => void 0} />' },
+  { code: '<input type="range" onClick={() => void 0} />' },
+  { code: '<input type="reset" onClick={() => void 0} />' },
+  { code: '<input type="search" onClick={() => void 0} />' },
+  { code: '<input type="submit" onClick={() => void 0} />' },
+  { code: '<input type="tel" onClick={() => void 0} />' },
+  { code: '<input type="text" onClick={() => void 0} />' },
+  { code: '<input type="time" onClick={() => void 0} />' },
+  { code: '<input type="url" onClick={() => void 0} />' },
+  { code: '<input type="week" onClick={() => void 0} />' },
+  /* End all flavors of input */
+  { code: '<button onClick={() => void 0} className="foo" />' },
+  { code: '<datalist onClick={() => {}} />;' },
+  { code: '<menuitem onClick={() => {}} />;' },
+  { code: '<option onClick={() => void 0} className="foo" />' },
+  { code: '<select onClick={() => void 0} className="foo" />' },
+  { code: '<textarea onClick={() => void 0} className="foo" />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" />' },
+  { code: '<a onClick={() => void 0} href="http://x.y.z" tabIndex="0" />' },
+  { code: '<audio onClick={() => {}} />;' },
+  { code: '<form onClick={() => {}} />;' },
+  { code: '<form onSubmit={() => {}} />;' },
+  // { code: '<link onClick={() => {}} href="#" />;' },
+  /* HTML elements attributed with an interactive role */
+  { code: '<div role="button" onClick={() => {}} />;' },
+  { code: '<div role="checkbox" onClick={() => {}} />;' },
+  { code: '<div role="columnheader" onClick={() => {}} />;' },
+  { code: '<div role="combobox" onClick={() => {}} />;' },
+  { code: '<div role="form" onClick={() => {}} />;' },
+  { code: '<div role="gridcell" onClick={() => {}} />;' },
+  { code: '<div role="link" onClick={() => {}} />;' },
+  { code: '<div role="menuitem" onClick={() => {}} />;' },
+  { code: '<div role="menuitemcheckbox" onClick={() => {}} />;' },
+  { code: '<div role="menuitemradio" onClick={() => {}} />;' },
+  { code: '<div role="option" onClick={() => {}} />;' },
+  { code: '<div role="radio" onClick={() => {}} />;' },
+  { code: '<div role="rowheader" onClick={() => {}} />;' },
+  { code: '<div role="searchbox" onClick={() => {}} />;' },
+  { code: '<div role="slider" onClick={() => {}} />;' },
+  { code: '<div role="spinbutton" onClick={() => {}} />;' },
+  { code: '<div role="switch" onClick={() => {}} />;' },
+  { code: '<div role="tab" onClick={() => {}} />;' },
+  { code: '<div role="textbox" onClick={() => {}} />;' },
+  { code: '<div role="treeitem" onClick={() => {}} />;' },
+  /* Presentation is a special case role that indicates intentional static semantics */
+  { code: '<div role="presentation" onClick={() => {}} />;' },
+  { code: '<div role="presentation" onKeyDown={() => {}} />;' },
+  /* HTML elements with an inherent, non-interactive role */
+  { code: '<address onClick={() => {}} />;' },
+  { code: '<article onClick={() => {}} />;' },
+  { code: '<article onDblClick={() => void 0} />;' },
+  { code: '<aside onClick={() => {}} />;' },
+  { code: '<blockquote onClick={() => {}} />;' },
+  { code: '<br onClick={() => {}} />;' },
+  { code: '<canvas onClick={() => {}} />;' },
+  { code: '<caption onClick={() => {}} />;' },
+  { code: '<code onClick={() => {}} />;' },
+  { code: '<dd onClick={() => {}} />;' },
+  { code: '<del onClick={() => {}} />;' },
+  { code: '<details onClick={() => {}} />;' },
+  { code: '<dfn onClick={() => {}} />;' },
+  { code: '<dir onClick={() => {}} />;' },
+  { code: '<dl onClick={() => {}} />;' },
+  { code: '<dt onClick={() => {}} />;' },
+  { code: '<em onClick={() => {}} />;' },
+  { code: '<embed onClick={() => {}} />;' },
+  { code: '<fieldset onClick={() => {}} />;' },
+  { code: '<figcaption onClick={() => {}} />;' },
+  { code: '<figure onClick={() => {}} />;' },
+  { code: '<footer onClick={() => {}} />;' },
+  { code: '<h1 onClick={() => {}} />;' },
+  { code: '<h2 onClick={() => {}} />;' },
+  { code: '<h3 onClick={() => {}} />;' },
+  { code: '<h4 onClick={() => {}} />;' },
+  { code: '<h5 onClick={() => {}} />;' },
+  { code: '<h6 onClick={() => {}} />;' },
+  { code: '<hr onClick={() => {}} />;' },
+  { code: '<html onClick={() => {}} />;' },
+  { code: '<iframe onClick={() => {}} />;' },
+  { code: '<img onClick={() => {}} />;' },
+  { code: '<ins onClick={() => {}} />;' },
+  { code: '<label onClick={() => {}} />;' },
+  { code: '<legend onClick={() => {}} />;' },
+  { code: '<li onClick={() => {}} />;' },
+  { code: '<main onClick={() => void 0} />;' },
+  { code: '<mark onClick={() => {}} />;' },
+  { code: '<marquee onClick={() => {}} />;' },
+  { code: '<menu onClick={() => {}} />;' },
+  { code: '<meter onClick={() => {}} />;' },
+  { code: '<nav onClick={() => {}} />;' },
+  { code: '<ol onClick={() => {}} />;' },
+  { code: '<optgroup onClick={() => {}} />;' },
+  { code: '<output onClick={() => {}} />;' },
+  { code: '<p onClick={() => {}} />;' },
+  { code: '<pre onClick={() => {}} />;' },
+  { code: '<progress onClick={() => {}} />;' },
+  { code: '<ruby onClick={() => {}} />;' },
+  { code: '<section onClick={() => {}} aria-label="Aa" />;' },
+  { code: '<section onClick={() => {}} aria-labelledby="js_1" />;' },
+  { code: '<strong onClick={() => {}} />;' },
+  { code: '<sub onClick={() => {}} />;' },
+  { code: '<summary onClick={() => {}} />;' },
+  { code: '<sup onClick={() => {}} />;' },
+  { code: '<table onClick={() => {}} />;' },
+  { code: '<tbody onClick={() => {}} />;' },
+  { code: '<tfoot onClick={() => {}} />;' },
+  { code: '<th onClick={() => {}} />;' },
+  { code: '<thead onClick={() => {}} />;' },
+  { code: '<time onClick={() => {}} />;' },
+  { code: '<tr onClick={() => {}} />;' },
+  { code: '<video onClick={() => {}} />;' },
+  { code: '<ul onClick={() => {}} />;' },
+  /* HTML elements attributed with an abstract role */
+  { code: '<div role="command" onClick={() => {}} />;' },
+  { code: '<div role="composite" onClick={() => {}} />;' },
+  { code: '<div role="input" onClick={() => {}} />;' },
+  { code: '<div role="landmark" onClick={() => {}} />;' },
+  { code: '<div role="range" onClick={() => {}} />;' },
+  { code: '<div role="roletype" onClick={() => {}} />;' },
+  { code: '<div role="sectionhead" onClick={() => {}} />;' },
+  { code: '<div role="select" onClick={() => {}} />;' },
+  { code: '<div role="structure" onClick={() => {}} />;' },
+  { code: '<div role="widget" onClick={() => {}} />;' },
+  { code: '<div role="window" onClick={() => {}} />;' },
+  /* HTML elements attributed with a non-interactive role */
+  { code: '<div role="alert" onClick={() => {}} />;' },
+  { code: '<div role="alertdialog" onClick={() => {}} />;' },
+  { code: '<div role="application" onClick={() => {}} />;' },
+  { code: '<div role="article" onClick={() => {}} />;' },
+  { code: '<div role="banner" onClick={() => {}} />;' },
+  { code: '<div role="cell" onClick={() => {}} />;' },
+  { code: '<div role="complementary" onClick={() => {}} />;' },
+  { code: '<div role="contentinfo" onClick={() => {}} />;' },
+  { code: '<div role="definition" onClick={() => {}} />;' },
+  { code: '<div role="dialog" onClick={() => {}} />;' },
+  { code: '<div role="directory" onClick={() => {}} />;' },
+  { code: '<div role="document" onClick={() => {}} />;' },
+  { code: '<div role="feed" onClick={() => {}} />;' },
+  { code: '<div role="figure" onClick={() => {}} />;' },
+  { code: '<div role="grid" onClick={() => {}} />;' },
+  { code: '<div role="group" onClick={() => {}} />;' },
+  { code: '<div role="heading" onClick={() => {}} />;' },
+  { code: '<div role="img" onClick={() => {}} />;' },
+  { code: '<div role="list" onClick={() => {}} />;' },
+  { code: '<div role="listbox" onClick={() => {}} />;' },
+  { code: '<div role="listitem" onClick={() => {}} />;' },
+  { code: '<div role="log" onClick={() => {}} />;' },
+  { code: '<div role="main" onClick={() => {}} />;' },
+  { code: '<div role="marquee" onClick={() => {}} />;' },
+  { code: '<div role="math" onClick={() => {}} />;' },
+  { code: '<div role="menu" onClick={() => {}} />;' },
+  { code: '<div role="menubar" onClick={() => {}} />;' },
+  { code: '<div role="navigation" onClick={() => {}} />;' },
+  { code: '<div role="note" onClick={() => {}} />;' },
+  { code: '<div role="progressbar" onClick={() => {}} />;' },
+  { code: '<div role="radiogroup" onClick={() => {}} />;' },
+  { code: '<div role="region" onClick={() => {}} />;' },
+  { code: '<div role="row" onClick={() => {}} />;' },
+  { code: '<div role="rowgroup" onClick={() => {}} />;' },
+  { code: '<div role="section" onClick={() => {}} />;' },
+  { code: '<div role="search" onClick={() => {}} />;' },
+  { code: '<div role="separator" onClick={() => {}} />;' },
+  { code: '<div role="scrollbar" onClick={() => {}} />;' },
+  { code: '<div role="status" onClick={() => {}} />;' },
+  { code: '<div role="table" onClick={() => {}} />;' },
+  { code: '<div role="tablist" onClick={() => {}} />;' },
+  { code: '<div role="tabpanel" onClick={() => {}} />;' },
+  // { code: '<td onClick={() => {}} />;' },
+  { code: '<div role="term" onClick={() => {}} />;' },
+  { code: '<div role="timer" onClick={() => {}} />;' },
+  { code: '<div role="toolbar" onClick={() => {}} />;' },
+  { code: '<div role="tooltip" onClick={() => {}} />;' },
+  { code: '<div role="tree" onClick={() => {}} />;' },
+  { code: '<div role="treegrid" onClick={() => {}} />;' },
+  // All the possible handlers
+  { code: '<div onCopy={() => {}} />;' },
+  { code: '<div onCut={() => {}} />;' },
+  { code: '<div onPaste={() => {}} />;' },
+  { code: '<div onCompositionEnd={() => {}} />;' },
+  { code: '<div onCompositionStart={() => {}} />;' },
+  { code: '<div onCompositionUpdate={() => {}} />;' },
+  { code: '<div onChange={() => {}} />;' },
+  { code: '<div onInput={() => {}} />;' },
+  { code: '<div onSubmit={() => {}} />;' },
+  { code: '<div onSelect={() => {}} />;' },
+  { code: '<div onTouchCancel={() => {}} />;' },
+  { code: '<div onTouchEnd={() => {}} />;' },
+  { code: '<div onTouchMove={() => {}} />;' },
+  { code: '<div onTouchStart={() => {}} />;' },
+  { code: '<div onScroll={() => {}} />;' },
+  { code: '<div onWheel={() => {}} />;' },
+  { code: '<div onAbort={() => {}} />;' },
+  { code: '<div onCanPlay={() => {}} />;' },
+  { code: '<div onCanPlayThrough={() => {}} />;' },
+  { code: '<div onDurationChange={() => {}} />;' },
+  { code: '<div onEmptied={() => {}} />;' },
+  { code: '<div onEncrypted={() => {}} />;' },
+  { code: '<div onEnded={() => {}} />;' },
+  { code: '<div onError={() => {}} />;' },
+  { code: '<div onLoadedData={() => {}} />;' },
+  { code: '<div onLoadedMetadata={() => {}} />;' },
+  { code: '<div onLoadStart={() => {}} />;' },
+  { code: '<div onPause={() => {}} />;' },
+  { code: '<div onPlay={() => {}} />;' },
+  { code: '<div onPlaying={() => {}} />;' },
+  { code: '<div onProgress={() => {}} />;' },
+  { code: '<div onRateChange={() => {}} />;' },
+  { code: '<div onSeeked={() => {}} />;' },
+  { code: '<div onSeeking={() => {}} />;' },
+  { code: '<div onStalled={() => {}} />;' },
+  { code: '<div onSuspend={() => {}} />;' },
+  { code: '<div onTimeUpdate={() => {}} />;' },
+  { code: '<div onVolumeChange={() => {}} />;' },
+  { code: '<div onWaiting={() => {}} />;' },
+  { code: '<div onLoad={() => {}} />;' },
+  { code: '<div onError={() => {}} />;' },
+  { code: '<div onAnimationStart={() => {}} />;' },
+  { code: '<div onAnimationEnd={() => {}} />;' },
+  { code: '<div onAnimationIteration={() => {}} />;' },
+  { code: '<div onTransitionEnd={() => {}} />;' },
+];
+
+const neverValid = [
+  { code: '<div onClick={() => void 0} />;', errors: [expectedError] },
+  { code: '<div onClick={() => void 0} role={undefined} />;', errors: [expectedError] },
+  { code: '<div onClick={() => void 0} {...props} />;', errors: [expectedError] },
+  { code: '<div onKeyUp={() => void 0} aria-hidden={false} />;', errors: [expectedError] },
+  /* Static elements; no inherent role */
+  { code: '<a onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<a onClick={() => void 0} />', errors: [expectedError] },
+  { code: '<a tabIndex="0" onClick={() => void 0} />', errors: [expectedError] },
+  { code: '<acronym onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<applet onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<area onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<b onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<base onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<bdi onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<bdo onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<big onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<blink onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<body onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<center onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<cite onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<col onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<colgroup onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<content onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<data onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<font onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<frame onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<frameset onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<head onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<header onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<hgroup onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<i onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<kbd onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<keygen onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<map onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<meta onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<noembed onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<noscript onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<object onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<param onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<picture onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<q onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<rp onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<rt onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<rtc onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<s onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<samp onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<script onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<section onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<small onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<source onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<spacer onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<span onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<strike onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<style onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<title onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<track onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<tt onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<u onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<var onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<wbr onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<xmp onClick={() => {}} />;', errors: [expectedError] },
+  // Handlers
+  { code: '<div onKeyDown={() => {}} />;', errors: [expectedError] },
+  { code: '<div onKeyPress={() => {}} />;', errors: [expectedError] },
+  { code: '<div onKeyUp={() => {}} />;', errors: [expectedError] },
+  { code: '<div onClick={() => {}} />;', errors: [expectedError] },
+  { code: '<div onMouseDown={() => {}} />;', errors: [expectedError] },
+  { code: '<div onMouseUp={() => {}} />;', errors: [expectedError] },
+  // Custom components
+  { code: '<TestComponent onClick={doFoo} />', settings: componentsSettings, errors: [expectedError] },
+];
+
+const recommendedOptions = configs.recommended.rules[`jsx-a11y/${ruleName}`][1] || {};
+ruleTester.run(`${ruleName}:recommended`, rule, {
+  valid: parsers.all([].concat(
+    alwaysValid,
+    // All the possible handlers
+    { code: '<div onCopy={() => {}} />;' },
+    { code: '<div onCut={() => {}} />;' },
+    { code: '<div onPaste={() => {}} />;' },
+    { code: '<div onCompositionEnd={() => {}} />;' },
+    { code: '<div onCompositionStart={() => {}} />;' },
+    { code: '<div onCompositionUpdate={() => {}} />;' },
+    { code: '<div onFocus={() => {}} />;' },
+    { code: '<div onBlur={() => {}} />;' },
+    { code: '<div onChange={() => {}} />;' },
+    { code: '<div onInput={() => {}} />;' },
+    { code: '<div onSubmit={() => {}} />;' },
+    { code: '<div onContextMenu={() => {}} />;' },
+    { code: '<div onDblClick={() => {}} />;' },
+    { code: '<div onDoubleClick={() => {}} />;' },
+    { code: '<div onDrag={() => {}} />;' },
+    { code: '<div onDragEnd={() => {}} />;' },
+    { code: '<div onDragEnter={() => {}} />;' },
+    { code: '<div onDragExit={() => {}} />;' },
+    { code: '<div onDragLeave={() => {}} />;' },
+    { code: '<div onDragOver={() => {}} />;' },
+    { code: '<div onDragStart={() => {}} />;' },
+    { code: '<div onDrop={() => {}} />;' },
+    { code: '<div onMouseEnter={() => {}} />;' },
+    { code: '<div onMouseLeave={() => {}} />;' },
+    { code: '<div onMouseMove={() => {}} />;' },
+    { code: '<div onMouseOut={() => {}} />;' },
+    { code: '<div onMouseOver={() => {}} />;' },
+    { code: '<div onSelect={() => {}} />;' },
+    { code: '<div onTouchCancel={() => {}} />;' },
+    { code: '<div onTouchEnd={() => {}} />;' },
+    { code: '<div onTouchMove={() => {}} />;' },
+    { code: '<div onTouchStart={() => {}} />;' },
+    { code: '<div onScroll={() => {}} />;' },
+    { code: '<div onWheel={() => {}} />;' },
+    { code: '<div onAbort={() => {}} />;' },
+    { code: '<div onCanPlay={() => {}} />;' },
+    { code: '<div onCanPlayThrough={() => {}} />;' },
+    { code: '<div onDurationChange={() => {}} />;' },
+    { code: '<div onEmptied={() => {}} />;' },
+    { code: '<div onEncrypted={() => {}} />;' },
+    { code: '<div onEnded={() => {}} />;' },
+    { code: '<div onError={() => {}} />;' },
+    { code: '<div onLoadedData={() => {}} />;' },
+    { code: '<div onLoadedMetadata={() => {}} />;' },
+    { code: '<div onLoadStart={() => {}} />;' },
+    { code: '<div onPause={() => {}} />;' },
+    { code: '<div onPlay={() => {}} />;' },
+    { code: '<div onPlaying={() => {}} />;' },
+    { code: '<div onProgress={() => {}} />;' },
+    { code: '<div onRateChange={() => {}} />;' },
+    { code: '<div onSeeked={() => {}} />;' },
+    { code: '<div onSeeking={() => {}} />;' },
+    { code: '<div onStalled={() => {}} />;' },
+    { code: '<div onSuspend={() => {}} />;' },
+    { code: '<div onTimeUpdate={() => {}} />;' },
+    { code: '<div onVolumeChange={() => {}} />;' },
+    { code: '<div onWaiting={() => {}} />;' },
+    { code: '<div onLoad={() => {}} />;' },
+    { code: '<div onError={() => {}} />;' },
+    { code: '<div onAnimationStart={() => {}} />;' },
+    { code: '<div onAnimationEnd={() => {}} />;' },
+    { code: '<div onAnimationIteration={() => {}} />;' },
+    { code: '<div onTransitionEnd={() => {}} />;' },
+    // Expressions should pass in recommended mode
+    { code: '<div role={ROLE_BUTTON} onClick={() => {}} />;' },
+    { code: '<div  {...this.props} role={this.props.role} onKeyPress={e => this.handleKeyPress(e)}>{this.props.children}</div>' },
+    // Cases for allowExpressionValues set to true
+    {
+      code: '<div role={BUTTON} onClick={() => {}} />;',
+      options: [{ allowExpressionValues: true }],
+    },
+    // Specific case for ternary operator with literals on both side
+    {
+      code: '<div role={isButton ? "button" : "link"} onClick={() => {}} />;',
+      options: [{ allowExpressionValues: true }],
+    },
+    {
+      code: '<div role={isButton ? "button" : LINK} onClick={() => {}} />;',
+      options: [{ allowExpressionValues: true }],
+      errors: [expectedError],
+    },
+    {
+      code: '<div role={isButton ? BUTTON : LINK} onClick={() => {}} />;',
+      options: [{ allowExpressionValues: true }],
+      errors: [expectedError],
+    },
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    neverValid,
+  ))
+    .map(ruleOptionsMapperFactory(recommendedOptions))
+    .map(parserOptionsMapper),
+});
+
+ruleTester.run(`${ruleName}:strict`, rule, {
+  valid: parsers.all([].concat(
+    alwaysValid,
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    neverValid,
+    // All the possible handlers
+    { code: '<div onContextMenu={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDblClick={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDoubleClick={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDrag={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDragEnd={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDragEnter={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDragExit={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDragLeave={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDragOver={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDragStart={() => {}} />;', errors: [expectedError] },
+    { code: '<div onDrop={() => {}} />;', errors: [expectedError] },
+    { code: '<div onMouseEnter={() => {}} />;', errors: [expectedError] },
+    { code: '<div onMouseLeave={() => {}} />;', errors: [expectedError] },
+    { code: '<div onMouseMove={() => {}} />;', errors: [expectedError] },
+    { code: '<div onMouseOut={() => {}} />;', errors: [expectedError] },
+    { code: '<div onMouseOver={() => {}} />;', errors: [expectedError] },
+    // Expressions should fail in strict mode
+    { code: '<div role={ROLE_BUTTON} onClick={() => {}} />;', errors: [expectedError] },
+    { code: '<div  {...this.props} role={this.props.role} onKeyPress={e => this.handleKeyPress(e)}>{this.props.children}</div>', errors: [expectedError] },
+    // Cases for allowExpressionValues set to false
+    {
+      code: '<div role={BUTTON} onClick={() => {}} />;',
+      options: [{ allowExpressionValues: false }],
+      errors: [expectedError],
+    },
+    // Specific case for ternary operator with literals on both side
+    {
+      code: '<div role={isButton ? "button" : "link"} onClick={() => {}} />;',
+      options: [{ allowExpressionValues: false }],
+      errors: [expectedError],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/prefer-tag-over-role-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/prefer-tag-over-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/prefer-tag-over-role-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,63 @@
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/prefer-tag-over-role';
+
+const ruleTester = new RuleTester();
+
+const expectedError = (role, tag) => ({
+  message: `Use ${tag} instead of the "${role}" role to ensure accessibility across all devices.`,
+  type: 'JSXOpeningElement',
+});
+
+ruleTester.run('prefer-tag-over-role', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<div role="unknown" />;' },
+    { code: '<div role="also unknown" />;' },
+    { code: '<other />' },
+    { code: '<img role="img" />' },
+    { code: '<input role="checkbox" />' },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    {
+      code: '<div role="checkbox" />',
+      errors: [expectedError('checkbox', '<input type="checkbox">')],
+    },
+    {
+      code: '<div role="button checkbox" />',
+      errors: [expectedError('checkbox', '<input type="checkbox">')],
+    },
+    {
+      code: '<div role="heading" />',
+      errors: [
+        expectedError('heading', '<h1>, <h2>, <h3>, <h4>, <h5>, or <h6>'),
+      ],
+    },
+    {
+      code: '<div role="link" />',
+      errors: [
+        expectedError(
+          'link',
+          '<a href=...>, or <area href=...>',
+        ),
+      ],
+    },
+    {
+      code: '<div role="rowgroup" />',
+      errors: [expectedError('rowgroup', '<tbody>, <tfoot>, or <thead>')],
+    },
+    {
+      code: '<span role="checkbox" />',
+      errors: [expectedError('checkbox', '<input type="checkbox">')],
+    },
+    {
+      code: '<other role="checkbox" />',
+      errors: [expectedError('checkbox', '<input type="checkbox">')],
+    },
+    {
+      code: '<div role="banner" />',
+      errors: [expectedError('banner', '<header>')],
+    },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/role-has-required-aria-props-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/role-has-required-aria-props-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/role-has-required-aria-props-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,134 @@
+/**
+ * @fileoverview Enforce that elements with ARIA roles must
+ *  have all required attributes for that role.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { roles } from 'aria-query';
+import { RuleTester } from 'eslint';
+
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/role-has-required-aria-props';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const errorMessage = (role) => {
+  const requiredProps = Object.keys(roles.get(role).requiredProps);
+
+  return {
+    message: `Elements with the ARIA role "${role}" must have the following attributes defined: ${requiredProps}`,
+    type: 'JSXAttribute',
+  };
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      MyComponent: 'div',
+    },
+  },
+};
+
+// Create basic test cases using all valid role types.
+const basicValidityTests = roles.keys().map((role) => {
+  const {
+    requiredProps: requiredPropKeyValues,
+  } = roles.get(role);
+  const requiredProps = Object.keys(requiredPropKeyValues);
+  const propChain = requiredProps.join(' ');
+
+  return {
+    code: `<div role="${role.toLowerCase()}" ${propChain} />`,
+  };
+});
+
+ruleTester.run('role-has-required-aria-props', rule, {
+  valid: parsers.all([].concat(
+    { code: '<Bar baz />' },
+    { code: '<MyComponent role="combobox" />' },
+    // Variables should pass, as we are only testing literals.
+    { code: '<div />' },
+    { code: '<div></div>' },
+    { code: '<div role={role} />' },
+    { code: '<div role={role || "button"} />' },
+    { code: '<div role={role || "foobar"} />' },
+    { code: '<div role="row" />' },
+    { code: '<span role="checkbox" aria-checked="false" aria-labelledby="foo" tabindex="0"></span>' },
+    { code: '<input role="checkbox" aria-checked="false" aria-labelledby="foo" tabindex="0" {...props} type="checkbox" />' },
+    { code: '<input type="checkbox" role="switch" />' },
+    { code: '<MyComponent role="checkbox" aria-checked="false" aria-labelledby="foo" tabindex="0" />', settings: componentsSettings },
+    { code: '<div role="heading" aria-level={2} />' },
+    { code: '<div role="heading" aria-level="3" />' },
+  )).concat(basicValidityTests).map(parserOptionsMapper),
+
+  invalid: parsers.all([].concat(
+    // SLIDER
+    { code: '<div role="slider" />', errors: [errorMessage('slider')] },
+    {
+      code: '<div role="slider" aria-valuemax />',
+      errors: [errorMessage('slider')],
+    },
+    {
+      code: '<div role="slider" aria-valuemax aria-valuemin />',
+      errors: [errorMessage('slider')],
+    },
+
+    // CHECKBOX
+    { code: '<div role="checkbox" />', errors: [errorMessage('checkbox')] },
+    { code: '<div role="checkbox" checked />', errors: [errorMessage('checkbox')] },
+    {
+      code: '<div role="checkbox" aria-chcked />',
+      errors: [errorMessage('checkbox')],
+    },
+    {
+      code: '<span role="checkbox" aria-labelledby="foo" tabindex="0"></span>',
+      errors: [errorMessage('checkbox')],
+    },
+
+    // COMBOBOX
+    { code: '<div role="combobox" />', errors: [errorMessage('combobox')] },
+    { code: '<div role="combobox" expanded />', errors: [errorMessage('combobox')] },
+    {
+      code: '<div role="combobox" aria-expandd />',
+      errors: [errorMessage('combobox')],
+    },
+
+    // SCROLLBAR
+    { code: '<div role="scrollbar" />', errors: [errorMessage('scrollbar')] },
+    {
+      code: '<div role="scrollbar" aria-valuemax />',
+      errors: [errorMessage('scrollbar')],
+    },
+    {
+      code: '<div role="scrollbar" aria-valuemax aria-valuemin />',
+      errors: [errorMessage('scrollbar')],
+    },
+    {
+      code: '<div role="scrollbar" aria-valuemax aria-valuenow />',
+      errors: [errorMessage('scrollbar')],
+    },
+    {
+      code: '<div role="scrollbar" aria-valuemin aria-valuenow />',
+      errors: [errorMessage('scrollbar')],
+    },
+    {
+      code: '<div role="heading" />',
+      errors: [errorMessage('heading')],
+    },
+    {
+      code: '<div role="option" />',
+      errors: [errorMessage('option')],
+    },
+    // Custom element
+    { code: '<MyComponent role="combobox" />', settings: componentsSettings, errors: [errorMessage('combobox')] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/role-supports-aria-props-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/role-supports-aria-props-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/role-supports-aria-props-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,570 @@
+/**
+ * @fileoverview Enforce that an element does not have an unsupported ARIA attribute.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import {
+  aria,
+  roles,
+} from 'aria-query';
+import { RuleTester } from 'eslint';
+import { version as eslintVersion } from 'eslint/package.json';
+import semver from 'semver';
+
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/role-supports-aria-props';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const generateErrorMessage = (attr, role, tag, isImplicit) => {
+  if (isImplicit) {
+    return `The attribute ${attr} is not supported by the role ${role}. This role is implicit on the element ${tag}.`;
+  }
+
+  return `The attribute ${attr} is not supported by the role ${role}.`;
+};
+
+const errorMessage = (attr, role, tag, isImplicit) => ({
+  message: generateErrorMessage(attr, role, tag, isImplicit),
+  type: 'JSXOpeningElement',
+});
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Link: 'a',
+    },
+  },
+};
+
+const nonAbstractRoles = roles.keys().filter((role) => roles.get(role).abstract === false);
+
+const createTests = (rolesNames) => rolesNames.reduce((tests, role) => {
+  const {
+    props: propKeyValues,
+  } = roles.get(role);
+  const validPropsForRole = Object.keys(propKeyValues);
+  const invalidPropsForRole = aria.keys()
+    .map((attribute) => attribute.toLowerCase())
+    .filter((attribute) => validPropsForRole.indexOf(attribute) === -1);
+  const normalRole = role.toLowerCase();
+
+  return [
+    tests[0].concat(validPropsForRole.map((prop) => ({
+      code: `<div role="${normalRole}" ${prop.toLowerCase()} />`,
+    }))),
+    tests[1].concat(invalidPropsForRole.map((prop) => ({
+      code: `<div role="${normalRole}" ${prop.toLowerCase()} />`,
+      errors: [errorMessage(prop.toLowerCase(), normalRole, 'div', false)],
+    }))),
+  ];
+}, [[], []]);
+
+const [validTests, invalidTests] = createTests(nonAbstractRoles);
+
+ruleTester.run('role-supports-aria-props', rule, {
+  valid: parsers.all([].concat(
+    { code: '<Foo bar />' },
+    { code: '<div />' },
+    { code: '<div id="main" />' },
+    { code: '<div role />' },
+    { code: '<div role="presentation" {...props} />' },
+    { code: '<Foo.Bar baz={true} />' },
+    { code: '<Link href="#" aria-checked />' },
+
+    // IMPLICIT ROLE TESTS
+    // A TESTS - implicit role is `link`
+    { code: '<a href="#" aria-expanded />' },
+    { code: '<a href="#" aria-atomic />' },
+    { code: '<a href="#" aria-busy />' },
+    { code: '<a href="#" aria-controls />' },
+    { code: '<a href="#" aria-current />' },
+    { code: '<a href="#" aria-describedby />' },
+    { code: '<a href="#" aria-disabled />' },
+    { code: '<a href="#" aria-dropeffect />' },
+    { code: '<a href="#" aria-flowto />' },
+    { code: '<a href="#" aria-haspopup />' },
+    { code: '<a href="#" aria-grabbed />' },
+    { code: '<a href="#" aria-hidden />' },
+    { code: '<a href="#" aria-label />' },
+    { code: '<a href="#" aria-labelledby />' },
+    { code: '<a href="#" aria-live />' },
+    { code: '<a href="#" aria-owns />' },
+    { code: '<a href="#" aria-relevant />' },
+
+    // this will have global
+    { code: '<a aria-checked />' },
+
+    // AREA TESTS - implicit role is `link`
+    { code: '<area href="#" aria-expanded />' },
+    { code: '<area href="#" aria-atomic />' },
+    { code: '<area href="#" aria-busy />' },
+    { code: '<area href="#" aria-controls />' },
+    { code: '<area href="#" aria-describedby />' },
+    { code: '<area href="#" aria-disabled />' },
+    { code: '<area href="#" aria-dropeffect />' },
+    { code: '<area href="#" aria-flowto />' },
+    { code: '<area href="#" aria-grabbed />' },
+    { code: '<area href="#" aria-haspopup />' },
+    { code: '<area href="#" aria-hidden />' },
+    { code: '<area href="#" aria-label />' },
+    { code: '<area href="#" aria-labelledby />' },
+    { code: '<area href="#" aria-live />' },
+    { code: '<area href="#" aria-owns />' },
+    { code: '<area href="#" aria-relevant />' },
+
+    // this will have global
+    { code: '<area aria-checked />' },
+
+    // LINK TESTS - implicit role is `link`
+    { code: '<link href="#" aria-expanded />' },
+    { code: '<link href="#" aria-atomic />' },
+    { code: '<link href="#" aria-busy />' },
+    { code: '<link href="#" aria-controls />' },
+    { code: '<link href="#" aria-describedby />' },
+    { code: '<link href="#" aria-disabled />' },
+    { code: '<link href="#" aria-dropeffect />' },
+    { code: '<link href="#" aria-flowto />' },
+    { code: '<link href="#" aria-grabbed />' },
+    { code: '<link href="#" aria-hidden />' },
+    { code: '<link href="#" aria-haspopup />' },
+    { code: '<link href="#" aria-label />' },
+    { code: '<link href="#" aria-labelledby />' },
+    { code: '<link href="#" aria-live />' },
+    { code: '<link href="#" aria-owns />' },
+    { code: '<link href="#" aria-relevant />' },
+
+    // this will have global
+    { code: '<link aria-checked />' },
+
+    // IMG TESTS - no implicit role
+    { code: '<img alt="" aria-checked />' },
+
+    // this will have role of `img`
+    { code: '<img alt="foobar" aria-busy />' },
+
+    // MENU TESTS - implicit role is `toolbar` when `type="toolbar"`
+    { code: '<menu type="toolbar" aria-activedescendant />' },
+    { code: '<menu type="toolbar" aria-atomic />' },
+    { code: '<menu type="toolbar" aria-busy />' },
+    { code: '<menu type="toolbar" aria-controls />' },
+    { code: '<menu type="toolbar" aria-describedby />' },
+    { code: '<menu type="toolbar" aria-disabled />' },
+    { code: '<menu type="toolbar" aria-dropeffect />' },
+    { code: '<menu type="toolbar" aria-flowto />' },
+    { code: '<menu type="toolbar" aria-grabbed />' },
+    { code: '<menu type="toolbar" aria-hidden />' },
+    { code: '<menu type="toolbar" aria-label />' },
+    { code: '<menu type="toolbar" aria-labelledby />' },
+    { code: '<menu type="toolbar" aria-live />' },
+    { code: '<menu type="toolbar" aria-owns />' },
+    { code: '<menu type="toolbar" aria-relevant />' },
+
+    // this will have global
+    { code: '<menu aria-checked />' },
+
+    // MENUITEM TESTS
+    // when `type="command`, the implicit role is `menuitem`
+    { code: '<menuitem type="command" aria-atomic />' },
+    { code: '<menuitem type="command" aria-busy />' },
+    { code: '<menuitem type="command" aria-controls />' },
+    { code: '<menuitem type="command" aria-describedby />' },
+    { code: '<menuitem type="command" aria-disabled />' },
+    { code: '<menuitem type="command" aria-dropeffect />' },
+    { code: '<menuitem type="command" aria-flowto />' },
+    { code: '<menuitem type="command" aria-grabbed />' },
+    { code: '<menuitem type="command" aria-haspopup />' },
+    { code: '<menuitem type="command" aria-hidden />' },
+    { code: '<menuitem type="command" aria-label />' },
+    { code: '<menuitem type="command" aria-labelledby />' },
+    { code: '<menuitem type="command" aria-live />' },
+    { code: '<menuitem type="command" aria-owns />' },
+    { code: '<menuitem type="command" aria-relevant />' },
+    // when `type="checkbox`, the implicit role is `menuitemcheckbox`
+    { code: '<menuitem type="checkbox" aria-checked />' },
+    { code: '<menuitem type="checkbox" aria-atomic />' },
+    { code: '<menuitem type="checkbox" aria-busy />' },
+    { code: '<menuitem type="checkbox" aria-controls />' },
+    { code: '<menuitem type="checkbox" aria-describedby />' },
+    { code: '<menuitem type="checkbox" aria-disabled />' },
+    { code: '<menuitem type="checkbox" aria-dropeffect />' },
+    { code: '<menuitem type="checkbox" aria-flowto />' },
+    { code: '<menuitem type="checkbox" aria-grabbed />' },
+    { code: '<menuitem type="checkbox" aria-haspopup />' },
+    { code: '<menuitem type="checkbox" aria-hidden />' },
+    { code: '<menuitem type="checkbox" aria-invalid />' },
+    { code: '<menuitem type="checkbox" aria-label />' },
+    { code: '<menuitem type="checkbox" aria-labelledby />' },
+    { code: '<menuitem type="checkbox" aria-live />' },
+    { code: '<menuitem type="checkbox" aria-owns />' },
+    { code: '<menuitem type="checkbox" aria-relevant />' },
+    // when `type="radio`, the implicit role is `menuitemradio`
+    { code: '<menuitem type="radio" aria-checked />' },
+    { code: '<menuitem type="radio" aria-atomic />' },
+    { code: '<menuitem type="radio" aria-busy />' },
+    { code: '<menuitem type="radio" aria-controls />' },
+    { code: '<menuitem type="radio" aria-describedby />' },
+    { code: '<menuitem type="radio" aria-disabled />' },
+    { code: '<menuitem type="radio" aria-dropeffect />' },
+    { code: '<menuitem type="radio" aria-flowto />' },
+    { code: '<menuitem type="radio" aria-grabbed />' },
+    { code: '<menuitem type="radio" aria-haspopup />' },
+    { code: '<menuitem type="radio" aria-hidden />' },
+    { code: '<menuitem type="radio" aria-invalid />' },
+    { code: '<menuitem type="radio" aria-label />' },
+    { code: '<menuitem type="radio" aria-labelledby />' },
+    { code: '<menuitem type="radio" aria-live />' },
+    { code: '<menuitem type="radio" aria-owns />' },
+    { code: '<menuitem type="radio" aria-relevant />' },
+    { code: '<menuitem type="radio" aria-posinset />' },
+    { code: '<menuitem type="radio" aria-setsize />' },
+
+    // these will have global
+    { code: '<menuitem aria-checked />' },
+    { code: '<menuitem type="foo" aria-checked />' },
+
+    // INPUT TESTS
+    // when `type="button"`, the implicit role is `button`
+    { code: '<input type="button" aria-expanded />' },
+    { code: '<input type="button" aria-pressed />' },
+    { code: '<input type="button" aria-atomic />' },
+    { code: '<input type="button" aria-busy />' },
+    { code: '<input type="button" aria-controls />' },
+    { code: '<input type="button" aria-describedby />' },
+    { code: '<input type="button" aria-disabled />' },
+    { code: '<input type="button" aria-dropeffect />' },
+    { code: '<input type="button" aria-flowto />' },
+    { code: '<input type="button" aria-grabbed />' },
+    { code: '<input type="button" aria-haspopup />' },
+    { code: '<input type="button" aria-hidden />' },
+    { code: '<input type="button" aria-label />' },
+    { code: '<input type="button" aria-labelledby />' },
+    { code: '<input type="button" aria-live />' },
+    { code: '<input type="button" aria-owns />' },
+    { code: '<input type="button" aria-relevant />' },
+    // when `type="image"`, the implicit role is `button`
+    { code: '<input type="image" aria-expanded />' },
+    { code: '<input type="image" aria-pressed />' },
+    { code: '<input type="image" aria-atomic />' },
+    { code: '<input type="image" aria-busy />' },
+    { code: '<input type="image" aria-controls />' },
+    { code: '<input type="image" aria-describedby />' },
+    { code: '<input type="image" aria-disabled />' },
+    { code: '<input type="image" aria-dropeffect />' },
+    { code: '<input type="image" aria-flowto />' },
+    { code: '<input type="image" aria-grabbed />' },
+    { code: '<input type="image" aria-haspopup />' },
+    { code: '<input type="image" aria-hidden />' },
+    { code: '<input type="image" aria-label />' },
+    { code: '<input type="image" aria-labelledby />' },
+    { code: '<input type="image" aria-live />' },
+    { code: '<input type="image" aria-owns />' },
+    { code: '<input type="image" aria-relevant />' },
+    // when `type="reset"`, the implicit role is `button`
+    { code: '<input type="reset" aria-expanded />' },
+    { code: '<input type="reset" aria-pressed />' },
+    { code: '<input type="reset" aria-atomic />' },
+    { code: '<input type="reset" aria-busy />' },
+    { code: '<input type="reset" aria-controls />' },
+    { code: '<input type="reset" aria-describedby />' },
+    { code: '<input type="reset" aria-disabled />' },
+    { code: '<input type="reset" aria-dropeffect />' },
+    { code: '<input type="reset" aria-flowto />' },
+    { code: '<input type="reset" aria-grabbed />' },
+    { code: '<input type="reset" aria-haspopup />' },
+    { code: '<input type="reset" aria-hidden />' },
+    { code: '<input type="reset" aria-label />' },
+    { code: '<input type="reset" aria-labelledby />' },
+    { code: '<input type="reset" aria-live />' },
+    { code: '<input type="reset" aria-owns />' },
+    { code: '<input type="reset" aria-relevant />' },
+    // when `type="submit"`, the implicit role is `button`
+    { code: '<input type="submit" aria-expanded />' },
+    { code: '<input type="submit" aria-pressed />' },
+    { code: '<input type="submit" aria-atomic />' },
+    { code: '<input type="submit" aria-busy />' },
+    { code: '<input type="submit" aria-controls />' },
+    { code: '<input type="submit" aria-describedby />' },
+    { code: '<input type="submit" aria-disabled />' },
+    { code: '<input type="submit" aria-dropeffect />' },
+    { code: '<input type="submit" aria-flowto />' },
+    { code: '<input type="submit" aria-grabbed />' },
+    { code: '<input type="submit" aria-haspopup />' },
+    { code: '<input type="submit" aria-hidden />' },
+    { code: '<input type="submit" aria-label />' },
+    { code: '<input type="submit" aria-labelledby />' },
+    { code: '<input type="submit" aria-live />' },
+    { code: '<input type="submit" aria-owns />' },
+    { code: '<input type="submit" aria-relevant />' },
+    // when `type="checkbox"`, the implicit role is `checkbox`
+    { code: '<input type="checkbox" aria-atomic />' },
+    { code: '<input type="checkbox" aria-busy />' },
+    { code: '<input type="checkbox" aria-checked />' },
+    { code: '<input type="checkbox" aria-controls />' },
+    { code: '<input type="checkbox" aria-describedby />' },
+    { code: '<input type="checkbox" aria-disabled />' },
+    { code: '<input type="checkbox" aria-dropeffect />' },
+    { code: '<input type="checkbox" aria-flowto />' },
+    { code: '<input type="checkbox" aria-grabbed />' },
+    { code: '<input type="checkbox" aria-hidden />' },
+    { code: '<input type="checkbox" aria-invalid />' },
+    { code: '<input type="checkbox" aria-label />' },
+    { code: '<input type="checkbox" aria-labelledby />' },
+    { code: '<input type="checkbox" aria-live />' },
+    { code: '<input type="checkbox" aria-owns />' },
+    { code: '<input type="checkbox" aria-relevant />' },
+    // when `type="radio"`, the implicit role is `radio`
+    { code: '<input type="radio" aria-atomic />' },
+    { code: '<input type="radio" aria-busy />' },
+    { code: '<input type="radio" aria-checked />' },
+    { code: '<input type="radio" aria-controls />' },
+    { code: '<input type="radio" aria-describedby />' },
+    { code: '<input type="radio" aria-disabled />' },
+    { code: '<input type="radio" aria-dropeffect />' },
+    { code: '<input type="radio" aria-flowto />' },
+    { code: '<input type="radio" aria-grabbed />' },
+    { code: '<input type="radio" aria-hidden />' },
+    { code: '<input type="radio" aria-label />' },
+    { code: '<input type="radio" aria-labelledby />' },
+    { code: '<input type="radio" aria-live />' },
+    { code: '<input type="radio" aria-owns />' },
+    { code: '<input type="radio" aria-relevant />' },
+    { code: '<input type="radio" aria-posinset />' },
+    { code: '<input type="radio" aria-setsize />' },
+    // when `type="range"`, the implicit role is `slider`
+    { code: '<input type="range" aria-valuemax />' },
+    { code: '<input type="range" aria-valuemin />' },
+    { code: '<input type="range" aria-valuenow />' },
+    { code: '<input type="range" aria-orientation />' },
+    { code: '<input type="range" aria-atomic />' },
+    { code: '<input type="range" aria-busy />' },
+    { code: '<input type="range" aria-controls />' },
+    { code: '<input type="range" aria-describedby />' },
+    { code: '<input type="range" aria-disabled />' },
+    { code: '<input type="range" aria-dropeffect />' },
+    { code: '<input type="range" aria-flowto />' },
+    { code: '<input type="range" aria-grabbed />' },
+    { code: '<input type="range" aria-haspopup />' },
+    { code: '<input type="range" aria-hidden />' },
+    { code: '<input type="range" aria-invalid />' },
+    { code: '<input type="range" aria-label />' },
+    { code: '<input type="range" aria-labelledby />' },
+    { code: '<input type="range" aria-live />' },
+    { code: '<input type="range" aria-owns />' },
+    { code: '<input type="range" aria-relevant />' },
+    { code: '<input type="range" aria-valuetext />' },
+
+    // these will have role of `textbox`,
+    { code: '<input type="email" aria-disabled />' },
+    { code: '<input type="password" aria-disabled />' },
+    { code: '<input type="search" aria-disabled />' },
+    { code: '<input type="tel" aria-disabled />' },
+    { code: '<input type="url" aria-disabled />' },
+    { code: '<input aria-disabled />' },
+
+    // Allow null/undefined values regardless of role
+    { code: '<h2 role="presentation" aria-level={null} />' },
+    { code: '<h2 role="presentation" aria-level={undefined} />' },
+
+    // OTHER TESTS
+    { code: '<button aria-pressed />' },
+    { code: '<form aria-hidden />' },
+    { code: '<h1 aria-hidden />' },
+    { code: '<h2 aria-hidden />' },
+    { code: '<h3 aria-hidden />' },
+    { code: '<h4 aria-hidden />' },
+    { code: '<h5 aria-hidden />' },
+    { code: '<h6 aria-hidden />' },
+    { code: '<hr aria-hidden />' },
+    { code: '<li aria-current />' },
+    { code: '<meter aria-atomic />' },
+    { code: '<option aria-atomic />' },
+    { code: '<progress aria-atomic />' },
+    { code: '<textarea aria-hidden />' },
+    { code: '<select aria-expanded />' },
+    { code: '<datalist aria-expanded />' },
+    { code: '<div role="heading" aria-level />' },
+    { code: '<div role="heading" aria-level="1" />' },
+
+    semver.satisfies(eslintVersion, '>= 6') ? {
+      code: `
+        const HelloThere = () => (
+            <Hello
+                role="searchbox"
+                frag={
+                    <>
+                        <div>Hello</div>
+                        <div>There</div>
+                    </>
+                }
+            />
+        );
+
+        const Hello = (props) => <div>{props.frag}</div>;
+      `,
+    } : [],
+    validTests,
+  )).map(parserOptionsMapper),
+
+  invalid: parsers.all([].concat(
+    // implicit basic checks
+    {
+      code: '<a href="#" aria-checked />',
+      errors: [errorMessage('aria-checked', 'link', 'a', true)],
+    },
+    {
+      code: '<area href="#" aria-checked />',
+      errors: [errorMessage('aria-checked', 'link', 'area', true)],
+    },
+    {
+      code: '<link href="#" aria-checked />',
+      errors: [errorMessage('aria-checked', 'link', 'link', true)],
+    },
+    {
+      code: '<img alt="foobar" aria-checked />',
+      errors: [errorMessage('aria-checked', 'img', 'img', true)],
+    },
+    {
+      code: '<menu type="toolbar" aria-checked />',
+      errors: [errorMessage('aria-checked', 'toolbar', 'menu', true)],
+    },
+    {
+      code: '<aside aria-checked />',
+      errors: [errorMessage('aria-checked', 'complementary', 'aside', true)],
+    },
+    {
+      code: '<ul aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'list', 'ul', true)],
+    },
+    {
+      code: '<details aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'group', 'details', true)],
+    },
+    {
+      code: '<dialog aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'dialog', 'dialog', true)],
+    },
+    {
+      code: '<aside aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'complementary', 'aside', true)],
+    },
+    {
+      code: '<article aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'article', 'article', true)],
+    },
+    {
+      code: '<body aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'document', 'body', true)],
+    },
+    {
+      code: '<li aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'listitem', 'li', true)],
+    },
+    {
+      code: '<nav aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'navigation', 'nav', true)],
+    },
+    {
+      code: '<ol aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'list', 'ol', true)],
+    },
+    {
+      code: '<output aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'status', 'output', true)],
+    },
+    {
+      code: '<section aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'region', 'section', true)],
+    },
+    {
+      code: '<tbody aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'rowgroup', 'tbody', true)],
+    },
+    {
+      code: '<tfoot aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'rowgroup', 'tfoot', true)],
+    },
+    {
+      code: '<thead aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'rowgroup', 'thead', true)],
+    },
+    {
+      code: '<input type="radio" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'radio', 'input', true)],
+    },
+    {
+      code: '<input type="radio" aria-selected />',
+      errors: [errorMessage('aria-selected', 'radio', 'input', true)],
+    },
+    {
+      code: '<input type="radio" aria-haspopup />',
+      errors: [errorMessage('aria-haspopup', 'radio', 'input', true)],
+    },
+    {
+      code: '<input type="checkbox" aria-haspopup />',
+      errors: [errorMessage('aria-haspopup', 'checkbox', 'input', true)],
+    },
+    {
+      code: '<input type="reset" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'button', 'input', true)],
+    },
+    {
+      code: '<input type="submit" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'button', 'input', true)],
+    },
+    {
+      code: '<input type="image" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'button', 'input', true)],
+    },
+    {
+      code: '<input type="button" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'button', 'input', true)],
+    },
+    {
+      code: '<menuitem type="command" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'menuitem', 'menuitem', true)],
+    },
+    {
+      code: '<menuitem type="radio" aria-selected />',
+      errors: [errorMessage('aria-selected', 'menuitemradio', 'menuitem', true)],
+    },
+    {
+      code: '<menu type="toolbar" aria-haspopup />',
+      errors: [errorMessage('aria-haspopup', 'toolbar', 'menu', true)],
+    },
+    {
+      code: '<menu type="toolbar" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'toolbar', 'menu', true)],
+    },
+    {
+      code: '<menu type="toolbar" aria-expanded />',
+      errors: [errorMessage('aria-expanded', 'toolbar', 'menu', true)],
+    },
+    {
+      code: '<link href="#" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'link', 'link', true)],
+    },
+    {
+      code: '<area href="#" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'link', 'area', true)],
+    },
+    {
+      code: '<a href="#" aria-invalid />',
+      errors: [errorMessage('aria-invalid', 'link', 'a', true)],
+    },
+    {
+      code: '<Link href="#" aria-checked />',
+      errors: [errorMessage('aria-checked', 'link', 'a', true)],
+      settings: componentsSettings,
+    },
+  )).concat(invalidTests).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/scope-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/scope-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/scope-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+/**
+ * @fileoverview Enforce scope prop is only used on <th> elements.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/scope';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'The scope prop can only be used on <th> elements.',
+  type: 'JSXAttribute',
+};
+
+const componentsSettings = {
+  'jsx-a11y': {
+    components: {
+      Foo: 'div',
+      TableHeader: 'th',
+    },
+  },
+};
+
+ruleTester.run('scope', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<div foo />;' },
+    { code: '<th scope />' },
+    { code: '<th scope="row" />' },
+    { code: '<th scope={foo} />' },
+    { code: '<th scope={"col"} {...props} />' },
+    { code: '<Foo scope="bar" {...props} />' },
+    { code: '<TableHeader scope="row" />', settings: componentsSettings },
+  )).map(parserOptionsMapper),
+  invalid: parsers.all([].concat(
+    { code: '<div scope />', errors: [expectedError] },
+    { code: '<Foo scope="bar" />', settings: componentsSettings, errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/tabindex-no-positive-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/tabindex-no-positive-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/rules/tabindex-no-positive-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,55 @@
+/**
+ * @fileoverview Enforce tabIndex value is not greater than zero.
+ * @author Ethan Cohen
+ */
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+import { RuleTester } from 'eslint';
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+import parsers from '../../__util__/helpers/parsers';
+import rule from '../../../src/rules/tabindex-no-positive';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+const expectedError = {
+  message: 'Avoid positive integer values for tabIndex.',
+  type: 'JSXAttribute',
+};
+
+ruleTester.run('tabindex-no-positive', rule, {
+  valid: parsers.all([].concat(
+    { code: '<div />;' },
+    { code: '<div {...props} />' },
+    { code: '<div id="main" />' },
+    { code: '<div tabIndex={undefined} />' },
+    { code: '<div tabIndex={`${undefined}`} />' },
+    { code: '<div tabIndex={`${undefined}${undefined}`} />' },
+    { code: '<div tabIndex={0} />' },
+    { code: '<div tabIndex={-1} />' },
+    { code: '<div tabIndex={null} />' },
+    { code: '<div tabIndex={bar()} />' },
+    { code: '<div tabIndex={bar} />' },
+    { code: '<div tabIndex={"foobar"} />' },
+    { code: '<div tabIndex="0" />' },
+    { code: '<div tabIndex="-1" />' },
+    { code: '<div tabIndex="-5" />' },
+    { code: '<div tabIndex="-5.5" />' },
+    { code: '<div tabIndex={-5.5} />' },
+    { code: '<div tabIndex={-5} />' },
+  )).map(parserOptionsMapper),
+
+  invalid: parsers.all([].concat(
+    { code: '<div tabIndex="1" />', errors: [expectedError] },
+    { code: '<div tabIndex={1} />', errors: [expectedError] },
+    { code: '<div tabIndex={"1"} />', errors: [expectedError] },
+    { code: '<div tabIndex={`1`} />', errors: [expectedError] },
+    { code: '<div tabIndex={1.589} />', errors: [expectedError] },
+  )).map(parserOptionsMapper),
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/attributesComparator-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/attributesComparator-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/attributesComparator-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,91 @@
+import test from 'tape';
+
+import attributesComparator from '../../../src/util/attributesComparator';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+
+test('attributesComparator', (t) => {
+  t.equal(
+    attributesComparator(),
+    true,
+    'baseAttributes are undefined and attributes are undefined -> true',
+  );
+
+  t.equal(
+    attributesComparator([], []),
+    true,
+    'baseAttributes are empty and attributes are empty -> true',
+  );
+
+  t.equal(
+    attributesComparator([], [
+      JSXAttributeMock('foo', 0),
+      JSXAttributeMock('bar', 'baz'),
+    ]),
+    true,
+    'baseAttributes are empty and attributes have values -> true',
+  );
+
+  const baseAttributes = [
+    {
+      name: 'biz',
+      value: 1,
+    }, {
+      name: 'fizz',
+      value: 'pop',
+    }, {
+      name: 'fuzz',
+      value: 'lolz',
+    },
+  ];
+
+  t.equal(
+    attributesComparator(baseAttributes, []),
+    false,
+    'baseAttributes have values and attributes are empty -> false',
+  );
+
+  t.equal(
+    attributesComparator(baseAttributes, [
+      JSXElementMock(),
+      JSXAttributeMock('biz', 2),
+      JSXAttributeMock('ziff', 'opo'),
+      JSXAttributeMock('far', 'lolz'),
+    ]),
+    false,
+    'baseAttributes have values and attributes have values, and the values are different -> false',
+  );
+
+  t.equal(
+    attributesComparator(baseAttributes, [
+      JSXAttributeMock('biz', 1),
+      JSXAttributeMock('fizz', 'pop'),
+      JSXAttributeMock('goo', 'gazz'),
+    ]),
+    false,
+    'baseAttributes have values and attributes have values, and the values are a subset -> false',
+  );
+
+  t.equal(
+    attributesComparator(baseAttributes, [
+      JSXAttributeMock('biz', 1),
+      JSXAttributeMock('fizz', 'pop'),
+      JSXAttributeMock('fuzz', 'lolz'),
+    ]),
+    true,
+    'baseAttributes have values and attributes have values, and the values are the same -> true',
+  );
+
+  t.equal(
+    attributesComparator(baseAttributes, [
+      JSXAttributeMock('biz', 1),
+      JSXAttributeMock('fizz', 'pop'),
+      JSXAttributeMock('fuzz', 'lolz'),
+      JSXAttributeMock('dar', 'tee'),
+    ]),
+    true,
+    'baseAttributes have values and attributes have values, and the values are a superset -> true',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getAccessibleChildText-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getAccessibleChildText-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getAccessibleChildText-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,174 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import getAccessibleChildText from '../../../src/util/getAccessibleChildText';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+
+test('getAccessibleChildText', (t) => {
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [JSXAttributeMock('aria-label', 'foo')],
+    ), elementType),
+    'foo',
+    'returns the aria-label when present',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [JSXAttributeMock('aria-label', 'foo')],
+      [{ type: 'JSXText', value: 'bar' }],
+    ), elementType),
+    'foo',
+    'returns the aria-label instead of children',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [JSXAttributeMock('aria-hidden', 'true')],
+    ), elementType),
+    '',
+    'skips elements with aria-hidden=true',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'JSXText', value: 'bar' }],
+    ), elementType),
+    'bar',
+    'returns literal value for JSXText child',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [JSXElementMock('img', [
+        JSXAttributeMock('src', 'some/path'),
+        JSXAttributeMock('alt', 'a sensible label'),
+      ])],
+    ), elementType),
+    'a sensible label',
+    'returns alt text for img child',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [JSXElementMock('span', [
+        JSXAttributeMock('alt', 'a sensible label'),
+      ])],
+    ), elementType),
+    '',
+    'returns blank when alt tag is used on arbitrary element',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'Literal', value: 'bar' }],
+    ), elementType),
+    'bar',
+    'returns literal value for JSXText child',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'Literal', value: ' bar   ' }],
+    ), elementType),
+    'bar',
+    'returns trimmed literal value for JSXText child',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'Literal', value: 'foo         bar' }],
+    ), elementType),
+    'foo bar',
+    'returns space-collapsed literal value for JSXText child',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'Literal', value: 'foo, bar. baz? foo; bar:' }],
+    ), elementType),
+    'foo bar baz foo bar',
+    'returns punctuation-stripped literal value for JSXText child',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [JSXElementMock(
+        'span',
+        [],
+        [{ type: 'Literal', value: 'bar' }],
+      )],
+    ), elementType),
+    'bar',
+    'returns recursive value for JSXElement child',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [JSXElementMock(
+        'span',
+        [],
+        [JSXElementMock(
+          'span',
+          [JSXAttributeMock('aria-hidden', 'true')],
+        )],
+      )],
+    ), elementType),
+    '',
+    'skips children with aria-hidden-true',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'Literal', value: 'foo' }, { type: 'Literal', value: 'bar' }],
+    ), elementType),
+    'foo bar',
+    'joins multiple children properly - no spacing',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'Literal', value: ' foo ' }, { type: 'Literal', value: ' bar ' }],
+    ), elementType),
+    'foo bar',
+    'joins multiple children properly - with spacing',
+  );
+
+  t.equal(
+    getAccessibleChildText(JSXElementMock(
+      'a',
+      [],
+      [{ type: 'Literal', value: 'foo' }, { type: 'Unknown' }, { type: 'Literal', value: 'bar' }],
+    ), elementType),
+    'foo bar',
+    'skips unknown elements',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getComputedRole-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getComputedRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getComputedRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,71 @@
+import test from 'tape';
+
+import getComputedRole from '../../../src/util/getComputedRole';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+test('getComputedRole', (t) => {
+  t.equal(
+    getComputedRole(
+      'div',
+      [JSXAttributeMock('role', 'button')],
+    ),
+    'button',
+    'explicit role + valid role -> returns the role',
+  );
+
+  t.equal(
+    getComputedRole(
+      'li',
+      [JSXAttributeMock('role', 'beeswax')],
+    ),
+    'listitem',
+    'explicit role + invalid role + has implicit -> returns the implicit role',
+  );
+
+  t.equal(
+    getComputedRole(
+      'div',
+      [JSXAttributeMock('role', 'beeswax')],
+    ),
+    null,
+    'explicit role + invalid role + lacks implicit -> returns null',
+  );
+
+  t.equal(
+    getComputedRole(
+      'li',
+      [],
+    ),
+    'listitem',
+    'explicit role + no role + has implicit -> returns the implicit role',
+  );
+
+  t.equal(
+    getComputedRole(
+      'div',
+      [],
+    ),
+    null,
+    'explicit role + no role + lacks implicit -> returns null',
+  );
+
+  t.equal(
+    getComputedRole(
+      'li',
+      [JSXAttributeMock('role', 'beeswax')],
+    ),
+    'listitem',
+    'implicit role + has implicit -> returns the implicit role',
+  );
+
+  t.equal(
+    getComputedRole(
+      'div',
+      [],
+    ),
+    null,
+    'implicit role + lacks implicit -> returns null',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getElementType-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getElementType-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getElementType-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,154 @@
+import test from 'tape';
+
+import getElementType from '../../../src/util/getElementType';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+test('getElementType', (t) => {
+  t.test('no settings in context', (st) => {
+    const elementType = getElementType({ settings: {} });
+
+    st.equal(
+      elementType(JSXElementMock('input').openingElement),
+      'input',
+      'returns the exact tag name for a DOM element',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('CustomInput').openingElement),
+      'CustomInput',
+      'returns the exact tag name for a custom element',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('toString').openingElement),
+      'toString',
+      'returns the exact tag name for names that are in Object.prototype',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('span', [JSXAttributeMock('as', 'h1')]).openingElement),
+      'span',
+      'returns the default tag name provided',
+    );
+
+    st.end();
+  });
+
+  t.test('components settings in context', (st) => {
+    const elementType = getElementType({
+      settings: {
+        'jsx-a11y': {
+          components: {
+            CustomInput: 'input',
+          },
+        },
+      },
+    });
+
+    st.equal(
+      elementType(JSXElementMock('input').openingElement),
+      'input',
+      'returns the exact tag name for a DOM element',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('CustomInput').openingElement),
+      'input',
+      'returns the mapped tag name for a custom element',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('CityInput').openingElement),
+      'CityInput',
+      'returns the exact tag name for a custom element not in the components map',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('span', [JSXAttributeMock('as', 'h1')]).openingElement),
+      'span',
+      'return the default tag name since not polymorphicPropName was provided',
+    );
+
+    st.end();
+  });
+
+  t.test('polymorphicPropName settings in context', (st) => {
+    const elementType = getElementType({
+      settings: {
+        'jsx-a11y': {
+          polymorphicPropName: 'asChild',
+          components: {
+            CustomButton: 'button',
+          },
+        },
+      },
+    });
+
+    st.equal(
+      elementType(JSXElementMock('span', [JSXAttributeMock('asChild', 'h1')]).openingElement),
+      'h1',
+      'returns the tag name provided by the polymorphic prop, "asChild", defined in the settings',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('CustomButton', [JSXAttributeMock('asChild', 'a')]).openingElement),
+      'a',
+      'returns the tag name provided by the polymorphic prop, "asChild", defined in the settings instead of the component mapping tag',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('CustomButton', [JSXAttributeMock('as', 'a')]).openingElement),
+      'button',
+      'returns the tag name provided by the componnet mapping if the polymorphic prop, "asChild", defined in the settings is not set',
+    );
+
+    st.end();
+  });
+
+  t.test('polymorphicPropName settings and explicitly defined polymorphicAllowList in context', (st) => {
+    const elementType = getElementType({
+      settings: {
+        'jsx-a11y': {
+          polymorphicPropName: 'asChild',
+          polymorphicAllowList: [
+            'Box',
+            'Icon',
+          ],
+          components: {
+            Box: 'div',
+            Icon: 'svg',
+          },
+        },
+      },
+    });
+
+    st.equal(
+      elementType(JSXElementMock('Spinner', [JSXAttributeMock('asChild', 'img')]).openingElement),
+      'Spinner',
+      'does not use the polymorphic prop if polymorphicAllowList is defined, but element is not part of polymorphicAllowList',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('Icon', [JSXAttributeMock('asChild', 'img')]).openingElement),
+      'img',
+      'uses the polymorphic prop if it is in explicitly defined polymorphicAllowList',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('Box', [JSXAttributeMock('asChild', 'span')]).openingElement),
+      'span',
+      'returns the tag name provided by the polymorphic prop, "asChild", defined in the settings instead of the component mapping tag',
+    );
+
+    st.equal(
+      elementType(JSXElementMock('Box', [JSXAttributeMock('as', 'a')]).openingElement),
+      'div',
+      'returns the tag name provided by the component mapping if the polymorphic prop, "asChild", defined in the settings is not set',
+    );
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getExplicitRole-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getExplicitRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getExplicitRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+import test from 'tape';
+
+import getExplicitRole from '../../../src/util/getExplicitRole';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+test('getExplicitRole', (t) => {
+  t.equal(
+    getExplicitRole(
+      'div',
+      [JSXAttributeMock('role', 'button')],
+    ),
+    'button',
+    'valid role returns the role',
+  );
+
+  t.equal(
+    getExplicitRole(
+      'div',
+      [JSXAttributeMock('role', 'beeswax')],
+    ),
+    null,
+    'invalid role returns null',
+  );
+
+  t.equal(
+    getExplicitRole(
+      'div',
+      [],
+    ),
+    null,
+    'no role returns null',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getImplicitRole-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getImplicitRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getImplicitRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+import test from 'tape';
+
+import getImplicitRole from '../../../src/util/getImplicitRole';
+
+test('getImplicitRole', (t) => {
+  t.equal(
+    getImplicitRole(
+      'li',
+      [],
+    ),
+    'listitem',
+    'has implicit, returns implicit role',
+  );
+
+  t.equal(
+    getImplicitRole(
+      'div',
+      [],
+    ),
+    null,
+    'lacks implicit, returns null',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getSuggestion-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getSuggestion-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getSuggestion-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,33 @@
+import test from 'tape';
+
+import getSuggestion from '../../../src/util/getSuggestion';
+
+test('spell check suggestion API', (t) => {
+  t.deepEqual([], getSuggestion('foo'), 'returns no suggestions given empty word and no dictionary');
+
+  t.deepEqual(
+    getSuggestion('foo'),
+    [],
+    'returns no suggestions given real word and no dictionary',
+  );
+
+  t.deepEqual(
+    getSuggestion('fo', ['foo', 'bar', 'baz']),
+    ['foo'],
+    'returns correct suggestion given real word and a dictionary',
+  );
+
+  t.deepEqual(
+    getSuggestion('theer', ['there', 'their', 'foo', 'bar']),
+    ['there', 'their'],
+    'returns multiple correct suggestions given real word and a dictionary',
+  );
+
+  t.deepEqual(
+    getSuggestion('theer', ['there', 'their', 'foo', 'bar'], 1),
+    ['there'],
+    'returns correct # of suggestions given the limit argument',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getTabIndex-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getTabIndex-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/getTabIndex-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,85 @@
+import test from 'tape';
+
+import getTabIndex from '../../../src/util/getTabIndex';
+import IdentifierMock from '../../../__mocks__/IdentifierMock';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+test('getTabIndex', (t) => {
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', 0)),
+    0,
+    'tabIndex is defined as zero -> zero',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', 1)),
+    1,
+    'tabIndex is defined as a positive integer -> returns it',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', -1)),
+    -1,
+    'tabIndex is defined as a negative integer -> returns it',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', '')),
+    undefined,
+    'tabIndex is defined as an empty string -> undefined',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', 9.1)),
+    undefined,
+    'tabIndex is defined as a float -> undefined',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', '0')),
+    0,
+    'tabIndex is defined as a string which converts to a number -> returns the integer',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', '0a')),
+    undefined,
+    'tabIndex is defined as a string which is NaN -> returns undefined',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', true)),
+    undefined,
+    'tabIndex is defined as true -> returns undefined',
+  );
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', false)),
+    undefined,
+    'tabIndex is defined as false -> returns undefined',
+  );
+
+  t.equal(
+    typeof getTabIndex(JSXAttributeMock('tabIndex', () => 0)),
+    'function',
+    'tabIndex is defined as a function expression -> returns the correct type',
+  );
+
+  const name = 'identName';
+  t.equal(
+    getTabIndex(JSXAttributeMock(
+      'tabIndex',
+      IdentifierMock(name),
+      true,
+    )),
+    name,
+    'tabIndex is defined as a variable expression -> returns the Identifier name',
+  );
+
+  t.equal(
+    getTabIndex(JSXAttributeMock('tabIndex', undefined)),
+    undefined,
+    'tabIndex is not defined -> returns undefined',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/hasAccessibleChild-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/hasAccessibleChild-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/hasAccessibleChild-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,157 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import hasAccessibleChild from '../../../src/util/hasAccessibleChild';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
+
+test('hasAccessibleChild', (t) => {
+  t.equal(
+    hasAccessibleChild(JSXElementMock('div', []), elementType),
+    false,
+    'has no children and does not set dangerouslySetInnerHTML -> false',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [JSXAttributeMock('dangerouslySetInnerHTML', true)], []),
+      elementType,
+    ),
+    true,
+    'has no children and sets dangerouslySetInnerHTML -> true',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock(
+        'div',
+        [],
+        [{
+          type: 'Literal',
+          value: 'foo',
+        }],
+      ),
+      elementType,
+    ),
+    true,
+    'has children + Literal child -> true',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [JSXElementMock('div', [])]),
+      elementType,
+    ),
+    true,
+    'has children + visible JSXElement child -> true',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [{
+        type: 'JSXText',
+        value: 'foo',
+      }]),
+      elementType,
+    ),
+    true,
+    'has children + JSText element -> true',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [
+        JSXElementMock('div', [
+          JSXAttributeMock('aria-hidden', true),
+        ]),
+      ]),
+      elementType,
+    ),
+    false,
+    'has children + hidden child JSXElement -> false',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [
+        JSXExpressionContainerMock({
+          type: 'Identifier',
+          name: 'foo',
+        }),
+      ]),
+      elementType,
+    ),
+    true,
+    'defined JSXExpressionContainer -> true',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [
+        JSXExpressionContainerMock({
+          type: 'Identifier',
+          name: 'undefined',
+        }),
+      ]),
+      elementType,
+    ),
+    false,
+    'has children + undefined JSXExpressionContainer -> false',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [{
+        type: 'Unknown',
+      }]),
+      elementType,
+    ),
+    false,
+    'unknown child type -> false',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [JSXAttributeMock('children', true)], []),
+      elementType,
+    ),
+    true,
+    'children passed as a prop -> true',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [
+        JSXElementMock('input', [JSXAttributeMock('type', 'hidden')]),
+      ]),
+      elementType,
+    ),
+    false,
+    'has chidren -> hidden child input JSXElement -> false',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [
+        JSXElementMock('CustomInput', [JSXAttributeMock('type', 'hidden')]),
+      ]),
+      elementType,
+    ),
+    true,
+    'has children + custom JSXElement of type hidden -> true',
+  );
+
+  t.equal(
+    hasAccessibleChild(
+      JSXElementMock('div', [], [
+        JSXElementMock('CustomInput', [JSXAttributeMock('type', 'hidden')]),
+      ]),
+      () => 'input',
+    ),
+    false,
+    'custom JSXElement mapped to input if type is hidden -> false',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/input-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/input-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/input-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,87 @@
+import test from 'tape';
+
+import JSXAttributeMock from '../../../../__mocks__/JSXAttributeMock';
+import getImplicitRoleForInput from '../../../../src/util/implicitRoles/input';
+
+test('isAbstractRole', (t) => {
+  t.test('works for buttons', (st) => {
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'button')]),
+      'button',
+    );
+
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'image')]),
+      'button',
+    );
+
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'reset')]),
+      'button',
+    );
+
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'submit')]),
+      'button',
+    );
+
+    st.end();
+  });
+
+  t.equal(
+    getImplicitRoleForInput([JSXAttributeMock('type', 'checkbox')]),
+    'checkbox',
+    'works for checkboxes',
+  );
+
+  t.equal(
+    getImplicitRoleForInput([JSXAttributeMock('type', 'radio')]),
+    'radio',
+    'works for radios',
+  );
+
+  t.equal(
+    getImplicitRoleForInput([JSXAttributeMock('type', 'range')]),
+    'slider',
+    'works for ranges',
+  );
+
+  t.test('works for textboxes', (st) => {
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'email')]),
+      'textbox',
+    );
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'password')]),
+      'textbox',
+    );
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'search')]),
+      'textbox',
+    );
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'tel')]),
+      'textbox',
+    );
+    st.equal(
+      getImplicitRoleForInput([JSXAttributeMock('type', 'url')]),
+      'textbox',
+    );
+
+    st.end();
+  });
+
+  t.equal(
+    getImplicitRoleForInput([JSXAttributeMock('type', '')]),
+    'textbox',
+    'works for the default case',
+  );
+
+  t.equal(
+    getImplicitRoleForInput([JSXAttributeMock('type', true)]),
+    'textbox',
+    'works for the true case',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/menu-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/menu-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/menu-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+import test from 'tape';
+
+import JSXAttributeMock from '../../../../__mocks__/JSXAttributeMock';
+import getImplicitRoleForMenu from '../../../../src/util/implicitRoles/menu';
+
+test('isAbstractRole', (t) => {
+  t.equal(
+    getImplicitRoleForMenu([JSXAttributeMock('type', 'toolbar')]),
+    'toolbar',
+    'works for toolbars',
+  );
+
+  t.equal(
+    getImplicitRoleForMenu([JSXAttributeMock('type', '')]),
+    '',
+    'works for non-toolbars',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/menuitem-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/menuitem-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/implicitRoles/menuitem-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+import test from 'tape';
+
+import JSXAttributeMock from '../../../../__mocks__/JSXAttributeMock';
+import getImplicitRoleForMenuitem from '../../../../src/util/implicitRoles/menuitem';
+
+test('isAbstractRole', (t) => {
+  t.equal(
+    getImplicitRoleForMenuitem([JSXAttributeMock('type', 'command')]),
+    'menuitem',
+    'works for menu items',
+  );
+
+  t.equal(
+    getImplicitRoleForMenuitem([JSXAttributeMock('type', 'checkbox')]),
+    'menuitemcheckbox',
+    'works for menu item checkboxes',
+  );
+
+  t.equal(
+    getImplicitRoleForMenuitem([JSXAttributeMock('type', 'radio')]),
+    'menuitemradio',
+    'works for menu item radios',
+  );
+
+  t.equal(
+    getImplicitRoleForMenuitem([JSXAttributeMock('type', '')]),
+    '',
+    'works for non-toolbars',
+  );
+
+  t.equal(
+    getImplicitRoleForMenuitem([JSXAttributeMock('type', true)]),
+    '',
+    'works for the true case',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isAbstractRole-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isAbstractRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isAbstractRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import isAbstractRole from '../../../src/util/isAbstractRole';
+import {
+  genElementSymbol,
+  genAbstractRoleElements,
+  genNonAbstractRoleElements,
+} from '../../../__mocks__/genInteractives';
+
+test('isAbstractRole', (t) => {
+  t.equal(
+    isAbstractRole(undefined, []),
+    false,
+    'does NOT identify JSX Components (no tagName) as abstract role elements',
+  );
+
+  t.test('elements with an abstract role', (st) => {
+    genAbstractRoleElements().forEach(({ openingElement }) => {
+      const { attributes } = openingElement;
+      st.equal(
+        isAbstractRole(
+          elementType(openingElement),
+          attributes,
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` as an abstract role element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('elements with a non-abstract role', (st) => {
+    genNonAbstractRoleElements().forEach(({ openingElement }) => {
+      const { attributes } = openingElement;
+      st.equal(
+        isAbstractRole(
+          elementType(openingElement),
+          attributes,
+        ),
+        false,
+        `does NOT identify \`${genElementSymbol(openingElement)}\` as an abstract role element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isContentEditable-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isContentEditable-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isContentEditable-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+import test from 'tape';
+
+import isContentEditable from '../../../src/util/isContentEditable';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+test('isContentEditable - HTML5', (t) => {
+  t.equal(
+    isContentEditable('some tag', [
+      JSXAttributeMock('contentEditable', 'true'),
+    ]),
+    true,
+    'identifies HTML5 contentEditable elements',
+  );
+
+  t.test('not content editable', (st) => {
+    st.equal(
+      isContentEditable('some tag', [
+        JSXAttributeMock('contentEditable', null),
+      ]),
+      false,
+      'does not identify HTML5 content editable elements with null as the value',
+    );
+
+    st.equal(
+      isContentEditable('some tag', [
+        JSXAttributeMock('contentEditable', undefined),
+      ]),
+      false,
+      'does not identify HTML5 content editable elements with undefined as the value',
+    );
+
+    st.equal(
+      isContentEditable('some tag', [
+        JSXAttributeMock('contentEditable', true),
+      ]),
+      false,
+      'does not identify HTML5 content editable elements with true as the value',
+    );
+
+    st.equal(
+      isContentEditable('some tag', [
+        JSXAttributeMock('contentEditable', 'false'),
+      ]),
+      false,
+      'does not identify HTML5 content editable elements with "false" as the value',
+    );
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isDOMElement-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isDOMElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isDOMElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+import test from 'tape';
+import { dom } from 'aria-query';
+import { elementType } from 'jsx-ast-utils';
+
+import isDOMElement from '../../../src/util/isDOMElement';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+
+test('isDOMElement', (t) => {
+  t.test('DOM elements', (st) => {
+    dom.forEach((_, el) => {
+      const element = JSXElementMock(el);
+
+      st.equal(
+        isDOMElement(elementType(element.openingElement)),
+        true,
+        `identifies ${el} as a DOM element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.equal(
+    isDOMElement(JSXElementMock('CustomElement')),
+    false,
+    'does not identify a custom element',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isDisabledElement-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isDisabledElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isDisabledElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,88 @@
+import test from 'tape';
+
+import isDisabledElement from '../../../src/util/isDisabledElement';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+test('isDisabledElement', (t) => {
+  t.test('HTML5', (st) => {
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('disabled', 'disabled'),
+      ]),
+      true,
+      'identifies HTML5 disabled elements',
+    );
+
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('disabled', null),
+      ]),
+      true,
+      'identifies HTML5 disabled elements with null as the value',
+    );
+
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('disabled', undefined),
+      ]),
+      false,
+      'does not identify HTML5 disabled elements with undefined as the value',
+    );
+
+    st.end();
+  });
+
+  t.test('ARIA', (st) => {
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('aria-disabled', 'true'),
+      ]),
+      true,
+      'does not identify ARIA disabled elements',
+    );
+
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('aria-disabled', true),
+      ]),
+      true,
+      'does not identify ARIA disabled elements',
+    );
+
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('aria-disabled', 'false'),
+      ]),
+      false,
+      'does not identify ARIA disabled elements',
+    );
+
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('aria-disabled', false),
+      ]),
+      false,
+      'does not identify ARIA disabled elements',
+    );
+
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('aria-disabled', null),
+      ]),
+      false,
+      'does not identify ARIA disabled elements with null as the value',
+    );
+
+    st.equal(
+      isDisabledElement([
+        JSXAttributeMock('aria-disabled', undefined),
+      ]),
+      false,
+      'does not identify ARIA disabled elements with undefined as the value',
+    );
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isFocusable-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isFocusable-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isFocusable-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,111 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import isFocusable from '../../../src/util/isFocusable';
+import {
+  genElementSymbol,
+  genInteractiveElements,
+  genNonInteractiveElements,
+} from '../../../__mocks__/genInteractives';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+function mergeTabIndex(index, attributes) {
+  return [].concat(attributes, JSXAttributeMock('tabIndex', index));
+}
+
+test('isFocusable', (t) => {
+  t.test('interactive elements', (st) => {
+    genInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` as a focusable element`,
+      );
+
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          mergeTabIndex(-1, openingElement.attributes),
+        ),
+        false,
+        `does NOT identify \`${genElementSymbol(openingElement)}\` with tabIndex of -1 as a focusable element`,
+      );
+
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          mergeTabIndex(0, openingElement.attributes),
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` with tabIndex of 0 as a focusable element`,
+      );
+
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          mergeTabIndex(1, openingElement.attributes),
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` with tabIndex of 1 as a focusable element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('non-interactive elements', (st) => {
+    genNonInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `does NOT identify \`${genElementSymbol(openingElement)}\` as a focusable element`,
+      );
+
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          mergeTabIndex(-1, openingElement.attributes),
+        ),
+        false,
+        `does NOT identify \`${genElementSymbol(openingElement)}\` with tabIndex of -1 as a focusable element`,
+      );
+
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          mergeTabIndex(0, openingElement.attributes),
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` with tabIndex of 0 as a focusable element`,
+      );
+
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          mergeTabIndex(1, openingElement.attributes),
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` with tabIndex of 1 as a focusable element`,
+      );
+
+      st.equal(
+        isFocusable(
+          elementType(openingElement),
+          mergeTabIndex('bogus', openingElement.attributes),
+        ),
+        false,
+        `does NOT identify \`${genElementSymbol(openingElement)}\` with tabIndex of 'bogus' as a focusable element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isInteractiveElement-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isInteractiveElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isInteractiveElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,104 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import isInteractiveElement from '../../../src/util/isInteractiveElement';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+import {
+  genElementSymbol,
+  genIndeterminantInteractiveElements,
+  genInteractiveElements,
+  genInteractiveRoleElements,
+  genNonInteractiveElements,
+  genNonInteractiveRoleElements,
+} from '../../../__mocks__/genInteractives';
+
+test('isInteractiveElement', (t) => {
+  t.equal(
+    isInteractiveElement(undefined, []),
+    false,
+    'identifies them as interactive elements',
+  );
+
+  t.test('interactive elements', (st) => {
+    genInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` as an interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('interactive role elements', (st) => {
+    genInteractiveRoleElements().forEach(({ openingElement }) => {
+      st.equal(
+        isInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as an interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('non-interactive elements', (st) => {
+    genNonInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as an interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('non-interactive role elements', (st) => {
+    genNonInteractiveRoleElements().forEach(({ openingElement }) => {
+      st.equal(
+        isInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as an interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('indeterminate elements', (st) => {
+    genIndeterminantInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as an interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.equal(
+    isInteractiveElement('CustomComponent', JSXElementMock()),
+    false,
+    'JSX elements are not interactive',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isInteractiveRole-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isInteractiveRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isInteractiveRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import isInteractiveRole from '../../../src/util/isInteractiveRole';
+import {
+  genElementSymbol,
+  genInteractiveRoleElements,
+  genNonInteractiveRoleElements,
+} from '../../../__mocks__/genInteractives';
+
+test('isInteractiveRole', (t) => {
+  t.equal(
+    isInteractiveRole(undefined, []),
+    false,
+    'identifies JSX Components (no tagName) as interactive role elements',
+  );
+
+  t.test('elements with a non-interactive role', (st) => {
+    genNonInteractiveRoleElements().forEach(({ openingElement }) => {
+      const { attributes } = openingElement;
+
+      st.equal(
+        isInteractiveRole(
+          elementType(openingElement),
+          attributes,
+        ),
+        false,
+        `does NOT identify \`${genElementSymbol(openingElement)}\` as an interactive role element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.equal(
+    isInteractiveRole('div', []),
+    false,
+    'does NOT identify elements without a role as interactive role elements',
+  );
+
+  t.test('elements with an interactive role', (st) => {
+    genInteractiveRoleElements().forEach(({ openingElement }) => {
+      const { attributes } = openingElement;
+
+      st.equal(
+        isInteractiveRole(
+          elementType(openingElement),
+          attributes,
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` as an interactive role element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonInteractiveElement-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonInteractiveElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonInteractiveElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,97 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import isNonInteractiveElement from '../../../src/util/isNonInteractiveElement';
+import {
+  genElementSymbol,
+  genIndeterminantInteractiveElements,
+  genInteractiveElements,
+  genInteractiveRoleElements,
+  genNonInteractiveElements,
+  genNonInteractiveRoleElements,
+} from '../../../__mocks__/genInteractives';
+
+test('isNonInteractiveElement', (t) => {
+  t.equal(
+    isNonInteractiveElement(undefined, []),
+    false,
+    'identifies JSX Components (no tagName) as non-interactive elements',
+  );
+
+  t.test('non-interactive elements', (st) => {
+    genNonInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isNonInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` as a non-interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('non-interactive role elements', (st) => {
+    genNonInteractiveRoleElements().forEach(({ openingElement }) => {
+      st.equal(
+        isNonInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as a non-interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('interactive elements', (st) => {
+    genInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isNonInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as a non-interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('interactive role elements', (st) => {
+    genInteractiveRoleElements().forEach(({ openingElement }) => {
+      st.equal(
+        isNonInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as a non-interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.test('indeterminate elements', (st) => {
+    genIndeterminantInteractiveElements().forEach(({ openingElement }) => {
+      st.equal(
+        isNonInteractiveElement(
+          elementType(openingElement),
+          openingElement.attributes,
+        ),
+        false,
+        `identifies \`${genElementSymbol(openingElement)}\` as a non-interactive element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonInteractiveRole-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonInteractiveRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonInteractiveRole-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+import test from 'tape';
+import { elementType } from 'jsx-ast-utils';
+
+import isNonInteractiveRole from '../../../src/util/isNonInteractiveRole';
+import {
+  genElementSymbol,
+  genInteractiveRoleElements,
+  genNonInteractiveRoleElements,
+} from '../../../__mocks__/genInteractives';
+
+test('isNonInteractiveRole', (t) => {
+  t.equal(
+    isNonInteractiveRole(undefined, []),
+    false,
+    'identifies JSX Components (no tagName) as non-interactive elements',
+  );
+
+  t.test('elements with a non-interactive role', (st) => {
+    genNonInteractiveRoleElements().forEach(({ openingElement }) => {
+      const { attributes } = openingElement;
+
+      st.equal(
+        isNonInteractiveRole(
+          elementType(openingElement),
+          attributes,
+        ),
+        true,
+        `identifies \`${genElementSymbol(openingElement)}\` as a non-interactive role element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.equal(
+    isNonInteractiveRole('div', []),
+    false,
+    'does NOT identify elements without a role as non-interactive role elements',
+  );
+
+  t.test('elements with an interactive role', (st) => {
+    genInteractiveRoleElements().forEach(({ openingElement }) => {
+      const { attributes } = openingElement;
+
+      st.equal(
+        isNonInteractiveRole(
+          elementType(openingElement),
+          attributes,
+        ),
+        false,
+        `does NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive role element`,
+      );
+    });
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonLiteralProperty-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonLiteralProperty-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isNonLiteralProperty-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+import test from 'tape';
+
+import isNonLiteralProperty from '../../../src/util/isNonLiteralProperty';
+import IdentifierMock from '../../../__mocks__/IdentifierMock';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+import JSXSpreadAttributeMock from '../../../__mocks__/JSXSpreadAttributeMock';
+import JSXTextMock from '../../../__mocks__/JSXTextMock';
+import LiteralMock from '../../../__mocks__/LiteralMock';
+
+const theProp = 'theProp';
+
+const spread = JSXSpreadAttributeMock('theSpread');
+
+test('isNonLiteralProperty', (t) => {
+  t.equal(
+    isNonLiteralProperty([], theProp),
+    false,
+    'does not identify them as non-literal role elements',
+  );
+
+  t.equal(
+    isNonLiteralProperty([JSXAttributeMock(theProp, LiteralMock('theRole'))], theProp),
+    false,
+    'does not identify elements with a literal property as non-literal role elements without spread operator',
+  );
+
+  t.equal(
+    isNonLiteralProperty([spread, JSXAttributeMock(theProp, LiteralMock('theRole'))], theProp),
+    false,
+    'does not identify elements with a literal property as non-literal role elements with spread operator',
+  );
+
+  t.equal(
+    isNonLiteralProperty([JSXAttributeMock(theProp, JSXTextMock('theRole'))], theProp),
+    false,
+    'identifies elements with a JSXText property as non-literal role elements',
+  );
+
+  t.equal(
+    isNonLiteralProperty([JSXAttributeMock(theProp, IdentifierMock('undefined'))], theProp),
+    false,
+    'does not identify elements with a property of undefined as non-literal role elements',
+  );
+
+  t.equal(
+    isNonLiteralProperty([JSXAttributeMock(theProp, IdentifierMock('theIdentifier'))], theProp),
+    true,
+    'identifies elements with an expression property as non-literal role elements',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isSemanticRoleElement-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isSemanticRoleElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/isSemanticRoleElement-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,72 @@
+import test from 'tape';
+
+import isSemanticRoleElement from '../../../src/util/isSemanticRoleElement';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+
+test('isSemanticRoleElement', (t) => {
+  t.equal(
+    isSemanticRoleElement('input', [
+      JSXAttributeMock('type', 'checkbox'),
+      JSXAttributeMock('role', 'switch'),
+    ]),
+    true,
+    'identifies semantic role elements',
+  );
+
+  t.test('rejects non-semantics role elements', (st) => {
+    st.equal(
+      isSemanticRoleElement('input', [
+        JSXAttributeMock('type', 'radio'),
+        JSXAttributeMock('role', 'switch'),
+      ]),
+      false,
+    );
+
+    st.equal(
+      isSemanticRoleElement('input', [
+        JSXAttributeMock('type', 'text'),
+        JSXAttributeMock('role', 'combobox'),
+      ]),
+      false,
+    );
+
+    st.equal(
+      isSemanticRoleElement('button', [
+        JSXAttributeMock('role', 'switch'),
+        JSXAttributeMock('aria-pressed', 'true'),
+      ]),
+      false,
+    );
+
+    st.equal(
+      isSemanticRoleElement('input', [
+        JSXAttributeMock('role', 'switch'),
+      ]),
+      false,
+    );
+
+    st.end();
+  });
+
+  t.doesNotThrow(
+    () => {
+      isSemanticRoleElement('input', [
+        JSXAttributeMock('type', 'checkbox'),
+        JSXAttributeMock('role', 'checkbox'),
+        JSXAttributeMock('aria-checked', 'false'),
+        JSXAttributeMock('aria-labelledby', 'foo'),
+        JSXAttributeMock('tabindex', '0'),
+        {
+          type: 'JSXSpreadAttribute',
+          argument: {
+            type: 'Identifier',
+            name: 'props',
+          },
+        },
+      ]);
+    },
+    'does not throw on JSXSpreadAttribute',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/mayContainChildComponent-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/mayContainChildComponent-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/mayContainChildComponent-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,219 @@
+import test from 'tape';
+
+import mayContainChildComponent from '../../../src/util/mayContainChildComponent';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
+
+test('mayContainChildComponent', (t) => {
+  t.equal(
+    mayContainChildComponent(
+      JSXElementMock('div', [], [
+        JSXElementMock('div', [], [
+          JSXElementMock('span', [], []),
+          JSXElementMock('span', [], [
+            JSXElementMock('span', [], []),
+            JSXElementMock('span', [], [
+              JSXElementMock('span', [], []),
+            ]),
+          ]),
+        ]),
+        JSXElementMock('span', [], []),
+        JSXElementMock('img', [
+          JSXAttributeMock('src', 'some/path'),
+        ]),
+      ]),
+      'FancyComponent',
+      5,
+    ),
+    false,
+    'no FancyComponent returns false',
+  );
+
+  t.test('contains an indicated component', (st) => {
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('input'),
+        ]),
+        'input',
+      ),
+      true,
+      'returns true',
+    );
+
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('FancyComponent'),
+        ]),
+        'FancyComponent',
+      ),
+      true,
+      'returns true',
+    );
+
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('div', [], [
+            JSXElementMock('FancyComponent'),
+          ]),
+        ]),
+        'FancyComponent',
+      ),
+      false,
+      'FancyComponent is outside of default depth, should return false',
+    );
+
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('div', [], [
+            JSXElementMock('FancyComponent'),
+          ]),
+        ]),
+        'FancyComponent',
+        2,
+      ),
+      true,
+      'FancyComponent is inside of custom depth, should return true',
+    );
+
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('div', [], [
+            JSXElementMock('span', [], []),
+            JSXElementMock('span', [], [
+              JSXElementMock('span', [], []),
+              JSXElementMock('span', [], [
+                JSXElementMock('span', [], [
+                  JSXElementMock('span', [], [
+                    JSXElementMock('FancyComponent'),
+                  ]),
+                ]),
+              ]),
+            ]),
+          ]),
+          JSXElementMock('span', [], []),
+          JSXElementMock('img', [
+            JSXAttributeMock('src', 'some/path'),
+          ]),
+        ]),
+        'FancyComponent',
+        6,
+      ),
+      true,
+      'deep nesting, returns true',
+    );
+
+    st.end();
+  });
+
+  t.equal(
+    mayContainChildComponent(
+      JSXElementMock('div', [], [
+        JSXExpressionContainerMock('mysteryBox'),
+      ]),
+      'FancyComponent',
+    ),
+    true,
+    'Intederminate situations + expression container children - returns true',
+  );
+
+  t.test('Glob name matching - component name contains question mark ? - match any single character', (st) => {
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('FancyComponent'),
+        ]),
+        'Fanc?Co??onent',
+      ),
+      true,
+      'returns true',
+    );
+
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('FancyComponent'),
+        ]),
+        'FancyComponent?',
+      ),
+      false,
+      'returns false',
+    );
+
+    st.test('component name contains asterisk * - match zero or more characters', (s2t) => {
+      s2t.equal(
+        mayContainChildComponent(
+          JSXElementMock('div', [], [
+            JSXElementMock('FancyComponent'),
+          ]),
+          'Fancy*',
+        ),
+        true,
+        'returns true',
+      );
+
+      s2t.equal(
+        mayContainChildComponent(
+          JSXElementMock('div', [], [
+            JSXElementMock('FancyComponent'),
+          ]),
+          '*Component',
+        ),
+        true,
+        'returns true',
+      );
+
+      s2t.equal(
+        mayContainChildComponent(
+          JSXElementMock('div', [], [
+            JSXElementMock('FancyComponent'),
+          ]),
+          'Fancy*C*t',
+        ),
+        true,
+        'returns true',
+      );
+
+      s2t.end();
+    });
+
+    st.end();
+  });
+
+  t.test('using a custom elementType function', (st) => {
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('CustomInput'),
+        ]),
+        'input',
+        2,
+        () => 'input',
+      ),
+      true,
+      'returns true when the custom elementType returns the proper name',
+    );
+
+    st.equal(
+      mayContainChildComponent(
+        JSXElementMock('div', [], [
+          JSXElementMock('CustomInput'),
+        ]),
+        'input',
+        2,
+        () => 'button',
+      ),
+      false,
+      'returns false when the custom elementType returns a wrong name',
+    );
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/mayHaveAccessibleLabel-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/mayHaveAccessibleLabel-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/mayHaveAccessibleLabel-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,256 @@
+import test from 'tape';
+
+import mayHaveAccessibleLabel from '../../../src/util/mayHaveAccessibleLabel';
+import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
+import JSXElementMock from '../../../__mocks__/JSXElementMock';
+import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
+import JSXSpreadAttributeMock from '../../../__mocks__/JSXSpreadAttributeMock';
+import JSXTextMock from '../../../__mocks__/JSXTextMock';
+import LiteralMock from '../../../__mocks__/LiteralMock';
+
+test('mayHaveAccessibleLabel', (t) => {
+  t.equal(
+    mayHaveAccessibleLabel(
+      JSXElementMock('div', [], [
+        JSXElementMock('div', [], [
+          JSXElementMock('span', [], []),
+          JSXElementMock('span', [], [
+            JSXElementMock('span', [], []),
+            JSXElementMock('span', [], [
+              JSXElementMock('span', [], []),
+            ]),
+          ]),
+        ]),
+        JSXElementMock('span', [], []),
+        JSXElementMock('img', [
+          JSXAttributeMock('src', 'some/path'),
+        ]),
+      ]),
+      5,
+    ),
+    false,
+    'no label returns false',
+  );
+
+  t.test('label via attributes', (st) => {
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('aria-label', 'A delicate label'),
+      ], [])),
+      true,
+      'aria-label returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('aria-label', ''),
+      ], [])),
+      false,
+      'aria-label without content returns false',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('aria-label', ' '),
+      ], [])),
+      false,
+      'aria-label with only spaces whitespace, should return false',
+    );
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('aria-label', '\n'),
+      ], [])),
+      false,
+      'aria-label with only newline whitespace, should return false',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('aria-labelledby', 'elementId'),
+      ], [])),
+      true,
+      'aria-labelledby returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('aria-labelledby', ''),
+      ], [])),
+      false,
+      'aria-labelledby without content returns false',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('aria-labelledby', 'elementId', true),
+      ], [])),
+      true,
+      'aria-labelledby with an expression container, should return true',
+    );
+
+    st.end();
+  });
+
+  t.test('label via custom label attribute', (st) => {
+    const customLabelProp = 'cowbell';
+
+    st.equal(
+      mayHaveAccessibleLabel(
+        JSXElementMock('div', [
+          JSXAttributeMock(customLabelProp, 'A delicate label'),
+        ], []),
+        1,
+        [customLabelProp],
+      ),
+      true,
+      'aria-label returns true',
+    );
+
+    st.end();
+  });
+
+  t.test('text label', (st) => {
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        LiteralMock('A fancy label'),
+      ])),
+      true,
+      'Literal text, returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        LiteralMock(' '),
+      ])),
+      false,
+      'Literal spaces whitespace, returns false',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        LiteralMock('\n'),
+      ])),
+      false,
+      'Literal newline whitespace, returns false',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        JSXTextMock('A fancy label'),
+      ])),
+      true,
+      'JSXText, returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        JSXElementMock('div', [], [
+          JSXTextMock('A fancy label'),
+        ]),
+      ])),
+      false,
+      'label is outside of default depth, returns false',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(
+        JSXElementMock('div', [], [
+          JSXElementMock('div', [], [
+            JSXTextMock('A fancy label'),
+          ]),
+        ]),
+        2,
+      ),
+      true,
+      'label is inside of custom depth, returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(
+        JSXElementMock('div', [], [
+          JSXElementMock('div', [], [
+            JSXElementMock('span', [], []),
+            JSXElementMock('span', [], [
+              JSXElementMock('span', [], []),
+              JSXElementMock('span', [], [
+                JSXElementMock('span', [], [
+                  JSXElementMock('span', [], [
+                    JSXTextMock('A fancy label'),
+                  ]),
+                ]),
+              ]),
+            ]),
+          ]),
+          JSXElementMock('span', [], []),
+          JSXElementMock('img', [
+            JSXAttributeMock('src', 'some/path'),
+          ]),
+        ]),
+        6,
+      ),
+      true,
+      'deep nesting, returns true',
+    );
+
+    st.end();
+  });
+
+  t.test('image content', (st) => {
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        JSXElementMock('img', [
+          JSXAttributeMock('src', 'some/path'),
+        ]),
+      ])),
+      false,
+      'without alt, returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        JSXElementMock('img', [
+          JSXAttributeMock('src', 'some/path'),
+          JSXAttributeMock('alt', 'A sensible label'),
+        ]),
+      ])),
+      true,
+      'with alt, returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        JSXElementMock('img', [
+          JSXAttributeMock('src', 'some/path'),
+          JSXAttributeMock('aria-label', 'A sensible label'),
+        ]),
+      ])),
+      true,
+      'with aria-label, returns true',
+    );
+
+    st.end();
+  });
+
+  t.test('Intederminate situations', (st) => {
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [], [
+        JSXExpressionContainerMock('mysteryBox'),
+      ])),
+      true,
+      'expression container children, returns true',
+    );
+
+    st.equal(
+      mayHaveAccessibleLabel(JSXElementMock('div', [
+        JSXAttributeMock('style', 'some-junk'),
+        JSXSpreadAttributeMock('props'),
+      ], [])),
+      true,
+      'spread operator in attributes, returns true',
+    );
+
+    st.end();
+  });
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/parserOptionsMapper-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/parserOptionsMapper-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/parserOptionsMapper-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,93 @@
+import { version as eslintVersion } from 'eslint/package.json';
+import test from 'tape';
+import semver from 'semver';
+
+import parserOptionsMapper from '../../__util__/parserOptionsMapper';
+
+const usingLegacy = semver.major(eslintVersion) < 9;
+
+test('parserOptionsMapper', (t) => {
+  const expectedResult = usingLegacy
+    ? {
+      code: '<div />',
+      errors: [],
+      options: {},
+      parserOptions: {
+        ecmaVersion: 2018,
+        ecmaFeatures: {
+          experimentalObjectRestSpread: true,
+          jsx: true,
+        },
+      },
+      settings: {},
+    }
+    : {
+      code: '<div />',
+      errors: [],
+      options: {},
+      languageOptions: {
+        ecmaVersion: 'latest',
+        parserOptions: {
+          ecmaFeatures: {
+            experimentalObjectRestSpread: true,
+            jsx: true,
+          },
+        },
+      },
+      settings: {},
+    };
+
+  t.deepEqual(
+    parserOptionsMapper({
+      code: '<div />',
+      errors: [],
+      options: {},
+    }),
+    expectedResult,
+    'returns a test case object',
+  );
+
+  const expectedResult2 = usingLegacy
+    ? {
+      code: '<div />',
+      errors: [],
+      options: {},
+      parserOptions: {
+        ecmaVersion: 5,
+        ecmaFeatures: {
+          experimentalObjectRestSpread: true,
+          jsx: true,
+        },
+      },
+      settings: {},
+    }
+    : {
+      code: '<div />',
+      errors: [],
+      options: {},
+      languageOptions: {
+        ecmaVersion: 5,
+        parserOptions: {
+          ecmaFeatures: {
+            experimentalObjectRestSpread: true,
+            jsx: true,
+          },
+        },
+      },
+      settings: {},
+    };
+  t.deepEqual(
+    parserOptionsMapper({
+      code: '<div />',
+      errors: [],
+      options: {},
+      languageOptions: {
+        ecmaVersion: 5,
+      },
+    }),
+    expectedResult2,
+    'allows for overriding parserOptions',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/schemas-test.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/schemas-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/__tests__/src/util/schemas-test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+import test from 'tape';
+
+import { generateObjSchema, arraySchema, enumArraySchema } from '../../../src/util/schemas';
+
+test('schemas', (t) => {
+  t.test('should generate an object schema with correct properties', (st) => {
+    const schema = generateObjSchema({
+      foo: 'bar',
+      baz: arraySchema,
+    });
+    const properties = schema.properties || {};
+
+    st.deepEqual(properties.foo, properties.foo, 'bar');
+    st.deepEqual(properties.baz.type, 'array');
+
+    st.end();
+  });
+
+  t.deepEqual(
+    enumArraySchema(),
+    {
+      additionalItems: false,
+      items: {
+        enum: [],
+        type: 'string',
+      },
+      minItems: 0,
+      type: 'array',
+      uniqueItems: true,
+    },
+    'enumArraySchema works with no arguments',
+  );
+
+  t.end();
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/accessible-emoji.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/accessible-emoji.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/accessible-emoji.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+# jsx-a11y/accessible-emoji
+
+❌ This rule is deprecated.
+
+<!-- end auto-generated rule header -->
+
+Emoji have become a common way of communicating content to the end user. To a person using a screen reader, however, they may not be aware that this content is there at all. By wrapping the emoji in a `<span>`, giving it the `role="img"`, and providing a useful description in `aria-label`, the screen reader will treat the emoji as an image in the accessibility tree with an accessible name for the end user.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<span role="img" aria-label="Snowman">&#9731;</span>
+<span role="img" aria-label="Panda">🐼</span>
+<span role="img" aria-labelledby="panda1">🐼</span>
+```
+
+### Fail
+```jsx
+<span>🐼</span>
+<i role="img" aria-label="Panda">🐼</i>
+```
+
+## Accessibility guidelines
+- [WCAG 1.1.1](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html)
+
+### Resources
+- [Léonie Watson, Accessible Emoji](https://tink.uk/accessible-emoji/)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/alt-text.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/alt-text.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/alt-text.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,168 @@
+# jsx-a11y/alt-text
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce that all elements that require alternative text have meaningful information to relay back to the end user. This is a critical component of accessibility for screen reader users in order for them to understand the content's purpose on the page. By default, this rule checks for alternative text on the following elements: `<img>`, `<area>`, `<input type="image">`, and `<object>`.
+
+## How to resolve
+
+### `<img>`
+
+An `<img>` must have the `alt` prop set with meaningful text or as an empty string to indicate that it is an image for decoration.
+
+For images that are being used as icons for a button or control, the `alt` prop should be set to an empty string (`alt=""`).
+
+```jsx
+<button>
+  <img src="icon.png" alt="" />
+  Save
+
+</button>
+```
+
+The content of an `alt` attribute is used to calculate the accessible label of an element, whereas the text content is used to produce a label for the element. For this reason, adding a label to an icon can produce a confusing or duplicated label on a control that already has appropriate text content.
+
+### `<object>`
+
+Add alternative text to all embedded `<object>` elements using either inner text, setting the `title` prop, or using the `aria-label` or `aria-labelledby` props.
+
+### `<input type="image">`
+
+All `<input type="image">` elements must have a non-empty `alt` prop set with a meaningful description of the image or have the `aria-label` or `aria-labelledby` props set.
+
+### `<area>`
+
+All clickable `<area>` elements within an image map have an `alt`, `aria-label` or `aria-labelledby` prop that describes the purpose of the link.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/alt-text": [ 2, {
+            "elements": [ "img", "object", "area", "input[type=\"image\"]" ],
+            "img": ["Image"],
+            "object": ["Object"],
+            "area": ["Area"],
+            "input[type=\"image\"]": ["InputImage"]
+          }],
+    }
+}
+```
+
+The `elements` option is a whitelist for DOM elements to check for alternative text. If an element is removed from the default set of elements (noted above), any custom components for that component will also be ignored. In order to indicate any custom wrapper components that should be checked, you can map the DOM element to an array of JSX custom components. This is a good use case when you have a wrapper component that simply renders an `img` element, for instance (like in React):
+
+```jsx
+// Image.js
+const Image = props => {
+  const {
+    alt,
+    ...otherProps
+  } = props;
+
+  return (
+    <img alt={alt} {...otherProps} />
+  );
+}
+
+...
+
+// Header.js (for example)
+...
+return (
+  <header>
+    <Image alt="Logo" src="logo.jpg" />
+  </header>
+
+);
+```
+
+Note that passing props as spread attribute without explicitly the necessary accessibility props defined will cause this rule to fail. Explicitly pass down the set of props needed for rule to pass. Use `Image` component above as a reference for destructuring and applying the prop. **It is a good thing to explicitly pass props that you expect to be passed for self-documentation.** For example:
+
+#### Bad
+
+```jsx
+function Foo(props) {
+  return <img {...props} />
+}
+```
+
+#### Good
+
+```jsx
+function Foo({ alt, ...props}) {
+    return <img alt={alt} {...props} />
+}
+
+// OR
+
+function Foo(props) {
+    const {
+        alt,
+
+        ...otherProps
+    } = props;
+
+   return <img alt={alt} {...otherProps} />
+}
+```
+
+### Succeed
+
+```jsx
+<img src="foo" alt="Foo eating a sandwich." />
+<img src="foo" alt={"Foo eating a sandwich."} />
+<img src="foo" alt={altText} />
+<img src="foo" alt={`${person} smiling`} />
+<img src="foo" alt="" />
+
+<object aria-label="foo" />
+<object aria-labelledby="id1" />
+<object>Meaningful description</object>
+<object title="An object" />
+
+<area aria-label="foo" />
+<area aria-labelledby="id1" />
+
+<area alt="This is descriptive!" />
+
+<input type="image" alt="This is descriptive!" />
+<input type="image" aria-label="foo" />
+<input type="image" aria-labelledby="id1" />
+
+```
+
+### Fail
+
+```jsx
+<img src="foo" />
+<img {...props} />
+<img {...props} alt /> // Has no value
+<img {...props} alt={undefined} /> // Has no value
+<img {...props} alt={`${undefined}`} /> // Has no value
+<img src="foo" role="presentation" /> // Avoid ARIA if it can be achieved without
+
+<img src="foo" role="none" /> // Avoid ARIA if it can be achieved without
+
+<object {...props} />
+
+
+<area {...props} />
+
+<input type="image" {...props} />
+```
+
+## Accessibility guidelines
+
+- [WCAG 1.1.1](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html)
+
+### Resources
+
+- [axe-core, object-alt](https://dequeuniversity.com/rules/axe/3.2/object-alt)
+- [axe-core, image-alt](https://dequeuniversity.com/rules/axe/3.2/image-alt)
+- [axe-core, input-image-alt](https://dequeuniversity.com/rules/axe/3.2/input-image-alt)
+- [axe-core, area-alt](https://dequeuniversity.com/rules/axe/3.2/area-alt)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-ambiguous-text.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-ambiguous-text.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-ambiguous-text.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,91 @@
+# jsx-a11y/anchor-ambiguous-text
+
+🚫 This rule is _disabled_ in the ☑️ `recommended` config.
+
+<!-- end auto-generated rule header -->
+
+Enforces `<a>` values are not exact matches for the phrases "click here", "here", "link", "a link", or "learn more". Screen readers announce tags as links/interactive, but rely on values for context. Ambiguous anchor descriptions do not provide sufficient context for users.
+
+## Rule options
+
+This rule takes one optional object argument with the parameter `words`.
+
+```json
+{
+  "rules": {
+    "jsx-a11y/anchor-ambiguous-text": [2, {
+      "words": ["click this"],
+    }],
+  }
+}
+```
+
+The `words` option allows users to modify the strings that can be checked for in the anchor text. Useful for specifying other words in other languages. The default value is set by `DEFAULT_AMBIGUOUS_WORDS`:
+
+```js
+const DEFAULT_AMBIGUOUS_WORDS = ['click here', 'here', 'link', 'a link', 'learn more'];
+```
+
+The logic to calculate the inner text of an anchor is as follows:
+
+- if an element has the `aria-label` property, its value is used instead of the inner text
+- if an element has `aria-hidden="true`, it is skipped over
+- if an element is `<img />` or configured to be interpreted like one, its `alt` value is used as its inner text
+
+Note that this rule still disallows ambiguous `aria-label` or `alt` values.
+
+Note that this rule is case-insensitive, trims whitespace, and ignores certain punctuation (`[,.?¿!‽¡;:]`). It only looks for **exact matches**.
+
+### Succeed
+
+```jsx
+<a>read this tutorial</a> // passes since it is not one of the disallowed words
+<a>${here}</a> // this is valid since 'here' is a variable name
+<a aria-label="tutorial on using eslint-plugin-jsx-a11y">click here</a> // the aria-label supersedes the inner text
+```
+
+### Fail
+
+```jsx
+<a>here</a>
+<a>HERE</a>
+<a>link</a>
+<a>click here</a>
+<a>learn more</a>
+<a>learn more.</a>
+<a>learn more,</a>
+<a>learn more?</a>
+<a>learn more!</a>
+<a>learn more:</a>
+<a>learn more;</a>
+<a>a link</a>
+<a> a link </a>
+<a><span> click </span> here</a> // goes through element children
+<a>a<i></i> link</a>
+<a><i></i>a link</a>
+<a><span aria-hidden="true">more text</span>learn more</a> // skips over elements with aria-hidden=true
+<a aria-label="click here">something</a> // the aria-label here is inaccessible
+<a><img alt="click here"/></a> // the alt tag is still ambiguous
+<a alt="tutorial on using eslint-plugin-jsx-a11y">click here</a> // the alt tag is only parsed on img
+```
+
+## Accessibility guidelines
+
+Ensure anchor tags describe the content of the link, opposed to simply describing them as a link.
+
+Compare
+
+```jsx
+<p><a href="#">click here</a> to read a tutorial by Foo Bar</p>
+```
+
+which can be more concise and accessible with
+
+```jsx
+<p>read <a href="#">a tutorial by Foo Bar</a></p>
+```
+
+### Resources
+
+1. [WebAIM, Hyperlinks](https://webaim.org/techniques/hypertext/)
+2. [Deque University, Link Checklist - 'Avoid "link" (or similar) in the link text'](https://dequeuniversity.com/checklists/web/links)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-has-content.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-has-content.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-has-content.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+# jsx-a11y/anchor-has-content
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce that anchors have content and that the content is accessible to screen readers. Accessible means that it is not hidden using the `aria-hidden` prop. Refer to the references to learn about why this is important.
+
+Alternatively, you may use the `title` prop or the `aria-label` prop.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/anchor-has-content": [ 2, {
+            "components": [ "Anchor" ],
+          }],
+    }
+}
+```
+
+For the `components` option, these strings determine which JSX elements (**always including** `<a>`) should be checked for having content. This is a good use case when you have a wrapper component that simply renders an `a` element (like in React):
+
+```js
+// Anchor.js
+const Anchor = props => {
+  return (
+    <a {...props}>{ props.children }</a>
+  );
+}
+
+...
+
+// CreateAccount.js (for example)
+...
+return (
+  <Anchor>Create Account</Anchor>
+);
+```
+
+
+### Succeed
+```jsx
+<a>Anchor Content!</a>
+<a><TextWrapper /></a>
+<a dangerouslySetInnerHTML={{ __html: 'foo' }} />
+<a title='foo' />
+<a aria-label='foo' />
+```
+
+### Fail
+```jsx
+<a />
+<a><TextWrapper aria-hidden /></a>
+```
+## Accessibility guidelines
+- [WCAG 2.4.4](https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-in-context)
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+- [axe-core, link-name](https://dequeuniversity.com/rules/axe/3.2/link-name)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-is-valid.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-is-valid.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-is-valid.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,270 @@
+# jsx-a11y/anchor-is-valid
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+The HTML `<a>` element, with a valid `href` attribute, is formally defined as representing a **hyperlink**. That is, a link between one HTML document and another, or between one location inside an HTML document and another location inside the same document.
+
+In fact, the interactive, underlined `<a>` element has become so synonymous with web navigation that this expectation has become entrenched inside browsers, assistive technologies such as screen readers and in how people generally expect the internet to behave. In short, anchors should navigate.
+
+The use of JavaScript frameworks and libraries, like _React_, has made it very easy to add or subtract functionality from the standard HTML elements. This has led to _anchors_ often being used in applications based on how they look and function instead of what they represent.
+
+Whilst it is possible, for example, to turn the `<a>` element into a fully functional `<button>` element with ARIA, the native user agent implementations of HTML elements are to be preferred over custom ARIA solutions.
+
+## How do I resolve this error?
+
+### Case: I want to perform an action and need a clickable UI element
+
+The native user agent implementations of the `<a>` and `<button>` elements not only differ in how they look and how they act when activated, but also in how the user is expected to interact with them. Both are perfectly clickable when using a mouse, but keyboard users expect `<a>` to activate on `enter` only and `<button>` to activate on _both_ `enter` and `space`.
+
+This is exacerbated by the expectation sighted users have of how _buttons_ and _anchors_ work based on their appearance. Therefore we find that using _anchors_ as _buttons_ can easily create confusion without a relatively complicated ARIA and CSS implementation that only serves to create an element HTML already offers and browsers already implement fully accessibly.
+
+We are aware that sometimes _anchors_ are used instead of _buttons_ to achieve a specific visual design. When using the `<button>` element this can still be achieved with styling but, due to the meaning many people attach to the standard underlined `<a>` due its appearance, please reconsider this in the design.
+
+Consider the following:
+
+```jsx
+<a href="javascript:void(0)" onClick={foo}>Perform action</a>
+<a href="#" onClick={foo}>Perform action</a>
+<a onClick={foo}>Perform action</a>
+```
+
+All these _anchor_ implementations indicate that the element is only used to execute JavaScript code. All the above should be replaced with:
+
+```jsx
+<button onClick={foo}>Perform action</button>
+```
+
+### Case: I want navigable links
+
+An `<a>` element without an `href` attribute no longer functions as a hyperlink. That means that it can no longer accept keyboard focus or be clicked on. The documentation for [no-noninteractive-tabindex](no-noninteractive-tabindex.md) explores this further. Preferably use another element (such as `div` or `span`) for display of text.
+
+To properly function as a hyperlink, the `href` attribute should be present and also contain a valid _URL_. _JavaScript_ strings, empty values or using only **#** are not considered valid `href` values.
+
+Valid `href` attributes values are:
+
+```jsx
+<a href="/some/valid/uri">Navigate to page</a>
+<a href="/some/valid/uri#top">Navigate to page and location</a>
+<a href="#top">Navigate to internal page location</a>
+```
+
+### Case: I need the HTML to be interactive, don't I need to use an a tag for that?
+
+An `<a>` tag is not inherently interactive. Without an href attribute, it really is no different from a `<span>`.
+
+Let's look at an example that is not accessible by all users:
+
+```jsx
+<a
+  className="thing"
+  onMouseEnter={() => this.setState({ showSomething: true })}
+>
+  {label}
+</a>
+```
+
+If you need to create an interface element that the user can click on, consider using a button:
+
+```jsx
+<button
+  className="thing"
+  onClick={() => this.setState({ showSomething: true })}
+>
+  {label}
+</button>
+```
+
+If you want to navigate while providing the user with extra functionality, for example in the `onMouseEnter` event, use an anchor with an `href` attribute containing a URL or path as its value.
+
+```jsx
+<a
+  href={someValidPath}
+  className="thing"
+  onMouseEnter={() => this.setState({ showSomething: true })}
+>
+  {label}
+</a>
+```
+
+If you need to create an interface element that the user can mouse over or mouse out of, consider using a div element. In this case, you may need to apply a role of presentation or an interactive role. Interactive ARIA roles include `button`, `link`, `checkbox`, `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `radio`, `searchbox`, `switch` and `textbox`.
+
+```jsx
+<div
+  role="menuitem"
+  className="thing"
+  onClick={() => this.setState({ showSomething: true })}
+  onMouseEnter={() => this.setState({ showSomething: true })}
+>
+  {label}
+</div>
+```
+
+In the example immediately above an `onClick` event handler was added to provide the same experience mouse users enjoy to keyboard-only and touch-screen users. Never fully rely on mouse events alone to expose functionality.
+
+### Case: I use Next.js and I'm getting this error inside of `<Link>`s
+
+This is a [known issue](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/402) with Next.js's decision to construct internal links by nesting an href-free `<a>` tag inside of a `<Link>` component. Next.js is also [aware of the issue](https://github.com/vercel/next.js/issues/5533) and has an [RFC](https://github.com/vercel/next.js/discussions/8207) working towards a solution.
+
+Until the Next.js API can be updated to a more performant and standard setup, you have a few workaround options:
+
+1. If you have only a few `Link`s, or they're clustered in just a few files like `nav.tsx`, you can use disable macros like `{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}` to turn off validation of this rule for those usages.
+
+2. You can use the `Link` component's `passHref` prop to override a dummy `href` on the `<a>`:
+```typescript
+<Link href="/my-amazing-page" passHref>
+  <a href="replace">Go to my amazing page</a>
+</Link>
+```
+
+3. You can invest in a custom component that wraps the creation of the `Link` and `a`. You can then add your new custom component to the list of components to validate to ensure that your links are all created with a navigable href. A sample custom component is shared [here](https://gist.github.com/zackdotcomputer/d7af9901e7db87364aad7fbfadb5c99b) and it would be used like this:
+```typescript
+// Internally, LinkTo handles the making of the Link and A, collecting the
+// need for a lint workaround into a single file.
+// Externally, LinkTo can be linted using this rule, ensuring it will always
+// have a valid href prop.
+<LinkTo href="/my-amazing-page">Go to my amazing page</LinkTo>
+```
+
+### Case: I understand the previous cases but still need an element resembling a link that is purely clickable
+
+We recommend, without reserve, that elements resembling anchors should navigate. This will provide a superior user experience to a larger group of users out there.
+
+However, we understand that developers are not always in total control of the visual design of web applications. In cases where it is imperative to provide an element resembling an anchor that purely acts as a click target with no navigation as result, we would like to recommend a compromise.
+
+Again change the element to a `<button>`:
+
+```jsx
+<button
+  type="button"
+  className="link-button"
+  onClick={() => this.setState({ showSomething: true })}
+>
+  Press me, I look like a link
+</button>
+```
+
+Then use styling to change its appearance to that of a link:
+
+```css
+.link-button {
+  background-color: transparent;
+  border: none;
+  cursor: pointer;
+  text-decoration: underline;
+  display: inline;
+  margin: 0;
+  padding: 0;
+}
+```
+
+This button element can now also be used inline in text.
+
+Once again we stress that this is an inferior implementation and some users will encounter difficulty to use your website, however, it will allow a larger group of people to interact with your website than the alternative of ignoring the rule's warning.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+  "rules": {
+    "jsx-a11y/anchor-is-valid": [
+      "error",
+      {
+        "components": ["Link"],
+        "specialLink": ["hrefLeft", "hrefRight"],
+        "aspects": ["noHref", "invalidHref", "preferButton"]
+      }
+    ]
+  }
+}
+```
+
+For the `components` option, these strings determine which JSX elements (**always including** `<a>`) should be checked for the props designated in the `specialLink` options (**always including** `href`). This is a good use case when you have a wrapper component that simply renders an `<a>` element (like in React):
+
+```js
+// Link.js
+const Link = props => <a {...props}>A link</a>;
+
+...
+
+// NavBar.js (for example)
+...
+return (
+  <nav>
+    <Link href="/home" />
+  </nav>
+);
+```
+
+For the `aspects` option, these strings determine which sub-rules are run. This allows omission of certain error types in restrictive environments.
+
+- `noHref`: Checks whether an anchor contains an `href` attribute.
+- `invalidHref`: Checks if a given `href` value is valid.
+- `preferButton`: Checks if anchors have been used as buttons.
+
+The option can be used on its own or with the `components` and `specialLink` options.
+
+If omitted, all sub-rule aspects will be run by default. This is the recommended configuration for all cases except where the rule becomes unusable due to well founded restrictions.
+
+The option must contain at least one `aspect`.
+
+### Succeed
+
+```jsx
+<a href="https://github.com" />
+<a href="#section" />
+<a href="foo" />
+<a href="/foo/bar" />
+<a href={someValidPath} />
+<a href="https://github.com" onClick={foo} />
+<a href="#section" onClick={foo} />
+<a href="foo" onClick={foo} />
+<a href="/foo/bar" onClick={foo} />
+<a href={someValidPath} onClick={foo} />
+```
+
+### Fail
+
+Anchors should be a button:
+
+```jsx
+<a onClick={foo} />
+<a href="#" onClick={foo} />
+<a href={"#"} onClick={foo} />
+<a href={`#`} onClick={foo} />
+<a href="javascript:void(0)" onClick={foo} />
+<a href={"javascript:void(0)"} onClick={foo} />
+<a href={`javascript:void(0)`} onClick={foo} />
+```
+
+Missing `href` attribute:
+
+```jsx
+<a />
+<a href={undefined} />
+<a href={null} />
+```
+
+Invalid `href` attribute:
+
+```jsx
+<a href="#" />
+<a href={"#"} />
+<a href={`#`} />
+<a href="javascript:void(0)" />
+<a href={"javascript:void(0)"} />
+<a href={`javascript:void(0)`} />
+```
+
+## Accessibility guidelines
+
+- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
+
+### Resources
+
+- [WebAIM - Introduction to Links and Hypertext](https://webaim.org/techniques/hypertext/)
+- [Links vs. Buttons in Modern Web Applications](https://marcysutton.com/links-vs-buttons-in-modern-web-applications/)
+- [Using ARIA - Notes on ARIA use in HTML](https://www.w3.org/TR/using-aria/#NOTES)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-activedescendant-has-tabindex.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-activedescendant-has-tabindex.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-activedescendant-has-tabindex.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+# jsx-a11y/aria-activedescendant-has-tabindex
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+`aria-activedescendant` is used to manage focus within a [composite widget](https://www.w3.org/TR/wai-aria/#composite).
+The element with the attribute `aria-activedescendant` retains the active document
+focus; it indicates which of its child elements has secondary focus by assigning
+the ID of that element to the value of `aria-activedescendant`. This pattern is
+used to build a widget like a search typeahead select list. The search input box
+retains document focus so that the user can type in the input. If the down arrow
+key is pressed and a search suggestion is highlighted, the ID of the suggestion
+element will be applied as the value of `aria-activedescendant` on the input
+element.
+
+Because an element with `aria-activedescendant` must be tabbable, it must either
+have an inherent `tabIndex` of zero or declare a `tabIndex` attribute.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<CustomComponent />
+<CustomComponent aria-activedescendant={someID} />
+<CustomComponent aria-activedescendant={someID} tabIndex={0} />
+<CustomComponent aria-activedescendant={someID} tabIndex={-1} />
+<div />
+<input />
+<div tabIndex={0} />
+<div aria-activedescendant={someID} tabIndex={0} />
+<div aria-activedescendant={someID} tabIndex="0" />
+<div aria-activedescendant={someID} tabIndex={1} />
+<div aria-activedescendant={someID} tabIndex={-1} />
+<div aria-activedescendant={someID} tabIndex="-1" />
+<input aria-activedescendant={someID} />
+<input aria-activedescendant={someID} tabIndex={0} />
+<input aria-activedescendant={someID} tabIndex={-1} />
+```
+
+### Fail
+```jsx
+<div aria-activedescendant={someID} />
+```
+
+## Accessibility guidelines
+General best practice (reference resources)
+
+### Resources
+- [MDN, Using the aria-activedescendant attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-activedescendant_attribute)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-props.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-props.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-props.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+# jsx-a11y/aria-props
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Elements cannot use an invalid ARIA attribute. This will fail if it finds an `aria-*` property that is not listed in [WAI-ARIA States and Properties spec](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties).
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<!-- Good: Labeled using correctly spelled aria-labelledby -->
+<div id="address_label">Enter your address</div>
+<input aria-labelledby="address_label">
+```
+
+### Fail
+
+```jsx
+<!-- Bad: Labeled using incorrectly spelled aria-labeledby -->
+<div id="address_label">Enter your address</div>
+<input aria-labeledby="address_label">
+```
+
+## Accessibility guidelines
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-proptypes.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-proptypes.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-proptypes.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+# jsx-a11y/aria-proptypes
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+ARIA state and property values must be valid.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<!-- Good: the aria-hidden state is of type true/false -->
+<span aria-hidden="true">foo</span>
+```
+
+### Fail
+```jsx
+<!-- Bad: the aria-hidden state is of type true/false -->
+<span aria-hidden="yes">foo</span>
+```
+
+## Accessibility guidelines
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+- [ARIA Spec, States and Properties](https://www.w3.org/TR/wai-aria/#states_and_properties)
+- [Chrome Audit Rules, AX_ARIA_04](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_04)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-role.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+# jsx-a11y/aria-role
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Elements with ARIA roles must use a valid, non-abstract ARIA role. A reference to role definitions can be found at [WAI-ARIA](https://www.w3.org/TR/wai-aria/#role_definitions) site.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/aria-role": [ 2, {
+            "allowedInvalidRoles": ["text"],
+            "ignoreNonDOM": true
+        }],
+    }
+}
+```
+
+`allowedInvalidRules` is an optional string array of custom roles that should be allowed in addition to the ARIA spec, such as for cases when you [need to use a non-standard role](https://axesslab.com/text-splitting).
+
+For the `ignoreNonDOM` option, this determines if developer created components are checked.
+
+### Succeed
+```jsx
+<div role="button"></div>     <!-- Good: "button" is a valid ARIA role -->
+<div role={role}></div>       <!-- Good: role is a variable & cannot be determined until runtime. -->
+<div></div>                   <!-- Good: No ARIA role -->
+<Foo role={role}></Foo>       <!-- Good: ignoreNonDOM is set to true -->
+```
+
+### Fail
+
+```jsx
+<div role="datepicker"></div> <!-- Bad: "datepicker" is not an ARIA role -->
+<div role="range"></div>      <!-- Bad: "range" is an _abstract_ ARIA role -->
+<div role=""></div>           <!-- Bad: An empty ARIA role is not allowed -->
+<Foo role={role}></Foo>       <!-- Bad: ignoreNonDOM is set to false or not set -->
+```
+
+## Accessibility guidelines
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+- [Chrome Audit Rules, AX_ARIA_01](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_01)
+- [DPUB-ARIA roles](https://www.w3.org/TR/dpub-aria-1.0/)
+- [MDN: Using ARIA: Roles, states, and properties](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-unsupported-elements.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-unsupported-elements.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/aria-unsupported-elements.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+# jsx-a11y/aria-unsupported-elements
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Certain reserved DOM elements do not support ARIA roles, states and properties. This is often because they are not visible, for example `meta`, `html`, `script`, `style`. This rule enforces that these DOM elements do not contain the `role` and/or `aria-*` props.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<!-- Good: the meta element should not be given any ARIA attributes -->
+<meta charset="UTF-8" />
+```
+
+### Fail
+```jsx
+<!-- Bad: the meta element should not be given any ARIA attributes -->
+<meta charset="UTF-8" aria-hidden="false" />
+```
+
+## Accessibility guidelines
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+- [Chrome Audit Rules, AX_ARIA_12](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_12)
+- [DPUB-ARIA roles](https://www.w3.org/TR/dpub-aria-1.0/)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/autocomplete-valid.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/autocomplete-valid.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/autocomplete-valid.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,49 @@
+# jsx-a11y/autocomplete-valid
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Ensure the autocomplete attribute is correct and suitable for the form field it is used with.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```
+{
+    "rules": {
+        "jsx-a11y/autocomplete-valid": [ 2, {
+            "inputComponents": ["Input", "FormField"]
+        }],
+    }
+}
+```
+
+### Succeed
+```jsx
+<!-- Good: the autocomplete attribute is used according to the HTML specification -->
+<input type="text" autocomplete="name" />
+
+<!-- Good: MyInput is not listed in inputComponents -->
+<MyInput autocomplete="incorrect" />
+```
+
+### Fail
+```jsx
+<!-- Bad: the autocomplete attribute has an invalid value -->
+<input type="text" autocomplete="incorrect" />
+
+<!-- Bad: the autocomplete attribute is on an inappropriate input element -->
+<input type="email" autocomplete="url" />
+
+<!-- Bad: MyInput is listed in inputComponents -->
+<MyInput autocomplete="incorrect" />
+```
+
+## Accessibility guidelines
+- [WCAG 1.3.5](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose)
+
+### Resources
+- [axe-core, autocomplete-valid](https://dequeuniversity.com/rules/axe/3.2/autocomplete-valid)
+- [HTML 5.2, Autocomplete requirements](https://www.w3.org/TR/html52/sec-forms.html#autofilling-form-controls-the-autocomplete-attribute)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/click-events-have-key-events.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/click-events-have-key-events.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/click-events-have-key-events.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+# jsx-a11y/click-events-have-key-events
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce `onClick` is accompanied by at least one of the following: `onKeyUp`, `onKeyDown`, `onKeyPress`. Coding for the keyboard is important for users with physical disabilities who cannot use a mouse, AT compatibility, and screen reader users. This does not apply for interactive or hidden elements.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<div onClick={() => {}} onKeyDown={this.handleKeyDown} />
+<div onClick={() => {}} onKeyUp={this.handleKeyUp} />
+<div onClick={() => {}} onKeyPress={this.handleKeyPress} />
+<button onClick={() => {}} />
+<div onClick{() => {}} aria-hidden="true" />
+```
+
+### Fail
+```jsx
+<div onClick={() => {}} />
+```
+
+## Accessibility guidelines
+- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/control-has-associated-label.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/control-has-associated-label.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/control-has-associated-label.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,113 @@
+# jsx-a11y/control-has-associated-label
+
+🚫 This rule is _disabled_ in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce that a control (an interactive element) has a text label.
+
+There are two supported ways to supply a control with a text label:
+
+- Provide text content inside the element.
+- Use the `aria-label` attribute on the element, with a text value.
+- Use the `aria-labelledby` attribute on the element, and point the IDREF value to an element with an accessible label.
+- Alternatively, with an `img` tag, you may use the `alt` attribute to supply a text description of the image.
+
+The rule is permissive in the sense that it will assume that expressions will eventually provide a label. So an element like this will pass.
+
+```jsx
+<button type="button">{maybeSomethingThatContainsALabel}</button>
+```
+
+## How do I resolve this error?
+
+### Case: I have a simple button that requires a label.
+
+Provide text content in the `button` element.
+
+```jsx
+<button type="button">Save</button>
+```
+
+### Case: I have an icon button and I don't want visible text.
+
+Use the `aria-label` attribute and provide the text label as the value.
+
+```jsx
+<button type="button" aria-label="Save" class="icon-save" />
+```
+
+### Case: The label for my element is already located on the page and I don't want to repeat the text in my source code.
+
+Use the `aria-labelledby` attribute and point the IDREF value to an element with an accessible label.
+
+```jsx
+<div id="js_1">Comment</div>
+<textarea aria-labelledby="js_1"></textarea>
+```
+
+### Case: My label and input components are custom components, but I still want to require that they have an accessible text label.
+
+You can configure the rule to be aware of your custom components. Refer to the Rule Details below.
+
+```jsx
+<CustomInput label="Surname" type="text" value={value} />
+```
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+  "rules": {
+    "jsx-a11y/control-has-associated-label": [ 2, {
+      "labelAttributes": ["label"],
+      "controlComponents": ["CustomComponent"],
+      "ignoreElements": [
+        "audio",
+        "canvas",
+        "embed",
+        "input",
+        "textarea",
+        "tr",
+        "video",
+      ],
+      "ignoreRoles": [
+        "grid",
+        "listbox",
+        "menu",
+        "menubar",
+        "radiogroup",
+        "row",
+        "tablist",
+        "toolbar",
+        "tree",
+        "treegrid",
+      ],
+      "depth": 3,
+    }],
+  }
+}
+```
+
+- `labelAttributes` is a list of attributes to check on the control component and its children for a label. Use this if you have a custom component that uses a string passed on a prop to render an HTML `label`, for example.
+- `controlComponents` is a list of custom React Components names that will render down to an interactive element.
+- `ignoreElements` is an array of elements that should not be considered control (interactive) elements and therefore they do not require a text label.
+- `ignoreRoles` is an array of ARIA roles that should not be considered control (interactive) roles and therefore they do not require a text label.
+- `depth` (default 2, max 25) is an integer that determines how deep within a `JSXElement` the rule should look for text content or an element with a label to determine if the interactive element will have an accessible label.
+
+### Succeed
+```jsx
+<button type="button" aria-label="Save" class="icon-save" />
+```
+
+### Fail
+```jsx
+<button type="button" class="icon-save" />
+```
+
+## Accessibility guidelines
+- [WCAG 1.3.1](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships)
+- [WCAG 3.3.2](https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions)
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/heading-has-content.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/heading-has-content.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/heading-has-content.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,67 @@
+# jsx-a11y/heading-has-content
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce that heading elements (`h1`, `h2`, etc.) have content and that the content is accessible to screen readers. Accessible means that it is not hidden using the `aria-hidden` prop. Refer to the references to learn about why this is important.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/heading-has-content": [ 2, {
+            "components": [ "MyHeading" ],
+          }],
+    }
+}
+```
+
+For the `components` option, these strings determine which JSX elements (**always including** `<h1>` thru `<h6>`) should be checked for having content. This is a good use case when you have a wrapper component that simply renders an `h1` element (like in React):
+
+
+```js
+// Header.js
+const Header = props => {
+  return (
+    <h1 {...props}>{ props.children }</h1>
+  );
+}
+
+...
+
+// CreateAccount.js (for example)
+...
+return (
+  <Header>Create Account</Header>
+);
+```
+
+#### Bad
+```jsx
+function Foo(props) {
+  return <label {...props} />
+}
+```
+
+### Succeed
+```jsx
+<h1>Heading Content!</h1>
+<h1><TextWrapper /><h1>
+<h1 dangerouslySetInnerHTML={{ __html: 'foo' }} />
+```
+
+### Fail
+```jsx
+<h1 />
+<h1><TextWrapper aria-hidden />
+```
+
+## Accessibility guidelines
+- [WCAG 2.4.6](https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-descriptive.html)
+
+### Resources
+- [axe-core, empty-heading](https://dequeuniversity.com/rules/axe/3.2/empty-heading)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/html-has-lang.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/html-has-lang.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/html-has-lang.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+# jsx-a11y/html-has-lang
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+<html> elements must have the lang prop. This rule is largely superseded by the [`lang` rule](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/lang.md).
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<html lang="en">
+<html lang="en-US">
+<html lang={language}>
+```
+
+### Fail
+
+```jsx
+<html>
+```
+
+## Accessibility guidelines
+- [WCAG 3.1.1](https://www.w3.org/WAI/WCAG21/Understanding/language-of-page)
+
+### Resources
+- [axe-core, html-has-lang](https://dequeuniversity.com/rules/axe/3.2/html-has-lang)
+- [axe-core, html-lang-valid](https://dequeuniversity.com/rules/axe/3.2/html-lang-valid)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/iframe-has-title.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/iframe-has-title.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/iframe-has-title.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+# jsx-a11y/iframe-has-title
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+`<iframe>` elements must have a unique title property to indicate its content to the user.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<iframe title="This is a unique title" />
+<iframe title={uniqueTitle} />
+```
+
+### Fail
+```jsx
+<iframe />
+<iframe {...props} />
+<iframe title="" />
+<iframe title={''} />
+<iframe title={``} />
+<iframe title={undefined} />
+<iframe title={false} />
+<iframe title={true} />
+<iframe title={42} />
+```
+
+## Accessibility guidelines
+- [WCAG 2.4.1](https://www.w3.org/WAI/WCAG21/Understanding/bypass-blocks)
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+- [axe-core, frame-title](https://dequeuniversity.com/rules/axe/3.2/frame-title)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/img-redundant-alt.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/img-redundant-alt.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/img-redundant-alt.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,48 @@
+# jsx-a11y/img-redundant-alt
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce img alt attribute does not contain the word image, picture, or photo. Screen readers already announce `img` elements as an image. There is no need to use words such as *image*, *photo*, and/or *picture*.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/img-redundant-alt": [ 2, {
+            "components": [ "Image" ],
+            "words": [ "Bild", "Foto" ],
+          }],
+    }
+}
+```
+
+For the `components` option, these strings determine which JSX elements (**always including** `<img>`) should be checked for having redundant words in the `alt` prop value . This is a good use case when you have a wrapper component that simply renders an `img` element (like in React).
+
+For the `words` option, these strings can be used to specify custom words that should be checked for in the alt prop, including `image`, `photo`, and `picture`. Useful for specifying words in other languages.
+
+The rule will first check if `aria-hidden` is true to determine whether to enforce the rule. If the image is hidden, then rule will always succeed.
+
+### Succeed
+```jsx
+<img src="foo" alt="Foo eating a sandwich." />
+<img src="bar" aria-hidden alt="Picture of me taking a photo of an image" /> // Will pass because it is hidden.
+<img src="baz" alt={`Baz taking a ${photo}`} /> // This is valid since photo is a variable name.
+```
+
+### Fail
+```jsx
+<img src="foo" alt="Photo of foo being weird." />
+<img src="bar" alt="Image of me at a bar!" />
+<img src="baz" alt="Picture of baz fixing a bug." />
+```
+
+## Accessibility guidelines
+General best practice (reference resources)
+
+### Resources
+- [WebAIM, Alternative Text](https://webaim.org/techniques/alttext/)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/interactive-supports-focus.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/interactive-supports-focus.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/interactive-supports-focus.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,156 @@
+# jsx-a11y/interactive-supports-focus
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Elements with an interactive role and interaction handlers (mouse or key press) must be focusable.
+
+## How do I resolve this error?
+
+### Case: I got the error "Elements with the '${role}' interactive role must be tabbable". How can I fix this?
+
+This element is a stand-alone control like a button, a link or a form element. A user should be able to reach this element by pressing the tab key on their keyboard.
+
+Add the `tabIndex` property to your component. A value of zero indicates that this element can be tabbed to.
+
+```jsx
+<div
+  role="button"
+  tabIndex={0} />
+```
+
+-- or --
+
+Replace the component with one that renders semantic html element like `<button>`, `<a href>` or `<input>` -- whichever fits your purpose.
+
+Generally buttons, links and form elements should be reachable via tab key presses. An element that can be tabbed to is said to be in the _tab ring_.
+
+### Case: I got the error "Elements with the '${role}' interactive role must be focusable". How can I fix this?
+
+This element is part of a group of buttons, links, menu items, etc. Or this element is part of a composite widget. Composite widgets prescribe standard [keyboard interaction patterns](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav). Within a group of similar elements -- like a button bar -- or within a composite widget, elements that can be focused are given a tabindex of -1. This makes the element _focusable_ but not _tabbable_. Generally one item in a group should have a tabindex of zero so that a user can tab to the component. Once an element in the component has focus, your key management behaviors will control traversal within the component's pieces. As the UI author, you will need to implement the key handling behaviors such as listening for traversal key (up/down/left/right) presses and moving the page focus between the focusable elements in your widget.
+
+```jsx
+<div role="menu">
+  <div role="menuitem" tabIndex="0">Open</div>
+  <div role="menuitem" tabIndex="-1">Save</div>
+  <div role="menuitem" tabIndex="-1">Close</div>
+</div>
+```
+
+In the example above, the first item in the group can be tabbed to. The developer provides the ability to traverse to the subsequent items via the up/down/left/right arrow keys. Traversing via arrow keys is not provided by the browser or the assistive technology. See [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav) for information about established traversal behaviors for various UI widgets.
+
+### Case: This element is not a button, link, menuitem, etc. It is catching bubbled events from elements that it contains
+
+If your element is catching bubbled click or key events from descendant elements, then the proper role for this element is `presentation`.
+
+```jsx
+<div
+  onClick={onClickHandler}
+  role="presentation">
+  <button>Save</button>
+</div>
+```
+
+Marking an element with the role `presentation` indicates to assistive technology that this element should be ignored; it exists to support the web application and is not meant for humans to interact with directly.
+
+## Rule options
+
+This rule takes an options object with the key `tabbable`. The value is an array of interactive ARIA roles that should be considered tabbable, not just focusable. Any interactive role not included in this list will be flagged as needing to be focusable (tabindex of -1).
+
+```js
+{
+  'jsx-a11y/interactive-supports-focus': [
+    'error',
+    {
+      tabbable: [
+        'button',
+        'checkbox',
+        'link',
+        'searchbox',
+        'spinbutton',
+        'switch',
+        'textbox',
+      ],
+    },
+  ]
+}
+```
+
+The recommended options list interactive roles that act as form elements. Generally, elements with a role like `menuitem` are a part of a composite widget. Focus in a composite widget is controlled and moved programmatically to satisfy the prescribed [keyboard interaction pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav) for the widget.
+
+The list of possible values includes:
+
+```js
+[
+  'button',
+  'checkbox',
+  'columnheader',
+  'combobox',
+  'grid',
+  'gridcell',
+  'link',
+  'listbox',
+  'menu',
+  'menubar',
+  'menuitem',
+  'menuitemcheckbox',
+  'menuitemradio',
+  'option',
+  'progressbar',
+  'radio',
+  'radiogroup',
+  'row',
+  'rowheader',
+  'searchbox',
+  'slider',
+  'spinbutton',
+  'switch',
+  'tab',
+  'tablist',
+  'textbox',
+  'toolbar',
+  'tree',
+  'treegrid',
+  'treeitem',
+  'doc-backlink',
+  'doc-biblioref',
+  'doc-glossref',
+  'doc-noteref',
+]
+```
+
+### Succeed
+
+```jsx
+<!-- Good: div with onClick attribute is hidden from screen reader -->
+<div aria-hidden onClick={() => void 0} />
+<!-- Good: span with onClick attribute is in the tab order -->
+<span onClick="doSomething();" tabIndex="0" role="button">Click me!</span>
+<!-- Good: span with onClick attribute may be focused programmatically -->
+<span onClick="doSomething();" tabIndex="-1" role="menuitem">Click me too!</span>
+<!-- Good: anchor element with href is inherently focusable -->
+<a href="javascript:void(0);" onClick="doSomething();">Click ALL the things!</a>
+<!-- Good: buttons are inherently focusable -->
+<button onClick="doSomething();">Click the button :)</button>
+```
+
+### Fail
+
+```jsx
+<!-- Bad: span with onClick attribute has no tabindex -->
+<span onclick="submitForm();" role="button">Submit</span>
+<!-- Bad: anchor element without href is not focusable -->
+<a onclick="showNextPage();" role="button">Next page</a>
+```
+
+## Accessibility guidelines
+
+- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
+
+### Resources
+
+- [Chrome Audit Rules, AX_FOCUS_02](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_focus_02)
+- [Mozilla Developer Network - ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Keyboard_and_focus)
+- [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
+- [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/label-has-associated-control.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/label-has-associated-control.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/label-has-associated-control.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,152 @@
+# jsx-a11y/label-has-associated-control
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce that a label tag has a text label and an associated control.
+
+There are two supported ways to associate a label with a control:
+
+- Wrapping a control in a label tag.
+- Adding `htmlFor` to a label and assigning it a DOM ID string that indicates an input on the page.
+
+This rule checks that any `label` tag (or an indicated custom component that will output a `label` tag) either (1) wraps an `input` element (or an indicated custom component that will output an `input` tag) or (2) has an `htmlFor` attribute and that the `label` tag has text content.
+
+## How do I resolve this error?
+
+### Case: I just want a text label associated with an input.
+
+The simplest way to achieve an association between a label and an input is to wrap the input in the label.
+
+```jsx
+<label>
+  Surname
+  <input type="text" />
+</label>
+```
+
+All modern browsers and assistive technology will associate the label with the control.
+
+### Case: The label is a sibling of the control.
+
+In this case, use `htmlFor` and an ID to associate the controls.
+
+```jsx
+<label htmlFor={domId}>Surname</label>
+<input type="text" id={domId} />
+```
+
+### Case: My label and input components are custom components.
+
+You can configure the rule to be aware of your custom components.
+
+```jsx
+<CustomInputLabel label="Surname">
+  <CustomInput type="text" value={value} />
+</CustomInputLabel>
+```
+
+And the configuration:
+
+```json
+{
+  "rules": {
+    "jsx-a11y/label-has-associated-control": [ 2, {
+      "labelComponents": ["CustomInputLabel"],
+      "labelAttributes": ["label"],
+      "controlComponents": ["CustomInput"],
+      "depth": 3,
+    }],
+  }
+}
+```
+
+### Case: I have two labels for the same input
+
+If the second `label` is in a different part of the HTML, then the second one can only contain `htmlFor` but not nesting. You will probably need eslint override comment on the second label.
+
+```jsx
+{/* eslint jsx-a11y/label-has-associated-control: ["error", { assert: "either" } ] */}
+<label htmlFor="a">
+  Username:
+</label>
+...
+<label htmlFor="a">
+  <input id="a" />
+</label>
+```
+
+## How to manage IDs of `input`
+
+A common way to think of `id` with libraries like React is, `id`s should be avoided since it must be unique on the page, and components need to be reusable. Hence it is tempted to generate `id` during render-time if `id` is required. *However:*
+
+IDs shouldn't be generated in the browser, so that server and client rendering are deterministic. Render-time uuids aren't just a hack, they're actually broken and should never be used.
+
+To restate, **every ID needs to be deterministic**, on the server and the client, and guaranteed to be unique on the page. EG: For each input, a required ID prop can be passed down from as far up the tree as possible to guarantee uniqueness.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+  "rules": {
+    "jsx-a11y/label-has-associated-control": [ 2, {
+      "labelComponents": ["CustomLabel"],
+      "labelAttributes": ["inputLabel"],
+      "controlComponents": ["CustomInput"],
+      "assert": "both",
+      "depth": 3,
+    }],
+  }
+}
+```
+
+`labelComponents` is a list of custom React Component names that should be checked for an associated control.
+
+`labelAttributes` is a list of attributes to check on the label component and its children for a label. Use this if you have a custom component that uses a string passed on a prop to render an HTML `label`, for example.
+
+`controlComponents` is a list of custom React Components names that will output an input element. [Glob format](https://linuxhint.com/bash_globbing_tutorial/) is also supported for specifying names (e.g., `Label*` matches `LabelComponent` but not `CustomLabel`, `????Label` matches `LinkLabel` but not `CustomLabel`).
+
+`assert` asserts that the label has htmlFor, a nested label, both or either. Available options: `'htmlFor', 'nesting', 'both', 'either'`.
+
+`depth` (default 2, max 25) is an integer that determines how deep within a `JSXElement` label the rule should look for text content or an element with a label to determine if the `label` element will have an accessible label.
+
+### Fail
+```jsx
+function Foo(props) {
+  return <label {...props} />
+}
+```
+
+### Succeed
+```jsx
+function Foo(props) {
+    const {
+        htmlFor,
+        ...otherProps
+    } = props;
+
+   return <label htmlFor={htmlFor} {...otherProps} />
+}
+```
+
+### Fail
+```jsx
+<input type="text" />
+<label>Surname</label>
+```
+
+### Succeed
+```jsx
+<label>
+  <input type="text" />
+  Surname
+</label>
+```
+
+## Accessibility guidelines
+- [WCAG 1.3.1](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships)
+- [WCAG 3.3.2](https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions)
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/label-has-for.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/label-has-for.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/label-has-for.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,130 @@
+# jsx-a11y/label-has-for
+
+❌ This rule is deprecated. It was replaced by [`jsx-a11y/label-has-associated-control`](label-has-associated-control.md).
+
+🚫 This rule is _disabled_ in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+_This rule was deprecated in v6.1.0. It will no longer be maintained._
+
+Enforce label tags have associated control.
+
+There are two supported ways to associate a label with a control:
+
+- nesting: by wrapping a control in a label tag
+- id: by using the prop `htmlFor` (or any configured attribute) as in `htmlFor=[ID of control]`
+
+To fully cover 100% of assistive devices, you're encouraged to validate for both nesting and id.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/label-has-for": [ 2, {
+            "components": [ "Label" ],
+            "required": {
+                "every": [ "nesting", "id" ]
+            },
+            "allowChildren": false
+        }]
+    }
+}
+```
+
+For the `components` option, these strings determine which JSX elements (**always including** `<label>`) should be checked for having `htmlFor` prop. This is a good use case when you have a wrapper component that simply renders a `label` element (like in React):
+
+```js
+// Label.js
+const Label = props => {
+  const {
+    htmlFor,
+    ...otherProps
+  } = props;
+
+  return (
+    <label htmlFor={htmlFor} {...otherProps} />
+  );
+}
+
+...
+
+// CreateAccount.js (for example)
+...
+return (
+  <form>
+    <input id="firstName" type="text" />
+    <Label htmlFor="firstName">First Name</Label>
+  </form>
+);
+```
+
+The `required` option (defaults to `"required": { "every": ["nesting", "id"] }`) determines which checks are activated. You're allowed to pass in one of the following types:
+
+- string: must be one of the acceptable strings (`"nesting"` or `"id"`)
+- object, must have one of the following properties:
+
+  - some: an array of acceptable strings, will pass if ANY of the requested checks passed
+  - every: an array of acceptable strings, will pass if ALL of the requested checks passed
+
+The `allowChildren` option (defaults to `false`) determines whether `{children}` content is allowed to be passed into a `label` element. For example, the following pattern, by default, is not allowed:
+
+```js
+<label>{children}</label>
+```
+
+However, if `allowChildren` is set to `true`, no error will be raised. If you want to pass in `{children}` content without raising an error, because you cannot be sure what `{children}` will render, then set `allowChildren` to `true`.
+
+Note that passing props as spread attribute without `htmlFor` explicitly defined will cause this rule to fail. Explicitly pass down `htmlFor` prop for rule to pass. The prop must have an actual value to pass. Use `Label` component above as a reference. **It is a good thing to explicitly pass props that you expect to be passed for self-documentation.** For example:
+
+#### Bad
+
+```jsx
+function Foo(props) {
+  return <label {...props} />
+}
+```
+
+#### Good
+
+```jsx
+function Foo({ htmlFor, ...props}) {
+    return <label htmlFor={htmlFor} {...props} />
+}
+
+// OR
+
+function Foo(props) {
+    const {
+        htmlFor,
+        ...otherProps
+    } = props;
+
+   return <label htmlFor={htmlFor} {...otherProps} />
+}
+```
+
+### Succeed
+
+```jsx
+<label htmlFor="firstName">
+  <input type="text" id="firstName" />
+  First Name
+</label>
+```
+
+### Fail
+
+```jsx
+<input type="text" id="firstName" />
+<label>First Name</label>
+```
+
+## Accessibility guidelines
+
+- [WCAG 1.3.1](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships)
+- [WCAG 3.3.2](https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions)
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/lang.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/lang.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/lang.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+# jsx-a11y/lang
+
+<!-- end auto-generated rule header -->
+
+The `lang` prop on the `<html>` element must be a valid IETF's BCP 47 language tag.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+
+```jsx
+<html lang="en">
+<html lang="en-US">
+```
+
+### Fail
+
+```jsx
+<html>
+<html lang="foo">
+```
+
+## Accessibility guidelines
+- [WCAG 3.1.1](https://www.w3.org/WAI/WCAG21/Understanding/language-of-page)
+
+### Resources
+- [axe-core, valid-lang](https://dequeuniversity.com/rules/axe/3.2/valid-lang)
+- [Language tags in HTML and XML](https://www.w3.org/International/articles/language-tags/)
+- [IANA Language Subtag Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/media-has-caption.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/media-has-caption.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/media-has-caption.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,48 @@
+# jsx-a11y/media-has-caption
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Providing captions for media is essential for deaf users to follow along. Captions should be a transcription or translation of the dialogue, sound effects, relevant musical cues, and other relevant audio information. Not only is this important for accessibility, but can also be useful for all users in the case that the media is unavailable (similar to `alt` text on an image when an image is unable to load).
+
+The captions should contain all important and relevant information to understand the corresponding media. This may mean that the captions are not a 1:1 mapping of the dialogue in the media content. However, captions are *not* necessary for video components with the `muted` attribute.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/media-has-caption": [ 2, {
+            "audio": [ "Audio" ],
+            "video": [ "Video" ],
+            "track": [ "Track" ],
+          }],
+    }
+}
+```
+
+For the `audio`, `video`, and `track` options, these strings determine which JSX elements (**always including** their corresponding DOM element) should be used for this rule. This is a good use case when you have a wrapper component that simply renders an `audio`, `video`, or `track` element (like in React):
+
+### Succeed
+```jsx
+<audio><track kind="captions" {...props} /></audio>
+<video><track kind="captions" {...props} /></video>
+<video muted {...props} ></video>
+```
+
+### Fail
+```jsx
+<audio {...props} />
+<video {...props} />
+```
+
+## Accessibility guidelines
+- [WCAG 1.2.2](https://www.w3.org/WAI/WCAG21/Understanding/captions-prerecorded.html)
+- [WCAG 1.2.3](https://www.w3.org/WAI/WCAG21/Understanding/audio-description-or-media-alternative-prerecorded.html)
+
+### Resources
+- [axe-core, audio-caption](https://dequeuniversity.com/rules/axe/2.1/audio-caption)
+- [axe-core, video-caption](https://dequeuniversity.com/rules/axe/2.1/video-caption)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/mouse-events-have-key-events.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/mouse-events-have-key-events.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/mouse-events-have-key-events.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,58 @@
+# jsx-a11y/mouse-events-have-key-events
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce onmouseover/onmouseout are accompanied by onfocus/onblur. Coding for the keyboard is important for users with physical disabilities who cannot use a mouse, AT compatibility, and screen reader users.
+
+## Rule options
+
+By default, this rule checks that `onmouseover` is paired with `onfocus` and that `onmouseout` is paired with `onblur`. This rule takes an optional argument to specify other handlers to check for "hover in" and/or "hover out" events:
+
+```json
+{
+  "rules": {
+    "jsx-a11y/mouse-events-have-key-events": [
+      "error",
+      {
+        "hoverInHandlers": [
+          "onMouseOver",
+          "onMouseEnter",
+          "onPointerOver",
+          "onPointerEnter"
+        ],
+        "hoverOutHandlers": [
+          "onMouseOut",
+          "onMouseLeave",
+          "onPointerOut",
+          "onPointerLeave"
+        ]
+      }
+    ]
+  }
+}
+```
+
+Note that while `onmouseover` and `onmouseout` are checked by default if no arguments are passed in, those are *not* included by default if you *do* provide an argument, so remember to explicitly include them if you want to check them.
+
+### Succeed
+```jsx
+<div onMouseOver={ () => void 0 } onFocus={ () => void 0 } />
+<div onMouseOut={ () => void 0 } onBlur={ () => void 0 } />
+<div onMouseOver={ () => void 0 } onFocus={ () => void 0 } {...otherProps} />
+<div onMouseOut={ () => void 0 } onBlur={ () => void 0 } {...otherProps} />
+```
+
+### Fail
+In example 3 and 4 below, even if otherProps contains onBlur and/or onFocus, this rule will still fail. Props should be passed down explicitly for rule to pass.
+
+```jsx
+<div onMouseOver={ () => void 0 } />
+<div onMouseOut={ () => void 0 } />
+<div onMouseOver={ () => void 0 } {...otherProps} />
+<div onMouseOut={ () => void 0 } {...otherProps} />
+```
+
+## Accessibility guidelines
+- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-access-key.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-access-key.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-access-key.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+# jsx-a11y/no-access-key
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce no accessKey prop on element. Access keys are HTML attributes that allow web developers to assign keyboard shortcuts to elements. Inconsistencies between keyboard shortcuts and keyboard commands used by screen readers and keyboard-only users create accessibility complications so to avoid complications, access keys should not be used.
+
+### References
+1. [WebAIM](https://webaim.org/techniques/keyboard/accesskey#spec)
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<div />
+```
+
+### Fail
+```jsx
+<div accessKey="h" />
+```
+
+## Accessibility guidelines
+General best practice (reference resources)
+
+### Resources
+- [WebAIM, Keyboard Accessibility: Accesskey](https://webaim.org/techniques/keyboard/accesskey#spec)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-aria-hidden-on-focusable.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-aria-hidden-on-focusable.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-aria-hidden-on-focusable.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+# jsx-a11y/no-aria-hidden-on-focusable
+
+<!-- end auto-generated rule header -->
+
+Enforce that `aria-hidden="true"` is not set on focusable elements.
+
+`aria-hidden="true"` can be used to hide purely decorative content from screen reader users. An element with `aria-hidden="true"` that can also be reached by keyboard can lead to confusion or unexpected behavior for screen reader users. Avoid using `aria-hidden="true"` on focusable elements.
+
+## Rule details
+
+### Succeed
+```jsx
+  <div aria-hidden="true" />
+  <img aria-hidden="true" />
+  <a aria-hidden="false" href="#" />
+  <button aria-hidden="true" tabIndex="-1" /> // `tabIndex=-1` removes the element from sequential focus navigation so we don't flag it.
+  <a href="/" />
+  <div aria-hidden="true"><a href="#"></a></div> // This is also bad but will not be handled by this rule.
+```
+
+### Fail
+```jsx
+  <div aria-hidden="true" tabIndex="0" />
+  <input aria-hidden="true" />
+  <a href="/" aria-hidden="true" />
+  <button aria-hidden="true" />
+  <textarea aria-hidden="true" />
+```
+
+## Accessibility guidelines
+General best practice (reference resources)
+
+### Resources
+
+- [aria-hidden elements do not contain focusable elements](https://dequeuniversity.com/rules/axe/html/4.4/aria-hidden-focus)
+- [Element with aria-hidden has no content in sequential focus navigation](https://www.w3.org/WAI/standards-guidelines/act/rules/6cfa84/proposed/)
+- [MDN aria-hidden](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-autofocus.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-autofocus.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-autofocus.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+# jsx-a11y/no-autofocus
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce that autoFocus prop is not used on elements. Autofocusing elements can cause usability issues for sighted and non-sighted users, alike.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/no-autofocus": [ 2, {
+            "ignoreNonDOM": true
+        }],
+    }
+}
+```
+
+For the `ignoreNonDOM` option, this determines if developer created components are checked.
+
+### Succeed
+```jsx
+<div />
+```
+
+### Fail
+```jsx
+<div autoFocus />
+<div autoFocus="true" />
+<div autoFocus="false" />
+<div autoFocus={undefined} />
+```
+
+## Accessibility guidelines
+General best practice (reference resources)
+
+### Resources
+- [WHATWG HTML Standard, The autofocus attribute](https://html.spec.whatwg.org/multipage/interaction.html#attr-fe-autofocus)
+- [The accessibility of HTML 5 autofocus](https://www.brucelawson.co.uk/2009/the-accessibility-of-html-5-autofocus/)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-distracting-elements.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-distracting-elements.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-distracting-elements.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,41 @@
+# jsx-a11y/no-distracting-elements
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforces that no distracting elements are used. Elements that can be visually distracting can cause accessibility issues with visually impaired users. Such elements are most likely deprecated, and should be avoided. By default, the following elements are visually distracting: `<marquee>` and `<blink>`.
+
+## Rule options
+
+This rule takes one optional object argument of type object:
+
+```json
+{
+    "rules": {
+        "jsx-a11y/no-distracting-elements": [ 2, {
+            "elements": [ "marquee", "blink" ],
+          }],
+    }
+}
+```
+
+For the `elements` option, these strings determine which JSX elements should be checked for usage. This shouldn't need to be configured unless you have a seriously compelling use case for these elements. You cannot add any additional elements than what is offered, as the schema is only valid with the provided enumerated list. If you have another element that you think may cause a11y issues due to visual impairment, please feel free to file an issue or send a PR!
+
+### Succeed
+```jsx
+<div />
+```
+
+### Fail
+```jsx
+<marquee />
+<blink />
+```
+
+## Accessibility guidelines
+- [WCAG 2.2.2](https://www.w3.org/WAI/WCAG21/Understanding/pause-stop-hide)
+
+### Resources
+- [axe-core, marquee](https://dequeuniversity.com/rules/axe/3.2/marquee)
+- [axe-core, blink](https://dequeuniversity.com/rules/axe/3.2/blink)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-interactive-element-to-noninteractive-role.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-interactive-element-to-noninteractive-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-interactive-element-to-noninteractive-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,73 @@
+# jsx-a11y/no-interactive-element-to-noninteractive-role
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Interactive HTML elements indicate _controls_ in the user interface. Interactive elements include `<a href>`, `<button>`, `<input>`, `<select>`, `<textarea>`.
+
+Non-interactive HTML elements and non-interactive ARIA roles indicate _content_ and _containers_ in the user interface. Non-interactive elements include `<main>`, `<area>`, `<h1>` (,`<h2>`, etc), `<img>`, `<li>`, `<ul>` and `<ol>`.
+
+[WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#usage_intro) should not be used to convert an interactive element to a non-interactive element. Non-interactive ARIA roles include `article`, `banner`, `complementary`, `img`, `listitem`, `main`, `region` and `tooltip`.
+
+## How do I resolve this error?
+
+### Case: The element should be a container, like an article
+
+Wrap your interactive element in a `<div>` with the desired role.
+
+```jsx
+<div role="article">
+  <button>Save</button>
+</div>
+```
+
+### Case: The element should be content, like an image
+
+Put the content inside your interactive element.
+
+```jsx
+<div
+  role="button"
+  onClick={() => {}}
+  onKeyPress={() => {}}
+  tabIndex="0">
+  <div role="img" aria-label="Save" />
+</div>
+```
+
+## Rule options
+
+The recommended options for this rule allow the `tr` element to be given a role of `presentation` (or its semantic equivalent `none`). Under normal circumstances, an element with an interactive role should not be semantically neutralized with `presentation` (or `none`).
+
+Options are provided as an object keyed by HTML element name; the value is an array of interactive roles that are allowed on the specified element.
+
+```js
+{
+  'no-interactive-element-to-noninteractive-role': [
+    'error',
+    {
+      tr: ['none', 'presentation'],
+    },
+  ]
+}
+```
+
+Under the recommended options, the following code is valid. It would be invalid under the strict rules.
+
+```jsx
+<tr role="presentation" />
+```
+
+## Accessibility guidelines
+
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+
+- [ARIA Spec, States and Properties](https://www.w3.org/TR/wai-aria/#states_and_properties)
+- [Chrome Audit Rules, AX_ARIA_04](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_04)
+- [WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#usage_intro)
+- [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex)
+- [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
+- [Mozilla Developer Network - ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Keyboard_and_focus)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-element-interactions.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-element-interactions.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-element-interactions.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,145 @@
+# jsx-a11y/no-noninteractive-element-interactions
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Non-interactive HTML elements and non-interactive ARIA roles indicate _content_ and _containers_ in the user interface. A non-interactive element does not support event handlers (mouse and key handlers). Non-interactive elements include `<main>`, `<area>`, `<h1>` (,`<h2>`, etc), `<p>`, `<img>`, `<li>`, `<ul>` and `<ol>`. Non-interactive [WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#usage_intro) include `article`, `banner`, `complementary`, `img`, `listitem`, `main`, `region` and `tooltip`.
+
+## How do I resolve this error?
+
+### Case: This element acts like a button, link, menuitem, etc
+
+Move the event handler function to an inner element that is either a semantically interactive element (`<button>`, `<a href>`) or that has an interactive role. This leaves the _content_ or _container_ semantic value of this element intact.
+
+Common interactive roles include:
+
+  1. `button`
+  1. `link`
+  1. `checkbox`
+  1. `menuitem`
+  1. `menuitemcheckbox`
+  1. `menuitemradio`
+  1. `option`
+  1. `radio`
+  1. `searchbox`
+  1. `switch`
+  1. `textbox`
+
+Note: Adding a role to your element does **not** add behavior. When a semantic HTML element like `<button>` is used, then it will also respond to Enter key presses when it has focus. The developer is responsible for providing the expected behavior of an element that the role suggests it would have: focusability and key press support.
+see [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex).
+
+### Case: This element is catching bubbled events from elements that it contains
+
+Move the event handler function to an inner element like `<div>` and give that element a role of `presentation`. This leaves the _content_ or _container_ semantic value of this element intact.
+
+```jsx
+<div role="article">
+  <div
+    onClick="onClickHandler"
+    onKeyPress={onKeyPressHandler}
+    role="presentation">
+    {this.props.children}
+  </div>
+</div>
+```
+
+Marking an element with the role `presentation` indicates to assistive technology that this element should be ignored; it exists to support the web application and is not meant for humans to interact with directly.
+
+### Case: This is a heading that expands/collapses content on the package
+
+Headers often double as expand/collapse controls for the content they headline. An accordion component is a common example of this pattern. Rather than assign the interaction handling code to the heading itself, put a button inside the heading instead. This pattern retains the role of the heading and the role of the button.
+
+```jsx
+<h3>
+  <button onClick={this._expandSection}>News</button>
+</h3>
+<ul id="articles-list">
+  <li>...</li>
+</ul>
+```
+
+### Case: This element is a table cell
+
+Table cells (and tables in general) are meant to contain data. ARIA provides us with a construct called a [Grid](https://w3c.github.io/aria-practices/#grid) that is essentially a 2 dimensional logical container for content and interactive elements.
+
+You have two options in this case.
+
+#### Option 1, move the interactive content inside the table cells
+
+For instance, move the button inside the cell:
+
+```jsx
+<table>
+  <tr>
+    <td><button>Sort</button></td>
+  </tr>
+</table>
+```
+
+This preserves the table cell semantics and the button semantics; the two are not conflated on the cell.
+
+#### Option 2, convert the table into an ARIA grid
+
+If your user interface has a table-like layout, but is filled with interactive components in the cells, consider converting the table into a grid.
+
+```jsx
+<table role="grid">
+  <tr>
+    <td role="gridcell" onClick={this.sort}>Sort</td>
+  </tr>
+</table>
+```
+
+You can also put the interactive content inside the grid cell. This maintains the semantic distinction between the cell and the interaction content, although a grid cell can be interactive.
+
+## Rule options
+
+You may configure which handler props should be taken into account when applying this rule. The recommended configuration includes the following 6 handlers.
+
+```javascript
+'jsx-a11y/no-noninteractive-element-interactions': [
+  'error',
+  {
+    handlers: [
+      'onClick',
+      'onMouseDown',
+      'onMouseUp',
+      'onKeyPress',
+      'onKeyDown',
+      'onKeyUp',
+    ],
+  },
+],
+```
+
+Adjust the list of handler prop names in the handlers array to increase or decrease the coverage surface of this rule in your codebase.
+
+### Succeed
+
+```jsx
+<div onClick={() => void 0} role="button" />
+<div onClick={() => void 0} role="presentation" />
+<input type="text" onClick={() => void 0} /> // Interactive element does not require role.
+<button onClick={() => void 0} className="foo" /> // button is interactive.
+<div onClick={() => void 0} role="button" aria-hidden /> // This is hidden from screen reader.
+<Input onClick={() => void 0} type="hidden" /> // This is a higher-level DOM component
+```
+
+### Fail
+
+```jsx
+<li onClick={() => void 0} />
+<div onClick={() => void 0} role="listitem" />
+```
+
+## Accessibility guidelines
+
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+
+- [WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#usage_intro)
+- [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex)
+- [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
+- [Mozilla Developer Network - ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Keyboard_and_focus)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-element-to-interactive-role.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-element-to-interactive-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-element-to-interactive-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,76 @@
+# jsx-a11y/no-noninteractive-element-to-interactive-role
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Non-interactive HTML elements indicate _content_ and _containers_ in the user interface. Non-interactive elements include `<main>`, `<area>`, `<h1>` (,`<h2>`, etc), `<img>`, `<li>`, `<ul>` and `<ol>`.
+
+Interactive HTML elements indicate _controls_ in the user interface. Interactive elements include `<a href>`, `<button>`, `<input>`, `<select>`, `<textarea>`.
+
+[WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#usage_intro) should not be used to convert a non-interactive element to an interactive element. Interactive ARIA roles include `button`, `link`, `checkbox`, `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `radio`, `searchbox`, `switch` and `textbox`.
+
+## How do I resolve this error?
+
+### Case: This element should be a control, like a button
+
+Put the control inside the non-interactive container element.
+
+```jsx
+<li>
+  <div
+    role="button"
+    onClick={() => {}}
+    onKeyPress={() => {}}>
+    Save
+  </div>
+</li>
+```
+
+Or wrap the content inside your interactive element.
+
+```jsx
+<div
+  role="button"
+  onClick={() => {}}
+  onKeyPress={() => {}}
+  tabIndex="0">
+  <img src="some/file.png" alt="Save" />
+</div>
+```
+
+## Rule options
+
+The recommended options for this rule allow several common interactive roles to be applied to a non-interactive element. The options are provided as an object keyed by HTML element name; the value is an array of interactive roles that are allowed on the specified element.
+
+```js
+{
+  'no-noninteractive-element-to-interactive-role': [
+    'error',
+    {
+      ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
+      ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
+      li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
+      table: ['grid'],
+      td: ['gridcell'],
+    },
+  ]
+}
+```
+
+Under the recommended options, the following code is valid. It would be invalid under the strict rules.
+
+```jsx
+<ul role="menu" />
+```
+
+## Accessibility guidelines
+
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+
+- [WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#usage_intro)
+- [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex)
+- [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
+- [Mozilla Developer Network - ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Keyboard_and_focus)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-tabindex.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-tabindex.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-noninteractive-tabindex.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,115 @@
+# jsx-a11y/no-noninteractive-tabindex
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Tab key navigation should be limited to elements on the page that can be interacted with. Thus it is not necessary to add a tabindex to items in an unordered list, for example, to make them navigable through assistive technology. These applications already afford page traversal mechanisms based on the HTML of the page. Generally, we should try to reduce the size of the page's tab ring rather than increasing it.
+
+## How do I resolve this error?
+
+### Case: I am using an `<a>` tag. Isn't that interactive?
+
+The `<a>` tag is tricky. Consider the following:
+
+```jsx
+<a>Edit</a>
+<a href="#">Edit</a>
+<a role="button">Edit</a>
+```
+
+The bare `<a>` tag is an _anchor_. It has no semantic AX API mapping in either ARIA or the AXObject model. It's as meaningful as `<div>`, which is to say it has no meaning. An `<a>` tag with an `href` attribute has an inherent role of `link`. An `<a>` tag with an explicit role obtains the designated role. In the example above, this role is `button`.
+
+### Case: I am using "semantic" HTML. Isn't that interactive?
+
+If we take a step back into the field of linguistics for a moment, let's consider what it means for something to be "semantic". Nothing, in and of itself, has meaning. Meaning is constructed through dialogue. A speaker intends a meaning and a listener/observer interprets a meaning. Each participant constructs their own meaning through dialogue. There is no intrinsic or isolated meaning outside of interaction. Thus, we must ask, given that we have a "speaker" who communicates via "semantic" HTML, who is listening/observing?
+
+In our case, the observer is the Accessibility (AX) API. Browsers interpret HTML (inflected at times by ARIA) to construct a meaning (AX Tree) of the page. Whatever the semantic HTML intends has only the force of suggestion to the AX API. Therefore, we have inconsistencies. For example, there is not yet an ARIA role for `text` or `label` and thus no way to change a `<label>` into plain text or a `<span>` into a label via ARIA. `<div>` has an AXObject correpondant `DivRole`, but no such object maps to `<span>`.
+
+What this lint rule endeavors to do is apply the AX API understanding of the semantics of an HTML document back onto your code. The concept of interactivity boils down to whether a user can do something with the indicated or focused component.
+
+Common interactive roles include:
+
+  1. `button`
+  1. `link`
+  1. `checkbox`
+  1. `menuitem`
+  1. `menuitemcheckbox`
+  1. `menuitemradio`
+  1. `option`
+  1. `radio`
+  1. `searchbox`
+  1. `switch`
+  1. `textbox`
+
+Endeavor to limit tabbable elements to those that a user can act upon.
+
+### Case: Shouldn't I add a tabindex so that users can navigate to this item?
+
+It is not necessary to put a tabindex on an `<article>`, for instance or on `<li>` items; assistive technologies provide affordances to users to find and traverse these containers. Most elements that require a tabindex -- `<a href>`, `<button>`, `<input>`, `<textarea>` -- have it already.
+
+Your application might require an exception to this rule in the case of an element that captures incoming tab traversal for a composite widget. In that case, turn off this rule on a per instance basis. This is an uncommon case.
+
+If you know that a particular element will be scrollable, you might want to add `tabindex="0"` if your website supports browsers that don't make these containers keyboard-focusable. The current status for this platform feature can be tracked in [Chrome Platform Status "Feature: Keyboard-focusable scroll containers"](https://www.chromestatus.com/feature/5231964663578624).
+
+```jsx
+// eslint-disable-next-line no-noninteractive-tabindex
+<pre tabIndex="0">
+  <code>{someLongCode}</code>
+</pre>
+```
+
+## Rule options
+
+The recommended options for this rule allow `tabIndex` on elements with the noninteractive `tabpanel` role. Adding `tabIndex` to a tabpanel is a recommended practice in some instances.
+
+```javascript
+'jsx-a11y/no-noninteractive-tabindex': [
+  'error',
+  {
+    tags: [],
+    roles: ['tabpanel'],
+    allowExpressionValues: true,
+  },
+]
+```
+
+The `allowExpressionValues` option determines whether the `role` attribute is allowed to be assigned using an expression. For example, the following would pass in recommended mode if `allowExpressionValues` is set to be `true`:
+
+```jsx
+<div role={ROLE_BUTTON} onClick={() => {}} tabIndex="0" />;
+// In case of a conditional expression, there should be literals on both sides of ternary operator
+<div role={isButton ? "button" : "link"} onClick={() => {}} tabIndex="0" />;
+```
+
+### Succeed
+
+```jsx
+<div />
+<MyButton tabIndex={0} />
+<button />
+<button tabIndex="0" />
+<button tabIndex={0} />
+<div />
+<div tabIndex="-1" />
+<div role="button" tabIndex="0" />
+<div role="article" tabIndex="-1" />
+<article tabIndex="-1" />
+```
+
+### Fail
+
+```jsx
+<div tabIndex="0" />
+<div role="article" tabIndex="0" />
+<article tabIndex="0" />
+<article tabIndex={0} />
+```
+
+## Accessibility guidelines
+
+- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
+
+### Resources
+
+- [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-onchange.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-onchange.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-onchange.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,36 @@
+# jsx-a11y/no-onchange
+
+❌ This rule is deprecated.
+
+<!-- end auto-generated rule header -->
+
+⚠️ **Deprecated:** This rule is based on reports of behavior of [old browsers (eg. IE 10 and below)](https://www.quirksmode.org/dom/events/change.html#t05). In the meantime, this behavior has been corrected, both in newer versions of browsers as well as [in the DOM spec](https://bugzilla.mozilla.org/show_bug.cgi?id=969068#c2).
+
+Enforce usage of `onBlur` over/in parallel with `onChange` on select menu elements for accessibility. `onBlur` **should** be used instead of `onChange`, unless absolutely necessary and it causes no negative consequences for keyboard only or screen reader users. `onBlur` is a more declarative action by the user: for instance in a dropdown, using the arrow keys to toggle between options will trigger the `onChange` event in some browsers. Regardless, when a change of context results from an `onBlur` event or an `onChange` event, the user should be notified of the change unless it occurs below the currently focused element.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<select onBlur={updateModel}>
+  <option/>
+</select>
+
+<select>
+  <option onBlur={handleOnBlur} onChange={handleOnChange} />
+</select>
+```
+
+### Fail
+```jsx
+<select onChange={updateModel} />
+```
+
+## Accessibility guidelines
+- [WCAG 3.2.2](https://www.w3.org/WAI/WCAG21/Understanding/on-input)
+
+### Resources
+- [onChange Event Accessibility Issues](https://web.archive.org/web/20191207202425/http://cita.disability.uiuc.edu/html-best-practices/auto/onchange.php)
+- [onChange Select Menu](https://www.themaninblue.com/writing/perspective/2004/10/19/)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-redundant-roles.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-redundant-roles.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-redundant-roles.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+# jsx-a11y/no-redundant-roles
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Some HTML elements have native semantics that are implemented by the browser. This includes default/implicit ARIA roles. Setting an ARIA role that matches its default/implicit role is redundant since it is already set by the browser.
+
+## Rule options
+
+The default options for this rule allow an implicit role of `navigation` to be applied to a `nav` element as is [advised by w3](https://www.w3.org/WAI/GL/wiki/Using_HTML5_nav_element#Example:The_.3Cnav.3E_element). The options are provided as an object keyed by HTML element name; the value is an array of implicit ARIA roles that are allowed on the specified element.
+
+```js
+{
+  'jsx-a11y/no-redundant-roles': [
+    'error',
+    {
+      nav: ['navigation'],
+    },
+  ],
+}
+```
+
+### Succeed
+
+```jsx
+<div />
+<button role="presentation" />
+<MyComponent role="main" />
+```
+
+### Fail
+
+```jsx
+<button role="button" />
+<img role="img" src="foo.jpg" />
+```
+
+## Accessibility guidelines
+
+General best practice (reference resources)
+
+### Resources
+
+- [ARIA Spec, ARIA Adds Nothing to Default Semantics of Most HTML Elements](https://www.w3.org/TR/using-aria/#aria-does-nothing)
+- [Identifying SVG as an image](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#identifying_svg_as_an_image)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-static-element-interactions.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-static-element-interactions.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/no-static-element-interactions.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+# jsx-a11y/no-static-element-interactions
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Static HTML elements do not have semantic meaning. This is clear in the case of `<div>` and `<span>`. It is less so clear in the case of elements that _seem_ semantic, but that do not have a semantic mapping in the accessibility layer. For example `<a>`, `<big>`, `<blockquote>`, `<footer>`, `<picture>`, `<strike>` and `<time>` -- to name a few -- have no semantic layer mapping. They are as void of meaning as `<div>`.
+
+The [WAI-ARIA `role` attribute](https://www.w3.org/TR/wai-aria-1.1/#usage_intro) confers a semantic mapping to an element. The semantic value can then be expressed to a user via assistive technology.
+
+In order to add interactivity such as a mouse or key event listener to a static element, that element must be given a role value as well.
+
+## How do I resolve this error?
+
+### Case: This element acts like a button, link, menuitem, etc
+
+Indicate the element's role with the `role` attribute:
+
+```jsx
+<div
+  onClick={onClickHandler}
+  onKeyPress={onKeyPressHandler}
+  role="button"
+  tabindex="0">
+  Save
+</div>
+```
+
+Common interactive roles include:
+
+  1. `button`
+  1. `link`
+  1. `checkbox`
+  1. `menuitem`
+  1. `menuitemcheckbox`
+  1. `menuitemradio`
+  1. `option`
+  1. `radio`
+  1. `searchbox`
+  1. `switch`
+  1. `textbox`
+
+Note: Adding a role to your element does **not** add behavior. When a semantic HTML element like `<button>` is used, then it will also respond to Enter key presses when it has focus. The developer is responsible for providing the expected behavior of an element that the role suggests it would have: focusability and key press support.
+
+### Case: The event handler is only being used to capture bubbled events
+
+If your element is catching bubbled click or key events from descendant elements, there are no appropriate roles for your element: you will have to deactivate the rule. Consider explaining the reason for disabling the rule as well.
+
+```jsx
+{/* The <div> element has a child <button> element that allows keyboard interaction */}
+{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
+<div onClick={this.handleButtonClick}>
+  <button>Save</button>
+  <button>Cancel</button>
+</div>
+```
+
+Do not use the role `presentation` on the element: it removes the element's semantics, and may also remove its children's semantics, creating big issues with assistive technology.
+
+## Rule options
+
+You may configure which handler props should be taken into account when applying this rule. The recommended configuration includes the following 6 handlers and the `allowExpressionValues` option.
+
+```javascript
+'jsx-a11y/no-static-element-interactions': [
+  'error',
+  {
+    handlers: [
+      'onClick',
+      'onMouseDown',
+      'onMouseUp',
+      'onKeyPress',
+      'onKeyDown',
+      'onKeyUp',
+    ],
+    allowExpressionValues: true,
+  },
+],
+```
+
+Adjust the list of handler prop names in the handlers array to increase or decrease the coverage surface of this rule in your codebase.
+
+The `allowExpressionValues` option determines whether the `role` attribute is allowed to be assigned using an expression. For example, the following would pass in recommended mode if `allowExpressionValues` is set to be `true`:
+
+```jsx
+<div role={ROLE_BUTTON} onClick={() => {}} />;
+// In case of a conditional expression, there should be literals on both sides of ternary operator
+<div role={isButton ? "button" : "link"} onClick={() => {}} />;
+```
+
+### Succeed
+
+```jsx
+<button onClick={() => {}} className="foo" />
+<div className="foo" onClick={() => {}} role="button" />
+<input type="text" onClick={() => {}} />
+```
+
+### Fail
+
+```jsx
+<div onClick={() => {}} />
+```
+
+## Accessibility guidelines
+
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+
+- [WAI-ARIA `role` attribute](https://www.w3.org/TR/wai-aria-1.1/#usage_intro)
+- [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex)
+- [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
+- [Mozilla Developer Network - ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Keyboard_and_focus)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/prefer-tag-over-role.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/prefer-tag-over-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/prefer-tag-over-role.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+# jsx-a11y/prefer-tag-over-role
+
+<!-- end auto-generated rule header -->
+
+Enforces using semantic DOM elements over the ARIA `role` property.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+
+```jsx
+<div>...</div>
+<header>...</header>
+<img alt="" src="image.jpg" />
+```
+
+### Fail
+
+```jsx
+<div role="checkbox">
+<div role="img">
+```
+
+## Accessibility guidelines
+
+- [WAI-ARIA Roles model](https://www.w3.org/TR/wai-aria-1.0/roles)
+
+### Resources
+
+- [MDN WAI-ARIA Roles](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/role-has-required-aria-props.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/role-has-required-aria-props.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/role-has-required-aria-props.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+# jsx-a11y/role-has-required-aria-props
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Elements with ARIA roles must have all required attributes for that role.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<!-- Good: the checkbox role requires the aria-checked state -->
+<span role="checkbox" aria-checked="false" aria-labelledby="foo" tabindex="0"></span>
+```
+
+### Fail
+
+```jsx
+<!-- Bad: the checkbox role requires the aria-checked state -->
+<span role="checkbox" aria-labelledby="foo" tabindex="0"></span>
+```
+
+## Accessibility guidelines
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+- [ARIA Spec, Roles](https://www.w3.org/TR/wai-aria/#roles)
+- [Chrome Audit Rules, AX_ARIA_03](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_03)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/role-supports-aria-props.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/role-supports-aria-props.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/role-supports-aria-props.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,39 @@
+# jsx-a11y/role-supports-aria-props
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`. Many ARIA attributes (states and properties) can only be used on elements with particular roles. Some elements have implicit roles, such as `<a href="#" />`, which will resolve to `role="link"`.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<!-- Good: the radiogroup role does support the aria-required property -->
+<ul role="radiogroup" aria-required aria-labelledby="foo">
+    <li tabIndex="-1" role="radio" aria-checked="false">Rainbow Trout</li>
+    <li tabIndex="-1" role="radio" aria-checked="false">Brook Trout</li>
+    <li tabIndex="0" role="radio" aria-checked="true">Lake Trout</li>
+</ul>
+```
+
+### Fail
+
+```jsx
+<!-- Bad: the radio role does not support the aria-required property -->
+<ul role="radiogroup" aria-labelledby="foo">
+    <li aria-required tabIndex="-1" role="radio" aria-checked="false">Rainbow Trout</li>
+    <li aria-required tabIndex="-1" role="radio" aria-checked="false">Brook Trout</li>
+    <li aria-required tabIndex="0" role="radio" aria-checked="true">Lake Trout</li>
+</ul>
+```
+
+## Accessibility guidelines
+- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+
+### Resources
+- [ARIA Spec, States and Properties](https://www.w3.org/TR/wai-aria/#states_and_properties)
+- [Chrome Audit Rules, AX_ARIA_10](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_10)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/scope.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/scope.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/scope.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+# jsx-a11y/scope
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+The `scope` prop should be used only on `<th>` elements.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<th scope="col" />
+<th scope={scope} />
+```
+
+### Fail
+
+```jsx
+<div scope />
+```
+
+## Accessibility guidelines
+- [WCAG 1.3.1](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships)
+- [WCAG 4.1.1](https://www.w3.org/WAI/WCAG21/Understanding/parsing)
+
+### Resources
+- [axe-core, scope-attr-valid](https://dequeuniversity.com/rules/axe/3.5/scope-attr-valid)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/tabindex-no-positive.md
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/tabindex-no-positive.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/tabindex-no-positive.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+# jsx-a11y/tabindex-no-positive
+
+💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
+
+<!-- end auto-generated rule header -->
+
+Avoid positive `tabIndex` property values to synchronize the flow of the page with keyboard tab order.
+
+## Rule details
+
+This rule takes no arguments.
+
+### Succeed
+```jsx
+<span tabIndex="0">foo</span>
+<span tabIndex="-1">bar</span>
+<span tabIndex={0}>baz</span>
+```
+
+### Fail
+```jsx
+<span tabIndex="5">foo</span>
+<span tabIndex="3">bar</span>
+<span tabIndex="1">baz</span>
+<span tabIndex="2">never really sure what goes after baz</span>
+```
+
+## Accessibility guidelines
+- [WCAG 2.4.3](https://www.w3.org/WAI/WCAG21/Understanding/focus-order)
+
+### Resources
+- [Chrome Audit Rules, AX_FOCUS_03](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_focus_03)
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/configs/flat-config-base.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/configs/flat-config-base.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/configs/flat-config-base.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,11 @@
+"use strict";
+
+module.exports = {
+  languageOptions: {
+    parserOptions: {
+      ecmaFeatures: {
+        jsx: true
+      }
+    }
+  }
+};
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/configs/legacy-config-base.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/configs/legacy-config-base.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/configs/legacy-config-base.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+module.exports = {
+  parserOptions: {
+    ecmaFeatures: {
+      jsx: true
+    }
+  }
+};
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/index.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,208 @@
+"use strict";
+
+function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
+function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
+function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
+function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
+function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
+/* eslint-disable global-require */
+var flatConfigBase = require('./configs/flat-config-base');
+var legacyConfigBase = require('./configs/legacy-config-base');
+var _require = require('../package.json'),
+  name = _require.name,
+  version = _require.version;
+var allRules = {
+  'accessible-emoji': require('./rules/accessible-emoji'),
+  'alt-text': require('./rules/alt-text'),
+  'anchor-ambiguous-text': require('./rules/anchor-ambiguous-text'),
+  'anchor-has-content': require('./rules/anchor-has-content'),
+  'anchor-is-valid': require('./rules/anchor-is-valid'),
+  'aria-activedescendant-has-tabindex': require('./rules/aria-activedescendant-has-tabindex'),
+  'aria-props': require('./rules/aria-props'),
+  'aria-proptypes': require('./rules/aria-proptypes'),
+  'aria-role': require('./rules/aria-role'),
+  'aria-unsupported-elements': require('./rules/aria-unsupported-elements'),
+  'autocomplete-valid': require('./rules/autocomplete-valid'),
+  'click-events-have-key-events': require('./rules/click-events-have-key-events'),
+  'control-has-associated-label': require('./rules/control-has-associated-label'),
+  'heading-has-content': require('./rules/heading-has-content'),
+  'html-has-lang': require('./rules/html-has-lang'),
+  'iframe-has-title': require('./rules/iframe-has-title'),
+  'img-redundant-alt': require('./rules/img-redundant-alt'),
+  'interactive-supports-focus': require('./rules/interactive-supports-focus'),
+  'label-has-associated-control': require('./rules/label-has-associated-control'),
+  'label-has-for': require('./rules/label-has-for'),
+  lang: require('./rules/lang'),
+  'media-has-caption': require('./rules/media-has-caption'),
+  'mouse-events-have-key-events': require('./rules/mouse-events-have-key-events'),
+  'no-access-key': require('./rules/no-access-key'),
+  'no-aria-hidden-on-focusable': require('./rules/no-aria-hidden-on-focusable'),
+  'no-autofocus': require('./rules/no-autofocus'),
+  'no-distracting-elements': require('./rules/no-distracting-elements'),
+  'no-interactive-element-to-noninteractive-role': require('./rules/no-interactive-element-to-noninteractive-role'),
+  'no-noninteractive-element-interactions': require('./rules/no-noninteractive-element-interactions'),
+  'no-noninteractive-element-to-interactive-role': require('./rules/no-noninteractive-element-to-interactive-role'),
+  'no-noninteractive-tabindex': require('./rules/no-noninteractive-tabindex'),
+  'no-onchange': require('./rules/no-onchange'),
+  'no-redundant-roles': require('./rules/no-redundant-roles'),
+  'no-static-element-interactions': require('./rules/no-static-element-interactions'),
+  'prefer-tag-over-role': require('./rules/prefer-tag-over-role'),
+  'role-has-required-aria-props': require('./rules/role-has-required-aria-props'),
+  'role-supports-aria-props': require('./rules/role-supports-aria-props'),
+  scope: require('./rules/scope'),
+  'tabindex-no-positive': require('./rules/tabindex-no-positive')
+};
+var recommendedRules = {
+  'jsx-a11y/alt-text': 'error',
+  'jsx-a11y/anchor-ambiguous-text': 'off',
+  // TODO: error
+  'jsx-a11y/anchor-has-content': 'error',
+  'jsx-a11y/anchor-is-valid': 'error',
+  'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
+  'jsx-a11y/aria-props': 'error',
+  'jsx-a11y/aria-proptypes': 'error',
+  'jsx-a11y/aria-role': 'error',
+  'jsx-a11y/aria-unsupported-elements': 'error',
+  'jsx-a11y/autocomplete-valid': 'error',
+  'jsx-a11y/click-events-have-key-events': 'error',
+  'jsx-a11y/control-has-associated-label': ['off', {
+    ignoreElements: ['audio', 'canvas', 'embed', 'input', 'textarea', 'tr', 'video'],
+    ignoreRoles: ['grid', 'listbox', 'menu', 'menubar', 'radiogroup', 'row', 'tablist', 'toolbar', 'tree', 'treegrid'],
+    includeRoles: ['alert', 'dialog']
+  }],
+  'jsx-a11y/heading-has-content': 'error',
+  'jsx-a11y/html-has-lang': 'error',
+  'jsx-a11y/iframe-has-title': 'error',
+  'jsx-a11y/img-redundant-alt': 'error',
+  'jsx-a11y/interactive-supports-focus': ['error', {
+    tabbable: ['button', 'checkbox', 'link', 'searchbox', 'spinbutton', 'switch', 'textbox']
+  }],
+  'jsx-a11y/label-has-associated-control': 'error',
+  'jsx-a11y/label-has-for': 'off',
+  'jsx-a11y/media-has-caption': 'error',
+  'jsx-a11y/mouse-events-have-key-events': 'error',
+  'jsx-a11y/no-access-key': 'error',
+  'jsx-a11y/no-autofocus': 'error',
+  'jsx-a11y/no-distracting-elements': 'error',
+  'jsx-a11y/no-interactive-element-to-noninteractive-role': ['error', {
+    tr: ['none', 'presentation'],
+    canvas: ['img']
+  }],
+  'jsx-a11y/no-noninteractive-element-interactions': ['error', {
+    handlers: ['onClick', 'onError', 'onLoad', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
+    alert: ['onKeyUp', 'onKeyDown', 'onKeyPress'],
+    body: ['onError', 'onLoad'],
+    dialog: ['onKeyUp', 'onKeyDown', 'onKeyPress'],
+    iframe: ['onError', 'onLoad'],
+    img: ['onError', 'onLoad']
+  }],
+  'jsx-a11y/no-noninteractive-element-to-interactive-role': ['error', {
+    ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
+    ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
+    li: ['menuitem', 'menuitemradio', 'menuitemcheckbox', 'option', 'row', 'tab', 'treeitem'],
+    table: ['grid'],
+    td: ['gridcell'],
+    fieldset: ['radiogroup', 'presentation']
+  }],
+  'jsx-a11y/no-noninteractive-tabindex': ['error', {
+    tags: [],
+    roles: ['tabpanel'],
+    allowExpressionValues: true
+  }],
+  'jsx-a11y/no-redundant-roles': 'error',
+  'jsx-a11y/no-static-element-interactions': ['error', {
+    allowExpressionValues: true,
+    handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp']
+  }],
+  'jsx-a11y/role-has-required-aria-props': 'error',
+  'jsx-a11y/role-supports-aria-props': 'error',
+  'jsx-a11y/scope': 'error',
+  'jsx-a11y/tabindex-no-positive': 'error'
+};
+var strictRules = {
+  'jsx-a11y/alt-text': 'error',
+  'jsx-a11y/anchor-has-content': 'error',
+  'jsx-a11y/anchor-is-valid': 'error',
+  'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
+  'jsx-a11y/aria-props': 'error',
+  'jsx-a11y/aria-proptypes': 'error',
+  'jsx-a11y/aria-role': 'error',
+  'jsx-a11y/aria-unsupported-elements': 'error',
+  'jsx-a11y/autocomplete-valid': 'error',
+  'jsx-a11y/click-events-have-key-events': 'error',
+  'jsx-a11y/control-has-associated-label': ['off', {
+    ignoreElements: ['audio', 'canvas', 'embed', 'input', 'textarea', 'tr', 'video'],
+    ignoreRoles: ['grid', 'listbox', 'menu', 'menubar', 'radiogroup', 'row', 'tablist', 'toolbar', 'tree', 'treegrid'],
+    includeRoles: ['alert', 'dialog']
+  }],
+  'jsx-a11y/heading-has-content': 'error',
+  'jsx-a11y/html-has-lang': 'error',
+  'jsx-a11y/iframe-has-title': 'error',
+  'jsx-a11y/img-redundant-alt': 'error',
+  'jsx-a11y/interactive-supports-focus': ['error', {
+    tabbable: ['button', 'checkbox', 'link', 'progressbar', 'searchbox', 'slider', 'spinbutton', 'switch', 'textbox']
+  }],
+  'jsx-a11y/label-has-for': 'off',
+  'jsx-a11y/label-has-associated-control': 'error',
+  'jsx-a11y/media-has-caption': 'error',
+  'jsx-a11y/mouse-events-have-key-events': 'error',
+  'jsx-a11y/no-access-key': 'error',
+  'jsx-a11y/no-autofocus': 'error',
+  'jsx-a11y/no-distracting-elements': 'error',
+  'jsx-a11y/no-interactive-element-to-noninteractive-role': 'error',
+  'jsx-a11y/no-noninteractive-element-interactions': ['error', {
+    body: ['onError', 'onLoad'],
+    iframe: ['onError', 'onLoad'],
+    img: ['onError', 'onLoad']
+  }],
+  'jsx-a11y/no-noninteractive-element-to-interactive-role': 'error',
+  'jsx-a11y/no-noninteractive-tabindex': 'error',
+  'jsx-a11y/no-redundant-roles': 'error',
+  'jsx-a11y/no-static-element-interactions': 'error',
+  'jsx-a11y/role-has-required-aria-props': 'error',
+  'jsx-a11y/role-supports-aria-props': 'error',
+  'jsx-a11y/scope': 'error',
+  'jsx-a11y/tabindex-no-positive': 'error'
+};
+
+/** Base plugin object */
+var jsxA11y = {
+  meta: {
+    name,
+    version
+  },
+  rules: _objectSpread({}, allRules)
+};
+
+/**
+ * Given a ruleset and optionally a flat config name, generate a config.
+ * @param {object} rules - ruleset for this config
+ * @param {string} flatConfigName - name for the config if flat
+ * @returns Config for this set of rules.
+ */
+var createConfig = function createConfig(rules, flatConfigName) {
+  return _objectSpread(_objectSpread({}, flatConfigName ? _objectSpread(_objectSpread({}, flatConfigBase), {}, {
+    name: "jsx-a11y/".concat(flatConfigName),
+    plugins: {
+      'jsx-a11y': jsxA11y
+    }
+  }) : _objectSpread(_objectSpread({}, legacyConfigBase), {}, {
+    plugins: ['jsx-a11y']
+  })), {}, {
+    rules: _objectSpread({}, rules)
+  });
+};
+
+// Create configs for the plugin object
+var configs = {
+  recommended: createConfig(recommendedRules),
+  strict: createConfig(strictRules)
+};
+var flatConfigs = {
+  recommended: createConfig(recommendedRules, 'recommended'),
+  strict: createConfig(strictRules, 'strict')
+};
+module.exports = _objectSpread(_objectSpread({}, jsxA11y), {}, {
+  configs,
+  flatConfigs
+});
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/accessible-emoji.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/accessible-emoji.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/accessible-emoji.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,63 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _emojiRegex = _interopRequireDefault(require("emoji-regex"));
+var _jsxAstUtils = require("jsx-ast-utils");
+var _safeRegexTest = _interopRequireDefault(require("safe-regex-test"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce emojis are wrapped in <span> and provide screen reader access.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Emojis should be wrapped in <span>, have role="img", and have an accessible description with aria-label or aria-labelledby.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      description: 'Enforce emojis are wrapped in `<span>` and provide screen reader access.',
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/accessible-emoji.md'
+    },
+    deprecated: true,
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    var testEmoji = (0, _safeRegexTest["default"])((0, _emojiRegex["default"])());
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var literalChildValue = node.parent.children.find(function (child) {
+          return child.type === 'Literal' || child.type === 'JSXText';
+        });
+        if (literalChildValue && testEmoji(literalChildValue.value)) {
+          var elementIsHidden = (0, _isHiddenFromScreenReader["default"])(elementType(node), node.attributes);
+          if (elementIsHidden) {
+            return; // emoji is decorative
+          }
+          var rolePropValue = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'role'));
+          var ariaLabelProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-label');
+          var arialLabelledByProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-labelledby');
+          var hasLabel = ariaLabelProp !== undefined || arialLabelledByProp !== undefined;
+          var isSpan = elementType(node) === 'span';
+          if (hasLabel === false || rolePropValue !== 'img' || isSpan === false) {
+            context.report({
+              node,
+              message: errorMessage
+            });
+          }
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/alt-text.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/alt-text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/alt-text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,218 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayPrototype = _interopRequireDefault(require("array.prototype.flatmap"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _hasAccessibleChild = _interopRequireDefault(require("../util/hasAccessibleChild"));
+var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce all elements that require alternative text have it.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var DEFAULT_ELEMENTS = ['img', 'object', 'area', 'input[type="image"]'];
+var schema = (0, _schemas.generateObjSchema)({
+  elements: _schemas.arraySchema,
+  img: _schemas.arraySchema,
+  object: _schemas.arraySchema,
+  area: _schemas.arraySchema,
+  'input[type="image"]': _schemas.arraySchema
+});
+var ariaLabelHasValue = function ariaLabelHasValue(prop) {
+  var value = (0, _jsxAstUtils.getPropValue)(prop);
+  if (value === undefined) {
+    return false;
+  }
+  if (typeof value === 'string' && value.length === 0) {
+    return false;
+  }
+  return true;
+};
+var ruleByElement = {
+  img(context, node, nodeType) {
+    var altProp = (0, _jsxAstUtils.getProp)(node.attributes, 'alt');
+
+    // Missing alt prop error.
+    if (altProp === undefined) {
+      if ((0, _isPresentationRole["default"])(nodeType, node.attributes)) {
+        context.report({
+          node,
+          message: 'Prefer alt="" over a presentational role. First rule of aria is to not use aria if it can be achieved via native HTML.'
+        });
+        return;
+      }
+      // Check for `aria-label` to provide text alternative
+      // Don't create an error if the attribute is used correctly. But if it
+      // isn't, suggest that the developer use `alt` instead.
+      var ariaLabelProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-label');
+      if (ariaLabelProp !== undefined) {
+        if (!ariaLabelHasValue(ariaLabelProp)) {
+          context.report({
+            node,
+            message: 'The aria-label attribute must have a value. The alt attribute is preferred over aria-label for images.'
+          });
+        }
+        return;
+      }
+      // Check for `aria-labelledby` to provide text alternative
+      // Don't create an error if the attribute is used correctly. But if it
+      // isn't, suggest that the developer use `alt` instead.
+      var ariaLabelledbyProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-labelledby');
+      if (ariaLabelledbyProp !== undefined) {
+        if (!ariaLabelHasValue(ariaLabelledbyProp)) {
+          context.report({
+            node,
+            message: 'The aria-labelledby attribute must have a value. The alt attribute is preferred over aria-labelledby for images.'
+          });
+        }
+        return;
+      }
+      context.report({
+        node,
+        message: "".concat(nodeType, " elements must have an alt prop, either with meaningful text, or an empty string for decorative images.")
+      });
+      return;
+    }
+
+    // Check if alt prop is undefined.
+    var altValue = (0, _jsxAstUtils.getPropValue)(altProp);
+    var isNullValued = altProp.value === null; // <img alt />
+
+    if (altValue && !isNullValued || altValue === '') {
+      return;
+    }
+
+    // Undefined alt prop error.
+    context.report({
+      node,
+      message: "Invalid alt value for ".concat(nodeType, ". Use alt=\"\" for presentational images.")
+    });
+  },
+  object(context, node, unusedNodeType, elementType) {
+    var ariaLabelProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-label');
+    var arialLabelledByProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-labelledby');
+    var hasLabel = ariaLabelHasValue(ariaLabelProp) || ariaLabelHasValue(arialLabelledByProp);
+    var titleProp = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'title'));
+    var hasTitleAttr = !!titleProp;
+    if (hasLabel || hasTitleAttr || (0, _hasAccessibleChild["default"])(node.parent, elementType)) {
+      return;
+    }
+    context.report({
+      node,
+      message: 'Embedded <object> elements must have alternative text by providing inner text, aria-label or aria-labelledby props.'
+    });
+  },
+  area(context, node) {
+    var ariaLabelProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-label');
+    var arialLabelledByProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-labelledby');
+    var hasLabel = ariaLabelHasValue(ariaLabelProp) || ariaLabelHasValue(arialLabelledByProp);
+    if (hasLabel) {
+      return;
+    }
+    var altProp = (0, _jsxAstUtils.getProp)(node.attributes, 'alt');
+    if (altProp === undefined) {
+      context.report({
+        node,
+        message: 'Each area of an image map must have a text alternative through the `alt`, `aria-label`, or `aria-labelledby` prop.'
+      });
+      return;
+    }
+    var altValue = (0, _jsxAstUtils.getPropValue)(altProp);
+    var isNullValued = altProp.value === null; // <area alt />
+
+    if (altValue && !isNullValued || altValue === '') {
+      return;
+    }
+    context.report({
+      node,
+      message: 'Each area of an image map must have a text alternative through the `alt`, `aria-label`, or `aria-labelledby` prop.'
+    });
+  },
+  'input[type="image"]': function inputImage(context, node, nodeType) {
+    // Only test input[type="image"]
+    if (nodeType === 'input') {
+      var typePropValue = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'type'));
+      if (typePropValue !== 'image') {
+        return;
+      }
+    }
+    var ariaLabelProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-label');
+    var arialLabelledByProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-labelledby');
+    var hasLabel = ariaLabelHasValue(ariaLabelProp) || ariaLabelHasValue(arialLabelledByProp);
+    if (hasLabel) {
+      return;
+    }
+    var altProp = (0, _jsxAstUtils.getProp)(node.attributes, 'alt');
+    if (altProp === undefined) {
+      context.report({
+        node,
+        message: '<input> elements with type="image" must have a text alternative through the `alt`, `aria-label`, or `aria-labelledby` prop.'
+      });
+      return;
+    }
+    var altValue = (0, _jsxAstUtils.getPropValue)(altProp);
+    var isNullValued = altProp.value === null; // <area alt />
+
+    if (altValue && !isNullValued || altValue === '') {
+      return;
+    }
+    context.report({
+      node,
+      message: '<input> elements with type="image" must have a text alternative through the `alt`, `aria-label`, or `aria-labelledby` prop.'
+    });
+  }
+};
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md',
+      description: 'Enforce all elements that require alternative text have meaningful information to relay back to end user.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var options = context.options[0] || {};
+    // Elements to validate for alt text.
+    var elementOptions = options.elements || DEFAULT_ELEMENTS;
+    // Get custom components for just the elements that will be tested.
+    var customComponents = (0, _arrayPrototype["default"])(elementOptions, function (element) {
+      return options[element];
+    });
+    var typesToValidate = new Set([].concat(customComponents, elementOptions).map(function (type) {
+      return type === 'input[type="image"]' ? 'input' : type;
+    }));
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement(node) {
+        var nodeType = elementType(node);
+        if (!typesToValidate.has(nodeType)) {
+          return;
+        }
+        var DOMElement = nodeType;
+        if (DOMElement === 'input') {
+          DOMElement = 'input[type="image"]';
+        }
+
+        // Map nodeType to the DOM element if we are running this on a custom component.
+        if (elementOptions.indexOf(DOMElement) === -1) {
+          DOMElement = elementOptions.find(function (element) {
+            var customComponentsForElement = options[element] || [];
+            return customComponentsForElement.indexOf(nodeType) > -1;
+          });
+        }
+        ruleByElement[DOMElement](context, node, nodeType, elementType);
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-ambiguous-text.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-ambiguous-text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-ambiguous-text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _schemas = require("../util/schemas");
+var _getAccessibleChildText = _interopRequireDefault(require("../util/getAccessibleChildText"));
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce anchor text to not exactly match 'click here', 'here', 'link', 'learn more', and user-specified words.
+ * @author Matt Wang
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var DEFAULT_AMBIGUOUS_WORDS = ['click here', 'here', 'link', 'a link', 'learn more'];
+var schema = (0, _schemas.generateObjSchema)({
+  words: _schemas.arraySchema
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-ambiguous-text.md',
+      description: 'Enforce `<a>` text to not exactly match "click here", "here", "link", or "a link".'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    var typesToValidate = ['a'];
+    var options = context.options[0] || {};
+    var _options$words = options.words,
+      words = _options$words === void 0 ? DEFAULT_AMBIGUOUS_WORDS : _options$words;
+    var ambiguousWords = new Set(words);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var nodeType = elementType(node);
+
+        // Only check anchor elements and custom types.
+        if (typesToValidate.indexOf(nodeType) === -1) {
+          return;
+        }
+        var nodeText = (0, _getAccessibleChildText["default"])(node.parent, elementType);
+        if (!ambiguousWords.has(nodeText)) {
+          // check the value
+          return;
+        }
+        context.report({
+          node,
+          message: 'Ambiguous text within anchor. Screen reader users rely on link text for context; the words "{{wordsList}}" are ambiguous and do not provide enough context.',
+          data: {
+            wordsList: words.join('", "')
+          }
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-has-content.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-has-content.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-has-content.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,60 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _schemas = require("../util/schemas");
+var _hasAccessibleChild = _interopRequireDefault(require("../util/hasAccessibleChild"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce anchor elements to contain accessible content.
+ * @author Lisa Ring & Niklas Holmberg
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Anchors must have content and the content must be accessible by a screen reader.';
+var schema = (0, _schemas.generateObjSchema)({
+  components: _schemas.arraySchema
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md',
+      description: 'Enforce all anchors to contain accessible content.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var options = context.options[0] || {};
+        var componentOptions = options.components || [];
+        var typeCheck = ['a'].concat(componentOptions);
+        var nodeType = elementType(node);
+
+        // Only check anchor elements and custom types.
+        if (typeCheck.indexOf(nodeType) === -1) {
+          return;
+        }
+        if ((0, _hasAccessibleChild["default"])(node.parent, elementType)) {
+          return;
+        }
+        if ((0, _jsxAstUtils.hasAnyProp)(node.attributes, ['title', 'aria-label'])) {
+          return;
+        }
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-is-valid.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-is-valid.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/anchor-is-valid.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,122 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _safeRegexTest = _interopRequireDefault(require("safe-regex-test"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Performs validity check on anchor hrefs. Warns when anchors are used as buttons.
+ * @author Almero Steyn
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var allAspects = ['noHref', 'invalidHref', 'preferButton'];
+var preferButtonErrorMessage = 'Anchor used as a button. Anchors are primarily expected to navigate. Use the button element instead. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md';
+var noHrefErrorMessage = 'The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md';
+var invalidHrefErrorMessage = 'The href attribute requires a valid value to be accessible. Provide a valid, navigable address as the href value. If you cannot provide a valid href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md';
+var schema = (0, _schemas.generateObjSchema)({
+  components: _schemas.arraySchema,
+  specialLink: _schemas.arraySchema,
+  aspects: (0, _schemas.enumArraySchema)(allAspects, 1)
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md',
+      description: 'Enforce all anchors are valid, navigable elements.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    var testJShref = (0, _safeRegexTest["default"])(/^\W*?javascript:/);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var attributes = node.attributes;
+        var options = context.options[0] || {};
+        var componentOptions = options.components || [];
+        var typeCheck = ['a'].concat(componentOptions);
+        var nodeType = elementType(node);
+
+        // Only check anchor elements and custom types.
+        if (typeCheck.indexOf(nodeType) === -1) {
+          return;
+        }
+
+        // Set up the rule aspects to check.
+        var aspects = options.aspects || allAspects;
+
+        // Create active aspect flag object. Failing checks will only report
+        // if the related flag is set to true.
+        var activeAspects = {};
+        allAspects.forEach(function (aspect) {
+          activeAspects[aspect] = aspects.indexOf(aspect) !== -1;
+        });
+        var propOptions = options.specialLink || [];
+        var propsToValidate = ['href'].concat(propOptions);
+        var values = propsToValidate.map(function (prop) {
+          return (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, prop));
+        });
+        // Checks if any actual or custom href prop is provided.
+        var hasAnyHref = values.some(function (value) {
+          return value != null;
+        });
+        // Need to check for spread operator as props can be spread onto the element
+        // leading to an incorrect validation error.
+        var hasSpreadOperator = attributes.some(function (prop) {
+          return prop.type === 'JSXSpreadAttribute';
+        });
+        var onClick = (0, _jsxAstUtils.getProp)(attributes, 'onClick');
+
+        // When there is no href at all, specific scenarios apply:
+        if (!hasAnyHref) {
+          // If no spread operator is found and no onClick event is present
+          // it is a link without href.
+          if (!hasSpreadOperator && activeAspects.noHref && (!onClick || onClick && !activeAspects.preferButton)) {
+            context.report({
+              node,
+              message: noHrefErrorMessage
+            });
+          }
+          // If no spread operator is found but an onClick is preset it should be a button.
+          if (!hasSpreadOperator && onClick && activeAspects.preferButton) {
+            context.report({
+              node,
+              message: preferButtonErrorMessage
+            });
+          }
+          return;
+        }
+
+        // Hrefs have been found, now check for validity.
+        var invalidHrefValues = values.filter(function (value) {
+          return value != null && typeof value === 'string' && (!value.length || value === '#' || testJShref(value));
+        });
+        if (invalidHrefValues.length !== 0) {
+          // If an onClick is found it should be a button, otherwise it is an invalid link.
+          if (onClick && activeAspects.preferButton) {
+            context.report({
+              node,
+              message: preferButtonErrorMessage
+            });
+          } else if (activeAspects.invalidHref) {
+            context.report({
+              node,
+              message: invalidHrefErrorMessage
+            });
+          }
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-activedescendant-has-tabindex.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-activedescendant-has-tabindex.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-activedescendant-has-tabindex.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,66 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _getTabIndex = _interopRequireDefault(require("../util/getTabIndex"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce elements with aria-activedescendant are tabbable.
+ * @author Jesse Beach <@jessebeach>
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'An element that manages focus with `aria-activedescendant` must have a tabindex';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md',
+      description: 'Enforce elements with aria-activedescendant are tabbable.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var attributes = node.attributes;
+        if ((0, _jsxAstUtils.getProp)(attributes, 'aria-activedescendant') === undefined) {
+          return;
+        }
+        var type = elementType(node);
+        // Do not test higher level JSX components, as we do not know what
+        // low-level DOM element this maps to.
+        if (!_ariaQuery.dom.has(type)) {
+          return;
+        }
+        var tabIndex = (0, _getTabIndex["default"])((0, _jsxAstUtils.getProp)(attributes, 'tabIndex'));
+
+        // If this is an interactive element and the tabindex attribute is not specified,
+        // or the tabIndex property was not mutated, then the tabIndex
+        // property will be undefined.
+        if ((0, _isInteractiveElement["default"])(type, attributes) && tabIndex === undefined) {
+          return;
+        }
+        if (tabIndex >= -1) {
+          return;
+        }
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-props.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-props.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-props.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getSuggestion = _interopRequireDefault(require("../util/getSuggestion"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce all aria-* properties are valid.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var ariaAttributes = _ariaQuery.aria.keys();
+var errorMessage = function errorMessage(name) {
+  var suggestions = (0, _getSuggestion["default"])(name, ariaAttributes);
+  var message = "".concat(name, ": This attribute is an invalid ARIA attribute.");
+  if (suggestions.length > 0) {
+    return "".concat(message, " Did you mean to use ").concat(suggestions, "?");
+  }
+  return message;
+};
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md',
+      description: 'Enforce all `aria-*` props are valid.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        var name = (0, _jsxAstUtils.propName)(attribute);
+
+        // `aria` needs to be prefix of property.
+        if (name.indexOf('aria-') !== 0) {
+          return;
+        }
+        var isValid = _ariaQuery.aria.has(name);
+        if (isValid === false) {
+          context.report({
+            node: attribute,
+            message: errorMessage(name)
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-proptypes.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-proptypes.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-proptypes.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+/**
+ * @fileoverview Enforce ARIA state and property values are valid.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = function errorMessage(name, type, permittedValues) {
+  switch (type) {
+    case 'tristate':
+      return "The value for ".concat(name, " must be a boolean or the string \"mixed\".");
+    case 'token':
+      return "The value for ".concat(name, " must be a single token from the following: ").concat(permittedValues, ".");
+    case 'tokenlist':
+      return "The value for ".concat(name, " must be a list of one or more tokens from the following: ").concat(permittedValues, ".");
+    case 'idlist':
+      return "The value for ".concat(name, " must be a list of strings that represent DOM element IDs (idlist)");
+    case 'id':
+      return "The value for ".concat(name, " must be a string that represents a DOM element ID");
+    case 'boolean':
+    case 'string':
+    case 'integer':
+    case 'number':
+    default:
+      return "The value for ".concat(name, " must be a ").concat(type, ".");
+  }
+};
+var _validityCheck = function validityCheck(value, expectedType, permittedValues) {
+  switch (expectedType) {
+    case 'boolean':
+      return typeof value === 'boolean';
+    case 'string':
+    case 'id':
+      return typeof value === 'string';
+    case 'tristate':
+      return typeof value === 'boolean' || value === 'mixed';
+    case 'integer':
+    case 'number':
+      // Booleans resolve to 0/1 values so hard check that it's not first.
+      // eslint-disable-next-line no-restricted-globals
+      return typeof value !== 'boolean' && isNaN(Number(value)) === false;
+    case 'token':
+      return permittedValues.indexOf(typeof value === 'string' ? value.toLowerCase() : value) > -1;
+    case 'idlist':
+      return typeof value === 'string' && value.split(' ').every(function (token) {
+        return _validityCheck(token, 'id', []);
+      });
+    case 'tokenlist':
+      return typeof value === 'string' && value.split(' ').every(function (token) {
+        return permittedValues.indexOf(token.toLowerCase()) > -1;
+      });
+    default:
+      return false;
+  }
+};
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  validityCheck: _validityCheck,
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md',
+      description: 'Enforce ARIA state and property values are valid.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        var name = (0, _jsxAstUtils.propName)(attribute);
+        var normalizedName = name.toLowerCase();
+
+        // Not a valid aria-* state or property.
+        if (normalizedName.indexOf('aria-') !== 0 || _ariaQuery.aria.get(normalizedName) === undefined) {
+          return;
+        }
+
+        // Ignore the attribute if its value is null or undefined.
+        if ((0, _jsxAstUtils.getPropValue)(attribute) == null) return;
+        var value = (0, _jsxAstUtils.getLiteralPropValue)(attribute);
+
+        // Ignore the attribute if its value is not a literal.
+        if (value === null) {
+          return;
+        }
+
+        // These are the attributes of the property/state to check against.
+        var attributes = _ariaQuery.aria.get(normalizedName);
+        var permittedType = attributes.type;
+        var allowUndefined = attributes.allowUndefined || false;
+        var permittedValues = attributes.values || [];
+        var isValid = _validityCheck(value, permittedType, permittedValues) || allowUndefined && value === undefined;
+        if (isValid) {
+          return;
+        }
+        context.report({
+          node: attribute,
+          message: errorMessage(name, permittedType, permittedValues)
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-role.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,89 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _schemas = require("../util/schemas");
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce aria role attribute is valid.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Elements with ARIA roles must use a valid, non-abstract ARIA role.';
+var schema = (0, _schemas.generateObjSchema)({
+  allowedInvalidRoles: {
+    items: {
+      type: 'string'
+    },
+    type: 'array',
+    uniqueItems: true
+  },
+  ignoreNonDOM: {
+    type: 'boolean',
+    "default": false
+  }
+});
+var validRoles = new Set(_ariaQuery.roles.keys().filter(function (role) {
+  return _ariaQuery.roles.get(role)["abstract"] === false;
+}));
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md',
+      description: 'Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var options = context.options[0] || {};
+    var ignoreNonDOM = !!options.ignoreNonDOM;
+    var allowedInvalidRoles = new Set(options.allowedInvalidRoles || []);
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        // If ignoreNonDOM and the parent isn't DOM, don't run rule.
+        if (ignoreNonDOM) {
+          var type = elementType(attribute.parent);
+          if (!_ariaQuery.dom.get(type)) {
+            return;
+          }
+        }
+
+        // Get prop name
+        var name = (0, _jsxAstUtils.propName)(attribute).toUpperCase();
+        if (name !== 'ROLE') {
+          return;
+        }
+        var value = (0, _jsxAstUtils.getLiteralPropValue)(attribute);
+
+        // If value is undefined, then the role attribute will be dropped in the DOM.
+        // If value is null, then getLiteralAttributeValue is telling us that the
+        // value isn't in the form of a literal.
+        if (value === undefined || value === null) {
+          return;
+        }
+        var values = String(value).split(' ');
+        var isValid = values.every(function (val) {
+          return allowedInvalidRoles.has(val) || validRoles.has(val);
+        });
+        if (isValid === true) {
+          return;
+        }
+        context.report({
+          node: attribute,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-unsupported-elements.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-unsupported-elements.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/aria-unsupported-elements.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce that elements that do not support ARIA roles,
+ *  states and properties do not have those attributes.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = function errorMessage(invalidProp) {
+  return "This element does not support ARIA roles, states and properties. Try removing the prop '".concat(invalidProp, "'.");
+};
+var invalidAttributes = new Set(_ariaQuery.aria.keys().concat('role'));
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md',
+      description: 'Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var nodeType = elementType(node);
+        var nodeAttrs = _ariaQuery.dom.get(nodeType) || {};
+        var _nodeAttrs$reserved = nodeAttrs.reserved,
+          isReservedNodeType = _nodeAttrs$reserved === void 0 ? false : _nodeAttrs$reserved;
+
+        // If it's not reserved, then it can have aria-* roles, states, and properties
+        if (isReservedNodeType === false) {
+          return;
+        }
+        node.attributes.forEach(function (prop) {
+          if (prop.type === 'JSXSpreadAttribute') {
+            return;
+          }
+          var name = (0, _jsxAstUtils.propName)(prop).toLowerCase();
+          if (invalidAttributes.has(name)) {
+            context.report({
+              node,
+              message: errorMessage(name)
+            });
+          }
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/autocomplete-valid.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/autocomplete-valid.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/autocomplete-valid.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,67 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _axeCore = require("axe-core");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Ensure autocomplete attribute is correct.
+ * @author Wilco Fiers
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var schema = (0, _schemas.generateObjSchema)({
+  inputComponents: _schemas.arraySchema
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md',
+      description: 'Enforce that autocomplete attributes are used correctly.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var options = context.options[0] || {};
+        var _options$inputCompone = options.inputComponents,
+          inputComponents = _options$inputCompone === void 0 ? [] : _options$inputCompone;
+        var inputTypes = ['input'].concat(inputComponents);
+        var elType = elementType(node);
+        var autocomplete = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'autocomplete'));
+        if (typeof autocomplete !== 'string' || !inputTypes.includes(elType)) {
+          return;
+        }
+        var type = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'type'));
+        var _runVirtualRule = (0, _axeCore.runVirtualRule)('autocomplete-valid', {
+            nodeName: 'input',
+            attributes: {
+              autocomplete,
+              // Which autocomplete is valid depends on the input type
+              type: type === null ? undefined : type
+            }
+          }),
+          violations = _runVirtualRule.violations;
+        if (violations.length === 0) {
+          return;
+        }
+        // Since we only test one rule, with one node, return the message from first (and only) instance of each
+        context.report({
+          node,
+          message: violations[0].nodes[0].all[0].message
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/click-events-have-key-events.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/click-events-have-key-events.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/click-events-have-key-events.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,68 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce a clickable non-interactive element has at least 1 keyboard event listener.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Visible, non-interactive elements with click handlers must have at least one keyboard listener.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md',
+      description: 'Enforce a clickable non-interactive element has at least one keyboard event listener.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var props = node.attributes;
+        if ((0, _jsxAstUtils.getProp)(props, 'onclick') === undefined) {
+          return;
+        }
+        var type = elementType(node);
+        var requiredProps = ['onkeydown', 'onkeyup', 'onkeypress'];
+        if (!_ariaQuery.dom.has(type)) {
+          // Do not test higher level JSX components, as we do not know what
+          // low-level DOM element this maps to.
+          return;
+        }
+        if ((0, _isHiddenFromScreenReader["default"])(type, props) || (0, _isPresentationRole["default"])(type, props)) {
+          return;
+        }
+        if ((0, _isInteractiveElement["default"])(type, props)) {
+          return;
+        }
+        if ((0, _jsxAstUtils.hasAnyProp)(props, requiredProps)) {
+          return;
+        }
+
+        // Visible, non-interactive elements with click handlers require one keyboard event listener.
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/control-has-associated-label.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/control-has-associated-label.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/control-has-associated-label.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,103 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isDOMElement = _interopRequireDefault(require("../util/isDOMElement"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
+var _mayHaveAccessibleLabel = _interopRequireDefault(require("../util/mayHaveAccessibleLabel"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce controls are associated with a text label.
+ * @author Jesse Beach
+ *
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'A control must be associated with a text label.';
+var ignoreList = ['link'];
+var schema = (0, _schemas.generateObjSchema)({
+  labelAttributes: _schemas.arraySchema,
+  controlComponents: _schemas.arraySchema,
+  ignoreElements: _schemas.arraySchema,
+  ignoreRoles: _schemas.arraySchema,
+  depth: {
+    description: 'JSX tree depth limit to check for accessible label',
+    type: 'integer',
+    minimum: 0
+  }
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      description: 'Enforce that a control (an interactive element) has a text label.',
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/control-has-associated-label.md'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    var options = context.options[0] || {};
+    var _options$labelAttribu = options.labelAttributes,
+      labelAttributes = _options$labelAttribu === void 0 ? [] : _options$labelAttribu,
+      _options$controlCompo = options.controlComponents,
+      controlComponents = _options$controlCompo === void 0 ? [] : _options$controlCompo,
+      _options$ignoreElemen = options.ignoreElements,
+      ignoreElements = _options$ignoreElemen === void 0 ? [] : _options$ignoreElemen,
+      _options$ignoreRoles = options.ignoreRoles,
+      ignoreRoles = _options$ignoreRoles === void 0 ? [] : _options$ignoreRoles;
+    var newIgnoreElements = new Set([].concat(ignoreElements, ignoreList));
+    var rule = function rule(node) {
+      var tag = elementType(node.openingElement);
+      var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.openingElement.attributes, 'role'));
+      // Ignore interactive elements that might get their label from a source
+      // that cannot be discerned from static analysis, like
+      // <label><input />Save</label>
+      if (newIgnoreElements.has(tag)) {
+        return;
+      }
+      // Ignore roles that are "interactive" but should not require a label.
+      if ((0, _arrayIncludes["default"])(ignoreRoles, role)) {
+        return;
+      }
+      var props = node.openingElement.attributes;
+      var nodeIsDOMElement = (0, _isDOMElement["default"])(tag);
+      var nodeIsHiddenFromScreenReader = (0, _isHiddenFromScreenReader["default"])(tag, props);
+      var nodeIsInteractiveElement = (0, _isInteractiveElement["default"])(tag, props);
+      var nodeIsInteractiveRole = (0, _isInteractiveRole["default"])(tag, props);
+      var nodeIsControlComponent = controlComponents.indexOf(tag) > -1;
+      if (nodeIsHiddenFromScreenReader) {
+        return;
+      }
+      var hasAccessibleLabel = true;
+      if (nodeIsInteractiveElement || nodeIsDOMElement && nodeIsInteractiveRole || nodeIsControlComponent) {
+        // Prevent crazy recursion.
+        var recursionDepth = Math.min(options.depth === undefined ? 2 : options.depth, 25);
+        hasAccessibleLabel = (0, _mayHaveAccessibleLabel["default"])(node, recursionDepth, labelAttributes, elementType, controlComponents);
+      }
+      if (!hasAccessibleLabel) {
+        context.report({
+          node: node.openingElement,
+          message: errorMessage
+        });
+      }
+    };
+
+    // Create visitor selectors.
+    return {
+      JSXElement: rule
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/heading-has-content.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/heading-has-content.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/heading-has-content.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,61 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _hasAccessibleChild = _interopRequireDefault(require("../util/hasAccessibleChild"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce heading (h1, h2, etc) elements contain accessible content.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Headings must have content and the content must be accessible by a screen reader.';
+var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
+var schema = (0, _schemas.generateObjSchema)({
+  components: _schemas.arraySchema
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md',
+      description: 'Enforce heading (`h1`, `h2`, etc) elements contain accessible content.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var options = context.options[0] || {};
+        var componentOptions = options.components || [];
+        var typeCheck = headings.concat(componentOptions);
+        var nodeType = elementType(node);
+
+        // Only check 'h*' elements and custom types.
+        if (typeCheck.indexOf(nodeType) === -1) {
+          return;
+        }
+        if ((0, _hasAccessibleChild["default"])(node.parent, elementType)) {
+          return;
+        }
+        if ((0, _isHiddenFromScreenReader["default"])(nodeType, node.attributes)) {
+          return;
+        }
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/html-has-lang.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/html-has-lang.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/html-has-lang.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce html element has lang prop.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = '<html> elements must have the lang prop.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md',
+      description: 'Enforce `<html>` element has `lang` prop.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var type = elementType(node);
+        if (type && type !== 'html') {
+          return;
+        }
+        var lang = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'lang'));
+        if (lang) {
+          return;
+        }
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/iframe-has-title.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/iframe-has-title.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/iframe-has-title.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _schemas = require("../util/schemas");
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce iframe elements have a title attribute.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = '<iframe> elements must have a unique title property.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md',
+      description: 'Enforce iframe elements have a title attribute.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var type = elementType(node);
+        if (type && type !== 'iframe') {
+          return;
+        }
+        var title = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'title'));
+        if (title && typeof title === 'string') {
+          return;
+        }
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/img-redundant-alt.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/img-redundant-alt.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/img-redundant-alt.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,88 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _stringPrototype = _interopRequireDefault(require("string.prototype.includes"));
+var _safeRegexTest = _interopRequireDefault(require("safe-regex-test"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce img alt attribute does not have the word image, picture, or photo.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var REDUNDANT_WORDS = ['image', 'photo', 'picture'];
+var errorMessage = 'Redundant alt attribute. Screen-readers already announce `img` tags as an image. You don’t need to use the words `image`, `photo,` or `picture` (or any specified custom words) in the alt prop.';
+var schema = (0, _schemas.generateObjSchema)({
+  components: _schemas.arraySchema,
+  words: _schemas.arraySchema
+});
+var isASCII = (0, _safeRegexTest["default"])(/[\x20-\x7F]+/);
+function containsRedundantWord(value, redundantWords) {
+  var lowercaseRedundantWords = redundantWords.map(function (redundantWord) {
+    return redundantWord.toLowerCase();
+  });
+  if (isASCII(value)) {
+    return value.split(/\s+/).some(function (valueWord) {
+      return (0, _arrayIncludes["default"])(lowercaseRedundantWords, valueWord.toLowerCase());
+    });
+  }
+  return lowercaseRedundantWords.some(function (redundantWord) {
+    return (0, _stringPrototype["default"])(value.toLowerCase(), redundantWord);
+  });
+}
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md',
+      description: 'Enforce `<img>` alt prop does not contain the word "image", "picture", or "photo".'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var options = context.options[0] || {};
+        var componentOptions = options.components || [];
+        var typesToValidate = ['img'].concat(componentOptions);
+        var nodeType = elementType(node);
+
+        // Only check 'label' elements and custom types.
+        if (typesToValidate.indexOf(nodeType) === -1) {
+          return;
+        }
+        var altProp = (0, _jsxAstUtils.getProp)(node.attributes, 'alt');
+        // Return if alt prop is not present.
+        if (altProp === undefined) {
+          return;
+        }
+        var value = (0, _jsxAstUtils.getLiteralPropValue)(altProp);
+        var isVisible = (0, _isHiddenFromScreenReader["default"])(nodeType, node.attributes) === false;
+        var _options$words = options.words,
+          words = _options$words === void 0 ? [] : _options$words;
+        var redundantWords = REDUNDANT_WORDS.concat(words);
+        if (typeof value === 'string' && isVisible) {
+          var hasRedundancy = containsRedundantWord(value, redundantWords);
+          if (hasRedundancy === true) {
+            context.report({
+              node,
+              message: errorMessage
+            });
+          }
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/interactive-supports-focus.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/interactive-supports-focus.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/interactive-supports-focus.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,87 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isDisabledElement = _interopRequireDefault(require("../util/isDisabledElement"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
+var _isNonInteractiveElement = _interopRequireDefault(require("../util/isNonInteractiveElement"));
+var _isNonInteractiveRole = _interopRequireDefault(require("../util/isNonInteractiveRole"));
+var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
+var _getTabIndex = _interopRequireDefault(require("../util/getTabIndex"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce that elements with onClick handlers must be tabbable.
+ * @author Ethan Cohen
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var schema = (0, _schemas.generateObjSchema)({
+  tabbable: (0, _schemas.enumArraySchema)(_ariaQuery.roles.keys().filter(function (name) {
+    return !_ariaQuery.roles.get(name)["abstract"] && _ariaQuery.roles.get(name).superClass.some(function (klasses) {
+      return (0, _arrayIncludes["default"])(klasses, 'widget');
+    });
+  }))
+});
+var interactiveProps = [].concat(_jsxAstUtils.eventHandlersByType.mouse, _jsxAstUtils.eventHandlersByType.keyboard);
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md',
+      description: 'Enforce that elements with interactive handlers like `onClick` must be focusable.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var tabbable = context.options && context.options[0] && context.options[0].tabbable || [];
+        var attributes = node.attributes;
+        var type = elementType(node);
+        var hasInteractiveProps = (0, _jsxAstUtils.hasAnyProp)(attributes, interactiveProps);
+        var hasTabindex = (0, _getTabIndex["default"])((0, _jsxAstUtils.getProp)(attributes, 'tabIndex')) !== undefined;
+        if (!_ariaQuery.dom.has(type)) {
+          // Do not test higher level JSX components, as we do not know what
+          // low-level DOM element this maps to.
+          return;
+        }
+        if (!hasInteractiveProps || (0, _isDisabledElement["default"])(attributes) || (0, _isHiddenFromScreenReader["default"])(type, attributes) || (0, _isPresentationRole["default"])(type, attributes)) {
+          // Presentation is an intentional signal from the author that this
+          // element is not meant to be perceivable. For example, a click screen
+          // to close a dialog .
+          return;
+        }
+        if (hasInteractiveProps && (0, _isInteractiveRole["default"])(type, attributes) && !(0, _isInteractiveElement["default"])(type, attributes) && !(0, _isNonInteractiveElement["default"])(type, attributes) && !(0, _isNonInteractiveRole["default"])(type, attributes) && !hasTabindex) {
+          var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role'));
+          if ((0, _arrayIncludes["default"])(tabbable, role)) {
+            // Always tabbable, tabIndex = 0
+            context.report({
+              node,
+              message: "Elements with the '".concat(role, "' interactive role must be tabbable.")
+            });
+          } else {
+            // Focusable, tabIndex = -1 or 0
+            context.report({
+              node,
+              message: "Elements with the '".concat(role, "' interactive role must be focusable.")
+            });
+          }
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/label-has-associated-control.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/label-has-associated-control.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/label-has-associated-control.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,127 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _mayContainChildComponent = _interopRequireDefault(require("../util/mayContainChildComponent"));
+var _mayHaveAccessibleLabel = _interopRequireDefault(require("../util/mayHaveAccessibleLabel"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce label tags have an associated control.
+ * @author Jesse Beach
+ *
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'A form label must be associated with a control.';
+var errorMessageNoLabel = 'A form label must have accessible text.';
+var schema = (0, _schemas.generateObjSchema)({
+  labelComponents: _schemas.arraySchema,
+  labelAttributes: _schemas.arraySchema,
+  controlComponents: _schemas.arraySchema,
+  assert: {
+    description: 'Assert that the label has htmlFor, a nested label, both or either',
+    type: 'string',
+    "enum": ['htmlFor', 'nesting', 'both', 'either']
+  },
+  depth: {
+    description: 'JSX tree depth limit to check for accessible label',
+    type: 'integer',
+    minimum: 0
+  }
+});
+function validateID(node, context) {
+  var _settings$jsxA11y$at, _settings$jsxA11y, _settings$jsxA11y$att;
+  var settings = context.settings;
+  var htmlForAttributes = (_settings$jsxA11y$at = (_settings$jsxA11y = settings['jsx-a11y']) === null || _settings$jsxA11y === void 0 ? void 0 : (_settings$jsxA11y$att = _settings$jsxA11y.attributes) === null || _settings$jsxA11y$att === void 0 ? void 0 : _settings$jsxA11y$att["for"]) !== null && _settings$jsxA11y$at !== void 0 ? _settings$jsxA11y$at : ['htmlFor'];
+  for (var i = 0; i < htmlForAttributes.length; i += 1) {
+    var attribute = htmlForAttributes[i];
+    if ((0, _jsxAstUtils.hasProp)(node.attributes, attribute)) {
+      var htmlForAttr = (0, _jsxAstUtils.getProp)(node.attributes, attribute);
+      var htmlForValue = (0, _jsxAstUtils.getPropValue)(htmlForAttr);
+      return htmlForAttr !== false && !!htmlForValue;
+    }
+  }
+  return false;
+}
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      description: 'Enforce that a `label` tag has a text label and an associated control.',
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var options = context.options[0] || {};
+    var labelComponents = options.labelComponents || [];
+    var assertType = options.assert || 'either';
+    var componentNames = ['label'].concat(labelComponents);
+    var elementType = (0, _getElementType["default"])(context);
+    var rule = function rule(node) {
+      if (componentNames.indexOf(elementType(node.openingElement)) === -1) {
+        return;
+      }
+      var controlComponents = ['input', 'meter', 'output', 'progress', 'select', 'textarea'].concat(options.controlComponents || []);
+      // Prevent crazy recursion.
+      var recursionDepth = Math.min(options.depth === undefined ? 2 : options.depth, 25);
+      var hasLabelId = validateID(node.openingElement, context);
+      // Check for multiple control components.
+      var hasNestedControl = controlComponents.some(function (name) {
+        return (0, _mayContainChildComponent["default"])(node, name, recursionDepth, elementType);
+      });
+      var hasAccessibleLabel = (0, _mayHaveAccessibleLabel["default"])(node, recursionDepth, options.labelAttributes, elementType, controlComponents);
+      if (!hasAccessibleLabel) {
+        context.report({
+          node: node.openingElement,
+          message: errorMessageNoLabel
+        });
+        return;
+      }
+      switch (assertType) {
+        case 'htmlFor':
+          if (hasLabelId) {
+            return;
+          }
+          break;
+        case 'nesting':
+          if (hasNestedControl) {
+            return;
+          }
+          break;
+        case 'both':
+          if (hasLabelId && hasNestedControl) {
+            return;
+          }
+          break;
+        case 'either':
+          if (hasLabelId || hasNestedControl) {
+            return;
+          }
+          break;
+        default:
+          break;
+      }
+
+      // htmlFor case
+      context.report({
+        node: node.openingElement,
+        message: errorMessage
+      });
+    };
+
+    // Create visitor selectors.
+    return {
+      JSXElement: rule
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/label-has-for.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/label-has-for.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/label-has-for.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,150 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _hasAccessibleChild = _interopRequireDefault(require("../util/hasAccessibleChild"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce label tags have htmlFor attribute.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var enumValues = ['nesting', 'id'];
+var schema = {
+  type: 'object',
+  properties: {
+    components: _schemas.arraySchema,
+    required: {
+      oneOf: [{
+        type: 'string',
+        "enum": enumValues
+      }, (0, _schemas.generateObjSchema)({
+        some: (0, _schemas.enumArraySchema)(enumValues)
+      }, ['some']), (0, _schemas.generateObjSchema)({
+        every: (0, _schemas.enumArraySchema)(enumValues)
+      }, ['every'])]
+    },
+    allowChildren: {
+      type: 'boolean'
+    }
+  }
+};
+// Breadth-first search, assuming that HTML for forms is shallow.
+function validateNesting(node) {
+  var queue = node.parent.children.slice();
+  var child;
+  var opener;
+  while (queue.length) {
+    child = queue.shift();
+    opener = child.openingElement;
+    if (child.type === 'JSXElement' && opener && (opener.name.name === 'input' || opener.name.name === 'textarea' || opener.name.name === 'select')) {
+      return true;
+    }
+    if (child.children) {
+      queue = queue.concat(child.children);
+    }
+  }
+  return false;
+}
+function validateID(_ref, context) {
+  var _settings$jsxA11y$at, _settings$jsxA11y, _settings$jsxA11y$att;
+  var attributes = _ref.attributes;
+  var settings = context.settings;
+  var htmlForAttributes = (_settings$jsxA11y$at = (_settings$jsxA11y = settings['jsx-a11y']) === null || _settings$jsxA11y === void 0 ? void 0 : (_settings$jsxA11y$att = _settings$jsxA11y.attributes) === null || _settings$jsxA11y$att === void 0 ? void 0 : _settings$jsxA11y$att["for"]) !== null && _settings$jsxA11y$at !== void 0 ? _settings$jsxA11y$at : ['htmlFor'];
+  for (var i = 0; i < htmlForAttributes.length; i += 1) {
+    var attribute = htmlForAttributes[i];
+    if ((0, _jsxAstUtils.hasProp)(attributes, attribute)) {
+      var htmlForAttr = (0, _jsxAstUtils.getProp)(attributes, attribute);
+      var htmlForValue = (0, _jsxAstUtils.getPropValue)(htmlForAttr);
+      return htmlForAttr !== false && !!htmlForValue;
+    }
+  }
+  return false;
+}
+function validate(node, required, allowChildren, elementType, context) {
+  if (allowChildren === true) {
+    return (0, _hasAccessibleChild["default"])(node.parent, elementType);
+  }
+  if (required === 'nesting') {
+    return validateNesting(node);
+  }
+  return validateID(node, context);
+}
+function getValidityStatus(node, required, allowChildren, elementType, context) {
+  if (Array.isArray(required.some)) {
+    var _isValid = required.some.some(function (rule) {
+      return validate(node, rule, allowChildren, elementType, context);
+    });
+    var _message = !_isValid ? "Form label must have ANY of the following types of associated control: ".concat(required.some.join(', ')) : null;
+    return {
+      isValid: _isValid,
+      message: _message
+    };
+  }
+  if (Array.isArray(required.every)) {
+    var _isValid2 = required.every.every(function (rule) {
+      return validate(node, rule, allowChildren, elementType, context);
+    });
+    var _message2 = !_isValid2 ? "Form label must have ALL of the following types of associated control: ".concat(required.every.join(', ')) : null;
+    return {
+      isValid: _isValid2,
+      message: _message2
+    };
+  }
+  var isValid = validate(node, required, allowChildren, elementType, context);
+  var message = !isValid ? "Form label must have the following type of associated control: ".concat(required) : null;
+  return {
+    isValid,
+    message
+  };
+}
+var _default = exports["default"] = {
+  meta: {
+    deprecated: true,
+    replacedBy: ['label-has-associated-control'],
+    docs: {
+      description: 'Enforce that `<label>` elements have the `htmlFor` prop.',
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/label-has-for.md'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement(node) {
+        var options = context.options[0] || {};
+        var componentOptions = options.components || [];
+        var typesToValidate = ['label'].concat(componentOptions);
+        var nodeType = elementType(node);
+
+        // Only check 'label' elements and custom types.
+        if (typesToValidate.indexOf(nodeType) === -1) {
+          return;
+        }
+        var required = options.required || {
+          every: ['nesting', 'id']
+        };
+        var allowChildren = options.allowChildren || false;
+        var _getValidityStatus = getValidityStatus(node, required, allowChildren, elementType, context),
+          isValid = _getValidityStatus.isValid,
+          message = _getValidityStatus.message;
+        if (!isValid) {
+          context.report({
+            node,
+            message
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/lang.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/lang.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/lang.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,68 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _languageTags = _interopRequireDefault(require("language-tags"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce lang attribute has a valid value.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'lang attribute must have a valid value.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/lang.md',
+      description: 'Enforce lang attribute has a valid value.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXAttribute: function JSXAttribute(node) {
+        var name = (0, _jsxAstUtils.propName)(node);
+        if (name && name.toUpperCase() !== 'LANG') {
+          return;
+        }
+        var parent = node.parent;
+        var type = elementType(parent);
+        if (type && type !== 'html') {
+          return;
+        }
+        var value = (0, _jsxAstUtils.getLiteralPropValue)(node);
+
+        // Don't check identifiers
+        if (value === null) {
+          return;
+        }
+        if (value === undefined) {
+          context.report({
+            node,
+            message: errorMessage
+          });
+          return;
+        }
+        if (_languageTags["default"].check(value)) {
+          return;
+        }
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/media-has-caption.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/media-has-caption.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/media-has-caption.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,96 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayPrototype = _interopRequireDefault(require("array.prototype.flatmap"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview <audio> and <video> elements must have a <track> for captions.
+ * @author Ethan Cohen
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Media elements such as <audio> and <video> must have a <track> for captions.';
+var MEDIA_TYPES = ['audio', 'video'];
+var schema = (0, _schemas.generateObjSchema)({
+  audio: _schemas.arraySchema,
+  video: _schemas.arraySchema,
+  track: _schemas.arraySchema
+});
+var isMediaType = function isMediaType(context, type) {
+  var options = context.options[0] || {};
+  return MEDIA_TYPES.concat((0, _arrayPrototype["default"])(MEDIA_TYPES, function (mediaType) {
+    return options[mediaType];
+  })).some(function (typeToCheck) {
+    return typeToCheck === type;
+  });
+};
+var isTrackType = function isTrackType(context, type) {
+  var options = context.options[0] || {};
+  return ['track'].concat(options.track || []).some(function (typeToCheck) {
+    return typeToCheck === type;
+  });
+};
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md',
+      description: 'Enforces that `<audio>` and `<video>` elements must have a `<track>` for captions.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXElement: function JSXElement(node) {
+        var element = node.openingElement;
+        var type = elementType(element);
+        if (!isMediaType(context, type)) {
+          return;
+        }
+        var mutedProp = (0, _jsxAstUtils.getProp)(element.attributes, 'muted');
+        var mutedPropVal = (0, _jsxAstUtils.getLiteralPropValue)(mutedProp);
+        if (mutedPropVal === true) {
+          return;
+        }
+        // $FlowFixMe https://github.com/facebook/flow/issues/1414
+        var trackChildren = node.children.filter(function (child) {
+          if (child.type !== 'JSXElement') {
+            return false;
+          }
+
+          // $FlowFixMe https://github.com/facebook/flow/issues/1414
+          return isTrackType(context, elementType(child.openingElement));
+        });
+        if (trackChildren.length === 0) {
+          context.report({
+            node: element,
+            message: errorMessage
+          });
+          return;
+        }
+        var hasCaption = trackChildren.some(function (track) {
+          var kindProp = (0, _jsxAstUtils.getProp)(track.openingElement.attributes, 'kind');
+          var kindPropValue = (0, _jsxAstUtils.getLiteralPropValue)(kindProp) || '';
+          return kindPropValue.toLowerCase() === 'captions';
+        });
+        if (!hasCaption) {
+          context.report({
+            node: element,
+            message: errorMessage
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/mouse-events-have-key-events.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/mouse-events-have-key-events.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/mouse-events-have-key-events.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,93 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
+function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
+function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
+function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
+function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
+ * @fileoverview Enforce onmouseover/onmouseout are
+ *  accompanied by onfocus/onblur.
+ * @author Ethan Cohen
+ * 
+ */ // ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+var schema = (0, _schemas.generateObjSchema)({
+  hoverInHandlers: _objectSpread(_objectSpread({}, _schemas.arraySchema), {}, {
+    description: 'An array of events that need to be accompanied by `onFocus`'
+  }),
+  hoverOutHandlers: _objectSpread(_objectSpread({}, _schemas.arraySchema), {}, {
+    description: 'An array of events that need to be accompanied by `onBlur`'
+  })
+});
+
+// Use `onMouseOver` and `onMouseOut` by default if no config is
+// passed in for backwards compatibility
+var DEFAULT_HOVER_IN_HANDLERS = ['onMouseOver'];
+var DEFAULT_HOVER_OUT_HANDLERS = ['onMouseOut'];
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/mouse-events-have-key-events.md',
+      description: 'Enforce that `onMouseOver`/`onMouseOut` are accompanied by `onFocus`/`onBlur` for keyboard-only users.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var _options$0$hoverInHan, _options$, _options$0$hoverOutHa, _options$2;
+        var name = node.name.name;
+        if (!_ariaQuery.dom.get(name)) {
+          return;
+        }
+        var options = context.options;
+        var hoverInHandlers = (_options$0$hoverInHan = (_options$ = options[0]) === null || _options$ === void 0 ? void 0 : _options$.hoverInHandlers) !== null && _options$0$hoverInHan !== void 0 ? _options$0$hoverInHan : DEFAULT_HOVER_IN_HANDLERS;
+        var hoverOutHandlers = (_options$0$hoverOutHa = (_options$2 = options[0]) === null || _options$2 === void 0 ? void 0 : _options$2.hoverOutHandlers) !== null && _options$0$hoverOutHa !== void 0 ? _options$0$hoverOutHa : DEFAULT_HOVER_OUT_HANDLERS;
+        var attributes = node.attributes;
+
+        // Check hover in / onfocus pairing
+        var firstHoverInHandlerWithValue = hoverInHandlers.find(function (handler) {
+          var prop = (0, _jsxAstUtils.getProp)(attributes, handler);
+          var propValue = (0, _jsxAstUtils.getPropValue)(prop);
+          return propValue != null;
+        });
+        if (firstHoverInHandlerWithValue != null) {
+          var hasOnFocus = (0, _jsxAstUtils.getProp)(attributes, 'onFocus');
+          var onFocusValue = (0, _jsxAstUtils.getPropValue)(hasOnFocus);
+          if (hasOnFocus === false || onFocusValue === null || onFocusValue === undefined) {
+            context.report({
+              node: (0, _jsxAstUtils.getProp)(attributes, firstHoverInHandlerWithValue),
+              message: "".concat(firstHoverInHandlerWithValue, " must be accompanied by onFocus for accessibility.")
+            });
+          }
+        }
+
+        // Check hover out / onblur pairing
+        var firstHoverOutHandlerWithValue = hoverOutHandlers.find(function (handler) {
+          var prop = (0, _jsxAstUtils.getProp)(attributes, handler);
+          var propValue = (0, _jsxAstUtils.getPropValue)(prop);
+          return propValue != null;
+        });
+        if (firstHoverOutHandlerWithValue != null) {
+          var hasOnBlur = (0, _jsxAstUtils.getProp)(attributes, 'onBlur');
+          var onBlurValue = (0, _jsxAstUtils.getPropValue)(hasOnBlur);
+          if (hasOnBlur === false || onBlurValue === null || onBlurValue === undefined) {
+            context.report({
+              node: (0, _jsxAstUtils.getProp)(attributes, firstHoverOutHandlerWithValue),
+              message: "".concat(firstHoverOutHandlerWithValue, " must be accompanied by onBlur for accessibility.")
+            });
+          }
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-access-key.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-access-key.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-access-key.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+/**
+ * @fileoverview Enforce no accesskey attribute on element.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'No access key attribute allowed. Inconsistencies between keyboard shortcuts and keyboard commands used by screen readers and keyboard-only users create a11y complications.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-access-key.md',
+      description: 'Enforce that the `accessKey` prop is not used on any element to avoid complications with keyboard commands used by a screen reader.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var accessKey = (0, _jsxAstUtils.getProp)(node.attributes, 'accesskey');
+        var accessKeyValue = (0, _jsxAstUtils.getPropValue)(accessKey);
+        if (accessKey && accessKeyValue) {
+          context.report({
+            node,
+            message: errorMessage
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-aria-hidden-on-focusable.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-aria-hidden-on-focusable.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-aria-hidden-on-focusable.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,47 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isFocusable = _interopRequireDefault(require("../util/isFocusable"));
+var _schemas = require("../util/schemas");
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce aria-hidden is not used on interactive elements or contain interactive elements.
+ * @author Kate Higa
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-aria-hidden-on-focusable.md',
+      description: 'Disallow `aria-hidden="true"` from being set on focusable elements.'
+    },
+    schema: [schema]
+  },
+  create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement(node) {
+        var attributes = node.attributes;
+        var type = elementType(node);
+        var isAriaHidden = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(attributes, 'aria-hidden')) === true;
+        if (isAriaHidden && (0, _isFocusable["default"])(type, attributes)) {
+          context.report({
+            node,
+            message: 'aria-hidden="true" must not be set on focusable elements.'
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-autofocus.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-autofocus.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-autofocus.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,62 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _ariaQuery = require("aria-query");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce autoFocus prop is not used.
+ * @author Ethan Cohen <@evcohen>
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'The autoFocus prop should not be used, as it can reduce usability and accessibility for users.';
+var schema = (0, _schemas.generateObjSchema)({
+  ignoreNonDOM: {
+    type: 'boolean',
+    "default": false
+  }
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md',
+      description: 'Enforce autoFocus prop is not used.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        // Determine if ignoreNonDOM is set to true
+        // If true, then do not run rule.
+        var options = context.options[0] || {};
+        var ignoreNonDOM = !!options.ignoreNonDOM;
+        if (ignoreNonDOM) {
+          var type = elementType(attribute.parent);
+          if (!_ariaQuery.dom.get(type)) {
+            return;
+          }
+        }
+
+        // Don't normalize, since React only recognizes autoFocus on low-level DOM elements.
+        if ((0, _jsxAstUtils.propName)(attribute) === 'autoFocus') {
+          context.report({
+            node: attribute,
+            message: errorMessage
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-distracting-elements.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-distracting-elements.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-distracting-elements.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce distracting elements are not used.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = function errorMessage(element) {
+  return "Do not use <".concat(element, "> elements as they can create visual accessibility issues and are deprecated.");
+};
+var DEFAULT_ELEMENTS = ['marquee', 'blink'];
+var schema = (0, _schemas.generateObjSchema)({
+  elements: (0, _schemas.enumArraySchema)(DEFAULT_ELEMENTS)
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-distracting-elements.md',
+      description: 'Enforce distracting elements are not used.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var options = context.options[0] || {};
+        var elementOptions = options.elements || DEFAULT_ELEMENTS;
+        var type = elementType(node);
+        var distractingElement = elementOptions.find(function (element) {
+          return type === element;
+        });
+        if (distractingElement) {
+          context.report({
+            node,
+            message: errorMessage(distractingElement)
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-interactive-element-to-noninteractive-role.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-interactive-element-to-noninteractive-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-interactive-element-to-noninteractive-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,81 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _hasown = _interopRequireDefault(require("hasown"));
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+var _isNonInteractiveRole = _interopRequireDefault(require("../util/isNonInteractiveRole"));
+var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Disallow inherently interactive elements to be assigned
+ * non-interactive roles.
+ * @author Jesse Beach
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Interactive elements should not be assigned non-interactive roles.';
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-interactive-element-to-noninteractive-role.md',
+      description: 'Interactive elements should not be assigned non-interactive roles.'
+    },
+    schema: [{
+      type: 'object',
+      additionalProperties: {
+        type: 'array',
+        items: {
+          type: 'string'
+        },
+        uniqueItems: true
+      }
+    }]
+  },
+  create: function create(context) {
+    var options = context.options;
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        var attributeName = (0, _jsxAstUtils.propName)(attribute);
+        // $FlowFixMe: [TODO] Mark propName as a JSXIdentifier, not a string.
+        if (attributeName !== 'role') {
+          return;
+        }
+        var node = attribute.parent;
+        var attributes = node.attributes;
+        var type = elementType(node);
+        var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'role'));
+        if (!_ariaQuery.dom.has(type)) {
+          // Do not test higher level JSX components, as we do not know what
+          // low-level DOM element this maps to.
+          return;
+        }
+        // Allow overrides from rule configuration for specific elements and
+        // roles.
+        var allowedRoles = options[0] || {};
+        if ((0, _hasown["default"])(allowedRoles, type) && (0, _arrayIncludes["default"])(allowedRoles[type], role)) {
+          return;
+        }
+        if ((0, _isInteractiveElement["default"])(type, attributes) && ((0, _isNonInteractiveRole["default"])(type, attributes) || (0, _isPresentationRole["default"])(type, attributes))) {
+          // Visible, non-interactive elements should not have an interactive handler.
+          context.report({
+            node: attribute,
+            message: errorMessage
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-element-interactions.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-element-interactions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-element-interactions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _hasown = _interopRequireDefault(require("hasown"));
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isAbstractRole = _interopRequireDefault(require("../util/isAbstractRole"));
+var _isContentEditable = _interopRequireDefault(require("../util/isContentEditable"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
+var _isNonInteractiveElement = _interopRequireDefault(require("../util/isNonInteractiveElement"));
+var _isNonInteractiveRole = _interopRequireDefault(require("../util/isNonInteractiveRole"));
+var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce non-interactive elements have no interactive handlers.
+ * @author Jese Beach
+ * 
+ */
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Non-interactive elements should not be assigned mouse or keyboard event listeners.';
+var defaultInteractiveProps = [].concat(_jsxAstUtils.eventHandlersByType.focus, _jsxAstUtils.eventHandlersByType.image, _jsxAstUtils.eventHandlersByType.keyboard, _jsxAstUtils.eventHandlersByType.mouse);
+var schema = (0, _schemas.generateObjSchema)({
+  handlers: _schemas.arraySchema
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md',
+      description: 'Non-interactive elements should not be assigned mouse or keyboard event listeners.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var options = context.options;
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function (_JSXOpeningElement) {
+        function JSXOpeningElement(_x) {
+          return _JSXOpeningElement.apply(this, arguments);
+        }
+        JSXOpeningElement.toString = function () {
+          return _JSXOpeningElement.toString();
+        };
+        return JSXOpeningElement;
+      }(function (node) {
+        var attributes = node.attributes;
+        var type = elementType(node);
+        var config = options[0] || {};
+        var interactiveProps = config.handlers || defaultInteractiveProps;
+        // Allow overrides from rule configuration for specific elements and roles.
+        if ((0, _hasown["default"])(config, type)) {
+          attributes = attributes.filter(function (attr) {
+            return attr.type !== 'JSXSpreadAttribute' && !(0, _arrayIncludes["default"])(config[type], (0, _jsxAstUtils.propName)(attr));
+          });
+        }
+        var hasInteractiveProps = interactiveProps.some(function (prop) {
+          return (0, _jsxAstUtils.hasProp)(attributes, prop) && (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(attributes, prop)) != null;
+        });
+        if (!_ariaQuery.dom.has(type)) {
+          // Do not test higher level JSX components, as we do not know what
+          // low-level DOM element this maps to.
+          return;
+        }
+        if (!hasInteractiveProps || (0, _isContentEditable["default"])(type, attributes) || (0, _isHiddenFromScreenReader["default"])(type, attributes) || (0, _isPresentationRole["default"])(type, attributes)) {
+          // Presentation is an intentional signal from the author that this
+          // element is not meant to be perceivable. For example, a click screen
+          // to close a dialog .
+          return;
+        }
+        if ((0, _isInteractiveElement["default"])(type, attributes) || (0, _isInteractiveRole["default"])(type, attributes) || !(0, _isNonInteractiveElement["default"])(type, attributes) && !(0, _isNonInteractiveRole["default"])(type, attributes) || (0, _isAbstractRole["default"])(type, attributes)) {
+          // This rule has no opinion about abtract roles.
+          return;
+        }
+
+        // Visible, non-interactive elements should not have an interactive handler.
+        context.report({
+          node,
+          message: errorMessage
+        });
+      })
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-element-to-interactive-role.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-element-to-interactive-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-element-to-interactive-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,80 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _hasown = _interopRequireDefault(require("hasown"));
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _getExplicitRole = _interopRequireDefault(require("../util/getExplicitRole"));
+var _isNonInteractiveElement = _interopRequireDefault(require("../util/isNonInteractiveElement"));
+var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Disallow inherently non-interactive elements to be assigned
+ * interactive roles.
+ * @author Jesse Beach
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Non-interactive elements should not be assigned interactive roles.';
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-to-interactive-role.md',
+      description: 'Non-interactive elements should not be assigned interactive roles.'
+    },
+    schema: [{
+      type: 'object',
+      additionalProperties: {
+        type: 'array',
+        items: {
+          type: 'string'
+        },
+        uniqueItems: true
+      }
+    }]
+  },
+  create: function create(context) {
+    var options = context.options;
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        var attributeName = (0, _jsxAstUtils.propName)(attribute);
+        // $FlowFixMe: [TODO] Mark propName as a JSXIdentifier, not a string.
+        if (attributeName !== 'role') {
+          return;
+        }
+        var node = attribute.parent;
+        var attributes = node.attributes;
+        var type = elementType(node);
+        var role = (0, _getExplicitRole["default"])(type, node.attributes);
+        if (!_ariaQuery.dom.has(type)) {
+          // Do not test higher level JSX components, as we do not know what
+          // low-level DOM element this maps to.
+          return;
+        }
+        // Allow overrides from rule configuration for specific elements and
+        // roles.
+        var allowedRoles = options[0] || {};
+        if ((0, _hasown["default"])(allowedRoles, type) && (0, _arrayIncludes["default"])(allowedRoles[type], role)) {
+          return;
+        }
+        if ((0, _isNonInteractiveElement["default"])(type, attributes) && (0, _isInteractiveRole["default"])(type, attributes)) {
+          context.report({
+            node: attribute,
+            message: errorMessage
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-tabindex.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-tabindex.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-noninteractive-tabindex.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,108 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
+var _isNonLiteralProperty = _interopRequireDefault(require("../util/isNonLiteralProperty"));
+var _schemas = require("../util/schemas");
+var _getTabIndex = _interopRequireDefault(require("../util/getTabIndex"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
+function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
+function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
+function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
+function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
+ * @fileoverview Disallow tabindex on static and noninteractive elements
+ * @author jessebeach
+ * 
+ */ // ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+var errorMessage = '`tabIndex` should only be declared on interactive elements.';
+var schema = (0, _schemas.generateObjSchema)({
+  roles: _objectSpread(_objectSpread({}, _schemas.arraySchema), {}, {
+    description: 'An array of ARIA roles'
+  }),
+  tags: _objectSpread(_objectSpread({}, _schemas.arraySchema), {}, {
+    description: 'An array of HTML tag names'
+  })
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-tabindex.md',
+      description: '`tabIndex` should only be declared on interactive elements.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var options = context.options;
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function (_JSXOpeningElement) {
+        function JSXOpeningElement(_x) {
+          return _JSXOpeningElement.apply(this, arguments);
+        }
+        JSXOpeningElement.toString = function () {
+          return _JSXOpeningElement.toString();
+        };
+        return JSXOpeningElement;
+      }(function (node) {
+        var type = elementType(node);
+        var attributes = node.attributes;
+        var tabIndexProp = (0, _jsxAstUtils.getProp)(attributes, 'tabIndex');
+        var tabIndex = (0, _getTabIndex["default"])(tabIndexProp);
+        // Early return;
+        if (typeof tabIndex === 'undefined') {
+          return;
+        }
+        var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'role'));
+        if (!_ariaQuery.dom.has(type)) {
+          // Do not test higher level JSX components, as we do not know what
+          // low-level DOM element this maps to.
+          return;
+        }
+        // Allow for configuration overrides.
+        var _ref = options[0] || {},
+          tags = _ref.tags,
+          roles = _ref.roles,
+          allowExpressionValues = _ref.allowExpressionValues;
+        if (tags && (0, _arrayIncludes["default"])(tags, type)) {
+          return;
+        }
+        if (roles && (0, _arrayIncludes["default"])(roles, role)) {
+          return;
+        }
+        if (allowExpressionValues === true && (0, _isNonLiteralProperty["default"])(attributes, 'role')) {
+          // Special case if role is assigned using ternary with literals on both side
+          var roleProp = (0, _jsxAstUtils.getProp)(attributes, 'role');
+          if (roleProp && roleProp.type === 'JSXAttribute' && roleProp.value.type === 'JSXExpressionContainer') {
+            if (roleProp.value.expression.type === 'ConditionalExpression') {
+              if (roleProp.value.expression.consequent.type === 'Literal' && roleProp.value.expression.alternate.type === 'Literal') {
+                return;
+              }
+            }
+          }
+          return;
+        }
+        if ((0, _isInteractiveElement["default"])(type, attributes) || (0, _isInteractiveRole["default"])(type, attributes)) {
+          return;
+        }
+        if (tabIndex >= 0) {
+          context.report({
+            node: tabIndexProp,
+            message: errorMessage
+          });
+        }
+      })
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-onchange.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-onchange.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-onchange.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce usage of onBlur over onChange for accessibility.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'onBlur must be used instead of onchange, unless absolutely necessary and it causes no negative consequences for keyboard only or screen reader users.';
+var applicableTypes = ['select', 'option'];
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-onchange.md',
+      description: 'Enforce usage of `onBlur` over `onChange` on select menus for accessibility.'
+    },
+    deprecated: true,
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var nodeType = elementType(node);
+        if (applicableTypes.indexOf(nodeType) === -1) {
+          return;
+        }
+        var onChange = (0, _jsxAstUtils.getProp)(node.attributes, 'onChange');
+        var hasOnBlur = (0, _jsxAstUtils.getProp)(node.attributes, 'onBlur') !== undefined;
+        if (onChange && !hasOnBlur) {
+          context.report({
+            node,
+            message: errorMessage
+          });
+        }
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-redundant-roles.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-redundant-roles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-redundant-roles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,86 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _hasown = _interopRequireDefault(require("hasown"));
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _getExplicitRole = _interopRequireDefault(require("../util/getExplicitRole"));
+var _getImplicitRole = _interopRequireDefault(require("../util/getImplicitRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce explicit role property is not the
+ * same as implicit/default role property on element.
+ * @author Ethan Cohen <@evcohen>
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = function errorMessage(element, implicitRole) {
+  return "The element ".concat(element, " has an implicit role of ").concat(implicitRole, ". Defining this explicitly is redundant and should be avoided.");
+};
+var DEFAULT_ROLE_EXCEPTIONS = {
+  nav: ['navigation']
+};
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-redundant-roles.md',
+      description: 'Enforce explicit role property is not the same as implicit/default role property on element.'
+    },
+    schema: [{
+      type: 'object',
+      additionalProperties: {
+        type: 'array',
+        items: {
+          type: 'string'
+        },
+        uniqueItems: true
+      }
+    }]
+  },
+  create: function create(context) {
+    var options = context.options;
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function (_JSXOpeningElement) {
+        function JSXOpeningElement(_x) {
+          return _JSXOpeningElement.apply(this, arguments);
+        }
+        JSXOpeningElement.toString = function () {
+          return _JSXOpeningElement.toString();
+        };
+        return JSXOpeningElement;
+      }(function (node) {
+        var type = elementType(node);
+        var implicitRole = (0, _getImplicitRole["default"])(type, node.attributes);
+        var explicitRole = (0, _getExplicitRole["default"])(type, node.attributes);
+        if (!implicitRole || !explicitRole) {
+          return;
+        }
+        if (implicitRole === explicitRole) {
+          var allowedRedundantRoles = options[0] || {};
+          var redundantRolesForElement;
+          if ((0, _hasown["default"])(allowedRedundantRoles, type)) {
+            redundantRolesForElement = allowedRedundantRoles[type];
+          } else {
+            redundantRolesForElement = DEFAULT_ROLE_EXCEPTIONS[type] || [];
+          }
+          if ((0, _arrayIncludes["default"])(redundantRolesForElement, implicitRole)) {
+            return;
+          }
+          context.report({
+            node,
+            message: errorMessage(type, implicitRole.toLowerCase())
+          });
+        }
+      })
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-static-element-interactions.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-static-element-interactions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/no-static-element-interactions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,102 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isAbstractRole = _interopRequireDefault(require("../util/isAbstractRole"));
+var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
+var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
+var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
+var _isNonInteractiveElement = _interopRequireDefault(require("../util/isNonInteractiveElement"));
+var _isNonInteractiveRole = _interopRequireDefault(require("../util/isNonInteractiveRole"));
+var _isNonLiteralProperty = _interopRequireDefault(require("../util/isNonLiteralProperty"));
+var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce static elements have no interactive handlers.
+ * @author Ethan Cohen
+ * 
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive content element.';
+var defaultInteractiveProps = [].concat(_jsxAstUtils.eventHandlersByType.focus, _jsxAstUtils.eventHandlersByType.keyboard, _jsxAstUtils.eventHandlersByType.mouse);
+var schema = (0, _schemas.generateObjSchema)({
+  handlers: _schemas.arraySchema
+});
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-static-element-interactions.md',
+      description: 'Enforce that non-interactive, visible elements (such as `<div>`) that have click handlers use the role attribute.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var options = context.options;
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function (_JSXOpeningElement) {
+        function JSXOpeningElement(_x) {
+          return _JSXOpeningElement.apply(this, arguments);
+        }
+        JSXOpeningElement.toString = function () {
+          return _JSXOpeningElement.toString();
+        };
+        return JSXOpeningElement;
+      }(function (node) {
+        var attributes = node.attributes;
+        var type = elementType(node);
+        var _ref = options[0] || {},
+          allowExpressionValues = _ref.allowExpressionValues,
+          _ref$handlers = _ref.handlers,
+          handlers = _ref$handlers === void 0 ? defaultInteractiveProps : _ref$handlers;
+        var hasInteractiveProps = handlers.some(function (prop) {
+          return (0, _jsxAstUtils.hasProp)(attributes, prop) && (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(attributes, prop)) != null;
+        });
+        if (!_ariaQuery.dom.has(type)) {
+          // Do not test higher level JSX components, as we do not know what
+          // low-level DOM element this maps to.
+          return;
+        }
+        if (!hasInteractiveProps || (0, _isHiddenFromScreenReader["default"])(type, attributes) || (0, _isPresentationRole["default"])(type, attributes)) {
+          // Presentation is an intentional signal from the author that this
+          // element is not meant to be perceivable. For example, a click screen
+          // to close a dialog .
+          return;
+        }
+        if ((0, _isInteractiveElement["default"])(type, attributes) || (0, _isInteractiveRole["default"])(type, attributes) || (0, _isNonInteractiveElement["default"])(type, attributes) || (0, _isNonInteractiveRole["default"])(type, attributes) || (0, _isAbstractRole["default"])(type, attributes)) {
+          // This rule has no opinion about abstract roles.
+          return;
+        }
+        if (allowExpressionValues === true && (0, _isNonLiteralProperty["default"])(attributes, 'role')) {
+          // Special case if role is assigned using ternary with literals on both side
+          var roleProp = (0, _jsxAstUtils.getProp)(attributes, 'role');
+          if (roleProp && roleProp.type === 'JSXAttribute' && roleProp.value.type === 'JSXExpressionContainer') {
+            if (roleProp.value.expression.type === 'ConditionalExpression') {
+              if (roleProp.value.expression.consequent.type === 'Literal' && roleProp.value.expression.alternate.type === 'Literal') {
+                return;
+              }
+            }
+          }
+          return;
+        }
+
+        // Visible, non-interactive elements should not have an interactive handler.
+        context.report({
+          node,
+          message: errorMessage
+        });
+      })
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/prefer-tag-over-role.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/prefer-tag-over-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/prefer-tag-over-role.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,75 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _schemas = require("../util/schemas");
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
+function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
+function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
+function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
+function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
+var errorMessage = 'Use {{tag}} instead of the "{{role}}" role to ensure accessibility across all devices.';
+var schema = (0, _schemas.generateObjSchema)();
+var formatTag = function formatTag(tag) {
+  if (!tag.attributes) {
+    return "<".concat(tag.name, ">");
+  }
+  var _tag$attributes = _slicedToArray(tag.attributes, 1),
+    attribute = _tag$attributes[0];
+  var value = attribute.value ? "\"".concat(attribute.value, "\"") : '...';
+  return "<".concat(tag.name, " ").concat(attribute.name, "=").concat(value, ">");
+};
+var getLastPropValue = function getLastPropValue(rawProp) {
+  var propValue = (0, _jsxAstUtils.getPropValue)(rawProp);
+  if (!propValue) {
+    return propValue;
+  }
+  var lastSpaceIndex = propValue.lastIndexOf(' ');
+  return lastSpaceIndex === -1 ? propValue : propValue.substring(lastSpaceIndex + 1);
+};
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      description: 'Enforces using semantic DOM elements over the ARIA `role` property.',
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/prefer-tag-over-role.md'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement: function JSXOpeningElement(node) {
+        var role = getLastPropValue((0, _jsxAstUtils.getProp)(node.attributes, 'role'));
+        if (!role) {
+          return;
+        }
+        var matchedTagsSet = _ariaQuery.roleElements.get(role);
+        if (!matchedTagsSet) {
+          return;
+        }
+        var matchedTags = Array.from(matchedTagsSet);
+        if (matchedTags.some(function (matchedTag) {
+          return matchedTag.name === elementType(node);
+        })) {
+          return;
+        }
+        context.report({
+          data: {
+            tag: matchedTags.length === 1 ? formatTag(matchedTags[0]) : [matchedTags.slice(0, matchedTags.length - 1).map(formatTag).join(', '), formatTag(matchedTags[matchedTags.length - 1])].join(', or '),
+            role
+          },
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/role-has-required-aria-props.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/role-has-required-aria-props.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/role-has-required-aria-props.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,88 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _isSemanticRoleElement = _interopRequireDefault(require("../util/isSemanticRoleElement"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce that elements with ARIA roles must
+ *  have all required attributes for that role.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = function errorMessage(role, requiredProps) {
+  return "Elements with the ARIA role \"".concat(role, "\" must have the following attributes defined: ").concat(String(requiredProps).toLowerCase());
+};
+var schema = (0, _schemas.generateObjSchema)();
+var roleKeys = _ariaQuery.roles.keys();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-has-required-aria-props.md',
+      description: 'Enforce that elements with ARIA roles must have all required attributes for that role.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        var name = (0, _jsxAstUtils.propName)(attribute).toLowerCase();
+        if (name !== 'role') {
+          return;
+        }
+        var type = elementType(attribute.parent);
+        if (!_ariaQuery.dom.get(type)) {
+          return;
+        }
+        var roleAttrValue = (0, _jsxAstUtils.getLiteralPropValue)(attribute);
+        var attributes = attribute.parent.attributes;
+
+        // If value is undefined, then the role attribute will be dropped in the DOM.
+        // If value is null, then getLiteralAttributeValue is telling us
+        // that the value isn't in the form of a literal.
+        if (roleAttrValue === undefined || roleAttrValue === null) {
+          return;
+        }
+        var normalizedValues = String(roleAttrValue).toLowerCase().split(' ');
+        var validRoles = normalizedValues.filter(function (val) {
+          return roleKeys.indexOf(val) > -1;
+        });
+
+        // Check semantic DOM elements
+        // For example, <input type="checkbox" role="switch" />
+        if ((0, _isSemanticRoleElement["default"])(type, attributes)) {
+          return;
+        }
+        // Check arbitrary DOM elements
+        validRoles.forEach(function (role) {
+          var _roles$get = _ariaQuery.roles.get(role),
+            requiredPropKeyValues = _roles$get.requiredProps;
+          var requiredProps = Object.keys(requiredPropKeyValues);
+          if (requiredProps.length > 0) {
+            var hasRequiredProps = requiredProps.every(function (prop) {
+              return (0, _jsxAstUtils.getProp)(attributes, prop);
+            });
+            if (hasRequiredProps === false) {
+              context.report({
+                node: attribute,
+                message: errorMessage(role.toLowerCase(), requiredProps)
+              });
+            }
+          }
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/role-supports-aria-props.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/role-supports-aria-props.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/role-supports-aria-props.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,78 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+var _getImplicitRole = _interopRequireDefault(require("../util/getImplicitRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce that elements with explicit or implicit roles defined contain only
+ * `aria-*` properties supported by that `role`.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = function errorMessage(attr, role, tag, isImplicit) {
+  if (isImplicit) {
+    return "The attribute ".concat(attr, " is not supported by the role ").concat(role, ". This role is implicit on the element ").concat(tag, ".");
+  }
+  return "The attribute ".concat(attr, " is not supported by the role ").concat(role, ".");
+};
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/role-supports-aria-props.md',
+      description: 'Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`.'
+    },
+    schema: [schema]
+  },
+  create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXOpeningElement(node) {
+        // If role is not explicitly defined, then try and get its implicit role.
+        var type = elementType(node);
+        var role = (0, _jsxAstUtils.getProp)(node.attributes, 'role');
+        var roleValue = role ? (0, _jsxAstUtils.getLiteralPropValue)(role) : (0, _getImplicitRole["default"])(type, node.attributes);
+        var isImplicit = roleValue && role === undefined;
+
+        // If there is no explicit or implicit role, then assume that the element
+        // can handle the global set of aria-* properties.
+        // This actually isn't true - should fix in future release.
+        if (typeof roleValue !== 'string' || _ariaQuery.roles.get(roleValue) === undefined) {
+          return;
+        }
+
+        // Make sure it has no aria-* properties defined outside its property set.
+        var _roles$get = _ariaQuery.roles.get(roleValue),
+          propKeyValues = _roles$get.props;
+        var invalidAriaPropsForRole = new Set(_ariaQuery.aria.keys().filter(function (attribute) {
+          return !(attribute in propKeyValues);
+        }));
+        node.attributes.filter(function (prop) {
+          return (0, _jsxAstUtils.getPropValue)(prop) != null // Ignore the attribute if its value is null or undefined.
+          && prop.type !== 'JSXSpreadAttribute' // Ignore the attribute if it's a spread.
+          ;
+        }).forEach(function (prop) {
+          var name = (0, _jsxAstUtils.propName)(prop);
+          if (invalidAriaPropsForRole.has(name)) {
+            context.report({
+              node,
+              message: errorMessage(name, roleValue, type, isImplicit)
+            });
+          }
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/scope.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/scope.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/scope.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,58 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+var _getElementType = _interopRequireDefault(require("../util/getElementType"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * @fileoverview Enforce scope prop is only used on <th> elements.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'The scope prop can only be used on <th> elements.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/scope.md',
+      description: 'Enforce `scope` prop is only used on `<th>` elements.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    var elementType = (0, _getElementType["default"])(context);
+    return {
+      JSXAttribute: function JSXAttribute(node) {
+        var name = (0, _jsxAstUtils.propName)(node);
+        if (name && name.toUpperCase() !== 'SCOPE') {
+          return;
+        }
+        var parent = node.parent;
+        var tagName = elementType(parent);
+
+        // Do not test higher level JSX components, as we do not know what
+        // low-level DOM element this maps to.
+        if (!_ariaQuery.dom.has(tagName)) {
+          return;
+        }
+        if (tagName && tagName.toUpperCase() === 'TH') {
+          return;
+        }
+        context.report({
+          node,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/tabindex-no-positive.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/tabindex-no-positive.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/rules/tabindex-no-positive.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,53 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _schemas = require("../util/schemas");
+/**
+ * @fileoverview Enforce tabIndex value is not greater than zero.
+ * @author Ethan Cohen
+ */
+
+// ----------------------------------------------------------------------------
+// Rule Definition
+// ----------------------------------------------------------------------------
+
+var errorMessage = 'Avoid positive integer values for tabIndex.';
+var schema = (0, _schemas.generateObjSchema)();
+var _default = exports["default"] = {
+  meta: {
+    docs: {
+      url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/tabindex-no-positive.md',
+      description: 'Enforce `tabIndex` value is not greater than zero.'
+    },
+    schema: [schema]
+  },
+  create: function create(context) {
+    return {
+      JSXAttribute: function JSXAttribute(attribute) {
+        var name = (0, _jsxAstUtils.propName)(attribute).toUpperCase();
+
+        // Check if tabIndex is the attribute
+        if (name !== 'TABINDEX') {
+          return;
+        }
+
+        // Only check literals because we can't infer values from certain expressions.
+        var value = Number((0, _jsxAstUtils.getLiteralPropValue)(attribute));
+
+        // eslint-disable-next-line no-restricted-globals
+        if (isNaN(value) || value <= 0) {
+          return;
+        }
+        context.report({
+          node: attribute,
+          message: errorMessage
+        });
+      }
+    };
+  }
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/attributesComparator.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/attributesComparator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/attributesComparator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,34 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns true if all items in baseAttributes are found in attributes. Always
+ * returns true if baseAttributes is empty.
+ */
+function attributesComparator() {
+  var baseAttributes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
+  var attributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
+  return baseAttributes.every(function (baseAttr) {
+    return attributes.some(function (attribute) {
+      // Guard against non-JSXAttribute nodes like JSXSpreadAttribute
+      if (attribute.type !== 'JSXAttribute') {
+        return false;
+      }
+      // Attribute matches.
+      if (baseAttr.name !== (0, _jsxAstUtils.propName)(attribute)) {
+        return false;
+      }
+      // Value exists and does not match.
+      if (baseAttr.value && baseAttr.value !== (0, _jsxAstUtils.getLiteralPropValue)(attribute)) {
+        return false;
+      }
+      return true;
+    });
+  });
+}
+var _default = exports["default"] = attributesComparator;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getAccessibleChildText.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getAccessibleChildText.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getAccessibleChildText.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,55 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getAccessibleChildText;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _isHiddenFromScreenReader = _interopRequireDefault(require("./isHiddenFromScreenReader"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * Returns a new "standardized" string: all whitespace is collapsed to one space,
+ * and the string is lowercase
+ * @param {string} input
+ * @returns lowercase, single-spaced, punctuation-stripped, trimmed string
+ */
+function standardizeSpaceAndCase(input) {
+  return input.trim().replace(/[,.?¿!‽¡;:]/g, '') // strip punctuation
+  .replace(/\s\s+/g, ' ') // collapse spaces
+  .toLowerCase();
+}
+
+/**
+ * Returns the (recursively-defined) accessible child text of a node, which (in-order) is:
+ * 1. The element's aria-label
+ * 2. If the element is a direct literal, the literal value
+ * 3. Otherwise, merge all of its children
+ * @param {JSXElement} node - node to traverse
+ * @returns child text as a string
+ */
+function getAccessibleChildText(node, elementType) {
+  var ariaLabel = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.openingElement.attributes, 'aria-label'));
+  // early escape-hatch when aria-label is applied
+  if (ariaLabel) return standardizeSpaceAndCase(ariaLabel);
+
+  // early-return if alt prop exists and is an image
+  var altTag = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.openingElement.attributes, 'alt'));
+  if (elementType(node.openingElement) === 'img' && altTag) return standardizeSpaceAndCase(altTag);
+
+  // skip if aria-hidden is true
+  if ((0, _isHiddenFromScreenReader["default"])(elementType(node.openingElement), node.openingElement.attributes)) {
+    return '';
+  }
+  var rawChildText = node.children.map(function (currentNode) {
+    // $FlowFixMe JSXText is missing in ast-types-flow
+    if (currentNode.type === 'Literal' || currentNode.type === 'JSXText') {
+      return String(currentNode.value);
+    }
+    if (currentNode.type === 'JSXElement') {
+      return getAccessibleChildText(currentNode, elementType);
+    }
+    return '';
+  }).join(' ');
+  return standardizeSpaceAndCase(rawChildText);
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getComputedRole.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getComputedRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getComputedRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,19 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getComputedRole;
+var _getExplicitRole = _interopRequireDefault(require("./getExplicitRole"));
+var _getImplicitRole = _interopRequireDefault(require("./getImplicitRole"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * Returns an element's computed role, which is
+ *
+ *  1. The valid value of its explicit role attribute; or
+ *  2. The implicit value of its tag.
+ */
+function getComputedRole(tag, attributes) {
+  return (0, _getExplicitRole["default"])(tag, attributes) || (0, _getImplicitRole["default"])(tag, attributes);
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getElementType.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getElementType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getElementType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _hasown = _interopRequireDefault(require("hasown"));
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _jsxAstUtils = require("jsx-ast-utils");
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+var getElementType = function getElementType(context) {
+  var _settings$jsxA11y, _settings$jsxA11y2, _settings$jsxA11y3;
+  var settings = context.settings;
+  var polymorphicPropName = (_settings$jsxA11y = settings['jsx-a11y']) === null || _settings$jsxA11y === void 0 ? void 0 : _settings$jsxA11y.polymorphicPropName;
+  var polymorphicAllowList = (_settings$jsxA11y2 = settings['jsx-a11y']) === null || _settings$jsxA11y2 === void 0 ? void 0 : _settings$jsxA11y2.polymorphicAllowList;
+  var componentMap = (_settings$jsxA11y3 = settings['jsx-a11y']) === null || _settings$jsxA11y3 === void 0 ? void 0 : _settings$jsxA11y3.components;
+  return function (node) {
+    var polymorphicProp = polymorphicPropName ? (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, polymorphicPropName)) : undefined;
+    var rawType = (0, _jsxAstUtils.elementType)(node);
+    if (polymorphicProp && (!polymorphicAllowList || (0, _arrayIncludes["default"])(polymorphicAllowList, rawType))) {
+      rawType = polymorphicProp;
+    }
+    if (!componentMap) {
+      return rawType;
+    }
+    return (0, _hasown["default"])(componentMap, rawType) ? componentMap[rawType] : rawType;
+  };
+};
+var _default = exports["default"] = getElementType;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getExplicitRole.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getExplicitRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getExplicitRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,27 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getExplicitRole;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns an element's computed role, which is
+ *
+ *  1. The valid value of its explicit role attribute; or
+ *  2. The implicit value of its tag.
+ */
+function getExplicitRole(tag, attributes) {
+  var explicitRole = function toLowerCase(role) {
+    if (typeof role === 'string') {
+      return role.toLowerCase();
+    }
+    return null;
+  }((0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role')));
+  if (_ariaQuery.roles.has(explicitRole)) {
+    return explicitRole;
+  }
+  return null;
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getImplicitRole.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getImplicitRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getImplicitRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,24 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRole;
+var _ariaQuery = require("aria-query");
+var _implicitRoles = _interopRequireDefault(require("./implicitRoles"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * Returns an element's implicit role given its attributes and type.
+ * Some elements only have an implicit role when certain props are defined.
+ */
+function getImplicitRole(type, attributes) {
+  var implicitRole;
+  if (_implicitRoles["default"][type]) {
+    implicitRole = _implicitRoles["default"][type](attributes);
+  }
+  if (_ariaQuery.roles.has(implicitRole)) {
+    return implicitRole;
+  }
+  return null;
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getSuggestion.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getSuggestion.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getSuggestion.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getSuggestion;
+var _damerauLevenshtein = _interopRequireDefault(require("damerau-levenshtein"));
+var _object = _interopRequireDefault(require("object.fromentries"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+// Minimum edit distance to be considered a good suggestion.
+var THRESHOLD = 2;
+
+/**
+ * Returns an array of suggestions given a word and a dictionary and limit of suggestions
+ * to return.
+ */
+function getSuggestion(word) {
+  var dictionary = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
+  var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 2;
+  var distances = (0, _object["default"])(dictionary.map(function (dictionaryWord) {
+    var distance = (0, _damerauLevenshtein["default"])(word.toUpperCase(), dictionaryWord.toUpperCase());
+    var steps = distance.steps;
+    return [dictionaryWord, steps];
+  }));
+  return Object.keys(distances).filter(function (suggestion) {
+    return distances[suggestion] <= THRESHOLD;
+  }).sort(function (a, b) {
+    return distances[a] - distances[b];
+  }) // Sort by distance
+  .slice(0, limit);
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getTabIndex.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getTabIndex.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/getTabIndex.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,33 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getTabIndex;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the tabIndex value.
+ */
+function getTabIndex(tabIndex) {
+  var literalValue = (0, _jsxAstUtils.getLiteralPropValue)(tabIndex);
+
+  // String and number values.
+  if (['string', 'number'].indexOf(typeof literalValue) > -1) {
+    // Empty string will convert to zero, so check for it explicity.
+    if (typeof literalValue === 'string' && literalValue.length === 0) {
+      return undefined;
+    }
+    var value = Number(literalValue);
+    if (Number.isNaN(value)) {
+      return undefined;
+    }
+    return Number.isInteger(value) ? value : undefined;
+  }
+
+  // Booleans are not valid values, return undefined.
+  if (literalValue === true || literalValue === false) {
+    return undefined;
+  }
+  return (0, _jsxAstUtils.getPropValue)(tabIndex);
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/hasAccessibleChild.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/hasAccessibleChild.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/hasAccessibleChild.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = hasAccessibleChild;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _isHiddenFromScreenReader = _interopRequireDefault(require("./isHiddenFromScreenReader"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+function hasAccessibleChild(node, elementType) {
+  return node.children.some(function (child) {
+    switch (child.type) {
+      case 'Literal':
+        return !!child.value;
+      // $FlowFixMe JSXText is missing in ast-types-flow
+      case 'JSXText':
+        return !!child.value;
+      case 'JSXElement':
+        return !(0, _isHiddenFromScreenReader["default"])(elementType(child.openingElement), child.openingElement.attributes);
+      case 'JSXExpressionContainer':
+        if (child.expression.type === 'Identifier') {
+          return child.expression.name !== 'undefined';
+        }
+        return true;
+      default:
+        return false;
+    }
+  }) || (0, _jsxAstUtils.hasAnyProp)(node.openingElement.attributes, ['dangerouslySetInnerHTML', 'children']);
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/a.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/a.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/a.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForAnchor;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the implicit role for an anchor tag.
+ */
+function getImplicitRoleForAnchor(attributes) {
+  if ((0, _jsxAstUtils.getProp)(attributes, 'href')) {
+    return 'link';
+  }
+  return '';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/area.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/area.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/area.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForArea;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the implicit role for an area tag.
+ */
+function getImplicitRoleForArea(attributes) {
+  if ((0, _jsxAstUtils.getProp)(attributes, 'href')) {
+    return 'link';
+  }
+  return '';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/article.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/article.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/article.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForArticle;
+/**
+ * Returns the implicit role for an article tag.
+ */
+function getImplicitRoleForArticle() {
+  return 'article';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/aside.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/aside.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/aside.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForAside;
+/**
+ * Returns the implicit role for an aside tag.
+ */
+function getImplicitRoleForAside() {
+  return 'complementary';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/body.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/body.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/body.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForBody;
+/**
+ * Returns the implicit role for a body tag.
+ */
+function getImplicitRoleForBody() {
+  return 'document';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/button.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/button.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/button.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForButton;
+/**
+ * Returns the implicit role for a button tag.
+ */
+function getImplicitRoleForButton() {
+  return 'button';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/datalist.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/datalist.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/datalist.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForDatalist;
+/**
+ * Returns the implicit role for a datalist tag.
+ */
+function getImplicitRoleForDatalist() {
+  return 'listbox';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/details.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/details.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/details.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForDetails;
+/**
+ * Returns the implicit role for a details tag.
+ */
+function getImplicitRoleForDetails() {
+  return 'group';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/dialog.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/dialog.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/dialog.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForDialog;
+/**
+ * Returns the implicit role for a dialog tag.
+ */
+function getImplicitRoleForDialog() {
+  return 'dialog';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/form.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/form.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/form.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForForm;
+/**
+ * Returns the implicit role for a form tag.
+ */
+function getImplicitRoleForForm() {
+  return 'form';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h1.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h1.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h1.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForH1;
+/**
+ * Returns the implicit role for an h1 tag.
+ */
+function getImplicitRoleForH1() {
+  return 'heading';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h2.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h2.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h2.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForH2;
+/**
+ * Returns the implicit role for an h2 tag.
+ */
+function getImplicitRoleForH2() {
+  return 'heading';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h3.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h3.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h3.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForH3;
+/**
+ * Returns the implicit role for an h3 tag.
+ */
+function getImplicitRoleForH3() {
+  return 'heading';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h4.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h4.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h4.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForH4;
+/**
+ * Returns the implicit role for an h4 tag.
+ */
+function getImplicitRoleForH4() {
+  return 'heading';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h5.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h5.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h5.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForH5;
+/**
+ * Returns the implicit role for an h5 tag.
+ */
+function getImplicitRoleForH5() {
+  return 'heading';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h6.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h6.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/h6.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForH6;
+/**
+ * Returns the implicit role for an h6tag.
+ */
+function getImplicitRoleForH6() {
+  return 'heading';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/hr.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/hr.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/hr.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForHr;
+/**
+ * Returns the implicit role for an hr tag.
+ */
+function getImplicitRoleForHr() {
+  return 'separator';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/img.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/img.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/img.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForImg;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the implicit role for an img tag.
+ */
+function getImplicitRoleForImg(attributes) {
+  var _getLiteralPropValue;
+  var alt = (0, _jsxAstUtils.getProp)(attributes, 'alt');
+  if (alt && (0, _jsxAstUtils.getLiteralPropValue)(alt) === '') {
+    return '';
+  }
+
+  /**
+   * If the src attribute can be determined to be an svg, allow the role to be set to 'img'
+   * so that VoiceOver on Safari can be better supported.
+   *
+   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#identifying_svg_as_an_image
+   * @see https://bugs.webkit.org/show_bug.cgi?id=216364
+   */
+  var src = (0, _jsxAstUtils.getProp)(attributes, 'src');
+  if (src && (_getLiteralPropValue = (0, _jsxAstUtils.getLiteralPropValue)(src)) !== null && _getLiteralPropValue !== void 0 && _getLiteralPropValue.includes('.svg')) {
+    return '';
+  }
+  return 'img';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/index.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,82 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _a = _interopRequireDefault(require("./a"));
+var _area = _interopRequireDefault(require("./area"));
+var _article = _interopRequireDefault(require("./article"));
+var _aside = _interopRequireDefault(require("./aside"));
+var _body = _interopRequireDefault(require("./body"));
+var _button = _interopRequireDefault(require("./button"));
+var _datalist = _interopRequireDefault(require("./datalist"));
+var _details = _interopRequireDefault(require("./details"));
+var _dialog = _interopRequireDefault(require("./dialog"));
+var _form = _interopRequireDefault(require("./form"));
+var _h = _interopRequireDefault(require("./h1"));
+var _h2 = _interopRequireDefault(require("./h2"));
+var _h3 = _interopRequireDefault(require("./h3"));
+var _h4 = _interopRequireDefault(require("./h4"));
+var _h5 = _interopRequireDefault(require("./h5"));
+var _h6 = _interopRequireDefault(require("./h6"));
+var _hr = _interopRequireDefault(require("./hr"));
+var _img = _interopRequireDefault(require("./img"));
+var _input = _interopRequireDefault(require("./input"));
+var _li = _interopRequireDefault(require("./li"));
+var _link = _interopRequireDefault(require("./link"));
+var _menu = _interopRequireDefault(require("./menu"));
+var _menuitem = _interopRequireDefault(require("./menuitem"));
+var _meter = _interopRequireDefault(require("./meter"));
+var _nav = _interopRequireDefault(require("./nav"));
+var _ol = _interopRequireDefault(require("./ol"));
+var _option = _interopRequireDefault(require("./option"));
+var _output = _interopRequireDefault(require("./output"));
+var _progress = _interopRequireDefault(require("./progress"));
+var _section = _interopRequireDefault(require("./section"));
+var _select = _interopRequireDefault(require("./select"));
+var _tbody = _interopRequireDefault(require("./tbody"));
+var _textarea = _interopRequireDefault(require("./textarea"));
+var _tfoot = _interopRequireDefault(require("./tfoot"));
+var _thead = _interopRequireDefault(require("./thead"));
+var _ul = _interopRequireDefault(require("./ul"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+var _default = exports["default"] = {
+  a: _a["default"],
+  area: _area["default"],
+  article: _article["default"],
+  aside: _aside["default"],
+  body: _body["default"],
+  button: _button["default"],
+  datalist: _datalist["default"],
+  details: _details["default"],
+  dialog: _dialog["default"],
+  form: _form["default"],
+  h1: _h["default"],
+  h2: _h2["default"],
+  h3: _h3["default"],
+  h4: _h4["default"],
+  h5: _h5["default"],
+  h6: _h6["default"],
+  hr: _hr["default"],
+  img: _img["default"],
+  input: _input["default"],
+  li: _li["default"],
+  link: _link["default"],
+  menu: _menu["default"],
+  menuitem: _menuitem["default"],
+  meter: _meter["default"],
+  nav: _nav["default"],
+  ol: _ol["default"],
+  option: _option["default"],
+  output: _output["default"],
+  progress: _progress["default"],
+  section: _section["default"],
+  select: _select["default"],
+  tbody: _tbody["default"],
+  textarea: _textarea["default"],
+  tfoot: _tfoot["default"],
+  thead: _thead["default"],
+  ul: _ul["default"]
+};
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/input.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/input.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/input.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForInput;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the implicit role for an input tag.
+ */
+function getImplicitRoleForInput(attributes) {
+  var type = (0, _jsxAstUtils.getProp)(attributes, 'type');
+  if (type) {
+    var value = (0, _jsxAstUtils.getLiteralPropValue)(type) || '';
+    switch (typeof value === 'string' && value.toUpperCase()) {
+      case 'BUTTON':
+      case 'IMAGE':
+      case 'RESET':
+      case 'SUBMIT':
+        return 'button';
+      case 'CHECKBOX':
+        return 'checkbox';
+      case 'RADIO':
+        return 'radio';
+      case 'RANGE':
+        return 'slider';
+      case 'EMAIL':
+      case 'PASSWORD':
+      case 'SEARCH': // with [list] selector it's combobox
+      case 'TEL': // with [list] selector it's combobox
+      case 'URL': // with [list] selector it's combobox
+      default:
+        return 'textbox';
+    }
+  }
+  return 'textbox';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/li.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/li.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/li.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForLi;
+/**
+ * Returns the implicit role for an li tag.
+ */
+function getImplicitRoleForLi() {
+  return 'listitem';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/link.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/link.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/link.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForLink;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the implicit role for a link tag.
+ */
+function getImplicitRoleForLink(attributes) {
+  if ((0, _jsxAstUtils.getProp)(attributes, 'href')) {
+    return 'link';
+  }
+  return '';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/menu.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/menu.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/menu.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,19 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForMenu;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the implicit role for a menu tag.
+ */
+function getImplicitRoleForMenu(attributes) {
+  var type = (0, _jsxAstUtils.getProp)(attributes, 'type');
+  if (type) {
+    var value = (0, _jsxAstUtils.getLiteralPropValue)(type);
+    return value && value.toUpperCase() === 'TOOLBAR' ? 'toolbar' : '';
+  }
+  return '';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/menuitem.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/menuitem.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/menuitem.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForMenuitem;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns the implicit role for a menuitem tag.
+ */
+function getImplicitRoleForMenuitem(attributes) {
+  var type = (0, _jsxAstUtils.getProp)(attributes, 'type');
+  if (type) {
+    var value = (0, _jsxAstUtils.getLiteralPropValue)(type) || '';
+    switch (typeof value === 'string' && value.toUpperCase()) {
+      case 'COMMAND':
+        return 'menuitem';
+      case 'CHECKBOX':
+        return 'menuitemcheckbox';
+      case 'RADIO':
+        return 'menuitemradio';
+      default:
+        return '';
+    }
+  }
+  return '';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/meter.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/meter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/meter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForMeter;
+/**
+ * Returns the implicit role for a meter tag.
+ */
+function getImplicitRoleForMeter() {
+  return 'progressbar';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/nav.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/nav.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/nav.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForNav;
+/**
+ * Returns the implicit role for a nav tag.
+ */
+function getImplicitRoleForNav() {
+  return 'navigation';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/ol.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/ol.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/ol.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForOl;
+/**
+ * Returns the implicit role for an ol tag.
+ */
+function getImplicitRoleForOl() {
+  return 'list';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/option.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/option.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/option.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForOption;
+/**
+ * Returns the implicit role for an option tag.
+ */
+function getImplicitRoleForOption() {
+  return 'option';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/output.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/output.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/output.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForOutput;
+/**
+ * Returns the implicit role for an output tag.
+ */
+function getImplicitRoleForOutput() {
+  return 'status';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/progress.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/progress.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/progress.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForProgress;
+/**
+ * Returns the implicit role for a progress tag.
+ */
+function getImplicitRoleForProgress() {
+  return 'progressbar';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/section.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/section.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/section.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForSection;
+/**
+ * Returns the implicit role for a section tag.
+ */
+function getImplicitRoleForSection() {
+  return 'region';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/select.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/select.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/select.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForSelect;
+/**
+ * Returns the implicit role for a select tag.
+ */
+function getImplicitRoleForSelect() {
+  return 'listbox';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/tbody.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/tbody.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/tbody.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForTbody;
+/**
+ * Returns the implicit role for a tbody tag.
+ */
+function getImplicitRoleForTbody() {
+  return 'rowgroup';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/textarea.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/textarea.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/textarea.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForTextarea;
+/**
+ * Returns the implicit role for a textarea tag.
+ */
+function getImplicitRoleForTextarea() {
+  return 'textbox';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/tfoot.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/tfoot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/tfoot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForTfoot;
+/**
+ * Returns the implicit role for a tfoot tag.
+ */
+function getImplicitRoleForTfoot() {
+  return 'rowgroup';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/thead.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/thead.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/thead.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForThead;
+/**
+ * Returns the implicit role for a thead tag.
+ */
+function getImplicitRoleForThead() {
+  return 'rowgroup';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/ul.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/ul.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/implicitRoles/ul.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = getImplicitRoleForUl;
+/**
+ * Returns the implicit role for a ul tag.
+ */
+function getImplicitRoleForUl() {
+  return 'list';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isAbstractRole.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isAbstractRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isAbstractRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,23 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var abstractRoles = new Set(_ariaQuery.roles.keys().filter(function (role) {
+  return _ariaQuery.roles.get(role)["abstract"];
+}));
+var DOMElements = new Set(_ariaQuery.dom.keys());
+var isAbstractRole = function isAbstractRole(tagName, attributes) {
+  // Do not test higher level JSX components, as we do not know what
+  // low-level DOM element this maps to.
+  if (!DOMElements.has(tagName)) {
+    return false;
+  }
+  var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role'));
+  return abstractRoles.has(role);
+};
+var _default = exports["default"] = isAbstractRole;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isContentEditable.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isContentEditable.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isContentEditable.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = isContentEditable;
+var _jsxAstUtils = require("jsx-ast-utils");
+function isContentEditable(tagName, attributes) {
+  var _prop$value;
+  var prop = (0, _jsxAstUtils.getProp)(attributes, 'contentEditable');
+  return (prop === null || prop === void 0 ? void 0 : (_prop$value = prop.value) === null || _prop$value === void 0 ? void 0 : _prop$value.raw) === '"true"';
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isDOMElement.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isDOMElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isDOMElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+/**
+ * Returns boolean indicating whether the given element is a DOM element.
+ */
+var isDOMElement = function isDOMElement(tagName) {
+  return _ariaQuery.dom.has(tagName);
+};
+var _default = exports["default"] = isDOMElement;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isDisabledElement.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isDisabledElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isDisabledElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,23 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var isDisabledElement = function isDisabledElement(attributes) {
+  var disabledAttr = (0, _jsxAstUtils.getProp)(attributes, 'disabled');
+  var disabledAttrValue = (0, _jsxAstUtils.getPropValue)(disabledAttr);
+  var isHTML5Disabled = disabledAttr && disabledAttrValue !== undefined;
+  if (isHTML5Disabled) {
+    return true;
+  }
+  var ariaDisabledAttr = (0, _jsxAstUtils.getProp)(attributes, 'aria-disabled');
+  var ariaDisabledAttrValue = (0, _jsxAstUtils.getLiteralPropValue)(ariaDisabledAttr);
+  if (ariaDisabledAttr && ariaDisabledAttrValue !== undefined && ariaDisabledAttrValue === true) {
+    return true;
+  }
+  return false;
+};
+var _default = exports["default"] = isDisabledElement;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isFocusable.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isFocusable.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isFocusable.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,23 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _getTabIndex = _interopRequireDefault(require("./getTabIndex"));
+var _isInteractiveElement = _interopRequireDefault(require("./isInteractiveElement"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * Returns boolean indicating whether an element appears in tab focus.
+ * Identifies an element as focusable if it is an interactive element, or an element with a tabIndex greater than or equal to 0.
+ */
+function isFocusable(type, attributes) {
+  var tabIndex = (0, _getTabIndex["default"])((0, _jsxAstUtils.getProp)(attributes, 'tabIndex'));
+  if ((0, _isInteractiveElement["default"])(type, attributes)) {
+    return tabIndex === undefined || tabIndex >= 0;
+  }
+  return tabIndex >= 0;
+}
+var _default = exports["default"] = isFocusable;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isHiddenFromScreenReader.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isHiddenFromScreenReader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isHiddenFromScreenReader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns boolean indicating that the aria-hidden prop
+ * is present or the value is true. Will also return true if
+ * there is an input with type='hidden'.
+ *
+ * <div aria-hidden /> is equivalent to the DOM as <div aria-hidden=true />.
+ */
+var isHiddenFromScreenReader = function isHiddenFromScreenReader(type, attributes) {
+  if (type.toUpperCase() === 'INPUT') {
+    var hidden = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'type'));
+    if (hidden && hidden.toUpperCase() === 'HIDDEN') {
+      return true;
+    }
+  }
+  var ariaHidden = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(attributes, 'aria-hidden'));
+  return ariaHidden === true;
+};
+var _default = exports["default"] = isHiddenFromScreenReader;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isInteractiveElement.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isInteractiveElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isInteractiveElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,116 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _axobjectQuery = require("axobject-query");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _arrayPrototype = _interopRequireDefault(require("array.prototype.flatmap"));
+var _attributesComparator = _interopRequireDefault(require("./attributesComparator"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
+function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
+function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
+function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
+function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
+function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
+function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
+function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
+function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
+var roleKeys = _ariaQuery.roles.keys();
+var elementRoleEntries = _toConsumableArray(_ariaQuery.elementRoles);
+var nonInteractiveRoles = new Set(roleKeys.filter(function (name) {
+  var role = _ariaQuery.roles.get(name);
+  return !role["abstract"]
+  // 'toolbar' does not descend from widget, but it does support
+  // aria-activedescendant, thus in practice we treat it as a widget.
+  && name !== 'toolbar' && !role.superClass.some(function (classes) {
+    return (0, _arrayIncludes["default"])(classes, 'widget');
+  });
+}).concat(
+// The `progressbar` is descended from `widget`, but in practice, its
+// value is always `readonly`, so we treat it as a non-interactive role.
+'progressbar'));
+var interactiveRoles = new Set(roleKeys.filter(function (name) {
+  var role = _ariaQuery.roles.get(name);
+  return !role["abstract"]
+  // The `progressbar` is descended from `widget`, but in practice, its
+  // value is always `readonly`, so we treat it as a non-interactive role.
+  && name !== 'progressbar' && role.superClass.some(function (classes) {
+    return (0, _arrayIncludes["default"])(classes, 'widget');
+  });
+}).concat(
+// 'toolbar' does not descend from widget, but it does support
+// aria-activedescendant, thus in practice we treat it as a widget.
+'toolbar'));
+var interactiveElementRoleSchemas = (0, _arrayPrototype["default"])(elementRoleEntries, function (_ref) {
+  var _ref2 = _slicedToArray(_ref, 2),
+    elementSchema = _ref2[0],
+    rolesArr = _ref2[1];
+  return rolesArr.some(function (role) {
+    return interactiveRoles.has(role);
+  }) ? [elementSchema] : [];
+});
+var nonInteractiveElementRoleSchemas = (0, _arrayPrototype["default"])(elementRoleEntries, function (_ref3) {
+  var _ref4 = _slicedToArray(_ref3, 2),
+    elementSchema = _ref4[0],
+    rolesArr = _ref4[1];
+  return rolesArr.every(function (role) {
+    return nonInteractiveRoles.has(role);
+  }) ? [elementSchema] : [];
+});
+var interactiveAXObjects = new Set(_axobjectQuery.AXObjects.keys().filter(function (name) {
+  return _axobjectQuery.AXObjects.get(name).type === 'widget';
+}));
+var interactiveElementAXObjectSchemas = (0, _arrayPrototype["default"])(_toConsumableArray(_axobjectQuery.elementAXObjects), function (_ref5) {
+  var _ref6 = _slicedToArray(_ref5, 2),
+    elementSchema = _ref6[0],
+    AXObjectsArr = _ref6[1];
+  return AXObjectsArr.every(function (role) {
+    return interactiveAXObjects.has(role);
+  }) ? [elementSchema] : [];
+});
+function checkIsInteractiveElement(tagName, attributes) {
+  function elementSchemaMatcher(elementSchema) {
+    return tagName === elementSchema.name && (0, _attributesComparator["default"])(elementSchema.attributes, attributes);
+  }
+
+  // Check in elementRoles for inherent interactive role associations for
+  // this element.
+  var isInherentInteractiveElement = interactiveElementRoleSchemas.some(elementSchemaMatcher);
+  if (isInherentInteractiveElement) {
+    return true;
+  }
+  // Check in elementRoles for inherent non-interactive role associations for
+  // this element.
+  var isInherentNonInteractiveElement = nonInteractiveElementRoleSchemas.some(elementSchemaMatcher);
+  if (isInherentNonInteractiveElement) {
+    return false;
+  }
+  // Check in elementAXObjects for AX Tree associations for this element.
+  var isInteractiveAXElement = interactiveElementAXObjectSchemas.some(elementSchemaMatcher);
+  if (isInteractiveAXElement) {
+    return true;
+  }
+  return false;
+}
+
+/**
+ * Returns boolean indicating whether the given element is
+ * interactive on the DOM or not. Usually used when an element
+ * has a dynamic handler on it and we need to discern whether or not
+ * it's intention is to be interacted with on the DOM.
+ */
+var isInteractiveElement = function isInteractiveElement(tagName, attributes) {
+  // Do not test higher level JSX components, as we do not know what
+  // low-level DOM element this maps to.
+  if (!_ariaQuery.dom.has(tagName)) {
+    return false;
+  }
+  return checkIsInteractiveElement(tagName, attributes);
+};
+var _default = exports["default"] = isInteractiveElement;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isInteractiveRole.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isInteractiveRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isInteractiveRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _arrayPrototype = _interopRequireDefault(require("array.prototype.flatmap"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+var roles = _ariaQuery.roles.keys();
+var interactiveRoles = roles.filter(function (name) {
+  return !_ariaQuery.roles.get(name)["abstract"] && _ariaQuery.roles.get(name).superClass.some(function (klasses) {
+    return (0, _arrayIncludes["default"])(klasses, 'widget');
+  });
+});
+
+// 'toolbar' does not descend from widget, but it does support
+// aria-activedescendant, thus in practice we treat it as a widget.
+interactiveRoles.push('toolbar');
+/**
+ * Returns boolean indicating whether the given element has a role
+ * that is associated with an interactive component. Used when an element
+ * has a dynamic handler on it and we need to discern whether or not
+ * its intention is to be interacted with in the DOM.
+ *
+ * isInteractiveRole is a Logical Disjunction:
+ * https://en.wikipedia.org/wiki/Logical_disjunction
+ * The JSX element does not have a tagName or it has a tagName and a role
+ * attribute with a value in the set of non-interactive roles.
+ */
+var isInteractiveRole = function isInteractiveRole(tagName, attributes) {
+  var value = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role'));
+
+  // If value is undefined, then the role attribute will be dropped in the DOM.
+  // If value is null, then getLiteralAttributeValue is telling us that the
+  // value isn't in the form of a literal
+  if (value === undefined || value === null) {
+    return false;
+  }
+  var isInteractive = false;
+  var normalizedValues = String(value).toLowerCase().split(' ');
+  var validRoles = (0, _arrayPrototype["default"])(normalizedValues, function (name) {
+    return (0, _arrayIncludes["default"])(roles, name) ? [name] : [];
+  });
+  if (validRoles.length > 0) {
+    // The first role value is a series takes precedence.
+    isInteractive = (0, _arrayIncludes["default"])(interactiveRoles, validRoles[0]);
+  }
+  return isInteractive;
+};
+var _default = exports["default"] = isInteractiveRole;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonInteractiveElement.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonInteractiveElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonInteractiveElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,131 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _axobjectQuery = require("axobject-query");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _arrayPrototype = _interopRequireDefault(require("array.prototype.flatmap"));
+var _attributesComparator = _interopRequireDefault(require("./attributesComparator"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
+function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
+function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
+function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
+function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
+function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
+function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
+function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
+function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
+var roleKeys = _ariaQuery.roles.keys();
+var elementRoleEntries = _toConsumableArray(_ariaQuery.elementRoles);
+var nonInteractiveRoles = new Set(roleKeys.filter(function (name) {
+  var role = _ariaQuery.roles.get(name);
+  return !role["abstract"]
+  // 'toolbar' does not descend from widget, but it does support
+  // aria-activedescendant, thus in practice we treat it as a widget.
+  && name !== 'toolbar'
+  // This role is meant to have no semantic value.
+  // @see https://www.w3.org/TR/wai-aria-1.2/#generic
+  && name !== 'generic' && !role.superClass.some(function (classes) {
+    return (0, _arrayIncludes["default"])(classes, 'widget');
+  });
+}).concat(
+// The `progressbar` is descended from `widget`, but in practice, its
+// value is always `readonly`, so we treat it as a non-interactive role.
+'progressbar'));
+var interactiveRoles = new Set(roleKeys.filter(function (name) {
+  var role = _ariaQuery.roles.get(name);
+  return !role["abstract"]
+  // The `progressbar` is descended from `widget`, but in practice, its
+  // value is always `readonly`, so we treat it as a non-interactive role.
+  && name !== 'progressbar'
+  // This role is meant to have no semantic value.
+  // @see https://www.w3.org/TR/wai-aria-1.2/#generic
+  && name !== 'generic' && role.superClass.some(function (classes) {
+    return (0, _arrayIncludes["default"])(classes, 'widget');
+  });
+}).concat(
+// 'toolbar' does not descend from widget, but it does support
+// aria-activedescendant, thus in practice we treat it as a widget.
+'toolbar'));
+var interactiveElementRoleSchemas = (0, _arrayPrototype["default"])(elementRoleEntries, function (_ref) {
+  var _ref2 = _slicedToArray(_ref, 2),
+    elementSchema = _ref2[0],
+    rolesArr = _ref2[1];
+  return rolesArr.some(function (role) {
+    return interactiveRoles.has(role);
+  }) ? [elementSchema] : [];
+});
+var nonInteractiveElementRoleSchemas = (0, _arrayPrototype["default"])(elementRoleEntries, function (_ref3) {
+  var _ref4 = _slicedToArray(_ref3, 2),
+    elementSchema = _ref4[0],
+    rolesArr = _ref4[1];
+  return rolesArr.every(function (role) {
+    return nonInteractiveRoles.has(role);
+  }) ? [elementSchema] : [];
+});
+var nonInteractiveAXObjects = new Set(_axobjectQuery.AXObjects.keys().filter(function (name) {
+  return (0, _arrayIncludes["default"])(['window', 'structure'], _axobjectQuery.AXObjects.get(name).type);
+}));
+var nonInteractiveElementAXObjectSchemas = (0, _arrayPrototype["default"])(_toConsumableArray(_axobjectQuery.elementAXObjects), function (_ref5) {
+  var _ref6 = _slicedToArray(_ref5, 2),
+    elementSchema = _ref6[0],
+    AXObjectsArr = _ref6[1];
+  return AXObjectsArr.every(function (role) {
+    return nonInteractiveAXObjects.has(role);
+  }) ? [elementSchema] : [];
+});
+function checkIsNonInteractiveElement(tagName, attributes) {
+  function elementSchemaMatcher(elementSchema) {
+    return tagName === elementSchema.name && tagName !== 'td' // TODO: investigate why this is needed
+    && (0, _attributesComparator["default"])(elementSchema.attributes, attributes);
+  }
+  // Check in elementRoles for inherent non-interactive role associations for
+  // this element.
+  var isInherentNonInteractiveElement = nonInteractiveElementRoleSchemas.some(elementSchemaMatcher);
+  if (isInherentNonInteractiveElement) {
+    return true;
+  }
+  // Check in elementRoles for inherent interactive role associations for
+  // this element.
+  var isInherentInteractiveElement = interactiveElementRoleSchemas.some(elementSchemaMatcher);
+  if (isInherentInteractiveElement) {
+    return false;
+  }
+  // Check in elementAXObjects for AX Tree associations for this element.
+  var isNonInteractiveAXElement = nonInteractiveElementAXObjectSchemas.some(elementSchemaMatcher);
+  if (isNonInteractiveAXElement) {
+    return true;
+  }
+  return false;
+}
+
+/**
+ * Returns boolean indicating whether the given element is a non-interactive
+ * element. If the element has either a non-interactive role assigned or it
+ * is an element with an inherently non-interactive role, then this utility
+ * returns true. Elements that lack either an explicitly assigned role or
+ * an inherent role are not considered. For those, this utility returns false
+ * because a positive determination of interactiveness cannot be determined.
+ */
+var isNonInteractiveElement = function isNonInteractiveElement(tagName, attributes) {
+  // Do not test higher level JSX components, as we do not know what
+  // low-level DOM element this maps to.
+  if (!_ariaQuery.dom.has(tagName)) {
+    return false;
+  }
+  // <header> elements do not technically have semantics, unless the
+  // element is a direct descendant of <body>, and this plugin cannot
+  // reliably test that.
+  // @see https://www.w3.org/TR/wai-aria-practices/examples/landmarks/banner.html
+  if (tagName === 'header') {
+    return false;
+  }
+  return checkIsNonInteractiveElement(tagName, attributes);
+};
+var _default = exports["default"] = isNonInteractiveElement;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonInteractiveRole.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonInteractiveRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonInteractiveRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,55 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _ariaQuery = require("aria-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _arrayPrototype = _interopRequireDefault(require("array.prototype.flatmap"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+var nonInteractiveRoles = _ariaQuery.roles.keys().filter(function (name) {
+  return !_ariaQuery.roles.get(name)["abstract"] && !_ariaQuery.roles.get(name).superClass.some(function (klasses) {
+    return (0, _arrayIncludes["default"])(klasses, 'widget');
+  });
+});
+
+/**
+ * Returns boolean indicating whether the given element has a role
+ * that is associated with a non-interactive component. Non-interactive roles
+ * include `listitem`, `article`, or `dialog`. These are roles that indicate
+ * for the most part containers.
+ *
+ * Elements with these roles should not respond or handle user interactions.
+ * For example, an `onClick` handler should not be assigned to an element with
+ * the role `listitem`. An element inside the `listitem`, like a button or a
+ * link, should handle the click.
+ *
+ * This utility returns true for elements that are assigned a non-interactive
+ * role. It will return false for elements that do not have a role. So whereas
+ * a `div` might be considered non-interactive, for the purpose of this utility,
+ * it is considered neither interactive nor non-interactive -- a determination
+ * cannot be made in this case and false is returned.
+ */
+
+var isNonInteractiveRole = function isNonInteractiveRole(tagName, attributes) {
+  // Do not test higher level JSX components, as we do not know what
+  // low-level DOM element this maps to.
+  if (!_ariaQuery.dom.has(tagName)) {
+    return false;
+  }
+  var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role'));
+  var isNonInteractive = false;
+  var normalizedValues = String(role).toLowerCase().split(' ');
+  var validRoles = (0, _arrayPrototype["default"])(normalizedValues, function (name) {
+    return _ariaQuery.roles.has(name) ? [name] : [];
+  });
+  if (validRoles.length > 0) {
+    // The first role value is a series takes precedence.
+    isNonInteractive = (0, _arrayIncludes["default"])(nonInteractiveRoles, validRoles[0]);
+  }
+  return isNonInteractive;
+};
+var _default = exports["default"] = isNonInteractiveRole;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonLiteralProperty.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonLiteralProperty.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isNonLiteralProperty.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+/**
+ * Returns boolean indicating whether the given element has been specified with
+ * an AST node with a non-literal type.
+ *
+ * Returns true if the elements has a role and its value is not of a type Literal.
+ * Otherwise returns false.
+ */
+var isNonLiteralProperty = function isNonLiteralProperty(attributes, propName) {
+  var prop = (0, _jsxAstUtils.getProp)(attributes, propName);
+  if (!prop) return false;
+  var propValue = prop.value;
+  if (!propValue) return false;
+  if (propValue.type === 'Literal') return false;
+  if (propValue.type === 'JSXExpressionContainer') {
+    var expression = propValue.expression;
+    if (expression.type === 'Identifier' && expression.name === 'undefined') return false;
+    if (expression.type === 'JSXText') return false;
+  }
+  return true;
+};
+var _default = exports["default"] = isNonLiteralProperty;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isPresentationRole.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isPresentationRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isPresentationRole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _jsxAstUtils = require("jsx-ast-utils");
+var presentationRoles = new Set(['presentation', 'none']);
+var isPresentationRole = function isPresentationRole(tagName, attributes) {
+  return presentationRoles.has((0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role')));
+};
+var _default = exports["default"] = isPresentationRole;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isSemanticRoleElement.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isSemanticRoleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/isSemanticRoleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+var _axobjectQuery = require("axobject-query");
+var _jsxAstUtils = require("jsx-ast-utils");
+var isSemanticRoleElement = function isSemanticRoleElement(elementType, attributes) {
+  var roleAttr = (0, _jsxAstUtils.getProp)(attributes, 'role');
+  var res = false;
+  var roleAttrValue = (0, _jsxAstUtils.getLiteralPropValue)(roleAttr);
+  _axobjectQuery.elementAXObjects.forEach(function (axObjects, concept) {
+    if (res) {
+      return;
+    }
+    if (concept.name === elementType && (concept.attributes || []).every(function (cAttr) {
+      return attributes.some(function (attr) {
+        if (!attr.type || attr.type !== 'JSXAttribute') {
+          return false;
+        }
+        var namesMatch = cAttr.name === (0, _jsxAstUtils.propName)(attr);
+        var valuesMatch;
+        if (cAttr.value !== undefined) {
+          valuesMatch = cAttr.value === (0, _jsxAstUtils.getLiteralPropValue)(attr);
+        }
+        if (!namesMatch) {
+          return false;
+        }
+        return namesMatch && valuesMatch !== undefined ? valuesMatch : true;
+      });
+    })) {
+      axObjects.forEach(function (name) {
+        if (res) {
+          return;
+        }
+        var roles = _axobjectQuery.AXObjectRoles.get(name);
+        if (roles) {
+          roles.forEach(function (role) {
+            if (res === true) {
+              return;
+            }
+            if (role.name === roleAttrValue) {
+              res = true;
+            }
+          });
+        }
+      });
+    }
+  });
+  return res;
+};
+var _default = exports["default"] = isSemanticRoleElement;
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/mayContainChildComponent.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/mayContainChildComponent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/mayContainChildComponent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = mayContainChildComponent;
+var _jsxAstUtils = require("jsx-ast-utils");
+var _minimatch = _interopRequireDefault(require("minimatch"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * Returns true if it can positively determine that the element lacks an
+ * accessible label. If no determination is possible, it returns false. Treat
+ * false as an unknown value. The element might still have an accessible label,
+ * but this module cannot determine it positively.
+ *
+ * 
+ */
+
+function mayContainChildComponent(root, componentName) {
+  var maxDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
+  var elementType = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _jsxAstUtils.elementType;
+  function traverseChildren(node, depth) {
+    // Bail when maxDepth is exceeded.
+    if (depth > maxDepth) {
+      return false;
+    }
+    if (node.children) {
+      /* $FlowFixMe */
+      for (var i = 0; i < node.children.length; i += 1) {
+        /* $FlowFixMe */
+        var childNode = node.children[i];
+        // Assume an expression container renders a label. It is the best we can
+        // do in this case.
+        if (childNode.type === 'JSXExpressionContainer') {
+          return true;
+        }
+        // Check for components with the provided name.
+        if (childNode.type === 'JSXElement' && childNode.openingElement && (0, _minimatch["default"])(elementType(childNode.openingElement), componentName)) {
+          return true;
+        }
+        if (traverseChildren(childNode, depth + 1)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+  return traverseChildren(root, 1);
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/mayHaveAccessibleLabel.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/mayHaveAccessibleLabel.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/mayHaveAccessibleLabel.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = mayHaveAccessibleLabel;
+var _arrayIncludes = _interopRequireDefault(require("array-includes"));
+var _jsxAstUtils = require("jsx-ast-utils");
+var _minimatch = _interopRequireDefault(require("minimatch"));
+function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
+/**
+ * Returns true if a labelling element is found or if it cannot determine if
+ * a label is present because of expression containers or spread attributes.
+ * A false return value means that the node definitely does not have a label,
+ * but a true return return value means that the node may or may not have a
+ * label.
+ *
+ * 
+ */
+
+function tryTrim(value) {
+  return typeof value === 'string' ? value.trim() : value;
+}
+function hasLabellingProp(openingElement) {
+  var additionalLabellingProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
+  var labellingProps = [].concat('alt',
+  // Assume alt is used correctly on an image
+  'aria-label', 'aria-labelledby', additionalLabellingProps);
+  return openingElement.attributes.some(function (attribute) {
+    // We must assume that a spread value contains a labelling prop.
+    if (attribute.type !== 'JSXAttribute') {
+      return true;
+    }
+    // Attribute matches.
+    if ((0, _arrayIncludes["default"])(labellingProps, (0, _jsxAstUtils.propName)(attribute)) && !!tryTrim((0, _jsxAstUtils.getPropValue)(attribute))) {
+      return true;
+    }
+    return false;
+  });
+}
+function mayHaveAccessibleLabel(root) {
+  var maxDepth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
+  var additionalLabellingProps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
+  var getElementType = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _jsxAstUtils.elementType;
+  var controlComponents = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [];
+  function checkElement(node, depth) {
+    // Bail when maxDepth is exceeded.
+    if (depth > maxDepth) {
+      return false;
+    }
+    // Check for literal text.
+    if (node.type === 'Literal' && !!tryTrim(node.value)) {
+      return true;
+    }
+    // Assume an expression container renders a label. It is the best we can
+    // do in this case.
+    if (node.type === 'JSXExpressionContainer') {
+      return true;
+    }
+    // Check for JSXText.
+    // $FlowFixMe Remove after updating ast-types-flow
+    if (node.type === 'JSXText' && !!tryTrim(node.value)) {
+      return true;
+    }
+    // Check for labelling props.
+    if (node.openingElement
+    /* $FlowFixMe */ && hasLabellingProp(node.openingElement, additionalLabellingProps)) {
+      return true;
+    }
+    if (node.type === 'JSXElement' && node.children.length === 0 && node.openingElement) {
+      // $FlowFixMe `node.openingElement` has `unknown` type
+      var name = getElementType(node.openingElement);
+      var isReactComponent = name.length > 0 && name[0] === name[0].toUpperCase();
+      if (isReactComponent && !controlComponents.some(function (control) {
+        return (0, _minimatch["default"])(name, control);
+      })) {
+        return true;
+      }
+    }
+
+    // Recurse into the child element nodes.
+    if (node.children) {
+      /* $FlowFixMe */
+      for (var i = 0; i < node.children.length; i += 1) {
+        /* $FlowFixMe */
+        if (checkElement(node.children[i], depth + 1)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+  return checkElement(root, 0);
+}
+module.exports = exports.default;
Index: frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/schemas.js
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/schemas.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/lib/util/schemas.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.generateObjSchema = exports.enumArraySchema = exports.arraySchema = void 0;
+function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
+function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
+function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
+function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
+function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
+/**
+ * JSON schema to accept an array of unique strings
+ */
+var arraySchema = exports.arraySchema = {
+  type: 'array',
+  items: {
+    type: 'string'
+  },
+  uniqueItems: true,
+  additionalItems: false
+};
+
+/**
+ * JSON schema to accept an array of unique strings from an enumerated list.
+ */
+var enumArraySchema = exports.enumArraySchema = function enumArraySchema() {
+  var enumeratedList = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
+  var minItems = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+  return _objectSpread(_objectSpread({}, arraySchema), {}, {
+    items: {
+      type: 'string',
+      "enum": enumeratedList
+    },
+    minItems
+  });
+};
+
+/**
+ * Factory function to generate an object schema
+ * with specified properties object
+ */
+var generateObjSchema = exports.generateObjSchema = function generateObjSchema() {
+  var properties = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+  var required = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
+  return {
+    type: 'object',
+    properties,
+    required
+  };
+};
Index: frontend/node_modules/eslint-plugin-jsx-a11y/package.json
===================================================================
--- frontend/node_modules/eslint-plugin-jsx-a11y/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-plugin-jsx-a11y/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,119 @@
+{
+  "name": "eslint-plugin-jsx-a11y",
+  "version": "6.10.2",
+  "description": "Static AST checker for accessibility rules on JSX elements.",
+  "keywords": [
+    "eslint",
+    "eslintplugin",
+    "eslint-plugin",
+    "a11y",
+    "accessibility",
+    "jsx"
+  ],
+  "author": "Ethan Cohen",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/jsx-eslint/eslint-plugin-jsx-a11y"
+  },
+  "main": "lib/index.js",
+  "scripts": {
+    "prepack": "npmignore --auto --commentLines=autogenerated && npm run build",
+    "build": "rimraf lib && babel src --out-dir lib --copy-files",
+    "create": "node ./scripts/create-rule",
+    "flow": "flow",
+    "lint:fix": "npm run lint -- --fix",
+    "lint": "npx eslint@8 --ext=js,mjs,cjs,ts,tsx .",
+    "prepublish": "not-in-publish || npm run prepublishOnly",
+    "prepublishOnly": "safe-publish-latest && npm run lint && npm run flow && npm run tests-only",
+    "pretest": "npm run lint:fix && npm run flow",
+    "test": "npm run tests-only",
+    "tests-only": "tape --require=@babel/register '__tests__/**/*.js'",
+    "posttest": "npx npm@'>=10.2' audit --production",
+    "pretest:examples": "npm run build",
+    "test:examples": "npm run test-example:legacy && npm run test-example:flat-esm && npm run test-example:flat-cjs",
+    "test-example:legacy": "cd examples/legacy && npm install && npm run lint",
+    "test-example:flat-esm": "cd examples/flat-esm && npm install && npm run lint",
+    "test-example:flat-cjs": "cd examples/flat-cjs && npm install && npm run lint",
+    "pregenerate-list-of-rules": "npm run build",
+    "generate-list-of-rules": "eslint-doc-generator --rule-doc-title-format prefix-name --rule-doc-section-options false --config-emoji recommended,☑️ --ignore-config flat/recommended --ignore-config flat/strict",
+    "generate-list-of-rules:check": "npm run generate-list-of-rules -- --check",
+    "version": "auto-changelog && git add CHANGELOG.md",
+    "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
+  },
+  "devDependencies": {
+    "@babel/cli": "^7.25.9",
+    "@babel/core": "^7.26.0",
+    "@babel/eslint-parser": "^7.25.9",
+    "@babel/plugin-transform-flow-strip-types": "^7.25.9",
+    "@babel/register": "^7.25.9",
+    "auto-changelog": "^2.5.0",
+    "babel-plugin-add-module-exports": "^1.0.4",
+    "babel-preset-airbnb": "^5.0.0",
+    "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9",
+    "eslint-config-airbnb-base": "^15.0.0",
+    "eslint-doc-generator": "^1.7.1",
+    "eslint-plugin-eslint-plugin": "^4.3.0",
+    "eslint-plugin-flowtype": "^5.8.0 || ^8.0.3",
+    "eslint-plugin-import": "^2.31.0",
+    "estraverse": "^5.3.0",
+    "flow-bin": "^0.147.0",
+    "in-publish": "^2.0.1",
+    "jackspeak": "=2.1.1",
+    "jscodeshift": "^17.0.0",
+    "minimist": "^1.2.8",
+    "npmignore": "^0.3.1",
+    "object.assign": "^4.1.5",
+    "object.entries": "^1.1.8",
+    "rimraf": "^3.0.2",
+    "safe-publish-latest": "^2.0.0",
+    "semver": "^6.3.1",
+    "tape": "^5.9.0",
+    "to-ast": "^1.0.0"
+  },
+  "engines": {
+    "node": ">=4.0"
+  },
+  "license": "MIT",
+  "dependencies": {
+    "aria-query": "^5.3.2",
+    "array-includes": "^3.1.8",
+    "array.prototype.flatmap": "^1.3.2",
+    "ast-types-flow": "^0.0.8",
+    "axe-core": "^4.10.0",
+    "axobject-query": "^4.1.0",
+    "damerau-levenshtein": "^1.0.8",
+    "emoji-regex": "^9.2.2",
+    "hasown": "^2.0.2",
+    "jsx-ast-utils": "^3.3.5",
+    "language-tags": "^1.0.9",
+    "minimatch": "^3.1.2",
+    "object.fromentries": "^2.0.8",
+    "safe-regex-test": "^1.0.3",
+    "string.prototype.includes": "^2.0.1"
+  },
+  "peerDependencies": {
+    "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
+  },
+  "auto-changelog": {
+    "output": "CHANGELOG.md",
+    "template": "keepachangelog",
+    "unreleased": false,
+    "commitLimit": false,
+    "backfillLimit": false,
+    "hideCredit": true,
+    "startingVersion": "6.6.2"
+  },
+  "publishConfig": {
+    "ignore": [
+      "!lib",
+      ".github/workflows",
+      ".flowconfig",
+      "/src",
+      "/reports",
+      "/flow",
+      "scripts/",
+      "CONTRIBUTING.md",
+      "/examples"
+    ]
+  }
+}
