diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index effb8a43e..3f6b552e4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -222,4 +222,46 @@ jobs: BLUEMIX_USERID: apikey BLUEMIX_PASS: ${{ secrets.BLUEMIX_PASS }} CLOUD_PWD: ${{ secrets.CLOUD_PWD }} - TRAVIS_BRANCH: prod \ No newline at end of file + TRAVIS_BRANCH: prod + + java-accessibility-checker-deploy: + runs-on: ubuntu-22.04 + permissions: + packages: write + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v4 + with: + distribution: 'semeru' # See 'Supported distributions' for available options + java-version: '17' + server-id: central + server-username: ${{ secrets.MVN_GITHUB_USER }} + server-password: ${{ secrets.MVN_GITHUB_TOKEN }} + - uses: s4u/maven-settings-action@v3.0.0 + with: + servers: | + [{ + "id": "central", + "username": "${{ secrets.MVN_GITHUB_USER }}", + "password": "${{ secrets.MVN_GITHUB_TOKEN }}" + }] + - name: Configure GPG Key + run: echo "$GPG_SIGNING_KEY" >private.key + env: + GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} + - name: Import GPG Key + run: gpg --pinentry-mode=loopback --passphrase "$GPG_SIGNING_KEY_PASS" --import private.key + env: + GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} + - name: Set version + run: sed -i'.old' -e 's/\3\.0\.0\<\/version\>/\'"${GITHUB_REF:10}"'\<\/version\>/g' ./pom.xml + working-directory: java-accessibility-checker + - name: Publish package + run: mvn --batch-mode deploy -DskipTests -Dgpg.passphrase=$GPG_SIGNING_KEY_PASS + working-directory: java-accessibility-checker + env: + GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 579f607a0..b22b0cad2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -361,6 +361,77 @@ jobs: - run: npm run wdio working-directory: accessibility-checker/test/webdriverio +############################################################################### +# Java test +#### + java-accessibility-checker-selenium-test: + runs-on: ubuntu-22.04 + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v4 + with: + distribution: 'semeru' # See 'Supported distributions' for available options + java-version: '17' + - name: Latest Chrome + uses: browser-actions/setup-chrome@v1 + with: + chrome-version: latest + install-chromedriver: true + id: setup-chrome + - run: npm install + working-directory: rule-server + - run: npm run build + working-directory: rule-server + - run: node main.js & + working-directory: rule-server/dist + - run: sleep 10 + working-directory: rule-server/dist + - name: Test package + run: mvn --batch-mode test -Dtest="AccessibilityCheckerSeleniumTest" + working-directory: java-accessibility-checker + env: + chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} + chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} + + java-accessibility-checker-playwright-test: + runs-on: ubuntu-22.04 + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v4 + with: + distribution: 'semeru' # See 'Supported distributions' for available options + java-version: '17' + - name: Latest Chrome + uses: browser-actions/setup-chrome@v1 + with: + chrome-version: latest + install-chromedriver: true + id: setup-chrome + - run: npm install + working-directory: rule-server + - run: npm run build + working-directory: rule-server + - run: node main.js & + working-directory: rule-server/dist + - run: sleep 10 + working-directory: rule-server/dist + - name: Test package + run: mvn --batch-mode test -Dtest="AccessibilityCheckerPlaywrightTest" + working-directory: java-accessibility-checker + env: + chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} + chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} + ############################################################################### # Karma Tests #### diff --git a/accessibility-checker-engine/help-v4/en-US/aria_application_label_unique.html b/accessibility-checker-engine/help-v4/en-US/aria_application_label_unique.html index a27730a88..9ebc32c97 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_application_label_unique.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_application_label_unique.html @@ -82,6 +82,7 @@

Weather portlet

* [IBM 2.4.1 Bypass Blocks](https://www.ibm.com/able/requirements/requirements/#2_4_1) * [ARIA6: aria-label to label objects](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA6) * [ARIA13: aria-labelledby to name regions and landmarks](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA13) +* [ARIA specification - Application Role](https://www.w3.org/TR/wai-aria-1.2/#application) ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_application_labelled.html b/accessibility-checker-engine/help-v4/en-US/aria_application_labelled.html index 843c1487c..45e18169c 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_application_labelled.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_application_labelled.html @@ -79,6 +79,7 @@

Weather portlet

* [IBM 2.4.1 Bypass Blocks](https://www.ibm.com/able/requirements/requirements/#2_4_1) * [ARIA practices - Accessible Names and Descriptions](https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/) +* [ARIA specification - Application Role](https://www.w3.org/TR/wai-aria-1.2/#application) ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_article_label_unique.html b/accessibility-checker-engine/help-v4/en-US/aria_article_label_unique.html index 3a8dc7da8..72edce742 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_article_label_unique.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_article_label_unique.html @@ -83,6 +83,7 @@

Stock Ticker Portlet * [IBM 2.4.1 Bypass Blocks](https://www.ibm.com/able/requirements/requirements/#2_4_1) * [ARIA6: aria-label to label objects](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA6) * [ARIA13: aria-labelledby to name regions and landmarks](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA13) +* [ARIA specification - Article Role](https://www.w3.org/TR/wai-aria-1.2/#article) ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_attribute_required.html b/accessibility-checker-engine/help-v4/en-US/aria_attribute_required.html index 15c6ede5e..487d1d7da 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_attribute_required.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_attribute_required.html @@ -84,6 +84,7 @@

* [IBM 4.1.2 Name, Role, Value](https://www.ibm.com/able/requirements/requirements/#4_1_2) * [ARIA practices guide](https://www.w3.org/WAI/ARIA/apg/) +* [ARIA specification](https://www.w3.org/TR/wai-aria-1.2/)] ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_banner_label_unique.html b/accessibility-checker-engine/help-v4/en-US/aria_banner_label_unique.html index d22157c79..9c3208c4f 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_banner_label_unique.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_banner_label_unique.html @@ -83,6 +83,7 @@

Weather portlet

* [IBM 2.4.1 Bypass Blocks](https://www.ibm.com/able/requirements/requirements/#2_4_1) * [ARIA6: aria-label to label objects](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA6) * [ARIA13: aria-labelledby to name regions and landmarks](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA13) +* [ARIA specification - Banner Role](https://www.w3.org/TR/wai-aria-1.2/#banner)] ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_banner_single.html b/accessibility-checker-engine/help-v4/en-US/aria_banner_single.html index facf0c030..ded0553f7 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_banner_single.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_banner_single.html @@ -76,7 +76,8 @@

### About this requirement * [IBM 2.4.1 Bypass Blocks](https://www.ibm.com/able/requirements/requirements/#2_4_1) -* [ARIA practices - HTML Sectioning Elements](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/#htmlsectioningelements) +* [ARIA practices - Landmark Regions](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/) +* [ARIA specification - Banner Role](https://www.w3.org/TR/wai-aria-1.2/#banner)] ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_unique.html b/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_unique.html index 1867efa1d..61ebe6ef9 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_unique.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_unique.html @@ -82,6 +82,7 @@

Weather portlet

* [IBM 2.4.1 Bypass Blocks](https://www.ibm.com/able/requirements/requirements/#2_4_1) * [ARIA6: aria-label to label objects](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA6) * [ARIA13: aria-labelledby to name regions and landmarks](https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA13) +* [ARIA specification - Complementary Role](https://www.w3.org/TR/wai-aria-1.2/#complementary) ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_visible.html b/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_visible.html index 777148ff5..7605e3a5e 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_visible.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_complementary_label_visible.html @@ -79,6 +79,7 @@

Weather portlet

* [IBM 2.4.1 Bypass Blocks](https://www.ibm.com/able/requirements/requirements/#2_4_1) * [ARIA specification - complementary role](https://www.w3.org/TR/wai-aria-1.2/#complementary) * [ARIA practices - Landmark Regions](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/) +* [ARIA specification - Complementary Role](https://www.w3.org/TR/wai-aria-1.2/#complementary) ### Who does this affect? diff --git a/accessibility-checker-engine/help-v4/en-US/aria_contentinfo_label_unique.html b/accessibility-checker-engine/help-v4/en-US/aria_contentinfo_label_unique.html index 9b47d704e..afdffc649 100644 --- a/accessibility-checker-engine/help-v4/en-US/aria_contentinfo_label_unique.html +++ b/accessibility-checker-engine/help-v4/en-US/aria_contentinfo_label_unique.html @@ -44,7 +44,10 @@

+ + + diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_attribute_required_ruleunit/separator.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_attribute_required_ruleunit/separator.html index 3651a14e5..bf2f6fd4f 100644 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_attribute_required_ruleunit/separator.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_attribute_required_ruleunit/separator.html @@ -82,7 +82,7 @@

WAI-ARIA role valid attribute test

"aria": "/document[1]/separator[3]" }, "reasonId": "fail_missing", - "message": "An element with ARIA role 'separator' does not have the required ARIA attribute(s): 'aria-valuenow'", + "message": "Element with 'separator' role does not have the required ARIA attribute(s): 'aria-valuenow'", "messageArgs": [ "separator", "aria-valuenow" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_fail.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_fail.html index 82f558c87..094382093 100755 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_fail.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_fail.html @@ -55,7 +55,7 @@

Institutional Links

"aria": "/document[1]/main[1]/navigation[1]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"Institutional Links\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"Institutional Links\" label", "messageArgs": [ "navigation", "Institutional Links" @@ -74,7 +74,7 @@

Institutional Links

"aria": "/document[1]/main[1]/navigation[2]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"Institutional Links\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"Institutional Links\" label", "messageArgs": [ "navigation", "Institutional Links" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_pass.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_pass.html index 66548d237..fe5f1300a 100755 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_pass.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_0_pass.html @@ -58,7 +58,7 @@

Related topics

"aria": "/document[1]/main[1]/navigation[1]" }, "reasonId": "Pass_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "navigation" ], @@ -76,7 +76,7 @@

Related topics

"aria": "/document[1]/main[1]/navigation[2]" }, "reasonId": "Pass_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "navigation" ], diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_2_fail.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_2_fail.html index 4d206d21b..9d8877c55 100755 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_2_fail.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_2_fail.html @@ -59,7 +59,7 @@

Related topics

"aria": "/document[1]/main[1]/navigation[1]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "navigation", "" @@ -78,7 +78,7 @@

Related topics

"aria": "/document[1]/main[1]/application[1]/navigation[1]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "navigation", "" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_3_pass.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_3_pass.html index 80b685a2c..a40520bd0 100755 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_3_pass.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_3_pass.html @@ -57,7 +57,7 @@

Related topics

"aria": "/document[1]/main[1]/navigation[1]" }, "reasonId": "Pass_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "navigation" ], @@ -75,7 +75,7 @@

Related topics

"aria": "/document[1]/main[1]/navigation[2]" }, "reasonId": "Pass_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "navigation" ], diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_4_mixed.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_4_mixed.html index 7b223bd3e..66ac6266d 100755 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_4_mixed.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_landmark_name_unique_ruleunit/example_4_mixed.html @@ -107,7 +107,7 @@ "aria": "/document[1]/complementary[1]" }, "reasonId": "Pass_0", - "message": "Multiple \"complementary\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"complementary\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "complementary" ], @@ -125,7 +125,7 @@ "aria": "/document[1]/complementary[2]" }, "reasonId": "Pass_0", - "message": "Multiple \"complementary\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"complementary\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "complementary" ], @@ -143,7 +143,7 @@ "aria": "/document[1]/complementary[3]" }, "reasonId": "Pass_0", - "message": "Multiple \"complementary\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"complementary\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "complementary" ], @@ -161,7 +161,7 @@ "aria": "/document[1]/region[1]" }, "reasonId": "Fail_0", - "message": "Multiple \"region\" landmarks with the same parent region are not distinguished from one another because they have the same \"region FAIL\" label", + "message": "Multiple elements with \"region\" landmarks within the same parent region are not distinguished from one another because they have the same \"region FAIL\" label", "messageArgs": [ "region", "region FAIL" @@ -180,7 +180,7 @@ "aria": "/document[1]/region[2]" }, "reasonId": "Fail_0", - "message": "Multiple \"region\" landmarks with the same parent region are not distinguished from one another because they have the same \"region FAIL\" label", + "message": "Multiple elements with \"region\" landmarks within the same parent region are not distinguished from one another because they have the same \"region FAIL\" label", "messageArgs": [ "region", "region FAIL" @@ -199,7 +199,7 @@ "aria": "/document[1]/region[3]" }, "reasonId": "Fail_0", - "message": "Multiple \"region\" landmarks with the same parent region are not distinguished from one another because they have the same \"region FAIL\" label", + "message": "Multiple elements with \"region\" landmarks within the same parent region are not distinguished from one another because they have the same \"region FAIL\" label", "messageArgs": [ "region", "region FAIL" @@ -218,7 +218,7 @@ "aria": "/document[1]/main[1]" }, "reasonId": "Fail_0", - "message": "Multiple \"main\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"main\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "main", "" @@ -237,7 +237,7 @@ "aria": "/document[1]/main[2]" }, "reasonId": "Fail_0", - "message": "Multiple \"main\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"main\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "main", "" @@ -256,7 +256,7 @@ "aria": "/document[1]/main[2]/region[1]" }, "reasonId": "Pass_0", - "message": "Multiple \"region\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"region\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "region" ], @@ -274,7 +274,7 @@ "aria": "/document[1]/main[2]/region[1]/navigation[1]" }, "reasonId": "Pass_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "navigation" ], @@ -292,7 +292,7 @@ "aria": "/document[1]/main[2]/region[1]/navigation[2]" }, "reasonId": "Pass_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "navigation" ], @@ -310,7 +310,7 @@ "aria": "/document[1]/main[2]/region[2]" }, "reasonId": "Pass_0", - "message": "Multiple \"region\" landmarks with the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", + "message": "Multiple elements with \"region\" landmarks within the same parent region are distinguished by unique 'aria-label' or 'aria-labelledby'", "messageArgs": [ "region" ], @@ -328,7 +328,7 @@ "aria": "/document[1]/main[2]/region[2]/navigation[1]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"Top Label\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"Top Label\" label", "messageArgs": [ "navigation", "Top Label" @@ -347,7 +347,7 @@ "aria": "/document[1]/main[2]/region[2]/navigation[2]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"Top Label\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"Top Label\" label", "messageArgs": [ "navigation", "Top Label" @@ -366,7 +366,7 @@ "aria": "/document[1]/main[2]/region[2]/navigation[3]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "navigation", "" @@ -385,7 +385,7 @@ "aria": "/document[1]/main[2]/region[2]/navigation[4]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "navigation", "" @@ -404,7 +404,7 @@ "aria": "/document[1]/main[2]/region[2]/navigation[5]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "navigation", "" @@ -423,7 +423,7 @@ "aria": "/document[1]/main[2]/region[2]/navigation[6]" }, "reasonId": "Fail_0", - "message": "Multiple \"navigation\" landmarks with the same parent region are not distinguished from one another because they have the same \"\" label", + "message": "Multiple elements with \"navigation\" landmarks within the same parent region are not distinguished from one another because they have the same \"\" label", "messageArgs": [ "navigation", "" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail1.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail1.html index 314b58a06..e7bc7f953 100644 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail1.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail1.html @@ -40,7 +40,7 @@ "aria": "/document[1]/listitem[1]" }, "reasonId": "Fail_1", - "message": "The element with role \"listitem\" is not contained in or owned by an element with one of the following roles: \"list\"", + "message": "Element with \"listitem\" role is not contained in or owned by an element with one of the following roles: \"list\"", "messageArgs": [ "listitem", "list" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail2.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail2.html index 766cb1eb5..d0d29e378 100644 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail2.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail2.html @@ -45,7 +45,7 @@ "aria": "/document[1]/list[1]/tabpanel[1]/listitem[1]" }, "reasonId": "Fail_1", - "message": "The element with role \"listitem\" is not contained in or owned by an element with one of the following roles: \"list\"", + "message": "Element with \"listitem\" role is not contained in or owned by an element with one of the following roles: \"list\"", "messageArgs": [ "listitem", "list" @@ -64,7 +64,7 @@ "aria": "/document[1]/list[1]/tabpanel[1]/listitem[2]" }, "reasonId": "Fail_1", - "message": "The element with role \"listitem\" is not contained in or owned by an element with one of the following roles: \"list\"", + "message": "Element with \"listitem\" role is not contained in or owned by an element with one of the following roles: \"list\"", "messageArgs": [ "listitem", "list" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail3.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail3.html index 09b7d2ad5..3df4de3d3 100644 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail3.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail3.html @@ -45,7 +45,7 @@ "aria": "/document[1]/list[1]/generic[1]/listitem[1]" }, "reasonId": "Fail_1", - "message": "The element with role \"listitem\" is not contained in or owned by an element with one of the following roles: \"list\"", + "message": "Element with \"listitem\" role is not contained in or owned by an element with one of the following roles: \"list\"", "messageArgs": [ "listitem", "list" @@ -64,7 +64,7 @@ "aria": "/document[1]/list[1]/generic[1]/listitem[2]" }, "reasonId": "Fail_1", - "message": "The element with role \"listitem\" is not contained in or owned by an element with one of the following roles: \"list\"", + "message": "Element with \"listitem\" role is not contained in or owned by an element with one of the following roles: \"list\"", "messageArgs": [ "listitem", "list" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail4.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail4.html index 926ded207..6ce101a29 100644 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail4.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/aria_parent_required_ruleunit/ACT_ff89c9_fail4.html @@ -42,7 +42,7 @@ "aria": "/document[1]/listitem[1]" }, "reasonId": "Fail_1", - "message": "The element with role \"listitem\" is not contained in or owned by an element with one of the following roles: \"list\"", + "message": "Element with \"listitem\" role is not contained in or owned by an element with one of the following roles: \"list\"", "messageArgs": [ "listitem", "list" @@ -61,7 +61,7 @@ "aria": "/document[1]/listitem[2]" }, "reasonId": "Fail_1", - "message": "The element with role \"listitem\" is not contained in or owned by an element with one of the following roles: \"list\"", + "message": "Element with \"listitem\" role is not contained in or owned by an element with one of the following roles: \"list\"", "messageArgs": [ "listitem", "list" diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_orientation_unlocked_ruleunit/act-fail1.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_orientation_unlocked_ruleunit/act-fail1.html index 5c2fb6680..84eb35f17 100644 --- a/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_orientation_unlocked_ruleunit/act-fail1.html +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_orientation_unlocked_ruleunit/act-fail1.html @@ -1,4 +1,4 @@ - + Page with some content + +
+ Page Content
+ + + \ No newline at end of file diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_orientation_unlocked_ruleunit/act-pass3.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_orientation_unlocked_ruleunit/act-pass3.html new file mode 100644 index 000000000..bf6ead37f --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_orientation_unlocked_ruleunit/act-pass3.html @@ -0,0 +1,40 @@ + + + Page with some content + + + +
+ Page Content +
+ + + \ No newline at end of file diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_scrollable_tabbable_ruleunit/textarea_pass.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_scrollable_tabbable_ruleunit/textarea_pass.html new file mode 100644 index 000000000..7c97d9292 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_scrollable_tabbable_ruleunit/textarea_pass.html @@ -0,0 +1,46 @@ + + + + + test case + + + + + + + + \ No newline at end of file diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_scrollable_tabbable_ruleunit/textarea_pass2.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_scrollable_tabbable_ruleunit/textarea_pass2.html new file mode 100644 index 000000000..a8937f074 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/element_scrollable_tabbable_ruleunit/textarea_pass2.html @@ -0,0 +1,40 @@ + + + + + test case + + + + + + + + \ No newline at end of file diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/img_alt_null_ruleunit/Img-alt-arialabel.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/img_alt_null_ruleunit/Img-alt-arialabel.html new file mode 100755 index 000000000..ca1c31b51 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/img_alt_null_ruleunit/Img-alt-arialabel.html @@ -0,0 +1,33 @@ + + + Failed Example + + + + + + + + diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/label_name_visible_ruleunit/label_multiple_offscreen.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/label_name_visible_ruleunit/label_multiple_offscreen.html new file mode 100644 index 000000000..1331b14d5 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/label_name_visible_ruleunit/label_multiple_offscreen.html @@ -0,0 +1,44 @@ + + + + + test case + + +
+ 1st label + 2nd label + 3rd label + 4th label + 5th label6th label + 7th label + 8th label +
+ +
another line
+ + + + \ No newline at end of file diff --git a/accessibility-checker-engine/test/v2/checker/accessibility/rules/label_name_visible_ruleunit/label_offscreen.html b/accessibility-checker-engine/test/v2/checker/accessibility/rules/label_name_visible_ruleunit/label_offscreen.html new file mode 100644 index 000000000..b96435230 --- /dev/null +++ b/accessibility-checker-engine/test/v2/checker/accessibility/rules/label_name_visible_ruleunit/label_offscreen.html @@ -0,0 +1,59 @@ + + + + + test case + + + + + +
another line
+ + + + \ No newline at end of file diff --git a/accessibility-checker-extension/package-lock.json b/accessibility-checker-extension/package-lock.json index 85335fbdf..c581bf354 100644 --- a/accessibility-checker-extension/package-lock.json +++ b/accessibility-checker-extension/package-lock.json @@ -54,7 +54,7 @@ "url-loader": "^4.1.1", "use-resize-observer": "^8.0.0", "web-ext": "^8.0.0", - "webpack": "^5.79.0", + "webpack": "^5.94.0", "webpack-cli": "^4.9.1", "webpack-ext-reloader": "^1.1.9" } @@ -2351,30 +2351,30 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2386,9 +2386,9 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2798,28 +2798,10 @@ "@types/har-format": "*" } }, - "node_modules/@types/eslint": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.2.tgz", - "integrity": "sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw==", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/filesystem": { "version": "0.0.32", @@ -3013,133 +2995,133 @@ "dev": true }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -3248,10 +3230,10 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "peerDependencies": { "acorn": "^8" } @@ -3981,20 +3963,20 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "funding": [ { "type": "opencollective", @@ -4003,13 +3985,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -4171,9 +4157,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001467", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001467.tgz", - "integrity": "sha512-cEdN/5e+RPikvl9AHm4uuLXxeCNq8rFsQ+lPHTfe/OtypP3WwnVVbjn+6uBV7PaFL6xUFzTh+sSCOz1rKhcO+Q==", + "version": "1.0.30001653", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", + "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", "funding": [ { "type": "opencollective", @@ -4182,6 +4168,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -5648,9 +5638,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.332", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.332.tgz", - "integrity": "sha512-c1Vbv5tuUlBFp0mb3mCIjw+REEsgthRgNE8BlbEDKmvzb8rxjcVki6OkQP83vLN34s0XCxpSkq7AZNep1a6xhw==" + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -5676,9 +5666,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -5732,9 +5722,9 @@ "dev": true }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } @@ -6386,9 +6376,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -8505,9 +8495,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -9079,9 +9069,9 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -10859,12 +10849,12 @@ } }, "node_modules/terser": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.6.tgz", - "integrity": "sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -10876,15 +10866,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -11455,9 +11445,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "funding": [ { "type": "opencollective", @@ -11466,14 +11456,18 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -11918,33 +11912,32 @@ "dev": true }, "node_modules/webpack": { - "version": "5.79.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", - "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -12136,9 +12129,9 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -14178,27 +14171,27 @@ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" }, "dependencies": { "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } } } @@ -14209,9 +14202,9 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -14467,28 +14460,10 @@ "@types/har-format": "*" } }, - "@types/eslint": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.2.tgz", - "integrity": "sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw==", - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "@types/filesystem": { "version": "0.0.32", @@ -14680,133 +14655,133 @@ "dev": true }, "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "requires": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -14889,10 +14864,10 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "requires": {} }, "acorn-jsx": { @@ -15425,22 +15400,22 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" } }, "buffer": { @@ -15543,9 +15518,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001467", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001467.tgz", - "integrity": "sha512-cEdN/5e+RPikvl9AHm4uuLXxeCNq8rFsQ+lPHTfe/OtypP3WwnVVbjn+6uBV7PaFL6xUFzTh+sSCOz1rKhcO+Q==" + "version": "1.0.30001653", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", + "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==" }, "chainsaw": { "version": "0.1.0", @@ -16648,9 +16623,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.332", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.332.tgz", - "integrity": "sha512-c1Vbv5tuUlBFp0mb3mCIjw+REEsgthRgNE8BlbEDKmvzb8rxjcVki6OkQP83vLN34s0XCxpSkq7AZNep1a6xhw==" + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" }, "emoji-regex": { "version": "9.2.2", @@ -16673,9 +16648,9 @@ } }, "enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -16714,9 +16689,9 @@ "dev": true }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" }, "escape-goat": { "version": "4.0.0", @@ -17175,9 +17150,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -18776,9 +18751,9 @@ } }, "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "normalize-path": { "version": "3.0.0", @@ -19186,9 +19161,9 @@ "dev": true }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "picomatch": { "version": "2.3.1", @@ -20472,12 +20447,12 @@ } }, "terser": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.6.tgz", - "integrity": "sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -20490,15 +20465,15 @@ } }, "terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "requires": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "terser": "^5.26.0" }, "dependencies": { "ajv": { @@ -20920,12 +20895,12 @@ "dev": true }, "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" } }, "update-notifier": { @@ -21257,33 +21232,32 @@ "dev": true }, "webpack": { - "version": "5.79.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", - "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "requires": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "dependencies": { @@ -21324,9 +21298,9 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "requires": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", diff --git a/accessibility-checker-extension/package.json b/accessibility-checker-extension/package.json index 17fada385..0bd1efd4e 100644 --- a/accessibility-checker-extension/package.json +++ b/accessibility-checker-extension/package.json @@ -62,7 +62,7 @@ "url-loader": "^4.1.1", "use-resize-observer": "^8.0.0", "web-ext": "^8.0.0", - "webpack": "^5.79.0", + "webpack": "^5.94.0", "webpack-cli": "^4.9.1", "webpack-ext-reloader": "^1.1.9" }, diff --git a/accessibility-checker-extension/src/ts/background/backgroundController.ts b/accessibility-checker-extension/src/ts/background/backgroundController.ts index f1b0acfb4..fde450956 100644 --- a/accessibility-checker-extension/src/ts/background/backgroundController.ts +++ b/accessibility-checker-extension/src/ts/background/backgroundController.ts @@ -15,7 +15,7 @@ *****************************************************************************/ import { getDevtoolsController } from "../devtools/devtoolsController"; -import { IArchiveDefinition, IIssue, IMessage, IReport, IRuleset, ISessionState, ISettings } from "../interfaces/interfaces"; +import { IArchiveDefinition, IIssue, IMessage, IReport, IRuleset, ISessionState, ISettings, IssueValue } from "../interfaces/interfaces"; import { CommonMessaging } from "../messaging/commonMessaging"; import { Controller, eControllerType, ListenerType } from "../messaging/controller"; import Config from "../util/config"; @@ -394,6 +394,63 @@ class BackgroundController extends Controller { } delete result.node; } + + // Process report before returning it to avoid large message passing of pass messages + if (report) { + let valueMap: { [key: string]: { [key2: string]: string } } = { + "VIOLATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Needs review" + }, + "RECOMMENDATION": { + "POTENTIAL": "Recommendation", + "FAIL": "Recommendation", + "PASS": "Pass", + "MANUAL": "Recommendation" + }, + "INFORMATION": { + "POTENTIAL": "Needs review", + "FAIL": "Violation", + "PASS": "Pass", + "MANUAL": "Recommendation" + } + }; + + let valueToStringSingular = (value: IssueValue) => { + return valueMap[value[0]][value[1]]; + } + for (const result of report.results) { + if (result.ruleTime > 50) { + console.info(`[PERF: ${result.ruleId}] ${result.ruleTime}`); + } + } + // let passResults = []; + let remainResults = []; + let counts = { + "Violation": 0, + "Needs review": 0, + "Recommendation": 0, + "Pass": 0, + total: 0 + }; + let xpaths : string[] = report.results.map((result) => result.path.dom); + report.testedUniqueElements = Array.from(new Set(xpaths)).length; + for (const result of report.results) { + let sing = valueToStringSingular(result.value); + ++counts[sing as eLevel]; + ++counts.total; + if (result.value[1] === "PASS" && result.value[0] !== "INFORMATION") { + // passResults.push(result); + } else { + remainResults.push(result); + } + } + report.results = remainResults; + report.counts = counts; + } + return report; } catch (err) { console.error(err); @@ -418,11 +475,6 @@ class BackgroundController extends Controller { this.metrics.sendLogsV2(); getDevtoolsController(toolTabId, false, "remote").setScanningState("processing"); if (report) { - for (const result of report.results) { - if (result.ruleTime > 50) { - console.info(`[PERF: ${result.ruleId}] ${result.ruleTime}`); - } - } report.results.sort((resultA, resultB) => { let valueA = UtilIssue.valueToStringSingular(resultA.value); let valueB = UtilIssue.valueToStringSingular(resultB.value); @@ -435,29 +487,6 @@ class BackgroundController extends Controller { if (valueB === "Recommendation") return 1; return 0; }); - // let passResults = []; - let remainResults = []; - let counts = { - "Violation": 0, - "Needs review": 0, - "Recommendation": 0, - "Pass": 0, - total: 0 - }; - let xpaths : string[] = report.results.map((result) => result.path.dom); - report.testedUniqueElements = Array.from(new Set(xpaths)).length; - for (const result of report.results) { - let sing = UtilIssue.valueToStringSingular(result.value); - ++counts[sing as eLevel]; - ++counts.total; - if (result.value[1] === "PASS" && result.value[0] !== "INFORMATION") { - // passResults.push(result); - } else { - remainResults.push(result); - } - } - report.results = remainResults; - report.counts = counts; } getDevtoolsController(toolTabId, false, "remote").setReport(report); diff --git a/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx b/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx index 30e7395b1..f028f0137 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/reportTreeGrid.tsx @@ -837,8 +837,10 @@ export class ReportTreeGrid extends React.Component { + evt.stopPropagation(); this.onRow(group, thisIssue); this.devtoolsAppController.setSecondaryView("help"); this.devtoolsAppController.openSecondary(`#${rowId} a`); diff --git a/accessibility-checker-extension/test/package-lock.json b/accessibility-checker-extension/test/package-lock.json index 74b0184f6..5c044331b 100644 --- a/accessibility-checker-extension/test/package-lock.json +++ b/accessibility-checker-extension/test/package-lock.json @@ -984,9 +984,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", diff --git a/accessibility-checker/src-ts/lib/ACHelper.ts b/accessibility-checker/src-ts/lib/ACHelper.ts index ab1cd9ce3..6f68a2f0c 100644 --- a/accessibility-checker/src-ts/lib/ACHelper.ts +++ b/accessibility-checker/src-ts/lib/ACHelper.ts @@ -6,7 +6,7 @@ import { IConfigInternal } from "./common/config/IConfig"; import { ReporterManager } from "./common/report/ReporterManager"; import { existsSync, mkdirSync, writeFileSync } from "fs"; import { IAbstractAPI } from "./common/api-ext/IAbstractAPI"; -import { IBaselineReport, IEngineReport } from "./common/engine/IReport"; +import { EngineSummaryCounts, IBaselineReport, IEngineReport } from "./common/engine/IReport"; import { dirname, join, resolve as pathResolve } from "path"; import { BaselineManager, RefactorMap } from "./common/report/BaselineManager"; @@ -229,6 +229,50 @@ async function getComplianceHelperSelenium(label, parsed, curPol) : Promise { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; +} + +const getCounts = (engineReport) => { + let counts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; +} + + let policies = ${JSON.stringify(Config.policies)}; let checker = new window.ace_ibma.Checker(); @@ -238,7 +282,14 @@ setTimeout(function() { checker.check(document, policies).then(function(report) { for (const result of report.results) { delete result.node; + result.level = valueToLevel(result.value) } + report.summary ||= {}; + report.summary.counts ||= getCounts(report); + let reportLevels = ${JSON.stringify((Config.reportLevels || []).concat(Config.failLevels || []).map(lvl => lvl.toString()))}; + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + report.results = report.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); cb(report); }) },0) @@ -291,8 +342,50 @@ async function getComplianceHelperWebDriverIO(label, parsed, curPol) : Promise { + let report : IEngineReport = await page.executeAsync(({ policies, customRulesets, reportLevels }, done) => { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + + const getCounts = (engineReport) => { + let counts: EngineSummaryCounts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } + let checker = new (window as any).ace_ibma.Checker(); customRulesets.forEach((rs) => checker.addRuleset(rs)); return new Promise((resolve, reject) => { @@ -300,13 +393,19 @@ async function getComplianceHelperWebDriverIO(label, parsed, curPol) : Promise reportLevels.includes(result.level) || result.level !== "pass"); resolve(report); done(report); }) }, 0) }) - }, { policies: Config.policies, customRulesets: ACEngineManager.customRulesets }); + }, { policies: Config.policies, customRulesets: ACEngineManager.customRulesets, reportLevels: (Config.reportLevels || []).concat(Config.failLevels || []).map(lvl => lvl.toString()) }); if (curPol != null && !checkPolicy) { const valPolicies = ACEngineManager.customRulesets.map(rs => rs.id).concat(await page.execute(() => (new (window as any).ace_ibma.Checker().rulesetIds))); checkPolicy = true; @@ -347,8 +446,49 @@ async function getComplianceHelperPuppeteer(label, parsed, curPol) : Promise { - + let report : IEngineReport = await page.evaluate(({ policies, customRulesets, reportLevels }) => { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + + const getCounts = (engineReport) => { + let counts: EngineSummaryCounts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } + let checker = new (window as any).ace_ibma.Checker(); customRulesets.forEach((rs) => checker.addRuleset(rs)); return new Promise((resolve, reject) => { @@ -356,12 +496,18 @@ async function getComplianceHelperPuppeteer(label, parsed, curPol) : Promise reportLevels.includes(result.level) || result.level !== "pass"); resolve(report); }) }, 0) }) - }, { policies: Config.policies, customRulesets: ACEngineManager.customRulesets }); + }, { policies: Config.policies, customRulesets: ACEngineManager.customRulesets, reportLevels: (Config.reportLevels || []).concat(Config.failLevels || []).map(lvl => lvl.toString()) }); if (curPol != null && !checkPolicy) { const valPolicies = ACEngineManager.customRulesets.map(rs => rs.id).concat(await page.evaluate("new window.ace_ibma.Checker().rulesetIds")); checkPolicy = true; @@ -399,6 +545,48 @@ async function getComplianceHelperPuppeteer(label, parsed, curPol) : Promise { try { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + + const getCounts = (engineReport) => { + let counts: EngineSummaryCounts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } + let startScan = Date.now(); let checker = ACEngineManager.getChecker(); ACEngineManager.customRulesets.forEach((rs) => checker.addGuideline(rs)); @@ -406,7 +594,14 @@ async function getComplianceHelperLocal(label, parsed, curPol) : Promise lvl.toString()); + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + report.results = report.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); return report; }) diff --git a/accessibility-checker/test/baselines/Baseline_aChecker.Baseline.html.json b/accessibility-checker/test/baselines/Baseline_aChecker.Baseline.html.json index 3ecaefde0..d59eb3dd9 100644 --- a/accessibility-checker/test/baselines/Baseline_aChecker.Baseline.html.json +++ b/accessibility-checker/test/baselines/Baseline_aChecker.Baseline.html.json @@ -23,7 +23,7 @@ }, "snippet": "", "category": "Accessibility", - "ignored": false, + "ignored": true, "level": "violation", "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/html_lang_exists.html#%7B%22message%22%3A%22Page%20detected%20as%20HTML%2C%20but%20does%20not%20have%20a%20'lang'%20attribute%22%2C%22snippet%22%3A%22%3Chtml%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_3%22%2C%22ruleId%22%3A%22html_lang_exists%22%2C%22msgArgs%22%3A%5B%5D%7D" }, @@ -50,7 +50,7 @@ }, "snippet": "", "category": "Accessibility", - "ignored": false, + "ignored": true, "level": "potentialviolation", "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/html_skipnav_exists.html#%7B%22message%22%3A%22Verify%20there%20is%20a%20way%20to%20bypass%20blocks%20of%20content%20that%20are%20repeated%20on%20multiple%20Web%20pages%22%2C%22snippet%22%3A%22%3Chtml%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22POTENTIAL%22%5D%2C%22reasonId%22%3A%22Potential_1%22%2C%22ruleId%22%3A%22html_skipnav_exists%22%2C%22msgArgs%22%3A%5B%5D%7D" }, @@ -77,7 +77,7 @@ }, "snippet": "", "category": "Accessibility", - "ignored": false, + "ignored": true, "level": "violation", "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/page_title_exists.html#%7B%22message%22%3A%22Missing%20%3Ctitle%3E%20element%20in%20%3Chead%3E%20element%22%2C%22snippet%22%3A%22%3Chtml%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_2%22%2C%22ruleId%22%3A%22page_title_exists%22%2C%22msgArgs%22%3A%5B%5D%7D" }, @@ -91,7 +91,7 @@ "dom": "/html[1]", "aria": "/document[1]" }, - "ruleTime": 2, + "ruleTime": 1, "reasonId": "Pass_0", "message": "Rule Passed", "messageArgs": [], @@ -145,7 +145,7 @@ "dom": "/html[1]/head[1]", "aria": "/document[1]" }, - "ruleTime": 0, + "ruleTime": 1, "reasonId": "Pass_0", "message": "Rule Passed", "messageArgs": [], @@ -212,7 +212,7 @@ }, "snippet": "", "category": "Accessibility", - "ignored": false, + "ignored": true, "level": "violation", "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/skip_main_exists.html#%7B%22message%22%3A%22The%20page%20does%20not%20provide%20a%20way%20to%20quickly%20navigate%20to%20the%20main%20content%20(ARIA%20%5C%22main%5C%22%20landmark%20or%20a%20skip%20link)%22%2C%22snippet%22%3A%22%3Cbody%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_1%22%2C%22ruleId%22%3A%22skip_main_exists%22%2C%22msgArgs%22%3A%5B%5D%7D" }, @@ -226,7 +226,7 @@ "dom": "/html[1]/body[1]", "aria": "/document[1]" }, - "ruleTime": 0, + "ruleTime": 1, "reasonId": "Pass_0", "message": "Rule Passed", "messageArgs": [], @@ -334,7 +334,7 @@ "dom": "/html[1]/body[1]/img[1]", "aria": "/document[1]/img[1]" }, - "ruleTime": 0, + "ruleTime": 1, "reasonId": "Pass_0", "message": "Rule Passed", "messageArgs": [], @@ -374,7 +374,7 @@ }, "snippet": "", "category": "Accessibility", - "ignored": false, + "ignored": true, "level": "violation", "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/img_alt_valid.html#%7B%22message%22%3A%22The%20image%20has%20neither%20an%20accessible%20name%20nor%20is%20marked%20as%20decorative%20or%20redundant%22%2C%22snippet%22%3A%22%3Cimg%20id%3D%5C%22ace%5C%22%20src%3D%5C%22fail.png%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22fail_no_alt%22%2C%22ruleId%22%3A%22img_alt_valid%22%2C%22msgArgs%22%3A%5B%5D%7D" }, @@ -513,36 +513,6 @@ "level": "pass", "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/text_whitespace_valid.html#%7B%22message%22%3A%22Rule%20Passed%22%2C%22snippet%22%3A%22%3Cimg%20id%3D%5C%22ace%5C%22%20src%3D%5C%22fail.png%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22PASS%22%5D%2C%22reasonId%22%3A%22pass%22%2C%22ruleId%22%3A%22text_whitespace_valid%22%2C%22msgArgs%22%3A%5B%5D%7D" }, - { - "ruleId": "aria_accessiblename_exists", - "value": [ - "RECOMMENDATION", - "FAIL" - ], - "path": { - "dom": "/html[1]/body[1]/img[1]", - "aria": "/document[1]/img[1]" - }, - "ruleTime": 0, - "reasonId": "fail_no_accessible_name", - "message": "Element with \"img\" role has no accessible name", - "messageArgs": [ - "img", - "img" - ], - "apiArgs": [], - "bounds": { - "left": 8, - "top": 8, - "height": 0, - "width": 0 - }, - "snippet": "", - "category": "Accessibility", - "ignored": false, - "level": "recommendation", - "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/aria_accessiblename_exists.html#%7B%22message%22%3A%22Element%20%3Cimg%3E%20with%20%5C%22img%5C%22%20role%20has%20no%20accessible%20name%22%2C%22snippet%22%3A%22%3Cimg%20id%3D%5C%22ace%5C%22%20src%3D%5C%22fail.png%5C%22%3E%22%2C%22value%22%3A%5B%22RECOMMENDATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22fail_no_accessible_name%22%2C%22ruleId%22%3A%22aria_accessiblename_exists%22%2C%22msgArgs%22%3A%5B%22img%22%2C%22img%22%5D%7D" - }, { "ruleId": "aria_descendant_valid", "value": [ @@ -553,7 +523,7 @@ "dom": "/html[1]/body[1]/img[1]", "aria": "/document[1]/img[1]" }, - "ruleTime": 1, + "ruleTime": 0, "reasonId": "pass", "message": "The element contains valid descendants", "messageArgs": [], @@ -571,8 +541,8 @@ "help": "https://able.ibm.com/rules/archives/preview/doc/en-US/aria_descendant_valid.html#%7B%22message%22%3A%22The%20element%20contains%20valid%20descendants%22%2C%22snippet%22%3A%22%3Cimg%20id%3D%5C%22ace%5C%22%20src%3D%5C%22fail.png%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22PASS%22%5D%2C%22reasonId%22%3A%22pass%22%2C%22ruleId%22%3A%22aria_descendant_valid%22%2C%22msgArgs%22%3A%5B%5D%7D" } ], - "numExecuted": 21, - "ruleTime": 4, + "numExecuted": 20, + "ruleTime": 5, "nls": { "html_lang_exists": { "0": "Page must identify the default language of the document with a 'lang' attribute", @@ -618,10 +588,6 @@ "0": "Element 'id' attribute values must be unique within a document", "Pass_0": "Rule Passed" }, - "aria_accessiblename_exists": { - "0": "Elements with certain roles should have accessible names", - "fail_no_accessible_name": "Element <{0}> with \"{1}\" role has no accessible name" - }, "aria_descendant_valid": { "0": "Browsers ignore the explicit and implicit ARIA roles of the descendants of certain elements", "pass": "The element contains valid descendants" @@ -629,18 +595,18 @@ }, "summary": { "counts": { - "violation": 4, - "potentialviolation": 1, - "recommendation": 1, + "violation": 0, + "potentialviolation": 0, + "recommendation": 0, "potentialrecommendation": 0, "manual": 0, "pass": 15, - "ignored": 0, + "ignored": 5, "elements": 4, - "elementsViolation": 3, - "elementsViolationReview": 3 + "elementsViolation": 0, + "elementsViolationReview": 0 }, - "scanTime": 32, + "scanTime": 34, "ruleArchive": "Preview Rules (preview)", "policies": [ "IBM_Accessibility", @@ -654,10 +620,10 @@ "manual", "pass" ], - "startScan": 1716219646120, + "startScan": 1724686697450, "URL": "data:text/html;charset=utf-8,%3C!--%0A%20%20%20%20%20%2F******************************************************************************%0A%20%20%20%20%20Copyright%3A%3A%202020-%20IBM%2C%20Inc%0A%0A%20%20%20%20Licensed%20under%20the%20Apache%20License%2C%20Version%202.0%20(the%20%22License%22)%3B%0A%20%20%20%20you%20may%20not%20use%20this%20file%20except%20in%20compliance%20with%20the%20License.%0A%20%20%20%20You%20may%20obtain%20a%20copy%20of%20the%20License%20at%0A%0A%20%20%20%20http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0%0A%0A%20%20%20%20Unless%20required%20by%20applicable%20law%20or%20agreed%20to%20in%20writing%2C%20software%0A%20%20%20%20distributed%20under%20the%20License%20is%20distributed%20on%20an%20%22AS%20IS%22%20BASIS%2C%0A%20%20%20%20WITHOUT%20WARRANTIES%20OR%20CONDITIONS%20OF%20ANY%20KIND%2C%20either%20express%20or%20implied.%0A%20%20%20%20See%20the%20License%20for%20the%20specific%20language%20governing%20permissions%20and%0A%20%20%20%20limitations%20under%20the%20License.%0A%20%20*****************************************************************************%2F%0A%0A--%3E%20%20%20%20%0A%20%20%20%20%3Chtml%3E%0A%20%20%20%20%3Cbody%3E%0A%20%20%20%20%20%20%20%20%3Cimg%20src%3D%22fail.png%22%20id%3D%22ace%22%3E%0A%20%20%20%20%3C%2Fbody%3E%0A%3C%2Fhtml%3E" }, - "scanID": "e3856ce5-070e-4798-9dcc-9866c4468897", + "scanID": "5711a3a0-a763-4067-9eef-7f1db63cf8cb", "toolID": "accessibility-checker-v3.0.0", "label": "Baseline_aChecker.Baseline.html" } \ No newline at end of file diff --git a/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.js b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.js index 8de6d3187..2e2e69201 100644 --- a/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.js +++ b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.Puppeteer.test.js @@ -120,6 +120,10 @@ var skipList = [ // TODO: temprarily ignore till the issue is resolved: https://github.com/IBMa/equal-access/issues/1932 path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "aria_attribute_conflict_ruleunit","aria-hidden.html"), + + // Puppeteer and embedded-chrome @media css behave differently (?) + path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "element_orientation_unlocked_ruleunit","act-fail4.html"), + path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "element_orientation_unlocked_ruleunit","act-pass3.html") ] var skipMap = {} diff --git a/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.test.js b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.test.js index 86147e1e8..6dab68d37 100644 --- a/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.test.js +++ b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.Content.test.js @@ -106,7 +106,11 @@ var skipList = [ path.join(testRoot, "style_before_after_review_ruleunit", "D100.html"), // TODO: temprarily ignore till the issue is resolved: https://github.com/IBMa/equal-access/issues/1932 - path.join(testRoot, "aria_attribute_conflict_ruleunit","aria-hidden.html") + path.join(testRoot, "aria_attribute_conflict_ruleunit","aria-hidden.html"), + + // Puppeteer and embedded-chrome @media css behave differently (?) + path.join(testRoot, "element_orientation_unlocked_ruleunit","act-fail4.html"), + path.join(testRoot, "element_orientation_unlocked_ruleunit","act-pass3.html") ] var skipMap = {} diff --git a/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.URL.test.js b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.URL.test.js index 1936812ef..3c9458084 100644 --- a/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.URL.test.js +++ b/accessibility-checker/test/mocha/aChecker.Fast/aChecker.Scans/aChecker.URL.test.js @@ -108,7 +108,11 @@ var skipList = [ path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "style_before_after_review_ruleunit","D100.html"), // TODO: temprarily ignore till the issue is resolved: https://github.com/IBMa/equal-access/issues/1932 - path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "aria_attribute_conflict_ruleunit","aria-hidden.html") + path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "aria_attribute_conflict_ruleunit","aria-hidden.html"), + + // Puppeteer and embedded-chrome @media css behave differently (?) + path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "element_orientation_unlocked_ruleunit","act-fail4.html"), + path.join(process.cwd(), "..", "accessibility-checker-engine", "test", "v2", "checker", "accessibility", "rules", "element_orientation_unlocked_ruleunit","act-pass3.html") ] var skipMap = {} diff --git a/common/module/src/engine/IReport.ts b/common/module/src/engine/IReport.ts index 5c42187e4..b36abbbc3 100644 --- a/common/module/src/engine/IReport.ts +++ b/common/module/src/engine/IReport.ts @@ -65,6 +65,9 @@ export type IEngineReport = { [ruleId: string]: { [reasonId: string]: string } + }, + summary?: { + counts?: EngineSummaryCounts } } @@ -76,6 +79,28 @@ export type IBaselineResult = IEngineResult & { level: eRuleLevel } +export type EngineSummaryCounts = { + violation: number, + potentialviolation: number, + recommendation: number, + potentialrecommendation: number, + manual: number, + pass: number +} + +export type SummaryCounts = { + violation: number, + potentialviolation: number, + recommendation: number, + potentialrecommendation: number, + manual: number, + pass: number, + ignored: number, + elements: number, + elementsViolation: number, + elementsViolationReview: number +} + export type IBaselineReport = { results: IBaselineResult[] numExecuted: number, @@ -85,18 +110,7 @@ export type IBaselineReport = { } } summary: { - counts: { - violation: number, - potentialviolation: number, - recommendation: number, - potentialrecommendation: number, - manual: number, - pass: number, - ignored: number, - elements: number, - elementsViolation: number, - elementsViolationReview: number - } + counts: SummaryCounts, scanTime: number, ruleArchive: string policies: string[] @@ -120,7 +134,8 @@ export type CompressedReport = [ string, // ruleArchive string[], // policies string[], // reportLevels - CompressedIssue[] + CompressedIssue[], + SummaryCounts ] export type CompressedIssue = [ // results diff --git a/common/module/src/engine/IRule.ts b/common/module/src/engine/IRule.ts index f10a64d8c..dd65ba100 100644 --- a/common/module/src/engine/IRule.ts +++ b/common/module/src/engine/IRule.ts @@ -99,7 +99,8 @@ export type Issue = RuleResult & { ruleTime: number, message: string, bounds?: Bounds, - snippet: string + snippet: string, + level?: string } export type RuleContextHierarchy = { [namespace: string] : IMapResult[] }; diff --git a/common/module/src/report/ReporterManager.ts b/common/module/src/report/ReporterManager.ts index 605fc8a5c..d914e27f9 100644 --- a/common/module/src/report/ReporterManager.ts +++ b/common/module/src/report/ReporterManager.ts @@ -105,7 +105,8 @@ export class ReporterManager { report.engineReport.summary.ruleArchive, // 7 report.engineReport.summary.policies, // 8 report.engineReport.summary.reportLevels, // 9 - compressedResults // 10 + compressedResults, // 10 + report.engineReport.summary.counts // 11 ] for (let idx=0; idx 32000) { @@ -151,18 +152,7 @@ export class ReporterManager { numExecuted: report[5], nls, summary: { - counts: { - violation: 0, - potentialviolation: 0, - recommendation: 0, - potentialrecommendation: 0, - manual: 0, - pass: 0, - ignored: 0, - elements: 0, - elementsViolation: 0, - elementsViolationReview: 0 - }, + counts: report[11], scanTime: report[6], ruleArchive: report[7], policies: report[8], @@ -174,7 +164,6 @@ export class ReporterManager { toolID: ReporterManager.toolID, label: report[3] } - engineReport.summary.counts = ReporterManager.getCounts(engineReport); return { startScan: report[0], url: report[1], @@ -389,8 +378,10 @@ export class ReporterManager { } }); - (retVal as any).summary = {}; - retVal.summary.counts = ReporterManager.getCounts(retVal); + (retVal as any).summary = { + counts: engineResult.summary.counts + }; + retVal.summary.counts = ReporterManager.addCounts(retVal); retVal.results = retVal.results.filter(pageResult => { if (ReporterManager.config.reportLevels.includes(pageResult.level)) { @@ -427,18 +418,13 @@ export class ReporterManager { return retVal; } - private static getCounts(engineReport: IBaselineReport) { + private static addCounts(engineReport: IBaselineReport) { let counts = { - violation: 0, - potentialviolation: 0, - recommendation: 0, - potentialrecommendation: 0, - manual: 0, - pass: 0, ignored: 0, elements: 0, elementsViolation: 0, - elementsViolationReview: 0 + elementsViolationReview: 0, + ...engineReport.summary.counts } let elementSet = new Set(); let elementViolationSet = new Set(); @@ -447,8 +433,8 @@ export class ReporterManager { elementSet.add(issue.path.dom); if (issue.ignored) { ++counts.ignored; + --counts[issue.level.toString()]; } else { - ++counts[issue.level.toString()]; if (issue.level === eRuleLevel.violation) { elementViolationSet.add(issue.path.dom); elementViolationReviewSet.add(issue.path.dom); diff --git a/cypress-accessibility-checker/package-lock.json b/cypress-accessibility-checker/package-lock.json index 907868c68..fcbcfd3b6 100644 --- a/cypress-accessibility-checker/package-lock.json +++ b/cypress-accessibility-checker/package-lock.json @@ -582,12 +582,12 @@ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } diff --git a/cypress-accessibility-checker/src/lib/ACCommands.js b/cypress-accessibility-checker/src/lib/ACCommands.js index 87a573493..ced1ae95c 100644 --- a/cypress-accessibility-checker/src/lib/ACCommands.js +++ b/cypress-accessibility-checker/src/lib/ACCommands.js @@ -16,6 +16,47 @@ let logger = { create: loggerCreate }; +function valueToLevel(reportValue) { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; +} + +function getCounts(engineReport) { + let counts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; +} + let ACCommands = module.exports = { DEBUG: false, initialize: (win, fileConfig) => { @@ -107,7 +148,14 @@ let ACCommands = module.exports = { .then(function (report) { for (const result of report.results) { delete result.node; + result.level = valueToLevel(result.value) } + report.summary ||= {}; + report.summary.counts ||= getCounts(report); + let reportLevels = (ACCommands.Config.reportLevels || []).concat(ACCommands.Config.failLevels || []); + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + report.results = report.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); return report; }) } catch (err) { diff --git a/cypress-accessibility-checker/test/baselines/violations.json b/cypress-accessibility-checker/test/baselines/violations.json index 9d1b3891f..b5489abdf 100644 --- a/cypress-accessibility-checker/test/baselines/violations.json +++ b/cypress-accessibility-checker/test/baselines/violations.json @@ -107,39 +107,9 @@ "ignored": true, "level": "violation", "help": "https://able.ibm.com/rules/archives/2024.08.06/doc/en-US/img_alt_valid.html#%7B%22message%22%3A%22The%20image%20has%20neither%20an%20accessible%20name%20nor%20is%20marked%20as%20decorative%20or%20redundant%22%2C%22snippet%22%3A%22%3Cimg%20src%3D%5C%22missing-alt.jpg%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22fail_no_alt%22%2C%22ruleId%22%3A%22img_alt_valid%22%2C%22msgArgs%22%3A%5B%5D%7D" - }, - { - "ruleId": "aria_accessiblename_exists", - "value": [ - "RECOMMENDATION", - "FAIL" - ], - "path": { - "dom": "/html[1]/body[1]/img[1]", - "aria": "/document[1]/img[1]" - }, - "ruleTime": 0, - "reasonId": "fail_no_accessible_name", - "message": "Element with \"img\" role has no accessible name", - "messageArgs": [ - "img", - "img" - ], - "apiArgs": [], - "bounds": { - "left": 16, - "top": 133, - "height": 32, - "width": 32 - }, - "snippet": "", - "category": "Accessibility", - "ignored": true, - "level": "recommendation", - "help": "https://able.ibm.com/rules/archives/2024.08.06/doc/en-US/aria_accessiblename_exists.html#%7B%22message%22%3A%22Element%20%3Cimg%3E%20with%20%5C%22img%5C%22%20role%20has%20no%20accessible%20name%22%2C%22snippet%22%3A%22%3Cimg%20src%3D%5C%22missing-alt.jpg%5C%22%3E%22%2C%22value%22%3A%5B%22RECOMMENDATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22fail_no_accessible_name%22%2C%22ruleId%22%3A%22aria_accessiblename_exists%22%2C%22msgArgs%22%3A%5B%22img%22%2C%22img%22%5D%7D" } ], - "numExecuted": 31, + "numExecuted": 30, "ruleTime": 0, "nls": { "html_lang_exists": { @@ -154,10 +124,6 @@ "0": "Pages must provide a way to skip directly to the main content", "Fail_1": "The page does not provide a way to quickly navigate to the main content (ARIA \"main\" landmark or a skip link)" }, - "aria_accessiblename_exists": { - "0": "Elements with certain roles should have accessible names", - "fail_no_accessible_name": "Element <{0}> with \"{1}\" role has no accessible name" - }, "img_alt_valid": { "0": "Images must have accessible names unless they are decorative or redundant", "fail_no_alt": "The image has neither an accessible name nor is marked as decorative or redundant" @@ -171,7 +137,7 @@ "potentialrecommendation": 0, "manual": 0, "pass": 26, - "ignored": 5, + "ignored": 4, "elements": 7, "elementsViolation": 0, "elementsViolationReview": 0 @@ -188,10 +154,10 @@ "potentialrecommendation", "manual" ], - "startScan": 1723480681453, + "startScan": 1724696836617, "URL": "http://localhost:8080/test/sample-html/violations.html" }, - "scanID": "03c0fc62-453a-4b6c-a2b2-869c2818e5ea", + "scanID": "3287e266-6c7a-41d9-8e27-62d66146ad2b", "toolID": "cypress-accessibility-checker-v3.0.0", "label": "violations" } \ No newline at end of file diff --git a/java-accessibility-checker/.gitattributes b/java-accessibility-checker/.gitattributes new file mode 100644 index 000000000..a777e6858 --- /dev/null +++ b/java-accessibility-checker/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/java-accessibility-checker/.gitignore b/java-accessibility-checker/.gitignore new file mode 100644 index 000000000..1364bf4a5 --- /dev/null +++ b/java-accessibility-checker/.gitignore @@ -0,0 +1,5 @@ +.mvn +results +target +settings.xml +*.gpg \ No newline at end of file diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md new file mode 100644 index 000000000..d1bcffc17 --- /dev/null +++ b/java-accessibility-checker/README-DEV.md @@ -0,0 +1,47 @@ +Deployments found at https://central.sonatype.com/publishing/deployments + +## Example maven commands + +Run all tests: +``` +mvn test +``` + +Run specific test +``` +mvn test -Dtest="TheSecondUnitTest#whenTestCase2_thenPrintTest2_1" +``` + +Deploy +``` +mvn -s ./settings.xml clean deploy -Dgpg.passphrase=yourpassphrase +``` + +Deployments show up on https://central.sonatype.com/publishing/deployments and then they can be Dropped or Published. Once Published, they cannot be Dropped. + +Generate javadoc for local review (files in target/site/apidocs/) +``` +mvn javadoc:javadoc +``` + +## PGP Key Management + +Generate PGP key: +``` +gpg --gen-key +> Real name: IBM Accessibility +> Email address: eatools@us.ibm.com +gpg --armor --output public-key.gpg --export eatools@us.ibm.com +``` +Go to https://keyserver.ubuntu.com/, Click `Submit Key`, and paste in public-key.gpg + +Export private key: +``` +gpg --export-secret-keys -a 7A58C8C58C35FF078630FA3615954E19FBC774C4 +``` + +Verify Key: +``` +gpg --list-signatures +``` +Go to https://keyserver.ubuntu.com/pks/lookup?search=7A58C8C58C35FF078630FA3615954E19FBC774C4&fingerprint=on&op=index and replace `7A58C8C58C35FF078630FA3615954E19FBC774C4` with the key signature \ No newline at end of file diff --git a/java-accessibility-checker/boilerplates/junit-playwright/.gitattributes b/java-accessibility-checker/boilerplates/junit-playwright/.gitattributes new file mode 100644 index 000000000..f91f64602 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/java-accessibility-checker/boilerplates/junit-playwright/.gitignore b/java-accessibility-checker/boilerplates/junit-playwright/.gitignore new file mode 100644 index 000000000..1b6985c00 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradle/libs.versions.toml b/java-accessibility-checker/boilerplates/junit-playwright/gradle/libs.versions.toml new file mode 100644 index 000000000..ab0036d1b --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradle/libs.versions.toml @@ -0,0 +1,12 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +commons-math3 = "3.6.1" +guava = "33.1.0-jre" +junit = "4.13.2" + +[libraries] +commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } +junit = { module = "junit:junit", version.ref = "junit" } diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.jar b/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..2c3521197 Binary files /dev/null and b/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.jar differ diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.properties b/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..09523c0e5 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradlew b/java-accessibility-checker/boilerplates/junit-playwright/gradlew new file mode 100755 index 000000000..f5feea6d6 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradlew.bat b/java-accessibility-checker/boilerplates/junit-playwright/gradlew.bat new file mode 100644 index 000000000..9d21a2183 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/.gitignore b/java-accessibility-checker/boilerplates/junit-playwright/lib/.gitignore new file mode 100644 index 000000000..872aa273a --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/.gitignore @@ -0,0 +1 @@ +results \ No newline at end of file diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle new file mode 100644 index 000000000..18de9eba5 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle @@ -0,0 +1,39 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java library project to get you started. + * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.9/userguide/building_java_projects.html in the Gradle documentation. + */ + +plugins { + id 'java-library' +} + +group 'com.foo' +version '1.0.0' + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Use JUnit test framework. + testImplementation libs.junit + + implementation 'com.microsoft.playwright:playwright:1.46.0' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-4' +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +test { + testLogging { + showStandardStreams = true + } +} diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/src/main/java/com/foo/SomeClassPlaywright.java b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/main/java/com/foo/SomeClassPlaywright.java new file mode 100644 index 000000000..9183700fd --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/main/java/com/foo/SomeClassPlaywright.java @@ -0,0 +1,23 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.foo; + +public class SomeClassPlaywright { + + public boolean someFunction() { + return true; + } +} diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/src/test/java/com/foo/SomeClassPlaywrightTest.java b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/test/java/com/foo/SomeClassPlaywrightTest.java new file mode 100644 index 000000000..57e961a8c --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/test/java/com/foo/SomeClassPlaywrightTest.java @@ -0,0 +1,63 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.foo; + +import org.junit.Test; +import static org.junit.Assert.*; + +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import com.ibm.able.equalaccess.AccessibilityChecker; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; +import com.microsoft.playwright.*; + +public class SomeClassPlaywrightTest { + private static Page driver; + + /** + * Setup a Playwright Chromium environment before tests + */ + @BeforeClass public static void setup() { + try { + Playwright playwright = Playwright.create(); + Browser browser = playwright.chromium().launch(); + driver = browser.newPage(); + } catch (Throwable err) { + System.err.println(err.toString()); + err.printStackTrace(); + } + } + + /** + * Close Playwright environment after tests + */ + @AfterClass public static void teardown() { + SomeClassPlaywrightTest.driver.close(); + AccessibilityChecker.close(); + } + + @Test public void getCompliance() { + SomeClassPlaywrightTest.driver.navigate("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + + ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); + eAssertResult resultCode = AccessibilityChecker.assertCompliance(report); + // The page has compliance issues, so this assert should fail + assertEquals("Scan resulted in "+resultCode.toString(), eAssertResult.PASS, resultCode); + } +} diff --git a/java-accessibility-checker/boilerplates/junit-playwright/settings.gradle b/java-accessibility-checker/boilerplates/junit-playwright/settings.gradle new file mode 100644 index 000000000..7665fe699 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/settings.gradle @@ -0,0 +1,14 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.9/userguide/multi_project_builds.html in the Gradle documentation. + */ + +plugins { + // Apply the foojay-resolver plugin to allow automatic download of JDKs + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +rootProject.name = 'java-accessibility-checker-boilerplate-playwright' +include('lib') diff --git a/java-accessibility-checker/boilerplates/junit-selenium/.gitattributes b/java-accessibility-checker/boilerplates/junit-selenium/.gitattributes new file mode 100644 index 000000000..f91f64602 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/java-accessibility-checker/boilerplates/junit-selenium/.gitignore b/java-accessibility-checker/boilerplates/junit-selenium/.gitignore new file mode 100644 index 000000000..1b6985c00 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradle/libs.versions.toml b/java-accessibility-checker/boilerplates/junit-selenium/gradle/libs.versions.toml new file mode 100644 index 000000000..ab0036d1b --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradle/libs.versions.toml @@ -0,0 +1,12 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +commons-math3 = "3.6.1" +guava = "33.1.0-jre" +junit = "4.13.2" + +[libraries] +commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } +junit = { module = "junit:junit", version.ref = "junit" } diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.jar b/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..2c3521197 Binary files /dev/null and b/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.jar differ diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.properties b/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..09523c0e5 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradlew b/java-accessibility-checker/boilerplates/junit-selenium/gradlew new file mode 100755 index 000000000..f5feea6d6 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradlew.bat b/java-accessibility-checker/boilerplates/junit-selenium/gradlew.bat new file mode 100644 index 000000000..9d21a2183 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/.gitignore b/java-accessibility-checker/boilerplates/junit-selenium/lib/.gitignore new file mode 100644 index 000000000..872aa273a --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/.gitignore @@ -0,0 +1 @@ +results \ No newline at end of file diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle new file mode 100644 index 000000000..53f9c854c --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -0,0 +1,40 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java library project to get you started. + * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.9/userguide/building_java_projects.html in the Gradle documentation. + */ + +plugins { + id 'java-library' +} + +group 'com.foo' +version '1.0.0' + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Use JUnit test framework. + testImplementation libs.junit + + // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java + implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-4' +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +test { + testLogging { + showStandardStreams = true + } +} diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClassSelenium.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClassSelenium.java new file mode 100644 index 000000000..e509be553 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClassSelenium.java @@ -0,0 +1,23 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.foo; + +public class SomeClassSelenium { + + public boolean someFunction() { + return true; + } +} diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassSeleniumTest.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassSeleniumTest.java new file mode 100644 index 000000000..c2a02072c --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassSeleniumTest.java @@ -0,0 +1,74 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.foo; + +import org.junit.Test; +import static org.junit.Assert.*; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.openqa.selenium.SessionNotCreatedException; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; + +import com.ibm.able.equalaccess.AccessibilityChecker; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; + +public class SomeClassSeleniumTest { + private static ChromeDriver driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + String workingDir = System.getProperty("user.dir"); + String chromeDriverDir = System.getenv("chromedriverpath"); + ChromeOptions options = new ChromeOptions(); + if (chromeDriverDir == null) { + chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + } else { + options.setBinary(System.getenv("chromebinpath")); + } + System.setProperty("webdriver.chrome.driver", chromeDriverDir); + options.addArguments("--headless=new"); + try { + SomeClassSeleniumTest.driver = new ChromeDriver(options); + } catch (SessionNotCreatedException e) { + System.out.println(e.getMessage()); + System.out.println(e.getAdditionalInformation()); + throw e; + } + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + SomeClassSeleniumTest.driver.close(); + AccessibilityChecker.close(); + } + + @Test public void getCompliance() { + SomeClassSeleniumTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + + ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); + eAssertResult resultCode = AccessibilityChecker.assertCompliance(report); + // The page has compliance issues, so this assert should fail + assertEquals("Scan resulted in "+resultCode.toString(), eAssertResult.PASS, resultCode); + } +} diff --git a/java-accessibility-checker/boilerplates/junit-selenium/settings.gradle b/java-accessibility-checker/boilerplates/junit-selenium/settings.gradle new file mode 100644 index 000000000..9e57c289e --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/settings.gradle @@ -0,0 +1,14 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.9/userguide/multi_project_builds.html in the Gradle documentation. + */ + +plugins { + // Apply the foojay-resolver plugin to allow automatic download of JDKs + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +rootProject.name = 'java-accessibility-checker-boilerplate-selenium' +include('lib') diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml new file mode 100644 index 000000000..529001e71 --- /dev/null +++ b/java-accessibility-checker/pom.xml @@ -0,0 +1,173 @@ + + + 4.0.0 + + com.ibm.able + accessibility-checker + 3.0.0 + jar + + accessibility-checker + A module that allows you to perform integrated accessibility testing for environments such as JUnit and Selenium + https://www.ibm.com/able/toolkit/tools/ + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + scm:git:git://github.com/IBMa/equal-access.git + scm:git:ssh://github.com:IBMa/equal-access.git + http://github.com/IBMa/equal-access/tree/master + + + + UTF-8 + 17 + 17 + 17 + + + + + + org.junit + junit-bom + 5.11.0 + pom + import + + + + + + + + junit + junit + 4.13.2 + test + + + + + + + com.google.code.gson + gson + 2.11.0 + + + org.mozilla + rhino + 1.7.14 + + + org.seleniumhq.selenium + selenium-java + 4.23.0 + provided + + + com.microsoft.playwright + playwright + 1.46.0 + provided + + + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + --pinentry-mode + loopback + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.5.0 + true + + central + + + + + + + + + Tom Brunet + thbrunet@us.ibm.com + IBM Accessibility + http://ibm.com/able + + + \ No newline at end of file diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java new file mode 100644 index 000000000..2cdefd2a7 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java @@ -0,0 +1,211 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.Config; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.enginecontext.EngineContextManager; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; +import com.ibm.able.equalaccess.report.BaselineManager; +import com.ibm.able.equalaccess.report.ReporterManager; +import com.ibm.able.equalaccess.report.BaselineManager.DiffResult; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; +import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.abs.MyFS; + +/** + * The main checker object. See the .jar overview for usage information. + */ +public class AccessibilityChecker { + private AccessibilityChecker() {} + + private static boolean initialized = false; + private static IAbstractAPI myFS = new MyFS(); + private static IEngineContext localEngine; + + + /** + * Perform a scan of the provided context. + * + * Currently supported content contexts: org.openqa.selenium.WebDriver, com.microsoft.playwright.Page. + * @param content The page to scan. + * @param label Provide a label for the scan that is being performed + * @return Resulting report + */ + public static ACReport getCompliance(Object content, String label) { + if (content == null) { + System.err.println("aChecker: Unable to get compliance of null or undefined object"); + return null; + } + + AccessibilityChecker.initialize(); + + IEngineContext engineContext = EngineContextManager.getEngineContext(content); + + // Get the Data when the scan is started + // Start time will be in milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now. + long startScan = new Date().getTime(); + ACEReport origReport = engineContext.getCompliance(label); + String url = engineContext.getUrl(); + String title = engineContext.getTitle(); + ACReport finalReport = ReporterManager.get().addEngineReport(engineContext.getProfile(), startScan, url, title, label, origReport); + return finalReport; + } + + /** + * Close the checker and ensure all summary reports are generated + */ + public static void close() { + ReporterManager.get().generateSummaries(); + } + + + /** + * Check the scan results against configured failLevels or against a previously set baseline. + * @param report Report generated by getCompliance + * @return - 0 if report matches baseline, or no issues match failLevels + * - 1 results do not match baseline results + * - 2 failure based on failLevels (this means no baseline found) + */ + public static eAssertResult assertCompliance(ACReport report) { + return BaselineManager.assertCompliance(report); + } + + /** + * Get the processed configuration object + * @return Current configuration set for the checker + */ + public static Config getConfig() { + return ACConfigManager.getConfig(); + } + + /** + * Get a processed configuration object that include properties used internally to the checker + * @return Current configuration set for the checker + */ + public static ConfigInternal getConfigUnsupported() { + return ACConfigManager.getConfigUnsupported(); + } + + /** + * This function is responsible for getting the diff results based on label for a scan that was already performed. + * + * @param label Provide a label for which to get the diff results for. + * + * @return return the diff results object from global space based on label provided, the object will be + * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. + */ + public static DiffResult[] getDiffResults(String label) { + return BaselineManager.getDiffResults(label); + } + + /** + * This function is responsible for getting the baseline object for a label that was provided. + * + * @param label Provide a label for which to get the baseline for. + * + * @return return the baseline object from global space based on label provided, the object will be + * in the same format as outlined in the return of aChecker.buildReport function. + */ + public static ACReport getBaseline(String label) { + return BaselineManager.getBaseline(label); + } + + /** + * This function is responsible for comparing actual with expected and returning all the differences as an array. + * + * @param actual Provide the actual object to be used for compare + * @param expected Provide the expected object to be used for compare + * + * @return differences - return an array of diff objects that were found, following is the format of the object: + * [ + * { + * "kind": "E", + * "path": [ + * "reports", + * 0, + * "issues", + * 10, + * "xpath" + * ], + * "lhs": "/html[1]/body[1]/div[2]/table[5]", + * "rhs": "/html[1]/body[1]/div[2]/table[5]d", + * }, + * { + * "kind": "E", + * "path": [ + * "label" + * ], + * "lhs": "Table-layoutMultiple", + * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html", + * } + * ] + */ + public static DiffResult[] diffResultsWithExpected(ACReport actual, ACReport expected) { + return BaselineManager.diffResultsWithExpected(actual, expected); + } + +// export function addRuleset(ruleset) { +// ACEngineManager.addRuleset(ruleset); +// } + + public static Guideline getGuideline(String rsId) { + Guideline[] gs = getGuidelines(); + for (int i=0; i refactorMap = new HashMap<>(); + Rule[] rules = localEngine.getRules(); + for (Rule rule: rules) { + if (rule.refactor != null) { + for (String key: rule.refactor.keySet()) { + refactorMap.put(key, rule); + } + } + } + ConfigInternal config = getConfigUnsupported(); + ReporterManager.initialize(config, myFS, localEngine.getGuidelines()); + BaselineManager.initialize(config, myFS, refactorMap); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> AccessibilityChecker.close() )); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java new file mode 100644 index 000000000..df2e47a6b --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java @@ -0,0 +1,27 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.abs; + +import java.io.File; +import java.io.IOException; + +import com.ibm.able.equalaccess.engine.ACReport; + +public interface IAbstractAPI { + public ACReport loadBaseline(String scanLabel); + public File prepFile(String filePath); + public void writeFile(String path, Object contents) throws IOException; +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java new file mode 100644 index 000000000..956c41a7f --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java @@ -0,0 +1,70 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.abs; + +import com.ibm.able.equalaccess.engine.ACReport; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.ConfigInternal; + +public class MyFS implements IAbstractAPI { + public static Gson gson = new Gson(); + + @Override + public void writeFile(String filePath, Object contents) throws IOException { + File outFile = this.prepFile(filePath); + FileWriter myWriter = new FileWriter(outFile); + myWriter.write(contents.toString()); + myWriter.close(); + } + + @Override + public File prepFile(String filePath) { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + Path outFile = Paths.get(System.getProperty("user.dir"), config.outputFolder, filePath); + File f = outFile.toFile(); + File dir = f.getParentFile(); + if (!dir.exists()) { + dir.mkdirs(); + } + return f; + } + + @Override + public ACReport loadBaseline(String scanLabel) { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + Path outPath = Paths.get(System.getProperty("user.dir"), config.baselineFolder, scanLabel+".json"); + File outFile = outPath.toFile(); + if (!outFile.exists()) return null; + JsonReader reader; + try { + reader = new JsonReader(new FileReader(outFile)); + } catch (FileNotFoundException e) { + return null; + } + return gson.fromJson(reader, ACReport.class); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java new file mode 100644 index 000000000..102e1f5ac --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java @@ -0,0 +1,372 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.equalaccess.config; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.regex.Pattern; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.ibm.able.equalaccess.util.Fetch; +import com.ibm.able.equalaccess.util.Misc; + +public class ACConfigManager { + public static final String ARCHIVE_LATEST = "latest"; + public static final String ARCHIVE_PREVIEW = "preview"; + public static final String ARCHIVE_VERSIONED = "versioned"; + + private ACConfigManager() {} + + private static class ConfigError extends Error { + ConfigError(String message) { + super(message); + } + + } + + /** + * negative if versionA is less than versionB, positive if versionA is greater than versionB, and zero if they are equal. NaN is treated as 0. + * @param versionA + * @param versionB + */ + public static int compareVersions(String versionA, String versionB) { + Pattern versionRE = Pattern.compile("[0-9.]+(-rc\\.[\\d]+)?"); + versionA = versionA.trim(); + versionB = versionB.trim(); + if (!versionRE.matcher(versionA).matches()) throw new ConfigError("Invalid version"); + if (!versionRE.matcher(versionB).matches()) throw new ConfigError("Invalid version"); + if (versionA.equals(versionB)) return 0; + // Get x.y.z-rc.a into [x.y.z, a] + // Get x.y.z into [x.y.z] + String[] split1A = versionA.split("-rc\\."); + String[] split1B = versionB.split("-rc\\."); + // Get x.y.z into [x,y,z] + String[] split2A = split1A[0].split("\\."); + String[] split2B = split1B[0].split("\\."); + + // For the components of the shortest version - can only compare numbers we have + int minLength = Math.min(split2A.length, split2B.length); + for (int idx=0; idx= 0) { + return archive.id; + } + } + // Something wrong, go with the latest + return ARCHIVE_LATEST; + } + + /** + * This function is responsible processing the achecker config which was initialized to make sure it contains, + * information which matches what the engine reads. + * + * i.e. + * Need to change reportLevels and failLevels to match with level Declarations in the engine. + * replace violation with level.violation + * Need to change array of policies into a string + * ["CI162_5_2_DCP070116","CI162_5_2_DCP070116"] to "CI162_5_2_DCP070116,CI162_5_2_DCP070116" + * + * @param acConfig Provide the config object in which needs to be processed. + * + * @return ConfigInternal - return the config object which has been made engine readable + */ + private static ConfigInternal processACConfig(ConfigInternal acConfig) throws IOException { + String[] validArchiveKeywords = { ARCHIVE_LATEST, ARCHIVE_PREVIEW, ARCHIVE_VERSIONED }; + String ruleServer = acConfig.ruleServer; + + // Get and parse the rule archive. + String ruleArchiveFile = String.format("%s%s/archives.json",ruleServer,ruleServer.contains("jsdelivr.net")?"@next":""); + + Archive[] ruleArchiveParse; + try { + ruleArchiveParse = Fetch.getJSONArr(ruleArchiveFile, Archive[].class, acConfig.ignoreHTTPSErrors); + } catch (Error err) { + System.err.println(ruleArchiveFile); + System.err.println(err.toString()); + err.printStackTrace(); + throw err; + } + String ruleArchivePath = null; + if (ruleArchiveParse.length > 0) { + if (acConfig.DEBUG) System.out.println("Found archiveFile: " + ruleArchiveFile); + acConfig.ruleArchiveSet = ruleArchiveParse; + String ruleArchive = acConfig.ruleArchive; + // If the user asked us to sync the rule version with the tool version, we need to figure out what the last rule version was + if (ARCHIVE_VERSIONED.equals(ruleArchive)) { + if (acConfig.toolVersion == null) { + ruleArchive = ARCHIVE_LATEST; + } else { + ruleArchive = findLatestArchiveId(acConfig.ruleArchiveSet, acConfig.toolVersion); + } + } + acConfig.ruleArchiveLabel = acConfig.ruleArchive; + for (int i = 0; i < acConfig.ruleArchiveSet.length; i++) { + if (ruleArchive.equals(acConfig.ruleArchiveSet[i].id) && !acConfig.ruleArchiveSet[i].sunset) { + ruleArchivePath = acConfig.ruleArchiveSet[i].path; + acConfig.ruleArchiveVersion = acConfig.ruleArchiveSet[i].version; + acConfig.ruleArchiveLabel = ruleArchiveParse[i].name + " (" + ruleArchiveParse[i].id + ")"; + break; + } + } + if (ruleArchivePath == null || acConfig.ruleArchiveVersion == null) { + String errStr = "[ERROR] RuleArchiveInvalid: Make Sure correct rule archive is provided in the configuration file. More information is available in the README.md"; + System.err.println(errStr); + throw new ConfigError(errStr); + } + for (int i = 0; i < acConfig.ruleArchiveSet.length; i++) { + if (acConfig.ruleArchiveVersion.equals(acConfig.ruleArchiveSet[i].version) + && !Arrays.asList(validArchiveKeywords).contains(acConfig.ruleArchiveSet[i].id)) + { + acConfig.ruleArchivePath = acConfig.ruleArchiveSet[i].path; + break; + } + } + } else { + String errStr = "[ERROR] UnableToParseArchive: Archives are unable to be parse. Contact support team."; + System.err.println(errStr); + throw new ConfigError(errStr); + } + + // Build the new rulePack based of the baseA11yServerURL + if (acConfig.rulePack == null || "".equals(acConfig.rulePack)) { + if (ruleServer.contains("jsdelivr.net")) { + acConfig.rulePack = String.format("%s@%s", ruleServer, acConfig.ruleArchiveVersion); + } else { + acConfig.rulePack = String.format("%s%s/js", ruleServer, ruleArchivePath); + } + } + acConfig.ruleServer = ruleServer; + + if (acConfig.DEBUG) System.err.println("Built new rulePack: " + acConfig.rulePack); + + if (acConfig.DEBUG) System.err.println("END 'processACConfig' function"); + + // Return the updated ACConfig object + return acConfig; + } + + /** + * This function is responsible initializing all the default values for the configurations, in the case any + * of the config options are missing. + * + * @param config Provide the config object in which we need to initialize the default values. + */ + private static void initializeDefaults(ConfigInternal config) { + // Use an unpopulated config as the default values + ConfigInternal acConstants = new ConfigInternal(); + if (config.DEBUG) System.out.println("START 'initializeDefaults' function"); + + if (config.DEBUG) System.out.println("Config before initialization: "); + if (config.DEBUG) System.out.println(config); + // Make sure all the following options are defined, otherwise reset them to default values. + config.ruleArchiveLabel = Misc.firstNotNull(config.ruleArchiveLabel, config.ruleArchive); + // For capture screenshots need to check for null or undefined and then set default otherwise it will evaluate the + // boolean which causes it to always comply with the default value and not user provided option + config.captureScreenshots = Misc.firstNotNull(config.captureScreenshots, acConstants.captureScreenshots); + + // Build the toolID based on name and version + config.toolID = "java-accessibility-checker-v3.1.70"; + config.toolName = "java-accessibility-checker"; + config.toolVersion = "3.1.70"; + + // Using the uuid module generate a uuid number which is used to assoiciate to the scans that + // are done for a single run of karma. + config.scanID = java.util.UUID.randomUUID().toString(); + + for (Field field : acConstants.getClass().getDeclaredFields()) { + try { + if (field.get(config) == null) { + field.set(config, field.get(acConstants)); + } + } catch (IllegalArgumentException | IllegalAccessException e) { + // Skip if we can't access the field + } + } + + if (config.DEBUG) System.out.println("Config after initialization: "); + if (config.DEBUG) System.out.println(config); + + if (config.DEBUG) System.out.println("END 'initializeDefaults' function"); + } + + /** + * This function is responsible reading in the .yaml or .yml or .json and set the config options based on this. + * + * @return {Object} config - return the config object that was read in, refer to function initializeDefaults + * to view how the object is to be constructed. + */ + private static ConfigInternal loadConfigFromJSONFile() { + // Use an unpopulated config as the default values + ConfigInternal acConstants = new ConfigInternal(); + + if (acConstants.DEBUG) System.out.println("START 'loadConfigFromJSONFile' function"); + + // Get the current working directory, where we will look for the yaml, yml or json file + String workingDir = System.getProperty("user.dir"); + if (acConstants.DEBUG) System.out.println("Working directory set to: " + workingDir); + + String[] configFiles = acConstants.configFiles; + + ConfigInternal config = null; + // Loop over all the possible location where the config file can reside, if one is found load it and break out. + for (String configFile: configFiles) { + // Get the full path to the config file we are going to check + String fileToCheck = Paths.get(workingDir, configFile).toString(); + + // Get the extension of the file we are about to scan + String fileExtension = fileToCheck.substring(fileToCheck.lastIndexOf('.') + 1); + + // If this is a yml or yaml file verify that the file exists and then load as such. + if ("json".equals(fileExtension)) { + if (acConstants.DEBUG) System.out.println(fileToCheck+": Trying to load as json or js."); + + // Need to use try/catch mech so that in the case the require throws an exception, we can + // catch this and discatd the error, as in the case there is no config file provided then + // we load in default values. + try { + Gson gson = new Gson(); + JsonReader reader = new JsonReader(new FileReader(fileToCheck)); + config = gson.fromJson(reader, ConfigInternal.class); + if (acConstants.DEBUG) System.out.println(fileToCheck+": LOADED"); + return config; + } catch (FileNotFoundException e) { + if (acConstants.DEBUG) System.out.println(fileToCheck+": Skipping, JSON file does not exist."); + } + } + } + + if (acConstants.DEBUG) System.out.println("END 'loadConfigFromJSONFile' function"); + return config; + } + + /** + * This function is responsible for processing the karma configuration for accessibility-checker. + * The ACConfig provided in the Karma configuration will be processed by this + * function and then the config variables will be assoiciated to the global space so that + * they can be accessed from window.__karma__.config + * + * @param config All the Karma configuration, we will extract what we need from this over + * all object, we need the entire object so that we can reasign some config + * variables to global scope so that all karma testscases/scripts can access + * them. + * + * @return Object will be processed and all the params that are needed for this module will + * be extracted + */ + private static ConfigInternal processConfiguration(Config config) { + // Use an unpopulated config as the default values + ConfigInternal ACConstants = new ConfigInternal(); + if (ACConstants.DEBUG) System.out.println("START 'processConfiguration' function"); + + // Variable Declaration + ConfigInternal ACConfig = null; + ConfigInternal configFromFile = null; + + // Read in the .yaml (.yml) or .json file to load in the configuration + configFromFile = loadConfigFromJSONFile(); + if (ACConstants.DEBUG && configFromFile == null) System.out.println("No config from file"); + if (ACConstants.DEBUG && configFromFile != null) System.out.println("Loaded config from file: "); + if (ACConstants.DEBUG && configFromFile != null) System.out.println(configFromFile); + + // In the case configuration was provided in a yaml, yml or json file, then set this as the configuration + // otherwise load them from the Karma configuration. + if (configFromFile != null) { + if (ACConstants.DEBUG) System.out.println("Using config which was loaded from config file."); + ACConfig = configFromFile; + } else if (config != null) { + if (ACConstants.DEBUG) System.out.println("Using config as parameter."); + ACConfig = new ConfigInternal(config); + } else { + if (ACConstants.DEBUG) System.out.println("Using default config."); + ACConfig = new ConfigInternal(); + } + + // In the case the ACConfig object is not defined, then define it with default config options so + // it can be set in window.__karma__.config.ACConfig, so that we know even in the testcases, other + // wrapper scripts that there was nothing defined at all, and at the same time to make sure that this + // code was actually executed. + initializeDefaults(ACConfig); + // Now we process the final accessibility-checker config object that is build to make sure it is valid, also need to perform some + // mapping for provided paremeters to actualy read by the engine. + try { + ACConfig = processACConfig(ACConfig); + } catch (IOException e) { + System.err.println(e); + e.printStackTrace(); + } + + // In the case the Karma config is set to config.LOG_DEBUG then also enable the accessibility-checker debuging + ACConfig.DEBUG = ACConstants.DEBUG; + + if (ACConstants.DEBUG) System.out.println("END 'processConfiguration' function"); + return ACConfig; + } + + private static ConfigInternal config = null; + public static void setConfig(Config inConfig) { + config = ACConfigManager.processConfiguration(inConfig); + // TODO: + // ReporterManager.setConfig(config); + } + + public static Config getConfig() { + return ACConfigManager.getConfigUnsupported(); + } + + public static ConfigInternal getConfigUnsupported() { + if (ACConfigManager.config == null) { + ACConfigManager.setConfig(null); + } + return config; + } + + public static void resetConfig() { + config = null; + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Archive.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Archive.java new file mode 100644 index 000000000..9d44348f1 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Archive.java @@ -0,0 +1,39 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.config; + +import java.util.HashMap; +import java.util.Map; + +public class Archive { + public static class Ruleset { + public String id; + public String name; + public String description; + } + + public String id; + public String name; + public String path; + public Ruleset[] policies; + public Map rulesets = new HashMap(); + + public String version; + public boolean latest; + public boolean sunset; + public String helpPath; + public String enginePath; +} \ No newline at end of file diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Config.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Config.java new file mode 100644 index 000000000..7747d03fb --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Config.java @@ -0,0 +1,115 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.config; + +public class Config { + Config() {} + + Config(Config other) { + this.ruleArchive = other.ruleArchive; + this.policies = other.policies.clone(); + this.failLevels = other.failLevels.clone(); + this.reportLevels = other.reportLevels.clone(); + this.outputFormat = other.outputFormat.clone(); + this.label = other.label.clone(); + this.outputFolder = other.outputFolder; + this.outputFilenameTimestamp = other.outputFilenameTimestamp; + this.baselineFolder = other.baselineFolder; + this.cacheFolder = other.cacheFolder; + this.extensions = other.extensions; + } + /** + * (optional) Specify the rule archive + * + * Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids + * Default: "latest" + * Values: "latest" | "preview" | "versioned" | archive id + */ + public String ruleArchive = "latest"; + + /** + * (optional) Specify one or many policies to scan. + * + * Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids + * Default: ["IBM_Accessibility"] + */ + public String[] policies = { "IBM_Accessibility" }; + + /** + * (optional) Specify one or many violation levels on which to fail the test + * + * i.e. If specified violation then the testcase will only fail if + * a violation is found during the scan. + * Default: ["violation", "review"] + */ + public String[] failLevels = { "violation", "potentialviolation" }; + + /** + * (optional) Specify one or many violation levels which should be reported + * + * i.e. If specified violation then in the report it would only contain + * results which are level of violation. + * Default: ["violation", "review"] + */ + public String[] reportLevels = { "violation", "potentialviolation" }; + + /** + * (optional) In which fornats should the results be output + * Default: ["json"] + */ + public String[] outputFormat = { "json" }; + + /** + * (optional) Specify any labels that you would like associated to your scan + * Default: [] + */ + public String[] label = null; + + /** + * (optional) Where the scan results should be saved. + * Default: "results" + */ + public String outputFolder = "results"; + + /** + * (optional) Should the timestamp be included in the filename of the reports? + * Default: true + */ + public boolean outputFilenameTimestamp = true; + + /** + * (optional) Where the baseline results should be loaded from + * Default: "baselines" + */ + public String baselineFolder = "baselines"; + + /** + * (optional) Where the tool can read/write cached files (ace-node.js / archive.json) + * Default: `${os.tmpdir()}/accessibility-checker/` + */ + public String cacheFolder = System.getProperty("java.io.tmpdir")+"/accessibility-checker/"; + + /** + * (optional) For tools that scan files, which extensions should we include + * Default: ["html", "htm", "svg"] + */ + public String[] extensions = { "html", "htm", "svg" }; + + /** + * (optional) If the tool allows, should we capture screenshots + */ + public Boolean captureScreenshots = false; +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java new file mode 100644 index 000000000..02adcaadf --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java @@ -0,0 +1,99 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.config; + +import java.nio.file.Paths; + +public class ConfigInternal extends Config { + ConfigInternal() { + super(); + } + + ConfigInternal(Config config) { + super(config); + } + + /** + * Run in debug mode + */ + public boolean DEBUG = "true".equals(System.getenv("DEBUG")); + + /** + * Spot to store parsed archive file + */ + public Archive[] ruleArchiveSet = null; + + /** + * Label to expose to reports + */ + public String ruleArchiveLabel = null; + + /** + * (optional) Rule server to pull the rules from and to use for help + * Default: "https://able.ibm.com/rules" + */ + public String ruleServer = "https://cdn.jsdelivr.net/npm/accessibility-checker-engine"; + + /** + * Path to the rule pack + */ + public String rulePack = null; + + /** + * Path within the archive + */ + public String ruleArchivePath = null; + + /** + * Version number of the selected archive + */ + public String ruleArchiveVersion = null; + + /** + * (optional) If the tool allows, should we run headless + */ + public boolean headless = true; + + /** + * (optional) If the tool allows, set the maximum number of tabs to open + */ + public int maxTabs = 1; + + /** + * Configuration filenames to try loading + */ + public String[] configFiles = { + "achecker.json", + "aceconfig.json", + Paths.get(".config", "achecker.json").toString(), + Paths.get(".config", "aceconfig.json").toString() + }; + + public String toolID = null; + public String toolName = null; + public String toolVersion = null; + + public String scanID = null; + + public boolean ignoreHTTPSErrors = false; + + public boolean perfMetrics = true; + + /** + * "DEFAULT" | "REMOTE" | "INJECT" + */ + public String engineMode = "DEFAULT"; +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java new file mode 100644 index 000000000..3441196e3 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java @@ -0,0 +1,116 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.equalaccess.engine; +import java.util.Map; + +import com.google.gson.annotations.SerializedName; + +public class ACEReport { + public static class SummaryCounts implements Cloneable { + public int violation = 0; + public int potentialviolation = 0; + public int recommendation = 0; + public int potentialrecommendation = 0; + public int manual = 0; + public int pass = 0; + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + } + } + public static class Summary implements Cloneable { + public SummaryCounts counts = new SummaryCounts(); + + public Object clone() { + Summary ret = null; + try { + ret = (Summary) super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + ret.counts = (SummaryCounts)counts.clone(); + return ret; + } + } + + public static class Result implements Cloneable { + public Result() {} + public Result(Result o) { + apiArgs = o.apiArgs; + bounds = (Bounds) o.bounds.clone(); + category = o.category; + message = o.message; + messageArgs = o.messageArgs.clone(); + path = o.path; + reasonId = o.reasonId; + ruleId = o.ruleId; + ruleTime = o.ruleTime; + snippet = o.snippet; + value = o.value.clone(); + } + public Object[] apiArgs = new Object[]{}; + /** Bounds of the result as would be found in the viewport */ + public Bounds bounds = new Bounds(); + /** Category of the result (e.g., accessibility) */ + public String category; + /** Result message describing what was found */ + public String message; + /** Parameter parts used to construct the message */ + @SerializedName(value = "messageArgs", alternate = "msgArgs") + public String[] messageArgs; + /** Mapping of "dom", "aria", etc to identify the location of the result */ + public Map path; + /** Identifier of the rule that triggered the result */ + public String ruleId; + /** Identifier indicating the specific reason this issue triggered within the rule */ + public String reasonId; + /** How long this rule took to run */ + public int ruleTime; + /** HTML snippet that this result triggered on */ + public String snippet; + /** Combination of the level of the result (e.g., ["VIOLATION", "FAIL"]) */ + public String[] value; + + @Override + public Object clone() { + // Shallow copy + Result ret = null; + try { + ret = (Result)super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + ret.bounds = (Bounds) bounds.clone(); + return ret; + } + } + + public int numExecuted; + public int ruleTime; + public int totalTime; + public Map> nls; + public Result[] results; + public String screenshot=null; + public Summary summary; +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACError.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACError.java new file mode 100644 index 000000000..004773357 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACError.java @@ -0,0 +1,23 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.engine; + +public class ACError extends Error { + public ACError(String msg) { + super(msg); + } + +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java new file mode 100644 index 000000000..2066a06b4 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java @@ -0,0 +1,327 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.equalaccess.engine; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.ibm.able.equalaccess.config.ConfigInternal; + +public class ACReport implements Cloneable { + + /** + * Summary of counts from the scan + */ + public static class SummaryCounts implements Cloneable { + public int violation = 0; + public int potentialviolation = 0; + public int recommendation = 0; + public int potentialrecommendation = 0; + public int manual = 0; + public int pass = 0; + public int ignored = 0; + public int elements = 0; + public int elementsViolation = 0; + public int elementsViolationReview = 0; + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + } + + public SummaryCounts() { + } + + public SummaryCounts(ACEReport.SummaryCounts rhs) { + violation = rhs.violation; + potentialviolation = rhs.potentialviolation; + recommendation = rhs.recommendation; + potentialrecommendation = rhs.potentialrecommendation; + manual = rhs.manual; + pass = rhs.pass; + } + } + + /** + * Scan summary information + */ + public static class Summary implements Cloneable { + public SummaryCounts counts = new SummaryCounts(); + public long scanTime = 0; + public String ruleArchive = ""; + public String[] policies = {}; + public String[] reportLevels = {}; + public long startScan = 0; + public String URL = ""; + + public Object clone() { + Summary ret = null; + try { + ret = (Summary) super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + ret.counts = (SummaryCounts)counts.clone(); + return ret; + } + } + + /** + * An individual issue identified by a rule + */ + public static class Result extends ACEReport.Result { + /** Did this issue match a baseline */ + public boolean ignored = false; + /** Help url for this item */ + public String help = ""; + /** Level of the issue (violation, potentialviolation, etc) */ + public eRuleLevel level; + + public Result() {} + public Result(ACEReport.Result engineResult) { + super(engineResult); + } + + @Override + public Object clone() { + return super.clone(); + } + + public String toHelpData() { + return gsonMinimal.toJson(this); + } + + public static Gson gsonMinimal = new GsonBuilder() + .registerTypeAdapter(Result.class, new JsonSerializer() { + @Override + public JsonElement serialize(Result issue, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jObject = new JsonObject(); + jObject.addProperty("ruleId", issue.ruleId); + jObject.addProperty("reasonId", issue.reasonId); + jObject.addProperty("message", issue.message); + jObject.addProperty("snippet", issue.snippet); + JsonArray buildValue = new JsonArray(); + for (String s: issue.value) { + buildValue.add(s); + } + jObject.add("value", buildValue); + JsonArray buildMsgArgs = new JsonArray(); + for (String s : issue.messageArgs) { + buildMsgArgs.add(s); + } + jObject.add("msgArgs", buildMsgArgs); + return jObject; + } + }) + .create(); + } + + /** Array of items detected by the getCompliance scan */ + public Result[] results = new Result[0]; + /** Number of rules executed as part of the scan */ + public int numExecuted = 0; + /** Mapping of ruleId to reasonId to a parameterized message */ + public Map> nls = new HashMap<>(); + /** Summary of the scan */ + public Summary summary = new Summary(); + /** Identifier of the scan (same id used for each scan of the session) */ + public String scanID = ""; + /** Identifier for the accessibility-checker tool used to perform the scan */ + public String toolID = ""; + /** Label as specified in the getCompliance call that generated the report */ + public String label = ""; + /** base64 screenshot, if one was taken */ + public String screenshot=null; + /** Amount of time in ms that was spent executing rule functions (as opposed to walking the tree) */ + public int ruleTime = 0; + + private ConfigInternal config; + + public ACReport() {} + public ACReport(ConfigInternal config, ACEReport engineReport, String label) { + this.config = config; + numExecuted = engineReport.numExecuted; + nls = engineReport.nls; + screenshot = engineReport.screenshot; + ruleTime = engineReport.ruleTime; + results = new Result[engineReport.results.length]; + for (int idx=0; idx < results.length; ++idx) { + results[idx] = new Result(engineReport.results[idx]); + } + scanID = config.scanID; + toolID = config.toolID; + this.label = label; + } + + /** + * Ignore: To be used by the ReporterManager + * @param summaryCounts + */ + public void addCounts(ACEReport.SummaryCounts summaryCounts) { + SummaryCounts counts = this.summary.counts = new SummaryCounts(summaryCounts); + counts.ignored = 0; + counts.elements = 0; + counts.elementsViolation = 0; + counts.elementsViolationReview = 0; + Set elementSet = new HashSet<>(); + Set elementViolationSet = new HashSet<>(); + Set elementViolationReviewSet = new HashSet<>(); + for (Result issue: results) { + elementSet.add(issue.path.get("dom")); + if (issue.ignored) { + ++counts.ignored; + if (eRuleLevel.violation.equals(issue.level)) { + --counts.violation; + } else if (eRuleLevel.potentialviolation.equals(issue.level)) { + --counts.potentialviolation; + } else if (eRuleLevel.recommendation.equals(issue.level)) { + --counts.recommendation; + } else if (eRuleLevel.potentialrecommendation.equals(issue.level)) { + --counts.potentialrecommendation; + } else if (eRuleLevel.manual.equals(issue.level)) { + --counts.manual; + } else if (eRuleLevel.pass.equals(issue.level)) { + --counts.pass; + } + } else { + if (eRuleLevel.violation.equals(issue.level)) { + elementViolationSet.add(issue.path.get("dom")); + elementViolationReviewSet.add(issue.path.get("dom")); + } else if (eRuleLevel.potentialviolation.equals(issue.level) || eRuleLevel.manual.equals(issue.level)) { + elementViolationReviewSet.add(issue.path.get("dom")); + } + } + } + counts.elements = elementSet.size(); + counts.elementsViolation = elementViolationSet.size(); + counts.elementsViolationReview = elementViolationReviewSet.size(); + } + + /** + * Filters the report using the specified reportLevels + * @param reportLevels + */ + public void filter(String[] reportLevels) { + Map> keepNlsKeys = new HashMap<>(); + List reportLevelsList = Arrays.asList(reportLevels); + Stream filtResults = Arrays.stream(results).filter(pageResult -> { + if (reportLevelsList.contains(pageResult.level.toString())) { + Set keepRuleReasons = keepNlsKeys.get(pageResult.ruleId); + if (keepRuleReasons == null) { + keepNlsKeys.put(pageResult.ruleId, new HashSet()); + keepRuleReasons = keepNlsKeys.get(pageResult.ruleId); + keepRuleReasons.add("0"); + } + keepRuleReasons.add(pageResult.reasonId); + if (pageResult.message.length() > 32000) { + pageResult.message = pageResult.message.substring(0, 32000 - 3) + "..."; + } + if (pageResult.snippet.length() > 32000) { + pageResult.snippet = pageResult.snippet.substring(0, 32000 - 3) + "..."; + } + return true; + } else { + return false; + } + }); + results = filtResults.toArray(size -> new Result[size]); + + if (nls != null) { + for (String ruleId: nls.keySet().toArray(new String[] {})) { + if (!keepNlsKeys.containsKey(ruleId)) { + nls.remove(ruleId); + } else { + Set keepRuleReasons = keepNlsKeys.get(ruleId); + Map nlsRuleMap = nls.get(ruleId); + for (String reasonId: nls.get(ruleId).values()) { + if (!keepRuleReasons.contains(reasonId)) { + nlsRuleMap.remove(reasonId); + } + } + } + } + } + } + public void sortResults() { + Arrays.sort(this.results, (a, b) -> { + int cc = b.category.compareTo(a.category); + if (cc != 0) return cc; + int pc = b.path.get("dom").compareTo(a.path.get("dom")); + if (pc != 0) return pc; + return b.ruleId.compareTo(a.ruleId); + }); + } + + @Override + public Object clone() { + // Shallow copy + ACReport ret = null; + try { + ret = (ACReport)super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + ret.summary = (Summary)summary.clone(); + ret.results = new ACReport.Result[results.length]; + for (int idx=0; idx reportLevelsList = Arrays.asList(config.reportLevels); + + for (Result issue: results) { + if (reportLevelsList.contains(issue.level.toString())) { + // Build string of the issues with only level, messageCode, xpath and snippet. + resultsString.append("- Message: " + issue.message + + "\n Level: " + issue.level + + "\n XPath: " + issue.path.get("dom") + + "\n Snippet: " + issue.snippet + + "\n Help: " + issue.help + + "\n"); + } + } + + return resultsString.toString(); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java new file mode 100644 index 000000000..4fb1b57c9 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java @@ -0,0 +1,83 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.equalaccess.engine; + +import java.util.List; + +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.report.CompressedReport; +import com.ibm.able.equalaccess.report.ReporterStored; + +public class ACReportSummary { + public static class SummaryCounts { + public int violation = 0; + public int potentialviolation = 0; + public int recommendation = 0; + public int potentialrecommendation = 0; + public int manual = 0; + public int pass = 0; + public int ignored = 0; + public int elements = 0; + public int elementsViolation = 0; + public int elementsViolationReview = 0; + } + public static class PageSummary { + public String label; + public ACReport.SummaryCounts counts; + } + public SummaryCounts counts = new SummaryCounts(); + + public long startReport = 0; + public long endReport = 0; + public String toolID = ""; + public String[] policies = {}; + public String[] reportLevels = {}; + public String[] labels = {}; + public String[] failLevels = {}; + public String scanID = ""; + public PageSummary[] pageScanSummary = new PageSummary[0]; + + public ACReportSummary() {} + public ACReportSummary(ConfigInternal config, long endReport, List compressedReports) { + this.startReport = compressedReports.get(0).getStartScan(); + this.endReport = endReport; + this.toolID = config.toolID; + this.policies = config.policies; + this.reportLevels = config.reportLevels; + this.labels = config.label; + this.failLevels = config.failLevels; + this.scanID = config.scanID; + this.pageScanSummary = new PageSummary[compressedReports.size()]; + for (int idx=0; idx> refactor = null; +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java new file mode 100644 index 000000000..c19ed4aa4 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java @@ -0,0 +1,38 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.engine; + +public enum eRuleConfidence { + PASS("PASS"), + FAIL("FAIL"), + POTENTIAL("POTENTIAL"), + MANUAL("MANUAL") + ; + + private final String text; + + eRuleConfidence(final String text) { + this.text = text; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + @Override + public String toString() { + return text; + } +} \ No newline at end of file diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java new file mode 100644 index 000000000..2d022db39 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java @@ -0,0 +1,42 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.engine; + +public enum eRuleLevel { + violation("violation"), + potentialviolation("potentialviolation"), + recommendation("recommendation"), + potentialrecommendation("potentialrecommendation"), + manual("manual"), + pass("pass"), + ignored("ignored"), + undefined("undefined") + ; + + private final String text; + + eRuleLevel(final String text) { + this.text = text; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + @Override + public String toString() { + return text; + } +} \ No newline at end of file diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java new file mode 100644 index 000000000..7179552e0 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java @@ -0,0 +1,115 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.enginecontext; + +import java.io.IOException; +import com.google.gson.Gson; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.util.Fetch; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Scriptable; + +public class EngineContextLocal implements IEngineContext { + private static Gson gson = new Gson(); + private Context engine = null; + private Scriptable engineScope = null; + + @Override + public void loadEngine() { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String engineUrl = config.rulePack+"/ace.js"; + try { + String engineContent = Fetch.get(engineUrl, config.ignoreHTTPSErrors)+";var ace_checker = new ace.Checker();"; + + // Creates and enters a Context. The Context stores information + // about the execution environment of a script. + engine = Context.enter(); + + // Initialize the standard objects (Object, Function, etc.) + // This must be done before scripts can be executed. Returns + // a scope object that we use in later calls. + engineScope = engine.initStandardObjects(); + + // Now evaluate the string we've colected. + engine.evaluateString(engineScope, engineContent, "", 1, null); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine fromm "+engineUrl+" due to IOException: "+e.toString()); + e.printStackTrace(); + } + } + + @Override + public ACEReport getCompliance(String label) { + // Can't getCompliance with no content model + throw new UnsupportedOperationException("Cannot 'getCompliance' with EngineContextLocal"); + } + + @Override + public String getUrl() { + // Can't getUrl with no content model + throw new UnsupportedOperationException("Cannot 'getUrl' with EngineContextLocal"); + } + + @Override + public String getTitle() { + // Can't getTitle with no content model + throw new UnsupportedOperationException("Cannot 'getTitle' with EngineContextLocal"); + } + + @Override + public Guideline[] getGuidelines() { + String scriptStr = "JSON.stringify(ace_checker.getGuidelines())"; + String jsonGuidelines = engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + return gson.fromJson(jsonGuidelines, Guideline[].class); + } + + @Override + public Rule[] getRules() { + String scriptStr = "JSON.stringify(Object.keys(ace_checker.engine.ruleMap).map(key => ace_checker.engine.ruleMap[key]))"; + String jsonGuidelines = engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + return gson.fromJson(jsonGuidelines, Rule[].class); + } + + public String encodeURIComponent(String s) { + if (engine == null) { + // Creates and enters a Context. The Context stores information + // about the execution environment of a script. + engine = Context.enter(); + + // Initialize the standard objects (Object, Function, etc.) + // This must be done before scripts can be executed. Returns + // a scope object that we use in later calls. + engineScope = engine.initStandardObjects(); + } + String scriptStr = String.format("encodeURIComponent(`%s`)", s.replace("\"", "\\\"")); + return engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + } + + @Override + public String getProfile() { + return "Local"; + } + + @Override + public String getHelp(String ruleId, String reasonId, String helpRoot) { + String scriptStr = String.format("ace_checker.engine.getHelp(`%s`,`%s`,`%s`)", ruleId, reasonId, helpRoot); + return engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java new file mode 100644 index 000000000..4731e4e82 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java @@ -0,0 +1,92 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.enginecontext; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import com.ibm.able.equalaccess.engine.ACError; +import com.ibm.able.equalaccess.util.Misc; + +public class EngineContextManager { + private EngineContextManager() {} + + public static String encodeURIComponent(String s) { + return new EngineContextLocal().encodeURIComponent(s); + } + + public static IEngineContext getEngineContext(Object contentContext) { + IEngineContext engineContext = null; + if (contentContext == null) { + engineContext = new EngineContextLocal(); + } + // See if this is Selenium and we can load it + if (engineContext == null + && Misc.classIsAvailable("org.openqa.selenium.WebDriver")) + { + if (!Misc.classIsAvailable("com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium")) { + System.err.println("Attempted scan with WebDriver, but com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium could not be loaded"); + throw new ACError("Attempted scan with WebDriver, but com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium could not be loaded"); + } + try { + Class webdriverClass = Class.forName("org.openqa.selenium.WebDriver"); + if (webdriverClass.isAssignableFrom(contentContext.getClass())) { + // We have a webdriver, use EngineContextSelenium to instantiate it + Class ecClass = Class.forName("com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium"); + engineContext = (IEngineContext) ecClass.getConstructor(webdriverClass).newInstance(contentContext); + } + } catch (ClassNotFoundException e) { + } catch (NoSuchMethodException e) { + } catch (SecurityException e) { + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } catch (IllegalArgumentException e) { + } catch (InvocationTargetException e) { + } + } + // See if this is Playwright and we can load it + if (engineContext == null + && Misc.classIsAvailable("com.microsoft.playwright.Page")) + { + if (!Misc.classIsAvailable("com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright")) { + System.err.println("Attempted scan with Page, but com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright could not be loaded"); + throw new ACError("Attempted scan with Page, but com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright could not be loaded"); + } + try { + Class playwrightPageClass = Class.forName("com.microsoft.playwright.Page"); + if (playwrightPageClass.isAssignableFrom(contentContext.getClass())) { + // We have a webdriver, use EngineContextSelenium to instantiate it + Class ecClass = Class.forName("com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright"); + engineContext = (IEngineContext) ecClass.getConstructor(playwrightPageClass).newInstance(contentContext); + } + } catch (ClassNotFoundException e) { + } catch (NoSuchMethodException e) { + } catch (SecurityException e) { + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } catch (IllegalArgumentException e) { + } catch (InvocationTargetException e) { + } + } + if (engineContext != null) { + engineContext.loadEngine(); + } else { + System.err.println("Unable to load engine context for "+contentContext.getClass().getName()); + throw new ACError("Unable to load engine context for "+contentContext.getClass().getName()); + } + return engineContext; + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java new file mode 100644 index 000000000..91e37586d --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java @@ -0,0 +1,37 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.enginecontext; + +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; + +public interface IEngineContext { + public void loadEngine(); + + public ACEReport getCompliance(String label); + public String getUrl(); + public String getTitle(); + public Guideline[] getGuidelines(); + public Rule[] getRules(); + public String getHelp(String ruleId, String reasonId, String helpRoot); + public String encodeURIComponent(String s); + /** + * The profile to use in metrics for this engine context + * @return profile string (e.g., Selenium) + */ + public String getProfile(); +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java new file mode 100644 index 000000000..6d78554a8 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java @@ -0,0 +1,305 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.enginecontext.playwright; + +import java.io.IOException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.Config; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACError; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.util.Fetch; +import com.microsoft.playwright.*; + +public class EngineContextPlaywright implements IEngineContext { + private static Gson gson = new Gson(); + private Page driver = null; + private String engineContent = null; + + public EngineContextPlaywright(Page driver) { + this.driver = driver; + } + + @Override + public void loadEngine() { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String engineUrl = config.rulePack+"/ace.js"; + String engineLoadMode = config.engineMode; + if ("DEFAULT".equals(engineLoadMode)) { + engineLoadMode = "INJECT"; + } + try { + if ("INJECT".equals(engineLoadMode) && engineContent == null) { + engineContent = Fetch.get(engineUrl, config.ignoreHTTPSErrors); + } + + if (config.DEBUG) System.out.println("[INFO] aChecker.loadEngine detected Selenium"); + String scriptStr; + if ("REMOTE".equals(engineLoadMode)) { + scriptStr = """ +(scriptUrl) => { + try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + return new Promise((resolve, reject) => { + let script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script.setAttribute('aChecker', 'ACE'); + script.setAttribute('src', scriptUrl); + script.addEventListener('load', function () { + globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + resolve(); + }); + script.addEventListener('error', function (evt) { + reject(new Error(`Unable to load engine into ${document.location.href}. This can happen if the page server sets a Content-Security-Policy that prevents ${scriptUrl} from loading.`)) + }); + let heads = document.getElementsByTagName('head'); + if (heads.length > 0) { heads[0].appendChild(script); } + else if (document.body) { document.body.appendChild(script); } + else { Promise.reject("Invalid document"); } + }) + } + } catch (e) { + return Promise.reject(e); + } +} +"""; + this.driver.evaluate(scriptStr, config.rulePack); + } else if ("INJECT".equals(engineLoadMode)) { + // Selenium + scriptStr = """ +(engineContent) => { + try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + return new Promise((resolve, reject) => { + eval(engineContent); + globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + resolve(); + }) + } + } catch (e) { + return Promise.reject(e); + } +} +"""; + this.driver.evaluate(scriptStr, engineContent); + } else { + scriptStr = ""; + } + + // this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); + + } catch (Error e) { + System.err.println(e); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine from "+engineUrl+" due to IOException: "+e.toString()); + e.printStackTrace(); + } + } + + @Override + public ACEReport getCompliance(String label) { + Config config = ACConfigManager.getConfig(); + try { + List resultList = new ArrayList<>(config.reportLevels.length + config.failLevels.length); + Collections.addAll(resultList, config.reportLevels); + Collections.addAll(resultList, config.failLevels); + String scriptStr = """ +([policies, reportLevels]) => { + try { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + const getCounts = (engineReport) => { + let counts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } + + let checker = new window.ace_ibma.Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + return new Promise((resolve, reject) => { + checker.check(document, policies).then(async function(report) { + for (const result of report.results) { + delete result.node; + result.level = valueToLevel(result.value) + } + report.summary ||= {}; + report.summary.counts ||= getCounts(report); + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + report.results = report.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); + resolve(JSON.stringify(report)); + }) + }); + } catch (e) { + return Promise.reject(e); + } +} + """; + ACEReport report; + String jsonReport = this.driver.evaluate(scriptStr, Arrays.asList( + config.policies, + resultList.toArray() + /* TODO: ${JSON.stringify(ACEngineManager.customRulesets)}; */ + )).toString(); + if (!jsonReport.startsWith("{\"results\":[")) { + throw new ACError(jsonReport); + } else { + report = gson.fromJson(jsonReport, ACEReport.class); + } + + // TODO: + // String getPolicies = "return new window.ace_ibma.Checker().rulesetIds;"; + // if (curPol != null && !checkPolicy) { + // checkPolicy = true; + // const valPolicies = ACEngineManager.customRulesets.map(rs => rs.id).concat(await browser.executeScript(getPolicies)); + // areValidPolicy(valPolicies, curPol); + // } + + // If there is something to report... + if (report.results != null && config.captureScreenshots) { + byte[] image = this.driver.screenshot(); + report.screenshot = new String(image); + } + return report; + } catch (Error err) { + System.err.println(err); + throw err; + } + } + + @Override + public String getUrl() { + return this.driver.url(); + } + + @Override + public String getTitle() { + return this.driver.title(); + } + + @Override + public Guideline[] getGuidelines() { + String scriptStr = String.format(""" +() => { + try { + let checker = new window.ace_ibma.Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + return Promise.resolve(JSON.stringify(checker.getGuidelines())); + } catch (e) { + return Promise.reject(e); + } +} +"""); + String jsonGuidelines = this.driver.evaluate(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Guideline[].class); + } + + @Override + public Rule[] getRules() { + String scriptStr = String.format(""" +() => { + try { + let checker = new window.ace_ibma.Checker(); + return Promise.resolve(JSON.stringify(checker.getRules())); + } catch (e) { + return Promise.reject(e); + } +} +"""); + String jsonGuidelines = this.driver.evaluate(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Rule[].class); + } + + @Override + public String getProfile() { + return "Selenium"; + } + + @Override + public String getHelp(String ruleId, String reasonId, String helpRoot) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getHelp'"); + } + + @Override + public String encodeURIComponent(String s) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'encodeURIComponent'"); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java new file mode 100644 index 000000000..778c1fc5b --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java @@ -0,0 +1,305 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.enginecontext.selenium; + +import java.io.IOException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; + +import com.google.gson.Gson; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.Config; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACError; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.util.Fetch; + +public class EngineContextSelenium implements IEngineContext { + private static Gson gson = new Gson(); + private WebDriver driver = null; + private String engineContent = null; + + public EngineContextSelenium(WebDriver driver) { + this.driver = driver; + } + + @Override + public void loadEngine() { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String engineUrl = config.rulePack+"/ace.js"; + String engineLoadMode = config.engineMode; + if ("DEFAULT".equals(engineLoadMode)) { + engineLoadMode = "INJECT"; + } + try { + if ("INJECT".equals(engineLoadMode) && engineContent == null) { + engineContent = Fetch.get(engineUrl, config.ignoreHTTPSErrors); + } + + if (config.DEBUG) System.out.println("[INFO] aChecker.loadEngine detected Selenium"); + String scriptStr; + if ("REMOTE".equals(engineLoadMode)) { + scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + let script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script.setAttribute('aChecker', 'ACE'); + script.setAttribute('src', '%s/ace.js'); + script.addEventListener('load', function() { + window.ace_ibma = globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + cb(); + }); + let heads = document.getElementsByTagName('head'); + if (heads.length > 0) { heads[0].appendChild(script); } + else { document.body.appendChild(script); } + } else { + cb(); + } +} catch (e) { + cb(e); +} +""", config.rulePack); + } else if ("INJECT".equals(engineLoadMode)) { + // Selenium + scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + eval(%s) + window.ace_ibma = globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + cb(); + + } else { + cb(); + } +} catch (e) { + cb(e); +} +""", gson.toJson(engineContent)); + } else { + scriptStr = ""; + } + + this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); + + ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr); + } catch (Error e) { + System.err.println(e); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine from "+engineUrl+" due to IOException: "+e.toString()); + e.printStackTrace(); + } + } + + @Override + public ACEReport getCompliance(String label) { + Config config = ACConfigManager.getConfig(); + try { + List resultList = new ArrayList<>(config.reportLevels.length + config.failLevels.length); + Collections.addAll(resultList, config.reportLevels); + Collections.addAll(resultList, config.failLevels); + String scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + const getCounts = (engineReport) => { + let counts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } + let policies = %s; + let reportLevels = %s; + + let checker = new (globalThis.ace_ibma || window.ace_ibma).Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + setTimeout(function() { + checker.check(document, policies).then(function(report) { + for (const result of report.results) { + delete result.node; + result.level = valueToLevel(result.value) + } + report.summary ||= {}; + report.summary.counts ||= getCounts(report); + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + report.results = report.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); cb(JSON.stringify(report)); + }) + },0) +} catch (e) { + cb(e); +} + """, gson.toJson(config.policies), gson.toJson(resultList.toArray()) /* TODO: ${JSON.stringify(ACEngineManager.customRulesets)}; */); + ACEReport report; + try { + this.driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(60)); + String jsonReport = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + if (!jsonReport.startsWith("{\"results\":[")) { + throw new ACError(jsonReport); + } else { + report = gson.fromJson(jsonReport, ACEReport.class); + } + } catch (TimeoutException err) { + System.err.println("TIMEOUT?!"); + throw err; + } + + // TODO: + // String getPolicies = "return new (globalThis.ace_ibma || window.ace_ibma).Checker().rulesetIds;"; + // if (curPol != null && !checkPolicy) { + // checkPolicy = true; + // const valPolicies = ACEngineManager.customRulesets.map(rs => rs.id).concat(await browser.executeScript(getPolicies)); + // areValidPolicy(valPolicies, curPol); + // } + + // If there is something to report... + if (report.results != null) { + if (config.captureScreenshots) { + String image = ((TakesScreenshot)this.driver).getScreenshotAs(OutputType.BASE64); + report.screenshot = image; + } + } + return report; + } catch (Error err) { + System.err.println(err); + throw err; + } + } + + @Override + public String getUrl() { + return this.driver.getCurrentUrl(); + } + + @Override + public String getTitle() { + return this.driver.getTitle(); + } + + @Override + public Guideline[] getGuidelines() { + String scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + let checker = new (globalThis.ace_ibma || window.ace_ibma).Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + cb(JSON.stringify(checker.getGuidelines())); +} catch (e) { + cb(e); +} +"""); + String jsonGuidelines = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Guideline[].class); + } + + @Override + public Rule[] getRules() { + String scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + let checker = new (globalThis.ace_ibma || window.ace_ibma).Checker(); + cb(JSON.stringify(checker.getRules())); +} catch (e) { + cb(e); +} +"""); + String jsonGuidelines = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Rule[].class); + } + + @Override + public String getProfile() { + return "Selenium"; + } + + @Override + public String getHelp(String ruleId, String reasonId, String helpRoot) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getHelp'"); + } + + @Override + public String encodeURIComponent(String s) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'encodeURIComponent'"); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java new file mode 100644 index 000000000..b2c699f41 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java @@ -0,0 +1,90 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.report; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.util.Misc; + +public class ACReporterCSV implements IReporter { + private static String toCSV(String str) { + if (str == null) { + return "\"null\""; + } else if (str.length() == 0) { + return "\"\""; + } else { + return "\""+ str.replace("\"", "\"\"") + "\""; + } + } + + private IAbstractAPI fsApi; + public ACReporterCSV(IAbstractAPI fsApi) { + this.fsApi = fsApi; + } + @Override + public String name() { + return "csv"; + } + + @Override + public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored storedReport) { + return null; + } + + @Override + public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, + List compressedReports) + { + long startScan = !compressedReports.isEmpty() ? compressedReports.get(0).getStartScan() : 0; + Date startScanD = new Date(startScan); + String reportFilename = "results_"+Misc.toISOString(startScanD).replace(":","-")+".csv"; + if (!config.outputFilenameTimestamp) { + reportFilename = "results.csv"; + } + + try { + FileWriter resultStr = new FileWriter(fsApi.prepFile(reportFilename)); + // StringBuilder resultStr = new StringBuilder(); + resultStr.append("Label,Level,RuleId,Message,Xpath,Help\n"); + for (CompressedReport compressedReport: compressedReports) { + for (int idx=0; idx compressedReports) + { + if (compressedReports != null && compressedReports.size() > 0) { + ACReportSummary summReport = new ACReportSummary(config, endReport, compressedReports); + if (summReport != null) { + Date startScan = new Date(compressedReports.get(0).getStartScan()); + String reportFilename = "summary_"+Misc.toISOString(startScan).replaceAll(":","-")+".json"; + if (!config.outputFilenameTimestamp) { + reportFilename = "summary.json"; + } + return new ReporterFile(reportFilename, gson.toJson(summReport)); + } + } + return null; + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java new file mode 100644 index 000000000..c86de32f4 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java @@ -0,0 +1,116 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.report; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.Map.Entry; + +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.enginecontext.EngineContextManager; +import com.ibm.able.equalaccess.util.Fetch; + +/******************************************************************************* + * NAME: ACMetricsLogger.js + * DESCRIPTION: Common Metrics logger object which can be shared between tools + * to upload metrics of the tool to the metrics server. + *******************************************************************************/ + +public class ACReporterMetrics implements IReporter { + private String policies; + private String metricsURLV2 = "https://able.ibm.com/tools"; + private String toolName; + private Map> scanTimesV2 = new HashMap<>(); + + public ACReporterMetrics(String toolName, String[] policies) { + this.policies = String.join(",", policies); + // Init all the local object variables + this.toolName = toolName; + } + + @Override + public String name() { + return "metrics"; + } + + @Override + public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored storedReport) { + if (config.label == null || !Arrays.asList(config.label).contains("IBMa-Java-TeSt")) { + // URI encode the profile text provided + String profile = EngineContextManager.encodeURIComponent(storedReport.scanProfile); + if (!scanTimesV2.containsKey(profile)) { + scanTimesV2.put(profile, new ArrayList()); + } + // Add the time it took for the testcase to run to the global array, indexed by the profile + scanTimesV2.get(profile).add(""+storedReport.engineReport.summary.scanTime); + } + return null; + } + + @Override + public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, + List compressedReports) + { + try { + // Variable Declaration + String accountId = ""; + + // Loop over all the profiles with in the scanTime Object + for (Entry> entry: scanTimesV2.entrySet()) { + // Loop over all the V2 Scan Times until it reaches 0 + if (!entry.getValue().isEmpty()) { + String preQS = "?t=" + this.toolName + "&tag=" + entry.getKey() + "&a=" + accountId + "&pol=" + this.policies + "&st="; + StringBuilder qsBuilder = new StringBuilder(); + ArrayList times = entry.getValue(); + for (int idx=0; idx < times.size(); ++idx) { + qsBuilder.append(times.get(idx)); + qsBuilder.append(","); + + if ((idx % 150) == 0) { + String qs = preQS + qsBuilder.substring(0, qsBuilder.length()-1); + + // Dispatch the call to the metrics server + try { + Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs); + } catch (Throwable t) { + System.err.println(t); + } + } + qsBuilder = new StringBuilder(); + } + if (qsBuilder.length() > 0) { + String qs = preQS + qsBuilder.substring(0, qsBuilder.length()-1); + + // Dispatch the call to the metrics server + try { + Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs); + } catch (Throwable t) { + System.err.println(t); + } + } + } + } + } catch (Throwable t) { + System.err.println(t); + t.printStackTrace(); + } + return null; + }; +}; diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java new file mode 100644 index 000000000..0ea851961 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java @@ -0,0 +1,288 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*****************************************************************************/ + +package com.ibm.able.equalaccess.report; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.engine.Rule; + +/** + * This interface is responsible for aChecker baselines and comparing scans to baselines + */ +public class BaselineManager { + private static Gson gson = new Gson(); + public static enum eAssertResult { + ERROR(-1), + PASS(0), + BASELINE_MISMATCH(1), + FAIL(2) + ; + + private final int val; + + eAssertResult(final int val) { + this.val = val; + } + + int intValue() { + return this.val; + } + } + + public static class DiffResult { + public String kind = null; + public Object[] path = new Object[]{}; + public Object lhs = null; + public Object rhs = null; + public Integer index = null; + public DiffResult item = null; + + public DiffResult(String kind, Object[] path, Object lhs, Object rhs) { + this.kind = kind; + this.path = path; + this.lhs = lhs; + this.rhs = rhs; + } + + public DiffResult(String kind, int index, Object lhs, Object rhs) { + this.kind = kind; + this.index = index; + if (lhs != null && rhs != null) throw new RuntimeException("Cannot have index with lhs and rhs"); + this.item = new DiffResult(lhs != null ? "D" : "N", null, lhs, rhs); + } + } + + private static ConfigInternal config; + private static Map diffResults = new HashMap<>(); + private static IAbstractAPI absAPI; + private static Map refactorMap; + + public static void initialize(ConfigInternal config, IAbstractAPI absAPI, Map refactorMap) { + BaselineManager.config = config; + BaselineManager.absAPI = absAPI; + BaselineManager.refactorMap = refactorMap; + } + + public static ACReport getBaseline(String label) { + try { + ACReport retVal = BaselineManager.absAPI.loadBaseline(label); + if (retVal != null && retVal.results != null) { + for (ACReport.Result result: retVal.results) { + if (refactorMap.containsKey(result.ruleId)) { + Rule rule = refactorMap.get(result.ruleId); + Map mapping = rule.refactor.get(result.ruleId); + result.ruleId = rule.id; + result.reasonId = mapping.get(result.reasonId); + } + } + } + return retVal; + } catch (Error e) { + // console.error("getBaseline Error:", e); + return null; + } + } + + /** + * This function is responsible for comparing the scan results with baseline or checking that there are + * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will + * be used to perform the check, in the case no baseline is provided then we comply with only failing if + * there is a sinble violation which falls into failLevels. + * + * @param actualResults the actual results object provided by the user, this object should follow the + * same format as outlined in the return of aChecker.buildReport function. + * + * @return return 0 in the case actual matches baseline or no violations fall into failsLevels, + * return 1 in the case actual results does not match baseline results, + * return 2 in the case that there is a failure based on failLevels (this means no baseline found). + * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. + */ + public static eAssertResult assertCompliance(ACReport actualResults) { + // Get the label directly from the results object, the same label has to match + // the baseline object which is available in the global space. + String label = actualResults.label; + + // Fetch the baseline object based on the label provided + ACReport expected = BaselineManager.getBaseline(label); + + // In the case there are no baseline found then run a different assertion algo, + // when there is baseline compare the baselines in the case there is no baseline then + // check to make sure there are no violations that are listed in the fails on. + if (expected != null) { + // Run the diff algo to get the list of differences + DiffResult[] differences = BaselineManager.diffResultsWithExpected(actualResults, expected); + + // console.log("difference=" + JSON.stringify(differences, null, ' ')); + + // In the case that there are no differences then that means it passed + if (differences == null || differences.length == 0) { + return eAssertResult.PASS; + } else { + // Re-sort results and check again + ACReport modActual = (ACReport) actualResults.clone(); + modActual.sortResults(); + ACReport modExpected = (ACReport) expected.clone(); + modExpected.sortResults(); + DiffResult[] differences2 = BaselineManager.diffResultsWithExpected(modActual, modExpected); + if (differences2 == null || differences2.length == 0) { + return eAssertResult.PASS; + } else { + // In the case that there are failures add the whole diff array to + // global space indexed by the label so that user can access it. + BaselineManager.diffResults.put(label, differences); + + return eAssertResult.BASELINE_MISMATCH; + } + } + } else { + // In the case that there was no baseline data found compare the results based on + // the failLevels array, which was defined by the user. + int returnCode = BaselineManager.compareBasedOnFailLevels(actualResults); + + // In the case there are no violations that match the fail on then return as success + if (returnCode == 0) { + return eAssertResult.PASS; + } else { + // In the case there are some violation that match in the fail on then return 2 + // to identify that there was a failure, and we used a 2nd method for compare. + return eAssertResult.FAIL; + } + } + }; + + + /** + * This function is responsible for comparing actual with expected and returning all the differences as an array. + * + * @param actual Provide the actual object to be used for compare + * @param expected Provide the expected object to be used for compare + * + * @return differences - return an array of diff objects that were found, following is the format of the object: + * [ + * { + * "kind": "E", + * "path": [ + * "reports", + * 0, + * "issues", + * 10, + * "xpath" + * ], + * "lhs": "/html[1]/body[1]/div[2]/table[5]", + * "rhs": "/html[1]/body[1]/div[2]/table[5]d", + * }, + * { + * "kind": "E", + * "path": [ + * "label" + * ], + * "lhs": "Table-layoutMultiple", + * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html", + * } + * ] + */ + public static DiffResult[] diffResultsWithExpected(ACReport actual, ACReport expected) { + // Run Deep diff function to compare the actual and expected values. + DiffResult[] differences = diff(actual, expected); + if (differences != null && differences.length > 0) { + differences = Arrays.stream(differences).filter(difference -> { + return "E".equals(difference.kind) + && difference.path.length == 4 + && difference.path.length > 2 && "bounds".equals(difference.path[2]) + && Math.abs((Integer)difference.lhs-(Integer)difference.rhs) <= 1; + }).toArray(size -> new DiffResult[size]); + if (differences.length == 0) return null; + } + + // Return the results of the diff, which will include the differences between the objects + return differences; + } + + /** + * This function is responsible for checking if any of the issues reported have any level that falls + * into the failsLevel array. + * + * @param report Provide the scan results, object which would be in the + * the same format as outlined in the return of aChecker.buildReport function. + * + * @return return 1 in the case a single issue was found which is in the failsLevel array. + * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. + */ + public static int compareBasedOnFailLevels(ACReport report) { + // Variable Declaration + String[] failLevels = BaselineManager.config.failLevels; + + // Loop over all the issues to check for any level that is in failLevels + // console.log(report); + for (ACReport.Result issue: report.results) { + // In the case current level is in the failsLevel array them fail, with out checking further + // currently we are not saving exactly which results failed, as all the issues are going to be saved to + // results file. + if (Arrays.asList(failLevels).indexOf(issue.level.toString()) > -1) { + // return 1 as there was a fialure + return 1; + } + } + + // return 0 as there were no levels that fall into the failLevels + return 0; + } + + /** + * This function is responsible for getting the diff results based on label for a scan that was already performed. + * + * @param label Provide a label for which to get the diff results for. + * + * @return return the diff results object from global space based on label provided, the object will be + * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. + */ + public static DiffResult[] getDiffResults(String label) { + return diffResults.get(label); + } + + private static DiffResult[] diff(ACReport actual, ACReport expected) { + Result[] actualRs = actual.results; + Result[] expectedRs = expected.results; + ArrayList retVal = new ArrayList<>(); + for (int idx=actualRs.length; idx < expectedRs.length; ++idx) { + retVal.add(new DiffResult("A", idx, null, gson.toJson(expectedRs[idx]))); + } + for (int idx=expectedRs.length; idx < actualRs.length; ++idx) { + retVal.add(new DiffResult("A", idx, gson.toJson(expectedRs[idx]), null)); + } + for (int idx=0; idx> nlsStore = new HashMap<>(); + + public Object[] data = {}; + + public CompressedReport(ReporterStored info) { + ACReport report = info.engineReport; + ACReport.Summary summary = report.summary; + CompressedReport.scanID = report.scanID; + CompressedReport.toolID = report.toolID; + this.data = new Object[] { + summary.startScan, // startScan (0) + summary.URL, // url (1) + info.pageTitle, // pagetitle (2) + report.label, // label (3) + info.scanProfile, // scanProfile (4) + report.numExecuted, // numExecuted (5) + summary.scanTime, // scanTime (6) + summary.ruleArchive, // ruleArchive (7) + summary.policies, // policies (8) + summary.reportLevels, // reportLevels (9) + new Object[report.results.length][], // (10) + summary.counts + }; + for (int idx=0; idx 32000) { + issue[idx2] = ((String) issue[idx2]).substring(0, 32000 - 3) + "..."; + } + } + Map storeRuleMap = nlsStore.getOrDefault(result.ruleId, new HashMap()); + storeRuleMap.put( + result.reasonId, + report.nls.getOrDefault( + result.ruleId, + new HashMap() + ).getOrDefault( + result.reasonId, + result.ruleId+"_"+result.reasonId + ) + ); + } + } + + public ReporterStored uncompress() { + ACReport engineReport = new ACReport(); + engineReport.label = (String)data[3]; + engineReport.numExecuted = (Integer)data[5]; + ACReport.Summary summary = engineReport.summary; + summary.scanTime = (Long)data[6]; + summary.ruleArchive = (String)data[7]; + summary.policies = (String[])data[8]; + summary.reportLevels = (String[])data[9]; + summary.startScan = (Long)data[0]; + summary.URL = (String)data[1]; + summary.counts = (ACReport.SummaryCounts)data[11]; + engineReport.results = new ACReport.Result[((Object[])data[10]).length]; + for (int idx=0; idx<((Object[][])data[10]).length; ++idx) { + Object[] issue = ((Object[][])data[10])[idx]; + ACReport.Result result = engineReport.results[idx] = new ACReport.Result(); + result.category = (String)issue[0]; + result.ruleId = (String)issue[1]; + result.value = (String[])issue[2]; + result.reasonId = (String)issue[3]; + result.messageArgs = (String[])issue[4]; + result.apiArgs = new Object[] {}; + result.path = (Map)issue[5]; + result.ruleTime = (Integer)issue[6]; + result.message = (String)issue[10]; + result.snippet = (String)issue[7]; + result.help = (String)issue[8]; + result.ignored = (Boolean)issue[9]; + result.level = ReporterManager.valueToLevel((String[])issue[2]); + Map nlsRuleMap = engineReport.nls.getOrDefault(result.ruleId, new HashMap()); + nlsRuleMap.put( + result.reasonId, + nlsStore.getOrDefault( + result.ruleId, + new HashMap() + ).getOrDefault( + result.reasonId, + result.ruleId+"_"+result.reasonId + ) + ); + } + return new ReporterStored(data[2].toString(), data[4].toString(), engineReport); + } + + public long getStartScan() { + return (Long)data[0]; + } + + public String getLabel() { + return (String)data[3]; + } + + public int issuesLength() { + return ((Object[][])data[10]).length; + } + + public eRuleLevel issueLevel(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return ReporterManager.valueToLevel((String[])issue[2]); + } + + public String issueRuleId(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return (String)issue[1]; + } + + public String issueMessage(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return (String)issue[10]; + } + + public String issuePathDom(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return ((Map)issue[5]).get("dom"); + } + + public String issueHelp(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return (String)issue[8]; + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/IReporter.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/IReporter.java new file mode 100644 index 000000000..9830bdac2 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/IReporter.java @@ -0,0 +1,30 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.report; + +import java.util.List; + +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.Guideline; + +public interface IReporter { + String name(); + /** + * @return [ reportPath: string, report: string ] + */ + ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored reportData); + ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, List summaryData); +}; \ No newline at end of file diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java new file mode 100644 index 000000000..755138527 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java @@ -0,0 +1,27 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.report; + +public class ReporterFile { + public String path; + // summary: string | Buffer | ((filename?: string) => Promise) + public Object contents; + + public ReporterFile(String path, String contents) { + this.path = path; + this.contents = contents; + } +} \ No newline at end of file diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java new file mode 100644 index 000000000..6fa71e8ff --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java @@ -0,0 +1,228 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.report; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gson.Gson; +import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.ACError; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.eRuleConfidence; +import com.ibm.able.equalaccess.engine.eRuleLevel; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.enginecontext.EngineContextManager; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; + +public class ReporterManager { + private static Gson gson = new Gson(); + private static ReporterManager singleton = null; + public static ReporterManager get() { + if (singleton == null) throw new ACError("ReporterManager not intialized"); + return singleton; + } + public static ReporterManager initialize(ConfigInternal config, IAbstractAPI absAPI, Guideline[] rulesets) { + return singleton = new ReporterManager(config, absAPI, rulesets); + } + + private ConfigInternal config; + private IAbstractAPI absAPI; + private Guideline[] rulesets; + private List reporters = new ArrayList<>(); + private List reports = new ArrayList<>(); + private IReporter returnReporter = new ACReporterJSON(); + + private ReporterManager(ConfigInternal config, IAbstractAPI absAPI, Guideline[] rulesets) { + this.config = config; + this.absAPI = absAPI; + this.rulesets = rulesets; + if (config.perfMetrics) { + reporters.add(new ACReporterMetrics(config.toolName, config.policies)); + } + + if (!Arrays.asList(config.outputFormat).contains("disable")) { + if (Arrays.asList(config.outputFormat).contains("json")) { + reporters.add(new ACReporterJSON()); + } + if (Arrays.asList(config.outputFormat).contains("html")) { + // TODO: + // reporters.push(new ACReporterHTML()) + } + if (Arrays.asList(config.outputFormat).contains("csv")) { + reporters.add(new ACReporterCSV(absAPI)); + } + if (Arrays.asList(config.outputFormat).contains("xlsx")) { + // TODO: + // reporters.add(new ACReporterXLSX()); + } + } + } + private Set usedLabels = new HashSet(); + + public ACReport addEngineReport(String scanProfile, long startScan, String url, String pageTitle, String label, ACEReport engineReport) { + verifyLabel(label); + usedLabels.add(label); + ACReport filteredReport = filterReport(engineReport, label); + filteredReport.summary.startScan = startScan; + filteredReport.summary.URL = url; + filteredReport.label = label; + ReporterStored storedReport = new ReporterStored(pageTitle, scanProfile, filteredReport); + for (Result issue: filteredReport.results) { + issue.help = getHelpUrl(issue); + } + CompressedReport compressedReport = new CompressedReport(storedReport); + if (reporters.size() > 0) { + reports.add(compressedReport); + for (IReporter reporter: reporters) { + ReporterFile reportInfo = reporter.generateReport(config, rulesets, storedReport); + if (reportInfo != null) { + try { + absAPI.writeFile(reportInfo.path, reportInfo.contents); + } catch (IOException e) { + System.err.println(e); + e.printStackTrace(); + } + } + } + } + ReporterFile retVal = returnReporter.generateReport(config, rulesets, storedReport); + if (retVal != null) return gson.fromJson(retVal.contents.toString(), ACReport.class); + return null; + } + + private void verifyLabel(String label) { + // In the case that the label is null or undefined, throw an error + if (label == null) { + throw new ACError("labelNotProvided: Label must be provided when calling aChecker.getCompliance."); + } + + // Check to make sure that the label that is provided is unique with all the other ones + // that we have gone through. + boolean labelUnique = isLabelUnique(label); + + // In the case that the label is not unique + if (!labelUnique) { + throw new ACError("Label provided to aChecker.getCompliance ("+label+") should be unique across all testcases in a single accessibility-checker session."); + } + } + + private boolean isLabelUnique(String label) { + return !usedLabels.contains(label); + } + + private ACReport filterReport(ACEReport engineResult, String scanLabel) { + Map>> ignoreLookup = new HashMap>> (); + + ACReport baselineReport = absAPI.loadBaseline(scanLabel); + if (baselineReport != null) { + for (Result issue : baselineReport.results) { + // ignoreLookup[issue.path.dom] = ignoreLookup[issue.path.dom] || {} + Map> a = ignoreLookup.get(issue.path.get("dom")); + if (a == null) { + ignoreLookup.put(issue.path.get("dom"), new HashMap>()); + a = ignoreLookup.get(issue.path.get("dom")); + } + // ignoreLookup[issue.path.dom][issue.ruleId] = ignoreLookup[issue.path.dom][issue.ruleId] || {} + Set b = a.get(issue.ruleId); + if (b == null) { + b = new HashSet(); + } + // ignoreLookup[issue.path.dom][issue.ruleId][issue.reasonId] = true; + b.add(issue.reasonId); + } + } + ACReport retVal = new ACReport(config, engineResult, scanLabel); + + // Set the config level and filter the results. Make note of which NLS keys we need + for (ACReport.Result pageResult: retVal.results) { + eRuleLevel reportLevel = ReporterManager.valueToLevel(pageResult.value); + boolean ignored = false; + if (!eRuleConfidence.PASS.toString().equals(pageResult.value[1]) + && ignoreLookup.containsKey(pageResult.path.get("dom")) + && ignoreLookup.get(pageResult.path.get("dom")).containsKey(pageResult.ruleId) + && ignoreLookup.get(pageResult.path.get("dom")).get(pageResult.ruleId).contains(pageResult.reasonId)) + { + ignored = true; + } + pageResult.ignored = ignored; + pageResult.level = reportLevel; + } + + retVal.addCounts(engineResult.summary.counts); + retVal.filter(config.reportLevels); + + return retVal; + } + + public static eRuleLevel valueToLevel(String[] reportValue) { + eRuleLevel reportLevel = eRuleLevel.undefined; + if ("PASS".equals(reportValue[1])) { + reportLevel = eRuleLevel.pass; + } else if (("VIOLATION".equals(reportValue[0]) || "RECOMMENDATION".equals(reportValue[0])) && "MANUAL".equals(reportValue[1])) { + reportLevel = eRuleLevel.manual; + } else if ("VIOLATION".equals(reportValue[0])) { + if ("FAIL".equals(reportValue[1])) { + reportLevel = eRuleLevel.violation; + } else if ("POTENTIAL".equals(reportValue[1])) { + reportLevel = eRuleLevel.potentialviolation; + } + } else if ("RECOMMENDATION".equals(reportValue[0])) { + if ("FAIL".equals(reportValue[1])) { + reportLevel = eRuleLevel.recommendation; + } else if ("POTENTIAL".equals(reportValue[1])) { + reportLevel = eRuleLevel.potentialrecommendation; + } + } + return reportLevel; + } + + private static final IEngineContext engine = EngineContextManager.getEngineContext(null); + private String getHelpUrl(ACReport.Result issue) { + if (issue.help != null && issue.help.length() > 0) return issue.help; + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String helpUrl = engine.getHelp(issue.ruleId, issue.reasonId, config.ruleArchivePath == null ? config.ruleArchive : config.ruleArchivePath.substring(config.ruleArchivePath.lastIndexOf("/")+1)); + return helpUrl+"#"+engine.encodeURIComponent(issue.toHelpData()); + } + + public void generateSummaries() { + long endReport = new Date().getTime(); + // If no scans, don't generate summaries + if (reports.isEmpty()) return; + for (IReporter reporter: reporters) { + ReporterFile summaryInfo = reporter.generateSummary(config, rulesets, endReport, reports); + if (summaryInfo != null) { + try { + absAPI.writeFile(summaryInfo.path, summaryInfo.contents); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + reports.clear(); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java new file mode 100644 index 000000000..e95e29316 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java @@ -0,0 +1,30 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.report; + +import com.ibm.able.equalaccess.engine.ACReport; + +public class ReporterStored { + public String pageTitle; + public String scanProfile; + public ACReport engineReport; + + public ReporterStored(String title, String profile, ACReport report) { + pageTitle = title; + scanProfile = profile; + engineReport = report; + } +}; \ No newline at end of file diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Fetch.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Fetch.java new file mode 100644 index 000000000..c8b8f002a --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Fetch.java @@ -0,0 +1,107 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import com.google.gson.Gson; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.X509TrustManager; + +public class Fetch { + private Fetch() {} + + private static Gson gson = new Gson(); + + public static String get(String urlStr) throws IOException { + return get(urlStr, false); + } + + public static String get(String urlStr, boolean ignoreSSL) throws IOException { + SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory(); + HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier(); + + if (ignoreSSL) { + try { + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, new TrustManager[] { new X509TrustManager() { + + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[0]; + } + }}, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + } catch (Error err) { + System.err.println("Ignoring SSL Err! "+err); + } catch (Exception err2) { + System.err.println("Ignoring SSL Err! "+err2); + } + } + URL url = new URL(urlStr); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); + StringBuilder sb = new StringBuilder(); + String output; + while ((output = br.readLine()) != null) { + sb.append(output); + } + if (ignoreSSL) { + HttpsURLConnection.setDefaultSSLSocketFactory(factory); + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } + return sb.toString(); + } + + public static T[] getJSONArr(String urlStr, Class clazz) throws IOException { + return getJSONArr(urlStr, clazz, false); + } + + public static T[] getJSONArr(String urlStr, Class clazz, boolean ignoreHTTPSErrors) throws IOException { + return gson.fromJson(Fetch.get(urlStr, ignoreHTTPSErrors), clazz); + } + + public static T getJSONObj(String urlStr, Class clazz) throws IOException { + return getJSONObj(urlStr, clazz, false); + } + + public static T getJSONObj(String urlStr, Class clazz, boolean ignoreHTTPSErrors) throws IOException { + return gson.fromJson(Fetch.get(urlStr, ignoreHTTPSErrors), clazz); + } +} diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Misc.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Misc.java new file mode 100644 index 000000000..6f479c7c9 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Misc.java @@ -0,0 +1,49 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.util; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class Misc { + private Misc() {} + + public static T firstNotNull(T ... args) { + for (T x : args) { + if (x != null) return x; + } + return null; + } + + public static boolean classIsAvailable(String className) { + try { + Class.forName(className); + return true; + } catch (Throwable ex) { + // Class or one of its dependencies is not present... + return false; + } + } + + public static String toISOString(Date d) { + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); + df.setTimeZone(tz); + return df.format(d); + } +} diff --git a/java-accessibility-checker/src/main/javadoc/overview.html b/java-accessibility-checker/src/main/javadoc/overview.html new file mode 100644 index 000000000..478934911 --- /dev/null +++ b/java-accessibility-checker/src/main/javadoc/overview.html @@ -0,0 +1,272 @@ + + + + + accessibility-checker overview + + + +
+

accessibility-checker

+
+
+

Overview

+
+

+ accessibility-checker is a Java module that + allows you to do the following: +

+
    +
  • + perform integrated accessibility testing within a + continuous integration pipeline, such as Travis CI +
  • +
  • + works with test frameworks (parsing engines), such as + Selenium and Playwright +
  • +
  • + aside from just performing accessibility scanning, it + provides a framework to validate accessibility scan + results against baseline files and/or simply failing the + test cases based on the levels of violations found + during the scan +
  • +
+

+ The Java module is a component of the + IBM Equal Access Toolkit. The Toolkit provides the tools and + guidance to create + experiences that are delightful for people of all abilities. + The guidance is organized by phase, such as Plan, Design, + Develop, and Verify, and explains how to integrate the + automated testing tools into the + Verify phase. The Toolkit is a major part + of the accessibility + information and applications at + ibm.com/able. +

+
+

Usage

+ +
+
+

Programmatic

+ +
+

+ The following is how to perform an accessibility scan within + your test cases and verify the scan results. See the AccessibilityChecker docs for details. +

+
+
+ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest");
+eAssertResult resultCode = AccessibilityChecker.assertCompliance(report);
+// The page has compliance issues, so this assert should fail
+assertEquals("Scan resulted in "+resultCode.toString(), eAssertResult.PASS, resultCode);            
+                
+
+

+ Note that it's critical to close the engine, otherwise, + output files for the report may not be generated properly. + If you execute batch scans, the engine should be closed + after all the scans are completed for better performance. + The following is a sample usage scenario: +

+ +
+
+AccessibilityChecker.close();
+                
+
+

+ Refer to + Examples + for sample usage scenarios. +

+
+

+ Quick Start and installation +

+ +
+

+ Grab a + boilerplate +

+ +
+

Prerequisites

+ +
+
    +
  1. Java 17
  2. +
  3. org.seleniumhq.selenium:selenium-java:4.23.0 or com.microsoft.playwright:playwright:1.46.0
  4. +
+
+

Configuration

+
+
+

+ Configuring accessibility-checker +

+ +
+

+ A default configuration is defined which uses the latest + archive, IBM_Accessibility policy, and some + default settings. If you would like to override any of these + values, create an accessibility-checker configuration file. +

+

+ Configuring accessibility-checker plugin + involves constructing a AccessibilityChecker.json file in + the project root, which will contain all the configuration + options for accessibility-checker. Following is + the structure of the AccessibilityChecker.json file: +

+
+
+{
+    // optional - Specify the rule archive
+    // Default: latest
+    // Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids.
+    // If "latest", will use the latest rule release
+    // If "versioned" (supported in 3.1.61+), will use the latest rule release at
+    // the time this version of the tool was released 
+    "ruleArchive": "versioned",
+
+    // optional - Specify one or many policies to scan.
+    // i.e. For one policy use policies: IBM_Accessibility
+    // i.e. Multiple policies: IBM_Accessibility, WCAG_2_1
+    // Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids
+    "policies": ["IBM_Accessibility"],
+
+    // optional - Specify one or many violation levels on which to fail the test
+    //            i.e. If specified violation then the testcase will only fail if
+    //                 a violation is found during the scan.
+    // i.e. failLevels: violation
+    // i.e. failLevels: violation,potential violation or refer to below as a list
+    // Default: violation, potentialviolation
+    "failLevels": [ "violation", "potentialviolation" ],
+
+    // optional - Specify one or many violation levels that should be reported
+    //            i.e. If specified violation then in the report it would only contain
+    //                 results which are level of violation.
+    // i.e. reportLevels: violation
+    // Valid values: violation, potentialviolation, recommendation, potentialrecommendation, manual
+    // Default: violation, potentialviolation
+    "reportLevels": [ "violation", "potentialviolation",
+        "recommendation", "potentialrecommendation", "manual" ],
+
+    // Optional - In which formats should the results be output
+    // Valid values: json, csv, disable
+    // Default: json
+    "outputFormat": [ "json" ],
+
+    // Optional - Specify labels that you would like associated to your scan
+    // i.e.
+    //   label: Firefox,master,V12,Linux
+    //   label:
+    //       - Firefox
+    //       - master
+    //       - V12
+    //       - Linux
+    // Default: N/A
+    "label": [ "master" ],
+
+    // optional - Where the scan results should be saved.
+    // Default: results
+    "outputFolder": "results"
+
+    // Optional - Should the timestamp be included in the filename of the reports?
+    // Default: true
+    "outputFilenameTimestamp": true
+
+    // optional - Where the baseline results should be loaded from
+    // Default: baselines
+    "baselineFolder": "test/baselines"
+
+    // optional - Where the tool can read/write cached files (ace-node.js / archive.json)
+    // Default: `${os.tmpdir()}/accessibility-checker/`
+    "cacheFolder": "/tmp/accessibility-checker"
+}
+
+ +
+

+ Known issues and workarounds +

+ +
+
    +
  1. +

    + If your site has a + Content Security Policy, the engine + script may be prevented from loading. In the browser + console, you'll see something like: +

    +
    +

    + VM43:24 Refused to load the script ‘https://cdn.jsdelivr.net/npm/accessibility-checker-engine@3.1.42/ace.js’ + because it violates the following Content + Security Policy directive: +

    +
    +

    + If you would prefer not to add cdn.jsdelivr.net to + the CSP, you can add able.ibm.com instead via your + config file (e.g., ruleServer: "https://able.ibm.com/rules") +

    +
  2. +
+
+

Feedback and reporting bugs

+ +
+

+ If you think you've found a bug, have questions or + suggestions, open a + GitHub + Issue, tagged with java-accessibility-checker. +

+

+ If you are an IBM employee, feel free to ask questions in + the IBM internal Slack channel + #accessibility-at-ibm. +

+
+

License

+ +
+

+ IBM Equal Access Toolkit is released under the Apache-2.0 license +

+
+
+ + + \ No newline at end of file diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerPlaywrightTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerPlaywrightTest.java new file mode 100644 index 000000000..4c462436d --- /dev/null +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerPlaywrightTest.java @@ -0,0 +1,223 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess; + +import org.junit.Test; +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Arrays; +import java.util.Map; +import java.util.List; +import java.util.HashSet; +import java.util.Set; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + +import com.google.common.io.Files; +import com.google.gson.Gson; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; +import com.microsoft.playwright.*; + +public class AccessibilityCheckerPlaywrightTest { + public static class UnitTestInfoResult { + public String ruleId; + public String reasonId; + public String category; + public String message; + public String[] messageArgs; + public String[] value; + public Map path; + + public boolean matches(Result result) { + return ruleId.equals(result.ruleId) + && reasonId.equals(result.reasonId) + && category.equals(result.category) + && message.equals(result.message) + && value[1].equals(result.value[1]) + && path.get("dom").equals(result.path.get("dom")) + && path.get("aria").equals(result.path.get("aria")); + } + } + public static class UnitTestInfo { + public String[] ruleIds; + public UnitTestInfoResult[] results; + } + private static Page driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + try { + Playwright playwright = Playwright.create(); + Browser browser = playwright.chromium().launch(); + AccessibilityCheckerPlaywrightTest.driver = browser.newPage(); + } catch (Throwable err) { + System.err.println(err.toString()); + err.printStackTrace(); + } + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + AccessibilityCheckerPlaywrightTest.driver.close(); + AccessibilityChecker.close(); + } + + @Test public void getCompliance() { + ACConfigManager.getConfig().label = new String[] { "IBMa-Java-TeSt" }; + AccessibilityCheckerPlaywrightTest.driver.navigate("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceTest"); + assertNotNull(report); + assertTrue(report.results.length > 0); + } + + @Test public void baselines() throws IOException { + Paths.get("baselines", "Playwright_getComplianceTest3.json").toFile().delete(); + AccessibilityCheckerPlaywrightTest.driver.navigate("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceTest2"); + assertEquals(eAssertResult.FAIL, AccessibilityChecker.assertCompliance(report)); + new File("baselines").mkdirs(); + Files.copy(Paths.get("results", "Playwright_getComplianceTest2.json").toFile(), Paths.get("baselines", "Playwright_getComplianceTest3.json").toFile()); + + report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceTest3"); + assertEquals(eAssertResult.PASS, AccessibilityChecker.assertCompliance(report)); + Paths.get("baselines", "Playwright_getComplianceTest3.json").toFile().delete(); + } + + // @Test public void getComplianceLong() { + // AccessibilityCheckerTest.driver.navigate("https://openliberty.io/docs/latest/reference/javadoc/liberty-jakartaee8-javadoc.html?path=liberty-javaee8-javadoc/index-all.html"); + // ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceLong"); + // assertNotNull(report); + // assertTrue(report.results.length > 0); + // } + + private void listFiles(File f, java.util.List retFiles) { + if (f.isFile() && f.exists() && (f.getName().endsWith("html") || f.getName().endsWith("htm"))) { + retFiles.add(f); + } else if (f.isDirectory()) { + for (File subF: f.listFiles((testFile, name) -> testFile.isDirectory() || name.endsWith(".htm") || name.endsWith(".html"))) { + listFiles(subF, retFiles); + } + } + + } + @Test public void getComplianceTestsuite() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "customRuleServer": true, + "rulePack": "https://localhost:9445/rules/archives/preview/js", + "ruleArchive": "preview", + "ignoreHTTPSErrors": true, + "policies": [ "IBM_Accessibility", "IBM_Accessibility_next"], + "failLevels": [ "violation", "potentialviolation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual", + "pass" + ], + "outputFormat": [ "json" ], + "label": [ + "IBMa-Java-TeSt" + ] +} +"""); + myWriter.close(); + ACConfigManager.getConfig(); + + Gson gson = new Gson(); + File testRootDir = Paths.get(System.getProperty("user.dir"), "..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); + ArrayList testFiles = new ArrayList<>(); + listFiles(testRootDir, testFiles); + + + // Skip test cases that don't work in this environment (e.g., can't disable meta refresh in chrome) + Set skipList = new HashSet<>(Arrays.asList(new File[] { + //not in karma conf file + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-hasTextEmbedded.html").toFile(), + // path.join(testRootDir, "a_text_purpose_ruleunit", "A-nonTabable.html"), + + // Meta refresh + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-invalidRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-validRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_redirect_optional_ruleunit", "Meta-RefreshZero.html").toFile(), + + // CSS test issues + Paths.get(testRootDir.getAbsolutePath(), "style_color_misuse_ruleunit","D543.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_before_after_review_ruleunit","D100.html").toFile(), + + // Misc + // path.join(testRootDir, "aria_banner_label_unique_ruleunit", "validLandMarks-testCaseFromAnn.html"), + })); + + for (File testFile: testFiles) { + if (skipList.contains(testFile)) continue; + AccessibilityCheckerPlaywrightTest.driver.navigate("file://"+testFile.getAbsolutePath()); + ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_"+testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); + String unitTestInfoStr = AccessibilityCheckerPlaywrightTest.driver.evaluate("() => JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); + if (!"false".equals(unitTestInfoStr)) { + UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); + List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); + if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { + System.out.println(testFile.getCanonicalPath()); + System.out.flush(); + List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); + List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); + for (int idxActual=0; idxActual path; + + public boolean matches(Result result) { + return ruleId.equals(result.ruleId) + && reasonId.equals(result.reasonId) + && category.equals(result.category) + && message.equals(result.message) + && value[1].equals(result.value[1]) + && path.get("dom").equals(result.path.get("dom")) + && path.get("aria").equals(result.path.get("aria")); + } + } + public static class UnitTestInfo { + public String[] ruleIds; + public UnitTestInfoResult[] results; + } + private static WebDriver driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + // Make sure we're starting with a clean config + File configFile = new File("achecker.json"); + configFile.delete(); + ACConfigManager.resetConfig(); + + try { + // ClientConfig timeoutConfig = ClientConfig.defaultConfig().readTimeout(Duration.ofMinutes(60)); + FirefoxOptions options = new FirefoxOptions(); + driver = new FirefoxDriver(options); + } catch (SessionNotCreatedException e) { + System.out.println(e.getMessage()); + System.out.println(e.getAdditionalInformation()); + throw e; + } + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + AccessibilityCheckerSeleniumFFTest.driver.close(); + AccessibilityChecker.close(); + } + + private void listFiles(File f, java.util.List retFiles) { + if (f.isFile() && f.exists() && (f.getName().endsWith("html") || f.getName().endsWith("htm"))) { + retFiles.add(f); + } else if (f.isDirectory()) { + for (File subF: f.listFiles((testFile, name) -> testFile.isDirectory() || name.endsWith(".htm") || name.endsWith(".html"))) { + listFiles(subF, retFiles); + } + } + + } + + @Test public void getCompliance() { + ACConfigManager.getConfig().label = new String[] { "IBMa-Java-TeSt" }; + AccessibilityCheckerSeleniumFFTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "SeleniumFF_getComplianceTest"); + assertNotNull(report); + assertTrue(report.results.length > 0); + } + + public void getComplianceTestsuite() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "customRuleServer": true, + "rulePack": "https://localhost:9445/rules/archives/preview/js", + "ruleArchive": "preview", + "ignoreHTTPSErrors": true, + "policies": [ "IBM_Accessibility", "IBM_Accessibility_next"], + "failLevels": [ "violation", "potentialviolation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual", + "pass" + ], + "outputFormat": [ "json" ], + "label": [ + "IBMa-Java-TeSt" + ] +} +"""); + myWriter.close(); + ACConfigManager.getConfig(); + + Gson gson = new Gson(); + File testRootDir = Paths.get(System.getProperty("user.dir"), "..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); + ArrayList testFiles = new ArrayList<>(); + listFiles(testRootDir, testFiles); + + + // Skip test cases that don't work in this environment (e.g., can't disable meta refresh in chrome) + Set skipList = new HashSet<>(Arrays.asList(new File[] { + //not in karma conf file + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-hasTextEmbedded.html").toFile(), + // path.join(testRootDir, "a_text_purpose_ruleunit", "A-nonTabable.html"), + + // Meta refresh + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-invalidRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-validRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_redirect_optional_ruleunit", "Meta-RefreshZero.html").toFile(), + + // CSS test issues + Paths.get(testRootDir.getAbsolutePath(), "style_color_misuse_ruleunit","D543.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_before_after_review_ruleunit","D100.html").toFile(), + + // Firefox + Paths.get(testRootDir.getAbsolutePath(), "aria_role_redundant_ruleunit", "Fail.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_focus_visible_ruleunit", "CSS-used.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "object_text_exists_ruleunit", "act_fail_3.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_conflict_ruleunit", "aria-hidden.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecified.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecifiedValidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InvalidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InValidRoleInvalidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InValidRoleSpecified.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecifiedInvalidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecifiedMultiple.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InValidRoleSpecifiedMultiple.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "area_element_test.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "elementsWithSupportingAttributes.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_role_valid_ruleunit", "area_no_href.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "element_scrollable_tabbable_ruleunit", "act_fail2.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "element_scrollable_tabbable_ruleunit", "textarea_pass2.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "element_scrollable_tabbable_ruleunit", "act_fail1.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "fieldset_label_valid_ruleunit", "FieldSet-hasarialabel.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "fieldset_label_valid_ruleunit", "FieldSet-nested.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "fieldset_label_valid_ruleunit", "test_mixed_1.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-nonTabable.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-slot-text-error2.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-slot-text-error1.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "target_spacing_sufficient_ruleunit", "link_in_text.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "target_spacing_sufficient_ruleunit", "block_element_inline.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_landmark_name_unique_ruleunit", "example_0_fail.html").toFile() + + // Misc + // path.join(testRootDir, "aria_banner_label_unique_ruleunit", "validLandMarks-testCaseFromAnn.html"), + })); + + for (File testFile: testFiles) { + if (skipList.contains(testFile)) continue; + AccessibilityCheckerSeleniumFFTest.driver.get("file://"+testFile.getAbsolutePath()); + ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_"+testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); + String unitTestInfoStr = ((JavascriptExecutor)driver).executeScript("return JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); + if (!"false".equals(unitTestInfoStr)) { + UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); + List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); + if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { + System.out.println(testFile.getCanonicalPath()); + System.out.flush(); + List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); + List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); + for (int idxActual=0; idxActual path; + + public boolean matches(Result result) { + return ruleId.equals(result.ruleId) + && reasonId.equals(result.reasonId) + && category.equals(result.category) + && message.equals(result.message) + && value[1].equals(result.value[1]) + && path.get("dom").equals(result.path.get("dom")) + && path.get("aria").equals(result.path.get("aria")); + } + } + public static class UnitTestInfo { + public String[] ruleIds; + public UnitTestInfoResult[] results; + } + private static ChromeDriver driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + // Make sure we're starting with a clean config + File configFile = new File("achecker.json"); + configFile.delete(); + ACConfigManager.resetConfig(); + + String workingDir = System.getProperty("user.dir"); + String chromeDriverDir = System.getenv("chromedriverpath"); + ChromeOptions options = new ChromeOptions(); + if (chromeDriverDir == null) { + chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + } else { + options.setBinary(System.getenv("chromebinpath")); + } + System.setProperty("webdriver.chrome.driver", chromeDriverDir); + options.addArguments("--headless=new"); + // options.setImplicitWaitTimeout + // options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); + try { + ClientConfig timeoutConfig = ClientConfig.defaultConfig().readTimeout(Duration.ofMinutes(60)); + AccessibilityCheckerSeleniumTest.driver = new ChromeDriver(ChromeDriverService.createDefaultService(), options, timeoutConfig); + } catch (SessionNotCreatedException e) { + System.out.println(e.getMessage()); + System.out.println(e.getAdditionalInformation()); + throw e; + } + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + AccessibilityCheckerSeleniumTest.driver.close(); + AccessibilityChecker.close(); + } + + @Test public void getCompliance() { + ACConfigManager.getConfig().label = new String[] { "IBMa-Java-TeSt" }; + AccessibilityCheckerSeleniumTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_getComplianceTest"); + assertNotNull(report); + assertTrue(report.results.length > 0); + } + + @Test public void baselines() throws IOException { + Paths.get("baselines", "Selenium_getComplianceTest3.json").toFile().delete(); + AccessibilityCheckerSeleniumTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_getComplianceTest2"); + assertEquals(eAssertResult.FAIL, AccessibilityChecker.assertCompliance(report)); + new File("baselines").mkdirs(); + Files.copy(Paths.get("results", "Selenium_getComplianceTest2.json").toFile(), Paths.get("baselines", "Selenium_getComplianceTest3.json").toFile()); + + report = AccessibilityChecker.getCompliance(driver, "Selenium_getComplianceTest3"); + assertEquals(eAssertResult.PASS, AccessibilityChecker.assertCompliance(report)); + Paths.get("baselines", "Selenium_getComplianceTest3.json").toFile().delete(); + } + + // @Test public void getComplianceLong() { + // AccessibilityCheckerTest.driver.get("https://openliberty.io/docs/latest/reference/javadoc/liberty-jakartaee8-javadoc.html?path=liberty-javaee8-javadoc/index-all.html"); + // ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_getComplianceLong"); + // assertNotNull(report); + // assertTrue(report.results.length > 0); + // } + + private void listFiles(File f, java.util.List retFiles) { + if (f.isFile() && f.exists() && (f.getName().endsWith("html") || f.getName().endsWith("htm"))) { + retFiles.add(f); + } else if (f.isDirectory()) { + for (File subF: f.listFiles((testFile, name) -> testFile.isDirectory() || name.endsWith(".htm") || name.endsWith(".html"))) { + listFiles(subF, retFiles); + } + } + + } + @Test public void getComplianceTestsuite() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "customRuleServer": true, + "rulePack": "https://localhost:9445/rules/archives/preview/js", + "ruleArchive": "preview", + "ignoreHTTPSErrors": true, + "policies": [ "IBM_Accessibility", "IBM_Accessibility_next"], + "failLevels": [ "violation", "potentialviolation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual", + "pass" + ], + "outputFormat": [ "json" ], + "label": [ + "IBMa-Java-TeSt" + ] +} +"""); + myWriter.close(); + ACConfigManager.getConfig(); + + Gson gson = new Gson(); + File testRootDir = Paths.get(System.getProperty("user.dir"), "..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); + ArrayList testFiles = new ArrayList<>(); + listFiles(testRootDir, testFiles); + + + // Skip test cases that don't work in this environment (e.g., can't disable meta refresh in chrome) + Set skipList = new HashSet<>(Arrays.asList(new File[] { + //not in karma conf file + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-hasTextEmbedded.html").toFile(), + // path.join(testRootDir, "a_text_purpose_ruleunit", "A-nonTabable.html"), + + // Meta refresh + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-invalidRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-validRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_redirect_optional_ruleunit", "Meta-RefreshZero.html").toFile(), + + // CSS test issues + Paths.get(testRootDir.getAbsolutePath(), "style_color_misuse_ruleunit","D543.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_before_after_review_ruleunit","D100.html").toFile(), + + // Misc + // path.join(testRootDir, "aria_banner_label_unique_ruleunit", "validLandMarks-testCaseFromAnn.html"), + })); + + for (File testFile: testFiles) { + if (skipList.contains(testFile)) continue; + AccessibilityCheckerSeleniumTest.driver.get("file://"+testFile.getAbsolutePath()); + ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_"+testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); + String unitTestInfoStr = AccessibilityCheckerSeleniumTest.driver.executeScript("return JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); + if (!"false".equals(unitTestInfoStr)) { + UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); + List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); + if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { + System.out.println(testFile.getCanonicalPath()); + System.out.flush(); + List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); + List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); + for (int idxActual=0; idxActual 0); + assertTrue(ACConfigManager.compareVersions("1.1.0", "1.0.0") > 0); + assertTrue(ACConfigManager.compareVersions("2.0.0", "1.0.0") > 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "1.0.1") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "1.1.0") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "2.0.0") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "1.0.0-rc.0") > 0); + assertTrue(ACConfigManager.compareVersions("1.0.0-rc.1", "1.0.0-rc.0") > 0); + assertTrue(ACConfigManager.compareVersions("1.0.0-rc.0", "1.0.0") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0-rc.0", "1.0.0-rc.1") < 0); + } +} \ No newline at end of file diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java new file mode 100644 index 000000000..3d7d8f100 --- /dev/null +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java @@ -0,0 +1,49 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.engine; + +import org.junit.Test; +import static org.junit.Assert.*; + +import com.ibm.able.equalaccess.engine.ACReport; + +public class ACReportTest { + + @Test public void cloneTest() { + ACReport one = new ACReport(); + one.results = new ACReport.Result[1]; + one.results[0] = new ACReport.Result(); + ACReport two = (ACReport) one.clone(); + assertNotSame(one, two); + + two.label="ASDF"; + assertNotEquals(one.label, two.label); + + two.summary.URL="Hi"; + assertNotEquals(one.summary.URL, two.summary.URL); + + two.summary.counts.elements = 5; + assertNotEquals(one.summary.counts.elements, two.summary.counts.elements); + + assertNotSame(one.results[0], two.results[0]); + + two.results[0].category = "Test"; + assertNotEquals(one.results[0].category, two.results[0].category); + + two.results[0].bounds.top = 5; + assertNotEquals(one.results[0].bounds.top, two.results[0].bounds.top); + } +} diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java new file mode 100644 index 000000000..6ce610e2d --- /dev/null +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java @@ -0,0 +1,33 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.util; + +import org.junit.Test; +import static org.junit.Assert.*; + +import java.io.IOException; + +public class FetchTest { + @Test public void getArr() { + String s = null; + try { + s = Fetch.get("https://cdn.jsdelivr.net/npm/accessibility-checker-engine@next/archives.json"); + } catch (IOException e) { + e.printStackTrace(); + } + assertEquals(String.class, s.getClass()); + } +} diff --git a/karma-accessibility-checker/src/lib/ACHelper.js b/karma-accessibility-checker/src/lib/ACHelper.js index 20f5cda98..b49117054 100644 --- a/karma-accessibility-checker/src/lib/ACHelper.js +++ b/karma-accessibility-checker/src/lib/ACHelper.js @@ -235,7 +235,50 @@ let aChecker = { * @memberOf this */ aChecker.runScan = async function (content, policies, url, pageTitle, label, iframeWindow) { - try { + try { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + + const getCounts = (engineReport) => { + let counts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } + + // Get the Data when the scan is started // Start time will be in milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now. const startScan = Date.now(); @@ -247,7 +290,14 @@ let aChecker = { let engineReport = await checker.check(content, policies); for (const result of engineReport.results) { delete result.node; + result.level = valueToLevel(result.value) } + let reportLevels = (aChecker.Config.reportLevels || []).concat(aChecker.Config.failLevels || []).map(lvl => lvl.toString()); + engineReport.summary ||= {}; + engineReport.summary.counts ||= getCounts(engineReport); + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + engineReport.results = engineReport.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); ReporterManager.config = BaselineManager.config = aChecker.Config; diff --git a/karma-accessibility-checker/src/lib/ReporterManager.js b/karma-accessibility-checker/src/lib/ReporterManager.js index ce00870e2..14daa7235 100644 --- a/karma-accessibility-checker/src/lib/ReporterManager.js +++ b/karma-accessibility-checker/src/lib/ReporterManager.js @@ -141,8 +141,10 @@ class ReporterManager { } }); - retVal.summary = {}; - retVal.summary.counts = ReporterManager.getCounts(retVal); + retVal.summary = { + counts: retVal.summary.counts + }; + retVal.summary.counts = ReporterManager.addCounts(retVal); retVal.results = retVal.results.filter(pageResult => { if (ReporterManager.config.reportLevels.includes(pageResult.level)) { @@ -179,18 +181,13 @@ class ReporterManager { return retVal; } - static getCounts(engineReport) { + static addCounts(engineReport) { let counts = { - violation: 0, - potentialviolation: 0, - recommendation: 0, - potentialrecommendation: 0, - manual: 0, - pass: 0, ignored: 0, elements: 0, elementsViolation: 0, - elementsViolationReview: 0 + elementsViolationReview: 0, + ...engineReport.summary.counts } let elementSet = new Set(); let elementViolationSet = new Set(); @@ -199,8 +196,8 @@ class ReporterManager { elementSet.add(issue.path.dom); if (issue.ignored) { ++counts.ignored; + --counts[issue.level.toString()]; } else { - ++counts[issue.level.toString()]; if (issue.level === eRuleLevel.violation) { elementViolationSet.add(issue.path.dom); elementViolationReviewSet.add(issue.path.dom); diff --git a/report-react/package-lock.json b/report-react/package-lock.json index 099bb6b83..4823faa97 100644 --- a/report-react/package-lock.json +++ b/report-react/package-lock.json @@ -10839,9 +10839,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -24482,9 +24482,9 @@ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "requires": { "braces": "^3.0.3", "picomatch": "^2.3.1" diff --git a/rule-server/package-lock.json b/rule-server/package-lock.json index a2eaa89a8..628824afd 100644 --- a/rule-server/package-lock.json +++ b/rule-server/package-lock.json @@ -872,9 +872,9 @@ "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" }, "node_modules/axios": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", - "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", diff --git a/rule-server/src/static/archives.json b/rule-server/src/static/archives.json index 768a8a11e..242a0617d 100644 --- a/rule-server/src/static/archives.json +++ b/rule-server/src/static/archives.json @@ -3,7 +3,13 @@ "id": "latest", "name": "Latest Deployment", "path": "/archives/latest" - }, + }, + { + "id": "29August2024", + "name": "29 August 2024 Deployment (IBM 7.2, 7.3)", + "version": "3.1.75", + "path": "/archives/2024.08.29" + }, { "id": "06August2024", "name": "06 August 2024 Deployment (IBM 7.2, 7.3)", @@ -213,7 +219,6 @@ "name": "17 November 2021 Deployment (IBM 7.2)", "version": "3.1.12", "path": "/archives/2021.11.17" - }, { "id": "25Oct2021", @@ -292,4 +297,4 @@ "name": "Preview Rules", "path": "/archives/preview" } -] +] \ No newline at end of file diff --git a/rule-server/src/static/archives/2024.08.29/doc/assets/NeedsReview16.svg b/rule-server/src/static/archives/2024.08.29/doc/assets/NeedsReview16.svg new file mode 100644 index 000000000..917834a38 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/assets/NeedsReview16.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/rule-server/src/static/archives/2024.08.29/doc/assets/Recommendation16.svg b/rule-server/src/static/archives/2024.08.29/doc/assets/Recommendation16.svg new file mode 100644 index 000000000..b57dc73d5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/assets/Recommendation16.svg @@ -0,0 +1,15 @@ + + + + + + +i + diff --git a/rule-server/src/static/archives/2024.08.29/doc/assets/Violation16.svg b/rule-server/src/static/archives/2024.08.29/doc/assets/Violation16.svg new file mode 100644 index 000000000..5f8c9c710 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/assets/Violation16.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/rule-server/src/static/archives/2024.08.29/doc/common/help.css b/rule-server/src/static/archives/2024.08.29/doc/common/help.css new file mode 100644 index 000000000..0db9f74b4 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/common/help.css @@ -0,0 +1,268 @@ +/****************************************************************************** + Copyright:: 2022- IBM, Inc + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +@import url("https://1.www.s81c.com/common/carbon-for-ibm-dotcom/tag/v1/latest/plex.css"); +@import url('https://unpkg.com/carbon-components/css/carbon-components.min.css'); +@import url("https://1.www.s81c.com/common/carbon-for-ibm-dotcom/tag/v1/latest/themes.css"); + +bx-list-item>code, p>code, td>code { + background-color: var(--cds-layer); + border-radius: 4px; + bottom: 0.0625em; + color: var(--cds-text-primary); + display: inline; + font-size: .75rem; + font-size: .875em; + font-weight: 400; + letter-spacing: .32px; + line-height: 1.33333; + padding: 0 0.5em; + position: relative; +} + +.toolHelp a { + color: var(--cds-link-primary) +} + +.toolHelp .toolMain p ~ p { + margin-top: .5rem; +} + +.toolHelp .toolHead h3 { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 24px; +} + +.toolHelp .toolHead .issueLevel { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; + font-style: normal; + font-weight: 400; + font-size: 12px; + line-height: 16px; +} + +.toolHelp .toolHead #ruleMessage { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 24px; + margin-top: .5rem; + margin-bottom: .5rem; +} + +.toolHelp .toolHead #groupLabel { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; + font-style: normal; + font-weight: 400; + font-size: 12px; + line-height: 16px; +} + +/* productive-heading-03 */ +.toolHelp .toolMain h3 { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 24px; +} + +.toolHelp .toolSide .bx--list__item { + color: black; + font-size: 0.875rem; + line-height: 18px; +} + +/* productive-heading-03 */ +.toolHelp .toolSide h3 { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 24px; +} + +@media (min-width: 42rem) { + html, body, .toolHelp .bx--row:nth-child(2) { + height: 100%; + } +} +body { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; + color: var(--cds-text-primary); + background-color: var(--cds-ui-background); +} + +.toolHelp { + padding: 0px; + margin: 0px; + max-width: 100%; + background-color: #e8daff; +} + +.toolHelp p { + font-family: 'IBM Plex Sans','Helvetica Neue',Arial,sans-serif; +font-style: normal; +font-weight: 400; +font-size: 14px; +line-height: 20px; +/* or 143% */ + +letter-spacing: 0.16px; +} + +.dds-theme-zone-g90 .toolHelp { + background-color: #31135E; +} + +.toolHelp .bx--row { + margin: 0px; +} + +.toolHelp .toolHead { + margin-bottom: 1rem; + padding-top: 1rem; +} +.toolHelp .toolMain { + background-color: var(--cds-ui-background); + padding-top: 1rem; + padding-bottom: 1rem; + border-top: solid var(--cds-text-primary) 1px; +} +.toolHelp .toolMain h2 { + margin-top: 32px; + margin-bottom: 0.5rem; +} +.toolHelp .toolMain h3 { + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} +.toolHelp .toolMain p { + margin-top: 0px; +} + +.toolHelp .toolSide { + padding: 16px 16px 16px 32px; + background-color: var(--cds-ui-background); + color: var(--cds-text-primary); + border-top: solid var(--cds-text-primary) 1px; +} +@media (min-width: 42rem) { + .toolHelp .toolSide { + border-left: solid var(--cds-text-primary) 1px; + } +} + +.toolHelp .toolSide h2 { + margin-top: 32px; + margin-bottom: 0.5rem; +} +.toolHelp .toolSide h3 { + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} +.toolHelp .toolSide p { + margin-top: 0px; +} +@media (min-width: 66rem) { + .toolHelp .toolMain p, bx-list-item { + max-width: 66.66%; + } +} +bx-code-snippet[type="multi"]::after { + height: 0px; +} + +#ruleInfo { + margin-top: 1rem; +} + +#ruleInfo p { + font-size: 14px; +} + +mark-down table tbody tr:hover { + background: var(--cds-layer-hover); +} +mark-down table tbody tr:hover td, mark-down table tbody tr:hover th { + background: var(--cds-layer-hover); + -webkit-border-after: 1px solid var(--cds-layer-hover); + border-block-end: 1px solid var(--cds-layer-hover); + -webkit-border-before: 1px solid var(--cds-layer-hover); + border-block-start: 1px solid var(--cds-layer-hover); + color: var(--cds-text-primary,#161616); +} + +mark-down table { + margin-top: 1rem; + width: 100%; +} + +@media (min-width: 66rem) { + mark-down table { + max-width: 66.66%; + } +} + +mark-down table thead { + font-size: var(--cds-heading-compact-01-font-size,0.875rem); + font-weight: var(--cds-heading-compact-01-font-weight,600); + line-height: var(--cds-heading-compact-01-line-height,1.28572); + letter-spacing: var(--cds-heading-compact-01-letter-spacing,0.16px); + background-color: var(--cds-layer-accent); +} + +mark-down table tr { + border: none; + block-size: 3rem; + inline-size: 100%; +} + +mark-down table th { + background-color: var(--cds-layer-accent); + color: var(--cds-text-primary,#161616); + -webkit-padding-end: 1rem; + padding-inline-end: 1rem; + -webkit-padding-start: 1rem; + padding-inline-start: 1rem; +} + +mark-down table td, mark-down table th { + text-align: start; + vertical-align: middle; +} + +mark-down table tbody { + font-size: var(--cds-body-compact-01-font-size,0.875rem); + font-weight: var(--cds-body-compact-01-font-weight,400); + line-height: var(--cds-body-compact-01-line-height,1.28572); + letter-spacing: var(--cds-body-compact-01-letter-spacing,0.16px); + background-color: var(--cds-layer); + inline-size: 100%; +} + +mark-down table td, mark-down table tbody th { + background: var(--cds-layer); + -webkit-border-after: 1px solid var(--cds-border-subtle); + border-block-end: 1px solid var(--cds-border-subtle); + -webkit-border-before: 1px solid var(--cds-layer); + border-block-start: 1px solid var(--cds-layer); + color: var(--cds-text-secondary,#525252); + -webkit-padding-end: 1rem; + padding-inline-end: 1rem; + -webkit-padding-start: 1rem; + padding-inline-start: 1rem; +} \ No newline at end of file diff --git a/rule-server/src/static/archives/2024.08.29/doc/common/help.js b/rule-server/src/static/archives/2024.08.29/doc/common/help.js new file mode 100644 index 000000000..c8fa2f0ec --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/common/help.js @@ -0,0 +1,225 @@ +/****************************************************************************** + Copyright:: 2022- IBM, Inc + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +class HTMLBaseElement extends HTMLElement { + constructor(...args) { + const self = super(...args); + self.parsed = false; // guard to make it easy to do certain stuff only once + self.parentNodes = []; + return self; + } + + connectedCallback() { + // collect the parentNodes + let el = this; + while (el.parentNode) { + el = el.parentNode; + this.parentNodes.push(el); + } + // check if the parser has already passed the end tag of the component + // in which case this element, or one of its parents, should have a nextSibling + // if not (no whitespace at all between tags and no nextElementSiblings either) + // resort to DOMContentLoaded or load having triggered + if ([this, ...this.parentNodes].some((el) => el.nextSibling) || document.readyState !== "loading") { + if (this.childrenAvailableCallback) + this.childrenAvailableCallback(); + this.parsed = true; + } else { + this.mutationObserver = new MutationObserver(() => { + if ([this, ...this.parentNodes].some((el) => el.nextSibling) || document.readyState !== "loading") { + if (this.childrenAvailableCallback) + this.childrenAvailableCallback(); + this.parsed = true; + this.mutationObserver.disconnect(); + } + }); + + this.mutationObserver.observe(this, { + childList: true, + }); + } + } +} + +function isDarkMode() { + return (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); +} + +customElements.define( + "mark-down", + class extends HTMLBaseElement { + constructor() { + super(); + setTimeout(() => { + let converted = marked.parse(this.textContent); + this.innerHTML = converted + .replace(/<(\/?)ul>/g, "<$1bx-unordered-list>") + .replace(/<(\/?)li>/g, "<$1bx-list-item>") + .replace(/[ \r\n]*/g, "") + .replace(/<\/code>[ \r\n]*<\/pre>/g, ""); + }, 0) + } + // childrenAvailableCallback() { + // let converted = marked.parse(this.innerHTML); + // this.innerHTML = converted + // .replace(/<(\/?)ul>/g, "<$1bx-unordered-list>") + // .replace(/<(\/?)li>/g, "<$1bx-list-item>") + // .replace(/[ \r\n]*/g, "") + // .replace(/<\/code>[ \r\n]*<\/pre>/g, ""); + // } + } +); + +customElements.define( + "code-snippet", + class extends HTMLBaseElement { + childrenAvailableCallback() { + let oldCode = this.innerHTML; + this.innerHTML = ""; + // const shadowRoot = this.attachShadow({mode: 'open'}); + const shadowRoot = this; + let snip = document.createElement("bx-code-snippet"); + snip.setAttribute("type", "multi"); + snip.innerHTML = oldCode.replace(/ ruleInfo.msgArgs[matchedNum]); + document.querySelector("#ruleMessage").innerHTML = ruleMessage.replace(/&/g, "&").replace(//g, ">") + } + setTimeout(() => { + if (ruleInfo.snippet) { + let snip = ruleInfo.snippet; + snip = snip.replace(/( [a-zA-Z-]+="[^"]*")/g, "\n $1"); + let snipElem = document.createElement("code-snippet"); + for (let line of snip.split("\n")) { + snipElem.appendChild(document.createTextNode(line+"\n")); + } + let locSnippet = document.querySelector("#locSnippet"); + locSnippet.innerHTML = `

Element location

`; + locSnippet.appendChild(snipElem); + } + }, 0); + if (ruleInfo.value) { + let value = ruleInfo.value; + const val = valueMap[value[0]][value[1]]; + let icon = ""; + if (val === "Violation") icon = ``; + if (val === "Needs review") icon = ``; + if (val === "Recommendation") icon = ``; + let level = document.querySelector("#locLevel"); + let parent = level.parentElement; + level = parent.removeChild(level); + parent.insertBefore(level, parent.firstElementChild); + document.querySelector("#locLevel").innerHTML = `
${val}
`; + } + if (RULE_ID) { + document.querySelector("#ruleInfo").innerHTML = `

Rule ID: ${RULE_ID}${ruleInfo.reasonId ? `
Reason ID: ${ruleInfo.reasonId}

` : ""}`; + } + } +} + +if ("onhashchange" in window) {// does the browser support the hashchange event? + window.onhashchange = function () { + let ruleInfo = JSON.parse(decodeURIComponent(window.location.hash.substring(1))); + updateWithRuleInfo(ruleInfo); + } +} + +window.addEventListener("DOMContentLoaded", (evt) => { + let groupMsg = typeof RULE_MESSAGES !== "undefined" && (RULE_MESSAGES["en-US"].group || RULE_MESSAGES["en-US"][0]) || ""; + groupMsg = groupMsg.replace(/&/g, "&").replace(//g, ">"); + document.querySelector("#groupLabel").innerHTML = groupMsg; + let ruleInfo; + if (window.location.search && window.location.search.length > 0) { + const searchParams = new URLSearchParams(window.location.search); + ruleInfo = JSON.parse(decodeURIComponent(searchParams.get("issue"))); + } else if (window.location.hash && window.location.hash.length > 0) { + ruleInfo = JSON.parse(decodeURIComponent(window.location.hash.substring(1))); + } + updateWithRuleInfo(ruleInfo); + + if (isDarkMode()) { + document.body.setAttribute("class", "dds-theme-zone-g90"); + } else { + document.body.setAttribute("class", "dds-theme-zone-g10"); + } + +}) + diff --git a/rule-server/src/static/archives/2024.08.29/doc/common/rules.css b/rule-server/src/static/archives/2024.08.29/doc/common/rules.css new file mode 100644 index 000000000..515c8a230 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/common/rules.css @@ -0,0 +1,29 @@ +/****************************************************************************** + Copyright:: 2022- IBM, Inc + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +@import url('https://unpkg.com/carbon-components/css/carbon-components.min.css'); + +html, body, .toolHelp .bx--row:nth-child(2) { + height: 100%; +} + +body { + font-family: 'IBM Plex Sans', sans-serif; + padding: 1rem; +} + +h2 { + margin-top: 1rem; + font-size: 16px; + line-height: 24px; + font-weight: 600; +} diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/IBMA_Color_Contrast_WCAG2AA_PV.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/IBMA_Color_Contrast_WCAG2AA_PV.html new file mode 100644 index 000000000..70d9b1d64 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/IBMA_Color_Contrast_WCAG2AA_PV.html @@ -0,0 +1,90 @@ + + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/Rpt_Aria_ArticleRoleLabel_Implicit.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/Rpt_Aria_ArticleRoleLabel_Implicit.html new file mode 100644 index 000000000..283bed41c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/Rpt_Aria_ArticleRoleLabel_Implicit.html @@ -0,0 +1,95 @@ + + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/Rpt_Aria_GroupRoleLabel_Implicit.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/Rpt_Aria_GroupRoleLabel_Implicit.html new file mode 100644 index 000000000..d5cdca57e --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/Rpt_Aria_GroupRoleLabel_Implicit.html @@ -0,0 +1,107 @@ + + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/a_target_warning.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/a_target_warning.html new file mode 100644 index 000000000..667ca418e --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/a_target_warning.html @@ -0,0 +1,91 @@ + + + + a_target_warning - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/a_text_purpose.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/a_text_purpose.html new file mode 100644 index 000000000..2c7138526 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/a_text_purpose.html @@ -0,0 +1,108 @@ + + + + a_text_purpose - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/applet_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/applet_alt_exists.html new file mode 100644 index 000000000..c8b9a1a00 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/applet_alt_exists.html @@ -0,0 +1,103 @@ + + + + applet_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/application_content_accessible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/application_content_accessible.html new file mode 100644 index 000000000..3eb9eeb14 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/application_content_accessible.html @@ -0,0 +1,97 @@ + + + + application_content_accessible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/area_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/area_alt_exists.html new file mode 100644 index 000000000..fad66e3df --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/area_alt_exists.html @@ -0,0 +1,101 @@ + + + + area_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_accessiblename_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_accessiblename_exists.html new file mode 100644 index 000000000..7b6975aeb --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_accessiblename_exists.html @@ -0,0 +1,112 @@ + + + + aria_accessiblename_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_activedescendant_tabindex_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_activedescendant_tabindex_valid.html new file mode 100644 index 000000000..b73e726db --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_activedescendant_tabindex_valid.html @@ -0,0 +1,107 @@ + + + + aria_activedescendant_tabindex_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_activedescendant_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_activedescendant_valid.html new file mode 100644 index 000000000..0f3ad21b7 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_activedescendant_valid.html @@ -0,0 +1,103 @@ + + + + aria_activedescendant_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_application_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_application_label_unique.html new file mode 100644 index 000000000..74ce77ae0 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_application_label_unique.html @@ -0,0 +1,103 @@ + + + + aria_application_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_application_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_application_labelled.html new file mode 100644 index 000000000..b45966878 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_application_labelled.html @@ -0,0 +1,100 @@ + + + + aria_application_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_article_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_article_label_unique.html new file mode 100644 index 000000000..9a404e925 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_article_label_unique.html @@ -0,0 +1,104 @@ + + + + aria_article_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_allowed.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_allowed.html new file mode 100644 index 000000000..c144962bc --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_allowed.html @@ -0,0 +1,97 @@ + + + + aria_attribute_allowed - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_conflict.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_conflict.html new file mode 100644 index 000000000..de93cc132 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_conflict.html @@ -0,0 +1,109 @@ + + + + aria_attribute_conflict - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_deprecated.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_deprecated.html new file mode 100644 index 000000000..e0d6a25dd --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_deprecated.html @@ -0,0 +1,103 @@ + + + + aria_attribute_deprecated - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_exists.html new file mode 100644 index 000000000..6e3d8066d --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_exists.html @@ -0,0 +1,93 @@ + + + + aria_attribute_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_redundant.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_redundant.html new file mode 100644 index 000000000..04b98c64f --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_redundant.html @@ -0,0 +1,98 @@ + + + + aria_attribute_redundant - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_required.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_required.html new file mode 100644 index 000000000..a6368c79f --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_required.html @@ -0,0 +1,106 @@ + + + + aria_attribute_required - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_valid.html new file mode 100644 index 000000000..f3aeae30c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_valid.html @@ -0,0 +1,102 @@ + + + + aria_attribute_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + + + +
+
+
+ + \ No newline at end of file diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_value_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_value_valid.html new file mode 100644 index 000000000..15b357434 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_attribute_value_valid.html @@ -0,0 +1,94 @@ + + + + aria_attribute_value_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + \ No newline at end of file diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_banner_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_banner_label_unique.html new file mode 100644 index 000000000..ca98ec2f1 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_banner_label_unique.html @@ -0,0 +1,104 @@ + + + + aria_banner_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_banner_single.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_banner_single.html new file mode 100644 index 000000000..845247fa0 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_banner_single.html @@ -0,0 +1,98 @@ + + + + aria_banner_single - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_child_tabbable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_child_tabbable.html new file mode 100644 index 000000000..4a030b145 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_child_tabbable.html @@ -0,0 +1,98 @@ + + + + aria_child_tabbable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_child_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_child_valid.html new file mode 100644 index 000000000..8114ac69d --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_child_valid.html @@ -0,0 +1,121 @@ + + + + aria_child_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_label_unique.html new file mode 100644 index 000000000..ca8800820 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_label_unique.html @@ -0,0 +1,103 @@ + + + + aria_complementary_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_label_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_label_visible.html new file mode 100644 index 000000000..34b03c6b5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_label_visible.html @@ -0,0 +1,100 @@ + + + + aria_complementary_label_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_labelled.html new file mode 100644 index 000000000..2dd634c90 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_complementary_labelled.html @@ -0,0 +1,100 @@ + + + + aria_complementary_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_content_in_landmark.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_content_in_landmark.html new file mode 100644 index 000000000..35c206de4 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_content_in_landmark.html @@ -0,0 +1,92 @@ + + + + aria_content_in_landmark - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_label_unique.html new file mode 100644 index 000000000..2b5641797 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_label_unique.html @@ -0,0 +1,104 @@ + + + + aria_contentinfo_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_misuse.html new file mode 100644 index 000000000..740efe106 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_misuse.html @@ -0,0 +1,105 @@ + + + + aria_contentinfo_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_single.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_single.html new file mode 100644 index 000000000..861de7861 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_contentinfo_single.html @@ -0,0 +1,100 @@ + + + + aria_contentinfo_single - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_descendant_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_descendant_valid.html new file mode 100644 index 000000000..e2154211c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_descendant_valid.html @@ -0,0 +1,101 @@ + + + + aria_descendant_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_document_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_document_label_unique.html new file mode 100644 index 000000000..9224ea9fc --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_document_label_unique.html @@ -0,0 +1,91 @@ + + + + aria_document_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_eventhandler_role_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_eventhandler_role_valid.html new file mode 100644 index 000000000..acdfcea1a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_eventhandler_role_valid.html @@ -0,0 +1,92 @@ + + + + aria_eventhandler_role_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_form_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_form_label_unique.html new file mode 100644 index 000000000..ec58b65a1 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_form_label_unique.html @@ -0,0 +1,112 @@ + + + + aria_form_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_graphic_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_graphic_labelled.html new file mode 100644 index 000000000..d3d9b2125 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_graphic_labelled.html @@ -0,0 +1,99 @@ + + + + aria_graphic_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_hidden_nontabbable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_hidden_nontabbable.html new file mode 100644 index 000000000..d7c54e671 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_hidden_nontabbable.html @@ -0,0 +1,113 @@ + + + + aria_hidden_nontabbable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_id_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_id_unique.html new file mode 100644 index 000000000..b0bc3040c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_id_unique.html @@ -0,0 +1,98 @@ + + + + aria_id_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_img_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_img_labelled.html new file mode 100644 index 000000000..7dff4a079 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_img_labelled.html @@ -0,0 +1,100 @@ + + + + aria_img_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_keyboard_handler_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_keyboard_handler_exists.html new file mode 100644 index 000000000..6c840d10e --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_keyboard_handler_exists.html @@ -0,0 +1,103 @@ + + + + aria_keyboard_handler_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_landmark_name_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_landmark_name_unique.html new file mode 100644 index 000000000..556c2d184 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_landmark_name_unique.html @@ -0,0 +1,110 @@ + + + + aria_landmark_name_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_main_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_main_label_unique.html new file mode 100644 index 000000000..f063a76c8 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_main_label_unique.html @@ -0,0 +1,111 @@ + + + + aria_main_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_main_label_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_main_label_visible.html new file mode 100644 index 000000000..bcdaf8ae9 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_main_label_visible.html @@ -0,0 +1,102 @@ + + + + aria_main_label_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_navigation_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_navigation_label_unique.html new file mode 100644 index 000000000..ff7c4baa9 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_navigation_label_unique.html @@ -0,0 +1,106 @@ + + + + aria_navigation_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_parent_required.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_parent_required.html new file mode 100644 index 000000000..155570233 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_parent_required.html @@ -0,0 +1,98 @@ + + + + aria_parent_required - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_region_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_region_label_unique.html new file mode 100644 index 000000000..55466d5ef --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_region_label_unique.html @@ -0,0 +1,102 @@ + + + + aria_region_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_region_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_region_labelled.html new file mode 100644 index 000000000..082df90d9 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_region_labelled.html @@ -0,0 +1,102 @@ + + + + aria_region_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_allowed.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_allowed.html new file mode 100644 index 000000000..439e94700 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_allowed.html @@ -0,0 +1,105 @@ + + + + aria_role_allowed - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_redundant.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_redundant.html new file mode 100644 index 000000000..ab0dc4c50 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_redundant.html @@ -0,0 +1,107 @@ + + + + aria_role_redundant - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_valid.html new file mode 100644 index 000000000..896311194 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_role_valid.html @@ -0,0 +1,90 @@ + + + + aria_role_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_search_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_search_label_unique.html new file mode 100644 index 000000000..cea329abb --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_search_label_unique.html @@ -0,0 +1,100 @@ + + + + aria_search_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_toolbar_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_toolbar_label_unique.html new file mode 100644 index 000000000..4b1b4db28 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_toolbar_label_unique.html @@ -0,0 +1,102 @@ + + + + aria_toolbar_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_widget_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_widget_labelled.html new file mode 100644 index 000000000..52460feb5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/aria_widget_labelled.html @@ -0,0 +1,102 @@ + + + + aria_widget_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/asciiart_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/asciiart_alt_exists.html new file mode 100644 index 000000000..06a60bfa8 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/asciiart_alt_exists.html @@ -0,0 +1,91 @@ + + + + asciiart_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/blink_css_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/blink_css_review.html new file mode 100644 index 000000000..801a20fca --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/blink_css_review.html @@ -0,0 +1,94 @@ + + + + blink_css_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/blink_elem_deprecated.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/blink_elem_deprecated.html new file mode 100644 index 000000000..e5ba6de0a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/blink_elem_deprecated.html @@ -0,0 +1,94 @@ + + + + blink_elem_deprecated - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/blockquote_cite_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/blockquote_cite_exists.html new file mode 100644 index 000000000..0899d3948 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/blockquote_cite_exists.html @@ -0,0 +1,91 @@ + + + + blockquote_cite_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/canvas_content_described.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/canvas_content_described.html new file mode 100644 index 000000000..1f305d6e2 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/canvas_content_described.html @@ -0,0 +1,115 @@ + + + + canvas_content_described - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/caption_track_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/caption_track_exists.html new file mode 100644 index 000000000..45bdbbe4d --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/caption_track_exists.html @@ -0,0 +1,100 @@ + + + + caption_track_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_active_descendant.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_active_descendant.html new file mode 100644 index 000000000..d4d30b1bd --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_active_descendant.html @@ -0,0 +1,109 @@ + + + + combobox_active_descendant - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_autocomplete_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_autocomplete_valid.html new file mode 100644 index 000000000..0eeed4998 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_autocomplete_valid.html @@ -0,0 +1,136 @@ + + + + combobox_autocomplete_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_design_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_design_valid.html new file mode 100644 index 000000000..b9d827b06 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_design_valid.html @@ -0,0 +1,93 @@ + + + + combobox_design_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_focusable_elements.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_focusable_elements.html new file mode 100644 index 000000000..553320b99 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_focusable_elements.html @@ -0,0 +1,92 @@ + + + + combobox_focusable_elements - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_haspopup_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_haspopup_valid.html new file mode 100644 index 000000000..5069d1662 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_haspopup_valid.html @@ -0,0 +1,107 @@ + + + + combobox_haspopup_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_popup_reference.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_popup_reference.html new file mode 100644 index 000000000..d166b30a5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/combobox_popup_reference.html @@ -0,0 +1,109 @@ + + + + combobox_popup_reference - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/dir_attribute_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/dir_attribute_valid.html new file mode 100644 index 000000000..443618ffc --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/dir_attribute_valid.html @@ -0,0 +1,89 @@ + + + + dir_attribute_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/download_keyboard_controllable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/download_keyboard_controllable.html new file mode 100644 index 000000000..4bae1a219 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/download_keyboard_controllable.html @@ -0,0 +1,92 @@ + + + + download_keyboard_controllable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/draggable_alternative_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/draggable_alternative_exists.html new file mode 100644 index 000000000..621e69815 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/draggable_alternative_exists.html @@ -0,0 +1,105 @@ + + + + draggable_alternative_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_accesskey_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_accesskey_labelled.html new file mode 100644 index 000000000..7cbc57d89 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_accesskey_labelled.html @@ -0,0 +1,97 @@ + + + + element_accesskey_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_accesskey_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_accesskey_unique.html new file mode 100644 index 000000000..2818e7745 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_accesskey_unique.html @@ -0,0 +1,100 @@ + + + + element_accesskey_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_attribute_deprecated.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_attribute_deprecated.html new file mode 100644 index 000000000..0136c1d56 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_attribute_deprecated.html @@ -0,0 +1,103 @@ + + + + element_attribute_deprecated - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_id_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_id_unique.html new file mode 100644 index 000000000..17580119f --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_id_unique.html @@ -0,0 +1,102 @@ + + + + element_id_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_lang_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_lang_valid.html new file mode 100644 index 000000000..bca07c8d9 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_lang_valid.html @@ -0,0 +1,108 @@ + + + + element_lang_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_mouseevent_keyboard.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_mouseevent_keyboard.html new file mode 100644 index 000000000..4b0fda7a8 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_mouseevent_keyboard.html @@ -0,0 +1,102 @@ + + + + element_mouseevent_keyboard - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_orientation_unlocked.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_orientation_unlocked.html new file mode 100644 index 000000000..d637b6c4c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_orientation_unlocked.html @@ -0,0 +1,112 @@ + + + + element_orientation_unlocked - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_scrollable_tabbable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_scrollable_tabbable.html new file mode 100644 index 000000000..cf1c4069c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_scrollable_tabbable.html @@ -0,0 +1,115 @@ + + + + element_scrollable_tabbable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_role_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_role_valid.html new file mode 100644 index 000000000..441bd42e4 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_role_valid.html @@ -0,0 +1,136 @@ + + + + element_tabbable_role_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_unobscured.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_unobscured.html new file mode 100644 index 000000000..1980fcbef --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_unobscured.html @@ -0,0 +1,103 @@ + + + + element_tabbable_unobscured - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_visible.html new file mode 100644 index 000000000..e7a684f2f --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/element_tabbable_visible.html @@ -0,0 +1,124 @@ + + + + element_tabbable_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/embed_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/embed_alt_exists.html new file mode 100644 index 000000000..f6e037df5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/embed_alt_exists.html @@ -0,0 +1,95 @@ + + + + embed_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/embed_noembed_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/embed_noembed_exists.html new file mode 100644 index 000000000..a0aca36d8 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/embed_noembed_exists.html @@ -0,0 +1,102 @@ + + + + embed_noembed_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/emoticons_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/emoticons_alt_exists.html new file mode 100644 index 000000000..2d06c83b0 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/emoticons_alt_exists.html @@ -0,0 +1,91 @@ + + + + emoticons_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/error_message_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/error_message_exists.html new file mode 100644 index 000000000..1e1f3d5a2 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/error_message_exists.html @@ -0,0 +1,105 @@ + + + + error_message_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/fieldset_label_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/fieldset_label_valid.html new file mode 100644 index 000000000..50b49155c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/fieldset_label_valid.html @@ -0,0 +1,106 @@ + + + + fieldset_label_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/fieldset_legend_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/fieldset_legend_valid.html new file mode 100644 index 000000000..c68280bbb --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/fieldset_legend_valid.html @@ -0,0 +1,101 @@ + + + + fieldset_legend_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/figure_label_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/figure_label_exists.html new file mode 100644 index 000000000..35aceb565 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/figure_label_exists.html @@ -0,0 +1,104 @@ + + + + figure_label_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/form_font_color.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_font_color.html new file mode 100644 index 000000000..2818da309 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_font_color.html @@ -0,0 +1,90 @@ + + + + form_font_color - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/form_interaction_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_interaction_review.html new file mode 100644 index 000000000..30abfe2d6 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_interaction_review.html @@ -0,0 +1,92 @@ + + + + form_interaction_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/form_label_unique.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_label_unique.html new file mode 100644 index 000000000..d1b74b905 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_label_unique.html @@ -0,0 +1,90 @@ + + + + form_label_unique - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/form_submit_button_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_submit_button_exists.html new file mode 100644 index 000000000..509b44144 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_submit_button_exists.html @@ -0,0 +1,92 @@ + + + + form_submit_button_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/form_submit_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_submit_review.html new file mode 100644 index 000000000..6129ae2af --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/form_submit_review.html @@ -0,0 +1,93 @@ + + + + form_submit_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/frame_src_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/frame_src_valid.html new file mode 100644 index 000000000..bea8d0a99 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/frame_src_valid.html @@ -0,0 +1,95 @@ + + + + frame_src_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/frame_title_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/frame_title_exists.html new file mode 100644 index 000000000..5e0e81cbc --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/frame_title_exists.html @@ -0,0 +1,99 @@ + + + + frame_title_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/heading_content_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/heading_content_exists.html new file mode 100644 index 000000000..953e2d3d5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/heading_content_exists.html @@ -0,0 +1,89 @@ + + + + heading_content_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/heading_markup_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/heading_markup_misuse.html new file mode 100644 index 000000000..1fa519ba4 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/heading_markup_misuse.html @@ -0,0 +1,92 @@ + + + + heading_markup_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/html_lang_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/html_lang_exists.html new file mode 100644 index 000000000..d66c20426 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/html_lang_exists.html @@ -0,0 +1,92 @@ + + + + html_lang_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/html_lang_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/html_lang_valid.html new file mode 100644 index 000000000..1d90f0a2a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/html_lang_valid.html @@ -0,0 +1,111 @@ + + + + html_lang_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/html_skipnav_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/html_skipnav_exists.html new file mode 100644 index 000000000..97c0fbe6c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/html_skipnav_exists.html @@ -0,0 +1,91 @@ + + + + html_skipnav_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/iframe_interactive_tabbable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/iframe_interactive_tabbable.html new file mode 100644 index 000000000..88576fd71 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/iframe_interactive_tabbable.html @@ -0,0 +1,105 @@ + + + + iframe_interactive_tabbable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/imagebutton_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/imagebutton_alt_exists.html new file mode 100644 index 000000000..6f3354129 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/imagebutton_alt_exists.html @@ -0,0 +1,90 @@ + + + + imagebutton_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/imagemap_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/imagemap_alt_exists.html new file mode 100644 index 000000000..2327fe32b --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/imagemap_alt_exists.html @@ -0,0 +1,101 @@ + + + + imagemap_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_background.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_background.html new file mode 100644 index 000000000..501d5a5c6 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_background.html @@ -0,0 +1,90 @@ + + + + img_alt_background - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_decorative.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_decorative.html new file mode 100644 index 000000000..3f47082d2 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_decorative.html @@ -0,0 +1,93 @@ + + + + img_alt_decorative - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_misuse.html new file mode 100644 index 000000000..a15718c7d --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_misuse.html @@ -0,0 +1,91 @@ + + + + img_alt_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_null.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_null.html new file mode 100644 index 000000000..7aaa6538e --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_null.html @@ -0,0 +1,94 @@ + + + + img_alt_null - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_redundant.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_redundant.html new file mode 100644 index 000000000..e4adefc89 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_redundant.html @@ -0,0 +1,94 @@ + + + + img_alt_redundant - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_valid.html new file mode 100644 index 000000000..81d8347a7 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_alt_valid.html @@ -0,0 +1,99 @@ + + + + img_alt_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_ismap_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_ismap_misuse.html new file mode 100644 index 000000000..6ca9f2ca8 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_ismap_misuse.html @@ -0,0 +1,91 @@ + + + + img_ismap_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/img_longdesc_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_longdesc_misuse.html new file mode 100644 index 000000000..62d46371a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/img_longdesc_misuse.html @@ -0,0 +1,98 @@ + + + + img_longdesc_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_autocomplete_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_autocomplete_valid.html new file mode 100644 index 000000000..07419cfb9 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_autocomplete_valid.html @@ -0,0 +1,121 @@ + + + + input_autocomplete_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_checkboxes_grouped.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_checkboxes_grouped.html new file mode 100644 index 000000000..f538de4eb --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_checkboxes_grouped.html @@ -0,0 +1,90 @@ + + + + input_checkboxes_grouped - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_fields_grouped.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_fields_grouped.html new file mode 100644 index 000000000..cdd42e7c8 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_fields_grouped.html @@ -0,0 +1,104 @@ + + + + input_fields_grouped - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_haspopup_conflict.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_haspopup_conflict.html new file mode 100644 index 000000000..3d0bb75f4 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_haspopup_conflict.html @@ -0,0 +1,120 @@ + + + + input_haspopup_conflict - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_after.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_after.html new file mode 100644 index 000000000..7aeaa1caf --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_after.html @@ -0,0 +1,98 @@ + + + + input_label_after - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_before.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_before.html new file mode 100644 index 000000000..f1e8b9ad7 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_before.html @@ -0,0 +1,99 @@ + + + + input_label_before - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_exists.html new file mode 100644 index 000000000..42ee41906 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_exists.html @@ -0,0 +1,94 @@ + + + + input_label_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_visible.html new file mode 100644 index 000000000..db950076a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_label_visible.html @@ -0,0 +1,127 @@ + + + + input_label_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_onchange_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_onchange_review.html new file mode 100644 index 000000000..a9cae294b --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_onchange_review.html @@ -0,0 +1,103 @@ + + + + input_onchange_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/input_placeholder_label_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_placeholder_label_visible.html new file mode 100644 index 000000000..a7d082dfc --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/input_placeholder_label_visible.html @@ -0,0 +1,107 @@ + + + + input_placeholder_label_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/label_content_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/label_content_exists.html new file mode 100644 index 000000000..83638a423 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/label_content_exists.html @@ -0,0 +1,90 @@ + + + + label_content_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/label_name_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/label_name_visible.html new file mode 100644 index 000000000..687551cb0 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/label_name_visible.html @@ -0,0 +1,97 @@ + + + + label_name_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/label_ref_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/label_ref_valid.html new file mode 100644 index 000000000..7f240e323 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/label_ref_valid.html @@ -0,0 +1,97 @@ + + + + label_ref_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/list_children_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/list_children_valid.html new file mode 100644 index 000000000..2b7416267 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/list_children_valid.html @@ -0,0 +1,111 @@ + + + + list_children_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/list_markup_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/list_markup_review.html new file mode 100644 index 000000000..aef0e47c1 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/list_markup_review.html @@ -0,0 +1,91 @@ + + + + list_markup_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/list_structure_proper.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/list_structure_proper.html new file mode 100644 index 000000000..51825a449 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/list_structure_proper.html @@ -0,0 +1,89 @@ + + + + list_structure_proper - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/marquee_elem_avoid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/marquee_elem_avoid.html new file mode 100644 index 000000000..8ccae10d0 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/marquee_elem_avoid.html @@ -0,0 +1,94 @@ + + + + marquee_elem_avoid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/media_alt_brief.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_alt_brief.html new file mode 100644 index 000000000..efd7ae0f5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_alt_brief.html @@ -0,0 +1,111 @@ + + + + media_alt_brief - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/media_alt_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_alt_exists.html new file mode 100644 index 000000000..71396386d --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_alt_exists.html @@ -0,0 +1,95 @@ + + + + media_alt_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/media_audio_transcribed.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_audio_transcribed.html new file mode 100644 index 000000000..d02377888 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_audio_transcribed.html @@ -0,0 +1,97 @@ + + + + media_audio_transcribed - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/media_autostart_controllable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_autostart_controllable.html new file mode 100644 index 000000000..43c34071a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_autostart_controllable.html @@ -0,0 +1,93 @@ + + + + media_autostart_controllable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/media_keyboard_controllable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_keyboard_controllable.html new file mode 100644 index 000000000..d5ec73e48 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_keyboard_controllable.html @@ -0,0 +1,111 @@ + + + + media_keyboard_controllable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/media_live_captioned.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_live_captioned.html new file mode 100644 index 000000000..8f90d42c4 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_live_captioned.html @@ -0,0 +1,91 @@ + + + + media_live_captioned - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/media_track_available.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_track_available.html new file mode 100644 index 000000000..e89356c17 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/media_track_available.html @@ -0,0 +1,96 @@ + + + + media_track_available - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_redirect_optional.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_redirect_optional.html new file mode 100644 index 000000000..1aae651c5 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_redirect_optional.html @@ -0,0 +1,94 @@ + + + + meta_redirect_optional - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_refresh_delay.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_refresh_delay.html new file mode 100644 index 000000000..14c3db809 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_refresh_delay.html @@ -0,0 +1,95 @@ + + + + meta_refresh_delay - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_viewport_zoomable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_viewport_zoomable.html new file mode 100644 index 000000000..665826d05 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/meta_viewport_zoomable.html @@ -0,0 +1,98 @@ + + + + meta_viewport_zoomable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/noembed_content_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/noembed_content_exists.html new file mode 100644 index 000000000..c732e33d1 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/noembed_content_exists.html @@ -0,0 +1,100 @@ + + + + noembed_content_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/object_text_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/object_text_exists.html new file mode 100644 index 000000000..1e3b2571c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/object_text_exists.html @@ -0,0 +1,101 @@ + + + + object_text_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/page_title_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/page_title_exists.html new file mode 100644 index 000000000..2e97f758f --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/page_title_exists.html @@ -0,0 +1,103 @@ + + + + page_title_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/page_title_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/page_title_valid.html new file mode 100644 index 000000000..1007c9f80 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/page_title_valid.html @@ -0,0 +1,105 @@ + + + + page_title_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/script_focus_blur_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_focus_blur_review.html new file mode 100644 index 000000000..88f135481 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_focus_blur_review.html @@ -0,0 +1,96 @@ + + + + script_focus_blur_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/script_onclick_avoid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_onclick_avoid.html new file mode 100644 index 000000000..07132ad72 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_onclick_avoid.html @@ -0,0 +1,92 @@ + + + + script_onclick_avoid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/script_onclick_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_onclick_misuse.html new file mode 100644 index 000000000..e211e9d26 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_onclick_misuse.html @@ -0,0 +1,92 @@ + + + + script_onclick_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/script_select_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_select_review.html new file mode 100644 index 000000000..f4ce0fdec --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/script_select_review.html @@ -0,0 +1,97 @@ + + + + script_select_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/select_options_grouped.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/select_options_grouped.html new file mode 100644 index 000000000..255896592 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/select_options_grouped.html @@ -0,0 +1,90 @@ + + + + select_options_grouped - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/skip_main_described.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/skip_main_described.html new file mode 100644 index 000000000..a3674a81b --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/skip_main_described.html @@ -0,0 +1,100 @@ + + + + skip_main_described - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/skip_main_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/skip_main_exists.html new file mode 100644 index 000000000..aeff0fcd6 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/skip_main_exists.html @@ -0,0 +1,103 @@ + + + + skip_main_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/style_background_decorative.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_background_decorative.html new file mode 100644 index 000000000..6cf43d2e7 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_background_decorative.html @@ -0,0 +1,93 @@ + + + + style_background_decorative - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/style_before_after_review.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_before_after_review.html new file mode 100644 index 000000000..e83a2b1c0 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_before_after_review.html @@ -0,0 +1,95 @@ + + + + style_before_after_review - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/style_color_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_color_misuse.html new file mode 100644 index 000000000..e7906bfb2 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_color_misuse.html @@ -0,0 +1,89 @@ + + + + style_color_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/style_focus_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_focus_visible.html new file mode 100644 index 000000000..fdc7d90e0 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_focus_visible.html @@ -0,0 +1,97 @@ + + + + style_focus_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/style_highcontrast_visible.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_highcontrast_visible.html new file mode 100644 index 000000000..75e0e8a02 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_highcontrast_visible.html @@ -0,0 +1,100 @@ + + + + style_highcontrast_visible - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/style_hover_persistent.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_hover_persistent.html new file mode 100644 index 000000000..dc72cef43 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_hover_persistent.html @@ -0,0 +1,118 @@ + + + + style_hover_persistent - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/style_viewport_resizable.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_viewport_resizable.html new file mode 100644 index 000000000..b8daa7d29 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/style_viewport_resizable.html @@ -0,0 +1,93 @@ + + + + style_viewport_resizable - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/svg_graphics_labelled.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/svg_graphics_labelled.html new file mode 100644 index 000000000..785efcc07 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/svg_graphics_labelled.html @@ -0,0 +1,127 @@ + + + + svg_graphics_labelled - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_aria_descendants.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_aria_descendants.html new file mode 100644 index 000000000..4ec41910b --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_aria_descendants.html @@ -0,0 +1,110 @@ + + + + table_aria_descendants - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_caption_empty.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_caption_empty.html new file mode 100644 index 000000000..aa31cbc13 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_caption_empty.html @@ -0,0 +1,101 @@ + + + + table_caption_empty - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_caption_nested.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_caption_nested.html new file mode 100644 index 000000000..c52a43310 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_caption_nested.html @@ -0,0 +1,98 @@ + + + + table_caption_nested - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_exists.html new file mode 100644 index 000000000..fe05efe22 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_exists.html @@ -0,0 +1,93 @@ + + + + table_headers_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_ref_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_ref_valid.html new file mode 100644 index 000000000..15d66ea3d --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_ref_valid.html @@ -0,0 +1,91 @@ + + + + table_headers_ref_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_related.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_related.html new file mode 100644 index 000000000..addc41858 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_headers_related.html @@ -0,0 +1,91 @@ + + + + table_headers_related - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_layout_linearized.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_layout_linearized.html new file mode 100644 index 000000000..2e9a26134 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_layout_linearized.html @@ -0,0 +1,92 @@ + + + + table_layout_linearized - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_scope_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_scope_valid.html new file mode 100644 index 000000000..0632f7a4a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_scope_valid.html @@ -0,0 +1,93 @@ + + + + table_scope_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_structure_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_structure_misuse.html new file mode 100644 index 000000000..2fe51c995 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_structure_misuse.html @@ -0,0 +1,91 @@ + + + + table_structure_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/table_summary_redundant.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_summary_redundant.html new file mode 100644 index 000000000..130448ab8 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/table_summary_redundant.html @@ -0,0 +1,101 @@ + + + + table_summary_redundant - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/target_spacing_sufficient.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/target_spacing_sufficient.html new file mode 100644 index 000000000..a18167c6a --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/target_spacing_sufficient.html @@ -0,0 +1,108 @@ + + + + target_spacing_sufficient - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/text_block_heading.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_block_heading.html new file mode 100644 index 000000000..dad93b0a2 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_block_heading.html @@ -0,0 +1,92 @@ + + + + text_block_heading - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/text_contrast_sufficient.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_contrast_sufficient.html new file mode 100644 index 000000000..6a1f68348 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_contrast_sufficient.html @@ -0,0 +1,92 @@ + + + + text_contrast_sufficient - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/text_quoted_correctly.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_quoted_correctly.html new file mode 100644 index 000000000..8daea810e --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_quoted_correctly.html @@ -0,0 +1,106 @@ + + + + text_quoted_correctly - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/text_sensory_misuse.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_sensory_misuse.html new file mode 100644 index 000000000..5886e86ac --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_sensory_misuse.html @@ -0,0 +1,96 @@ + + + + text_sensory_misuse - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/text_spacing_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_spacing_valid.html new file mode 100644 index 000000000..5b7b8fc45 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_spacing_valid.html @@ -0,0 +1,103 @@ + + + + text_spacing_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/text_whitespace_valid.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_whitespace_valid.html new file mode 100644 index 000000000..befb5cc2c --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/text_whitespace_valid.html @@ -0,0 +1,93 @@ + + + + text_whitespace_valid - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/widget_tabbable_exists.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/widget_tabbable_exists.html new file mode 100644 index 000000000..442e7f0ce --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/widget_tabbable_exists.html @@ -0,0 +1,98 @@ + + + + widget_tabbable_exists - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/en-US/widget_tabbable_single.html b/rule-server/src/static/archives/2024.08.29/doc/en-US/widget_tabbable_single.html new file mode 100644 index 000000000..002ba6652 --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/en-US/widget_tabbable_single.html @@ -0,0 +1,96 @@ + + + + widget_tabbable_single - Accessibility Checker Help + + + + + + + + + + + + +
+
+
+ +

+ +
+ +

+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + diff --git a/rule-server/src/static/archives/2024.08.29/doc/rules.html b/rule-server/src/static/archives/2024.08.29/doc/rules.html new file mode 100644 index 000000000..22e11d3ad --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/doc/rules.html @@ -0,0 +1,20112 @@ + + + Accessibility Checker Rules + + + + + + + + +
+ + IBM Accessibility 7.2IBM Accessibility 7.3WCAG 2.2 (A, AA)WCAG 2.1 (A, AA)WCAG 2.0 (A, AA) + +
+
+

1.1.1 Non-text Content [A]

+
All non-text content that is presented to the user has a text alternative that serves the equivalent purpose.
+ applet_alt_exists: <applet> elements must provide an 'alt' attribute and an alternative description + +  Violation — +
An <applet> element does not have an 'alt' attribute that provides a short text alternative Violation — + The 'alt' attribute value for an <applet> element duplicates the 'code' attribute Violation — + An <applet> element provides alternative text, but does not provide inner content + + img_alt_redundant: The text alternative for an image within a link should not repeat the link text or adjacent link text + +  Violation — + Link text is repeated in an image 'alt' value within the same link Violation — + Link text of previous link is repeated in image 'alt' value of a link Violation — + Image 'alt' value within a link is repeated in link text of the link after + + img_alt_valid: Images must have accessible names unless they are decorative or redundant + +  Violation — + Image 'alt' attribute value consists only of blank space(s) Violation — + The image has neither an accessible name nor is marked as decorative or redundant Violation — + The image does not have an 'alt' attribute or ARIA label, and the 'title' attribute value consists only of blank space(s) + + area_alt_exists: <area> elements in an image map must have a text alternative + +  Violation — + <area> element in an image map has no text alternative + + imagebutton_alt_exists: The <input> element of type "image" should have a text alternative + +  Violation — + The <input> element of type "image" has no text alternative + + imagemap_alt_exists: An image map and each <area> element in an image map must have text alternative(s) + +  Violation — + Image map or child <area> has no text alternative + + img_alt_decorative: Image designated as decorative must have 'alt="" + +  Violation — + Image designated as decorative has non-null 'alt' attribute + + img_alt_null: When the image 'alt' attribute is empty, the 'title' attribute must also be empty + +  Violation — + The image 'alt' attribute is empty, but the 'title' attribute is not empty + + object_text_exists: <object> element must have a text alternative for the content rendered by the object + +  Violation — + An <object> element does not have a text alternative + + svg_graphics_labelled: A none decorative SVG element must have an accessible name + +  Violation — + The SVG element has no accessible name + + application_content_accessible: Non-decorative static text and image content within an element with "application" role must be accessible + +  Needs review — + Verify that the non-decorative static text and image content within an element with "application" role are accessible + + img_alt_misuse: 'alt' attribute value must be a good inline replacement for the image + +  Needs review — + Verify that the file name serves as a good inline replacement for the image + + img_ismap_misuse: Server-side image map hot-spots must have duplicate text links + +  Needs review — + Server-side image map hot-spots do not have duplicate text links + + img_longdesc_misuse: The 'longdesc' attribute must reference HTML content + +  Needs review — + Verify that the file designated by the 'longdesc' attribute contains valid HTML content (file extension not recognized) + + media_alt_exists: Audio or video on the page must have a short text alternative that describes the media content + +  Needs review — + Filename used as label for embedded audio or video + + style_background_decorative: Images included by using CSS alone must not convey important information + +  Needs review — + Verify the CSS background image does not convey important information + + style_highcontrast_visible: Windows high contrast mode must be supported when using CSS to include, position or alter non-decorative content + +  Needs review — + Confirm Windows high contrast mode is supported when using CSS to include, position or alter non-decorative content + + figure_label_exists: A <figure> element must have an associated label + +  Recommendation — + The <figure> element does not have an associated label + + embed_alt_exists: Provide alternative content for <embed> elements + +  Recommendation — + Verify that the <embed> element has alternative content + + embed_noembed_exists: <embed> elements should be immediately followed by a non-embedded element + +  Recommendation — + Verify that the <embed> element is immediately followed by a non-embedded element + + media_alt_brief: Alternative text in 'alt' attribute should be brief (<150 characters) + +  Recommendation — + Text alternative is more than 150 characters + + noembed_content_exists: <noembed> elements should contain descriptive text + +  Recommendation — + Add descriptive text to the <noembed> element + + canvas_content_described: The <canvas> element may not be accessible + +  Recommendation — + Verify accessibility of the <canvas> element + + img_alt_background: Background images that convey important information must have a text alternative that describes the image + +  Recommendation — + Verify important background image information has a text alternative in system high contrast mode + + +
+

1.2.1 Audio-only and Video-only (Prerecorded) [A]

+
For prerecorded audio-only or video-only media, an alternative provides equivalent information.
+ media_audio_transcribed: Audio information should also be available in text form + +  Recommendation — + Provide transcripts for audio files + + +
+

1.2.2 Captions (Prerecorded) [A]

+
Captions are provided for all prerecorded audio content in synchronized media.
+ caption_track_exists: A <video> element must have a text alternative for any meaningful audio content + +  Needs review — + Verify that captions are available for any meaningful audio or provide a caption track for the <video> element + + +
+

1.2.3 Audio Description or Media Alternative (Prerecorded) [A]

+
An alternative for time-based media or audio description of the prerecorded video content is provided for synchronized media.
+ media_track_available: Pre-recorded media should have an audio track that describes visual information + +  Recommendation — + Verify availability of a user-selectable audio track with description of visual content + + +
+

1.2.4 Captions (Live) [AA]

+
Captions are provided for all live audio content in synchronized media.
+ media_live_captioned: Live media (streaming video with audio) should have captions for audio content + +  Recommendation — + Verify captions are provided for live media (streaming video with audio) + + +
+

1.2.5 Audio Description (Prerecorded) [AA]

+
Audio description is provided for all prerecorded video content in synchronized media.
+ media_track_available: Pre-recorded media should have an audio track that describes visual information + +  Recommendation — + Verify availability of a user-selectable audio track with description of visual content + + +
+

1.3.1 Info and Relationships [A]

+
Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
+ input_checkboxes_grouped: Related sets of radio buttons or checkboxes should be programmatically grouped + +  Violation — + {0} input found that has the same name, "{2}" as a {1} input Violation — + {0} input is not in the group with another {0} with the name "{1}" Violation — + {0} input and others with the name "{1}" are not grouped together Violation — + {0} input is in a different group than another {0} with the name "{1}" Needs review — + Verify that this ungrouped checkbox input is not related to other checkboxes Needs review — + Verify that this un-named, ungrouped checkbox input is not related to other checkboxes + + table_headers_ref_valid: The 'headers' attribute should refer to a valid cell in the same table + +  Violation — + The 'headers' attribute value "{0}" does not reference a valid 'id' in this document Violation — + The 'headers' attribute value "{0}" refers to itself Violation — + The 'headers' attribute value "{0}" does not refer to a cell in the same table Violation — + The 'headers' attribute value "{0}" does not refer to a cell indicated with <th> or a role of "columnheader" or "rowheader" + + fieldset_label_valid: Groups with nested inputs must have unique accessible name + +  Violation — + Group/Fieldset does not have an accessible name Violation — + Group/Fieldset "{0}" has a duplicate name to another group + + table_scope_valid: Value for 'scope' attribute must be "row", "col", "rowgroup", or "colgroup" + +  Violation — + Value provided is invalid for the 'scope' attribute Violation — + The 'scope' attribute should only be used on a <th> element + + aria_hidden_nontabbable: A hidden element should not contain any tabbable elements + +  Violation — + Element "{0}" should not be focusable within the subtree of an element with an 'aria-hidden' attribute with value 'true' + + aria_parent_required: Each element with an implicit or explicit role must be contained within a valid element + +  Violation — + Element with "{0}" role is not contained in or owned by an element with one of the following roles: "{1}" + + form_label_unique: Form controls should have exactly one label + +  Violation — + Form control has more than one label + + label_ref_valid: The 'for' attribute for a label must reference a non-empty, unique 'id' attribute of an <input> element + +  Violation — + The value "{0}" of the 'for' attribute is not the 'id' of a valid <input> element + + table_caption_empty: A <caption> element for a <table> element must contain descriptive text + +  Violation — + The <table> element has an empty <caption> element + + table_caption_nested: The <caption> element must be nested inside the associated <table> element + +  Violation — + <caption> element is not nested inside a <table> element + + table_headers_exists: Data table must identify headers + +  Violation — + Table has no headers identified + + table_headers_related: For a complex data table, all <th> and <td> elements must be related via 'header' or 'scope' attributes + +  Violation — + Complex table does not have headers for each cell properly defined with 'header' or 'scope' + + table_structure_misuse: Table elements with 'role="presentation" or 'role="none" should not have structural elements or attributes + +  Violation — + The <{0}> element with "presentation" role or "none" role has structural element(s) and/or attribute(s) '{1}' + + table_summary_redundant: The table summary must not duplicate the caption + +  Violation — + The table summary duplicates the caption + + blockquote_cite_exists: Use <blockquote> only for quotations, not indentation + +  Needs review — + Verify that <blockquote> should have a 'cite' attribute and not be used for indentation only + + heading_markup_misuse: Heading elements must not be used for presentation + +  Needs review — + Verify that the heading element is a genuine heading + + list_markup_review: Proper HTML elements should be used to create a list + +  Needs review — + Verify this is a list and if so, modify to use proper HTML elements for the list + + text_block_heading: Heading text should use a heading element or role + +  Needs review — + Confirm this text '{0}' is used as a heading and if so, modify to use a heading element or role + + text_quoted_correctly: Quotations should be marked with <q> or <blockquote> elements + +  Needs review — + If the following text is a quotation, mark it as a <q> or <blockquote> element: {0} + + fieldset_legend_valid: <fieldset> elements should have a single, non-empty <legend> as a label + +  Recommendation — + <fieldset> element does not have a <legend> Recommendation — + <fieldset> element has more than one <legend> Recommendation — + <fieldset> element <legend> is empty + + aria_child_valid: An element with an ARIA role must own a required child + +  Recommendation — + The element with role "{0}" does not own any child element with any of the following role(s): "{1}" Recommendation — + The element with role "{0}" owns the child element with the role "{1}" that is not one of the allowed role(s): "{2}" + + input_fields_grouped: Groups of logically related input elements should be contained within a <fieldset> element + +  Recommendation — + Use the <fieldset> element to group logically related input elements + + list_structure_proper: List elements should only be used for lists of related items + +  Recommendation — + List element is missing or improperly structured + + select_options_grouped: Groups of related options within a selection list should be grouped with <optgroup> + +  Recommendation — + Group of related options may need <optgroup> + + table_layout_linearized: Avoid using tables to format text documents in columns unless the table can be linearized + +  Recommendation — + Verify table is not being used to format text content in columns unless the table can be linearized + + +
+

1.3.2 Meaningful Sequence [A]

+
When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically determined.
+ dir_attribute_valid: 'dir' attribute value must be "ltr", "rtl", or "auto" + +  Violation — + Invalid value used for the 'dir' attribute + + text_whitespace_valid: Space characters should not be used to control spacing within a word + +  Needs review — + Space characters should not be used to create space between the letters of a word + + style_highcontrast_visible: Windows high contrast mode must be supported when using CSS to include, position or alter non-decorative content + +  Needs review — + Confirm Windows high contrast mode is supported when using CSS to include, position or alter non-decorative content + + +
+

1.3.3 Sensory Characteristics [A]

+
Instructions provided for understanding and operating content do not rely solely on sensory characteristics of components such as shape, size, visual location, orientation, or sound.
+ text_sensory_misuse: Instructions should be meaningful without relying solely on shape, size, or location words + +  Needs review — + Confirm the word(s) '{0}' of the user instruction is used to indicate a logical rather than visual position Needs review — + Confirm the user instruction is still understandable without the word(s) '{0}' + + +
+

1.3.4 Orientation [AA]

+
Content does not restrict its view and operation to a single display orientation, such as portrait or landscape.
+ element_orientation_unlocked: Elements should not be restricted to either landscape or portrait orientation using CSS transform property + +  Violation — + The element <{0}> is restricted to either landscape or portrait orientation using CSS transform property + + +
+

1.3.5 Identify Input Purpose [AA]

+
The purpose of each input field that collects information about the user can be programmatically determined when the field serves a common purpose.
+ input_autocomplete_valid: The 'autocomplete' attribute's token(s) must be appropriate for the input form field + +  Violation — + The 'autocomplete' attribute's token(s) are not appropriate for the input form field Violation — + The 'autocomplete' attribute's token(s) are not appropriate for an input form field of any type Violation — + The 'autocomplete' attribute has an incorrect value + + +
+

1.4.1 Use of Color [A]

+
Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.
+ form_font_color: Combine color and descriptive markup to indicate required form fields + +  Needs review — + Check color is not used as the only visual means to convey which fields are required + + style_color_misuse: Combine color and descriptive markup to convey information + +  Needs review — + Verify color is not used as the only visual means of conveying information + + +
+

1.4.2 Audio Control [A]

+
If any audio plays automatically for more than 3 seconds, either a mechanism is available to pause or stop the audio, or a mechanism is available to control audio volume independently from the overall system volume level.
+ media_autostart_controllable: Mechanism must be available to pause or stop and control the volume of the audio that plays automatically + +  Needs review — + Verify there is a mechanism to pause or stop and control the volume for the audio that plays automatically + + +
+

1.4.3 Contrast (Minimum) [AA]

+
The visual presentation of text and images of text has a contrast ratio of at least 4.5:1, with a 3:1 ratio for large-scale text.
+ text_contrast_sufficient: The contrast ratio of text with its background must meet WCAG AA requirements + +  Violation — + Text contrast of {0} with its background is less than the WCAG AA minimum requirements for text of size {1}px and weight of {2} Needs review — + The foreground text and its background color are both detected as {3}. Verify the text meets the WCAG AA requirements for minimum contrast Needs review — + Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG AA minimum requirements for text of size {1}px and weight of {2} Needs review — + Verify the contrast ratio of the text with shadow meets the WCAG AA minimum requirements for text of size {1}px and weight of {2} + + +
+

1.4.4 Resize text [AA]

+
Text can be resized without assistive technology up to 200 percent without loss of content or functionality.
+ style_viewport_resizable: Text must scale up to 200% without loss of content or functionality + +  Needs review — + Verify that text sized using viewport units can be resized up to 200% + + meta_viewport_zoomable: The 'meta[name=viewport]' should not prevent the browser zooming the content + +  Recommendation — + Confirm the 'meta[name=viewport]' with "{0}" can be zoomed by user + + +
+

1.4.5 Images of Text [AA]

+
If the technologies being used can achieve the visual presentation, text should not be used to convey information rather than images of text.
+ +
+

1.4.10 Reflow [AA]

+
Content can reflow without loss of information or functionality, and without requiring scrolling in two dimensions.
+ style_viewport_resizable: Text must scale up to 200% without loss of content or functionality + +  Needs review — + Verify that text sized using viewport units can be resized up to 200% + + +
+

1.4.11 Non-text Contrast [AA]

+
The parts of graphical objects required to understand the content, and the visual information required to identify UI components and states, have a contrast ratio of at least 3:1 against adjacent colors.
+ style_highcontrast_visible: Windows high contrast mode must be supported when using CSS to include, position or alter non-decorative content + +  Needs review — + Confirm Windows high contrast mode is supported when using CSS to include, position or alter non-decorative content + + +
+

1.4.12 Text Spacing [AA]

+
No loss of content or functionality occurs when users change letter, word and paragraph spacing, as well as line height.
+ text_spacing_valid: CSS !important should not be used in inline style to control letter or word spacing or line height + +  Violation — + CSS !important should not be used in inline ‘letter-spacing’ style Violation — + CSS !important should not be used in inline ‘word-spacing’ style Violation — + CSS !important should not be used in inline ‘line-height’ style + + +
+

1.4.13 Content on Hover or Focus [AA]

+
Where hover or focus actions cause additional content to become visible and hidden, the additional content is dismissable, hoverable and persistent.
+ style_hover_persistent: The pointer should be able to move over content displayed on hover + +  Needs review — + Confirm the pointer can be positioned over the displayed element, not just the trigger Needs review — + Confirm the pointer can be positioned over all the information displayed on hover Needs review — + Confirm the margin style attribute has not prevented the pointer from hovering over the displayed element, not just the trigger + + +
+

2.1.1 Keyboard [A]

+
All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes.
+ aria_activedescendant_tabindex_valid: Element using 'aria-activedescendant' property should be tabbable + +  Violation — + The <{0}> element using 'aria-activedescendant' set to "{1}" is not tabbable + + aria_child_tabbable: UI component must have at least one tabbable descendant for keyboard access + +  Violation — + None of the descendent elements with "{1}" role is tabbable + + element_scrollable_tabbable: Scrollable elements should be tabbable or contain tabbable content + +  Violation — + The scrollable element <{0}> with non-interactive content is not tabbable + + iframe_interactive_tabbable: Iframe with interactive content should not be excluded from tab order using tabindex + +  Violation — + The <iframe> with interactive content is excluded from tab order using tabindex + + application_content_accessible: Non-decorative static text and image content within an element with "application" role must be accessible + +  Needs review — + Verify that the non-decorative static text and image content within an element with "application" role are accessible + + aria_keyboard_handler_exists: Interactive WAI_ARIA UI components must provide keyboard access + +  Needs review — + Verify the <{0}> element with "{1}" role has keyboard access + + script_focus_blur_review: Scripting must not remove focus from content that normally receives focus + +  Needs review — + Verify script does not remove focus from content that normally receives focus + + script_onclick_misuse: Scripts should not be used to emulate links + +  Needs review — + Possible use of a script to emulate a link + + widget_tabbable_exists: Component must have at least one tabbable element + +  Needs review — + Component with "{0}" role does not have a tabbable element + + widget_tabbable_single: Components with a widget role must have no more than one tabbable element + +  Needs review — + Component with "{0}" role has more than one tabbable element + + media_keyboard_controllable: Media using <audio> and/or <video> elements must have keyboard accessible controls + +  Needs review — + Verify media using <audio> and/or <video> elements have keyboard accessible controls + + script_onclick_avoid: Scripts should not be used to emulate links + +  Recommendation — + Verify that 'onclick' events are not used in script to emulate a link + + canvas_content_described: The <canvas> element may not be accessible + +  Recommendation — + Verify accessibility of the <canvas> element + + element_mouseevent_keyboard: All interactive content with mouse event handlers must have equivalent keyboard access + +  Recommendation — + Confirm the <{0}> element with mouse event handler(s) '{1}' has a corresponding keyboard handler(s) + + +
+

2.1.2 No Keyboard Trap [A]

+
If keyboard focus can be moved to a component using a keyboard interface, then focus can be moved away from that component using only a keyboard interface, and, if it requires more than unmodified arrow or tab keys or other standard exit methods, the user is advised of the method for moving focus away.
+ download_keyboard_controllable: File download mechanisms should be keyboard-operable and preserve page focus location + +  Recommendation — + Verify that the file download mechanism does not cause a keyboard trap + + +
+

2.1.4 Character Key Shortcuts [A]

+
If a keyboard shortcut is implemented using only letter, punctuation, number or symbol characters, then the shortcut can be turned off, remapped or activated only on focus.
+ +
+

2.2.1 Timing Adjustable [A]

+
For each time limit that is set by the content, the user can turn off, adjust, or extend the limit.
+ meta_redirect_optional: Page should not automatically refresh without warning or option to turn it off or adjust the time limit + +  Violation — + Check page does not automatically refresh without warning or options Violation — + Check page does not automatically refresh without warning or options + + meta_refresh_delay: Pages should not refresh automatically + +  Needs review — + Verify page is not being caused to refresh automatically + + +
+

2.2.2 Pause, Stop, Hide [A]

+
For moving, blinking, scrolling, or auto-updating information, the user can pause, stop, hide or adjust the information.
+ blink_elem_deprecated: Content that blinks persistently must not be used + +  Violation — + Content found that blinks persistently + + marquee_elem_avoid: The <marquee> element is obsolete and should not be used + +  Violation — + Scrolling content found that uses the obsolete <marquee> element + + blink_css_review: Do not use the "blink" value of the 'text-decoration' property for longer than five seconds + +  Needs review — + Check the "blink" value of the CSS 'text-decoration' property is not used for more than than five seconds + + +
+

2.3.1 Three Flashes or Below Threshold [A]

+
Content does not contain anything that flashes more than three times in any one second period, or the flash is below the general flash and red flash thresholds.
+ +
+

2.4.1 Bypass Blocks [A]

+
A mechanism is available to bypass blocks of content that are repeated on multiple Web pages.
+ aria_application_label_unique: Each element with "application" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "application" role do not have unique labels + + aria_application_labelled: Each element with "application" role must have a label that describes its purpose + +  Violation — + Element with "application" role does not have a label + + aria_article_label_unique: Each element with "article" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "article" role do not have unique labels + + aria_banner_label_unique: Each element with "banner" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "banner" role do not have unique labels + + aria_banner_single: A page, document, or application should only have one element with "banner" role + +  Violation — + Multiple elements with "banner" role found on the page + + aria_complementary_label_unique: Each element with "complementary" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "complementary" role do not have unique labels + + aria_complementary_labelled: Each element with "complementary" role must have a label that describes its purpose + +  Violation — + Element with "complementary" role does not have a label + + aria_content_in_landmark: All content must reside within an element with a landmark role + +  Violation — + Content is not within a landmark element + + aria_contentinfo_label_unique: Each element with "contentinfo" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "contentinfo" role do not have unique labels + + aria_contentinfo_single: A page, document, or application should only have one element with "contentinfo" role + +  Violation — + Multiple elements with "contentinfo" role found on the page + + aria_document_label_unique: Each element with "document" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "document" roles do not have unique labels + + aria_form_label_unique: Each element with "form" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "form" role do not have unique labels + + aria_landmark_name_unique: Each landmark should have a unique 'aria-labelledby' or 'aria-label' or be nested in a different parent region + +  Violation — + Multiple elements with "{0}" landmarks within the same parent region are not distinguished from one another because they have the same "{1}" label + + aria_main_label_unique: Each element with "main" role must have unique label that describes its purposes + +  Violation — + Multiple elements with "main" role do not have unique labels + + aria_navigation_label_unique: Each element with "navigation" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "navigation" role do not have unique labels + + aria_region_label_unique: Each element with "region" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "region" role do not have unique labels + + aria_region_labelled: Each element with "region" role must have a label that describes its purpose + +  Violation — + Element with "region" role does not have a label + + aria_search_label_unique: Each element with "search" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "search" role do not have unique labels + + aria_toolbar_label_unique: Each element with "toolbar" role must have a unique label that describes its purpose + +  Violation — + Multiple elements with "toolbar" roles do not have unique labels + + skip_main_exists: Pages must provide a way to skip directly to the main content + +  Violation — + The page does not provide a way to quickly navigate to the main content (ARIA "main" landmark or a skip link) + + frame_src_valid: A <frame> containing non-HTML content must be made accessible + +  Needs review — + Verify <frame> content is accessible + + html_skipnav_exists: Provide a way to bypass blocks of content that are repeated on multiple Web pages + +  Needs review — + Verify there is a way to bypass blocks of content that are repeated on multiple Web pages + + skip_main_described: The description of a hyperlink used to skip content must communicate where it links to + +  Needs review — + Verify that if this hyperlink skips content, the description communicates where it links to + + aria_complementary_label_visible: Each element with "complementary" role should have a visible label that describes its purpose + +  Recommendation — + Element with "complementary" role does not have a visible label + + aria_contentinfo_misuse: Each element with "contentinfo" role is only permitted with an element with "main" role + +  Recommendation — + Element with "contentinfo" role is present without an element with "main" role + + aria_main_label_visible: Each element with "main" role should have a unique visible label that describes its purpose + +  Recommendation — + Multiple elements with "main" role do not have unique visible labels + + +
+

2.4.2 Page Titled [A]

+
Web pages, non-web documents, and software have titles that describe topic or purpose.
+ page_title_exists: The page should have a title that correctly identifies the subject of the page + +  Violation — + Missing <head> element so there can be no <title> element present Violation — + Missing <title> element in <head> element Violation — + The <title> element is empty (no innerHTML) + + page_title_valid: Page <title> should be a descriptive title, rather than a filename + +  Needs review — + Verify that using the filename as the page <title> value is descriptive + + +
+

2.4.3 Focus Order [A]

+
If content can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability.
+ widget_tabbable_single: Components with a widget role must have no more than one tabbable element + +  Needs review — + Component with "{0}" role has more than one tabbable element + + +
+

2.4.4 Link Purpose (In Context) [A]

+
The purpose of each link can be determined from the link text alone or from the link text together with its programmatically determined link content.
+ img_alt_redundant: The text alternative for an image within a link should not repeat the link text or adjacent link text + +  Violation — + Link text is repeated in an image 'alt' value within the same link Violation — + Link text of previous link is repeated in image 'alt' value of a link Violation — + Image 'alt' value within a link is repeated in link text of the link after + + a_text_purpose: Hyperlinks must have an accessible name for their purpose + +  Violation — + Hyperlink has no link text, label or image with a text alternative + + +
+

2.4.5 Multiple Ways [AA]

+
More than one way is available to locate a Web page within a set of Web pages, except where the Web Page is the result of, or a step in, a process.
+ +
+

2.4.6 Headings and Labels [AA]

+
Headings and labels describe topic or purpose.
+ heading_content_exists: Heading elements must provide descriptive text + +  Recommendation — + Heading element has no descriptive content + + +
+

2.4.7 Focus Visible [AA]

+
Any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible.
+ element_tabbable_visible: A tabbable element should be visible on the screen when it has keyboard focus + +  Needs review — + Confirm the element should be tabbable and if so, it becomes visible when it has keyboard focus + + script_focus_blur_review: Scripting must not remove focus from content that normally receives focus + +  Needs review — + Verify script does not remove focus from content that normally receives focus + + style_focus_visible: The keyboard focus indicator should be visible when default border or outline is modified by CSS + +  Needs review — + Check the keyboard focus indicator is visible when using CSS declaration for 'border' or 'outline' + + +
+

2.4.11 Focus Not Obscured (Minimum) [AA]

+
When an element receives focus, it is not entirely covered by other content.
+ +
+

2.5.1 Pointer Gestures [A]

+
All functionality that uses multipoint or path-based gestures for operation can be operated with a single pointer without a path-based gesture.
+ +
+

2.5.2 Pointer Cancellation [A]

+
For functionality that can be operated using a single pointer, completion of the function is on the up-event with an ability to abort, undo or reverse the outcome.
+ +
+

2.5.3 Label in Name [A]

+
For user interface components with labels that include text or images of text, the accessible name contains the text that is presented visually.
+ label_name_visible: Accessible name must match or contain the visible label text + +  Violation — + Accessible name does not match or contain the visible label text + + input_label_visible: An input element must have an associated visible label + +  Needs review — + The ‘placeholder’ is the only visible label Needs review — + The input element does not have an associated visible label + + +
+

2.5.4 Motion Actuation [A]

+
Functionality that can be operated by motion can also be operated by user interface components, and the motion trigger can be disabled.
+ +
+

2.5.7 Dragging Movement [AA]

+
All functionality that uses a dragging movement for operation can be achieved by a single pointer without dragging.
+ +
+

2.5.8 Minimum Target Size [AA]

+
The size of the target for pointer inputs is at least 24 by 24 CSS pixels.
+ +
+

3.1.1 Language of Page [A]

+
The default human language of Web pages, non-Web documents, or software can be programmatically determined.
+ html_lang_exists: Page must identify the default language of the document with a 'lang' attribute + +  Violation — + Page detected as XHTML 1.0, but has neither 'lang' nor 'xml:lang' attributes Violation — + Page detected as XHTML, but does not have an 'xml:lang' attribute Violation — + Page detected as HTML, but does not have a 'lang' attribute Violation — + Page detected with 'lang' and 'xml:lang' attributes and primary languages do not match: "{0}", "{1}" Violation — + Page detected with 'lang' and 'xml:lang' attributes that do not match: "{0}", "{1}" Needs review — + Page detected as XHTML 1.0 with only a 'lang' attribute. Confirm that page is only delivered via text/html mime type Needs review — + Page detected as XHTML 1.0 with only an 'xml:lang' attribute. Confirm that page is only delivered via xml mime type + + html_lang_valid: The default human language of the page must be valid and specified in accordance with BCP 47 + +  Violation — + Specified 'lang' attribute does not include a valid primary language Violation — + Specified 'lang' attribute does not conform to BCP 47 Violation — + Specified 'xml:lang' attribute does not include a valid primary language Violation — + Specified 'xml:lang' attribute does not conform to BCP 47 + + +
+

3.1.2 Language of Parts [AA]

+
The human language of each passage or phrase in the content can be programmatically determined.
+ element_lang_valid: The change in language of specific content must be valid and specified in accordance with BCP 47 + +  Violation — + Specified 'lang' attribute does not include a valid primary language Violation — + Specified 'lang' attribute does not conform to BCP 47 Violation — + Specified 'xml:lang' attribute does not include a valid primary language Violation — + Specified 'xml:lang' attribute does not conform to BCP 47 + + +
+

3.2.1 On Focus [A]

+
When any component receives focus, it does not initiate a change of context.
+ script_focus_blur_review: Scripting must not remove focus from content that normally receives focus + +  Needs review — + Verify script does not remove focus from content that normally receives focus + + script_select_review: No changes of context should occur when a selection value receives focus + +  Needs review — + Verify that no change of context or action occurs when selection options in this component receive focus + + +
+

3.2.2 On Input [A]

+
Changing the setting of any user interface component does not automatically cause a change of context unless the user has been advised of the behavior before using the component.
+ form_interaction_review: User should be informed in advance when interacting with content causes a change of context + +  Needs review — + Verify that interacting with content will not open pop-up windows or change the active window without informing the user + + form_submit_button_exists: A <form> element should have a submit button or an image button + +  Needs review — + Verify the <form> element has a submit button or an image button + + input_onchange_review: Users must be advised if, due to a change of element value, a form automatically submits, a new window opens, or a change in focus occurs + +  Needs review — + Confirm that the user is advised if, due to a change of element value, a form automatically submits, a new window opens, or a change in focus occurs + + a_target_warning: Users should be warned in advance if their input action will open a new window + +  Recommendation — + Inform the user when their input action will open a new window + + +
+

3.2.3 Consistent Navigation [AA]

+
Navigational mechanisms that are repeated on multiple Web pages within a set of Web pages occur in the same relative order each time they are repeated, unless a change is initiated by the user.
+ +
+

3.2.4 Consistent Identification [AA]

+
Components that have the same functionality within a set of Web pages are identified consistently.
+ +
+

3.2.6 Consistent Help [AA]

+
Make it easier to find help and support. If a Web page contains help mechanisms they occur in the same order relative to other page content, unless a change is initiated by the user.
+ +
+

3.3.1 Error Identification [A]

+
If an input error is automatically detected, the item that is in error is identified and the error is described to the user in text.
+ error_message_exists: A custom error message must reference a valid 'id' value and when triggered the message must be appropriately exposed + +  Violation — + Custom error message has invalid reference 'id' value Violation — + Custom error message is not visible + + +
+

3.3.2 Labels or Instructions [A]

+
Labels or instructions are provided when content requires user input.
+ fieldset_label_valid: Groups with nested inputs must have unique accessible name + +  Violation — + Group/Fieldset does not have an accessible name Violation — + Group/Fieldset "{0}" has a duplicate name to another group + + input_label_after: Checkboxes and radio buttons must have a label after the input control + +  Violation — + Checkbox or radio button is nested in label, so label is not after the input control Violation — + Label text is located before its associated checkbox or radio button element + + input_label_before: Text inputs and <select> elements must have a label before the input control + +  Violation — + Text input is nested in label such that input precedes the label text Violation — + Label text is located after its associated text input or <select> element + + input_label_visible: An input element must have an associated visible label + +  Needs review — + The ‘placeholder’ is the only visible label Needs review — + The input element does not have an associated visible label + + element_accesskey_labelled: An element with an assigned 'accesskey' attribute must have an associated label + +  Recommendation — + The element with an assigned 'accesskey' attribute does not have an associated label + + +
+

3.3.3 Error Suggestion [AA]

+
If an input error is automatically detected and suggestions for correction are known, then the suggestions are provided to the user, unless it would jeopardize the security or purpose of the content.
+ +
+

3.3.4 Error Prevention (Legal, Financial, Data) [AA]

+
For content that cause legal commitments or financial transactions for the user to occur, that modify or delete user-controllable data in data storage systems, or that submit user test responses, the user can reverse, correct, or confirm the action.
+ +
+

3.3.7 Redundant Entry [AA]

+
Make it easier for users to complete multi-step processes. Don't ask for the same information twice in the same session.
+ +
+

3.3.8 Accessible Authentication (Minimum) [AA]

+
Make logins possible with less mental effort. Don't make people solve, recall, or transcribe something to log in.
+ +
+

4.1.1 Parsing [A]

+
(Obsolete and removed) This requirement was originally adopted to address problems that assistive technology (AT) had directly parsing HTML. AT no longer has any need to directly parse HTML. Consequently, these problems either no longer exist or are addressed by other requirements.
+ +
+

4.1.2 Name, Role, Value [A]

+
For all user interface components (including, but not limited to: form elements, links and components generated by scripts), the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies.
+ combobox_popup_reference: The 'aria-controls' (for ARIA 1.2) or the 'aria-owns' (for ARIA 1.0) attribute of the expanded combobox must reference a valid popup 'id' value + +  Violation — + The 'aria-owns' attribute of the expanded combobox is missing Violation — + The 'aria-controls' attribute of the expanded combobox is missing Violation — + The 'aria-owns' attribute "{0}" of the expanded combobox does not reference a valid popup 'id' value Violation — + The 'aria-controls' attribute "{0}" of the expanded combobox does not reference a valid popup 'id' value Violation — + The combobox 'aria-expanded' attribute is true, but the combobox popup is not visible Violation — + The combobox 'aria-expanded' attribute is false, but the combobox popup is visible + + aria_activedescendant_valid: The 'aria-activedescendant' property must reference the 'id' of a non-empty, non-hidden active child element + +  Violation — + The 'aria-activedescendant' property is empty Violation — + The 'aria-activedescendant' property references a hidden node Violation — + Element is not a combobox, and the referenced active-descendant element is not a valid descendant + + combobox_active_descendant: 'aria-activedescendant' must be used to define focus within the combobox popup, except when using a dialog popup + +  Violation — + The element referenced by 'aria-activedescendant' "{0}" does not exist Violation — + The 'aria-activedescendant' "{0}" references an element with the roles "{1}", which does not have a valid ARIA role of 'option', 'gridcell', 'row', or 'treeitem' Violation — + The 'aria-activedescendant' "{0}" references an element that does not have 'aria-selected' set to true + + input_haspopup_conflict: <input> element with a 'list' attribute should not use an explicit 'aria-haspopup' attribute + +  Needs review — + The <input> element with type "{0}" and 'list' attribute uses an explicit 'aria-haspopup' attribute Needs review — + The <input> element with a missing or invalid type and 'list' attribute uses an explicit 'aria-haspopup' attribute Needs review — + The list attribute for the <input> element is invalid Violation — + The list attribute for the <input> element with the type "{0}" is invalid Violation — + The list attribute for the <input> element does not reference a datalist element + + aria_role_valid: ARIA roles must be valid for the element to which they are assigned + +  Violation — + The ARIA role '{0}' is not valid for the element <{1}> Violation — + The ARIA role '{0}' is not valid for the element <{1}> and may be ignored by the browser since the element is focusable + + combobox_autocomplete_valid: A combobox that supports autocompletion behavior must have the 'aria-autocomplete' attribute only on its text input element with a valid value; a value of '"inline"' is not supported + +  Violation — + The combobox has the 'aria-autocomplete' attribute incorrectly set on an element within the popup referenced by "{0}" Violation — + The combobox does not support an 'aria-autocomplete' attribute value set to '"inline"' + + combobox_focusable_elements: Tabbable focus for the combobox must be allowed only on the text input, except when using a dialog popup + +  Violation — + The combobox element does not allow DOM focus as required Violation — + The popup of the combobox has DOM focus or has 'aria-activedescendant' defined, which is not allowed + + combobox_haspopup_valid: The combobox attribute 'aria-haspopup' value must be appropriate for the role of the element referenced by 'aria-controls' (ARIA 1.2) or 'aria-owns' (ARIA 1.0) + +  Violation — + The 'role' value "{0}" of the popup element "{1}" should be one of "listbox", "grid", "tree" or "dialog" Violation — + The value of the combobox 'aria-haspopup' attribute "{0}" does not match the 'role' value of the popup element "{1}" + + input_label_exists: Each form control must have an associated label + +  Violation — + Form control element <{0}> has no associated label Violation — + Form control with "{0}" role has no associated label + + aria_descendant_valid: Browsers ignore the explicit and implicit ARIA roles of the descendants of certain elements + +  Needs review — + The element with role "{0}" contains descendants with implicit roles "{1}" which are ignored by browsers Violation — + The element with role "{0}" contains descendants with roles "{1}" which are ignored by browsers + + aria_role_allowed: Elements must have a valid 'role' per ARIA specification + +  Violation — + The role '{0}' defined on the element is not valid per ARIA specification Needs review — + Some of the roles, '{0}', defined on the element are not valid per ARIA specification + + a_text_purpose: Hyperlinks must have an accessible name for their purpose + +  Violation — + Hyperlink has no link text, label or image with a text alternative + + aria_attribute_allowed: ARIA attributes must be valid for the element's role + +  Violation — + The attribute(s) '{0}' referenced by the element <{1}> is not a valid ARIA state or property + + aria_attribute_conflict: An ARIA attribute must not conflict with the corresponding HTML attribute + +  Violation — + The ARIA attribute "{0}" is in conflict with the corresponding HTML attribute "{1}" + + aria_attribute_exists: When specifying a required ARIA attribute, the value must not be empty + +  Violation — + The element attribute(s): '{0}' value is empty + + aria_attribute_required: The required attributes for the element with a role must be defined + +  Violation — + Element with '{0}' role does not have the required ARIA attribute(s): '{1}' + + aria_attribute_value_valid: ARIA property values must be valid + +  Violation — + The value "{0}" specified for attribute '{1}' on element <{2}> is not valid + + aria_eventhandler_role_valid: Elements with event handlers must have a valid ARIA role + +  Violation — + The <{0}> element with '{1}' does not have a valid ARIA role specified + + aria_hidden_nontabbable: A hidden element should not contain any tabbable elements + +  Violation — + Element "{0}" should not be focusable within the subtree of an element with an 'aria-hidden' attribute with value 'true' + + aria_id_unique: The ARIA property must reference a non-empty unique id of an existing element that is visible + +  Violation — + The 'id' "{0}" specified for the ARIA property '{1}' value is not valid + + aria_widget_labelled: Interactive component must have a programmatically associated name + +  Violation — + Interactive component with ARIA role '{0}' does not have a programmatically associated name + + combobox_design_valid: The combobox design pattern must be valid for ARIA 1.2 + +  Violation — + The combobox design pattern is detected as ARIA 1.1, which is not allowed by ARIA 1.2 + + element_tabbable_role_valid: A tabbable element must have a valid widget role + +  Violation — + The tabbable element's role '{0}' is not a widget role + + frame_title_exists: Inline frames must have a unique, non-empty 'title' attribute + +  Violation — + Inline frame does not have a 'title' attribute + + label_content_exists: A <label> element must have non-empty descriptive text that identifies the purpose of the interactive component + +  Violation — + The <label> element does not have descriptive text that identifies the expected input + + list_children_valid: List component with "group" role must limit children to <listitem> elements + +  Violation — + List component with "group" role has children that are not <listitem> elements + + table_aria_descendants: Table structure elements cannot specify an explicit 'role' within table containers + +  Violation — + An explicit ARIA 'role' is not valid for <{0}> element within an ARIA role '{1}' per the ARIA in HTML specification + + aria_accessiblename_exists: Elements with certain roles should have accessible names + +  Recommendation — + Element <{0}> with "{1}" role has no accessible name + + aria_attribute_redundant: An ARIA attribute should not be redundant with a corresponding HTML attribute + +  Recommendation — + The ARIA attribute "{0}" is redundant with the HTML attribute "{1}" + + canvas_content_described: The <canvas> element may not be accessible + +  Recommendation — + Verify accessibility of the <canvas> element + + +
+

4.1.3 Status Messages [AA]

+
In content implemented using markup languages, status messages can be programmatically determined through role or properties such that they can be presented to the user by assistive technologies without receiving focus.
+ +
+

HTML specification [NA]

+
The HTML specification issues that cause accessibility issues may be covered by other rules and will be reported under those accessibility requirements. However, some non-conforming HTML specification issues are still reported.
+ element_id_unique: Element 'id' attribute values must be unique within a document + +  Violation — + The <{0}> element has the id "{1}" that is empty Violation — + The <{0}> element has the id "{1}" that is already in use + + element_accesskey_unique: 'accesskey' attribute values on each element must be unique for the page + +  Violation — + 'accesskey' attribute value on the element is not unique + + element_attribute_deprecated: Avoid use of obsolete features if possible + +  Recommendation — + The <{0}> element is deprecated in HTML 5 Recommendation — + The HTML attribute(s) "{0}" is deprecated in HTML 5 Recommendation — + The HTML attribute(s) "{0}" is deprecated for the <{1}> element in HTML 5 + + +
+

ARIA specification [NA]

+
The ARIA specification issues that cause accessibility issues may be covered by other rules and will be reported under those accessibility requirements. However, some non-conforming ARIA specification issues are still reported.
+ aria_attribute_valid: ARIA attributes should be valid for the element and ARIA role to which they are assigned + +  Violation — + The ARIA attributes "{0}" are not valid for the element <{1}> with ARIA role "{2}" Violation — + The ARIA attributes "{0}" are not valid for the element <{1}> with implicit ARIA role "{2}" + + aria_attribute_deprecated: No deprecated ARIA role or attribute should be used + +  Recommendation — + The ARIA role "{0}" is deprecated in the ARIA specification Recommendation — + The ARIA attributes "{0}" are deprecated in the ARIA specification Recommendation — + The ARIA attributes "{0}" are deprecated for the role "{1}" in the ARIA specification + + aria_role_redundant: An explicitly-assigned ARIA role should not be redundant with the implicit role of the element + +  Recommendation — + The explicitly-assigned ARIA role "{0}" is redundant with the implicit role of the element <{1}> + + +
+
+
+ + \ No newline at end of file diff --git a/rule-server/src/static/archives/2024.08.29/js/ace-debug.js b/rule-server/src/static/archives/2024.08.29/js/ace-debug.js new file mode 100644 index 000000000..5165449cc --- /dev/null +++ b/rule-server/src/static/archives/2024.08.29/js/ace-debug.js @@ -0,0 +1,30682 @@ +/*! + * Copyright:: 2016,2017,2019,2020- IBM, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var ace; +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/v2/aria/ARIADefinitions.ts": +/*!****************************************!*\ + !*** ./src/v2/aria/ARIADefinitions.ts ***! + \****************************************/ +/***/ ((__unused_webpack_module, exports) => { + + +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ARIADefinitions = void 0; +var ARIADefinitions = /** @class */ (function () { + function ARIADefinitions() { + } + ARIADefinitions.nameFromContent = function (role) { + return (role in ARIADefinitions.designPatterns) + && ARIADefinitions.designPatterns[role].nameFrom + && ARIADefinitions.designPatterns[role].nameFrom.includes("contents"); + }; + /* + * array of WAI-ARIA global states and properties + * @see https://www.w3.org/TR/wai-aria-1.2/#global_states + */ + ARIADefinitions.globalProperties = ["aria-atomic", "aria-busy", "aria-controls", "aria-current", "aria-describedby", + "aria-details", "aria-flowto", "aria-hidden", "aria-keyshortcuts", + "aria-label", "aria-labelledby", "aria-live", "aria-owns", "aria-relevant", "aria-roledescription" + // the following are deprecated in ARIA 1.2, will indicate deprecation in individual role + , + 'aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid' + ]; + //properties contains id(s) that refer to other element(s) + ARIADefinitions.referenceProperties = ["aria-owns", "aria-controls", "aria-describedby", "aria-labelledby", "aria-flowto", "aria-activedescendant"]; + // deprecated roles + ARIADefinitions.globalDeprecatedRoles = [ + 'directory', 'doc-biblioentry', 'doc-endnote' + ]; + // the following are deprecated in ARIA 1.1 for all the roles + ARIADefinitions.globalDeprecatedProperties = [ + 'aria-grabbed', 'aria-dropeffect' + ]; + /* + * XSD data types for all WAI-ARIA properties + * along with valid values when the data type is NMTOKEN + * WAI-ARIA properties data types explaned: + * type: Used to identify the type of values allowed for the WAI-ARIA property + * values: Used to identify specific values of an WAI-ARIA property when type is nmtoken + * hiddenIDRefSupported: Used to identify if the WAI-ARIA property supports referencing hidden ID + * true: refers to WAI-ARIA property supports hidden ID references + * false: refers to WAI-ARIA property does not support hidden ID references + * Default value will be set to false, if not specified. + */ + ARIADefinitions.propertyDataTypes = { + "aria-activedescendant": { + type: "http://www.w3.org/2001/XMLSchema#idref", + hiddenIDRefSupported: true + }, + "aria-atomic": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-autocomplete": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["inline", "list", "both", "none", "undefined"] //add undefined to handle value empty + }, + "aria-busy": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-checked": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "mixed", "undefined"] + }, + "aria-colcount": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-colindex": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-colspan": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-controls": { + type: "http://www.w3.org/2001/XMLSchema#idrefs", + hiddenIDRefSupported: true + }, + "aria-current": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["page", "step", "location", "date", "time", "true", "false", "undefined"] //add undefined for empty value + }, + "aria-describedby": { + type: "http://www.w3.org/2001/XMLSchema#idrefs", + hiddenIDRefSupported: true + }, + "aria-details": { + type: "http://www.w3.org/2001/XMLSchema#idrefs" + }, + "aria-disabled": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-dropeffect": { + type: "http://www.w3.org/2001/XMLSchema#nmtokens", + values: ["copy", "move", "link", "execute", "popup", "none"] + }, + "aria-errormessage": { + type: "http://www.w3.org/2001/XMLSchema#idref", + hiddenIDRefSupported: true + }, + "aria-expanded": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "undefined"] + }, + "aria-flowto": { + type: "http://www.w3.org/2001/XMLSchema#idrefs", + hiddenIDRefSupported: false + }, + "aria-grabbed": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "undefined"] + }, + "aria-haspopup": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "menu", "listbox", "tree", "grid", "dialog"] + }, + "aria-hidden": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "undefined"] + }, + "aria-invalid": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "spelling", "grammar", "undefined"] //add undefined for empty value + }, + "aria-keyshortcuts": { + type: "http://www.w3.org/2001/XMLSchema#string" + }, + "aria-label": { + type: "http://www.w3.org/2001/XMLSchema#string" + }, + "aria-labelledby": { + type: "http://www.w3.org/2001/XMLSchema#idrefs", + hiddenIDRefSupported: true + }, + "aria-level": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-live": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["off", "polite", "assertive"] + }, + "aria-modal": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-multiline": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-multiselectable": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-orientation": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["horizontal", "vertical", "undefined"] + }, + "aria-owns": { + type: "http://www.w3.org/2001/XMLSchema#idrefs", + hiddenIDRefSupported: true + }, + "aria-placeholder": { + type: "http://www.w3.org/2001/XMLSchema#string" + }, + "aria-posinset": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-pressed": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "mixed", "undefined"] + }, + "aria-readonly": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-relevant": { + type: "http://www.w3.org/2001/XMLSchema#nmtokens", + values: ["additions", "removals", "text", "all"] + }, + "aria-required": { + type: "http://www.w3.org/2001/XMLSchema#boolean" + }, + "aria-roledescription": { + type: "http://www.w3.org/2001/XMLSchema#string" + }, + "aria-rowcount": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-rowindex": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-rowspan": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-selected": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["true", "false", "undefined"] + }, + "aria-setsize": { + type: "http://www.w3.org/2001/XMLSchema#int" + }, + "aria-sort": { + type: "http://www.w3.org/2001/XMLSchema#nmtoken", + values: ["ascending", "descending", "other", "none"] + }, + "aria-valuemax": { + type: "http://www.w3.org/2001/XMLSchema#decimal" + }, + "aria-valuemin": { + type: "http://www.w3.org/2001/XMLSchema#decimal" + }, + "aria-valuenow": { + type: "http://www.w3.org/2001/XMLSchema#decimal" + }, + "aria-valuetext": { + type: "http://www.w3.org/2001/XMLSchema#string" + } + }; + /* + * design patterns for concrete WAI-ARIA roles + * legitimate keys for each role include: + * + * - container: appropriate container(s) for that role + * - props: states and properties that may be associated with this role (in addition to the global states and properties listed above) + * - reqProps: required states or properties for this role + * - reqChildren: required children for this role + * - htmlEquiv: HTML equivalent for this role + * - roleType: one of widget, structure, landmark, liveRegion, window (as seen in https://www.w3.org/TR/wai-aria-1.2/#roles_categorization) + * - nameRequired: determines whether an accessible name is required for a widget (see ARIA spec.) + * - nameFrom: determines how an accessible name is supplied (author or content - see ARIA spec.) + * - deprecated: if present, indicates that the role is deprecated, and provides a list of alternative role(s) + */ + ARIADefinitions.designPatterns = { + "alert": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "liveRegion", + nameRequired: false, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "alertdialog": { + container: null, + props: ["aria-modal"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "window", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "application": { + container: null, + props: ["aria-activedescendant", "aria-expanded"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: true, + nameFrom: ["author"] + }, + "article": { + container: null, + props: ["aria-posinset", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "banner": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "blockquote": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "button": { + container: null, + props: ["aria-expanded", "aria-pressed"], + reqProps: null, + reqChildren: null, + htmlEquiv: "button | input[@type='button']", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-invalid'] + }, + "caption": { + container: ["figure", "grid", "table", "treegrid"], + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "cell": { + container: ["row"], + props: ["aria-colindex", "aria-colspan", "aria-rowindex", "aria-rowspan"], + reqProps: null, + reqChildren: null, + htmlEquiv: "td", + roleType: "structure", + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "checkbox": { + container: null, + props: ["aria-expanded", "aria-readonly", "aria-required"], + reqProps: ["aria-checked"], + reqChildren: null, + htmlEquiv: "input[@type='checkbox']", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-haspopup'] + }, + "code": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "columnheader": { + container: ["row"], + props: ["aria-colindex", "aria-colspan", "aria-expanded", "aria-readonly", "aria-required", "aria-rowindex", "aria-rowspan", "aria-selected", "aria-sort"], + reqProps: null, + reqChildren: null, + htmlEquiv: "th[@scope='col']", + roleType: "structure", + nameRequired: true, + nameFrom: ["author", "contents"] + }, + "combobox": { + container: null, + props: ["aria-controls", "aria-activedescendant", "aria-autocomplete", "aria-readonly", "aria-required"], + reqProps: ["aria-expanded"], + reqChildren: [], + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"] + }, + "complementary": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "comment": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: false, + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "contentinfo": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "definition": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "deletion": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "dialog": { + container: null, + props: ["aria-modal"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "window", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "directory": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecated: true, + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "doc-abstract": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-acknowledgments": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-afterword": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-appendix": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-backlink": { + container: null, + props: ["aria-disabled", "aria-expanded", "aria-haspopup"], + reqProps: null, + reqChildren: null, + htmlEquiv: "a | link", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"] + }, + "doc-biblioentry": { + container: ["list"], + props: ["aria-level", "aria-posinset", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: "li", + roleType: "structure", + nameRequired: true, + nameFrom: ["author"] + }, + "doc-bibliography": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-biblioref": { + container: null, + props: ["aria-disabled", "aria-expanded", "aria-haspopup"], + reqProps: null, + reqChildren: null, + htmlEquiv: "a | link", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"] + }, + "doc-chapter": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-colophon": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: true, + nameFrom: ["author"] + }, + "doc-conclusion": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-cover": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: "img", + roleType: "structure", + nameRequired: false, + nameFrom: ["author"], + presentationalChildren: true + }, + "doc-credit": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-credits": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-dedication": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-endnote": { + container: ["list"], + props: ["aria-level", "aria-posinset", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: "li", + roleType: "structure", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-endnotes": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: true, + nameFrom: ["author"] + }, + "doc-epigraph": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-epilogue": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-errata": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-example": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-footnote": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-foreword": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-glossary": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-glossref": { + container: null, + props: ["aria-disabled", "aria-expanded", "aria-haspopup"], + reqProps: null, + reqChildren: null, + htmlEquiv: "a | link", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"] + }, + "doc-index": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-introduction": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-noteref": { + container: null, + props: ["aria-disabled", "aria-expanded", "aria-haspopup"], + reqProps: null, + reqChildren: null, + htmlEquiv: "a | link", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"] + }, + "doc-notice": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-pagebreak": { + container: null, + props: ["aria-orientation"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true + }, + "doc-pagelist": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-pagefooter": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + }, + "doc-pageheader": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + }, + "doc-part": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-preface": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-prologue": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-pullquote": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-qna": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-subtitle": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: false, + nameFrom: ["author", "contents"] + }, + "doc-tip": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: false, + nameFrom: ["author"] + }, + "doc-toc": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: false, + nameFrom: ["author"] + }, + "document": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: false, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "emphasis": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "feed": { + container: null, + props: null, + reqProps: null, + reqChildren: ["article"], + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "figure": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "form": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: "form", + roleType: "landmark", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "generic": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: "div | span", + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby", "aria-roledescription"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "graphics-document": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + nameRequired: true, + nameFrom: ["author"] + }, + "graphics-object": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + nameRequired: false, + nameFrom: ["author"] + }, + "graphics-symbol": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + nameRequired: true, + nameFrom: ["author"], + presentationalChildren: true + }, + "grid": { + container: null, + props: ["aria-activedescendant", "aria-colcount", "aria-multiselectable", "aria-readonly", "aria-rowcount"], + reqProps: null, + reqChildren: ["row", "rowgroup"], + htmlEquiv: "table", + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "gridcell": { + container: ["row"], + props: ["aria-colindex", "aria-colspan", "aria-disabled", "aria-errormessage", "aria-expanded", "aria-haspopup", "aria-invalid", "aria-readonly", "aria-required", "aria-rowindex", "aria-rowspan", "aria-selected"], + reqProps: null, + reqChildren: null, + htmlEquiv: "td", + roleType: "widget", + nameFrom: ["author", "contents"] + }, + "group": { + container: null, + props: ["aria-activedescendant"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "heading": { + container: null, + props: null, + reqProps: ["aria-level"], + reqChildren: null, + htmlEquiv: "h1 | h2 | h3 | h4 | h5 | h6", + roleType: "structure", + nameRequired: true, + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "img": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: "img", + roleType: "structure", + nameRequired: true, + nameFrom: ["author"], + presentationalChildren: true, + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "insertion": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "link": { + container: null, + props: ["aria-expanded"], + reqProps: null, + reqChildren: null, + htmlEquiv: "a | link", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-errormessage', 'aria-invalid'] + }, + "list": { + container: null, + props: null, + reqProps: null, + reqChildren: ["listitem"], + htmlEquiv: "ol | ul", + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "listbox": { + container: null, + props: ["aria-activedescendant", "aria-expanded", "aria-multiselectable", "aria-orientation", "aria-readonly", "aria-required"], + reqProps: null, + reqChildren: ["group", "option"], + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-haspopup'] + }, + "listitem": { + container: ["list"], + props: ["aria-level", "aria-posinset", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: "li", + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "log": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "liveRegion", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "main": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "mark": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: "mark", + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "marquee": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "liveRegion", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "math": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + presentationalChildren: false, + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "menu": { + container: null, + props: ["aria-activedescendant", "aria-orientation"], + reqProps: null, + reqChildren: ["group", "menuitem", "menuitemcheckbox", "menuitemradio"], + htmlEquiv: null, + roleType: "widget", + nameRequired: false, + nameFrom: ["author"], + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "menubar": { + container: null, + props: ["aria-activedescendant", "aria-orientation"], + reqProps: null, + reqChildren: ["group", "menuitem", "menuitemcheckbox", "menuitemradio"], + htmlEquiv: null, + roleType: "widget", + nameRequired: false, + nameFrom: ["author"], + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "menuitem": { + container: ["group", "menu", "menubar"], + props: ["aria-expanded", "aria-posinset", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-errormessage', 'aria-invalid'] + }, + "menuitemcheckbox": { + container: ["group", "menu", "menubar"], + props: ["aria-expanded", "aria-posinset", "aria-setsize"], + reqProps: ["aria-checked"], + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-invalid'] + }, + "menuitemradio": { + container: ["group", "menu", "menubar"], + props: ["aria-expanded", "aria-posinset", "aria-setsize"], + reqProps: ["aria-checked"], + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-invalid'] + }, + "meter": { + container: null, + props: ["aria-valuemax", "aria-valuemin", "aria-valuetext"], + reqProps: ["aria-valuenow"], + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: true, + nameFrom: ["author"], + presentationalChildren: true, + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "navigation": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "none": { + container: null, + props: [], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "note": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "option": { + container: ["group", "listbox"], + props: ["aria-selected", "aria-checked", "aria-posinset", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: "option", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "paragraph": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "presentation": { + container: null, + props: [], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "progressbar": { + container: null, + props: ["aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-valuetext"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + presentationalChildren: true, + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "radio": { + container: null, + props: ["aria-posinset", "aria-setsize"], + reqProps: ["aria-checked"], + reqChildren: null, + htmlEquiv: "input[@type='radio']", + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "radiogroup": { + container: null, + props: ["aria-activedescendant", "aria-orientation", "aria-readonly", "aria-required"], + reqProps: null, + reqChildren: ["radio"], + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-haspopup'] + }, + "region": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "row": { + container: ["grid", "rowgroup", "table", "treegrid"], + props: ["aria-activedescendant", "aria-colindex", "aria-expanded", "aria-level", "aria-posinset", "aria-rowindex", "aria-selected", "aria-setsize"], + reqProps: null, + reqChildren: ["cell", "columnheader", "gridcell", "rowheader"], + htmlEquiv: "tr", + roleType: "structure", + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "rowgroup": { + container: ["grid", "table", "treegrid"], + props: [], + reqProps: null, + reqChildren: ["row"], + htmlEquiv: "tbody | tfoot | thead", + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "rowheader": { + container: ["row"], + props: ["aria-colindex", "aria-colspan", "aria-expanded", "aria-readonly", "aria-required", "aria-rowindex", "aria-rowspan", "aria-selected", "aria-sort"], + reqProps: null, + reqChildren: null, + htmlEquiv: "th[@scope='row']", + roleType: "structure", + nameRequired: true, + nameFrom: ["author", "contents"] + }, + "scrollbar": { + container: null, + props: ["aria-orientation", "aria-valuemax", "aria-valuemin", "aria-valuetext"], + reqProps: ["aria-controls", "aria-valuenow"], + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: false, + nameFrom: ["author"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "search": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "landmark", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "searchbox": { + container: null, + props: ["aria-activedescendant", "aria-autocomplete", "aria-multiline", "aria-placeholder", "aria-readonly", "aria-required"], + reqProps: null, + reqChildren: null, + htmlEquiv: "input[@type='search']", + roleType: "widget", + nameRequired: true, + nameFrom: ["author"] + }, + "separator": { + container: null, + props: ["aria-orientation"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "slider": { + container: null, + props: ["aria-orientation", "aria-readonly", "aria-valuemax", "aria-valuemin", "aria-valuetext"], + reqProps: ["aria-valuenow"], + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + presentationalChildren: true + }, + "spinbutton": { + container: null, + props: ["aria-activedescendant", "aria-readonly", "aria-required", "aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-valuetext"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-haspopup'] + }, + "status": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "liveRegion", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "strong": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "subscript": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "suggestion": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "superscript": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "switch": { + container: null, + props: ["aria-expanded", "aria-readonly", "aria-required"], + reqProps: ["aria-checked"], + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-haspopup'] + }, + "tab": { + container: ["tablist"], + props: ["aria-expanded", "aria-posinset", "aria-selected", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + presentationalChildren: true, + deprecatedProps: ['aria-errormessage', 'aria-invalid'] + }, + "table": { + container: null, + props: ["aria-colcount", "aria-rowcount"], + reqProps: null, + reqChildren: ["row", "rowgroup", "caption"], + htmlEquiv: "table", + roleType: "structure", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "tablist": { + container: null, + props: ["aria-activedescendant", "aria-multiselectable", "aria-orientation"], + reqProps: null, + reqChildren: ["tab"], + htmlEquiv: null, + roleType: "widget", + nameRequired: false, + nameFrom: ["author"], + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "tabpanel": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "term": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: "dfn", + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "textbox": { + container: null, + props: ["aria-activedescendant", "aria-autocomplete", "aria-multiline", "aria-placeholder", "aria-readonly", "aria-required"], + reqProps: null, + reqChildren: null, + htmlEquiv: "input[@type='text']", + roleType: "widget", + nameRequired: true, + nameFrom: ["author"] + }, + "time": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["prohibited"], + prohibitedProps: ["aria-label", "aria-labelledby"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "timer": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "liveRegion", + nameFrom: ["author"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "toolbar": { + container: null, + props: ["aria-activedescendant", "aria-orientation"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameFrom: ["author"], + deprecatedProps: ['aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "tooltip": { + container: null, + props: null, + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "structure", + nameRequired: false, + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-disabled', 'aria-errormessage', 'aria-haspopup', 'aria-invalid'] + }, + "tree": { + container: null, + props: ["aria-activedescendant", "aria-multiselectable", "aria-orientation", "aria-required"], + reqProps: null, + reqChildren: ["group", "treeitem"], + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-haspopup'] + }, + "treegrid": { + container: null, + props: ["aria-activedescendant", "aria-colcount", "aria-multiselectable", "aria-orientation", "aria-readonly", "aria-required", "aria-rowcount"], + reqProps: null, + reqChildren: ["row", "rowgroup"], + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author"], + deprecatedProps: ['aria-haspopup'] + }, + "treeitem": { + container: ["group", "tree"], + props: ["aria-checked", "aria-expanded", "aria-level", "aria-posinset", "aria-selected", "aria-setsize"], + reqProps: null, + reqChildren: null, + htmlEquiv: null, + roleType: "widget", + nameRequired: true, + nameFrom: ["author", "contents"], + deprecatedProps: ['aria-errormessage', 'aria-invalid'] + }, + }; // end designPatterns + // copied from https://html.spec.whatwg.org/multipage/semantics-other.html#disabled-elements + // https://html.spec.whatwg.org/multipage/input.html#input-type-attr-summary + ARIADefinitions.elementsAllowedDisabled = ["button", "input", "select", "textarea", "optgroup", "option", "fieldset"]; // also form-associated custom element + ARIADefinitions.elementsAllowedRequired = ["select", "textarea"]; // remove 'input' and add to the individual element, becuase required is not supported on input@type="range", "color", "hidden" or any button types + ARIADefinitions.elementsAllowedReadOnly = ["textarea"]; // remove 'input' and add to the individual element, because readonly is not supported on input@type="checkbox", "radio", "range", "color", "file", hidden" or any button types + /* https://www.w3.org/TR/html-aria/#docconformance + * documentConformanceRequirement contains properties of the tags related to role without any additional attribute value + * documentConformanceRequirementSpecialTags contains those tags that require special considerations + */ + ARIADefinitions.documentConformanceRequirement = { + "abbr": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "address": { + implicitRole: ["group"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "article": { + implicitRole: ["article"], + validRoles: ["application", "document", "feed", "main", "none", "presentation", "region"], + globalAriaAttributesValid: true + }, + "aside": { + implicitRole: ["complementary"], + validRoles: ["doc-dedication", "doc-example", "doc-footnote", "doc-glossary", "doc-pullquote", "doc-tip", "feed", "none", "note", "presentation", "region", "search"], + globalAriaAttributesValid: true + }, + "audio": { + implicitRole: null, + validRoles: ["application"], + globalAriaAttributesValid: true + }, + "b": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "base": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "bdi": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "bdo": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "blockquote": { + implicitRole: ["blockquote"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "body": { + implicitRole: ["generic"], + validRoles: null, + otherDisallowedAriaAttributes: ['aria-hidden'], + globalAriaAttributesValid: true + }, + "br": { + implicitRole: null, + validRoles: ["none", "presentation"], + globalAriaAttributesValid: false, + otherAllowedAriaAttributes: ["aria-hidden"] + }, + "button": { + implicitRole: ["button"], + validRoles: ["checkbox", "combobox", "gridcell", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "slider", "switch", "tab", "treeitem"], + globalAriaAttributesValid: true + }, + "canvas": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "caption": { + implicitRole: ['caption'], + validRoles: null, + globalAriaAttributesValid: true, + allowAttributesFromImplicitRole: false + }, + "cite": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "code": { + implicitRole: ["code"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "col": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "colgroup": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "data": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "datalist": { + implicitRole: ["listbox"], + validRoles: null, + globalAriaAttributesValid: false, + allowAttributesFromImplicitRole: false + }, + "dd": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true + }, + "del": { + implicitRole: ["deletion"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "details": { + implicitRole: ["group"], + validRoles: null, + globalAriaAttributesValid: true + }, + "dfn": { + implicitRole: ["term"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "dialog": { + implicitRole: ["dialog"], + validRoles: ["alertdialog"], + globalAriaAttributesValid: true + }, + "dl": { + implicitRole: null, + validRoles: ["group", "list", "none", "presentation"], + globalAriaAttributesValid: true + }, + "dt": { + implicitRole: ["term"], + validRoles: ["listitem"], + globalAriaAttributesValid: true + }, + "em": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "embed": { + implicitRole: null, + validRoles: ["application", "document", "img", "none", "presentation"], + globalAriaAttributesValid: true + }, + "fieldset": { + implicitRole: ["group"], + validRoles: ["none", "presentation", "radiogroup"], + globalAriaAttributesValid: true + }, + "figcaption": { + implicitRole: null, + validRoles: ["group", "none", "presentation"], + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "form": { + implicitRole: ["form"], + validRoles: ["none", "presentation", "search"], + globalAriaAttributesValid: true + }, + "head": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "hgroup": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "h1": { + implicitRole: ["heading"], + validRoles: ["doc-subtitle", "none", "presentation", "tab"], + globalAriaAttributesValid: true + }, + "h2": { + implicitRole: ["heading"], + validRoles: ["doc-subtitle", "none", "presentation", "tab"], + globalAriaAttributesValid: true + }, + "h3": { + implicitRole: ["heading"], + validRoles: ["doc-subtitle", "none", "presentation", "tab"], + globalAriaAttributesValid: true + }, + "h4": { + implicitRole: ["heading"], + validRoles: ["doc-subtitle", "none", "presentation", "tab"], + globalAriaAttributesValid: true + }, + "h5": { + implicitRole: ["heading"], + validRoles: ["doc-subtitle", "none", "presentation", "tab"], + globalAriaAttributesValid: true + }, + "h6": { + implicitRole: ["heading"], + validRoles: ["doc-subtitle", "none", "presentation", "tab"], + globalAriaAttributesValid: true + }, + "hr": { + implicitRole: ["separator"], + validRoles: ["doc-pagebreak", "none", "presentation"], + globalAriaAttributesValid: true + }, + "html": { + implicitRole: ["document"], + validRoles: null, + globalAriaAttributesValid: false, + allowAttributesFromImplicitRole: false + }, + "i": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "iframe": { + implicitRole: null, + validRoles: ["application", "document", "img", "none", "presentation"], + globalAriaAttributesValid: true + }, + "ins": { + implicitRole: ["insertion"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "kbd": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "label": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "legend": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "link": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "main": { + implicitRole: ["main"], + validRoles: null, + globalAriaAttributesValid: true + }, + "map": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "mark": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "math": { + implicitRole: ["math"], + validRoles: null, + globalAriaAttributesValid: true + }, + "menu": { + implicitRole: ["list"], + validRoles: ["group", "listbox", "menu", "menubar", "none", "presentation", "radiogroup", "tablist", "toolbar", "tree"], + globalAriaAttributesValid: true + }, + "meta": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "meter": { + implicitRole: ["meter"], + validRoles: null, + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ['aria-valuemax', 'aria-valuemin'], + allowAttributesFromImplicitRole: false + }, + "nav": { + implicitRole: ["navigation"], + validRoles: ["doc-index", "doc-pagelist", "doc-toc", "menu", "menubar", "tablist", "none", "presentation"], + globalAriaAttributesValid: true + }, + "noscript": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "object": { + implicitRole: null, + validRoles: ["application", "document", "img"], + globalAriaAttributesValid: true + }, + "ol": { + implicitRole: ["list"], + validRoles: ["group", "listbox", "menu", "menubar", "none", "presentation", "radiogroup", "tablist", "toolbar", "tree"], + globalAriaAttributesValid: true + }, + "optgroup": { + implicitRole: ["group"], + validRoles: null, + globalAriaAttributesValid: true + }, + "option": { + implicitRole: ["option"], + validRoles: null, + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ["aria-selected"] + }, + "output": { + implicitRole: ["status"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "p": { + implicitRole: ["paragraph"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "param": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "picture": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false, + otherAllowedAriaAttributes: ["aria-hidden"] + }, + "pre": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "progress": { + implicitRole: ["progressbar"], + validRoles: null, + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ["aria-valuemax"] + }, + "q": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "rp": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "rt": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "ruby": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "s": { + implicitRole: ["deletion"], + validRoles: ["any"], + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ["aria-label", "aria-labelledby"] + }, + "samp": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "script": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "search": { + implicitRole: ['search'], + validRoles: ['search', 'form', 'group', 'none', 'presentation', 'region'], + globalAriaAttributesValid: true + }, + "slot": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "small": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "source": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "span": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "strong": { + implicitRole: ["strong"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "style": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "sub": { + implicitRole: ["subscript"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "sup": { + implicitRole: ["superscript"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "svg": { + implicitRole: ["graphics-document"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "table": { + implicitRole: ["table"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "template": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "textarea": { + implicitRole: ["textbox"], + validRoles: null, + globalAriaAttributesValid: true + }, + "tfoot": { + implicitRole: ["rowgroup"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "thead": { + implicitRole: ["rowgroup"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "time": { + implicitRole: ["time"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "title": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "track": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "u": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "ul": { + implicitRole: ["list"], + validRoles: ["group", "listbox", "menu", "menubar", "none", "presentation", "radiogroup", "tablist", "toolbar", "tree"], + globalAriaAttributesValid: true + }, + "var": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true, + prohibitedAriaAttributesWhenNoImplicitRole: ["aria-label", "aria-labelledby"] + }, + "video": { + implicitRole: null, + validRoles: ["application"], + globalAriaAttributesValid: true + }, + "wbr": { + implicitRole: null, + validRoles: ["none", "presentation"], + globalAriaAttributesValid: false, + otherAllowedAriaAttributes: ["aria-hidden"] + } + }; // end documentConformanceRequirement + ARIADefinitions.documentConformanceRequirementSpecialTags = { + "a": { + "with-href": { + implicitRole: ["link"], + //roleCondition: " when non-empty href attribute is present", + validRoles: ["button", "checkbox", "doc-backlink", "doc-biblioref", "doc-glossref", "doc-noteref", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "tab", "treeitem"], + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ["aria-disabled=true"] + }, + "without-href": { + implicitRole: ["generic"], + //roleCondition: " when href attribute is not present", + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "area": { + "with-href": { + implicitRole: ["link"], + //roleCondition: " when non-empty href attribute is present", + validRoles: null, + globalAriaAttributesValid: true + }, + "without-href": { + implicitRole: ["generic"], + //roleCondition: " when href attribute is not present", + validRoles: ["button", "link"], + globalAriaAttributesValid: true + } + }, + // TODO + // "autonomous custom element": { + // implicitRole: ["Role exposed from author defined ElementInternals. Otherwise no corresponding role."], + // validRoles: ["If role defined by ElementInternals", "any role", "no role Otherwise"], + // globalAriaAttributesValid: true + // }, + "div": { + "child-dl": { + implicitRole: ["generic"], + validRoles: ["presentation", "none"], + globalAriaAttributesValid: true + }, + "no-child-dl": { + implicitRole: ["generic"], + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "figure": { + "child-figcaption": { + implicitRole: ["figure"], + validRoles: ['doc-example'], + globalAriaAttributesValid: true + }, + "no-child-figcaption": { + implicitRole: ["figure"], + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "footer": { + "des-section-article-aside-main-nav": { + implicitRole: ["generic"], + //roleCondition: " when descendant of an article, aside, main, nav or section element", + validRoles: ["doc-footnote", "group", "none", "presentation"], + globalAriaAttributesValid: true + }, + "other": { + implicitRole: ["contentinfo"], + //roleCondition: " when not a descendant of an article, aside, main, nav or section element", + validRoles: ["doc-footnote", "group", "none", "presentation"], + globalAriaAttributesValid: true + } + }, + // TODO + // "form-associated custom element": { + // implicitRole: ["Role exposed from author defined ElementInternals. Otherwise 'generic'."], + // validRoles: ["If role defined by ElementInternals", "form-related roles: button", "checkbox", "combobox", "group", "listbox", "progressbar", "radio", "radiogroup", "searchbox", "slider", "spinbutton", "switch", "textbox", "no role Otherwise"], + // globalAriaAttributesValid: true + // }, + "header": { + "des-section-article-aside-main-nav": { + implicitRole: ["generic"], + //roleCondition: " when descendant of an article, aside, main, nav or section element", + validRoles: ["group", "none", "presentation"], + globalAriaAttributesValid: true + }, + "other": { + implicitRole: ["banner"], + //roleCondition: " when not a descendant of an article, aside, main, nav or section element", + validRoles: ["group", "none", "presentation"], + globalAriaAttributesValid: true + } + }, + "img": { + "img-with-accname": { + implicitRole: ["img"], + //roleCondition: "when accessible name presents", + validRoles: ["button", "checkbox", "doc-cover", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "meter", "option", "progressbar", "radio", "scrollbar", "separator", "slider", "switch", "tab", "treeitem"], + globalAriaAttributesValid: true + }, + "img-without-accname-empty-alt": { + implicitRole: ["presentation", "none"], + //roleCondition: "when no accessible name presents and alt=''", + validRoles: null, + globalAriaAttributesValid: false, + otherAllowedAriaAttributes: ["aria-hidden=true"] + }, + "img-without-accname-no-alt": { + implicitRole: ["img"], + //roleCondition: "when neither accessible name no alt presents", + validRoles: ["presentation", "none"], + globalAriaAttributesValid: false, + otherAllowedAriaAttributes: ["aria-hidden=true"] + } + }, + "input": { + "button": { + implicitRole: ["button"], + validRoles: ["checkbox", "combobox", "gridcell", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "slider", "switch", "tab", "treeitem"], + globalAriaAttributesValid: true + }, + "checkbox-with-aria-pressed": { + implicitRole: ["checkbox"], + //roleCondition: " with type=checkbox and aria-pressed attribute is present", + validRoles: ["menuitemcheckbox", "option", "switch", "button"], + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-required"], + otherDisallowedAriaAttributes: ["aria-checked"] + }, + "checkbox-without-aria-pressed": { + implicitRole: ["checkbox"], + //roleCondition: " with type=checkbox and aria-pressed attribute is not present", + validRoles: ["menuitemcheckbox", "option", "switch"], + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-required"], + otherDisallowedAriaAttributes: ["aria-checked"] + }, + "color": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true + }, + "date": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-required", "aria-readonly"], + otherRolesForAttributes: ["textbox"] + }, + "datetime-local": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-required", "aria-readonly"], + otherRolesForAttributes: ["textbox"] + }, + "email-no-list": { + implicitRole: ["textbox"], + //roleCondition: " with type=email and no list attribute is present", + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-placeholder", "aria-required", "aria-readonly"], + otherRolesForAttributes: ["textbox"] + }, + "email-with-list": { + implicitRole: ["combobox"], + validRoles: null, + globalAriaAttributesValid: true + }, + "file": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-required"], + }, + "hidden": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: false + }, + "image": { + implicitRole: ["button"], + validRoles: ["checkbox", "gridcell", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "slider", "switch", "tab", "treeitem"], + globalAriaAttributesValid: true + }, + "month": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-readonly"], + otherRolesForAttributes: ["textbox"] + }, + "number": { + implicitRole: ["spinbutton"], + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-placeholder", "aria-required", "aria-readonly"], + }, + "password": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-placeholder", "aria-required", "aria-readonly"], + otherRolesForAttributes: ["textbox"] + }, + "radio": { + implicitRole: ["radio"], + validRoles: ["menuitemradio"], + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-required"], + otherDisallowedAriaAttributes: ["aria-checked"] + }, + "range": { + implicitRole: ["slider"], + validRoles: null, + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ["aria-valuemax", "aria-valuemin"] + }, + "reset": { + implicitRole: ["button"], + validRoles: ["checkbox", "combobox", "gridcell", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "slider", "switch", "tab", "treeitem"], + globalAriaAttributesValid: true + }, + "search-no-list": { + implicitRole: ["searchbox"], + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-placeholder", "aria-required", "aria-readonly"] + }, + "search-with-list": { + implicitRole: ["combobox"], + validRoles: null, + globalAriaAttributesValid: true + }, + "submit": { + implicitRole: ["button"], + validRoles: ["checkbox", "combobox", "gridcell", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "slider", "switch", "tab", "treeitem"], + globalAriaAttributesValid: true + }, + "tel-no-list": { + implicitRole: ["textbox"], + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-placeholder", "aria-required", "aria-readonly"] + }, + "tel-with-list": { + implicitRole: ["combobox"], + validRoles: null, + globalAriaAttributesValid: true + }, + "text-no-list": { + implicitRole: ["textbox"], + validRoles: ["combobox", "searchbox", "spinbutton"], + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-placeholder", "aria-required", "aria-readonly"] + }, + "text-with-list": { + implicitRole: ["combobox"], + validRoles: null, + globalAriaAttributesValid: true + // otherDisallowedAriaAttributes: ["aria-haspopup"] // covered in a different rule + }, + "time": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-readonly"], + otherRolesForAttributes: ["textbox"] + }, + "url-no-list": { + implicitRole: ["textbox"], + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-placeholder", "aria-required", "aria-readonly"] + }, + "url-with-list": { + implicitRole: ["combobox"], + validRoles: null, + globalAriaAttributesValid: true + }, + "week": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-readonly"], + otherRolesForAttributes: ["textbox"] + }, + "default-with-list": { + // input with a missing or invalid type, with a list attribute + implicitRole: ["combobox"], + validRoles: null, + globalAriaAttributesValid: true + }, + "default-no-list": { + // input with a missing or invalid type, with a list attribute + implicitRole: ["textbox"], + validRoles: null, + globalAriaAttributesValid: true + } + }, + "li": { + "child-of-list-role": { + implicitRole: ['listitem'], + validRoles: null, + globalAriaAttributesValid: true + }, + "no-child-of-list-role": { + implicitRole: ['generic'], + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "section": { + "with-name": { + implicitRole: ["region"], + validRoles: ["alert", "alertdialog", "application", "banner", "complementary", "contentinfo", "dialog", "doc-abstract", "doc-acknowledgments", "doc-afterword", "doc-appendix", "doc-bibliography", "doc-chapter", "doc-colophon", "doc-conclusion", "doc-credit", "doc-credits", "doc-dedication", "doc-endnotes", "doc-epigraph", "doc-epilogue", "doc-errata", "doc-example", "doc-foreword", "doc-glossary", "doc-index", "doc-introduction", "doc-notice", "doc-pagelist", "doc-part", "doc-preface", "doc-prologue", "doc-pullquote", "doc-qna", "doc-toc", "document", "feed", "group", "log", "main", "marquee", "navigation", "none", "note", "presentation", "search", "status", "tabpanel"], + globalAriaAttributesValid: true + }, + "without-name": { + implicitRole: null, + validRoles: ["alert", "alertdialog", "application", "banner", "complementary", "contentinfo", "dialog", "doc-abstract", "doc-acknowledgments", "doc-afterword", "doc-appendix", "doc-bibliography", "doc-chapter", "doc-colophon", "doc-conclusion", "doc-credit", "doc-credits", "doc-dedication", "doc-endnotes", "doc-epigraph", "doc-epilogue", "doc-errata", "doc-example", "doc-foreword", "doc-glossary", "doc-index", "doc-introduction", "doc-notice", "doc-pagelist", "doc-part", "doc-preface", "doc-prologue", "doc-pullquote", "doc-qna", "doc-toc", "document", "feed", "group", "log", "main", "marquee", "navigation", "none", "note", "presentation", "search", "status", "tabpanel"], + globalAriaAttributesValid: true + } + }, + "select": { + "no-multiple-attr-size-gt1": { + //roleCondition: " with a multiple attribute or a size attribute having value greater than 1" + implicitRole: ["combobox"], + validRoles: ["menu"], + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ["aria-multiselectable"] + }, + "multiple-attr-size-gt1": { + //roleCondition: " with no multiple attribute and no size attribute having value greater than 1" + implicitRole: ["listbox"], + validRoles: null, + globalAriaAttributesValid: true, + otherDisallowedAriaAttributes: ["aria-multiselectable"] + } + }, + "summary": { + "first-summary-of-detail": { + implicitRole: null, + validRoles: null, + globalAriaAttributesValid: true, + otherAllowedAriaAttributes: ["aria-disabled", "aria-haspopup"] + }, + "no-first-summary-of-detail": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "tbody": { + "des-table": { + implicitRole: ["rowgroup"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "des-grid": { + implicitRole: ["rowgroup"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "des-treegrid": { + implicitRole: ["rowgroup"], + validRoles: ["any"], + globalAriaAttributesValid: true + }, + "des-other": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "td": { + "des-table": { + implicitRole: ["cell"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-grid": { + implicitRole: ["gridcell"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-treegrid": { + implicitRole: ["gridcell"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-other": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "th": { + "des-table-grid-treegrid-row-scope": { + implicitRole: ["rowheader", "cell"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-table-grid-treegrid-column-scope": { + implicitRole: ["columnheader", "cell"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-other": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "tr": { + "des-table": { + implicitRole: ["row"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-grid": { + implicitRole: ["row"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-treegrid": { + implicitRole: ["row"], + validRoles: null, + globalAriaAttributesValid: true + }, + "des-other": { + implicitRole: null, + validRoles: ["any"], + globalAriaAttributesValid: true + } + }, + "default": { + implicitRole: null, + //roleCondition: "", + validRoles: ["any"], + globalAriaAttributesValid: true + } + }; // end of documentConformanceRequirementSpecialTags + // map aria attribute to the corresponding native attribute, apply to any element applicable + // note this mapping is for the related attributes in the same element without checking the parent tree. + // refer to https://w3c.github.io/html-aria/ + ARIADefinitions.relatedAriaHtmlAttributes = { + "aria-checked": { + conflict: [{ + ariaAttributeValue: "false", + htmlAttributeNames: ["checked"], + htmlAttributeValues: null + }], + overlapping: [{ + ariaAttributeValue: "true", + htmlAttributeNames: ["checked"], + htmlAttributeValues: null + }] + }, + "aria-disabled": { + conflict: [{ + ariaAttributeValue: "false", + htmlAttributeNames: ["disabled"], + htmlAttributeValues: null + }], + overlapping: [{ + ariaAttributeValue: "true", + htmlAttributeNames: ["disabled"], + htmlAttributeValues: null + }] + }, + "aria-hidden": { + conflict: [{ + ariaAttributeValue: "false", + htmlAttributeNames: ["hidden"], + htmlAttributeValues: ["hidden,null"] + }, + { + ariaAttributeValue: "true", + htmlAttributeNames: ["hidden"], + htmlAttributeValues: ["until-found"] + }], + overlapping: [{ + ariaAttributeValue: "true", + htmlAttributeNames: ["hidden"], + htmlAttributeValues: ["hidden,null"] + }] + }, + "aria-placeholder": { + conflict: [{ + ariaAttributeValue: null, + htmlAttributeNames: ["placeholder"], + htmlAttributeValues: null + }] + }, + "aria-valuemax": { + conflict: [{ + ariaAttributeValue: null, + htmlAttributeNames: ["max"], + htmlAttributeValues: null + }] + //overlap case covered in the role definition: Authors SHOULD NOT use aria-valuemax on any element which allows the max attribute. Use the max attribute instead. + }, + "aria-valuemin": { + conflict: [{ + ariaAttributeValue: null, + htmlAttributeNames: ["min"], + htmlAttributeValues: null + }] + ////overlap case covered in the role definition:Authors SHOULD NOT use aria-valuemin on any element which allows the min attribute. Use the min attribute instead. + }, + "aria-readonly": { + conflict: [{ + ariaAttributeValue: "false", + htmlAttributeNames: ["readonly", "contenteditable", "iscontenteditable"], + htmlAttributeValues: [null, "false", "false"] + }], + overlapping: [{ + ariaAttributeValue: "true", + htmlAttributeNames: ["readonly", "contenteditable", "iscontenteditable"], + htmlAttributeValues: [null, "true", "true"] + }] + }, + "aria-required": { + conflict: [{ + ariaAttributeValue: "false", + htmlAttributeNames: ["required"], + htmlAttributeValues: null + }], + overlapping: [{ + ariaAttributeValue: "true", + htmlAttributeNames: ["required"], + htmlAttributeValues: null + }] + }, + "aria-colspan": { + conflict: [{ + // conflict occurs if both values are different + ariaAttributeValue: "VALUE", + htmlAttributeNames: ["colspan"], + htmlAttributeValues: ["VALUE"] + }], + overlapping: [{ + // overlap occurs if both exists + ariaAttributeValue: null, + htmlAttributeNames: ["colspan"], + htmlAttributeValues: null + }] + }, + "aria-rowspan": { + conflict: [{ + // conflict occurs if both values are different + ariaAttributeValue: "VALUE", + htmlAttributeNames: ["rowspan"], + htmlAttributeValues: ["VALUE"] + }], + overlapping: [{ + // overlap occurs if both exists + ariaAttributeValue: null, + htmlAttributeNames: ["rowspan"], + htmlAttributeValues: null + }] + }, + "aria-autocomplete": { + conflict: [{ + // conflict occurs if both exists, aria value is only for custom widget, rather than native + ariaAttributeValue: null, + htmlAttributeNames: ["autocomplete"], + htmlAttributeValues: null + }] + } + }; + ARIADefinitions.containers = []; + return ARIADefinitions; +}()); +exports.ARIADefinitions = ARIADefinitions; +; +var containerArray = []; +for (var roleDesign in ARIADefinitions.designPatterns) { + var containers = ARIADefinitions.designPatterns[roleDesign].container; + if (containers !== null) { + for (var _i = 0, containers_1 = containers; _i < containers_1.length; _i++) { + var container = containers_1[_i]; + if (containerArray.indexOf(container) == -1) { + containerArray.push(container); + } + } + } +} +ARIADefinitions.containers = containerArray; + + +/***/ }), + +/***/ "./src/v2/aria/ARIAMapper.ts": +/*!***********************************!*\ + !*** ./src/v2/aria/ARIAMapper.ts ***! + \***********************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ARIAMapper = void 0; +var ARIADefinitions_1 = __webpack_require__(/*! ./ARIADefinitions */ "./src/v2/aria/ARIADefinitions.ts"); +var CommonMapper_1 = __webpack_require__(/*! ../common/CommonMapper */ "./src/v2/common/CommonMapper.ts"); +var DOMUtil_1 = __webpack_require__(/*! ../dom/DOMUtil */ "./src/v2/dom/DOMUtil.ts"); +var legacy_1 = __webpack_require__(/*! ../checker/accessibility/util/legacy */ "./src/v2/checker/accessibility/util/legacy.ts"); +var fragment_1 = __webpack_require__(/*! ../checker/accessibility/util/fragment */ "./src/v2/checker/accessibility/util/fragment.ts"); +var ARIAWalker_1 = __webpack_require__(/*! ./ARIAWalker */ "./src/v2/aria/ARIAWalker.ts"); +var CacheUtil_1 = __webpack_require__(/*! ../../v4/util/CacheUtil */ "./src/v4/util/CacheUtil.ts"); +var DOMWalker_1 = __webpack_require__(/*! ../dom/DOMWalker */ "./src/v2/dom/DOMWalker.ts"); +var ARIAMapper = /** @class */ (function (_super) { + __extends(ARIAMapper, _super); + function ARIAMapper() { + return _super !== null && _super.apply(this, arguments) || this; + } + ARIAMapper.prototype.childrenCanHaveRole = function (node, role) { + // if (node.nodeType === 1 /* Node.ELEMENT_NODE */) { + // const elem = node as Element; + // if (elem.getAttribute("aria-hidden") === "true") { + // return false; + // } + // } + return !(role in ARIADefinitions_1.ARIADefinitions.designPatterns && ARIADefinitions_1.ARIADefinitions.designPatterns[role].presentationalChildren); + }; + ARIAMapper.prototype.getRole = function (node) { + var role = ARIAMapper.nodeToRole(node); + return role; + }; + ARIAMapper.prototype.getNamespace = function () { + return "aria"; + }; + ARIAMapper.prototype.getAttributes = function (node) { + var retVal = {}; + if (node.nodeType === 1 /* Node.ELEMENT_NODE */) { + var elem_1 = node; + for (var idx = 0; idx < elem_1.attributes.length; ++idx) { + var attrInfo = elem_1.attributes[idx]; + var name_1 = attrInfo.name.toLowerCase(); + if (name_1.startsWith("aria-")) { + retVal[name_1.substring(5)] = attrInfo.nodeValue; + } + } + var applyAttrRole = function (nodeName) { + if (!(nodeName in ARIAMapper.elemAttrValueCalculators)) + return; + for (var attr in ARIAMapper.elemAttrValueCalculators[nodeName]) { + if (!(attr in retVal)) { + var value = ARIAMapper.elemAttrValueCalculators[nodeName][attr]; + if (typeof value != "undefined" && value !== null) { + if (typeof value !== typeof "") { + value = value(elem_1); + } + retVal[attr] = value; + } + } + } + }; + applyAttrRole("global"); + applyAttrRole(node.nodeName.toLowerCase()); + } + else if (node.nodeType === 3 /* Node.TEXT_NODE */) { + for (var attr in ARIAMapper.textAttrValueCalculators) { + var val = ARIAMapper.textAttrValueCalculators[attr](node); + if (typeof val != "undefined" && val !== null) { + retVal[attr] = val; + } + } + } + return retVal; + }; + ARIAMapper.getAriaOwnedBy = function (elem) { + var doc = fragment_1.FragmentUtil.getOwnerFragment(elem); + if (!(0, CacheUtil_1.getCache)(doc, "ARIAMapper::precalcOwned", false)) { + var owners = doc.querySelectorAll("[aria-owns]"); + for (var iOwner = 0; iOwner < owners.length; ++iOwner) { + var owner = owners[iOwner]; + var ownIds = owner.getAttribute("aria-owns").split(/ +/g); + for (var iId = 0; iId < ownIds.length; ++iId) { + var owned = doc.getElementById(ownIds[iId]); + //ignore if the aria-owns point to the element itself + if (owned && !DOMUtil_1.DOMUtil.sameNode(owner, owned)) { + (0, CacheUtil_1.setCache)(owned, "aria-owned", owner); + } + } + } + (0, CacheUtil_1.setCache)(doc, "ARIAMapper::precalcOwned", true); + } + return (0, CacheUtil_1.getCache)(elem, "aria-owned", null); + }; + ARIAMapper.prototype.getNodeHierarchy = function (node) { + if (!node) + return []; + if (node.nodeType !== 1) { + var parentHierarchy = this.getNodeHierarchy(DOMWalker_1.DOMWalker.parentElement(node)); + var parentInfo = parentHierarchy.length > 0 ? parentHierarchy[parentHierarchy.length - 1] : { + role: "", + rolePath: "", + roleCount: {}, + childrenCanHaveRole: true + }; + var nodeHierarchy = []; + // Set hierarchy + for (var _i = 0, parentHierarchy_1 = parentHierarchy; _i < parentHierarchy_1.length; _i++) { + var item = parentHierarchy_1[_i]; + nodeHierarchy.push(item); + } + nodeHierarchy.push({ + attributes: {}, + bounds: this.getBounds(node), + namespace: this.getNamespace(), + node: node, + role: this.getRole(node) || "none", + rolePath: parentInfo.rolePath + "/" + (this.getRole(node) || "none"), + roleCount: {}, + childrenCanHaveRole: parentInfo.childrenCanHaveRole + }); + return nodeHierarchy; + } + else { + var elem = node; + var nodeHierarchy = (0, CacheUtil_1.getCache)(elem, "ARIAMapper::getNodeHierarchy", null); + if (!nodeHierarchy) { + // This element hasn't been processed yet - but ::reset processes them all in the right order + // Get details about the correct parent first + var parent_1 = ARIAMapper.getAriaOwnedBy(elem); + if (!parent_1) { + parent_1 = DOMWalker_1.DOMWalker.parentElement(elem); + } + while (parent_1 && parent_1.nodeType !== 1) { + parent_1 = DOMWalker_1.DOMWalker.parentElement(elem); + } + var parentHierarchy = parent_1 ? this.getNodeHierarchy(parent_1) : []; + var parentInfo = parentHierarchy.length > 0 ? parentHierarchy[parentHierarchy.length - 1] : { + role: "", + rolePath: "", + roleCount: {}, + childrenCanHaveRole: true + }; + while (parentInfo.role === "none" || parentInfo.role === "/none") { + parent_1 = ARIAMapper.getAriaOwnedBy(parent_1) || DOMWalker_1.DOMWalker.parentElement(parent_1); + parentHierarchy = parent_1 ? this.getNodeHierarchy(parent_1) : []; + parentInfo = parentHierarchy[parentHierarchy.length - 1]; + } + // Set initial node info + var nodeInfo = { + attributes: elem.nodeType === 1 ? this.getAttributes(elem) : {}, + bounds: this.getBounds(elem), + namespace: this.getNamespace(), + node: elem, + role: this.getRole(elem) || "none", + rolePath: "", + roleCount: {}, + childrenCanHaveRole: true + }; + // Adjust role if we're within a presentational container + var presentationalContainer = !parentInfo.childrenCanHaveRole; + if (presentationalContainer) { + nodeInfo.role = "none"; + } + else { + nodeInfo.childrenCanHaveRole = parentInfo.childrenCanHaveRole + && this.childrenCanHaveRole(elem, nodeInfo.role); + } + // Set the paths + if (nodeInfo.role !== "none") { + parentInfo.roleCount[nodeInfo.role] = (parentInfo.roleCount[nodeInfo.role] || 0) + 1; + nodeInfo.rolePath = parentInfo.rolePath + "/" + nodeInfo.role + "[" + parentInfo.roleCount[nodeInfo.role] + "]"; + } + else { + nodeInfo.rolePath = parentInfo.rolePath; + } + // Set hierarchy + nodeHierarchy = []; + for (var _a = 0, parentHierarchy_2 = parentHierarchy; _a < parentHierarchy_2.length; _a++) { + var item = parentHierarchy_2[_a]; + nodeHierarchy.push(item); + } + nodeHierarchy.push(nodeInfo); + (0, CacheUtil_1.setCache)(elem, "ARIAMapper::getNodeHierarchy", nodeHierarchy); + } + return nodeHierarchy; + } + }; + ARIAMapper.prototype.reset = function (node) { + ARIAMapper.nameComputationId = 0; + this.hierarchyRole = []; + this.hierarchyResults = []; + this.hierarchyPath = [{ + rolePath: "", + roleCount: {} + }]; + // Get to the topmost node + var goodNode = node; + var next; + while (next = DOMWalker_1.DOMWalker.parentNode(goodNode)) { + goodNode = next; + } + ; + // Walk the tree and set the hierarchies in the right order + var ariaWalker = new ARIAWalker_1.ARIAWalker(goodNode, false, goodNode); + do { + if (ariaWalker.node.nodeType === 1) { + this.getNodeHierarchy(ariaWalker.node); + } + } while (ariaWalker.nextNode()); + }; + ARIAMapper.prototype.openScope = function (node) { + if (this.hierarchyRole === null) { + this.reset(node); + } + this.pushHierarchy(node); + for (var idx = 0; idx < this.hierarchyResults.length; ++idx) { + if (this.hierarchyResults[idx].role[0] === "/") { + this.hierarchyResults[idx].role = this.hierarchyResults[idx].role.substring(1); + } + } + return this.hierarchyResults; + }; + ARIAMapper.prototype.pushHierarchy = function (node) { + // If we're not an element, no special handling + var nodeHierarchy = []; + // Determine our node info + nodeHierarchy = this.getNodeHierarchy(node); + var nodeInfo = nodeHierarchy[nodeHierarchy.length - 1]; + this.hierarchyRole.push(nodeInfo.role); + if (nodeInfo.role !== "none") { + this.hierarchyPath.push(nodeInfo); + } + this.hierarchyResults = nodeHierarchy; + }; + ARIAMapper.prototype.closeScope = function (node) { + var retVal = []; + for (var _i = 0, _a = this.hierarchyResults; _i < _a.length; _i++) { + var res = _a[_i]; + // const temp = res.node; + // res.node = null; + // let cloned = JSON.parse(JSON.stringify(res)); + // cloned.node = res.node = temp; + // retVal.push(cloned); + retVal.push(res); + } + if (retVal.length > 0) { + retVal[retVal.length - 1].role = "/" + retVal[retVal.length - 1].role; + var parent_2 = DOMWalker_1.DOMWalker.parentElement(node); + this.hierarchyResults = parent_2 ? (0, CacheUtil_1.getCache)(parent_2, "ARIAMapper::getNodeInfo", []) : []; + } + return retVal; + }; + ARIAMapper.computeName = function (cur) { + ++ARIAMapper.nameComputationId; + return ARIAMapper.computeNameHelp(ARIAMapper.nameComputationId, cur, false, false); + }; + ARIAMapper.computeNameHelp = function (walkId, cur, labelledbyTraverse, walkTraverse) { + // 2g. None of the other content applies to text nodes, so just do this first + if (cur.nodeType === 3 /* Node.TEXT_NODE */) + return cur.nodeValue; + if (cur.nodeType === 11) + return ""; + if (cur.nodeType !== 1 /* Node.ELEMENT_NODE */) { + if (walkTraverse || labelledbyTraverse) + return ""; + throw new Error("Can only compute name on Element and Text " + cur.nodeType); + } + var elem = cur; + // We've been here before - prevent recursion + if ((0, CacheUtil_1.getCache)(elem, "data-namewalk", null) === "" + walkId) + return ""; + (0, CacheUtil_1.setCache)(elem, "data-namewalk", "" + walkId); + // See https://www.w3.org/TR/html-aam-1.0/#input-type-text-input-type-password-input-type-search-input-type-tel-input-type-url-and-textarea-element + // 2a. Only show hidden content if it's referenced by a labelledby + if (!labelledbyTraverse && !DOMWalker_1.DOMWalker.isNodeVisible(cur)) { + return ""; + } + // 2b. collect valid id references + if (!labelledbyTraverse && elem.hasAttribute("aria-labelledby")) { + var labelledby = elem.getAttribute("aria-labelledby").split(" "); + var validElems = []; + for (var _i = 0, labelledby_1 = labelledby; _i < labelledby_1.length; _i++) { + var ref = labelledby_1[_i]; + var refElem = fragment_1.FragmentUtil.getById(cur, ref); + if (refElem && !DOMUtil_1.DOMUtil.sameNode(elem, refElem)) { + validElems.push(refElem); + } + } + if (validElems.length > 0) { + var accumulated = ""; + for (var _a = 0, validElems_1 = validElems; _a < validElems_1.length; _a++) { + var elem_2 = validElems_1[_a]; + accumulated += " " + this.computeNameHelp(walkId, elem_2, true, false); + } + return accumulated.trim(); + } + } + // Since nodeToRole calls back here for form and section, we need special casing here to handle those two cases + if (["section", "form"].includes(cur.nodeName.toLowerCase())) { + if (elem.hasAttribute("aria-label") && elem.getAttribute("aria-label").trim().length > 0) { + // If I'm not an embedded control or I'm not recursing, return the aria-label + if (!labelledbyTraverse && !walkTraverse) { + return elem.getAttribute("aria-label").trim(); + } + } + if (elem.hasAttribute("title")) { + return elem.getAttribute("title"); + } + return ""; + } + // 2c. If label or walk, and this is a control, skip to the value, otherwise provide the label + var role = ARIAMapper.nodeToRole(cur); + var isEmbeddedControl = [ + "textbox", "button", "combobox", "listbox", + "progressbar", "scrollbar", "slider", "spinbutton" + ].includes(role); + if (elem.hasAttribute("aria-label") && elem.getAttribute("aria-label").trim().length > 0) { + // If I'm not an embedded control or I'm not recursing, return the aria-label + if (!labelledbyTraverse && !walkTraverse || !isEmbeddedControl) { + return elem.getAttribute("aria-label").trim(); + } + } + // 2d. + if (role !== "presentation" && role !== "none") { + if ((cur.nodeName.toLowerCase() === "img" || cur.nodeName.toLowerCase() === "area") && elem.hasAttribute("alt")) { + return DOMUtil_1.DOMUtil.cleanWhitespace(elem.getAttribute("alt")).trim(); + } + if (cur.nodeName.toLowerCase() === "input" && elem.hasAttribute("id") && elem.getAttribute("id").length > 0) { + var label = elem.ownerDocument.querySelector("label[for='" + elem.getAttribute("id") + "']"); + if (label) { + if (label.hasAttribute("aria-label") || (label.hasAttribute("aria-labelledby") && !legacy_1.RPTUtil.isIdReferToSelf(cur, label.getAttribute("aria-labelledby")))) { + return this.computeNameHelp(walkId, label, false, false); + } + else { + return label.textContent; + } + } + } + if (cur.nodeName.toLowerCase() === "fieldset") { + if (cur.querySelector("legend")) { + var legend = cur.querySelector("legend"); + return legend.innerText; + } + else { + return this.computeNameHelp(walkId, cur, false, false); + } + } + } + // 2e. + if ((walkTraverse || labelledbyTraverse) && isEmbeddedControl) { + // If the embedded control has role textbox, return its value. + if (role === "textbox") { + if (elem.nodeName.toLowerCase() === "input") { + if (elem.hasAttribute("value")) + return elem.getAttribute("value"); + } + else { + walkTraverse = false; + } + } + // If the embedded control has role button, return the text alternative of the button. + if (role === "button") { + if (elem.nodeName.toLowerCase() === "input") { + var type = elem.getAttribute("type").toLowerCase(); + if (["button", "submit", "reset"].includes(type)) { + if (elem.hasAttribute("value")) + return elem.getAttribute("value"); + if (type === "submit") + return "Submit"; + if (type === "reset") + return "Reset"; + } + } + else { + walkTraverse = false; + } + } + // TODO: If the embedded control has role combobox or listbox, return the text alternative of the chosen option. + if (role === "combobox") { + if (elem.hasAttribute("aria-activedescendant")) { + var selected = fragment_1.FragmentUtil.getById(elem, "aria-activedescendant"); + if (selected && !DOMUtil_1.DOMUtil.sameNode(elem, selected)) { + return ARIAMapper.computeNameHelp(walkId, selected, false, false); + } + } + } + // If the embedded control has role range (e.g., a spinbutton or slider): + if (["progressbar", "scrollbar", "slider", "spinbutton"].includes(role)) { + // If the aria-valuetext property is present, return its value, + if (elem.hasAttribute("aria-valuetext")) + return elem.getAttribute("aria-valuetext"); + // Otherwise, if the aria-valuenow property is present, return its value, + if (elem.hasAttribute("aria-valuenow")) + return elem.getAttribute("aria-valuenow"); + // TODO: Otherwise, use the value as specified by a host language attribute. + } + } + // 2f. 2h. + if (walkTraverse || ARIADefinitions_1.ARIADefinitions.nameFromContent(role) || labelledbyTraverse) { + // 2fi. Set the accumulated text to the empty string. + var accumulated = ""; + // 2fii. Check for CSS generated textual content associated with the current node and + // include it in the accumulated text. The CSS :before and :after pseudo elements [CSS2] + // can provide textual content for elements that have a content model. + // For :before pseudo elements, User agents MUST prepend CSS textual content, without + // a space, to the textual content of the current node. + // For :after pseudo elements, User agents MUST append CSS textual content, without a + // space, to the textual content of the current node. + var before = null; + before = elem.ownerDocument.defaultView.getComputedStyle(elem, "before").content; + if (before && before !== "none") { + before = before.replace(/^"/, "").replace(/"$/, ""); + accumulated += before; + } + // 2fiii. For each child node of the current node: + // Set the current node to the child node. + // Compute the text alternative of the current node beginning with step 2. Set the result + // to that text alternative. + // Append the result to the accumulated text. + if (elem.nodeName.toUpperCase() === "SLOT") { + //if no assignedNode, check its own text + if (!elem.assignedNodes() || elem.assignedNodes().length === 0) { + var innerText = legacy_1.RPTUtil.getInnerText(elem); + if (innerText && innerText !== null && innerText.trim().length > 0) + accumulated += " " + innerText; + } + else { + // check text from all assigned nodes + for (var _b = 0, _c = elem.assignedNodes(); _b < _c.length; _b++) { + var slotChild = _c[_b]; + var nextChildContent = ARIAMapper.computeNameHelp(walkId, slotChild, labelledbyTraverse, true); + accumulated += " " + nextChildContent; + } + } + } + else { + var walkChild = elem.firstChild; + while (walkChild) { + var nextChildContent = ARIAMapper.computeNameHelp(walkId, walkChild, labelledbyTraverse, true); + accumulated += " " + nextChildContent; + walkChild = walkChild.nextSibling; + } + } + var after = null; + try { + after = elem.ownerDocument.defaultView.getComputedStyle(elem, "after").content; + } + catch (e) { } + if (after && after !== "none") { + after = after.replace(/^"/, "").replace(/"$/, ""); + accumulated += after; + } + // 2fiv. Return the accumulated text. + accumulated = accumulated.replace(/\s+/g, " ").trim(); + if (accumulated.trim().length > 0) { + return accumulated; + } + } + // 2i. Otherwise, if the current node has a Tooltip attribute, return its value. + if (elem.hasAttribute("title")) { + return elem.getAttribute("title"); + } + if (elem.tagName.toLowerCase() === "svg") { + var title = elem.querySelector("title"); + if (title) { + return title.textContent || title.innerText; + } + } + return ""; + }; + /* if (role in ARIADefinitions.designPatterns + && ARIADefinitions.designPatterns[role].nameFrom + && ARIADefinitions.designPatterns[role].nameFrom.includes("contents")) + { + name = elem.textContent; + } + if (elem.nodeName.toLowerCase() === "input" && elem.hasAttribute("id") && elem.getAttribute("id").trim().length > 0) { + name = elem.ownerDocument.querySelector("label[for='"+elem.getAttribute("id").trim()+"']").textContent; + } + if (elem.hasAttribute("aria-label")) { + name = elem.getAttribute("aria-label"); + } + if (elem.hasAttribute("aria-labelledby")) { + name = ""; + const ids = elem.getAttribute("aria-labelledby").split(" "); + for (const id of ids) { + name += FragmentUtil.getById(elem, id).textContent + " "; + } + name = name.trim(); + } + return name; + }*/ + ARIAMapper.nodeToRole = function (node) { + if (node.nodeType === 3 /* Node.TEXT_NODE */) { + return "text"; + } + else if (node.nodeType !== 1 /* Node.ELEMENT_NODE */) { + return null; + } + var elem = node; + if (!elem || elem.nodeType !== 1 /* Node.ELEMENT_NODE */) { + return null; + } + if (elem.hasAttribute("role") && elem.getAttribute("role").trim().length > 0) { + var roleStr = elem.getAttribute("role").trim(); + var roles_2 = roleStr.split(" "); + for (var _i = 0, roles_1 = roles_2; _i < roles_1.length; _i++) { + var role = roles_1[_i]; + if (role === "presentation" || role === "none") { + // If element is focusable, then presentation roles are to be ignored + if (!legacy_1.RPTUtil.isFocusable(elem)) { + return null; + } + } + else if (role in ARIADefinitions_1.ARIADefinitions.designPatterns) { + return role; + } + } + } + //return this.elemToImplicitRole(elem); + var roles = legacy_1.RPTUtil.getImplicitRole(elem); + return !roles || roles.length === 0 ? null : roles[0]; + }; + //////////////////////////////////////////////////////////////////////////// + // Helper functions + //// + // https://www.w3.org/TR/html-aam-1.0/#mapping-html-to-accessibility-apis + ARIAMapper.elemAttrValueCalculators = { + "global": { + "name": ARIAMapper.computeName + }, + "datalist": { + // set to "true" if the datalist's selection model allows multiple option elements to be + // selected at a time, and "false" otherwise + "multiselectable": function (elem) { + var id = elem.getAttribute("id"); + if (id && id.length > 0) { + var input = elem.ownerDocument.querySelector("input[list='" + id + "']"); + return "" + (elem.getAttribute("multiple") + && (elem.getAttribute("multiple") == "true" || elem.getAttribute("multiple") == "")); + } + return null; + } + }, + "h1": { + "level": "1" + }, + "h2": { + "level": "2" + }, + "h3": { + "level": "3" + }, + "h4": { + "level": "4" + }, + "h5": { + "level": "5" + }, + "h6": { + "level": "6" + }, + "input": { + // - type="checkbox" state set to "mixed" if the element's indeterminate IDL attribute + // is true, or "true" if the element's checkedness is true, or "false" otherwise + // - type="radio" state set to "true" if the element's checkedness is true, or "false" + // otherwise. + "checked": function (elem) { + if (elem.getAttribute("type") === "checkbox" || elem.getAttribute("type") === "radio") { + return "" + elem.checked; + } + return null; + } + // - type="radio" and not in menu reflecting number of type=radio input elements + // within the radio button group + , + "setsize": function (elem) { return null; throw new Error("NOT IMPLEMENTED"); } + // - type="radio" and not in menu value reflecting the elements position + // within the radio button group." + , + "posinset": function (elem) { return null; throw new Error("NOT IMPLEMENTED"); } + // input (type attribute in the Text, Search, Telephone, URL, or E-mail states with a + // suggestions source element) combobox role, with the aria-owns property set to the same + // value as the list attribute + , + "owns": function (elem) { return null; throw new Error("NOT IMPLEMENTED"); } + }, + "keygen": { + "multiselectable": "false" + }, + "li": { + // Number of li elements within the ol, ul, menu + "setsize": function (elem) { + var parent = DOMUtil_1.DOMUtil.getAncestor(elem, ["ol", "ul", "menu"]); + if (!parent) + return null; + var lis = parent.querySelectorAll("li"); + var otherlis = parent.querySelectorAll("ol li, ul li, menu li"); + return "" + (lis.length - otherlis.length); + } + // Position of li element within the ol, ul, menu + , + "posinset": function (elem) { + var parent = DOMUtil_1.DOMUtil.getAncestor(elem, ["ol", "ul", "menu"]); + if (!parent) + return null; + var lis = parent.querySelectorAll("li"); + var num = 0; + for (var idx = 0; idx < lis.length; ++idx) { + var li = lis[idx]; + if (DOMUtil_1.DOMUtil.sameNode(parent, DOMUtil_1.DOMUtil.getAncestor(li, ["ol", "ul", "menu"]))) { + return "" + num; + } + ++num; + } + return null; + } + }, + "menuitem": { + // type = checkbox or radio, set to "true" if the checked attribute + // is present, and "false" otherwise + "checked": function (elem) { return "" + !!(elem.getAttribute("checked") + && (elem.getAttribute("checked") == "true" || elem.getAttribute("checked") == "")); } + }, + "option": { + // set to "true" if the element's selectedness is true, or "false" otherwise. + "selected": function (elem) { return "" + !!(elem.getAttribute("selected") + && (elem.getAttribute("selected") == "true" || elem.getAttribute("selected") == "")); } + }, + "progress": { + "valuemax": function (elem) { return elem.getAttribute("max") || "1"; }, + "valuemin": function (elem) { return "0"; }, + "valuenow": function (elem) { return elem.getAttribute("value"); } + } + }; + ARIAMapper.textAttrValueCalculators = { + "name": function (node) { return node.nodeValue; } + }; + ARIAMapper.nameComputationId = 0; + return ARIAMapper; +}(CommonMapper_1.CommonMapper)); +exports.ARIAMapper = ARIAMapper; + + +/***/ }), + +/***/ "./src/v2/aria/ARIAWalker.ts": +/*!***********************************!*\ + !*** ./src/v2/aria/ARIAWalker.ts ***! + \***********************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ARIAWalker = void 0; +var fragment_1 = __webpack_require__(/*! ../checker/accessibility/util/fragment */ "./src/v2/checker/accessibility/util/fragment.ts"); +var DOMWalker_1 = __webpack_require__(/*! ../dom/DOMWalker */ "./src/v2/dom/DOMWalker.ts"); +var ARIAMapper_1 = __webpack_require__(/*! ./ARIAMapper */ "./src/v2/aria/ARIAMapper.ts"); +/** + * Walks in an ARIA order + * + * See also ../dom/DOMWalker + */ +var ARIAWalker = /** @class */ (function () { + function ARIAWalker(element, bEnd, root) { + this.root = root || element; + this.node = element; + this.bEndTag = (bEnd == undefined ? false : bEnd == true); + } + ARIAWalker.prototype.atRoot = function () { + if (this.ownerElement) + return false; + if (this.root === this.node) { + return true; + } + else if (this.root.isSameNode) { + return this.root.isSameNode(this.node); + } + else if (this.root.compareDocumentPosition) { + return this.root.compareDocumentPosition(this.node) === 0; + } + else { + // Not supported in this environment - try our best + return this.node.parentNode === null; + } + }; + ARIAWalker.prototype.nextNode = function () { + var skipOwned = false; + do { + skipOwned = false; + // console.log(this.node.nodeName, this.bEndTag?"END":"START", this.node.nodeType === 1 && (this.node as any).getAttribute("id")); + if (!this.bEndTag) { + var iframeNode = this.node; + var elementNode = this.node; + var slotElement = this.node; + if (this.node.nodeType === 1 /* Node.ELEMENT_NODE */ + && this.node.nodeName.toUpperCase() === "IFRAME" + && DOMWalker_1.DOMWalker.isNodeVisible(iframeNode) + && iframeNode.contentDocument + && iframeNode.contentDocument.documentElement) { + var ownerElement = this.node; + this.node = iframeNode.contentDocument.documentElement; + this.node.ownerElement = ownerElement; + } + else if (this.node.nodeType === 1 /* Node.ELEMENT_NODE */ + && DOMWalker_1.DOMWalker.isNodeVisible(elementNode) + && elementNode.shadowRoot + && elementNode.shadowRoot.firstChild) { + var ownerElement = this.node; + this.node = elementNode.shadowRoot; + this.node.ownerElement = ownerElement; + } + else if (this.node.nodeType === 1 + && elementNode.nodeName.toLowerCase() === "slot" + && slotElement.assignedNodes().length > 0) { + //TODO: need to conside its own content, a slot may have its own content or assigned content + var slotOwner = this.node; + this.node = slotElement.assignedNodes()[0]; + this.node.slotOwner = slotOwner; + this.node.slotIndex = 0; + } + else if ((this.node.nodeType === 1 /* Node.ELEMENT_NODE */ || this.node.nodeType === 11) /* Node.ELEMENT_NODE */ && this.node.firstChild) { + this.node = this.node.firstChild; + } + else { + this.bEndTag = true; + } + } + else { + if (this.atRoot()) { + return false; + } + else if (this.node.slotOwner) { + var slotOwner = this.node.slotOwner; + var nextSlotIndex = this.node.slotIndex + 1; + delete this.node.slotOwner; + delete this.node.slotIndex; + if (nextSlotIndex < slotOwner.assignedNodes().length) { + this.node = slotOwner.assignedNodes()[nextSlotIndex]; + this.node.slotOwner = slotOwner; + this.node.slotIndex = nextSlotIndex; + this.bEndTag = false; + } + else { + this.node = slotOwner; + this.bEndTag = true; + } + } + else if (this.node.ownerElement) { + this.node = this.node.ownerElement; + this.bEndTag = true; + } + else if (this.node.nextSibling) { + this.node = this.node.nextSibling; + this.bEndTag = false; + skipOwned = true; + } + else if (this.node.parentNode) { + if (this.node.parentNode.nodeType === 1 && this.node.parentNode.hasAttribute("aria-owns")) { + var ownIds = this.node.parentNode.getAttribute("aria-owns").split(/ +/g); + if (this.node.nodeType !== 1 || !this.node.hasAttribute("id")) { + this.node = fragment_1.FragmentUtil.getOwnerFragment(this.node).getElementById(ownIds[0]); + this.bEndTag = false; + } + else { + var idx = ownIds.indexOf(this.node.getAttribute("id")); + if (idx === ownIds.length - 1) { + // last one + this.node = this.node.parentNode; + this.bEndTag = true; + } + else { + // grab next + this.node = fragment_1.FragmentUtil.getOwnerFragment(this.node).getElementById(ownIds[idx + 1]); + this.bEndTag = false; + } + } + } + this.node = this.node.parentNode; + this.bEndTag = true; + } + else { + return false; + } + } + } while ((this.node.nodeType !== 1 /* Node.ELEMENT_NODE */ && this.node.nodeType !== 11 && this.node.nodeType !== 3 /* Node.TEXT_NODE */) + || (this.node.nodeType === 1 && this.node.getAttribute("aChecker") === "ACE") + || (skipOwned && this.node.nodeType === 1 && !!ARIAMapper_1.ARIAMapper.getAriaOwnedBy(this.node))); + return true; + }; + ARIAWalker.prototype.prevNode = function () { + do { + if (this.bEndTag) { + var iframeNode = this.node; + var elementNode = this.node; + if (this.node.nodeType === 1 /* Node.ELEMENT_NODE */ + && this.node.nodeName.toUpperCase() === "IFRAME" + && DOMWalker_1.DOMWalker.isNodeVisible(iframeNode) + && iframeNode.contentDocument + && iframeNode.contentDocument.documentElement) { + var ownerElement = this.node; + this.node = iframeNode.contentDocument.documentElement; + this.node.ownerElement = ownerElement; + } + else if (this.node.nodeType === 1 /* Node.ELEMENT_NODE */ + && DOMWalker_1.DOMWalker.isNodeVisible(elementNode) + && elementNode.shadowRoot + && elementNode.shadowRoot.lastChild) { + var ownerElement = this.node; + this.node = elementNode.shadowRoot; + this.node.ownerElement = ownerElement; + } + else if ((this.node.nodeType === 1 /* Node.ELEMENT_NODE */ || this.node.nodeType === 11) && this.node.lastChild) { + this.node = this.node.lastChild; + } + else { + this.bEndTag = false; + } + } + else { + if (this.atRoot()) { + return false; + } + else if (this.node.previousSibling) { + this.node = this.node.previousSibling; + this.bEndTag = true; + } + else if (this.node.ownerElement) { + this.node = this.node.ownerElement; + this.bEndTag = false; + } + else if (this.node.parentNode) { + this.node = this.node.parentNode; + this.bEndTag = false; + } + else { + return false; + } + } + } while ((this.node.nodeType !== 1 /* Node.ELEMENT_NODE */ && this.node.nodeType !== 11) + || (this.node.nodeType === 1 && this.node.getAttribute("aChecker") === "ACE")); + return true; + }; + return ARIAWalker; +}()); +exports.ARIAWalker = ARIAWalker; + + +/***/ }), + +/***/ "./src/v2/checker/accessibility/util/ancestor.ts": +/*!*******************************************************!*\ + !*** ./src/v2/checker/accessibility/util/ancestor.ts ***! + \*******************************************************/ +/***/ ((__unused_webpack_module, exports) => { + + +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AncestorUtil = void 0; +var AncestorUtil = /** @class */ (function () { + function AncestorUtil() { + } + AncestorUtil.isPresentationFrame = function (contextHierarchy) { + if (contextHierarchy && contextHierarchy.dom) { + // Skip current node because we want ancestry + for (var idx = contextHierarchy.dom.length - 2; idx >= 0; --idx) { + var elem = contextHierarchy.dom[idx].node; + if (elem.nodeType === 1 + && elem.nodeName.toLowerCase() === "iframe" + && (elem.getAttribute("role") === "presentation" || elem.getAttribute("aria-hidden") === "true")) { + return true; + } + } + } + return false; + }; + AncestorUtil.isFrame = function (contextHierarchy) { + if (contextHierarchy && contextHierarchy.dom) { + // Skip current node because we want ancestry + for (var idx = contextHierarchy.dom.length - 2; idx >= 0; --idx) { + var elem = contextHierarchy.dom[idx].node; + if (elem.nodeType === 1 && elem.nodeName.toLowerCase() === "iframe") { + return true; + } + } + } + return false; + }; + return AncestorUtil; +}()); +exports.AncestorUtil = AncestorUtil; + + +/***/ }), + +/***/ "./src/v2/checker/accessibility/util/fragment.ts": +/*!*******************************************************!*\ + !*** ./src/v2/checker/accessibility/util/fragment.ts ***! + \*******************************************************/ +/***/ ((__unused_webpack_module, exports) => { + + +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.FragmentUtil = void 0; +var FragmentUtil = /** @class */ (function () { + function FragmentUtil() { + } + FragmentUtil.getOwnerFragment = function (node) { + var n = node; + while (n.parentNode && (n = n.parentNode)) { + if (n.nodeType === 11) { + return n; + } + } + return node.ownerDocument; + }; + FragmentUtil.getById = function (node, id) { + return this.getOwnerFragment(node).getElementById(id); + }; + FragmentUtil.getAncestor = function (hierarchies, elemName) { + var matches = hierarchies["dom"].filter(function (info) { return info.role === elemName; }); + return matches.length > 0 && matches[0].node || null; + }; + FragmentUtil.getAncestorWithRole = function (hierarchies, role) { + var matches = hierarchies["aria"].filter(function (info) { return info.role === role; }); + return matches.length > 0 && matches[0].node || null; + }; + return FragmentUtil; +}()); +exports.FragmentUtil = FragmentUtil; + + +/***/ }), + +/***/ "./src/v2/checker/accessibility/util/lang.ts": +/*!***************************************************!*\ + !*** ./src/v2/checker/accessibility/util/lang.ts ***! + \***************************************************/ +/***/ ((__unused_webpack_module, exports) => { + + +/****************************************************************************** + Copyright:: 2021- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.LangUtil = void 0; +// From https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry +var validPrimaryLangs = [ + ["aa", "ab", "ae", "af", "ak", "am", "an", "ar", "as", "av", "ay", "az", "aaa", "aab", "aac", "aad", "aae", "aaf", "aag", "aah", "aai", "aak", "aal", "aam", "aan", "aao", "aap", "aaq", "aas", "aat", "aau", "aav", "aaw", "aax", "aaz", "aba", "abb", "abc", "abd", "abe", "abf", "abg", "abh", "abi", "abj", "abl", "abm", "abn", "abo", "abp", "abq", "abr", "abs", "abt", "abu", "abv", "abw", "abx", "aby", "abz", "aca", "acb", "acd", "ace", "acf", "ach", "aci", "ack", "acl", "acm", "acn", "acp", "acq", "acr", "acs", "act", "acu", "acv", "acw", "acx", "acy", "acz", "ada", "adb", "add", "ade", "adf", "adg", "adh", "adi", "adj", "adl", "adn", "ado", "adp", "adq", "adr", "ads", "adt", "adu", "adw", "adx", "ady", "adz", "aea", "aeb", "aec", "aed", "aee", "aek", "ael", "aem", "aen", "aeq", "aer", "aes", "aeu", "aew", "aey", "aez", "afa", "afb", "afd", "afe", "afg", "afh", "afi", "afk", "afn", "afo", "afp", "afs", "aft", "afu", "afz", "aga", "agb", "agc", "agd", "age", "agf", "agg", "agh", "agi", "agj", "agk", "agl", "agm", "agn", "ago", "agp", "agq", "agr", "ags", "agt", "agu", "agv", "agw", "agx", "agy", "agz", "aha", "ahb", "ahg", "ahh", "ahi", "ahk", "ahl", "ahm", "ahn", "aho", "ahp", "ahr", "ahs", "aht", "aia", "aib", "aic", "aid", "aie", "aif", "aig", "aih", "aii", "aij", "aik", "ail", "aim", "ain", "aio", "aip", "aiq", "air", "ais", "ait", "aiw", "aix", "aiy", "aja", "ajg", "aji", "ajn", "ajp", "ajt", "aju", "ajw", "ajz", "akb", "akc", "akd", "ake", "akf", "akg", "akh", "aki", "akj", "akk", "akl", "akm", "ako", "akp", "akq", "akr", "aks", "akt", "aku", "akv", "akw", "akx", "aky", "akz", "ala", "alc", "ald", "ale", "alf", "alg", "alh", "ali", "alj", "alk", "all", "alm", "aln", "alo", "alp", "alq", "alr", "als", "alt", "alu", "alv", "alw", "alx", "aly", "alz", "ama", "amb", "amc", "ame", "amf", "amg", "ami", "amj", "amk", "aml", "amm", "amn", "amo", "amp", "amq", "amr", "ams", "amt", "amu", "amv", "amw", "amx", "amy", "amz", "ana", "anb", "anc", "and", "ane", "anf", "ang", "anh", "ani", "anj", "ank", "anl", "anm", "ann", "ano", "anp", "anq", "anr", "ans", "ant", "anu", "anv", "anw", "anx", "any", "anz", "aoa", "aob", "aoc", "aod", "aoe", "aof", "aog", "aoh", "aoi", "aoj", "aok", "aol", "aom", "aon", "aor", "aos", "aot", "aou", "aox", "aoz", "apa", "apb", "apc", "apd", "ape", "apf", "apg", "aph", "api", "apj", "apk", "apl", "apm", "apn", "apo", "app", "apq", "apr", "aps", "apt", "apu", "apv", "apw", "apx", "apy", "apz", "aqa", "aqc", "aqd", "aqg", "aqk", "aql", "aqm", "aqn", "aqp", "aqr", "aqt", "aqz", "arb", "arc", "ard", "are", "arh", "ari", "arj", "ark", "arl", "arn", "aro", "arp", "arq", "arr", "ars", "art", "aru", "arv", "arw", "arx", "ary", "arz", "asa", "asb", "asc", "asd", "ase", "asf", "asg", "ash", "asi", "asj", "ask", "asl", "asn", "aso", "asp", "asq", "asr", "ass", "ast", "asu", "asv", "asw", "asx", "asy", "asz", "ata", "atb", "atc", "atd", "ate", "atg", "ath", "ati", "atj", "atk", "atl", "atm", "atn", "ato", "atp", "atq", "atr", "ats", "att", "atu", "atv", "atw", "atx", "aty", "atz", "aua", "aub", "auc", "aud", "aue", "auf", "aug", "auh", "aui", "auj", "auk", "aul", "aum", "aun", "auo", "aup", "auq", "aur", "aus", "aut", "auu", "auw", "aux", "auy", "auz", "avb", "avd", "avi", "avk", "avl", "avm", "avn", "avo", "avs", "avt", "avu", "avv", "awa", "awb", "awc", "awd", "awe", "awg", "awh", "awi", "awk", "awm", "awn", "awo", "awr", "aws", "awt", "awu", "awv", "aww", "awx", "awy", "axb", "axe", "axg", "axk", "axl", "axm", "axx", "aya", "ayb", "ayc", "ayd", "aye", "ayg", "ayh", "ayi", "ayk", "ayl", "ayn", "ayo", "ayp", "ayq", "ayr", "ays", "ayt", "ayu", "ayx", "ayy", "ayz", "aza", "azb", "azc", "azd", "azg", "azj", "azm", "azn", "azo", "azt", "azz"], + ["ba", "be", "bg", "bh", "bi", "bm", "bn", "bo", "br", "bs", "baa", "bab", "bac", "bad", "bae", "baf", "bag", "bah", "bai", "baj", "bal", "ban", "bao", "bap", "bar", "bas", "bat", "bau", "bav", "baw", "bax", "bay", "baz", "bba", "bbb", "bbc", "bbd", "bbe", "bbf", "bbg", "bbh", "bbi", "bbj", "bbk", "bbl", "bbm", "bbn", "bbo", "bbp", "bbq", "bbr", "bbs", "bbt", "bbu", "bbv", "bbw", "bbx", "bby", "bbz", "bca", "bcb", "bcc", "bcd", "bce", "bcf", "bcg", "bch", "bci", "bcj", "bck", "bcl", "bcm", "bcn", "bco", "bcp", "bcq", "bcr", "bcs", "bct", "bcu", "bcv", "bcw", "bcy", "bcz", "bda", "bdb", "bdc", "bdd", "bde", "bdf", "bdg", "bdh", "bdi", "bdj", "bdk", "bdl", "bdm", "bdn", "bdo", "bdp", "bdq", "bdr", "bds", "bdt", "bdu", "bdv", "bdw", "bdx", "bdy", "bdz", "bea", "beb", "bec", "bed", "bee", "bef", "beg", "beh", "bei", "bej", "bek", "bem", "beo", "bep", "beq", "ber", "bes", "bet", "beu", "bev", "bew", "bex", "bey", "bez", "bfa", "bfb", "bfc", "bfd", "bfe", "bff", "bfg", "bfh", "bfi", "bfj", "bfk", "bfl", "bfm", "bfn", "bfo", "bfp", "bfq", "bfr", "bfs", "bft", "bfu", "bfw", "bfx", "bfy", "bfz", "bga", "bgb", "bgc", "bgd", "bge", "bgf", "bgg", "bgi", "bgj", "bgk", "bgl", "bgm", "bgn", "bgo", "bgp", "bgq", "bgr", "bgs", "bgt", "bgu", "bgv", "bgw", "bgx", "bgy", "bgz", "bha", "bhb", "bhc", "bhd", "bhe", "bhf", "bhg", "bhh", "bhi", "bhj", "bhk", "bhl", "bhm", "bhn", "bho", "bhp", "bhq", "bhr", "bhs", "bht", "bhu", "bhv", "bhw", "bhx", "bhy", "bhz", "bia", "bib", "bic", "bid", "bie", "bif", "big", "bij", "bik", "bil", "bim", "bin", "bio", "bip", "biq", "bir", "bit", "biu", "biv", "biw", "bix", "biy", "biz", "bja", "bjb", "bjc", "bjd", "bje", "bjf", "bjg", "bjh", "bji", "bjj", "bjk", "bjl", "bjm", "bjn", "bjo", "bjp", "bjq", "bjr", "bjs", "bjt", "bju", "bjv", "bjw", "bjx", "bjy", "bjz", "bka", "bkb", "bkc", "bkd", "bkf", "bkg", "bkh", "bki", "bkj", "bkk", "bkl", "bkm", "bkn", "bko", "bkp", "bkq", "bkr", "bks", "bkt", "bku", "bkv", "bkw", "bkx", "bky", "bkz", "bla", "blb", "blc", "bld", "ble", "blf", "blg", "blh", "bli", "blj", "blk", "bll", "blm", "bln", "blo", "blp", "blq", "blr", "bls", "blt", "blv", "blw", "blx", "bly", "blz", "bma", "bmb", "bmc", "bmd", "bme", "bmf", "bmg", "bmh", "bmi", "bmj", "bmk", "bml", "bmm", "bmn", "bmo", "bmp", "bmq", "bmr", "bms", "bmt", "bmu", "bmv", "bmw", "bmx", "bmy", "bmz", "bna", "bnb", "bnc", "bnd", "bne", "bnf", "bng", "bni", "bnj", "bnk", "bnl", "bnm", "bnn", "bno", "bnp", "bnq", "bnr", "bns", "bnt", "bnu", "bnv", "bnw", "bnx", "bny", "bnz", "boa", "bob", "boe", "bof", "bog", "boh", "boi", "boj", "bok", "bol", "bom", "bon", "boo", "bop", "boq", "bor", "bot", "bou", "bov", "bow", "box", "boy", "boz", "bpa", "bpb", "bpd", "bpe", "bpg", "bph", "bpi", "bpj", "bpk", "bpl", "bpm", "bpn", "bpo", "bpp", "bpq", "bpr", "bps", "bpt", "bpu", "bpv", "bpw", "bpx", "bpy", "bpz", "bqa", "bqb", "bqc", "bqd", "bqf", "bqg", "bqh", "bqi", "bqj", "bqk", "bql", "bqm", "bqn", "bqo", "bqp", "bqq", "bqr", "bqs", "bqt", "bqu", "bqv", "bqw", "bqx", "bqy", "bqz", "bra", "brb", "brc", "brd", "brf", "brg", "brh", "bri", "brj", "brk", "brl", "brm", "brn", "bro", "brp", "brq", "brr", "brs", "brt", "bru", "brv", "brw", "brx", "bry", "brz", "bsa", "bsb", "bsc", "bse", "bsf", "bsg", "bsh", "bsi", "bsj", "bsk", "bsl", "bsm", "bsn", "bso", "bsp", "bsq", "bsr", "bss", "bst", "bsu", "bsv", "bsw", "bsx", "bsy", "bta", "btb", "btc", "btd", "bte", "btf", "btg", "bth", "bti", "btj", "btk", "btl", "btm", "btn", "bto", "btp", "btq", "btr", "bts", "btt", "btu", "btv", "btw", "btx", "bty", "btz", "bua", "bub", "buc", "bud", "bue", "buf", "bug", "buh", "bui", "buj", "buk", "bum", "bun", "buo", "bup", "buq", "bus", "but", "buu", "buv", "buw", "bux", "buy", "buz", "bva", "bvb", "bvc", "bvd", "bve", "bvf", "bvg", "bvh", "bvi", "bvj", "bvk", "bvl", "bvm", "bvn", "bvo", "bvp", "bvq", "bvr", "bvt", "bvu", "bvv", "bvw", "bvx", "bvy", "bvz", "bwa", "bwb", "bwc", "bwd", "bwe", "bwf", "bwg", "bwh", "bwi", "bwj", "bwk", "bwl", "bwm", "bwn", "bwo", "bwp", "bwq", "bwr", "bws", "bwt", "bwu", "bww", "bwx", "bwy", "bwz", "bxa", "bxb", "bxc", "bxd", "bxe", "bxf", "bxg", "bxh", "bxi", "bxj", "bxk", "bxl", "bxm", "bxn", "bxo", "bxp", "bxq", "bxr", "bxs", "bxu", "bxv", "bxw", "bxx", "bxz", "bya", "byb", "byc", "byd", "bye", "byf", "byg", "byh", "byi", "byj", "byk", "byl", "bym", "byn", "byo", "byp", "byq", "byr", "bys", "byt", "byv", "byw", "byx", "byy", "byz", "bza", "bzb", "bzc", "bzd", "bze", "bzf", "bzg", "bzh", "bzi", "bzj", "bzk", "bzl", "bzm", "bzn", "bzo", "bzp", "bzq", "bzr", "bzs", "bzt", "bzu", "bzv", "bzw", "bzx", "bzy", "bzz"], + ["ca", "ce", "ch", "co", "cr", "cs", "cu", "cv", "cy", "caa", "cab", "cac", "cad", "cae", "caf", "cag", "cah", "cai", "caj", "cak", "cal", "cam", "can", "cao", "cap", "caq", "car", "cas", "cau", "cav", "caw", "cax", "cay", "caz", "cba", "cbb", "cbc", "cbd", "cbe", "cbg", "cbh", "cbi", "cbj", "cbk", "cbl", "cbn", "cbo", "cbq", "cbr", "cbs", "cbt", "cbu", "cbv", "cbw", "cby", "cca", "ccc", "ccd", "cce", "ccg", "cch", "ccj", "ccl", "ccm", "ccn", "cco", "ccp", "ccq", "ccr", "ccs", "cda", "cdc", "cdd", "cde", "cdf", "cdg", "cdh", "cdi", "cdj", "cdm", "cdn", "cdo", "cdr", "cds", "cdy", "cdz", "cea", "ceb", "ceg", "cek", "cel", "cen", "cet", "cey", "cfa", "cfd", "cfg", "cfm", "cga", "cgc", "cgg", "cgk", "chb", "chc", "chd", "chf", "chg", "chh", "chj", "chk", "chl", "chm", "chn", "cho", "chp", "chq", "chr", "cht", "chw", "chx", "chy", "chz", "cia", "cib", "cic", "cid", "cie", "cih", "cik", "cim", "cin", "cip", "cir", "ciw", "ciy", "cja", "cje", "cjh", "cji", "cjk", "cjm", "cjn", "cjo", "cjp", "cjr", "cjs", "cjv", "cjy", "cka", "ckb", "ckh", "ckl", "ckm", "ckn", "cko", "ckq", "ckr", "cks", "ckt", "cku", "ckv", "ckx", "cky", "ckz", "cla", "clc", "cld", "cle", "clh", "cli", "clj", "clk", "cll", "clm", "clo", "clt", "clu", "clw", "cly", "cma", "cmc", "cme", "cmg", "cmi", "cmk", "cml", "cmm", "cmn", "cmo", "cmr", "cms", "cmt", "cna", "cnb", "cnc", "cng", "cnh", "cni", "cnk", "cnl", "cno", "cnp", "cnr", "cns", "cnt", "cnu", "cnw", "cnx", "coa", "cob", "coc", "cod", "coe", "cof", "cog", "coh", "coj", "cok", "col", "com", "con", "coo", "cop", "coq", "cot", "cou", "cov", "cow", "cox", "coy", "coz", "cpa", "cpb", "cpc", "cpe", "cpf", "cpg", "cpi", "cpn", "cpo", "cpp", "cps", "cpu", "cpx", "cpy", "cqd", "cqu", "cra", "crb", "crc", "crd", "crf", "crg", "crh", "cri", "crj", "crk", "crl", "crm", "crn", "cro", "crp", "crq", "crr", "crs", "crt", "crv", "crw", "crx", "cry", "crz", "csa", "csb", "csc", "csd", "cse", "csf", "csg", "csh", "csi", "csj", "csk", "csl", "csm", "csn", "cso", "csp", "csq", "csr", "css", "cst", "csu", "csv", "csw", "csx", "csy", "csz", "cta", "ctc", "ctd", "cte", "ctg", "cth", "ctl", "ctm", "ctn", "cto", "ctp", "cts", "ctt", "ctu", "cty", "ctz", "cua", "cub", "cuc", "cug", "cuh", "cui", "cuj", "cuk", "cul", "cum", "cuo", "cup", "cuq", "cur", "cus", "cut", "cuu", "cuv", "cuw", "cux", "cuy", "cvg", "cvn", "cwa", "cwb", "cwd", "cwe", "cwg", "cwt", "cya", "cyb", "cyo", "czh", "czk", "czn", "czo", "czt"], + ["da", "de", "dv", "dz", "daa", "dac", "dad", "dae", "daf", "dag", "dah", "dai", "daj", "dak", "dal", "dam", "dao", "dap", "daq", "dar", "das", "dau", "dav", "daw", "dax", "day", "daz", "dba", "dbb", "dbd", "dbe", "dbf", "dbg", "dbi", "dbj", "dbl", "dbm", "dbn", "dbo", "dbp", "dbq", "dbr", "dbt", "dbu", "dbv", "dbw", "dby", "dcc", "dcr", "dda", "ddd", "dde", "ddg", "ddi", "ddj", "ddn", "ddo", "ddr", "dds", "ddw", "dec", "ded", "dee", "def", "deg", "deh", "dei", "dek", "del", "dem", "den", "dep", "deq", "der", "des", "dev", "dez", "dga", "dgb", "dgc", "dgd", "dge", "dgg", "dgh", "dgi", "dgk", "dgl", "dgn", "dgo", "dgr", "dgs", "dgt", "dgu", "dgw", "dgx", "dgz", "dha", "dhd", "dhg", "dhi", "dhl", "dhm", "dhn", "dho", "dhr", "dhs", "dhu", "dhv", "dhw", "dhx", "dia", "dib", "dic", "did", "dif", "dig", "dih", "dii", "dij", "dik", "dil", "dim", "din", "dio", "dip", "diq", "dir", "dis", "dit", "diu", "diw", "dix", "diy", "diz", "dja", "djb", "djc", "djd", "dje", "djf", "dji", "djj", "djk", "djl", "djm", "djn", "djo", "djr", "dju", "djw", "dka", "dkg", "dkk", "dkl", "dkr", "dks", "dkx", "dlg", "dlk", "dlm", "dln", "dma", "dmb", "dmc", "dmd", "dme", "dmf", "dmg", "dmk", "dml", "dmm", "dmn", "dmo", "dmr", "dms", "dmu", "dmv", "dmw", "dmx", "dmy", "dna", "dnd", "dne", "dng", "dni", "dnj", "dnk", "dnn", "dno", "dnr", "dnt", "dnu", "dnv", "dnw", "dny", "doa", "dob", "doc", "doe", "dof", "doh", "doi", "dok", "dol", "don", "doo", "dop", "doq", "dor", "dos", "dot", "dov", "dow", "dox", "doy", "doz", "dpp", "dra", "drb", "drc", "drd", "dre", "drg", "drh", "dri", "drl", "drn", "dro", "drq", "drr", "drs", "drt", "dru", "drw", "dry", "dsb", "dse", "dsh", "dsi", "dsl", "dsn", "dso", "dsq", "dta", "dtb", "dtd", "dth", "dti", "dtk", "dtm", "dtn", "dto", "dtp", "dtr", "dts", "dtt", "dtu", "dty", "dua", "dub", "duc", "dud", "due", "duf", "dug", "duh", "dui", "duj", "duk", "dul", "dum", "dun", "duo", "dup", "duq", "dur", "dus", "duu", "duv", "duw", "dux", "duy", "duz", "dva", "dwa", "dwk", "dwl", "dwr", "dws", "dwu", "dww", "dwy", "dwz", "dya", "dyb", "dyd", "dyg", "dyi", "dym", "dyn", "dyo", "dyu", "dyy", "dza", "dzd", "dze", "dzg", "dzl", "dzn"], + ["ee", "el", "en", "eo", "es", "et", "eu", "eaa", "ebc", "ebg", "ebk", "ebo", "ebr", "ebu", "ecr", "ecs", "ecy", "eee", "efa", "efe", "efi", "ega", "egl", "ego", "egx", "egy", "ehs", "ehu", "eip", "eit", "eiv", "eja", "eka", "ekc", "eke", "ekg", "eki", "ekk", "ekl", "ekm", "eko", "ekp", "ekr", "eky", "ele", "elh", "eli", "elk", "elm", "elo", "elp", "elu", "elx", "ema", "emb", "eme", "emg", "emi", "emk", "emm", "emn", "emo", "emp", "emq", "ems", "emu", "emw", "emx", "emy", "emz", "ena", "enb", "enc", "end", "enf", "enh", "enl", "enm", "enn", "eno", "enq", "enr", "enu", "env", "enw", "enx", "eot", "epi", "era", "erg", "erh", "eri", "erk", "ero", "err", "ers", "ert", "erw", "ese", "esg", "esh", "esi", "esk", "esl", "esm", "esn", "eso", "esq", "ess", "esu", "esx", "esy", "etb", "etc", "eth", "etn", "eto", "etr", "ets", "ett", "etu", "etx", "etz", "euq", "eve", "evh", "evn", "ewo", "ext", "eya", "eyo", "eza", "eze"], + ["fa", "ff", "fi", "fj", "fo", "fr", "fy", "faa", "fab", "fad", "faf", "fag", "fah", "fai", "faj", "fak", "fal", "fam", "fan", "fap", "far", "fat", "fau", "fax", "fay", "faz", "fbl", "fcs", "fer", "ffi", "ffm", "fgr", "fia", "fie", "fif", "fil", "fip", "fir", "fit", "fiu", "fiw", "fkk", "fkv", "fla", "flh", "fli", "fll", "fln", "flr", "fly", "fmp", "fmu", "fnb", "fng", "fni", "fod", "foi", "fom", "fon", "for", "fos", "fox", "fpe", "fqs", "frc", "frd", "frk", "frm", "fro", "frp", "frq", "frr", "frs", "frt", "fse", "fsl", "fss", "fub", "fuc", "fud", "fue", "fuf", "fuh", "fui", "fuj", "fum", "fun", "fuq", "fur", "fut", "fuu", "fuv", "fuy", "fvr", "fwa", "fwe"], + ["ga", "gd", "gl", "gn", "gu", "gv", "gaa", "gab", "gac", "gad", "gae", "gaf", "gag", "gah", "gai", "gaj", "gak", "gal", "gam", "gan", "gao", "gap", "gaq", "gar", "gas", "gat", "gau", "gav", "gaw", "gax", "gay", "gaz", "gba", "gbb", "gbc", "gbd", "gbe", "gbf", "gbg", "gbh", "gbi", "gbj", "gbk", "gbl", "gbm", "gbn", "gbo", "gbp", "gbq", "gbr", "gbs", "gbu", "gbv", "gbw", "gbx", "gby", "gbz", "gcc", "gcd", "gce", "gcf", "gcl", "gcn", "gcr", "gct", "gda", "gdb", "gdc", "gdd", "gde", "gdf", "gdg", "gdh", "gdi", "gdj", "gdk", "gdl", "gdm", "gdn", "gdo", "gdq", "gdr", "gds", "gdt", "gdu", "gdx", "gea", "geb", "gec", "ged", "gef", "geg", "geh", "gei", "gej", "gek", "gel", "gem", "geq", "ges", "gev", "gew", "gex", "gey", "gez", "gfk", "gft", "gfx", "gga", "ggb", "ggd", "gge", "ggg", "ggk", "ggl", "ggn", "ggo", "ggr", "ggt", "ggu", "ggw", "gha", "ghc", "ghe", "ghh", "ghk", "ghl", "ghn", "gho", "ghr", "ghs", "ght", "gia", "gib", "gic", "gid", "gie", "gig", "gih", "gii", "gil", "gim", "gin", "gio", "gip", "giq", "gir", "gis", "git", "giu", "giw", "gix", "giy", "giz", "gji", "gjk", "gjm", "gjn", "gjr", "gju", "gka", "gkd", "gke", "gkn", "gko", "gkp", "gku", "glb", "glc", "gld", "glh", "gli", "glj", "glk", "gll", "glo", "glr", "glu", "glw", "gly", "gma", "gmb", "gmd", "gme", "gmg", "gmh", "gml", "gmm", "gmn", "gmq", "gmr", "gmu", "gmv", "gmw", "gmx", "gmy", "gmz", "gna", "gnb", "gnc", "gnd", "gne", "gng", "gnh", "gni", "gnj", "gnk", "gnl", "gnm", "gnn", "gno", "gnq", "gnr", "gnt", "gnu", "gnw", "gnz", "goa", "gob", "goc", "god", "goe", "gof", "gog", "goh", "goi", "goj", "gok", "gol", "gom", "gon", "goo", "gop", "goq", "gor", "gos", "got", "gou", "gow", "gox", "goy", "goz", "gpa", "gpe", "gpn", "gqa", "gqi", "gqn", "gqr", "gqu", "gra", "grb", "grc", "grd", "grg", "grh", "gri", "grj", "grk", "grm", "gro", "grq", "grr", "grs", "grt", "gru", "grv", "grw", "grx", "gry", "grz", "gse", "gsg", "gsl", "gsm", "gsn", "gso", "gsp", "gss", "gsw", "gta", "gti", "gtu", "gua", "gub", "guc", "gud", "gue", "guf", "gug", "guh", "gui", "guk", "gul", "gum", "gun", "guo", "gup", "guq", "gur", "gus", "gut", "guu", "guv", "guw", "gux", "guz", "gva", "gvc", "gve", "gvf", "gvj", "gvl", "gvm", "gvn", "gvo", "gvp", "gvr", "gvs", "gvy", "gwa", "gwb", "gwc", "gwd", "gwe", "gwf", "gwg", "gwi", "gwj", "gwm", "gwn", "gwr", "gwt", "gwu", "gww", "gwx", "gxx", "gya", "gyb", "gyd", "gye", "gyf", "gyg", "gyi", "gyl", "gym", "gyn", "gyo", "gyr", "gyy", "gyz", "gza", "gzi", "gzn"], + ["ha", "he", "hi", "ho", "hr", "ht", "hu", "hy", "hz", "haa", "hab", "hac", "had", "hae", "haf", "hag", "hah", "hai", "haj", "hak", "hal", "ham", "han", "hao", "hap", "haq", "har", "has", "hav", "haw", "hax", "hay", "haz", "hba", "hbb", "hbn", "hbo", "hbu", "hca", "hch", "hdn", "hds", "hdy", "hea", "hed", "heg", "heh", "hei", "hem", "hgm", "hgw", "hhi", "hhr", "hhy", "hia", "hib", "hid", "hif", "hig", "hih", "hii", "hij", "hik", "hil", "him", "hio", "hir", "hit", "hiw", "hix", "hji", "hka", "hke", "hkh", "hkk", "hkn", "hks", "hla", "hlb", "hld", "hle", "hlt", "hlu", "hma", "hmb", "hmc", "hmd", "hme", "hmf", "hmg", "hmh", "hmi", "hmj", "hmk", "hml", "hmm", "hmn", "hmp", "hmq", "hmr", "hms", "hmt", "hmu", "hmv", "hmw", "hmx", "hmy", "hmz", "hna", "hnd", "hne", "hng", "hnh", "hni", "hnj", "hnn", "hno", "hns", "hnu", "hoa", "hob", "hoc", "hod", "hoe", "hoh", "hoi", "hoj", "hok", "hol", "hom", "hoo", "hop", "hor", "hos", "hot", "hov", "how", "hoy", "hoz", "hpo", "hps", "hra", "hrc", "hre", "hrk", "hrm", "hro", "hrp", "hrr", "hrt", "hru", "hrw", "hrx", "hrz", "hsb", "hsh", "hsl", "hsn", "hss", "hti", "hto", "hts", "htu", "htx", "hub", "huc", "hud", "hue", "huf", "hug", "huh", "hui", "huj", "huk", "hul", "hum", "huo", "hup", "huq", "hur", "hus", "hut", "huu", "huv", "huw", "hux", "huy", "huz", "hvc", "hve", "hvk", "hvn", "hvv", "hwa", "hwc", "hwo", "hya", "hyw", "hyx"], + ["ia", "id", "ie", "ig", "ii", "ik", "in", "io", "is", "it", "iu", "iw", "iai", "ian", "iap", "iar", "iba", "ibb", "ibd", "ibe", "ibg", "ibh", "ibi", "ibl", "ibm", "ibn", "ibr", "ibu", "iby", "ica", "ich", "icl", "icr", "ida", "idb", "idc", "idd", "ide", "idi", "idr", "ids", "idt", "idu", "ifa", "ifb", "ife", "iff", "ifk", "ifm", "ifu", "ify", "igb", "ige", "igg", "igl", "igm", "ign", "igo", "igs", "igw", "ihb", "ihi", "ihp", "ihw", "iin", "iir", "ijc", "ije", "ijj", "ijn", "ijo", "ijs", "ike", "iki", "ikk", "ikl", "iko", "ikp", "ikr", "iks", "ikt", "ikv", "ikw", "ikx", "ikz", "ila", "ilb", "ilg", "ili", "ilk", "ill", "ilm", "ilo", "ilp", "ils", "ilu", "ilv", "ilw", "ima", "ime", "imi", "iml", "imn", "imo", "imr", "ims", "imy", "inb", "inc", "ine", "ing", "inh", "inj", "inl", "inm", "inn", "ino", "inp", "ins", "int", "inz", "ior", "iou", "iow", "ipi", "ipo", "iqu", "iqw", "ira", "ire", "irh", "iri", "irk", "irn", "iro", "irr", "iru", "irx", "iry", "isa", "isc", "isd", "ise", "isg", "ish", "isi", "isk", "ism", "isn", "iso", "isr", "ist", "isu", "itb", "itc", "itd", "ite", "iti", "itk", "itl", "itm", "ito", "itr", "its", "itt", "itv", "itw", "itx", "ity", "itz", "ium", "ivb", "ivv", "iwk", "iwm", "iwo", "iws", "ixc", "ixl", "iya", "iyo", "iyx", "izh", "izi", "izr", "izz"], + ["ja", "ji", "jv", "jw", "jaa", "jab", "jac", "jad", "jae", "jaf", "jah", "jaj", "jak", "jal", "jam", "jan", "jao", "jaq", "jar", "jas", "jat", "jau", "jax", "jay", "jaz", "jbe", "jbi", "jbj", "jbk", "jbm", "jbn", "jbo", "jbr", "jbt", "jbu", "jbw", "jcs", "jct", "jda", "jdg", "jdt", "jeb", "jee", "jeg", "jeh", "jei", "jek", "jel", "jen", "jer", "jet", "jeu", "jgb", "jge", "jgk", "jgo", "jhi", "jhs", "jia", "jib", "jic", "jid", "jie", "jig", "jih", "jii", "jil", "jim", "jio", "jiq", "jit", "jiu", "jiv", "jiy", "jje", "jjr", "jka", "jkm", "jko", "jkp", "jkr", "jks", "jku", "jle", "jls", "jma", "jmb", "jmc", "jmd", "jmi", "jml", "jmn", "jmr", "jms", "jmw", "jmx", "jna", "jnd", "jng", "jni", "jnj", "jnl", "jns", "job", "jod", "jog", "jor", "jos", "jow", "jpa", "jpr", "jpx", "jqr", "jra", "jrb", "jrr", "jrt", "jru", "jsl", "jua", "jub", "juc", "jud", "juh", "jui", "juk", "jul", "jum", "jun", "juo", "jup", "jur", "jus", "jut", "juu", "juw", "juy", "jvd", "jvn", "jwi", "jya", "jye", "jyy"], + ["ka", "kg", "ki", "kj", "kk", "kl", "km", "kn", "ko", "kr", "ks", "ku", "kv", "kw", "ky", "kaa", "kab", "kac", "kad", "kae", "kaf", "kag", "kah", "kai", "kaj", "kak", "kam", "kao", "kap", "kaq", "kar", "kav", "kaw", "kax", "kay", "kba", "kbb", "kbc", "kbd", "kbe", "kbf", "kbg", "kbh", "kbi", "kbj", "kbk", "kbl", "kbm", "kbn", "kbo", "kbp", "kbq", "kbr", "kbs", "kbt", "kbu", "kbv", "kbw", "kbx", "kby", "kbz", "kca", "kcb", "kcc", "kcd", "kce", "kcf", "kcg", "kch", "kci", "kcj", "kck", "kcl", "kcm", "kcn", "kco", "kcp", "kcq", "kcr", "kcs", "kct", "kcu", "kcv", "kcw", "kcx", "kcy", "kcz", "kda", "kdc", "kdd", "kde", "kdf", "kdg", "kdh", "kdi", "kdj", "kdk", "kdl", "kdm", "kdn", "kdo", "kdp", "kdq", "kdr", "kdt", "kdu", "kdv", "kdw", "kdx", "kdy", "kdz", "kea", "keb", "kec", "ked", "kee", "kef", "keg", "keh", "kei", "kej", "kek", "kel", "kem", "ken", "keo", "kep", "keq", "ker", "kes", "ket", "keu", "kev", "kew", "kex", "key", "kez", "kfa", "kfb", "kfc", "kfd", "kfe", "kff", "kfg", "kfh", "kfi", "kfj", "kfk", "kfl", "kfm", "kfn", "kfo", "kfp", "kfq", "kfr", "kfs", "kft", "kfu", "kfv", "kfw", "kfx", "kfy", "kfz", "kga", "kgb", "kgc", "kgd", "kge", "kgf", "kgg", "kgh", "kgi", "kgj", "kgk", "kgl", "kgm", "kgn", "kgo", "kgp", "kgq", "kgr", "kgs", "kgt", "kgu", "kgv", "kgw", "kgx", "kgy", "kha", "lyg", "khb", "khc", "khd", "khe", "khf", "khg", "khh", "khi", "khj", "khk", "khl", "khn", "kho", "khp", "khq", "khr", "khs", "kht", "khu", "khv", "khw", "khx", "khy", "khz", "kia", "kib", "kic", "kid", "kie", "kif", "kig", "kih", "kii", "kij", "kil", "kim", "kio", "kip", "kiq", "kis", "kit", "kiu", "kiv", "kiw", "kix", "kiy", "kiz", "kja", "kjb", "kjc", "kjd", "kje", "kjf", "kjg", "kjh", "kji", "kjj", "kjk", "kjl", "kjm", "kjn", "kjo", "kjp", "kjq", "kjr", "kjs", "kjt", "kju", "kjv", "kjx", "kjy", "kjz", "kka", "kkb", "kkc", "kkd", "kke", "kkf", "kkg", "kkh", "kki", "kkj", "kkk", "kkl", "kkm", "kkn", "kko", "kkp", "kkq", "kkr", "kks", "kkt", "kku", "kkv", "kkw", "kkx", "kky", "kkz", "kla", "klb", "klc", "kld", "kle", "klf", "klg", "klh", "kli", "klj", "klk", "kll", "klm", "kln", "klo", "klp", "klq", "klr", "kls", "klt", "klu", "klv", "klw", "klx", "kly", "klz", "kma", "kmb", "kmc", "kmd", "kme", "kmf", "kmg", "kmh", "kmi", "kmj", "kmk", "kml", "kmm", "kmn", "kmo", "kmp", "kmq", "kmr", "kms", "kmt", "kmu", "kmv", "kmw", "kmx", "kmy", "kmz", "kna", "knb", "knc", "knd", "kne", "knf", "kng", "kni", "knj", "knk", "knl", "knm", "knn", "kno", "knp", "knq", "knr", "kns", "knt", "knu", "knv", "knw", "knx", "kny", "knz", "koa", "koc", "kod", "koe", "kof", "kog", "koh", "koi", "koj", "kok", "kol", "koo", "kop", "koq", "kos", "kot", "kou", "kov", "kow", "kox", "koy", "koz", "kpa", "kpb", "kpc", "kpd", "kpe", "kpf", "kpg", "kph", "kpi", "kpj", "kpk", "kpl", "kpm", "kpn", "kpo", "kpp", "kpq", "kpr", "kps", "kpt", "kpu", "kpv", "kpw", "kpx", "kpy", "kpz", "kqa", "kqb", "kqc", "kqd", "kqe", "kqf", "kqg", "kqh", "kqi", "kqj", "kqk", "kql", "kqm", "kqn", "kqo", "kqp", "kqq", "kqr", "kqs", "kqt", "kqu", "kqv", "kqw", "kqx", "kqy", "kqz", "kra", "krb", "krc", "krd", "kre", "krf", "krh", "kri", "krj", "krk", "krl", "krm", "krn", "kro", "krp", "krr", "krs", "krt", "kru", "krv", "krw", "krx", "kry", "krz", "ksa", "ksb", "ksc", "ksd", "kse", "ksf", "ksg", "ksh", "ksi", "ksj", "ksk", "ksl", "ksm", "ksn", "kso", "ksp", "ksq", "ksr", "kss", "kst", "ksu", "ksv", "ksw", "ksx", "ksy", "ksz", "kta", "ktb", "ktc", "ktd", "kte", "ktf", "ktg", "kth", "kti", "ktj", "ktk", "ktl", "ktm", "ktn", "kto", "ktp", "ktq", "ktr", "kts", "ktt", "ktu", "ktv", "ktw", "ktx", "kty", "ktz", "kub", "kuc", "kud", "kue", "kuf", "kug", "kuh", "kui", "kuj", "kuk", "kul", "kum", "kun", "kuo", "kup", "kuq", "kus", "kut", "kuu", "kuv", "kuw", "kux", "kuy", "kuz", "kva", "kvb", "kvc", "kvd", "kve", "kvf", "kvg", "kvh", "kvi", "kvj", "kvk", "kvl", "kvm", "kvn", "kvo", "kvp", "kvq", "kvr", "kvs", "kvt", "kvu", "kvv", "kvw", "kvx", "kvy", "kvz", "kwa", "kwb", "kwc", "kwd", "kwe", "kwf", "kwg", "kwh", "kwi", "kwj", "kwk", "kwl", "kwm", "kwn", "kwo", "kwp", "kwq", "kwr", "kws", "kwt", "kwu", "kwv", "kww", "kwx", "kwy", "kwz", "kxa", "kxb", "kxc", "kxd", "kxe", "kxf", "kxh", "kxi", "kxj", "kxk", "kxl", "kxm", "kxn", "kxo", "kxp", "kxq", "kxr", "kxs", "kxt", "kxu", "kxv", "kxw", "kxx", "kxy", "kxz", "kya", "kyb", "kyc", "kyd", "kye", "kyf", "kyg", "kyh", "kyi", "kyj", "kyk", "kyl", "kym", "kyn", "kyo", "kyp", "kyq", "kyr", "kys", "kyt", "kyu", "kyv", "kyw", "kyx", "kyy", "kyz", "kza", "kzb", "kzc", "kzd", "kze", "kzf", "kzg", "kzh", "kzi", "kzj", "kzk", "kzl", "kzm", "kzn", "kzo", "kzp", "kzq", "kzr", "kzs", "kzt", "kzu", "kzv", "kzw", "kzx", "kzy", "kzz"], + ["la", "lb", "lg", "li", "ln", "lo", "lt", "lu", "lv", "laa", "lab", "lac", "lad", "lae", "laf", "lag", "lah", "lai", "laj", "lak", "lal", "lam", "lan", "lap", "laq", "lar", "las", "lau", "law", "lax", "lay", "laz", "lba", "lbb", "lbc", "lbe", "lbf", "lbg", "lbi", "lbj", "lbk", "lbl", "lbm", "lbn", "lbo", "lbq", "lbr", "lbs", "lbt", "lbu", "lbv", "lbw", "lbx", "lby", "lbz", "lcc", "lcd", "lce", "lcf", "lch", "lcl", "lcm", "lcp", "lcq", "lcs", "lda", "ldb", "ldd", "ldg", "ldh", "ldi", "ldj", "ldk", "ldl", "ldm", "ldn", "ldo", "ldp", "ldq", "lea", "leb", "lec", "led", "lee", "lef", "leg", "leh", "lei", "lej", "lek", "lel", "lem", "len", "leo", "lep", "leq", "ler", "les", "let", "leu", "lev", "lew", "lex", "ley", "lez", "lfa", "lfn", "lga", "lgb", "lgg", "lgh", "lgi", "lgk", "lgl", "lgm", "lgn", "lgq", "lgr", "lgt", "lgu", "lgz", "lha", "lhh", "lhi", "lhl", "lhm", "lhn", "lhp", "lhs", "lht", "lhu", "lia", "lib", "lic", "lid", "lie", "lif", "lig", "lih", "lii", "lij", "lik", "lil", "lio", "lip", "liq", "lir", "lis", "liu", "liv", "liw", "lix", "liy", "liz", "lja", "lje", "lji", "ljl", "ljp", "ljw", "ljx", "lka", "lkb", "lkc", "lkd", "lke", "lkh", "lki", "lkj", "lkl", "lkm", "lkn", "lko", "lkr", "lks", "lkt", "lku", "lky", "lla", "llb", "llc", "lld", "lle", "llf", "llg", "llh", "lli", "llj", "llk", "lll", "llm", "lln", "llo", "llp", "llq", "lls", "llu", "llx", "lma", "lmb", "lmc", "lmd", "lme", "lmf", "lmg", "lmh", "lmi", "lmj", "lmk", "lml", "lmm", "lmn", "lmo", "lmp", "lmq", "lmr", "lmu", "lmv", "lmw", "lmx", "lmy", "lmz", "lna", "lnb", "lnd", "lng", "lnh", "lni", "lnj", "lnl", "lnm", "lnn", "lno", "lns", "lnu", "lnw", "lnz", "loa", "lob", "loc", "loe", "lof", "log", "loh", "loi", "loj", "lok", "lol", "lom", "lon", "loo", "lop", "loq", "lor", "los", "lot", "lou", "lov", "low", "lox", "loy", "loz", "lpa", "lpe", "lpn", "lpo", "lpx", "lra", "lrc", "lre", "lrg", "lri", "lrk", "lrl", "lrm", "lrn", "lro", "lrr", "lrt", "lrv", "lrz", "lsa", "lsb", "lsd", "lse", "lsg", "lsh", "lsi", "lsl", "lsm", "lsn", "lso", "lsp", "lsr", "lss", "lst", "lsv", "lsy", "ltc", "ltg", "lth", "lti", "ltn", "lto", "lts", "ltu", "lua", "luc", "lud", "lue", "luf", "lui", "luj", "luk", "lul", "lum", "lun", "luo", "lup", "luq", "lur", "lus", "lut", "luu", "luv", "luw", "luy", "luz", "lva", "lvi", "lvk", "lvs", "lvu", "lwa", "lwe", "lwg", "lwh", "lwl", "lwm", "lwo", "lws", "lwt", "lwu", "lww", "lxm", "lya", "lyg", "lyn", "lzh", "lzl", "lzn", "lzz"], + ["mg", "mh", "mi", "mk", "ml", "mn", "mo", "mr", "ms", "mt", "my", "maa", "mab", "mad", "mae", "maf", "mag", "mai", "maj", "mak", "mam", "man", "map", "maq", "mas", "mat", "mau", "mav", "maw", "max", "maz", "mba", "mbb", "mbc", "mbd", "mbe", "mbf", "mbh", "mbi", "mbj", "mbk", "mbl", "mbm", "mbn", "mbo", "mbp", "mbq", "mbr", "mbs", "mbt", "mbu", "mbv", "mbw", "mbx", "mby", "mbz", "mca", "mcb", "mcc", "mcd", "mce", "mcf", "mcg", "mch", "mci", "mcj", "mck", "mcl", "mcm", "mcn", "mco", "mcp", "mcq", "mcr", "mcs", "mct", "mcu", "mcv", "mcw", "mcx", "mcy", "mcz", "mda", "mdb", "mdc", "mdd", "mde", "mdf", "mdg", "mdh", "mdi", "mdj", "mdk", "mdl", "mdm", "mdn", "mdp", "mdq", "mdr", "mds", "mdt", "mdu", "mdv", "mdw", "mdx", "mdy", "mdz", "mea", "meb", "mec", "med", "mee", "mef", "meg", "meh", "mei", "mej", "mek", "mel", "mem", "men", "meo", "mep", "meq", "mer", "mes", "met", "meu", "mev", "mew", "mey", "mez", "mfa", "mfb", "mfc", "mfd", "mfe", "mff", "mfg", "mfh", "mfi", "mfj", "mfk", "mfl", "mfm", "mfn", "mfo", "mfp", "mfq", "mfr", "mfs", "mft", "mfu", "mfv", "mfw", "mfx", "mfy", "mfz", "mga", "mgb", "mgc", "mgd", "mge", "mgf", "mgg", "mgh", "mgi", "mgj", "mgk", "mgl", "mgm", "mgn", "mgo", "mgp", "mgq", "mgr", "mgs", "mgt", "mgu", "mgv", "mgw", "mgx", "mgy", "mgz", "mha", "mhb", "mhc", "mhd", "mhe", "mhf", "mhg", "mhh", "mhi", "mhj", "mhk", "mhl", "mhm", "mhn", "mho", "mhp", "mhq", "mhr", "mhs", "mht", "mhu", "mhw", "mhx", "mhy", "mhz", "mia", "mib", "mic", "mid", "mie", "mif", "mig", "mih", "mii", "mij", "mik", "mil", "mim", "min", "mio", "mip", "miq", "mir", "mis", "mit", "miu", "miw", "mix", "miy", "miz", "mja", "mjb", "mjc", "mjd", "mje", "mjg", "mjh", "mji", "mjj", "mjk", "mjl", "mjm", "mjn", "mjo", "mjp", "mjq", "mjr", "mjs", "mjt", "mju", "mjv", "mjw", "mjx", "mjy", "mjz", "mka", "mkb", "mkc", "mke", "mkf", "mkg", "mkh", "mki", "mkj", "mkk", "mkl", "mkm", "mkn", "mko", "mkp", "mkq", "mkr", "mks", "mkt", "mku", "mkv", "mkw", "mkx", "mky", "mkz", "mla", "mlb", "mlc", "mld", "mle", "mlf", "mlh", "mli", "mlj", "mlk", "mll", "mlm", "mln", "mlo", "mlp", "mlq", "mlr", "mls", "mlu", "mlv", "mlw", "mlx", "mlz", "mma", "mmb", "mmc", "mmd", "mme", "mmf", "mmg", "mmh", "mmi", "mmj", "mmk", "mml", "mmm", "mmn", "mmo", "mmp", "mmq", "mmr", "mmt", "mmu", "mmv", "mmw", "mmx", "mmy", "mmz", "mna", "mnb", "mnc", "mnd", "mne", "mnf", "mng", "mnh", "mni", "mnj", "mnk", "mnl", "mnm", "mnn", "mno", "mnp", "mnq", "mnr", "mns", "mnt", "mnu", "mnv", "mnw", "mnx", "mny", "mnz", "moa", "moc", "mod", "moe", "mof", "mog", "moh", "moi", "moj", "mok", "mom", "moo", "mop", "moq", "mor", "mos", "mot", "mou", "mov", "mow", "mox", "moy", "moz", "mpa", "mpb", "mpc", "mpd", "mpe", "mpg", "mph", "mpi", "mpj", "mpk", "mpl", "mpm", "mpn", "mpo", "mpp", "mpq", "mpr", "mps", "mpt", "mpu", "mpv", "mpw", "mpx", "mpy", "mpz", "mqa", "mqb", "mqc", "mqe", "mqf", "mqg", "mqh", "mqi", "mqj", "mqk", "mql", "mqm", "mqn", "mqo", "mqp", "mqq", "mqr", "mqs", "mqt", "mqu", "mqv", "mqw", "mqx", "mqy", "mqz", "mra", "mrb", "mrc", "mrd", "mre", "mrf", "mrg", "mrh", "mrj", "mrk", "mrl", "mrm", "mrn", "mro", "mrp", "mrq", "mrr", "mrs", "mrt", "mru", "mrv", "mrw", "mrx", "mry", "mrz", "msb", "msc", "msd", "mse", "msf", "msg", "msh", "msi", "msj", "msk", "msl", "msm", "msn", "mso", "msp", "msq", "msr", "mss", "mst", "msu", "msv", "msw", "msx", "msy", "msz", "mta", "mtb", "mtc", "mtd", "mte", "mtf", "mtg", "mth", "mti", "mtj", "mtk", "mtl", "mtm", "mtn", "mto", "mtp", "mtq", "mtr", "mts", "mtt", "mtu", "mtv", "mtw", "mtx", "mty", "mua", "mub", "muc", "mud", "mue", "mug", "muh", "mui", "muj", "muk", "mul", "mum", "mun", "muo", "mup", "muq", "mur", "mus", "mut", "muu", "muv", "mux", "muy", "muz", "mva", "mvb", "mvd", "mve", "mvf", "mvg", "mvh", "mvi", "mvk", "mvl", "mvm", "mvn", "mvo", "mvp", "mvq", "mvr", "mvs", "mvt", "mvu", "mvv", "mvw", "mvx", "mvy", "mvz", "mwa", "mwb", "mwc", "mwd", "mwe", "mwf", "mwg", "mwh", "mwi", "mwj", "mwk", "mwl", "mwm", "mwn", "mwo", "mwp", "mwq", "mwr", "mws", "mwt", "mwu", "mwv", "mww", "mwx", "mwy", "mwz", "mxa", "mxb", "mxc", "mxd", "mxe", "mxf", "mxg", "mxh", "mxi", "mxj", "mxk", "mxl", "mxm", "mxn", "mxo", "mxp", "mxq", "mxr", "mxs", "mxt", "mxu", "mxv", "mxw", "mxx", "mxy", "mxz", "myb", "myc", "myd", "mye", "myf", "myg", "myh", "myi", "myj", "myk", "myl", "mym", "myn", "myo", "myp", "myq", "myr", "mys", "myt", "myu", "myv", "myw", "myx", "myy", "myz", "mza", "mzb", "mzc", "mzd", "mze", "mzg", "mzh", "mzi", "mzj", "mzk", "mzl", "mzm", "mzn", "mzo", "mzp", "mzq", "mzr", "mzs", "mzt", "mzu", "mzv", "mzw", "mzx", "mzy", "mzz"], + ["na", "nb", "nd", "ne", "ng", "nl", "nn", "no", "nr", "nv", "ny", "naa", "nab", "nac", "nad", "nae", "naf", "nag", "nah", "nai", "naj", "nak", "nal", "nam", "nan", "nao", "nap", "naq", "nar", "nas", "nat", "naw", "nax", "nay", "naz", "nba", "nbb", "nbc", "nbd", "nbe", "nbf", "nbg", "nbh", "nbi", "nbj", "nbk", "nbm", "nbn", "nbo", "nbp", "nbq", "nbr", "nbs", "nbt", "nbu", "nbv", "nbw", "nbx", "nby", "nca", "ncb", "ncc", "ncd", "nce", "ncf", "ncg", "nch", "nci", "ncj", "nck", "ncl", "ncm", "ncn", "nco", "ncp", "ncq", "ncr", "ncs", "nct", "ncu", "ncx", "ncz", "nda", "ndb", "ndc", "ndd", "ndf", "ndg", "ndh", "ndi", "ndj", "ndk", "ndl", "ndm", "ndn", "ndp", "ndq", "ndr", "nds", "ndt", "ndu", "ndv", "ndw", "ndx", "ndy", "ndz", "nea", "neb", "nec", "ned", "nee", "nef", "neg", "neh", "nei", "nej", "nek", "nem", "nen", "neo", "neq", "ner", "nes", "net", "neu", "nev", "new", "nex", "ney", "nez", "nfa", "nfd", "nfl", "nfr", "nfu", "nga", "ngb", "ngc", "ngd", "nge", "ngf", "ngg", "ngh", "ngi", "ngj", "ngk", "ngl", "ngm", "ngn", "ngo", "ngp", "ngq", "ngr", "ngs", "ngt", "ngu", "ngv", "ngw", "ngx", "ngy", "ngz", "nha", "nhb", "nhc", "nhd", "nhe", "nhf", "nhg", "nhh", "nhi", "nhk", "nhm", "nhn", "nho", "nhp", "nhq", "nhr", "nht", "nhu", "nhv", "nhw", "nhx", "nhy", "nhz", "nia", "nib", "nic", "nid", "nie", "nif", "nig", "nih", "nii", "nij", "nik", "nil", "nim", "nin", "nio", "niq", "nir", "nis", "nit", "niu", "niv", "niw", "nix", "niy", "niz", "nja", "njb", "njd", "njh", "nji", "njj", "njl", "njm", "njn", "njo", "njr", "njs", "njt", "nju", "njx", "njy", "njz", "nka", "nkb", "nkc", "nkd", "nke", "nkf", "nkg", "nkh", "nki", "nkj", "nkk", "nkm", "nkn", "nko", "nkp", "nkq", "nkr", "nks", "nkt", "nku", "nkv", "nkw", "nkx", "nkz", "nla", "nlc", "nle", "nlg", "nli", "nlj", "nlk", "nll", "nlm", "nln", "nlo", "nlq", "nlr", "nlu", "nlv", "nlw", "nlx", "nly", "nlz", "nma", "nmb", "nmc", "nmd", "nme", "nmf", "nmg", "nmh", "nmi", "nmj", "nmk", "nml", "nmm", "nmn", "nmo", "nmp", "nmq", "nmr", "nms", "nmt", "nmu", "nmv", "nmw", "nmx", "nmy", "nmz", "nna", "nnb", "nnc", "nnd", "nne", "nnf", "nng", "nnh", "nni", "nnj", "nnk", "nnl", "nnm", "nnn", "nnp", "nnq", "nnr", "nns", "nnt", "nnu", "nnv", "nnw", "nnx", "nny", "nnz", "noa", "noc", "nod", "noe", "nof", "nog", "noh", "noi", "noj", "nok", "nol", "nom", "non", "noo", "nop", "noq", "nos", "not", "nou", "nov", "now", "noy", "noz", "npa", "npb", "npg", "nph", "npi", "npl", "npn", "npo", "nps", "npu", "npx", "npy", "nqg", "nqk", "nql", "nqm", "nqn", "nqo", "nqq", "nqt", "nqy", "nra", "nrb", "nrc", "nre", "nrf", "nrg", "nri", "nrk", "nrl", "nrm", "nrn", "nrp", "nrr", "nrt", "nru", "nrx", "nrz", "nsa", "nsb", "nsc", "nsd", "nse", "nsf", "nsg", "nsh", "nsi", "nsk", "nsl", "nsm", "nsn", "nso", "nsp", "nsq", "nsr", "nss", "nst", "nsu", "nsv", "nsw", "nsx", "nsy", "nsz", "ntd", "nte", "ntg", "nti", "ntj", "ntk", "ntm", "nto", "ntp", "ntr", "nts", "ntu", "ntw", "ntx", "nty", "ntz", "nua", "nub", "nuc", "nud", "nue", "nuf", "nug", "nuh", "nui", "nuj", "nuk", "nul", "num", "nun", "nuo", "nup", "nuq", "nur", "nus", "nut", "nuu", "nuv", "nuw", "nux", "nuy", "nuz", "nvh", "nvm", "nvo", "nwa", "nwb", "nwc", "nwe", "nwg", "nwi", "nwm", "nwo", "nwr", "nwx", "nwy", "nxa", "nxd", "nxe", "nxg", "nxi", "nxk", "nxl", "nxm", "nxn", "nxo", "nxq", "nxr", "nxu", "nxx", "nyb", "nyc", "nyd", "nye", "nyf", "nyg", "nyh", "nyi", "nyj", "nyk", "nyl", "nym", "nyn", "nyo", "nyp", "nyq", "nyr", "nys", "nyt", "nyu", "nyv", "nyw", "nyx", "nyy", "nza", "nzb", "nzd", "nzi", "nzk", "nzm", "nzs", "nzu", "nzy", "nzz"], + ["oc", "oj", "om", "or", "os", "oaa", "oac", "oar", "oav", "obi", "obk", "obl", "obm", "obo", "obr", "obt", "obu", "oca", "och", "ocm", "oco", "ocu", "oda", "odk", "odt", "odu", "ofo", "ofs", "ofu", "ogb", "ogc", "oge", "ogg", "ogo", "ogu", "oht", "ohu", "oia", "oin", "ojb", "ojc", "ojg", "ojp", "ojs", "ojv", "ojw", "oka", "okb", "okc", "okd", "oke", "okg", "okh", "oki", "okj", "okk", "okl", "okm", "okn", "oko", "okr", "oks", "oku", "okv", "okx", "okz", "ola", "old", "ole", "olk", "olm", "olo", "olr", "olt", "olu", "oma", "omb", "omc", "ome", "omg", "omi", "omk", "oml", "omn", "omo", "omp", "omq", "omr", "omt", "omu", "omv", "omw", "omx", "omy", "ona", "onb", "one", "ong", "oni", "onj", "onk", "onn", "ono", "onp", "onr", "ons", "ont", "onu", "onw", "onx", "ood", "oog", "oon", "oor", "oos", "opa", "opk", "opm", "opo", "opt", "opy", "ora", "orc", "ore", "org", "orh", "orn", "oro", "orr", "ors", "ort", "oru", "orv", "orw", "orx", "ory", "orz", "osa", "osc", "osi", "osn", "oso", "osp", "ost", "osu", "osx", "ota", "otb", "otd", "ote", "oti", "otk", "otl", "otm", "otn", "oto", "otq", "otr", "ots", "ott", "otu", "otw", "otx", "oty", "otz", "oua", "oub", "oue", "oui", "oum", "oun", "ovd", "owi", "owl", "oyb", "oyd", "oym", "oyy", "ozm"], + ["pa", "pi", "pl", "ps", "pt", "paa", "pab", "pac", "pad", "pae", "paf", "pag", "pah", "pai", "pak", "pal", "pam", "pao", "pap", "paq", "par", "pas", "pat", "pau", "pav", "paw", "pax", "pay", "paz", "pbb", "pbc", "pbe", "pbf", "pbg", "pbh", "pbi", "pbl", "pbm", "pbn", "pbo", "pbp", "pbr", "pbs", "pbt", "pbu", "pbv", "pby", "pbz", "pca", "pcb", "pcc", "pcd", "pce", "pcf", "pcg", "pch", "pci", "pcj", "pck", "pcl", "pcm", "pcn", "pcp", "pcr", "pcw", "pda", "pdc", "pdi", "pdn", "pdo", "pdt", "pdu", "pea", "peb", "ped", "pee", "pef", "peg", "peh", "pei", "pej", "pek", "pel", "pem", "peo", "pep", "peq", "pes", "pev", "pex", "pey", "pez", "pfa", "pfe", "pfl", "pga", "pgd", "pgg", "pgi", "pgk", "pgl", "pgn", "pgs", "pgu", "pgy", "pgz", "pha", "phd", "phg", "phh", "phi", "phk", "phl", "phm", "phn", "pho", "phq", "phr", "pht", "phu", "phv", "phw", "pia", "pib", "pic", "pid", "pie", "pif", "pig", "pih", "pii", "pij", "pil", "pim", "pin", "pio", "pip", "pir", "pis", "pit", "piu", "piv", "piw", "pix", "piy", "piz", "pjt", "pka", "pkb", "pkc", "pkg", "pkh", "pkn", "pko", "pkp", "pkr", "pks", "pkt", "pku", "pla", "plb", "plc", "pld", "ple", "plf", "plg", "plh", "plj", "plk", "pll", "pln", "plo", "plp", "plq", "plr", "pls", "plt", "plu", "plv", "plw", "ply", "plz", "pma", "pmb", "pmc", "pmd", "pme", "pmf", "pmh", "pmi", "pmj", "pmk", "pml", "pmm", "pmn", "pmo", "pmq", "pmr", "pms", "pmt", "pmu", "pmw", "pmx", "pmy", "pmz", "pna", "pnb", "pnc", "pnd", "pne", "png", "pnh", "pni", "pnj", "pnk", "pnl", "pnm", "pnn", "pno", "pnp", "pnq", "pnr", "pns", "pnt", "pnu", "pnv", "pnw", "pnx", "pny", "pnz", "poc", "pod", "poe", "pof", "pog", "poh", "poi", "pok", "pom", "pon", "poo", "pop", "poq", "pos", "pot", "pov", "pow", "pox", "poy", "poz", "ppa", "ppe", "ppi", "ppk", "ppl", "ppm", "ppn", "ppo", "ppp", "ppq", "ppr", "pps", "ppt", "ppu", "pqa", "pqe", "pqm", "pqw", "pra", "prb", "prc", "prd", "pre", "prf", "prg", "prh", "pri", "prk", "prl", "prm", "prn", "pro", "prp", "prq", "prr", "prs", "prt", "pru", "prw", "prx", "pry", "prz", "psa", "psc", "psd", "pse", "psg", "psh", "psi", "psl", "psm", "psn", "pso", "psp", "psq", "psr", "pss", "pst", "psu", "psw", "psy", "pta", "pth", "pti", "ptn", "pto", "ptp", "ptq", "ptr", "ptt", "ptu", "ptv", "ptw", "pty", "pua", "pub", "puc", "pud", "pue", "puf", "pug", "pui", "puj", "puk", "pum", "puo", "pup", "puq", "pur", "put", "puu", "puw", "pux", "puy", "puz", "pwa", "pwb", "pwg", "pwi", "pwm", "pwn", "pwo", "pwr", "pww", "pxm", "pye", "pym", "pyn", "pys", "pyu", "pyx", "pyy", "pzn"], + ["qu", "qua", "qub", "quc", "qud", "quf", "qug", "quh", "qui", "quk", "qul", "qum", "qun", "qup", "quq", "qur", "qus", "quv", "quw", "qux", "quy", "quz", "qva", "qvc", "qve", "qvh", "qvi", "qvj", "qvl", "qvm", "qvn", "qvo", "qvp", "qvs", "qvw", "qvy", "qvz", "qwa", "qwc", "qwe", "qwh", "qwm", "qws", "qwt", "qxa", "qxc", "qxh", "qxl", "qxn", "qxo", "qxp", "qxq", "qxr", "qxs", "qxt", "qxu", "qxw", "qya", "qyp"], + ["rm", "rn", "ro", "ru", "rw", "raa", "rab", "rac", "rad", "raf", "rag", "rah", "rai", "raj", "rak", "ral", "ram", "ran", "rao", "rap", "raq", "rar", "ras", "rat", "rau", "rav", "raw", "rax", "ray", "raz", "rbb", "rbk", "rbl", "rbp", "rcf", "rdb", "rea", "reb", "ree", "reg", "rei", "rej", "rel", "rem", "ren", "rer", "res", "ret", "rey", "rga", "rge", "rgk", "rgn", "rgr", "rgs", "rgu", "rhg", "rhp", "ria", "rie", "rif", "ril", "rim", "rin", "rir", "rit", "riu", "rjg", "rji", "rjs", "rka", "rkb", "rkh", "rki", "rkm", "rkt", "rkw", "rma", "rmb", "rmc", "rmd", "rme", "rmf", "rmg", "rmh", "rmi", "rmk", "rml", "rmm", "rmn", "rmo", "rmp", "rmq", "rmr", "rms", "rmt", "rmu", "rmv", "rmw", "rmx", "rmy", "rmz", "rna", "rnd", "rng", "rnl", "rnn", "rnp", "rnr", "rnw", "roa", "rob", "roc", "rod", "roe", "rof", "rog", "rol", "rom", "roo", "rop", "ror", "rou", "row", "rpn", "rpt", "rri", "rro", "rrt", "rsb", "rsi", "rsl", "rsm", "rtc", "rth", "rtm", "rts", "rtw", "rub", "ruc", "rue", "ruf", "rug", "ruh", "rui", "ruk", "ruo", "rup", "ruq", "rut", "ruu", "ruy", "ruz", "rwa", "rwk", "rwl", "rwm", "rwo", "rwr", "rxd", "rxw", "ryn", "rys", "ryu", "rzh"], + ["sa", "sc", "sd", "se", "sg", "sh", "si", "sk", "sl", "sm", "sn", "so", "sq", "sr", "ss", "st", "su", "sv", "sw", "saa", "sab", "sac", "sad", "sae", "saf", "sah", "sai", "saj", "sak", "sal", "sam", "sao", "sap", "saq", "sar", "sas", "sat", "sau", "sav", "saw", "sax", "say", "saz", "sba", "sbb", "sbc", "sbd", "sbe", "sbf", "sbg", "sbh", "sbi", "sbj", "sbk", "sbl", "sbm", "sbn", "sbo", "sbp", "sbq", "sbr", "sbs", "sbt", "sbu", "sbv", "sbw", "sbx", "sby", "sbz", "sca", "scb", "sce", "scf", "scg", "sch", "sci", "sck", "scl", "scn", "sco", "scp", "scq", "scs", "sct", "scu", "scv", "scw", "scx", "sda", "sdb", "sdc", "sde", "sdf", "sdg", "sdh", "sdj", "sdk", "sdl", "sdm", "sdn", "sdo", "sdp", "sdq", "sdr", "sds", "sdt", "sdu", "sdv", "sdx", "sdz", "sea", "seb", "sec", "sed", "see", "sef", "seg", "seh", "sei", "sej", "sek", "sel", "sem", "sen", "seo", "sep", "seq", "ser", "ses", "set", "seu", "sev", "sew", "sey", "sez", "sfb", "sfe", "sfm", "sfs", "sfw", "sga", "sgb", "sgc", "sgd", "sge", "sgg", "sgh", "sgi", "sgj", "sgk", "sgl", "sgm", "sgn", "sgo", "sgp", "sgr", "sgs", "sgt", "sgu", "sgw", "sgx", "sgy", "sgz", "sha", "shb", "shc", "shd", "she", "shg", "shh", "shi", "shj", "shk", "shl", "shm", "shn", "sho", "shp", "shq", "shr", "shs", "sht", "shu", "shv", "shw", "shx", "shy", "shz", "sia", "sib", "sid", "sie", "sif", "sig", "sih", "sii", "sij", "sik", "sil", "sim", "sio", "sip", "siq", "sir", "sis", "sit", "siu", "siv", "siw", "six", "siy", "siz", "sja", "sjb", "sjd", "sje", "sjg", "sjk", "sjl", "sjm", "sjn", "sjo", "sjp", "sjr", "sjs", "sjt", "sju", "sjw", "ska", "skb", "skc", "skd", "ske", "skf", "skg", "skh", "ski", "skj", "skk", "skm", "skn", "sko", "skp", "skq", "skr", "sks", "skt", "sku", "skv", "skw", "skx", "sky", "skz", "sla", "slc", "sld", "sle", "slf", "slg", "slh", "sli", "slj", "sll", "slm", "sln", "slp", "slq", "slr", "sls", "slt", "slu", "slw", "slx", "sly", "slz", "sma", "smb", "smc", "smd", "smf", "smg", "smh", "smi", "smj", "smk", "sml", "smm", "smn", "smp", "smq", "smr", "sms", "smt", "smu", "smv", "smw", "smx", "smy", "smz", "snb", "snc", "sne", "snf", "sng", "snh", "sni", "snj", "snk", "snl", "snm", "snn", "sno", "snp", "snq", "snr", "sns", "snu", "snv", "snw", "snx", "sny", "snz", "soa", "sob", "soc", "sod", "soe", "sog", "soh", "soi", "soj", "sok", "sol", "son", "soo", "sop", "soq", "sor", "sos", "sou", "sov", "sow", "sox", "soy", "soz", "spb", "spc", "spd", "spe", "spg", "spi", "spk", "spl", "spm", "spn", "spo", "spp", "spq", "spr", "sps", "spt", "spu", "spv", "spx", "spy", "sqa", "sqh", "sqj", "sqk", "sqm", "sqn", "sqo", "sqq", "sqr", "sqs", "sqt", "squ", "sqx", "sra", "srb", "src", "sre", "srf", "srg", "srh", "sri", "srk", "srl", "srm", "srn", "sro", "srq", "srr", "srs", "srt", "sru", "srv", "srw", "srx", "sry", "srz", "ssa", "ssb", "ssc", "ssd", "sse", "ssf", "ssg", "ssh", "ssi", "ssj", "ssk", "ssl", "ssm", "ssn", "sso", "ssp", "ssq", "ssr", "sss", "sst", "ssu", "ssv", "ssx", "ssy", "ssz", "sta", "stb", "std", "ste", "stf", "stg", "sth", "sti", "stj", "stk", "stl", "stm", "stn", "sto", "stp", "stq", "str", "sts", "stt", "stu", "stv", "stw", "sty", "sua", "sub", "suc", "sue", "sug", "sui", "suj", "suk", "sul", "sum", "suo", "suq", "sur", "sus", "sut", "suv", "suw", "sux", "suy", "suz", "sva", "svb", "svc", "sve", "svk", "svm", "svr", "svs", "svx", "swb", "swc", "swf", "swg", "swh", "swi", "swj", "swk", "swl", "swm", "swn", "swo", "swp", "swq", "swr", "sws", "swt", "swu", "swv", "sww", "swx", "swy", "sxb", "sxc", "sxe", "sxg", "sxk", "sxl", "sxm", "sxn", "sxo", "sxr", "sxs", "sxu", "sxw", "sya", "syb", "syc", "syd", "syi", "syk", "syl", "sym", "syn", "syo", "syr", "sys", "syw", "syx", "syy", "sza", "szb", "szc", "szd", "sze", "szg", "szl", "szn", "szp", "szs", "szv", "szw", "szy"], + ["ta", "te", "tg", "th", "ti", "tk", "tl", "tn", "to", "tr", "ts", "tt", "tw", "ty", "taa", "tab", "tac", "tad", "tae", "taf", "tag", "tai", "taj", "tak", "tal", "tan", "tao", "tap", "taq", "tar", "tas", "tau", "tav", "taw", "tax", "tay", "taz", "tba", "tbb", "tbc", "tbd", "tbe", "tbf", "tbg", "tbh", "tbi", "tbj", "tbk", "tbl", "tbm", "tbn", "tbo", "tbp", "tbq", "tbr", "tbs", "tbt", "tbu", "tbv", "tbw", "tbx", "tby", "tbz", "tca", "tcb", "tcc", "tcd", "tce", "tcf", "tcg", "tch", "tci", "tck", "tcl", "tcm", "tcn", "tco", "tcp", "tcq", "tcs", "tct", "tcu", "tcw", "tcx", "tcy", "tcz", "tda", "tdb", "tdc", "tdd", "tde", "tdf", "tdg", "tdh", "tdi", "tdj", "tdk", "tdl", "tdm", "tdn", "tdo", "tdq", "tdr", "tds", "tdt", "tdu", "tdv", "tdx", "tdy", "tea", "teb", "tec", "ted", "tee", "tef", "teg", "teh", "tei", "tek", "tem", "ten", "teo", "tep", "teq", "ter", "tes", "tet", "teu", "tev", "tew", "tex", "tey", "tez", "tfi", "tfn", "tfo", "tfr", "tft", "tga", "tgb", "tgc", "tgd", "tge", "tgf", "tgg", "tgh", "tgi", "tgj", "tgn", "tgo", "tgp", "tgq", "tgr", "tgs", "tgt", "tgu", "tgv", "tgw", "tgx", "tgy", "tgz", "thc", "thd", "the", "thf", "thh", "thi", "thk", "thl", "thm", "thn", "thp", "thq", "thr", "ths", "tht", "thu", "thv", "thw", "thx", "thy", "thz", "tia", "tic", "tid", "tie", "tif", "tig", "tih", "tii", "tij", "tik", "til", "tim", "tin", "tio", "tip", "tiq", "tis", "tit", "tiu", "tiv", "tiw", "tix", "tiy", "tiz", "tja", "tjg", "tji", "tjj", "tjl", "tjm", "tjn", "tjo", "tjp", "tjs", "tju", "tjw", "tka", "tkb", "tkd", "tke", "tkf", "tkg", "tkk", "tkl", "tkm", "tkn", "tkp", "tkq", "tkr", "tks", "tkt", "tku", "tkv", "tkw", "tkx", "tkz", "tla", "tlb", "tlc", "tld", "tlf", "tlg", "tlh", "tli", "tlj", "tlk", "tll", "tlm", "tln", "tlo", "tlp", "tlq", "tlr", "tls", "tlt", "tlu", "tlv", "tlw", "tlx", "tly", "tma", "tmb", "tmc", "tmd", "tme", "tmf", "tmg", "tmh", "tmi", "tmj", "tmk", "tml", "tmm", "tmn", "tmo", "tmp", "tmq", "tmr", "tms", "tmt", "tmu", "tmv", "tmw", "tmy", "tmz", "tna", "tnb", "tnc", "tnd", "tne", "tnf", "tng", "tnh", "tni", "tnk", "tnl", "tnm", "tnn", "tno", "tnp", "tnq", "tnr", "tns", "tnt", "tnu", "tnv", "tnw", "tnx", "tny", "tnz", "tob", "toc", "tod", "toe", "tof", "tog", "toh", "toi", "toj", "tol", "tom", "too", "top", "toq", "tor", "tos", "tou", "tov", "tow", "tox", "toy", "toz", "tpa", "tpc", "tpe", "tpf", "tpg", "tpi", "tpj", "tpk", "tpl", "tpm", "tpn", "tpo", "tpp", "tpq", "tpr", "tpt", "tpu", "tpv", "tpw", "tpx", "tpy", "tpz", "tqb", "tql", "tqm", "tqn", "tqo", "tqp", "tqq", "tqr", "tqt", "tqu", "tqw", "tra", "trb", "trc", "trd", "tre", "trf", "trg", "trh", "tri", "trj", "trk", "trl", "trm", "trn", "tro", "trp", "trq", "trr", "trs", "trt", "tru", "trv", "trw", "trx", "try", "trz", "tsa", "tsb", "tsc", "tsd", "tse", "tsf", "tsg", "tsh", "tsi", "tsj", "tsk", "tsl", "tsm", "tsp", "tsq", "tsr", "tss", "tst", "tsu", "tsv", "tsw", "tsx", "tsy", "tsz", "tta", "ttb", "ttc", "ttd", "tte", "ttf", "ttg", "tth", "tti", "ttj", "ttk", "ttl", "ttm", "ttn", "tto", "ttp", "ttq", "ttr", "tts", "ttt", "ttu", "ttv", "ttw", "tty", "ttz", "tua", "tub", "tuc", "tud", "tue", "tuf", "tug", "tuh", "tui", "tuj", "tul", "tum", "tun", "tuo", "tup", "tuq", "tus", "tut", "tuu", "tuv", "tuw", "tux", "tuy", "tuz", "tva", "tvd", "tve", "tvk", "tvl", "tvm", "tvn", "tvo", "tvs", "tvt", "tvu", "tvw", "tvx", "tvy", "twa", "twb", "twc", "twd", "twe", "twf", "twg", "twh", "twl", "twm", "twn", "two", "twp", "twq", "twr", "twt", "twu", "tww", "twx", "twy", "txa", "txb", "txc", "txe", "txg", "txh", "txi", "txj", "txm", "txn", "txo", "txq", "txr", "txs", "txt", "txu", "txx", "txy", "tya", "tye", "tyh", "tyi", "tyj", "tyl", "tyn", "typ", "tyr", "tys", "tyt", "tyu", "tyv", "tyx", "tyy", "tyz", "tza", "tzh", "tzj", "tzl", "tzm", "tzn", "tzo", "tzx"], + ["ug", "uk", "ur", "uz", "uam", "uan", "uar", "uba", "ubi", "ubl", "ubr", "ubu", "uby", "uda", "ude", "udg", "udi", "udj", "udl", "udm", "udu", "ues", "ufi", "uga", "ugb", "uge", "ugn", "ugo", "ugy", "uha", "uhn", "uis", "uiv", "uji", "uka", "ukg", "ukh", "uki", "ukk", "ukl", "ukp", "ukq", "uks", "uku", "ukv", "ukw", "uky", "ula", "ulb", "ulc", "ule", "ulf", "uli", "ulk", "ull", "ulm", "uln", "ulu", "ulw", "uma", "umb", "umc", "umd", "umg", "umi", "umm", "umn", "umo", "ump", "umr", "ums", "umu", "una", "und", "une", "ung", "uni", "unk", "unm", "unn", "unp", "unr", "unu", "unx", "unz", "uok", "upi", "upv", "ura", "urb", "urc", "ure", "urf", "urg", "urh", "uri", "urj", "urk", "url", "urm", "urn", "uro", "urp", "urr", "urt", "uru", "urv", "urw", "urx", "ury", "urz", "usa", "ush", "usi", "usk", "usp", "uss", "usu", "uta", "ute", "uth", "utp", "utr", "utu", "uum", "uun", "uur", "uuu", "uve", "uvh", "uvl", "uwa", "uya", "uzn", "uzs"], + ["ve", "vi", "vo", "vaa", "vae", "vaf", "vag", "vah", "vai", "vaj", "val", "vam", "van", "vao", "vap", "var", "vas", "vau", "vav", "vay", "vbb", "vbk", "vec", "ved", "vel", "vem", "veo", "vep", "ver", "vgr", "vgt", "vic", "vid", "vif", "vig", "vil", "vin", "vis", "vit", "viv", "vka", "vki", "vkj", "vkk", "vkl", "vkm", "vkn", "vko", "vkp", "vkt", "vku", "vkz", "vlp", "vls", "vma", "vmb", "vmc", "vmd", "vme", "vmf", "vmg", "vmh", "vmi", "vmj", "vmk", "vml", "vmm", "vmp", "vmq", "vmr", "vms", "vmu", "vmv", "vmw", "vmx", "vmy", "vmz", "vnk", "vnm", "vnp", "vor", "vot", "vra", "vro", "vrs", "vrt", "vsi", "vsl", "vsv", "vto", "vum", "vun", "vut", "vwa"], + ["wa", "wo", "waa", "wab", "wac", "wad", "wae", "waf", "wag", "wah", "wai", "waj", "wak", "wal", "wam", "wan", "wao", "wap", "waq", "war", "was", "wat", "wau", "wav", "waw", "wax", "way", "waz", "wba", "wbb", "wbe", "wbf", "wbh", "wbi", "wbj", "wbk", "wbl", "wbm", "wbp", "wbq", "wbr", "wbs", "wbt", "wbv", "wbw", "wca", "wci", "wdd", "wdg", "wdj", "wdk", "wdu", "wdy", "wea", "wec", "wed", "weg", "weh", "wei", "wem", "wen", "weo", "wep", "wer", "wes", "wet", "weu", "wew", "wfg", "wga", "wgb", "wgg", "wgi", "wgo", "wgu", "wgw", "wgy", "wha", "whg", "whk", "whu", "wib", "wic", "wie", "wif", "wig", "wih", "wii", "wij", "wik", "wil", "wim", "win", "wir", "wit", "wiu", "wiv", "wiw", "wiy", "wja", "wji", "wka", "wkb", "wkd", "wkl", "wkr", "wku", "wkw", "wky", "wla", "wlc", "wle", "wlg", "wlh", "wli", "wlk", "wll", "wlm", "wlo", "wlr", "wls", "wlu", "wlv", "wlw", "wlx", "wly", "wma", "wmb", "wmc", "wmd", "wme", "wmg", "wmh", "wmi", "wmm", "wmn", "wmo", "wms", "wmt", "wmw", "wmx", "wnb", "wnc", "wnd", "wne", "wng", "wni", "wnk", "wnm", "wnn", "wno", "wnp", "wnu", "wnw", "wny", "woa", "wob", "woc", "wod", "woe", "wof", "wog", "woi", "wok", "wom", "won", "woo", "wor", "wos", "wow", "woy", "wpc", "wra", "wrb", "wrd", "wrg", "wrh", "wri", "wrk", "wrl", "wrm", "wrn", "wro", "wrp", "wrr", "wrs", "wru", "wrv", "wrw", "wrx", "wry", "wrz", "wsa", "wsg", "wsi", "wsk", "wsr", "wss", "wsu", "wsv", "wtf", "wth", "wti", "wtk", "wtm", "wtw", "wua", "wub", "wud", "wuh", "wul", "wum", "wun", "wur", "wut", "wuu", "wuv", "wux", "wuy", "wwa", "wwb", "wwo", "wwr", "www", "wxa", "wxw", "wya", "wyb", "wyi", "wym", "wyr", "wyy"], + ["xh", "xaa", "xab", "xac", "xad", "xae", "xag", "xai", "xaj", "xak", "xal", "xam", "xan", "xao", "xap", "xaq", "xar", "xas", "xat", "xau", "xav", "xaw", "xay", "xba", "xbb", "xbc", "xbd", "xbe", "xbg", "xbi", "xbj", "xbm", "xbn", "xbo", "xbp", "xbr", "xbw", "xbx", "xby", "xcb", "xcc", "xce", "xcg", "xch", "xcl", "xcm", "xcn", "xco", "xcr", "xct", "xcu", "xcv", "xcw", "xcy", "xda", "xdc", "xdk", "xdm", "xdo", "xdy", "xeb", "xed", "xeg", "xel", "xem", "xep", "xer", "xes", "xet", "xeu", "xfa", "xga", "xgb", "xgd", "xgf", "xgg", "xgi", "xgl", "xgm", "xgn", "xgr", "xgu", "xgw", "xha", "xhc", "xhd", "xhe", "xhr", "xht", "xhu", "xhv", "xia", "xib", "xii", "xil", "xin", "xip", "xir", "xis", "xiv", "xiy", "xjb", "xjt", "xka", "xkb", "xkc", "xkd", "xke", "xkf", "xkg", "xkh", "xki", "xkj", "xkk", "xkl", "xkn", "xko", "xkp", "xkq", "xkr", "xks", "xkt", "xku", "xkv", "xkw", "xkx", "xky", "xkz", "xla", "xlb", "xlc", "xld", "xle", "xlg", "xli", "xln", "xlo", "xlp", "xls", "xlu", "xly", "xma", "xmb", "xmc", "xmd", "xme", "xmf", "xmg", "xmh", "xmj", "xmk", "xml", "xmm", "xmn", "xmo", "xmp", "xmq", "xmr", "xms", "xmt", "xmu", "xmv", "xmw", "xmx", "xmy", "xmz", "xna", "xnb", "xnd", "xng", "xnh", "xni", "xnj", "xnk", "xnm", "xnn", "xno", "xnq", "xnr", "xns", "xnt", "xnu", "xny", "xnz", "xoc", "xod", "xog", "xoi", "xok", "xom", "xon", "xoo", "xop", "xor", "xow", "xpa", "xpb", "xpc", "xpd", "xpe", "xpf", "xpg", "xph", "xpi", "xpj", "xpk", "xpl", "xpm", "xpn", "xpo", "xpp", "xpq", "xpr", "xps", "xpt", "xpu", "xpv", "xpw", "xpx", "xpy", "xpz", "xqa", "xqt", "xra", "xrb", "xrd", "xre", "xrg", "xri", "xrm", "xrn", "xrq", "xrr", "xrt", "xru", "xrw", "xsa", "xsb", "xsc", "xsd", "xse", "xsh", "xsi", "xsj", "xsl", "xsm", "xsn", "xso", "xsp", "xsq", "xsr", "xss", "xsu", "xsv", "xsy", "xta", "xtb", "xtc", "xtd", "xte", "xtg", "xth", "xti", "xtj", "xtl", "xtm", "xtn", "xto", "xtp", "xtq", "xtr", "xts", "xtt", "xtu", "xtv", "xtw", "xty", "xtz", "xua", "xub", "xud", "xug", "xuj", "xul", "xum", "xun", "xuo", "xup", "xur", "xut", "xuu", "xve", "xvi", "xvn", "xvo", "xvs", "xwa", "xwc", "xwd", "xwe", "xwg", "xwj", "xwk", "xwl", "xwo", "xwr", "xwt", "xww", "xxb", "xxk", "xxm", "xxr", "xxt", "xya", "xyb", "xyj", "xyk", "xyl", "xyt", "xyy", "xzh", "xzm", "xzp"], + ["yi", "yo", "yaa", "yab", "yac", "yad", "yae", "yaf", "yag", "yah", "yai", "yaj", "yak", "yal", "yam", "yan", "yao", "yap", "yaq", "yar", "yas", "yat", "yau", "yav", "yaw", "yax", "yay", "yaz", "yba", "ybb", "ybd", "ybe", "ybh", "ybi", "ybj", "ybk", "ybl", "ybm", "ybn", "ybo", "ybx", "yby", "ych", "ycl", "ycn", "ycp", "yda", "ydd", "yde", "ydg", "ydk", "yds", "yea", "yec", "yee", "yei", "yej", "yel", "yen", "yer", "yes", "yet", "yeu", "yev", "yey", "yga", "ygi", "ygl", "ygm", "ygp", "ygr", "ygs", "ygu", "ygw", "yha", "yhd", "yhl", "yhs", "yia", "yif", "yig", "yih", "yii", "yij", "yik", "yil", "yim", "yin", "yip", "yiq", "yir", "yis", "yit", "yiu", "yiv", "yix", "yiy", "yiz", "yka", "ykg", "yki", "ykk", "ykl", "ykm", "ykn", "yko", "ykr", "ykt", "yku", "yky", "yla", "ylb", "yle", "ylg", "yli", "yll", "ylm", "yln", "ylo", "ylr", "ylu", "yly", "yma", "ymb", "ymc", "ymd", "yme", "ymg", "ymh", "ymi", "ymk", "yml", "ymm", "ymn", "ymo", "ymp", "ymq", "ymr", "yms", "ymt", "ymx", "ymz", "yna", "ynd", "yne", "yng", "ynh", "ynk", "ynl", "ynn", "yno", "ynq", "yns", "ynu", "yob", "yog", "yoi", "yok", "yol", "yom", "yon", "yos", "yot", "yox", "yoy", "ypa", "ypb", "ypg", "yph", "ypk", "ypm", "ypn", "ypo", "ypp", "ypz", "yra", "yrb", "yre", "yri", "yrk", "yrl", "yrm", "yrn", "yro", "yrs", "yrw", "yry", "ysc", "ysd", "ysg", "ysl", "ysm", "ysn", "yso", "ysp", "ysr", "yss", "ysy", "yta", "ytl", "ytp", "ytw", "yty", "yua", "yub", "yuc", "yud", "yue", "yuf", "yug", "yui", "yuj", "yuk", "yul", "yum", "yun", "yup", "yuq", "yur", "yut", "yuu", "yuw", "yux", "yuy", "yuz", "yva", "yvt", "ywa", "ywg", "ywl", "ywn", "ywq", "ywr", "ywt", "ywu", "yww", "yxa", "yxg", "yxl", "yxm", "yxu", "yxy", "yyr", "yyu", "yyz", "yzg", "yzk"], + ["za", "zh", "zu", "zaa", "zab", "zac", "zad", "zae", "zaf", "zag", "zah", "zai", "zaj", "zak", "zal", "zam", "zao", "zap", "zaq", "zar", "zas", "zat", "zau", "zav", "zaw", "zax", "zay", "zaz", "zba", "zbc", "zbe", "zbl", "zbt", "zbu", "zbw", "zca", "zch", "zdj", "zea", "zeg", "zeh", "zen", "zga", "zgb", "zgh", "zgm", "zgn", "zgr", "zhb", "zhd", "zhi", "zhn", "zhw", "zhx", "zia", "zib", "zik", "zil", "zim", "zin", "zir", "ziw", "ziz", "zka", "zkb", "zkd", "zkg", "zkh", "zkk", "zkn", "zko", "zkp", "zkr", "zkt", "zku", "zkv", "zkz", "zla", "zle", "zlj", "zlm", "zln", "zlq", "zls", "zlw", "zma", "zmb", "zmc", "zmd", "zme", "zmf", "zmg", "zmh", "zmi", "zmj", "zmk", "zml", "zmm", "zmn", "zmo", "zmp", "zmq", "zmr", "zms", "zmt", "zmu", "zmv", "zmw", "zmx", "zmy", "zmz", "zna", "znd", "zne", "zng", "znk", "zns", "zoc", "zoh", "zom", "zoo", "zoq", "zor", "zos", "zpa", "zpb", "zpc", "zpd", "zpe", "zpf", "zpg", "zph", "zpi", "zpj", "zpk", "zpl", "zpm", "zpn", "zpo", "zpp", "zpq", "zpr", "zps", "zpt", "zpu", "zpv", "zpw", "zpx", "zpy", "zpz", "zqe", "zra", "zrg", "zrn", "zro", "zrp", "zrs", "zsa", "zsk", "zsl", "zsm", "zsr", "zsu", "zte", "ztg", "ztl", "ztm", "ztn", "ztp", "ztq", "zts", "ztt", "ztu", "ztx", "zty", "zua", "zuh", "zum", "zun", "zuy", "zwa", "zxx", "zyb", "zyg", "zyj", "zyn", "zyp", "zza", "zzj"] +]; +var LangUtil = /** @class */ (function () { + function LangUtil() { + } + /* Determine if given string is a valid BCP 47 string */ + LangUtil.isBcp47 = function (langStr) { + return /^(([a-zA-Z]{2,3}(-[a-zA-Z](-[a-zA-Z]{3}){0,2})?|[a-zA-Z]{4}|[a-zA-Z]{5,8})(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-([0-9a-zA-Z]{5,8}|[0-9][a-zA-Z]{3}))*(-[0-9a-wy-zA-WY-Z](-[a-zA-Z0-9]{2,8})+)*(-x(-[a-zA-Z0-9]{1,8})+)?|x(-[a-zA-Z0-9]{1,8})+|(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE|art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))$/.test(langStr); + }; + LangUtil.validPrimaryLang = function (langStr) { + var primary = langStr.toLowerCase(); + if (primary.includes("-")) { + primary = primary.split("-")[0]; + } + if (!primary.match(/[a-z]{2,3}/)) + return false; + // qaa..qtz + if (primary.length === 3 + && primary.charAt(0) === "q" + && primary.charCodeAt(1) >= 97 && primary.charCodeAt(1) <= 116 + && primary.charCodeAt(2) >= 97 && primary.charCodeAt(2) <= 122) { + } + return validPrimaryLangs[primary.charCodeAt(0) - 97].includes(primary); + }; + LangUtil.matchPrimaryLang = function (lang1, lang2) { + var primary1 = lang1; + if (primary1.includes("-")) { + primary1 = primary1.split("-")[0]; + } + var primary2 = lang2; + if (primary2.includes("-")) { + primary2 = primary2.split("-")[0]; + } + return primary1.toLowerCase() === primary2.toLowerCase(); + }; + return LangUtil; +}()); +exports.LangUtil = LangUtil; + + +/***/ }), + +/***/ "./src/v2/checker/accessibility/util/legacy.ts": +/*!*****************************************************!*\ + !*** ./src/v2/checker/accessibility/util/legacy.ts ***! + \*****************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + +/****************************************************************************** + Copyright:: 2020- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.NodeWalker = exports.RPTUtil = void 0; +var CacheUtil_1 = __webpack_require__(/*! ../../../../v4/util/CacheUtil */ "./src/v4/util/CacheUtil.ts"); +var ARIADefinitions_1 = __webpack_require__(/*! ../../../aria/ARIADefinitions */ "./src/v2/aria/ARIADefinitions.ts"); +var ARIAMapper_1 = __webpack_require__(/*! ../../../aria/ARIAMapper */ "./src/v2/aria/ARIAMapper.ts"); +var DOMWalker_1 = __webpack_require__(/*! ../../../dom/DOMWalker */ "./src/v2/dom/DOMWalker.ts"); +var VisUtil_1 = __webpack_require__(/*! ../../../dom/VisUtil */ "./src/v2/dom/VisUtil.ts"); +var fragment_1 = __webpack_require__(/*! ./fragment */ "./src/v2/checker/accessibility/util/fragment.ts"); +var CSSUtil_1 = __webpack_require__(/*! ../../../../v4/util/CSSUtil */ "./src/v4/util/CSSUtil.ts"); +var DOMUtil_1 = __webpack_require__(/*! ../../../dom/DOMUtil */ "./src/v2/dom/DOMUtil.ts"); +var DOMMapper_1 = __webpack_require__(/*! ../../../dom/DOMMapper */ "./src/v2/dom/DOMMapper.ts"); +var RPTUtil = /** @class */ (function () { + function RPTUtil() { + } + RPTUtil.isDefinedAriaAttributeAtIndex = function (ele, index) { + var attrName = ele.attributes[index].name; + return RPTUtil.isDefinedAriaAttribute(ele, attrName); + }; + /** + * this method returns user-defined aria attribute name from dom + * @param ele element + * @returns user defined aria attributes + */ + RPTUtil.getUserDefinedAriaAttributes = function (elem) { + var ariaAttributes = []; + var domAttributes = elem.attributes; + if (domAttributes) { + for (var i = 0; i < domAttributes.length; i++) { + var attrName = domAttributes[i].name.trim().toLowerCase(); + var isAria = attrName.substring(0, 5) === 'aria-'; + if (isAria) + ariaAttributes.push(attrName); + } + } + return ariaAttributes; + }; + /** + * this method returns user-defined html attribute name from dom + * @param ele element + * @returns user defined html attributes + */ + RPTUtil.getUserDefinedHtmlAttributes = function (elem) { + var htmlAttributes = []; + var domAttributes = elem.attributes; + if (domAttributes) { + for (var i = 0; i < domAttributes.length; i++) { + var attrName = domAttributes[i].name.trim().toLowerCase(); + var isAria = attrName.substring(0, 5) === 'aria-'; + if (!isAria) + htmlAttributes.push(attrName); + } + } + return htmlAttributes; + }; + /** + * this method returns user-defined aria attribute name-value pair from dom + * @param ele element + * @returns user defined aria attributes + */ + RPTUtil.getUserDefinedAriaAttributeNameValuePairs = function (elem) { + var ariaAttributes = []; + var domAttributes = elem.attributes; + if (domAttributes) { + for (var i = 0; i < domAttributes.length; i++) { + var attrName = domAttributes[i].name.trim().toLowerCase(); + var attrValue = elem.getAttribute(attrName); + if (attrValue === '') + attrValue = null; + var isAria = attrName.substring(0, 5) === 'aria-'; + if (isAria) + ariaAttributes.push({ name: attrName, value: attrValue }); + } + } + return ariaAttributes; + }; + /** + * this method returns user-defined html attribute name-value pair from dom + * @param ele element + * @returns user defined html attributes + */ + RPTUtil.getUserDefinedHtmlAttributeNameValuePairs = function (elem) { + var htmlAttributes = []; + var domAttributes = elem.attributes; + if (domAttributes) { + for (var i = 0; i < domAttributes.length; i++) { + var attrName = domAttributes[i].name.trim().toLowerCase(); + var attrValue = elem.getAttribute(attrName); + if (attrValue === '') + attrValue = null; + var isAria = attrName.substring(0, 5) === 'aria-'; + if (!isAria) + htmlAttributes.push({ name: attrName, value: attrValue }); + } + } + return htmlAttributes; + }; + /** + * This method handles implicit aria definitions, for example, an input with checked is equivalent to aria-checked="true" + */ + RPTUtil.getAriaAttribute = function (ele, attributeName) { + // If the attribute is defined, it takes precedence + var retVal = ele.getAttribute(attributeName); + if (ele.hasAttribute(attributeName) && retVal.trim() === "") { //"" is treated as false, so we need return it before the below check + return retVal; + } + // Then determine implicit values from other attributes + if (!retVal) { + var tag = ele.nodeName.toLowerCase(); + if (attributeName in RPTUtil.ariaAttributeImplicitMappings) { + if (tag in RPTUtil.ariaAttributeImplicitMappings[attributeName]) { + retVal = RPTUtil.ariaAttributeImplicitMappings[attributeName][tag]; + if (typeof (retVal) === "function") { + retVal = retVal(ele); + } + } + else if ("*" in RPTUtil.ariaAttributeImplicitMappings[attributeName]) { + retVal = RPTUtil.ariaAttributeImplicitMappings[attributeName]["*"]; + if (typeof (retVal) === "function") { + retVal = retVal(ele); + } + } + } + } + // Check role-based defaults + if (!retVal) { + var role = ARIAMapper_1.ARIAMapper.nodeToRole(ele); + if (role in RPTUtil.ariaAttributeRoleDefaults && attributeName in RPTUtil.ariaAttributeRoleDefaults[role]) { + retVal = RPTUtil.ariaAttributeRoleDefaults[role][attributeName]; + if (typeof (retVal) === "function") { + retVal = retVal(ele); + } + } + } + // Still not defined? Check global defaults + if (!retVal && attributeName in RPTUtil.ariaAttributeGlobalDefaults) { + retVal = RPTUtil.ariaAttributeGlobalDefaults[attributeName]; + } + return retVal; + }; + RPTUtil.wordCount = function (str) { + str = str.trim(); + if (str.length === 0) + return 0; + return str.split(/\s+/g).length; + }; + /** + * Note that this only detects if the element itself is in the tab order. + * However, this element may delegate focus to another element via aria-activedescendant. + * Also, focus varies by browser... sticking to things that are focusable on Chrome and Firefox. + */ + RPTUtil.isTabbable = function (element) { + // Using https://allyjs.io/data-tables/focusable.html + // Handle the explicit cases first + if (!VisUtil_1.VisUtil.isNodeVisible(element)) + return false; + if (element.hasAttribute("tabindex")) { + return parseInt(element.getAttribute("tabindex")) >= 0; + } + // Explicit cases handled - now the implicit + var nodeName = element.nodeName.toLowerCase(); + if (nodeName in RPTUtil.tabTagMap) { + var retVal = RPTUtil.tabTagMap[nodeName]; + if (typeof (retVal) === "function") { + retVal = retVal(element); + } + return retVal; + } + else { + return false; + } + }; + /** + * a target is en element that accept a pointer action (click or touch) + * + */ + RPTUtil.isTarget = function (element) { + if (!element) + return false; + if (element.hasAttribute("tabindex") || RPTUtil.isTabbable(element)) + return true; + var roles = RPTUtil.getRoles(element, true); + if (!roles && roles.length === 0) + return false; + var tagProperty = RPTUtil.getElementAriaProperty(element); + var allowedRoles = RPTUtil.getAllowedAriaRoles(element, tagProperty); + if (!allowedRoles || allowedRoles.length === 0) + return false; + var parent = element.parentElement; + // datalist, fieldset, optgroup, etc. may be just used for grouping purpose, so go up to the parent + while (parent && roles.some(function (role) { return role === 'group'; })) + parent = parent.parentElement; + if (parent && (parent.hasAttribute("tabindex") || RPTUtil.isTabbable(parent))) { + var target_roles_1 = ["listitem", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "treeitem"]; + if (allowedRoles.includes('any') || roles.some(function (role) { return target_roles_1.includes(role); })) + return true; + } + return false; + }; + /** + * a target is en element that accept a pointer action (click or touch) + * a target is a browser default if it's a native widget (no user defined role) without user style + */ + RPTUtil.isTargetBrowserDefault = function (element) { + if (!element) + return false; + // user defained widget + var roles = RPTUtil.getRoles(element, false); + if (roles && roles.length > 0) + return false; + // no user style to space control size, including use of font + var styles = (0, CSSUtil_1.getDefinedStyles)(element); + if (styles['line-height'] || styles['height'] || styles['width'] || styles['min-height'] || styles['min-width'] + || styles['font-size'] || styles['margin-top'] || styles['margin-bottom'] || styles['margin-left'] || styles['margin-right']) + return false; + return true; + }; + /** + * an "inline" CSS display property tells the element to fit itself on the same line. An 'inline' element's width and height are ignored. + * some element has default inline property, such as , + * most formatting elements inherent inline property, such as , , , + * other inline elements: