From 622bfc108b469b143ad425b0ccd9080fae3f1107 Mon Sep 17 00:00:00 2001 From: tanhauhau Date: Sun, 10 Jul 2022 23:46:53 +0800 Subject: [PATCH] swtich to use aria-query --- package-lock.json | 29 +++++++++++++++++++ package.json | 2 ++ src/compiler/compile/compiler_warnings.ts | 4 +++ src/compiler/compile/nodes/Element.ts | 27 ++++------------- .../input.svelte | 4 ++- .../warnings.json | 21 ++++++++++++-- 6 files changed, 61 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 38abdfc3306..ab4b20ed594 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,12 +18,14 @@ "@rollup/plugin-typescript": "^2.0.1", "@rollup/plugin-virtual": "^2.0.0", "@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.8.0", + "@types/aria-query": "^5.0.0", "@types/mocha": "^7.0.0", "@types/node": "^8.10.53", "@typescript-eslint/eslint-plugin": "^5.22.0", "@typescript-eslint/parser": "^5.22.0", "acorn": "^8.4.1", "agadoo": "^1.1.0", + "aria-query": "^5.0.0", "code-red": "^0.2.5", "css-tree": "^1.1.2", "eslint": "^8.0.0", @@ -285,6 +287,12 @@ "resolved": "git+ssh://git@github.com/sveltejs/eslint-config.git#31fd4faeea88990069502460b023698b1c9c2d13", "dev": true }, + "node_modules/@types/aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "dev": true + }, "node_modules/@types/estree": { "version": "0.0.50", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", @@ -698,6 +706,15 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/array-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", @@ -4927,6 +4944,12 @@ "dev": true, "from": "@sveltejs/eslint-config@github:sveltejs/eslint-config#v5.8.0" }, + "@types/aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "dev": true + }, "@types/estree": { "version": "0.0.50", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", @@ -5208,6 +5231,12 @@ "sprintf-js": "~1.0.2" } }, + "aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", + "dev": true + }, "array-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", diff --git a/package.json b/package.json index de712b9bab9..ade713f4e3f 100644 --- a/package.json +++ b/package.json @@ -124,12 +124,14 @@ "@rollup/plugin-typescript": "^2.0.1", "@rollup/plugin-virtual": "^2.0.0", "@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.8.0", + "@types/aria-query": "^5.0.0", "@types/mocha": "^7.0.0", "@types/node": "^8.10.53", "@typescript-eslint/eslint-plugin": "^5.22.0", "@typescript-eslint/parser": "^5.22.0", "acorn": "^8.4.1", "agadoo": "^1.1.0", + "aria-query": "^5.0.0", "code-red": "^0.2.5", "css-tree": "^1.1.2", "eslint": "^8.0.0", diff --git a/src/compiler/compile/compiler_warnings.ts b/src/compiler/compile/compiler_warnings.ts index 86ec98cb8b1..833722c3b95 100644 --- a/src/compiler/compile/compiler_warnings.ts +++ b/src/compiler/compile/compiler_warnings.ts @@ -80,6 +80,10 @@ export default { code: 'a11y-no-redundant-roles', message: `A11y: Redundant role '${role}'` }), + a11y_role_has_required_aria_props: (role: string, props: string[]) => ({ + code: 'a11y-role-has-required-aria-props', + message: `A11y: Elements with the ARIA role "${role}" must have the following attributes defined: ${props.map(name => `"${name}"`).join(', ')}` + }), a11y_accesskey: { code: 'a11y-accesskey', message: 'A11y: Avoid using accesskey' diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index f9dad93a75c..35131cefcfd 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -23,6 +23,7 @@ import { string_literal } from '../utils/stringify'; import { Literal } from 'estree'; import compiler_warnings from '../compiler_warnings'; import compiler_errors from '../compiler_errors'; +import { ARIARoleDefintionKey, roles } from 'aria-query'; const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/; @@ -45,20 +46,6 @@ const a11y_required_attributes = { object: ['title', 'aria-label', 'aria-labelledby'] }; -const a11y_required_role_props = { - checkbox: ['aria-checked'], - combobox: ['aria-controls', 'aria-expanded'], - heading: ['aria-level'], - menuitemcheckbox: ['aria-checked'], - menuitemradio: ['aria-checked'], - meter: ['aria-valuemax', 'aria-valuemin', 'aria-valuenow'], - option: ['aria-selected'], - radio: ['aria-checked'], - scrollbar: ['aria-controls', 'aria-valuenow'], - slider: ['aria-valuenow'], - switch: ['aria-checked'] -}; - const a11y_distracting_elements = new Set([ 'blink', 'marquee' @@ -477,18 +464,14 @@ export default class Element extends Node { } } - // @ts-ignore - const required_role_props = a11y_required_role_props[value]; - // role-has-required-aria-props - if (required_role_props) { + const role = roles.get(value as ARIARoleDefintionKey); + if (role) { + const required_role_props = Object.keys(role.requiredProps); const has_missing_props = required_role_props.some(prop => !attributes.find(a => a.name === prop)); if (has_missing_props) { - component.warn(attribute, { - code: 'a11y-role-has-required-aria-props', - message: `A11y: Elements with the ARIA role "${value}" must have the following attributes defined: ${String(required_role_props)}` - }); + component.warn(attribute, compiler_warnings.a11y_role_has_required_aria_props(value as string, required_role_props)); } } } diff --git a/test/validator/samples/a11y-role-has-required-aria-props/input.svelte b/test/validator/samples/a11y-role-has-required-aria-props/input.svelte index b3d2af589b4..8e88b089080 100644 --- a/test/validator/samples/a11y-role-has-required-aria-props/input.svelte +++ b/test/validator/samples/a11y-role-has-required-aria-props/input.svelte @@ -1,7 +1,9 @@
+
-
\ No newline at end of file +
+
diff --git a/test/validator/samples/a11y-role-has-required-aria-props/warnings.json b/test/validator/samples/a11y-role-has-required-aria-props/warnings.json index c0f5a3b02d0..4de7c840016 100644 --- a/test/validator/samples/a11y-role-has-required-aria-props/warnings.json +++ b/test/validator/samples/a11y-role-has-required-aria-props/warnings.json @@ -1,7 +1,7 @@ [ { "code": "a11y-role-has-required-aria-props", - "message": "A11y: Elements with the ARIA role \"heading\" must have the following attributes defined: aria-level", + "message": "A11y: Elements with the ARIA role \"heading\" must have the following attributes defined: \"aria-level\"", "start": { "line": 1, "column": 5, @@ -16,7 +16,7 @@ }, { "code": "a11y-role-has-required-aria-props", - "message": "A11y: Elements with the ARIA role \"checkbox\" must have the following attributes defined: aria-checked", + "message": "A11y: Elements with the ARIA role \"checkbox\" must have the following attributes defined: \"aria-checked\"", "start": { "line": 2, "column": 6, @@ -31,7 +31,7 @@ }, { "code": "a11y-role-has-required-aria-props", - "message": "A11y: Elements with the ARIA role \"meter\" must have the following attributes defined: aria-valuemax,aria-valuemin,aria-valuenow", + "message": "A11y: Elements with the ARIA role \"meter\" must have the following attributes defined: \"aria-valuenow\"", "start": { "line": 3, "column": 5, @@ -43,5 +43,20 @@ "character": 74 }, "pos": 62 + }, + { + "code": "a11y-role-has-required-aria-props", + "message": "A11y: Elements with the ARIA role \"scrollbar\" must have the following attributes defined: \"aria-controls\", \"aria-valuenow\"", + "start": { + "character": 87, + "column": 5, + "line": 4 + }, + "end": { + "character": 103, + "column": 21, + "line": 4 + }, + "pos": 87 } ]